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