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