6d5dfe47d2c4fdfda33b73863cba42dcfaeaafbb
[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.as(not null).model.nitdoc_md_processor
39 end
40
41 private var inline_proc: MarkdownProcessor is lazy do
42 return original_mentity.as(not null).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 # The specific markdown decorator used internally to process MDoc object.
97 #
98 # You should use the various methods of `MDoc` like `MDoc::html_documentation`
99 #
100 # The class is public so specific behavior can be plugged on it.
101 class NitdocDecorator
102 super HTMLDecorator
103
104 private var toolcontext = new ToolContext
105
106 redef fun add_code(v, block) do
107 var meta = block.meta or else "nit"
108
109 # Do not try to highlight non-nit code.
110 if meta != "nit" and meta != "nitish" then
111 v.add "<pre class=\"{meta}\"><code>"
112 v.emit_in block
113 v.add "</code></pre>\n"
114 return
115 end
116 # Try to parse code
117 var code = block.raw_content
118 var ast = toolcontext.parse_something(code)
119 if ast isa AError then
120 v.add "<pre class=\"{meta}\"><code>"
121 v.emit_in block
122 v.add "</code></pre>\n"
123 return
124 end
125 v.add "<pre class=\"nitcode\"><code>"
126 var hl = new HighlightVisitor
127 hl.line_id_prefix = ""
128 hl.enter_visit(ast)
129 v.add(hl.html)
130 v.add "</code></pre>\n"
131 end
132
133 redef fun add_span_code(v, text, from, to) do
134 # Try to parse it
135 var code = code_from_text(text, from, to)
136 var ast = toolcontext.parse_something(code)
137
138 if ast isa AError then
139 v.add "<code class=\"rawcode\">"
140 append_code(v, text, from, to)
141 else
142 v.add "<code class=\"nitcode\">"
143 var hl = new HighlightVisitor
144 hl.line_id_prefix = ""
145 hl.enter_visit(ast)
146 v.add(hl.html)
147 end
148 v.add "</code>"
149 end
150
151 private fun code_from_text(buffer: Text, from, to: Int): String do
152 var out = new FlatBuffer
153 for i in [from..to[ do out.add buffer[i]
154 return out.write_to_string
155 end
156 end
157
158 # Decorator for span elements.
159 #
160 # Because inline comments can appear as span elements,
161 # InlineDecorator do not decorate things like paragraphs or headers.
162 private class InlineDecorator
163 super NitdocDecorator
164
165 redef fun add_paragraph(v, block) do
166 v.emit_in block
167 end
168
169 redef fun add_headline(v, block) do
170 v.emit_in block
171 end
172
173 redef fun add_code(v, block) do
174 # Try to parse code
175 var ast = toolcontext.parse_something(block.block.text.to_s)
176 if ast isa AError then
177 v.add "<code>"
178 v.emit_in block
179 v.add "</code>"
180 return
181 end
182 v.add "<code class=\"nitcode\">"
183 var hl = new HighlightVisitor
184 hl.enter_visit(ast)
185 v.add(hl.html)
186 v.add "</code>"
187 end
188 end
189
190 redef class Model
191 # Get a markdown processor for Nitdoc comments.
192 var nitdoc_md_processor: MarkdownProcessor is lazy do
193 var proc = new MarkdownProcessor
194 proc.emitter.decorator = new NitdocDecorator
195 return proc
196 end
197
198 # Get a markdown inline processor for Nitdoc comments.
199 #
200 # This processor is specificaly designed to inlinable doc elements like synopsys.
201 var nitdoc_inline_processor: MarkdownProcessor is lazy do
202 var proc = new MarkdownProcessor
203 proc.emitter.decorator = new InlineDecorator
204 return proc
205 end
206 end