ni_nitdoc: quicksearch now contains modules
[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.name}</p>")
898 else
899 append("<p class=\"concern-doc\">{owner.name}: {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.name}</p>")
913 else
914 append("<p class=\"concern-doc\">{mmodule.name}: {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 # Return the property signature decorated with html
1170 fun html_signature(mbuilder: ModelBuilder): String do
1171 var nprop = mbuilder.mpropdef2npropdef[intro]
1172 return "{name}{nprop.html_signature(mbuilder)}"
1173 end
1174
1175 # Escape name for html output
1176 redef fun name do return super.html_escape
1177 end
1178
1179 redef class MType
1180 fun link(mbuilder: ModelBuilder): String is abstract
1181 end
1182
1183 redef class MClassType
1184 redef fun link(mbuilder) do return mclass.link(mbuilder)
1185 end
1186
1187 redef class MNullableType
1188 redef fun link(mbuilder) do return "nullable {mtype.link(mbuilder)}"
1189 end
1190
1191 redef class MClassDef
1192 # Return the classdef namespace decorated with html
1193 fun html_namespace(mbuilder: ModelBuilder): String do
1194 var res = new Buffer
1195 res.append(mmodule.html_full_namespace(mbuilder))
1196 res.append("::<span>{self.mclass.link(mbuilder)}</span>")
1197 return res.to_s
1198 end
1199 end
1200
1201 redef class MPropDef
1202 super Comparable
1203 redef type OTHER: MPropDef
1204 redef fun <(other: OTHER): Bool do return self.mproperty.name < other.mproperty.name
1205
1206 fun url: String do return "{mclassdef.mclass.url}#{anchor}"
1207 fun anchor: String do return "PROP_{mclassdef.mclass.public_owner.name}_{c_name}"
1208
1209 # Return a link (html a tag) to the nitdoc class page
1210 fun link(mbuilder: ModelBuilder): String do
1211 if mbuilder.mpropdef2npropdef.has_key(self) then
1212 var nprop = mbuilder.mpropdef2npropdef[self]
1213 return "<a href=\"{url}\" title=\"{nprop.short_comment}\">{mproperty.name}</a>"
1214 else
1215 return "<a href=\"{url}\">{mproperty.name}</a>"
1216 end
1217 end
1218
1219 # Return a list item for the mpropdef
1220 fun html_list_item(mbuilder: ModelBuilder): String do
1221 var res = new Buffer
1222 if is_intro then
1223 res.append("<li class='intro'>")
1224 res.append("<span title='introduction'>I</span>&nbsp;{link(mbuilder)} ({mclassdef.mclass.link(mbuilder)})")
1225 res.append("</li>")
1226 else
1227 res.append("<li class='redef'>")
1228 res.append("<span title='redefinition'>R</span>&nbsp;{link(mbuilder)} ({mclassdef.mclass.link(mbuilder)})")
1229 res.append("</li>")
1230 end
1231 return res.to_s
1232 end
1233
1234 # Return a list item for the mpropdef
1235 fun html_sidebar_item(page: NitdocClass): String do
1236 var res = new Buffer
1237 if is_intro and mclassdef.mclass == page.mclass then
1238 res.append("<li class='intro'>")
1239 res.append("<span title='Introduced'>I</span>")
1240 else if is_intro and mclassdef.mclass != page.mclass then
1241 res.append("<li class='inherit'>")
1242 res.append("<span title='Inherited'>H</span>")
1243 else
1244 res.append("<li class='redef'>")
1245 res.append("<span title='Redefined'>R</span>")
1246 end
1247 res.append(link(page.mbuilder))
1248 res.append("</li>")
1249 return res.to_s
1250 end
1251
1252 fun html_full_desc(page: NitdocClass): String is abstract
1253 fun html_info(page: NitdocClass): String is abstract
1254
1255 fun full_name: String do
1256 return "{mclassdef.mclass.public_owner.name}::{mclassdef.mclass.name}::{mproperty.name}"
1257 end
1258 end
1259
1260 redef class MMethodDef
1261 redef fun html_full_desc(page) do
1262 if not page.mbuilder.mpropdef2npropdef.has_key(self) then
1263 return ""
1264 end
1265 var res = new Buffer
1266 var mprop = mproperty
1267 var nprop = page.mbuilder.mpropdef2npropdef[self]
1268 var classes = new Array[String]
1269 var is_redef = mprop.intro_mclassdef.mclass != page.mclass
1270 classes.add("fun")
1271 if mprop.is_init then classes.add("init")
1272 if is_redef then classes.add("redef")
1273 if mprop.visibility == none_visibility then
1274 classes.add("private")
1275 else if mprop.visibility == protected_visibility then
1276 classes.add("protected")
1277 else
1278 classes.add("public")
1279 end
1280 res.append("<article class='{classes.join(" ")}' id='{anchor}'>")
1281 res.append("<h3 class='signature'>{mprop.html_signature(page.mbuilder)}</h3>")
1282 res.append(html_info(page))
1283 res.append("<div class='description'>")
1284 if nprop.comment == "" then
1285 res.append("<a class=\"newComment\" title=\"32\" tag=\"\">New Comment</a>")
1286 else
1287 res.append("<pre class=\"text_label\" title=\"\" name=\"\" tag=\"\" type=\"1\">{nprop.comment}</pre>")
1288 end
1289 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>")
1290 # definitions block
1291 res.append("<p>")
1292 page.nitdoc.mainmodule.linearize_mpropdefs(mprop.mpropdefs)
1293 var previous_defs = new Array[MMethodDef]
1294 var next_defs = new Array[MMethodDef]
1295 var self_passed = false
1296 for def in mprop.mpropdefs do
1297 if def == self then
1298 self_passed = true
1299 continue
1300 end
1301 if not self_passed then
1302 if not page.mclass.ancestors.has(def.mclassdef.mclass) then continue
1303 if def.is_intro then continue
1304 previous_defs.add(def)
1305 else
1306 if not page.mclass.descendants.has(def.mclassdef.mclass) then continue
1307 next_defs.add(def)
1308 end
1309 end
1310 res.append("defined by {mclassdef.mmodule.html_full_namespace(page.mbuilder)}")
1311 if not is_intro then
1312 res.append(", introduced by {mprop.intro.mclassdef.mclass.link(page.mbuilder)}")
1313 end
1314 if not previous_defs.is_empty then
1315 res.append(", inherited from ")
1316 for i in [0..previous_defs.length[ do
1317 res.append(previous_defs[i].mclassdef.mclass.link(page.mbuilder))
1318 if i < previous_defs.length - 1 then res.append(", ")
1319 end
1320 end
1321 if not next_defs.is_empty then
1322 res.append(", redefined by ")
1323 for i in [0..next_defs.length[ do
1324 res.append(next_defs[i].mclassdef.mclass.link(page.mbuilder))
1325 if i < next_defs.length - 1 then res.append(", ")
1326 end
1327 end
1328 res.append(".</p>")
1329 res.append("</div>")
1330 res.append("</article>")
1331 return res.to_s
1332 end
1333
1334 redef fun html_info(page) do
1335 var res = new Buffer
1336 res.append("<div class='info'>")
1337 if mproperty.visibility <= none_visibility then
1338 res.append("private ")
1339 else if mproperty.visibility <= protected_visibility then
1340 res.append("protected ")
1341 end
1342 if mproperty.intro_mclassdef.mclass != page.mclass then res.append("redef ")
1343 res.append("fun {mproperty.html_namespace(page.mbuilder)}")
1344 res.append("</div>")
1345 res.append("<div style=\"float: right;\"><a id=\"lblDiffCommit\"></a></div>")
1346 return res.to_s
1347 end
1348 end
1349
1350 redef class MVirtualTypeDef
1351 redef fun html_full_desc(page) do
1352 var res = new Buffer
1353 var mprop = mproperty
1354 var is_redef = mprop.intro_mclassdef.mclass != page.mclass
1355 var classes = new Array[String]
1356 classes.add("type")
1357 if is_redef then classes.add("redef")
1358 if mprop.visibility == none_visibility then
1359 classes.add("private")
1360 else if mprop.visibility == protected_visibility then
1361 classes.add("protected")
1362 else
1363 classes.add("public")
1364 end
1365 res.append("<article class='{classes.join(" ")}' id='{anchor}'>")
1366 res.append("<h3 class='signature'>{mprop.name}: {bound.link(page.mbuilder)}</h3>")
1367 res.append(html_info(page))
1368 res.append("<div class='description'>")
1369
1370 if page.mbuilder.mpropdef2npropdef.has_key(self) and page.mbuilder.mpropdef2npropdef[self].comment != "" then
1371 var nprop = page.mbuilder.mpropdef2npropdef[self]
1372 res.append("<pre class=\"text_label\" title=\"\" name=\"\" tag=\"\" type=\"1\">{nprop.comment}</pre>")
1373 else
1374 res.append("<a class=\"newComment\" title=\"32\" tag=\"\">New Comment</a>")
1375 end
1376 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>")
1377 # definitions block
1378 res.append("<p>")
1379 page.nitdoc.mainmodule.linearize_mpropdefs(mprop.mpropdefs)
1380 var previous_defs = new Array[MVirtualTypeDef]
1381 var next_defs = new Array[MVirtualTypeDef]
1382 var self_passed = false
1383 for def in mprop.mpropdefs do
1384 if def == self then
1385 self_passed = true
1386 continue
1387 end
1388 if not self_passed then
1389 if not page.mclass.ancestors.has(def.mclassdef.mclass) then continue
1390 if def.is_intro then continue
1391 previous_defs.add(def)
1392 else
1393 if not page.mclass.descendants.has(def.mclassdef.mclass) then continue
1394 next_defs.add(def)
1395 end
1396 end
1397 res.append("defined by {mclassdef.mmodule.html_full_namespace(page.mbuilder)}")
1398 if not is_intro then
1399 res.append(", introduced by {mprop.intro.mclassdef.mclass.link(page.mbuilder)}")
1400 end
1401 if not previous_defs.is_empty then
1402 res.append(", inherited from ")
1403 for i in [0..previous_defs.length[ do
1404 res.append(previous_defs[i].mclassdef.mclass.link(page.mbuilder))
1405 if i < previous_defs.length - 1 then res.append(", ")
1406 end
1407 end
1408 if not next_defs.is_empty then
1409 res.append(", redefined by ")
1410 for i in [0..next_defs.length[ do
1411 res.append(next_defs[i].mclassdef.mclass.link(page.mbuilder))
1412 if i < next_defs.length - 1 then res.append(", ")
1413 end
1414 end
1415 res.append(".</p>")
1416 res.append("</div>")
1417 res.append("</article>")
1418 return res.to_s
1419 end
1420
1421 redef fun html_info(page) do
1422 var res = new Buffer
1423 res.append("<div class='info'>")
1424 if mproperty.intro_mclassdef.mclass != page.mclass then res.append("redef ")
1425 res.append("type {mproperty.html_namespace(page.mbuilder)}")
1426 res.append("</div>")
1427 res.append("<div style=\"float: right;\"><a id=\"lblDiffCommit\"></a></div>")
1428 return res.to_s
1429 end
1430 end
1431
1432 #
1433 # Nodes redefs
1434 #
1435
1436 redef class AModule
1437 private fun comment: String do
1438 var ret = new Buffer
1439 if n_moduledecl is null or n_moduledecl.n_doc is null then ret
1440 if n_moduledecl.n_doc is null then return ""
1441 for t in n_moduledecl.n_doc.n_comment do
1442 ret.append(t.text.substring_from(1))
1443 end
1444 return ret.to_s.html_escape
1445 end
1446
1447 private fun short_comment: String do
1448 var ret = new Buffer
1449 if n_moduledecl != null and n_moduledecl.n_doc != null then
1450 ret.append(n_moduledecl.n_doc.n_comment.first.text.substring_from(2).replace("\n", ""))
1451 end
1452 return ret.to_s.html_escape
1453 end
1454 end
1455
1456 redef class AStdClassdef
1457 private fun comment: String do
1458 var ret = new Buffer
1459 if n_doc != null then
1460 for t in n_doc.n_comment do ret.append(t.text.substring_from(1))
1461 end
1462 return ret.to_s.html_escape
1463 end
1464
1465 private fun short_comment: String do
1466 var ret = new Buffer
1467 if n_doc != null then ret.append(n_doc.n_comment.first.text.substring_from(2).replace("\n", ""))
1468 return ret.to_s.html_escape
1469 end
1470 end
1471
1472 redef class APropdef
1473 private fun short_comment: String is abstract
1474 private fun html_signature(mbuilder: ModelBuilder): String is abstract
1475 private fun comment: String is abstract
1476 end
1477
1478 redef class AAttrPropdef
1479 redef fun short_comment do
1480 var ret = new Buffer
1481 if n_doc != null then ret.append(n_doc.n_comment.first.text.substring_from(2).replace("\n", ""))
1482 return ret.to_s.html_escape
1483 end
1484
1485 redef private fun comment: String do
1486 var ret = new Buffer
1487 if n_doc != null then
1488 for t in n_doc.n_comment do ret.append(t.text.substring_from(1))
1489 end
1490 return ret.to_s.html_escape
1491 end
1492
1493 redef fun html_signature(mbuilder) do
1494 var res = ""
1495 if n_type != null and n_type.to_html != "" then res += ": {n_type.to_html}"
1496 return res
1497 end
1498 end
1499
1500 redef class AMethPropdef
1501 redef fun short_comment do
1502 var ret = new Buffer
1503 if n_doc != null then ret.append(n_doc.n_comment.first.text.substring_from(2).replace("\n", ""))
1504 return ret.to_s.html_escape
1505 end
1506
1507 redef private fun comment: String do
1508 var ret = new Buffer
1509 if n_doc != null then
1510 for t in n_doc.n_comment do ret.append(t.text.substring_from(1))
1511 end
1512 return ret.to_s.html_escape
1513 end
1514
1515 redef fun html_signature(mbuilder) do
1516 if n_signature != null then return n_signature.to_html
1517 return ""
1518 end
1519 end
1520
1521 redef class ATypePropdef
1522 redef fun short_comment do
1523 var ret = new Buffer
1524 if n_doc != null then ret.append(n_doc.n_comment.first.text.substring_from(2).replace("\n", ""))
1525 return ret.to_s.html_escape
1526 end
1527
1528 redef private fun comment: String do
1529 var ret = new Buffer
1530 if n_doc != null then
1531 for t in n_doc.n_comment do ret.append(t.text.substring_from(1))
1532 end
1533 return ret.to_s.html_escape
1534 end
1535
1536 redef fun html_signature(mbuilder) do
1537 return mpropdef.bound.link(mbuilder)
1538 end
1539 end
1540
1541 redef class ASignature
1542 fun to_html: String do
1543 #TODO closures
1544 var ret = ""
1545 if not n_params.is_empty then
1546 ret = "{ret}({n_params.join(", ")})"
1547 end
1548 if n_type != null and n_type.to_html != "" then ret += ": {n_type.to_html}"
1549 return ret
1550 end
1551 end
1552
1553 redef class AParam
1554 redef fun to_s do
1555 var ret = "{n_id.text}"
1556 if n_type != null then
1557 ret = "{ret}: {n_type.to_html}"
1558 if n_dotdotdot != null then ret = "{ret}..."
1559 end
1560 return ret
1561 end
1562 end
1563
1564 redef class AType
1565 fun to_html: String do
1566 var ret = "<a href=\"{n_id.text}.html\">{n_id.text}</a>"
1567 if n_kwnullable != null then ret = "nullable {ret}"
1568 if not n_types.is_empty then ret = "{ret}[{n_types.join(", ")}]"
1569 return ret
1570 end
1571
1572 fun name: String do return n_id.text.html_escape
1573 end
1574
1575 # Create a tool context to handle options and paths
1576 var toolcontext = new ToolContext
1577
1578 # Here we launch the nit index
1579 var nitdoc = new Nitdoc(toolcontext)
1580 nitdoc.start