diff options
| author | Ian Johnson <ian@ianjohnson.dev> | 2023-06-25 21:15:12 -0400 |
|---|---|---|
| committer | Loris Cro <kappaloris@gmail.com> | 2023-07-04 17:08:46 +0200 |
| commit | d3eaa75c07aaac09d9dd74aa2a175ba799159faa (patch) | |
| tree | a9bcb1c20d9432f1b7ea63f432478eff19a444e6 /lib/docs | |
| parent | ba6e5e65a0f84b803fffe4dd26b6e71417cab616 (diff) | |
| download | zig-d3eaa75c07aaac09d9dd74aa2a175ba799159faa.tar.gz zig-d3eaa75c07aaac09d9dd74aa2a175ba799159faa.zip | |
autodoc: use commonmark.js for Markdown rendering
Diffstat (limited to 'lib/docs')
| -rw-r--r-- | lib/docs/main.js | 394 |
1 files changed, 46 insertions, 348 deletions
diff --git a/lib/docs/main.js b/lib/docs/main.js index 10e5eae248..4d1a935fda 100644 --- a/lib/docs/main.js +++ b/lib/docs/main.js @@ -482,40 +482,40 @@ const NAV_MODES = { const root_file_idx = zigAnalysis.modules[zigAnalysis.rootMod].file; const root_file_name = getFile(root_file_idx).name; domActiveGuide.innerHTML = markdown(` - # Zig Guides - These autodocs don't contain any guide. +# Zig Guides +These autodocs don't contain any guide. - While the API section is a reference guide autogenerated from Zig source code, - guides are meant to be handwritten explanations that provide for example: +While the API section is a reference guide autogenerated from Zig source code, +guides are meant to be handwritten explanations that provide for example: - - how-to explanations for common use-cases - - technical documentation - - information about advanced usage patterns - - You can add guides by specifying which markdown files to include - in the top level doc comment of your root file, like so: - - (At the top of *${root_file_name}*) - \`\`\` - //!zig-autodoc-guide: intro.md - //!zig-autodoc-guide: quickstart.md - //!zig-autodoc-guide: advanced-docs/advanced-stuff.md - \`\`\` - - You can also create sections to group guides together: - - \`\`\` - //!zig-autodoc-section: CLI Usage - //!zig-autodoc-guide: cli-basics.md - //!zig-autodoc-guide: cli-advanced.md - \`\`\` - - - **Note that this feature is still under heavy development so expect bugs** - **and missing features!** +- how-to explanations for common use-cases +- technical documentation +- information about advanced usage patterns + +You can add guides by specifying which markdown files to include +in the top level doc comment of your root file, like so: + +(At the top of *${root_file_name}*) +\`\`\` +//!zig-autodoc-guide: intro.md +//!zig-autodoc-guide: quickstart.md +//!zig-autodoc-guide: advanced-docs/advanced-stuff.md +\`\`\` + +You can also create sections to group guides together: - Happy writing! - `); +\`\`\` +//!zig-autodoc-section: CLI Usage +//!zig-autodoc-guide: cli-basics.md +//!zig-autodoc-guide: cli-advanced.md +\`\`\` + + +**Note that this feature is still under heavy development so expect bugs** +**and missing features!** + +Happy writing! +`); } else { domActiveGuide.innerHTML = markdown(activeGuide.body); } @@ -3586,231 +3586,25 @@ function addDeclToSearchResults(decl, declIndex, modNames, item, list, stack) { function markdown(input, contextType) { - const raw_lines = input.split("\n"); // zig allows no '\r', so we don't need to split on CR - - const lines = []; - - // PHASE 1: - // Dissect lines and determine the type for each line. - // Also computes indentation level and removes unnecessary whitespace - - let is_reading_code = false; - let code_indent = 0; - for (let line_no = 0; line_no < raw_lines.length; line_no++) { - const raw_line = raw_lines[line_no]; - - const line = { - indent: 0, - raw_text: raw_line, - text: raw_line.trim(), - type: "p", // p, h1 … h6, code, ul, ol, blockquote, skip, empty - ordered_number: -1, // NOTE: hack to make the type checker happy - }; - - if (!is_reading_code) { - while ( - line.indent < line.raw_text.length && - line.raw_text[line.indent] == " " - ) { - line.indent += 1; - } - - if (line.text.startsWith("######")) { - line.type = "h6"; - line.text = line.text.substr(6); - } else if (line.text.startsWith("#####")) { - line.type = "h5"; - line.text = line.text.substr(5); - } else if (line.text.startsWith("####")) { - line.type = "h4"; - line.text = line.text.substr(4); - } else if (line.text.startsWith("###")) { - line.type = "h3"; - line.text = line.text.substr(3); - } else if (line.text.startsWith("##")) { - line.type = "h2"; - line.text = line.text.substr(2); - } else if (line.text.startsWith("#")) { - line.type = "h1"; - line.text = line.text.substr(1); - } else if (line.text.match(/^-[ \t]+.*$/)) { - // line starts with a hyphen, followed by spaces or tabs - const match = line.text.match(/^-[ \t]+/); - line.type = "ul"; - line.text = line.text.substr(match[0].length); - } else if (line.text.match(/^\d+\.[ \t]+.*$/)) { - // line starts with {number}{dot}{spaces or tabs} - const match = line.text.match(/(\d+)\.[ \t]+/); - line.type = "ol"; - line.text = line.text.substr(match[0].length); - line.ordered_number = Number(match[1].length); - } else if (line.text == "```") { - line.type = "skip"; - is_reading_code = true; - code_indent = line.indent; - } else if (line.text == "") { - line.type = "empty"; + const parsed = new commonmark.Parser({ smart: true }).parse(input); + + // Look for decl references in inline code (`ref`) + const walker = parsed.walker(); + let event; + while ((event = walker.next())) { + const node = event.node; + if (node.type === "code") { + const declHash = detectDeclPath(node.literal, contextType); + if (declHash) { + const link = new commonmark.Node("link"); + link.destination = declHash; + node.insertBefore(link); + link.appendChild(node); } - } else { - if (line.text == "```") { - is_reading_code = false; - line.type = "skip"; - } else { - line.type = "code"; - line.text = line.raw_text.substr(code_indent); // remove the indent of the ``` from all the code block - } - } - - if (line.type != "skip") { - lines.push(line); } } - // PHASE 2: - // Render HTML from markdown lines. - // Look at each line and emit fitting HTML code - - function markdownInlines(innerText, contextType) { - // inline types: - // **{INLINE}** : <strong> - // __{INLINE}__ : <u> - // ~~{INLINE}~~ : <s> - // *{INLINE}* : <emph> - // _{INLINE}_ : <emph> - // `{TEXT}` : <code> - // [{INLINE}]({URL}) : <a> - //  : <img> - // [[std;format.fmt]] : <a> (inner link) - - const formats = [ - { - marker: "**", - tag: "strong", - }, - { - marker: "~~", - tag: "s", - }, - { - marker: "__", - tag: "u", - }, - { - marker: "*", - tag: "em", - }, - ]; - - const stack = []; - - let innerHTML = ""; - let currentRun = ""; - - function flushRun() { - if (currentRun != "") { - innerHTML += escapeHtml(currentRun); - } - currentRun = ""; - } - - let parsing_code = false; - let codetag = ""; - let in_code = false; - - // state used to link decl references - let quote_start = undefined; - let quote_start_html = undefined; - - for (let i = 0; i < innerText.length; i++) { - if (parsing_code && in_code) { - if (innerText.substr(i, codetag.length) == codetag) { - // remove leading and trailing whitespace if string both starts and ends with one. - if ( - currentRun[0] == " " && - currentRun[currentRun.length - 1] == " " - ) { - currentRun = currentRun.substr(1, currentRun.length - 2); - } - flushRun(); - i += codetag.length - 1; - in_code = false; - parsing_code = false; - innerHTML += "</code>"; - codetag = ""; - - // find out if this is a decl that should be linked - const maybe_decl_path = innerText.substr(quote_start, i-quote_start); - const decl_hash = detectDeclPath(maybe_decl_path, contextType); - if (decl_hash) { - const anchor_opening_tag = "<a href='"+ decl_hash +"'>"; - innerHTML = innerHTML.slice(0, quote_start_html) - + anchor_opening_tag - + innerHTML.slice(quote_start_html) + "</a>"; - } - } else { - currentRun += innerText[i]; - } - continue; - } - - if (innerText[i] == "`") { - flushRun(); - if (!parsing_code) { - quote_start = i + 1; - quote_start_html = innerHTML.length; - innerHTML += "<code>"; - } - parsing_code = true; - codetag += "`"; - continue; - } - - if (parsing_code) { - currentRun += innerText[i]; - in_code = true; - } else { - let any = false; - for ( - let idx = stack.length > 0 ? -1 : 0; - idx < formats.length; - idx++ - ) { - const fmt = idx >= 0 ? formats[idx] : stack[stack.length - 1]; - if (innerText.substr(i, fmt.marker.length) == fmt.marker) { - flushRun(); - if (stack[stack.length - 1] == fmt) { - stack.pop(); - innerHTML += "</" + fmt.tag + ">"; - } else { - stack.push(fmt); - innerHTML += "<" + fmt.tag + ">"; - } - i += fmt.marker.length - 1; - any = true; - break; - } - } - if (!any) { - currentRun += innerText[i]; - } - } - } - flushRun(); - - if (in_code) { - in_code = false; - parsing_code = false; - innerHTML += "</code>"; - codetag = ""; - } - - while (stack.length > 0) { - const fmt = stack.pop(); - innerHTML += "</" + fmt.tag + ">"; - } - - return innerHTML; - } + return new commonmark.HtmlRenderer({ safe: true }).render(parsed); function detectDeclPath(text, context) { let result = ""; @@ -3876,102 +3670,6 @@ function addDeclToSearchResults(decl, declIndex, modNames, item, list, stack) { return result; } - - function previousLineIs(type, line_no) { - if (line_no > 0) { - return lines[line_no - 1].type == type; - } else { - return false; - } - } - - function nextLineIs(type, line_no) { - if (line_no < lines.length - 1) { - return lines[line_no + 1].type == type; - } else { - return false; - } - } - - function getPreviousLineIndent(line_no) { - if (line_no > 0) { - return lines[line_no - 1].indent; - } else { - return 0; - } - } - - function getNextLineIndent(line_no) { - if (line_no < lines.length - 1) { - return lines[line_no + 1].indent; - } else { - return 0; - } - } - - let html = ""; - for (let line_no = 0; line_no < lines.length; line_no++) { - const line = lines[line_no]; - - switch (line.type) { - case "h1": - case "h2": - case "h3": - case "h4": - case "h5": - case "h6": - html += - "<" + - line.type + - ">" + - markdownInlines(line.text, contextType) + - "</" + - line.type + - ">\n"; - break; - - case "ul": - case "ol": - if ( - !previousLineIs(line.type, line_no) || - getPreviousLineIndent(line_no) < line.indent - ) { - html += "<" + line.type + ">\n"; - } - - html += "<li>" + markdownInlines(line.text, contextType) + "</li>\n"; - - if ( - !nextLineIs(line.type, line_no) || - getNextLineIndent(line_no) < line.indent - ) { - html += "</" + line.type + ">\n"; - } - break; - - case "p": - if (!previousLineIs("p", line_no)) { - html += "<p>\n"; - } - html += markdownInlines(line.text, contextType) + "\n"; - if (!nextLineIs("p", line_no)) { - html += "</p>\n"; - } - break; - - case "code": - if (!previousLineIs("code", line_no)) { - html += "<pre><code>"; - } - html += escapeHtml(line.text) + "\n"; - if (!nextLineIs("code", line_no)) { - html += "</code></pre>\n"; - } - break; - } - } - - return html; } function activateSelectedResult() { |
