X-Git-Url: http://nitlanguage.org diff --git a/src/markdown.nit b/src/markdown.nit index 9f21f32..e254480 100644 --- a/src/markdown.nit +++ b/src/markdown.nit @@ -15,15 +15,22 @@ # Transform Nit verbatim documentation into HTML module markdown -import parser +private import parser import html +private import highlight +private import parser_util # The class that does the convertion from a `ADoc` to HTML private class Doc2Mdwn + var toolcontext: ToolContext + # The lines of the current code block, empty is no current code block var curblock = new Array[String] - fun work(ndoc: ADoc): HTMLTag + # Count empty lines between code blocks + var empty_lines = 0 + + fun work(mdoc: MDoc): HTMLTag do var root = new HTMLTag("div") root.add_class("nitdoc") @@ -34,31 +41,55 @@ private class Doc2Mdwn # Indent level of the current line var indent = 0 + # Expected fencing closing tag (if any) + var in_fence: nullable String = null + # The current element (p, li, etc.) if any var n: nullable HTMLTag = null # The current ul element (if any) var ul: nullable HTMLTag = null + var is_first_line = true # Local variable to benefit adaptive typing - for c in ndoc.n_comment do - # Remove the starting `#` - var text = c.text.substring_from(1) - + for text in mdoc.content do # Count the number of spaces lastindent = indent indent = 0 - while text.length > indent and text[indent] == ' ' do indent += 1 + while text.length > indent and text.chars[indent] == ' ' do indent += 1 + + # In a fence + if in_fence != null then + # fence closing + if text.substring(0,in_fence.length) == in_fence then + close_codeblock(n or else root) + in_fence = null + continue + end + # else fence content + curblock.add(text) + continue + end # Is codeblock? Then just collect them - if indent > 4 then - var part = text.substring_from(4) - curblock.add(part) + if indent >= 3 then + for i in [0..empty_lines[ do curblock.add("") + empty_lines = 0 + # to allows 4 spaces including the one that follows the # + curblock.add(text) continue end - # Was a codblock just before the current line ? - close_codeblock(n or else root) + # fence opening + if text.substring(0,3) == "~~~" then + # Was a codblock just before the current line ? + close_codeblock(n or else root) + + var l = 3 + while l < text.length and text.chars[l] == '~' do l += 1 + in_fence = text.substring(0, l) + continue + end # Cleanup the string text = text.trim @@ -70,9 +101,15 @@ private class Doc2Mdwn if text.is_empty or indent < lastindent then n = null ul = null - if text.is_empty then continue + if text.is_empty then + if not curblock.is_empty then empty_lines += 1 + continue + end end + # Was a codblock just before the current line ? + close_codeblock(n or else root) + # Special first word: new paragraph if text.has_prefix("TODO") or text.has_prefix("FIXME") then n = new HTMLTag("p") @@ -112,9 +149,10 @@ private class Doc2Mdwn process_line(n, text) # Special case, the fist line is the synopsys and is in its own paragraph - if c == ndoc.n_comment.first then + if is_first_line then n.add_class("synopsys") n = null + is_first_line = false end end @@ -124,9 +162,9 @@ private class Doc2Mdwn return root end - fun short_work(ndoc: ADoc): HTMLTag + fun short_work(mdoc: MDoc): HTMLTag do - var text = ndoc.n_comment.first.text.substring_from(1) + var text = mdoc.content.first var n = new HTMLTag("span") n.add_class("synopsys") n.add_class("nitdoc") @@ -149,8 +187,7 @@ private class Doc2Mdwn # Code part var n2 = new HTMLTag("code") n.add(n2) - - n2.text part + process_code(n2, part) end is_text = not is_text end @@ -160,29 +197,80 @@ private class Doc2Mdwn do # Is there a codeblock to manage? if not curblock.is_empty then - var n = new HTMLTag("pre") - root.add(n) - var btext = curblock.to_s + empty_lines = 0 + + # determine the smalest indent + var minindent = -1 + for text in curblock do + var indent = 0 + while indent < text.length and text.chars[indent] == ' ' do indent += 1 + # skip white lines + if indent >= text.length then continue + if minindent == -1 or indent < minindent then + minindent = indent + end + end + if minindent < 0 then minindent = 0 - n.append btext + # Generate the text + var btext = new FlatBuffer + for text in curblock do + btext.append text.substring_from(minindent) + btext.add '\n' + end + # add the node + var n = new HTMLTag("pre") + root.add(n) + process_code(n, btext.to_s) curblock.clear end end + + fun process_code(n: HTMLTag, text: String) + do + # Try to parse it + var ast = toolcontext.parse_something(text) + + if ast isa AError then + n.append text + # n.attrs["title"] = ast.message + n.add_class("rawcode") + else + var v = new HighlightVisitor + v.enter_visit(ast) + n.add(v.html) + n.add_class("nitcode") + end + end end -redef class ADoc +redef class MDoc # Build a `
` element that contains the full documentation in HTML fun full_markdown: HTMLTag do - var d2m = new Doc2Mdwn - return d2m.work(self) + var res = full_markdown_cache + if res != null then return res + var tc = new ToolContext + var d2m = new Doc2Mdwn(tc) + res = d2m.work(self) + full_markdown_cache = res + return res end + private var full_markdown_cache: nullable HTMLTag + # Build a `` element that contains the synopsys in HTML fun short_markdown: HTMLTag do - var d2m = new Doc2Mdwn - return d2m.short_work(self) + var res = short_markdown_cache + if res != null then return res + var tc = new ToolContext + var d2m = new Doc2Mdwn(tc) + res = d2m.short_work(self) + short_markdown_cache = res + return res end + + private var short_markdown_cache: nullable HTMLTag end