1 # This file is part of NIT ( http://www.nitlanguage.org ).
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
7 # http://www.apache.org/licenses/LICENSE-2.0
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
15 # Transform Nit verbatim documentation into HTML
20 private import highlight
21 private import parser_util
23 # The class that does the convertion from a `ADoc` to HTML
24 private class Doc2Mdwn
25 var toolcontext
: ToolContext
27 # The lines of the current code block, empty is no current code block
28 var curblock
= new Array[String]
30 # Count empty lines between code blocks
33 fun work
(mdoc
: MDoc): HTMLTag
35 var root
= new HTMLTag("div")
36 root
.add_class
("nitdoc")
38 # Indent level of the previous line
41 # Indent level of the current line
44 # Expected fencing closing tag (if any)
45 var in_fence
: nullable String = null
47 # The current element (p, li, etc.) if any
48 var n
: nullable HTMLTag = null
50 # The current ul element (if any)
51 var ul
: nullable HTMLTag = null
53 var is_first_line
= true
54 # Local variable to benefit adaptive typing
55 for text
in mdoc
.content
do
56 # Count the number of spaces
59 while text
.length
> indent
and text
.chars
[indent
] == ' ' do indent
+= 1
62 if in_fence
!= null then
64 if text
.substring
(0,in_fence
.length
) == in_fence
then
65 close_codeblock
(n
or else root
)
74 # Is codeblock? Then just collect them
76 for i
in [0..empty_lines
[ do curblock
.add
("")
78 # to allows 4 spaces including the one that follows the #
84 if text
.substring
(0,3) == "~~~" then
85 # Was a codblock just before the current line ?
86 close_codeblock
(n
or else root
)
89 while l
< text
.length
and text
.chars
[l
] == '~' do l
+= 1
90 in_fence
= text
.substring
(0, l
)
97 # The HTML node of the last line, so we know if we continue the same block
100 # No line or loss of indentation: reset
101 if text
.is_empty
or indent
< lastindent
then
104 if text
.is_empty
then
105 if not curblock
.is_empty
then empty_lines
+= 1
110 # Was a codblock just before the current line ?
111 close_codeblock
(n
or else root
)
113 # Special first word: new paragraph
114 if text
.has_prefix
("TODO") or text
.has_prefix
("FIXME") then
119 else if text
.has_prefix
("REQUIRE") or text
.has_prefix
("Require") or text
.has_prefix
("ENSURE") or text
.has_prefix
("Ensure") then
122 n
.add_class
("contract")
127 if text
.has_prefix
("* ") or text
.has_prefix
("- ") then
128 text
= text
.substring_from
(1).trim
130 ul
= new HTMLTag("ul")
133 n
= new HTMLTag("li")
137 # Nothing? then paragraph
145 # Because spaces and `\n` where trimmed
149 process_line
(n
, text
)
151 # Special case, the fist line is the synopsys and is in its own paragraph
152 if is_first_line
then
153 n
.add_class
("synopsys")
155 is_first_line
= false
159 # If the codeblock was the last code sequence
160 close_codeblock
(n
or else root
)
165 fun short_work
(mdoc
: MDoc): HTMLTag
167 var text
= mdoc
.content
.first
168 var n
= new HTMLTag("span")
169 n
.add_class
("synopsys")
170 n
.add_class
("nitdoc")
171 process_line
(n
, text
)
175 fun process_line
(n
: HTMLTag, text
: String)
177 # Loosly detect code parts
178 var parts
= text
.split
("`")
180 # Process each code parts, thus alternate between text and code
188 var n2
= new HTMLTag("code")
190 process_code
(n2
, part
)
192 is_text
= not is_text
196 fun close_codeblock
(root
: HTMLTag)
198 # Is there a codeblock to manage?
199 if not curblock
.is_empty
then
202 # determine the smalest indent
204 for text
in curblock
do
206 while indent
< text
.length
and text
.chars
[indent
] == ' ' do indent
+= 1
208 if indent
>= text
.length
then continue
209 if minindent
== -1 or indent
< minindent
then
213 if minindent
< 0 then minindent
= 0
216 var btext
= new FlatBuffer
217 for text
in curblock
do
218 btext
.append text
.substring_from
(minindent
)
223 var n
= new HTMLTag("pre")
225 process_code
(n
, btext
.to_s
)
230 fun process_code
(n
: HTMLTag, text
: String)
233 var ast
= toolcontext
.parse_something
(text
)
235 if ast
isa AError then
237 # n.attrs["title"] = ast.message
238 n
.add_class
("rawcode")
240 var v
= new HighlightVisitor
243 n
.add_class
("nitcode")
249 # Build a `<div>` element that contains the full documentation in HTML
250 fun full_markdown
: HTMLTag
252 var res
= full_markdown_cache
253 if res
!= null then return res
254 var tc
= new ToolContext
255 var d2m
= new Doc2Mdwn(tc
)
257 full_markdown_cache
= res
261 private var full_markdown_cache
: nullable HTMLTag
263 # Build a `<span>` element that contains the synopsys in HTML
264 fun short_markdown
: HTMLTag
266 var res
= short_markdown_cache
267 if res
!= null then return res
268 var tc
= new ToolContext
269 var d2m
= new Doc2Mdwn(tc
)
270 res
= d2m
.short_work
(self)
271 short_markdown_cache
= res
275 private var short_markdown_cache
: nullable HTMLTag