1 # This file is part of NIT ( http://www.nitlanguage.org ).
3 # Copyright 2008 Jean Privat <jean@pryen.org>
5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at
9 # http://www.apache.org/licenses/LICENSE-2.0
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
17 # The main module of the nitdoc program
25 # Store knowledge and facilities to generate files
27 super AbstractCompiler
28 # Destination directory
29 readable writable var _dir
: String = "doc"
31 # Content of a generated file
32 var _stage_context
: StageContext = new StageContext(null)
34 # Add a string in the content
36 _stage_context
.content
.add
(s
)
37 _stage_context
.validate
= true
40 # Add a string in the content iff some other string are added
41 fun stage
(s
: String) do _stage_context
.content
.add
(s
)
43 # Create a new stage in the content
44 fun open_stage
do _stage_context
= new StageContext(_stage_context
)
46 # Close the current stage in the content
49 var s
= _stage_context
.parent
50 if _stage_context
.validate
then
51 s
.content
.add_all
(_stage_context
.content
)
58 # Write the content to a new file
59 fun write_to
(filename
: String)
61 var f
= new OFStream.open
(filename
)
62 for s
in _stage_context
.content
do
71 _stage_context
= new StageContext(null)
74 # Sorter of entities in alphabetical order
75 var _sorter
: AlphaSorter[MMEntity] = new AlphaSorter[MMEntity]
77 # Sort entities in the alphabetical order
78 fun sort
(array
: Array[MMEntity])
83 readable var _opt_dir
: OptionString = new OptionString("Directory where doc is generated", "-d", "--dir")
84 readable var _opt_source
: OptionString = new OptionString("What link for source (%f for filename, %l for first line, %L for last line)", "--source")
85 readable var _opt_public
: OptionBool = new OptionBool("Generate only the public API", "--public")
86 readable var _opt_private
: OptionBool = new OptionBool("Generate the private API", "--private")
87 readable var _opt_nodot
: OptionBool = new OptionBool("Do not generate graphes with graphviz", "--no-dot")
88 readable var _opt_sharedir
: OptionString = new OptionString("Directory containing the nitdoc files", "--sharedir")
89 var sharedir
: nullable String
93 if self._opt_public
.value
== true then return true
97 fun with_private
: Bool
99 if self._opt_private
.value
== true then return true
103 # The current processed filename
106 # The main virtual module
107 var mainmod
: nullable MMVirtualModule
109 redef fun perform_work
(mods
)
111 mainmod
= new MMVirtualModule(self, mods
)
115 sys
.system
("cp -r '{sharedir.to_s}'/* {dir}/")
117 # Compute the set of direct owned nested modules
118 var owns
= new HashMap[MMModule, Array[MMModule]]
119 for mod
in modules
do
120 owns
[mod
] = new Array[MMModule]# [mod]
122 for mod
in modules
do
123 if mod
== mainmod
then continue
124 var d
= mod
.directory
127 if o
!= null and o
!= mod
then
131 if dp
== null or dp
== d
then break
136 # Builds the various module hierarchies
137 var mnh
= new PartialOrder[MMModule] # nested module hierarchy
138 var tmh
= new PartialOrder[MMModule] # top module import hierrchy
139 var ms
= mainmod
.mhe
.linear_extension
.reversed
141 if ms
== mainmod
then continue
142 m
.mnhe_
= mnh
.add
(m
, owns
[m
])
143 var pub
= new Array[MMModule]
144 for m2
in m
.mhe
.greaters
do
145 if m2
.toplevel_owner
!= m2
and m2
.toplevel_owner
!= m
.toplevel_owner
then continue
146 if m
.mnhe
<= m2
then continue
147 if m
.visibility_for
(m2
) <= 0 then
149 else if m
.visibility_for
(m2
) == 1 then
154 m
.tmhe_
= tmh
.add
(m
, pub
)
157 var head
= "<meta charset=\"utf-8\
">" +
158 "<script type=\"text
/javascript\
" src=\"scripts
/jquery-1
.7
.1.min
.js\
"></script>\n" +
159 "<script type=\"text
/javascript\
" src=\"scripts
/js-facilities
.js\
"></script>\n" +
160 "<link rel=\"stylesheet\
" href=\"styles
/main
.css\
" type=\"text
/css\
" media=\"screen\
" />"
162 var action_bar
= "<header><nav class='main'><ul><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"
165 self.filename
= "index.html"
167 add
("<!DOCTYPE html>")
168 add
("<html><head>{head}<title>Index</title></head><body>\n")
170 add
("<div class=\"page\
">")
171 add
("<div class=\"content fullpage\
">")
172 add
("<h1>Modules</h1>\n<article class='overview'><ul>")
173 var modss
= mainmod
.mhe
.greaters_and_self
.to_a
176 if not mod
.is_toplevel
then continue
177 if not mod
.require_doc
(self) then continue
178 assert mod
isa MMSrcModule
179 add
("<li>{mod.html_link(self)} {mod.short_doc}</li>")
185 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")
187 if not mod
.is_toplevel
then continue
188 if not mod
.require_doc
(self) then continue
189 op
.append
("\"{mod.name}\
"[URL=\"{mod.html_name}.html\
"];\n")
190 for mod2
in mod
.tmhe
.direct_greaters
do
191 if not modss
.has
(mod2
) then continue
192 op
.append
("\"{mod.name}\
"->\"{mod2.name}\
";\n")
196 self.gen_dot
(op
.to_s
, "dep", "Modules hierarchy")
197 add
("</article></div>")
198 add
("<div class='clear'></div>")
200 add
("</body></html>\n")
201 write_to
("{dir}/index.html")
203 # Generate page for modules
204 for mod
in modules
do
205 if mod
== mainmod
then continue
206 assert mod
isa MMSrcModule
207 if not mod
.require_doc
(self) then continue
208 self.filename
= mod
.html_name
209 action_bar
= "<header><nav class='main'><ul><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"
211 add
("<!DOCTYPE html>")
212 add
("<html><head>{head}<title>Module {mod.name}</title></head><body>\n")
214 add
("<div class=\"page\
">")
215 mod
.file_page_doc
(self)
217 add
("</body></html>\n")
218 write_to
("{dir}/{mod.html_name}.html")
221 # Generate pages for global classes
222 for c
in mainmod
.local_classes
do
223 if not c
.require_doc
(self) then continue
224 self.filename
= c
.html_name
225 action_bar
= "<header><nav class='main'><ul><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"
227 add
("<!DOCTYPE html>")
228 add
("<html><head>{head}<title>Class {c.name}</title></head><body>\n")
230 add
("<div class=\"page\
">")
231 c
.file_page_doc
(self)
233 add
("</body></html>\n")
234 write_to
("{dir}/{c.html_name}.html")
237 self.filename
= "fullindex"
238 action_bar
= "<header><nav class='main'><ul><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"
240 add
("<!DOCTYPE html>")
241 add
("<html><head>{head}<title>Full Index</title></head><body>\n")
243 add
("<div class=\"page\
">")
244 add
("<div class=\"content fullpage\
">")
245 mainmod
.file_index_page_doc
(self)
248 add
("</body></html>\n")
249 write_to
("{dir}/full-index.html")
253 # Add a (source) link fo a given location
254 fun show_source
(l
: Location)
256 var s
= opt_source
.value
258 add
("in #{l.file.filename.simplify_path}")
260 # THIS IS JUST UGLY ! (but there is no replace yet)
261 var x
= s
.split_with
("%f")
262 s
= x
.join
(l
.file
.filename
.simplify_path
)
263 x
= s
.split_with
("%l")
264 s
= x
.join
(l
.line_start
.to_s
)
265 x
= s
.split_with
("%L")
266 s
= x
.join
(l
.line_end
.to_s
)
267 add
(" (<a href=\"{s}\
">show code</a>)")
271 # Generate a clicable graphiz image using a dot content.
272 # `name' refer to the filename (without extension) and the id name of the map.
273 # `name' must also match the name of the graph in the dot content (eg. digraph NAME {...)
274 fun gen_dot
(dot
: String, name
: String, alt
: String)
276 if opt_nodot
.value
then return
277 var f
= new OFStream.open
("{self.dir}/{name}.dot")
280 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 ; \}")
281 self.add
("<article class=\"graph\
"><img src=\"{name}.png\
" usemap=\"#{name}\" style=\"margin:auto\" alt=\"{alt}\"/></article>")
282 var fmap
= new IFStream.open
("{self.dir}/{name}.map")
283 self.add
(fmap
.read_all
)
292 option_context
.add_option
(opt_public
)
293 option_context
.add_option
(opt_private
)
294 option_context
.add_option
(opt_dir
)
295 option_context
.add_option
(opt_source
)
296 option_context
.add_option
(opt_nodot
)
297 option_context
.add_option
(opt_sharedir
)
300 redef fun process_options
303 var d
= opt_dir
.value
304 if d
!= null then dir
= d
306 if not opt_nodot
.value
then
307 # Test if dot is runable
308 var res
= sys
.system
("sh -c dot </dev/null >/dev/null 2>&1")
310 stderr
.write
"--no-dot implied since `dot' is not available. Try to install graphviz.\n"
311 opt_nodot
.value
= true
315 sharedir
= opt_sharedir
.value
316 if sharedir
== null then
317 var dir
= once
("NIT_DIR".to_symbol
).environ
319 dir
= "{sys.program_name.dirname}/../share/nitdoc"
320 if dir
.file_exists
then sharedir
= dir
322 dir
= "{dir}/share/nitdoc"
323 if dir
.file_exists
then sharedir
= dir
325 if sharedir
== null then
326 fatal_error
(null, "Error: Cannot locate nitdoc shared files. Uses --sharedir or envvar NIT_DIR.")
328 dir
= "{sharedir.to_s}/scripts/js-facilities.js"
329 if sharedir
== null then
330 fatal_error
(null, "Error: Invalid nitdoc shared files. Check --sharedir or envvar NIT_DIR.")
336 redef fun handle_property_conflict
(lc
, impls
)
338 # THIS IS SO UGLY! See MMVirtualModule
339 if lc
.mmmodule
== self.mainmod
then
340 return # We just accept, so one in impls is arbitrary inherited
346 # A virtual module is used to work as an implicit main module that combine unrelated modules
347 # Since conflict may arrise in a virtual module (the main method for instance) conflicts are disabled
348 class MMVirtualModule
350 init(ctx
: MMContext, mods
: Array[MMModule])
352 # We need to compute the whole metamodel since there is no mmbuilder to do it
353 super(" main".to_symbol
, mods
.first
.directory
, ctx
, new Location(null,0,0,0,0))
354 ctx
.add_module
(self, mods
)
356 self.add_super_module
(m
, 1)
358 self.import_global_classes
359 self.import_local_classes
360 for c
in self.local_classes
do
361 c
.compute_super_classes
363 for c
in self.local_classes
do
368 redef fun require_doc
(dctx
) do return false
371 # Conditionnal part of the text content of a DocContext
373 # Content of the current stage
374 readable var _content
: Array[String] = new Array[String]
376 # Is a normal string already added?
377 readable writable var _validate
: Bool = false
379 # Parent stage is any
380 readable var _parent
: nullable StageContext = null
382 init(parent
: nullable StageContext) do _parent
= parent
386 # Efficiently sort object with their to_s method
387 class AlphaSorter[E
: Object]
388 super AbstractSorter[E
]
389 redef fun compare
(a
, b
)
409 # Keep track of to_s values
410 var _dico
: HashMap[Object, String] = new HashMap[Object, String]
415 # Generalization of metamodel entities
418 fun html_link
(dctx
: DocContext): String is abstract
420 # Return a one liner description
421 fun short_doc
: String do return " "
423 # The doc node from the AST
424 # Return null is none
425 fun doc
: nullable ADoc do return null
430 redef fun html_link
(dctx
) do
431 return "<a href=\"{html_name}.html\
" title=\"{short_doc}\
">{self}</a>"
434 fun require_doc
(dctx
: DocContext): Bool
436 if dctx
.public_only
and not is_toplevel
then return false
440 # Return true if the module is a top-level owner or a top-level module
441 fun is_toplevel
: Bool
443 var pd
= directory
.parent
444 return pd
== null or (pd
.owner
== null and directory
.owner
== self)
447 # Element in the module nesting tree
448 fun mnhe
: PartialOrderElement[MMModule] do return mnhe_
.as(not null)
449 var mnhe_
: nullable PartialOrderElement[MMModule] = null
451 # Element in the top level module importation hierarchy
452 fun tmhe
: PartialOrderElement[MMModule] do return tmhe_
.as(not null)
453 var tmhe_
: nullable PartialOrderElement[MMModule] = null
455 fun toplevel_owner
: MMModule
459 var ds
= m
.mnhe
.direct_smallers
460 if ds
.length
== 0 then return m
461 if ds
.length
== 1 then m
= ds
.first
else abort
465 fun html_name
: String
470 fun direct_owner
: nullable MMModule
473 while d
.owner
== self do d
= d
.parent
.as(not null)
477 # Fill the body for the page associated to the module
478 fun file_page_doc
(dctx
: DocContext)
480 dctx
.add
("<div class=\"menu\
">\n")
482 var mods
= new Array[MMModule]
483 mods
= self.mhe
.greaters
.to_a
487 dctx
.stage
("<nav>\n")
488 dctx
.stage
("<h3>Module Hierarchy</h3>\n")
489 dctx
.stage
("<h4>All dependencies</h4>\n")
492 if not mod
.require_doc
(dctx
) then continue
493 if self.mnhe
<= mod
then continue # do not want nested stuff
494 if mod
.direct_owner
!= null and not mod
.direct_owner
.mnhe
<= self then continue # not in the right nesting
495 dctx
.add
("<li>{mod.html_link(dctx)}</li>")
497 dctx
.stage
("</ul>\n")
499 mods
= self.mhe
.smallers
.to_a
501 dctx
.stage
("<h4>All clients</h4>\n")
504 if not mod
.require_doc
(dctx
) then continue
505 if self.mnhe
<= mod
then continue # do not want nested stuff
506 if mod
.direct_owner
!= null and not mod
.direct_owner
.mnhe
<= self then continue # not in the right nesting
507 dctx
.add
("<li>{mod.html_link(dctx)}</li>")
509 dctx
.stage
("</ul>\n")
510 dctx
.stage
("</nav>\n")
513 if not dctx
.public_only
then
514 mods
= self.mnhe
.direct_greaters
.to_a
517 dctx
.stage
("<nav>\n")
518 dctx
.stage
("<h3>Nested Modules</h3><ul>\n")
520 if not mod
.require_doc
(dctx
) then continue
521 dctx
.add
("<li>{mod.html_link(dctx)}</li>")
523 dctx
.stage
("</ul></nav>\n")
527 dctx
.add
("</div>") # metadata
529 dctx
.add
("<div class=\"content\
">\n")
530 dctx
.add
("<h1>{name}</h1>\n")
531 dctx
.add
("<div class='subtitle'>module ")
532 for m
in mnhe
.smallers
do
533 dctx
.add
("{m.html_link(dctx)}::")
535 dctx
.add
("{self.name}</div>\n")
537 dctx
.add
("<section class='description'>\n")
541 dctx
.add
("<div id=\"description\
">\n")
542 dctx
.add
("<pre>{doc.to_html}</pre>\n")
547 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")
548 var ms
= new Array[nullable MMModule]
550 var m0
: nullable MMModule = self
556 var cla
= new HashSet[MMModule]
558 for m0
in self.mhe
.greaters
do
559 if not m0
.require_doc
(dctx
) then continue
560 if self.visibility_for
(m0
) <= 1 then continue # private or hidden
561 if self.mnhe
<= m0
then continue # do not want nested stuff
562 if m0
.direct_owner
!= null and not m0
.direct_owner
.mnhe
<= self then continue # not in the right nesting
565 for m0
in self.mhe
.smallers
do
566 if not m0
.require_doc
(dctx
) then continue
567 if m0
.visibility_for
(self) <= 1 then continue # private or hidden
568 if m0
.direct_owner
!= null and not m0
.direct_owner
.mnhe
<= self then continue # not in the right nesting
571 for m0
in self.mnhe
.smallers
do
577 op
.append
("subgraph \"cluster_
{m0.name}\
"\{\n")
580 if c
.direct_owner
!= m0
then continue
582 op
.append
("\"{c.name}\
"[shape=box,margin=0.03];\n")
584 op
.append
("\"{c.name}\
"[URL=\"{c.html_name}.html\
"];\n")
588 op
.append
("\"{m0.name}\
"[URL=\"{m0.html_name}.html\
"];\n")
589 for c
in m0
.mhe
.direct_greaters
do
590 if not cla
.has
(c
) then continue
591 op
.append
("\"{m0.name}\
"->\"{c.name}\
";\n")
596 # Close the nesting subgraph
602 for c2
in c
.tmhe
.direct_greaters
do
603 if not cla
.has
(c2
) then continue
604 op
.append
("\"{c.name}\
"->\"{c2.name}\
";\n")
608 dctx
.gen_dot
(op
.to_s
, name
.to_s
, "Dependency graph for module {name}")
609 dctx
.add
("</section>")
611 var clas
= new Array[MMLocalClass]
612 var props
= new HashMap[MMGlobalProperty, Array[MMLocalProperty]]
613 var gprops
= new Array[MMLocalProperty]
616 for g
in m
.global_classes
do
618 if not lc
.require_doc
(dctx
) then continue
619 var im
= g
.intro
.mmmodule
620 if self.visibility_for
(im
) <= 1 then continue # private import or invisible import
622 for lc2
in lc
.crhe
.greaters_and_self
do
623 if not lc2
isa MMSrcLocalClass then continue
624 if not self.mnhe
<= lc2
.mmmodule
then continue # not introduced/redefined here/stolen
627 if not keep
then continue
629 lc
.compute_super_classes
630 for gp
in lc
.global_properties
do
631 if self.visibility_for
(gp
.intro
.local_class
.mmmodule
) <= 1 then continue # private import or invisible import
633 var mp
= lp
.local_class
.mmmodule
634 if not self.mnhe
<= mp
then continue # not introduced/redefined here/stolen
636 if not lp
.require_doc
(dctx
) then continue
637 if props
.has_key
(lp
.global
) then
638 if not props
[lp
.global
].has
(lp
) then
639 props
[lp
.global
].add
(lp
)
642 props
[lp
.global
] = [lp
]
643 gprops
.add
(lp
.global
.intro
)
648 dctx
.add
("<section class=\"module\
">\n")
650 dctx
.stage
("<article class=\"classes filterable\
">\n")
651 dctx
.stage
("<h2>Classes</h2>\n")
655 if self.mnhe
<= lc
.global
.intro
.mmmodule
then
656 dctx
.add
("<li class='intro'><span title='introduced in this module'>I</span> ")
658 dctx
.add
("<li class='redef'><span title='refined in this module'>R</span> ")
660 dctx
.add
("{lc.html_link(dctx)}</li>\n")
662 dctx
.stage
("</ul></article>\n")
666 dctx
.stage
("<article class=\"properties filterable\
">\n")
667 dctx
.stage
("<h2>Properties</h2>\n")
674 if gp
.intro
isa MMAttribute then continue
676 var lpi
= self[gp
.intro
.local_class
.global
][gp
]
679 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")
682 dctx
.add
("<li class='intro'><span title='introduction in this module'>I</span> {lpi.html_name}")
683 dctx
.add
(" ({lpi.local_class})</li>\n")
685 if lps
.length
>= 1 then
688 dctx
.add
("<li class='redef'><span title='redefinition'>R</span> {lp.html_open_link(dctx)}{lp.html_name} ({lp.local_class})</a></li>")
692 dctx
.stage
("</ul></article>\n")
694 dctx
.add
("</section>\n")
698 # Fill the body for the page associated to the full index
699 fun file_index_page_doc
(dctx
: DocContext)
702 dctx
.add
("<h1>Full Index</h1>\n")
704 var clas
= new Array[MMLocalClass]
705 var props
= new HashMap[MMGlobalProperty, Array[MMLocalProperty]]
706 var gprops
= new Array[MMLocalProperty]
707 var mods
= new Array[MMModule]
708 for m
in mhe
.greaters_and_self
do
709 if not m
.require_doc
(dctx
) then continue
712 for g
in global_classes
do
714 if not lc
.require_doc
(dctx
) then continue
716 for gp
in lc
.global_properties
do
718 if not lp
.require_doc
(dctx
) then continue
719 if props
.has_key
(lp
.global
) then
720 if not props
[lp
.global
].has
(lp
) then
721 props
[lp
.global
].add
(lp
)
724 props
[lp
.global
] = [lp
]
725 gprops
.add
(lp
.global
.intro
)
730 dctx
.stage
("<article class=\"modules filterable\
">\n")
731 dctx
.stage
("<h2>Modules</h2>\n")
735 dctx
.add
("<li>{m.html_link(dctx)}</li>")
737 dctx
.stage
("</ul></article>\n")
741 dctx
.stage
("<article class=\"classes filterable\
">\n")
742 dctx
.stage
("<h2>Classes</h2>\n")
746 dctx
.add
("<li>{lc.html_link(dctx)}</li>")
748 dctx
.stage
("</ul></article>\n")
752 dctx
.stage
("<article class=\"properties filterable\
">\n")
753 dctx
.stage
("<h2>Properties</h2>\n")
760 if gp
.intro
isa MMAttribute then continue
762 var lpi
= self[gp
.intro
.local_class
.global
][gp
]
765 dctx
.add
("<li class='intro'><span title='introduction'>I</span> {lpi.html_open_link(dctx)}{lpi.html_name} ({lpi.local_class})</a></li>\n")
766 if lps
.length
>= 1 then
769 dctx
.add
("<li class='redef'><span title='redefinition'>R</span> {lp.html_open_link(dctx)}{lp.html_name} ({lp.local_class})</a></li>\n")
773 dctx
.stage
("</ul></article>\n")
778 redef class MMLocalProperty
780 # Anchor of the property description in the module html file
781 fun html_anchor
: String
783 return "PROP_{local_class}_{cmangle(name)}"
786 fun html_open_link
(dctx
: DocContext): String
788 if not require_doc
(dctx
) then print
"not required {self}"
789 var title
= "{html_name}{signature.to_s}"
790 if short_doc
!= " " then
791 title
+= " #{short_doc}"
793 return "<a href=\"{local_class.html_name}.html
#{html_anchor}\" title=\"{title}\">"
796 fun html_name
: String
798 return self.name
.to_s
.html_escape
801 redef fun html_link
(dctx
)
803 if not require_doc
(dctx
) then print
"not required {self}"
804 var title
= "{html_name}{signature.to_s}"
805 if short_doc
!= " " then
806 title
+= " #{short_doc}"
808 return "<a href=\"{local_class.html_name}.html
#{html_anchor}\" title=\"{title}\">{html_name}</a>"
811 fun html_link_special
(dctx
: DocContext, lc
: MMLocalClass): String
813 if not require_doc
(dctx
) then print
"not required {self}"
814 var title
= "{html_name}{signature_for(lc.get_type)}"
815 if short_doc
!= " " then
816 title
+= " #{short_doc}"
818 return "<a href=\"{lc.html_name}.html
#{html_anchor}\" title=\"{title}\">{html_name}</a>"
821 # Kind of property (fun, attr, etc.)
822 fun kind
: String is abstract
829 else if global
.intro
== self then
832 return global
.intro
.short_doc
839 if n
== null or not n
isa APropdef then
846 if d
.n_comment
.is_empty
then
853 # The most specific module in the nesting hierarchy that exports the intro of self
854 fun intro_module
: MMModule
856 var m
= global
.intro
.mmmodule
857 var mo
= m
.direct_owner
858 while mo
!= null and mo
.visibility_for
(m
) >= 2 do
865 # Is the intro of self exported by the top-level module ?
866 fun is_toplevel
: Bool
869 return m
== m
.toplevel_owner
872 # Return true if the global property must be documented according to the visibility configured
873 fun require_doc
(dctx
: DocContext): Bool
875 if global
.visibility_level
== 3 and not dctx
.with_private
then return false # Private
876 if dctx
.public_only
then
878 if m
!= m
.toplevel_owner
then return false # Unexported
883 # Document the global property in the global class lc
884 fun full_documentation
(dctx
: DocContext, lc
: MMLocalClass)
886 var visibility
: String
887 if global
.visibility_level
== 1 then
888 visibility
= "public"
889 else if global
.visibility_level
== 2 then
890 visibility
= "protected"
891 else if global
.visibility_level
== 3 then
892 visibility
= "private"
897 var intro_class
= global
.intro
.local_class
898 var is_redef
= local_class
.global
!= intro_class
.global
or local_class
.mmmodule
.toplevel_owner
!= intro_class
.mmmodule
.toplevel_owner
900 dctx
.add
("<article id=\"{html_anchor}\
" class=\"{kind} {visibility} {if is_redef then "redef" else ""}\
">\n")
901 dctx
.add
("<h3 class=\"signature\
">{html_name}{signature.to_html(dctx, true)}</h3>\n")
902 dctx
.add
("<div class=\"info\
">\n")
903 #dctx.add("<p>LP: {self.mmmodule.html_link(dctx)}::{self.local_class.html_link(dctx)}::{self.html_link(dctx)}</p>")
908 if not is_toplevel
then
909 dctx
.add
("(unexported) ")
911 if global
.visibility_level
== 2 then
912 dctx
.add
("protected ")
913 else if global
.visibility_level
== 3 then
917 dctx
.add
(" {intro_class.mmmodule.toplevel_owner.name}")
918 if intro_class
.global
== lc
.global
then
919 dctx
.add
("::{lc.name}")
921 dctx
.add
("::{mmmodule[intro_class.global].html_link(dctx)}")
924 dctx
.add
("::{mmmodule[intro_class.global][global].html_link(dctx)}")
926 dctx
.add
("::{html_name}")
930 dctx
.add
("<div class=\"description\
">")
932 # Collect all refinement of the global property in the same global property
933 var lps
= new Array[MMLocalProperty]
934 for l
in prhe
.greaters_and_self
do
939 if global
.intro
.doc
!= null then
941 if lp
.doc
== null then introdoc
= true
945 dctx
.add
("<pre>{global.intro.doc.to_html}</pre>")
948 var tlmods
= new Array[MMModule]
950 var bm
= lp
.mmmodule
.toplevel_owner
951 var lcm
= lc
.global
.intro
.mmmodule
952 if lcm
.mhe
< lp
.mmmodule
then bm
= lcm
.toplevel_owner
953 if not tlmods
.has
(bm
) then tlmods
.add
(bm
)
957 # Document the top level property for the current top level module
959 if tm
.global_classes
.has
(lc
.global
) then
960 tlp
= tm
[lc
.global
][self.global
]
962 else if tm
.global_classes
.has
(self.local_class
.global
) then
963 # Self is the inherited property. Process it
964 tlp
= tm
[self.local_class
.global
][self.global
]
967 # We skip this module since the props defined by the module is
971 var tlcm
= lc
.global
.intro
.mmmodule
.toplevel_owner
972 if not tlcm
.mhe
<= tm
then
973 dctx
.add
("<h4>In module {tm.html_link(dctx)} :</h4>")
976 #dctx.add("<p>TLP: {tm} x {lc} : {tlp.full_name}</p>")
979 if doc
!= null and (not introdoc
or global
.intro
.doc
!= doc
) then
980 dctx
.add
("<pre>{doc.to_html}</pre>")
983 if tlp
.local_class
.global
!= lc
.global
then
984 dctx
.add
("inherited from {tlp.local_class.html_link(dctx)} ")
986 if tm
!= tlp
.mmmodule
then
987 dctx
.add
("defined by the module {tlp.mmmodule.html_link(dctx)} ")
996 dctx
.stage
(". previously defined by:")
998 var tl
= lp
.mmmodule
.toplevel_owner
999 if tl
!= tm
then continue
1000 if lp
== tlp
then continue
1001 dctx
.add
(" {lp.mmmodule.html_link(dctx)}")
1002 if lp
.local_class
.global
!= lc
.global
then
1003 dctx
.add
(" for {lp.local_class.html_link(dctx)}")
1013 #if doc != null and (not introdoc or global.intro.doc != doc) then
1014 # dctx.add("<pre>{doc.to_html}</pre>")
1021 dctx
.add
("</article>")
1024 redef class MMMethod
1025 redef fun kind
do return if global
.is_init
then "init" else "fun"
1027 redef class MMAttribute
1028 redef fun kind
do return "var"
1030 redef class MMTypeProperty
1031 redef fun kind
do return "type"
1034 redef class MMSrcModule
1048 if n
.n_moduledecl
== null then
1051 var np
= n
.n_moduledecl
1056 if d
.n_comment
.is_empty
then
1065 # Html transcription of the doc
1068 var res
= new Buffer
1069 for c
in n_comment
do
1070 res
.append
(c
.text
.substring_from
(1))
1072 return res
.to_s
.html_escape
1075 # Oneliner transcription of the doc
1078 return n_comment
.first
.text
.substring_from
(1).html_escape
1082 redef class MMLocalClass
1085 # Anchor of the class description in the module html file
1086 fun html_anchor
: String do return "CLASS_{self}"
1088 fun html_name
: String do return "{self}"
1090 redef fun html_link
(dctx
)
1092 if not require_doc
(dctx
) then print
"{dctx.filename}: not required {self}"
1093 return "<a href=\"{html_name}.html\
" title=\"{short_doc}\
">{self}</a>"
1096 redef fun short_doc
do return global
.intro
.short_doc
1098 redef fun doc
do return global
.intro
.doc
1102 if global
.is_interface
then
1104 else if global
.is_abstract
then
1105 return "abstract class"
1106 else if global
.is_enum
then
1113 # The most specific module in the nesting hierarchy that exports the intro of self
1114 fun intro_module
: MMModule
1116 var m
= global
.intro
.mmmodule
1117 var mo
= m
.direct_owner
1118 while mo
!= null and mo
.visibility_for
(m
) >= 2 do
1125 fun menu_link
(dctx
: DocContext, p
: MMLocalProperty)
1127 if p
.local_class
.global
!= self.global
then
1128 if p
.global
.intro
.local_class
.name
== "Object".to_symbol
then return
1129 if p
.global
.is_init
or p
isa MMTypeProperty then
1130 dctx
.add
("<li class='inherit'><span title='Inherited'>H</span> {p.html_link_special(dctx, self)}</li>\n")
1132 dctx
.add
("<li class='inherit'><span title='Inherited'>H</span> {p.html_link(dctx)}</li>\n")
1134 else if p
.global
.intro
.local_class
.global
== self.global
then
1135 dctx
.add
("<li class='intro'><span title='Introduced'>I</span> {p.html_link_special(dctx, self)}</li>\n")
1137 dctx
.add
("<li class='redef'><span title='Redefined'>R</span> {p.html_link_special(dctx, self)}</li>\n")
1141 # Return true if the global class must be documented according to the visibility configured
1142 fun require_doc
(dctx
: DocContext): Bool
1144 if global
.visibility_level
== 3 and not dctx
.with_private
then return false # Private
1145 if dctx
.public_only
then
1146 var m
= intro_module
1147 if m
!= m
.toplevel_owner
then return false # Unexported
1152 # Fill the body for the page associated to the global class
1153 fun file_page_doc
(dctx
: DocContext)
1155 dctx
.add
("<div class=\"menu\
">\n")
1157 var props
= new Array[MMLocalProperty]
1158 var inh
= new HashMap[MMLocalClass, Array[MMLocalProperty]]
1159 var inhs
= new Array[MMLocalClass]
1160 for g
in global_properties
do
1162 if not p
.require_doc
(dctx
) then continue
1163 if p
.local_class
.global
== global
or g
.is_init_for
(self) or p
isa MMTypeProperty then
1166 var lc
= mmmodule
[p
.local_class
.global
]
1167 if inh
.has_key
(lc
) then
1178 dctx
.add
("<nav class=\"properties filterable\
">\n")
1179 dctx
.add
("<h3>Properties</h3>\n")
1181 dctx
.stage
("<h4>Virtual Types</h4>\n<ul>\n")
1183 if p
isa MMTypeProperty then
1187 dctx
.stage
("</ul>\n")
1190 dctx
.stage
("<h4>Constructors</h4>\n<ul>\n")
1192 if p
.global
.is_init_for
(self) then
1196 dctx
.stage
("</ul>\n")
1199 dctx
.stage
("<h4>Methods</h4>\n<ul>\n")
1201 if not p
.global
.is_init
and p
isa MMMethod then
1205 dctx
.stage
("</ul>\n")
1207 dctx
.add
("</nav>\n")
1209 dctx
.add
("<nav class=\"inheritance filterable\
">\n")
1210 dctx
.add
("<h3>Inheritance</h3>\n")
1211 dctx
.add
("<h4>Superclasses</h4>\n<ul>\n")
1212 for lc
in cshe
.linear_extension
do
1213 if lc
== self then continue
1214 if not lc
.require_doc
(dctx
) then continue
1215 dctx
.add
("<li>{lc.html_link(dctx)}</li>\n")
1218 if cshe
.smallers
.length
== 0 then
1219 dctx
.add
("<h4>No Known Subclasses</h4>\n")
1220 else if cshe
.smallers
.length
<= 100 then
1221 dctx
.add
("<h4>Subclasses</h4>\n")
1223 for lc
in cshe
.smallers
do
1224 if not lc
.require_doc
(dctx
) then continue
1225 dctx
.add
("<li>{lc.html_link(dctx)}</li>\n")
1228 else if cshe
.direct_smallers
.length
<= 100 then
1229 dctx
.add
("<h4>Direct Subclasses Only</h4>\n<ul>\n")
1230 for lc
in cshe
.direct_smallers
do
1231 if not lc
.require_doc
(dctx
) then continue
1232 dctx
.add
("<li>{lc.html_link(dctx)}</li>\n")
1236 dctx
.add
("<h4>Too much Subclasses to list</h4>\n")
1238 dctx
.add
("</nav>\n")
1240 dctx
.add
("</div>\n")
1243 dctx
.add
("<div class=\"content\
">\n")
1244 dctx
.add
("<h1>{name}</h1>\n")
1245 dctx
.add
("<div class='subtitle'>")
1246 if global
.visibility_level
== 2 then
1248 else if global
.visibility_level
== 3 then
1249 dctx
.add
("private ")
1250 else if self.global
.intro
.mmmodule
.toplevel_owner
.visibility_for
(self.global
.intro
.mmmodule
) <= 1 then
1251 dctx
.add
("(unexported) ")
1253 dctx
.add
("{kind} {global.intro.mmmodule.toplevel_owner.html_link(dctx)}::{name}</div>")
1255 dctx
.add
("<section class=\"description\
">\n")
1258 dctx
.add
("<pre>{doc.to_html}</pre>\n")
1261 var cla
= new HashSet[MMLocalClass]
1262 var sm
= new HashSet[MMLocalClass]
1263 var sm2
= new HashSet[MMLocalClass]
1265 while cla
.length
+ sm
.length
< 10 and sm
.length
> 0 do
1269 sm2
.add_all
(x
.cshe
.direct_smallers
)
1275 cla
.add_all
(cshe
.greaters_and_self
)
1278 var name
= "class_{name}"
1279 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")
1282 op
.append
("\"{c.name}\
"[shape=box,margin=0.03];\n")
1284 op
.append
("\"{c.name}\
"[URL=\"{c.html_name}.html\
"];\n")
1286 for c2
in c
.cshe
.direct_greaters
do
1287 if not cla
.has
(c2
) then continue
1288 op
.append
("\"{c.name}\
"->\"{c2.name}\
";\n")
1290 if not c
.cshe
.direct_smallers
.is_empty
then
1292 for c2
in c
.cshe
.direct_smallers
do
1293 if cla
.has
(c2
) then others
= false
1296 op
.append
("\"{c.name}...\
"[label=\"\
"];\n")
1297 op
.append
("\"{c.name}...\
"->\"{c.name}\
"[style=dotted];\n")
1302 dctx
.gen_dot
(op
.to_s
, name
.to_s
, "Inheritance graph for class {name}")
1305 var mods
= new Array[MMModule]
1306 mods
.add
(global
.intro
.mmmodule
.toplevel_owner
)
1307 for lc
in crhe
.greaters
do
1308 if not lc
isa MMSrcLocalClass then continue
1309 var m
= lc
.mmmodule
.toplevel_owner
1310 if not mods
.has
(m
) then mods
.add
(m
)
1314 if m
== global
.intro
.mmmodule
.toplevel_owner
then
1315 dctx
.add
("<p>Introduced by {m.html_link(dctx)}")
1317 dctx
.add
("<p>Refined by {m.html_link(dctx)}")
1320 dctx
.stage
(". Definition in:")
1321 for lc
in crhe
.greaters
do
1322 if lc
.mmmodule
.toplevel_owner
!= m
then continue
1323 dctx
.add
(" {lc.mmmodule.html_link(dctx)}")
1324 assert lc
isa MMSrcLocalClass
1327 dctx
.show_source
(n
.location
)
1333 dctx
.add
("</section>\n")
1336 dctx
.stage
("<section class=\"types\
">\n")
1337 dctx
.stage
("<h2>Formal and Virtual Types</h2>\n")
1338 for i
in [0..arity
[ do
1339 var f
= get_formal
(i
)
1340 f
.full_documentation
(dctx
, self)
1343 if not p
isa MMTypeProperty then continue
1344 p
.full_documentation
(dctx
, self)
1346 dctx
.stage
("</section>\n")
1350 dctx
.stage
("<section class=\"constructors\
">\n")
1351 dctx
.stage
("<h2 class=\"section-header\
">Constructors</h2>\n")
1353 if not p
.global
.is_init_for
(self) then continue
1354 p
.full_documentation
(dctx
, self)
1356 dctx
.stage
("</section>\n")
1360 dctx
.stage
("<section class=\"methods\
">\n")
1361 dctx
.stage
("<h2 class=\"section-header\
">Methods</h2>\n")
1363 if p
.global
.is_init
then continue
1364 if p
.local_class
.global
!= self.global
then continue
1365 if not p
isa MMMethod then continue
1366 p
.full_documentation
(dctx
, self)
1368 if not inhs
.is_empty
then
1370 dctx
.stage
("<h3>Inherited Methods</h3>\n")
1373 dctx
.stage
("<p>Defined in {lc.html_link(dctx)}:")
1375 if p
.global
.is_init
then continue
1376 if not p
isa MMMethod then continue
1377 dctx
.add
(" {p.html_link(dctx)}")
1384 dctx
.add
("</section>\n")
1386 dctx
.add
("</div> <!-- end class {name} -->\n")
1390 redef class MMSrcLocalClass
1396 else if global
.intro
== self then
1399 var bc
= global
.intro
1407 if not n
isa AStdClassdef then
1414 if d
.n_comment
.is_empty
then
1422 redef class MMSignature
1423 # Htlm transcription of the signature (with nested links)
1424 fun to_html
(dctx
: DocContext, with_closure
: Bool): String
1426 var res
= new Buffer
1429 for i
in [0..arity
[ do
1430 if i
> 0 then res
.append
(", ")
1431 res
.append
(self.params
[i
].name
.to_s
)
1433 res
.append
(self[i
].html_link
(dctx
))
1434 if self.vararg_rank
== i
then
1440 if return_type
!= null then
1442 res
.append
(return_type
.html_link
(dctx
))
1444 if with_closure
then
1445 for c
in closures
do
1447 if c
.is_optional
then res
.append
("[")
1448 if c
.is_break
then res
.append
("break ")
1449 res
.append
("!{c.name}")
1450 res
.append
(c
.signature
.to_html
(dctx
, false))
1451 if c
.is_optional
then res
.append
("]")
1459 # Htlm transcription of the type (with nested links)
1460 fun html_link
(dctx
: DocContext): String do return to_s
1463 redef class MMTypeSimpleClass
1464 redef fun html_link
(dctx
) do return local_class
.html_link
(dctx
)
1467 redef class MMTypeGeneric
1468 redef fun html_link
(dctx
)
1470 var res
= new Buffer
1471 res
.append
(local_class
.html_link
(dctx
))
1473 res
.append
(params
[0].html_link
(dctx
))
1474 for i
in [1..params
.length
[ do
1476 res
.append
(params
[i
].html_link
(dctx
))
1483 redef class MMTypeFormalParameter
1484 fun html_anchor
: String
1486 return "FT_{local_class}_{cmangle(name)}"
1488 redef fun html_link
(dctx
)
1490 return "<a href=\"#{html_anchor}\">{name}</a>"
1492 fun full_documentation
(dctx
: DocContext, lc
: MMLocalClass)
1494 dctx
.add
("<article id=\"{html_anchor}\
">\n")
1495 dctx
.add
("<h3 class=\"signature\
">{name}: {bound.html_link(dctx)}</h3>\n")
1496 dctx
.add
("<div class=\"info\
">")
1497 dctx
.add
("formal generic type")
1499 dctx
.add
("</article>")
1503 redef class MMNullableType
1504 redef fun html_link
(dctx
) do return "nullable " + as_notnull
.html_link
(dctx
)
1507 redef class MMVirtualType
1508 redef fun html_link
(dctx
) do return property
.html_link
(dctx
)
1511 var c
= new DocContext