23cf6b8c077b94080983a189a9967c3ba74eae48
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_nodot
: OptionBool = new OptionBool("Do not generate graphes with graphviz", "--no-dot")
90 if self._opt_public
.value
== true then return true
94 # The current processed filename
97 # The main virtual module
98 var mainmod
: nullable MMVirtualModule
100 redef fun perform_work
(mods
)
102 mainmod
= new MMVirtualModule(self, mods
)
106 # Compute the set of direct owned nested modules
107 var owns
= new HashMap[MMModule, Array[MMModule]]
108 for mod
in modules
do
109 owns
[mod
] = new Array[MMModule]# [mod]
111 for mod
in modules
do
112 if mod
== mainmod
then continue
113 var d
= mod
.directory
116 if o
!= null and o
!= mod
then
120 if dp
== null or dp
== d
then break
125 # Builds the various module hierarchies
126 var mnh
= new PartialOrder[MMModule] # nested module hierarchy
127 var tmh
= new PartialOrder[MMModule] # top module import hierrchy
128 var ms
= mainmod
.mhe
.linear_extension
.reversed
130 if ms
== mainmod
then continue
131 m
.mnhe_
= mnh
.add
(m
, owns
[m
])
132 var pub
= new Array[MMModule]
133 for m2
in m
.mhe
.greaters
do
134 if m2
.toplevel_owner
!= m2
and m2
.toplevel_owner
!= m
.toplevel_owner
then continue
135 if m
.mnhe
<= m2
then continue
136 if m
.visibility_for
(m2
) <= 0 then
138 else if m
.visibility_for
(m2
) == 1 then
143 m
.tmhe_
= tmh
.add
(m
, pub
)
146 var head
= "<meta charset=\"utf-8\
">" +
147 "<script type=\"text
/javascript\
" src=\"http
://moz-concept
.com
/nitdoc
/scripts
/jquery-1
.7
.1.min
.js\
"></script>\n" +
148 "<script type=\"text
/javascript\
" src=\"http
://moz-concept
.com
/nitdoc
/scripts
/js-facilities
.js\
"></script>\n" +
149 "<link rel=\"stylesheet\
" href=\"http
://moz-concept
.com
/nitdoc
/styles
/main
.css\
" type=\"text
/css\
" media=\"screen\
" />"
151 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"
154 self.filename
= "index.html"
156 add
("<!DOCTYPE html>")
157 add
("<html><head>{head}<title>Index</title></head><body>\n")
159 add
("<div class=\"page\
">")
160 add
("<div class=\"content fullpage\
">")
161 add
("<h1>Modules</h1>\n<article class='overview'><ul>")
162 var modss
= mainmod
.mhe
.greaters_and_self
.to_a
165 if not mod
.is_toplevel
then continue
166 if not mod
.require_doc
(self) then continue
167 assert mod
isa MMSrcModule
168 add
("<li>{mod.html_link(self)} {mod.short_doc}</li>")
174 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")
176 if not mod
.is_toplevel
then continue
177 if not mod
.require_doc
(self) then continue
178 op
.append
("\"{mod.name}\
"[URL=\"{mod.html_name}.html\
"];\n")
179 for mod2
in mod
.tmhe
.direct_greaters
do
180 if not modss
.has
(mod2
) then continue
181 op
.append
("\"{mod.name}\
"->\"{mod2.name}\
";\n")
185 self.gen_dot
(op
.to_s
, "dep", "Modules hierarchy")
186 add
("</article></div>")
187 add
("<div class='clear'></div>")
189 add
("</body></html>\n")
190 write_to
("{dir}/index.html")
192 # Generate page for modules
193 for mod
in modules
do
194 if mod
== mainmod
then continue
195 assert mod
isa MMSrcModule
196 if not mod
.require_doc
(self) then continue
197 self.filename
= mod
.html_name
198 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"
200 add
("<!DOCTYPE html>")
201 add
("<html><head>{head}<title>Module {mod.name}</title></head><body>\n")
203 add
("<div class=\"page\
">")
204 mod
.file_page_doc
(self)
206 add
("</body></html>\n")
207 write_to
("{dir}/{mod.html_name}.html")
210 # Generate pages for global classes
211 for c
in mainmod
.local_classes
do
212 if not c
.require_doc
(self) then continue
213 self.filename
= c
.html_name
214 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"
216 add
("<!DOCTYPE html>")
217 add
("<html><head>{head}<title>Class {c.name}</title></head><body>\n")
219 add
("<div class=\"page\
">")
220 c
.file_page_doc
(self)
222 add
("</body></html>\n")
223 write_to
("{dir}/{c.html_name}.html")
226 self.filename
= "fullindex"
227 action_bar
= "<header><nav class='main'><ul><li><a href='./'>Overview</a></li><li class=\"current\
">Full Index</li></ul></nav></header>\n"
229 add
("<!DOCTYPE html>")
230 add
("<html><head>{head}<title>Full Index</title></head><body>\n")
232 add
("<div class=\"page\
">")
233 add
("<div class=\"content fullpage\
">")
234 mainmod
.file_index_page_doc
(self)
237 add
("</body></html>\n")
238 write_to
("{dir}/full-index.html")
242 # Add a (source) link fo a given location
243 fun show_source
(l
: Location)
245 var s
= opt_source
.value
247 add
("in #{l.file.filename.simplify_path}")
249 # THIS IS JUST UGLY ! (but there is no replace yet)
250 var x
= s
.split_with
("%f")
251 s
= x
.join
(l
.file
.filename
.simplify_path
)
252 x
= s
.split_with
("%l")
253 s
= x
.join
(l
.line_start
.to_s
)
254 x
= s
.split_with
("%L")
255 s
= x
.join
(l
.line_end
.to_s
)
256 add
(" (<a href=\"{s}\
">show code</a>)")
260 # Generate a clicable graphiz image using a dot content.
261 # `name' refer to the filename (without extension) and the id name of the map.
262 # `name' must also match the name of the graph in the dot content (eg. digraph NAME {...)
263 fun gen_dot
(dot
: String, name
: String, alt
: String)
265 if opt_nodot
.value
then return
266 var f
= new OFStream.open
("{self.dir}/{name}.dot")
269 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 ; \}")
270 self.add
("<article class=\"graph\
"><img src=\"{name}.png\
" usemap=\"#{name}\" style=\"margin:auto\" alt=\"{alt}\"/></article>")
271 var fmap
= new IFStream.open
("{self.dir}/{name}.map")
272 self.add
(fmap
.read_all
)
281 option_context
.add_option
(opt_public
)
282 option_context
.add_option
(opt_dir
)
283 option_context
.add_option
(opt_source
)
284 option_context
.add_option
(opt_nodot
)
287 redef fun process_options
290 var d
= opt_dir
.value
291 if d
!= null then dir
= d
293 if not opt_nodot
.value
then
294 # Test if dot is runable
295 var res
= sys
.system
("sh -c dot </dev/null >/dev/null 2>&1")
297 stderr
.write
"--no-dot implied since `dot' is not available. Try to install graphviz.\n"
298 opt_nodot
.value
= true
303 redef fun handle_property_conflict
(lc
, impls
)
305 # THIS IS SO UGLY! See MMVirtualModule
306 if lc
.mmmodule
== self.mainmod
then
307 return # We just accept, so one in impls is arbitrary inherited
314 # Replace all occurence of pattern ith string
315 fun replace
(p
: Pattern, string
: String): String
317 return self.split_with
(p
).join
(string
)
320 # Escape the following characters < > & and " with their html counterpart
321 fun html_escape
: String
324 if ret
.has
('&') then ret
= ret
.replace
('&', "&")
325 if ret
.has
('<') then ret
= ret
.replace
('<', "<")
326 if ret
.has
('>') then ret
= ret
.replace
('>', ">")
327 if ret
.has
('"') then ret
= ret
.replace
('"', """)
331 # Remove "/./", "//" and "bla/../"
332 fun simplify_path
: String
334 var a
= self.split_with
("/")
335 var a2
= new Array[String]
337 if x
== "." then continue
338 if x
== "" and not a2
.is_empty
then continue
339 if x
== ".." and not a2
.is_empty
then
349 # A virtual module is used to work as an implicit main module that combine unrelated modules
350 # Since conflict may arrise in a virtual module (the main method for instance) conflicts are disabled
351 class MMVirtualModule
353 init(ctx
: MMContext, mods
: Array[MMModule])
355 # We need to compute the whole metamodel since there is no mmbuilder to do it
356 super(" main".to_symbol
, mods
.first
.directory
, ctx
, new Location(null,0,0,0,0))
357 ctx
.add_module
(self, mods
)
359 self.add_super_module
(m
, 1)
361 self.import_global_classes
362 self.import_local_classes
363 for c
in self.local_classes
do
364 c
.compute_super_classes
366 for c
in self.local_classes
do
371 redef fun require_doc
(dctx
) do return false
374 # Conditionnal part of the text content of a DocContext
376 # Content of the current stage
377 readable var _content
: Array[String] = new Array[String]
379 # Is a normal string already added?
380 readable writable var _validate
: Bool = false
382 # Parent stage is any
383 readable var _parent
: nullable StageContext = null
385 init(parent
: nullable StageContext) do _parent
= parent
389 # Efficiently sort object with their to_s method
390 class AlphaSorter[E
: Object]
391 super AbstractSorter[E
]
392 redef fun compare
(a
, b
)
412 # Keep track of to_s values
413 var _dico
: HashMap[Object, String] = new HashMap[Object, String]
418 # Generalization of metamodel entities
421 fun html_link
(dctx
: DocContext): String is abstract
423 # Return a one liner description
424 fun short_doc
: String do return " "
426 # The doc node from the AST
427 # Return null is none
428 fun doc
: nullable ADoc do return null
433 redef fun html_link
(dctx
) do
434 return "<a href=\"{html_name}.html\
" title=\"{short_doc}\
">{self}</a>"
437 fun require_doc
(dctx
: DocContext): Bool
439 if dctx
.public_only
and not is_toplevel
then return false
443 # Return true if the module is a top-level owner or a top-level module
444 fun is_toplevel
: Bool
446 var pd
= directory
.parent
447 return pd
== null or (pd
.owner
== null and directory
.owner
== self)
450 # Element in the module nesting tree
451 fun mnhe
: PartialOrderElement[MMModule] do return mnhe_
.as(not null)
452 var mnhe_
: nullable PartialOrderElement[MMModule] = null
454 # Element in the top level module importation hierarchy
455 fun tmhe
: PartialOrderElement[MMModule] do return tmhe_
.as(not null)
456 var tmhe_
: nullable PartialOrderElement[MMModule] = null
458 fun toplevel_owner
: MMModule
462 var ds
= m
.mnhe
.direct_smallers
463 if ds
.length
== 0 then return m
464 if ds
.length
== 1 then m
= ds
.first
else abort
468 fun html_name
: String
473 fun direct_owner
: nullable MMModule
476 while d
.owner
== self do d
= d
.parent
.as(not null)
480 # Fill the body for the page associated to the module
481 fun file_page_doc
(dctx
: DocContext)
483 dctx
.add
("<div class=\"menu\
">\n")
485 var mods
= new Array[MMModule]
486 mods
= self.mhe
.greaters
.to_a
490 dctx
.stage
("<nav>\n")
491 dctx
.stage
("<h3>Module Hierarchy</h3>\n")
492 dctx
.stage
("<h4>All dependencies</h4>\n")
495 if not mod
.require_doc
(dctx
) then continue
496 if self.mnhe
<= mod
then continue # do not want nested stuff
497 if mod
.direct_owner
!= null and not mod
.direct_owner
.mnhe
<= self then continue # not in the right nesting
498 dctx
.add
("<li>{mod.html_link(dctx)}</li>")
500 dctx
.stage
("</ul>\n")
502 mods
= self.mhe
.smallers
.to_a
504 dctx
.stage
("<h4>All clients</h4>\n")
507 if not mod
.require_doc
(dctx
) then continue
508 if self.mnhe
<= mod
then continue # do not want nested stuff
509 if mod
.direct_owner
!= null and not mod
.direct_owner
.mnhe
<= self then continue # not in the right nesting
510 dctx
.add
("<li>{mod.html_link(dctx)}</li>")
512 dctx
.stage
("</ul>\n")
513 dctx
.stage
("</nav>\n")
516 if not dctx
.public_only
then
517 mods
= self.mnhe
.direct_greaters
.to_a
520 dctx
.stage
("<nav>\n")
521 dctx
.stage
("<h3>Nested Modules</h3><ul>\n")
523 if not mod
.require_doc
(dctx
) then continue
524 dctx
.add
("<li>{mod.html_link(dctx)}</li>")
526 dctx
.stage
("</ul></nav>\n")
530 dctx
.add
("</div>") # metadata
532 dctx
.add
("<div class=\"content\
">\n")
533 dctx
.add
("<h1>{name}</h1>\n")
534 dctx
.add
("<div class='subtitle'>module ")
535 for m
in mnhe
.smallers
do
536 dctx
.add
("{m.html_link(dctx)}::")
538 dctx
.add
("{self.name}</div>\n")
540 dctx
.add
("<section class='description'>\n")
544 dctx
.add
("<div id=\"description\
">\n")
545 dctx
.add
("<pre>{doc.to_html}</pre>\n")
550 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")
551 var ms
= new Array[nullable MMModule]
553 var m0
: nullable MMModule = self
559 var cla
= new HashSet[MMModule]
561 for m0
in self.mhe
.greaters
do
562 if not m0
.require_doc
(dctx
) then continue
563 if self.visibility_for
(m0
) <= 1 then continue # private or hidden
564 if self.mnhe
<= m0
then continue # do not want nested stuff
565 if m0
.direct_owner
!= null and not m0
.direct_owner
.mnhe
<= self then continue # not in the right nesting
568 for m0
in self.mhe
.smallers
do
569 if not m0
.require_doc
(dctx
) then continue
570 if m0
.visibility_for
(self) <= 1 then continue # private or hidden
571 if m0
.direct_owner
!= null and not m0
.direct_owner
.mnhe
<= self then continue # not in the right nesting
574 for m0
in self.mnhe
.smallers
do
580 op
.append
("subgraph \"cluster_
{m0.name}\
"\{\n")
583 if c
.direct_owner
!= m0
then continue
585 op
.append
("\"{c.name}\
"[shape=box,margin=0.03];\n")
587 op
.append
("\"{c.name}\
"[URL=\"{c.html_name}.html\
"];\n")
591 op
.append
("\"{m0.name}\
"[URL=\"{m0.html_name}.html\
"];\n")
592 for c
in m0
.mhe
.direct_greaters
do
593 if not cla
.has
(c
) then continue
594 op
.append
("\"{m0.name}\
"->\"{c.name}\
";\n")
599 # Close the nesting subgraph
605 for c2
in c
.tmhe
.direct_greaters
do
606 if not cla
.has
(c2
) then continue
607 op
.append
("\"{c.name}\
"->\"{c2.name}\
";\n")
611 dctx
.gen_dot
(op
.to_s
, name
.to_s
, "Dependency graph for module {name}")
612 dctx
.add
("</section>")
614 var clas
= new Array[MMLocalClass]
615 var props
= new HashMap[MMGlobalProperty, Array[MMLocalProperty]]
616 var gprops
= new Array[MMLocalProperty]
619 for g
in m
.global_classes
do
621 if not lc
.require_doc
(dctx
) then continue
622 var im
= g
.intro
.mmmodule
623 if self.visibility_for
(im
) <= 1 then continue # private import or invisible import
625 for lc2
in lc
.crhe
.greaters_and_self
do
626 if not lc2
isa MMSrcLocalClass then continue
627 if not self.mnhe
<= lc2
.mmmodule
then continue # not introduced/redefined here/stolen
630 if not keep
then continue
632 for gp
in lc
.global_properties
do
633 if self.visibility_for
(gp
.intro
.local_class
.mmmodule
) <= 1 then continue # private import or invisible import
635 var mp
= lp
.local_class
.mmmodule
636 if not self.mnhe
<= mp
then continue # not introduced/redefined here/stolen
638 if not lp
.require_doc
(dctx
) then continue
639 if props
.has_key
(lp
.global
) then
640 if not props
[lp
.global
].has
(lp
) then
641 props
[lp
.global
].add
(lp
)
644 props
[lp
.global
] = [lp
]
645 gprops
.add
(lp
.global
.intro
)
650 dctx
.add
("<section class=\"module\
">\n")
652 dctx
.stage
("<article class=\"classes filterable\
">\n")
653 dctx
.stage
("<h2>Classes</h2>\n")
657 if self.mnhe
<= lc
.global
.intro
.mmmodule
then
658 dctx
.add
("<li class='intro'><span title='introduced in this module'>I</span> ")
660 dctx
.add
("<li class='redef'><span title='refined in this module'>R</span> ")
662 dctx
.add
("{lc.html_link(dctx)}</li>\n")
664 dctx
.stage
("</ul></article>\n")
668 dctx
.stage
("<article class=\"properties filterable\
">\n")
669 dctx
.stage
("<h2>Properties</h2>\n")
676 if gp
.intro
isa MMAttribute then continue
678 var lpi
= self[gp
.intro
.local_class
.global
][gp
]
681 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")
684 dctx
.add
("<li class='intro'><span title='introduction in this module'>I</span> {lpi.html_name}")
685 dctx
.add
(" ({lpi.local_class})</li>\n")
687 if lps
.length
>= 1 then
690 dctx
.add
("<li class='redef'><span title='redefinition'>R</span> {lp.html_open_link(dctx)}{lp.html_name} ({lp.local_class})</a></li>")
694 dctx
.stage
("</ul></article>\n")
696 dctx
.add
("</section>\n")
700 # Fill the body for the page associated to the full index
701 fun file_index_page_doc
(dctx
: DocContext)
704 dctx
.add
("<h1>Full Index</h1>\n")
706 var clas
= new Array[MMLocalClass]
707 var props
= new HashMap[MMGlobalProperty, Array[MMLocalProperty]]
708 var gprops
= new Array[MMLocalProperty]
709 var mods
= new Array[MMModule]
710 for m
in mhe
.greaters_and_self
do
711 if not m
.require_doc
(dctx
) then continue
714 for g
in global_classes
do
716 if not lc
.require_doc
(dctx
) then continue
718 for gp
in lc
.global_properties
do
720 if not lp
.require_doc
(dctx
) then continue
721 if props
.has_key
(lp
.global
) then
722 if not props
[lp
.global
].has
(lp
) then
723 props
[lp
.global
].add
(lp
)
726 props
[lp
.global
] = [lp
]
727 gprops
.add
(lp
.global
.intro
)
732 dctx
.stage
("<article class=\"modules filterable\
">\n")
733 dctx
.stage
("<h2>Modules</h2>\n")
737 dctx
.add
("<li>{m.html_link(dctx)}</li>")
739 dctx
.stage
("</ul></article>\n")
743 dctx
.stage
("<article class=\"classes filterable\
">\n")
744 dctx
.stage
("<h2>Classes</h2>\n")
748 dctx
.add
("<li>{lc.html_link(dctx)}</li>")
750 dctx
.stage
("</ul></article>\n")
754 dctx
.stage
("<article class=\"properties filterable\
">\n")
755 dctx
.stage
("<h2>Properties</h2>\n")
762 if gp
.intro
isa MMAttribute then continue
764 var lpi
= self[gp
.intro
.local_class
.global
][gp
]
767 dctx
.add
("<li class='intro'><span title='introduction'>I</span> {lpi.html_open_link(dctx)}{lpi.html_name} ({lpi.local_class})</a></li>\n")
768 if lps
.length
>= 1 then
771 dctx
.add
("<li class='redef'><span title='redefinition'>R</span> {lp.html_open_link(dctx)}{lp.html_name} ({lp.local_class})</a></li>\n")
775 dctx
.stage
("</ul></article>\n")
780 redef class MMLocalProperty
782 # Anchor of the property description in the module html file
783 fun html_anchor
: String
785 return "PROP_{local_class}_{cmangle(name)}"
788 fun html_open_link
(dctx
: DocContext): String
790 if not require_doc
(dctx
) then print
"not required {self}"
791 var title
= "{html_name}{signature.to_s}"
792 if short_doc
!= " " then
793 title
+= " #{short_doc}"
795 return "<a href=\"{local_class.html_name}.html
#{html_anchor}\" title=\"{title}\">"
798 fun html_name
: String
800 return self.name
.to_s
.html_escape
803 redef fun html_link
(dctx
)
805 if not require_doc
(dctx
) then print
"not required {self}"
806 var title
= "{html_name}{signature.to_s}"
807 if short_doc
!= " " then
808 title
+= " #{short_doc}"
810 return "<a href=\"{local_class.html_name}.html
#{html_anchor}\" title=\"{title}\">{html_name}</a>"
813 fun html_link_special
(dctx
: DocContext, lc
: MMLocalClass): String
815 if not require_doc
(dctx
) then print
"not required {self}"
816 var title
= "{html_name}{signature_for(lc.get_type)}"
817 if short_doc
!= " " then
818 title
+= " #{short_doc}"
820 return "<a href=\"{lc.html_name}.html
#{html_anchor}\" title=\"{title}\">{html_name}</a>"
823 # Kind of property (fun, attr, etc.)
824 fun kind
: String is abstract
831 else if global
.intro
== self then
834 return global
.intro
.short_doc
841 if n
== null or not n
isa APropdef then
848 if d
.n_comment
.is_empty
then
855 # The most specific module in the nesting hierarchy that exports the intro of self
856 fun intro_module
: MMModule
858 var m
= global
.intro
.mmmodule
859 var mo
= m
.direct_owner
860 while mo
!= null and mo
.visibility_for
(m
) >= 2 do
867 # Is the intro of self exported by the top-level module ?
868 fun is_toplevel
: Bool
871 return m
== m
.toplevel_owner
874 # Return true if the global class must be documented according to the visibility configured
875 fun require_doc
(dctx
: DocContext): Bool
877 if global
.visibility_level
== 3 then return false # Private
878 if dctx
.public_only
then
880 if m
!= m
.toplevel_owner
then return false # Unexported
885 # Document the global property in the global class lc
886 fun full_documentation
(dctx
: DocContext, lc
: MMLocalClass)
888 var visibility
: String
889 if global
.visibility_level
== 1 then
890 visibility
= "public"
891 else if global
.visibility_level
== 2 then
892 visibility
= "protected"
893 else if global
.visibility_level
== 3 then
894 visibility
= "private"
899 var intro_class
= global
.intro
.local_class
900 var is_redef
= local_class
.global
!= intro_class
.global
or local_class
.mmmodule
.toplevel_owner
!= intro_class
.mmmodule
.toplevel_owner
902 dctx
.add
("<article id=\"{html_anchor}\
" class=\"{kind} {visibility} {if is_redef then "redef" else ""}\
">\n")
903 dctx
.add
("<h3 class=\"signature\
">{html_name}{signature.to_html(dctx, true)}</h3>\n")
904 dctx
.add
("<div class=\"info\
">\n")
905 #dctx.add("<p>LP: {self.mmmodule.html_link(dctx)}::{self.local_class.html_link(dctx)}::{self.html_link(dctx)}</p>")
910 if not is_toplevel
then
911 dctx
.add
("(unexported) ")
913 if global
.visibility_level
== 2 then
914 dctx
.add
("protected ")
915 else if global
.visibility_level
== 3 then
919 dctx
.add
(" {intro_class.mmmodule.toplevel_owner.name}")
920 if intro_class
.global
== lc
.global
then
921 dctx
.add
("::{lc.name}")
923 dctx
.add
("::{mmmodule[intro_class.global].html_link(dctx)}")
926 dctx
.add
("::{mmmodule[intro_class.global][global].html_link(dctx)}")
928 dctx
.add
("::{html_name}")
932 dctx
.add
("<div class=\"description\
">")
934 # Collect all refinement of the global property in the same global property
935 var lps
= new Array[MMLocalProperty]
936 for l
in prhe
.greaters_and_self
do
941 if global
.intro
.doc
!= null then
943 if lp
.doc
== null then introdoc
= true
947 dctx
.add
("<pre>{global.intro.doc.to_html}</pre>")
950 var tlmods
= new Array[MMModule]
952 var bm
= lp
.mmmodule
.toplevel_owner
953 var lcm
= lc
.global
.intro
.mmmodule
954 if lcm
.mhe
< lp
.mmmodule
then bm
= lcm
.toplevel_owner
955 if not tlmods
.has
(bm
) then tlmods
.add
(bm
)
959 # Document the top level property for the current top level module
961 if tm
.global_classes
.has
(lc
.global
) then
962 tlp
= tm
[lc
.global
][self.global
]
964 else if tm
.global_classes
.has
(self.local_class
.global
) then
965 # Self is the inherited property. Process it
966 tlp
= tm
[self.local_class
.global
][self.global
]
969 # We skip this module since the props defined by the module is
973 var tlcm
= lc
.global
.intro
.mmmodule
.toplevel_owner
974 if not tlcm
.mhe
<= tm
then
975 dctx
.add
("<h4>In module {tm.html_link(dctx)} :</h4>")
978 #dctx.add("<p>TLP: {tm} x {lc} : {tlp.full_name}</p>")
981 if doc
!= null and (not introdoc
or global
.intro
.doc
!= doc
) then
982 dctx
.add
("<pre>{doc.to_html}</pre>")
985 if tlp
.local_class
.global
!= lc
.global
then
986 dctx
.add
("inherited from {tlp.local_class.html_link(dctx)} ")
988 if tm
!= tlp
.mmmodule
then
989 dctx
.add
("defined by the module {tlp.mmmodule.html_link(dctx)} ")
998 dctx
.stage
(". previously defined by:")
1000 var tl
= lp
.mmmodule
.toplevel_owner
1001 if tl
!= tm
then continue
1002 if lp
== tlp
then continue
1003 dctx
.add
(" {lp.mmmodule.html_link(dctx)}")
1004 if lp
.local_class
.global
!= lc
.global
then
1005 dctx
.add
(" for {lp.local_class.html_link(dctx)}")
1015 #if doc != null and (not introdoc or global.intro.doc != doc) then
1016 # dctx.add("<pre>{doc.to_html}</pre>")
1023 dctx
.add
("</article>")
1026 redef class MMMethod
1027 redef fun kind
do return if global
.is_init
then "init" else "fun"
1029 redef class MMAttribute
1030 redef fun kind
do return "var"
1032 redef class MMTypeProperty
1033 redef fun kind
do return "type"
1036 redef class MMSrcModule
1050 if n
.n_moduledecl
== null then
1053 var np
= n
.n_moduledecl
1058 if d
.n_comment
.is_empty
then
1067 # Html transcription of the doc
1070 var res
= new Buffer
1071 for c
in n_comment
do
1072 res
.append
(c
.text
.substring_from
(1))
1074 return res
.to_s
.html_escape
1077 # Oneliner transcription of the doc
1080 return n_comment
.first
.text
.substring_from
(1).html_escape
1084 redef class MMLocalClass
1087 # Anchor of the class description in the module html file
1088 fun html_anchor
: String do return "CLASS_{self}"
1090 fun html_name
: String do return "{self}"
1092 redef fun html_link
(dctx
)
1094 if not require_doc
(dctx
) then print
"{dctx.filename}: not required {self}"
1095 return "<a href=\"{html_name}.html\
" title=\"{short_doc}\
">{self}</a>"
1098 redef fun short_doc
do return global
.intro
.short_doc
1100 redef fun doc
do return global
.intro
.doc
1104 if global
.is_interface
then
1106 else if global
.is_abstract
then
1107 return "abstract class"
1108 else if global
.is_enum
then
1115 # The most specific module in the nesting hierarchy that exports the intro of self
1116 fun intro_module
: MMModule
1118 var m
= global
.intro
.mmmodule
1119 var mo
= m
.direct_owner
1120 while mo
!= null and mo
.visibility_for
(m
) >= 2 do
1127 fun menu_link
(dctx
: DocContext, p
: MMLocalProperty)
1129 if p
.local_class
.global
!= self.global
then
1130 if p
.global
.intro
.local_class
.name
== "Object".to_symbol
then return
1131 if p
.global
.is_init
or p
isa MMTypeProperty then
1132 dctx
.add
("<li class='inherit'><span title='Inherited'>H</span> {p.html_link_special(dctx, self)}</li>\n")
1134 dctx
.add
("<li class='inherit'><span title='Inherited'>H</span> {p.html_link(dctx)}</li>\n")
1136 else if p
.global
.intro
.local_class
.global
== self.global
then
1137 dctx
.add
("<li class='intro'><span title='Introduced'>I</span> {p.html_link_special(dctx, self)}</li>\n")
1139 dctx
.add
("<li class='redef'><span title='Redefined'>R</span> {p.html_link_special(dctx, self)}</li>\n")
1143 # Return true if the global class must be documented according to the visibility configured
1144 fun require_doc
(dctx
: DocContext): Bool
1146 if global
.visibility_level
== 3 then return false # Private
1147 if dctx
.public_only
then
1148 var m
= intro_module
1149 if m
!= m
.toplevel_owner
then return false # Unexported
1154 # Fill the body for the page associated to the global class
1155 fun file_page_doc
(dctx
: DocContext)
1157 dctx
.add
("<div class=\"menu\
">\n")
1159 var props
= new Array[MMLocalProperty]
1160 var inh
= new HashMap[MMLocalClass, Array[MMLocalProperty]]
1161 var inhs
= new Array[MMLocalClass]
1162 for g
in global_properties
do
1164 if not p
.require_doc
(dctx
) then continue
1165 if p
.local_class
.global
== global
or g
.is_init_for
(self) or p
isa MMTypeProperty then
1168 var lc
= mmmodule
[p
.local_class
.global
]
1169 if inh
.has_key
(lc
) then
1180 dctx
.add
("<nav class=\"properties filterable\
">\n")
1181 dctx
.add
("<h3>Properties</h3>\n")
1183 dctx
.stage
("<h4>Virtual Types</h4>\n<ul>\n")
1185 if p
isa MMTypeProperty then
1189 dctx
.stage
("</ul>\n")
1192 dctx
.stage
("<h4>Constructors</h4>\n<ul>\n")
1194 if p
.global
.is_init_for
(self) then
1198 dctx
.stage
("</ul>\n")
1201 dctx
.stage
("<h4>Methods</h4>\n<ul>\n")
1203 if not p
.global
.is_init
and p
isa MMMethod then
1207 dctx
.stage
("</ul>\n")
1209 dctx
.add
("</nav>\n")
1211 dctx
.add
("<nav class=\"inheritance filterable\
">\n")
1212 dctx
.add
("<h3>Inheritance</h3>\n")
1213 dctx
.add
("<h4>Superclasses</h4>\n<ul>\n")
1214 for lc
in cshe
.linear_extension
do
1215 if lc
== self then continue
1216 if not lc
.require_doc
(dctx
) then continue
1217 dctx
.add
("<li>{lc.html_link(dctx)}</li>\n")
1220 if cshe
.smallers
.length
== 0 then
1221 dctx
.add
("<h4>No Known Subclasses</h4>\n")
1222 else if cshe
.smallers
.length
<= 100 then
1223 dctx
.add
("<h4>Subclasses</h4>\n")
1225 for lc
in cshe
.smallers
do
1226 if not lc
.require_doc
(dctx
) then continue
1227 dctx
.add
("<li>{lc.html_link(dctx)}</li>\n")
1230 else if cshe
.direct_smallers
.length
<= 100 then
1231 dctx
.add
("<h4>Direct Subclasses Only</h4>\n<ul>\n")
1232 for lc
in cshe
.direct_smallers
do
1233 if not lc
.require_doc
(dctx
) then continue
1234 dctx
.add
("<li>{lc.html_link(dctx)}</li>\n")
1238 dctx
.add
("<h4>Too much Subclasses to list</h4>\n")
1240 dctx
.add
("</nav>\n")
1242 dctx
.add
("</div>\n")
1245 dctx
.add
("<div class=\"content\
">\n")
1246 dctx
.add
("<h1>{name}</h1>\n")
1247 dctx
.add
("<div class='subtitle'>")
1248 if global
.visibility_level
== 2 then
1250 else if global
.visibility_level
== 3 then
1251 dctx
.add
("private ")
1252 else if self.global
.intro
.mmmodule
.toplevel_owner
.visibility_for
(self.global
.intro
.mmmodule
) <= 1 then
1253 dctx
.add
("(unexported) ")
1255 dctx
.add
("{kind} {global.intro.mmmodule.toplevel_owner.html_link(dctx)}::{name}</div>")
1257 dctx
.add
("<section class=\"description\
">\n")
1260 dctx
.add
("<pre>{doc.to_html}</pre>\n")
1263 var cla
= new HashSet[MMLocalClass]
1264 var sm
= new HashSet[MMLocalClass]
1265 var sm2
= new HashSet[MMLocalClass]
1267 while cla
.length
+ sm
.length
< 10 and sm
.length
> 0 do
1271 sm2
.add_all
(x
.cshe
.direct_smallers
)
1277 cla
.add_all
(cshe
.greaters_and_self
)
1280 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")
1283 op
.append
("\"{c.name}\
"[shape=box,margin=0.03];\n")
1285 op
.append
("\"{c.name}\
"[URL=\"{c.html_name}.html\
"];\n")
1287 for c2
in c
.cshe
.direct_greaters
do
1288 if not cla
.has
(c2
) then continue
1289 op
.append
("\"{c.name}\
"->\"{c2.name}\
";\n")
1291 if not c
.cshe
.direct_smallers
.is_empty
then
1293 for c2
in c
.cshe
.direct_smallers
do
1294 if cla
.has
(c2
) then others
= false
1297 op
.append
("\"{c.name}...\
"[label=\"\
"];\n")
1298 op
.append
("\"{c.name}...\
"->\"{c.name}\
"[style=dotted];\n")
1303 dctx
.gen_dot
(op
.to_s
, name
.to_s
, "Inheritance graph for class {name}")
1306 var mods
= new Array[MMModule]
1307 mods
.add
(global
.intro
.mmmodule
.toplevel_owner
)
1308 for lc
in crhe
.greaters
do
1309 if not lc
isa MMSrcLocalClass then continue
1310 var m
= lc
.mmmodule
.toplevel_owner
1311 if not mods
.has
(m
) then mods
.add
(m
)
1315 if m
== global
.intro
.mmmodule
.toplevel_owner
then
1316 dctx
.add
("<p>Introduced by {m.html_link(dctx)}")
1318 dctx
.add
("<p>Refined by {m.html_link(dctx)}")
1321 dctx
.stage
(". Definition in:")
1322 for lc
in crhe
.greaters
do
1323 if lc
.mmmodule
.toplevel_owner
!= m
then continue
1324 dctx
.add
(" {lc.mmmodule.html_link(dctx)}")
1325 assert lc
isa MMSrcLocalClass
1328 dctx
.show_source
(n
.location
)
1334 dctx
.add
("</section>\n")
1337 dctx
.stage
("<section class=\"types\
">\n")
1338 dctx
.stage
("<h2>Formal and Virtual Types</h2>\n")
1339 for i
in [0..arity
[ do
1340 var f
= get_formal
(i
)
1341 f
.full_documentation
(dctx
, self)
1344 if not p
isa MMTypeProperty then continue
1345 p
.full_documentation
(dctx
, self)
1347 dctx
.stage
("</section>\n")
1351 dctx
.stage
("<section class=\"constructors\
">\n")
1352 dctx
.stage
("<h2 class=\"section-header\
">Constructors</h2>\n")
1354 if not p
.global
.is_init_for
(self) then continue
1355 p
.full_documentation
(dctx
, self)
1357 dctx
.stage
("</section>\n")
1361 dctx
.stage
("<section class=\"methods\
">\n")
1362 dctx
.stage
("<h2 class=\"section-header\
">Methods</h2>\n")
1364 if p
.global
.is_init
then continue
1365 if p
.local_class
.global
!= self.global
then continue
1366 if not p
isa MMMethod then continue
1367 p
.full_documentation
(dctx
, self)
1369 if not inhs
.is_empty
then
1371 dctx
.stage
("<h3>Inherited Methods</h3>\n")
1374 dctx
.stage
("<p>Defined in {lc.html_link(dctx)}:")
1376 if p
.global
.is_init
then continue
1377 if not p
isa MMMethod then continue
1378 dctx
.add
(" {p.html_link(dctx)}")
1385 dctx
.add
("</section>\n")
1387 dctx
.add
("</div> <!-- end class {name} -->\n")
1391 redef class MMSrcLocalClass
1397 else if global
.intro
== self then
1400 var bc
= global
.intro
1408 if not n
isa AStdClassdef then
1415 if d
.n_comment
.is_empty
then
1423 redef class MMSignature
1424 # Htlm transcription of the signature (with nested links)
1425 fun to_html
(dctx
: DocContext, with_closure
: Bool): String
1427 var res
= new Buffer
1430 res
.append
(self.params
[0].name
.to_s
)
1432 res
.append
(self[0].html_link
(dctx
))
1433 for i
in [1..arity
[ do
1435 res
.append
(self.params
[i
].name
.to_s
)
1437 res
.append
(self[i
].html_link
(dctx
))
1441 if return_type
!= null then
1443 res
.append
(return_type
.html_link
(dctx
))
1445 if with_closure
then
1446 for c
in closures
do
1448 if c
.is_optional
then res
.append
("[")
1449 if c
.is_break
then res
.append
("break ")
1450 res
.append
("!{c.name}")
1451 res
.append
(c
.signature
.to_html
(dctx
, false))
1452 if c
.is_optional
then res
.append
("]")
1460 # Htlm transcription of the type (with nested links)
1461 fun html_link
(dctx
: DocContext): String do return to_s
1464 redef class MMTypeSimpleClass
1465 redef fun html_link
(dctx
) do return local_class
.html_link
(dctx
)
1468 redef class MMTypeGeneric
1469 redef fun html_link
(dctx
)
1471 var res
= new Buffer
1472 res
.append
(local_class
.html_link
(dctx
))
1474 res
.append
(params
[0].html_link
(dctx
))
1475 for i
in [1..params
.length
[ do
1477 res
.append
(params
[i
].html_link
(dctx
))
1484 redef class MMTypeFormalParameter
1485 fun html_anchor
: String
1487 return "FT_{local_class}_{cmangle(name)}"
1489 redef fun html_link
(dctx
)
1491 return "<a href=\"#{html_anchor}\">{name}</a>"
1493 fun full_documentation
(dctx
: DocContext, lc
: MMLocalClass)
1495 dctx
.add
("<article id=\"{html_anchor}\
">\n")
1496 dctx
.add
("<h3 class=\"signature\
">{name}: {bound.html_link(dctx)}</h3>\n")
1497 dctx
.add
("<div class=\"info\
">")
1498 dctx
.add
("formal generic type")
1500 dctx
.add
("</article>")
1504 redef class MMNullableType
1505 redef fun html_link
(dctx
) do return "nullable " + as_notnull
.html_link
(dctx
)
1508 redef class MMVirtualType
1509 redef fun html_link
(dctx
) do return property
.html_link
(dctx
)
1512 var c
= new DocContext