ni_nitdoc: Inform whoses modules are concerned in a class
[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
32 private var opt_dir = new OptionString("Directory where doc is generated", "-d", "--dir")
33 private var opt_source = new OptionString("What link for source (%f for filename, %l for first line, %L for last line)", "--source")
34 private var opt_sharedir = new OptionString("Directory containing the nitdoc files", "--sharedir")
35 private var opt_nodot = new OptionBool("Do not generate graphes with graphiviz", "--no-dot")
36
37 init(toolcontext: ToolContext) do
38 # We need a model to collect stufs
39 self.toolcontext = toolcontext
40 self.arguments = toolcontext.option_context.rest
41 toolcontext.option_context.add_option(opt_dir)
42 toolcontext.option_context.add_option(opt_source)
43 toolcontext.option_context.add_option(opt_sharedir)
44 toolcontext.option_context.add_option(opt_nodot)
45 process_options
46
47 if arguments.length < 1 then
48 toolcontext.option_context.usage
49 exit(1)
50 end
51
52 model = new Model
53 modelbuilder = new ModelBuilder(model, toolcontext)
54
55 # Here we load an process std modules
56 var mmodules = modelbuilder.parse_and_build([arguments.first])
57 if mmodules.is_empty then return
58 modelbuilder.full_propdef_semantic_analysis
59 assert mmodules.length == 1
60 self.mainmodule = mmodules.first
61 end
62
63 private fun process_options do
64 if not opt_dir.value is null then
65 destinationdir = opt_dir.value
66 else
67 destinationdir = "nitdoc_directory"
68 end
69 if not opt_sharedir.value is null then
70 sharedir = opt_sharedir.value
71 else
72 var dir = "NIT_DIR".environ
73 if dir.is_empty then
74 dir = "{sys.program_name.dirname}/../share/nitdoc"
75 else
76 dir = "{dir}/share/nitdoc"
77 end
78 sharedir = dir
79 if sharedir is null then
80 print "Error: Cannot locate nitdoc share files. Uses --sharedir or envvar NIT_DIR"
81 abort
82 end
83 dir = "{sharedir.to_s}/scripts/js-facilities.js"
84 if sharedir is null then
85 print "Error: Invalid nitdoc share files. Check --sharedir or envvar NIT_DIR"
86 abort
87 end
88 end
89 end
90
91 fun start do
92 if arguments.length == 1 then
93 # Create destination dir if it's necessary
94 if not destinationdir.file_exists then destinationdir.mkdir
95 sys.system("cp -r {sharedir.to_s}/* {destinationdir.to_s}/")
96 overview
97 fullindex
98 modules
99 classes
100 end
101 end
102
103 fun overview do
104 var overviewpage = new NitdocOverview.with(modelbuilder.nmodules, self.opt_nodot.value, destinationdir.to_s)
105 overviewpage.save("{destinationdir.to_s}/index.html")
106 end
107
108 fun fullindex do
109 var fullindex = new NitdocFullindex.with(model.mmodules)
110 fullindex.save("{destinationdir.to_s}/full-index.html")
111 end
112
113 fun modules do
114 for mod in modelbuilder.nmodules do
115 var modulepage = new NitdocModules.with(mod)
116 modulepage.save("{destinationdir.to_s}/{mod.mmodule.name}.html")
117 end
118 end
119
120 fun classes do
121 for amodule in modelbuilder.nmodules do
122 for mclass, aclassdef in amodule.mclass2nclassdef do
123 mclass.amodule(modelbuilder.mmodule2nmodule)
124 var classpage = new NitdocMClasses.with(mclass, aclassdef)
125 classpage.save("{destinationdir.to_s}/{mclass.name}.html")
126 end
127 end
128 end
129
130 end
131
132 class NitdocOverview
133 super NitdocPage
134
135 var amodules: Array[AModule]
136
137 # Init with Array[AModule] to get all ifnormations about each MModule containt in a program
138 # opt_nodot to inform about the graph gen
139 # destination: to know where will be saved dot files
140 init with(modules: Array[AModule], opt_nodot: Bool, destination: String) do
141 self.amodules = modules
142 self.opt_nodot = opt_nodot
143 self.destinationdir = destination
144 end
145
146 redef fun head do
147 super
148 add("title").text("Overview | Nit Standard Library")
149 end
150
151 redef fun header do
152 open("header")
153 open("nav").add_class("main")
154 open("ul")
155 add("li").add_class("current").text("Overview")
156 open("li")
157 add_html("<a href=\"full-index.html\">Full Index</a>")
158 close("li")
159 open("li").attr("id", "liGitHub")
160 open("a").add_class("btn").attr("id", "logGitHub")
161 add("img").attr("id", "imgGitHub").attr("src", "resources/icons/github-icon.png")
162 close("a")
163 open("div").add_class("popover bottom")
164 add("div").add_class("arrow").text(" ")
165 open("div").add_class("githubTitle")
166 add("h3").text("Github Sign In")
167 close("div")
168 open("div")
169 add("label").attr("id", "lbloginGit").text("Username")
170 add("input").attr("id", "loginGit").attr("name", "login").attr("type", "text")
171 open("label").attr("id", "logginMessage").text("Hello ")
172 open("a").attr("id", "githubAccount")
173 add("strong").attr("id", "nickName").text(" ")
174 close("a")
175 close("label")
176 close("div")
177 open("div")
178 add("label").attr("id", "lbpasswordGit").text("Password")
179 add("input").attr("id", "passwordGit").attr("name", "password").attr("type", "password")
180 open("div").attr("id", "listBranches")
181 add("label").attr("id", "lbBranches").text("Branch")
182 add("select").add_class("dropdown").attr("id", "dropBranches").attr("name", "dropBranches").attr("tabindex", "1").text(" ")
183 close("div")
184 close("div")
185 open("div")
186 add("label").attr("id", "lbrepositoryGit").text("Repository")
187 add("input").attr("id", "repositoryGit").attr("name", "repository").attr("type", "text")
188 close("div")
189 open("div")
190 add("label").attr("id", "lbbranchGit").text("Branch")
191 add("input").attr("id", "branchGit").attr("name", "branch").attr("type", "text")
192 close("div")
193 open("div")
194 add("a").attr("id", "signIn").text("Sign In")
195 close("div")
196 close("div")
197 close("li")
198 close("ul")
199 close("nav")
200 close("header")
201 end
202
203 redef fun body do
204 super
205 open("div").add_class("page")
206 open("div").add_class("content fullpage")
207 add("h1").text("Nit Standard Library")
208 open("article").add_class("overview")
209 add_html("<p>Documentation for the standard library of Nit<br />Version jenkins-component=stdlib-19<br />Date: TODAY</p>")
210 close("article")
211 open("article").add_class("overview")
212 add("h2").text("Modules")
213 open("ul")
214 add_modules
215 close("ul")
216 process_generate_dot
217 close("article")
218 close("div")
219 close("div")
220 add("footer").text("Nit standard library. Version jenkins-component=stdlib-19.")
221 end
222
223 fun add_modules do
224 var ls = new List[nullable MModule]
225 for amodule in amodules do
226 var mmodule = amodule.mmodule.public_owner
227 if mmodule != null and not ls.has(mmodule) then
228 open("li")
229 add("a").attr("href", "{mmodule.name}.html").text("{mmodule.to_s} ")
230 add_html(amodule.comment)
231 close("li")
232 ls.add(mmodule)
233 end
234 end
235 end
236
237 fun process_generate_dot do
238 var op = new Buffer
239 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")
240 for amodule in amodules do
241 op.append("\"{amodule.mmodule.name}\"[URL=\"{amodule.mmodule.name}.html\"];\n")
242 for mmodule2 in amodule.mmodule.in_importation.direct_greaters do
243 op.append("\"{amodule.mmodule.name}\"->\"{mmodule2.name}\";\n")
244 end
245 end
246 op.append("\}\n")
247 generate_dot(op.to_s, "dep", "Modules hierarchy")
248 end
249
250 end
251
252 class NitdocFullindex
253 super NitdocPage
254
255 var mmodules: Array[MModule]
256
257 init with(mmodules: Array[MModule]) do
258 self.mmodules = mmodules
259 opt_nodot = false
260 destinationdir = ""
261 end
262
263 redef fun head do
264 super
265 add("title").text("Full Index | Nit Standard Library")
266 end
267
268 redef fun header do
269 open("header")
270 open("nav").add_class("main")
271 open("ul")
272 open("li")
273 add_html("<a href=\"index.html\">Overview</a>")
274 close("li")
275 add("li").add_class("current").text("Full Index")
276 open("li").attr("id", "liGitHub")
277 open("a").add_class("btn").attr("id", "logGitHub")
278 add("img").attr("id", "imgGitHub").attr("src", "resources/icons/github-icon.png")
279 close("a")
280 open("div").add_class("popover bottom")
281 add("div").add_class("arrow").text(" ")
282 open("div").add_class("githubTitle")
283 add("h3").text("Github Sign In")
284 close("div")
285 open("div")
286 add("label").attr("id", "lbloginGit").text("Username")
287 add("input").attr("id", "loginGit").attr("name", "login").attr("type", "text")
288 open("label").attr("id", "logginMessage").text("Hello ")
289 open("a").attr("id", "githubAccount")
290 add("strong").attr("id", "nickName").text(" ")
291 close("a")
292 close("label")
293 close("div")
294 open("div")
295 add("label").attr("id", "lbpasswordGit").text("Password")
296 add("input").attr("id", "passwordGit").attr("name", "password").attr("type", "password")
297 open("div").attr("id", "listBranches")
298 add("label").attr("id", "lbBranches").text("Branch")
299 add("select").add_class("dropdown").attr("id", "dropBranches").attr("name", "dropBranches").attr("tabindex", "1").text(" ")
300 close("div")
301 close("div")
302 open("div")
303 add("label").attr("id", "lbrepositoryGit").text("Repository")
304 add("input").attr("id", "repositoryGit").attr("name", "repository").attr("type", "text")
305 close("div")
306 open("div")
307 add("label").attr("id", "lbbranchGit").text("Branch")
308 add("input").attr("id", "branchGit").attr("name", "branch").attr("type", "text")
309 close("div")
310 open("div")
311 add("a").attr("id", "signIn").text("Sign In")
312 close("div")
313 close("div")
314 close("li")
315 close("ul")
316 close("nav")
317 close("header")
318 end
319
320 redef fun body do
321 super
322 open("div").add_class("page")
323 open("div").add_class("content fullpage")
324 add("h1").text("Full Index")
325 add_content
326 close("div")
327 close("div")
328 add("footer").text("Nit standard library. Version jenkins-component=stdlib-19.")
329 end
330
331 fun add_content do
332 module_column
333 classes_column
334 properties_column
335 end
336
337 # Add to content modules column
338 fun module_column do
339 var ls = new List[nullable MModule]
340 open("article").add_class("modules filterable")
341 add("h2").text("Modules")
342 open("ul")
343 for mmodule in mmodules do
344 if mmodule.public_owner != null and not ls.has(mmodule.public_owner) then
345 ls.add(mmodule.public_owner)
346 open("li")
347 add("a").attr("href", "{mmodule.public_owner.name}.html").text(mmodule.public_owner.name)
348 close("li")
349 end
350 end
351 close("ul")
352 close("article")
353 end
354
355 # Add to content classes modules
356 fun classes_column do
357 open("article").add_class("classes filterable")
358 add("h2").text("Classes")
359 open("ul")
360
361 for mclass in mmodules.first.imported_mclasses do
362 open("li")
363 add("a").attr("href", "{mclass.name}.html").text(mclass.name)
364 close("li")
365 end
366
367 close("ul")
368 close("article")
369 end
370
371 # Insert the properties column of fullindex page
372 fun properties_column do
373 open("article").add_class("properties filterable")
374 add("h2").text("Properties")
375 open("ul")
376
377 for method in mmodules.first.imported_methods do
378 if method.visibility is none_visibility or method.visibility is intrude_visibility then continue
379 open("li").add_class("intro")
380 add("span").attr("title", "introduction").text("I")
381 add_html("&nbsp;")
382 add("a").attr("href", "{method.local_class.name}.html").attr("title", "").text("{method.name} ({method.local_class.name})")
383 close("li")
384 end
385
386 for method in mmodules.first.redef_methods do
387 if method.visibility is none_visibility or method.visibility is intrude_visibility then continue
388 open("li").add_class("redef")
389 add("span").attr("title", "redefinition").text("R")
390 add_html("&nbsp;")
391 add("a").attr("href", "{method.local_class.name}.html").attr("title", "").text("{method.name} ({method.local_class.name})")
392 close("li")
393 end
394
395 close("ul")
396 close("article")
397 end
398
399 end
400
401 class NitdocModules
402 super NitdocPage
403
404 var amodule: AModule
405 var modulename: String
406 init with(amodule: AModule) do
407 self.amodule = amodule
408 self.modulename = self.amodule.mmodule.name
409 opt_nodot = false
410 destinationdir = ""
411 end
412
413 redef fun head do
414 super
415 add("title").text("{modulename} module | {amodule.short_comment}")
416 end
417
418 redef fun header do
419 open("header")
420 open("nav").add_class("main")
421 open("ul")
422 open("li")
423 add_html("<a href=\"index.html\">Overview</a>")
424 close("li")
425 add("li").add_class("current").text(modulename)
426 open("li")
427 add_html("<a href=\"full-index.html\" >Full Index</a>")
428 close("li")
429 open("li").attr("id", "liGitHub")
430 open("a").add_class("btn").attr("id", "logGitHub")
431 add("img").attr("id", "imgGitHub").attr("src", "resources/icons/github-icon.png")
432 close("a")
433 open("div").add_class("popover bottom")
434 add("div").add_class("arrow").text(" ")
435 open("div").add_class("githubTitle")
436 add("h3").text("Github Sign In")
437 close("div")
438 open("div")
439 add("label").attr("id", "lbloginGit").text("Username")
440 add("input").attr("id", "loginGit").attr("name", "login").attr("type", "text")
441 open("label").attr("id", "logginMessage").text("Hello ")
442 open("a").attr("id", "githubAccount")
443 add("strong").attr("id", "nickName").text(" ")
444 close("a")
445 close("label")
446 close("div")
447 open("div")
448 add("label").attr("id", "lbpasswordGit").text("Password")
449 add("input").attr("id", "passwordGit").attr("name", "password").attr("type", "password")
450 open("div").attr("id", "listBranches")
451 add("label").attr("id", "lbBranches").text("Branch")
452 add("select").add_class("dropdown").attr("id", "dropBranches").attr("name", "dropBranches").attr("tabindex", "1").text(" ")
453 close("div")
454 close("div")
455 open("div")
456 add("label").attr("id", "lbrepositoryGit").text("Repository")
457 add("input").attr("id", "repositoryGit").attr("name", "repository").attr("type", "text")
458 close("div")
459 open("div")
460 add("label").attr("id", "lbbranchGit").text("Branch")
461 add("input").attr("id", "branchGit").attr("name", "branch").attr("type", "text")
462 close("div")
463 open("div")
464 add("a").attr("id", "signIn").text("Sign In")
465 close("div")
466 close("div")
467 close("li")
468 close("ul")
469 close("nav")
470 close("header")
471 end
472
473 redef fun body do
474 super
475 open("div").add_class("page")
476 menu
477 add_content
478 close("div")
479 add("footer").text("Nit standard library. Version jenkins-component=stdlib-19.")
480 end
481
482 # Insert all tags in content part
483 fun add_content do
484 open("div").add_class("content")
485 add("h1").text(modulename)
486 add("div").add_class("subtitle").text("module {modulename}")
487 module_comment
488 classes
489 properties
490 close("div")
491 end
492
493 # Insert module comment in the content
494 fun module_comment do
495 var doc = amodule.comment
496 open("div").attr("id", "description")
497 add("pre").add_class("text_label").text(doc)
498 add("textarea").add_class("edit").attr("rows", "1").attr("cols", "76").attr("id", "fileContent").text(" ")
499 add("a").attr("id", "cancelBtn").text("Cancel")
500 add("a").attr("id", "commitBtn").text("Commit")
501 add("pre").add_class("text_label").attr("id", "preSave").attr("type", "2")
502 close("div")
503 end
504
505 fun menu do
506 var mmodule = amodule.mmodule
507 open("div").add_class("menu")
508 open("nav")
509 add("h3").text("Module Hierarchy").attr("style","cursor: pointer;")
510 if mmodule.in_importation.direct_greaters.length > 0 then
511 add_html("<h4>All dependencies</h4><ul>")
512 for m in mmodule.in_importation.direct_greaters do
513 if m == mmodule or mmodule == m.public_owner then continue
514 open("li")
515 add("a").attr("href", "{m.name}.html").text(m.name)
516 close("li")
517 end
518 add_html("</ul>")
519 end
520 if mmodule.in_importation.greaters.length > 0 then
521 add_html("<h4>All clients</h4><ul>")
522 for m in mmodule.in_importation.greaters do
523 if m == mmodule then continue
524 open("li")
525 add("a").attr("href", "{m.name}.html").text(m.name)
526 close("li")
527 end
528 add_html("</ul>")
529 end
530 close("nav")
531 if mmodule.in_nesting.direct_greaters.length > 0 then
532 open("nav")
533 add("h3").text("Nested Modules").attr("style","cursor: pointer;")
534 open("ul")
535 for m in mmodule.in_nesting.direct_greaters do
536 open("li")
537 add("a").attr("href", "{m.name}.html").text(m.name)
538 close("li")
539 end
540 close("ul")
541
542 close("nav")
543 end
544 close("div")
545 end
546
547 fun classes do
548 open("div").add_class("module")
549 open("article").add_class("classes filterable")
550 add("h2").text("Classes")
551 open("ul")
552 for c, state in amodule.mmodule.mclasses do
553 var name = c.name
554 if state == c_is_intro or state == c_is_imported then
555 open("li").add_class("intro")
556 add("span").attr("title", "introduced in this module").text("I ")
557 else
558 open("li").add_class("redef")
559 add("span").attr("title", "refined in this module").text("R ")
560 end
561 add("a").attr("href", "{name}.html").text(name)
562 close("li")
563 end
564 close("ul")
565 close("article")
566 close("div")
567 end
568
569 fun properties do
570 open("article").add_class("properties filterable")
571 add_html("<h2>Properties</h2>")
572 open("ul")
573 for method in amodule.mmodule.imported_methods do
574 if method.visibility is none_visibility or method.visibility is intrude_visibility then continue
575 open("li").add_class("intro")
576 add("span").attr("title", "introduction").text("I")
577 add_html("&nbsp;")
578 add("a").attr("href", "{method.local_class.name}.html").attr("title", "").text("{method.name} ({method.local_class.name})")
579 close("li")
580 end
581
582 for method in amodule.mmodule.redef_methods do
583 if method.visibility is none_visibility or method.visibility is intrude_visibility then continue
584 open("li").add_class("redef")
585 add("span").attr("title", "redefinition").text("R")
586 add_html("&nbsp;")
587 add("a").attr("href", "{method.local_class.name}.html").attr("title", "").text("{method.name} ({method.local_class.name})")
588 close("li")
589 end
590
591 close("ul")
592 close("article")
593 end
594
595 end
596
597 # Nit Standard Library
598 class NitdocMClasses
599 super NitdocPage
600
601 var mclass: MClass
602 var aclassdef: AClassdef
603 var stdclassdef: nullable AStdClassdef
604 var public_owner: nullable MModule
605
606 init with(mclass: MClass, aclassdef: AClassdef) do
607 self.mclass = mclass
608 self.aclassdef = aclassdef
609 if aclassdef isa AStdClassdef then self.stdclassdef = aclassdef
610 self.public_owner = mclass.intro_mmodule.public_owner
611 opt_nodot = false
612 destinationdir = ""
613 end
614
615 redef fun head do
616 super
617 add("title").text("{self.mclass.name} class | Nit Standard Library")
618 end
619
620 redef fun header do
621 open("header")
622 open("nav").add_class("main")
623 open("ul")
624 open("li")
625 add_html("<a href=\"index.html\">Overview</a>")
626 close("li")
627 open("li")
628 if public_owner is null then
629 add_html("<a href=\"{mclass.intro_mmodule.name}.html\">{mclass.intro_mmodule.name}</a>")
630 else
631 add_html("<a href=\"{public_owner.name}.html\">{public_owner.name}</a>")
632 end
633 close("li")
634 add("li").add_class("current").text(mclass.name)
635 open("li")
636 add_html("<a href=\"full-index.html\" >Full Index</a>")
637 close("li")
638 open("li").attr("id", "liGitHub")
639 open("a").add_class("btn").attr("id", "logGitHub")
640 add("img").attr("id", "imgGitHub").attr("src", "resources/icons/github-icon.png")
641 close("a")
642 open("div").add_class("popover bottom")
643 add("div").add_class("arrow").text(" ")
644 open("div").add_class("githubTitle")
645 add("h3").text("Github Sign In")
646 close("div")
647 open("div")
648 add("label").attr("id", "lbloginGit").text("Username")
649 add("input").attr("id", "loginGit").attr("name", "login").attr("type", "text")
650 open("label").attr("id", "logginMessage").text("Hello ")
651 open("a").attr("id", "githubAccount")
652 add("strong").attr("id", "nickName").text(" ")
653 close("a")
654 close("label")
655 close("div")
656 open("div")
657 add("label").attr("id", "lbpasswordGit").text("Password")
658 add("input").attr("id", "passwordGit").attr("name", "password").attr("type", "password")
659 open("div").attr("id", "listBranches")
660 add("label").attr("id", "lbBranches").text("Branch")
661 add("select").add_class("dropdown").attr("id", "dropBranches").attr("name", "dropBranches").attr("tabindex", "1").text(" ")
662 close("div")
663 close("div")
664 open("div")
665 add("label").attr("id", "lbrepositoryGit").text("Repository")
666 add("input").attr("id", "repositoryGit").attr("name", "repository").attr("type", "text")
667 close("div")
668 open("div")
669 add("label").attr("id", "lbbranchGit").text("Branch")
670 add("input").attr("id", "branchGit").attr("name", "branch").attr("type", "text")
671 close("div")
672 open("div")
673 add("a").attr("id", "signIn").text("Sign In")
674 close("div")
675 close("div")
676 close("li")
677 close("ul")
678 close("nav")
679 close("header")
680 end
681
682 redef fun body do
683 super
684 open("div").add_class("page")
685 add_content
686 close("div")
687 add("footer").text("Nit standard library. Version jenkins-component=stdlib-19.")
688 end
689
690 # Insert all tags in content part
691 fun add_content do
692 open("div").add_class("menu")
693 properties_column
694 inheritance_column
695 close("div")
696 open("div").add_class("content")
697 content
698 close("div")
699 end
700
701 fun properties_column do
702 open("nav").add_class("properties filterable")
703 add("h3").text("Properties")
704
705 if mclass.virtual_types.length > 0 then
706 add("h4").text("Virtual Types")
707 open("ul")
708 for prop in mclass.virtual_types do
709 add_html("<li class=\"redef\"><span title=\"Redefined\">R</span><a href=\"{prop.link_anchor}\">{prop.name}</a></li>")
710 end
711 close("ul")
712 end
713 if mclass.constructors.length > 0 then
714 add("h4").text("Constructors")
715 open("ul")
716 for prop in mclass.constructors do
717 add_html("<li class=\"intro\"><span title=\"Introduced\">I</span><a href=\"{prop.link_anchor}\">{prop.name}</a></li>")
718 end
719 close("ul")
720 end
721 add("h4").text("Methods")
722 open("ul")
723 if mclass.intro_methods.length > 0 then
724 for prop in mclass.intro_methods do
725 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>")
726 end
727 end
728 if mclass.inherited_methods.length > 0 then
729 for prop in mclass.inherited_methods do
730 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>")
731 end
732 end
733 if mclass.redef_methods.length > 0 then
734 for prop in mclass.redef_methods do
735 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>")
736 end
737 end
738 close("ul")
739 close("nav")
740 end
741
742 fun inheritance_column do
743 open("nav")
744 add("h3").text("Inheritance")
745 if mclass.parents.length > 0 then
746 add("h4").text("Superclasses")
747 open("ul")
748 for sup in mclass.parents do add_html("<li><a href=\"{sup.name}.html\">{sup.name}</a></li>")
749 close("ul")
750 end
751
752 if mclass.descendants.length is 0 then
753 add("h4").text("No Known Subclasses")
754 else if mclass.descendants.length <= 100 then
755 add("h4").text("Subclasses")
756 open("ul")
757 for sub in mclass.descendants do add_html("<li><a href=\"{sub.name}\">{sub.name}</a></li>")
758 close("ul")
759 else if mclass.children.length <= 100 then
760 add("h4").text("Direct Subclasses Only")
761 open("ul")
762 for sub in mclass.children do add_html("<li><a href=\"{sub.name}\">{sub.name}</a></li>")
763 close("ul")
764 else
765 add("h4").text("Too much Subclasses to list")
766 end
767 close("nav")
768 end
769
770 fun content do
771 var subtitle = ""
772 var lmmodule = new List[MModule]
773 # Insert the subtitle part
774 add("h1").text(mclass.name)
775 open("div").add_class("subtitle")
776 if mclass.visibility is none_visibility then subtitle += "private "
777 subtitle += "{mclass.kind} <a href=\"{mclass.public_owner.name}.html\">{mclass.public_owner.name}</a>::{mclass.name}"
778 add_html(subtitle)
779 close("div")
780 add_html("<div style=\"float: right;\"><a id=\"lblDiffCommit\"></a></div>")
781 # We add the class description
782 open("section").add_class("description")
783 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>")
784 close("section")
785 open("section").add_class("concerns")
786 add("h2").add_class("section-header").text("Concerns")
787 open("ul")
788 for owner, childs in mclass.concerns do
789 open("li")
790 add_html("<a href=\"#MOD_{owner.name}\">{owner.name}</a>: {owner.amodule.short_comment}")
791 if not childs is null then
792 open("ul")
793 for child in childs.as(not null) do add_html("<li><a href=\"#MOD_{child.name}\">{child.name}</a>: {child.amodule.short_comment} </li>")
794 close("ul")
795 end
796 close("li")
797 end
798 close("ul")
799 close("section")
800 end
801
802 end
803
804 class NitdocPage
805 super HTMLPage
806
807 var opt_nodot: Bool
808 var destinationdir : String
809
810 redef fun head do
811 add("meta").attr("charset", "utf-8")
812 add("script").attr("type", "text/javascript").attr("src", "scripts/jquery-1.7.1.min.js")
813 add("script").attr("type", "text/javascript").attr("src", "quicksearch-list.js")
814 add("script").attr("type", "text/javascript").attr("src", "scripts/js-facilities.js")
815 add("link").attr("rel", "stylesheet").attr("href", "styles/main.css").attr("type", "text/css").attr("media", "screen")
816 end
817
818 redef fun body do header
819 fun header do end
820
821 # Generate a clickable graphviz image using a dot content
822 fun generate_dot(dot: String, name: String, alt: String) do
823 if opt_nodot then return
824 var file = new OFStream.open("{self.destinationdir}/{name}.dot")
825 file.write(dot)
826 file.close
827 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 ; \}")
828 open("article").add_class("graph")
829 add("img").attr("src", "{name}.png").attr("usemap", "#{name}").attr("style", "margin:auto").attr("alt", "{alt}")
830 close("article")
831 var fmap = new IFStream.open("{self.destinationdir}/{name}.map")
832 add_html(fmap.read_all)
833 fmap.close
834 end
835
836 end
837
838 redef class AModule
839 private fun comment: String do
840 var ret = ""
841 if n_moduledecl is null or n_moduledecl.n_doc is null then ret
842 if n_moduledecl.n_doc is null then return ""
843 for t in n_moduledecl.n_doc.n_comment do
844 ret += "{t.text.replace("# ", "")}"
845 end
846 return ret
847 end
848
849 private fun short_comment: String do
850 var ret = ""
851 if n_moduledecl != null and n_moduledecl.n_doc != null then
852 var txt = n_moduledecl.n_doc.n_comment.first.text
853 txt = txt.replace("# ", "")
854 txt = txt.replace("\n", "")
855 ret += txt
856 end
857 return ret
858 end
859 end
860
861 redef class MModule
862
863 var amodule: nullable AModule
864
865 # Get the list of all methods in a module
866 fun imported_methods: Set[MMethod] do
867 var methods = new HashSet[MMethod]
868 for mclass in imported_mclasses do
869 for method in mclass.intro_methods do
870 methods.add(method)
871 end
872 end
873 return methods
874 end
875
876 # Get the list aof all refined methods in a module
877 fun redef_methods: Set[MMethod] do
878 var methods = new HashSet[MMethod]
879 for mclass in redef_mclasses do
880 for method in mclass.intro_methods do
881 methods.add(method)
882 end
883 end
884 return methods
885 end
886 end
887
888 redef class MProperty
889
890 var is_redef: Bool
891 var apropdef: nullable APropdef
892
893 redef init(intro_mclassdef: MClassDef, name: String, visibility: MVisibility)
894 do
895 super
896 is_redef = false
897 end
898
899 fun local_class: MClass do
900 var classdef = self.intro_mclassdef
901 return classdef.mclass
902 end
903
904 fun class_text: String do
905 return local_class.name
906 end
907
908 fun link_anchor: String do
909 return "{class_text}.html#{anchor}"
910 end
911
912 fun anchor: String do
913 return "PROP_{c_name}"
914 end
915
916 end
917
918 redef class MClass
919
920 # Associate all MMethods to each MModule concerns
921 fun all_methods: HashMap[MModule, Set[MMethod]] do
922 var hm = new HashMap[MModule, Set[MMethod]]
923 for mmodule, childs in concerns do
924 if not hm.has_key(mmodule) then hm[mmodule] = new HashSet[MMethod]
925 for prop in intro_methods do
926 if mmodule == prop.intro_mclassdef.mmodule then
927 prop.is_redef = false
928 hm[mmodule].add(prop)
929 end
930 end
931 for prop in redef_methods do
932 if mmodule == prop.intro_mclassdef.mmodule then
933 prop.is_redef = true
934 hm[mmodule].add(prop)
935 end
936 end
937
938 if childs != null then
939 for child in childs do
940 if not hm.has_key(child) then hm[child] = new HashSet[MMethod]
941 for prop in intro_methods do
942 if child == prop.intro_mclassdef.mmodule then
943 prop.is_redef = false
944 hm[child].add(prop)
945 end
946 end
947 for prop in redef_methods do
948 if child == prop.intro_mclassdef.mmodule then
949 prop.is_redef = true
950 hm[child].add(prop)
951 end
952 end
953 end
954 end
955 end
956 return hm
957 end
958
959 fun public_owner: MModule do
960 var owner = intro_mmodule
961 if owner.public_owner is null then
962 return owner
963 else
964 return owner.public_owner.as(not null)
965 end
966 end
967
968 # Associate Amodule to all MModule concern by 'self'
969 fun amodule(amodules: HashMap[MModule, AModule]) do
970 for owner, childs in concerns do
971 if childs != null then for child in childs do child.amodule = amodules[child]
972 owner.amodule = amodules[owner]
973 end
974 end
975
976 end
977
978 redef class AStdClassdef
979 private fun comment: String do
980 var ret = ""
981 if n_doc != null then
982 for t in n_doc.n_comment do
983 var txt = t.text.replace("# ", "")
984 txt = txt.replace("#", "")
985 ret += "{txt}"
986 end
987 end
988 return ret
989 end
990
991 private fun short_comment: String do
992 var ret = ""
993 if n_doc != null then
994 var txt = n_doc.n_comment.first.text
995 txt = txt.replace("# ", "")
996 txt = txt.replace("\n", "")
997 ret += txt
998 end
999 return ret
1000 end
1001 end
1002
1003 redef class ASignature
1004 redef fun to_s do
1005 #TODO closures
1006 var ret = ""
1007 if not n_params.is_empty then
1008 ret = "{ret}({n_params.join(", ")})"
1009 end
1010 if n_type != null and n_type.to_s != "" then ret += " {n_type.to_s}"
1011 return ret
1012 end
1013 end
1014
1015 redef class AParam
1016 redef fun to_s do
1017 var ret = "{n_id.text}"
1018 if n_type != null then
1019 ret = "{ret}: {n_type.to_s}"
1020 if n_dotdotdot != null then ret = "{ret}..."
1021 end
1022 return ret
1023 end
1024 end
1025
1026 redef class AType
1027 redef fun to_s do
1028 var ret = "<a href=\"{n_id.text}.html\">{n_id.text}</a>"
1029 if n_kwnullable != null then ret = "nullable {ret}"
1030 if not n_types.is_empty then ret = "{ret}[{n_types.join(", ")}]"
1031 return ret
1032 end
1033 end
1034
1035 redef class APropdef
1036 private fun short_comment: String is abstract
1037 private fun signature: String is abstract
1038 private fun comment: String is abstract
1039 end
1040
1041 redef class AAttrPropdef
1042 redef fun short_comment do
1043 var ret = ""
1044 if n_doc != null then
1045 var txt = n_doc.n_comment.first.text
1046 txt = txt.replace("# ", "")
1047 txt = txt.replace("\n", "")
1048 ret += txt
1049 end
1050 return ret
1051 end
1052 end
1053
1054 redef class AMethPropdef
1055 redef fun short_comment do
1056 var ret = ""
1057 if n_doc != null then
1058 var txt = n_doc.n_comment.first.text
1059 txt = txt.replace("# ", "")
1060 txt = txt.replace("\n", "")
1061 ret += txt
1062 end
1063 return ret
1064 end
1065
1066 redef fun signature: String do
1067 var sign = ""
1068 if n_signature != null then sign = " {n_signature.to_s}"
1069 return sign
1070 end
1071
1072 redef private fun comment: String do
1073 var ret = ""
1074 if n_doc != null then
1075 for t in n_doc.n_comment do
1076 var txt = t.text.replace("# ", "")
1077 txt = txt.replace("#", "")
1078 ret += "{txt}"
1079 end
1080 end
1081 return ret
1082 end
1083 end
1084
1085 # Create a tool context to handle options and paths
1086 var toolcontext = new ToolContext
1087 toolcontext.process_options
1088
1089 # Here we launch the nit index
1090 var nitdoc = new Nitdoc(toolcontext)
1091 nitdoc.start