Rename REAMDE to README.md
[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 # Comment synopsys HTML escaped
24 var short_comment: String is lazy do return content.first.html_escape
25
26 # Full comment HTML escaped
27 var full_comment: String is lazy do return content.join("\n").html_escape
28
29 # Synopsys in a template
30 var tpl_short_comment: Writable is lazy do
31 var res = new Template
32 var syn = nitdoc_inline_processor.process(content.first)
33 res.add "<span class=\"synopsys nitdoc\">{syn}</span>"
34 return res
35
36 end
37
38 # Full comment in a template
39 var tpl_comment: Writable is lazy do
40 var res = new Template
41 var lines = content.to_a
42 res.add "<div class=\"nitdoc\">"
43 # do not use DocUnit as synopsys
44 if not content.first.has_prefix(" ") and
45 not content.first.has_prefix("\t") then
46 # parse synopsys
47 var syn = nitdoc_inline_processor.process(lines.shift)
48 res.add "<p class=\"synopsys\">{syn}</p>"
49 end
50 # check for annotations
51 for i in [0 .. lines.length[ do
52 var line = lines[i]
53 if line.to_upper.has_prefix("ENSURE") or line.to_upper.has_prefix("REQUIRE") then
54 var html = nitdoc_inline_processor.process(line)
55 lines[i] = "<p class=\"contract\">{html}</p>"
56 else if line.to_upper.has_prefix("TODO") or line.to_upper.has_prefix("FIXME") then
57 var html = nitdoc_inline_processor.process(line)
58 lines[i] = "<p class=\"todo\">{html}</p>"
59 end
60 end
61 # add other lines
62 res.add nitdoc_md_processor.process(lines.join("\n"))
63 res.add "</div>"
64 return res
65 end
66 end
67
68 private class NitdocDecorator
69 super HTMLDecorator
70
71 var toolcontext = new ToolContext
72
73 redef fun add_code(v, block) do
74 var meta = "nit"
75 if block isa BlockFence and block.meta != null then
76 meta = block.meta.to_s
77 end
78 # Do not try to highlight non-nit code.
79 if meta != "nit" and meta != "nitish" then
80 v.add "<pre class=\"{meta}\"><code>"
81 v.emit_in block
82 v.add "</code></pre>\n"
83 return
84 end
85 # Try to parse code
86 var code = code_from_block(block)
87 var ast = toolcontext.parse_something(code)
88 if ast isa AError then
89 v.add "<pre class=\"{meta}\"><code>"
90 v.emit_in block
91 v.add "</code></pre>\n"
92 return
93 end
94 v.add "<pre class=\"nitcode\"><code>"
95 var hl = new HighlightVisitor
96 hl.line_id_prefix = ""
97 hl.enter_visit(ast)
98 v.add(hl.html)
99 v.add "</code></pre>\n"
100 end
101
102 redef fun add_span_code(v, text, from, to) do
103 # Try to parse it
104 var code = code_from_text(text, from, to)
105 var ast = toolcontext.parse_something(code)
106
107 if ast isa AError then
108 v.add "<code class=\"rawcode\">"
109 append_code(v, text, from, to)
110 else
111 v.add "<code class=\"nitcode\">"
112 var hl = new HighlightVisitor
113 hl.line_id_prefix = ""
114 hl.enter_visit(ast)
115 v.add(hl.html)
116 end
117 v.add "</code>"
118 end
119
120 fun code_from_text(buffer: Text, from, to: Int): String do
121 var out = new FlatBuffer
122 for i in [from..to[ do out.add buffer[i]
123 return out.write_to_string
124 end
125
126 fun code_from_block(block: BlockCode): String do
127 var infence = block isa BlockFence
128 var text = new FlatBuffer
129 var line = block.block.first_line
130 while line != null do
131 if not line.is_empty then
132 var str = line.value
133 if not infence and str.has_prefix(" ") then
134 text.append str.substring(4, str.length - line.trailing)
135 else
136 text.append str
137 end
138 end
139 text.append "\n"
140 line = line.next
141 end
142 return text.write_to_string
143 end
144 end
145
146 # Decorator for span elements.
147 #
148 # Because inline comments can appear as span elements,
149 # InlineDecorator do not decorate things like paragraphs or headers.
150 private class InlineDecorator
151 super NitdocDecorator
152
153 redef fun add_paragraph(v, block) do
154 v.emit_in block
155 end
156
157 redef fun add_headline(v, block) do
158 v.emit_in block
159 end
160
161 redef fun add_code(v, block) do
162 # Try to parse code
163 var ast = toolcontext.parse_something(block.block.text.to_s)
164 if ast isa AError then
165 v.add "<code>"
166 v.emit_in block
167 v.add "</code>"
168 return
169 end
170 v.add "<code class=\"nitcode\">"
171 var hl = new HighlightVisitor
172 hl.enter_visit(ast)
173 v.add(hl.html)
174 v.add "</code>"
175 end
176 end
177
178 # Get a markdown processor for Nitdoc comments.
179 private fun nitdoc_md_processor: MarkdownProcessor do
180 var proc = new MarkdownProcessor
181 proc.emitter.decorator = new NitdocDecorator
182 return once proc
183 end
184
185 # Get a markdown inline processor for Nitdoc comments.
186 #
187 # This processor is specificaly designed to inlinable doc elements like synopsys.
188 private fun nitdoc_inline_processor: MarkdownProcessor do
189 var proc = new MarkdownProcessor
190 proc.emitter.decorator = new InlineDecorator
191 return once proc
192 end