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