nitdoc: include the help in the menubar
[nit.git] / src / 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 # The main module of the nitdoc program
18 package nitdoc
19
20 import syntax
21 private import utils
22 import abstracttool
23
24
25 # Store knowledge and facilities to generate files
26 class DocContext
27 super AbstractCompiler
28 # Destination directory
29 readable writable var _dir: String = "doc"
30
31 # Content of a generated file
32 var _stage_context: StageContext = new StageContext(null)
33
34 # Add a string in the content
35 fun add(s: String) do
36 _stage_context.content.add(s)
37 _stage_context.validate = true
38 end
39
40 # Add a string in the content iff some other string are added
41 fun stage(s: String) do _stage_context.content.add(s)
42
43 # Create a new stage in the content
44 fun open_stage do _stage_context = new StageContext(_stage_context)
45
46 # Close the current stage in the content
47 fun close_stage
48 do
49 var s = _stage_context.parent
50 if _stage_context.validate then
51 s.content.add_all(_stage_context.content)
52 s.validate = true
53 end
54 assert s != null
55 _stage_context = s
56 end
57
58 # Write the content to a new file
59 fun write_to(filename: String)
60 do
61 var f = new OFStream.open(filename)
62 for s in _stage_context.content do
63 f.write(s)
64 end
65 f.close
66 end
67
68 # Start a new file
69 fun clear
70 do
71 _stage_context = new StageContext(null)
72 end
73
74 # Sorter of entities in alphabetical order
75 var _sorter: AlphaSorter[MMEntity] = new AlphaSorter[MMEntity]
76
77 # Sort entities in the alphabetical order
78 fun sort(array: Array[MMEntity])
79 do
80 _sorter.sort(array)
81 end
82
83 readable var _opt_dir: OptionString = new OptionString("Directory where doc is generated", "-d", "--dir")
84 readable var _opt_source: OptionString = new OptionString("What link for source (%f for filename, %l for first line, %L for last line)", "--source")
85 readable var _opt_public: OptionBool = new OptionBool("Generate only the public API", "--public")
86 readable var _opt_private: OptionBool = new OptionBool("Generate the private API", "--private")
87 readable var _opt_nodot: OptionBool = new OptionBool("Do not generate graphes with graphviz", "--no-dot")
88 readable var _opt_sharedir: OptionString = new OptionString("Directory containing the nitdoc files", "--sharedir")
89 var sharedir: nullable String
90
91 fun public_only: Bool
92 do
93 if self._opt_public.value == true then return true
94 return false
95 end
96
97 fun with_private: Bool
98 do
99 if self._opt_private.value == true then return true
100 return false
101 end
102
103 # The current processed filename
104 var filename: String
105
106 # The main virtual module
107 var mainmod: nullable MMVirtualModule
108
109 redef fun perform_work(mods)
110 do
111 mainmod = new MMVirtualModule(self, mods)
112
113 dir.mkdir
114
115 sys.system("cp -r '{sharedir.to_s}'/* {dir}/")
116
117 # Compute the set of direct owned nested modules
118 var owns = new HashMap[MMModule, Array[MMModule]]
119 for mod in modules do
120 owns[mod] = new Array[MMModule]# [mod]
121 end
122 for mod in modules do
123 if mod == mainmod then continue
124 var d = mod.directory
125 loop
126 var o = d.owner
127 if o != null and o != mod then
128 owns[o].add(mod)
129 end
130 var dp = d.parent
131 if dp == null or dp == d then break
132 d = dp
133 end
134 end
135
136 # Builds the various module hierarchies
137 var mnh = new PartialOrder[MMModule] # nested module hierarchy
138 var tmh = new PartialOrder[MMModule] # top module import hierrchy
139 var ms = mainmod.mhe.linear_extension.reversed
140 for m in ms do
141 if ms == mainmod then continue
142 m.mnhe_ = mnh.add(m, owns[m])
143 var pub = new Array[MMModule]
144 for m2 in m.mhe.greaters do
145 if m2.toplevel_owner != m2 and m2.toplevel_owner != m.toplevel_owner then continue
146 if m.mnhe <= m2 then continue
147 if m.visibility_for(m2) <= 0 then
148 # nothing
149 else if m.visibility_for(m2) == 1 then
150 else
151 pub.add(m2)
152 end
153 end
154 m.tmhe_ = tmh.add(m, pub)
155 end
156
157 var head = "<meta charset=\"utf-8\">" +
158 "<script type=\"text/javascript\" src=\"scripts/jquery-1.7.1.min.js\"></script>\n" +
159 "<script type=\"text/javascript\" src=\"scripts/js-facilities.js\"></script>\n" +
160 "<link rel=\"stylesheet\" href=\"styles/main.css\" type=\"text/css\" media=\"screen\" />"
161
162 var action_bar = "<header><nav class='main'><ul><li class=\"current\">Overview</li><li><a href='full-index.html'>Full Index</a></li><li><a href=\"help.html\">Help</a></li></ul></nav></header>\n"
163
164 # generate the index
165 self.filename = "index.html"
166 clear
167 add("<!DOCTYPE html>")
168 add("<html><head>{head}<title>Index</title></head><body>\n")
169 add(action_bar)
170 add("<div class=\"page\">")
171 add("<div class=\"content fullpage\">")
172 add("<h1>Modules</h1>\n<article class='overview'><ul>")
173 var modss = mainmod.mhe.greaters_and_self.to_a
174 sort(modss)
175 for mod in modss do
176 if not mod.is_toplevel then continue
177 if not mod.require_doc(self) then continue
178 assert mod isa MMSrcModule
179 add("<li>{mod.html_link(self)} {mod.short_doc}</li>")
180
181 end
182 add("</ul>")
183
184 var op = new Buffer
185 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")
186 for mod in modss do
187 if not mod.is_toplevel then continue
188 if not mod.require_doc(self) then continue
189 op.append("\"{mod.name}\"[URL=\"{mod.html_name}.html\"];\n")
190 for mod2 in mod.tmhe.direct_greaters do
191 if not modss.has(mod2) then continue
192 op.append("\"{mod.name}\"->\"{mod2.name}\";\n")
193 end
194 end
195 op.append("\}\n")
196 self.gen_dot(op.to_s, "dep", "Modules hierarchy")
197 add("</article></div>")
198 add("<div class='clear'></div>")
199 add("</div>")
200 add("</body></html>\n")
201 write_to("{dir}/index.html")
202
203 # Generate page for modules
204 for mod in modules do
205 if mod == mainmod then continue
206 assert mod isa MMSrcModule
207 if not mod.require_doc(self) then continue
208 self.filename = mod.html_name
209 action_bar = "<header><nav class='main'><ul><li><a href='./index.html'>Overview</a></li><li class=\"current\">{mod.name}</li><li><a href='full-index.html'>Full Index</a></li><li><a href=\"help.html\">Help</a></li></ul></nav></header>\n"
210 clear
211 add("<!DOCTYPE html>")
212 add("<html><head>{head}<title>Module {mod.name}</title></head><body>\n")
213 add(action_bar)
214 add("<div class=\"page\">")
215 mod.file_page_doc(self)
216 add("</div>")
217 add("</body></html>\n")
218 write_to("{dir}/{mod.html_name}.html")
219 end
220
221 # Generate pages for global classes
222 for c in mainmod.local_classes do
223 if not c.require_doc(self) then continue
224 self.filename = c.html_name
225 action_bar = "<header><nav class='main'><ul><li><a href='./index.html'>Overview</a></li><li>{c.global.intro.mmmodule.toplevel_owner.html_link(self)}</li><li class=\"current\">{c.name}</li><li><a href='full-index.html'>Full Index</a></li><li><a href=\"help.html\">Help</a></li></ul></nav></header>\n"
226 clear
227 add("<!DOCTYPE html>")
228 add("<html><head>{head}<title>Class {c.name}</title></head><body>\n")
229 add(action_bar)
230 add("<div class=\"page\">")
231 c.file_page_doc(self)
232 add("</div>")
233 add("</body></html>\n")
234 write_to("{dir}/{c.html_name}.html")
235 end
236
237 self.filename = "fullindex"
238 action_bar = "<header><nav class='main'><ul><li><a href='./index.html'>Overview</a></li><li class=\"current\">Full Index</li><li><a href=\"help.html\">Help</a></li></ul></nav></header>\n"
239 clear
240 add("<!DOCTYPE html>")
241 add("<html><head>{head}<title>Full Index</title></head><body>\n")
242 add(action_bar)
243 add("<div class=\"page\">")
244 add("<div class=\"content fullpage\">")
245 mainmod.file_index_page_doc(self)
246 add("</div>")
247 add("</div>")
248 add("</body></html>\n")
249 write_to("{dir}/full-index.html")
250 end
251
252
253 # Add a (source) link fo a given location
254 fun show_source(l: Location)
255 do
256 var s = opt_source.value
257 if s == null then
258 add("in #{l.file.filename.simplify_path}")
259 else
260 # THIS IS JUST UGLY ! (but there is no replace yet)
261 var x = s.split_with("%f")
262 s = x.join(l.file.filename.simplify_path)
263 x = s.split_with("%l")
264 s = x.join(l.line_start.to_s)
265 x = s.split_with("%L")
266 s = x.join(l.line_end.to_s)
267 add(" (<a href=\"{s}\">show code</a>)")
268 end
269 end
270
271 # Generate a clicable graphiz image using a dot content.
272 # `name' refer to the filename (without extension) and the id name of the map.
273 # `name' must also match the name of the graph in the dot content (eg. digraph NAME {...)
274 fun gen_dot(dot: String, name: String, alt: String)
275 do
276 if opt_nodot.value then return
277 var f = new OFStream.open("{self.dir}/{name}.dot")
278 f.write(dot)
279 f.close
280 sys.system("\{ test -f {self.dir}/{name}.png && test -f {self.dir}/{name}.s.dot && diff {self.dir}/{name}.dot {self.dir}/{name}.s.dot >/dev/null 2>&1 ; \} || \{ cp {self.dir}/{name}.dot {self.dir}/{name}.s.dot && dot -Tpng -o{self.dir}/{name}.png -Tcmapx -o{self.dir}/{name}.map {self.dir}/{name}.s.dot ; \}")
281 self.add("<article class=\"graph\"><img src=\"{name}.png\" usemap=\"#{name}\" style=\"margin:auto\" alt=\"{alt}\"/></article>")
282 var fmap = new IFStream.open("{self.dir}/{name}.map")
283 self.add(fmap.read_all)
284 fmap.close
285 end
286
287 init
288 do
289 keep_ast = true
290 super("nitdoc")
291 filename = "-unset-"
292 option_context.add_option(opt_public)
293 option_context.add_option(opt_private)
294 option_context.add_option(opt_dir)
295 option_context.add_option(opt_source)
296 option_context.add_option(opt_nodot)
297 option_context.add_option(opt_sharedir)
298 end
299
300 redef fun process_options
301 do
302 super
303 var d = opt_dir.value
304 if d != null then dir = d
305
306 if not opt_nodot.value then
307 # Test if dot is runable
308 var res = sys.system("sh -c dot </dev/null >/dev/null 2>&1")
309 if res != 0 then
310 stderr.write "--no-dot implied since `dot' is not available. Try to install graphviz.\n"
311 opt_nodot.value = true
312 end
313 end
314
315 sharedir = opt_sharedir.value
316 if sharedir == null then
317 var dir = once ("NIT_DIR".to_symbol).environ
318 if dir.is_empty then
319 dir = "{sys.program_name.dirname}/../share/nitdoc"
320 if dir.file_exists then sharedir = dir
321 else
322 dir = "{dir}/share/nitdoc"
323 if dir.file_exists then sharedir = dir
324 end
325 if sharedir == null then
326 fatal_error(null, "Error: Cannot locate nitdoc shared files. Uses --sharedir or envvar NIT_DIR.")
327 end
328 dir = "{sharedir.to_s}/scripts/js-facilities.js"
329 if sharedir == null then
330 fatal_error(null, "Error: Invalid nitdoc shared files. Check --sharedir or envvar NIT_DIR.")
331 end
332
333 end
334 end
335
336 redef fun handle_property_conflict(lc, impls)
337 do
338 # THIS IS SO UGLY! See MMVirtualModule
339 if lc.mmmodule == self.mainmod then
340 return # We just accept, so one in impls is arbitrary inherited
341 end
342 super
343 end
344 end
345
346 # A virtual module is used to work as an implicit main module that combine unrelated modules
347 # Since conflict may arrise in a virtual module (the main method for instance) conflicts are disabled
348 class MMVirtualModule
349 super MMModule
350 init(ctx: MMContext, mods: Array[MMModule])
351 do
352 # We need to compute the whole metamodel since there is no mmbuilder to do it
353 super(" main".to_symbol, mods.first.directory, ctx, new Location(null,0,0,0,0))
354 ctx.add_module(self, mods)
355 for m in mods do
356 self.add_super_module(m, 1)
357 end
358 self.import_global_classes
359 self.import_local_classes
360 for c in self.local_classes do
361 c.compute_super_classes
362 end
363 for c in self.local_classes do
364 c.compute_ancestors
365 end
366
367 end
368 redef fun require_doc(dctx) do return false
369 end
370
371 # Conditionnal part of the text content of a DocContext
372 class StageContext
373 # Content of the current stage
374 readable var _content: Array[String] = new Array[String]
375
376 # Is a normal string already added?
377 readable writable var _validate: Bool = false
378
379 # Parent stage is any
380 readable var _parent: nullable StageContext = null
381
382 init(parent: nullable StageContext) do _parent = parent
383 end
384
385
386 # Efficiently sort object with their to_s method
387 class AlphaSorter[E: Object]
388 super AbstractSorter[E]
389 redef fun compare(a, b)
390 do
391 var sa: String
392 var sb: String
393 var d = _dico
394 if d.has_key(a) then
395 sa = d[a]
396 else
397 sa = a.to_s
398 d[a] = sa
399 end
400 if d.has_key(b) then
401 sb = d[b]
402 else
403 sb = b.to_s
404 d[b] = sb
405 end
406 return sa <=> sb
407 end
408
409 # Keep track of to_s values
410 var _dico: HashMap[Object, String] = new HashMap[Object, String]
411
412 init do end
413 end
414
415 # Generalization of metamodel entities
416 class MMEntity
417 # Return a link to
418 fun html_link(dctx: DocContext): String is abstract
419
420 # Return a one liner description
421 fun short_doc: String do return "&nbsp;"
422
423 # The doc node from the AST
424 # Return null is none
425 fun doc: nullable ADoc do return null
426 end
427
428 redef class MMModule
429 super MMEntity
430 redef fun html_link(dctx) do
431 return "<a href=\"{html_name}.html\" title=\"{short_doc}\">{self}</a>"
432 end
433
434 fun require_doc(dctx: DocContext): Bool
435 do
436 if dctx.public_only and not is_toplevel then return false
437 return true
438 end
439
440 # Return true if the module is a top-level owner or a top-level module
441 fun is_toplevel: Bool
442 do
443 var pd = directory.parent
444 return pd == null or (pd.owner == null and directory.owner == self)
445 end
446
447 # Element in the module nesting tree
448 fun mnhe: PartialOrderElement[MMModule] do return mnhe_.as(not null)
449 var mnhe_: nullable PartialOrderElement[MMModule] = null
450
451 # Element in the top level module importation hierarchy
452 fun tmhe: PartialOrderElement[MMModule] do return tmhe_.as(not null)
453 var tmhe_: nullable PartialOrderElement[MMModule] = null
454
455 fun toplevel_owner: MMModule
456 do
457 var m = self
458 loop
459 var ds = m.mnhe.direct_smallers
460 if ds.length == 0 then return m
461 if ds.length == 1 then m = ds.first else abort
462 end
463 end
464
465 fun html_name: String
466 do
467 return "{name}"
468 end
469
470 fun direct_owner: nullable MMModule
471 do
472 var d = directory
473 while d.owner == self do d = d.parent.as(not null)
474 return d.owner
475 end
476
477 # Fill the body for the page associated to the module
478 fun file_page_doc(dctx: DocContext)
479 do
480 dctx.add("<div class=\"menu\">\n")
481
482 var mods = new Array[MMModule]
483 mods = self.mhe.greaters.to_a
484 dctx.sort(mods)
485
486 dctx.open_stage
487 dctx.stage("<nav>\n")
488 dctx.stage("<h3>Module Hierarchy</h3>\n")
489 dctx.stage("<h4>All dependencies</h4>\n")
490 dctx.stage("<ul>\n")
491 for mod in mods do
492 if not mod.require_doc(dctx) then continue
493 if self.mnhe <= mod then continue # do not want nested stuff
494 if mod.direct_owner != null and not mod.direct_owner.mnhe <= self then continue # not in the right nesting
495 dctx.add("<li>{mod.html_link(dctx)}</li>")
496 end
497 dctx.stage("</ul>\n")
498
499 mods = self.mhe.smallers.to_a
500 dctx.sort(mods)
501 dctx.stage("<h4>All clients</h4>\n")
502 dctx.stage("<ul>\n")
503 for mod in mods do
504 if not mod.require_doc(dctx) then continue
505 if self.mnhe <= mod then continue # do not want nested stuff
506 if mod.direct_owner != null and not mod.direct_owner.mnhe <= self then continue # not in the right nesting
507 dctx.add("<li>{mod.html_link(dctx)}</li>")
508 end
509 dctx.stage("</ul>\n")
510 dctx.stage("</nav>\n")
511 dctx.close_stage
512
513 if not dctx.public_only then
514 mods = self.mnhe.direct_greaters.to_a
515 dctx.sort(mods)
516 dctx.open_stage
517 dctx.stage("<nav>\n")
518 dctx.stage("<h3>Nested Modules</h3><ul>\n")
519 for mod in mods do
520 if not mod.require_doc(dctx) then continue
521 dctx.add("<li>{mod.html_link(dctx)}</li>")
522 end
523 dctx.stage("</ul></nav>\n")
524 dctx.close_stage
525 end
526
527 dctx.add("</div>") # metadata
528
529 dctx.add("<div class=\"content\">\n")
530 dctx.add("<h1>{name}</h1>\n")
531 dctx.add("<div class='subtitle'>module ")
532 for m in mnhe.smallers do
533 dctx.add("{m.html_link(dctx)}::")
534 end
535 dctx.add("{self.name}</div>\n")
536
537 dctx.add("<section class='description'>\n")
538
539 var doc = doc
540 if doc != null then
541 dctx.add("<div id=\"description\">\n")
542 dctx.add("<pre>{doc.to_html}</pre>\n")
543 dctx.add("</div>\n")
544 end
545
546 var op = new Buffer
547 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")
548 var ms = new Array[nullable MMModule]
549 do
550 var m0: nullable MMModule = self
551 while m0 != null do
552 m0 = m0.direct_owner
553 ms.add(m0)
554 end
555 end
556 var cla = new HashSet[MMModule]
557 cla.add(self)
558 for m0 in self.mhe.greaters do
559 if not m0.require_doc(dctx) then continue
560 if self.visibility_for(m0) <= 1 then continue # private or hidden
561 if self.mnhe <= m0 then continue # do not want nested stuff
562 if m0.direct_owner != null and not m0.direct_owner.mnhe <= self then continue # not in the right nesting
563 cla.add(m0)
564 end
565 for m0 in self.mhe.smallers do
566 if not m0.require_doc(dctx) then continue
567 if m0.visibility_for(self) <= 1 then continue # private or hidden
568 if m0.direct_owner != null and not m0.direct_owner.mnhe <= self then continue # not in the right nesting
569 cla.add(m0)
570 end
571 for m0 in self.mnhe.smallers do
572 cla.add(m0)
573 end
574 ms = ms.reversed
575 for m0 in ms do
576 if m0 != null then
577 op.append("subgraph \"cluster_{m0.name}\"\{\n")
578 end
579 for c in cla do
580 if c.direct_owner != m0 then continue
581 if c == self then
582 op.append("\"{c.name}\"[shape=box,margin=0.03];\n")
583 else
584 op.append("\"{c.name}\"[URL=\"{c.html_name}.html\"];\n")
585 end
586 end
587 if m0 != null then
588 op.append("\"{m0.name}\"[URL=\"{m0.html_name}.html\"];\n")
589 for c in m0.mhe.direct_greaters do
590 if not cla.has(c) then continue
591 op.append("\"{m0.name}\"->\"{c.name}\";\n")
592 end
593 end
594 end
595 for m0 in ms do
596 # Close the nesting subgraph
597 if m0 != null then
598 op.append("\}\n")
599 end
600 end
601 for c in cla do
602 for c2 in c.tmhe.direct_greaters do
603 if not cla.has(c2) then continue
604 op.append("\"{c.name}\"->\"{c2.name}\";\n")
605 end
606 end
607 op.append("\}\n")
608 dctx.gen_dot(op.to_s, name.to_s, "Dependency graph for module {name}")
609 dctx.add("</section>")
610
611 var clas = new Array[MMLocalClass]
612 var props = new HashMap[MMGlobalProperty, Array[MMLocalProperty]]
613 var gprops = new Array[MMLocalProperty]
614 do
615 var m = self
616 for g in m.global_classes do
617 var lc = m[g]
618 if not lc.require_doc(dctx) then continue
619 var im = g.intro.mmmodule
620 if self.visibility_for(im) <= 1 then continue # private import or invisible import
621 var keep = false
622 for lc2 in lc.crhe.greaters_and_self do
623 if not lc2 isa MMSrcLocalClass then continue
624 if not self.mnhe <= lc2.mmmodule then continue # not introduced/redefined here/stolen
625 keep = true
626 end
627 if not keep then continue
628 clas.add(self[g])
629 lc.compute_super_classes
630 for gp in lc.global_properties do
631 if self.visibility_for(gp.intro.local_class.mmmodule) <= 1 then continue # private import or invisible import
632 var lp = lc[gp]
633 var mp = lp.local_class.mmmodule
634 if not self.mnhe <= mp then continue # not introduced/redefined here/stolen
635 lp = self[g][gp]
636 if not lp.require_doc(dctx) then continue
637 if props.has_key(lp.global) then
638 if not props[lp.global].has(lp) then
639 props[lp.global].add(lp)
640 end
641 else
642 props[lp.global] = [lp]
643 gprops.add(lp.global.intro)
644 end
645 end
646 end
647 end
648 dctx.add("<section class=\"module\">\n")
649 dctx.open_stage
650 dctx.stage("<article class=\"classes filterable\">\n")
651 dctx.stage("<h2>Classes</h2>\n")
652 dctx.sort(clas)
653 dctx.stage("<ul>\n")
654 for lc in clas do
655 if self.mnhe <= lc.global.intro.mmmodule then
656 dctx.add("<li class='intro'><span title='introduced in this module'>I</span>&nbsp;")
657 else
658 dctx.add("<li class='redef'><span title='refined in this module'>R</span>&nbsp;")
659 end
660 dctx.add("{lc.html_link(dctx)}</li>\n")
661 end
662 dctx.stage("</ul></article>\n")
663 dctx.close_stage
664
665 dctx.open_stage
666 dctx.stage("<article class=\"properties filterable\">\n")
667 dctx.stage("<h2>Properties</h2>\n")
668 dctx.sort(gprops)
669 dctx.stage("<ul>\n")
670 for lgp in gprops do
671 var gp = lgp.global
672 var lps = props[gp]
673
674 if gp.intro isa MMAttribute then continue
675
676 var lpi = self[gp.intro.local_class.global][gp]
677
678 if lps.has(lpi) then
679 dctx.add("<li class='intro'><span title='introduction in an other module'>I</span>&nbsp;{lpi.html_open_link(dctx)}{lpi.html_name}&nbsp;({lpi.local_class})</a></li>\n")
680 lps.remove(lpi)
681 else
682 dctx.add("<li class='intro'><span title='introduction in this module'>I</span>&nbsp;{lpi.html_name}")
683 dctx.add("&nbsp;({lpi.local_class})</li>\n")
684 end
685 if lps.length >= 1 then
686 dctx.sort(lps)
687 for lp in lps do
688 dctx.add("<li class='redef'><span title='redefinition'>R</span>&nbsp;{lp.html_open_link(dctx)}{lp.html_name}&nbsp;({lp.local_class})</a></li>")
689 end
690 end
691 end
692 dctx.stage("</ul></article>\n")
693 dctx.close_stage
694 dctx.add("</section>\n")
695 dctx.add("</div>\n")
696 end
697
698 # Fill the body for the page associated to the full index
699 fun file_index_page_doc(dctx: DocContext)
700 do
701
702 dctx.add("<h1>Full Index</h1>\n")
703
704 var clas = new Array[MMLocalClass]
705 var props = new HashMap[MMGlobalProperty, Array[MMLocalProperty]]
706 var gprops = new Array[MMLocalProperty]
707 var mods = new Array[MMModule]
708 for m in mhe.greaters_and_self do
709 if not m.require_doc(dctx) then continue
710 mods.add(m)
711 end
712 for g in global_classes do
713 var lc = self[g]
714 if not lc.require_doc(dctx) then continue
715 clas.add(lc)
716 for gp in lc.global_properties do
717 var lp = lc[gp]
718 if not lp.require_doc(dctx) then continue
719 if props.has_key(lp.global) then
720 if not props[lp.global].has(lp) then
721 props[lp.global].add(lp)
722 end
723 else
724 props[lp.global] = [lp]
725 gprops.add(lp.global.intro)
726 end
727 end
728 end
729 dctx.open_stage
730 dctx.stage("<article class=\"modules filterable\">\n")
731 dctx.stage("<h2>Modules</h2>\n")
732 dctx.sort(mods)
733 dctx.stage("<ul>\n")
734 for m in mods do
735 dctx.add("<li>{m.html_link(dctx)}</li>")
736 end
737 dctx.stage("</ul></article>\n")
738 dctx.close_stage
739
740 dctx.open_stage
741 dctx.stage("<article class=\"classes filterable\">\n")
742 dctx.stage("<h2>Classes</h2>\n")
743 dctx.sort(clas)
744 dctx.stage("<ul>\n")
745 for lc in clas do
746 dctx.add("<li>{lc.html_link(dctx)}</li>")
747 end
748 dctx.stage("</ul></article>\n")
749 dctx.close_stage
750
751 dctx.open_stage
752 dctx.stage("<article class=\"properties filterable\">\n")
753 dctx.stage("<h2>Properties</h2>\n")
754 dctx.sort(gprops)
755 dctx.stage("<ul>\n")
756 for lgp in gprops do
757 var gp = lgp.global
758 var lps = props[gp]
759
760 if gp.intro isa MMAttribute then continue
761
762 var lpi = self[gp.intro.local_class.global][gp]
763
764 lps.remove(lpi)
765 dctx.add("<li class='intro'><span title='introduction'>I</span>&nbsp;{lpi.html_open_link(dctx)}{lpi.html_name}&nbsp;({lpi.local_class})</a></li>\n")
766 if lps.length >= 1 then
767 dctx.sort(lps)
768 for lp in lps do
769 dctx.add("<li class='redef'><span title='redefinition'>R</span>&nbsp;{lp.html_open_link(dctx)}{lp.html_name}&nbsp;({lp.local_class})</a></li>\n")
770 end
771 end
772 end
773 dctx.stage("</ul></article>\n")
774 dctx.close_stage
775 end
776 end
777
778 redef class MMLocalProperty
779 super MMEntity
780 # Anchor of the property description in the module html file
781 fun html_anchor: String
782 do
783 return "PROP_{local_class}_{cmangle(name)}"
784 end
785
786 fun html_open_link(dctx: DocContext): String
787 do
788 if not require_doc(dctx) then print "not required {self}"
789 var title = "{html_name}{signature.to_s}"
790 if short_doc != "&nbsp;" then
791 title += " #{short_doc}"
792 end
793 return "<a href=\"{local_class.html_name}.html#{html_anchor}\" title=\"{title}\">"
794 end
795
796 fun html_name: String
797 do
798 return self.name.to_s.html_escape
799 end
800
801 redef fun html_link(dctx)
802 do
803 if not require_doc(dctx) then print "not required {self}"
804 var title = "{html_name}{signature.to_s}"
805 if short_doc != "&nbsp;" then
806 title += " #{short_doc}"
807 end
808 return "<a href=\"{local_class.html_name}.html#{html_anchor}\" title=\"{title}\">{html_name}</a>"
809 end
810
811 fun html_link_special(dctx: DocContext, lc: MMLocalClass): String
812 do
813 if not require_doc(dctx) then print "not required {self}"
814 var title = "{html_name}{signature_for(lc.get_type)}"
815 if short_doc != "&nbsp;" then
816 title += " #{short_doc}"
817 end
818 return "<a href=\"{lc.html_name}.html#{html_anchor}\" title=\"{title}\">{html_name}</a>"
819 end
820
821 # Kind of property (fun, attr, etc.)
822 fun kind: String is abstract
823
824 redef fun short_doc
825 do
826 var d = doc
827 if d != null then
828 return d.short
829 else if global.intro == self then
830 return "&nbsp;"
831 else
832 return global.intro.short_doc
833 end
834 end
835
836 redef fun doc
837 do
838 var n = node
839 if n == null or not n isa APropdef then
840 return null
841 end
842 var d = n.n_doc
843 if d == null then
844 return null
845 end
846 if d.n_comment.is_empty then
847 return null
848 else
849 return d
850 end
851 end
852
853 # The most specific module in the nesting hierarchy that exports the intro of self
854 fun intro_module: MMModule
855 do
856 var m = global.intro.mmmodule
857 var mo = m.direct_owner
858 while mo != null and mo.visibility_for(m) >= 2 do
859 m = mo
860 mo = m.direct_owner
861 end
862 return m
863 end
864
865 # Is the intro of self exported by the top-level module ?
866 fun is_toplevel: Bool
867 do
868 var m = intro_module
869 return m == m.toplevel_owner
870 end
871
872 # Return true if the global property must be documented according to the visibility configured
873 fun require_doc(dctx: DocContext): Bool
874 do
875 if global.visibility_level == 3 and not dctx.with_private then return false # Private
876 if dctx.public_only then
877 var m = intro_module
878 if m != m.toplevel_owner then return false # Unexported
879 end
880 return true
881 end
882
883 # Document the global property in the global class lc
884 fun full_documentation(dctx: DocContext, lc: MMLocalClass)
885 do
886 var visibility: String
887 if global.visibility_level == 1 then
888 visibility = "public"
889 else if global.visibility_level == 2 then
890 visibility = "protected"
891 else if global.visibility_level == 3 then
892 visibility = "private"
893 else
894 abort
895 end
896
897 var intro_class = global.intro.local_class
898 var is_redef = local_class.global != intro_class.global or local_class.mmmodule.toplevel_owner != intro_class.mmmodule.toplevel_owner
899
900 dctx.add("<article id=\"{html_anchor}\" class=\"{kind} {visibility} {if is_redef then "redef" else ""}\">\n")
901 dctx.add("<h3 class=\"signature\">{html_name}{signature.to_html(dctx, true)}</h3>\n")
902 dctx.add("<div class=\"info\">\n")
903 #dctx.add("<p>LP: {self.mmmodule.html_link(dctx)}::{self.local_class.html_link(dctx)}::{self.html_link(dctx)}</p>")
904
905 if is_redef then
906 dctx.add("redef ")
907 end
908 if not is_toplevel then
909 dctx.add("(unexported) ")
910 end
911 if global.visibility_level == 2 then
912 dctx.add("protected ")
913 else if global.visibility_level == 3 then
914 dctx.add("private ")
915 end
916 dctx.add(kind)
917 dctx.add(" {intro_class.mmmodule.toplevel_owner.name}")
918 if intro_class.global == lc.global then
919 dctx.add("::{lc.name}")
920 else
921 dctx.add("::{mmmodule[intro_class.global].html_link(dctx)}")
922 end
923 if is_redef then
924 dctx.add("::{mmmodule[intro_class.global][global].html_link(dctx)}")
925 else
926 dctx.add("::{html_name}")
927 end
928 dctx.add("</div>")
929
930 dctx.add("<div class=\"description\">")
931
932 # Collect all refinement of the global property in the same global property
933 var lps = new Array[MMLocalProperty]
934 for l in prhe.greaters_and_self do
935 lps.add(l)
936 end
937
938 var introdoc = false
939 if global.intro.doc != null then
940 for lp in lps do
941 if lp.doc == null then introdoc = true
942 end
943 end
944 if introdoc then
945 dctx.add("<pre>{global.intro.doc.to_html}</pre>")
946 end
947
948 var tlmods = new Array[MMModule]
949 for lp in lps do
950 var bm = lp.mmmodule.toplevel_owner
951 var lcm = lc.global.intro.mmmodule
952 if lcm.mhe < lp.mmmodule then bm = lcm.toplevel_owner
953 if not tlmods.has(bm) then tlmods.add(bm)
954 end
955
956 for tm in tlmods do
957 # Document the top level property for the current top level module
958 var tlp
959 if tm.global_classes.has(lc.global) then
960 tlp = tm[lc.global][self.global]
961 assert lps.has(tlp)
962 else if tm.global_classes.has(self.local_class.global) then
963 # Self is the inherited property. Process it
964 tlp = tm[self.local_class.global][self.global]
965 assert lps.has(tlp)
966 else
967 # We skip this module since the props defined by the module is
968 continue
969 end
970
971 var tlcm = lc.global.intro.mmmodule.toplevel_owner
972 if not tlcm.mhe <= tm then
973 dctx.add("<h4>In module {tm.html_link(dctx)} :</h4>")
974 end
975
976 #dctx.add("<p>TLP: {tm} x {lc} : {tlp.full_name}</p>")
977
978 var doc = tlp.doc
979 if doc != null and (not introdoc or global.intro.doc != doc) then
980 dctx.add("<pre>{doc.to_html}</pre>")
981 end
982 dctx.add("<p>")
983 if tlp.local_class.global != lc.global then
984 dctx.add("inherited from {tlp.local_class.html_link(dctx)} ")
985 end
986 if tm != tlp.mmmodule then
987 dctx.add("defined by the module {tlp.mmmodule.html_link(dctx)} ")
988 end
989 var n = tlp.node
990 if n != null then
991 var l = n.location
992 dctx.show_source(l)
993 end
994
995 dctx.open_stage
996 dctx.stage(". previously defined by:")
997 for lp in lps do
998 var tl = lp.mmmodule.toplevel_owner
999 if tl != tm then continue
1000 if lp == tlp then continue
1001 dctx.add(" {lp.mmmodule.html_link(dctx)}")
1002 if lp.local_class.global != lc.global then
1003 dctx.add(" for {lp.local_class.html_link(dctx)}")
1004 end
1005
1006 n = lp.node
1007 if n != null then
1008 var l = n.location
1009 dctx.show_source(l)
1010 end
1011
1012 #var doc = lp.doc
1013 #if doc != null and (not introdoc or global.intro.doc != doc) then
1014 # dctx.add("<pre>{doc.to_html}</pre>")
1015 #end
1016 end
1017 dctx.close_stage
1018 dctx.add("</p>")
1019 end
1020 dctx.add("</div>")
1021 dctx.add("</article>")
1022 end
1023 end
1024 redef class MMMethod
1025 redef fun kind do return if global.is_init then "init" else "fun"
1026 end
1027 redef class MMAttribute
1028 redef fun kind do return "var"
1029 end
1030 redef class MMTypeProperty
1031 redef fun kind do return "type"
1032 end
1033
1034 redef class MMSrcModule
1035 redef fun short_doc
1036 do
1037 var d = doc
1038 if d != null then
1039 return d.short
1040 else
1041 return "&nbsp;"
1042 end
1043 end
1044
1045 redef fun doc
1046 do
1047 var n = node
1048 if n.n_moduledecl == null then
1049 return null
1050 end
1051 var np = n.n_moduledecl
1052 var d = np.n_doc
1053 if d == null then
1054 return null
1055 end
1056 if d.n_comment.is_empty then
1057 return null
1058 else
1059 return d
1060 end
1061 end
1062 end
1063
1064 redef class ADoc
1065 # Html transcription of the doc
1066 fun to_html: String
1067 do
1068 var res = new Buffer
1069 for c in n_comment do
1070 res.append(c.text.substring_from(1))
1071 end
1072 return res.to_s.html_escape
1073 end
1074
1075 # Oneliner transcription of the doc
1076 fun short: String
1077 do
1078 return n_comment.first.text.substring_from(1).html_escape
1079 end
1080 end
1081
1082 redef class MMLocalClass
1083 super MMEntity
1084
1085 # Anchor of the class description in the module html file
1086 fun html_anchor: String do return "CLASS_{self}"
1087
1088 fun html_name: String do return "{self}"
1089
1090 redef fun html_link(dctx)
1091 do
1092 if not require_doc(dctx) then print "{dctx.filename}: not required {self}"
1093 return "<a href=\"{html_name}.html\" title=\"{short_doc}\">{self}</a>"
1094 end
1095
1096 redef fun short_doc do return global.intro.short_doc
1097
1098 redef fun doc do return global.intro.doc
1099
1100 fun kind: String
1101 do
1102 if global.is_interface then
1103 return "interface"
1104 else if global.is_abstract then
1105 return "abstract class"
1106 else if global.is_enum then
1107 return "enum"
1108 else
1109 return "class"
1110 end
1111 end
1112
1113 # The most specific module in the nesting hierarchy that exports the intro of self
1114 fun intro_module: MMModule
1115 do
1116 var m = global.intro.mmmodule
1117 var mo = m.direct_owner
1118 while mo != null and mo.visibility_for(m) >= 2 do
1119 m = mo
1120 mo = m.direct_owner
1121 end
1122 return m
1123 end
1124
1125 fun menu_link(dctx: DocContext, p: MMLocalProperty)
1126 do
1127 if p.local_class.global != self.global then
1128 if p.global.intro.local_class.name == "Object".to_symbol then return
1129 if p.global.is_init or p isa MMTypeProperty then
1130 dctx.add("<li class='inherit'><span title='Inherited'>H</span>&nbsp;{p.html_link_special(dctx, self)}</li>\n")
1131 else
1132 dctx.add("<li class='inherit'><span title='Inherited'>H</span>&nbsp;{p.html_link(dctx)}</li>\n")
1133 end
1134 else if p.global.intro.local_class.global == self.global then
1135 dctx.add("<li class='intro'><span title='Introduced'>I</span>&nbsp;{p.html_link_special(dctx, self)}</li>\n")
1136 else
1137 dctx.add("<li class='redef'><span title='Redefined'>R</span>&nbsp;{p.html_link_special(dctx, self)}</li>\n")
1138 end
1139 end
1140
1141 # Return true if the global class must be documented according to the visibility configured
1142 fun require_doc(dctx: DocContext): Bool
1143 do
1144 if global.visibility_level == 3 and not dctx.with_private then return false # Private
1145 if dctx.public_only then
1146 var m = intro_module
1147 if m != m.toplevel_owner then return false # Unexported
1148 end
1149 return true
1150 end
1151
1152 # Fill the body for the page associated to the global class
1153 fun file_page_doc(dctx: DocContext)
1154 do
1155 dctx.add("<div class=\"menu\">\n")
1156
1157 var props = new Array[MMLocalProperty]
1158 var inh = new HashMap[MMLocalClass, Array[MMLocalProperty]]
1159 var inhs = new Array[MMLocalClass]
1160 for g in global_properties do
1161 var p = self[g]
1162 if not p.require_doc(dctx) then continue
1163 if p.local_class.global == global or g.is_init_for(self) or p isa MMTypeProperty then
1164 props.add(p)
1165 else
1166 var lc = mmmodule[p.local_class.global]
1167 if inh.has_key(lc) then
1168 inh[lc].add(p)
1169 else
1170 inh[lc] = [p]
1171 inhs.add(lc)
1172 end
1173 props.add(p)
1174 end
1175 end
1176 dctx.sort(props)
1177
1178 dctx.add("<nav class=\"properties filterable\">\n")
1179 dctx.add("<h3>Properties</h3>\n")
1180 dctx.open_stage
1181 dctx.stage("<h4>Virtual Types</h4>\n<ul>\n")
1182 for p in props do
1183 if p isa MMTypeProperty then
1184 menu_link(dctx, p)
1185 end
1186 end
1187 dctx.stage("</ul>\n")
1188 dctx.close_stage
1189 dctx.open_stage
1190 dctx.stage("<h4>Constructors</h4>\n<ul>\n")
1191 for p in props do
1192 if p.global.is_init_for(self) then
1193 menu_link(dctx, p)
1194 end
1195 end
1196 dctx.stage("</ul>\n")
1197 dctx.close_stage
1198 dctx.open_stage
1199 dctx.stage("<h4>Methods</h4>\n<ul>\n")
1200 for p in props do
1201 if not p.global.is_init and p isa MMMethod then
1202 menu_link(dctx, p)
1203 end
1204 end
1205 dctx.stage("</ul>\n")
1206 dctx.close_stage
1207 dctx.add("</nav>\n")
1208
1209 dctx.add("<nav class=\"inheritance filterable\">\n")
1210 dctx.add("<h3>Inheritance</h3>\n")
1211 dctx.add("<h4>Superclasses</h4>\n<ul>\n")
1212 for lc in cshe.linear_extension do
1213 if lc == self then continue
1214 if not lc.require_doc(dctx) then continue
1215 dctx.add("<li>{lc.html_link(dctx)}</li>\n")
1216 end
1217 dctx.add("</ul>\n")
1218 if cshe.smallers.length == 0 then
1219 dctx.add("<h4>No Known Subclasses</h4>\n")
1220 else if cshe.smallers.length <= 100 then
1221 dctx.add("<h4>Subclasses</h4>\n")
1222 dctx.add("<ul>\n")
1223 for lc in cshe.smallers do
1224 if not lc.require_doc(dctx) then continue
1225 dctx.add("<li>{lc.html_link(dctx)}</li>\n")
1226 end
1227 dctx.add("</ul>\n")
1228 else if cshe.direct_smallers.length <= 100 then
1229 dctx.add("<h4>Direct Subclasses Only</h4>\n<ul>\n")
1230 for lc in cshe.direct_smallers do
1231 if not lc.require_doc(dctx) then continue
1232 dctx.add("<li>{lc.html_link(dctx)}</li>\n")
1233 end
1234 dctx.add("</ul>\n")
1235 else
1236 dctx.add("<h4>Too much Subclasses to list</h4>\n")
1237 end
1238 dctx.add("</nav>\n")
1239
1240 dctx.add("</div>\n")
1241
1242
1243 dctx.add("<div class=\"content\">\n")
1244 dctx.add("<h1>{name}</h1>\n")
1245 dctx.add("<div class='subtitle'>")
1246 if global.visibility_level == 2 then
1247 abort
1248 else if global.visibility_level == 3 then
1249 dctx.add("private ")
1250 else if self.global.intro.mmmodule.toplevel_owner.visibility_for(self.global.intro.mmmodule) <= 1 then
1251 dctx.add("(unexported) ")
1252 end
1253 dctx.add("{kind} {global.intro.mmmodule.toplevel_owner.html_link(dctx)}::{name}</div>")
1254
1255 dctx.add("<section class=\"description\">\n")
1256 var doc = doc
1257 if doc != null then
1258 dctx.add("<pre>{doc.to_html}</pre>\n")
1259 end
1260
1261 var cla = new HashSet[MMLocalClass]
1262 var sm = new HashSet[MMLocalClass]
1263 var sm2 = new HashSet[MMLocalClass]
1264 sm.add(self)
1265 while cla.length + sm.length < 10 and sm.length > 0 do
1266 cla.add_all(sm)
1267 sm2.clear
1268 for x in sm do
1269 sm2.add_all(x.cshe.direct_smallers)
1270 end
1271 var t = sm
1272 sm = sm2
1273 sm2 = t
1274 end
1275 cla.add_all(cshe.greaters_and_self)
1276
1277 var op = new Buffer
1278 var name = "class_{name}"
1279 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")
1280 for c in cla do
1281 if c == self then
1282 op.append("\"{c.name}\"[shape=box,margin=0.03];\n")
1283 else
1284 op.append("\"{c.name}\"[URL=\"{c.html_name}.html\"];\n")
1285 end
1286 for c2 in c.cshe.direct_greaters do
1287 if not cla.has(c2) then continue
1288 op.append("\"{c.name}\"->\"{c2.name}\";\n")
1289 end
1290 if not c.cshe.direct_smallers.is_empty then
1291 var others = true
1292 for c2 in c.cshe.direct_smallers do
1293 if cla.has(c2) then others = false
1294 end
1295 if others then
1296 op.append("\"{c.name}...\"[label=\"\"];\n")
1297 op.append("\"{c.name}...\"->\"{c.name}\"[style=dotted];\n")
1298 end
1299 end
1300 end
1301 op.append("\}\n")
1302 dctx.gen_dot(op.to_s, name.to_s, "Inheritance graph for class {name}")
1303
1304
1305 var mods = new Array[MMModule]
1306 mods.add(global.intro.mmmodule.toplevel_owner)
1307 for lc in crhe.greaters do
1308 if not lc isa MMSrcLocalClass then continue
1309 var m = lc.mmmodule.toplevel_owner
1310 if not mods.has(m) then mods.add(m)
1311 end
1312 dctx.sort(mods)
1313 for m in mods do
1314 if m == global.intro.mmmodule.toplevel_owner then
1315 dctx.add("<p>Introduced by {m.html_link(dctx)}")
1316 else
1317 dctx.add("<p>Refined by {m.html_link(dctx)}")
1318 end
1319 dctx.open_stage
1320 dctx.stage(". Definition in:")
1321 for lc in crhe.greaters do
1322 if lc.mmmodule.toplevel_owner != m then continue
1323 dctx.add(" {lc.mmmodule.html_link(dctx)}")
1324 assert lc isa MMSrcLocalClass
1325 var n = lc.node
1326 if n != null then
1327 dctx.show_source(n.location)
1328 end
1329 end
1330 dctx.close_stage
1331 dctx.add("</p>\n")
1332 end
1333 dctx.add("</section>\n")
1334
1335 dctx.open_stage
1336 dctx.stage("<section class=\"types\">\n")
1337 dctx.stage("<h2>Formal and Virtual Types</h2>\n")
1338 for i in [0..arity[ do
1339 var f = get_formal(i)
1340 f.full_documentation(dctx, self)
1341 end
1342 for p in props do
1343 if not p isa MMTypeProperty then continue
1344 p.full_documentation(dctx, self)
1345 end
1346 dctx.stage("</section>\n")
1347 dctx.close_stage
1348
1349 dctx.open_stage
1350 dctx.stage("<section class=\"constructors\">\n")
1351 dctx.stage("<h2 class=\"section-header\">Constructors</h2>\n")
1352 for p in props do
1353 if not p.global.is_init_for(self) then continue
1354 p.full_documentation(dctx, self)
1355 end
1356 dctx.stage("</section>\n")
1357 dctx.close_stage
1358
1359 dctx.open_stage
1360 dctx.stage("<section class=\"methods\">\n")
1361 dctx.stage("<h2 class=\"section-header\">Methods</h2>\n")
1362 for p in props do
1363 if p.global.is_init then continue
1364 if p.local_class.global != self.global then continue
1365 if not p isa MMMethod then continue
1366 p.full_documentation(dctx, self)
1367 end
1368 if not inhs.is_empty then
1369 dctx.open_stage
1370 dctx.stage("<h3>Inherited Methods</h3>\n")
1371 for lc in inhs do
1372 dctx.open_stage
1373 dctx.stage("<p>Defined in {lc.html_link(dctx)}:")
1374 for p in inh[lc] do
1375 if p.global.is_init then continue
1376 if not p isa MMMethod then continue
1377 dctx.add(" {p.html_link(dctx)}")
1378 end
1379 dctx.stage("</p>")
1380 dctx.close_stage
1381 end
1382 dctx.close_stage
1383 end
1384 dctx.add("</section>\n")
1385 dctx.close_stage
1386 dctx.add("</div> <!-- end class {name} -->\n")
1387 end
1388 end
1389
1390 redef class MMSrcLocalClass
1391 redef fun short_doc
1392 do
1393 var d = doc
1394 if d != null then
1395 return d.short
1396 else if global.intro == self then
1397 return "&nbsp;"
1398 else
1399 var bc = global.intro
1400 return bc.short_doc
1401 end
1402 end
1403
1404 redef fun doc
1405 do
1406 var n = node
1407 if not n isa AStdClassdef then
1408 return null
1409 end
1410 var d = n.n_doc
1411 if d == null then
1412 return null
1413 end
1414 if d.n_comment.is_empty then
1415 return null
1416 else
1417 return d
1418 end
1419 end
1420 end
1421
1422 redef class MMSignature
1423 # Htlm transcription of the signature (with nested links)
1424 fun to_html(dctx: DocContext, with_closure: Bool): String
1425 do
1426 var res = new Buffer
1427 if arity > 0 then
1428 res.append("(")
1429 for i in [0..arity[ do
1430 if i > 0 then res.append(", ")
1431 res.append(self.params[i].name.to_s)
1432 res.append(": ")
1433 res.append(self[i].html_link(dctx))
1434 if self.vararg_rank == i then
1435 res.append("...")
1436 end
1437 end
1438 res.append(")")
1439 end
1440 if return_type != null then
1441 res.append(": ")
1442 res.append(return_type.html_link(dctx))
1443 end
1444 if with_closure then
1445 for c in closures do
1446 res.append(" ")
1447 if c.is_optional then res.append("[")
1448 if c.is_break then res.append("break ")
1449 res.append("!{c.name}")
1450 res.append(c.signature.to_html(dctx, false))
1451 if c.is_optional then res.append("]")
1452 end
1453 end
1454 return res.to_s
1455 end
1456 end
1457
1458 redef class MMType
1459 # Htlm transcription of the type (with nested links)
1460 fun html_link(dctx: DocContext): String do return to_s
1461 end
1462
1463 redef class MMTypeSimpleClass
1464 redef fun html_link(dctx) do return local_class.html_link(dctx)
1465 end
1466
1467 redef class MMTypeGeneric
1468 redef fun html_link(dctx)
1469 do
1470 var res = new Buffer
1471 res.append(local_class.html_link(dctx))
1472 res.append("[")
1473 res.append(params[0].html_link(dctx))
1474 for i in [1..params.length[ do
1475 res.append(", ")
1476 res.append(params[i].html_link(dctx))
1477 end
1478 res.append("]")
1479 return res.to_s
1480 end
1481 end
1482
1483 redef class MMTypeFormalParameter
1484 fun html_anchor: String
1485 do
1486 return "FT_{local_class}_{cmangle(name)}"
1487 end
1488 redef fun html_link(dctx)
1489 do
1490 return "<a href=\"#{html_anchor}\">{name}</a>"
1491 end
1492 fun full_documentation(dctx: DocContext, lc: MMLocalClass)
1493 do
1494 dctx.add("<article id=\"{html_anchor}\">\n")
1495 dctx.add("<h3 class=\"signature\">{name}: {bound.html_link(dctx)}</h3>\n")
1496 dctx.add("<div class=\"info\">")
1497 dctx.add("formal generic type")
1498 dctx.add("</div>")
1499 dctx.add("</article>")
1500 end
1501 end
1502
1503 redef class MMNullableType
1504 redef fun html_link(dctx) do return "nullable " + as_notnull.html_link(dctx)
1505 end
1506
1507 redef class MMVirtualType
1508 redef fun html_link(dctx) do return property.html_link(dctx)
1509 end
1510
1511 var c = new DocContext
1512 c.exec_cmd_line