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