| ... | ... | @@ -482,40 +482,40 @@ const NAV_MODES = { |
| 482 | 482 | const root_file_idx = zigAnalysis.modules[zigAnalysis.rootMod].file; |
| 483 | 483 | const root_file_name = getFile(root_file_idx).name; |
| 484 | 484 | domActiveGuide.innerHTML = markdown(` |
| 485 | | # Zig Guides |
| 486 | | These autodocs don't contain any guide. |
| 485 | # Zig Guides |
| 486 | These autodocs don't contain any guide. |
| 487 | 487 | |
| 488 | | While the API section is a reference guide autogenerated from Zig source code, |
| 489 | | guides are meant to be handwritten explanations that provide for example: |
| 488 | While the API section is a reference guide autogenerated from Zig source code, |
| 489 | guides are meant to be handwritten explanations that provide for example: |
| 490 | 490 | |
| 491 | | - how-to explanations for common use-cases |
| 492 | | - technical documentation |
| 493 | | - information about advanced usage patterns |
| 494 | | |
| 495 | | You can add guides by specifying which markdown files to include |
| 496 | | in the top level doc comment of your root file, like so: |
| 497 | | |
| 498 | | (At the top of *${root_file_name}*) |
| 499 | | \`\`\` |
| 500 | | //!zig-autodoc-guide: intro.md |
| 501 | | //!zig-autodoc-guide: quickstart.md |
| 502 | | //!zig-autodoc-guide: advanced-docs/advanced-stuff.md |
| 503 | | \`\`\` |
| 504 | | |
| 505 | | You can also create sections to group guides together: |
| 506 | | |
| 507 | | \`\`\` |
| 508 | | //!zig-autodoc-section: CLI Usage |
| 509 | | //!zig-autodoc-guide: cli-basics.md |
| 510 | | //!zig-autodoc-guide: cli-advanced.md |
| 511 | | \`\`\` |
| 512 | | |
| 513 | | |
| 514 | | **Note that this feature is still under heavy development so expect bugs** |
| 515 | | **and missing features!** |
| 491 | - how-to explanations for common use-cases |
| 492 | - technical documentation |
| 493 | - information about advanced usage patterns |
| 494 | |
| 495 | You can add guides by specifying which markdown files to include |
| 496 | in the top level doc comment of your root file, like so: |
| 497 | |
| 498 | (At the top of *${root_file_name}*) |
| 499 | \`\`\` |
| 500 | //!zig-autodoc-guide: intro.md |
| 501 | //!zig-autodoc-guide: quickstart.md |
| 502 | //!zig-autodoc-guide: advanced-docs/advanced-stuff.md |
| 503 | \`\`\` |
| 504 | |
| 505 | You can also create sections to group guides together: |
| 516 | 506 | |
| 517 | | Happy writing! |
| 518 | | `); |
| 507 | \`\`\` |
| 508 | //!zig-autodoc-section: CLI Usage |
| 509 | //!zig-autodoc-guide: cli-basics.md |
| 510 | //!zig-autodoc-guide: cli-advanced.md |
| 511 | \`\`\` |
| 512 | |
| 513 | |
| 514 | **Note that this feature is still under heavy development so expect bugs** |
| 515 | **and missing features!** |
| 516 | |
| 517 | Happy writing! |
| 518 | `); |
| 519 | 519 | } else { |
| 520 | 520 | domActiveGuide.innerHTML = markdown(activeGuide.body); |
| 521 | 521 | } |
| ... | ... | @@ -3586,231 +3586,25 @@ function addDeclToSearchResults(decl, declIndex, modNames, item, list, stack) { |
| 3586 | 3586 | |
| 3587 | 3587 | |
| 3588 | 3588 | function markdown(input, contextType) { |
| 3589 | | const raw_lines = input.split("\n"); // zig allows no '\r', so we don't need to split on CR |
| 3590 | | |
| 3591 | | const lines = []; |
| 3592 | | |
| 3593 | | // PHASE 1: |
| 3594 | | // Dissect lines and determine the type for each line. |
| 3595 | | // Also computes indentation level and removes unnecessary whitespace |
| 3596 | | |
| 3597 | | let is_reading_code = false; |
| 3598 | | let code_indent = 0; |
| 3599 | | for (let line_no = 0; line_no < raw_lines.length; line_no++) { |
| 3600 | | const raw_line = raw_lines[line_no]; |
| 3601 | | |
| 3602 | | const line = { |
| 3603 | | indent: 0, |
| 3604 | | raw_text: raw_line, |
| 3605 | | text: raw_line.trim(), |
| 3606 | | type: "p", // p, h1 … h6, code, ul, ol, blockquote, skip, empty |
| 3607 | | ordered_number: -1, // NOTE: hack to make the type checker happy |
| 3608 | | }; |
| 3609 | | |
| 3610 | | if (!is_reading_code) { |
| 3611 | | while ( |
| 3612 | | line.indent < line.raw_text.length && |
| 3613 | | line.raw_text[line.indent] == " " |
| 3614 | | ) { |
| 3615 | | line.indent += 1; |
| 3616 | | } |
| 3617 | | |
| 3618 | | if (line.text.startsWith("######")) { |
| 3619 | | line.type = "h6"; |
| 3620 | | line.text = line.text.substr(6); |
| 3621 | | } else if (line.text.startsWith("#####")) { |
| 3622 | | line.type = "h5"; |
| 3623 | | line.text = line.text.substr(5); |
| 3624 | | } else if (line.text.startsWith("####")) { |
| 3625 | | line.type = "h4"; |
| 3626 | | line.text = line.text.substr(4); |
| 3627 | | } else if (line.text.startsWith("###")) { |
| 3628 | | line.type = "h3"; |
| 3629 | | line.text = line.text.substr(3); |
| 3630 | | } else if (line.text.startsWith("##")) { |
| 3631 | | line.type = "h2"; |
| 3632 | | line.text = line.text.substr(2); |
| 3633 | | } else if (line.text.startsWith("#")) { |
| 3634 | | line.type = "h1"; |
| 3635 | | line.text = line.text.substr(1); |
| 3636 | | } else if (line.text.match(/^-[ \t]+.*$/)) { |
| 3637 | | // line starts with a hyphen, followed by spaces or tabs |
| 3638 | | const match = line.text.match(/^-[ \t]+/); |
| 3639 | | line.type = "ul"; |
| 3640 | | line.text = line.text.substr(match[0].length); |
| 3641 | | } else if (line.text.match(/^\d+\.[ \t]+.*$/)) { |
| 3642 | | // line starts with {number}{dot}{spaces or tabs} |
| 3643 | | const match = line.text.match(/(\d+)\.[ \t]+/); |
| 3644 | | line.type = "ol"; |
| 3645 | | line.text = line.text.substr(match[0].length); |
| 3646 | | line.ordered_number = Number(match[1].length); |
| 3647 | | } else if (line.text == "```") { |
| 3648 | | line.type = "skip"; |
| 3649 | | is_reading_code = true; |
| 3650 | | code_indent = line.indent; |
| 3651 | | } else if (line.text == "") { |
| 3652 | | line.type = "empty"; |
| 3589 | const parsed = new commonmark.Parser({ smart: true }).parse(input); |
| 3590 | |
| 3591 | // Look for decl references in inline code (`ref`) |
| 3592 | const walker = parsed.walker(); |
| 3593 | let event; |
| 3594 | while ((event = walker.next())) { |
| 3595 | const node = event.node; |
| 3596 | if (node.type === "code") { |
| 3597 | const declHash = detectDeclPath(node.literal, contextType); |
| 3598 | if (declHash) { |
| 3599 | const link = new commonmark.Node("link"); |
| 3600 | link.destination = declHash; |
| 3601 | node.insertBefore(link); |
| 3602 | link.appendChild(node); |
| 3653 | 3603 | } |
| 3654 | | } else { |
| 3655 | | if (line.text == "```") { |
| 3656 | | is_reading_code = false; |
| 3657 | | line.type = "skip"; |
| 3658 | | } else { |
| 3659 | | line.type = "code"; |
| 3660 | | line.text = line.raw_text.substr(code_indent); // remove the indent of the ``` from all the code block |
| 3661 | | } |
| 3662 | | } |
| 3663 | | |
| 3664 | | if (line.type != "skip") { |
| 3665 | | lines.push(line); |
| 3666 | 3604 | } |
| 3667 | 3605 | } |
| 3668 | 3606 | |
| 3669 | | // PHASE 2: |
| 3670 | | // Render HTML from markdown lines. |
| 3671 | | // Look at each line and emit fitting HTML code |
| 3672 | | |
| 3673 | | function markdownInlines(innerText, contextType) { |
| 3674 | | // inline types: |
| 3675 | | // **{INLINE}** : <strong> |
| 3676 | | // __{INLINE}__ : <u> |
| 3677 | | // ~~{INLINE}~~ : <s> |
| 3678 | | // *{INLINE}* : <emph> |
| 3679 | | // _{INLINE}_ : <emph> |
| 3680 | | // `{TEXT}` : <code> |
| 3681 | | // [{INLINE}]({URL}) : <a> |
| 3682 | | //  : <img> |
| 3683 | | // [[std;format.fmt]] : <a> (inner link) |
| 3684 | | |
| 3685 | | const formats = [ |
| 3686 | | { |
| 3687 | | marker: "**", |
| 3688 | | tag: "strong", |
| 3689 | | }, |
| 3690 | | { |
| 3691 | | marker: "~~", |
| 3692 | | tag: "s", |
| 3693 | | }, |
| 3694 | | { |
| 3695 | | marker: "__", |
| 3696 | | tag: "u", |
| 3697 | | }, |
| 3698 | | { |
| 3699 | | marker: "*", |
| 3700 | | tag: "em", |
| 3701 | | }, |
| 3702 | | ]; |
| 3703 | | |
| 3704 | | const stack = []; |
| 3705 | | |
| 3706 | | let innerHTML = ""; |
| 3707 | | let currentRun = ""; |
| 3708 | | |
| 3709 | | function flushRun() { |
| 3710 | | if (currentRun != "") { |
| 3711 | | innerHTML += escapeHtml(currentRun); |
| 3712 | | } |
| 3713 | | currentRun = ""; |
| 3714 | | } |
| 3715 | | |
| 3716 | | let parsing_code = false; |
| 3717 | | let codetag = ""; |
| 3718 | | let in_code = false; |
| 3719 | | |
| 3720 | | // state used to link decl references |
| 3721 | | let quote_start = undefined; |
| 3722 | | let quote_start_html = undefined; |
| 3723 | | |
| 3724 | | for (let i = 0; i < innerText.length; i++) { |
| 3725 | | if (parsing_code && in_code) { |
| 3726 | | if (innerText.substr(i, codetag.length) == codetag) { |
| 3727 | | // remove leading and trailing whitespace if string both starts and ends with one. |
| 3728 | | if ( |
| 3729 | | currentRun[0] == " " && |
| 3730 | | currentRun[currentRun.length - 1] == " " |
| 3731 | | ) { |
| 3732 | | currentRun = currentRun.substr(1, currentRun.length - 2); |
| 3733 | | } |
| 3734 | | flushRun(); |
| 3735 | | i += codetag.length - 1; |
| 3736 | | in_code = false; |
| 3737 | | parsing_code = false; |
| 3738 | | innerHTML += "</code>"; |
| 3739 | | codetag = ""; |
| 3740 | | |
| 3741 | | // find out if this is a decl that should be linked |
| 3742 | | const maybe_decl_path = innerText.substr(quote_start, i-quote_start); |
| 3743 | | const decl_hash = detectDeclPath(maybe_decl_path, contextType); |
| 3744 | | if (decl_hash) { |
| 3745 | | const anchor_opening_tag = "<a href='"+ decl_hash +"'>"; |
| 3746 | | innerHTML = innerHTML.slice(0, quote_start_html) |
| 3747 | | + anchor_opening_tag |
| 3748 | | + innerHTML.slice(quote_start_html) + "</a>"; |
| 3749 | | } |
| 3750 | | } else { |
| 3751 | | currentRun += innerText[i]; |
| 3752 | | } |
| 3753 | | continue; |
| 3754 | | } |
| 3755 | | |
| 3756 | | if (innerText[i] == "`") { |
| 3757 | | flushRun(); |
| 3758 | | if (!parsing_code) { |
| 3759 | | quote_start = i + 1; |
| 3760 | | quote_start_html = innerHTML.length; |
| 3761 | | innerHTML += "<code>"; |
| 3762 | | } |
| 3763 | | parsing_code = true; |
| 3764 | | codetag += "`"; |
| 3765 | | continue; |
| 3766 | | } |
| 3767 | | |
| 3768 | | if (parsing_code) { |
| 3769 | | currentRun += innerText[i]; |
| 3770 | | in_code = true; |
| 3771 | | } else { |
| 3772 | | let any = false; |
| 3773 | | for ( |
| 3774 | | let idx = stack.length > 0 ? -1 : 0; |
| 3775 | | idx < formats.length; |
| 3776 | | idx++ |
| 3777 | | ) { |
| 3778 | | const fmt = idx >= 0 ? formats[idx] : stack[stack.length - 1]; |
| 3779 | | if (innerText.substr(i, fmt.marker.length) == fmt.marker) { |
| 3780 | | flushRun(); |
| 3781 | | if (stack[stack.length - 1] == fmt) { |
| 3782 | | stack.pop(); |
| 3783 | | innerHTML += "</" + fmt.tag + ">"; |
| 3784 | | } else { |
| 3785 | | stack.push(fmt); |
| 3786 | | innerHTML += "<" + fmt.tag + ">"; |
| 3787 | | } |
| 3788 | | i += fmt.marker.length - 1; |
| 3789 | | any = true; |
| 3790 | | break; |
| 3791 | | } |
| 3792 | | } |
| 3793 | | if (!any) { |
| 3794 | | currentRun += innerText[i]; |
| 3795 | | } |
| 3796 | | } |
| 3797 | | } |
| 3798 | | flushRun(); |
| 3799 | | |
| 3800 | | if (in_code) { |
| 3801 | | in_code = false; |
| 3802 | | parsing_code = false; |
| 3803 | | innerHTML += "</code>"; |
| 3804 | | codetag = ""; |
| 3805 | | } |
| 3806 | | |
| 3807 | | while (stack.length > 0) { |
| 3808 | | const fmt = stack.pop(); |
| 3809 | | innerHTML += "</" + fmt.tag + ">"; |
| 3810 | | } |
| 3811 | | |
| 3812 | | return innerHTML; |
| 3813 | | } |
| 3607 | return new commonmark.HtmlRenderer({ safe: true }).render(parsed); |
| 3814 | 3608 | |
| 3815 | 3609 | function detectDeclPath(text, context) { |
| 3816 | 3610 | let result = ""; |
| ... | ... | @@ -3876,102 +3670,6 @@ function addDeclToSearchResults(decl, declIndex, modNames, item, list, stack) { |
| 3876 | 3670 | return result; |
| 3877 | 3671 | |
| 3878 | 3672 | } |
| 3879 | | |
| 3880 | | function previousLineIs(type, line_no) { |
| 3881 | | if (line_no > 0) { |
| 3882 | | return lines[line_no - 1].type == type; |
| 3883 | | } else { |
| 3884 | | return false; |
| 3885 | | } |
| 3886 | | } |
| 3887 | | |
| 3888 | | function nextLineIs(type, line_no) { |
| 3889 | | if (line_no < lines.length - 1) { |
| 3890 | | return lines[line_no + 1].type == type; |
| 3891 | | } else { |
| 3892 | | return false; |
| 3893 | | } |
| 3894 | | } |
| 3895 | | |
| 3896 | | function getPreviousLineIndent(line_no) { |
| 3897 | | if (line_no > 0) { |
| 3898 | | return lines[line_no - 1].indent; |
| 3899 | | } else { |
| 3900 | | return 0; |
| 3901 | | } |
| 3902 | | } |
| 3903 | | |
| 3904 | | function getNextLineIndent(line_no) { |
| 3905 | | if (line_no < lines.length - 1) { |
| 3906 | | return lines[line_no + 1].indent; |
| 3907 | | } else { |
| 3908 | | return 0; |
| 3909 | | } |
| 3910 | | } |
| 3911 | | |
| 3912 | | let html = ""; |
| 3913 | | for (let line_no = 0; line_no < lines.length; line_no++) { |
| 3914 | | const line = lines[line_no]; |
| 3915 | | |
| 3916 | | switch (line.type) { |
| 3917 | | case "h1": |
| 3918 | | case "h2": |
| 3919 | | case "h3": |
| 3920 | | case "h4": |
| 3921 | | case "h5": |
| 3922 | | case "h6": |
| 3923 | | html += |
| 3924 | | "<" + |
| 3925 | | line.type + |
| 3926 | | ">" + |
| 3927 | | markdownInlines(line.text, contextType) + |
| 3928 | | "</" + |
| 3929 | | line.type + |
| 3930 | | ">\n"; |
| 3931 | | break; |
| 3932 | | |
| 3933 | | case "ul": |
| 3934 | | case "ol": |
| 3935 | | if ( |
| 3936 | | !previousLineIs(line.type, line_no) || |
| 3937 | | getPreviousLineIndent(line_no) < line.indent |
| 3938 | | ) { |
| 3939 | | html += "<" + line.type + ">\n"; |
| 3940 | | } |
| 3941 | | |
| 3942 | | html += "<li>" + markdownInlines(line.text, contextType) + "</li>\n"; |
| 3943 | | |
| 3944 | | if ( |
| 3945 | | !nextLineIs(line.type, line_no) || |
| 3946 | | getNextLineIndent(line_no) < line.indent |
| 3947 | | ) { |
| 3948 | | html += "</" + line.type + ">\n"; |
| 3949 | | } |
| 3950 | | break; |
| 3951 | | |
| 3952 | | case "p": |
| 3953 | | if (!previousLineIs("p", line_no)) { |
| 3954 | | html += "<p>\n"; |
| 3955 | | } |
| 3956 | | html += markdownInlines(line.text, contextType) + "\n"; |
| 3957 | | if (!nextLineIs("p", line_no)) { |
| 3958 | | html += "</p>\n"; |
| 3959 | | } |
| 3960 | | break; |
| 3961 | | |
| 3962 | | case "code": |
| 3963 | | if (!previousLineIs("code", line_no)) { |
| 3964 | | html += "<pre><code>"; |
| 3965 | | } |
| 3966 | | html += escapeHtml(line.text) + "\n"; |
| 3967 | | if (!nextLineIs("code", line_no)) { |
| 3968 | | html += "</code></pre>\n"; |
| 3969 | | } |
| 3970 | | break; |
| 3971 | | } |
| 3972 | | } |
| 3973 | | |
| 3974 | | return html; |
| 3975 | 3673 | } |
| 3976 | 3674 | |
| 3977 | 3675 | function activateSelectedResult() { |