5543600134ff3ddee60a9b8e104fe5dd725bf89a
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} ({lpi.local_class})</a></li>\n")
672 dctx
.add
("<li class='intro'><span title='introduction in this module'>I</span> {lpi}")
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} ({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} ({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} ({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
= "{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 redef fun html_link
(dctx
)
788 if not require_doc
(dctx
) then print
"not required {self}"
789 var title
= "{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}\">{self}</a>"
796 fun html_link_special
(dctx
: DocContext, lc
: MMLocalClass): String
798 if not require_doc
(dctx
) then print
"not required {self}"
799 var title
= "{name}{signature_for(lc.get_type)}"
800 if short_doc
!= " " then
801 title
+= " #{short_doc}"
803 return "<a href=\"{lc.html_name}.html
#{html_anchor}\" title=\"{title}\">{self}</a>"
806 # Kind of property (fun, attr, etc.)
807 fun kind
: String is abstract
814 else if global
.intro
== self then
817 return global
.intro
.short_doc
824 if n
== null or not n
isa APropdef then
831 if d
.n_comment
.is_empty
then
838 # The most specific module in the nesting hierarchy that exports the intro of self
839 fun intro_module
: MMModule
841 var m
= global
.intro
.mmmodule
842 var mo
= m
.direct_owner
843 while mo
!= null and mo
.visibility_for
(m
) >= 2 do
850 # Is the intro of self exported by the top-level module ?
851 fun is_toplevel
: Bool
854 return m
== m
.toplevel_owner
857 # Return true if the global class must be documented according to the visibility configured
858 fun require_doc
(dctx
: DocContext): Bool
860 if global
.visibility_level
== 3 then return false # Private
861 if dctx
.public_only
then
863 if m
!= m
.toplevel_owner
then return false # Unexported
868 # Document the global property in the global class lc
869 fun full_documentation
(dctx
: DocContext, lc
: MMLocalClass)
871 var visibility
: String
872 if global
.visibility_level
== 1 then
873 visibility
= "public"
874 else if global
.visibility_level
== 2 then
875 visibility
= "protected"
876 else if global
.visibility_level
== 3 then
877 visibility
= "private"
882 var intro_class
= global
.intro
.local_class
883 var is_redef
= local_class
.global
!= intro_class
.global
or local_class
.mmmodule
.toplevel_owner
!= intro_class
.mmmodule
.toplevel_owner
885 dctx
.add
("<article id=\"{html_anchor}\
" class=\"{kind} {visibility} {if is_redef then "redef" else ""}\
">\n")
886 dctx
.add
("<h3 class=\"signature\
">{name}{signature.to_html(dctx, true)}</h3>\n")
887 dctx
.add
("<div class=\"info\
">\n")
888 #dctx.add("<p>LP: {self.mmmodule.html_link(dctx)}::{self.local_class.html_link(dctx)}::{self.html_link(dctx)}</p>")
893 if not is_toplevel
then
894 dctx
.add
("(unexported) ")
896 if global
.visibility_level
== 2 then
897 dctx
.add
("protected ")
898 else if global
.visibility_level
== 3 then
902 dctx
.add
(" {intro_class.mmmodule.toplevel_owner.name}")
903 if intro_class
.global
== lc
.global
then
904 dctx
.add
("::{lc.name}")
906 dctx
.add
("::{mmmodule[intro_class.global].html_link(dctx)}")
909 dctx
.add
("::{mmmodule[intro_class.global][global].html_link(dctx)}")
915 dctx
.add
("<div class=\"description\
">")
917 # Collect all refinement of the global property in the same global property
918 var lps
= new Array[MMLocalProperty]
919 for l
in prhe
.greaters_and_self
do
924 if global
.intro
.doc
!= null then
926 if lp
.doc
== null then introdoc
= true
930 dctx
.add
("<pre>{global.intro.doc.to_html}</pre>")
933 var tlmods
= new Array[MMModule]
935 var bm
= lp
.mmmodule
.toplevel_owner
936 var lcm
= lc
.global
.intro
.mmmodule
937 if lcm
.mhe
< lp
.mmmodule
then bm
= lcm
.toplevel_owner
938 if not tlmods
.has
(bm
) then tlmods
.add
(bm
)
942 # Document the top level property for the current top level module
944 if tm
.global_classes
.has
(lc
.global
) then
945 tlp
= tm
[lc
.global
][self.global
]
947 else if tm
.global_classes
.has
(self.local_class
.global
) then
948 # Self is the inherited property. Process it
949 tlp
= tm
[self.local_class
.global
][self.global
]
952 # We skip this module since the props defined by the module is
956 var tlcm
= lc
.global
.intro
.mmmodule
.toplevel_owner
957 if not tlcm
.mhe
<= tm
then
958 dctx
.add
("<h4>In module {tm.html_link(dctx)} :</h4>")
961 #dctx.add("<p>TLP: {tm} x {lc} : {tlp.full_name}</p>")
964 if doc
!= null and (not introdoc
or global
.intro
.doc
!= doc
) then
965 dctx
.add
("<pre>{doc.to_html}</pre>")
968 if tlp
.local_class
.global
!= lc
.global
then
969 dctx
.add
("inherited from {tlp.local_class.html_link(dctx)} ")
971 if tm
!= tlp
.mmmodule
then
972 dctx
.add
("defined by the module {tlp.mmmodule.html_link(dctx)} ")
981 dctx
.stage
(". previously defined by:")
983 var tl
= lp
.mmmodule
.toplevel_owner
984 if tl
!= tm
then continue
985 if lp
== tlp
then continue
986 dctx
.add
(" {lp.mmmodule.html_link(dctx)}")
987 if lp
.local_class
.global
!= lc
.global
then
988 dctx
.add
(" for {lp.local_class.html_link(dctx)}")
998 #if doc != null and (not introdoc or global.intro.doc != doc) then
999 # dctx.add("<pre>{doc.to_html}</pre>")
1006 dctx
.add
("</article>")
1009 redef class MMMethod
1010 redef fun kind
do return if global
.is_init
then "init" else "fun"
1012 redef class MMAttribute
1013 redef fun kind
do return "var"
1015 redef class MMTypeProperty
1016 redef fun kind
do return "type"
1020 # Replace < and > with html entities
1023 var ret
= super.to_s
1025 if(ret
.has
('<')) then
1026 var parts
= ret
.split_with
("<")
1029 for i
in [0..parts
.length
[ do
1032 if(i
< parts
.length
- 1) then
1038 if(ret
.has
('>')) then
1039 var parts
= ret
.split_with
(">")
1042 for i
in [0..parts
.length
[ do
1045 if(i
< parts
.length
- 1) then
1055 redef class MMSrcModule
1069 if n
.n_moduledecl
== null then
1072 var np
= n
.n_moduledecl
1077 if d
.n_comment
.is_empty
then
1086 # Html transcription of the doc
1089 var res
= new Buffer
1090 for c
in n_comment
do
1091 res
.append
(c
.text
.substring_from
(1))
1093 return res
.to_s
.html_escape
1096 # Oneliner transcription of the doc
1099 return n_comment
.first
.text
.substring_from
(1).html_escape
1103 redef class MMLocalClass
1106 # Anchor of the class description in the module html file
1107 fun html_anchor
: String do return "CLASS_{self}"
1109 fun html_name
: String do return "{self}"
1111 redef fun html_link
(dctx
)
1113 if not require_doc
(dctx
) then print
"{dctx.filename}: not required {self}"
1114 return "<a href=\"{html_name}.html\
" title=\"{short_doc}\
">{self}</a>"
1117 redef fun short_doc
do return global
.intro
.short_doc
1119 redef fun doc
do return global
.intro
.doc
1123 if global
.is_interface
then
1125 else if global
.is_abstract
then
1126 return "abstract class"
1127 else if global
.is_enum
then
1134 # The most specific module in the nesting hierarchy that exports the intro of self
1135 fun intro_module
: MMModule
1137 var m
= global
.intro
.mmmodule
1138 var mo
= m
.direct_owner
1139 while mo
!= null and mo
.visibility_for
(m
) >= 2 do
1146 fun menu_link
(dctx
: DocContext, p
: MMLocalProperty)
1148 if p
.local_class
.global
!= self.global
then
1149 if p
.global
.intro
.local_class
.name
== "Object".to_symbol
then return
1150 if p
.global
.is_init
or p
isa MMTypeProperty then
1151 dctx
.add
("<li class='inherit'><span title='Inherited'>H</span> {p.html_link_special(dctx, self)}</li>\n")
1153 dctx
.add
("<li class='inherit'><span title='Inherited'>H</span> {p.html_link(dctx)}</li>\n")
1155 else if p
.global
.intro
.local_class
.global
== self.global
then
1156 dctx
.add
("<li class='intro'><span title='Introduced'>I</span> {p.html_link_special(dctx, self)}</li>\n")
1158 dctx
.add
("<li class='redef'><span title='Redefined'>R</span> {p.html_link_special(dctx, self)}</li>\n")
1162 # Return true if the global class must be documented according to the visibility configured
1163 fun require_doc
(dctx
: DocContext): Bool
1165 if global
.visibility_level
== 3 then return false # Private
1166 if dctx
.public_only
then
1167 var m
= intro_module
1168 if m
!= m
.toplevel_owner
then return false # Unexported
1173 # Fill the body for the page associated to the global class
1174 fun file_page_doc
(dctx
: DocContext)
1176 dctx
.add
("<div class=\"menu\
">\n")
1178 var props
= new Array[MMLocalProperty]
1179 var inh
= new HashMap[MMLocalClass, Array[MMLocalProperty]]
1180 var inhs
= new Array[MMLocalClass]
1181 for g
in global_properties
do
1183 if not p
.require_doc
(dctx
) then continue
1184 if p
.local_class
.global
== global
or g
.is_init_for
(self) or p
isa MMTypeProperty then
1187 var lc
= mmmodule
[p
.local_class
.global
]
1188 if inh
.has_key
(lc
) then
1199 dctx
.add
("<nav class=\"properties filterable\
">\n")
1200 dctx
.add
("<h3>Properties</h3>\n")
1202 dctx
.stage
("<h4>Virtual Types</h4>\n<ul>\n")
1204 if p
isa MMTypeProperty then
1208 dctx
.stage
("</ul>\n")
1211 dctx
.stage
("<h4>Constructors</h4>\n<ul>\n")
1213 if p
.global
.is_init_for
(self) then
1217 dctx
.stage
("</ul>\n")
1220 dctx
.stage
("<h4>Methods</h4>\n<ul>\n")
1222 if not p
.global
.is_init
and p
isa MMMethod then
1226 dctx
.stage
("</ul>\n")
1228 dctx
.add
("</nav>\n")
1230 dctx
.add
("<nav class=\"inheritance filterable\
">\n")
1231 dctx
.add
("<h3>Inheritance</h3>\n")
1232 dctx
.add
("<h4>Superclasses</h4>\n<ul>\n")
1233 for lc
in cshe
.linear_extension
do
1234 if lc
== self then continue
1235 if not lc
.require_doc
(dctx
) then continue
1236 dctx
.add
("<li>{lc.html_link(dctx)}</li>\n")
1239 if cshe
.smallers
.length
== 0 then
1240 dctx
.add
("<h4>No Known Subclasses</h4>\n")
1241 else if cshe
.smallers
.length
<= 100 then
1242 dctx
.add
("<h4>Subclasses</h4>\n")
1244 for lc
in cshe
.smallers
do
1245 if not lc
.require_doc
(dctx
) then continue
1246 dctx
.add
("<li>{lc.html_link(dctx)}</li>\n")
1249 else if cshe
.direct_smallers
.length
<= 100 then
1250 dctx
.add
("<h4>Direct Subclasses Only</h4>\n<ul>\n")
1251 for lc
in cshe
.direct_smallers
do
1252 if not lc
.require_doc
(dctx
) then continue
1253 dctx
.add
("<li>{lc.html_link(dctx)}</li>\n")
1257 dctx
.add
("<h4>Too much Subclasses to list</h4>\n")
1259 dctx
.add
("</nav>\n")
1261 dctx
.add
("</div>\n")
1264 dctx
.add
("<div class=\"content\
">\n")
1265 dctx
.add
("<h1>{name}</h1>\n")
1266 dctx
.add
("<div class='subtitle'>")
1267 if global
.visibility_level
== 2 then
1269 else if global
.visibility_level
== 3 then
1270 dctx
.add
("private ")
1271 else if self.global
.intro
.mmmodule
.toplevel_owner
.visibility_for
(self.global
.intro
.mmmodule
) <= 1 then
1272 dctx
.add
("(unexported) ")
1274 dctx
.add
("{kind} {global.intro.mmmodule.toplevel_owner.html_link(dctx)}::{name}</div>")
1276 dctx
.add
("<section class=\"description\
">\n")
1279 dctx
.add
("<pre>{doc.to_html}</pre>\n")
1282 var cla
= new HashSet[MMLocalClass]
1283 var sm
= new HashSet[MMLocalClass]
1284 var sm2
= new HashSet[MMLocalClass]
1286 while cla
.length
+ sm
.length
< 10 and sm
.length
> 0 do
1290 sm2
.add_all
(x
.cshe
.direct_smallers
)
1296 cla
.add_all
(cshe
.greaters_and_self
)
1299 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")
1302 op
.append
("\"{c.name}\
"[shape=box,margin=0.03];\n")
1304 op
.append
("\"{c.name}\
"[URL=\"{c.html_name}.html\
"];\n")
1306 for c2
in c
.cshe
.direct_greaters
do
1307 if not cla
.has
(c2
) then continue
1308 op
.append
("\"{c.name}\
"->\"{c2.name}\
";\n")
1310 if not c
.cshe
.direct_smallers
.is_empty
then
1312 for c2
in c
.cshe
.direct_smallers
do
1313 if cla
.has
(c2
) then others
= false
1316 op
.append
("\"{c.name}...\
"[label=\"\
"];\n")
1317 op
.append
("\"{c.name}...\
"->\"{c.name}\
"[style=dotted];\n")
1322 dctx
.gen_dot
(op
.to_s
, name
.to_s
, "Inheritance graph for class {name}")
1325 var mods
= new Array[MMModule]
1326 mods
.add
(global
.intro
.mmmodule
.toplevel_owner
)
1327 for lc
in crhe
.greaters
do
1328 if not lc
isa MMSrcLocalClass then continue
1329 var m
= lc
.mmmodule
.toplevel_owner
1330 if not mods
.has
(m
) then mods
.add
(m
)
1334 if m
== global
.intro
.mmmodule
.toplevel_owner
then
1335 dctx
.add
("<p>Introduced by {m.html_link(dctx)}")
1337 dctx
.add
("<p>Refined by {m.html_link(dctx)}")
1340 dctx
.stage
(". Definition in:")
1341 for lc
in crhe
.greaters
do
1342 if lc
.mmmodule
.toplevel_owner
!= m
then continue
1343 dctx
.add
(" {lc.mmmodule.html_link(dctx)}")
1344 assert lc
isa MMSrcLocalClass
1347 dctx
.show_source
(n
.location
)
1353 dctx
.add
("</section>\n")
1356 dctx
.stage
("<section class=\"types\
">\n")
1357 dctx
.stage
("<h2>Formal and Virtual Types</h2>\n")
1358 for i
in [0..arity
[ do
1359 var f
= get_formal
(i
)
1360 f
.full_documentation
(dctx
, self)
1363 if not p
isa MMTypeProperty then continue
1364 p
.full_documentation
(dctx
, self)
1366 dctx
.stage
("</section>\n")
1370 dctx
.stage
("<section class=\"constructors\
">\n")
1371 dctx
.stage
("<h2 class=\"section-header\
">Constructors</h2>\n")
1373 if not p
.global
.is_init_for
(self) then continue
1374 p
.full_documentation
(dctx
, self)
1376 dctx
.stage
("</section>\n")
1380 dctx
.stage
("<section class=\"methods\
">\n")
1381 dctx
.stage
("<h2 class=\"section-header\
">Methods</h2>\n")
1383 if p
.global
.is_init
then continue
1384 if p
.local_class
.global
!= self.global
then continue
1385 if not p
isa MMMethod then continue
1386 p
.full_documentation
(dctx
, self)
1388 if not inhs
.is_empty
then
1390 dctx
.stage
("<h3>Inherited Methods</h3>\n")
1393 dctx
.stage
("<p>Defined in {lc.html_link(dctx)}:")
1395 if p
.global
.is_init
then continue
1396 if not p
isa MMMethod then continue
1397 dctx
.add
(" {p.html_link(dctx)}")
1404 dctx
.add
("</section>\n")
1406 dctx
.add
("</div> <!-- end class {name} -->\n")
1410 redef class MMSrcLocalClass
1416 else if global
.intro
== self then
1419 var bc
= global
.intro
1427 if not n
isa AStdClassdef then
1434 if d
.n_comment
.is_empty
then
1442 redef class MMSignature
1443 # Htlm transcription of the signature (with nested links)
1444 fun to_html
(dctx
: DocContext, with_closure
: Bool): String
1446 var res
= new Buffer
1449 res
.append
(self.params
[0].name
.to_s
)
1451 res
.append
(self[0].html_link
(dctx
))
1452 for i
in [1..arity
[ do
1454 res
.append
(self.params
[i
].name
.to_s
)
1456 res
.append
(self[i
].html_link
(dctx
))
1460 if return_type
!= null then
1462 res
.append
(return_type
.html_link
(dctx
))
1464 if with_closure
then
1465 for c
in closures
do
1467 if c
.is_optional
then res
.append
("[")
1468 if c
.is_break
then res
.append
("break ")
1469 res
.append
("!{c.name}")
1470 res
.append
(c
.signature
.to_html
(dctx
, false))
1471 if c
.is_optional
then res
.append
("]")
1479 # Htlm transcription of the type (with nested links)
1480 fun html_link
(dctx
: DocContext): String do return to_s
1483 redef class MMTypeSimpleClass
1484 redef fun html_link
(dctx
) do return local_class
.html_link
(dctx
)
1487 redef class MMTypeGeneric
1488 redef fun html_link
(dctx
)
1490 var res
= new Buffer
1491 res
.append
(local_class
.html_link
(dctx
))
1493 res
.append
(params
[0].html_link
(dctx
))
1494 for i
in [1..params
.length
[ do
1496 res
.append
(params
[i
].html_link
(dctx
))
1503 redef class MMTypeFormalParameter
1504 fun html_anchor
: String
1506 return "FT_{local_class}_{cmangle(name)}"
1508 redef fun html_link
(dctx
)
1510 return "<a href=\"#{html_anchor}\">{name}</a>"
1512 fun full_documentation
(dctx
: DocContext, lc
: MMLocalClass)
1514 dctx
.add
("<article id=\"{html_anchor}\
">\n")
1515 dctx
.add
("<h3 class=\"signature\
">{name}: {bound.html_link(dctx)}</h3>\n")
1516 dctx
.add
("<div class=\"info\
">")
1517 dctx
.add
("formal generic type")
1519 dctx
.add
("</article>")
1523 redef class MMNullableType
1524 redef fun html_link
(dctx
) do return "nullable " + as_notnull
.html_link
(dctx
)
1527 redef class MMVirtualType
1528 redef fun html_link
(dctx
) do return property
.html_link
(dctx
)
1531 var c
= new DocContext