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")
89 if self._opt_public
.value
== true then return true
93 # The current processed filename
96 # The main virtual module
97 var mainmod
: nullable MMVirtualModule
99 redef fun perform_work
(mods
)
101 mainmod
= new MMVirtualModule(self, mods
)
105 # Compute the set of direct owned nested modules
106 var owns
= new HashMap[MMModule, Array[MMModule]]
107 for mod
in modules
do
108 owns
[mod
] = new Array[MMModule]# [mod]
110 for mod
in modules
do
111 if mod
== mainmod
then continue
112 var d
= mod
.directory
115 if o
!= null and o
!= mod
then
119 if dp
== null or dp
== d
then break
124 # Builds the various module hierarchies
125 var mnh
= new PartialOrder[MMModule] # nested module hierarchy
126 var tmh
= new PartialOrder[MMModule] # top module import hierrchy
127 var ms
= mainmod
.mhe
.linear_extension
.reversed
129 if ms
== mainmod
then continue
130 m
.mnhe_
= mnh
.add
(m
, owns
[m
])
131 var pub
= new Array[MMModule]
132 for m2
in m
.mhe
.greaters
do
133 if m2
.toplevel_owner
!= m2
and m2
.toplevel_owner
!= m
.toplevel_owner
then continue
134 if m
.mnhe
<= m2
then continue
135 if m
.visibility_for
(m2
) <= 0 then
137 else if m
.visibility_for
(m2
) == 1 then
142 m
.tmhe_
= tmh
.add
(m
, pub
)
145 var head
= "<meta charset=\"utf-8\
">" +
146 "<script type=\"text
/javascript\
" src=\"http
://moz-concept
.com
/nitdoc
/scripts
/jquery-1
.7
.1.min
.js\
"></script>\n" +
147 "<script type=\"text
/javascript\
" src=\"http
://moz-concept
.com
/nitdoc
/scripts
/js-facilities
.js\
"></script>\n" +
148 "<link rel=\"stylesheet\
" href=\"http
://moz-concept
.com
/nitdoc
/styles
/main
.css\
" type=\"text
/css\
" media=\"screen\
" />"
150 var action_bar
= "<header><nav class='main'><ul><li class=\"current\
">Overview</li><li><a href='full-index.html'>Full Index</a></li></ul></nav></header>\n"
153 self.filename
= "index.html"
155 add
("<!DOCTYPE html>")
156 add
("<html><head>{head}<title>Index</title></head><body>\n")
158 add
("<div class=\"page\
">")
159 add
("<div class=\"content fullpage\
">")
160 add
("<h1>Modules</h1>\n<article class='overview'><ul>")
161 var modss
= mainmod
.mhe
.greaters_and_self
.to_a
164 if not mod
.is_toplevel
then continue
165 if not mod
.require_doc
(self) then continue
166 assert mod
isa MMSrcModule
167 add
("<li>{mod.html_link(self)} {mod.short_doc}</li>")
173 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")
175 if not mod
.is_toplevel
then continue
176 if not mod
.require_doc
(self) then continue
177 op
.append
("\"{mod.name}\
"[URL=\"{mod.html_name}.html\
"];\n")
178 for mod2
in mod
.tmhe
.direct_greaters
do
179 if not modss
.has
(mod2
) then continue
180 op
.append
("\"{mod.name}\
"->\"{mod2.name}\
";\n")
184 self.gen_dot
(op
.to_s
, "dep", "Modules hierarchy")
185 add
("</article></div>")
186 add
("<div class='clear'></div>")
188 add
("</body></html>\n")
189 write_to
("{dir}/index.html")
191 # Generate page for modules
192 for mod
in modules
do
193 if mod
== mainmod
then continue
194 assert mod
isa MMSrcModule
195 if not mod
.require_doc
(self) then continue
196 self.filename
= mod
.html_name
197 action_bar
= "<header><nav class='main'><ul><li><a href='./'>Overview</a></li><li class=\"current\
">{mod.name}</li><li><a href='full-index.html'>Full Index</a></li></ul></nav></header>\n"
199 add
("<!DOCTYPE html>")
200 add
("<html><head>{head}<title>Module {mod.name}</title></head><body>\n")
202 add
("<div class=\"page\
">")
203 mod
.file_page_doc
(self)
205 add
("</body></html>\n")
206 write_to
("{dir}/{mod.html_name}.html")
209 # Generate pages for global classes
210 for c
in mainmod
.local_classes
do
211 if not c
.require_doc
(self) then continue
212 self.filename
= c
.html_name
213 action_bar
= "<header><nav class='main'><ul><li><a href='./'>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></ul></nav></header>\n"
215 add
("<!DOCTYPE html>")
216 add
("<html><head>{head}<title>Class {c.name}</title></head><body>\n")
218 add
("<div class=\"page\
">")
219 c
.file_page_doc
(self)
221 add
("</body></html>\n")
222 write_to
("{dir}/{c.html_name}.html")
225 self.filename
= "fullindex"
226 action_bar
= "<header><nav class='main'><ul><li><a href='./'>Overview</a></li><li class=\"current\
">Full Index</li></ul></nav></header>\n"
228 add
("<!DOCTYPE html>")
229 add
("<html><head>{head}<title>Full Index</title></head><body>\n")
231 add
("<div class=\"page\
">")
232 add
("<div class=\"content fullpage\
">")
233 mainmod
.file_index_page_doc
(self)
236 add
("</body></html>\n")
237 write_to
("{dir}/full-index.html")
241 # Add a (source) link fo a given location
242 fun show_source
(l
: Location)
244 var s
= opt_source
.value
246 add
("in #{l.file.filename.simplify_path}")
248 # THIS IS JUST UGLY ! (but there is no replace yet)
249 var x
= s
.split_with
("%f")
250 s
= x
.join
(l
.file
.filename
.simplify_path
)
251 x
= s
.split_with
("%l")
252 s
= x
.join
(l
.line_start
.to_s
)
253 x
= s
.split_with
("%L")
254 s
= x
.join
(l
.line_end
.to_s
)
255 add
(" (<a href=\"{s}\
">show code</a>)")
259 # Generate a clicable graphiz image using a dot content.
260 # `name' refer to the filename (without extension) and the id name of the map.
261 # `name' must also match the name of the graph in the dot content (eg. digraph NAME {...)
262 fun gen_dot
(dot
: String, name
: String, alt
: String)
264 var f
= new OFStream.open
("{self.dir}/{name}.dot")
267 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 ; \}")
268 self.add
("<article class=\"graph\
"><img src=\"{name}.png\
" usemap=\"#{name}\" style=\"margin:auto\" alt=\"{alt}\"/></article>")
269 var fmap
= new IFStream.open
("{self.dir}/{name}.map")
270 self.add
(fmap
.read_all
)
279 option_context
.add_option
(opt_public
)
280 option_context
.add_option
(opt_dir
)
281 option_context
.add_option
(opt_source
)
284 redef fun process_options
287 var d
= opt_dir
.value
288 if d
!= null then dir
= d
291 redef fun handle_property_conflict
(lc
, impls
)
293 # THIS IS SO UGLY! See MMVirtualModule
294 if lc
.mmmodule
== self.mainmod
then
295 return # We just accept, so one in impls is arbitrary inherited
302 # Remove "/./", "//" and "bla/../"
303 fun simplify_path
: String
305 var a
= self.split_with
("/")
306 var a2
= new Array[String]
308 if x
== "." then continue
309 if x
== "" and not a2
.is_empty
then continue
310 if x
== ".." and not a2
.is_empty
then
320 # A virtual module is used to work as an implicit main module that combine unrelated modules
321 # Since conflict may arrise in a virtual module (the main method for instance) conflicts are disabled
322 class MMVirtualModule
324 init(ctx
: MMContext, mods
: Array[MMModule])
326 # We need to compute the whole metamodel since there is no mmbuilder to do it
327 super(" main".to_symbol
, mods
.first
.directory
, ctx
, new Location(null,0,0,0,0))
328 ctx
.add_module
(self, mods
)
330 self.add_super_module
(m
, 1)
332 self.import_global_classes
333 self.import_local_classes
334 for c
in self.local_classes
do
335 c
.compute_super_classes
337 for c
in self.local_classes
do
342 redef fun require_doc
(dctx
) do return false
345 # Conditionnal part of the text content of a DocContext
347 # Content of the current stage
348 readable var _content
: Array[String] = new Array[String]
350 # Is a normal string already added?
351 readable writable var _validate
: Bool = false
353 # Parent stage is any
354 readable var _parent
: nullable StageContext = null
356 init(parent
: nullable StageContext) do _parent
= parent
360 # Efficiently sort object with their to_s method
361 class AlphaSorter[E
: Object]
362 super AbstractSorter[E
]
363 redef fun compare
(a
, b
)
383 # Keep track of to_s values
384 var _dico
: HashMap[Object, String] = new HashMap[Object, String]
389 # Generalization of metamodel entities
392 fun html_link
(dctx
: DocContext): String is abstract
394 # Return a one liner description
395 fun short_doc
: String do return " "
397 # The doc node from the AST
398 # Return null is none
399 fun doc
: nullable ADoc do return null
404 redef fun html_link
(dctx
) do
405 return "<a href=\"{html_name}.html\
" title=\"{short_doc}\
">{self}</a>"
408 fun require_doc
(dctx
: DocContext): Bool
410 if dctx
.public_only
and not is_toplevel
then return false
414 # Return true if the module is a top-level owner or a top-level module
415 fun is_toplevel
: Bool
417 var pd
= directory
.parent
418 return pd
== null or (pd
.owner
== null and directory
.owner
== self)
421 # Element in the module nesting tree
422 fun mnhe
: PartialOrderElement[MMModule] do return mnhe_
.as(not null)
423 var mnhe_
: nullable PartialOrderElement[MMModule] = null
425 # Element in the top level module importation hierarchy
426 fun tmhe
: PartialOrderElement[MMModule] do return tmhe_
.as(not null)
427 var tmhe_
: nullable PartialOrderElement[MMModule] = null
429 fun toplevel_owner
: MMModule
433 var ds
= m
.mnhe
.direct_smallers
434 if ds
.length
== 0 then return m
435 if ds
.length
== 1 then m
= ds
.first
else abort
439 fun html_name
: String
444 fun direct_owner
: nullable MMModule
447 while d
.owner
== self do d
= d
.parent
.as(not null)
451 # Fill the body for the page associated to the module
452 fun file_page_doc
(dctx
: DocContext)
454 dctx
.add
("<div class=\"menu\
">\n")
456 var mods
= new Array[MMModule]
457 mods
= self.mhe
.greaters
.to_a
461 dctx
.stage
("<nav>\n")
462 dctx
.stage
("<h3>Module Hierarchy</h3>\n")
463 dctx
.stage
("<h4>All dependencies</h4>\n")
466 if not mod
.require_doc
(dctx
) then continue
467 if self.mnhe
<= mod
then continue # do not want nested stuff
468 if mod
.direct_owner
!= null and not mod
.direct_owner
.mnhe
<= self then continue # not in the right nesting
469 dctx
.add
("<li>{mod.html_link(dctx)}</li>")
471 dctx
.stage
("</ul>\n")
473 mods
= self.mhe
.smallers
.to_a
475 dctx
.stage
("<h4>All clients</h4>\n")
478 if not mod
.require_doc
(dctx
) then continue
479 if self.mnhe
<= mod
then continue # do not want nested stuff
480 if mod
.direct_owner
!= null and not mod
.direct_owner
.mnhe
<= self then continue # not in the right nesting
481 dctx
.add
("<li>{mod.html_link(dctx)}</li>")
483 dctx
.stage
("</ul>\n")
484 dctx
.stage
("</nav>\n")
487 if not dctx
.public_only
then
488 mods
= self.mnhe
.direct_greaters
.to_a
491 dctx
.stage
("<nav>\n")
492 dctx
.stage
("<h3>Nested Modules</h3><ul>\n")
494 if not mod
.require_doc
(dctx
) then continue
495 dctx
.add
("<li>{mod.html_link(dctx)}</li>")
497 dctx
.stage
("</ul></nav>\n")
501 dctx
.add
("</div>") # metadata
503 dctx
.add
("<div class=\"content\
">\n")
504 dctx
.add
("<h1>{name}</h1>\n")
505 dctx
.add
("<div class='subtitle'>module ")
506 for m
in mnhe
.smallers
do
507 dctx
.add
("{m.html_link(dctx)}::")
509 dctx
.add
("{self.name}</div>\n")
511 dctx
.add
("<section class='description'>\n")
515 dctx
.add
("<div id=\"description\
">\n")
516 dctx
.add
("<pre>{doc.to_html}</pre>\n")
521 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")
522 var ms
= new Array[nullable MMModule]
524 var m0
: nullable MMModule = self
530 var cla
= new HashSet[MMModule]
532 for m0
in self.mhe
.greaters
do
533 if not m0
.require_doc
(dctx
) then continue
534 if self.visibility_for
(m0
) <= 1 then continue # private or hidden
535 if self.mnhe
<= m0
then continue # do not want nested stuff
536 if m0
.direct_owner
!= null and not m0
.direct_owner
.mnhe
<= self then continue # not in the right nesting
539 for m0
in self.mhe
.smallers
do
540 if not m0
.require_doc
(dctx
) then continue
541 if m0
.visibility_for
(self) <= 1 then continue # private or hidden
542 if m0
.direct_owner
!= null and not m0
.direct_owner
.mnhe
<= self then continue # not in the right nesting
545 for m0
in self.mnhe
.smallers
do
551 op
.append
("subgraph \"cluster_
{m0.name}\
"\{\n")
554 if c
.direct_owner
!= m0
then continue
556 op
.append
("\"{c.name}\
"[shape=box,margin=0.03];\n")
558 op
.append
("\"{c.name}\
"[URL=\"{c.html_name}.html\
"];\n")
562 op
.append
("\"{m0.name}\
"[URL=\"{m0.html_name}.html\
"];\n")
563 for c
in m0
.mhe
.direct_greaters
do
564 if not cla
.has
(c
) then continue
565 op
.append
("\"{m0.name}\
"->\"{c.name}\
";\n")
570 # Close the nesting subgraph
576 for c2
in c
.tmhe
.direct_greaters
do
577 if not cla
.has
(c2
) then continue
578 op
.append
("\"{c.name}\
"->\"{c2.name}\
";\n")
582 dctx
.gen_dot
(op
.to_s
, name
.to_s
, "Dependency graph for module {name}")
583 dctx
.add
("</section>")
585 var clas
= new Array[MMLocalClass]
586 var props
= new HashMap[MMGlobalProperty, Array[MMLocalProperty]]
587 var gprops
= new Array[MMLocalProperty]
590 for g
in m
.global_classes
do
592 if not lc
.require_doc
(dctx
) then continue
593 var im
= g
.intro
.mmmodule
594 if self.visibility_for
(im
) <= 1 then continue # private import or invisible import
596 for lc2
in lc
.crhe
.greaters_and_self
do
597 if not lc2
isa MMSrcLocalClass then continue
598 if not self.mnhe
<= lc2
.mmmodule
then continue # not introduced/redefined here/stolen
601 if not keep
then continue
603 for gp
in lc
.global_properties
do
604 if self.visibility_for
(gp
.intro
.local_class
.mmmodule
) <= 1 then continue # private import or invisible import
606 var mp
= lp
.local_class
.mmmodule
607 if not self.mnhe
<= mp
then continue # not introduced/redefined here/stolen
609 if not lp
.require_doc
(dctx
) then continue
610 if props
.has_key
(lp
.global
) then
611 if not props
[lp
.global
].has
(lp
) then
612 props
[lp
.global
].add
(lp
)
615 props
[lp
.global
] = [lp
]
616 gprops
.add
(lp
.global
.intro
)
621 dctx
.add
("<section class=\"module\
">\n")
623 dctx
.stage
("<article class=\"classes filterable\
">\n")
624 dctx
.stage
("<h2>Classes</h2>\n")
628 if self.mnhe
<= lc
.global
.intro
.mmmodule
then
629 dctx
.add
("<li class='intro'><span title='introduced in this module'>I</span> ")
631 dctx
.add
("<li class='redef'><span title='refined in this module'>R</span> ")
633 dctx
.add
("{lc.html_link(dctx)}</li>\n")
635 dctx
.stage
("</ul></article>\n")
639 dctx
.stage
("<article class=\"properties filterable\
">\n")
640 dctx
.stage
("<h2>Properties</h2>\n")
647 if gp
.intro
isa MMAttribute then continue
649 var lpi
= self[gp
.intro
.local_class
.global
][gp
]
652 dctx
.add
("<li class='intro'><span title='introduction in an other module'>I</span> {lpi.html_open_link(dctx)}{lpi} ({lpi.local_class})</a></li>\n")
655 dctx
.add
("<li class='intro'><span title='introduction in this module'>I</span> {lpi}")
656 dctx
.add
(" ({lpi.local_class})</li>\n")
658 if lps
.length
>= 1 then
661 dctx
.add
("<li class='redef'><span title='redefinition'>R</span> {lp.html_open_link(dctx)}{lp} ({lp.local_class})</a></li>")
665 dctx
.stage
("</ul></article>\n")
667 dctx
.add
("</section>\n")
671 # Fill the body for the page associated to the full index
672 fun file_index_page_doc
(dctx
: DocContext)
675 dctx
.add
("<h1>Full Index</h1>\n")
677 var clas
= new Array[MMLocalClass]
678 var props
= new HashMap[MMGlobalProperty, Array[MMLocalProperty]]
679 var gprops
= new Array[MMLocalProperty]
680 var mods
= new Array[MMModule]
681 for m
in mhe
.greaters_and_self
do
682 if not m
.require_doc
(dctx
) then continue
685 for g
in global_classes
do
687 if not lc
.require_doc
(dctx
) then continue
689 for gp
in lc
.global_properties
do
691 if not lp
.require_doc
(dctx
) then continue
692 if props
.has_key
(lp
.global
) then
693 if not props
[lp
.global
].has
(lp
) then
694 props
[lp
.global
].add
(lp
)
697 props
[lp
.global
] = [lp
]
698 gprops
.add
(lp
.global
.intro
)
703 dctx
.stage
("<article class=\"modules filterable\
">\n")
704 dctx
.stage
("<h2>Modules</h2>\n")
708 dctx
.add
("<li>{m.html_link(dctx)}</li>")
710 dctx
.stage
("</ul></article>\n")
714 dctx
.stage
("<article class=\"classes filterable\
">\n")
715 dctx
.stage
("<h2>Classes</h2>\n")
719 dctx
.add
("<li>{lc.html_link(dctx)}</li>")
721 dctx
.stage
("</ul></article>\n")
725 dctx
.stage
("<article class=\"properties filterable\
">\n")
726 dctx
.stage
("<h2>Properties</h2>\n")
733 if gp
.intro
isa MMAttribute then continue
735 var lpi
= self[gp
.intro
.local_class
.global
][gp
]
738 dctx
.add
("<li class='intro'><span title='introduction'>I</span> {lpi.html_open_link(dctx)}{lpi} ({lpi.local_class})</a></li>\n")
739 if lps
.length
>= 1 then
742 dctx
.add
("<li class='redef'><span title='redefinition'>R</span> {lp.html_open_link(dctx)}{lp} ({lp.local_class})</a></li>\n")
746 dctx
.stage
("</ul></article>\n")
751 redef class MMLocalProperty
753 # Anchor of the property description in the module html file
754 fun html_anchor
: String
756 return "PROP_{local_class}_{cmangle(name)}"
759 fun html_open_link
(dctx
: DocContext): String
761 if not require_doc
(dctx
) then print
"not required {self}"
762 var title
= "{name}{signature.to_s}"
763 if short_doc
!= " " then
764 title
+= " #{short_doc}"
766 return "<a href=\"{local_class.html_name}.html
#{html_anchor}\" title=\"{title}\">"
769 redef fun html_link
(dctx
)
771 if not require_doc
(dctx
) then print
"not required {self}"
772 var title
= "{name}{signature.to_s}"
773 if short_doc
!= " " then
774 title
+= " #{short_doc}"
776 return "<a href=\"{local_class.html_name}.html
#{html_anchor}\" title=\"{title}\">{self}</a>"
779 fun html_link_special
(dctx
: DocContext, lc
: MMLocalClass): String
781 if not require_doc
(dctx
) then print
"not required {self}"
782 var title
= "{name}{signature_for(lc.get_type)}"
783 if short_doc
!= " " then
784 title
+= " #{short_doc}"
786 return "<a href=\"{lc.html_name}.html
#{html_anchor}\" title=\"{title}\">{self}</a>"
789 # Kind of property (fun, attr, etc.)
790 fun kind
: String is abstract
797 else if global
.intro
== self then
800 return global
.intro
.short_doc
807 if n
== null or not n
isa APropdef then
814 if d
.n_comment
.is_empty
then
821 # The most specific module in the nesting hierarchy that exports the intro of self
822 fun intro_module
: MMModule
824 var m
= global
.intro
.mmmodule
825 var mo
= m
.direct_owner
826 while mo
!= null and mo
.visibility_for
(m
) >= 2 do
833 # Is the intro of self exported by the top-level module ?
834 fun is_toplevel
: Bool
837 return m
== m
.toplevel_owner
840 # Return true if the global class must be documented according to the visibility configured
841 fun require_doc
(dctx
: DocContext): Bool
843 if global
.visibility_level
== 3 then return false # Private
844 if dctx
.public_only
then
846 if m
!= m
.toplevel_owner
then return false # Unexported
851 # Document the global property in the global class lc
852 fun full_documentation
(dctx
: DocContext, lc
: MMLocalClass)
854 var visibility
: String
855 if global
.visibility_level
== 1 then
856 visibility
= "public"
857 else if global
.visibility_level
== 2 then
858 visibility
= "protected"
859 else if global
.visibility_level
== 3 then
860 visibility
= "private"
865 var intro_class
= global
.intro
.local_class
866 var is_redef
= local_class
.global
!= intro_class
.global
or local_class
.mmmodule
.toplevel_owner
!= intro_class
.mmmodule
.toplevel_owner
868 dctx
.add
("<article id=\"{html_anchor}\
" class=\"{kind} {visibility} {if is_redef then "redef" else ""}\
">\n")
869 dctx
.add
("<h3 class=\"signature\
">{name}{signature.to_html(dctx, true)}</h3>\n")
870 dctx
.add
("<div class=\"info\
">\n")
871 #dctx.add("<p>LP: {self.mmmodule.html_link(dctx)}::{self.local_class.html_link(dctx)}::{self.html_link(dctx)}</p>")
876 if not is_toplevel
then
877 dctx
.add
("(unexported) ")
879 if global
.visibility_level
== 2 then
880 dctx
.add
("protected ")
881 else if global
.visibility_level
== 3 then
885 dctx
.add
(" {intro_class.mmmodule.toplevel_owner.name}")
886 if intro_class
.global
== lc
.global
then
887 dctx
.add
("::{lc.name}")
889 dctx
.add
("::{mmmodule[intro_class.global].html_link(dctx)}")
892 dctx
.add
("::{mmmodule[intro_class.global][global].html_link(dctx)}")
898 dctx
.add
("<div class=\"description\
">")
900 # Collect all refinement of the global property in the same global property
901 var lps
= new Array[MMLocalProperty]
902 for l
in prhe
.greaters_and_self
do
907 if global
.intro
.doc
!= null then
909 if lp
.doc
== null then introdoc
= true
913 dctx
.add
("<pre>{global.intro.doc.to_html}</pre>")
916 var tlmods
= new Array[MMModule]
918 var bm
= lp
.mmmodule
.toplevel_owner
919 var lcm
= lc
.global
.intro
.mmmodule
920 if lcm
.mhe
< lp
.mmmodule
then bm
= lcm
.toplevel_owner
921 if not tlmods
.has
(bm
) then tlmods
.add
(bm
)
925 # Document the top level property for the current top level module
927 if tm
.global_classes
.has
(lc
.global
) then
928 tlp
= tm
[lc
.global
][self.global
]
930 else if tm
.global_classes
.has
(self.local_class
.global
) then
931 # Self is the inherited property. Process it
932 tlp
= tm
[self.local_class
.global
][self.global
]
935 # We skip this module since the props defined by the module is
939 var tlcm
= lc
.global
.intro
.mmmodule
.toplevel_owner
940 if not tlcm
.mhe
<= tm
then
941 dctx
.add
("<h4>In module {tm.html_link(dctx)} :</h4>")
944 #dctx.add("<p>TLP: {tm} x {lc} : {tlp.full_name}</p>")
947 if doc
!= null and (not introdoc
or global
.intro
.doc
!= doc
) then
948 dctx
.add
("<pre>{doc.to_html}</pre>")
951 if tlp
.local_class
.global
!= lc
.global
then
952 dctx
.add
("inherited from {tlp.local_class.html_link(dctx)} ")
954 if tm
!= tlp
.mmmodule
then
955 dctx
.add
("defined by the module {tlp.mmmodule.html_link(dctx)} ")
964 dctx
.stage
(". previously defined by:")
966 var tl
= lp
.mmmodule
.toplevel_owner
967 if tl
!= tm
then continue
968 if lp
== tlp
then continue
969 dctx
.add
(" {lp.mmmodule.html_link(dctx)}")
970 if lp
.local_class
.global
!= lc
.global
then
971 dctx
.add
(" for {lp.local_class.html_link(dctx)}")
981 #if doc != null and (not introdoc or global.intro.doc != doc) then
982 # dctx.add("<pre>{doc.to_html}</pre>")
989 dctx
.add
("</article>")
993 redef fun kind
do return if global
.is_init
then "init" else "fun"
995 redef class MMAttribute
996 redef fun kind
do return "var"
998 redef class MMTypeProperty
999 redef fun kind
do return "type"
1003 # Replace < and > with html entities
1006 var ret
= super.to_s
1008 if(ret
.has
('<')) then
1009 var parts
= ret
.split_with
("<")
1012 for i
in [0..parts
.length
[ do
1015 if(i
< parts
.length
- 1) then
1021 if(ret
.has
('>')) then
1022 var parts
= ret
.split_with
(">")
1025 for i
in [0..parts
.length
[ do
1028 if(i
< parts
.length
- 1) then
1038 redef class MMSrcModule
1052 if n
.n_moduledecl
== null then
1055 var np
= n
.n_moduledecl
1060 if d
.n_comment
.is_empty
then
1069 # Html transcription of the doc
1072 var res
= new Buffer
1073 for c
in n_comment
do
1074 res
.append
(c
.text
.substring_from
(1))
1079 # Oneliner transcription of the doc
1082 return n_comment
.first
.text
.substring_from
(1)
1086 redef class MMLocalClass
1089 # Anchor of the class description in the module html file
1090 fun html_anchor
: String do return "CLASS_{self}"
1092 fun html_name
: String do return "{self}"
1094 redef fun html_link
(dctx
)
1096 if not require_doc
(dctx
) then print
"{dctx.filename}: not required {self}"
1097 return "<a href=\"{html_name}.html\
" title=\"{short_doc}\
">{self}</a>"
1100 redef fun short_doc
do return global
.intro
.short_doc
1102 redef fun doc
do return global
.intro
.doc
1106 if global
.is_interface
then
1108 else if global
.is_abstract
then
1109 return "abstract class"
1110 else if global
.is_enum
then
1117 # The most specific module in the nesting hierarchy that exports the intro of self
1118 fun intro_module
: MMModule
1120 var m
= global
.intro
.mmmodule
1121 var mo
= m
.direct_owner
1122 while mo
!= null and mo
.visibility_for
(m
) >= 2 do
1129 fun menu_link
(dctx
: DocContext, p
: MMLocalProperty)
1131 if p
.local_class
.global
!= self.global
then
1132 if p
.global
.intro
.local_class
.name
== "Object".to_symbol
then return
1133 if p
.global
.is_init
or p
isa MMTypeProperty then
1134 dctx
.add
("<li class='inherit'><span title='Inherited'>H</span> {p.html_link_special(dctx, self)}</li>\n")
1136 dctx
.add
("<li class='inherit'><span title='Inherited'>H</span> {p.html_link(dctx)}</li>\n")
1138 else if p
.global
.intro
.local_class
.global
== self.global
then
1139 dctx
.add
("<li class='intro'><span title='Introduced'>I</span> {p.html_link_special(dctx, self)}</li>\n")
1141 dctx
.add
("<li class='redef'><span title='Redefined'>R</span> {p.html_link_special(dctx, self)}</li>\n")
1145 # Return true if the global class must be documented according to the visibility configured
1146 fun require_doc
(dctx
: DocContext): Bool
1148 if global
.visibility_level
== 3 then return false # Private
1149 if dctx
.public_only
then
1150 var m
= intro_module
1151 if m
!= m
.toplevel_owner
then return false # Unexported
1156 # Fill the body for the page associated to the global class
1157 fun file_page_doc
(dctx
: DocContext)
1159 dctx
.add
("<div class=\"menu\
">\n")
1161 var props
= new Array[MMLocalProperty]
1162 var inh
= new HashMap[MMLocalClass, Array[MMLocalProperty]]
1163 var inhs
= new Array[MMLocalClass]
1164 for g
in global_properties
do
1166 if not p
.require_doc
(dctx
) then continue
1167 if p
.local_class
.global
== global
or g
.is_init_for
(self) or p
isa MMTypeProperty then
1170 var lc
= mmmodule
[p
.local_class
.global
]
1171 if inh
.has_key
(lc
) then
1182 dctx
.add
("<nav class=\"properties filterable\
">\n")
1183 dctx
.add
("<h3>Properties</h3>\n")
1185 dctx
.stage
("<h4>Virtual Types</h4>\n<ul>\n")
1187 if p
isa MMTypeProperty then
1191 dctx
.stage
("</ul>\n")
1194 dctx
.stage
("<h4>Constructors</h4>\n<ul>\n")
1196 if p
.global
.is_init_for
(self) then
1200 dctx
.stage
("</ul>\n")
1203 dctx
.stage
("<h4>Methods</h4>\n<ul>\n")
1205 if not p
.global
.is_init
and p
isa MMMethod then
1209 dctx
.stage
("</ul>\n")
1211 dctx
.add
("</nav>\n")
1213 dctx
.add
("<nav class=\"inheritance filterable\
">\n")
1214 dctx
.add
("<h3>Inheritance</h3>\n")
1215 dctx
.add
("<h4>Superclasses</h4>\n<ul>\n")
1216 for lc
in cshe
.linear_extension
do
1217 if lc
== self then continue
1218 if not lc
.require_doc
(dctx
) then continue
1219 dctx
.add
("<li>{lc.html_link(dctx)}</li>\n")
1222 if cshe
.smallers
.length
== 0 then
1223 dctx
.add
("<h4>No Known Subclasses</h4>\n")
1224 else if cshe
.smallers
.length
<= 100 then
1225 dctx
.add
("<h4>Subclasses</h4>\n")
1227 for lc
in cshe
.smallers
do
1228 if not lc
.require_doc
(dctx
) then continue
1229 dctx
.add
("<li>{lc.html_link(dctx)}</li>\n")
1232 else if cshe
.direct_smallers
.length
<= 100 then
1233 dctx
.add
("<h4>Direct Subclasses Only</h4>\n<ul>\n")
1234 for lc
in cshe
.direct_smallers
do
1235 if not lc
.require_doc
(dctx
) then continue
1236 dctx
.add
("<li>{lc.html_link(dctx)}</li>\n")
1240 dctx
.add
("<h4>Too much Subclasses to list</h4>\n")
1242 dctx
.add
("</nav>\n")
1244 dctx
.add
("</div>\n")
1247 dctx
.add
("<div class=\"content\
">\n")
1248 dctx
.add
("<h1>{name}</h1>\n")
1249 dctx
.add
("<div class='subtitle'>")
1250 if global
.visibility_level
== 2 then
1252 else if global
.visibility_level
== 3 then
1253 dctx
.add
("private ")
1254 else if self.global
.intro
.mmmodule
.toplevel_owner
.visibility_for
(self.global
.intro
.mmmodule
) <= 1 then
1255 dctx
.add
("(unexported) ")
1257 dctx
.add
("{kind} {global.intro.mmmodule.toplevel_owner.html_link(dctx)}::{name}</div>")
1259 dctx
.add
("<section class=\"description\
">\n")
1262 dctx
.add
("<pre>{doc.to_html}</pre>\n")
1265 var cla
= new HashSet[MMLocalClass]
1266 var sm
= new HashSet[MMLocalClass]
1267 var sm2
= new HashSet[MMLocalClass]
1269 while cla
.length
+ sm
.length
< 10 and sm
.length
> 0 do
1273 sm2
.add_all
(x
.cshe
.direct_smallers
)
1279 cla
.add_all
(cshe
.greaters_and_self
)
1282 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")
1285 op
.append
("\"{c.name}\
"[shape=box,margin=0.03];\n")
1287 op
.append
("\"{c.name}\
"[URL=\"{c.html_name}.html\
"];\n")
1289 for c2
in c
.cshe
.direct_greaters
do
1290 if not cla
.has
(c2
) then continue
1291 op
.append
("\"{c.name}\
"->\"{c2.name}\
";\n")
1293 if not c
.cshe
.direct_smallers
.is_empty
then
1295 for c2
in c
.cshe
.direct_smallers
do
1296 if cla
.has
(c2
) then others
= false
1299 op
.append
("\"{c.name}...\
"[label=\"\
"];\n")
1300 op
.append
("\"{c.name}...\
"->\"{c.name}\
"[style=dotted];\n")
1305 dctx
.gen_dot
(op
.to_s
, name
.to_s
, "Inheritance graph for class {name}")
1308 var mods
= new Array[MMModule]
1309 mods
.add
(global
.intro
.mmmodule
.toplevel_owner
)
1310 for lc
in crhe
.greaters
do
1311 if not lc
isa MMSrcLocalClass then continue
1312 var m
= lc
.mmmodule
.toplevel_owner
1313 if not mods
.has
(m
) then mods
.add
(m
)
1317 if m
== global
.intro
.mmmodule
.toplevel_owner
then
1318 dctx
.add
("<p>Introduced by {m.html_link(dctx)}")
1320 dctx
.add
("<p>Refined by {m.html_link(dctx)}")
1323 dctx
.stage
(". Definition in:")
1324 for lc
in crhe
.greaters
do
1325 if lc
.mmmodule
.toplevel_owner
!= m
then continue
1326 dctx
.add
(" {lc.mmmodule.html_link(dctx)}")
1327 assert lc
isa MMSrcLocalClass
1330 dctx
.show_source
(n
.location
)
1336 dctx
.add
("</section>\n")
1339 dctx
.stage
("<section class=\"types\
">\n")
1340 dctx
.stage
("<h2>Formal and Virtual Types</h2>\n")
1341 for i
in [0..arity
[ do
1342 var f
= get_formal
(i
)
1343 f
.full_documentation
(dctx
, self)
1346 if not p
isa MMTypeProperty then continue
1347 p
.full_documentation
(dctx
, self)
1349 dctx
.stage
("</section>\n")
1353 dctx
.stage
("<section class=\"constructors\
">\n")
1354 dctx
.stage
("<h2 class=\"section-header\
">Constructors</h2>\n")
1356 if not p
.global
.is_init_for
(self) then continue
1357 p
.full_documentation
(dctx
, self)
1359 dctx
.stage
("</section>\n")
1363 dctx
.stage
("<section class=\"methods\
">\n")
1364 dctx
.stage
("<h2 class=\"section-header\
">Methods</h2>\n")
1366 if p
.global
.is_init
then continue
1367 if p
.local_class
.global
!= self.global
then continue
1368 if not p
isa MMMethod then continue
1369 p
.full_documentation
(dctx
, self)
1371 if not inhs
.is_empty
then
1373 dctx
.stage
("<h3>Inherited Methods</h3>\n")
1376 dctx
.stage
("<p>Defined in {lc.html_link(dctx)}:")
1378 if p
.global
.is_init
then continue
1379 if not p
isa MMMethod then continue
1380 dctx
.add
(" {p.html_link(dctx)}")
1387 dctx
.add
("</section>\n")
1389 dctx
.add
("</div> <!-- end class {name} -->\n")
1393 redef class MMSrcLocalClass
1399 else if global
.intro
== self then
1402 var bc
= global
.intro
1410 if not n
isa AStdClassdef then
1417 if d
.n_comment
.is_empty
then
1425 redef class MMSignature
1426 # Htlm transcription of the signature (with nested links)
1427 fun to_html
(dctx
: DocContext, with_closure
: Bool): String
1429 var res
= new Buffer
1432 res
.append
(self.params
[0].name
.to_s
)
1434 res
.append
(self[0].html_link
(dctx
))
1435 for i
in [1..arity
[ do
1437 res
.append
(self.params
[i
].name
.to_s
)
1439 res
.append
(self[i
].html_link
(dctx
))
1443 if return_type
!= null then
1445 res
.append
(return_type
.html_link
(dctx
))
1447 if with_closure
then
1448 for c
in closures
do
1450 if c
.is_optional
then res
.append
("[")
1451 if c
.is_break
then res
.append
("break ")
1452 res
.append
("!{c.name}")
1453 res
.append
(c
.signature
.to_html
(dctx
, false))
1454 if c
.is_optional
then res
.append
("]")
1462 # Htlm transcription of the type (with nested links)
1463 fun html_link
(dctx
: DocContext): String do return to_s
1466 redef class MMTypeSimpleClass
1467 redef fun html_link
(dctx
) do return local_class
.html_link
(dctx
)
1470 redef class MMTypeGeneric
1471 redef fun html_link
(dctx
)
1473 var res
= new Buffer
1474 res
.append
(local_class
.html_link
(dctx
))
1476 res
.append
(params
[0].html_link
(dctx
))
1477 for i
in [1..params
.length
[ do
1479 res
.append
(params
[i
].html_link
(dctx
))
1486 redef class MMTypeFormalParameter
1487 fun html_anchor
: String
1489 return "FT_{local_class}_{cmangle(name)}"
1491 redef fun html_link
(dctx
)
1493 return "<a href=\"#{html_anchor}\">{name}</a>"
1495 fun full_documentation
(dctx
: DocContext, lc
: MMLocalClass)
1497 dctx
.add
("<article id=\"{html_anchor}\
">\n")
1498 dctx
.add
("<h3 class=\"signature\
">{name}: {bound.html_link(dctx)}</h3>\n")
1499 dctx
.add
("<div class=\"info\
">")
1500 dctx
.add
("formal generic type")
1502 dctx
.add
("</article>")
1506 redef class MMNullableType
1507 redef fun html_link
(dctx
) do return "nullable " + as_notnull
.html_link
(dctx
)
1510 redef class MMVirtualType
1511 redef fun html_link
(dctx
) do return property
.html_link
(dctx
)
1514 var c
= new DocContext