Merge: doc: fixed some typos and other misc. corrections
[nit.git] / src / nitlight.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 # Tool that produces highlighting for Nit programs
16 module nitlight
17
18 import htmlight
19
20 class NitlightVisitor
21 super HtmlightVisitor
22
23 # The current highlight module
24 #
25 # It is used to know when to use anchored local links
26 var current_module: MModule
27
28 # List of all highlighted modules
29 #
30 # It is used to have links that only targets highlighted entities
31 #
32 # Entities outside these modules will not be linked.
33 var mmodules: Collection[MModule]
34
35 redef fun hrefto(entity) do return entity.href(self)
36 end
37
38 redef class MEntity
39 private fun href(v: NitlightVisitor): nullable String do return null
40 end
41
42 redef class MModule
43 redef fun href(v)
44 do
45 if self == v.current_module then return ""
46 if not v.mmodules.has(self) then return null
47 return c_name + ".html"
48 end
49 end
50
51 redef class MClass
52 redef fun href(v)
53 do
54 # Because we only have code, just link to the introduction
55 return intro.href(v)
56 end
57 end
58
59 redef class MClassDef
60 redef fun href(v)
61 do
62 var m = mmodule.href(v)
63 if m == null then return null
64 return m + "#" + to_s
65 end
66 end
67
68 redef class MProperty
69 redef fun href(v)
70 do
71 # Because we only have code, just link to the introduction
72 return intro.href(v)
73 end
74 end
75
76 redef class MPropDef
77 redef fun href(v)
78 do
79 var m = mclassdef.mmodule.href(v)
80 if m == null then return null
81 return m + "#" + to_s
82 end
83 end
84
85 var toolcontext = new ToolContext
86
87 # Try to colorize, even if programs are non valid
88 toolcontext.keep_going = true
89
90 var opt_fragment = new OptionBool("Omit document header and footer", "-f", "--fragment")
91 var opt_line_id_prefix = new OptionString("Prefix of the id of each line `<span>` element", "--line-id-prefix")
92 var opt_first_line = new OptionInt("Start the source file at this line (default: 1)", 0, "--first-line")
93 var opt_last_line = new OptionInt("End the source file at this line (default: to the end)", 0, "--last-line")
94 var opt_dir = new OptionString("Output html files in a specific directory (required if more than one module)", "-d", "--dir")
95 var opt_full = new OptionBool("Process also imported modules", "--full")
96 var opt_ast = new OptionBool("Generate specific HTML elements for each Node of the AST", "--ast")
97 var opt_noinfobox = new OptionBool("Disable the generation of infoboxes", "--no-infobox")
98 var opt_txt = new OptionBool("Generate text with ANSI coloring escape sequences", "--txt")
99 toolcontext.option_context.add_option(opt_fragment, opt_line_id_prefix, opt_first_line, opt_last_line, opt_dir, opt_full, opt_ast, opt_txt, opt_noinfobox)
100 toolcontext.tooldescription = "Usage: nitlight [OPTION]... <file.nit>...\nGenerates HTML of highlited code from Nit source files."
101 toolcontext.process_options(args)
102
103 var model = new Model
104 var modelbuilder = new ModelBuilder(model, toolcontext)
105
106 var args = toolcontext.option_context.rest
107
108 var mmodules = modelbuilder.parse_full(args)
109 modelbuilder.run_phases
110
111 if opt_full.value then mmodules = modelbuilder.parsed_modules
112
113 var dir = opt_dir.value
114 if dir != null then
115 dir.mkdir
116 else if mmodules.length > 1 then
117 print "More than one module to render, use option -d"
118 return
119 end
120
121 if opt_txt.value then
122 for mm in mmodules do
123 var v = new AnsiHighlightVisitor
124 v.include_loose_tokens = true
125 v.include_whole_lines = true
126
127 if opt_first_line.value != 0 then v.first_line = opt_first_line.value
128 if opt_last_line.value != 0 then v.last_line = opt_last_line.value
129 var m = modelbuilder.mmodule2node(mm)
130 assert m != null
131
132 v.highlight_node(m)
133 var page = v.result
134
135 if dir != null then
136 page.write_to_file("{dir}/{mm.c_name}.txt")
137 else
138 page.write_to(stdout)
139 end
140 end
141 return
142 end
143
144 for mm in mmodules do
145 if dir != null then toolcontext.info("write {dir}/{mm.c_name}.html", 1)
146
147 var v = new NitlightVisitor(mm, mmodules)
148 var prefix = opt_line_id_prefix.value
149 if prefix != null then
150 v.line_id_prefix = prefix.trim
151 end
152 v.include_loose_tokens = true
153 v.include_whole_lines = true
154
155 if opt_first_line.value != 0 then v.first_line = opt_first_line.value
156 if opt_last_line.value != 0 then v.last_line = opt_last_line.value
157 if opt_ast.value then v.with_ast = true
158 if opt_noinfobox.value then v.show_infobox = false
159 var page = null
160 var m = modelbuilder.mmodule2node(mm)
161 assert m != null
162 if not opt_fragment.value then
163 page = new HTMLTag("html")
164 page.add_raw_html """<head>
165 <meta charset="utf-8">
166 <title>file {{{m.location.file.filename}}}</title>"""
167 if dir == null then
168 page.add_raw_html """
169 <style type="text/css">
170 {{{v.css_content}}}
171 </style>
172 """
173 else
174 page.add_raw_html """<link rel="stylesheet" type="text/css" href="style.css" />"""
175 end
176 page.add_raw_html v.head_content
177 page.add_raw_html "</head><body><pre class='nit_code'>"
178 end
179 v.highlight_node(m)
180 if not opt_fragment.value then
181 page.add(v.html)
182 page.add_raw_html "</pre>"
183 page.add_raw_html v.foot_content
184 page.add_raw_html "</body>"
185 else
186 page = v.html
187 end
188
189 if dir != null then
190 page.write_to_file("{dir}/{mm.c_name}.html")
191 else
192 page.write_to(stdout)
193 end
194 end
195
196 if dir != null then
197 toolcontext.info("write {dir}/index.html", 1)
198
199 var page = new HTMLTag("html")
200 page.add_raw_html """<head>
201 <meta charset="utf-8">
202 </head><body><ul>
203 """
204 for mm in mmodules do
205 var n = new HTMLTag("li")
206 var n2 = new HTMLTag("a")
207 page.add n
208 n.add n2
209 n2.attr("href", "{mm.c_name}.html")
210 n2.text(mm.full_name)
211 end
212 page.add_raw_html "</li></body>"
213 page.write_to_file("{dir}/index.html")
214
215 var v = new HtmlightVisitor
216 toolcontext.info("write {dir}/style.css", 1)
217 var f = new FileWriter.open("{dir}/style.css")
218 f.write v.css_content
219 f.close
220 end