64820329aa761bf602e5fe2044847bae368d90b2
[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 = block.raw_content
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 end
154
155 # Decorator for span elements.
156 #
157 # Because inline comments can appear as span elements,
158 # InlineDecorator do not decorate things like paragraphs or headers.
159 private class InlineDecorator
160 super NitdocDecorator
161
162 redef fun add_paragraph(v, block) do
163 v.emit_in block
164 end
165
166 redef fun add_headline(v, block) do
167 v.emit_in block
168 end
169
170 redef fun add_code(v, block) do
171 # Try to parse code
172 var ast = toolcontext.parse_something(block.block.text.to_s)
173 if ast isa AError then
174 v.add "<code>"
175 v.emit_in block
176 v.add "</code>"
177 return
178 end
179 v.add "<code class=\"nitcode\">"
180 var hl = new HighlightVisitor
181 hl.enter_visit(ast)
182 v.add(hl.html)
183 v.add "</code>"
184 end
185 end
186
187 redef class Model
188 # Get a markdown processor for Nitdoc comments.
189 var nitdoc_md_processor: MarkdownProcessor is lazy do
190 var proc = new MarkdownProcessor
191 proc.emitter.decorator = new NitdocDecorator
192 return proc
193 end
194
195 # Get a markdown inline processor for Nitdoc comments.
196 #
197 # This processor is specificaly designed to inlinable doc elements like synopsys.
198 var nitdoc_inline_processor: MarkdownProcessor is lazy do
199 var proc = new MarkdownProcessor
200 proc.emitter.decorator = new InlineDecorator
201 return proc
202 end
203 end