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