diff --git a/util/generate_man.js b/util/generate_man.js index dcf3ebd3b..978c19eff 100755 --- a/util/generate_man.js +++ b/util/generate_man.js @@ -42,7 +42,6 @@ program .parse() const debug = program.opts().debug - const doInclude = (content, includes, f) => { const result = content.replace(includesRE, (m, m1) => { if (!m1.length) return m @@ -56,7 +55,7 @@ const doInclude = (content, includes, f) => { return result } -const processDovecotMd = () => { +const processDovecotMdPost = () => { return tree => { /* Convert definition lists to base mdast elements that remark-man * can handle. */ @@ -88,32 +87,83 @@ const processDovecotMd = () => { node.node.children = [ u('blockquote', node.children) ] }) + } +} + +const DovecotMd = (md) => { + const parts = md.split(',').map((x) => x.trim()) + switch (parts[0]) { + case 'doveadm': + return [ + { + type:'strong', + children: [ + { + type:'text', value:'doveadm(1)' + } + ] + }, + { + type:'emphasis', + children: [ + { + type:'text', value:' ' + parts.slice(1).join(' ') + } + ] + } + ] + case 'man': + return [{type:'text', value:parts[1] + '(' + (parts[3] ? parts[3] : '1') + ')'}] + case 'plugin': + return [{type:'text', value:parts[1] + ' plugin documentation'}] + case 'rfc': + return [{type:'text', value:'RFC ' + parts[1]}] + case 'setting': + return [ + { + type:'strong', + children: [ + { + type:'text', value:parts[1] + } + ] + }, + { + type:'text', value:' setting' + } + ] + case 'link': + return [{type:'text', value:parts[1]}] + default: + throw new Error('unknown dovecot markdown command: ' + parts[0]) + } +} +const processDovecotMdPre = () => { + return tree => { /* Go through and replace Dovecot markdown items with man-friendly * textual equivalents. */ - return map(tree, (node) => { - if (node.value) { - node.value = node.value.replace(includesDM, (m, m1) => { - if (!m1.length) return m - - const parts = m1.split(',').map((x) => x.trim()) - switch (parts[0]) { - case 'man': - return parts[1] + '(' + (parts[3] ? parts[3] : '1') + ')' - case 'plugin': - return parts[1] + ' plugin documentation' - case 'rfc': - return 'RFC ' + parts[1] - case 'setting': - return '`' + parts[1] + '`' - case 'link': - return parts[1] - default: - throw new Error('unknown dovecot markdown command: ' + parts[0]) - } - }) - } - return node + return map(tree, (para) => { + visit(para, 'text', (node, index, para) => { + /* if the text contains at least one tag, we need to convert + * this into an array of children that replace the parent's children. */ + var result; + var newChildren = [] + var pos = 0; + while ((result = includesDM.exec(node.value))) { + const pre = node.value.substr(pos, result.index - pos) + pos = result.index + result[0].length + if (pre != "") + newChildren.push({type: 'text', value: pre}) + newChildren.push(...DovecotMd(result[1])) + } + if (newChildren.length != 0) { + if (pos < node.value.length) + newChildren.push({type: 'text', value: node.value.substr(pos)}) + para.children = newChildren + } + }) + return para }) } } @@ -121,7 +171,7 @@ const processDovecotMd = () => { const main = async (component, outPath) => { /* Create output directory, if it doesn't exist. */ if (!fs.existsSync(outPath)) { - await fs.promises.mkdir(outPath) + await fs.promises.mkdir(outPath, { recursive: true }) } /* Generate list of man files. */ @@ -151,9 +201,10 @@ const main = async (component, outPath) => { continue await unified(). + use(processDovecotMdPre). use(remarkParse). use(remarkDeflist). - use(processDovecotMd). + use(processDovecotMdPost). use(remarkMan, { manual: 'Dovecot', version: gitHash,