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