1 # This file is part of NIT ( http://www.nitlanguage.org ).
3 # Copyright 2008 Jean Privat <jean@pryen.org>
5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at
9 # http://www.apache.org/licenses/LICENSE-2.0
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
17 # The main module of the nitdoc program
25 # Store knowledge and facilities to generate files
27 super AbstractCompiler
28 # Destination directory
29 readable writable var _dir
: String = "doc"
31 # Content of a generated file
32 var _stage_context
: StageContext = new StageContext(null)
34 # Add a string in the content
36 _stage_context
.content
.add
(s
)
37 _stage_context
.validate
= true
40 # Add a string in the content iff some other string are added
41 fun stage
(s
: String) do _stage_context
.content
.add
(s
)
43 # Create a new stage in the content
44 fun open_stage
do _stage_context
= new StageContext(_stage_context
)
46 # Close the current stage in the content
49 var s
= _stage_context
.parent
50 if _stage_context
.validate
then
51 s
.content
.add_all
(_stage_context
.content
)
58 # Write the content to a new file
59 fun write_to
(filename
: String)
61 var f
= new OFStream.open
(filename
)
62 for s
in _stage_context
.content
do
71 _stage_context
= new StageContext(null)
74 # Sorter of entities in alphabetical order
75 var _sorter
: AlphaSorter[MMEntity] = new AlphaSorter[MMEntity]
77 # Sort entities in the alphabetical order
78 fun sort
(array
: Array[MMEntity])
83 readable var _opt_dir
: OptionString = new OptionString("Directory where doc is generated", "-d", "--dir")
84 readable var _opt_source
: OptionString = new OptionString("What link for source (%f for filename, %l for first line, %L for last line)", "--source")
85 readable var _opt_public
: OptionBool = new OptionBool("Generate only the public API", "--public")
86 readable var _opt_private
: OptionBool = new OptionBool("Generate the private API", "--private")
87 readable var _opt_nodot
: OptionBool = new OptionBool("Do not generate graphes with graphviz", "--no-dot")
91 if self._opt_public
.value
== true then return true
95 fun with_private
: Bool
97 if self._opt_private
.value
== true then return true
101 # The current processed filename
104 # The main virtual module
105 var mainmod
: nullable MMVirtualModule
107 redef fun perform_work
(mods
)
109 mainmod
= new MMVirtualModule(self, mods
)
113 # Compute the set of direct owned nested modules
114 var owns
= new HashMap[MMModule, Array[MMModule]]
115 for mod
in modules
do
116 owns
[mod
] = new Array[MMModule]# [mod]
118 for mod
in modules
do
119 if mod
== mainmod
then continue
120 var d
= mod
.directory
123 if o
!= null and o
!= mod
then
127 if dp
== null or dp
== d
then break
132 # Builds the various module hierarchies
133 var mnh
= new PartialOrder[MMModule] # nested module hierarchy
134 var tmh
= new PartialOrder[MMModule] # top module import hierrchy
135 var ms
= mainmod
.mhe
.linear_extension
.reversed
137 if ms
== mainmod
then continue
138 m
.mnhe_
= mnh
.add
(m
, owns
[m
])
139 var pub
= new Array[MMModule]
140 for m2
in m
.mhe
.greaters
do
141 if m2
.toplevel_owner
!= m2
and m2
.toplevel_owner
!= m
.toplevel_owner
then continue
142 if m
.mnhe
<= m2
then continue
143 if m
.visibility_for
(m2
) <= 0 then
145 else if m
.visibility_for
(m2
) == 1 then
150 m
.tmhe_
= tmh
.add
(m
, pub
)
153 var head
= "<meta charset=\"utf-8\
">" +
154 "<script type=\"text
/javascript\
" src=\"http
://moz-concept
.com
/nitdoc
/scripts
/jquery-1
.7
.1.min
.js\
"></script>\n" +
155 "<script type=\"text
/javascript\
" src=\"http
://moz-concept
.com
/nitdoc
/scripts
/js-facilities
.js\
"></script>\n" +
156 "<link rel=\"stylesheet\
" href=\"http
://moz-concept
.com
/nitdoc
/styles
/main
.css\
" type=\"text
/css\
" media=\"screen\
" />"
158 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"
161 self.filename
= "index.html"
163 add
("<!DOCTYPE html>")
164 add
("<html><head>{head}<title>Index</title></head><body>\n")
166 add
("<div class=\"page\
">")
167 add
("<div class=\"content fullpage\
">")
168 add
("<h1>Modules</h1>\n<article class='overview'><ul>")
169 var modss
= mainmod
.mhe
.greaters_and_self
.to_a
172 if not mod
.is_toplevel
then continue
173 if not mod
.require_doc
(self) then continue
174 assert mod
isa MMSrcModule
175 add
("<li>{mod.html_link(self)} {mod.short_doc}</li>")
181 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")
183 if not mod
.is_toplevel
then continue
184 if not mod
.require_doc
(self) then continue
185 op
.append
("\"{mod.name}\
"[URL=\"{mod.html_name}.html\
"];\n")
186 for mod2
in mod
.tmhe
.direct_greaters
do
187 if not modss
.has
(mod2
) then continue
188 op
.append
("\"{mod.name}\
"->\"{mod2.name}\
";\n")
192 self.gen_dot
(op
.to_s
, "dep", "Modules hierarchy")
193 add
("</article></div>")
194 add
("<div class='clear'></div>")
196 add
("</body></html>\n")
197 write_to
("{dir}/index.html")
199 # Generate page for modules
200 for mod
in modules
do
201 if mod
== mainmod
then continue
202 assert mod
isa MMSrcModule
203 if not mod
.require_doc
(self) then continue
204 self.filename
= mod
.html_name
205 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"
207 add
("<!DOCTYPE html>")
208 add
("<html><head>{head}<title>Module {mod.name}</title></head><body>\n")
210 add
("<div class=\"page\
">")
211 mod
.file_page_doc
(self)
213 add
("</body></html>\n")
214 write_to
("{dir}/{mod.html_name}.html")
217 # Generate pages for global classes
218 for c
in mainmod
.local_classes
do
219 if not c
.require_doc
(self) then continue
220 self.filename
= c
.html_name
221 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"
223 add
("<!DOCTYPE html>")
224 add
("<html><head>{head}<title>Class {c.name}</title></head><body>\n")
226 add
("<div class=\"page\
">")
227 c
.file_page_doc
(self)
229 add
("</body></html>\n")
230 write_to
("{dir}/{c.html_name}.html")
233 self.filename
= "fullindex"
234 action_bar
= "<header><nav class='main'><ul><li><a href='./'>Overview</a></li><li class=\"current\
">Full Index</li></ul></nav></header>\n"
236 add
("<!DOCTYPE html>")
237 add
("<html><head>{head}<title>Full Index</title></head><body>\n")
239 add
("<div class=\"page\
">")
240 add
("<div class=\"content fullpage\
">")
241 mainmod
.file_index_page_doc
(self)
244 add
("</body></html>\n")
245 write_to
("{dir}/full-index.html")
249 # Add a (source) link fo a given location
250 fun show_source
(l
: Location)
252 var s
= opt_source
.value
254 add
("in #{l.file.filename.simplify_path}")
256 # THIS IS JUST UGLY ! (but there is no replace yet)
257 var x
= s
.split_with
("%f")
258 s
= x
.join
(l
.file
.filename
.simplify_path
)
259 x
= s
.split_with
("%l")
260 s
= x
.join
(l
.line_start
.to_s
)
261 x
= s
.split_with
("%L")
262 s
= x
.join
(l
.line_end
.to_s
)
263 add
(" (<a href=\"{s}\
">show code</a>)")
267 # Generate a clicable graphiz image using a dot content.
268 # `name' refer to the filename (without extension) and the id name of the map.
269 # `name' must also match the name of the graph in the dot content (eg. digraph NAME {...)
270 fun gen_dot
(dot
: String, name
: String, alt
: String)
272 if opt_nodot
.value
then return
273 var f
= new OFStream.open
("{self.dir}/{name}.dot")
276 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 ; \}")
277 self.add
("<article class=\"graph\
"><img src=\"{name}.png\
" usemap=\"#{name}\" style=\"margin:auto\" alt=\"{alt}\"/></article>")
278 var fmap
= new IFStream.open
("{self.dir}/{name}.map")
279 self.add
(fmap
.read_all
)
288 option_context
.add_option
(opt_public
)
289 option_context
.add_option
(opt_private
)
290 option_context
.add_option
(opt_dir
)
291 option_context
.add_option
(opt_source
)
292 option_context
.add_option
(opt_nodot
)
295 redef fun process_options
298 var d
= opt_dir
.value
299 if d
!= null then dir
= d
301 if not opt_nodot
.value
then
302 # Test if dot is runable
303 var res
= sys
.system
("sh -c dot </dev/null >/dev/null 2>&1")
305 stderr
.write
"--no-dot implied since `dot' is not available. Try to install graphviz.\n"
306 opt_nodot
.value
= true
311 redef fun handle_property_conflict
(lc
, impls
)
313 # THIS IS SO UGLY! See MMVirtualModule
314 if lc
.mmmodule
== self.mainmod
then
315 return # We just accept, so one in impls is arbitrary inherited
322 # Replace all occurence of pattern ith string
323 fun replace
(p
: Pattern, string
: String): String
325 return self.split_with
(p
).join
(string
)
328 # Escape the following characters < > & and " with their html counterpart
329 fun html_escape
: String
332 if ret
.has
('&') then ret
= ret
.replace
('&', "&")
333 if ret
.has
('<') then ret
= ret
.replace
('<', "<")
334 if ret
.has
('>') then ret
= ret
.replace
('>', ">")
335 if ret
.has
('"') then ret
= ret
.replace
('"', """)
339 # Remove "/./", "//" and "bla/../"
340 fun simplify_path
: String
342 var a
= self.split_with
("/")
343 var a2
= new Array[String]
345 if x
== "." then continue
346 if x
== "" and not a2
.is_empty
then continue
347 if x
== ".." and not a2
.is_empty
then
357 # A virtual module is used to work as an implicit main module that combine unrelated modules
358 # Since conflict may arrise in a virtual module (the main method for instance) conflicts are disabled
359 class MMVirtualModule
361 init(ctx
: MMContext, mods
: Array[MMModule])
363 # We need to compute the whole metamodel since there is no mmbuilder to do it
364 super(" main".to_symbol
, mods
.first
.directory
, ctx
, new Location(null,0,0,0,0))
365 ctx
.add_module
(self, mods
)
367 self.add_super_module
(m
, 1)
369 self.import_global_classes
370 self.import_local_classes
371 for c
in self.local_classes
do
372 c
.compute_super_classes
374 for c
in self.local_classes
do
379 redef fun require_doc
(dctx
) do return false
382 # Conditionnal part of the text content of a DocContext
384 # Content of the current stage
385 readable var _content
: Array[String] = new Array[String]
387 # Is a normal string already added?
388 readable writable var _validate
: Bool = false
390 # Parent stage is any
391 readable var _parent
: nullable StageContext = null
393 init(parent
: nullable StageContext) do _parent
= parent
397 # Efficiently sort object with their to_s method
398 class AlphaSorter[E
: Object]
399 super AbstractSorter[E
]
400 redef fun compare
(a
, b
)
420 # Keep track of to_s values
421 var _dico
: HashMap[Object, String] = new HashMap[Object, String]
426 # Generalization of metamodel entities
429 fun html_link
(dctx
: DocContext): String is abstract
431 # Return a one liner description
432 fun short_doc
: String do return " "
434 # The doc node from the AST
435 # Return null is none
436 fun doc
: nullable ADoc do return null
441 redef fun html_link
(dctx
) do
442 return "<a href=\"{html_name}.html\
" title=\"{short_doc}\
">{self}</a>"
445 fun require_doc
(dctx
: DocContext): Bool
447 if dctx
.public_only
and not is_toplevel
then return false
451 # Return true if the module is a top-level owner or a top-level module
452 fun is_toplevel
: Bool
454 var pd
= directory
.parent
455 return pd
== null or (pd
.owner
== null and directory
.owner
== self)
458 # Element in the module nesting tree
459 fun mnhe
: PartialOrderElement[MMModule] do return mnhe_
.as(not null)
460 var mnhe_
: nullable PartialOrderElement[MMModule] = null
462 # Element in the top level module importation hierarchy
463 fun tmhe
: PartialOrderElement[MMModule] do return tmhe_
.as(not null)
464 var tmhe_
: nullable PartialOrderElement[MMModule] = null
466 fun toplevel_owner
: MMModule
470 var ds
= m
.mnhe
.direct_smallers
471 if ds
.length
== 0 then return m
472 if ds
.length
== 1 then m
= ds
.first
else abort
476 fun html_name
: String
481 fun direct_owner
: nullable MMModule
484 while d
.owner
== self do d
= d
.parent
.as(not null)
488 # Fill the body for the page associated to the module
489 fun file_page_doc
(dctx
: DocContext)
491 dctx
.add
("<div class=\"menu\
">\n")
493 var mods
= new Array[MMModule]
494 mods
= self.mhe
.greaters
.to_a
498 dctx
.stage
("<nav>\n")
499 dctx
.stage
("<h3>Module Hierarchy</h3>\n")
500 dctx
.stage
("<h4>All dependencies</h4>\n")
503 if not mod
.require_doc
(dctx
) then continue
504 if self.mnhe
<= mod
then continue # do not want nested stuff
505 if mod
.direct_owner
!= null and not mod
.direct_owner
.mnhe
<= self then continue # not in the right nesting
506 dctx
.add
("<li>{mod.html_link(dctx)}</li>")
508 dctx
.stage
("</ul>\n")
510 mods
= self.mhe
.smallers
.to_a
512 dctx
.stage
("<h4>All clients</h4>\n")
515 if not mod
.require_doc
(dctx
) then continue
516 if self.mnhe
<= mod
then continue # do not want nested stuff
517 if mod
.direct_owner
!= null and not mod
.direct_owner
.mnhe
<= self then continue # not in the right nesting
518 dctx
.add
("<li>{mod.html_link(dctx)}</li>")
520 dctx
.stage
("</ul>\n")
521 dctx
.stage
("</nav>\n")
524 if not dctx
.public_only
then
525 mods
= self.mnhe
.direct_greaters
.to_a
528 dctx
.stage
("<nav>\n")
529 dctx
.stage
("<h3>Nested Modules</h3><ul>\n")
531 if not mod
.require_doc
(dctx
) then continue
532 dctx
.add
("<li>{mod.html_link(dctx)}</li>")
534 dctx
.stage
("</ul></nav>\n")
538 dctx
.add
("</div>") # metadata
540 dctx
.add
("<div class=\"content\
">\n")
541 dctx
.add
("<h1>{name}</h1>\n")
542 dctx
.add
("<div class='subtitle'>module ")
543 for m
in mnhe
.smallers
do
544 dctx
.add
("{m.html_link(dctx)}::")
546 dctx
.add
("{self.name}</div>\n")
548 dctx
.add
("<section class='description'>\n")
552 dctx
.add
("<div id=\"description\
">\n")
553 dctx
.add
("<pre>{doc.to_html}</pre>\n")
558 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")
559 var ms
= new Array[nullable MMModule]
561 var m0
: nullable MMModule = self
567 var cla
= new HashSet[MMModule]
569 for m0
in self.mhe
.greaters
do
570 if not m0
.require_doc
(dctx
) then continue
571 if self.visibility_for
(m0
) <= 1 then continue # private or hidden
572 if self.mnhe
<= m0
then continue # do not want nested stuff
573 if m0
.direct_owner
!= null and not m0
.direct_owner
.mnhe
<= self then continue # not in the right nesting
576 for m0
in self.mhe
.smallers
do
577 if not m0
.require_doc
(dctx
) then continue
578 if m0
.visibility_for
(self) <= 1 then continue # private or hidden
579 if m0
.direct_owner
!= null and not m0
.direct_owner
.mnhe
<= self then continue # not in the right nesting
582 for m0
in self.mnhe
.smallers
do
588 op
.append
("subgraph \"cluster_
{m0.name}\
"\{\n")
591 if c
.direct_owner
!= m0
then continue
593 op
.append
("\"{c.name}\
"[shape=box,margin=0.03];\n")
595 op
.append
("\"{c.name}\
"[URL=\"{c.html_name}.html\
"];\n")
599 op
.append
("\"{m0.name}\
"[URL=\"{m0.html_name}.html\
"];\n")
600 for c
in m0
.mhe
.direct_greaters
do
601 if not cla
.has
(c
) then continue
602 op
.append
("\"{m0.name}\
"->\"{c.name}\
";\n")
607 # Close the nesting subgraph
613 for c2
in c
.tmhe
.direct_greaters
do
614 if not cla
.has
(c2
) then continue
615 op
.append
("\"{c.name}\
"->\"{c2.name}\
";\n")
619 dctx
.gen_dot
(op
.to_s
, name
.to_s
, "Dependency graph for module {name}")
620 dctx
.add
("</section>")
622 var clas
= new Array[MMLocalClass]
623 var props
= new HashMap[MMGlobalProperty, Array[MMLocalProperty]]
624 var gprops
= new Array[MMLocalProperty]
627 for g
in m
.global_classes
do
629 if not lc
.require_doc
(dctx
) then continue
630 var im
= g
.intro
.mmmodule
631 if self.visibility_for
(im
) <= 1 then continue # private import or invisible import
633 for lc2
in lc
.crhe
.greaters_and_self
do
634 if not lc2
isa MMSrcLocalClass then continue
635 if not self.mnhe
<= lc2
.mmmodule
then continue # not introduced/redefined here/stolen
638 if not keep
then continue
640 lc
.compute_super_classes
641 for gp
in lc
.global_properties
do
642 if self.visibility_for
(gp
.intro
.local_class
.mmmodule
) <= 1 then continue # private import or invisible import
644 var mp
= lp
.local_class
.mmmodule
645 if not self.mnhe
<= mp
then continue # not introduced/redefined here/stolen
647 if not lp
.require_doc
(dctx
) then continue
648 if props
.has_key
(lp
.global
) then
649 if not props
[lp
.global
].has
(lp
) then
650 props
[lp
.global
].add
(lp
)
653 props
[lp
.global
] = [lp
]
654 gprops
.add
(lp
.global
.intro
)
659 dctx
.add
("<section class=\"module\
">\n")
661 dctx
.stage
("<article class=\"classes filterable\
">\n")
662 dctx
.stage
("<h2>Classes</h2>\n")
666 if self.mnhe
<= lc
.global
.intro
.mmmodule
then
667 dctx
.add
("<li class='intro'><span title='introduced in this module'>I</span> ")
669 dctx
.add
("<li class='redef'><span title='refined in this module'>R</span> ")
671 dctx
.add
("{lc.html_link(dctx)}</li>\n")
673 dctx
.stage
("</ul></article>\n")
677 dctx
.stage
("<article class=\"properties filterable\
">\n")
678 dctx
.stage
("<h2>Properties</h2>\n")
685 if gp
.intro
isa MMAttribute then continue
687 var lpi
= self[gp
.intro
.local_class
.global
][gp
]
690 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")
693 dctx
.add
("<li class='intro'><span title='introduction in this module'>I</span> {lpi.html_name}")
694 dctx
.add
(" ({lpi.local_class})</li>\n")
696 if lps
.length
>= 1 then
699 dctx
.add
("<li class='redef'><span title='redefinition'>R</span> {lp.html_open_link(dctx)}{lp.html_name} ({lp.local_class})</a></li>")
703 dctx
.stage
("</ul></article>\n")
705 dctx
.add
("</section>\n")
709 # Fill the body for the page associated to the full index
710 fun file_index_page_doc
(dctx
: DocContext)
713 dctx
.add
("<h1>Full Index</h1>\n")
715 var clas
= new Array[MMLocalClass]
716 var props
= new HashMap[MMGlobalProperty, Array[MMLocalProperty]]
717 var gprops
= new Array[MMLocalProperty]
718 var mods
= new Array[MMModule]
719 for m
in mhe
.greaters_and_self
do
720 if not m
.require_doc
(dctx
) then continue
723 for g
in global_classes
do
725 if not lc
.require_doc
(dctx
) then continue
727 for gp
in lc
.global_properties
do
729 if not lp
.require_doc
(dctx
) then continue
730 if props
.has_key
(lp
.global
) then
731 if not props
[lp
.global
].has
(lp
) then
732 props
[lp
.global
].add
(lp
)
735 props
[lp
.global
] = [lp
]
736 gprops
.add
(lp
.global
.intro
)
741 dctx
.stage
("<article class=\"modules filterable\
">\n")
742 dctx
.stage
("<h2>Modules</h2>\n")
746 dctx
.add
("<li>{m.html_link(dctx)}</li>")
748 dctx
.stage
("</ul></article>\n")
752 dctx
.stage
("<article class=\"classes filterable\
">\n")
753 dctx
.stage
("<h2>Classes</h2>\n")
757 dctx
.add
("<li>{lc.html_link(dctx)}</li>")
759 dctx
.stage
("</ul></article>\n")
763 dctx
.stage
("<article class=\"properties filterable\
">\n")
764 dctx
.stage
("<h2>Properties</h2>\n")
771 if gp
.intro
isa MMAttribute then continue
773 var lpi
= self[gp
.intro
.local_class
.global
][gp
]
776 dctx
.add
("<li class='intro'><span title='introduction'>I</span> {lpi.html_open_link(dctx)}{lpi.html_name} ({lpi.local_class})</a></li>\n")
777 if lps
.length
>= 1 then
780 dctx
.add
("<li class='redef'><span title='redefinition'>R</span> {lp.html_open_link(dctx)}{lp.html_name} ({lp.local_class})</a></li>\n")
784 dctx
.stage
("</ul></article>\n")
789 redef class MMLocalProperty
791 # Anchor of the property description in the module html file
792 fun html_anchor
: String
794 return "PROP_{local_class}_{cmangle(name)}"
797 fun html_open_link
(dctx
: DocContext): String
799 if not require_doc
(dctx
) then print
"not required {self}"
800 var title
= "{html_name}{signature.to_s}"
801 if short_doc
!= " " then
802 title
+= " #{short_doc}"
804 return "<a href=\"{local_class.html_name}.html
#{html_anchor}\" title=\"{title}\">"
807 fun html_name
: String
809 return self.name
.to_s
.html_escape
812 redef fun html_link
(dctx
)
814 if not require_doc
(dctx
) then print
"not required {self}"
815 var title
= "{html_name}{signature.to_s}"
816 if short_doc
!= " " then
817 title
+= " #{short_doc}"
819 return "<a href=\"{local_class.html_name}.html
#{html_anchor}\" title=\"{title}\">{html_name}</a>"
822 fun html_link_special
(dctx
: DocContext, lc
: MMLocalClass): String
824 if not require_doc
(dctx
) then print
"not required {self}"
825 var title
= "{html_name}{signature_for(lc.get_type)}"
826 if short_doc
!= " " then
827 title
+= " #{short_doc}"
829 return "<a href=\"{lc.html_name}.html
#{html_anchor}\" title=\"{title}\">{html_name}</a>"
832 # Kind of property (fun, attr, etc.)
833 fun kind
: String is abstract
840 else if global
.intro
== self then
843 return global
.intro
.short_doc
850 if n
== null or not n
isa APropdef then
857 if d
.n_comment
.is_empty
then
864 # The most specific module in the nesting hierarchy that exports the intro of self
865 fun intro_module
: MMModule
867 var m
= global
.intro
.mmmodule
868 var mo
= m
.direct_owner
869 while mo
!= null and mo
.visibility_for
(m
) >= 2 do
876 # Is the intro of self exported by the top-level module ?
877 fun is_toplevel
: Bool
880 return m
== m
.toplevel_owner
883 # Return true if the global property must be documented according to the visibility configured
884 fun require_doc
(dctx
: DocContext): Bool
886 if global
.visibility_level
== 3 and not dctx
.with_private
then return false # Private
887 if dctx
.public_only
then
889 if m
!= m
.toplevel_owner
then return false # Unexported
894 # Document the global property in the global class lc
895 fun full_documentation
(dctx
: DocContext, lc
: MMLocalClass)
897 var visibility
: String
898 if global
.visibility_level
== 1 then
899 visibility
= "public"
900 else if global
.visibility_level
== 2 then
901 visibility
= "protected"
902 else if global
.visibility_level
== 3 then
903 visibility
= "private"
908 var intro_class
= global
.intro
.local_class
909 var is_redef
= local_class
.global
!= intro_class
.global
or local_class
.mmmodule
.toplevel_owner
!= intro_class
.mmmodule
.toplevel_owner
911 dctx
.add
("<article id=\"{html_anchor}\
" class=\"{kind} {visibility} {if is_redef then "redef" else ""}\
">\n")
912 dctx
.add
("<h3 class=\"signature\
">{html_name}{signature.to_html(dctx, true)}</h3>\n")
913 dctx
.add
("<div class=\"info\
">\n")
914 #dctx.add("<p>LP: {self.mmmodule.html_link(dctx)}::{self.local_class.html_link(dctx)}::{self.html_link(dctx)}</p>")
919 if not is_toplevel
then
920 dctx
.add
("(unexported) ")
922 if global
.visibility_level
== 2 then
923 dctx
.add
("protected ")
924 else if global
.visibility_level
== 3 then
928 dctx
.add
(" {intro_class.mmmodule.toplevel_owner.name}")
929 if intro_class
.global
== lc
.global
then
930 dctx
.add
("::{lc.name}")
932 dctx
.add
("::{mmmodule[intro_class.global].html_link(dctx)}")
935 dctx
.add
("::{mmmodule[intro_class.global][global].html_link(dctx)}")
937 dctx
.add
("::{html_name}")
941 dctx
.add
("<div class=\"description\
">")
943 # Collect all refinement of the global property in the same global property
944 var lps
= new Array[MMLocalProperty]
945 for l
in prhe
.greaters_and_self
do
950 if global
.intro
.doc
!= null then
952 if lp
.doc
== null then introdoc
= true
956 dctx
.add
("<pre>{global.intro.doc.to_html}</pre>")
959 var tlmods
= new Array[MMModule]
961 var bm
= lp
.mmmodule
.toplevel_owner
962 var lcm
= lc
.global
.intro
.mmmodule
963 if lcm
.mhe
< lp
.mmmodule
then bm
= lcm
.toplevel_owner
964 if not tlmods
.has
(bm
) then tlmods
.add
(bm
)
968 # Document the top level property for the current top level module
970 if tm
.global_classes
.has
(lc
.global
) then
971 tlp
= tm
[lc
.global
][self.global
]
973 else if tm
.global_classes
.has
(self.local_class
.global
) then
974 # Self is the inherited property. Process it
975 tlp
= tm
[self.local_class
.global
][self.global
]
978 # We skip this module since the props defined by the module is
982 var tlcm
= lc
.global
.intro
.mmmodule
.toplevel_owner
983 if not tlcm
.mhe
<= tm
then
984 dctx
.add
("<h4>In module {tm.html_link(dctx)} :</h4>")
987 #dctx.add("<p>TLP: {tm} x {lc} : {tlp.full_name}</p>")
990 if doc
!= null and (not introdoc
or global
.intro
.doc
!= doc
) then
991 dctx
.add
("<pre>{doc.to_html}</pre>")
994 if tlp
.local_class
.global
!= lc
.global
then
995 dctx
.add
("inherited from {tlp.local_class.html_link(dctx)} ")
997 if tm
!= tlp
.mmmodule
then
998 dctx
.add
("defined by the module {tlp.mmmodule.html_link(dctx)} ")
1007 dctx
.stage
(". previously defined by:")
1009 var tl
= lp
.mmmodule
.toplevel_owner
1010 if tl
!= tm
then continue
1011 if lp
== tlp
then continue
1012 dctx
.add
(" {lp.mmmodule.html_link(dctx)}")
1013 if lp
.local_class
.global
!= lc
.global
then
1014 dctx
.add
(" for {lp.local_class.html_link(dctx)}")
1024 #if doc != null and (not introdoc or global.intro.doc != doc) then
1025 # dctx.add("<pre>{doc.to_html}</pre>")
1032 dctx
.add
("</article>")
1035 redef class MMMethod
1036 redef fun kind
do return if global
.is_init
then "init" else "fun"
1038 redef class MMAttribute
1039 redef fun kind
do return "var"
1041 redef class MMTypeProperty
1042 redef fun kind
do return "type"
1045 redef class MMSrcModule
1059 if n
.n_moduledecl
== null then
1062 var np
= n
.n_moduledecl
1067 if d
.n_comment
.is_empty
then
1076 # Html transcription of the doc
1079 var res
= new Buffer
1080 for c
in n_comment
do
1081 res
.append
(c
.text
.substring_from
(1))
1083 return res
.to_s
.html_escape
1086 # Oneliner transcription of the doc
1089 return n_comment
.first
.text
.substring_from
(1).html_escape
1093 redef class MMLocalClass
1096 # Anchor of the class description in the module html file
1097 fun html_anchor
: String do return "CLASS_{self}"
1099 fun html_name
: String do return "{self}"
1101 redef fun html_link
(dctx
)
1103 if not require_doc
(dctx
) then print
"{dctx.filename}: not required {self}"
1104 return "<a href=\"{html_name}.html\
" title=\"{short_doc}\
">{self}</a>"
1107 redef fun short_doc
do return global
.intro
.short_doc
1109 redef fun doc
do return global
.intro
.doc
1113 if global
.is_interface
then
1115 else if global
.is_abstract
then
1116 return "abstract class"
1117 else if global
.is_enum
then
1124 # The most specific module in the nesting hierarchy that exports the intro of self
1125 fun intro_module
: MMModule
1127 var m
= global
.intro
.mmmodule
1128 var mo
= m
.direct_owner
1129 while mo
!= null and mo
.visibility_for
(m
) >= 2 do
1136 fun menu_link
(dctx
: DocContext, p
: MMLocalProperty)
1138 if p
.local_class
.global
!= self.global
then
1139 if p
.global
.intro
.local_class
.name
== "Object".to_symbol
then return
1140 if p
.global
.is_init
or p
isa MMTypeProperty then
1141 dctx
.add
("<li class='inherit'><span title='Inherited'>H</span> {p.html_link_special(dctx, self)}</li>\n")
1143 dctx
.add
("<li class='inherit'><span title='Inherited'>H</span> {p.html_link(dctx)}</li>\n")
1145 else if p
.global
.intro
.local_class
.global
== self.global
then
1146 dctx
.add
("<li class='intro'><span title='Introduced'>I</span> {p.html_link_special(dctx, self)}</li>\n")
1148 dctx
.add
("<li class='redef'><span title='Redefined'>R</span> {p.html_link_special(dctx, self)}</li>\n")
1152 # Return true if the global class must be documented according to the visibility configured
1153 fun require_doc
(dctx
: DocContext): Bool
1155 if global
.visibility_level
== 3 and not dctx
.with_private
then return false # Private
1156 if dctx
.public_only
then
1157 var m
= intro_module
1158 if m
!= m
.toplevel_owner
then return false # Unexported
1163 # Fill the body for the page associated to the global class
1164 fun file_page_doc
(dctx
: DocContext)
1166 dctx
.add
("<div class=\"menu\
">\n")
1168 var props
= new Array[MMLocalProperty]
1169 var inh
= new HashMap[MMLocalClass, Array[MMLocalProperty]]
1170 var inhs
= new Array[MMLocalClass]
1171 for g
in global_properties
do
1173 if not p
.require_doc
(dctx
) then continue
1174 if p
.local_class
.global
== global
or g
.is_init_for
(self) or p
isa MMTypeProperty then
1177 var lc
= mmmodule
[p
.local_class
.global
]
1178 if inh
.has_key
(lc
) then
1189 dctx
.add
("<nav class=\"properties filterable\
">\n")
1190 dctx
.add
("<h3>Properties</h3>\n")
1192 dctx
.stage
("<h4>Virtual Types</h4>\n<ul>\n")
1194 if p
isa MMTypeProperty then
1198 dctx
.stage
("</ul>\n")
1201 dctx
.stage
("<h4>Constructors</h4>\n<ul>\n")
1203 if p
.global
.is_init_for
(self) then
1207 dctx
.stage
("</ul>\n")
1210 dctx
.stage
("<h4>Methods</h4>\n<ul>\n")
1212 if not p
.global
.is_init
and p
isa MMMethod then
1216 dctx
.stage
("</ul>\n")
1218 dctx
.add
("</nav>\n")
1220 dctx
.add
("<nav class=\"inheritance filterable\
">\n")
1221 dctx
.add
("<h3>Inheritance</h3>\n")
1222 dctx
.add
("<h4>Superclasses</h4>\n<ul>\n")
1223 for lc
in cshe
.linear_extension
do
1224 if lc
== self then continue
1225 if not lc
.require_doc
(dctx
) then continue
1226 dctx
.add
("<li>{lc.html_link(dctx)}</li>\n")
1229 if cshe
.smallers
.length
== 0 then
1230 dctx
.add
("<h4>No Known Subclasses</h4>\n")
1231 else if cshe
.smallers
.length
<= 100 then
1232 dctx
.add
("<h4>Subclasses</h4>\n")
1234 for lc
in cshe
.smallers
do
1235 if not lc
.require_doc
(dctx
) then continue
1236 dctx
.add
("<li>{lc.html_link(dctx)}</li>\n")
1239 else if cshe
.direct_smallers
.length
<= 100 then
1240 dctx
.add
("<h4>Direct Subclasses Only</h4>\n<ul>\n")
1241 for lc
in cshe
.direct_smallers
do
1242 if not lc
.require_doc
(dctx
) then continue
1243 dctx
.add
("<li>{lc.html_link(dctx)}</li>\n")
1247 dctx
.add
("<h4>Too much Subclasses to list</h4>\n")
1249 dctx
.add
("</nav>\n")
1251 dctx
.add
("</div>\n")
1254 dctx
.add
("<div class=\"content\
">\n")
1255 dctx
.add
("<h1>{name}</h1>\n")
1256 dctx
.add
("<div class='subtitle'>")
1257 if global
.visibility_level
== 2 then
1259 else if global
.visibility_level
== 3 then
1260 dctx
.add
("private ")
1261 else if self.global
.intro
.mmmodule
.toplevel_owner
.visibility_for
(self.global
.intro
.mmmodule
) <= 1 then
1262 dctx
.add
("(unexported) ")
1264 dctx
.add
("{kind} {global.intro.mmmodule.toplevel_owner.html_link(dctx)}::{name}</div>")
1266 dctx
.add
("<section class=\"description\
">\n")
1269 dctx
.add
("<pre>{doc.to_html}</pre>\n")
1272 var cla
= new HashSet[MMLocalClass]
1273 var sm
= new HashSet[MMLocalClass]
1274 var sm2
= new HashSet[MMLocalClass]
1276 while cla
.length
+ sm
.length
< 10 and sm
.length
> 0 do
1280 sm2
.add_all
(x
.cshe
.direct_smallers
)
1286 cla
.add_all
(cshe
.greaters_and_self
)
1289 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")
1292 op
.append
("\"{c.name}\
"[shape=box,margin=0.03];\n")
1294 op
.append
("\"{c.name}\
"[URL=\"{c.html_name}.html\
"];\n")
1296 for c2
in c
.cshe
.direct_greaters
do
1297 if not cla
.has
(c2
) then continue
1298 op
.append
("\"{c.name}\
"->\"{c2.name}\
";\n")
1300 if not c
.cshe
.direct_smallers
.is_empty
then
1302 for c2
in c
.cshe
.direct_smallers
do
1303 if cla
.has
(c2
) then others
= false
1306 op
.append
("\"{c.name}...\
"[label=\"\
"];\n")
1307 op
.append
("\"{c.name}...\
"->\"{c.name}\
"[style=dotted];\n")
1312 dctx
.gen_dot
(op
.to_s
, name
.to_s
, "Inheritance graph for class {name}")
1315 var mods
= new Array[MMModule]
1316 mods
.add
(global
.intro
.mmmodule
.toplevel_owner
)
1317 for lc
in crhe
.greaters
do
1318 if not lc
isa MMSrcLocalClass then continue
1319 var m
= lc
.mmmodule
.toplevel_owner
1320 if not mods
.has
(m
) then mods
.add
(m
)
1324 if m
== global
.intro
.mmmodule
.toplevel_owner
then
1325 dctx
.add
("<p>Introduced by {m.html_link(dctx)}")
1327 dctx
.add
("<p>Refined by {m.html_link(dctx)}")
1330 dctx
.stage
(". Definition in:")
1331 for lc
in crhe
.greaters
do
1332 if lc
.mmmodule
.toplevel_owner
!= m
then continue
1333 dctx
.add
(" {lc.mmmodule.html_link(dctx)}")
1334 assert lc
isa MMSrcLocalClass
1337 dctx
.show_source
(n
.location
)
1343 dctx
.add
("</section>\n")
1346 dctx
.stage
("<section class=\"types\
">\n")
1347 dctx
.stage
("<h2>Formal and Virtual Types</h2>\n")
1348 for i
in [0..arity
[ do
1349 var f
= get_formal
(i
)
1350 f
.full_documentation
(dctx
, self)
1353 if not p
isa MMTypeProperty then continue
1354 p
.full_documentation
(dctx
, self)
1356 dctx
.stage
("</section>\n")
1360 dctx
.stage
("<section class=\"constructors\
">\n")
1361 dctx
.stage
("<h2 class=\"section-header\
">Constructors</h2>\n")
1363 if not p
.global
.is_init_for
(self) then continue
1364 p
.full_documentation
(dctx
, self)
1366 dctx
.stage
("</section>\n")
1370 dctx
.stage
("<section class=\"methods\
">\n")
1371 dctx
.stage
("<h2 class=\"section-header\
">Methods</h2>\n")
1373 if p
.global
.is_init
then continue
1374 if p
.local_class
.global
!= self.global
then continue
1375 if not p
isa MMMethod then continue
1376 p
.full_documentation
(dctx
, self)
1378 if not inhs
.is_empty
then
1380 dctx
.stage
("<h3>Inherited Methods</h3>\n")
1383 dctx
.stage
("<p>Defined in {lc.html_link(dctx)}:")
1385 if p
.global
.is_init
then continue
1386 if not p
isa MMMethod then continue
1387 dctx
.add
(" {p.html_link(dctx)}")
1394 dctx
.add
("</section>\n")
1396 dctx
.add
("</div> <!-- end class {name} -->\n")
1400 redef class MMSrcLocalClass
1406 else if global
.intro
== self then
1409 var bc
= global
.intro
1417 if not n
isa AStdClassdef then
1424 if d
.n_comment
.is_empty
then
1432 redef class MMSignature
1433 # Htlm transcription of the signature (with nested links)
1434 fun to_html
(dctx
: DocContext, with_closure
: Bool): String
1436 var res
= new Buffer
1439 res
.append
(self.params
[0].name
.to_s
)
1441 res
.append
(self[0].html_link
(dctx
))
1442 for i
in [1..arity
[ do
1444 res
.append
(self.params
[i
].name
.to_s
)
1446 res
.append
(self[i
].html_link
(dctx
))
1450 if return_type
!= null then
1452 res
.append
(return_type
.html_link
(dctx
))
1454 if with_closure
then
1455 for c
in closures
do
1457 if c
.is_optional
then res
.append
("[")
1458 if c
.is_break
then res
.append
("break ")
1459 res
.append
("!{c.name}")
1460 res
.append
(c
.signature
.to_html
(dctx
, false))
1461 if c
.is_optional
then res
.append
("]")
1469 # Htlm transcription of the type (with nested links)
1470 fun html_link
(dctx
: DocContext): String do return to_s
1473 redef class MMTypeSimpleClass
1474 redef fun html_link
(dctx
) do return local_class
.html_link
(dctx
)
1477 redef class MMTypeGeneric
1478 redef fun html_link
(dctx
)
1480 var res
= new Buffer
1481 res
.append
(local_class
.html_link
(dctx
))
1483 res
.append
(params
[0].html_link
(dctx
))
1484 for i
in [1..params
.length
[ do
1486 res
.append
(params
[i
].html_link
(dctx
))
1493 redef class MMTypeFormalParameter
1494 fun html_anchor
: String
1496 return "FT_{local_class}_{cmangle(name)}"
1498 redef fun html_link
(dctx
)
1500 return "<a href=\"#{html_anchor}\">{name}</a>"
1502 fun full_documentation
(dctx
: DocContext, lc
: MMLocalClass)
1504 dctx
.add
("<article id=\"{html_anchor}\
">\n")
1505 dctx
.add
("<h3 class=\"signature\
">{name}: {bound.html_link(dctx)}</h3>\n")
1506 dctx
.add
("<div class=\"info\
">")
1507 dctx
.add
("formal generic type")
1509 dctx
.add
("</article>")
1513 redef class MMNullableType
1514 redef fun html_link
(dctx
) do return "nullable " + as_notnull
.html_link
(dctx
)
1517 redef class MMVirtualType
1518 redef fun html_link
(dctx
) do return property
.html_link
(dctx
)
1521 var c
= new DocContext