691d951ec651d69e38316b337b140e41e187bc91
1 # This file is part of NIT ( http://www.nitlanguage.org ).
3 # Copyright 2008 Jean Privat <jean@pryen.org>
5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at
9 # http://www.apache.org/licenses/LICENSE-2.0
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
17 # The main module of the nitdoc program
25 # Store knowledge and facilities to generate files
27 super AbstractCompiler
28 # Destination directory
29 readable writable var _dir
: String = "doc"
31 # Content of a generated file
32 var _stage_context
: StageContext = new StageContext(null)
34 # Add a string in the content
36 _stage_context
.content
.add
(s
)
37 _stage_context
.validate
= true
40 # Add a string in the content iff some other string are added
41 fun stage
(s
: String) do _stage_context
.content
.add
(s
)
43 # Create a new stage in the content
44 fun open_stage
do _stage_context
= new StageContext(_stage_context
)
46 # Close the current stage in the content
49 var s
= _stage_context
.parent
50 if _stage_context
.validate
then
51 s
.content
.add_all
(_stage_context
.content
)
58 # Write the content to a new file
59 fun write_to
(filename
: String)
61 var f
= new OFStream.open
(filename
)
62 for s
in _stage_context
.content
do
71 _stage_context
= new StageContext(null)
74 # Sorter of entities in alphabetical order
75 var _sorter
: AlphaSorter[MMEntity] = new AlphaSorter[MMEntity]
77 # Sort entities in the alphabetical order
78 fun sort
(array
: Array[MMEntity])
83 readable var _opt_dir
: OptionString = new OptionString("Directory where doc is generated", "-d", "--dir")
84 readable var _opt_source
: OptionString = new OptionString("What link for source (%f for filename, %l for first line, %L for last line)", "--source")
85 readable var _opt_public
: OptionBool = new OptionBool("Generate only the public API", "--public")
89 if self._opt_public
.value
== true then return true
93 # The current processed filename
96 # The main virtual module
97 var mainmod
: nullable MMVirtualModule
99 redef fun perform_work
(mods
)
101 mainmod
= new MMVirtualModule(self, mods
)
105 # Compute the set of direct owned nested modules
106 var owns
= new HashMap[MMModule, Array[MMModule]]
107 for mod
in modules
do
108 owns
[mod
] = new Array[MMModule]# [mod]
110 for mod
in modules
do
111 if mod
== mainmod
then continue
112 var d
= mod
.directory
115 if o
!= null and o
!= mod
then
119 if dp
== null or dp
== d
then break
124 # Builds the various module hierarchies
125 var mnh
= new PartialOrder[MMModule] # nested module hierarchy
126 var tmh
= new PartialOrder[MMModule] # top module import hierrchy
127 var ms
= mainmod
.mhe
.linear_extension
.reversed
129 if ms
== mainmod
then continue
130 m
.mnhe_
= mnh
.add
(m
, owns
[m
])
131 var pub
= new Array[MMModule]
132 for m2
in m
.mhe
.greaters
do
133 if m2
.toplevel_owner
!= m2
and m2
.toplevel_owner
!= m
.toplevel_owner
then continue
134 if m
.mnhe
<= m2
then continue
135 if m
.visibility_for
(m2
) <= 0 then
137 else if m
.visibility_for
(m2
) == 1 then
142 m
.tmhe_
= tmh
.add
(m
, pub
)
145 var head
= "<meta charset=\"utf-8\
">" +
146 "<script type=\"text
/javascript\
" src=\"http
://moz-concept
.com
/nitdoc
/scripts
/jquery-1
.7
.1.min
.js\
"></script>\n" +
147 "<script type=\"text
/javascript\
" src=\"http
://moz-concept
.com
/nitdoc
/scripts
/js-facilities
.js\
"></script>\n" +
148 "<link rel=\"stylesheet\
" href=\"http
://moz-concept
.com
/nitdoc
/styles
/main
.css\
" type=\"text
/css\
" media=\"screen\
" />"
150 var action_bar
= "<header><nav class='main'><ul><li class=\"current\
">Overview</li><li><a href='full-index.html'>Full Index</a></li></ul></nav></header>\n"
153 self.filename
= "index.html"
155 add
("<!DOCTYPE html>")
156 add
("<html><head>{head}<title>Index</title></head><body>\n")
158 add
("<div class=\"page\
">")
159 add
("<div class=\"content fullpage\
">")
160 add
("<h1>Modules</h1>\n<article class='overview'><ul>")
161 var modss
= mainmod
.mhe
.greaters_and_self
.to_a
164 if not mod
.is_toplevel
then continue
165 if not mod
.require_doc
(self) then continue
166 assert mod
isa MMSrcModule
167 add
("<li>{mod.html_link(self)} {mod.short_doc}</li>")
173 op
.append
("digraph dep \{ rankdir=BT; node[shape=none,margin=0,width=0,height=0,fontsize=10]; edge[dir=none,color=gray]; ranksep=0.2; nodesep=0.1;\n")
175 if not mod
.is_toplevel
then continue
176 if not mod
.require_doc
(self) then continue
177 op
.append
("\"{mod.name}\
"[URL=\"{mod.html_name}.html\
"];\n")
178 for mod2
in mod
.tmhe
.direct_greaters
do
179 if not modss
.has
(mod2
) then continue
180 op
.append
("\"{mod.name}\
"->\"{mod2.name}\
";\n")
184 self.gen_dot
(op
.to_s
, "dep", "Modules hierarchy")
185 add
("</article></div>")
186 add
("<div class='clear'></div>")
188 add
("</body></html>\n")
189 write_to
("{dir}/index.html")
191 # Generate page for modules
192 for mod
in modules
do
193 if mod
== mainmod
then continue
194 assert mod
isa MMSrcModule
195 if not mod
.require_doc
(self) then continue
196 self.filename
= mod
.html_name
197 action_bar
= "<header><nav class='main'><ul><li><a href='./'>Overview</a></li><li class=\"current\
">{mod.name}</li><li><a href='full-index.html'>Full Index</a></li></ul></nav></header>\n"
199 add
("<!DOCTYPE html>")
200 add
("<html><head>{head}<title>Module {mod.name}</title></head><body>\n")
202 add
("<div class=\"page\
">")
203 mod
.file_page_doc
(self)
205 add
("</body></html>\n")
206 write_to
("{dir}/{mod.html_name}.html")
209 # Generate pages for global classes
210 for c
in mainmod
.local_classes
do
211 if not c
.require_doc
(self) then continue
212 self.filename
= c
.html_name
213 action_bar
= "<header><nav class='main'><ul><li><a href='./'>Overview</a></li><li>{c.global.intro.mmmodule.toplevel_owner.html_link(self)}</li><li class=\"current\
">{c.name}</li><li><a href='full-index.html'>Full Index</a></li></ul></nav></header>\n"
215 add
("<!DOCTYPE html>")
216 add
("<html><head>{head}<title>Class {c.name}</title></head><body>\n")
218 add
("<div class=\"page\
">")
219 c
.file_page_doc
(self)
221 add
("</body></html>\n")
222 write_to
("{dir}/{c.html_name}.html")
225 self.filename
= "fullindex"
226 action_bar
= "<header><nav class='main'><ul><li><a href='./'>Overview</a></li><li class=\"current\
">Full Index</li></ul></nav></header>\n"
228 add
("<!DOCTYPE html>")
229 add
("<html><head>{head}<title>Full Index</title></head><body>\n")
231 add
("<div class=\"page\
">")
232 add
("<div class=\"content fullpage\
">")
233 mainmod
.file_index_page_doc
(self)
236 add
("</body></html>\n")
237 write_to
("{dir}/full-index.html")
241 # Add a (source) link fo a given location
242 fun show_source
(l
: Location)
244 var s
= opt_source
.value
246 add
("in #{l.file.filename.simplify_path}")
248 # THIS IS JUST UGLY ! (but there is no replace yet)
249 var x
= s
.split_with
("%f")
250 s
= x
.join
(l
.file
.filename
.simplify_path
)
251 x
= s
.split_with
("%l")
252 s
= x
.join
(l
.line_start
.to_s
)
253 x
= s
.split_with
("%L")
254 s
= x
.join
(l
.line_end
.to_s
)
255 add
(" (<a href=\"{s}\
">show code</a>)")
259 # Generate a clicable graphiz image using a dot content.
260 # `name' refer to the filename (without extension) and the id name of the map.
261 # `name' must also match the name of the graph in the dot content (eg. digraph NAME {...)
262 fun gen_dot
(dot
: String, name
: String, alt
: String)
264 var f
= new OFStream.open
("{self.dir}/{name}.dot")
267 sys
.system
("\{ test -f {self.dir}/{name}.png && test -f {self.dir}/{name}.s.dot && diff {self.dir}/{name}.dot {self.dir}/{name}.s.dot >/dev/null 2>&1 ; \} || \{ cp {self.dir}/{name}.dot {self.dir}/{name}.s.dot && dot -Tpng -o{self.dir}/{name}.png -Tcmapx -o{self.dir}/{name}.map {self.dir}/{name}.s.dot ; \}")
268 self.add
("<article class=\"graph\
"><img src=\"{name}.png\
" usemap=\"#{name}\" style=\"margin:auto\" alt=\"{alt}\"/></article>")
269 var fmap
= new IFStream.open
("{self.dir}/{name}.map")
270 self.add
(fmap
.read_all
)
279 option_context
.add_option
(opt_public
)
280 option_context
.add_option
(opt_dir
)
281 option_context
.add_option
(opt_source
)
284 redef fun process_options
287 var d
= opt_dir
.value
288 if d
!= null then dir
= d
291 redef fun handle_property_conflict
(lc
, impls
)
293 # THIS IS SO UGLY! See MMVirtualModule
294 if lc
.mmmodule
== self.mainmod
then
295 return # We just accept, so one in impls is arbitrary inherited
302 # Replace all occurence of pattern ith string
303 fun replace
(p
: Pattern, string
: String): String
305 return self.split_with
(p
).join
(string
)
308 # Escape the following characters < > & and " with their html counterpart
309 fun html_escape
: String
312 if ret
.has
('&') then ret
= ret
.replace
('&', "&")
313 if ret
.has
('<') then ret
= ret
.replace
('<', "<")
314 if ret
.has
('>') then ret
= ret
.replace
('>', ">")
315 if ret
.has
('"') then ret
= ret
.replace
('"', """)
319 # Remove "/./", "//" and "bla/../"
320 fun simplify_path
: String
322 var a
= self.split_with
("/")
323 var a2
= new Array[String]
325 if x
== "." then continue
326 if x
== "" and not a2
.is_empty
then continue
327 if x
== ".." and not a2
.is_empty
then
337 # A virtual module is used to work as an implicit main module that combine unrelated modules
338 # Since conflict may arrise in a virtual module (the main method for instance) conflicts are disabled
339 class MMVirtualModule
341 init(ctx
: MMContext, mods
: Array[MMModule])
343 # We need to compute the whole metamodel since there is no mmbuilder to do it
344 super(" main".to_symbol
, mods
.first
.directory
, ctx
, new Location(null,0,0,0,0))
345 ctx
.add_module
(self, mods
)
347 self.add_super_module
(m
, 1)
349 self.import_global_classes
350 self.import_local_classes
351 for c
in self.local_classes
do
352 c
.compute_super_classes
354 for c
in self.local_classes
do
359 redef fun require_doc
(dctx
) do return false
362 # Conditionnal part of the text content of a DocContext
364 # Content of the current stage
365 readable var _content
: Array[String] = new Array[String]
367 # Is a normal string already added?
368 readable writable var _validate
: Bool = false
370 # Parent stage is any
371 readable var _parent
: nullable StageContext = null
373 init(parent
: nullable StageContext) do _parent
= parent
377 # Efficiently sort object with their to_s method
378 class AlphaSorter[E
: Object]
379 super AbstractSorter[E
]
380 redef fun compare
(a
, b
)
400 # Keep track of to_s values
401 var _dico
: HashMap[Object, String] = new HashMap[Object, String]
406 # Generalization of metamodel entities
409 fun html_link
(dctx
: DocContext): String is abstract
411 # Return a one liner description
412 fun short_doc
: String do return " "
414 # The doc node from the AST
415 # Return null is none
416 fun doc
: nullable ADoc do return null
421 redef fun html_link
(dctx
) do
422 return "<a href=\"{html_name}.html\
" title=\"{short_doc}\
">{self}</a>"
425 fun require_doc
(dctx
: DocContext): Bool
427 if dctx
.public_only
and not is_toplevel
then return false
431 # Return true if the module is a top-level owner or a top-level module
432 fun is_toplevel
: Bool
434 var pd
= directory
.parent
435 return pd
== null or (pd
.owner
== null and directory
.owner
== self)
438 # Element in the module nesting tree
439 fun mnhe
: PartialOrderElement[MMModule] do return mnhe_
.as(not null)
440 var mnhe_
: nullable PartialOrderElement[MMModule] = null
442 # Element in the top level module importation hierarchy
443 fun tmhe
: PartialOrderElement[MMModule] do return tmhe_
.as(not null)
444 var tmhe_
: nullable PartialOrderElement[MMModule] = null
446 fun toplevel_owner
: MMModule
450 var ds
= m
.mnhe
.direct_smallers
451 if ds
.length
== 0 then return m
452 if ds
.length
== 1 then m
= ds
.first
else abort
456 fun html_name
: String
461 fun direct_owner
: nullable MMModule
464 while d
.owner
== self do d
= d
.parent
.as(not null)
468 # Fill the body for the page associated to the module
469 fun file_page_doc
(dctx
: DocContext)
471 dctx
.add
("<div class=\"menu\
">\n")
473 var mods
= new Array[MMModule]
474 mods
= self.mhe
.greaters
.to_a
478 dctx
.stage
("<nav>\n")
479 dctx
.stage
("<h3>Module Hierarchy</h3>\n")
480 dctx
.stage
("<h4>All dependencies</h4>\n")
483 if not mod
.require_doc
(dctx
) then continue
484 if self.mnhe
<= mod
then continue # do not want nested stuff
485 if mod
.direct_owner
!= null and not mod
.direct_owner
.mnhe
<= self then continue # not in the right nesting
486 dctx
.add
("<li>{mod.html_link(dctx)}</li>")
488 dctx
.stage
("</ul>\n")
490 mods
= self.mhe
.smallers
.to_a
492 dctx
.stage
("<h4>All clients</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")
501 dctx
.stage
("</nav>\n")
504 if not dctx
.public_only
then
505 mods
= self.mnhe
.direct_greaters
.to_a
508 dctx
.stage
("<nav>\n")
509 dctx
.stage
("<h3>Nested Modules</h3><ul>\n")
511 if not mod
.require_doc
(dctx
) then continue
512 dctx
.add
("<li>{mod.html_link(dctx)}</li>")
514 dctx
.stage
("</ul></nav>\n")
518 dctx
.add
("</div>") # metadata
520 dctx
.add
("<div class=\"content\
">\n")
521 dctx
.add
("<h1>{name}</h1>\n")
522 dctx
.add
("<div class='subtitle'>module ")
523 for m
in mnhe
.smallers
do
524 dctx
.add
("{m.html_link(dctx)}::")
526 dctx
.add
("{self.name}</div>\n")
528 dctx
.add
("<section class='description'>\n")
532 dctx
.add
("<div id=\"description\
">\n")
533 dctx
.add
("<pre>{doc.to_html}</pre>\n")
538 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")
539 var ms
= new Array[nullable MMModule]
541 var m0
: nullable MMModule = self
547 var cla
= new HashSet[MMModule]
549 for m0
in self.mhe
.greaters
do
550 if not m0
.require_doc
(dctx
) then continue
551 if self.visibility_for
(m0
) <= 1 then continue # private or hidden
552 if self.mnhe
<= m0
then continue # do not want nested stuff
553 if m0
.direct_owner
!= null and not m0
.direct_owner
.mnhe
<= self then continue # not in the right nesting
556 for m0
in self.mhe
.smallers
do
557 if not m0
.require_doc
(dctx
) then continue
558 if m0
.visibility_for
(self) <= 1 then continue # private or hidden
559 if m0
.direct_owner
!= null and not m0
.direct_owner
.mnhe
<= self then continue # not in the right nesting
562 for m0
in self.mnhe
.smallers
do
568 op
.append
("subgraph \"cluster_
{m0.name}\
"\{\n")
571 if c
.direct_owner
!= m0
then continue
573 op
.append
("\"{c.name}\
"[shape=box,margin=0.03];\n")
575 op
.append
("\"{c.name}\
"[URL=\"{c.html_name}.html\
"];\n")
579 op
.append
("\"{m0.name}\
"[URL=\"{m0.html_name}.html\
"];\n")
580 for c
in m0
.mhe
.direct_greaters
do
581 if not cla
.has
(c
) then continue
582 op
.append
("\"{m0.name}\
"->\"{c.name}\
";\n")
587 # Close the nesting subgraph
593 for c2
in c
.tmhe
.direct_greaters
do
594 if not cla
.has
(c2
) then continue
595 op
.append
("\"{c.name}\
"->\"{c2.name}\
";\n")
599 dctx
.gen_dot
(op
.to_s
, name
.to_s
, "Dependency graph for module {name}")
600 dctx
.add
("</section>")
602 var clas
= new Array[MMLocalClass]
603 var props
= new HashMap[MMGlobalProperty, Array[MMLocalProperty]]
604 var gprops
= new Array[MMLocalProperty]
607 for g
in m
.global_classes
do
609 if not lc
.require_doc
(dctx
) then continue
610 var im
= g
.intro
.mmmodule
611 if self.visibility_for
(im
) <= 1 then continue # private import or invisible import
613 for lc2
in lc
.crhe
.greaters_and_self
do
614 if not lc2
isa MMSrcLocalClass then continue
615 if not self.mnhe
<= lc2
.mmmodule
then continue # not introduced/redefined here/stolen
618 if not keep
then continue
620 for gp
in lc
.global_properties
do
621 if self.visibility_for
(gp
.intro
.local_class
.mmmodule
) <= 1 then continue # private import or invisible import
623 var mp
= lp
.local_class
.mmmodule
624 if not self.mnhe
<= mp
then continue # not introduced/redefined here/stolen
626 if not lp
.require_doc
(dctx
) then continue
627 if props
.has_key
(lp
.global
) then
628 if not props
[lp
.global
].has
(lp
) then
629 props
[lp
.global
].add
(lp
)
632 props
[lp
.global
] = [lp
]
633 gprops
.add
(lp
.global
.intro
)
638 dctx
.add
("<section class=\"module\
">\n")
640 dctx
.stage
("<article class=\"classes filterable\
">\n")
641 dctx
.stage
("<h2>Classes</h2>\n")
645 if self.mnhe
<= lc
.global
.intro
.mmmodule
then
646 dctx
.add
("<li class='intro'><span title='introduced in this module'>I</span> ")
648 dctx
.add
("<li class='redef'><span title='refined in this module'>R</span> ")
650 dctx
.add
("{lc.html_link(dctx)}</li>\n")
652 dctx
.stage
("</ul></article>\n")
656 dctx
.stage
("<article class=\"properties filterable\
">\n")
657 dctx
.stage
("<h2>Properties</h2>\n")
664 if gp
.intro
isa MMAttribute then continue
666 var lpi
= self[gp
.intro
.local_class
.global
][gp
]
669 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")
672 dctx
.add
("<li class='intro'><span title='introduction in this module'>I</span> {lpi.html_name}")
673 dctx
.add
(" ({lpi.local_class})</li>\n")
675 if lps
.length
>= 1 then
678 dctx
.add
("<li class='redef'><span title='redefinition'>R</span> {lp.html_open_link(dctx)}{lp.html_name} ({lp.local_class})</a></li>")
682 dctx
.stage
("</ul></article>\n")
684 dctx
.add
("</section>\n")
688 # Fill the body for the page associated to the full index
689 fun file_index_page_doc
(dctx
: DocContext)
692 dctx
.add
("<h1>Full Index</h1>\n")
694 var clas
= new Array[MMLocalClass]
695 var props
= new HashMap[MMGlobalProperty, Array[MMLocalProperty]]
696 var gprops
= new Array[MMLocalProperty]
697 var mods
= new Array[MMModule]
698 for m
in mhe
.greaters_and_self
do
699 if not m
.require_doc
(dctx
) then continue
702 for g
in global_classes
do
704 if not lc
.require_doc
(dctx
) then continue
706 for gp
in lc
.global_properties
do
708 if not lp
.require_doc
(dctx
) then continue
709 if props
.has_key
(lp
.global
) then
710 if not props
[lp
.global
].has
(lp
) then
711 props
[lp
.global
].add
(lp
)
714 props
[lp
.global
] = [lp
]
715 gprops
.add
(lp
.global
.intro
)
720 dctx
.stage
("<article class=\"modules filterable\
">\n")
721 dctx
.stage
("<h2>Modules</h2>\n")
725 dctx
.add
("<li>{m.html_link(dctx)}</li>")
727 dctx
.stage
("</ul></article>\n")
731 dctx
.stage
("<article class=\"classes filterable\
">\n")
732 dctx
.stage
("<h2>Classes</h2>\n")
736 dctx
.add
("<li>{lc.html_link(dctx)}</li>")
738 dctx
.stage
("</ul></article>\n")
742 dctx
.stage
("<article class=\"properties filterable\
">\n")
743 dctx
.stage
("<h2>Properties</h2>\n")
750 if gp
.intro
isa MMAttribute then continue
752 var lpi
= self[gp
.intro
.local_class
.global
][gp
]
755 dctx
.add
("<li class='intro'><span title='introduction'>I</span> {lpi.html_open_link(dctx)}{lpi.html_name} ({lpi.local_class})</a></li>\n")
756 if lps
.length
>= 1 then
759 dctx
.add
("<li class='redef'><span title='redefinition'>R</span> {lp.html_open_link(dctx)}{lp.html_name} ({lp.local_class})</a></li>\n")
763 dctx
.stage
("</ul></article>\n")
768 redef class MMLocalProperty
770 # Anchor of the property description in the module html file
771 fun html_anchor
: String
773 return "PROP_{local_class}_{cmangle(name)}"
776 fun html_open_link
(dctx
: DocContext): String
778 if not require_doc
(dctx
) then print
"not required {self}"
779 var title
= "{html_name}{signature.to_s}"
780 if short_doc
!= " " then
781 title
+= " #{short_doc}"
783 return "<a href=\"{local_class.html_name}.html
#{html_anchor}\" title=\"{title}\">"
786 fun html_name
: String
788 return self.name
.to_s
.html_escape
791 redef fun html_link
(dctx
)
793 if not require_doc
(dctx
) then print
"not required {self}"
794 var title
= "{html_name}{signature.to_s}"
795 if short_doc
!= " " then
796 title
+= " #{short_doc}"
798 return "<a href=\"{local_class.html_name}.html
#{html_anchor}\" title=\"{title}\">{html_name}</a>"
801 fun html_link_special
(dctx
: DocContext, lc
: MMLocalClass): String
803 if not require_doc
(dctx
) then print
"not required {self}"
804 var title
= "{html_name}{signature_for(lc.get_type)}"
805 if short_doc
!= " " then
806 title
+= " #{short_doc}"
808 return "<a href=\"{lc.html_name}.html
#{html_anchor}\" title=\"{title}\">{html_name}</a>"
811 # Kind of property (fun, attr, etc.)
812 fun kind
: String is abstract
819 else if global
.intro
== self then
822 return global
.intro
.short_doc
829 if n
== null or not n
isa APropdef then
836 if d
.n_comment
.is_empty
then
843 # The most specific module in the nesting hierarchy that exports the intro of self
844 fun intro_module
: MMModule
846 var m
= global
.intro
.mmmodule
847 var mo
= m
.direct_owner
848 while mo
!= null and mo
.visibility_for
(m
) >= 2 do
855 # Is the intro of self exported by the top-level module ?
856 fun is_toplevel
: Bool
859 return m
== m
.toplevel_owner
862 # Return true if the global class must be documented according to the visibility configured
863 fun require_doc
(dctx
: DocContext): Bool
865 if global
.visibility_level
== 3 then return false # Private
866 if dctx
.public_only
then
868 if m
!= m
.toplevel_owner
then return false # Unexported
873 # Document the global property in the global class lc
874 fun full_documentation
(dctx
: DocContext, lc
: MMLocalClass)
876 var visibility
: String
877 if global
.visibility_level
== 1 then
878 visibility
= "public"
879 else if global
.visibility_level
== 2 then
880 visibility
= "protected"
881 else if global
.visibility_level
== 3 then
882 visibility
= "private"
887 var intro_class
= global
.intro
.local_class
888 var is_redef
= local_class
.global
!= intro_class
.global
or local_class
.mmmodule
.toplevel_owner
!= intro_class
.mmmodule
.toplevel_owner
890 dctx
.add
("<article id=\"{html_anchor}\
" class=\"{kind} {visibility} {if is_redef then "redef" else ""}\
">\n")
891 dctx
.add
("<h3 class=\"signature\
">{html_name}{signature.to_html(dctx, true)}</h3>\n")
892 dctx
.add
("<div class=\"info\
">\n")
893 #dctx.add("<p>LP: {self.mmmodule.html_link(dctx)}::{self.local_class.html_link(dctx)}::{self.html_link(dctx)}</p>")
898 if not is_toplevel
then
899 dctx
.add
("(unexported) ")
901 if global
.visibility_level
== 2 then
902 dctx
.add
("protected ")
903 else if global
.visibility_level
== 3 then
907 dctx
.add
(" {intro_class.mmmodule.toplevel_owner.name}")
908 if intro_class
.global
== lc
.global
then
909 dctx
.add
("::{lc.name}")
911 dctx
.add
("::{mmmodule[intro_class.global].html_link(dctx)}")
914 dctx
.add
("::{mmmodule[intro_class.global][global].html_link(dctx)}")
916 dctx
.add
("::{html_name}")
920 dctx
.add
("<div class=\"description\
">")
922 # Collect all refinement of the global property in the same global property
923 var lps
= new Array[MMLocalProperty]
924 for l
in prhe
.greaters_and_self
do
929 if global
.intro
.doc
!= null then
931 if lp
.doc
== null then introdoc
= true
935 dctx
.add
("<pre>{global.intro.doc.to_html}</pre>")
938 var tlmods
= new Array[MMModule]
940 var bm
= lp
.mmmodule
.toplevel_owner
941 var lcm
= lc
.global
.intro
.mmmodule
942 if lcm
.mhe
< lp
.mmmodule
then bm
= lcm
.toplevel_owner
943 if not tlmods
.has
(bm
) then tlmods
.add
(bm
)
947 # Document the top level property for the current top level module
949 if tm
.global_classes
.has
(lc
.global
) then
950 tlp
= tm
[lc
.global
][self.global
]
952 else if tm
.global_classes
.has
(self.local_class
.global
) then
953 # Self is the inherited property. Process it
954 tlp
= tm
[self.local_class
.global
][self.global
]
957 # We skip this module since the props defined by the module is
961 var tlcm
= lc
.global
.intro
.mmmodule
.toplevel_owner
962 if not tlcm
.mhe
<= tm
then
963 dctx
.add
("<h4>In module {tm.html_link(dctx)} :</h4>")
966 #dctx.add("<p>TLP: {tm} x {lc} : {tlp.full_name}</p>")
969 if doc
!= null and (not introdoc
or global
.intro
.doc
!= doc
) then
970 dctx
.add
("<pre>{doc.to_html}</pre>")
973 if tlp
.local_class
.global
!= lc
.global
then
974 dctx
.add
("inherited from {tlp.local_class.html_link(dctx)} ")
976 if tm
!= tlp
.mmmodule
then
977 dctx
.add
("defined by the module {tlp.mmmodule.html_link(dctx)} ")
986 dctx
.stage
(". previously defined by:")
988 var tl
= lp
.mmmodule
.toplevel_owner
989 if tl
!= tm
then continue
990 if lp
== tlp
then continue
991 dctx
.add
(" {lp.mmmodule.html_link(dctx)}")
992 if lp
.local_class
.global
!= lc
.global
then
993 dctx
.add
(" for {lp.local_class.html_link(dctx)}")
1003 #if doc != null and (not introdoc or global.intro.doc != doc) then
1004 # dctx.add("<pre>{doc.to_html}</pre>")
1011 dctx
.add
("</article>")
1014 redef class MMMethod
1015 redef fun kind
do return if global
.is_init
then "init" else "fun"
1017 redef class MMAttribute
1018 redef fun kind
do return "var"
1020 redef class MMTypeProperty
1021 redef fun kind
do return "type"
1024 redef class MMSrcModule
1038 if n
.n_moduledecl
== null then
1041 var np
= n
.n_moduledecl
1046 if d
.n_comment
.is_empty
then
1055 # Html transcription of the doc
1058 var res
= new Buffer
1059 for c
in n_comment
do
1060 res
.append
(c
.text
.substring_from
(1))
1062 return res
.to_s
.html_escape
1065 # Oneliner transcription of the doc
1068 return n_comment
.first
.text
.substring_from
(1).html_escape
1072 redef class MMLocalClass
1075 # Anchor of the class description in the module html file
1076 fun html_anchor
: String do return "CLASS_{self}"
1078 fun html_name
: String do return "{self}"
1080 redef fun html_link
(dctx
)
1082 if not require_doc
(dctx
) then print
"{dctx.filename}: not required {self}"
1083 return "<a href=\"{html_name}.html\
" title=\"{short_doc}\
">{self}</a>"
1086 redef fun short_doc
do return global
.intro
.short_doc
1088 redef fun doc
do return global
.intro
.doc
1092 if global
.is_interface
then
1094 else if global
.is_abstract
then
1095 return "abstract class"
1096 else if global
.is_enum
then
1103 # The most specific module in the nesting hierarchy that exports the intro of self
1104 fun intro_module
: MMModule
1106 var m
= global
.intro
.mmmodule
1107 var mo
= m
.direct_owner
1108 while mo
!= null and mo
.visibility_for
(m
) >= 2 do
1115 fun menu_link
(dctx
: DocContext, p
: MMLocalProperty)
1117 if p
.local_class
.global
!= self.global
then
1118 if p
.global
.intro
.local_class
.name
== "Object".to_symbol
then return
1119 if p
.global
.is_init
or p
isa MMTypeProperty then
1120 dctx
.add
("<li class='inherit'><span title='Inherited'>H</span> {p.html_link_special(dctx, self)}</li>\n")
1122 dctx
.add
("<li class='inherit'><span title='Inherited'>H</span> {p.html_link(dctx)}</li>\n")
1124 else if p
.global
.intro
.local_class
.global
== self.global
then
1125 dctx
.add
("<li class='intro'><span title='Introduced'>I</span> {p.html_link_special(dctx, self)}</li>\n")
1127 dctx
.add
("<li class='redef'><span title='Redefined'>R</span> {p.html_link_special(dctx, self)}</li>\n")
1131 # Return true if the global class must be documented according to the visibility configured
1132 fun require_doc
(dctx
: DocContext): Bool
1134 if global
.visibility_level
== 3 then return false # Private
1135 if dctx
.public_only
then
1136 var m
= intro_module
1137 if m
!= m
.toplevel_owner
then return false # Unexported
1142 # Fill the body for the page associated to the global class
1143 fun file_page_doc
(dctx
: DocContext)
1145 dctx
.add
("<div class=\"menu\
">\n")
1147 var props
= new Array[MMLocalProperty]
1148 var inh
= new HashMap[MMLocalClass, Array[MMLocalProperty]]
1149 var inhs
= new Array[MMLocalClass]
1150 for g
in global_properties
do
1152 if not p
.require_doc
(dctx
) then continue
1153 if p
.local_class
.global
== global
or g
.is_init_for
(self) or p
isa MMTypeProperty then
1156 var lc
= mmmodule
[p
.local_class
.global
]
1157 if inh
.has_key
(lc
) then
1168 dctx
.add
("<nav class=\"properties filterable\
">\n")
1169 dctx
.add
("<h3>Properties</h3>\n")
1171 dctx
.stage
("<h4>Virtual Types</h4>\n<ul>\n")
1173 if p
isa MMTypeProperty then
1177 dctx
.stage
("</ul>\n")
1180 dctx
.stage
("<h4>Constructors</h4>\n<ul>\n")
1182 if p
.global
.is_init_for
(self) then
1186 dctx
.stage
("</ul>\n")
1189 dctx
.stage
("<h4>Methods</h4>\n<ul>\n")
1191 if not p
.global
.is_init
and p
isa MMMethod then
1195 dctx
.stage
("</ul>\n")
1197 dctx
.add
("</nav>\n")
1199 dctx
.add
("<nav class=\"inheritance filterable\
">\n")
1200 dctx
.add
("<h3>Inheritance</h3>\n")
1201 dctx
.add
("<h4>Superclasses</h4>\n<ul>\n")
1202 for lc
in cshe
.linear_extension
do
1203 if lc
== self then continue
1204 if not lc
.require_doc
(dctx
) then continue
1205 dctx
.add
("<li>{lc.html_link(dctx)}</li>\n")
1208 if cshe
.smallers
.length
== 0 then
1209 dctx
.add
("<h4>No Known Subclasses</h4>\n")
1210 else if cshe
.smallers
.length
<= 100 then
1211 dctx
.add
("<h4>Subclasses</h4>\n")
1213 for lc
in cshe
.smallers
do
1214 if not lc
.require_doc
(dctx
) then continue
1215 dctx
.add
("<li>{lc.html_link(dctx)}</li>\n")
1218 else if cshe
.direct_smallers
.length
<= 100 then
1219 dctx
.add
("<h4>Direct Subclasses Only</h4>\n<ul>\n")
1220 for lc
in cshe
.direct_smallers
do
1221 if not lc
.require_doc
(dctx
) then continue
1222 dctx
.add
("<li>{lc.html_link(dctx)}</li>\n")
1226 dctx
.add
("<h4>Too much Subclasses to list</h4>\n")
1228 dctx
.add
("</nav>\n")
1230 dctx
.add
("</div>\n")
1233 dctx
.add
("<div class=\"content\
">\n")
1234 dctx
.add
("<h1>{name}</h1>\n")
1235 dctx
.add
("<div class='subtitle'>")
1236 if global
.visibility_level
== 2 then
1238 else if global
.visibility_level
== 3 then
1239 dctx
.add
("private ")
1240 else if self.global
.intro
.mmmodule
.toplevel_owner
.visibility_for
(self.global
.intro
.mmmodule
) <= 1 then
1241 dctx
.add
("(unexported) ")
1243 dctx
.add
("{kind} {global.intro.mmmodule.toplevel_owner.html_link(dctx)}::{name}</div>")
1245 dctx
.add
("<section class=\"description\
">\n")
1248 dctx
.add
("<pre>{doc.to_html}</pre>\n")
1251 var cla
= new HashSet[MMLocalClass]
1252 var sm
= new HashSet[MMLocalClass]
1253 var sm2
= new HashSet[MMLocalClass]
1255 while cla
.length
+ sm
.length
< 10 and sm
.length
> 0 do
1259 sm2
.add_all
(x
.cshe
.direct_smallers
)
1265 cla
.add_all
(cshe
.greaters_and_self
)
1268 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")
1271 op
.append
("\"{c.name}\
"[shape=box,margin=0.03];\n")
1273 op
.append
("\"{c.name}\
"[URL=\"{c.html_name}.html\
"];\n")
1275 for c2
in c
.cshe
.direct_greaters
do
1276 if not cla
.has
(c2
) then continue
1277 op
.append
("\"{c.name}\
"->\"{c2.name}\
";\n")
1279 if not c
.cshe
.direct_smallers
.is_empty
then
1281 for c2
in c
.cshe
.direct_smallers
do
1282 if cla
.has
(c2
) then others
= false
1285 op
.append
("\"{c.name}...\
"[label=\"\
"];\n")
1286 op
.append
("\"{c.name}...\
"->\"{c.name}\
"[style=dotted];\n")
1291 dctx
.gen_dot
(op
.to_s
, name
.to_s
, "Inheritance graph for class {name}")
1294 var mods
= new Array[MMModule]
1295 mods
.add
(global
.intro
.mmmodule
.toplevel_owner
)
1296 for lc
in crhe
.greaters
do
1297 if not lc
isa MMSrcLocalClass then continue
1298 var m
= lc
.mmmodule
.toplevel_owner
1299 if not mods
.has
(m
) then mods
.add
(m
)
1303 if m
== global
.intro
.mmmodule
.toplevel_owner
then
1304 dctx
.add
("<p>Introduced by {m.html_link(dctx)}")
1306 dctx
.add
("<p>Refined by {m.html_link(dctx)}")
1309 dctx
.stage
(". Definition in:")
1310 for lc
in crhe
.greaters
do
1311 if lc
.mmmodule
.toplevel_owner
!= m
then continue
1312 dctx
.add
(" {lc.mmmodule.html_link(dctx)}")
1313 assert lc
isa MMSrcLocalClass
1316 dctx
.show_source
(n
.location
)
1322 dctx
.add
("</section>\n")
1325 dctx
.stage
("<section class=\"types\
">\n")
1326 dctx
.stage
("<h2>Formal and Virtual Types</h2>\n")
1327 for i
in [0..arity
[ do
1328 var f
= get_formal
(i
)
1329 f
.full_documentation
(dctx
, self)
1332 if not p
isa MMTypeProperty then continue
1333 p
.full_documentation
(dctx
, self)
1335 dctx
.stage
("</section>\n")
1339 dctx
.stage
("<section class=\"constructors\
">\n")
1340 dctx
.stage
("<h2 class=\"section-header\
">Constructors</h2>\n")
1342 if not p
.global
.is_init_for
(self) then continue
1343 p
.full_documentation
(dctx
, self)
1345 dctx
.stage
("</section>\n")
1349 dctx
.stage
("<section class=\"methods\
">\n")
1350 dctx
.stage
("<h2 class=\"section-header\
">Methods</h2>\n")
1352 if p
.global
.is_init
then continue
1353 if p
.local_class
.global
!= self.global
then continue
1354 if not p
isa MMMethod then continue
1355 p
.full_documentation
(dctx
, self)
1357 if not inhs
.is_empty
then
1359 dctx
.stage
("<h3>Inherited Methods</h3>\n")
1362 dctx
.stage
("<p>Defined in {lc.html_link(dctx)}:")
1364 if p
.global
.is_init
then continue
1365 if not p
isa MMMethod then continue
1366 dctx
.add
(" {p.html_link(dctx)}")
1373 dctx
.add
("</section>\n")
1375 dctx
.add
("</div> <!-- end class {name} -->\n")
1379 redef class MMSrcLocalClass
1385 else if global
.intro
== self then
1388 var bc
= global
.intro
1396 if not n
isa AStdClassdef then
1403 if d
.n_comment
.is_empty
then
1411 redef class MMSignature
1412 # Htlm transcription of the signature (with nested links)
1413 fun to_html
(dctx
: DocContext, with_closure
: Bool): String
1415 var res
= new Buffer
1418 res
.append
(self.params
[0].name
.to_s
)
1420 res
.append
(self[0].html_link
(dctx
))
1421 for i
in [1..arity
[ do
1423 res
.append
(self.params
[i
].name
.to_s
)
1425 res
.append
(self[i
].html_link
(dctx
))
1429 if return_type
!= null then
1431 res
.append
(return_type
.html_link
(dctx
))
1433 if with_closure
then
1434 for c
in closures
do
1436 if c
.is_optional
then res
.append
("[")
1437 if c
.is_break
then res
.append
("break ")
1438 res
.append
("!{c.name}")
1439 res
.append
(c
.signature
.to_html
(dctx
, false))
1440 if c
.is_optional
then res
.append
("]")
1448 # Htlm transcription of the type (with nested links)
1449 fun html_link
(dctx
: DocContext): String do return to_s
1452 redef class MMTypeSimpleClass
1453 redef fun html_link
(dctx
) do return local_class
.html_link
(dctx
)
1456 redef class MMTypeGeneric
1457 redef fun html_link
(dctx
)
1459 var res
= new Buffer
1460 res
.append
(local_class
.html_link
(dctx
))
1462 res
.append
(params
[0].html_link
(dctx
))
1463 for i
in [1..params
.length
[ do
1465 res
.append
(params
[i
].html_link
(dctx
))
1472 redef class MMTypeFormalParameter
1473 fun html_anchor
: String
1475 return "FT_{local_class}_{cmangle(name)}"
1477 redef fun html_link
(dctx
)
1479 return "<a href=\"#{html_anchor}\">{name}</a>"
1481 fun full_documentation
(dctx
: DocContext, lc
: MMLocalClass)
1483 dctx
.add
("<article id=\"{html_anchor}\
">\n")
1484 dctx
.add
("<h3 class=\"signature\
">{name}: {bound.html_link(dctx)}</h3>\n")
1485 dctx
.add
("<div class=\"info\
">")
1486 dctx
.add
("formal generic type")
1488 dctx
.add
("</article>")
1492 redef class MMNullableType
1493 redef fun html_link
(dctx
) do return "nullable " + as_notnull
.html_link
(dctx
)
1496 redef class MMVirtualType
1497 redef fun html_link
(dctx
) do return property
.html_link
(dctx
)
1500 var c
= new DocContext