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