ni_nitdoc: Describe forml/virtual types
[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 # Insert virtual types if there is almost one
801 if mclass.virtual_types.length > 0 or (stdclassdef != null and stdclassdef.n_formaldefs.length > 0) then
802 open("section").add_class("types")
803 add("h2").text("Formal and Virtual Types")
804 if mclass.virtual_types.length > 0 then for prop in mclass.virtual_types do description(prop)
805 if stdclassdef.n_formaldefs.length > 0 then
806 for prop in stdclassdef.n_formaldefs do
807 open("article").attr("id", "FT_Object_{prop.collect_text}")
808 open("h3").add_class("signature").text("{prop.collect_text}: nullable ")
809 add_html("<a title=\"The root of the class hierarchy.\" href=\"Object.html\">Object</a>")
810 close("h3")
811 add_html("<div class=\"info\">formal generic type</div>")
812 close("article")
813 end
814 end
815 close("section")
816 end
817 end
818
819 # Insert description tags for 'prop'
820 fun description(prop: MProperty) do
821 open("article").add_class("fun public {if prop.is_redef then "redef" else ""}").attr("id", "{prop.anchor}")
822 var sign = prop.name
823 if prop.apropdef != null then sign += prop.apropdef.signature
824 add_html("<h3 class=\"signature\">{sign}</h3>")
825 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>")
826
827 open("div").add_class("description")
828 if prop.apropdef is null or prop.apropdef.comment == "" then
829 add_html("<a class=\"newComment\" title=\"32\" tag=\"\">New Comment</a>")
830 else
831 add_html("<pre class=\"text_label\" title=\"\" name=\"\" tag=\"\" type=\"1\">{prop.apropdef.comment}</pre>")
832 end
833 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>")
834 open("p")
835 if prop.local_class != mclass then add_html("inherited from {prop.local_class.intro_mmodule.name} ")
836 #TODO display show code if doc github
837 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>).")
838
839 for parent in mclass.parents do
840 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>.")
841 end
842 close("p")
843 close("div")
844
845 close("article")
846 end
847
848 end
849
850 class NitdocPage
851 super HTMLPage
852
853 var opt_nodot: Bool
854 var destinationdir : String
855
856 redef fun head do
857 add("meta").attr("charset", "utf-8")
858 add("script").attr("type", "text/javascript").attr("src", "scripts/jquery-1.7.1.min.js")
859 add("script").attr("type", "text/javascript").attr("src", "quicksearch-list.js")
860 add("script").attr("type", "text/javascript").attr("src", "scripts/js-facilities.js")
861 add("link").attr("rel", "stylesheet").attr("href", "styles/main.css").attr("type", "text/css").attr("media", "screen")
862 end
863
864 redef fun body do header
865 fun header do end
866
867 # Generate a clickable graphviz image using a dot content
868 fun generate_dot(dot: String, name: String, alt: String) do
869 if opt_nodot then return
870 var file = new OFStream.open("{self.destinationdir}/{name}.dot")
871 file.write(dot)
872 file.close
873 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 ; \}")
874 open("article").add_class("graph")
875 add("img").attr("src", "{name}.png").attr("usemap", "#{name}").attr("style", "margin:auto").attr("alt", "{alt}")
876 close("article")
877 var fmap = new IFStream.open("{self.destinationdir}/{name}.map")
878 add_html(fmap.read_all)
879 fmap.close
880 end
881
882 end
883
884 redef class AModule
885 private fun comment: String do
886 var ret = ""
887 if n_moduledecl is null or n_moduledecl.n_doc is null then ret
888 if n_moduledecl.n_doc is null then return ""
889 for t in n_moduledecl.n_doc.n_comment do
890 ret += "{t.text.replace("# ", "")}"
891 end
892 return ret
893 end
894
895 private fun short_comment: String do
896 var ret = ""
897 if n_moduledecl != null and n_moduledecl.n_doc != null then
898 var txt = n_moduledecl.n_doc.n_comment.first.text
899 txt = txt.replace("# ", "")
900 txt = txt.replace("\n", "")
901 ret += txt
902 end
903 return ret
904 end
905 end
906
907 redef class MModule
908
909 var amodule: nullable AModule
910
911 # Get the list of all methods in a module
912 fun imported_methods: Set[MMethod] do
913 var methods = new HashSet[MMethod]
914 for mclass in imported_mclasses do
915 for method in mclass.intro_methods do
916 methods.add(method)
917 end
918 end
919 return methods
920 end
921
922 # Get the list aof all refined methods in a module
923 fun redef_methods: Set[MMethod] do
924 var methods = new HashSet[MMethod]
925 for mclass in redef_mclasses do
926 for method in mclass.intro_methods do
927 methods.add(method)
928 end
929 end
930 return methods
931 end
932 end
933
934 redef class MProperty
935
936 var is_redef: Bool
937 var apropdef: nullable APropdef
938
939 redef init(intro_mclassdef: MClassDef, name: String, visibility: MVisibility)
940 do
941 super
942 is_redef = false
943 end
944
945 fun local_class: MClass do
946 var classdef = self.intro_mclassdef
947 return classdef.mclass
948 end
949
950 fun class_text: String do
951 return local_class.name
952 end
953
954 fun link_anchor: String do
955 return "{class_text}.html#{anchor}"
956 end
957
958 fun anchor: String do
959 return "PROP_{c_name}"
960 end
961
962 end
963
964 redef class MClass
965
966 # Associate all MMethods to each MModule concerns
967 fun all_methods: HashMap[MModule, Set[MMethod]] do
968 var hm = new HashMap[MModule, Set[MMethod]]
969 for mmodule, childs in concerns do
970 if not hm.has_key(mmodule) then hm[mmodule] = new HashSet[MMethod]
971 for prop in intro_methods do
972 if mmodule == prop.intro_mclassdef.mmodule then
973 prop.is_redef = false
974 hm[mmodule].add(prop)
975 end
976 end
977 for prop in redef_methods do
978 if mmodule == prop.intro_mclassdef.mmodule then
979 prop.is_redef = true
980 hm[mmodule].add(prop)
981 end
982 end
983
984 if childs != null then
985 for child in childs do
986 if not hm.has_key(child) then hm[child] = new HashSet[MMethod]
987 for prop in intro_methods do
988 if child == prop.intro_mclassdef.mmodule then
989 prop.is_redef = false
990 hm[child].add(prop)
991 end
992 end
993 for prop in redef_methods do
994 if child == prop.intro_mclassdef.mmodule then
995 prop.is_redef = true
996 hm[child].add(prop)
997 end
998 end
999 end
1000 end
1001 end
1002 return hm
1003 end
1004
1005 fun public_owner: MModule do
1006 var owner = intro_mmodule
1007 if owner.public_owner is null then
1008 return owner
1009 else
1010 return owner.public_owner.as(not null)
1011 end
1012 end
1013
1014 # Associate Amodule to all MModule concern by 'self'
1015 fun amodule(amodules: HashMap[MModule, AModule]) do
1016 for owner, childs in concerns do
1017 if childs != null then for child in childs do child.amodule = amodules[child]
1018 owner.amodule = amodules[owner]
1019 end
1020 end
1021
1022 end
1023
1024 redef class AStdClassdef
1025 private fun comment: String do
1026 var ret = ""
1027 if n_doc != null then
1028 for t in n_doc.n_comment do
1029 var txt = t.text.replace("# ", "")
1030 txt = txt.replace("#", "")
1031 ret += "{txt}"
1032 end
1033 end
1034 return ret
1035 end
1036
1037 private fun short_comment: String do
1038 var ret = ""
1039 if n_doc != null then
1040 var txt = n_doc.n_comment.first.text
1041 txt = txt.replace("# ", "")
1042 txt = txt.replace("\n", "")
1043 ret += txt
1044 end
1045 return ret
1046 end
1047 end
1048
1049 redef class ASignature
1050 redef fun to_s do
1051 #TODO closures
1052 var ret = ""
1053 if not n_params.is_empty then
1054 ret = "{ret}({n_params.join(", ")})"
1055 end
1056 if n_type != null and n_type.to_s != "" then ret += " {n_type.to_s}"
1057 return ret
1058 end
1059 end
1060
1061 redef class AParam
1062 redef fun to_s do
1063 var ret = "{n_id.text}"
1064 if n_type != null then
1065 ret = "{ret}: {n_type.to_s}"
1066 if n_dotdotdot != null then ret = "{ret}..."
1067 end
1068 return ret
1069 end
1070 end
1071
1072 redef class AType
1073 redef fun to_s do
1074 var ret = "<a href=\"{n_id.text}.html\">{n_id.text}</a>"
1075 if n_kwnullable != null then ret = "nullable {ret}"
1076 if not n_types.is_empty then ret = "{ret}[{n_types.join(", ")}]"
1077 return ret
1078 end
1079 end
1080
1081 redef class APropdef
1082 private fun short_comment: String is abstract
1083 private fun signature: String is abstract
1084 private fun comment: String is abstract
1085 end
1086
1087 redef class AAttrPropdef
1088 redef fun short_comment do
1089 var ret = ""
1090 if n_doc != null then
1091 var txt = n_doc.n_comment.first.text
1092 txt = txt.replace("# ", "")
1093 txt = txt.replace("\n", "")
1094 ret += txt
1095 end
1096 return ret
1097 end
1098 end
1099
1100 redef class AMethPropdef
1101 redef fun short_comment do
1102 var ret = ""
1103 if n_doc != null then
1104 var txt = n_doc.n_comment.first.text
1105 txt = txt.replace("# ", "")
1106 txt = txt.replace("\n", "")
1107 ret += txt
1108 end
1109 return ret
1110 end
1111
1112 redef fun signature: String do
1113 var sign = ""
1114 if n_signature != null then sign = " {n_signature.to_s}"
1115 return sign
1116 end
1117
1118 redef private fun comment: String do
1119 var ret = ""
1120 if n_doc != null then
1121 for t in n_doc.n_comment do
1122 var txt = t.text.replace("# ", "")
1123 txt = txt.replace("#", "")
1124 ret += "{txt}"
1125 end
1126 end
1127 return ret
1128 end
1129 end
1130
1131 redef class MClassDef
1132 private fun namespace(mclass: MClass): String do
1133
1134 if mmodule.public_owner is null then
1135 return "{mmodule.full_name}::{mclass.name}"
1136 else if mclass is self.mclass then
1137 return "{mmodule.public_owner.name}::{mclass.name}"
1138 else
1139 return "{mmodule.public_owner.name}::<a href=\"{mclass.name}.html\">{mclass.name}</a>"
1140 end
1141 end
1142 end
1143
1144 # Create a tool context to handle options and paths
1145 var toolcontext = new ToolContext
1146 toolcontext.process_options
1147
1148 # Here we launch the nit index
1149 var nitdoc = new Nitdoc(toolcontext)
1150 nitdoc.start