1 # This file is part of NIT ( http://www.nitlanguage.org ).
3 # Copyright 2008 Jean Privat <jean@pryen.org>
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
9 # http://www.apache.org/licenses/LICENSE-2.0
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.
17 # The main module of the nitdoc program
25 # Store knowledge and facilities to generate files
27 super AbstractCompiler
28 # Destination directory
29 readable writable var _dir
: String = "doc"
31 # Content of a generated file
32 var _stage_context
: StageContext = new StageContext(null)
34 # Add a string in the content
36 _stage_context
.content
.add
(s
)
37 _stage_context
.validate
= true
40 # Add a string in the content iff some other string are added
41 fun stage
(s
: String) do _stage_context
.content
.add
(s
)
43 # Create a new stage in the content
44 fun open_stage
do _stage_context
= new StageContext(_stage_context
)
46 # Close the current stage in the content
49 var s
= _stage_context
.parent
50 if _stage_context
.validate
then
51 s
.content
.add_all
(_stage_context
.content
)
58 # Write the content to a new file
59 fun write_to
(filename
: String)
61 var f
= new OFStream.open
(filename
)
62 for s
in _stage_context
.content
do
71 _stage_context
= new StageContext(null)
74 # Sorter of entities in alphabetical order
75 var _sorter
: AlphaSorter[MMEntity] = new AlphaSorter[MMEntity]
77 # Sort entities in the alphabetical order
78 fun sort
(array
: Array[MMEntity])
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")
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
98 if self._opt_public
.value
== true then return true
102 fun with_private
: Bool
104 if self._opt_private
.value
== true then return true
108 # The current processed filename
111 # The main virtual module
112 var mainmod
: nullable MMVirtualModule
114 redef fun perform_work
(mods
)
116 mainmod
= new MMVirtualModule(self, mods
)
120 sys
.system
("cp -r '{sharedir.to_s}'/* {dir}/")
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]
127 for mod
in modules
do
128 if mod
== mainmod
then continue
129 var d
= mod
.directory
132 if o
!= null and o
!= mod
then
136 if dp
== null or dp
== d
then break
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
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
154 else if m
.visibility_for
(m2
) == 1 then
159 m
.tmhe_
= tmh
.add
(m
, pub
)
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\
" />"
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)
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"
173 var custom_title
= "Nitdoc"
174 if self._opt_custom_title
.value
!= null then custom_title
= self._opt_custom_title
.value
.as(not null)
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)
180 if self._opt_custom_footer_text
.value
!= null then footer_text
= self._opt_custom_footer_text
.value
.as(not null)
183 self.filename
= "index.html"
185 add
("<!DOCTYPE html>")
186 add
("<html><head>{head}<title>Overview | {custom_title}</title></head><body>\n")
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
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>")
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")
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")
214 self.gen_dot
(op
.to_s
, "dep", "Modules hierarchy")
215 add
("</article></div>")
217 add
("<footer>{footer_text}</footer>")
218 add
("</body></html>\n")
219 write_to
("{dir}/index.html")
221 # Generate page for modules
222 for mod
in modules
do
223 if mod
== mainmod
then continue
224 assert mod
isa MMSrcModule
225 if not mod
.require_doc
(self) then continue
226 self.filename
= mod
.html_name
227 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 add
("<!DOCTYPE html>")
230 add
("<html><head>{head}<title>{mod.name} module | {custom_title}</title></head><body>\n")
232 add
("<div class=\"page\
">")
233 mod
.file_page_doc
(self)
235 add
("<footer>{footer_text}</footer>")
236 add
("</body></html>\n")
237 write_to
("{dir}/{mod.html_name}.html")
240 # Generate pages for global classes
241 for c
in mainmod
.local_classes
do
242 if not c
.require_doc
(self) then continue
243 self.filename
= c
.html_name
244 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 add
("<!DOCTYPE html>")
247 add
("<html><head>{head}<title>{c.name} class | {custom_title}</title></head><body>\n")
249 add
("<div class=\"page\
">")
250 c
.file_page_doc
(self)
252 add
("<footer>{footer_text}</footer>")
253 add
("</body></html>\n")
254 write_to
("{dir}/{c.html_name}.html")
257 self.filename
= "fullindex"
258 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 add
("<!DOCTYPE html>")
261 add
("<html><head>{head}<title>Full Index | {custom_title}</title></head><body>\n")
263 add
("<div class=\"page\
">")
264 add
("<div class=\"content fullpage\
">")
265 mainmod
.file_index_page_doc
(self)
268 add
("<footer>{footer_text}</footer>")
269 add
("</body></html>\n")
270 write_to
("{dir}/full-index.html")
272 self.filename
= "quicksearch-list"
274 mainmod
.file_quicksearch_list_doc
(self)
275 write_to
("{dir}/quicksearch-list.js")
279 # Add a (source) link fo a given location
280 fun show_source
(l
: Location)
282 var s
= opt_source
.value
284 add
("({l.file.filename.simplify_path})")
286 # THIS IS JUST UGLY ! (but there is no replace yet)
287 var x
= s
.split_with
("%f")
288 s
= x
.join
(l
.file
.filename
.simplify_path
)
289 x
= s
.split_with
("%l")
290 s
= x
.join
(l
.line_start
.to_s
)
291 x
= s
.split_with
("%L")
292 s
= x
.join
(l
.line_end
.to_s
)
293 add
(" (<a href=\"{s}\
">show code</a>)")
297 # Generate a clicable graphiz image using a dot content.
298 # `name' refer to the filename (without extension) and the id name of the map.
299 # `name' must also match the name of the graph in the dot content (eg. digraph NAME {...)
300 fun gen_dot
(dot
: String, name
: String, alt
: String)
302 if opt_nodot
.value
then return
303 var f
= new OFStream.open
("{self.dir}/{name}.dot")
306 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 ; \}")
307 self.add
("<article class=\"graph\
"><img src=\"{name}.png\
" usemap=\"#{name}\" style=\"margin:auto\" alt=\"{alt}\"/></article>")
308 var fmap
= new IFStream.open
("{self.dir}/{name}.map")
309 self.add
(fmap
.read_all
)
318 option_context
.add_option
(opt_public
)
319 option_context
.add_option
(opt_private
)
320 option_context
.add_option
(opt_dir
)
321 option_context
.add_option
(opt_source
)
322 option_context
.add_option
(opt_nodot
)
323 option_context
.add_option
(opt_sharedir
)
324 option_context
.add_option
(opt_custom_title
)
325 option_context
.add_option
(opt_custom_menu_items
)
326 option_context
.add_option
(opt_custom_overview_text
)
327 option_context
.add_option
(opt_custom_footer_text
)
330 redef fun process_options
333 var d
= opt_dir
.value
334 if d
!= null then dir
= d
336 if not opt_nodot
.value
then
337 # Test if dot is runable
338 var res
= sys
.system
("sh -c dot </dev/null >/dev/null 2>&1")
340 stderr
.write
"--no-dot implied since `dot' is not available. Try to install graphviz.\n"
341 opt_nodot
.value
= true
345 sharedir
= opt_sharedir
.value
346 if sharedir
== null then
347 var dir
= "NIT_DIR".environ
349 dir
= "{sys.program_name.dirname}/../share/nitdoc"
350 if dir
.file_exists
then sharedir
= dir
352 dir
= "{dir}/share/nitdoc"
353 if dir
.file_exists
then sharedir
= dir
355 if sharedir
== null then
356 fatal_error
(null, "Error: Cannot locate nitdoc shared files. Uses --sharedir or envvar NIT_DIR.")
358 dir
= "{sharedir.to_s}/scripts/js-facilities.js"
359 if sharedir
== null then
360 fatal_error
(null, "Error: Invalid nitdoc shared files. Check --sharedir or envvar NIT_DIR.")
366 redef fun handle_property_conflict
(lc
, impls
)
368 # THIS IS SO UGLY! See MMVirtualModule
369 if lc
.mmmodule
== self.mainmod
then
370 return # We just accept, so one in impls is arbitrary inherited
376 # A virtual module is used to work as an implicit main module that combine unrelated modules
377 # Since conflict may arrise in a virtual module (the main method for instance) conflicts are disabled
378 class MMVirtualModule
380 init(ctx
: MMContext, mods
: Array[MMModule])
382 # We need to compute the whole metamodel since there is no mmbuilder to do it
383 super(" main".to_symbol
, mods
.first
.directory
, ctx
, new Location(null,0,0,0,0))
384 ctx
.add_module
(self, mods
)
386 self.add_super_module
(m
, 1)
388 self.import_global_classes
389 self.import_local_classes
390 for c
in self.local_classes
do
391 c
.compute_super_classes
393 for c
in self.local_classes
do
398 redef fun require_doc
(dctx
) do return false
401 # Conditionnal part of the text content of a DocContext
403 # Content of the current stage
404 readable var _content
: Array[String] = new Array[String]
406 # Is a normal string already added?
407 readable writable var _validate
: Bool = false
409 # Parent stage is any
410 readable var _parent
: nullable StageContext = null
412 init(parent
: nullable StageContext) do _parent
= parent
416 # Efficiently sort object with their to_s method
417 class AlphaSorter[E
: Object]
418 super AbstractSorter[E
]
419 redef fun compare
(a
, b
)
439 # Keep track of to_s values
440 var _dico
: HashMap[Object, String] = new HashMap[Object, String]
445 # Generalization of metamodel entities
448 fun html_link
(dctx
: DocContext): String is abstract
450 # Return a one liner description
451 fun short_doc
: String do return " "
453 # The doc node from the AST
454 # Return null is none
455 fun doc
: nullable ADoc do return null
457 # Return a JSON entry for quicksearch list
458 fun json_entry
(dctx
: DocContext): String is abstract
460 # Return the qualified name as string
461 fun qualified_name
: String is abstract
467 redef fun html_link
(dctx
) do
468 if short_doc
== " " then
469 return "<a href=\"{html_name}.html\
"\">{self}</a
>"
471 return "<a href
=\
"{html_name}.html\" title
=\
"{short_doc}\">{self}</a
>"
475 fun html_anchor: String do
476 return "<a id
=\
"MOD_{html_name}\"></a
>"
479 fun html_link_to_anchor: String do
480 return "<a href
=\
"#MOD_{html_name}\" title
=\
"Jump to definitions from module {html_name}\">{self}</a
>"
483 redef fun json_entry(dctx) do
484 return "\
{txt:\"{self.qualified_name}\
",url:\"{html_name}.html\
"\},"
487 redef fun qualified_name
do
488 var buffer
= new Buffer
489 for m
in mnhe
.smallers
do
490 buffer
.append
("{m.html_name}::")
492 buffer
.append
("{self.name}")
496 fun require_doc
(dctx
: DocContext): Bool
498 if dctx
.public_only
and not is_toplevel
then return false
502 # Return true if the module is a top-level owner or a top-level module
503 fun is_toplevel
: Bool
505 var pd
= directory
.parent
506 return pd
== null or (pd
.owner
== null and directory
.owner
== self)
509 # Element in the module nesting tree
510 fun mnhe
: PartialOrderElement[MMModule] do return mnhe_
.as(not null)
511 var mnhe_
: nullable PartialOrderElement[MMModule] = null
513 # Element in the top level module importation hierarchy
514 fun tmhe
: PartialOrderElement[MMModule] do return tmhe_
.as(not null)
515 var tmhe_
: nullable PartialOrderElement[MMModule] = null
517 fun toplevel_owner
: MMModule
521 var ds
= m
.mnhe
.direct_smallers
522 if ds
.length
== 0 then return m
523 if ds
.length
== 1 then m
= ds
.first
else abort
527 fun html_name
: String
532 fun direct_owner
: nullable MMModule
535 while d
.owner
== self do d
= d
.parent
.as(not null)
539 # Fill the body for the page associated to the module
540 fun file_page_doc
(dctx
: DocContext)
542 dctx
.add
("<div class=\"menu\
">\n")
544 var mods
= new Array[MMModule]
545 mods
= self.mhe
.greaters
.to_a
549 dctx
.stage
("<nav>\n")
550 dctx
.stage
("<h3>Module Hierarchy</h3>\n")
551 dctx
.stage
("<h4>All dependencies</h4>\n")
554 if not mod
.require_doc
(dctx
) then continue
555 if self.mnhe
<= mod
then continue # do not want nested stuff
556 if mod
.direct_owner
!= null and not mod
.direct_owner
.mnhe
<= self then continue # not in the right nesting
557 dctx
.add
("<li>{mod.html_link(dctx)}</li>")
559 dctx
.stage
("</ul>\n")
561 mods
= self.mhe
.smallers
.to_a
563 dctx
.stage
("<h4>All clients</h4>\n")
566 if not mod
.require_doc
(dctx
) then continue
567 if self.mnhe
<= mod
then continue # do not want nested stuff
568 if mod
.direct_owner
!= null and not mod
.direct_owner
.mnhe
<= self then continue # not in the right nesting
569 dctx
.add
("<li>{mod.html_link(dctx)}</li>")
571 dctx
.stage
("</ul>\n")
572 dctx
.stage
("</nav>\n")
575 if not dctx
.public_only
then
576 mods
= self.mnhe
.direct_greaters
.to_a
579 dctx
.stage
("<nav>\n")
580 dctx
.stage
("<h3>Nested Modules</h3><ul>\n")
582 if not mod
.require_doc
(dctx
) then continue
583 dctx
.add
("<li>{mod.html_link(dctx)}</li>")
585 dctx
.stage
("</ul></nav>\n")
589 dctx
.add
("</div>") # metadata
591 dctx
.add
("<div class=\"content\
">\n")
592 dctx
.add
("<h1>{name}</h1>\n")
593 dctx
.add
("<div class='subtitle'>module ")
594 for m
in mnhe
.smallers
do
595 dctx
.add
("{m.html_link(dctx)}::")
597 dctx
.add
("{self.name}</div>\n")
599 dctx
.add
("<section class='description'>\n")
603 dctx
.add
("<div id=\"description\
">\n")
604 dctx
.add
("<pre>{doc.to_html}</pre>\n")
609 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")
610 var ms
= new Array[nullable MMModule]
612 var m0
: nullable MMModule = self
618 var cla
= new HashSet[MMModule]
620 for m0
in self.mhe
.greaters
do
621 if not m0
.require_doc
(dctx
) then continue
622 if self.visibility_for
(m0
) <= 1 then continue # private or hidden
623 if self.mnhe
<= m0
then continue # do not want nested stuff
624 if m0
.direct_owner
!= null and not m0
.direct_owner
.mnhe
<= self then continue # not in the right nesting
627 for m0
in self.mhe
.smallers
do
628 if not m0
.require_doc
(dctx
) then continue
629 if m0
.visibility_for
(self) <= 1 then continue # private or hidden
630 if m0
.direct_owner
!= null and not m0
.direct_owner
.mnhe
<= self then continue # not in the right nesting
633 for m0
in self.mnhe
.smallers
do
639 op
.append
("subgraph \"cluster_
{m0.name}\
"\{\n")
642 if c
.direct_owner
!= m0
then continue
644 op
.append
("\"{c.name}\
"[shape=box,margin=0.03];\n")
646 op
.append
("\"{c.name}\
"[URL=\"{c.html_name}.html\
"];\n")
650 op
.append
("\"{m0.name}\
"[URL=\"{m0.html_name}.html\
"];\n")
651 for c
in m0
.mhe
.direct_greaters
do
652 if not cla
.has
(c
) then continue
653 op
.append
("\"{m0.name}\
"->\"{c.name}\
";\n")
658 # Close the nesting subgraph
664 for c2
in c
.tmhe
.direct_greaters
do
665 if not cla
.has
(c2
) then continue
666 op
.append
("\"{c.name}\
"->\"{c2.name}\
";\n")
670 dctx
.gen_dot
(op
.to_s
, name
.to_s
, "Dependency graph for module {name}")
671 dctx
.add
("</section>")
673 var clas
= new Array[MMLocalClass]
674 var props
= new HashMap[MMGlobalProperty, Array[MMLocalProperty]]
675 var gprops
= new Array[MMLocalProperty]
678 for g
in m
.global_classes
do
680 if not lc
.require_doc
(dctx
) then continue
681 var im
= g
.intro
.mmmodule
682 if self.visibility_for
(im
) <= 1 then continue # private import or invisible import
684 for lc2
in lc
.crhe
.greaters_and_self
do
685 if not lc2
isa MMSrcLocalClass then continue
686 if not self.mnhe
<= lc2
.mmmodule
then continue # not introduced/redefined here/stolen
689 if not keep
then continue
691 lc
.compute_super_classes
692 for gp
in lc
.global_properties
do
693 if self.visibility_for
(gp
.intro
.local_class
.mmmodule
) <= 1 then continue # private import or invisible import
695 var mp
= lp
.local_class
.mmmodule
696 if not self.mnhe
<= mp
then continue # not introduced/redefined here/stolen
698 if not lp
.require_doc
(dctx
) then continue
699 if props
.has_key
(lp
.global
) then
700 if not props
[lp
.global
].has
(lp
) then
701 props
[lp
.global
].add
(lp
)
704 props
[lp
.global
] = [lp
]
705 gprops
.add
(lp
.global
.intro
)
710 dctx
.add
("<section class=\"module\
">\n")
712 dctx
.stage
("<article class=\"classes filterable\
">\n")
713 dctx
.stage
("<h2>Classes</h2>\n")
717 if self.mnhe
<= lc
.global
.intro
.mmmodule
then
718 dctx
.add
("<li class='intro'><span title='introduced in this module'>I</span> ")
720 dctx
.add
("<li class='redef'><span title='refined in this module'>R</span> ")
722 dctx
.add
("{lc.html_link(dctx)}</li>\n")
724 dctx
.stage
("</ul></article>\n")
728 dctx
.stage
("<article class=\"properties filterable\
">\n")
729 dctx
.stage
("<h2>Properties</h2>\n")
736 if gp
.intro
isa MMAttribute then continue
738 var lpi
= self[gp
.intro
.local_class
.global
][gp
]
741 dctx
.add
("<li class='intro'><span title='introduction in an other module'>I</span> {lpi.html_open_link(dctx)}{lpi.html_name} ({lpi.local_class})</a></li>\n")
744 dctx
.add
("<li class='intro'><span title='introduction in this module'>I</span> {lpi.html_name}")
745 dctx
.add
(" ({lpi.local_class})</li>\n")
747 if lps
.length
>= 1 then
750 dctx
.add
("<li class='redef'><span title='redefinition'>R</span> {lp.html_open_link(dctx)}{lp.html_name} ({lp.local_class})</a></li>")
754 dctx
.stage
("</ul></article>\n")
756 dctx
.add
("</section>\n")
760 # Fill the body for the page associated to the full index
761 fun file_index_page_doc
(dctx
: DocContext)
764 dctx
.add
("<h1>Full Index</h1>\n")
766 var clas
= new Array[MMLocalClass]
767 var props
= new HashMap[MMGlobalProperty, Array[MMLocalProperty]]
768 var gprops
= new Array[MMLocalProperty]
769 var mods
= new Array[MMModule]
770 for m
in mhe
.greaters_and_self
do
771 if not m
.require_doc
(dctx
) then continue
774 for g
in global_classes
do
776 if not lc
.require_doc
(dctx
) then continue
778 for gp
in lc
.global_properties
do
780 if not lp
.require_doc
(dctx
) then continue
781 if props
.has_key
(lp
.global
) then
782 if not props
[lp
.global
].has
(lp
) then
783 props
[lp
.global
].add
(lp
)
786 props
[lp
.global
] = [lp
]
787 gprops
.add
(lp
.global
.intro
)
792 dctx
.stage
("<article class=\"modules filterable\
">\n")
793 dctx
.stage
("<h2>Modules</h2>\n")
797 dctx
.add
("<li>{m.html_link(dctx)}</li>")
799 dctx
.stage
("</ul></article>\n")
803 dctx
.stage
("<article class=\"classes filterable\
">\n")
804 dctx
.stage
("<h2>Classes</h2>\n")
808 dctx
.add
("<li>{lc.html_link(dctx)}</li>")
810 dctx
.stage
("</ul></article>\n")
814 dctx
.stage
("<article class=\"properties filterable\
">\n")
815 dctx
.stage
("<h2>Properties</h2>\n")
822 if gp
.intro
isa MMAttribute then continue
824 var lpi
= self[gp
.intro
.local_class
.global
][gp
]
827 dctx
.add
("<li class='intro'><span title='introduction'>I</span> {lpi.html_open_link(dctx)}{lpi.html_name} ({lpi.local_class})</a></li>\n")
828 if lps
.length
>= 1 then
831 dctx
.add
("<li class='redef'><span title='redefinition'>R</span> {lp.html_open_link(dctx)}{lp.html_name} ({lp.local_class})</a></li>\n")
835 dctx
.stage
("</ul></article>\n")
839 # Fill the quicksearch list JSON object
840 fun file_quicksearch_list_doc
(dctx
: DocContext)
842 var entities
= new HashMap[String, Array[MMEntity]]
843 var props
= new HashMap[MMGlobalProperty, Array[MMLocalProperty]]
844 for m
in mhe
.greaters_and_self
do
845 if not m
.require_doc
(dctx
) then continue
846 var a
= new Array[MMEntity]
848 entities
[m
.html_name
] = a
850 for g
in global_classes
do
852 if not lc
.require_doc
(dctx
) then continue
853 var a
= new Array[MMEntity]
855 entities
[lc
.html_name
] = a
856 for gp
in lc
.global_properties
do
858 if not lp
.require_doc
(dctx
) then continue
859 if lp
.kind
== "var" then continue
860 if props
.has_key
(lp
.global
) then
861 if not props
[lp
.global
].has
(lp
) then
862 props
[lp
.global
].add
(lp
)
865 props
[lp
.global
] = [lp
]
871 entities
[k
.short_name
] = v
874 var keys
= entities
.keys
.to_a
875 var sorter
= new AlphaSorter[String]
879 dctx
.stage
("var entries = \{")
881 dctx
.add
("\"{key}\
": [")
882 for entity
in entities
[key
] do
883 dctx
.add
(entity
.json_entry
(dctx
))
892 redef class MMGlobalProperty
893 # Return the short name of the property
894 fun short_name
: String do
895 return self.intro
.html_name
899 redef class MMLocalProperty
901 # Anchor of the property description in the module html file
902 fun html_anchor
: String
904 return "PROP_{self.mmmodule.toplevel_owner}_{local_class}_{cmangle(name)}"
907 redef fun json_entry
(dctx
) do
908 return "\{txt:\"{qualified_name}\",url
:\
"{local_class.html_name}.html#{html_anchor}\"\
},"
911 redef fun qualified_name do
912 return "{intro_module.qualified_name}::{local_class.html_name}::{html_name}"
915 fun html_open_link(dctx: DocContext): String
917 if not require_doc(dctx) then print "not required
{self}"
918 var title = "{html_name}{signature.to_s}"
919 if short_doc != " 
;" then
920 title += " #{short_doc}"
922 return "<a href=\"{local_class.html_name}.html
#{html_anchor}\" title=\"{title}\">"
925 fun html_name
: String
927 return self.name
.to_s
.html_escape
930 redef fun html_link
(dctx
)
932 if not require_doc
(dctx
) then print
"not required {self}"
933 var title
= "{html_name}{signature.to_s}"
934 if short_doc
!= " " then
935 title
+= " #{short_doc}"
937 return "<a href=\"{local_class.html_name}.html
#{html_anchor}\" title=\"{title}\">{html_name}</a>"
940 fun html_link_special
(dctx
: DocContext, lc
: MMLocalClass): String
942 if not require_doc
(dctx
) then print
"not required {self}"
943 var title
= "{html_name}{signature_for(lc.get_type)}"
944 if short_doc
!= " " then
945 title
+= " #{short_doc}"
947 return "<a href=\"{lc.html_name}.html
#{html_anchor}\" title=\"{title}\">{html_name}</a>"
950 # Kind of property (fun, attr, etc.)
951 fun kind
: String is abstract
958 else if global
.intro
== self then
961 return global
.intro
.short_doc
968 if n
== null or not n
isa APropdef then
975 if d
.n_comment
.is_empty
then
982 # The most specific module in the nesting hierarchy that exports the intro of self
983 fun intro_module
: MMModule
985 var m
= global
.intro
.mmmodule
986 var mo
= m
.direct_owner
987 while mo
!= null and mo
.visibility_for
(m
) >= 2 do
994 # Is the intro of self exported by the top-level module ?
995 fun is_toplevel
: Bool
998 return m
== m
.toplevel_owner
1001 # Return true if the global property must be documented according to the visibility configured
1002 fun require_doc
(dctx
: DocContext): Bool
1004 if global
.visibility_level
== 3 and not dctx
.with_private
then return false # Private
1005 if dctx
.public_only
then
1006 var m
= intro_module
1007 if m
!= m
.toplevel_owner
then return false # Unexported
1012 # Document the global property in the global class lc
1013 fun full_documentation
(dctx
: DocContext, lc
: MMLocalClass)
1015 var visibility
: String
1016 if global
.visibility_level
== 1 then
1017 visibility
= "public"
1018 else if global
.visibility_level
== 2 then
1019 visibility
= "protected"
1020 else if global
.visibility_level
== 3 then
1021 visibility
= "private"
1026 var intro_class
= global
.intro
.local_class
1027 var is_redef
= local_class
.global
!= intro_class
.global
or local_class
.mmmodule
.toplevel_owner
!= intro_class
.mmmodule
.toplevel_owner
1029 dctx
.add
("<article id=\"{html_anchor}\
" class=\"{kind} {visibility} {if is_redef then "redef" else ""}\
">\n")
1030 dctx
.add
("<h3 class=\"signature\
">{html_name}{signature.to_html(dctx, true)}</h3>\n")
1031 dctx
.add
("<div class=\"info\
">\n")
1032 #dctx.add("<p>LP: {self.mmmodule.html_link(dctx)}::{self.local_class.html_link(dctx)}::{self.html_link(dctx)}</p>")
1037 if not is_toplevel
then
1038 dctx
.add
("(unexported) ")
1040 if global
.visibility_level
== 2 then
1041 dctx
.add
("protected ")
1042 else if global
.visibility_level
== 3 then
1043 dctx
.add
("private ")
1046 dctx
.add
(" {intro_class.mmmodule.toplevel_owner.name}")
1047 if intro_class
.global
== lc
.global
then
1048 dctx
.add
("::{lc.name}")
1050 dctx
.add
("::{mmmodule[intro_class.global].html_link(dctx)}")
1053 dctx
.add
("::{mmmodule[intro_class.global][global].global.intro.html_link(dctx)}")
1055 dctx
.add
("::{html_name}")
1059 dctx
.add
("<div class=\"description\
">")
1061 # Collect all refinement of the global property in the same global property
1062 var lps
= new Array[MMLocalProperty]
1063 for l
in prhe
.greaters_and_self
do
1067 var introdoc
= false
1068 if global
.intro
.doc
!= null then
1070 if lp
.doc
== null then introdoc
= true
1074 dctx
.add
("<pre>{global.intro.doc.to_html}</pre>")
1077 var tlmods
= new Array[MMModule]
1079 var bm
= lp
.mmmodule
.toplevel_owner
1080 var lcm
= lc
.global
.intro
.mmmodule
1081 if lcm
.mhe
< lp
.mmmodule
then bm
= lcm
.toplevel_owner
1082 if not tlmods
.has
(bm
) then tlmods
.add
(bm
)
1086 # Document the top level property for the current top level module
1088 if tm
.global_classes
.has
(lc
.global
) then
1089 tlp
= tm
[lc
.global
][self.global
]
1091 else if tm
.global_classes
.has
(self.local_class
.global
) then
1092 # Self is the inherited property. Process it
1093 tlp
= tm
[self.local_class
.global
][self.global
]
1096 # We skip this module since the props defined by the module is
1100 var tlcm
= lc
.global
.intro
.mmmodule
.toplevel_owner
1101 if not tlcm
.mhe
<= tm
then
1102 dctx
.add
("<h4>In module {tm.html_link(dctx)} :</h4>")
1105 #dctx.add("<p>TLP: {tm} x {lc} : {tlp.full_name}</p>")
1108 if doc
!= null and (not introdoc
or global
.intro
.doc
!= doc
) then
1109 dctx
.add
("<pre>{doc.to_html}</pre>")
1112 if tlp
.local_class
.global
!= lc
.global
then
1113 dctx
.add
("inherited from {tlp.local_class.html_link(dctx)} ")
1115 if tm
!= tlp
.mmmodule
then
1116 dctx
.add
("defined by the module {tlp.mmmodule.html_link(dctx)} ")
1125 dctx
.stage
(". previously defined by:")
1127 var tl
= lp
.mmmodule
.toplevel_owner
1128 if tl
!= tm
then continue
1129 if lp
== tlp
then continue
1130 dctx
.add
(" {lp.mmmodule.html_link(dctx)}")
1131 if lp
.local_class
.global
!= lc
.global
then
1132 dctx
.add
(" for {lp.local_class.html_link(dctx)} ")
1142 #if doc != null and (not introdoc or global.intro.doc != doc) then
1143 # dctx.add("<pre>{doc.to_html}</pre>")
1150 dctx
.add
("</article>")
1153 redef class MMMethod
1154 redef fun kind
do return if global
.is_init
then "init" else "fun"
1156 redef class MMAttribute
1157 redef fun kind
do return "var"
1159 redef class MMTypeProperty
1160 redef fun kind
do return "type"
1163 redef class MMSrcModule
1177 if n
.n_moduledecl
== null then
1180 var np
= n
.n_moduledecl
1185 if d
.n_comment
.is_empty
then
1194 # Html transcription of the doc
1197 var res
= new Buffer
1198 for c
in n_comment
do
1199 res
.append
(c
.text
.substring_from
(1))
1201 return res
.to_s
.html_escape
1204 # Oneliner transcription of the doc
1207 return n_comment
.first
.text
.substring_from
(1).html_escape
1211 redef class MMLocalClass
1214 # Anchor of the class description in the module html file
1215 fun html_anchor
: String do return "CLASS_{self}"
1217 fun html_name
: String do return "{self}"
1219 redef fun html_link
(dctx
)
1221 if not require_doc
(dctx
) then print
"{dctx.filename}: not required {self}"
1222 if short_doc
== " " then
1223 return "<a href=\"{html_name}.html\
"\">{self}</a
>"
1225 return "<a href
=\
"{html_name}.html\" title
=\
"{short_doc}\">{self}</a
>"
1229 redef fun json_entry(dctx) do
1230 return "\
{txt:\"{qualified_name}\
",url:\"{html_name}.html\
"\},"
1233 redef fun qualified_name
do
1234 return "{intro_module.qualified_name}::{html_name}"
1237 redef fun short_doc
do return global
.intro
.short_doc
1239 redef fun doc
do return global
.intro
.doc
1243 if global
.is_interface
then
1245 else if global
.is_abstract
then
1246 return "abstract class"
1247 else if global
.is_enum
then
1254 # The most specific module in the nesting hierarchy that exports the intro of self
1255 fun intro_module
: MMModule
1257 var m
= global
.intro
.mmmodule
1258 var mo
= m
.direct_owner
1259 while mo
!= null and mo
.visibility_for
(m
) >= 2 do
1266 fun menu_link
(dctx
: DocContext, p
: MMLocalProperty)
1268 if p
.local_class
.global
!= self.global
then
1269 if p
.global
.intro
.local_class
.name
== "Object".to_symbol
then return
1270 if p
.global
.is_init
or p
isa MMTypeProperty then
1271 dctx
.add
("<li class='inherit'><span title='Inherited'>H</span> {p.html_link_special(dctx, self)}</li>\n")
1273 dctx
.add
("<li class='inherit'><span title='Inherited'>H</span> {p.html_link(dctx)}</li>\n")
1275 else if p
.global
.intro
.local_class
.global
== self.global
then
1276 dctx
.add
("<li class='intro'><span title='Introduced'>I</span> {p.html_link_special(dctx, self)}</li>\n")
1278 dctx
.add
("<li class='redef'><span title='Redefined'>R</span> {p.html_link_special(dctx, self)}</li>\n")
1282 # Return true if the global class must be documented according to the visibility configured
1283 fun require_doc
(dctx
: DocContext): Bool
1285 if global
.visibility_level
== 3 and not dctx
.with_private
then return false # Private
1286 if dctx
.public_only
then
1287 var m
= intro_module
1288 if m
!= m
.toplevel_owner
then return false # Unexported
1293 # Fill the body for the page associated to the global class
1294 fun file_page_doc
(dctx
: DocContext)
1296 dctx
.add
("<div class=\"menu\
">\n")
1298 var props
= new Array[MMLocalProperty]
1299 var inh
= new HashMap[MMLocalClass, Array[MMLocalProperty]]
1300 var inhs
= new Array[MMLocalClass]
1301 for g
in global_properties
do
1303 if not p
.require_doc
(dctx
) then continue
1304 if p
.local_class
.global
== global
or g
.is_init_for
(self) or p
isa MMTypeProperty then
1307 var lc
= mmmodule
[p
.local_class
.global
]
1308 if inh
.has_key
(lc
) then
1319 dctx
.add
("<nav class=\"properties filterable\
">\n")
1320 dctx
.add
("<h3>Properties</h3>\n")
1322 dctx
.stage
("<h4>Virtual Types</h4>\n<ul>\n")
1324 if p
isa MMTypeProperty then
1328 dctx
.stage
("</ul>\n")
1331 dctx
.stage
("<h4>Constructors</h4>\n<ul>\n")
1333 if p
.global
.is_init_for
(self) then
1337 dctx
.stage
("</ul>\n")
1340 dctx
.stage
("<h4>Methods</h4>\n<ul>\n")
1342 if not p
.global
.is_init
and p
isa MMMethod then
1346 dctx
.stage
("</ul>\n")
1348 dctx
.add
("</nav>\n")
1350 dctx
.add
("<nav class=\"inheritance filterable\
">\n")
1351 dctx
.add
("<h3>Inheritance</h3>\n")
1352 dctx
.add
("<h4>Superclasses</h4>\n<ul>\n")
1353 for lc
in cshe
.linear_extension
do
1354 if lc
== self then continue
1355 if not lc
.require_doc
(dctx
) then continue
1356 dctx
.add
("<li>{lc.html_link(dctx)}</li>\n")
1359 if cshe
.smallers
.length
== 0 then
1360 dctx
.add
("<h4>No Known Subclasses</h4>\n")
1361 else if cshe
.smallers
.length
<= 100 then
1362 dctx
.add
("<h4>Subclasses</h4>\n")
1364 for lc
in cshe
.smallers
do
1365 if not lc
.require_doc
(dctx
) then continue
1366 dctx
.add
("<li>{lc.html_link(dctx)}</li>\n")
1369 else if cshe
.direct_smallers
.length
<= 100 then
1370 dctx
.add
("<h4>Direct Subclasses Only</h4>\n<ul>\n")
1371 for lc
in cshe
.direct_smallers
do
1372 if not lc
.require_doc
(dctx
) then continue
1373 dctx
.add
("<li>{lc.html_link(dctx)}</li>\n")
1377 dctx
.add
("<h4>Too much Subclasses to list</h4>\n")
1379 dctx
.add
("</nav>\n")
1381 dctx
.add
("</div>\n")
1384 dctx
.add
("<div class=\"content\
">\n")
1385 dctx
.add
("<h1>{name}</h1>\n")
1386 dctx
.add
("<div class='subtitle'>")
1387 if global
.visibility_level
== 2 then
1389 else if global
.visibility_level
== 3 then
1390 dctx
.add
("private ")
1391 else if self.global
.intro
.mmmodule
.toplevel_owner
.visibility_for
(self.global
.intro
.mmmodule
) <= 1 then
1392 dctx
.add
("(unexported) ")
1394 dctx
.add
("{kind} {global.intro.mmmodule.toplevel_owner.html_link(dctx)}::{name}</div>")
1396 dctx
.add
("<section class=\"description\
">\n")
1399 dctx
.add
("<pre>{doc.to_html}</pre>\n")
1402 var cla
= new HashSet[MMLocalClass]
1403 var sm
= new HashSet[MMLocalClass]
1404 var sm2
= new HashSet[MMLocalClass]
1406 while cla
.length
+ sm
.length
< 10 and sm
.length
> 0 do
1410 sm2
.add_all
(x
.cshe
.direct_smallers
)
1416 cla
.add_all
(cshe
.greaters_and_self
)
1419 var name
= "class_{name}"
1420 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")
1423 op
.append
("\"{c.name}\
"[shape=box,margin=0.03];\n")
1425 op
.append
("\"{c.name}\
"[URL=\"{c.html_name}.html\
"];\n")
1427 for c2
in c
.cshe
.direct_greaters
do
1428 if not cla
.has
(c2
) then continue
1429 op
.append
("\"{c.name}\
"->\"{c2.name}\
";\n")
1431 if not c
.cshe
.direct_smallers
.is_empty
then
1433 for c2
in c
.cshe
.direct_smallers
do
1434 if cla
.has
(c2
) then others
= false
1437 op
.append
("\"{c.name}...\
"[label=\"\
"];\n")
1438 op
.append
("\"{c.name}...\
"->\"{c.name}\
"[style=dotted];\n")
1443 dctx
.gen_dot
(op
.to_s
, name
.to_s
, "Inheritance graph for class {name}")
1444 dctx
.add
("</section>\n")
1448 dctx
.stage
("<section class=\"concerns\
">\n")
1449 dctx
.stage
("<h2 class=\"section-header\
">Concerns</h2>\n")
1451 var mods
= new Array[MMModule]
1452 mods
.add
(global
.intro
.mmmodule
.toplevel_owner
)
1453 for lc
in crhe
.greaters
do
1454 if not lc
isa MMSrcLocalClass then continue
1455 var m
= lc
.mmmodule
.toplevel_owner
1456 if not mods
.has
(m
) then mods
.add
(m
)
1459 var intro
= global
.intro
.mmmodule
1464 if m
.short_doc
!= " " then short_doc
= ": {m.short_doc}"
1465 dctx
.add
("<li>{m.html_link_to_anchor}{short_doc}")
1467 for lc
in crhe
.linear_extension
.reversed
do
1468 if lc
.mmmodule
.toplevel_owner
!= m
then continue
1469 if lc
.mmmodule
== m
then continue
1471 if lc
.mmmodule
.short_doc
!= " " then short_doc
= ": {lc.mmmodule.short_doc}"
1472 dctx
.add
("<li>{lc.mmmodule.html_link_to_anchor}{short_doc}</li>")
1478 dctx
.stage
("</section>\n")
1482 dctx
.stage
("<section class=\"types\
">\n")
1483 dctx
.stage
("<h2>Formal and Virtual Types</h2>\n")
1484 for i
in [0..arity
[ do
1485 var f
= get_formal
(i
)
1486 f
.full_documentation
(dctx
, self)
1489 if not p
isa MMTypeProperty then continue
1490 p
.full_documentation
(dctx
, self)
1492 dctx
.stage
("</section>\n")
1496 dctx
.stage
("<section class=\"constructors\
">\n")
1497 dctx
.stage
("<h2 class=\"section-header\
">Constructors</h2>\n")
1499 if not p
.global
.is_init_for
(self) then continue
1500 p
.full_documentation
(dctx
, self)
1502 dctx
.stage
("</section>\n")
1506 dctx
.stage
("<section class=\"methods\
">\n")
1507 dctx
.stage
("<h2 class=\"section-header\
">Methods</h2>\n")
1508 var redefs
= new HashMap[MMModule, HashMap[MMModule, Array[MMMethod]]]
1510 if p
.global
.is_init
then continue
1511 if p
.local_class
.global
!= self.global
then continue
1512 if not p
isa MMMethod then continue
1514 var toplevel_module
= p
.mmmodule
.toplevel_owner
1515 if not redefs
.has_key
(toplevel_module
) then
1516 redefs
[toplevel_module
] = new HashMap[MMModule, Array[MMMethod]]
1519 var nested_module
= p
.mmmodule
1520 if not redefs
[toplevel_module
].has_key
(nested_module
) then
1521 redefs
[toplevel_module
][nested_module
] = new Array[MMMethod]
1524 redefs
[toplevel_module
][nested_module
].add
(p
)
1527 if p
.mmmodule
.toplevel_owner
!= p
.intro_module
then
1528 toplevel_module
= p
.intro_module
1529 nested_module
= p
.global
.intro
.mmmodule
1531 if not redefs
.has_key
(toplevel_module
) then
1532 redefs
[toplevel_module
] = new HashMap[MMModule, Array[MMMethod]]
1534 if not redefs
[toplevel_module
].has_key
(nested_module
) then
1535 redefs
[toplevel_module
][nested_module
] = new Array[MMMethod]
1538 redefs
[toplevel_module
][nested_module
].add
(p
.global
.intro
.as(MMMethod))
1542 # Display toplevel blocks
1544 if not redefs
.has_key
(m
) then continue
1545 dctx
.add
(m
.html_anchor
)
1546 if m
!= global
.intro
.mmmodule
.toplevel_owner
then
1547 dctx
.add
("<h3 class=\"concern-toplevel\
">Methods refined in {m.html_link(dctx)}</h3>")
1550 # Display nested module blocks
1551 for lc
in crhe
.linear_extension
.reversed
do
1552 if lc
.mmmodule
.toplevel_owner
!= m
then continue
1553 var nm
= lc
.mmmodule
1554 if not redefs
[m
].has_key
(nm
) then continue
1555 dctx
.add
(nm
.html_anchor
)
1556 if nm
!= global
.intro
.mmmodule
then
1558 if nm
.short_doc
!= " " then short_doc
= ": {nm.short_doc}"
1559 dctx
.add
("<p class=\"concern-doc\
">{nm.html_name}{short_doc}</p>\n")
1562 var pps
= redefs
[m
][nm
]
1565 p
.full_documentation
(dctx
, self)
1570 if not inhs
.is_empty
then
1572 dctx
.stage
("<h3>Inherited Methods</h3>\n")
1575 dctx
.stage
("<p>Defined in {lc.html_link(dctx)}:")
1577 var ims
= new Array[MMMethod]
1579 if p
.global
.is_init
then continue
1580 if not p
isa MMMethod then continue
1586 dctx
.add
(" {p.html_link(dctx)}")
1587 if i
< ims
.length
- 1 then dctx
.add
(",")
1596 dctx
.add
("</section>\n")
1598 dctx
.add
("</div> <!-- end class {name} -->\n")
1602 redef class MMSrcLocalClass
1608 else if global
.intro
== self then
1611 var bc
= global
.intro
1619 if not n
isa AStdClassdef then
1626 if d
.n_comment
.is_empty
then
1634 redef class MMSignature
1635 # Htlm transcription of the signature (with nested links)
1636 fun to_html
(dctx
: DocContext, with_closure
: Bool): String
1638 var res
= new Buffer
1641 for i
in [0..arity
[ do
1642 if i
> 0 then res
.append
(", ")
1643 res
.append
(self.params
[i
].name
.to_s
)
1645 res
.append
(self[i
].html_link
(dctx
))
1646 if self.vararg_rank
== i
then
1652 if return_type
!= null then
1654 res
.append
(return_type
.html_link
(dctx
))
1656 if with_closure
then
1657 for c
in closures
do
1659 if c
.is_optional
then res
.append
("[")
1660 if c
.is_break
then res
.append
("break ")
1661 res
.append
("!{c.name}")
1662 res
.append
(c
.signature
.to_html
(dctx
, false))
1663 if c
.is_optional
then res
.append
("]")
1671 # Htlm transcription of the type (with nested links)
1672 fun html_link
(dctx
: DocContext): String do return to_s
1675 redef class MMTypeSimpleClass
1676 redef fun html_link
(dctx
) do return local_class
.html_link
(dctx
)
1679 redef class MMTypeGeneric
1680 redef fun html_link
(dctx
)
1682 var res
= new Buffer
1683 res
.append
(local_class
.html_link
(dctx
))
1685 res
.append
(params
[0].html_link
(dctx
))
1686 for i
in [1..params
.length
[ do
1688 res
.append
(params
[i
].html_link
(dctx
))
1695 redef class MMTypeFormalParameter
1696 fun html_anchor
: String
1698 return "FT_{local_class}_{cmangle(name)}"
1700 redef fun html_link
(dctx
)
1702 return "<a href=\"#{html_anchor}\">{name}</a>"
1704 fun full_documentation
(dctx
: DocContext, lc
: MMLocalClass)
1706 dctx
.add
("<article id=\"{html_anchor}\
">\n")
1707 dctx
.add
("<h3 class=\"signature\
">{name}: {bound.html_link(dctx)}</h3>\n")
1708 dctx
.add
("<div class=\"info\
">")
1709 dctx
.add
("formal generic type")
1711 dctx
.add
("</article>")
1715 redef class MMNullableType
1716 redef fun html_link
(dctx
) do return "nullable " + as_notnull
.html_link
(dctx
)
1719 redef class MMVirtualType
1720 redef fun html_link
(dctx
) do return property
.html_link
(dctx
)
1723 var c
= new DocContext