a0b7a442c37fbc9b696833f35d6c7fc15d6883db
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}")
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
)
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
301 # A virtual module is used to work as an implicit main module that combine unrelated modules
302 # Since conflict may arrise in a virtual module (the main method for instance) conflicts are disabled
303 class MMVirtualModule
305 init(ctx
: MMContext, mods
: Array[MMModule])
307 # We need to compute the whole metamodel since there is no mmbuilder to do it
308 super(" main".to_symbol
, mods
.first
.directory
, ctx
, new Location(null,0,0,0,0))
309 ctx
.add_module
(self, mods
)
311 self.add_super_module
(m
, 1)
313 self.import_global_classes
314 self.import_local_classes
315 for c
in self.local_classes
do
316 c
.compute_super_classes
318 for c
in self.local_classes
do
323 redef fun require_doc
(dctx
) do return false
326 # Conditionnal part of the text content of a DocContext
328 # Content of the current stage
329 readable var _content
: Array[String] = new Array[String]
331 # Is a normal string already added?
332 readable writable var _validate
: Bool = false
334 # Parent stage is any
335 readable var _parent
: nullable StageContext = null
337 init(parent
: nullable StageContext) do _parent
= parent
341 # Efficiently sort object with their to_s method
342 class AlphaSorter[E
: Object]
343 super AbstractSorter[E
]
344 redef fun compare
(a
, b
)
364 # Keep track of to_s values
365 var _dico
: HashMap[Object, String] = new HashMap[Object, String]
370 # Generalization of metamodel entities
373 fun html_link
(dctx
: DocContext): String is abstract
375 # Return a one liner description
376 fun short_doc
: String do return " "
378 # The doc node from the AST
379 # Return null is none
380 fun doc
: nullable ADoc do return null
385 redef fun html_link
(dctx
) do
386 return "<a href=\"{html_name}.html\
">{self}</a>"
389 fun require_doc
(dctx
: DocContext): Bool
391 if dctx
.public_only
and not is_toplevel
then return false
395 # Return true if the module is a top-level owner or a top-level module
396 fun is_toplevel
: Bool
398 var pd
= directory
.parent
399 return pd
== null or (pd
.owner
== null and directory
.owner
== self)
402 # Element in the module nesting tree
403 fun mnhe
: PartialOrderElement[MMModule] do return mnhe_
.as(not null)
404 var mnhe_
: nullable PartialOrderElement[MMModule] = null
406 # Element in the top level module importation hierarchy
407 fun tmhe
: PartialOrderElement[MMModule] do return tmhe_
.as(not null)
408 var tmhe_
: nullable PartialOrderElement[MMModule] = null
410 fun toplevel_owner
: MMModule
414 var ds
= m
.mnhe
.direct_smallers
415 if ds
.length
== 0 then return m
416 if ds
.length
== 1 then m
= ds
.first
else abort
420 fun html_name
: String
425 fun direct_owner
: nullable MMModule
428 while d
.owner
== self do d
= d
.parent
.as(not null)
432 # Fill the body for the page associated to the module
433 fun file_page_doc
(dctx
: DocContext)
435 dctx
.add
("<div class=\"menu\
">\n")
437 var mods
= new Array[MMModule]
438 mods
= self.mhe
.greaters
.to_a
442 dctx
.stage
("<nav>\n")
443 dctx
.stage
("<h3>Module Hierarchy</h3>\n")
444 dctx
.stage
("<h4>All dependencies</h4>\n")
447 if not mod
.require_doc
(dctx
) then continue
448 if self.mnhe
<= mod
then continue # do not want nested stuff
449 if mod
.direct_owner
!= null and not mod
.direct_owner
.mnhe
<= self then continue # not in the right nesting
450 dctx
.add
("<li>{mod.html_link(dctx)}</li>")
452 dctx
.stage
("</ul>\n")
454 mods
= self.mhe
.smallers
.to_a
456 dctx
.stage
("<h4>All clients</h4>\n")
459 if not mod
.require_doc
(dctx
) then continue
460 if self.mnhe
<= mod
then continue # do not want nested stuff
461 if mod
.direct_owner
!= null and not mod
.direct_owner
.mnhe
<= self then continue # not in the right nesting
462 dctx
.add
("<li>{mod.html_link(dctx)}</li>")
464 dctx
.stage
("</ul>\n")
465 dctx
.stage
("</nav>\n")
468 if not dctx
.public_only
then
469 mods
= self.mnhe
.direct_greaters
.to_a
472 dctx
.stage
("<nav>\n")
473 dctx
.stage
("<h3>Nested Modules</h3><ul>\n")
475 if not mod
.require_doc
(dctx
) then continue
476 dctx
.add
("<li>{mod.html_link(dctx)}</li>")
478 dctx
.stage
("</ul></nav>\n")
482 dctx
.add
("</div>") # metadata
484 dctx
.add
("<div class=\"content\
">\n")
485 dctx
.add
("<h1>{name}</h1>\n")
486 dctx
.add
("<div class='subtitle'>module ")
487 for m
in mnhe
.smallers
do
488 dctx
.add
("{m.html_link(dctx)}::")
490 dctx
.add
("{self.name}</div>\n")
492 dctx
.add
("<section class='description'>\n")
496 dctx
.add
("<div id=\"description\
">\n")
497 dctx
.add
("<pre>{doc.to_html}</pre>\n")
502 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")
503 var ms
= new Array[nullable MMModule]
505 var m0
: nullable MMModule = self
511 var cla
= new HashSet[MMModule]
513 for m0
in self.mhe
.greaters
do
514 if not m0
.require_doc
(dctx
) then continue
515 if self.visibility_for
(m0
) <= 1 then continue # private or hidden
516 if self.mnhe
<= m0
then continue # do not want nested stuff
517 if m0
.direct_owner
!= null and not m0
.direct_owner
.mnhe
<= self then continue # not in the right nesting
520 for m0
in self.mhe
.smallers
do
521 if not m0
.require_doc
(dctx
) then continue
522 if m0
.visibility_for
(self) <= 1 then continue # private or hidden
523 if m0
.direct_owner
!= null and not m0
.direct_owner
.mnhe
<= self then continue # not in the right nesting
526 for m0
in self.mnhe
.smallers
do
532 op
.append
("subgraph \"cluster_
{m0.name}\
"\{\n")
535 if c
.direct_owner
!= m0
then continue
537 op
.append
("\"{c.name}\
"[shape=box,margin=0.03];\n")
539 op
.append
("\"{c.name}\
"[URL=\"{c.html_name}.html\
"];\n")
543 op
.append
("\"{m0.name}\
"[URL=\"{m0.html_name}.html\
"];\n")
544 for c
in m0
.mhe
.direct_greaters
do
545 if not cla
.has
(c
) then continue
546 op
.append
("\"{m0.name}\
"->\"{c.name}\
";\n")
551 # Close the nesting subgraph
557 for c2
in c
.tmhe
.direct_greaters
do
558 if not cla
.has
(c2
) then continue
559 op
.append
("\"{c.name}\
"->\"{c2.name}\
";\n")
563 dctx
.gen_dot
(op
.to_s
, name
.to_s
, "Dependency graph for module {name}")
564 dctx
.add
("</section>")
566 var clas
= new Array[MMLocalClass]
567 var props
= new HashMap[MMGlobalProperty, Array[MMLocalProperty]]
568 var gprops
= new Array[MMLocalProperty]
571 for g
in m
.global_classes
do
573 if not lc
.require_doc
(dctx
) then continue
574 var im
= g
.intro
.mmmodule
575 if self.visibility_for
(im
) <= 1 then continue # private import or invisible import
577 for lc2
in lc
.crhe
.greaters_and_self
do
578 if not lc2
isa MMSrcLocalClass then continue
579 if not self.mnhe
<= lc2
.mmmodule
then continue # not introduced/redefined here/stolen
582 if not keep
then continue
584 for gp
in lc
.global_properties
do
585 if self.visibility_for
(gp
.intro
.local_class
.mmmodule
) <= 1 then continue # private import or invisible import
587 var mp
= lp
.local_class
.mmmodule
588 if not self.mnhe
<= mp
then continue # not introduced/redefined here/stolen
590 if not lp
.require_doc
(dctx
) then continue
591 if props
.has_key
(lp
.global
) then
592 if not props
[lp
.global
].has
(lp
) then
593 props
[lp
.global
].add
(lp
)
596 props
[lp
.global
] = [lp
]
597 gprops
.add
(lp
.global
.intro
)
602 dctx
.add
("<section class=\"module\
">\n")
604 dctx
.stage
("<article class=\"classes filterable\
">\n")
605 dctx
.stage
("<h2>Classes</h2>\n")
609 if self.mnhe
<= lc
.global
.intro
.mmmodule
then
610 dctx
.add
("<li class='intro'><span title='introduced in this module'>I</span> ")
612 dctx
.add
("<li class='redef'><span title='refined in this module'>R</span> ")
614 dctx
.add
("{lc.html_link(dctx)}</li>\n")
616 dctx
.stage
("</ul></article>\n")
620 dctx
.stage
("<article class=\"properties filterable\
">\n")
621 dctx
.stage
("<h2>Properties</h2>\n")
628 if gp
.intro
isa MMAttribute then continue
630 var lpi
= self[gp
.intro
.local_class
.global
][gp
]
633 dctx
.add
("<li class='intro'><span title='introduction in an other module'>I</span> <a href=\"{lpi.local_class.html_name}.html
#{lpi.html_anchor}\">{lpi} ({lpi.local_class})</a></li>\n")
636 dctx
.add
("<li class='intro'><span title='introduction in this module'>I</span> {lpi}")
637 dctx
.add
(" ({lpi.local_class})</li>\n")
639 if lps
.length
>= 1 then
642 dctx
.add
("<li class='redef'><span title='redefinition'>R</span> <a href=\"{lp.local_class.html_name}.html
#{lp.html_anchor}\">{lp} ({lp.local_class})</a></li>")
646 dctx
.stage
("</ul></article>\n")
648 dctx
.add
("</section>\n")
652 # Fill the body for the page associated to the full index
653 fun file_index_page_doc
(dctx
: DocContext)
656 dctx
.add
("<h1>Full Index</h1>\n")
658 var clas
= new Array[MMLocalClass]
659 var props
= new HashMap[MMGlobalProperty, Array[MMLocalProperty]]
660 var gprops
= new Array[MMLocalProperty]
661 var mods
= new Array[MMModule]
662 for m
in mhe
.greaters_and_self
do
663 if not m
.require_doc
(dctx
) then continue
666 for g
in global_classes
do
668 if not lc
.require_doc
(dctx
) then continue
670 for gp
in lc
.global_properties
do
672 if not lp
.require_doc
(dctx
) then continue
673 if props
.has_key
(lp
.global
) then
674 if not props
[lp
.global
].has
(lp
) then
675 props
[lp
.global
].add
(lp
)
678 props
[lp
.global
] = [lp
]
679 gprops
.add
(lp
.global
.intro
)
684 dctx
.stage
("<article class=\"modules filterable\
">\n")
685 dctx
.stage
("<h2>Modules</h2>\n")
689 dctx
.add
("<li>{m.html_link(dctx)}</li>")
691 dctx
.stage
("</ul></article>\n")
695 dctx
.stage
("<article class=\"classes filterable\
">\n")
696 dctx
.stage
("<h2>Classes</h2>\n")
700 dctx
.add
("<li>{lc.html_link(dctx)}</li>")
702 dctx
.stage
("</ul></article>\n")
706 dctx
.stage
("<article class=\"properties filterable\
">\n")
707 dctx
.stage
("<h2>Properties</h2>\n")
714 if gp
.intro
isa MMAttribute then continue
716 var lpi
= self[gp
.intro
.local_class
.global
][gp
]
719 dctx
.add
("<li class='intro'><span title='introduction'>I</span> <a href=\"{lpi.local_class.html_name}.html
#{lpi.html_anchor}\">{lpi} ({lpi.local_class})</a></li>\n")
720 if lps
.length
>= 1 then
723 dctx
.add
("<li class='redef'><span title='redefinition'>R</span> <a href=\"{lp.local_class.html_name}.html
#{lp.html_anchor}\">{lp} ({lp.local_class})</a></li>\n")
727 dctx
.stage
("</ul></article>\n")
732 redef class MMLocalProperty
734 # Anchor of the property description in the module html file
735 fun html_anchor
: String
737 return "PROP_{local_class}_{cmangle(name)}"
740 redef fun html_link
(dctx
)
742 if not require_doc
(dctx
) then print
"not required {self}"
743 return "<a href=\"{local_class.html_name}.html
#{html_anchor}\">{self}</a>"
746 fun html_link_special
(dctx
: DocContext, lc
: MMLocalClass): String
748 if not require_doc
(dctx
) then print
"not required {self}"
749 return "<a href=\"{lc.html_name}.html
#{html_anchor}\">{self}</a>"
752 # Kind of property (fun, attr, etc.)
753 fun kind
: String is abstract
760 else if global
.intro
== self then
763 return global
.intro
.short_doc
770 if n
== null or not n
isa APropdef then
777 if d
.n_comment
.is_empty
then
784 # The most specific module in the nesting hierarchy that exports the intro of self
785 fun intro_module
: MMModule
787 var m
= global
.intro
.mmmodule
788 var mo
= m
.direct_owner
789 while mo
!= null and mo
.visibility_for
(m
) >= 2 do
796 # Is the intro of self exported by the top-level module ?
797 fun is_toplevel
: Bool
800 return m
== m
.toplevel_owner
803 # Return true if the global class must be documented according to the visibility configured
804 fun require_doc
(dctx
: DocContext): Bool
806 if global
.visibility_level
== 3 then return false # Private
807 if dctx
.public_only
then
809 if m
!= m
.toplevel_owner
then return false # Unexported
814 # Document the global property in the global class lc
815 fun full_documentation
(dctx
: DocContext, lc
: MMLocalClass)
817 var visibility
: String
818 if global
.visibility_level
== 1 then
819 visibility
= "public"
820 else if global
.visibility_level
== 2 then
821 visibility
= "protected"
822 else if global
.visibility_level
== 3 then
823 visibility
= "private"
828 var intro_class
= global
.intro
.local_class
829 var is_redef
= local_class
.global
!= intro_class
.global
or local_class
.mmmodule
.toplevel_owner
!= intro_class
.mmmodule
.toplevel_owner
831 dctx
.add
("<article id=\"{html_anchor}\
" class=\"{kind} {visibility} {if is_redef then "redef" else ""}\
">\n")
832 dctx
.add
("<h3 class=\"signature\
">{name}{signature.to_html(dctx, true)}</h3>\n")
833 dctx
.add
("<div class=\"info\
">\n")
834 #dctx.add("<p>LP: {self.mmmodule.html_link(dctx)}::{self.local_class.html_link(dctx)}::{self.html_link(dctx)}</p>")
839 if not is_toplevel
then
840 dctx
.add
("(unexported) ")
842 if global
.visibility_level
== 2 then
843 dctx
.add
("protected ")
844 else if global
.visibility_level
== 3 then
848 dctx
.add
(" {intro_class.mmmodule.toplevel_owner.name}")
849 if intro_class
.global
== lc
.global
then
850 dctx
.add
("::{lc.name}")
852 dctx
.add
("::{mmmodule[intro_class.global].html_link(dctx)}")
855 dctx
.add
("::{mmmodule[intro_class.global][global].html_link(dctx)}")
861 dctx
.add
("<div class=\"description\
">")
863 # Collect all refinement of the global property in the same global property
864 var lps
= new Array[MMLocalProperty]
865 for l
in prhe
.greaters_and_self
do
870 if global
.intro
.doc
!= null then
872 if lp
.doc
== null then introdoc
= true
876 dctx
.add
("<pre>{global.intro.doc.to_html}</pre>")
879 var tlmods
= new Array[MMModule]
881 var bm
= lp
.mmmodule
.toplevel_owner
882 var lcm
= lc
.global
.intro
.mmmodule
883 if lcm
.mhe
< lp
.mmmodule
then bm
= lcm
.toplevel_owner
884 if not tlmods
.has
(bm
) then tlmods
.add
(bm
)
888 # Document the top level property for the current top level module
890 if tm
.global_classes
.has
(lc
.global
) then
891 tlp
= tm
[lc
.global
][self.global
]
893 else if tm
.global_classes
.has
(self.local_class
.global
) then
894 # Self is the inherited property. Process it
895 tlp
= tm
[self.local_class
.global
][self.global
]
898 # We skip this module since the props defined by the module is
902 var tlcm
= lc
.global
.intro
.mmmodule
.toplevel_owner
903 if not tlcm
.mhe
<= tm
then
904 dctx
.add
("<h4>In module {tm.html_link(dctx)} :</h4>")
907 #dctx.add("<p>TLP: {tm} x {lc} : {tlp.full_name}</p>")
910 if doc
!= null and (not introdoc
or global
.intro
.doc
!= doc
) then
911 dctx
.add
("<pre>{doc.to_html}</pre>")
914 if tlp
.local_class
.global
!= lc
.global
then
915 dctx
.add
("inherited from {tlp.local_class.html_link(dctx)} ")
917 if tm
!= tlp
.mmmodule
then
918 dctx
.add
("defined by the module {tlp.mmmodule.html_link(dctx)} ")
927 dctx
.stage
(". previously defined by:")
929 var tl
= lp
.mmmodule
.toplevel_owner
930 if tl
!= tm
then continue
931 if lp
== tlp
then continue
932 dctx
.add
(" {lp.mmmodule.html_link(dctx)}")
933 if lp
.local_class
.global
!= lc
.global
then
934 dctx
.add
(" for {lp.local_class.html_link(dctx)}")
944 #if doc != null and (not introdoc or global.intro.doc != doc) then
945 # dctx.add("<pre>{doc.to_html}</pre>")
952 dctx
.add
("</article>")
956 redef fun kind
do return if global
.is_init
then "init" else "fun"
958 redef class MMAttribute
959 redef fun kind
do return "var"
961 redef class MMTypeProperty
962 redef fun kind
do return "type"
966 # Replace < and > with html entities
971 if(ret
.has
('<')) then
972 var parts
= ret
.split_with
("<")
975 for i
in [0..parts
.length
[ do
978 if(i
< parts
.length
- 1) then
984 if(ret
.has
('>')) then
985 var parts
= ret
.split_with
(">")
988 for i
in [0..parts
.length
[ do
991 if(i
< parts
.length
- 1) then
1001 redef class MMSrcModule
1015 if n
.n_moduledecl
== null then
1018 var np
= n
.n_moduledecl
1023 if d
.n_comment
.is_empty
then
1032 # Html transcription of the doc
1035 var res
= new Buffer
1036 for c
in n_comment
do
1037 res
.append
(c
.text
.substring_from
(1))
1042 # Oneliner transcription of the doc
1045 return n_comment
.first
.text
.substring_from
(1)
1049 redef class MMLocalClass
1052 # Anchor of the class description in the module html file
1053 fun html_anchor
: String do return "CLASS_{self}"
1055 fun html_name
: String do return "{self}"
1057 redef fun html_link
(dctx
)
1059 if not require_doc
(dctx
) then print
"{dctx.filename}: not required {self}"
1060 return "<a href=\"{html_name}.html\
">{self}</a>"
1063 redef fun short_doc
do return global
.intro
.short_doc
1065 redef fun doc
do return global
.intro
.doc
1069 if global
.is_interface
then
1071 else if global
.is_abstract
then
1072 return "abstract class"
1073 else if global
.is_enum
then
1080 # The most specific module in the nesting hierarchy that exports the intro of self
1081 fun intro_module
: MMModule
1083 var m
= global
.intro
.mmmodule
1084 var mo
= m
.direct_owner
1085 while mo
!= null and mo
.visibility_for
(m
) >= 2 do
1092 fun menu_link
(dctx
: DocContext, p
: MMLocalProperty)
1094 if p
.local_class
.global
!= self.global
then
1095 if p
.global
.intro
.local_class
.name
== "Object".to_symbol
then return
1096 if p
.global
.is_init
or p
isa MMTypeProperty then
1097 dctx
.add
("<li class='inherit'><span title='Inherited'>H</span> {p.html_link_special(dctx, self)}</li>\n")
1099 dctx
.add
("<li class='inherit'><span title='Inherited'>H</span> {p.html_link(dctx)}</li>\n")
1101 else if p
.global
.intro
.local_class
.global
== self.global
then
1102 dctx
.add
("<li class='intro'><span title='Introduced'>I</span> {p.html_link_special(dctx, self)}</li>\n")
1104 dctx
.add
("<li class='redef'><span title='Redefined'>R</span> {p.html_link_special(dctx, self)}</li>\n")
1108 # Return true if the global class must be documented according to the visibility configured
1109 fun require_doc
(dctx
: DocContext): Bool
1111 if global
.visibility_level
== 3 then return false # Private
1112 if dctx
.public_only
then
1113 var m
= intro_module
1114 if m
!= m
.toplevel_owner
then return false # Unexported
1119 # Fill the body for the page associated to the global class
1120 fun file_page_doc
(dctx
: DocContext)
1122 dctx
.add
("<div class=\"menu\
">\n")
1124 var props
= new Array[MMLocalProperty]
1125 var inh
= new HashMap[MMLocalClass, Array[MMLocalProperty]]
1126 var inhs
= new Array[MMLocalClass]
1127 for g
in global_properties
do
1129 if not p
.require_doc
(dctx
) then continue
1130 if p
.local_class
.global
== global
or g
.is_init_for
(self) or p
isa MMTypeProperty then
1133 var lc
= mmmodule
[p
.local_class
.global
]
1134 if inh
.has_key
(lc
) then
1145 dctx
.add
("<nav class=\"properties filterable\
">\n")
1146 dctx
.add
("<h3>Properties</h3>\n")
1148 dctx
.stage
("<h4>Virtual Types</h4>\n<ul>\n")
1150 if p
isa MMTypeProperty then
1154 dctx
.stage
("</ul>\n")
1157 dctx
.stage
("<h4>Constructors</h4>\n<ul>\n")
1159 if p
.global
.is_init_for
(self) then
1163 dctx
.stage
("</ul>\n")
1166 dctx
.stage
("<h4>Methods</h4>\n<ul>\n")
1168 if not p
.global
.is_init
and p
isa MMMethod then
1172 dctx
.stage
("</ul>\n")
1174 dctx
.add
("</nav>\n")
1176 dctx
.add
("<nav class=\"inheritance filterable\
">\n")
1177 dctx
.add
("<h3>Inheritance</h3>\n")
1178 dctx
.add
("<h4>Superclasses</h4>\n<ul>\n")
1179 for lc
in cshe
.linear_extension
do
1180 if lc
== self then continue
1181 if not lc
.require_doc
(dctx
) then continue
1182 dctx
.add
("<li>{lc.html_link(dctx)}</li>\n")
1185 if cshe
.smallers
.length
== 0 then
1186 dctx
.add
("<h4>No Known Subclasses</h4>\n")
1187 else if cshe
.smallers
.length
<= 100 then
1188 dctx
.add
("<h4>Subclasses</h4>\n")
1190 for lc
in cshe
.smallers
do
1191 if not lc
.require_doc
(dctx
) then continue
1192 dctx
.add
("<li>{lc.html_link(dctx)}</li>\n")
1195 else if cshe
.direct_smallers
.length
<= 100 then
1196 dctx
.add
("<h4>Direct Subclasses Only</h4>\n<ul>\n")
1197 for lc
in cshe
.direct_smallers
do
1198 if not lc
.require_doc
(dctx
) then continue
1199 dctx
.add
("<li>{lc.html_link(dctx)}</li>\n")
1203 dctx
.add
("<h4>Too much Subclasses to list</h4>\n")
1205 dctx
.add
("</nav>\n")
1207 dctx
.add
("</div>\n")
1210 dctx
.add
("<div class=\"content\
">\n")
1211 dctx
.add
("<h1>{name}</h1>\n")
1212 dctx
.add
("<div class='subtitle'>")
1213 if global
.visibility_level
== 2 then
1215 else if global
.visibility_level
== 3 then
1216 dctx
.add
("private ")
1217 else if self.global
.intro
.mmmodule
.toplevel_owner
.visibility_for
(self.global
.intro
.mmmodule
) <= 1 then
1218 dctx
.add
("(unexported) ")
1220 dctx
.add
("{kind} {global.intro.mmmodule.toplevel_owner.html_link(dctx)}::{name}</div>")
1222 dctx
.add
("<section class=\"description\
">\n")
1225 dctx
.add
("<pre>{doc.to_html}</pre>\n")
1228 var cla
= new HashSet[MMLocalClass]
1229 var sm
= new HashSet[MMLocalClass]
1230 var sm2
= new HashSet[MMLocalClass]
1232 while cla
.length
+ sm
.length
< 10 and sm
.length
> 0 do
1236 sm2
.add_all
(x
.cshe
.direct_smallers
)
1242 cla
.add_all
(cshe
.greaters_and_self
)
1245 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")
1248 op
.append
("\"{c.name}\
"[shape=box,margin=0.03];\n")
1250 op
.append
("\"{c.name}\
"[URL=\"{c.html_name}.html\
"];\n")
1252 for c2
in c
.cshe
.direct_greaters
do
1253 if not cla
.has
(c2
) then continue
1254 op
.append
("\"{c.name}\
"->\"{c2.name}\
";\n")
1256 if not c
.cshe
.direct_smallers
.is_empty
then
1258 for c2
in c
.cshe
.direct_smallers
do
1259 if cla
.has
(c2
) then others
= false
1262 op
.append
("\"{c.name}...\
"[label=\"\
"];\n")
1263 op
.append
("\"{c.name}...\
"->\"{c.name}\
"[style=dotted];\n")
1268 dctx
.gen_dot
(op
.to_s
, name
.to_s
, "Inheritance graph for class {name}")
1271 var mods
= new Array[MMModule]
1272 mods
.add
(global
.intro
.mmmodule
.toplevel_owner
)
1273 for lc
in crhe
.greaters
do
1274 if not lc
isa MMSrcLocalClass then continue
1275 var m
= lc
.mmmodule
.toplevel_owner
1276 if not mods
.has
(m
) then mods
.add
(m
)
1280 if m
== global
.intro
.mmmodule
.toplevel_owner
then
1281 dctx
.add
("<p>Introduced by {m.html_link(dctx)}")
1283 dctx
.add
("<p>Refined by {m.html_link(dctx)}")
1286 dctx
.stage
(". Definition in:")
1287 for lc
in crhe
.greaters
do
1288 if lc
.mmmodule
.toplevel_owner
!= m
then continue
1289 dctx
.add
(" {lc.mmmodule.html_link(dctx)}")
1290 assert lc
isa MMSrcLocalClass
1293 dctx
.show_source
(n
.location
)
1299 dctx
.add
("</section>\n")
1302 dctx
.stage
("<section class=\"types\
">\n")
1303 dctx
.stage
("<h2>Formal and Virtual Types</h2>\n")
1304 for i
in [0..arity
[ do
1305 var f
= get_formal
(i
)
1306 f
.full_documentation
(dctx
, self)
1309 if not p
isa MMTypeProperty then continue
1310 p
.full_documentation
(dctx
, self)
1312 dctx
.stage
("</section>\n")
1316 dctx
.stage
("<section class=\"constructors\
">\n")
1317 dctx
.stage
("<h2 class=\"section-header\
">Constructors</h2>\n")
1319 if not p
.global
.is_init_for
(self) then continue
1320 p
.full_documentation
(dctx
, self)
1322 dctx
.stage
("</section>\n")
1326 dctx
.stage
("<section class=\"methods\
">\n")
1327 dctx
.stage
("<h2 class=\"section-header\
">Methods</h2>\n")
1329 if p
.global
.is_init
then continue
1330 if p
.local_class
.global
!= self.global
then continue
1331 if not p
isa MMMethod then continue
1332 p
.full_documentation
(dctx
, self)
1334 if not inhs
.is_empty
then
1336 dctx
.stage
("<h3>Inherited Methods</h3>\n")
1339 dctx
.stage
("<p>Defined in {lc.html_link(dctx)}:")
1341 if p
.global
.is_init
then continue
1342 if not p
isa MMMethod then continue
1343 dctx
.add
(" {p.html_link(dctx)}")
1350 dctx
.add
("</section>\n")
1352 dctx
.add
("</div> <!-- end class {name} -->\n")
1356 redef class MMSrcLocalClass
1362 else if global
.intro
== self then
1365 var bc
= global
.intro
1373 if not n
isa AStdClassdef then
1380 if d
.n_comment
.is_empty
then
1388 redef class MMSignature
1389 # Htlm transcription of the signature (with nested links)
1390 fun to_html
(dctx
: DocContext, with_closure
: Bool): String
1392 var res
= new Buffer
1395 res
.append
(self.params
[0].name
.to_s
)
1397 res
.append
(self[0].html_link
(dctx
))
1398 for i
in [1..arity
[ do
1400 res
.append
(self.params
[i
].name
.to_s
)
1402 res
.append
(self[i
].html_link
(dctx
))
1406 if return_type
!= null then
1408 res
.append
(return_type
.html_link
(dctx
))
1410 if with_closure
then
1411 for c
in closures
do
1413 if c
.is_optional
then res
.append
("[")
1414 if c
.is_break
then res
.append
("break ")
1415 res
.append
("!{c.name}")
1416 res
.append
(c
.signature
.to_html
(dctx
, false))
1417 if c
.is_optional
then res
.append
("]")
1425 # Htlm transcription of the type (with nested links)
1426 fun html_link
(dctx
: DocContext): String do return to_s
1429 redef class MMTypeSimpleClass
1430 redef fun html_link
(dctx
) do return local_class
.html_link
(dctx
)
1433 redef class MMTypeGeneric
1434 redef fun html_link
(dctx
)
1436 var res
= new Buffer
1437 res
.append
(local_class
.html_link
(dctx
))
1439 res
.append
(params
[0].html_link
(dctx
))
1440 for i
in [1..params
.length
[ do
1442 res
.append
(params
[i
].html_link
(dctx
))
1449 redef class MMTypeFormalParameter
1450 fun html_anchor
: String
1452 return "FT_{local_class}_{cmangle(name)}"
1454 redef fun html_link
(dctx
)
1456 return "<a href=\"#{html_anchor}\">{name}</a>"
1458 fun full_documentation
(dctx
: DocContext, lc
: MMLocalClass)
1460 dctx
.add
("<article id=\"{html_anchor}\
">\n")
1461 dctx
.add
("<h3 class=\"signature\
">{name}: {bound.html_link(dctx)}</h3>\n")
1462 dctx
.add
("<div class=\"info\
">")
1463 dctx
.add
("formal generic type")
1465 dctx
.add
("</article>")
1469 redef class MMNullableType
1470 redef fun html_link
(dctx
) do return "nullable " + as_notnull
.html_link
(dctx
)
1473 redef class MMVirtualType
1474 redef fun html_link
(dctx
) do return property
.html_link
(dctx
)
1477 var c
= new DocContext