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