docdowm: empty lines are included in blocks
[nit.git] / src / markdown.nit
index 344f469..e254480 100644 (file)
 # Transform Nit verbatim documentation into HTML
 module markdown
 
-import parser
+private import parser
 import html
-import highlight
+private import highlight
+private import parser_util
 
 # The class that does the convertion from a `ADoc` to HTML
 private class Doc2Mdwn
@@ -26,6 +27,9 @@ private class Doc2Mdwn
        # The lines of the current code block, empty is no current code block
        var curblock = new Array[String]
 
+       # Count empty lines between code blocks
+       var empty_lines = 0
+
        fun work(mdoc: MDoc): HTMLTag
        do
                var root = new HTMLTag("div")
@@ -37,6 +41,9 @@ 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
 
@@ -51,16 +58,38 @@ private class Doc2Mdwn
                        indent = 0
                        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)
-                               curblock.add("\n")
+                       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
@@ -72,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")
@@ -162,10 +197,32 @@ private class Doc2Mdwn
        do
                # Is there a codeblock to manage?
                if not curblock.is_empty then
+                       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
+
+                       # 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)
-                       var btext = curblock.to_s
-                       process_code(n, btext)
+                       process_code(n, btext.to_s)
                        curblock.clear
                end
        end