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