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 var github_repo
: nullable String = null
32 # Content of a generated file
33 var _stage_context
: StageContext = new StageContext(null)
35 # Add a string in the content
37 _stage_context
.content
.add
(s
)
38 _stage_context
.validate
= true
41 # Add a string in the content iff some other string are added
42 fun stage
(s
: String) do _stage_context
.content
.add
(s
)
44 # Create a new stage in the content
45 fun open_stage
do _stage_context
= new StageContext(_stage_context
)
47 # Close the current stage in the content
50 var s
= _stage_context
.parent
51 if _stage_context
.validate
then
52 s
.content
.add_all
(_stage_context
.content
)
59 # Write the content to a new file
60 fun write_to
(filename
: String)
62 var f
= new OFStream.open
(filename
)
63 for s
in _stage_context
.content
do
72 _stage_context
= new StageContext(null)
75 # Sorter of entities in alphabetical order
76 var _sorter
: AlphaSorter[MMEntity] = new AlphaSorter[MMEntity]
78 # Sort entities in the alphabetical order
79 fun sort
(array
: Array[MMEntity])
84 readable var _opt_dir
: OptionString = new OptionString("Directory where doc is generated", "-d", "--dir")
85 readable var _opt_source
: OptionString = new OptionString("What link for source (%f for filename, %l for first line, %L for last line)", "--source")
86 readable var _opt_public
: OptionBool = new OptionBool("Generate only the public API", "--public")
87 readable var _opt_private
: OptionBool = new OptionBool("Generate the private API", "--private")
88 readable var _opt_nodot
: OptionBool = new OptionBool("Do not generate graphes with graphviz", "--no-dot")
89 readable var _opt_sharedir
: OptionString = new OptionString("Directory containing the nitdoc files", "--sharedir")
91 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")
92 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")
93 readable var _opt_custom_overview_text
: OptionString = new OptionString("Text displayed as introduction of Overview page before the modules list", "--custom-overview-text")
94 readable var _opt_custom_footer_text
: OptionString = new OptionString("Text displayed as footer of all pages", "--custom-footer-text")
95 readable var _opt_github_repo_name
: OptionString = new OptionString("GitHub repo name, example: --github MyRepoName", "--github")
96 var sharedir
: nullable String
100 if self._opt_public
.value
== true then return true
104 fun with_private
: Bool
106 if self._opt_private
.value
== true then return true
110 # The current processed filename
113 # The main virtual module
114 var mainmod
: nullable MMVirtualModule
116 redef fun perform_work
(mods
)
118 mainmod
= new MMVirtualModule(self, mods
)
122 sys
.system
("cp -r '{sharedir.to_s}'/* {dir}/")
124 # Compute the set of direct owned nested modules
125 var owns
= new HashMap[MMModule, Array[MMModule]]
126 for mod
in modules
do
127 owns
[mod
] = new Array[MMModule]# [mod]
129 for mod
in modules
do
130 if mod
== mainmod
then continue
131 var d
= mod
.directory
134 if o
!= null and o
!= mod
then
138 if dp
== null or dp
== d
then break
143 # Builds the various module hierarchies
144 var mnh
= new PartialOrder[MMModule] # nested module hierarchy
145 var tmh
= new PartialOrder[MMModule] # top module import hierrchy
146 var ms
= mainmod
.mhe
.linear_extension
.reversed
148 if ms
== mainmod
then continue
149 m
.mnhe_
= mnh
.add
(m
, owns
[m
])
150 var pub
= new Array[MMModule]
151 for m2
in m
.mhe
.greaters
do
152 if m2
.toplevel_owner
!= m2
and m2
.toplevel_owner
!= m
.toplevel_owner
then continue
153 if m
.mnhe
<= m2
then continue
154 if m
.visibility_for
(m2
) <= 0 then
156 else if m
.visibility_for
(m2
) == 1 then
161 m
.tmhe_
= tmh
.add
(m
, pub
)
164 var head
= "<meta charset=\"utf-8\
">" +
165 "<script type=\"text
/javascript\
" src=\"scripts
/jquery-1
.7
.1.min
.js\
"></script>\n" +
166 "<script type=\"text
/javascript\
" src=\"quicksearch-list
.js\
"></script>\n" +
167 "<script type=\"text
/javascript\
" src=\"scripts
/js-facilities
.js\
"></script>\n" +
168 "<link rel=\"stylesheet\
" href=\"styles
/main
.css\
" type=\"text
/css\
" media=\"screen\
" />"
170 var custom_items
= ""
171 if self._opt_custom_menu_items
.value
!= null then custom_items
= self._opt_custom_menu_items
.value
.as(not null)
173 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"
175 var custom_title
= "Nitdoc"
176 if self._opt_custom_title
.value
!= null then custom_title
= self._opt_custom_title
.value
.as(not null)
178 var overview_text
= ""
179 if self._opt_custom_overview_text
.value
!= null then overview_text
= self._opt_custom_overview_text
.value
.as(not null)
182 if self._opt_custom_footer_text
.value
!= null then footer_text
= self._opt_custom_footer_text
.value
.as(not null)
185 self.filename
= "index.html"
188 add
("<!DOCTYPE html>")
189 add
("<html><head>{head}<title>Overview | {custom_title}</title></head><body>\n")
191 add
("<div class=\"page\
">")
192 add
("<div class=\"content fullpage\
">")
193 add
("<h1>{custom_title}</h1>\n<article class='overview'>{overview_text}</article><article class='overview'><h2>Modules</h2><ul>")
194 var modss
= mainmod
.mhe
.greaters_and_self
.to_a
197 if not mod
.is_toplevel
then continue
198 if not mod
.require_doc
(self) then continue
199 assert mod
isa MMSrcModule
200 add
("<li>{mod.html_link(self)} {mod.short_doc}</li>")
206 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")
208 if not mod
.is_toplevel
then continue
209 if not mod
.require_doc
(self) then continue
210 op
.append
("\"{mod.name}\
"[URL=\"{mod.html_name}.html\
"];\n")
211 for mod2
in mod
.tmhe
.direct_greaters
do
212 if not modss
.has
(mod2
) then continue
213 op
.append
("\"{mod.name}\
"->\"{mod2.name}\
";\n")
217 self.gen_dot
(op
.to_s
, "dep", "Modules hierarchy")
218 add
("</article></div>")
220 add
("<footer>{footer_text}</footer>")
221 add
("</body></html>\n")
222 write_to
("{dir}/index.html")
224 # Generate page for modules
225 for mod
in modules
do
226 if mod
== mainmod
then continue
227 assert mod
isa MMSrcModule
228 if not mod
.require_doc
(self) then continue
229 self.filename
= mod
.html_name
230 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"
233 add
("<!DOCTYPE html>")
234 add
("<html><head>{head}<title>{mod.name} module | {custom_title}</title></head><body>\n")
236 add
("<div class=\"page\
">")
237 mod
.file_page_doc
(self)
239 add
("<footer>{footer_text}</footer>")
240 add
("</body></html>\n")
241 write_to
("{dir}/{mod.html_name}.html")
244 # Generate pages for global classes
245 for c
in mainmod
.local_classes
do
246 if not c
.require_doc
(self) then continue
247 self.filename
= c
.html_name
248 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"
251 add
("<!DOCTYPE html>")
252 add
("<html><head>{head}<title>{c.name} class | {custom_title}</title></head><body>\n")
254 add
("<div class=\"page\
">")
255 c
.file_page_doc
(self)
257 add
("<footer>{footer_text}</footer>")
258 add
("</body></html>\n")
259 write_to
("{dir}/{c.html_name}.html")
262 self.filename
= "fullindex"
263 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"
266 add
("<!DOCTYPE html>")
267 add
("<html><head>{head}<title>Full Index | {custom_title}</title></head><body>\n")
269 add
("<div class=\"page\
">")
270 add
("<div class=\"content fullpage\
">")
271 mainmod
.file_index_page_doc
(self)
274 add
("<footer>{footer_text}</footer>")
275 add
("</body></html>\n")
276 write_to
("{dir}/full-index.html")
278 self.filename
= "quicksearch-list"
280 mainmod
.file_quicksearch_list_doc
(self)
281 write_to
("{dir}/quicksearch-list.js")
284 # Add or not a tag for the github repository
285 fun addGithubInformation
do
286 if not github_repo
== null then add
("<div id=\"repoName\
" name=\"{github_repo.to_s}\
"></div>")
289 # Add a (source) link fo a given location
290 fun show_source
(l
: Location)
292 var s
= opt_source
.value
294 add
("({l.file.filename.simplify_path})")
296 # THIS IS JUST UGLY ! (but there is no replace yet)
297 var x
= s
.split_with
("%f")
298 s
= x
.join
(l
.file
.filename
.simplify_path
)
299 x
= s
.split_with
("%l")
300 s
= x
.join
(l
.line_start
.to_s
)
301 x
= s
.split_with
("%L")
302 s
= x
.join
(l
.line_end
.to_s
)
303 add
(" (<a href=\"{s}\
">show code</a>)")
307 # Generate a clicable graphiz image using a dot content.
308 # `name' refer to the filename (without extension) and the id name of the map.
309 # `name' must also match the name of the graph in the dot content (eg. digraph NAME {...)
310 fun gen_dot
(dot
: String, name
: String, alt
: String)
312 if opt_nodot
.value
then return
313 var f
= new OFStream.open
("{self.dir}/{name}.dot")
316 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 ; \}")
317 self.add
("<article class=\"graph\
"><img src=\"{name}.png\
" usemap=\"#{name}\" style=\"margin:auto\" alt=\"{alt}\"/></article>")
318 var fmap
= new IFStream.open
("{self.dir}/{name}.map")
319 self.add
(fmap
.read_all
)
328 option_context
.add_option
(opt_public
)
329 option_context
.add_option
(opt_private
)
330 option_context
.add_option
(opt_dir
)
331 option_context
.add_option
(opt_source
)
332 option_context
.add_option
(opt_nodot
)
333 option_context
.add_option
(opt_sharedir
)
334 option_context
.add_option
(opt_custom_title
)
335 option_context
.add_option
(opt_custom_menu_items
)
336 option_context
.add_option
(opt_custom_overview_text
)
337 option_context
.add_option
(opt_custom_footer_text
)
338 option_context
.add_option
(opt_github_repo_name
)
341 redef fun process_options
344 var d
= opt_dir
.value
345 if d
!= null then dir
= d
347 if not opt_nodot
.value
then
348 # Test if dot is runable
349 var res
= sys
.system
("sh -c dot </dev/null >/dev/null 2>&1")
351 stderr
.write
"--no-dot implied since `dot' is not available. Try to install graphviz.\n"
352 opt_nodot
.value
= true
356 sharedir
= opt_sharedir
.value
357 if sharedir
== null then
358 var dir
= "NIT_DIR".environ
360 dir
= "{sys.program_name.dirname}/../share/nitdoc"
361 if dir
.file_exists
then sharedir
= dir
363 dir
= "{dir}/share/nitdoc"
364 if dir
.file_exists
then sharedir
= dir
366 if sharedir
== null then
367 fatal_error
(null, "Error: Cannot locate nitdoc shared files. Uses --sharedir or envvar NIT_DIR.")
369 dir
= "{sharedir.to_s}/scripts/js-facilities.js"
370 if sharedir
== null then
371 fatal_error
(null, "Error: Invalid nitdoc shared files. Check --sharedir or envvar NIT_DIR.")
375 var git
= opt_github_repo_name
.value
376 if not git
== null then github_repo
= git
379 redef fun handle_property_conflict
(lc
, impls
)
381 # THIS IS SO UGLY! See MMVirtualModule
382 if lc
.mmmodule
== self.mainmod
then
383 return # We just accept, so one in impls is arbitrary inherited
389 # A virtual module is used to work as an implicit main module that combine unrelated modules
390 # Since conflict may arrise in a virtual module (the main method for instance) conflicts are disabled
391 class MMVirtualModule
393 init(ctx
: MMContext, mods
: Array[MMModule])
395 # We need to compute the whole metamodel since there is no mmbuilder to do it
396 super(" main".to_symbol
, mods
.first
.directory
, ctx
, new Location(null,0,0,0,0))
397 ctx
.add_module
(self, mods
)
399 self.add_super_module
(m
, 1)
401 self.import_global_classes
402 self.import_local_classes
403 for c
in self.local_classes
do
404 c
.compute_super_classes
406 for c
in self.local_classes
do
411 redef fun require_doc
(dctx
) do return false
414 # Conditionnal part of the text content of a DocContext
416 # Content of the current stage
417 readable var _content
: Array[String] = new Array[String]
419 # Is a normal string already added?
420 readable writable var _validate
: Bool = false
422 # Parent stage is any
423 readable var _parent
: nullable StageContext = null
425 init(parent
: nullable StageContext) do _parent
= parent
429 # Efficiently sort object with their to_s method
430 class AlphaSorter[E
: Object]
431 super AbstractSorter[E
]
432 redef fun compare
(a
, b
)
452 # Keep track of to_s values
453 var _dico
: HashMap[Object, String] = new HashMap[Object, String]
458 # Generalization of metamodel entities
461 fun html_link
(dctx
: DocContext): String is abstract
463 # Return a one liner description
464 fun short_doc
: String do return " "
466 # The doc node from the AST
467 # Return null is none
468 fun doc
: nullable ADoc do return null
470 # Return a JSON entry for quicksearch list
471 fun json_entry
(dctx
: DocContext): String is abstract
473 # Return the qualified name as string
474 fun qualified_name
: String is abstract
480 redef fun html_link
(dctx
) do
481 if short_doc
== " " then
482 return "<a href=\"{html_name}.html\
"\">{self}</a
>"
484 return "<a href
=\
"{html_name}.html\" title
=\
"{short_doc}\">{self}</a
>"
488 fun html_anchor: String do
489 return "<a id
=\
"MOD_{html_name}\"></a
>"
492 fun html_link_to_anchor: String do
493 return "<a href
=\
"#MOD_{html_name}\" title
=\
"Jump to definitions from module {html_name}\">{self}</a
>"
496 redef fun json_entry(dctx) do
497 return "\
{txt:\"{self.qualified_name}\
",url:\"{html_name}.html\
"\},"
500 redef fun qualified_name
do
501 var buffer
= new Buffer
502 for m
in mnhe
.smallers
do
503 buffer
.append
("{m.html_name}::")
505 buffer
.append
("{self.name}")
509 fun require_doc
(dctx
: DocContext): Bool
511 if dctx
.public_only
and not is_toplevel
then return false
515 # Return true if the module is a top-level owner or a top-level module
516 fun is_toplevel
: Bool
518 var pd
= directory
.parent
519 return pd
== null or (pd
.owner
== null and directory
.owner
== self)
522 # Element in the module nesting tree
523 fun mnhe
: PartialOrderElement[MMModule] do return mnhe_
.as(not null)
524 var mnhe_
: nullable PartialOrderElement[MMModule] = null
526 # Element in the top level module importation hierarchy
527 fun tmhe
: PartialOrderElement[MMModule] do return tmhe_
.as(not null)
528 var tmhe_
: nullable PartialOrderElement[MMModule] = null
530 fun toplevel_owner
: MMModule
534 var ds
= m
.mnhe
.direct_smallers
535 if ds
.length
== 0 then return m
536 if ds
.length
== 1 then m
= ds
.first
else abort
540 fun html_name
: String
545 fun direct_owner
: nullable MMModule
548 while d
.owner
== self do d
= d
.parent
.as(not null)
552 # Fill the body for the page associated to the module
553 fun file_page_doc
(dctx
: DocContext)
555 dctx
.add
("<div class=\"menu\
">\n")
557 var mods
= new Array[MMModule]
558 mods
= self.mhe
.greaters
.to_a
562 dctx
.stage
("<nav>\n")
563 dctx
.stage
("<h3>Module Hierarchy</h3>\n")
564 dctx
.stage
("<h4>All dependencies</h4>\n")
567 if not mod
.require_doc
(dctx
) then continue
568 if self.mnhe
<= mod
then continue # do not want nested stuff
569 if mod
.direct_owner
!= null and not mod
.direct_owner
.mnhe
<= self then continue # not in the right nesting
570 dctx
.add
("<li>{mod.html_link(dctx)}</li>")
572 dctx
.stage
("</ul>\n")
574 mods
= self.mhe
.smallers
.to_a
576 dctx
.stage
("<h4>All clients</h4>\n")
579 if not mod
.require_doc
(dctx
) then continue
580 if self.mnhe
<= mod
then continue # do not want nested stuff
581 if mod
.direct_owner
!= null and not mod
.direct_owner
.mnhe
<= self then continue # not in the right nesting
582 dctx
.add
("<li>{mod.html_link(dctx)}</li>")
584 dctx
.stage
("</ul>\n")
585 dctx
.stage
("</nav>\n")
588 if not dctx
.public_only
then
589 mods
= self.mnhe
.direct_greaters
.to_a
592 dctx
.stage
("<nav>\n")
593 dctx
.stage
("<h3>Nested Modules</h3><ul>\n")
595 if not mod
.require_doc
(dctx
) then continue
596 dctx
.add
("<li>{mod.html_link(dctx)}</li>")
598 dctx
.stage
("</ul></nav>\n")
602 dctx
.add
("</div>") # metadata
604 dctx
.add
("<div class=\"content\
">\n")
605 dctx
.add
("<h1>{name}</h1>\n")
606 dctx
.add
("<div class='subtitle'>module ")
607 for m
in mnhe
.smallers
do
608 dctx
.add
("{m.html_link(dctx)}::")
610 dctx
.add
("{self.name}</div>\n")
612 dctx
.add
("<section class='description'>\n")
616 dctx
.add
("<div id=\"description\
">\n")
617 dctx
.add
("<pre>{doc.to_html}</pre>\n")
622 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")
623 var ms
= new Array[nullable MMModule]
625 var m0
: nullable MMModule = self
631 var cla
= new HashSet[MMModule]
633 for m0
in self.mhe
.greaters
do
634 if not m0
.require_doc
(dctx
) then continue
635 if self.visibility_for
(m0
) <= 1 then continue # private or hidden
636 if self.mnhe
<= m0
then continue # do not want nested stuff
637 if m0
.direct_owner
!= null and not m0
.direct_owner
.mnhe
<= self then continue # not in the right nesting
640 for m0
in self.mhe
.smallers
do
641 if not m0
.require_doc
(dctx
) then continue
642 if m0
.visibility_for
(self) <= 1 then continue # private or hidden
643 if m0
.direct_owner
!= null and not m0
.direct_owner
.mnhe
<= self then continue # not in the right nesting
646 for m0
in self.mnhe
.smallers
do
652 op
.append
("subgraph \"cluster_
{m0.name}\
"\{\n")
655 if c
.direct_owner
!= m0
then continue
657 op
.append
("\"{c.name}\
"[shape=box,margin=0.03];\n")
659 op
.append
("\"{c.name}\
"[URL=\"{c.html_name}.html\
"];\n")
663 op
.append
("\"{m0.name}\
"[URL=\"{m0.html_name}.html\
"];\n")
664 for c
in m0
.mhe
.direct_greaters
do
665 if not cla
.has
(c
) then continue
666 op
.append
("\"{m0.name}\
"->\"{c.name}\
";\n")
671 # Close the nesting subgraph
677 for c2
in c
.tmhe
.direct_greaters
do
678 if not cla
.has
(c2
) then continue
679 op
.append
("\"{c.name}\
"->\"{c2.name}\
";\n")
683 dctx
.gen_dot
(op
.to_s
, name
.to_s
, "Dependency graph for module {name}")
684 dctx
.add
("</section>")
686 var clas
= new Array[MMLocalClass]
687 var props
= new HashMap[MMGlobalProperty, Array[MMLocalProperty]]
688 var gprops
= new Array[MMLocalProperty]
691 for g
in m
.global_classes
do
693 if not lc
.require_doc
(dctx
) then continue
694 var im
= g
.intro
.mmmodule
695 if self.visibility_for
(im
) <= 1 then continue # private import or invisible import
697 for lc2
in lc
.crhe
.greaters_and_self
do
698 if not lc2
isa MMSrcLocalClass then continue
699 if not self.mnhe
<= lc2
.mmmodule
then continue # not introduced/redefined here/stolen
702 if not keep
then continue
704 lc
.compute_super_classes
705 for gp
in lc
.global_properties
do
706 if self.visibility_for
(gp
.intro
.local_class
.mmmodule
) <= 1 then continue # private import or invisible import
708 var mp
= lp
.local_class
.mmmodule
709 if not self.mnhe
<= mp
then continue # not introduced/redefined here/stolen
711 if not lp
.require_doc
(dctx
) then continue
712 if props
.has_key
(lp
.global
) then
713 if not props
[lp
.global
].has
(lp
) then
714 props
[lp
.global
].add
(lp
)
717 props
[lp
.global
] = [lp
]
718 gprops
.add
(lp
.global
.intro
)
723 dctx
.add
("<section class=\"module\
">\n")
725 dctx
.stage
("<article class=\"classes filterable\
">\n")
726 dctx
.stage
("<h2>Classes</h2>\n")
730 if self.mnhe
<= lc
.global
.intro
.mmmodule
then
731 dctx
.add
("<li class='intro'><span title='introduced in this module'>I</span> ")
733 dctx
.add
("<li class='redef'><span title='refined in this module'>R</span> ")
735 dctx
.add
("{lc.html_link(dctx)}</li>\n")
737 dctx
.stage
("</ul></article>\n")
741 dctx
.stage
("<article class=\"properties filterable\
">\n")
742 dctx
.stage
("<h2>Properties</h2>\n")
749 if gp
.intro
isa MMAttribute then continue
751 var lpi
= self[gp
.intro
.local_class
.global
][gp
]
754 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")
757 dctx
.add
("<li class='intro'><span title='introduction in this module'>I</span> {lpi.html_name}")
758 dctx
.add
(" ({lpi.local_class})</li>\n")
760 if lps
.length
>= 1 then
763 dctx
.add
("<li class='redef'><span title='redefinition'>R</span> {lp.html_open_link(dctx)}{lp.html_name} ({lp.local_class})</a></li>")
767 dctx
.stage
("</ul></article>\n")
769 dctx
.add
("</section>\n")
773 # Fill the body for the page associated to the full index
774 fun file_index_page_doc
(dctx
: DocContext)
777 dctx
.add
("<h1>Full Index</h1>\n")
779 var clas
= new Array[MMLocalClass]
780 var props
= new HashMap[MMGlobalProperty, Array[MMLocalProperty]]
781 var gprops
= new Array[MMLocalProperty]
782 var mods
= new Array[MMModule]
783 for m
in mhe
.greaters_and_self
do
784 if not m
.require_doc
(dctx
) then continue
787 for g
in global_classes
do
789 if not lc
.require_doc
(dctx
) then continue
791 for gp
in lc
.global_properties
do
793 if not lp
.require_doc
(dctx
) then continue
794 if props
.has_key
(lp
.global
) then
795 if not props
[lp
.global
].has
(lp
) then
796 props
[lp
.global
].add
(lp
)
799 props
[lp
.global
] = [lp
]
800 gprops
.add
(lp
.global
.intro
)
805 dctx
.stage
("<article class=\"modules filterable\
">\n")
806 dctx
.stage
("<h2>Modules</h2>\n")
810 dctx
.add
("<li>{m.html_link(dctx)}</li>")
812 dctx
.stage
("</ul></article>\n")
816 dctx
.stage
("<article class=\"classes filterable\
">\n")
817 dctx
.stage
("<h2>Classes</h2>\n")
821 dctx
.add
("<li>{lc.html_link(dctx)}</li>")
823 dctx
.stage
("</ul></article>\n")
827 dctx
.stage
("<article class=\"properties filterable\
">\n")
828 dctx
.stage
("<h2>Properties</h2>\n")
835 if gp
.intro
isa MMAttribute then continue
837 var lpi
= self[gp
.intro
.local_class
.global
][gp
]
840 dctx
.add
("<li class='intro'><span title='introduction'>I</span> {lpi.html_open_link(dctx)}{lpi.html_name} ({lpi.local_class})</a></li>\n")
841 if lps
.length
>= 1 then
844 dctx
.add
("<li class='redef'><span title='redefinition'>R</span> {lp.html_open_link(dctx)}{lp.html_name} ({lp.local_class})</a></li>\n")
848 dctx
.stage
("</ul></article>\n")
852 # Fill the quicksearch list JSON object
853 fun file_quicksearch_list_doc
(dctx
: DocContext)
855 var entities
= new HashMap[String, Array[MMEntity]]
856 var props
= new HashMap[MMGlobalProperty, Array[MMLocalProperty]]
857 for m
in mhe
.greaters_and_self
do
858 if not m
.require_doc
(dctx
) then continue
859 var a
= new Array[MMEntity]
861 entities
[m
.html_name
] = a
863 for g
in global_classes
do
865 if not lc
.require_doc
(dctx
) then continue
866 var a
= new Array[MMEntity]
868 entities
[lc
.html_name
] = a
869 for gp
in lc
.global_properties
do
871 if not lp
.require_doc
(dctx
) then continue
872 if lp
.kind
== "var" then continue
873 if props
.has_key
(lp
.global
) then
874 if not props
[lp
.global
].has
(lp
) then
875 props
[lp
.global
].add
(lp
)
878 props
[lp
.global
] = [lp
]
884 entities
[k
.short_name
] = v
887 var keys
= entities
.keys
.to_a
888 var sorter
= new AlphaSorter[String]
892 dctx
.stage
("var entries = \{")
894 dctx
.add
("\"{key}\
": [")
895 for entity
in entities
[key
] do
896 dctx
.add
(entity
.json_entry
(dctx
))
905 redef class MMGlobalProperty
906 # Return the short name of the property
907 fun short_name
: String do
908 return self.intro
.html_name
912 redef class MMLocalProperty
914 # Anchor of the property description in the module html file
915 fun html_anchor
: String
917 return "PROP_{self.mmmodule.toplevel_owner}_{local_class}_{cmangle(name)}"
920 redef fun json_entry
(dctx
) do
921 return "\{txt:\"{qualified_name}\",url
:\
"{local_class.html_name}.html#{html_anchor}\"\
},"
924 redef fun qualified_name do
925 return "{intro_module.qualified_name}::{local_class.html_name}::{html_name}"
928 fun html_open_link(dctx: DocContext): String
930 if not require_doc(dctx) then print "not required
{self}"
931 var title = "{html_name}{signature.to_s}"
932 if short_doc != " 
;" then
933 title += " #{short_doc}"
935 return "<a href=\"{local_class.html_name}.html
#{html_anchor}\" title=\"{title}\">"
938 fun html_name
: String
940 return self.name
.to_s
.html_escape
943 redef fun html_link
(dctx
)
945 if not require_doc
(dctx
) then print
"not required {self}"
946 var title
= "{html_name}{signature.to_s}"
947 if short_doc
!= " " then
948 title
+= " #{short_doc}"
950 return "<a href=\"{local_class.html_name}.html
#{html_anchor}\" title=\"{title}\">{html_name}</a>"
953 fun html_link_special
(dctx
: DocContext, lc
: MMLocalClass): String
955 if not require_doc
(dctx
) then print
"not required {self}"
956 var title
= "{html_name}{signature_for(lc.get_type)}"
957 if short_doc
!= " " then
958 title
+= " #{short_doc}"
960 return "<a href=\"{lc.html_name}.html
#{html_anchor}\" title=\"{title}\">{html_name}</a>"
963 # Kind of property (fun, attr, etc.)
964 fun kind
: String is abstract
971 else if global
.intro
== self then
974 return global
.intro
.short_doc
981 if n
== null or not n
isa APropdef then
988 if d
.n_comment
.is_empty
then
995 # The most specific module in the nesting hierarchy that exports the intro of self
996 fun intro_module
: MMModule
998 var m
= global
.intro
.mmmodule
999 var mo
= m
.direct_owner
1000 while mo
!= null and mo
.visibility_for
(m
) >= 2 do
1007 # Is the intro of self exported by the top-level module ?
1008 fun is_toplevel
: Bool
1010 var m
= intro_module
1011 return m
== m
.toplevel_owner
1014 # Return true if the global property must be documented according to the visibility configured
1015 fun require_doc
(dctx
: DocContext): Bool
1017 if global
.visibility_level
== 3 and not dctx
.with_private
then return false # Private
1018 if dctx
.public_only
then
1019 var m
= intro_module
1020 if m
!= m
.toplevel_owner
then return false # Unexported
1025 # Document the global property in the global class lc
1026 fun full_documentation
(dctx
: DocContext, lc
: MMLocalClass)
1028 var visibility
: String
1029 if global
.visibility_level
== 1 then
1030 visibility
= "public"
1031 else if global
.visibility_level
== 2 then
1032 visibility
= "protected"
1033 else if global
.visibility_level
== 3 then
1034 visibility
= "private"
1039 var intro_class
= global
.intro
.local_class
1040 var is_redef
= local_class
.global
!= intro_class
.global
or local_class
.mmmodule
.toplevel_owner
!= intro_class
.mmmodule
.toplevel_owner
1042 dctx
.add
("<article id=\"{html_anchor}\
" class=\"{kind} {visibility} {if is_redef then "redef" else ""}\
">\n")
1043 dctx
.add
("<h3 class=\"signature\
">{html_name}{signature.to_html(dctx, true)}</h3>\n")
1044 dctx
.add
("<div class=\"info\
">\n")
1045 #dctx.add("<p>LP: {self.mmmodule.html_link(dctx)}::{self.local_class.html_link(dctx)}::{self.html_link(dctx)}</p>")
1050 if not is_toplevel
then
1051 dctx
.add
("(unexported) ")
1053 if global
.visibility_level
== 2 then
1054 dctx
.add
("protected ")
1055 else if global
.visibility_level
== 3 then
1056 dctx
.add
("private ")
1059 dctx
.add
(" {intro_class.mmmodule.toplevel_owner.name}")
1060 if intro_class
.global
== lc
.global
then
1061 dctx
.add
("::{lc.name}")
1063 dctx
.add
("::{mmmodule[intro_class.global].html_link(dctx)}")
1066 dctx
.add
("::{mmmodule[intro_class.global][global].global.intro.html_link(dctx)}")
1068 dctx
.add
("::{html_name}")
1072 dctx
.add
("<div class=\"description\
">")
1074 # Collect all refinement of the global property in the same global property
1075 var lps
= new Array[MMLocalProperty]
1076 for l
in prhe
.greaters_and_self
do
1080 var introdoc
= false
1081 if global
.intro
.doc
!= null then
1083 if lp
.doc
== null then introdoc
= true
1087 dctx
.add
("<pre>{global.intro.doc.to_html}</pre>")
1090 var tlmods
= new Array[MMModule]
1092 var bm
= lp
.mmmodule
.toplevel_owner
1093 var lcm
= lc
.global
.intro
.mmmodule
1094 if lcm
.mhe
< lp
.mmmodule
then bm
= lcm
.toplevel_owner
1095 if not tlmods
.has
(bm
) then tlmods
.add
(bm
)
1099 # Document the top level property for the current top level module
1101 if tm
.global_classes
.has
(lc
.global
) then
1102 tlp
= tm
[lc
.global
][self.global
]
1104 else if tm
.global_classes
.has
(self.local_class
.global
) then
1105 # Self is the inherited property. Process it
1106 tlp
= tm
[self.local_class
.global
][self.global
]
1109 # We skip this module since the props defined by the module is
1113 var tlcm
= lc
.global
.intro
.mmmodule
.toplevel_owner
1114 if not tlcm
.mhe
<= tm
then
1115 dctx
.add
("<h4>In module {tm.html_link(dctx)} :</h4>")
1118 #dctx.add("<p>TLP: {tm} x {lc} : {tlp.full_name}</p>")
1121 if doc
!= null and (not introdoc
or global
.intro
.doc
!= doc
) then
1122 dctx
.add
("<pre>{doc.to_html}</pre>")
1125 if tlp
.local_class
.global
!= lc
.global
then
1126 dctx
.add
("inherited from {tlp.local_class.html_link(dctx)} ")
1128 if tm
!= tlp
.mmmodule
then
1129 dctx
.add
("defined by the module {tlp.mmmodule.html_link(dctx)} ")
1138 dctx
.stage
(". previously defined by:")
1140 var tl
= lp
.mmmodule
.toplevel_owner
1141 if tl
!= tm
then continue
1142 if lp
== tlp
then continue
1143 dctx
.add
(" {lp.mmmodule.html_link(dctx)}")
1144 if lp
.local_class
.global
!= lc
.global
then
1145 dctx
.add
(" for {lp.local_class.html_link(dctx)} ")
1155 #if doc != null and (not introdoc or global.intro.doc != doc) then
1156 # dctx.add("<pre>{doc.to_html}</pre>")
1163 dctx
.add
("</article>")
1166 redef class MMMethod
1167 redef fun kind
do return if global
.is_init
then "init" else "fun"
1169 redef class MMAttribute
1170 redef fun kind
do return "var"
1172 redef class MMTypeProperty
1173 redef fun kind
do return "type"
1176 redef class MMSrcModule
1190 if n
.n_moduledecl
== null then
1193 var np
= n
.n_moduledecl
1198 if d
.n_comment
.is_empty
then
1207 # Html transcription of the doc
1210 var res
= new Buffer
1211 for c
in n_comment
do
1212 res
.append
(c
.text
.substring_from
(1))
1214 return res
.to_s
.html_escape
1217 # Oneliner transcription of the doc
1220 return n_comment
.first
.text
.substring_from
(1).html_escape
1224 redef class MMLocalClass
1227 # Anchor of the class description in the module html file
1228 fun html_anchor
: String do return "CLASS_{self}"
1230 fun html_name
: String do return "{self}"
1232 redef fun html_link
(dctx
)
1234 if not require_doc
(dctx
) then print
"{dctx.filename}: not required {self}"
1235 if short_doc
== " " then
1236 return "<a href=\"{html_name}.html\
"\">{self}</a
>"
1238 return "<a href
=\
"{html_name}.html\" title
=\
"{short_doc}\">{self}</a
>"
1242 redef fun json_entry(dctx) do
1243 return "\
{txt:\"{qualified_name}\
",url:\"{html_name}.html\
"\},"
1246 redef fun qualified_name
do
1247 return "{intro_module.qualified_name}::{html_name}"
1250 redef fun short_doc
do return global
.intro
.short_doc
1252 redef fun doc
do return global
.intro
.doc
1256 if global
.is_interface
then
1258 else if global
.is_abstract
then
1259 return "abstract class"
1260 else if global
.is_enum
then
1267 # The most specific module in the nesting hierarchy that exports the intro of self
1268 fun intro_module
: MMModule
1270 var m
= global
.intro
.mmmodule
1271 var mo
= m
.direct_owner
1272 while mo
!= null and mo
.visibility_for
(m
) >= 2 do
1279 fun menu_link
(dctx
: DocContext, p
: MMLocalProperty)
1281 if p
.local_class
.global
!= self.global
then
1282 if p
.global
.intro
.local_class
.name
== "Object".to_symbol
then return
1283 if p
.global
.is_init
or p
isa MMTypeProperty then
1284 dctx
.add
("<li class='inherit'><span title='Inherited'>H</span> {p.html_link_special(dctx, self)}</li>\n")
1286 dctx
.add
("<li class='inherit'><span title='Inherited'>H</span> {p.html_link(dctx)}</li>\n")
1288 else if p
.global
.intro
.local_class
.global
== self.global
then
1289 dctx
.add
("<li class='intro'><span title='Introduced'>I</span> {p.html_link_special(dctx, self)}</li>\n")
1291 dctx
.add
("<li class='redef'><span title='Redefined'>R</span> {p.html_link_special(dctx, self)}</li>\n")
1295 # Return true if the global class must be documented according to the visibility configured
1296 fun require_doc
(dctx
: DocContext): Bool
1298 if global
.visibility_level
== 3 and not dctx
.with_private
then return false # Private
1299 if dctx
.public_only
then
1300 var m
= intro_module
1301 if m
!= m
.toplevel_owner
then return false # Unexported
1306 # Fill the body for the page associated to the global class
1307 fun file_page_doc
(dctx
: DocContext)
1309 dctx
.add
("<div class=\"menu\
">\n")
1311 var props
= new Array[MMLocalProperty]
1312 var inh
= new HashMap[MMLocalClass, Array[MMLocalProperty]]
1313 var inhs
= new Array[MMLocalClass]
1314 for g
in global_properties
do
1316 if not p
.require_doc
(dctx
) then continue
1317 if p
.local_class
.global
== global
or g
.is_init_for
(self) or p
isa MMTypeProperty then
1320 var lc
= mmmodule
[p
.local_class
.global
]
1321 if inh
.has_key
(lc
) then
1332 dctx
.add
("<nav class=\"properties filterable\
">\n")
1333 dctx
.add
("<h3>Properties</h3>\n")
1335 dctx
.stage
("<h4>Virtual Types</h4>\n<ul>\n")
1337 if p
isa MMTypeProperty then
1341 dctx
.stage
("</ul>\n")
1344 dctx
.stage
("<h4>Constructors</h4>\n<ul>\n")
1346 if p
.global
.is_init_for
(self) then
1350 dctx
.stage
("</ul>\n")
1353 dctx
.stage
("<h4>Methods</h4>\n<ul>\n")
1355 if not p
.global
.is_init
and p
isa MMMethod then
1359 dctx
.stage
("</ul>\n")
1361 dctx
.add
("</nav>\n")
1363 dctx
.add
("<nav class=\"inheritance filterable\
">\n")
1364 dctx
.add
("<h3>Inheritance</h3>\n")
1365 dctx
.add
("<h4>Superclasses</h4>\n<ul>\n")
1366 for lc
in cshe
.linear_extension
do
1367 if lc
== self then continue
1368 if not lc
.require_doc
(dctx
) then continue
1369 dctx
.add
("<li>{lc.html_link(dctx)}</li>\n")
1372 if cshe
.smallers
.length
== 0 then
1373 dctx
.add
("<h4>No Known Subclasses</h4>\n")
1374 else if cshe
.smallers
.length
<= 100 then
1375 dctx
.add
("<h4>Subclasses</h4>\n")
1377 for lc
in cshe
.smallers
do
1378 if not lc
.require_doc
(dctx
) then continue
1379 dctx
.add
("<li>{lc.html_link(dctx)}</li>\n")
1382 else if cshe
.direct_smallers
.length
<= 100 then
1383 dctx
.add
("<h4>Direct Subclasses Only</h4>\n<ul>\n")
1384 for lc
in cshe
.direct_smallers
do
1385 if not lc
.require_doc
(dctx
) then continue
1386 dctx
.add
("<li>{lc.html_link(dctx)}</li>\n")
1390 dctx
.add
("<h4>Too much Subclasses to list</h4>\n")
1392 dctx
.add
("</nav>\n")
1394 dctx
.add
("</div>\n")
1397 dctx
.add
("<div class=\"content\
">\n")
1398 dctx
.add
("<h1>{name}</h1>\n")
1399 dctx
.add
("<div class='subtitle'>")
1400 if global
.visibility_level
== 2 then
1402 else if global
.visibility_level
== 3 then
1403 dctx
.add
("private ")
1404 else if self.global
.intro
.mmmodule
.toplevel_owner
.visibility_for
(self.global
.intro
.mmmodule
) <= 1 then
1405 dctx
.add
("(unexported) ")
1407 dctx
.add
("{kind} {global.intro.mmmodule.toplevel_owner.html_link(dctx)}::{name}</div>")
1409 dctx
.add
("<section class=\"description\
">\n")
1412 dctx
.add
("<pre>{doc.to_html}</pre>\n")
1415 var cla
= new HashSet[MMLocalClass]
1416 var sm
= new HashSet[MMLocalClass]
1417 var sm2
= new HashSet[MMLocalClass]
1419 while cla
.length
+ sm
.length
< 10 and sm
.length
> 0 do
1423 sm2
.add_all
(x
.cshe
.direct_smallers
)
1429 cla
.add_all
(cshe
.greaters_and_self
)
1432 var name
= "class_{name}"
1433 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")
1436 op
.append
("\"{c.name}\
"[shape=box,margin=0.03];\n")
1438 op
.append
("\"{c.name}\
"[URL=\"{c.html_name}.html\
"];\n")
1440 for c2
in c
.cshe
.direct_greaters
do
1441 if not cla
.has
(c2
) then continue
1442 op
.append
("\"{c.name}\
"->\"{c2.name}\
";\n")
1444 if not c
.cshe
.direct_smallers
.is_empty
then
1446 for c2
in c
.cshe
.direct_smallers
do
1447 if cla
.has
(c2
) then others
= false
1450 op
.append
("\"{c.name}...\
"[label=\"\
"];\n")
1451 op
.append
("\"{c.name}...\
"->\"{c.name}\
"[style=dotted];\n")
1456 dctx
.gen_dot
(op
.to_s
, name
.to_s
, "Inheritance graph for class {name}")
1457 dctx
.add
("</section>\n")
1461 dctx
.stage
("<section class=\"concerns\
">\n")
1462 dctx
.stage
("<h2 class=\"section-header\
">Concerns</h2>\n")
1464 var mods
= new Array[MMModule]
1465 mods
.add
(global
.intro
.mmmodule
.toplevel_owner
)
1466 for lc
in crhe
.greaters
do
1467 if not lc
isa MMSrcLocalClass then continue
1468 var m
= lc
.mmmodule
.toplevel_owner
1469 if not mods
.has
(m
) then mods
.add
(m
)
1472 var intro
= global
.intro
.mmmodule
1477 if m
.short_doc
!= " " then short_doc
= ": {m.short_doc}"
1478 dctx
.add
("<li>{m.html_link_to_anchor}{short_doc}")
1480 for lc
in crhe
.linear_extension
.reversed
do
1481 if lc
.mmmodule
.toplevel_owner
!= m
then continue
1482 if lc
.mmmodule
== m
then continue
1484 if lc
.mmmodule
.short_doc
!= " " then short_doc
= ": {lc.mmmodule.short_doc}"
1485 dctx
.add
("<li>{lc.mmmodule.html_link_to_anchor}{short_doc}</li>")
1491 dctx
.stage
("</section>\n")
1495 dctx
.stage
("<section class=\"types\
">\n")
1496 dctx
.stage
("<h2>Formal and Virtual Types</h2>\n")
1497 for i
in [0..arity
[ do
1498 var f
= get_formal
(i
)
1499 f
.full_documentation
(dctx
, self)
1502 if not p
isa MMTypeProperty then continue
1503 p
.full_documentation
(dctx
, self)
1505 dctx
.stage
("</section>\n")
1509 dctx
.stage
("<section class=\"constructors\
">\n")
1510 dctx
.stage
("<h2 class=\"section-header\
">Constructors</h2>\n")
1512 if not p
.global
.is_init_for
(self) then continue
1513 p
.full_documentation
(dctx
, self)
1515 dctx
.stage
("</section>\n")
1519 dctx
.stage
("<section class=\"methods\
">\n")
1520 dctx
.stage
("<h2 class=\"section-header\
">Methods</h2>\n")
1521 var redefs
= new HashMap[MMModule, HashMap[MMModule, Array[MMMethod]]]
1523 if p
.global
.is_init
then continue
1524 if p
.local_class
.global
!= self.global
then continue
1525 if not p
isa MMMethod then continue
1527 var toplevel_module
= p
.mmmodule
.toplevel_owner
1528 if not redefs
.has_key
(toplevel_module
) then
1529 redefs
[toplevel_module
] = new HashMap[MMModule, Array[MMMethod]]
1532 var nested_module
= p
.mmmodule
1533 if not redefs
[toplevel_module
].has_key
(nested_module
) then
1534 redefs
[toplevel_module
][nested_module
] = new Array[MMMethod]
1537 redefs
[toplevel_module
][nested_module
].add
(p
)
1540 if p
.mmmodule
.toplevel_owner
!= p
.intro_module
then
1541 toplevel_module
= p
.intro_module
1542 nested_module
= p
.global
.intro
.mmmodule
1544 if not redefs
.has_key
(toplevel_module
) then
1545 redefs
[toplevel_module
] = new HashMap[MMModule, Array[MMMethod]]
1547 if not redefs
[toplevel_module
].has_key
(nested_module
) then
1548 redefs
[toplevel_module
][nested_module
] = new Array[MMMethod]
1551 redefs
[toplevel_module
][nested_module
].add
(p
.global
.intro
.as(MMMethod))
1555 # Display toplevel blocks
1557 if not redefs
.has_key
(m
) then continue
1558 dctx
.add
(m
.html_anchor
)
1559 if m
!= global
.intro
.mmmodule
.toplevel_owner
then
1560 dctx
.add
("<h3 class=\"concern-toplevel\
">Methods refined in {m.html_link(dctx)}</h3>")
1563 # Display nested module blocks
1564 for lc
in crhe
.linear_extension
.reversed
do
1565 if lc
.mmmodule
.toplevel_owner
!= m
then continue
1566 var nm
= lc
.mmmodule
1567 if not redefs
[m
].has_key
(nm
) then continue
1568 dctx
.add
(nm
.html_anchor
)
1569 if nm
!= global
.intro
.mmmodule
then
1571 if nm
.short_doc
!= " " then short_doc
= ": {nm.short_doc}"
1572 dctx
.add
("<p class=\"concern-doc\
">{nm.html_name}{short_doc}</p>\n")
1575 var pps
= redefs
[m
][nm
]
1578 p
.full_documentation
(dctx
, self)
1583 if not inhs
.is_empty
then
1585 dctx
.stage
("<h3>Inherited Methods</h3>\n")
1588 dctx
.stage
("<p>Defined in {lc.html_link(dctx)}:")
1590 var ims
= new Array[MMMethod]
1592 if p
.global
.is_init
then continue
1593 if not p
isa MMMethod then continue
1599 dctx
.add
(" {p.html_link(dctx)}")
1600 if i
< ims
.length
- 1 then dctx
.add
(",")
1609 dctx
.add
("</section>\n")
1611 dctx
.add
("</div> <!-- end class {name} -->\n")
1615 redef class MMSrcLocalClass
1621 else if global
.intro
== self then
1624 var bc
= global
.intro
1632 if not n
isa AStdClassdef then
1639 if d
.n_comment
.is_empty
then
1647 redef class MMSignature
1648 # Htlm transcription of the signature (with nested links)
1649 fun to_html
(dctx
: DocContext, with_closure
: Bool): String
1651 var res
= new Buffer
1654 for i
in [0..arity
[ do
1655 if i
> 0 then res
.append
(", ")
1656 res
.append
(self.params
[i
].name
.to_s
)
1658 res
.append
(self[i
].html_link
(dctx
))
1659 if self.vararg_rank
== i
then
1665 if return_type
!= null then
1667 res
.append
(return_type
.html_link
(dctx
))
1669 if with_closure
then
1670 for c
in closures
do
1672 if c
.is_optional
then res
.append
("[")
1673 if c
.is_break
then res
.append
("break ")
1674 res
.append
("!{c.name}")
1675 res
.append
(c
.signature
.to_html
(dctx
, false))
1676 if c
.is_optional
then res
.append
("]")
1684 # Htlm transcription of the type (with nested links)
1685 fun html_link
(dctx
: DocContext): String do return to_s
1688 redef class MMTypeSimpleClass
1689 redef fun html_link
(dctx
) do return local_class
.html_link
(dctx
)
1692 redef class MMTypeGeneric
1693 redef fun html_link
(dctx
)
1695 var res
= new Buffer
1696 res
.append
(local_class
.html_link
(dctx
))
1698 res
.append
(params
[0].html_link
(dctx
))
1699 for i
in [1..params
.length
[ do
1701 res
.append
(params
[i
].html_link
(dctx
))
1708 redef class MMTypeFormalParameter
1709 fun html_anchor
: String
1711 return "FT_{local_class}_{cmangle(name)}"
1713 redef fun html_link
(dctx
)
1715 return "<a href=\"#{html_anchor}\">{name}</a>"
1717 fun full_documentation
(dctx
: DocContext, lc
: MMLocalClass)
1719 dctx
.add
("<article id=\"{html_anchor}\
">\n")
1720 dctx
.add
("<h3 class=\"signature\
">{name}: {bound.html_link(dctx)}</h3>\n")
1721 dctx
.add
("<div class=\"info\
">")
1722 dctx
.add
("formal generic type")
1724 dctx
.add
("</article>")
1728 redef class MMNullableType
1729 redef fun html_link
(dctx
) do return "nullable " + as_notnull
.html_link
(dctx
)
1732 redef class MMVirtualType
1733 redef fun html_link
(dctx
) do return property
.html_link
(dctx
)
1736 var c
= new DocContext