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