5284dc17f700a8b607ff23494899ca335fcb017b
[nit.git] / src / doc / doc_down.nit
1 # This file is part of NIT ( http://www.nitlanguage.org ).
2 #
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
6 #
7 # http://www.apache.org/licenses/LICENSE-2.0
8 #
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.
14
15 # Handle markdown formatting in Nit comments.
16 module doc_down
17
18 import markdown
19 import highlight
20 private import parser_util
21
22 redef class MDoc
23
24 # Synopsis HTML escaped.
25 var synopsis: String is lazy do return content.first.html_escape
26
27 # Comment without synopsis HTML escaped
28 var comment: String is lazy do
29 var lines = content.to_a
30 if not lines.is_empty then lines.shift
31 return content.join("\n").html_escape
32 end
33
34 # Full comment HTML escaped.
35 var documentation: String is lazy do return content.join("\n").html_escape
36
37 private var markdown_proc: MarkdownProcessor is lazy do
38 return original_mentity.model.nitdoc_md_processor
39 end
40
41 private var inline_proc: MarkdownProcessor is lazy do
42 return original_mentity.model.nitdoc_inline_processor
43 end
44
45 # Renders the synopsis as a HTML comment block.
46 var html_synopsis: Writable is lazy do
47 var res = new Template
48 var syn = inline_proc.process(content.first)
49 res.add "<span class=\"synopsys nitdoc\">{syn}</span>"
50 return res
51
52 end
53
54 # Renders the comment without the synopsis as a HTML comment block.
55 var html_comment: Writable is lazy do
56 var lines = content.to_a
57 if not lines.is_empty then lines.shift
58 return lines_to_html(lines)
59 end
60
61 # Renders the synopsis and the comment as a HTML comment block.
62 var html_documentation: Writable is lazy do return lines_to_html(content.to_a)
63
64 # Renders markdown line as a HTML comment block.
65 private fun lines_to_html(lines: Array[String]): Writable do
66 var res = new Template
67 res.add "<div class=\"nitdoc\">"
68 # do not use DocUnit as synopsys
69 if not lines.is_empty then
70 if not lines.first.has_prefix(" ") and
71 not lines.first.has_prefix("\t") then
72 # parse synopsys
73 var syn = inline_proc.process(lines.shift)
74 res.add "<p class=\"synopsys\">{syn}</p>"
75 end
76 end
77 # check for annotations
78 for i in [0 .. lines.length[ do
79 var line = lines[i]
80 if line.to_upper.has_prefix("ENSURE") or line.to_upper.has_prefix("REQUIRE") then
81 var html = inline_proc.process(line)
82 lines[i] = "<p class=\"contract\">{html}</p>"
83 else if line.to_upper.has_prefix("TODO") or line.to_upper.has_prefix("FIXME") then
84 var html = inline_proc.process(line)
85 lines[i] = "<p class=\"todo\">{html}</p>"
86 end
87 end
88 # add other lines
89 res.add markdown_proc.process(lines.join("\n"))
90 res.add "</div>"
91 return res
92
93 end
94 end
95
96 private class NitdocDecorator
97 super HTMLDecorator
98
99 var toolcontext = new ToolContext
100
101 redef fun add_code(v, block) do
102 var meta = "nit"
103 if block isa BlockFence and block.meta != null then
104 meta = block.meta.to_s
105 end
106 # Do not try to highlight non-nit code.
107 if meta != "nit" and meta != "nitish" then
108 v.add "<pre class=\"{meta}\"><code>"
109 v.emit_in block
110 v.add "</code></pre>\n"
111 return
112 end
113 # Try to parse code
114 var code = code_from_block(block)
115 var ast = toolcontext.parse_something(code)
116 if ast isa AError then
117 v.add "<pre class=\"{meta}\"><code>"
118 v.emit_in block
119 v.add "</code></pre>\n"
120 return
121 end
122 v.add "<pre class=\"nitcode\"><code>"
123 var hl = new HighlightVisitor
124 hl.line_id_prefix = ""
125 hl.enter_visit(ast)
126 v.add(hl.html)
127 v.add "</code></pre>\n"
128 end
129
130 redef fun add_span_code(v, text, from, to) do
131 # Try to parse it
132 var code = code_from_text(text, from, to)
133 var ast = toolcontext.parse_something(code)
134
135 if ast isa AError then
136 v.add "<code class=\"rawcode\">"
137 append_code(v, text, from, to)
138 else
139 v.add "<code class=\"nitcode\">"
140 var hl = new HighlightVisitor
141 hl.line_id_prefix = ""
142 hl.enter_visit(ast)
143 v.add(hl.html)
144 end
145 v.add "</code>"
146 end
147
148 fun code_from_text(buffer: Text, from, to: Int): String do
149 var out = new FlatBuffer
150 for i in [from..to[ do out.add buffer[i]
151 return out.write_to_string
152 end
153
154 fun code_from_block(block: BlockCode): String do
155 var infence = block isa BlockFence
156 var text = new FlatBuffer
157 var line = block.block.first_line
158 while line != null do
159 if not line.is_empty then
160 var str = line.value
161 if not infence and str.has_prefix(" ") then
162 text.append str.substring(4, str.length - line.trailing)
163 else
164 text.append str
165 end
166 end
167 text.append "\n"
168 line = line.next
169 end
170 return text.write_to_string
171 end
172 end
173
174 # Decorator for span elements.
175 #
176 # Because inline comments can appear as span elements,
177 # InlineDecorator do not decorate things like paragraphs or headers.
178 private class InlineDecorator
179 super NitdocDecorator
180
181 redef fun add_paragraph(v, block) do
182 v.emit_in block
183 end
184
185 redef fun add_headline(v, block) do
186 v.emit_in block
187 end
188
189 redef fun add_code(v, block) do
190 # Try to parse code
191 var ast = toolcontext.parse_something(block.block.text.to_s)
192 if ast isa AError then
193 v.add "<code>"
194 v.emit_in block
195 v.add "</code>"
196 return
197 end
198 v.add "<code class=\"nitcode\">"
199 var hl = new HighlightVisitor
200 hl.enter_visit(ast)
201 v.add(hl.html)
202 v.add "</code>"
203 end
204 end
205
206 redef class Model
207 # Get a markdown processor for Nitdoc comments.
208 var nitdoc_md_processor: MarkdownProcessor is lazy do
209 var proc = new MarkdownProcessor
210 proc.emitter.decorator = new NitdocDecorator
211 return proc
212 end
213
214 # Get a markdown inline processor for Nitdoc comments.
215 #
216 # This processor is specificaly designed to inlinable doc elements like synopsys.
217 var nitdoc_inline_processor: MarkdownProcessor is lazy do
218 var proc = new MarkdownProcessor
219 proc.emitter.decorator = new InlineDecorator
220 return proc
221 end
222 end