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