ni_nitdoc: Adding show source
[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 var amodule: nullable AModule
1004
1005 # Get the list of all methods in a module
1006 fun imported_methods: Set[MMethod] do
1007 var methods = new HashSet[MMethod]
1008 for mclass in imported_mclasses do
1009 for method in mclass.intro_methods do
1010 methods.add(method)
1011 end
1012 end
1013 return methods
1014 end
1015
1016 # Get the list aof all refined methods in a module
1017 fun redef_methods: Set[MMethod] do
1018 var methods = new HashSet[MMethod]
1019 for mclass in redef_mclasses do
1020 for method in mclass.intro_methods do
1021 methods.add(method)
1022 end
1023 end
1024 return methods
1025 end
1026 end
1027
1028 redef class MProperty
1029
1030 var is_redef: Bool
1031 var apropdef: nullable APropdef
1032
1033 redef init(intro_mclassdef: MClassDef, name: String, visibility: MVisibility)
1034 do
1035 super
1036 is_redef = false
1037 end
1038
1039 fun local_class: MClass do
1040 var classdef = self.intro_mclassdef
1041 return classdef.mclass
1042 end
1043
1044 fun class_text: String do
1045 return local_class.name
1046 end
1047
1048 fun link_anchor: String do
1049 return "{class_text}.html#{anchor}"
1050 end
1051
1052 fun anchor: String do
1053 return "PROP_{c_name}"
1054 end
1055
1056 end
1057
1058 redef class MClass
1059
1060 # Associate all MMethods to each MModule concerns
1061 fun all_methods: HashMap[MModule, Set[MMethod]] do
1062 var hm = new HashMap[MModule, Set[MMethod]]
1063 for mmodule, childs in concerns do
1064 if not hm.has_key(mmodule) then hm[mmodule] = new HashSet[MMethod]
1065 for prop in intro_methods do
1066 if mmodule == prop.intro_mclassdef.mmodule then
1067 prop.is_redef = false
1068 hm[mmodule].add(prop)
1069 end
1070 end
1071 for prop in redef_methods do
1072 if mmodule == prop.intro_mclassdef.mmodule then
1073 prop.is_redef = true
1074 hm[mmodule].add(prop)
1075 end
1076 end
1077
1078 if childs != null then
1079 for child in childs do
1080 if not hm.has_key(child) then hm[child] = new HashSet[MMethod]
1081 for prop in intro_methods do
1082 if child == prop.intro_mclassdef.mmodule then
1083 prop.is_redef = false
1084 hm[child].add(prop)
1085 end
1086 end
1087 for prop in redef_methods do
1088 if child == prop.intro_mclassdef.mmodule then
1089 prop.is_redef = true
1090 hm[child].add(prop)
1091 end
1092 end
1093 end
1094 end
1095 end
1096 return hm
1097 end
1098
1099 fun public_owner: MModule do
1100 var owner = intro_mmodule
1101 if owner.public_owner is null then
1102 return owner
1103 else
1104 return owner.public_owner.as(not null)
1105 end
1106 end
1107
1108 # Associate Amodule to all MModule concern by 'self'
1109 fun amodule(amodules: HashMap[MModule, AModule]) do
1110 for owner, childs in concerns do
1111 if childs != null then for child in childs do child.amodule = amodules[child]
1112 owner.amodule = amodules[owner]
1113 end
1114 end
1115
1116 # Associate MClass to all MMethod include in 'inherited_methods'
1117 fun inherited: HashMap[MClass, Set[MMethod]] do
1118 var hm = new HashMap[MClass, Set[MMethod]]
1119 for method in inherited_methods do
1120 var mclass = method.intro_mclassdef.mclass
1121 if not hm.has_key(mclass) then hm[mclass] = new HashSet[MMethod]
1122 hm[mclass].add(method)
1123 end
1124 return hm
1125 end
1126
1127 # Return true if MModule concern contain subMModule
1128 fun has_mmodule(sub: MModule): Bool do
1129 for mmodule, childs in concerns do
1130 if childs is null then continue
1131 if childs.has(sub) then return true
1132 end
1133 return false
1134 end
1135
1136 fun mmethod(mprop2npropdef: Map[MProperty, APropdef]) do
1137 for const in constructors do
1138 if mprop2npropdef.has_key(const)then
1139 const.apropdef = mprop2npropdef[const].as(AMethPropdef)
1140 end
1141 end
1142
1143 for intro in intro_methods do
1144 if mprop2npropdef.has_key(intro)then
1145 if mprop2npropdef[intro] isa AMethPropdef then intro.apropdef = mprop2npropdef[intro].as(AMethPropdef)
1146 end
1147 end
1148
1149 for rd in redef_methods do
1150 if mprop2npropdef.has_key(rd)then
1151 if mprop2npropdef[rd] isa AMethPropdef then rd.apropdef = mprop2npropdef[rd].as(AMethPropdef)
1152 end
1153 end
1154 end
1155
1156 fun link_anchor: String do
1157 return "{name}.html"
1158 end
1159
1160 end
1161
1162 redef class AStdClassdef
1163 private fun comment: String do
1164 var ret = ""
1165 if n_doc != null then
1166 for t in n_doc.n_comment do
1167 var txt = t.text.replace("# ", "")
1168 txt = txt.replace("#", "")
1169 ret += "{txt}"
1170 end
1171 end
1172 return ret
1173 end
1174
1175 private fun short_comment: String do
1176 var ret = ""
1177 if n_doc != null then
1178 var txt = n_doc.n_comment.first.text
1179 txt = txt.replace("# ", "")
1180 txt = txt.replace("\n", "")
1181 ret += txt
1182 end
1183 return ret
1184 end
1185 end
1186
1187 redef class ASignature
1188 redef fun to_s do
1189 #TODO closures
1190 var ret = ""
1191 if not n_params.is_empty then
1192 ret = "{ret}({n_params.join(", ")})"
1193 end
1194 if n_type != null and n_type.to_s != "" then ret += " {n_type.to_s}"
1195 return ret
1196 end
1197 end
1198
1199 redef class AParam
1200 redef fun to_s do
1201 var ret = "{n_id.text}"
1202 if n_type != null then
1203 ret = "{ret}: {n_type.to_s}"
1204 if n_dotdotdot != null then ret = "{ret}..."
1205 end
1206 return ret
1207 end
1208 end
1209
1210 redef class AType
1211 redef fun to_s do
1212 var ret = "<a href=\"{n_id.text}.html\">{n_id.text}</a>"
1213 if n_kwnullable != null then ret = "nullable {ret}"
1214 if not n_types.is_empty then ret = "{ret}[{n_types.join(", ")}]"
1215 return ret
1216 end
1217 end
1218
1219 redef class APropdef
1220 private fun short_comment: String is abstract
1221 private fun signature: String is abstract
1222 private fun comment: String is abstract
1223 end
1224
1225 redef class AAttrPropdef
1226 redef fun short_comment do
1227 var ret = ""
1228 if n_doc != null then
1229 var txt = n_doc.n_comment.first.text
1230 txt = txt.replace("# ", "")
1231 txt = txt.replace("\n", "")
1232 ret += txt
1233 end
1234 return ret
1235 end
1236 end
1237
1238 redef class AMethPropdef
1239 redef fun short_comment do
1240 var ret = ""
1241 if n_doc != null then
1242 var txt = n_doc.n_comment.first.text
1243 txt = txt.replace("# ", "")
1244 txt = txt.replace("\n", "")
1245 ret += txt
1246 end
1247 return ret
1248 end
1249
1250 redef fun signature: String do
1251 var sign = ""
1252 if n_signature != null then sign = " {n_signature.to_s}"
1253 return sign
1254 end
1255
1256 redef private fun comment: String do
1257 var ret = ""
1258 if n_doc != null then
1259 for t in n_doc.n_comment do
1260 var txt = t.text.replace("# ", "")
1261 txt = txt.replace("#", "")
1262 ret += "{txt}"
1263 end
1264 end
1265 return ret
1266 end
1267 end
1268
1269 redef class MClassDef
1270 private fun namespace(mclass: MClass): String do
1271
1272 if mmodule.public_owner is null then
1273 return "{mmodule.full_name}::{mclass.name}"
1274 else if mclass is self.mclass then
1275 return "{mmodule.public_owner.name}::{mclass.name}"
1276 else
1277 return "{mmodule.public_owner.name}::<a href=\"{mclass.name}.html\">{mclass.name}</a>"
1278 end
1279 end
1280 end
1281
1282 redef class Set[E]
1283 fun last: E do
1284 return to_a[length-1]
1285 end
1286 end
1287
1288 # Create a tool context to handle options and paths
1289 var toolcontext = new ToolContext
1290
1291 # Here we launch the nit index
1292 var nitdoc = new Nitdoc(toolcontext)
1293 nitdoc.start