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