ni_nitdoc: allow nultiple module documentation
[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
22 class Nitdoc
23 private var toolcontext: ToolContext
24 private var model: Model
25 private var modelbuilder: ModelBuilder
26 private var mainmodule: MModule
27 private var class_hierarchy: POSet[MClass]
28 private var arguments: Array[String]
29 private var output_dir: nullable String
30 private var dot_dir: nullable String
31 private var share_dir: nullable String
32 private var source: nullable String
33
34 private var opt_dir = new OptionString("Directory where doc is generated", "-d", "--dir")
35 private var opt_source = new OptionString("What link for source (%f for filename, %l for first line, %L for last line)", "--source")
36 private var opt_sharedir = new OptionString("Directory containing the nitdoc files", "--sharedir")
37 private var opt_nodot = new OptionBool("Do not generate graphes with graphiviz", "--no-dot")
38
39 init(toolcontext: ToolContext) do
40 # We need a model to collect stufs
41 self.toolcontext = toolcontext
42 self.arguments = toolcontext.option_context.rest
43 toolcontext.option_context.options.clear
44 toolcontext.option_context.add_option(opt_dir)
45 toolcontext.option_context.add_option(opt_source)
46 toolcontext.option_context.add_option(opt_sharedir)
47 toolcontext.option_context.add_option(opt_nodot)
48 toolcontext.process_options
49 process_options
50
51 if arguments.length < 1 then
52 toolcontext.option_context.usage
53 exit(1)
54 end
55
56 model = new Model
57 modelbuilder = new ModelBuilder(model, toolcontext)
58 # Here we load an process all modules passed on the command line
59 var mmodules = modelbuilder.parse_and_build(arguments)
60 modelbuilder.full_propdef_semantic_analysis
61 if mmodules.is_empty then return
62
63 if mmodules.length == 1 then
64 mainmodule = mmodules.first
65 else
66 # We need a main module, so we build it by importing all modules
67 mainmodule = new MModule(model, null, "<main>", new Location(null, 0, 0, 0, 0))
68 mainmodule.set_imported_mmodules(mmodules)
69 end
70 self.class_hierarchy = mainmodule.flatten_mclass_hierarchy
71 end
72
73 private fun process_options do
74 if not opt_dir.value is null then
75 output_dir = opt_dir.value
76 else
77 output_dir = "doc"
78 end
79 if not opt_sharedir.value is null then
80 share_dir = opt_sharedir.value
81 else
82 var dir = "NIT_DIR".environ
83 if dir.is_empty then
84 dir = "{sys.program_name.dirname}/../share/nitdoc"
85 else
86 dir = "{dir}/share/nitdoc"
87 end
88 share_dir = dir
89 if share_dir is null then
90 print "Error: Cannot locate nitdoc share files. Uses --sharedir or envvar NIT_DIR"
91 abort
92 end
93 dir = "{share_dir.to_s}/scripts/js-facilities.js"
94 if share_dir is null then
95 print "Error: Invalid nitdoc share files. Check --sharedir or envvar NIT_DIR"
96 abort
97 end
98 end
99 if not opt_source.value is null then
100 source = ""
101 else
102 source = opt_source.value
103 end
104 end
105
106 fun start do
107 # Create destination dir if it's necessary
108 if not output_dir.file_exists then output_dir.mkdir
109 sys.system("cp -r {share_dir.to_s}/* {output_dir.to_s}/")
110 self.dot_dir = null
111 if not opt_nodot.value then self.dot_dir = output_dir.to_s
112 overview
113 fullindex
114 modules
115 classes
116 quicksearch_list
117 end
118
119 fun overview do
120 var overviewpage = new NitdocOverview(modelbuilder, dot_dir)
121 overviewpage.save("{output_dir.to_s}/index.html")
122 end
123
124 fun fullindex do
125 var fullindex = new NitdocFullindex(self)
126 fullindex.save("{output_dir.to_s}/full-index.html")
127 end
128
129 fun modules do
130 for mmodule in model.mmodules do
131 if mmodule.name == "<main>" then continue
132 var modulepage = new NitdocModule(mmodule, modelbuilder, dot_dir)
133 modulepage.save("{output_dir.to_s}/{mmodule.url}")
134 end
135 end
136
137 fun classes do
138 for mclass in modelbuilder.model.mclasses do
139 var classpage = new NitdocClass(mclass, self, dot_dir, source)
140 classpage.save("{output_dir.to_s}/{mclass.url}")
141 end
142 end
143
144 # Generate QuickSearch file
145 fun quicksearch_list do
146 var file = new OFStream.open("{output_dir.to_s}/quicksearch-list.js")
147 var content = new Buffer
148 content.append("var entries = \{ ")
149
150 for mmodule in model.mmodules do
151 content.append("\"{mmodule.name}\": [")
152 content.append("\{txt: \"{mmodule.name}\", url:\"{mmodule.url}\" \},")
153 content.append("],")
154 end
155 for mclass in model.mclasses do
156 if mclass.visibility <= none_visibility then continue
157 content.append("\"{mclass.name}\": [")
158 content.append("\{txt: \"{mclass.name}\", url:\"{mclass.url}\" \},")
159 content.append("],")
160 end
161 var name2mprops = new HashMap[String, Set[MPropDef]]
162 for mproperty in model.mproperties do
163 if mproperty.visibility <= none_visibility then continue
164 if mproperty isa MAttribute then continue
165 if not name2mprops.has_key(mproperty.name) then name2mprops[mproperty.name] = new HashSet[MPropDef]
166 name2mprops[mproperty.name].add_all(mproperty.mpropdefs)
167 end
168 for mproperty, mpropdefs in name2mprops do
169 content.append("\"{mproperty}\": [")
170 for mpropdef in mpropdefs do
171 content.append("\{txt: \"{mpropdef.full_name}\", url:\"{mpropdef.url}\" \},")
172 end
173 content.append("],")
174 end
175
176 content.append(" \};")
177 file.write(content.to_s)
178 file.close
179 end
180
181 end
182
183 # Nitdoc base page
184 abstract class NitdocPage
185
186 var dot_dir: nullable String
187 var source: nullable String
188
189 init do end
190
191 fun append(str: String) do html.append(str)
192 var html = new Buffer
193
194 fun head do
195 append("<meta charset='utf-8'/>")
196 append("<script type='text/javascript' src='scripts/jquery-1.7.1.min.js'></script>")
197 append("<script type='text/javascript' src='quicksearch-list.js'></script>")
198 append("<script type='text/javascript' src='scripts/js-facilities.js'></script>")
199 append("<link rel='stylesheet' href='styles/main.css' type='text/css' media='screen'/>")
200 end
201
202 fun menu is abstract
203
204 fun header do
205 append("<header>")
206 append("<nav class='main'>")
207 append("<ul>")
208 menu
209 append("<li id='liGitHub'>")
210 append("<a class='btn' id='logGitHub'>")
211 append("<img id='imgGitHub' src='resources/icons/github-icon.png' alt='GitHub'/>")
212 append("</a>")
213 append("<div class='popover bottom'>")
214 append("<div class='arrow'>&nbsp;</div>")
215 append("<div class='githubTitle'>")
216 append("<h3>Github Sign In</h3>")
217 append("</div>")
218 append("<div>")
219 append("<label id='lbloginGit'>Username</label>")
220 append("<input id='loginGit' name='login' type='text'/>")
221 append("<label id='logginMessage'>Hello ")
222 append("<a id='githubAccount'><strong id='nickName'></strong></a>")
223 append("</label>")
224 append("</div>")
225 append("<div>")
226 append("<label id='lbpasswordGit'>Password</label>")
227 append("<input id='passwordGit' name='password' type='password'/>")
228 append("<div id='listBranches'>")
229 append("<label id='lbBranches'>Branch</label>")
230 append("<select class='dropdown' id='dropBranches' name='dropBranches' tabindex='1'></select>")
231 append("</div>")
232 append("</div>")
233 append("<div>")
234 append("<label id='lbrepositoryGit'>Repository</label>")
235 append("<input id='repositoryGit' name='repository' type='text'/>")
236 append("</div>")
237 append("<div>")
238 append("<label id='lbbranchGit'>Branch</label>")
239 append("<input id='branchGit' name='branch' type='text'/>")
240 append("</div>")
241 append("<div>")
242 append("<a id='signIn'>Sign In</a>")
243 append("</div>")
244 append("</div>")
245 append("</li>")
246 append("</ul>")
247 append("</nav>")
248 append("</header>")
249 end
250
251 fun content is abstract
252
253 fun footer do
254 append("<footer>Nit standard library. Version jenkins-component=stdlib-19.</footer>")
255 end
256
257 # Generate a clickable graphviz image using a dot content
258 fun generate_dot(dot: String, name: String, alt: String) do
259 var output_dir = dot_dir
260 if output_dir == null then return
261 var file = new OFStream.open("{output_dir}/{name}.dot")
262 file.write(dot)
263 file.close
264 sys.system("\{ test -f {output_dir}/{name}.png && test -f {output_dir}/{name}.s.dot && diff {output_dir}/{name}.dot {output_dir}/{name}.s.dot >/dev/null 2>&1 ; \} || \{ cp {output_dir}/{name}.dot {output_dir}/{name}.s.dot && dot -Tpng -o{output_dir}/{name}.png -Tcmapx -o{output_dir}/{name}.map {output_dir}/{name}.s.dot ; \}")
265 append("<article class='graph'>")
266 append("<img src='{name}.png' usemap='#{name}' style='margin:auto' alt='{alt}'/>")
267 append("</article>")
268 var fmap = new IFStream.open("{output_dir}/{name}.map")
269 append(fmap.read_all)
270 fmap.close
271 end
272
273 # Add a (source) link for a given location
274 fun show_source(l: Location): String
275 do
276 if source == null then
277 return "({l.file.filename.simplify_path})"
278 else
279 # THIS IS JUST UGLY ! (but there is no replace yet)
280 var x = source.split_with("%f")
281 source = x.join(l.file.filename.simplify_path)
282 x = source.split_with("%l")
283 source = x.join(l.line_start.to_s)
284 x = source.split_with("%L")
285 source = x.join(l.line_end.to_s)
286 return " (<a href=\"{source.to_s}\">show code</a>)"
287 end
288 end
289
290 # Render the page as a html string
291 fun render: String do
292 append("<!DOCTYPE html>")
293 append("<head>")
294 head
295 append("</head>")
296 append("<body>")
297 header
298 append("<div class='page'>")
299 content
300 append("</div>")
301 footer
302 append("</body>")
303 return html.to_s
304 end
305
306 # Save html page in the specified file
307 fun save(file: String) do
308 var out = new OFStream.open(file)
309 out.write(render)
310 out.close
311 end
312 end
313
314 # The overview page
315 class NitdocOverview
316 super NitdocPage
317 private var mbuilder: ModelBuilder
318 private var mmodules = new Array[MModule]
319
320 init(mbuilder: ModelBuilder, dot_dir: nullable String) do
321 self.mbuilder = mbuilder
322 self.dot_dir = dot_dir
323 # get modules
324 var mmodules = new HashSet[MModule]
325 for mmodule in mbuilder.model.mmodules do
326 if mmodule.name == "<main>" then continue
327 var owner = mmodule.public_owner
328 if owner != null then
329 mmodules.add(owner)
330 else
331 mmodules.add(mmodule)
332 end
333 end
334 # sort modules
335 var sorter = new ComparableSorter[MModule]
336 self.mmodules.add_all(mmodules)
337 sorter.sort(self.mmodules)
338 end
339
340 redef fun head do
341 super
342 append("<title>Overview | Nit Standard Library</title>")
343 end
344
345 redef fun menu do
346 append("<li class='current'>Overview</li>")
347 append("<li><a href='full-index.html'>Full Index</a></li>")
348 end
349
350 redef fun content do
351 append("<div class='content fullpage'>")
352 append("<h1>Nit Standard Library</h1>")
353 append("<article class='overview'><p>Documentation for the standard library of Nit<br />Version jenkins-component=stdlib-19<br />Date: TODAY</p></article>")
354 append("<article class='overview'>")
355 # module list
356 append("<h2>Modules</h2>")
357 append("<ul>")
358 for mmodule in mmodules do
359 if mbuilder.mmodule2nmodule.has_key(mmodule) then
360 var amodule = mbuilder.mmodule2nmodule[mmodule]
361 append("<li>{mmodule.link(mbuilder)}&nbsp;{amodule.short_comment}</li>")
362 end
363 end
364 append("</ul>")
365 # module graph
366 process_generate_dot
367 append("</article>")
368 append("</div>")
369 end
370
371 fun process_generate_dot do
372 var op = new Buffer
373 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")
374 for mmodule in mmodules do
375 op.append("\"{mmodule.name}\"[URL=\"{mmodule.url}\"];\n")
376 for imported in mmodule.in_importation.direct_greaters do
377 if imported.direct_owner == null then
378 op.append("\"{mmodule.name}\"->\"{imported.name}\";\n")
379 end
380 end
381 end
382 op.append("\}\n")
383 generate_dot(op.to_s, "dep", "Modules hierarchy")
384 end
385 end
386
387 # The full index page
388 class NitdocFullindex
389 super NitdocPage
390
391 private var nitdoc: Nitdoc
392
393 init(nitdoc: Nitdoc) do
394 self.nitdoc = nitdoc
395 self.dot_dir = null
396 end
397
398 redef fun head do
399 super
400 append("<title>Full Index | Nit Standard Library</title>")
401 end
402
403 redef fun menu do
404 append("<li><a href='index.html'>Overview</a></li>")
405 append("<li class='current'>Full Index</li>")
406 end
407
408 redef fun content do
409 append("<div class='content fullpage'>")
410 append("<h1>Full Index</h1>")
411 module_column
412 classes_column
413 properties_column
414 append("</div>")
415 end
416
417 # Add to content modules column
418 fun module_column do
419 var sorter = new ComparableSorter[MModule]
420 var sorted = new Array[MModule]
421 for mmodule in nitdoc.modelbuilder.model.mmodule_importation_hierarchy do
422 sorted.add(mmodule)
423 end
424 sorter.sort(sorted)
425 append("<article class='modules filterable'>")
426 append("<h2>Modules</h2>")
427 append("<ul>")
428 for mmodule in sorted do
429 append("<li>{mmodule.link(nitdoc.modelbuilder)}</li>")
430 end
431 append("</ul>")
432 append("</article>")
433 end
434
435 # Add to content classes modules
436 fun classes_column do
437 var sorted = nitdoc.modelbuilder.model.mclasses
438 var sorter = new ComparableSorter[MClass]
439 sorter.sort(sorted)
440 append("<article class='modules filterable'>")
441 append("<h2>Classes</h2>")
442 append("<ul>")
443 for mclass in sorted do
444 append("<li>{mclass.link(nitdoc.modelbuilder)}</li>")
445 end
446 append("</ul>")
447 append("</article>")
448 end
449
450 # Insert the properties column of fullindex page
451 fun properties_column do
452 var sorted = nitdoc.modelbuilder.model.mproperties
453 var sorter = new ComparableSorter[MProperty]
454 sorter.sort(sorted)
455 append("<article class='modules filterable'>")
456 append("<h2>Properties</h2>")
457 append("<ul>")
458 for mproperty in sorted do
459 if mproperty isa MAttribute then continue
460 append("<li>{mproperty.intro.link(nitdoc.modelbuilder)} ({mproperty.intro.mclassdef.mclass.link(nitdoc.modelbuilder)})</li>")
461 end
462 append("</ul>")
463 append("</article>")
464 end
465
466 end
467
468 # A module page
469 class NitdocModule
470 super NitdocPage
471
472 private var mmodule: MModule
473 private var mbuilder: ModelBuilder
474
475 init(mmodule: MModule, mbuilder: ModelBuilder, dot_dir: nullable String) do
476 self.mmodule = mmodule
477 self.mbuilder = mbuilder
478 self.dot_dir = dot_dir
479 end
480
481 redef fun head do
482 super
483 if mbuilder.mmodule2nmodule.has_key(mmodule) then
484 var amodule = mbuilder.mmodule2nmodule[mmodule]
485 append("<title>{mmodule.name} module | {amodule.short_comment}</title>")
486 end
487 end
488
489 redef fun menu do
490 append("<li><a href='index.html'>Overview</a></li>")
491 append("<li class='current'>{mmodule.name}</li>")
492 append("<li><a href='full-index.html'>Full Index</a></li>")
493 end
494
495 redef fun content do
496 sidebar
497 append("<div class='content'>")
498 append("<h1>{mmodule.name}</h1>")
499 append("<div class='subtitle'>{mmodule.html_signature(mbuilder)}</div>")
500 append(mmodule.html_full_comment(mbuilder))
501 process_generate_dot
502 classes
503 properties
504 append("</div>")
505 end
506
507 fun process_generate_dot do
508 var name = "dep_{mmodule.name}"
509 var op = new Buffer
510 op.append("digraph {name} \{ 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")
511 for m in mmodule.in_importation.poset do
512 if m.name == "<main>" then continue
513 var public_owner = m.public_owner
514 if public_owner == null then
515 public_owner = m
516 if m == mmodule then
517 op.append("\"{m.name}\"[shape=box,margin=0.03];\n")
518 else
519 op.append("\"{m.name}\"[URL=\"{m.url}\"];\n")
520 end
521 end
522 for imported in m.in_importation.direct_greaters do
523 if imported.name == "<main>" then continue
524 if imported.public_owner == null then
525 op.append("\"{public_owner.name}\"->\"{imported.name}\";\n")
526 end
527 end
528 end
529 op.append("\}\n")
530 generate_dot(op.to_s, name, "Dependency graph for module {mmodule.name}")
531 end
532
533 fun sidebar do
534 append("<div class='menu'>")
535 append("<nav>")
536 append("<h3>Module Hierarchy</h3>")
537 var dependencies = new Array[MModule]
538 for dep in mmodule.in_importation.greaters do
539 if dep == mmodule or dep.public_owner != null then continue
540 dependencies.add(dep)
541 end
542 if dependencies.length > 0 then
543 append("<h4>All dependencies</h4>")
544 display_module_list(dependencies)
545 end
546 var clients = new Array[MModule]
547 for dep in mmodule.in_importation.smallers do
548 if dep == mmodule or dep.public_owner != null then continue
549 clients.add(dep)
550 end
551 if clients.length > 0 then
552 append("<h4>All clients</h4>")
553 display_module_list(clients)
554 end
555 append("</nav>")
556 if mmodule.in_nesting.direct_greaters.length > 0 then
557 append("<nav>")
558 append("<h3>Nested Modules</h3>")
559 display_module_list(mmodule.in_nesting.direct_greaters.to_a)
560 append("</nav>")
561 end
562 append("</div>")
563 end
564
565 private fun display_module_list(list: Array[MModule]) do
566 append("<ul>")
567 var sorter = new ComparableSorter[MModule]
568 sorter.sort(list)
569 for m in list do append("<li>{m.link(mbuilder)}</li>")
570 append("</ul>")
571 end
572
573 # display the class column
574 fun classes do
575 var intro_mclasses = mmodule.intro_mclasses
576 var redef_mclasses = mmodule.redef_mclasses
577 var all_mclasses = new HashSet[MClass]
578 for m in mmodule.in_nesting.greaters do
579 all_mclasses.add_all(m.intro_mclasses)
580 all_mclasses.add_all(m.redef_mclasses)
581 end
582 all_mclasses.add_all(intro_mclasses)
583 all_mclasses.add_all(redef_mclasses)
584
585 var sorted = new Array[MClass]
586 sorted.add_all(all_mclasses)
587 var sorter = new ComparableSorter[MClass]
588 sorter.sort(sorted)
589 append("<div class='module'>")
590 append("<article class='classes filterable'>")
591 append("<h2>Classes</h2>")
592 append("<ul>")
593 for c in sorted do
594 if redef_mclasses.has(c) and c.intro_mmodule.public_owner != mmodule then
595 append("<li class='redef'>")
596 append("<span title='refined in this module'>R </span>")
597 else
598 append("<li class='intro'>")
599 append("<span title='introduced in this module'>I </span>")
600 end
601 append(c.link(mbuilder))
602 append("</li>")
603 end
604 append("</ul>")
605 append("</article>")
606 append("</div>")
607 end
608
609 # display the property column
610 fun properties do
611 # get properties
612 var mpropdefs = new HashSet[MPropDef]
613 for m in mmodule.in_nesting.greaters do
614 for c in m.mclassdefs do mpropdefs.add_all(c.mpropdefs)
615 end
616 for c in mmodule.mclassdefs do mpropdefs.add_all(c.mpropdefs)
617 var sorted = mpropdefs.to_a
618 var sorter = new ComparableSorter[MPropDef]
619 sorter.sort(sorted)
620 # display properties in one column
621 append("<article class='properties filterable'>")
622 append("<h2>Properties</h2>")
623 append("<ul>")
624 for mprop in sorted do
625 if mprop isa MAttributeDef then continue
626 if mprop.mproperty.visibility <= none_visibility then continue
627 append(mprop.html_list_item(mbuilder))
628 end
629 append("</ul>")
630 append("</article>")
631 end
632 end
633
634 # A class page
635 class NitdocClass
636 super NitdocPage
637
638 private var mclass: MClass
639 private var mbuilder: ModelBuilder
640 private var nitdoc: Nitdoc
641 private var vtypes = new HashSet[MVirtualTypeDef]
642 private var consts = new HashSet[MMethodDef]
643 private var meths = new HashSet[MMethodDef]
644 private var inherited = new HashSet[MPropDef]
645
646 init(mclass: MClass, nitdoc: Nitdoc, dot_dir: nullable String, source: nullable String) do
647 self.mclass = mclass
648 self.mbuilder = nitdoc.modelbuilder
649 self.nitdoc = nitdoc
650 self.dot_dir = dot_dir
651 self.source = source
652 # load properties
653 for mclassdef in mclass.mclassdefs do
654 for mpropdef in mclassdef.mpropdefs do
655 if mpropdef.mproperty.visibility <= none_visibility then continue
656 if mpropdef isa MVirtualTypeDef then vtypes.add(mpropdef)
657 if mpropdef isa MMethodDef then
658 if mpropdef.mproperty.is_init then
659 consts.add(mpropdef)
660 else
661 meths.add(mpropdef)
662 end
663 end
664 end
665 end
666 # get inherited properties
667 for mprop in mclass.inherited_mproperties do
668 var mpropdef = mprop.intro
669 if mprop.visibility <= none_visibility then continue
670 if mpropdef isa MVirtualTypeDef then vtypes.add(mpropdef)
671 if mpropdef isa MMethodDef then
672 if mpropdef.mproperty.is_init then
673 consts.add(mpropdef)
674 else
675 meths.add(mpropdef)
676 end
677 end
678 inherited.add(mpropdef)
679 end
680 end
681
682 redef fun head do
683 super
684 var nclass = mbuilder.mclassdef2nclassdef[mclass.intro]
685 if nclass isa AStdClassdef then
686 append("<title>{mclass.name} class | {nclass.short_comment}</title>")
687 else
688 append("<title>{mclass.name} class</title>")
689 end
690 end
691
692 redef fun menu do
693 append("<li><a href='index.html'>Overview</a></li>")
694 var public_owner = mclass.public_owner
695 if public_owner is null then
696 append("<li>{mclass.intro_mmodule.link(mbuilder)}</li>")
697 else
698 append("<li>{public_owner.link(mbuilder)}</li>")
699 end
700 append("<li class='current'>{mclass.name}</li>")
701 append("<li><a href='full-index.html'>Full Index</a></li>")
702 end
703
704 redef fun content do
705 append("<div class='menu'>")
706 properties_column
707 inheritance_column
708 append("</div>")
709 append("<div class='content'>")
710 class_doc
711 append("</div>")
712 end
713
714 fun properties_column do
715 var sorter = new ComparableSorter[MPropDef]
716 append("<nav class='properties filterable'>")
717 append("<h3>Properties</h3>")
718 # virtual types
719 if vtypes.length > 0 then
720 var vts = new Array[MVirtualTypeDef]
721 vts.add_all(vtypes)
722 sorter.sort(vts)
723 append("<h4>Virtual Types</h4>")
724 append("<ul>")
725 for mprop in vts do
726 append(mprop.html_sidebar_item(self))
727 end
728 append("</ul>")
729 end
730 # constructors
731 if consts.length > 0 then
732 var cts = new Array[MMethodDef]
733 cts.add_all(consts)
734 sorter.sort(cts)
735 append("<h4>Constructors</h4>")
736 append("<ul>")
737 for mprop in cts do
738 append(mprop.html_sidebar_item(self))
739 end
740 append("</ul>")
741 end
742 # methods
743 if meths.length > 0 then
744 var mts = new Array[MMethodDef]
745 mts.add_all(meths)
746 sorter.sort(mts)
747 append("<h4>Methods</h4>")
748 append("<ul>")
749 for mprop in mts do
750 if mclass.name != "Object" and mprop.mproperty.intro_mclassdef.mclass.name == "Object" and mprop.mproperty.visibility <= protected_visibility then continue
751 append(mprop.html_sidebar_item(self))
752 end
753 append("</ul>")
754 end
755 append("</nav>")
756 end
757
758 fun inheritance_column do
759 var sorted = new Array[MClass]
760 var sorterp = new ComparableSorter[MClass]
761 append("<nav>")
762 append("<h3>Inheritance</h3>")
763 if mclass.ancestors.length > 1 then
764 sorted = mclass.ancestors.to_a
765 sorterp.sort(sorted)
766 append("<h4>Superclasses</h4>")
767 append("<ul>")
768 for sup in sorted do
769 if sup == mclass then continue
770 append("<li>{sup.link(mbuilder)}</li>")
771 end
772 append("</ul>")
773 end
774
775 if mclass.descendants.length <= 1 then
776 append("<h4>No Known Subclasses</h4>")
777 else if mclass.descendants.length <= 100 then
778 sorted = mclass.descendants.to_a
779 sorterp.sort(sorted)
780 append("<h4>Subclasses</h4>")
781 append("<ul>")
782 for sub in sorted do
783 if sub == mclass then continue
784 append("<li>{sub.link(mbuilder)}</li>")
785 end
786 append("</ul>")
787 else if mclass.children.length <= 100 then
788 sorted = mclass.children.to_a
789 sorterp.sort(sorted)
790 append("<h4>Direct Subclasses Only</h4>")
791 append("<ul>")
792 for sub in sorted do
793 if sub == mclass then continue
794 append("<li>{sub.link(mbuilder)}</li>")
795 end
796 append("</ul>")
797 else
798 append("<h4>Too much Subclasses to list</h4>")
799 end
800 append("</nav>")
801 end
802
803 fun class_doc do
804 # title
805 append("<h1>{mclass.html_signature}</h1>")
806 append("<div class='subtitle info'>{mclass.html_full_signature(mbuilder)}")
807
808 append("</div>")
809 # comment
810 var nclass = mbuilder.mclassdef2nclassdef[mclass.intro]
811 append("<div style=\"float: right;\"><a id=\"lblDiffCommit\"></a></div>")
812 append("<section class='description'>")
813 if nclass isa AStdClassdef and not nclass.comment.is_empty then append("<pre class=\"text_label\" title=\"122\" name=\"\" tag=\"{mclass.mclassdefs.first.location.to_s}\" type=\"2\">{nclass.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>")
814 process_generate_dot
815 append("</section>")
816 # concerns
817 var concern2meths = new ArrayMap[MModule, Array[MMethodDef]]
818 var sorted_meths = new Array[MMethodDef]
819 var sorted = new Array[MModule]
820 sorted_meths.add_all(meths)
821 nitdoc.mainmodule.linearize_mpropdefs(sorted_meths)
822 for meth in meths do
823 if inherited.has(meth) then continue
824 var mmodule = meth.mclassdef.mmodule
825 if not concern2meths.has_key(mmodule) then
826 sorted.add(mmodule)
827 concern2meths[mmodule] = new Array[MMethodDef]
828 end
829 concern2meths[mmodule].add(meth)
830 end
831 var sections = new ArrayMap[MModule, Array[MModule]]
832 for mmodule in concern2meths.keys do
833 var owner = mmodule.public_owner
834 if owner == null then owner = mmodule
835 if not sections.has_key(owner) then sections[owner] = new Array[MModule]
836 if owner != mmodule then sections[owner].add(mmodule)
837 end
838 append("<section class='concerns'>")
839 append("<h2 class='section-header'>Concerns</h2>")
840 append("<ul>")
841 for owner, mmodules in sections do
842 var nowner = mbuilder.mmodule2nmodule[owner]
843 append("<li>")
844 if nowner.short_comment.is_empty then
845 append("<a href=\"#{owner.anchor}\">{owner.name}</a>")
846 else
847 append("<a href=\"#{owner.anchor}\">{owner.name}</a>: {nowner.short_comment}")
848 end
849 if not mmodules.is_empty then
850 append("<ul>")
851 for mmodule in mmodules do
852 var nmodule = mbuilder.mmodule2nmodule[mmodule]
853 if nmodule.short_comment.is_empty then
854 append("<li><a href=\"#{mmodule.anchor}\">{mmodule.name}</a></li>")
855 else
856 append("<li><a href=\"#{mmodule.anchor}\">{mmodule.name}</a>: {nmodule.short_comment}</li>")
857 end
858 end
859 append("</ul>")
860 end
861 append("</li>")
862 end
863 append("</ul>")
864 append("</section>")
865 # properties
866 var prop_sorter = new ComparableSorter[MPropDef]
867 var sorterprop = new ComparableSorter[MProperty]
868 var sorterc = new ComparableSorter[MClass]
869 var lmmodule = new List[MModule]
870 # virtual and formal types
871 var local_vtypes = new Array[MVirtualTypeDef]
872 for vt in vtypes do if not inherited.has(vt) then local_vtypes.add(vt)
873 if local_vtypes.length > 0 or mclass.arity > 0 then
874 append("<section class='types'>")
875 append("<h2>Formal and Virtual Types</h2>")
876 # formal types
877 if mclass.arity > 0 and nclass isa AStdClassdef then
878 for ft, bound in mclass.parameter_types do
879 append("<article id='FT_{ft}'>")
880 append("<h3 class='signature'>{ft}: {bound.link(mbuilder)}</h3>")
881 append("<div class=\"info\">formal generic type</div>")
882 append("</article>")
883 end
884 end
885 # virtual types
886 prop_sorter.sort(local_vtypes)
887 for prop in local_vtypes do append(prop.html_full_desc(self))
888 append("</section>")
889 end
890 # constructors
891 var local_consts = new Array[MMethodDef]
892 for const in consts do if not inherited.has(const) then local_consts.add(const)
893 prop_sorter.sort(local_consts)
894 if local_consts.length > 0 then
895 append("<section class='constructors'>")
896 append("<h2 class='section-header'>Constructors</h2>")
897 for prop in local_consts do append(prop.html_full_desc(self))
898 append("</section>")
899 end
900 # methods
901 if not concern2meths.is_empty then
902 append("<section class='methods'>")
903 append("<h2 class='section-header'>Methods</h2>")
904 for owner, mmodules in sections do
905 append("<a id=\"{owner.anchor}\"></a>")
906 if owner != mclass.intro_mmodule and owner != mclass.public_owner then
907 var nowner = mbuilder.mmodule2nmodule[owner]
908 append("<h3 class=\"concern-toplevel\">Methods refined in {owner.link(mbuilder)}</h3>")
909 if nowner.short_comment.is_empty then
910 append("<p class=\"concern-doc\">{owner.link(mbuilder)}</p>")
911 else
912 append("<p class=\"concern-doc\">{owner.link(mbuilder)}: {nowner.short_comment}</p>")
913 end
914 end
915 if concern2meths.has_key(owner) then
916 var mmethods = concern2meths[owner]
917 prop_sorter.sort(mmethods)
918 for prop in mmethods do append(prop.html_full_desc(self))
919 end
920 for mmodule in mmodules do
921 append("<a id=\"{mmodule.anchor}\"></a>")
922 var nmodule = mbuilder.mmodule2nmodule[mmodule]
923 if mmodule != mclass.intro_mmodule and mmodule != mclass.public_owner then
924 if nmodule.short_comment.is_empty then
925 append("<p class=\"concern-doc\">{mmodule.link(mbuilder)}</p>")
926 else
927 append("<p class=\"concern-doc\">{mmodule.link(mbuilder)}: {nmodule.short_comment}</p>")
928 end
929 end
930 var mmethods = concern2meths[mmodule]
931 prop_sorter.sort(mmethods)
932 for prop in mmethods do append(prop.html_full_desc(self))
933 end
934 end
935 end
936 # inherited properties
937 if inherited.length > 0 then
938 var sorted_inherited = new Array[MPropDef]
939 sorted_inherited.add_all(inherited)
940 nitdoc.mainmodule.linearize_mpropdefs(sorted_inherited)
941 var classes = new ArrayMap[MClass, Array[MPropDef]]
942 for mmethod in sorted_inherited.reversed do
943 var mclass = mmethod.mclassdef.mclass
944 if not classes.has_key(mclass) then classes[mclass] = new Array[MPropDef]
945 classes[mclass].add(mmethod)
946 end
947 append("<h3>Inherited Properties</h3>")
948 for c, mmethods in classes do
949 prop_sorter.sort(mmethods)
950 append("<p>Defined in {c.link(mbuilder)}: ")
951 for i in [0..mmethods.length[ do
952 var mmethod = mmethods[i]
953 append(mmethod.link(mbuilder))
954 if i <= mmethods.length - 1 then append(", ")
955 end
956 append("</p>")
957 end
958 end
959 append("</section>")
960 end
961
962 fun process_generate_dot do
963 var pe = nitdoc.class_hierarchy[mclass]
964 var cla = new HashSet[MClass]
965 var sm = new HashSet[MClass]
966 var sm2 = new HashSet[MClass]
967 sm.add(mclass)
968 while cla.length + sm.length < 10 and sm.length > 0 do
969 cla.add_all(sm)
970 sm2.clear
971 for x in sm do
972 sm2.add_all(pe.poset[x].direct_smallers)
973 end
974 var t = sm
975 sm = sm2
976 sm2 = t
977 end
978 cla.add_all(pe.greaters)
979
980 var op = new Buffer
981 var name = "dep_{mclass.name}"
982 op.append("digraph {name} \{ 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")
983 for c in cla do
984 if c == mclass then
985 op.append("\"{c.name}\"[shape=box,margin=0.03];\n")
986 else
987 op.append("\"{c.name}\"[URL=\"{c.url}\"];\n")
988 end
989 for c2 in pe.poset[c].direct_greaters do
990 if not cla.has(c2) then continue
991 op.append("\"{c.name}\"->\"{c2.name}\";\n")
992 end
993 if not pe.poset[c].direct_smallers.is_empty then
994 var others = true
995 for c2 in pe.poset[c].direct_smallers do
996 if cla.has(c2) then others = false
997 end
998 if others then
999 op.append("\"{c.name}...\"[label=\"\"];\n")
1000 op.append("\"{c.name}...\"->\"{c.name}\"[style=dotted];\n")
1001 end
1002 end
1003 end
1004 op.append("\}\n")
1005 generate_dot(op.to_s, name, "Dependency graph for class {mclass.name}")
1006 end
1007 end
1008
1009 #
1010 # Model redefs
1011 #
1012
1013 redef class MModule
1014 super Comparable
1015 redef type OTHER: MModule
1016 redef fun <(other: OTHER): Bool do return self.name < other.name
1017
1018 # Get the list of all methods in a module
1019 fun imported_methods: Set[MMethod] do
1020 var methods = new HashSet[MMethod]
1021 for mclass in imported_mclasses do
1022 for method in mclass.intro_methods do
1023 methods.add(method)
1024 end
1025 end
1026 return methods
1027 end
1028
1029 # Get the list aof all refined methods in a module
1030 fun redef_methods: Set[MMethod] do
1031 var methods = new HashSet[MMethod]
1032 for mclass in redef_mclasses do
1033 for method in mclass.intro_methods do
1034 methods.add(method)
1035 end
1036 end
1037 return methods
1038 end
1039
1040 # URL to nitdoc page
1041 fun url: String do
1042 var res = new Buffer
1043 res.append("module_")
1044 var mowner = public_owner
1045 if mowner != null then
1046 res.append("{public_owner.name}_")
1047 end
1048 res.append("{self.name}.html")
1049 return res.to_s
1050 end
1051
1052 # html anchor id to the module in a nitdoc page
1053 fun anchor: String do
1054 var res = new Buffer
1055 res.append("MOD_")
1056 var mowner = public_owner
1057 if mowner != null then
1058 res.append("{public_owner.name}_")
1059 end
1060 res.append(self.name)
1061 return res.to_s
1062 end
1063
1064 # Return a link (html a tag) to the nitdoc module page
1065 fun link(mbuilder: ModelBuilder): String do
1066 if mbuilder.mmodule2nmodule.has_key(self) then
1067 return "<a href='{url}' title='{mbuilder.mmodule2nmodule[self].short_comment}'>{name}</a>"
1068 else
1069 return "<a href='{url}'>{name}</a>"
1070 end
1071 end
1072
1073 # Return the module signature decorated with html
1074 fun html_signature(mbuilder: ModelBuilder): String do
1075 return "<span>module {html_full_namespace(mbuilder)}</span>"
1076 end
1077
1078 # Return the module full namespace decorated with html
1079 fun html_full_namespace(mbuilder: ModelBuilder): String do
1080 var res = new Buffer
1081 res.append("<span>")
1082 var mowner = public_owner
1083 if mowner != null then
1084 res.append(public_owner.html_namespace(mbuilder))
1085 res.append("::")
1086 end
1087 res.append(self.link(mbuilder))
1088 res.append("</span>")
1089 return res.to_s
1090 end
1091
1092 # Return the module full namespace decorated with html
1093 fun html_namespace(mbuilder: ModelBuilder): String do
1094 var res = new Buffer
1095 res.append("<span>")
1096 var mowner = public_owner
1097 if mowner != null then
1098 res.append(public_owner.html_namespace(mbuilder))
1099 else
1100 res.append(self.link(mbuilder))
1101 end
1102 res.append("</span>")
1103 return res.to_s
1104 end
1105
1106 # Return the full comment of the module decorated with html
1107 fun html_full_comment(mbuilder: ModelBuilder): String do
1108 var res = new Buffer
1109 if mbuilder.mmodule2nmodule.has_key(self) then
1110 res.append("<div id='description'>")
1111 res.append("<pre class='text_label'>{mbuilder.mmodule2nmodule[self].comment}</pre>")
1112 res.append("<textarea class='edit' rows='1' cols='76' id='fileContent'></textarea>")
1113 res.append("<a id='cancelBtn'>Cancel</a>")
1114 res.append("<a id='commitBtn'>Commit</a>")
1115 res.append("<pre class='text_label' id='preSave' type='2'></pre>")
1116 res.append("</div>")
1117 end
1118 return res.to_s
1119 end
1120 end
1121
1122 redef class MClass
1123 super Comparable
1124 redef type OTHER: MClass
1125 redef fun <(other: OTHER): Bool do return self.name < other.name
1126
1127 # Return the module signature decorated with html
1128 fun html_full_signature(mbuilder: ModelBuilder): String do
1129 var res = new Buffer
1130 if visibility <= none_visibility then
1131 res.append("private ")
1132 else if visibility == protected_visibility then
1133 res.append("protected ")
1134 end
1135 res.append("{kind} {html_namespace(mbuilder)}")
1136 return res.to_s
1137 end
1138
1139 # Add type parameters
1140 fun html_signature: String do
1141 if arity > 0 then
1142 return "{name}[{intro.parameter_names.join(", ")}]"
1143 else
1144 return name
1145 end
1146 end
1147
1148 # Return a link (html a tag) to the nitdoc class page
1149 fun link(mbuilder: ModelBuilder): String do
1150 if mbuilder.mclassdef2nclassdef.has_key(intro) then
1151 var nclass = mbuilder.mclassdef2nclassdef[intro]
1152 if nclass isa AStdClassdef then
1153 return "<a href='{url}' title=\"{nclass.short_comment}\">{html_signature}</a>"
1154 else
1155 return "<a href='{url}'>{html_signature}</a>"
1156 end
1157 else
1158 return "<a href='{url}'>{html_signature}</a>"
1159 end
1160 end
1161
1162 # Return the class namespace decorated with html
1163 fun html_namespace(mbuilder: ModelBuilder): String do
1164 var res = new Buffer
1165 res.append(intro_mmodule.html_namespace(mbuilder))
1166 res.append("::<span>{self.link(mbuilder)}</span>")
1167 return res.to_s
1168 end
1169
1170 fun url: String do
1171 return "class_{public_owner}_{c_name}.html"
1172 end
1173
1174 # Escape name for html output
1175 redef fun name do return super.html_escape
1176 end
1177
1178 redef class MProperty
1179 super Comparable
1180 redef type OTHER: MProperty
1181 redef fun <(other: OTHER): Bool do return self.name < other.name
1182
1183 # Return the property namespace decorated with html
1184 fun html_namespace(mbuilder: ModelBuilder): String do
1185 return "{intro_mclassdef.mclass.html_namespace(mbuilder)}::<span>{intro.link(mbuilder)}</span>"
1186 end
1187
1188 # Escape name for html output
1189 redef fun name do return super.html_escape
1190 end
1191
1192 redef class MType
1193 fun link(mbuilder: ModelBuilder): String is abstract
1194 end
1195
1196 redef class MClassType
1197 redef fun link(mbuilder) do return mclass.link(mbuilder)
1198 end
1199
1200 redef class MNullableType
1201 redef fun link(mbuilder) do return "nullable {mtype.link(mbuilder)}"
1202 end
1203
1204 redef class MGenericType
1205 redef fun link(mbuilder) do
1206 var res = new Buffer
1207 res.append("<a href='{mclass.url}'>{mclass.name}</a>[")
1208 for i in [0..arguments.length[ do
1209 res.append(arguments[i].link(mbuilder))
1210 if i < arguments.length - 1 then res.append(", ")
1211 end
1212 res.append("]")
1213 return res.to_s
1214 end
1215 end
1216
1217 redef class MParameterType
1218 redef fun link(mbuilder) do
1219 var name = mclass.intro.parameter_names[rank]
1220 return "<a href='{mclass.url}#FT_{name}' title='formal type'>{name}</a>"
1221 end
1222 end
1223
1224 redef class MVirtualType
1225 redef fun link(mbuilder) do return mproperty.intro.link(mbuilder)
1226 end
1227
1228 redef class MClassDef
1229 # Return the classdef namespace decorated with html
1230 fun html_namespace(mbuilder: ModelBuilder): String do
1231 var res = new Buffer
1232 res.append(mmodule.html_full_namespace(mbuilder))
1233 res.append("::<span>{self.mclass.link(mbuilder)}</span>")
1234 return res.to_s
1235 end
1236 end
1237
1238 redef class MPropDef
1239 super Comparable
1240 redef type OTHER: MPropDef
1241 redef fun <(other: OTHER): Bool do return self.mproperty.name < other.mproperty.name
1242
1243 fun url: String do return "{mclassdef.mclass.url}#{anchor}"
1244 fun anchor: String do return "PROP_{mclassdef.mclass.public_owner.name}_{c_name}"
1245
1246 # Return a link (html a tag) to the nitdoc class page
1247 fun link(mbuilder: ModelBuilder): String do
1248 if mbuilder.mpropdef2npropdef.has_key(self) then
1249 var nprop = mbuilder.mpropdef2npropdef[self]
1250 return "<a href=\"{url}\" title=\"{nprop.short_comment}\">{mproperty.name}</a>"
1251 else
1252 return "<a href=\"{url}\">{mproperty.name}</a>"
1253 end
1254 end
1255
1256 # Return a list item for the mpropdef
1257 fun html_list_item(mbuilder: ModelBuilder): String do
1258 var res = new Buffer
1259 if is_intro then
1260 res.append("<li class='intro'>")
1261 res.append("<span title='introduction'>I</span>&nbsp;{link(mbuilder)} ({mclassdef.mclass.link(mbuilder)})")
1262 res.append("</li>")
1263 else
1264 res.append("<li class='redef'>")
1265 res.append("<span title='redefinition'>R</span>&nbsp;{link(mbuilder)} ({mclassdef.mclass.link(mbuilder)})")
1266 res.append("</li>")
1267 end
1268 return res.to_s
1269 end
1270
1271 # Return a list item for the mpropdef
1272 fun html_sidebar_item(page: NitdocClass): String do
1273 var res = new Buffer
1274 if is_intro and mclassdef.mclass == page.mclass then
1275 res.append("<li class='intro'>")
1276 res.append("<span title='Introduced'>I</span>")
1277 else if is_intro and mclassdef.mclass != page.mclass then
1278 res.append("<li class='inherit'>")
1279 res.append("<span title='Inherited'>H</span>")
1280 else
1281 res.append("<li class='redef'>")
1282 res.append("<span title='Redefined'>R</span>")
1283 end
1284 res.append(link(page.mbuilder))
1285 res.append("</li>")
1286 return res.to_s
1287 end
1288
1289 fun html_full_desc(page: NitdocClass): String is abstract
1290 fun html_info(page: NitdocClass): String is abstract
1291
1292 fun full_name: String do
1293 return "{mclassdef.mclass.public_owner.name}::{mclassdef.mclass.name}::{mproperty.name}"
1294 end
1295 end
1296
1297 redef class MMethodDef
1298 redef fun html_full_desc(page) do
1299 if not page.mbuilder.mpropdef2npropdef.has_key(self) then
1300 return ""
1301 end
1302 var res = new Buffer
1303 var mprop = mproperty
1304 var nprop = page.mbuilder.mpropdef2npropdef[self]
1305 var classes = new Array[String]
1306 var is_redef = mprop.intro_mclassdef.mclass != page.mclass
1307 classes.add("fun")
1308 if mprop.is_init then classes.add("init")
1309 if is_redef then classes.add("redef")
1310 if mprop.visibility == none_visibility then
1311 classes.add("private")
1312 else if mprop.visibility == protected_visibility then
1313 classes.add("protected")
1314 else
1315 classes.add("public")
1316 end
1317 res.append("<article class='{classes.join(" ")}' id='{anchor}'>")
1318 if nprop isa AAttrPropdef then
1319 if nprop.mreadpropdef == self then
1320 res.append("<h3 class='signature'>{mprop.name}: {nprop.html_signature(page.mbuilder)}</h3>")
1321 else
1322 res.append("<h3 class='signature'>{mprop.name}(value: {nprop.html_signature(page.mbuilder)})</h3>")
1323 end
1324 else
1325 var intro_nprop = page.mbuilder.mpropdef2npropdef[mprop.intro]
1326 res.append("<h3 class='signature'>{mprop.name}{intro_nprop.html_signature(page.mbuilder)}</h3>")
1327 end
1328 res.append(html_info(page))
1329 res.append("<div class='description'>")
1330 if nprop.comment == "" then
1331 res.append("<a class=\"newComment\" title=\"32\" tag=\"\">New Comment</a>")
1332 else
1333 res.append("<pre class=\"text_label\" title=\"\" name=\"\" tag=\"\" type=\"1\">{nprop.comment}</pre>")
1334 end
1335 res.append("<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>")
1336 # definitions block
1337 res.append("<p class='info'>")
1338 page.nitdoc.mainmodule.linearize_mpropdefs(mprop.mpropdefs)
1339 var previous_defs = new Array[MMethodDef]
1340 var next_defs = new Array[MMethodDef]
1341 var self_passed = false
1342 for def in mprop.mpropdefs do
1343 if def == self then
1344 self_passed = true
1345 continue
1346 end
1347 if not self_passed then
1348 if not page.mclass.ancestors.has(def.mclassdef.mclass) then continue
1349 if def.is_intro then continue
1350 previous_defs.add(def)
1351 else
1352 if not page.mclass.descendants.has(def.mclassdef.mclass) then continue
1353 next_defs.add(def)
1354 end
1355 end
1356 res.append("defined by {mclassdef.mmodule.html_full_namespace(page.mbuilder)}")
1357 if not is_intro then
1358 res.append(", introduced by {mprop.intro.mclassdef.mclass.link(page.mbuilder)}")
1359 end
1360 if not previous_defs.is_empty then
1361 res.append(", inherited from ")
1362 for i in [0..previous_defs.length[ do
1363 res.append(previous_defs[i].mclassdef.mclass.link(page.mbuilder))
1364 if i < previous_defs.length - 1 then res.append(", ")
1365 end
1366 end
1367 if not next_defs.is_empty then
1368 res.append(", redefined by ")
1369 for i in [0..next_defs.length[ do
1370 res.append(next_defs[i].mclassdef.mclass.link(page.mbuilder))
1371 if i < next_defs.length - 1 then res.append(", ")
1372 end
1373 end
1374 res.append(".</p>")
1375 res.append("</div>")
1376 res.append("</article>")
1377 return res.to_s
1378 end
1379
1380 redef fun html_info(page) do
1381 var res = new Buffer
1382 res.append("<div class='info'>")
1383 if mproperty.visibility <= none_visibility then
1384 res.append("private ")
1385 else if mproperty.visibility <= protected_visibility then
1386 res.append("protected ")
1387 end
1388 if mproperty.intro_mclassdef.mclass != page.mclass then res.append("redef ")
1389 res.append("fun {mproperty.html_namespace(page.mbuilder)}")
1390 res.append("</div>")
1391 res.append("<div style=\"float: right;\"><a id=\"lblDiffCommit\"></a></div>")
1392 return res.to_s
1393 end
1394 end
1395
1396 redef class MVirtualTypeDef
1397 redef fun html_full_desc(page) do
1398 var res = new Buffer
1399 var mprop = mproperty
1400 var is_redef = mprop.intro_mclassdef.mclass != page.mclass
1401 var classes = new Array[String]
1402 classes.add("type")
1403 if is_redef then classes.add("redef")
1404 if mprop.visibility == none_visibility then
1405 classes.add("private")
1406 else if mprop.visibility == protected_visibility then
1407 classes.add("protected")
1408 else
1409 classes.add("public")
1410 end
1411 res.append("<article class='{classes.join(" ")}' id='{anchor}'>")
1412 res.append("<h3 class='signature'>{mprop.name}: {bound.link(page.mbuilder)}</h3>")
1413 res.append(html_info(page))
1414 res.append("<div class='description'>")
1415
1416 if page.mbuilder.mpropdef2npropdef.has_key(self) and page.mbuilder.mpropdef2npropdef[self].comment != "" then
1417 var nprop = page.mbuilder.mpropdef2npropdef[self]
1418 res.append("<pre class=\"text_label\" title=\"\" name=\"\" tag=\"\" type=\"1\">{nprop.comment}</pre>")
1419 else
1420 res.append("<a class=\"newComment\" title=\"32\" tag=\"\">New Comment</a>")
1421 end
1422 res.append("<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>")
1423 # definitions block
1424 res.append("<p class='info'>")
1425 page.nitdoc.mainmodule.linearize_mpropdefs(mprop.mpropdefs)
1426 var previous_defs = new Array[MVirtualTypeDef]
1427 var next_defs = new Array[MVirtualTypeDef]
1428 var self_passed = false
1429 for def in mprop.mpropdefs do
1430 if def == self then
1431 self_passed = true
1432 continue
1433 end
1434 if not self_passed then
1435 if not page.mclass.ancestors.has(def.mclassdef.mclass) then continue
1436 if def.is_intro then continue
1437 previous_defs.add(def)
1438 else
1439 if not page.mclass.descendants.has(def.mclassdef.mclass) then continue
1440 next_defs.add(def)
1441 end
1442 end
1443 res.append("defined by {mclassdef.mmodule.html_full_namespace(page.mbuilder)}")
1444 if not is_intro then
1445 res.append(", introduced by {mprop.intro.mclassdef.mclass.link(page.mbuilder)}")
1446 end
1447 if not previous_defs.is_empty then
1448 res.append(", inherited from ")
1449 for i in [0..previous_defs.length[ do
1450 res.append(previous_defs[i].mclassdef.mclass.link(page.mbuilder))
1451 if i < previous_defs.length - 1 then res.append(", ")
1452 end
1453 end
1454 if not next_defs.is_empty then
1455 res.append(", redefined by ")
1456 for i in [0..next_defs.length[ do
1457 res.append(next_defs[i].mclassdef.mclass.link(page.mbuilder))
1458 if i < next_defs.length - 1 then res.append(", ")
1459 end
1460 end
1461 res.append(".</p>")
1462 res.append("</div>")
1463 res.append("</article>")
1464 return res.to_s
1465 end
1466
1467 redef fun html_info(page) do
1468 var res = new Buffer
1469 res.append("<div class='info'>")
1470 if mproperty.intro_mclassdef.mclass != page.mclass then res.append("redef ")
1471 res.append("type {mproperty.html_namespace(page.mbuilder)}")
1472 res.append("</div>")
1473 res.append("<div style=\"float: right;\"><a id=\"lblDiffCommit\"></a></div>")
1474 return res.to_s
1475 end
1476 end
1477
1478 #
1479 # Nodes redefs
1480 #
1481
1482 redef class AModule
1483 private fun comment: String do
1484 var ret = new Buffer
1485 if n_moduledecl == null or n_moduledecl.n_doc == null then return ""
1486 for t in n_moduledecl.n_doc.n_comment do
1487 ret.append(t.text.substring_from(1))
1488 end
1489 return ret.to_s.html_escape
1490 end
1491
1492 private fun short_comment: String do
1493 var ret = new Buffer
1494 if n_moduledecl != null and n_moduledecl.n_doc != null then
1495 ret.append(n_moduledecl.n_doc.n_comment.first.text.substring_from(2).replace("\n", ""))
1496 end
1497 return ret.to_s.html_escape
1498 end
1499 end
1500
1501 redef class AStdClassdef
1502 private fun comment: String do
1503 var ret = new Buffer
1504 if n_doc != null then
1505 for t in n_doc.n_comment do ret.append(t.text.substring_from(1))
1506 end
1507 return ret.to_s.html_escape
1508 end
1509
1510 private fun short_comment: String do
1511 var ret = new Buffer
1512 if n_doc != null then ret.append(n_doc.n_comment.first.text.substring_from(2).replace("\n", ""))
1513 return ret.to_s.html_escape
1514 end
1515 end
1516
1517 redef class APropdef
1518 private fun short_comment: String is abstract
1519 private fun html_signature(mbuilder: ModelBuilder): String is abstract
1520 private fun comment: String is abstract
1521 end
1522
1523 redef class AAttrPropdef
1524 redef fun short_comment do
1525 var ret = new Buffer
1526 if n_doc != null then ret.append(n_doc.n_comment.first.text.substring_from(2).replace("\n", ""))
1527 return ret.to_s.html_escape
1528 end
1529
1530 redef private fun comment: String do
1531 var ret = new Buffer
1532 if n_doc != null then
1533 for t in n_doc.n_comment do ret.append(t.text.substring_from(1))
1534 end
1535 return ret.to_s.html_escape
1536 end
1537
1538 redef fun html_signature(mbuilder) do
1539 if n_type != null then return n_type.mtype.link(mbuilder)
1540 return ""
1541 end
1542 end
1543
1544 redef class AMethPropdef
1545 redef fun short_comment do
1546 var ret = new Buffer
1547 if n_doc != null then ret.append(n_doc.n_comment.first.text.substring_from(2).replace("\n", ""))
1548 return ret.to_s.html_escape
1549 end
1550
1551 redef private fun comment: String do
1552 var ret = new Buffer
1553 if n_doc != null then
1554 for t in n_doc.n_comment do ret.append(t.text.substring_from(1))
1555 end
1556 return ret.to_s.html_escape
1557 end
1558
1559 redef fun html_signature(mbuilder) do
1560 if n_signature != null then return n_signature.to_html(mbuilder)
1561 return ""
1562 end
1563 end
1564
1565 redef class ATypePropdef
1566 redef fun short_comment do
1567 var ret = new Buffer
1568 if n_doc != null then ret.append(n_doc.n_comment.first.text.substring_from(2).replace("\n", ""))
1569 return ret.to_s.html_escape
1570 end
1571
1572 redef private fun comment: String do
1573 var ret = new Buffer
1574 if n_doc != null then
1575 for t in n_doc.n_comment do ret.append(t.text.substring_from(1))
1576 end
1577 return ret.to_s.html_escape
1578 end
1579
1580 redef fun html_signature(mbuilder) do
1581 return mpropdef.bound.link(mbuilder)
1582 end
1583 end
1584
1585 redef class ASignature
1586 fun to_html(mbuilder: ModelBuilder): String do
1587 #TODO closures
1588 var res = new Buffer
1589 if not n_params.is_empty then
1590 res.append("(")
1591 for i in [0..n_params.length[ do
1592 res.append(n_params[i].to_html(mbuilder))
1593 if i < n_params.length - 1 then res.append(", ")
1594 end
1595 res.append(")")
1596 end
1597 if n_type != null and n_type.mtype.link(mbuilder) != "" then res.append(": {n_type.mtype.link(mbuilder)}")
1598 return res.to_s
1599 end
1600 end
1601
1602 redef class AParam
1603 fun to_html(mbuilder: ModelBuilder): String do
1604 var ret = "{n_id.text}"
1605 if n_type != null then
1606 ret = "{ret}: {n_type.mtype.link(mbuilder)}"
1607 if n_dotdotdot != null then ret = "{ret}..."
1608 end
1609 return ret
1610 end
1611 end
1612
1613 # Create a tool context to handle options and paths
1614 var toolcontext = new ToolContext
1615
1616 # Here we launch the nit index
1617 var nitdoc = new Nitdoc(toolcontext)
1618 nitdoc.start