ni_nitdoc: renamed NItdoc into NitdocContext
[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 if mclass.ancestors.length > 1 then
802 sorted = mclass.ancestors.to_a
803 sorterp.sort(sorted)
804 append("<h4>Superclasses</h4>")
805 append("<ul>")
806 for sup in sorted do
807 if sup == mclass then continue
808 append("<li>{sup.link(mbuilder)}</li>")
809 end
810 append("</ul>")
811 end
812
813 if mclass.descendants.length <= 1 then
814 append("<h4>No Known Subclasses</h4>")
815 else if mclass.descendants.length <= 100 then
816 sorted = mclass.descendants.to_a
817 sorterp.sort(sorted)
818 append("<h4>Subclasses</h4>")
819 append("<ul>")
820 for sub in sorted do
821 if sub == mclass then continue
822 append("<li>{sub.link(mbuilder)}</li>")
823 end
824 append("</ul>")
825 else if mclass.children.length <= 100 then
826 sorted = mclass.children.to_a
827 sorterp.sort(sorted)
828 append("<h4>Direct Subclasses Only</h4>")
829 append("<ul>")
830 for sub in sorted do
831 if sub == mclass then continue
832 append("<li>{sub.link(mbuilder)}</li>")
833 end
834 append("</ul>")
835 else
836 append("<h4>Too much Subclasses to list</h4>")
837 end
838 append("</nav>")
839 end
840
841 fun class_doc do
842 # title
843 append("<h1>{mclass.html_signature}</h1>")
844 append("<div class='subtitle info'>{mclass.html_full_signature(mbuilder)}")
845
846 append("</div>")
847 # comment
848 var nclass = mbuilder.mclassdef2nclassdef[mclass.intro]
849 append("<div style=\"float: right;\"><a id=\"lblDiffCommit\"></a></div>")
850 append("<section class='description'>")
851 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>")
852 process_generate_dot
853 append("</section>")
854 # concerns
855 var concern2meths = new ArrayMap[MModule, Array[MMethodDef]]
856 var sorted_meths = new Array[MMethodDef]
857 var sorted = new Array[MModule]
858 sorted_meths.add_all(meths)
859 ctx.mainmodule.linearize_mpropdefs(sorted_meths)
860 for meth in meths do
861 if inherited.has(meth) then continue
862 var mmodule = meth.mclassdef.mmodule
863 if not concern2meths.has_key(mmodule) then
864 sorted.add(mmodule)
865 concern2meths[mmodule] = new Array[MMethodDef]
866 end
867 concern2meths[mmodule].add(meth)
868 end
869 var sections = new ArrayMap[MModule, Array[MModule]]
870 for mmodule in concern2meths.keys do
871 var owner = mmodule.public_owner
872 if owner == null then owner = mmodule
873 if not sections.has_key(owner) then sections[owner] = new Array[MModule]
874 if owner != mmodule then sections[owner].add(mmodule)
875 end
876 append("<section class='concerns'>")
877 append("<h2 class='section-header'>Concerns</h2>")
878 append("<ul>")
879 for owner, mmodules in sections do
880 var nowner = mbuilder.mmodule2nmodule[owner]
881 append("<li>")
882 if nowner.short_comment.is_empty then
883 append("<a href=\"#{owner.anchor}\">{owner.name}</a>")
884 else
885 append("<a href=\"#{owner.anchor}\">{owner.name}</a>: {nowner.short_comment}")
886 end
887 if not mmodules.is_empty then
888 append("<ul>")
889 for mmodule in mmodules do
890 var nmodule = mbuilder.mmodule2nmodule[mmodule]
891 if nmodule.short_comment.is_empty then
892 append("<li><a href=\"#{mmodule.anchor}\">{mmodule.name}</a></li>")
893 else
894 append("<li><a href=\"#{mmodule.anchor}\">{mmodule.name}</a>: {nmodule.short_comment}</li>")
895 end
896 end
897 append("</ul>")
898 end
899 append("</li>")
900 end
901 append("</ul>")
902 append("</section>")
903 # properties
904 var prop_sorter = new ComparableSorter[MPropDef]
905 var sorterprop = new ComparableSorter[MProperty]
906 var sorterc = new ComparableSorter[MClass]
907 var lmmodule = new List[MModule]
908 # virtual and formal types
909 var local_vtypes = new Array[MVirtualTypeDef]
910 for vt in vtypes do if not inherited.has(vt) then local_vtypes.add(vt)
911 if local_vtypes.length > 0 or mclass.arity > 0 then
912 append("<section class='types'>")
913 append("<h2>Formal and Virtual Types</h2>")
914 # formal types
915 if mclass.arity > 0 and nclass isa AStdClassdef then
916 for ft, bound in mclass.parameter_types do
917 append("<article id='FT_{ft}'>")
918 append("<h3 class='signature'>{ft}: {bound.link(mbuilder)}</h3>")
919 append("<div class=\"info\">formal generic type</div>")
920 append("</article>")
921 end
922 end
923 # virtual types
924 prop_sorter.sort(local_vtypes)
925 for prop in local_vtypes do append(prop.html_full_desc(self))
926 append("</section>")
927 end
928 # constructors
929 var local_consts = new Array[MMethodDef]
930 for const in consts do if not inherited.has(const) then local_consts.add(const)
931 prop_sorter.sort(local_consts)
932 if local_consts.length > 0 then
933 append("<section class='constructors'>")
934 append("<h2 class='section-header'>Constructors</h2>")
935 for prop in local_consts do append(prop.html_full_desc(self))
936 append("</section>")
937 end
938 # methods
939 if not concern2meths.is_empty then
940 append("<section class='methods'>")
941 append("<h2 class='section-header'>Methods</h2>")
942 for owner, mmodules in sections do
943 append("<a id=\"{owner.anchor}\"></a>")
944 if owner != mclass.intro_mmodule and owner != mclass.public_owner then
945 var nowner = mbuilder.mmodule2nmodule[owner]
946 append("<h3 class=\"concern-toplevel\">Methods refined in {owner.link(mbuilder)}</h3>")
947 if nowner.short_comment.is_empty then
948 append("<p class=\"concern-doc\">{owner.link(mbuilder)}</p>")
949 else
950 append("<p class=\"concern-doc\">{owner.link(mbuilder)}: {nowner.short_comment}</p>")
951 end
952 end
953 if concern2meths.has_key(owner) then
954 var mmethods = concern2meths[owner]
955 prop_sorter.sort(mmethods)
956 for prop in mmethods do append(prop.html_full_desc(self))
957 end
958 for mmodule in mmodules do
959 append("<a id=\"{mmodule.anchor}\"></a>")
960 var nmodule = mbuilder.mmodule2nmodule[mmodule]
961 if mmodule != mclass.intro_mmodule and mmodule != mclass.public_owner then
962 if nmodule.short_comment.is_empty then
963 append("<p class=\"concern-doc\">{mmodule.link(mbuilder)}</p>")
964 else
965 append("<p class=\"concern-doc\">{mmodule.link(mbuilder)}: {nmodule.short_comment}</p>")
966 end
967 end
968 var mmethods = concern2meths[mmodule]
969 prop_sorter.sort(mmethods)
970 for prop in mmethods do append(prop.html_full_desc(self))
971 end
972 end
973 end
974 # inherited properties
975 if inherited.length > 0 then
976 var sorted_inherited = new Array[MPropDef]
977 sorted_inherited.add_all(inherited)
978 ctx.mainmodule.linearize_mpropdefs(sorted_inherited)
979 var classes = new ArrayMap[MClass, Array[MPropDef]]
980 for mmethod in sorted_inherited.reversed do
981 var mclass = mmethod.mclassdef.mclass
982 if not classes.has_key(mclass) then classes[mclass] = new Array[MPropDef]
983 classes[mclass].add(mmethod)
984 end
985 append("<h3>Inherited Properties</h3>")
986 for c, mmethods in classes do
987 prop_sorter.sort(mmethods)
988 append("<p>Defined in {c.link(mbuilder)}: ")
989 for i in [0..mmethods.length[ do
990 var mmethod = mmethods[i]
991 append(mmethod.link(mbuilder))
992 if i <= mmethods.length - 1 then append(", ")
993 end
994 append("</p>")
995 end
996 end
997 append("</section>")
998 end
999
1000 fun process_generate_dot do
1001 var pe = ctx.class_hierarchy[mclass]
1002 var cla = new HashSet[MClass]
1003 var sm = new HashSet[MClass]
1004 var sm2 = new HashSet[MClass]
1005 sm.add(mclass)
1006 while cla.length + sm.length < 10 and sm.length > 0 do
1007 cla.add_all(sm)
1008 sm2.clear
1009 for x in sm do
1010 sm2.add_all(pe.poset[x].direct_smallers)
1011 end
1012 var t = sm
1013 sm = sm2
1014 sm2 = t
1015 end
1016 cla.add_all(pe.greaters)
1017
1018 var op = new Buffer
1019 var name = "dep_{mclass.name}"
1020 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")
1021 for c in cla do
1022 if c == mclass then
1023 op.append("\"{c.name}\"[shape=box,margin=0.03];\n")
1024 else
1025 op.append("\"{c.name}\"[URL=\"{c.url}\"];\n")
1026 end
1027 for c2 in pe.poset[c].direct_greaters do
1028 if not cla.has(c2) then continue
1029 op.append("\"{c.name}\"->\"{c2.name}\";\n")
1030 end
1031 if not pe.poset[c].direct_smallers.is_empty then
1032 var others = true
1033 for c2 in pe.poset[c].direct_smallers do
1034 if cla.has(c2) then others = false
1035 end
1036 if others then
1037 op.append("\"{c.name}...\"[label=\"\"];\n")
1038 op.append("\"{c.name}...\"->\"{c.name}\"[style=dotted];\n")
1039 end
1040 end
1041 end
1042 op.append("\}\n")
1043 generate_dot(op.to_s, name, "Dependency graph for class {mclass.name}")
1044 end
1045 end
1046
1047 #
1048 # Model redefs
1049 #
1050
1051 redef class MModule
1052 super Comparable
1053 redef type OTHER: MModule
1054 redef fun <(other: OTHER): Bool do return self.name < other.name
1055
1056 # Get the list of all methods in a module
1057 fun imported_methods: Set[MMethod] do
1058 var methods = new HashSet[MMethod]
1059 for mclass in imported_mclasses do
1060 for method in mclass.intro_methods do
1061 methods.add(method)
1062 end
1063 end
1064 return methods
1065 end
1066
1067 # Get the list aof all refined methods in a module
1068 fun redef_methods: Set[MMethod] do
1069 var methods = new HashSet[MMethod]
1070 for mclass in redef_mclasses do
1071 for method in mclass.intro_methods do
1072 methods.add(method)
1073 end
1074 end
1075 return methods
1076 end
1077
1078 # URL to nitdoc page
1079 fun url: String do
1080 var res = new Buffer
1081 res.append("module_")
1082 var mowner = public_owner
1083 if mowner != null then
1084 res.append("{public_owner.name}_")
1085 end
1086 res.append("{self.name}.html")
1087 return res.to_s
1088 end
1089
1090 # html anchor id to the module in a nitdoc page
1091 fun anchor: String do
1092 var res = new Buffer
1093 res.append("MOD_")
1094 var mowner = public_owner
1095 if mowner != null then
1096 res.append("{public_owner.name}_")
1097 end
1098 res.append(self.name)
1099 return res.to_s
1100 end
1101
1102 # Return a link (html a tag) to the nitdoc module page
1103 fun link(mbuilder: ModelBuilder): String do
1104 if mbuilder.mmodule2nmodule.has_key(self) then
1105 return "<a href='{url}' title='{mbuilder.mmodule2nmodule[self].short_comment}'>{name}</a>"
1106 else
1107 return "<a href='{url}'>{name}</a>"
1108 end
1109 end
1110
1111 # Return the module signature decorated with html
1112 fun html_signature(mbuilder: ModelBuilder): String do
1113 return "<span>module {html_full_namespace(mbuilder)}</span>"
1114 end
1115
1116 # Return the module full namespace decorated with html
1117 fun html_full_namespace(mbuilder: ModelBuilder): String do
1118 var res = new Buffer
1119 res.append("<span>")
1120 var mowner = public_owner
1121 if mowner != null then
1122 res.append(public_owner.html_namespace(mbuilder))
1123 res.append("::")
1124 end
1125 res.append(self.link(mbuilder))
1126 res.append("</span>")
1127 return res.to_s
1128 end
1129
1130 # Return the module full namespace decorated with html
1131 fun html_namespace(mbuilder: ModelBuilder): String do
1132 var res = new Buffer
1133 res.append("<span>")
1134 var mowner = public_owner
1135 if mowner != null then
1136 res.append(public_owner.html_namespace(mbuilder))
1137 else
1138 res.append(self.link(mbuilder))
1139 end
1140 res.append("</span>")
1141 return res.to_s
1142 end
1143
1144 # Return the full comment of the module decorated with html
1145 fun html_full_comment(mbuilder: ModelBuilder): String do
1146 var res = new Buffer
1147 if mbuilder.mmodule2nmodule.has_key(self) then
1148 res.append("<div id='description'>")
1149 res.append("<pre class='text_label'>{mbuilder.mmodule2nmodule[self].comment}</pre>")
1150 res.append("<textarea class='edit' rows='1' cols='76' id='fileContent'></textarea>")
1151 res.append("<a id='cancelBtn'>Cancel</a>")
1152 res.append("<a id='commitBtn'>Commit</a>")
1153 res.append("<pre class='text_label' id='preSave' type='2'></pre>")
1154 res.append("</div>")
1155 end
1156 return res.to_s
1157 end
1158 end
1159
1160 redef class MClass
1161 super Comparable
1162 redef type OTHER: MClass
1163 redef fun <(other: OTHER): Bool do return self.name < other.name
1164
1165 # Return the module signature decorated with html
1166 fun html_full_signature(mbuilder: ModelBuilder): String do
1167 var res = new Buffer
1168 if visibility < public_visibility then res.append("{visibility.to_s} ")
1169 res.append("{kind} {html_namespace(mbuilder)}")
1170 return res.to_s
1171 end
1172
1173 # Add type parameters
1174 fun html_signature: String do
1175 if arity > 0 then
1176 return "{name}[{intro.parameter_names.join(", ")}]"
1177 else
1178 return name
1179 end
1180 end
1181
1182 # Return a link (html a tag) to the nitdoc class page
1183 fun link(mbuilder: ModelBuilder): String do
1184 if mbuilder.mclassdef2nclassdef.has_key(intro) then
1185 var nclass = mbuilder.mclassdef2nclassdef[intro]
1186 if nclass isa AStdClassdef then
1187 return "<a href='{url}' title=\"{nclass.short_comment}\">{html_signature}</a>"
1188 else
1189 return "<a href='{url}'>{html_signature}</a>"
1190 end
1191 else
1192 return "<a href='{url}'>{html_signature}</a>"
1193 end
1194 end
1195
1196 # Return the class namespace decorated with html
1197 fun html_namespace(mbuilder: ModelBuilder): String do
1198 var res = new Buffer
1199 res.append(intro_mmodule.html_namespace(mbuilder))
1200 res.append("::<span>{self.link(mbuilder)}</span>")
1201 return res.to_s
1202 end
1203
1204 fun url: String do
1205 return "class_{public_owner}_{c_name}.html"
1206 end
1207
1208 # Escape name for html output
1209 redef fun name do return super.html_escape
1210 end
1211
1212 redef class MProperty
1213 super Comparable
1214 redef type OTHER: MProperty
1215 redef fun <(other: OTHER): Bool do return self.name < other.name
1216
1217 # Return the property namespace decorated with html
1218 fun html_namespace(mbuilder: ModelBuilder): String do
1219 return "{intro_mclassdef.mclass.html_namespace(mbuilder)}::<span>{intro.link(mbuilder)}</span>"
1220 end
1221
1222 # Escape name for html output
1223 redef fun name do return super.html_escape
1224 end
1225
1226 redef class MType
1227 fun link(mbuilder: ModelBuilder): String is abstract
1228 end
1229
1230 redef class MClassType
1231 redef fun link(mbuilder) do return mclass.link(mbuilder)
1232 end
1233
1234 redef class MNullableType
1235 redef fun link(mbuilder) do return "nullable {mtype.link(mbuilder)}"
1236 end
1237
1238 redef class MGenericType
1239 redef fun link(mbuilder) do
1240 var res = new Buffer
1241 res.append("<a href='{mclass.url}'>{mclass.name}</a>[")
1242 for i in [0..arguments.length[ do
1243 res.append(arguments[i].link(mbuilder))
1244 if i < arguments.length - 1 then res.append(", ")
1245 end
1246 res.append("]")
1247 return res.to_s
1248 end
1249 end
1250
1251 redef class MParameterType
1252 redef fun link(mbuilder) do
1253 var name = mclass.intro.parameter_names[rank]
1254 return "<a href='{mclass.url}#FT_{name}' title='formal type'>{name}</a>"
1255 end
1256 end
1257
1258 redef class MVirtualType
1259 redef fun link(mbuilder) do return mproperty.intro.link(mbuilder)
1260 end
1261
1262 redef class MClassDef
1263 # Return the classdef namespace decorated with html
1264 fun html_namespace(mbuilder: ModelBuilder): String do
1265 var res = new Buffer
1266 res.append(mmodule.html_full_namespace(mbuilder))
1267 res.append("::<span>{self.mclass.link(mbuilder)}</span>")
1268 return res.to_s
1269 end
1270 end
1271
1272 redef class MPropDef
1273 super Comparable
1274 redef type OTHER: MPropDef
1275 redef fun <(other: OTHER): Bool do return self.mproperty.name < other.mproperty.name
1276
1277 fun url: String do return "{mclassdef.mclass.url}#{anchor}"
1278 fun anchor: String do return "PROP_{mclassdef.mclass.public_owner.name}_{c_name}"
1279
1280 # Return a link (html a tag) to the nitdoc class page
1281 fun link(mbuilder: ModelBuilder): String do
1282 if mbuilder.mpropdef2npropdef.has_key(self) then
1283 var nprop = mbuilder.mpropdef2npropdef[self]
1284 return "<a href=\"{url}\" title=\"{nprop.short_comment}\">{mproperty.name}</a>"
1285 else
1286 return "<a href=\"{url}\">{mproperty.name}</a>"
1287 end
1288 end
1289
1290 # Return a list item for the mpropdef
1291 fun html_list_item(mbuilder: ModelBuilder): String do
1292 var res = new Buffer
1293 if is_intro then
1294 res.append("<li class='intro'>")
1295 res.append("<span title='introduction'>I</span>&nbsp;{link(mbuilder)} ({mclassdef.mclass.link(mbuilder)})")
1296 res.append("</li>")
1297 else
1298 res.append("<li class='redef'>")
1299 res.append("<span title='redefinition'>R</span>&nbsp;{link(mbuilder)} ({mclassdef.mclass.link(mbuilder)})")
1300 res.append("</li>")
1301 end
1302 return res.to_s
1303 end
1304
1305 # Return a list item for the mpropdef
1306 fun html_sidebar_item(page: NitdocClass): String do
1307 var res = new Buffer
1308 if is_intro and mclassdef.mclass == page.mclass then
1309 res.append("<li class='intro'>")
1310 res.append("<span title='Introduced'>I</span>")
1311 else if is_intro and mclassdef.mclass != page.mclass then
1312 res.append("<li class='inherit'>")
1313 res.append("<span title='Inherited'>H</span>")
1314 else
1315 res.append("<li class='redef'>")
1316 res.append("<span title='Redefined'>R</span>")
1317 end
1318 res.append(link(page.mbuilder))
1319 res.append("</li>")
1320 return res.to_s
1321 end
1322
1323 fun html_full_desc(page: NitdocClass): String is abstract
1324 fun html_info(page: NitdocClass): String is abstract
1325
1326 fun full_name: String do
1327 return "{mclassdef.mclass.public_owner.name}::{mclassdef.mclass.name}::{mproperty.name}"
1328 end
1329
1330 fun html_inheritance(page: NitdocClass): String do
1331 var res = new Buffer
1332 # definitions block
1333 res.append("<p class='info'>")
1334 page.ctx.mainmodule.linearize_mpropdefs(mproperty.mpropdefs)
1335 var previous_defs = new Array[MPropDef]
1336 var next_defs = new Array[MPropDef]
1337 var self_passed = false
1338 for def in mproperty.mpropdefs do
1339 if def == self then
1340 self_passed = true
1341 continue
1342 end
1343 if not self_passed then
1344 if not page.mclass.ancestors.has(def.mclassdef.mclass) then continue
1345 if def.is_intro then continue
1346 previous_defs.add(def)
1347 else
1348 if not page.mclass.descendants.has(def.mclassdef.mclass) then continue
1349 next_defs.add(def)
1350 end
1351 end
1352 var source = ""
1353 if page.mbuilder.mpropdef2npropdef.has_key(self) then
1354 source = " {page.show_source(page.mbuilder.mpropdef2npropdef[self].location)}"
1355 end
1356 res.append("defined by {mclassdef.mmodule.html_full_namespace(page.mbuilder)}{source}")
1357 if not is_intro then
1358 source = ""
1359 if page.mbuilder.mpropdef2npropdef.has_key(mproperty.intro) then
1360 source = " {page.show_source(page.mbuilder.mpropdef2npropdef[mproperty.intro].location)}"
1361 end
1362 res.append(", introduced by {mproperty.intro.mclassdef.mclass.link(page.mbuilder)}{source}")
1363 end
1364 if not previous_defs.is_empty then
1365 res.append(", inherited from ")
1366 for i in [0..previous_defs.length[ do
1367 var def = previous_defs[i]
1368 source = ""
1369 if page.mbuilder.mpropdef2npropdef.has_key(def) then
1370 source = " {page.show_source(page.mbuilder.mpropdef2npropdef[def].location)}"
1371 end
1372 res.append("{def.mclassdef.mclass.link(page.mbuilder)}{source}")
1373 if i < previous_defs.length - 1 then res.append(", ")
1374 end
1375 end
1376 if not next_defs.is_empty then
1377 res.append(", redefined by ")
1378 for i in [0..next_defs.length[ do
1379 var def = next_defs[i]
1380 source = ""
1381 if page.mbuilder.mpropdef2npropdef.has_key(def) then
1382 source = " {page.show_source(page.mbuilder.mpropdef2npropdef[def].location)}"
1383 end
1384 res.append("{def.mclassdef.mclass.link(page.mbuilder)}{source}")
1385 if i < next_defs.length - 1 then res.append(", ")
1386 end
1387 end
1388 res.append(".</p>")
1389 return res.to_s
1390 end
1391 end
1392
1393 redef class MMethodDef
1394 redef fun html_full_desc(page) do
1395 if not page.mbuilder.mpropdef2npropdef.has_key(self) then
1396 return ""
1397 end
1398 var res = new Buffer
1399 var mprop = mproperty
1400 var nprop = page.mbuilder.mpropdef2npropdef[self]
1401 var classes = new Array[String]
1402 var is_redef = mprop.intro_mclassdef.mclass != page.mclass
1403 classes.add("fun")
1404 if mprop.is_init then classes.add("init")
1405 if is_redef then classes.add("redef")
1406 classes.add(mproperty.visibility.to_s)
1407 res.append("<article class='{classes.join(" ")}' id='{anchor}'>")
1408 if nprop isa AAttrPropdef then
1409 if nprop.mreadpropdef == self then
1410 res.append("<h3 class='signature'>{mprop.name}: {nprop.html_signature(page.mbuilder)}</h3>")
1411 else
1412 res.append("<h3 class='signature'>{mprop.name}(value: {nprop.html_signature(page.mbuilder)})</h3>")
1413 end
1414 else
1415 var intro_nprop = page.mbuilder.mpropdef2npropdef[mprop.intro]
1416 res.append("<h3 class='signature'>{mprop.name}{intro_nprop.html_signature(page.mbuilder)}</h3>")
1417 end
1418 res.append(html_info(page))
1419 res.append("<div class='description'>")
1420 if nprop.comment == "" then
1421 res.append("<a class=\"newComment\" title=\"32\" tag=\"\">New Comment</a>")
1422 else
1423 res.append("<pre class=\"text_label\" title=\"\" name=\"\" tag=\"\" type=\"1\">{nprop.comment}</pre>")
1424 end
1425 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>")
1426 res.append(html_inheritance(page))
1427 res.append("</div>")
1428 res.append("</article>")
1429 return res.to_s
1430 end
1431
1432 redef fun html_info(page) do
1433 var res = new Buffer
1434 res.append("<div class='info'>")
1435 if mproperty.visibility < public_visibility then res.append("{mproperty.visibility.to_s} ")
1436 if mproperty.intro_mclassdef.mclass != page.mclass then res.append("redef ")
1437 res.append("fun {mproperty.html_namespace(page.mbuilder)}")
1438 res.append("</div>")
1439 res.append("<div style=\"float: right;\"><a id=\"lblDiffCommit\"></a></div>")
1440 return res.to_s
1441 end
1442 end
1443
1444 redef class MVirtualTypeDef
1445 redef fun html_full_desc(page) do
1446 var res = new Buffer
1447 var mprop = mproperty
1448 var is_redef = mprop.intro_mclassdef.mclass != page.mclass
1449 var classes = new Array[String]
1450 classes.add("type")
1451 if is_redef then classes.add("redef")
1452 classes.add(mproperty.visibility.to_s)
1453 res.append("<article class='{classes.join(" ")}' id='{anchor}'>")
1454 res.append("<h3 class='signature'>{mprop.name}: {bound.link(page.mbuilder)}</h3>")
1455 res.append(html_info(page))
1456 res.append("<div class='description'>")
1457
1458 if page.mbuilder.mpropdef2npropdef.has_key(self) and page.mbuilder.mpropdef2npropdef[self].comment != "" then
1459 var nprop = page.mbuilder.mpropdef2npropdef[self]
1460 res.append("<pre class=\"text_label\" title=\"\" name=\"\" tag=\"\" type=\"1\">{nprop.comment}</pre>")
1461 else
1462 res.append("<a class=\"newComment\" title=\"32\" tag=\"\">New Comment</a>")
1463 end
1464 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>")
1465 res.append(html_inheritance(page))
1466 res.append("</div>")
1467 res.append("</article>")
1468 return res.to_s
1469 end
1470
1471 redef fun html_info(page) do
1472 var res = new Buffer
1473 res.append("<div class='info'>")
1474 if mproperty.intro_mclassdef.mclass != page.mclass then res.append("redef ")
1475 res.append("type {mproperty.html_namespace(page.mbuilder)}")
1476 res.append("</div>")
1477 res.append("<div style=\"float: right;\"><a id=\"lblDiffCommit\"></a></div>")
1478 return res.to_s
1479 end
1480 end
1481
1482 #
1483 # Nodes redefs
1484 #
1485
1486 redef class AModule
1487 private fun comment: String do
1488 var ret = new Buffer
1489 if n_moduledecl == null or n_moduledecl.n_doc == null then return ""
1490 for t in n_moduledecl.n_doc.n_comment do
1491 ret.append(t.text.substring_from(1))
1492 end
1493 return ret.to_s.html_escape
1494 end
1495
1496 private fun short_comment: String do
1497 var ret = new Buffer
1498 if n_moduledecl != null and n_moduledecl.n_doc != null then
1499 ret.append(n_moduledecl.n_doc.n_comment.first.text.substring_from(2).replace("\n", ""))
1500 end
1501 return ret.to_s.html_escape
1502 end
1503 end
1504
1505 redef class AStdClassdef
1506 private fun comment: String do
1507 var ret = new Buffer
1508 if n_doc != null then
1509 for t in n_doc.n_comment do ret.append(t.text.substring_from(1))
1510 end
1511 return ret.to_s.html_escape
1512 end
1513
1514 private fun short_comment: String do
1515 var ret = new Buffer
1516 if n_doc != null then ret.append(n_doc.n_comment.first.text.substring_from(2).replace("\n", ""))
1517 return ret.to_s.html_escape
1518 end
1519 end
1520
1521 redef class APropdef
1522 private fun short_comment: String is abstract
1523 private fun html_signature(mbuilder: ModelBuilder): String is abstract
1524 private fun comment: String is abstract
1525 end
1526
1527 redef class AAttrPropdef
1528 redef fun short_comment do
1529 var ret = new Buffer
1530 if n_doc != null then ret.append(n_doc.n_comment.first.text.substring_from(2).replace("\n", ""))
1531 return ret.to_s.html_escape
1532 end
1533
1534 redef private fun comment: String do
1535 var ret = new Buffer
1536 if n_doc != null then
1537 for t in n_doc.n_comment do ret.append(t.text.substring_from(1))
1538 end
1539 return ret.to_s.html_escape
1540 end
1541
1542 redef fun html_signature(mbuilder) do
1543 if n_type != null then return n_type.mtype.link(mbuilder)
1544 return ""
1545 end
1546 end
1547
1548 redef class AMethPropdef
1549 redef fun short_comment do
1550 var ret = new Buffer
1551 if n_doc != null then ret.append(n_doc.n_comment.first.text.substring_from(2).replace("\n", ""))
1552 return ret.to_s.html_escape
1553 end
1554
1555 redef private fun comment: String do
1556 var ret = new Buffer
1557 if n_doc != null then
1558 for t in n_doc.n_comment do ret.append(t.text.substring_from(1))
1559 end
1560 return ret.to_s.html_escape
1561 end
1562
1563 redef fun html_signature(mbuilder) do
1564 if n_signature != null then return n_signature.to_html(mbuilder)
1565 return ""
1566 end
1567 end
1568
1569 redef class ATypePropdef
1570 redef fun short_comment do
1571 var ret = new Buffer
1572 if n_doc != null then ret.append(n_doc.n_comment.first.text.substring_from(2).replace("\n", ""))
1573 return ret.to_s.html_escape
1574 end
1575
1576 redef private fun comment: String do
1577 var ret = new Buffer
1578 if n_doc != null then
1579 for t in n_doc.n_comment do ret.append(t.text.substring_from(1))
1580 end
1581 return ret.to_s.html_escape
1582 end
1583
1584 redef fun html_signature(mbuilder) do
1585 return mpropdef.bound.link(mbuilder)
1586 end
1587 end
1588
1589 redef class ASignature
1590 fun to_html(mbuilder: ModelBuilder): String do
1591 #TODO closures
1592 var res = new Buffer
1593 if not n_params.is_empty then
1594 res.append("(")
1595 for i in [0..n_params.length[ do
1596 res.append(n_params[i].to_html(mbuilder))
1597 if i < n_params.length - 1 then res.append(", ")
1598 end
1599 res.append(")")
1600 end
1601 if n_type != null and n_type.mtype.link(mbuilder) != "" then res.append(": {n_type.mtype.link(mbuilder)}")
1602 return res.to_s
1603 end
1604 end
1605
1606 redef class AParam
1607 fun to_html(mbuilder: ModelBuilder): String do
1608 var ret = "{n_id.text}"
1609 if n_type != null then
1610 ret = "{ret}: {n_type.mtype.link(mbuilder)}"
1611 if n_dotdotdot != null then ret = "{ret}..."
1612 end
1613 return ret
1614 end
1615 end
1616
1617 # Create a tool context to handle options and paths
1618 var toolcontext = new ToolContext
1619
1620 # Here we launch the nit index
1621 var nitdoc = new NitdocContext(toolcontext)
1622 nitdoc.start