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