ni_nitdoc: Sort all columns in full index page
[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.nmodules, 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 amodules: Array[AModule]
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(modules: Array[AModule], opt_nodot: Bool, destination: String) do
182 self.amodules = modules
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 ls = new List[nullable MModule]
266 for amodule in amodules do
267 var mmodule = amodule.mmodule.public_owner
268 if mmodule != null and not ls.has(mmodule) then
269 open("li")
270 add("a").attr("href", "{mmodule.name}.html").text("{mmodule.to_s} ")
271 add_html(amodule.comment)
272 close("li")
273 ls.add(mmodule)
274 end
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 amodule in amodules do
282 op.append("\"{amodule.mmodule.name}\"[URL=\"{amodule.mmodule.name}.html\"];\n")
283 for mmodule2 in amodule.mmodule.in_importation.direct_greaters do
284 op.append("\"{amodule.mmodule.name}\"->\"{mmodule2.name}\";\n")
285 end
286 end
287 op.append("\}\n")
288 generate_dot(op.to_s, "dep", "Modules hierarchy")
289 end
290
291 end
292
293 class NitdocFullindex
294 super NitdocPage
295
296 var mmodules: Array[MModule]
297
298 init with(mmodules: Array[MModule]) do
299 self.mmodules = mmodules
300 opt_nodot = false
301 destinationdir = ""
302 end
303
304 redef fun head do
305 super
306 add("title").text("Full Index | Nit Standard Library")
307 end
308
309 redef fun header do
310 open("header")
311 open("nav").add_class("main")
312 open("ul")
313 open("li")
314 add_html("<a href=\"index.html\">Overview</a>")
315 close("li")
316 add("li").add_class("current").text("Full Index")
317 open("li").attr("id", "liGitHub")
318 open("a").add_class("btn").attr("id", "logGitHub")
319 add("img").attr("id", "imgGitHub").attr("src", "resources/icons/github-icon.png")
320 close("a")
321 open("div").add_class("popover bottom")
322 add("div").add_class("arrow").text(" ")
323 open("div").add_class("githubTitle")
324 add("h3").text("Github Sign In")
325 close("div")
326 open("div")
327 add("label").attr("id", "lbloginGit").text("Username")
328 add("input").attr("id", "loginGit").attr("name", "login").attr("type", "text")
329 open("label").attr("id", "logginMessage").text("Hello ")
330 open("a").attr("id", "githubAccount")
331 add("strong").attr("id", "nickName").text(" ")
332 close("a")
333 close("label")
334 close("div")
335 open("div")
336 add("label").attr("id", "lbpasswordGit").text("Password")
337 add("input").attr("id", "passwordGit").attr("name", "password").attr("type", "password")
338 open("div").attr("id", "listBranches")
339 add("label").attr("id", "lbBranches").text("Branch")
340 add("select").add_class("dropdown").attr("id", "dropBranches").attr("name", "dropBranches").attr("tabindex", "1").text(" ")
341 close("div")
342 close("div")
343 open("div")
344 add("label").attr("id", "lbrepositoryGit").text("Repository")
345 add("input").attr("id", "repositoryGit").attr("name", "repository").attr("type", "text")
346 close("div")
347 open("div")
348 add("label").attr("id", "lbbranchGit").text("Branch")
349 add("input").attr("id", "branchGit").attr("name", "branch").attr("type", "text")
350 close("div")
351 open("div")
352 add("a").attr("id", "signIn").text("Sign In")
353 close("div")
354 close("div")
355 close("li")
356 close("ul")
357 close("nav")
358 close("header")
359 end
360
361 redef fun body do
362 super
363 open("div").add_class("page")
364 open("div").add_class("content fullpage")
365 add("h1").text("Full Index")
366 add_content
367 close("div")
368 close("div")
369 add("footer").text("Nit standard library. Version jenkins-component=stdlib-19.")
370 end
371
372 fun add_content do
373 module_column
374 classes_column
375 properties_column
376 end
377
378 # Add to content modules column
379 fun module_column do
380 var ls = new List[nullable MModule]
381 var sorted = mmodules
382 var sorterp = new ComparableSorter[MModule]
383 sorterp.sort(sorted)
384 open("article").add_class("modules filterable")
385 add("h2").text("Modules")
386 open("ul")
387 for mmodule in sorted do
388 if mmodule.public_owner != null and not ls.has(mmodule.public_owner) then
389 ls.add(mmodule.public_owner)
390 open("li")
391 add("a").attr("href", "{mmodule.public_owner.name}.html").text(mmodule.public_owner.name)
392 close("li")
393 end
394 end
395 close("ul")
396 close("article")
397 end
398
399 # Add to content classes modules
400 fun classes_column do
401 var sorted = mmodules.first.imported_mclasses.to_a
402 var sorterp = new ComparableSorter[MClass]
403 sorterp.sort(sorted)
404 open("article").add_class("classes filterable")
405 add("h2").text("Classes")
406 open("ul")
407
408 for mclass in sorted do
409 open("li")
410 add("a").attr("href", "{mclass.name}.html").text(mclass.name)
411 close("li")
412 end
413
414 close("ul")
415 close("article")
416 end
417
418 # Insert the properties column of fullindex page
419 fun properties_column do
420 open("article").add_class("properties filterable")
421 add("h2").text("Properties")
422 open("ul")
423 var sorted_imported = mmodules.first.imported_methods.to_a
424 var sorted_redef = mmodules.first.redef_methods.to_a
425 var sorterp = new ComparableSorter[MProperty]
426 sorterp.sort(sorted_imported)
427 sorterp.sort(sorted_redef)
428
429 for method in sorted_imported do
430 if method.visibility is none_visibility or method.visibility is intrude_visibility then continue
431 open("li").add_class("intro")
432 add("span").attr("title", "introduction").text("I")
433 add_html("&nbsp;")
434 add("a").attr("href", "{method.local_class.name}.html").attr("title", "").text("{method.name} ({method.local_class.name})")
435 close("li")
436 end
437
438 for method in sorted_redef do
439 if method.visibility is none_visibility or method.visibility is intrude_visibility then continue
440 open("li").add_class("redef")
441 add("span").attr("title", "redefinition").text("R")
442 add_html("&nbsp;")
443 add("a").attr("href", "{method.local_class.name}.html").attr("title", "").text("{method.name} ({method.local_class.name})")
444 close("li")
445 end
446
447 close("ul")
448 close("article")
449 end
450
451 end
452
453 class NitdocModules
454 super NitdocPage
455
456 var amodule: AModule
457 var modulename: String
458 init with(amodule: AModule) do
459 self.amodule = amodule
460 self.modulename = self.amodule.mmodule.name
461 opt_nodot = false
462 destinationdir = ""
463 end
464
465 redef fun head do
466 super
467 add("title").text("{modulename} module | {amodule.short_comment}")
468 end
469
470 redef fun header do
471 open("header")
472 open("nav").add_class("main")
473 open("ul")
474 open("li")
475 add_html("<a href=\"index.html\">Overview</a>")
476 close("li")
477 add("li").add_class("current").text(modulename)
478 open("li")
479 add_html("<a href=\"full-index.html\" >Full Index</a>")
480 close("li")
481 open("li").attr("id", "liGitHub")
482 open("a").add_class("btn").attr("id", "logGitHub")
483 add("img").attr("id", "imgGitHub").attr("src", "resources/icons/github-icon.png")
484 close("a")
485 open("div").add_class("popover bottom")
486 add("div").add_class("arrow").text(" ")
487 open("div").add_class("githubTitle")
488 add("h3").text("Github Sign In")
489 close("div")
490 open("div")
491 add("label").attr("id", "lbloginGit").text("Username")
492 add("input").attr("id", "loginGit").attr("name", "login").attr("type", "text")
493 open("label").attr("id", "logginMessage").text("Hello ")
494 open("a").attr("id", "githubAccount")
495 add("strong").attr("id", "nickName").text(" ")
496 close("a")
497 close("label")
498 close("div")
499 open("div")
500 add("label").attr("id", "lbpasswordGit").text("Password")
501 add("input").attr("id", "passwordGit").attr("name", "password").attr("type", "password")
502 open("div").attr("id", "listBranches")
503 add("label").attr("id", "lbBranches").text("Branch")
504 add("select").add_class("dropdown").attr("id", "dropBranches").attr("name", "dropBranches").attr("tabindex", "1").text(" ")
505 close("div")
506 close("div")
507 open("div")
508 add("label").attr("id", "lbrepositoryGit").text("Repository")
509 add("input").attr("id", "repositoryGit").attr("name", "repository").attr("type", "text")
510 close("div")
511 open("div")
512 add("label").attr("id", "lbbranchGit").text("Branch")
513 add("input").attr("id", "branchGit").attr("name", "branch").attr("type", "text")
514 close("div")
515 open("div")
516 add("a").attr("id", "signIn").text("Sign In")
517 close("div")
518 close("div")
519 close("li")
520 close("ul")
521 close("nav")
522 close("header")
523 end
524
525 redef fun body do
526 super
527 open("div").add_class("page")
528 menu
529 add_content
530 close("div")
531 add("footer").text("Nit standard library. Version jenkins-component=stdlib-19.")
532 end
533
534 # Insert all tags in content part
535 fun add_content do
536 open("div").add_class("content")
537 add("h1").text(modulename)
538 add("div").add_class("subtitle").text("module {modulename}")
539 module_comment
540 classes
541 properties
542 close("div")
543 end
544
545 # Insert module comment in the content
546 fun module_comment do
547 var doc = amodule.comment
548 open("div").attr("id", "description")
549 add("pre").add_class("text_label").text(doc)
550 add("textarea").add_class("edit").attr("rows", "1").attr("cols", "76").attr("id", "fileContent").text(" ")
551 add("a").attr("id", "cancelBtn").text("Cancel")
552 add("a").attr("id", "commitBtn").text("Commit")
553 add("pre").add_class("text_label").attr("id", "preSave").attr("type", "2")
554 close("div")
555 end
556
557 fun menu do
558 var mmodule = amodule.mmodule
559 open("div").add_class("menu")
560 open("nav")
561 add("h3").text("Module Hierarchy").attr("style","cursor: pointer;")
562 if mmodule.in_importation.direct_greaters.length > 0 then
563 add_html("<h4>All dependencies</h4><ul>")
564 for m in mmodule.in_importation.direct_greaters do
565 if m == mmodule or mmodule == m.public_owner then continue
566 open("li")
567 add("a").attr("href", "{m.name}.html").text(m.name)
568 close("li")
569 end
570 add_html("</ul>")
571 end
572 if mmodule.in_importation.greaters.length > 0 then
573 add_html("<h4>All clients</h4><ul>")
574 for m in mmodule.in_importation.greaters do
575 if m == mmodule then continue
576 open("li")
577 add("a").attr("href", "{m.name}.html").text(m.name)
578 close("li")
579 end
580 add_html("</ul>")
581 end
582 close("nav")
583 if mmodule.in_nesting.direct_greaters.length > 0 then
584 open("nav")
585 add("h3").text("Nested Modules").attr("style","cursor: pointer;")
586 open("ul")
587 for m in mmodule.in_nesting.direct_greaters do
588 open("li")
589 add("a").attr("href", "{m.name}.html").text(m.name)
590 close("li")
591 end
592 close("ul")
593
594 close("nav")
595 end
596 close("div")
597 end
598
599 fun classes do
600 open("div").add_class("module")
601 open("article").add_class("classes filterable")
602 add("h2").text("Classes")
603 open("ul")
604 for c, state in amodule.mmodule.mclasses do
605 var name = c.name
606 if state == c_is_intro or state == c_is_imported then
607 open("li").add_class("intro")
608 add("span").attr("title", "introduced in this module").text("I ")
609 else
610 open("li").add_class("redef")
611 add("span").attr("title", "refined in this module").text("R ")
612 end
613 add("a").attr("href", "{name}.html").text(name)
614 close("li")
615 end
616 close("ul")
617 close("article")
618 close("div")
619 end
620
621 fun properties do
622 open("article").add_class("properties filterable")
623 add_html("<h2>Properties</h2>")
624 open("ul")
625 for method in amodule.mmodule.imported_methods do
626 if method.visibility is none_visibility or method.visibility is intrude_visibility then continue
627 open("li").add_class("intro")
628 add("span").attr("title", "introduction").text("I")
629 add_html("&nbsp;")
630 add("a").attr("href", "{method.local_class.name}.html").attr("title", "").text("{method.name} ({method.local_class.name})")
631 close("li")
632 end
633
634 for method in amodule.mmodule.redef_methods do
635 if method.visibility is none_visibility or method.visibility is intrude_visibility then continue
636 open("li").add_class("redef")
637 add("span").attr("title", "redefinition").text("R")
638 add_html("&nbsp;")
639 add("a").attr("href", "{method.local_class.name}.html").attr("title", "").text("{method.name} ({method.local_class.name})")
640 close("li")
641 end
642
643 close("ul")
644 close("article")
645 end
646
647 end
648
649 # Nit Standard Library
650 class NitdocMClasses
651 super NitdocPage
652
653 var mclass: MClass
654 var aclassdef: AClassdef
655 var stdclassdef: nullable AStdClassdef
656 var public_owner: nullable MModule
657
658 init with(mclass: MClass, aclassdef: AClassdef, source: nullable String) do
659 self.mclass = mclass
660 self.aclassdef = aclassdef
661 if aclassdef isa AStdClassdef then self.stdclassdef = aclassdef
662 self.public_owner = mclass.intro_mmodule.public_owner
663 opt_nodot = false
664 destinationdir = ""
665 self.source = source
666 end
667
668 redef fun head do
669 super
670 add("title").text("{self.mclass.name} class | Nit Standard Library")
671 end
672
673 redef fun header do
674 open("header")
675 open("nav").add_class("main")
676 open("ul")
677 open("li")
678 add_html("<a href=\"index.html\">Overview</a>")
679 close("li")
680 open("li")
681 if public_owner is null then
682 add_html("<a href=\"{mclass.intro_mmodule.name}.html\">{mclass.intro_mmodule.name}</a>")
683 else
684 add_html("<a href=\"{public_owner.name}.html\">{public_owner.name}</a>")
685 end
686 close("li")
687 add("li").add_class("current").text(mclass.name)
688 open("li")
689 add_html("<a href=\"full-index.html\" >Full Index</a>")
690 close("li")
691 open("li").attr("id", "liGitHub")
692 open("a").add_class("btn").attr("id", "logGitHub")
693 add("img").attr("id", "imgGitHub").attr("src", "resources/icons/github-icon.png")
694 close("a")
695 open("div").add_class("popover bottom")
696 add("div").add_class("arrow").text(" ")
697 open("div").add_class("githubTitle")
698 add("h3").text("Github Sign In")
699 close("div")
700 open("div")
701 add("label").attr("id", "lbloginGit").text("Username")
702 add("input").attr("id", "loginGit").attr("name", "login").attr("type", "text")
703 open("label").attr("id", "logginMessage").text("Hello ")
704 open("a").attr("id", "githubAccount")
705 add("strong").attr("id", "nickName").text(" ")
706 close("a")
707 close("label")
708 close("div")
709 open("div")
710 add("label").attr("id", "lbpasswordGit").text("Password")
711 add("input").attr("id", "passwordGit").attr("name", "password").attr("type", "password")
712 open("div").attr("id", "listBranches")
713 add("label").attr("id", "lbBranches").text("Branch")
714 add("select").add_class("dropdown").attr("id", "dropBranches").attr("name", "dropBranches").attr("tabindex", "1").text(" ")
715 close("div")
716 close("div")
717 open("div")
718 add("label").attr("id", "lbrepositoryGit").text("Repository")
719 add("input").attr("id", "repositoryGit").attr("name", "repository").attr("type", "text")
720 close("div")
721 open("div")
722 add("label").attr("id", "lbbranchGit").text("Branch")
723 add("input").attr("id", "branchGit").attr("name", "branch").attr("type", "text")
724 close("div")
725 open("div")
726 add("a").attr("id", "signIn").text("Sign In")
727 close("div")
728 close("div")
729 close("li")
730 close("ul")
731 close("nav")
732 close("header")
733 end
734
735 redef fun body do
736 super
737 open("div").add_class("page")
738 add_content
739 close("div")
740 add("footer").text("Nit standard library. Version jenkins-component=stdlib-19.")
741 end
742
743 # Insert all tags in content part
744 fun add_content do
745 open("div").add_class("menu")
746 properties_column
747 inheritance_column
748 close("div")
749 open("div").add_class("content")
750 content
751 close("div")
752 end
753
754 fun properties_column do
755 open("nav").add_class("properties filterable")
756 add("h3").text("Properties")
757
758 if mclass.virtual_types.length > 0 then
759 add("h4").text("Virtual Types")
760 open("ul")
761 for prop in mclass.virtual_types do
762 add_html("<li class=\"redef\"><span title=\"Redefined\">R</span><a href=\"{prop.link_anchor}\">{prop.name}</a></li>")
763 end
764 close("ul")
765 end
766 if mclass.constructors.length > 0 then
767 add("h4").text("Constructors")
768 open("ul")
769 for prop in mclass.constructors do
770 add_html("<li class=\"intro\"><span title=\"Introduced\">I</span><a href=\"{prop.link_anchor}\">{prop.name}</a></li>")
771 end
772 close("ul")
773 end
774 add("h4").text("Methods")
775 open("ul")
776 if mclass.intro_methods.length > 0 then
777 for prop in mclass.intro_methods do
778 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>")
779 end
780 end
781 if mclass.inherited_methods.length > 0 then
782 for prop in mclass.inherited_methods do
783 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>")
784 end
785 end
786 if mclass.redef_methods.length > 0 then
787 for prop in mclass.redef_methods do
788 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>")
789 end
790 end
791 close("ul")
792 close("nav")
793 end
794
795 fun inheritance_column do
796 open("nav")
797 add("h3").text("Inheritance")
798 if mclass.parents.length > 0 then
799 add("h4").text("Superclasses")
800 open("ul")
801 for sup in mclass.parents do add_html("<li><a href=\"{sup.name}.html\">{sup.name}</a></li>")
802 close("ul")
803 end
804
805 if mclass.descendants.length is 0 then
806 add("h4").text("No Known Subclasses")
807 else if mclass.descendants.length <= 100 then
808 add("h4").text("Subclasses")
809 open("ul")
810 for sub in mclass.descendants do add_html("<li><a href=\"{sub.name}\">{sub.name}</a></li>")
811 close("ul")
812 else if mclass.children.length <= 100 then
813 add("h4").text("Direct Subclasses Only")
814 open("ul")
815 for sub in mclass.children do add_html("<li><a href=\"{sub.name}\">{sub.name}</a></li>")
816 close("ul")
817 else
818 add("h4").text("Too much Subclasses to list")
819 end
820 close("nav")
821 end
822
823 fun content do
824 var subtitle = ""
825 var lmmodule = new List[MModule]
826 # Insert the subtitle part
827 add("h1").text(mclass.name)
828 open("div").add_class("subtitle")
829 if mclass.visibility is none_visibility then subtitle += "private "
830 subtitle += "{mclass.kind} <a href=\"{mclass.public_owner.name}.html\">{mclass.public_owner.name}</a>::{mclass.name}"
831 add_html(subtitle)
832 close("div")
833 add_html("<div style=\"float: right;\"><a id=\"lblDiffCommit\"></a></div>")
834 # We add the class description
835 open("section").add_class("description")
836 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>")
837 close("section")
838 open("section").add_class("concerns")
839 add("h2").add_class("section-header").text("Concerns")
840 open("ul")
841 for owner, childs in mclass.concerns do
842 open("li")
843 add_html("<a href=\"#MOD_{owner.name}\">{owner.name}</a>: {owner.amodule.short_comment}")
844 if not childs is null then
845 open("ul")
846 for child in childs.as(not null) do add_html("<li><a href=\"#MOD_{child.name}\">{child.name}</a>: {child.amodule.short_comment} </li>")
847 close("ul")
848 end
849 close("li")
850 end
851 close("ul")
852 close("section")
853 # Insert virtual types if there is almost one
854 if mclass.virtual_types.length > 0 or (stdclassdef != null and stdclassdef.n_formaldefs.length > 0) then
855 open("section").add_class("types")
856 add("h2").text("Formal and Virtual Types")
857 if mclass.virtual_types.length > 0 then for prop in mclass.virtual_types do description(prop)
858 if stdclassdef.n_formaldefs.length > 0 then
859 for prop in stdclassdef.n_formaldefs do
860 open("article").attr("id", "FT_Object_{prop.collect_text}")
861 open("h3").add_class("signature").text("{prop.collect_text}: nullable ")
862 add_html("<a title=\"The root of the class hierarchy.\" href=\"Object.html\">Object</a>")
863 close("h3")
864 add_html("<div class=\"info\">formal generic type</div>")
865 close("article")
866 end
867 end
868 close("section")
869 end
870 # Insert constructors if there is almost one
871 if mclass.constructors.length > 0 then
872 open("section").add_class("constructors")
873 add("h2").add_class("section-header").text("Constructors")
874 for prop in mclass.constructors do description(prop)
875 close("section")
876 end
877 open("section").add_class("methods")
878 add("h2").add_class("section-header").text("Methods")
879 for mmodule, mmethods in mclass.all_methods do
880 add_html("<a id=\"MOD_{mmodule.name}\"></a>")
881 if mmodule != mclass.intro_mmodule and mmodule != mclass.public_owner then
882 if mclass.has_mmodule(mmodule) then
883 add_html("<p class=\"concern-doc\">{mmodule.name}: {mmodule.amodule.short_comment}</p>")
884 else
885 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>")
886 end
887 end
888 for prop in mmethods do description(prop)
889 end
890 # Insert inherited methods
891 if mclass.inherited_methods.length > 0 then
892 add("h3").text("Inherited Methods")
893 for i_mclass, methods in mclass.inherited do
894 open("p")
895 add_html("Defined in <a href=\"{i_mclass.name}.html\">{i_mclass.name}</a>: ")
896 for method in methods do
897 add_html("<a href=\"{method.link_anchor}\">{method.name}</a>")
898 if method != methods.last then add_html(", ")
899 end
900 close("p")
901 end
902 end
903 close("section")
904 end
905
906 # Insert description tags for 'prop'
907 fun description(prop: MProperty) do
908 open("article").add_class("fun public {if prop.is_redef then "redef" else ""}").attr("id", "{prop.anchor}")
909 var sign = prop.name
910 if prop.apropdef != null then sign += prop.apropdef.signature
911 add_html("<h3 class=\"signature\">{sign}</h3>")
912 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>")
913
914 open("div").add_class("description")
915 if prop.apropdef is null or prop.apropdef.comment == "" then
916 add_html("<a class=\"newComment\" title=\"32\" tag=\"\">New Comment</a>")
917 else
918 add_html("<pre class=\"text_label\" title=\"\" name=\"\" tag=\"\" type=\"1\">{prop.apropdef.comment}</pre>")
919 end
920 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>")
921 open("p")
922 if prop.local_class != mclass then add_html("inherited from {prop.local_class.intro_mmodule.name} ")
923 #TODO display show code if doc github
924 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)}.")
925
926 for parent in mclass.parents do
927 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>.")
928 end
929 close("p")
930 close("div")
931
932 close("article")
933 end
934
935 end
936
937 class NitdocPage
938 super HTMLPage
939
940 var opt_nodot: Bool
941 var destinationdir : String
942 var source: nullable String
943
944 redef fun head do
945 add("meta").attr("charset", "utf-8")
946 add("script").attr("type", "text/javascript").attr("src", "scripts/jquery-1.7.1.min.js")
947 add("script").attr("type", "text/javascript").attr("src", "quicksearch-list.js")
948 add("script").attr("type", "text/javascript").attr("src", "scripts/js-facilities.js")
949 add("link").attr("rel", "stylesheet").attr("href", "styles/main.css").attr("type", "text/css").attr("media", "screen")
950 end
951
952 redef fun body do header
953 fun header do end
954
955 # Generate a clickable graphviz image using a dot content
956 fun generate_dot(dot: String, name: String, alt: String) do
957 if opt_nodot then return
958 var file = new OFStream.open("{self.destinationdir}/{name}.dot")
959 file.write(dot)
960 file.close
961 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 ; \}")
962 open("article").add_class("graph")
963 add("img").attr("src", "{name}.png").attr("usemap", "#{name}").attr("style", "margin:auto").attr("alt", "{alt}")
964 close("article")
965 var fmap = new IFStream.open("{self.destinationdir}/{name}.map")
966 add_html(fmap.read_all)
967 fmap.close
968 end
969
970 # Add a (source) link fo a given location
971 fun show_source(l: Location): String
972 do
973 if source == null then
974 return "({l.file.filename.simplify_path})"
975 else
976 # THIS IS JUST UGLY ! (but there is no replace yet)
977 var x = source.split_with("%f")
978 source = x.join(l.file.filename.simplify_path)
979 x = source.split_with("%l")
980 source = x.join(l.line_start.to_s)
981 x = source.split_with("%L")
982 source = x.join(l.line_end.to_s)
983 return " (<a href=\"{source.to_s}\">show code</a>)"
984 end
985 end
986
987 end
988
989 redef class AModule
990 private fun comment: String do
991 var ret = ""
992 if n_moduledecl is null or n_moduledecl.n_doc is null then ret
993 if n_moduledecl.n_doc is null then return ""
994 for t in n_moduledecl.n_doc.n_comment do
995 ret += "{t.text.replace("# ", "")}"
996 end
997 return ret
998 end
999
1000 private fun short_comment: String do
1001 var ret = ""
1002 if n_moduledecl != null and n_moduledecl.n_doc != null then
1003 var txt = n_moduledecl.n_doc.n_comment.first.text
1004 txt = txt.replace("# ", "")
1005 txt = txt.replace("\n", "")
1006 ret += txt
1007 end
1008 return ret
1009 end
1010 end
1011
1012 redef class MModule
1013
1014 super Comparable
1015 redef type OTHER: MModule
1016 redef fun <(other: OTHER): Bool do return self.name < other.name
1017
1018 var amodule: nullable AModule
1019
1020 # Get the list of all methods in a module
1021 fun imported_methods: Set[MMethod] do
1022 var methods = new HashSet[MMethod]
1023 for mclass in imported_mclasses do
1024 for method in mclass.intro_methods do
1025 methods.add(method)
1026 end
1027 end
1028 return methods
1029 end
1030
1031 # Get the list aof all refined methods in a module
1032 fun redef_methods: Set[MMethod] do
1033 var methods = new HashSet[MMethod]
1034 for mclass in redef_mclasses do
1035 for method in mclass.intro_methods do
1036 methods.add(method)
1037 end
1038 end
1039 return methods
1040 end
1041 end
1042
1043 redef class MProperty
1044
1045 super Comparable
1046 redef type OTHER: MProperty
1047 redef fun <(other: OTHER): Bool do return self.name < other.name
1048
1049 var is_redef: Bool
1050 var apropdef: nullable APropdef
1051
1052 redef init(intro_mclassdef: MClassDef, name: String, visibility: MVisibility)
1053 do
1054 super
1055 is_redef = false
1056 end
1057
1058 fun local_class: MClass do
1059 var classdef = self.intro_mclassdef
1060 return classdef.mclass
1061 end
1062
1063 fun class_text: String do
1064 return local_class.name
1065 end
1066
1067 fun link_anchor: String do
1068 return "{class_text}.html#{anchor}"
1069 end
1070
1071 fun anchor: String do
1072 return "PROP_{c_name}"
1073 end
1074
1075 end
1076
1077 redef class MClass
1078
1079 super Comparable
1080 redef type OTHER: MClass
1081 redef fun <(other: OTHER): Bool do return self.name < other.name
1082
1083 # Associate all MMethods to each MModule concerns
1084 fun all_methods: HashMap[MModule, Set[MMethod]] do
1085 var hm = new HashMap[MModule, Set[MMethod]]
1086 for mmodule, childs in concerns do
1087 if not hm.has_key(mmodule) then hm[mmodule] = new HashSet[MMethod]
1088 for prop in intro_methods do
1089 if mmodule == prop.intro_mclassdef.mmodule then
1090 prop.is_redef = false
1091 hm[mmodule].add(prop)
1092 end
1093 end
1094 for prop in redef_methods do
1095 if mmodule == prop.intro_mclassdef.mmodule then
1096 prop.is_redef = true
1097 hm[mmodule].add(prop)
1098 end
1099 end
1100
1101 if childs != null then
1102 for child in childs do
1103 if not hm.has_key(child) then hm[child] = new HashSet[MMethod]
1104 for prop in intro_methods do
1105 if child == prop.intro_mclassdef.mmodule then
1106 prop.is_redef = false
1107 hm[child].add(prop)
1108 end
1109 end
1110 for prop in redef_methods do
1111 if child == prop.intro_mclassdef.mmodule then
1112 prop.is_redef = true
1113 hm[child].add(prop)
1114 end
1115 end
1116 end
1117 end
1118 end
1119 return hm
1120 end
1121
1122 fun public_owner: MModule do
1123 var owner = intro_mmodule
1124 if owner.public_owner is null then
1125 return owner
1126 else
1127 return owner.public_owner.as(not null)
1128 end
1129 end
1130
1131 # Associate Amodule to all MModule concern by 'self'
1132 fun amodule(amodules: HashMap[MModule, AModule]) do
1133 for owner, childs in concerns do
1134 if childs != null then for child in childs do child.amodule = amodules[child]
1135 owner.amodule = amodules[owner]
1136 end
1137 end
1138
1139 # Associate MClass to all MMethod include in 'inherited_methods'
1140 fun inherited: HashMap[MClass, Set[MMethod]] do
1141 var hm = new HashMap[MClass, Set[MMethod]]
1142 for method in inherited_methods do
1143 var mclass = method.intro_mclassdef.mclass
1144 if not hm.has_key(mclass) then hm[mclass] = new HashSet[MMethod]
1145 hm[mclass].add(method)
1146 end
1147 return hm
1148 end
1149
1150 # Return true if MModule concern contain subMModule
1151 fun has_mmodule(sub: MModule): Bool do
1152 for mmodule, childs in concerns do
1153 if childs is null then continue
1154 if childs.has(sub) then return true
1155 end
1156 return false
1157 end
1158
1159 fun mmethod(mprop2npropdef: Map[MProperty, APropdef]) do
1160 for const in constructors do
1161 if mprop2npropdef.has_key(const)then
1162 const.apropdef = mprop2npropdef[const].as(AMethPropdef)
1163 end
1164 end
1165
1166 for intro in intro_methods do
1167 if mprop2npropdef.has_key(intro)then
1168 if mprop2npropdef[intro] isa AMethPropdef then intro.apropdef = mprop2npropdef[intro].as(AMethPropdef)
1169 end
1170 end
1171
1172 for rd in redef_methods do
1173 if mprop2npropdef.has_key(rd)then
1174 if mprop2npropdef[rd] isa AMethPropdef then rd.apropdef = mprop2npropdef[rd].as(AMethPropdef)
1175 end
1176 end
1177 end
1178
1179 fun link_anchor: String do
1180 return "{name}.html"
1181 end
1182
1183 end
1184
1185 redef class AStdClassdef
1186 private fun comment: String do
1187 var ret = ""
1188 if n_doc != null then
1189 for t in n_doc.n_comment do
1190 var txt = t.text.replace("# ", "")
1191 txt = txt.replace("#", "")
1192 ret += "{txt}"
1193 end
1194 end
1195 return ret
1196 end
1197
1198 private fun short_comment: String do
1199 var ret = ""
1200 if n_doc != null then
1201 var txt = n_doc.n_comment.first.text
1202 txt = txt.replace("# ", "")
1203 txt = txt.replace("\n", "")
1204 ret += txt
1205 end
1206 return ret
1207 end
1208 end
1209
1210 redef class ASignature
1211 redef fun to_s do
1212 #TODO closures
1213 var ret = ""
1214 if not n_params.is_empty then
1215 ret = "{ret}({n_params.join(", ")})"
1216 end
1217 if n_type != null and n_type.to_s != "" then ret += " {n_type.to_s}"
1218 return ret
1219 end
1220 end
1221
1222 redef class AParam
1223 redef fun to_s do
1224 var ret = "{n_id.text}"
1225 if n_type != null then
1226 ret = "{ret}: {n_type.to_s}"
1227 if n_dotdotdot != null then ret = "{ret}..."
1228 end
1229 return ret
1230 end
1231 end
1232
1233 redef class AType
1234 redef fun to_s do
1235 var ret = "<a href=\"{n_id.text}.html\">{n_id.text}</a>"
1236 if n_kwnullable != null then ret = "nullable {ret}"
1237 if not n_types.is_empty then ret = "{ret}[{n_types.join(", ")}]"
1238 return ret
1239 end
1240 end
1241
1242 redef class APropdef
1243 private fun short_comment: String is abstract
1244 private fun signature: String is abstract
1245 private fun comment: String is abstract
1246 end
1247
1248 redef class AAttrPropdef
1249 redef fun short_comment do
1250 var ret = ""
1251 if n_doc != null then
1252 var txt = n_doc.n_comment.first.text
1253 txt = txt.replace("# ", "")
1254 txt = txt.replace("\n", "")
1255 ret += txt
1256 end
1257 return ret
1258 end
1259 end
1260
1261 redef class AMethPropdef
1262 redef fun short_comment do
1263 var ret = ""
1264 if n_doc != null then
1265 var txt = n_doc.n_comment.first.text
1266 txt = txt.replace("# ", "")
1267 txt = txt.replace("\n", "")
1268 ret += txt
1269 end
1270 return ret
1271 end
1272
1273 redef fun signature: String do
1274 var sign = ""
1275 if n_signature != null then sign = " {n_signature.to_s}"
1276 return sign
1277 end
1278
1279 redef private fun comment: String do
1280 var ret = ""
1281 if n_doc != null then
1282 for t in n_doc.n_comment do
1283 var txt = t.text.replace("# ", "")
1284 txt = txt.replace("#", "")
1285 ret += "{txt}"
1286 end
1287 end
1288 return ret
1289 end
1290 end
1291
1292 redef class MClassDef
1293 private fun namespace(mclass: MClass): String do
1294
1295 if mmodule.public_owner is null then
1296 return "{mmodule.full_name}::{mclass.name}"
1297 else if mclass is self.mclass then
1298 return "{mmodule.public_owner.name}::{mclass.name}"
1299 else
1300 return "{mmodule.public_owner.name}::<a href=\"{mclass.name}.html\">{mclass.name}</a>"
1301 end
1302 end
1303 end
1304
1305 redef class Set[E]
1306 fun last: E do
1307 return to_a[length-1]
1308 end
1309 end
1310
1311 # Create a tool context to handle options and paths
1312 var toolcontext = new ToolContext
1313
1314 # Here we launch the nit index
1315 var nitdoc = new Nitdoc(toolcontext)
1316 nitdoc.start