# 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
+ fun work(mdoc: MDoc): HTMLTag
do
var root = new HTMLTag("div")
root.add_class("nitdoc")
# 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
+ # 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
+ 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
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
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")
# Code part
var n2 = new HTMLTag("code")
n.add(n2)
-
- n2.text part
+ process_code(n2, part)
end
is_text = not is_text
end
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
+ # 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
+ if minindent == -1 or indent < minindent then
+ minindent = indent
+ end
+ end
- 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 `<div>` 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 `<span>` 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