Merge: doc: fixed some typos and other misc. corrections
[nit.git] / src / nitdoc.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 # Generator of static API documentation for the Nit language
16 #
17 # Generate API documentation in HTML format from Nit source code.
18 module nitdoc
19
20 import doc::static
21
22 redef class ToolContext
23
24 # Nitdoc generation phase
25 var docphase: Phase = new Nitdoc(self, null)
26
27 # Directory where the Nitdoc is rendered
28 var opt_dir = new OptionString("Output directory", "-d", "--dir")
29
30 # Do not generate documentation for attributes
31 var opt_no_attributes = new OptionBool("Ignore the attributes", "--no-attributes")
32
33 # Do not generate documentation for private properties
34 var opt_private = new OptionBool("Also generate private API", "--private")
35
36 # Use a shareurl instead of copy shared files
37 #
38 # This is usefull if you don't want to store the Nitdoc templates with your
39 # documentation.
40 var opt_shareurl = new OptionString("Use shareurl instead of copy shared files", "--shareurl")
41
42 # Use a custom title for the homepage
43 var opt_custom_title = new OptionString("Custom title for homepage", "--custom-title")
44
45 # Display a custom brand or logo in the documentation top menu
46 var opt_custom_brand = new OptionString("Custom link to external site", "--custom-brand")
47
48 # Display a custom introduction text before the packages overview
49 var opt_custom_intro = new OptionString("Custom intro text for homepage", "--custom-overview-text")
50
51 # Display a custom footer on each documentation page
52 #
53 # Generally used to display the documentation or product version.
54 var opt_custom_footer = new OptionString("Custom footer text", "--custom-footer-text")
55
56 # Piwik tracker URL
57 #
58 # If you want to monitor your visitors.
59 var opt_piwik_tracker = new OptionString("Piwik tracker URL (ex: `nitlanguage.org/piwik/`)", "--piwik-tracker")
60
61 # Piwik tracker site id
62 var opt_piwik_site_id = new OptionString("Piwik site ID", "--piwik-site-id")
63
64 # Do not generate dot/graphviz diagrams
65 var opt_nodot = new OptionBool("Do not generate graphs with graphviz", "--no-dot")
66
67 # Do not include highlighted code
68 var opt_nocode = new OptionBool("Do not generate code with nitlight", "--no-code")
69
70 # File pattern used to link documentation to source code.
71 var opt_source = new OptionString("Format to link source code (%f for filename, " +
72 "%l for first line, %L for last line) only works with option --no-code", "--source")
73
74 # Disable HTML rendering
75 var opt_norender = new OptionBool("DO not render any HTML", "--no-render")
76
77 # Test mode
78 #
79 # Display test data and remove the progress bar
80 var opt_test = new OptionBool("Output test data", "--test")
81
82 redef init do
83 super
84 option_context.add_option(
85 opt_dir, opt_no_attributes, opt_private,
86 opt_share_dir, opt_shareurl, opt_custom_title,
87 opt_custom_footer, opt_custom_intro, opt_custom_brand,
88 opt_piwik_tracker, opt_piwik_site_id,
89 opt_nodot, opt_nocode, opt_source, opt_norender, opt_test)
90 end
91 end
92
93 redef class DocModel
94
95 # Generate a documentation page
96 fun gen_page(page: DocPage, output_dir: String) do
97 page.apply_structure(self)
98 page.render(self).write_to_file("{output_dir}/{page.html_url}")
99 end
100 end
101
102 # Nitdoc phase explores the model and generate pages for each mentity found
103 private class Nitdoc
104 super Phase
105
106 redef fun process_mainmodule(mainmodule, mmodules)
107 do
108 var modelbuilder = toolcontext.modelbuilder
109 var model = modelbuilder.model
110
111 var min_visibility = private_visibility
112 if not toolcontext.opt_private.value then min_visibility = protected_visibility
113 var accept_attribute = true
114 if toolcontext.opt_no_attributes.value then accept_attribute = false
115
116 var catalog = new Catalog(toolcontext.modelbuilder)
117 catalog.build_catalog(mainmodule.model.mpackages)
118
119 var filter = new ModelFilter(
120 min_visibility,
121 accept_attribute = accept_attribute,
122 accept_fictive = true,
123 accept_generated = true,
124 accept_test = false,
125 accept_redef = true,
126 accept_extern = true,
127 accept_empty_doc = true,
128 accept_example = true,
129 accept_broken = false)
130
131 var doc = new DocModel(model, mainmodule, modelbuilder, catalog, filter)
132
133 model.nitdoc_md_processor = doc.md_processor
134 doc.no_dot = toolcontext.opt_nodot.value
135 doc.no_code = toolcontext.opt_nocode.value
136 doc.code_url = toolcontext.opt_source.value
137 doc.share_url = toolcontext.opt_shareurl.value
138 doc.custom_brand = toolcontext.opt_custom_brand.value
139 doc.custom_title = toolcontext.opt_custom_title.value
140 doc.custom_footer = toolcontext.opt_custom_footer.value
141 doc.custom_intro = toolcontext.opt_custom_intro.value
142 doc.tracker_url = toolcontext.opt_piwik_tracker.value
143 doc.piwik_site_id = toolcontext.opt_piwik_site_id.value
144
145 # Prepare output dir
146 var test_mode = toolcontext.opt_test.value
147 var no_render = toolcontext.opt_norender.value
148 var output_dir = toolcontext.opt_dir.value or else "doc"
149
150 if not no_render then
151 output_dir.mkdir
152
153 # Copy assets
154 var share_dir = toolcontext.opt_share_dir.value or else "{toolcontext.share_dir}/nitdoc"
155 sys.system("cp -r -- {share_dir.escape_to_sh}/* {output_dir.escape_to_sh}/")
156 end
157
158 # Collect model to document
159 var mpackages = model.collect_mpackages(filter)
160 var mgroups = model.collect_mgroups(filter)
161 var nmodules = model.collect_mmodules(filter)
162 var mclasses = model.collect_mclasses(filter)
163 var mprops = model.collect_mproperties(filter)
164
165 var mentities = new Array[MEntity]
166 mentities.add_all mpackages
167 mentities.add_all mgroups
168 mentities.add_all nmodules
169 mentities.add_all mclasses
170 mentities.add_all mprops
171
172 var persons = doc.catalog.persons
173 var tags = doc.catalog.tag2proj.keys
174
175 # Prepare progress bar
176 var count = 0
177 var pages = 1 # count homepage
178 pages += mentities.length
179 pages += persons.length
180 pages += tags.length
181
182 print "Generating documentation pages..."
183 var progress = new TermProgress(pages, 0)
184 if not test_mode then progress.display
185
186 # Make pages
187 count += 1
188 if not test_mode then progress.update(count, "homepage")
189 if not no_render then doc.gen_page(new PageHome("Overview"), output_dir)
190
191 for mentity in mentities do
192 count += 1
193 if not test_mode then progress.update(count, "page {count}/{pages}")
194 if not no_render then doc.gen_page(new PageMEntity(mentity), output_dir)
195 end
196 for name, person in persons do
197 count += 1
198 if not test_mode then progress.update(count, "page {count}/{pages}")
199 if not no_render then doc.gen_page(new PagePerson(person), output_dir)
200 end
201 for tag in tags do
202 count += 1
203 if not test_mode then progress.update(count, "page {count}/{pages}")
204 if not no_render then doc.gen_page(new PageTag(tag), output_dir)
205 end
206
207 if not test_mode then print "" # finalise progress
208 if not no_render then
209 doc.create_index_file("{output_dir}/quicksearch-list.js")
210 print "Documentation produced in `{output_dir}`"
211 end
212
213 if test_mode then
214 print "Generated {count}/{pages} pages"
215 print " PageHome: 1"
216 print " PageMPackage: {mpackages.length}"
217 print " PageMGroup: {mgroups.length}"
218 print " PageMModule: {nmodules.length}"
219 print " PageMClass: {mclasses.length}"
220 print " PageMProperty: {mprops.length}"
221 print " PagePerson: {persons.length}"
222 print " PageTag: {tags.length}"
223 end
224 end
225 end
226
227 redef class Catalog
228
229 # Build the catalog from `mpackages`
230 fun build_catalog(mpackages: Array[MPackage]) do
231 # Compute the poset
232 for p in mpackages do
233 var g = p.root
234 assert g != null
235 modelbuilder.scan_group(g)
236 end
237 # Build the catalog
238 for mpackage in mpackages do
239 package_page(mpackage)
240 git_info(mpackage)
241 mpackage_stats(mpackage)
242 end
243 end
244 end
245
246 # build toolcontext
247 var toolcontext = new ToolContext
248 var tpl = new Template
249 tpl.add "Usage: nitdoc [OPTION]... <file.nit>...\n"
250 tpl.add "Generates HTML pages of API documentation from Nit source files."
251 toolcontext.tooldescription = tpl.write_to_string
252
253 # process options
254 toolcontext.process_options(args)
255 var arguments = toolcontext.option_context.rest
256
257 # build model
258 var model = new Model
259 var mbuilder = new ModelBuilder(model, toolcontext)
260 var mmodules = mbuilder.parse_full(arguments)
261
262 # process
263 if mmodules.is_empty then return
264 print "Parsing code..."
265 mbuilder.run_phases
266 toolcontext.run_global_phases(mmodules)