ni_nitdoc: better display off mproperties
[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(model.mmodules)
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 mmodules: Array[MModule]
379
380 init(mmodules: Array[MModule]) do
381 self.mmodules = mmodules
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 ls = new List[nullable MModule]
407 var sorted = mmodules
408 var sorterp = new ComparableSorter[MModule]
409 sorterp.sort(sorted)
410 append("<article class='modules filterable'></article>")
411 append("<h2>Modules</h2>")
412 append("<ul>")
413 for mmodule in sorted do
414 if mmodule.public_owner != null and not ls.has(mmodule.public_owner) then
415 ls.add(mmodule.public_owner)
416 append("<li><a href='{mmodule.public_owner.name}.html'>(mmodule.public_owner.name)</a></li>")
417 end
418 end
419 append("</ul>")
420 append("</article>")
421 end
422
423 # Add to content classes modules
424 fun classes_column do
425 var sorted = mmodules.first.imported_mclasses.to_a
426 var sorterp = new ComparableSorter[MClass]
427 sorterp.sort(sorted)
428 append("<article class='classes filterable'>")
429 append("<h2>Classes</h2>")
430 append("<ul>")
431 for mclass in sorted do
432 append("<li><a href='{mclass}.html'>(mclass.name)</a></li>")
433 end
434 append("</ul>")
435 append("</article>")
436 end
437
438 # Insert the properties column of fullindex page
439 fun properties_column do
440 append("<article class='classes filterable'>")
441 append("<h2>Properties</h2>")
442 append("<ul>")
443 var sorted_imported = mmodules.first.imported_methods.to_a
444 var sorted_redef = mmodules.first.redef_methods.to_a
445 var sorterp = new ComparableSorter[MProperty]
446 sorterp.sort(sorted_imported)
447 sorterp.sort(sorted_redef)
448
449 for method in sorted_imported do
450 if method.visibility is none_visibility or method.visibility is intrude_visibility then continue
451 append("<li class='intro'</li>")
452 append("<span title='introduction'>I</span>&nbsp;")
453 append("<a href='{method.intro_mclassdef.mclass.name}.html' title=''>{method.name} ({method.intro_mclassdef.mclass.name})</a>")
454 append("</li>")
455 end
456
457 for method in sorted_redef do
458 if method.visibility is none_visibility or method.visibility is intrude_visibility then continue
459 append("<li class='redef'>")
460 append("<span title='redefinition'>R</span>&nbsp;")
461 append("<a href='{method.intro_mclassdef.mclass.name}.html' title=''>{method.name} ({method.intro_mclassdef.mclass.name})</span>")
462 append("</li>")
463 end
464 append("</ul>")
465 append("</article>")
466 end
467
468 end
469
470 # A module page
471 class NitdocModule
472 super NitdocPage
473
474 private var mmodule: MModule
475 private var mbuilder: ModelBuilder
476
477 init(mmodule: MModule, mbuilder: ModelBuilder, dot_dir: nullable String) do
478 self.mmodule = mmodule
479 self.mbuilder = mbuilder
480 self.dot_dir = dot_dir
481 end
482
483 redef fun head do
484 super
485 var amodule = mbuilder.mmodule2nmodule[mmodule]
486 append("<title>{mmodule.name} module | {amodule.short_comment}</title>")
487 end
488
489 redef fun menu do
490 append("<li><a href='index.html'>Overview</a></li>")
491 append("<li class='current'>{mmodule.name}</li>")
492 append("<li><a href='full-index.html'>Full Index</a></li>")
493 end
494
495 redef fun content do
496 sidebar
497 append("<div class='content'>")
498 append("<h1>{mmodule.name}</h1>")
499 append("<div class='subtitle'>{mmodule.html_signature(mbuilder)}</div>")
500 append(mmodule.html_full_comment(mbuilder))
501 process_generate_dot
502 classes
503 properties
504 append("</div>")
505 end
506
507 fun process_generate_dot do
508 var name = "dep_{mmodule.name}"
509 var op = new Buffer
510 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")
511 for m in mmodule.in_importation.poset do
512 var public_owner = m.public_owner
513 if public_owner == null then
514 public_owner = m
515 if m == mmodule then
516 op.append("\"{m.name}\"[shape=box,margin=0.03];\n")
517 else
518 op.append("\"{m.name}\"[URL=\"{m.name}.html\"];\n")
519 end
520 end
521 for imported in m.in_importation.direct_greaters do
522 if imported.public_owner == null then
523 op.append("\"{public_owner.name}\"->\"{imported.name}\";\n")
524 end
525 end
526 end
527 op.append("\}\n")
528 generate_dot(op.to_s, name, "Dependency graph for module {mmodule.name}")
529 end
530
531 fun sidebar do
532 var amodule = mbuilder.mmodule2nmodule[mmodule]
533 append("<div class='menu'>")
534 append("<nav>")
535 append("<h3>Module Hierarchy</h3>")
536 var dependencies = new Array[MModule]
537 for dep in mmodule.in_importation.greaters do
538 if dep == mmodule or dep.public_owner != null then continue
539 dependencies.add(dep)
540 end
541 if dependencies.length > 0 then
542 append("<h4>All dependencies</h4>")
543 display_module_list(dependencies)
544 end
545 var clients = new Array[MModule]
546 for dep in mmodule.in_importation.smallers do
547 if dep == mmodule or dep.public_owner != null then continue
548 clients.add(dep)
549 end
550 if clients.length > 0 then
551 append("<h4>All clients</h4>")
552 display_module_list(clients)
553 end
554 append("</nav>")
555 if mmodule.in_nesting.direct_greaters.length > 0 then
556 append("<nav>")
557 append("<h3>Nested Modules</h3>")
558 display_module_list(mmodule.in_nesting.direct_greaters.to_a)
559 append("</nav>")
560 end
561 append("</div>")
562 end
563
564 private fun display_module_list(list: Array[MModule]) do
565 append("<ul>")
566 var sorter = new ComparableSorter[MModule]
567 sorter.sort(list)
568 for m in list do append("<li>{m.link(mbuilder)}</li>")
569 append("</ul>")
570 end
571
572 # display the class column
573 fun classes do
574 var amodule = mbuilder.mmodule2nmodule[mmodule]
575 var intro_mclasses = mmodule.intro_mclasses
576 var redef_mclasses = mmodule.redef_mclasses
577 var all_mclasses = new HashSet[MClass]
578 for m in mmodule.in_nesting.greaters do
579 all_mclasses.add_all(m.intro_mclasses)
580 all_mclasses.add_all(m.redef_mclasses)
581 end
582 all_mclasses.add_all(intro_mclasses)
583 all_mclasses.add_all(redef_mclasses)
584
585 var sorted = new Array[MClass]
586 sorted.add_all(all_mclasses)
587 var sorter = new ComparableSorter[MClass]
588 sorter.sort(sorted)
589 append("<div class='module'>")
590 append("<article class='classes filterable'>")
591 append("<h2>Classes</h2>")
592 append("<ul>")
593 for c in sorted do
594 if redef_mclasses.has(c) and c.intro_mmodule.public_owner != mmodule then
595 append("<li class='redef'>")
596 append("<span title='refined in this module'>R </span>")
597 else
598 append("<li class='intro'>")
599 append("<span title='introduced in this module'>I </span>")
600 end
601 append(c.link(mbuilder))
602 append("</li>")
603 end
604 append("</ul>")
605 append("</article>")
606 append("</div>")
607 end
608
609 # display the property column
610 fun properties do
611 # get properties
612 var amodule = mbuilder.mmodule2nmodule[mmodule]
613 var mpropdefs = new HashSet[MPropDef]
614 for m in mmodule.in_nesting.greaters do
615 for c in m.mclassdefs do mpropdefs.add_all(c.mpropdefs)
616 end
617 for c in mmodule.mclassdefs do mpropdefs.add_all(c.mpropdefs)
618 var sorted = mpropdefs.to_a
619 var sorter = new ComparableSorter[MPropDef]
620 sorter.sort(sorted)
621 # display properties in one column
622 append("<article class='properties filterable'>")
623 append("<h2>Properties</h2>")
624 append("<ul>")
625 for mprop in sorted do
626 if mprop isa MAttributeDef then continue
627 if mprop.mproperty.visibility <= none_visibility then continue
628 append(mprop.html_list_item(mbuilder))
629 end
630 append("</ul>")
631 append("</article>")
632 end
633 end
634
635 # A class page
636 class NitdocClass
637 super NitdocPage
638
639 private var mclass: MClass
640 private var mbuilder: ModelBuilder
641 private var nitdoc: Nitdoc
642 private var vtypes = new HashSet[MVirtualTypeDef]
643 private var consts = new HashSet[MMethodDef]
644 private var meths = new HashSet[MMethodDef]
645 private var inherited = new HashSet[MPropDef]
646
647 init(mclass: MClass, nitdoc: Nitdoc, dot_dir: nullable String, source: nullable String) do
648 self.mclass = mclass
649 self.mbuilder = nitdoc.modelbuilder
650 self.nitdoc = nitdoc
651 self.dot_dir = dot_dir
652 self.source = source
653 # load properties
654 for mclassdef in mclass.mclassdefs do
655 for mpropdef in mclassdef.mpropdefs do
656 if mpropdef.mproperty.visibility <= none_visibility then continue
657 if mpropdef isa MVirtualTypeDef then vtypes.add(mpropdef)
658 if mpropdef isa MMethodDef then
659 if mpropdef.mproperty.is_init then
660 consts.add(mpropdef)
661 else
662 meths.add(mpropdef)
663 end
664 end
665 end
666 end
667 # get inherited properties
668 for mprop in mclass.inherited_mproperties do
669 var mpropdef = mprop.intro
670 if mprop.visibility <= none_visibility then continue
671 if mpropdef isa MVirtualTypeDef then vtypes.add(mpropdef)
672 if mpropdef isa MMethodDef then
673 if mpropdef.mproperty.is_init then
674 consts.add(mpropdef)
675 else
676 meths.add(mpropdef)
677 end
678 end
679 inherited.add(mpropdef)
680 end
681 end
682
683 redef fun head do
684 super
685 var nclass = mbuilder.mclassdef2nclassdef[mclass.intro]
686 if nclass isa AStdClassdef then
687 append("<title>{mclass.name} class | {nclass.short_comment}</title>")
688 else
689 append("<title>{mclass.name} class</title>")
690 end
691 end
692
693 redef fun menu do
694 append("<li><a href='index.html'>Overview</a></li>")
695 var public_owner = mclass.public_owner
696 if public_owner is null then
697 append("<li>{mclass.intro_mmodule.link(mbuilder)}</li>")
698 else
699 append("<li>{public_owner.link(mbuilder)}</li>")
700 end
701 append("<li class='current'>{mclass.name}</li>")
702 append("<li><a href='full-index.html'>Full Index</a></li>")
703 end
704
705 redef fun content do
706 append("<div class='menu'>")
707 properties_column
708 inheritance_column
709 append("</div>")
710 append("<div class='content'>")
711 class_doc
712 append("</div>")
713 end
714
715 fun properties_column do
716 var sorter = new ComparableSorter[MPropDef]
717 append("<nav class='properties filterable'>")
718 append("<h3>Properties</h3>")
719 # virtual types
720 if vtypes.length > 0 then
721 var vts = new Array[MVirtualTypeDef]
722 vts.add_all(vtypes)
723 sorter.sort(vts)
724 append("<h4>Virtual Types</h4>")
725 append("<ul>")
726 for mprop in vts do
727 append(mprop.html_sidebar_item(self))
728 end
729 append("</ul>")
730 end
731 # constructors
732 if consts.length > 0 then
733 var cts = new Array[MMethodDef]
734 cts.add_all(consts)
735 sorter.sort(cts)
736 append("<h4>Constructors</h4>")
737 append("<ul>")
738 for mprop in cts do
739 append(mprop.html_sidebar_item(self))
740 end
741 append("</ul>")
742 end
743 # methods
744 if meths.length > 0 then
745 var mts = new Array[MMethodDef]
746 mts.add_all(meths)
747 sorter.sort(mts)
748 append("<h4>Methods</h4>")
749 append("<ul>")
750 for mprop in mts do
751 if mprop.mproperty.intro_mclassdef.mclass.name == "Object" then continue
752 append(mprop.html_sidebar_item(self))
753 end
754 append("</ul>")
755 end
756 append("</nav>")
757 end
758
759 fun inheritance_column do
760 var sorted = new Array[MClass]
761 var sorterp = new ComparableSorter[MClass]
762 append("<nav>")
763 append("<h3>Inheritance</h3>")
764 if mclass.ancestors.length > 1 then
765 sorted = mclass.ancestors.to_a
766 sorterp.sort(sorted)
767 append("<h4>Superclasses</h4>")
768 append("<ul>")
769 for sup in sorted do
770 if sup == mclass then continue
771 append("<li><a href='{sup.name}.html'>{sup.name}</a></li>")
772 end
773 append("</ul>")
774 end
775
776 if mclass.descendants.length <= 1 then
777 append("<h4>No Known Subclasses</h4>")
778 else if mclass.descendants.length <= 100 then
779 sorted = mclass.descendants.to_a
780 sorterp.sort(sorted)
781 append("<h4>Subclasses</h4>")
782 append("<ul>")
783 for sub in sorted do
784 if sub == mclass then continue
785 append("<li><a href='{sub.name}.html'>{sub.name}</a></li>")
786 end
787 append("</ul>")
788 else if mclass.children.length <= 100 then
789 sorted = mclass.children.to_a
790 sorterp.sort(sorted)
791 append("<h4>Direct Subclasses Only</h4>")
792 append("<ul>")
793 for sub in sorted do
794 if sub == mclass then continue
795 append("<li><a href='{sub.name}.html'>{sub.name}</a></li>")
796 end
797 append("</ul>")
798 else
799 append("<h4>Too much Subclasses to list</h4>")
800 end
801 append("</nav>")
802 end
803
804 fun class_doc do
805 # title
806 append("<h1>{mclass.html_signature}</h1>")
807 append("<div class='subtitle info'>{mclass.html_full_signature(mbuilder)}")
808
809 append("</div>")
810 # comment
811 var nclass = mbuilder.mclassdef2nclassdef[mclass.intro]
812 append("<div style=\"float: right;\"><a id=\"lblDiffCommit\"></a></div>")
813 append("<section class='description'>")
814 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>")
815 process_generate_dot
816 append("</section>")
817 # concerns
818 var concern2meths = new ArrayMap[MModule, Array[MMethodDef]]
819 var sorted_meths = new Array[MMethodDef]
820 var sorted = new Array[MModule]
821 sorted_meths.add_all(meths)
822 nitdoc.mainmodule.linearize_mpropdefs(sorted_meths)
823 for meth in meths do
824 if inherited.has(meth) then continue
825 var mmodule = meth.mclassdef.mmodule
826 if not concern2meths.has_key(mmodule) then
827 sorted.add(mmodule)
828 concern2meths[mmodule] = new Array[MMethodDef]
829 end
830 concern2meths[mmodule].add(meth)
831 end
832 var sections = new ArrayMap[MModule, Array[MModule]]
833 for mmodule in concern2meths.keys do
834 var owner = mmodule.public_owner
835 if owner == null then owner = mmodule
836 if not sections.has_key(owner) then sections[owner] = new Array[MModule]
837 if owner != mmodule then sections[owner].add(mmodule)
838 end
839 append("<section class='concerns'>")
840 append("<h2 class='section-header'>Concerns</h2>")
841 append("<ul>")
842 for owner, mmodules in sections do
843 var nowner = mbuilder.mmodule2nmodule[owner]
844 append("<li>")
845 if nowner.short_comment.is_empty then
846 append("<a href=\"#MOD_{owner.name}\">{owner.name}</a>")
847 else
848 append("<a href=\"#MOD_{owner.name}\">{owner.name}</a>: {nowner.short_comment}")
849 end
850 if not mmodules.is_empty then
851 append("<ul>")
852 for mmodule in mmodules do
853 var nmodule = mbuilder.mmodule2nmodule[mmodule]
854 if nmodule.short_comment.is_empty then
855 append("<li><a href=\"#MOD_{mmodule.name}\">{mmodule.name}</a></li>")
856 else
857 append("<li><a href=\"#MOD_{mmodule.name}\">{mmodule.name}</a>: {nmodule.short_comment}</li>")
858 end
859 end
860 append("</ul>")
861 end
862 append("</li>")
863 end
864 append("</ul>")
865 append("</section>")
866 # properties
867 var prop_sorter = new ComparableSorter[MPropDef]
868 var sorterprop = new ComparableSorter[MProperty]
869 var sorterc = new ComparableSorter[MClass]
870 var lmmodule = new List[MModule]
871 # virtual and formal types
872 var local_vtypes = new Array[MVirtualTypeDef]
873 for vt in vtypes do if not inherited.has(vt) then local_vtypes.add(vt)
874 if local_vtypes.length > 0 or mclass.arity > 0 then
875 append("<section class='types'>")
876 append("<h2>Formal and Virtual Types</h2>")
877 # formal types
878 if mclass.arity > 0 and nclass isa AStdClassdef then
879 for ft, bound in mclass.parameter_types do
880 append("<article id='{ft}'>")
881 append("<h3 class='signature'>{ft}: {bound.link(mbuilder)}</h3>")
882 append("<div class=\"info\">formal generic type</div>")
883 append("</article>")
884 end
885 end
886 # virtual types
887 prop_sorter.sort(local_vtypes)
888 for prop in local_vtypes do append(prop.html_full_desc(self))
889 append("</section>")
890 end
891 # constructors
892 var local_consts = new Array[MMethodDef]
893 for const in consts do if not inherited.has(const) then local_consts.add(const)
894 prop_sorter.sort(local_consts)
895 if local_consts.length > 0 then
896 append("<section class='constructors'>")
897 append("<h2 class='section-header'>Constructors</h2>")
898 for prop in local_consts do append(prop.html_full_desc(self))
899 append("</section>")
900 end
901 # methods
902 if not concern2meths.is_empty then
903 append("<section class='methods'>")
904 append("<h2 class='section-header'>Methods</h2>")
905 for owner, mmodules in sections do
906 append("<a id=\"MOD_{owner.name}\"></a>")
907 if owner != mclass.intro_mmodule and owner != mclass.public_owner then
908 var nowner = mbuilder.mmodule2nmodule[owner]
909 append("<h3 class=\"concern-toplevel\">Methods refined in {owner.link(mbuilder)}</h3>")
910 if nowner.short_comment.is_empty then
911 append("<p class=\"concern-doc\">{owner.name}</p>")
912 else
913 append("<p class=\"concern-doc\">{owner.name}: {nowner.short_comment}</p>")
914 end
915 end
916 if concern2meths.has_key(owner) then
917 var mmethods = concern2meths[owner]
918 prop_sorter.sort(mmethods)
919 for prop in mmethods do append(prop.html_full_desc(self))
920 end
921 for mmodule in mmodules do
922 append("<a id=\"MOD_{mmodule.name}\"></a>")
923 var nmodule = mbuilder.mmodule2nmodule[mmodule]
924 if mmodule != mclass.intro_mmodule and mmodule != mclass.public_owner then
925 if nmodule.short_comment.is_empty then
926 append("<p class=\"concern-doc\">{mmodule.name}</p>")
927 else
928 append("<p class=\"concern-doc\">{mmodule.name}: {nmodule.short_comment}</p>")
929 end
930 end
931 var mmethods = concern2meths[mmodule]
932 prop_sorter.sort(mmethods)
933 for prop in mmethods do append(prop.html_full_desc(self))
934 end
935 end
936 end
937 # inherited properties
938 if inherited.length > 0 then
939 var sorted_inherited = new Array[MPropDef]
940 sorted_inherited.add_all(inherited)
941 nitdoc.mainmodule.linearize_mpropdefs(sorted_inherited)
942 var classes = new ArrayMap[MClass, Array[MPropDef]]
943 for mmethod in sorted_inherited.reversed do
944 var mclass = mmethod.mclassdef.mclass
945 if not classes.has_key(mclass) then classes[mclass] = new Array[MPropDef]
946 classes[mclass].add(mmethod)
947 end
948 append("<h3>Inherited Properties</h3>")
949 for c, mmethods in classes do
950 prop_sorter.sort(mmethods)
951 append("<p>Defined in {c.link(mbuilder)}: ")
952 for i in [0..mmethods.length[ do
953 var mmethod = mmethods[i]
954 append(mmethod.link(mbuilder))
955 if i <= mmethods.length - 1 then append(", ")
956 end
957 append("</p>")
958 end
959 end
960 append("</section>")
961 end
962
963 fun process_generate_dot do
964 var pe = nitdoc.class_hierarchy[mclass]
965 var cla = new HashSet[MClass]
966 var sm = new HashSet[MClass]
967 var sm2 = new HashSet[MClass]
968 sm.add(mclass)
969 while cla.length + sm.length < 10 and sm.length > 0 do
970 cla.add_all(sm)
971 sm2.clear
972 for x in sm do
973 sm2.add_all(pe.poset[x].direct_smallers)
974 end
975 var t = sm
976 sm = sm2
977 sm2 = t
978 end
979 cla.add_all(pe.greaters)
980
981 var op = new Buffer
982 var name = "dep_{mclass.name}"
983 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")
984 for c in cla do
985 if c == mclass then
986 op.append("\"{c.name}\"[shape=box,margin=0.03];\n")
987 else
988 op.append("\"{c.name}\"[URL=\"{c.name}.html\"];\n")
989 end
990 for c2 in pe.poset[c].direct_greaters do
991 if not cla.has(c2) then continue
992 op.append("\"{c.name}\"->\"{c2.name}\";\n")
993 end
994 if not pe.poset[c].direct_smallers.is_empty then
995 var others = true
996 for c2 in pe.poset[c].direct_smallers do
997 if cla.has(c2) then others = false
998 end
999 if others then
1000 op.append("\"{c.name}...\"[label=\"\"];\n")
1001 op.append("\"{c.name}...\"->\"{c.name}\"[style=dotted];\n")
1002 end
1003 end
1004 end
1005 op.append("\}\n")
1006 generate_dot(op.to_s, name, "Dependency graph for class {mclass.name}")
1007 end
1008 end
1009
1010 #
1011 # Model redefs
1012 #
1013
1014 redef class MModule
1015 super Comparable
1016 redef type OTHER: MModule
1017 redef fun <(other: OTHER): Bool do return self.name < other.name
1018
1019 # Get the list of all methods in a module
1020 fun imported_methods: Set[MMethod] do
1021 var methods = new HashSet[MMethod]
1022 for mclass in imported_mclasses do
1023 for method in mclass.intro_methods do
1024 methods.add(method)
1025 end
1026 end
1027 return methods
1028 end
1029
1030 # Get the list aof all refined methods in a module
1031 fun redef_methods: Set[MMethod] do
1032 var methods = new HashSet[MMethod]
1033 for mclass in redef_mclasses do
1034 for method in mclass.intro_methods do
1035 methods.add(method)
1036 end
1037 end
1038 return methods
1039 end
1040
1041 # Return a link (html a tag) to the nitdoc module page
1042 fun link(mbuilder: ModelBuilder): String do
1043 return "<a href='{name}.html' title='{mbuilder.mmodule2nmodule[self].short_comment}'>{name}</a>"
1044 end
1045
1046 # Return the module signature decorated with html
1047 fun html_signature(mbuilder: ModelBuilder): String do
1048 return "<span>module {html_full_namespace(mbuilder)}</span>"
1049 end
1050
1051 # Return the module full namespace decorated with html
1052 fun html_full_namespace(mbuilder: ModelBuilder): String do
1053 var res = new Buffer
1054 res.append("<span>")
1055 var mowner = public_owner
1056 if mowner != null then
1057 res.append(public_owner.html_namespace(mbuilder))
1058 res.append("::")
1059 end
1060 res.append(self.link(mbuilder))
1061 res.append("</span>")
1062 return res.to_s
1063 end
1064
1065 # Return the module full namespace decorated with html
1066 fun html_namespace(mbuilder: ModelBuilder): String do
1067 var res = new Buffer
1068 res.append("<span>")
1069 var mowner = public_owner
1070 if mowner != null then
1071 res.append(public_owner.html_namespace(mbuilder))
1072 else
1073 res.append(self.link(mbuilder))
1074 end
1075 res.append("</span>")
1076 return res.to_s
1077 end
1078
1079 # Return the full comment of the module decorated with html
1080 fun html_full_comment(mbuilder: ModelBuilder): String do
1081 var res = new Buffer
1082 res.append("<div id='description'>")
1083 res.append("<pre class='text_label'>{mbuilder.mmodule2nmodule[self].comment}</pre>")
1084 res.append("<textarea class='edit' rows='1' cols='76' id='fileContent'></textarea>")
1085 res.append("<a id='cancelBtn'>Cancel</a>")
1086 res.append("<a id='commitBtn'>Commit</a>")
1087 res.append("<pre class='text_label' id='preSave' type='2'></pre>")
1088 res.append("</div>")
1089 return res.to_s
1090 end
1091 end
1092
1093 redef class MClass
1094 super Comparable
1095 redef type OTHER: MClass
1096 redef fun <(other: OTHER): Bool do return self.name < other.name
1097
1098 # Return the module signature decorated with html
1099 fun html_full_signature(mbuilder: ModelBuilder): String do
1100 var res = new Buffer
1101 if visibility <= none_visibility then
1102 res.append("private ")
1103 else if visibility == protected_visibility then
1104 res.append("protected ")
1105 end
1106 res.append("{kind} {html_namespace(mbuilder)}")
1107 return res.to_s
1108 end
1109
1110 # Add type parameters
1111 fun html_signature: String do
1112 if arity > 0 then
1113 return "{name}[{intro.parameter_names.join(", ")}]"
1114 else
1115 return name
1116 end
1117 end
1118
1119 # Return a link (html a tag) to the nitdoc class page
1120 fun link(mbuilder: ModelBuilder): String do
1121 if mbuilder.mclassdef2nclassdef.has_key(intro) then
1122 var nclass = mbuilder.mclassdef2nclassdef[intro]
1123 if nclass isa AStdClassdef then
1124 return "<a href='{name}.html' title=\"{nclass.short_comment}\">{html_signature}</a>"
1125 else
1126 return "<a href='{name}.html'>{html_signature}</a>"
1127 end
1128 else
1129 return "<a href='{name}.html'>{html_signature}</a>"
1130 end
1131 end
1132
1133 # Return the class namespace decorated with html
1134 fun html_namespace(mbuilder: ModelBuilder): String do
1135 var res = new Buffer
1136 res.append(intro_mmodule.html_namespace(mbuilder))
1137 res.append("::<span>{self.link(mbuilder)}</span>")
1138 return res.to_s
1139 end
1140
1141 fun link_anchor: String do
1142 return "{name}.html"
1143 end
1144
1145 # Escape name for html output
1146 redef fun name do return super.html_escape
1147 end
1148
1149 redef class MProperty
1150 super Comparable
1151 redef type OTHER: MProperty
1152 redef fun <(other: OTHER): Bool do return self.name < other.name
1153
1154 fun anchor: String do
1155 return "PROP_{c_name}"
1156 end
1157
1158 # Return the property namespace decorated with html
1159 fun html_namespace(mbuilder: ModelBuilder): String do
1160 return "{intro_mclassdef.mclass.html_namespace(mbuilder)}::<span>{intro.link(mbuilder)}</span>"
1161 end
1162
1163 # Return the property signature decorated with html
1164 fun html_signature(mbuilder: ModelBuilder): String do
1165 var nprop = mbuilder.mpropdef2npropdef[intro]
1166 return "{name}{nprop.html_signature(mbuilder)}"
1167 end
1168
1169 # Escape name for html output
1170 redef fun name do return super.html_escape
1171 end
1172
1173 redef class MType
1174 fun link(mbuilder: ModelBuilder): String is abstract
1175 end
1176
1177 redef class MClassType
1178 redef fun link(mbuilder) do return mclass.link(mbuilder)
1179 end
1180
1181 redef class MNullableType
1182 redef fun link(mbuilder) do return "nullable {mtype.link(mbuilder)}"
1183 end
1184
1185 redef class MClassDef
1186 # Return the classdef namespace decorated with html
1187 fun html_namespace(mbuilder: ModelBuilder): String do
1188 var res = new Buffer
1189 res.append(mmodule.html_full_namespace(mbuilder))
1190 res.append("::<span>{self.mclass.link(mbuilder)}</span>")
1191 return res.to_s
1192 end
1193 end
1194
1195 redef class MPropDef
1196 super Comparable
1197 redef type OTHER: MPropDef
1198 redef fun <(other: OTHER): Bool do return self.mproperty.name < other.mproperty.name
1199
1200 # Return a link (html a tag) to the nitdoc class page
1201 fun link(mbuilder: ModelBuilder): String do
1202 if mbuilder.mpropdef2npropdef.has_key(self) then
1203 var nprop = mbuilder.mpropdef2npropdef[self]
1204 return "<a href=\"{mclassdef.mclass.name}.html#{mproperty.anchor}\" title=\"{nprop.short_comment}\">{mproperty.name}</a>"
1205 else
1206 return "<a href=\"{mclassdef.mclass.name}.html#{mproperty.anchor}\">{mproperty.name}</a>"
1207 end
1208 end
1209
1210 # Return a list item for the mpropdef
1211 fun html_list_item(mbuilder: ModelBuilder): String do
1212 var res = new Buffer
1213 if is_intro then
1214 res.append("<li class='intro'>")
1215 res.append("<span title='introduction'>I</span>&nbsp;{link(mbuilder)} ({mclassdef.mclass.name})")
1216 res.append("</li>")
1217 else
1218 res.append("<li class='redef'>")
1219 res.append("<span title='redefinition'>R</span>&nbsp;{link(mbuilder)} ({mclassdef.mclass.name})")
1220 res.append("</li>")
1221 end
1222 return res.to_s
1223 end
1224
1225 # Return a list item for the mpropdef
1226 fun html_sidebar_item(page: NitdocClass): String do
1227 var res = new Buffer
1228 if is_intro and mclassdef.mclass == page.mclass then
1229 res.append("<li class='intro'>")
1230 res.append("<span title='Introduced'>I</span>")
1231 else if is_intro and mclassdef.mclass != page.mclass then
1232 res.append("<li class='inherit'>")
1233 res.append("<span title='Inherited'>H</span>")
1234 else
1235 res.append("<li class='redef'>")
1236 res.append("<span title='Redefined'>R</span>")
1237 end
1238 res.append(link(page.mbuilder))
1239 res.append("</li>")
1240 return res.to_s
1241 end
1242
1243 fun html_full_desc(page: NitdocClass): String is abstract
1244 fun html_info(page: NitdocClass): String is abstract
1245 end
1246
1247 redef class MMethodDef
1248 redef fun html_full_desc(page) do
1249 if not page.mbuilder.mpropdef2npropdef.has_key(self) then
1250 return ""
1251 end
1252 var res = new Buffer
1253 var mprop = mproperty
1254 var nprop = page.mbuilder.mpropdef2npropdef[self]
1255 var classes = new Array[String]
1256 var is_redef = mprop.intro_mclassdef.mclass != page.mclass
1257 classes.add("fun")
1258 if mprop.is_init then classes.add("init")
1259 if is_redef then classes.add("redef")
1260 if mprop.visibility == none_visibility then
1261 classes.add("private")
1262 else if mprop.visibility == protected_visibility then
1263 classes.add("protected")
1264 else
1265 classes.add("public")
1266 end
1267 res.append("<article class='{classes.join(" ")}' id='{mprop.anchor}'>")
1268 res.append("<h3 class='signature'>{mprop.html_signature(page.mbuilder)}</h3>")
1269 res.append(html_info(page))
1270 res.append("<div class='description'>")
1271 if nprop.comment == "" then
1272 res.append("<a class=\"newComment\" title=\"32\" tag=\"\">New Comment</a>")
1273 else
1274 res.append("<pre class=\"text_label\" title=\"\" name=\"\" tag=\"\" type=\"1\">{nprop.comment}</pre>")
1275 end
1276 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>")
1277 # definitions block
1278 res.append("<p>")
1279 page.nitdoc.mainmodule.linearize_mpropdefs(mprop.mpropdefs)
1280 var previous_defs = new Array[MMethodDef]
1281 var next_defs = new Array[MMethodDef]
1282 var self_passed = false
1283 for def in mprop.mpropdefs do
1284 if def == self then
1285 self_passed = true
1286 continue
1287 end
1288 if not self_passed then
1289 if not page.mclass.ancestors.has(def.mclassdef.mclass) then continue
1290 if def.is_intro then continue
1291 previous_defs.add(def)
1292 else
1293 if not page.mclass.descendants.has(def.mclassdef.mclass) then continue
1294 next_defs.add(def)
1295 end
1296 end
1297 res.append("defined by {mclassdef.mmodule.html_full_namespace(page.mbuilder)}")
1298 if not is_intro then
1299 res.append(", introduced by {mprop.intro.mclassdef.mclass.link(page.mbuilder)}")
1300 end
1301 if not previous_defs.is_empty then
1302 res.append(", inherited from ")
1303 for i in [0..previous_defs.length[ do
1304 res.append(previous_defs[i].mclassdef.mclass.link(page.mbuilder))
1305 if i < previous_defs.length - 1 then res.append(", ")
1306 end
1307 end
1308 if not next_defs.is_empty then
1309 res.append(", redefined by ")
1310 for i in [0..next_defs.length[ do
1311 res.append(next_defs[i].mclassdef.mclass.link(page.mbuilder))
1312 if i < next_defs.length - 1 then res.append(", ")
1313 end
1314 end
1315 res.append(".</p>")
1316 res.append("</div>")
1317 res.append("</article>")
1318 return res.to_s
1319 end
1320
1321 redef fun html_info(page) do
1322 var res = new Buffer
1323 res.append("<div class='info'>")
1324 if mproperty.visibility <= none_visibility then
1325 res.append("private ")
1326 else if mproperty.visibility <= protected_visibility then
1327 res.append("protected ")
1328 end
1329 if mproperty.intro_mclassdef.mclass != page.mclass then res.append("redef ")
1330 res.append("fun {mproperty.html_namespace(page.mbuilder)}")
1331 res.append("</div>")
1332 res.append("<div style=\"float: right;\"><a id=\"lblDiffCommit\"></a></div>")
1333 return res.to_s
1334 end
1335 end
1336
1337 redef class MVirtualTypeDef
1338 redef fun html_full_desc(page) do
1339 var res = new Buffer
1340 var mprop = mproperty
1341 var is_redef = mprop.intro_mclassdef.mclass != page.mclass
1342 var classes = new Array[String]
1343 classes.add("type")
1344 if is_redef then classes.add("redef")
1345 if mprop.visibility == none_visibility then
1346 classes.add("private")
1347 else if mprop.visibility == protected_visibility then
1348 classes.add("protected")
1349 else
1350 classes.add("public")
1351 end
1352 res.append("<article class='{classes.join(" ")}' id='{mprop.anchor}'>")
1353 res.append("<h3 class='signature'>{mprop.name}: {bound.link(page.mbuilder)}</h3>")
1354 res.append(html_info(page))
1355 res.append("<div class='description'>")
1356
1357 if page.mbuilder.mpropdef2npropdef.has_key(self) and page.mbuilder.mpropdef2npropdef[self].comment != "" then
1358 var nprop = page.mbuilder.mpropdef2npropdef[self]
1359 res.append("<pre class=\"text_label\" title=\"\" name=\"\" tag=\"\" type=\"1\">{nprop.comment}</pre>")
1360 else
1361 res.append("<a class=\"newComment\" title=\"32\" tag=\"\">New Comment</a>")
1362 end
1363 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>")
1364 # definitions block
1365 res.append("<p>")
1366 page.nitdoc.mainmodule.linearize_mpropdefs(mprop.mpropdefs)
1367 var previous_defs = new Array[MVirtualTypeDef]
1368 var next_defs = new Array[MVirtualTypeDef]
1369 var self_passed = false
1370 for def in mprop.mpropdefs do
1371 if def == self then
1372 self_passed = true
1373 continue
1374 end
1375 if not self_passed then
1376 if not page.mclass.ancestors.has(def.mclassdef.mclass) then continue
1377 if def.is_intro then continue
1378 previous_defs.add(def)
1379 else
1380 if not page.mclass.descendants.has(def.mclassdef.mclass) then continue
1381 next_defs.add(def)
1382 end
1383 end
1384 res.append("defined by {mclassdef.mmodule.html_full_namespace(page.mbuilder)}")
1385 if not is_intro then
1386 res.append(", introduced by {mprop.intro.mclassdef.mclass.link(page.mbuilder)}")
1387 end
1388 if not previous_defs.is_empty then
1389 res.append(", inherited from ")
1390 for i in [0..previous_defs.length[ do
1391 res.append(previous_defs[i].mclassdef.mclass.link(page.mbuilder))
1392 if i < previous_defs.length - 1 then res.append(", ")
1393 end
1394 end
1395 if not next_defs.is_empty then
1396 res.append(", redefined by ")
1397 for i in [0..next_defs.length[ do
1398 res.append(next_defs[i].mclassdef.mclass.link(page.mbuilder))
1399 if i < next_defs.length - 1 then res.append(", ")
1400 end
1401 end
1402 res.append(".</p>")
1403 res.append("</div>")
1404 res.append("</article>")
1405 return res.to_s
1406 end
1407
1408 redef fun html_info(page) do
1409 var res = new Buffer
1410 res.append("<div class='info'>")
1411 if mproperty.intro_mclassdef.mclass != page.mclass then res.append("redef ")
1412 res.append("type {mproperty.html_namespace(page.mbuilder)}")
1413 res.append("</div>")
1414 res.append("<div style=\"float: right;\"><a id=\"lblDiffCommit\"></a></div>")
1415 return res.to_s
1416 end
1417 end
1418
1419 #
1420 # Nodes redefs
1421 #
1422
1423 redef class AModule
1424 private fun comment: String do
1425 var ret = new Buffer
1426 if n_moduledecl is null or n_moduledecl.n_doc is null then ret
1427 if n_moduledecl.n_doc is null then return ""
1428 for t in n_moduledecl.n_doc.n_comment do
1429 ret.append(t.text.substring_from(1))
1430 end
1431 return ret.to_s.html_escape
1432 end
1433
1434 private fun short_comment: String do
1435 var ret = new Buffer
1436 if n_moduledecl != null and n_moduledecl.n_doc != null then
1437 ret.append(n_moduledecl.n_doc.n_comment.first.text.substring_from(2).replace("\n", ""))
1438 end
1439 return ret.to_s.html_escape
1440 end
1441 end
1442
1443 redef class AStdClassdef
1444 private fun comment: String do
1445 var ret = new Buffer
1446 if n_doc != null then
1447 for t in n_doc.n_comment do ret.append(t.text.substring_from(1))
1448 end
1449 return ret.to_s.html_escape
1450 end
1451
1452 private fun short_comment: String do
1453 var ret = new Buffer
1454 if n_doc != null then ret.append(n_doc.n_comment.first.text.substring_from(2).replace("\n", ""))
1455 return ret.to_s.html_escape
1456 end
1457 end
1458
1459 redef class APropdef
1460 private fun short_comment: String is abstract
1461 private fun html_signature(mbuilder: ModelBuilder): String is abstract
1462 private fun comment: String is abstract
1463 end
1464
1465 redef class AAttrPropdef
1466 redef fun short_comment do
1467 var ret = new Buffer
1468 if n_doc != null then ret.append(n_doc.n_comment.first.text.substring_from(2).replace("\n", ""))
1469 return ret.to_s.html_escape
1470 end
1471
1472 redef private fun comment: String do
1473 var ret = new Buffer
1474 if n_doc != null then
1475 for t in n_doc.n_comment do ret.append(t.text.substring_from(1))
1476 end
1477 return ret.to_s.html_escape
1478 end
1479
1480 redef fun html_signature(mbuilder) do
1481 var res = ""
1482 if n_type != null and n_type.to_html != "" then res += ": {n_type.to_html}"
1483 return res
1484 end
1485 end
1486
1487 redef class AMethPropdef
1488 redef fun short_comment do
1489 var ret = new Buffer
1490 if n_doc != null then ret.append(n_doc.n_comment.first.text.substring_from(2).replace("\n", ""))
1491 return ret.to_s.html_escape
1492 end
1493
1494 redef private fun comment: String do
1495 var ret = new Buffer
1496 if n_doc != null then
1497 for t in n_doc.n_comment do ret.append(t.text.substring_from(1))
1498 end
1499 return ret.to_s.html_escape
1500 end
1501
1502 redef fun html_signature(mbuilder) do
1503 if n_signature != null then return n_signature.to_html
1504 return ""
1505 end
1506 end
1507
1508 redef class ATypePropdef
1509 redef fun short_comment do
1510 var ret = new Buffer
1511 if n_doc != null then ret.append(n_doc.n_comment.first.text.substring_from(2).replace("\n", ""))
1512 return ret.to_s.html_escape
1513 end
1514
1515 redef private fun comment: String do
1516 var ret = new Buffer
1517 if n_doc != null then
1518 for t in n_doc.n_comment do ret.append(t.text.substring_from(1))
1519 end
1520 return ret.to_s.html_escape
1521 end
1522
1523 redef fun html_signature(mbuilder) do
1524 return mpropdef.bound.link(mbuilder)
1525 end
1526 end
1527
1528 redef class ASignature
1529 fun to_html: String do
1530 #TODO closures
1531 var ret = ""
1532 if not n_params.is_empty then
1533 ret = "{ret}({n_params.join(", ")})"
1534 end
1535 if n_type != null and n_type.to_html != "" then ret += ": {n_type.to_html}"
1536 return ret
1537 end
1538 end
1539
1540 redef class AParam
1541 redef fun to_s do
1542 var ret = "{n_id.text}"
1543 if n_type != null then
1544 ret = "{ret}: {n_type.to_html}"
1545 if n_dotdotdot != null then ret = "{ret}..."
1546 end
1547 return ret
1548 end
1549 end
1550
1551 redef class AType
1552 fun to_html: String do
1553 var ret = "<a href=\"{n_id.text}.html\">{n_id.text}</a>"
1554 if n_kwnullable != null then ret = "nullable {ret}"
1555 if not n_types.is_empty then ret = "{ret}[{n_types.join(", ")}]"
1556 return ret
1557 end
1558
1559 fun name: String do return n_id.text.html_escape
1560 end
1561
1562 # Create a tool context to handle options and paths
1563 var toolcontext = new ToolContext
1564
1565 # Here we launch the nit index
1566 var nitdoc = new Nitdoc(toolcontext)
1567 nitdoc.start