--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Transform Nit verbatim documentation into HTML
+module markdown
+
+import parser
+import html
+
+# The class that does the convertion from a `ADoc` to HTML
+private class Doc2Mdwn
+ # The lines of the current code block, empty is no current code block
+ var curblock = new Array[String]
+
+ fun work(ndoc: ADoc): HTMLTag
+ do
+ var root = new HTMLTag("div")
+ root.add_class("nitdoc")
+
+ # Indent level of the previous line
+ var lastindent = 0
+
+ # Indent level of the current line
+ var indent = 0
+
+ # The current element (p, li, etc.) if any
+ var n: nullable HTMLTag = null
+
+ # The current ul element (if any)
+ var ul: nullable HTMLTag = null
+
+ # Local variable to benefit adaptive typing
+ for c in ndoc.n_comment do
+ # Remove the starting `#`
+ var text = c.text.substring_from(1)
+
+ # Count the number of spaces
+ lastindent = indent
+ indent = 0
+ while text.length > indent and text[indent] == ' ' do indent += 1
+
+ # Is codeblock? Then just collect them
+ if indent > 4 then
+ var part = text.substring_from(4)
+ curblock.add(part)
+ continue
+ end
+
+ # Was a codblock just before the current line ?
+ close_codeblock(n or else root)
+
+ # Cleanup the string
+ text = text.trim
+
+ # The HTML node of the last line, so we know if we continue the same block
+ var old = n
+
+ # No line or loss of indentation: reset
+ if text.is_empty or indent < lastindent then
+ n = null
+ ul = null
+ if text.is_empty then continue
+ end
+
+ # Special first word: new paragraph
+ if text.has_prefix("TODO") or text.has_prefix("FIXME") then
+ n = new HTMLTag("p")
+ root.add n
+ n.add_class("todo")
+ ul = null
+ else if text.has_prefix("REQUIRE") or text.has_prefix("Require") or text.has_prefix("ENSURE") or text.has_prefix("Ensure") then
+ n = new HTMLTag("p")
+ root.add n
+ n.add_class("contract")
+ ul = null
+ end
+
+ # List
+ if text.has_prefix("* ") or text.has_prefix("- ") then
+ text = text.substring_from(1).trim
+ if ul == null then
+ ul = new HTMLTag("ul")
+ root.add ul
+ end
+ n = new HTMLTag("li")
+ ul.add(n)
+ end
+
+ # Nothing? then paragraph
+ if n == null then
+ n = new HTMLTag("p")
+ root.add n
+ ul = null
+ end
+
+ if old == n then
+ # Because spaces and `\n` where trimmed
+ n.append("\n")
+ end
+
+ 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
+ n.add_class("synopsys")
+ n = null
+ end
+ end
+
+ # If the codeblock was the last code sequence
+ close_codeblock(n or else root)
+
+ return root
+ end
+
+ fun short_work(ndoc: ADoc): HTMLTag
+ do
+ var text = ndoc.n_comment.first.text.substring_from(1)
+ var n = new HTMLTag("span")
+ n.add_class("synopsys")
+ n.add_class("nitdoc")
+ process_line(n, text)
+ return n
+ end
+
+ fun process_line(n: HTMLTag, text: String)
+ do
+ # Loosly detect code parts
+ var parts = text.split("`")
+
+ # Process each code parts, thus alternate between text and code
+ var is_text = true
+ for part in parts do
+ if is_text then
+ # Text part
+ n.append part
+ else
+ # Code part
+ var n2 = new HTMLTag("code")
+ n.add(n2)
+
+ n2.text part
+ end
+ is_text = not is_text
+ end
+ end
+
+ fun close_codeblock(root: HTMLTag)
+ 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
+
+ n.append btext
+
+ curblock.clear
+ end
+ end
+end
+
+redef class ADoc
+ # Build a `<div>` element that contains the full documentation in HTML
+ fun full_markdown: HTMLTag
+ do
+ var d2m = new Doc2Mdwn
+ return d2m.work(self)
+ end
+
+ # Build a `<span>` element that contains the synopsys in HTML
+ fun short_markdown: HTMLTag
+ do
+ var d2m = new Doc2Mdwn
+ return d2m.short_work(self)
+ end
+end