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