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