ni_nitdoc: Cleaning nitdoc options
[nit.git] / src / ni_nitdoc.nit
1 # This file is part of NIT ( http://www.nitlanguage.org ).
2 #
3 # Copyright 2008 Jean Privat <jean@pryen.org>
4 #
5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at
8 #
9 # http://www.apache.org/licenses/LICENSE-2.0
10 #
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
16
17 module ni_nitdoc
18
19 import model_utils
20 import abstract_compiler
21 import html
22
23 class Nitdoc
24 private var toolcontext: ToolContext
25 private var model: Model
26 private var modelbuilder: ModelBuilder
27 private var mainmodule: MModule
28 private var arguments: Array[String]
29 private var destinationdir: nullable String
30 private var sharedir: nullable String
31
32 private var opt_dir = new OptionString("Directory where doc is generated", "-d", "--dir")
33 private var opt_source = new OptionString("What link for source (%f for filename, %l for first line, %L for last line)", "--source")
34 private var opt_sharedir = new OptionString("Directory containing the nitdoc files", "--sharedir")
35 private var opt_nodot = new OptionBool("Do not generate graphes with graphiviz", "--no-dot")
36
37 init(toolcontext: ToolContext) do
38 # We need a model to collect stufs
39 self.toolcontext = toolcontext
40 self.arguments = toolcontext.option_context.rest
41 toolcontext.option_context.options.clear
42 toolcontext.option_context.add_option(opt_dir)
43 toolcontext.option_context.add_option(opt_source)
44 toolcontext.option_context.add_option(opt_sharedir)
45 toolcontext.option_context.add_option(opt_nodot)
46 process_options
47
48 if arguments.length < 1 then
49 toolcontext.option_context.usage
50 exit(1)
51 end
52
53 model = new Model
54 modelbuilder = new ModelBuilder(model, toolcontext)
55
56 # Here we load an process std modules
57 var mmodules = modelbuilder.parse_and_build([arguments.first])
58 if mmodules.is_empty then return
59 modelbuilder.full_propdef_semantic_analysis
60 assert mmodules.length == 1
61 self.mainmodule = mmodules.first
62 end
63
64 private fun process_options do
65 if not opt_dir.value is null then
66 destinationdir = opt_dir.value
67 else
68 destinationdir = "nitdoc_directory"
69 end
70 if not opt_sharedir.value is null then
71 sharedir = opt_sharedir.value
72 else
73 var dir = "NIT_DIR".environ
74 if dir.is_empty then
75 dir = "{sys.program_name.dirname}/../share/nitdoc"
76 else
77 dir = "{dir}/share/nitdoc"
78 end
79 sharedir = dir
80 if sharedir is null then
81 print "Error: Cannot locate nitdoc share files. Uses --sharedir or envvar NIT_DIR"
82 abort
83 end
84 dir = "{sharedir.to_s}/scripts/js-facilities.js"
85 if sharedir is null then
86 print "Error: Invalid nitdoc share files. Check --sharedir or envvar NIT_DIR"
87 abort
88 end
89 end
90 end
91
92 fun start do
93 if arguments.length == 1 then
94 # Create destination dir if it's necessary
95 if not destinationdir.file_exists then destinationdir.mkdir
96 sys.system("cp -r {sharedir.to_s}/* {destinationdir.to_s}/")
97 overview
98 fullindex
99 modules
100 classes
101 quicksearch_list
102 end
103 end
104
105 fun overview do
106 var overviewpage = new NitdocOverview.with(modelbuilder.nmodules, self.opt_nodot.value, destinationdir.to_s)
107 overviewpage.save("{destinationdir.to_s}/index.html")
108 end
109
110 fun fullindex do
111 var fullindex = new NitdocFullindex.with(model.mmodules)
112 fullindex.save("{destinationdir.to_s}/full-index.html")
113 end
114
115 fun modules do
116 for mod in modelbuilder.nmodules do
117 var modulepage = new NitdocModules.with(mod)
118 modulepage.save("{destinationdir.to_s}/{mod.mmodule.name}.html")
119 end
120 end
121
122 fun classes do
123 for amodule in modelbuilder.nmodules do
124 for mclass, aclassdef in amodule.mclass2nclassdef do
125 mclass.amodule(modelbuilder.mmodule2nmodule)
126 mclass.mmethod(aclassdef.mprop2npropdef)
127 var classpage = new NitdocMClasses.with(mclass, aclassdef)
128 classpage.save("{destinationdir.to_s}/{mclass.name}.html")
129 end
130 end
131 end
132
133 # Generate QuickSearch file
134 fun quicksearch_list do
135 var file = new OFStream.open("{destinationdir.to_s}/quicksearch-list.js")
136 var content = new Buffer
137 content.append("var entries = \{ ")
138 for prop in model.mproperties do
139 if not prop isa MMethod then continue
140 content.append("\"{prop.name}\": [")
141 for propdef in prop.mpropdefs do
142 content.append("\{txt: \"{propdef.mproperty.full_name}\", url:\"{propdef.mproperty.link_anchor}\" \}")
143 if not propdef is prop.mpropdefs.last then content.append(", ")
144 end
145 content.append("]")
146 content.append(", ")
147 end
148
149 for mclass in model.mclasses do
150 content.append("\"{mclass.name}\": [")
151 for mclassdef in mclass.mclassdefs do
152 content.append("\{txt: \"{mclassdef.mclass.full_name}\", url:\"{mclass.link_anchor}\" \}")
153 if not mclassdef is mclass.mclassdefs.last then content.append(", ")
154 end
155 content.append("]")
156 if not mclass is model.mclasses.last then content.append(", ")
157 end
158
159 content.append(" \};")
160 file.write(content.to_s)
161 file.close
162 end
163
164 end
165
166 class NitdocOverview
167 super NitdocPage
168
169 var amodules: Array[AModule]
170
171 # Init with Array[AModule] to get all ifnormations about each MModule containt in a program
172 # opt_nodot to inform about the graph gen
173 # destination: to know where will be saved dot files
174 init with(modules: Array[AModule], opt_nodot: Bool, destination: String) do
175 self.amodules = modules
176 self.opt_nodot = opt_nodot
177 self.destinationdir = destination
178 end
179
180 redef fun head do
181 super
182 add("title").text("Overview | Nit Standard Library")
183 end
184
185 redef fun header do
186 open("header")
187 open("nav").add_class("main")
188 open("ul")
189 add("li").add_class("current").text("Overview")
190 open("li")
191 add_html("<a href=\"full-index.html\">Full Index</a>")
192 close("li")
193 open("li").attr("id", "liGitHub")
194 open("a").add_class("btn").attr("id", "logGitHub")
195 add("img").attr("id", "imgGitHub").attr("src", "resources/icons/github-icon.png")
196 close("a")
197 open("div").add_class("popover bottom")
198 add("div").add_class("arrow").text(" ")
199 open("div").add_class("githubTitle")
200 add("h3").text("Github Sign In")
201 close("div")
202 open("div")
203 add("label").attr("id", "lbloginGit").text("Username")
204 add("input").attr("id", "loginGit").attr("name", "login").attr("type", "text")
205 open("label").attr("id", "logginMessage").text("Hello ")
206 open("a").attr("id", "githubAccount")
207 add("strong").attr("id", "nickName").text(" ")
208 close("a")
209 close("label")
210 close("div")
211 open("div")
212 add("label").attr("id", "lbpasswordGit").text("Password")
213 add("input").attr("id", "passwordGit").attr("name", "password").attr("type", "password")
214 open("div").attr("id", "listBranches")
215 add("label").attr("id", "lbBranches").text("Branch")
216 add("select").add_class("dropdown").attr("id", "dropBranches").attr("name", "dropBranches").attr("tabindex", "1").text(" ")
217 close("div")
218 close("div")
219 open("div")
220 add("label").attr("id", "lbrepositoryGit").text("Repository")
221 add("input").attr("id", "repositoryGit").attr("name", "repository").attr("type", "text")
222 close("div")
223 open("div")
224 add("label").attr("id", "lbbranchGit").text("Branch")
225 add("input").attr("id", "branchGit").attr("name", "branch").attr("type", "text")
226 close("div")
227 open("div")
228 add("a").attr("id", "signIn").text("Sign In")
229 close("div")
230 close("div")
231 close("li")
232 close("ul")
233 close("nav")
234 close("header")
235 end
236
237 redef fun body do
238 super
239 open("div").add_class("page")
240 open("div").add_class("content fullpage")
241 add("h1").text("Nit Standard Library")
242 open("article").add_class("overview")
243 add_html("<p>Documentation for the standard library of Nit<br />Version jenkins-component=stdlib-19<br />Date: TODAY</p>")
244 close("article")
245 open("article").add_class("overview")
246 add("h2").text("Modules")
247 open("ul")
248 add_modules
249 close("ul")
250 process_generate_dot
251 close("article")
252 close("div")
253 close("div")
254 add("footer").text("Nit standard library. Version jenkins-component=stdlib-19.")
255 end
256
257 fun add_modules do
258 var ls = new List[nullable MModule]
259 for amodule in amodules do
260 var mmodule = amodule.mmodule.public_owner
261 if mmodule != null and not ls.has(mmodule) then
262 open("li")
263 add("a").attr("href", "{mmodule.name}.html").text("{mmodule.to_s} ")
264 add_html(amodule.comment)
265 close("li")
266 ls.add(mmodule)
267 end
268 end
269 end
270
271 fun process_generate_dot do
272 var op = new Buffer
273 op.append("digraph dep \{ rankdir=BT; node[shape=none,margin=0,width=0,height=0,fontsize=10]; edge[dir=none,color=gray]; ranksep=0.2; nodesep=0.1;\n")
274 for amodule in amodules do
275 op.append("\"{amodule.mmodule.name}\"[URL=\"{amodule.mmodule.name}.html\"];\n")
276 for mmodule2 in amodule.mmodule.in_importation.direct_greaters do
277 op.append("\"{amodule.mmodule.name}\"->\"{mmodule2.name}\";\n")
278 end
279 end
280 op.append("\}\n")
281 generate_dot(op.to_s, "dep", "Modules hierarchy")
282 end
283
284 end
285
286 class NitdocFullindex
287 super NitdocPage
288
289 var mmodules: Array[MModule]
290
291 init with(mmodules: Array[MModule]) do
292 self.mmodules = mmodules
293 opt_nodot = false
294 destinationdir = ""
295 end
296
297 redef fun head do
298 super
299 add("title").text("Full Index | Nit Standard Library")
300 end
301
302 redef fun header do
303 open("header")
304 open("nav").add_class("main")
305 open("ul")
306 open("li")
307 add_html("<a href=\"index.html\">Overview</a>")
308 close("li")
309 add("li").add_class("current").text("Full Index")
310 open("li").attr("id", "liGitHub")
311 open("a").add_class("btn").attr("id", "logGitHub")
312 add("img").attr("id", "imgGitHub").attr("src", "resources/icons/github-icon.png")
313 close("a")
314 open("div").add_class("popover bottom")
315 add("div").add_class("arrow").text(" ")
316 open("div").add_class("githubTitle")
317 add("h3").text("Github Sign In")
318 close("div")
319 open("div")
320 add("label").attr("id", "lbloginGit").text("Username")
321 add("input").attr("id", "loginGit").attr("name", "login").attr("type", "text")
322 open("label").attr("id", "logginMessage").text("Hello ")
323 open("a").attr("id", "githubAccount")
324 add("strong").attr("id", "nickName").text(" ")
325 close("a")
326 close("label")
327 close("div")
328 open("div")
329 add("label").attr("id", "lbpasswordGit").text("Password")
330 add("input").attr("id", "passwordGit").attr("name", "password").attr("type", "password")
331 open("div").attr("id", "listBranches")
332 add("label").attr("id", "lbBranches").text("Branch")
333 add("select").add_class("dropdown").attr("id", "dropBranches").attr("name", "dropBranches").attr("tabindex", "1").text(" ")
334 close("div")
335 close("div")
336 open("div")
337 add("label").attr("id", "lbrepositoryGit").text("Repository")
338 add("input").attr("id", "repositoryGit").attr("name", "repository").attr("type", "text")
339 close("div")
340 open("div")
341 add("label").attr("id", "lbbranchGit").text("Branch")
342 add("input").attr("id", "branchGit").attr("name", "branch").attr("type", "text")
343 close("div")
344 open("div")
345 add("a").attr("id", "signIn").text("Sign In")
346 close("div")
347 close("div")
348 close("li")
349 close("ul")
350 close("nav")
351 close("header")
352 end
353
354 redef fun body do
355 super
356 open("div").add_class("page")
357 open("div").add_class("content fullpage")
358 add("h1").text("Full Index")
359 add_content
360 close("div")
361 close("div")
362 add("footer").text("Nit standard library. Version jenkins-component=stdlib-19.")
363 end
364
365 fun add_content do
366 module_column
367 classes_column
368 properties_column
369 end
370
371 # Add to content modules column
372 fun module_column do
373 var ls = new List[nullable MModule]
374 open("article").add_class("modules filterable")
375 add("h2").text("Modules")
376 open("ul")
377 for mmodule in mmodules do
378 if mmodule.public_owner != null and not ls.has(mmodule.public_owner) then
379 ls.add(mmodule.public_owner)
380 open("li")
381 add("a").attr("href", "{mmodule.public_owner.name}.html").text(mmodule.public_owner.name)
382 close("li")
383 end
384 end
385 close("ul")
386 close("article")
387 end
388
389 # Add to content classes modules
390 fun classes_column do
391 open("article").add_class("classes filterable")
392 add("h2").text("Classes")
393 open("ul")
394
395 for mclass in mmodules.first.imported_mclasses do
396 open("li")
397 add("a").attr("href", "{mclass.name}.html").text(mclass.name)
398 close("li")
399 end
400
401 close("ul")
402 close("article")
403 end
404
405 # Insert the properties column of fullindex page
406 fun properties_column do
407 open("article").add_class("properties filterable")
408 add("h2").text("Properties")
409 open("ul")
410
411 for method in mmodules.first.imported_methods do
412 if method.visibility is none_visibility or method.visibility is intrude_visibility then continue
413 open("li").add_class("intro")
414 add("span").attr("title", "introduction").text("I")
415 add_html("&nbsp;")
416 add("a").attr("href", "{method.local_class.name}.html").attr("title", "").text("{method.name} ({method.local_class.name})")
417 close("li")
418 end
419
420 for method in mmodules.first.redef_methods do
421 if method.visibility is none_visibility or method.visibility is intrude_visibility then continue
422 open("li").add_class("redef")
423 add("span").attr("title", "redefinition").text("R")
424 add_html("&nbsp;")
425 add("a").attr("href", "{method.local_class.name}.html").attr("title", "").text("{method.name} ({method.local_class.name})")
426 close("li")
427 end
428
429 close("ul")
430 close("article")
431 end
432
433 end
434
435 class NitdocModules
436 super NitdocPage
437
438 var amodule: AModule
439 var modulename: String
440 init with(amodule: AModule) do
441 self.amodule = amodule
442 self.modulename = self.amodule.mmodule.name
443 opt_nodot = false
444 destinationdir = ""
445 end
446
447 redef fun head do
448 super
449 add("title").text("{modulename} module | {amodule.short_comment}")
450 end
451
452 redef fun header do
453 open("header")
454 open("nav").add_class("main")
455 open("ul")
456 open("li")
457 add_html("<a href=\"index.html\">Overview</a>")
458 close("li")
459 add("li").add_class("current").text(modulename)
460 open("li")
461 add_html("<a href=\"full-index.html\" >Full Index</a>")
462 close("li")
463 open("li").attr("id", "liGitHub")
464 open("a").add_class("btn").attr("id", "logGitHub")
465 add("img").attr("id", "imgGitHub").attr("src", "resources/icons/github-icon.png")
466 close("a")
467 open("div").add_class("popover bottom")
468 add("div").add_class("arrow").text(" ")
469 open("div").add_class("githubTitle")
470 add("h3").text("Github Sign In")
471 close("div")
472 open("div")
473 add("label").attr("id", "lbloginGit").text("Username")
474 add("input").attr("id", "loginGit").attr("name", "login").attr("type", "text")
475 open("label").attr("id", "logginMessage").text("Hello ")
476 open("a").attr("id", "githubAccount")
477 add("strong").attr("id", "nickName").text(" ")
478 close("a")
479 close("label")
480 close("div")
481 open("div")
482 add("label").attr("id", "lbpasswordGit").text("Password")
483 add("input").attr("id", "passwordGit").attr("name", "password").attr("type", "password")
484 open("div").attr("id", "listBranches")
485 add("label").attr("id", "lbBranches").text("Branch")
486 add("select").add_class("dropdown").attr("id", "dropBranches").attr("name", "dropBranches").attr("tabindex", "1").text(" ")
487 close("div")
488 close("div")
489 open("div")
490 add("label").attr("id", "lbrepositoryGit").text("Repository")
491 add("input").attr("id", "repositoryGit").attr("name", "repository").attr("type", "text")
492 close("div")
493 open("div")
494 add("label").attr("id", "lbbranchGit").text("Branch")
495 add("input").attr("id", "branchGit").attr("name", "branch").attr("type", "text")
496 close("div")
497 open("div")
498 add("a").attr("id", "signIn").text("Sign In")
499 close("div")
500 close("div")
501 close("li")
502 close("ul")
503 close("nav")
504 close("header")
505 end
506
507 redef fun body do
508 super
509 open("div").add_class("page")
510 menu
511 add_content
512 close("div")
513 add("footer").text("Nit standard library. Version jenkins-component=stdlib-19.")
514 end
515
516 # Insert all tags in content part
517 fun add_content do
518 open("div").add_class("content")
519 add("h1").text(modulename)
520 add("div").add_class("subtitle").text("module {modulename}")
521 module_comment
522 classes
523 properties
524 close("div")
525 end
526
527 # Insert module comment in the content
528 fun module_comment do
529 var doc = amodule.comment
530 open("div").attr("id", "description")
531 add("pre").add_class("text_label").text(doc)
532 add("textarea").add_class("edit").attr("rows", "1").attr("cols", "76").attr("id", "fileContent").text(" ")
533 add("a").attr("id", "cancelBtn").text("Cancel")
534 add("a").attr("id", "commitBtn").text("Commit")
535 add("pre").add_class("text_label").attr("id", "preSave").attr("type", "2")
536 close("div")
537 end
538
539 fun menu do
540 var mmodule = amodule.mmodule
541 open("div").add_class("menu")
542 open("nav")
543 add("h3").text("Module Hierarchy").attr("style","cursor: pointer;")
544 if mmodule.in_importation.direct_greaters.length > 0 then
545 add_html("<h4>All dependencies</h4><ul>")
546 for m in mmodule.in_importation.direct_greaters do
547 if m == mmodule or mmodule == m.public_owner then continue
548 open("li")
549 add("a").attr("href", "{m.name}.html").text(m.name)
550 close("li")
551 end
552 add_html("</ul>")
553 end
554 if mmodule.in_importation.greaters.length > 0 then
555 add_html("<h4>All clients</h4><ul>")
556 for m in mmodule.in_importation.greaters do
557 if m == mmodule then continue
558 open("li")
559 add("a").attr("href", "{m.name}.html").text(m.name)
560 close("li")
561 end
562 add_html("</ul>")
563 end
564 close("nav")
565 if mmodule.in_nesting.direct_greaters.length > 0 then
566 open("nav")
567 add("h3").text("Nested Modules").attr("style","cursor: pointer;")
568 open("ul")
569 for m in mmodule.in_nesting.direct_greaters do
570 open("li")
571 add("a").attr("href", "{m.name}.html").text(m.name)
572 close("li")
573 end
574 close("ul")
575
576 close("nav")
577 end
578 close("div")
579 end
580
581 fun classes do
582 open("div").add_class("module")
583 open("article").add_class("classes filterable")
584 add("h2").text("Classes")
585 open("ul")
586 for c, state in amodule.mmodule.mclasses do
587 var name = c.name
588 if state == c_is_intro or state == c_is_imported then
589 open("li").add_class("intro")
590 add("span").attr("title", "introduced in this module").text("I ")
591 else
592 open("li").add_class("redef")
593 add("span").attr("title", "refined in this module").text("R ")
594 end
595 add("a").attr("href", "{name}.html").text(name)
596 close("li")
597 end
598 close("ul")
599 close("article")
600 close("div")
601 end
602
603 fun properties do
604 open("article").add_class("properties filterable")
605 add_html("<h2>Properties</h2>")
606 open("ul")
607 for method in amodule.mmodule.imported_methods do
608 if method.visibility is none_visibility or method.visibility is intrude_visibility then continue
609 open("li").add_class("intro")
610 add("span").attr("title", "introduction").text("I")
611 add_html("&nbsp;")
612 add("a").attr("href", "{method.local_class.name}.html").attr("title", "").text("{method.name} ({method.local_class.name})")
613 close("li")
614 end
615
616 for method in amodule.mmodule.redef_methods do
617 if method.visibility is none_visibility or method.visibility is intrude_visibility then continue
618 open("li").add_class("redef")
619 add("span").attr("title", "redefinition").text("R")
620 add_html("&nbsp;")
621 add("a").attr("href", "{method.local_class.name}.html").attr("title", "").text("{method.name} ({method.local_class.name})")
622 close("li")
623 end
624
625 close("ul")
626 close("article")
627 end
628
629 end
630
631 # Nit Standard Library
632 class NitdocMClasses
633 super NitdocPage
634
635 var mclass: MClass
636 var aclassdef: AClassdef
637 var stdclassdef: nullable AStdClassdef
638 var public_owner: nullable MModule
639
640 init with(mclass: MClass, aclassdef: AClassdef) do
641 self.mclass = mclass
642 self.aclassdef = aclassdef
643 if aclassdef isa AStdClassdef then self.stdclassdef = aclassdef
644 self.public_owner = mclass.intro_mmodule.public_owner
645 opt_nodot = false
646 destinationdir = ""
647 end
648
649 redef fun head do
650 super
651 add("title").text("{self.mclass.name} class | Nit Standard Library")
652 end
653
654 redef fun header do
655 open("header")
656 open("nav").add_class("main")
657 open("ul")
658 open("li")
659 add_html("<a href=\"index.html\">Overview</a>")
660 close("li")
661 open("li")
662 if public_owner is null then
663 add_html("<a href=\"{mclass.intro_mmodule.name}.html\">{mclass.intro_mmodule.name}</a>")
664 else
665 add_html("<a href=\"{public_owner.name}.html\">{public_owner.name}</a>")
666 end
667 close("li")
668 add("li").add_class("current").text(mclass.name)
669 open("li")
670 add_html("<a href=\"full-index.html\" >Full Index</a>")
671 close("li")
672 open("li").attr("id", "liGitHub")
673 open("a").add_class("btn").attr("id", "logGitHub")
674 add("img").attr("id", "imgGitHub").attr("src", "resources/icons/github-icon.png")
675 close("a")
676 open("div").add_class("popover bottom")
677 add("div").add_class("arrow").text(" ")
678 open("div").add_class("githubTitle")
679 add("h3").text("Github Sign In")
680 close("div")
681 open("div")
682 add("label").attr("id", "lbloginGit").text("Username")
683 add("input").attr("id", "loginGit").attr("name", "login").attr("type", "text")
684 open("label").attr("id", "logginMessage").text("Hello ")
685 open("a").attr("id", "githubAccount")
686 add("strong").attr("id", "nickName").text(" ")
687 close("a")
688 close("label")
689 close("div")
690 open("div")
691 add("label").attr("id", "lbpasswordGit").text("Password")
692 add("input").attr("id", "passwordGit").attr("name", "password").attr("type", "password")
693 open("div").attr("id", "listBranches")
694 add("label").attr("id", "lbBranches").text("Branch")
695 add("select").add_class("dropdown").attr("id", "dropBranches").attr("name", "dropBranches").attr("tabindex", "1").text(" ")
696 close("div")
697 close("div")
698 open("div")
699 add("label").attr("id", "lbrepositoryGit").text("Repository")
700 add("input").attr("id", "repositoryGit").attr("name", "repository").attr("type", "text")
701 close("div")
702 open("div")
703 add("label").attr("id", "lbbranchGit").text("Branch")
704 add("input").attr("id", "branchGit").attr("name", "branch").attr("type", "text")
705 close("div")
706 open("div")
707 add("a").attr("id", "signIn").text("Sign In")
708 close("div")
709 close("div")
710 close("li")
711 close("ul")
712 close("nav")
713 close("header")
714 end
715
716 redef fun body do
717 super
718 open("div").add_class("page")
719 add_content
720 close("div")
721 add("footer").text("Nit standard library. Version jenkins-component=stdlib-19.")
722 end
723
724 # Insert all tags in content part
725 fun add_content do
726 open("div").add_class("menu")
727 properties_column
728 inheritance_column
729 close("div")
730 open("div").add_class("content")
731 content
732 close("div")
733 end
734
735 fun properties_column do
736 open("nav").add_class("properties filterable")
737 add("h3").text("Properties")
738
739 if mclass.virtual_types.length > 0 then
740 add("h4").text("Virtual Types")
741 open("ul")
742 for prop in mclass.virtual_types do
743 add_html("<li class=\"redef\"><span title=\"Redefined\">R</span><a href=\"{prop.link_anchor}\">{prop.name}</a></li>")
744 end
745 close("ul")
746 end
747 if mclass.constructors.length > 0 then
748 add("h4").text("Constructors")
749 open("ul")
750 for prop in mclass.constructors do
751 add_html("<li class=\"intro\"><span title=\"Introduced\">I</span><a href=\"{prop.link_anchor}\">{prop.name}</a></li>")
752 end
753 close("ul")
754 end
755 add("h4").text("Methods")
756 open("ul")
757 if mclass.intro_methods.length > 0 then
758 for prop in mclass.intro_methods do
759 if prop.visibility is public_visibility or prop.visibility is protected_visibility then add_html("<li class=\"intro\"><span title=\"Introduced\">I</span><a href=\"{prop.link_anchor}\">{prop.name}</a></li>")
760 end
761 end
762 if mclass.inherited_methods.length > 0 then
763 for prop in mclass.inherited_methods do
764 if prop.visibility is public_visibility or prop.visibility is protected_visibility then add_html("<li class=\"inherit\"><span title=\"Inherited\">H</span><a href=\"{prop.link_anchor}\">{prop.name}</a></li>")
765 end
766 end
767 if mclass.redef_methods.length > 0 then
768 for prop in mclass.redef_methods do
769 if prop.visibility is public_visibility or prop.visibility is protected_visibility then add_html("<li class=\"redef\"><span title=\"Refined\">R</span><a href=\"{prop.link_anchor}\">{prop.name}</a></li>")
770 end
771 end
772 close("ul")
773 close("nav")
774 end
775
776 fun inheritance_column do
777 open("nav")
778 add("h3").text("Inheritance")
779 if mclass.parents.length > 0 then
780 add("h4").text("Superclasses")
781 open("ul")
782 for sup in mclass.parents do add_html("<li><a href=\"{sup.name}.html\">{sup.name}</a></li>")
783 close("ul")
784 end
785
786 if mclass.descendants.length is 0 then
787 add("h4").text("No Known Subclasses")
788 else if mclass.descendants.length <= 100 then
789 add("h4").text("Subclasses")
790 open("ul")
791 for sub in mclass.descendants do add_html("<li><a href=\"{sub.name}\">{sub.name}</a></li>")
792 close("ul")
793 else if mclass.children.length <= 100 then
794 add("h4").text("Direct Subclasses Only")
795 open("ul")
796 for sub in mclass.children do add_html("<li><a href=\"{sub.name}\">{sub.name}</a></li>")
797 close("ul")
798 else
799 add("h4").text("Too much Subclasses to list")
800 end
801 close("nav")
802 end
803
804 fun content do
805 var subtitle = ""
806 var lmmodule = new List[MModule]
807 # Insert the subtitle part
808 add("h1").text(mclass.name)
809 open("div").add_class("subtitle")
810 if mclass.visibility is none_visibility then subtitle += "private "
811 subtitle += "{mclass.kind} <a href=\"{mclass.public_owner.name}.html\">{mclass.public_owner.name}</a>::{mclass.name}"
812 add_html(subtitle)
813 close("div")
814 add_html("<div style=\"float: right;\"><a id=\"lblDiffCommit\"></a></div>")
815 # We add the class description
816 open("section").add_class("description")
817 if not stdclassdef is null and not stdclassdef.comment.is_empty then add_html("<pre class=\"text_label\" title=\"122\" name=\"\" tag=\"{mclass.mclassdefs.first.location.to_s}\" type=\"2\">{stdclassdef.comment} </pre><textarea id=\"fileContent\" class=\"edit\" cols=\"76\" rows=\"1\" style=\"display: none;\"></textarea><a id=\"cancelBtn\" style=\"display: none;\">Cancel</a><a id=\"commitBtn\" style=\"display: none;\">Commit</a><pre id=\"preSave\" class=\"text_label\" type=\"2\"></pre>")
818 close("section")
819 open("section").add_class("concerns")
820 add("h2").add_class("section-header").text("Concerns")
821 open("ul")
822 for owner, childs in mclass.concerns do
823 open("li")
824 add_html("<a href=\"#MOD_{owner.name}\">{owner.name}</a>: {owner.amodule.short_comment}")
825 if not childs is null then
826 open("ul")
827 for child in childs.as(not null) do add_html("<li><a href=\"#MOD_{child.name}\">{child.name}</a>: {child.amodule.short_comment} </li>")
828 close("ul")
829 end
830 close("li")
831 end
832 close("ul")
833 close("section")
834 # Insert virtual types if there is almost one
835 if mclass.virtual_types.length > 0 or (stdclassdef != null and stdclassdef.n_formaldefs.length > 0) then
836 open("section").add_class("types")
837 add("h2").text("Formal and Virtual Types")
838 if mclass.virtual_types.length > 0 then for prop in mclass.virtual_types do description(prop)
839 if stdclassdef.n_formaldefs.length > 0 then
840 for prop in stdclassdef.n_formaldefs do
841 open("article").attr("id", "FT_Object_{prop.collect_text}")
842 open("h3").add_class("signature").text("{prop.collect_text}: nullable ")
843 add_html("<a title=\"The root of the class hierarchy.\" href=\"Object.html\">Object</a>")
844 close("h3")
845 add_html("<div class=\"info\">formal generic type</div>")
846 close("article")
847 end
848 end
849 close("section")
850 end
851 # Insert constructors if there is almost one
852 if mclass.constructors.length > 0 then
853 open("section").add_class("constructors")
854 add("h2").add_class("section-header").text("Constructors")
855 for prop in mclass.constructors do description(prop)
856 close("section")
857 end
858 open("section").add_class("methods")
859 add("h2").add_class("section-header").text("Methods")
860 for mmodule, mmethods in mclass.all_methods do
861 add_html("<a id=\"MOD_{mmodule.name}\"></a>")
862 if mmodule != mclass.intro_mmodule and mmodule != mclass.public_owner then
863 if mclass.has_mmodule(mmodule) then
864 add_html("<p class=\"concern-doc\">{mmodule.name}: {mmodule.amodule.short_comment}</p>")
865 else
866 add_html("<h3 class=\"concern-toplevel\">Methods refined in <a href=\"{mmodule.name}.html\">{mmodule.name}</a></h3><p class=\"concern-doc\">{mmodule.name}: {mmodule.amodule.short_comment}</p>")
867 end
868 end
869 for prop in mmethods do description(prop)
870 end
871 # Insert inherited methods
872 if mclass.inherited_methods.length > 0 then
873 add("h3").text("Inherited Methods")
874 for i_mclass, methods in mclass.inherited do
875 open("p")
876 add_html("Defined in <a href=\"{i_mclass.name}.html\">{i_mclass.name}</a>: ")
877 for method in methods do
878 add_html("<a href=\"{method.link_anchor}\">{method.name}</a>")
879 if method != methods.last then add_html(", ")
880 end
881 close("p")
882 end
883 end
884 close("section")
885 end
886
887 # Insert description tags for 'prop'
888 fun description(prop: MProperty) do
889 open("article").add_class("fun public {if prop.is_redef then "redef" else ""}").attr("id", "{prop.anchor}")
890 var sign = prop.name
891 if prop.apropdef != null then sign += prop.apropdef.signature
892 add_html("<h3 class=\"signature\">{sign}</h3>")
893 add_html("<div class=\"info\">{if prop.is_redef then "redef" else ""} fun {prop.intro_mclassdef.namespace(mclass)}::{prop.name}</div><div style=\"float: right;\"><a id=\"lblDiffCommit\"></a></div>")
894
895 open("div").add_class("description")
896 if prop.apropdef is null or prop.apropdef.comment == "" then
897 add_html("<a class=\"newComment\" title=\"32\" tag=\"\">New Comment</a>")
898 else
899 add_html("<pre class=\"text_label\" title=\"\" name=\"\" tag=\"\" type=\"1\">{prop.apropdef.comment}</pre>")
900 end
901 add_html("<textarea id=\"fileContent\" class=\"edit\" cols=\"76\" rows=\"1\" style=\"display: none;\"></textarea><a id=\"cancelBtn\" style=\"display: none;\">Cancel</a><a id=\"commitBtn\" style=\"display: none;\">Commit</a><pre id=\"preSave\" class=\"text_label\" type=\"2\"></pre>")
902 open("p")
903 if prop.local_class != mclass then add_html("inherited from {prop.local_class.intro_mmodule.name} ")
904 #TODO display show code if doc github
905 add_html("defined by the module <a href=\"{prop.intro_mclassdef.mmodule.name}.html\">{prop.intro_mclassdef.mmodule.name}</a> (<a href=\"\">show code</a>).")
906
907 for parent in mclass.parents do
908 if prop isa MMethod then if parent.constructors.has(prop) then add_html(" Previously defined by: <a href=\"{parent.intro_mmodule.name}.html\">{parent.intro_mmodule.name}</a> for <a href=\"{parent.name}.html\">{parent.name}</a>.")
909 end
910 close("p")
911 close("div")
912
913 close("article")
914 end
915
916 end
917
918 class NitdocPage
919 super HTMLPage
920
921 var opt_nodot: Bool
922 var destinationdir : String
923
924 redef fun head do
925 add("meta").attr("charset", "utf-8")
926 add("script").attr("type", "text/javascript").attr("src", "scripts/jquery-1.7.1.min.js")
927 add("script").attr("type", "text/javascript").attr("src", "quicksearch-list.js")
928 add("script").attr("type", "text/javascript").attr("src", "scripts/js-facilities.js")
929 add("link").attr("rel", "stylesheet").attr("href", "styles/main.css").attr("type", "text/css").attr("media", "screen")
930 end
931
932 redef fun body do header
933 fun header do end
934
935 # Generate a clickable graphviz image using a dot content
936 fun generate_dot(dot: String, name: String, alt: String) do
937 if opt_nodot then return
938 var file = new OFStream.open("{self.destinationdir}/{name}.dot")
939 file.write(dot)
940 file.close
941 sys.system("\{ test -f {self.destinationdir}/{name}.png && test -f {self.destinationdir}/{name}.s.dot && diff {self.destinationdir}/{name}.dot {self.destinationdir}/{name}.s.dot >/dev/null 2>&1 ; \} || \{ cp {self.destinationdir}/{name}.dot {self.destinationdir}/{name}.s.dot && dot -Tpng -o{self.destinationdir}/{name}.png -Tcmapx -o{self.destinationdir}/{name}.map {self.destinationdir}/{name}.s.dot ; \}")
942 open("article").add_class("graph")
943 add("img").attr("src", "{name}.png").attr("usemap", "#{name}").attr("style", "margin:auto").attr("alt", "{alt}")
944 close("article")
945 var fmap = new IFStream.open("{self.destinationdir}/{name}.map")
946 add_html(fmap.read_all)
947 fmap.close
948 end
949
950 end
951
952 redef class AModule
953 private fun comment: String do
954 var ret = ""
955 if n_moduledecl is null or n_moduledecl.n_doc is null then ret
956 if n_moduledecl.n_doc is null then return ""
957 for t in n_moduledecl.n_doc.n_comment do
958 ret += "{t.text.replace("# ", "")}"
959 end
960 return ret
961 end
962
963 private fun short_comment: String do
964 var ret = ""
965 if n_moduledecl != null and n_moduledecl.n_doc != null then
966 var txt = n_moduledecl.n_doc.n_comment.first.text
967 txt = txt.replace("# ", "")
968 txt = txt.replace("\n", "")
969 ret += txt
970 end
971 return ret
972 end
973 end
974
975 redef class MModule
976
977 var amodule: nullable AModule
978
979 # Get the list of all methods in a module
980 fun imported_methods: Set[MMethod] do
981 var methods = new HashSet[MMethod]
982 for mclass in imported_mclasses do
983 for method in mclass.intro_methods do
984 methods.add(method)
985 end
986 end
987 return methods
988 end
989
990 # Get the list aof all refined methods in a module
991 fun redef_methods: Set[MMethod] do
992 var methods = new HashSet[MMethod]
993 for mclass in redef_mclasses do
994 for method in mclass.intro_methods do
995 methods.add(method)
996 end
997 end
998 return methods
999 end
1000 end
1001
1002 redef class MProperty
1003
1004 var is_redef: Bool
1005 var apropdef: nullable APropdef
1006
1007 redef init(intro_mclassdef: MClassDef, name: String, visibility: MVisibility)
1008 do
1009 super
1010 is_redef = false
1011 end
1012
1013 fun local_class: MClass do
1014 var classdef = self.intro_mclassdef
1015 return classdef.mclass
1016 end
1017
1018 fun class_text: String do
1019 return local_class.name
1020 end
1021
1022 fun link_anchor: String do
1023 return "{class_text}.html#{anchor}"
1024 end
1025
1026 fun anchor: String do
1027 return "PROP_{c_name}"
1028 end
1029
1030 end
1031
1032 redef class MClass
1033
1034 # Associate all MMethods to each MModule concerns
1035 fun all_methods: HashMap[MModule, Set[MMethod]] do
1036 var hm = new HashMap[MModule, Set[MMethod]]
1037 for mmodule, childs in concerns do
1038 if not hm.has_key(mmodule) then hm[mmodule] = new HashSet[MMethod]
1039 for prop in intro_methods do
1040 if mmodule == prop.intro_mclassdef.mmodule then
1041 prop.is_redef = false
1042 hm[mmodule].add(prop)
1043 end
1044 end
1045 for prop in redef_methods do
1046 if mmodule == prop.intro_mclassdef.mmodule then
1047 prop.is_redef = true
1048 hm[mmodule].add(prop)
1049 end
1050 end
1051
1052 if childs != null then
1053 for child in childs do
1054 if not hm.has_key(child) then hm[child] = new HashSet[MMethod]
1055 for prop in intro_methods do
1056 if child == prop.intro_mclassdef.mmodule then
1057 prop.is_redef = false
1058 hm[child].add(prop)
1059 end
1060 end
1061 for prop in redef_methods do
1062 if child == prop.intro_mclassdef.mmodule then
1063 prop.is_redef = true
1064 hm[child].add(prop)
1065 end
1066 end
1067 end
1068 end
1069 end
1070 return hm
1071 end
1072
1073 fun public_owner: MModule do
1074 var owner = intro_mmodule
1075 if owner.public_owner is null then
1076 return owner
1077 else
1078 return owner.public_owner.as(not null)
1079 end
1080 end
1081
1082 # Associate Amodule to all MModule concern by 'self'
1083 fun amodule(amodules: HashMap[MModule, AModule]) do
1084 for owner, childs in concerns do
1085 if childs != null then for child in childs do child.amodule = amodules[child]
1086 owner.amodule = amodules[owner]
1087 end
1088 end
1089
1090 # Associate MClass to all MMethod include in 'inherited_methods'
1091 fun inherited: HashMap[MClass, Set[MMethod]] do
1092 var hm = new HashMap[MClass, Set[MMethod]]
1093 for method in inherited_methods do
1094 var mclass = method.intro_mclassdef.mclass
1095 if not hm.has_key(mclass) then hm[mclass] = new HashSet[MMethod]
1096 hm[mclass].add(method)
1097 end
1098 return hm
1099 end
1100
1101 # Return true if MModule concern contain subMModule
1102 fun has_mmodule(sub: MModule): Bool do
1103 for mmodule, childs in concerns do
1104 if childs is null then continue
1105 if childs.has(sub) then return true
1106 end
1107 return false
1108 end
1109
1110 fun mmethod(mprop2npropdef: Map[MProperty, APropdef]) do
1111 for const in constructors do
1112 if mprop2npropdef.has_key(const)then
1113 const.apropdef = mprop2npropdef[const].as(AMethPropdef)
1114 end
1115 end
1116
1117 for intro in intro_methods do
1118 if mprop2npropdef.has_key(intro)then
1119 if mprop2npropdef[intro] isa AMethPropdef then intro.apropdef = mprop2npropdef[intro].as(AMethPropdef)
1120 end
1121 end
1122
1123 for rd in redef_methods do
1124 if mprop2npropdef.has_key(rd)then
1125 if mprop2npropdef[rd] isa AMethPropdef then rd.apropdef = mprop2npropdef[rd].as(AMethPropdef)
1126 end
1127 end
1128 end
1129
1130 fun link_anchor: String do
1131 return "{name}.html"
1132 end
1133
1134 end
1135
1136 redef class AStdClassdef
1137 private fun comment: String do
1138 var ret = ""
1139 if n_doc != null then
1140 for t in n_doc.n_comment do
1141 var txt = t.text.replace("# ", "")
1142 txt = txt.replace("#", "")
1143 ret += "{txt}"
1144 end
1145 end
1146 return ret
1147 end
1148
1149 private fun short_comment: String do
1150 var ret = ""
1151 if n_doc != null then
1152 var txt = n_doc.n_comment.first.text
1153 txt = txt.replace("# ", "")
1154 txt = txt.replace("\n", "")
1155 ret += txt
1156 end
1157 return ret
1158 end
1159 end
1160
1161 redef class ASignature
1162 redef fun to_s do
1163 #TODO closures
1164 var ret = ""
1165 if not n_params.is_empty then
1166 ret = "{ret}({n_params.join(", ")})"
1167 end
1168 if n_type != null and n_type.to_s != "" then ret += " {n_type.to_s}"
1169 return ret
1170 end
1171 end
1172
1173 redef class AParam
1174 redef fun to_s do
1175 var ret = "{n_id.text}"
1176 if n_type != null then
1177 ret = "{ret}: {n_type.to_s}"
1178 if n_dotdotdot != null then ret = "{ret}..."
1179 end
1180 return ret
1181 end
1182 end
1183
1184 redef class AType
1185 redef fun to_s do
1186 var ret = "<a href=\"{n_id.text}.html\">{n_id.text}</a>"
1187 if n_kwnullable != null then ret = "nullable {ret}"
1188 if not n_types.is_empty then ret = "{ret}[{n_types.join(", ")}]"
1189 return ret
1190 end
1191 end
1192
1193 redef class APropdef
1194 private fun short_comment: String is abstract
1195 private fun signature: String is abstract
1196 private fun comment: String is abstract
1197 end
1198
1199 redef class AAttrPropdef
1200 redef fun short_comment do
1201 var ret = ""
1202 if n_doc != null then
1203 var txt = n_doc.n_comment.first.text
1204 txt = txt.replace("# ", "")
1205 txt = txt.replace("\n", "")
1206 ret += txt
1207 end
1208 return ret
1209 end
1210 end
1211
1212 redef class AMethPropdef
1213 redef fun short_comment do
1214 var ret = ""
1215 if n_doc != null then
1216 var txt = n_doc.n_comment.first.text
1217 txt = txt.replace("# ", "")
1218 txt = txt.replace("\n", "")
1219 ret += txt
1220 end
1221 return ret
1222 end
1223
1224 redef fun signature: String do
1225 var sign = ""
1226 if n_signature != null then sign = " {n_signature.to_s}"
1227 return sign
1228 end
1229
1230 redef private fun comment: String do
1231 var ret = ""
1232 if n_doc != null then
1233 for t in n_doc.n_comment do
1234 var txt = t.text.replace("# ", "")
1235 txt = txt.replace("#", "")
1236 ret += "{txt}"
1237 end
1238 end
1239 return ret
1240 end
1241 end
1242
1243 redef class MClassDef
1244 private fun namespace(mclass: MClass): String do
1245
1246 if mmodule.public_owner is null then
1247 return "{mmodule.full_name}::{mclass.name}"
1248 else if mclass is self.mclass then
1249 return "{mmodule.public_owner.name}::{mclass.name}"
1250 else
1251 return "{mmodule.public_owner.name}::<a href=\"{mclass.name}.html\">{mclass.name}</a>"
1252 end
1253 end
1254 end
1255
1256 redef class Set[E]
1257 fun last: E do
1258 return to_a[length-1]
1259 end
1260 end
1261
1262 # Create a tool context to handle options and paths
1263 var toolcontext = new ToolContext
1264 toolcontext.process_options
1265
1266 # Here we launch the nit index
1267 var nitdoc = new Nitdoc(toolcontext)
1268 nitdoc.start