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