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