1 # This file is part of NIT ( http://www.nitlanguage.org ).
3 # Copyright 2008 Jean Privat <jean@pryen.org>
5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at
9 # http://www.apache.org/licenses/LICENSE-2.0
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
17 # The main module of the nitdoc program
25 # Store knowledge and facilities to generate files
27 super AbstractCompiler
28 # Destination directory
29 readable writable var _dir
: String = "doc"
31 # Content of a generated file
32 var _stage_context
: StageContext = new StageContext(null)
34 # Add a string in the content
36 _stage_context
.content
.add
(s
)
37 _stage_context
.validate
= true
40 # Add a string in the content iff some other string are added
41 fun stage
(s
: String) do _stage_context
.content
.add
(s
)
43 # Create a new stage in the content
44 fun open_stage
do _stage_context
= new StageContext(_stage_context
)
46 # Close the current stage in the content
49 var s
= _stage_context
.parent
50 if _stage_context
.validate
then
51 s
.content
.add_all
(_stage_context
.content
)
58 # Write the content to a new file
59 fun write_to
(filename
: String)
61 var f
= new OFStream.open
(filename
)
62 for s
in _stage_context
.content
do
71 _stage_context
= new StageContext(null)
74 # Sorter of entities in alphabetical order
75 var _sorter
: AlphaSorter[MMEntity] = new AlphaSorter[MMEntity]
77 # Sort entities in the alphabetical order
78 fun sort
(array
: Array[MMEntity])
83 readable var _opt_dir
: OptionString = new OptionString("Directory where doc is generated", "-d", "--dir")
84 readable var _opt_source
: OptionString = new OptionString("What link for source (%f for filename, %l for first line, %L for last line)", "--source")
85 readable var _opt_public
: OptionBool = new OptionBool("Generate only the public API", "--public")
86 readable var _opt_private
: OptionBool = new OptionBool("Generate the private API", "--private")
87 readable var _opt_nodot
: OptionBool = new OptionBool("Do not generate graphes with graphviz", "--no-dot")
88 readable var _opt_sharedir
: OptionString = new OptionString("Directory containing the nitdoc files", "--sharedir")
89 var sharedir
: nullable String
93 if self._opt_public
.value
== true then return true
97 fun with_private
: Bool
99 if self._opt_private
.value
== true then return true
103 # The current processed filename
106 # The main virtual module
107 var mainmod
: nullable MMVirtualModule
109 redef fun perform_work
(mods
)
111 mainmod
= new MMVirtualModule(self, mods
)
115 sys
.system
("cp -r '{sharedir.to_s}'/* {dir}/")
117 # Compute the set of direct owned nested modules
118 var owns
= new HashMap[MMModule, Array[MMModule]]
119 for mod
in modules
do
120 owns
[mod
] = new Array[MMModule]# [mod]
122 for mod
in modules
do
123 if mod
== mainmod
then continue
124 var d
= mod
.directory
127 if o
!= null and o
!= mod
then
131 if dp
== null or dp
== d
then break
136 # Builds the various module hierarchies
137 var mnh
= new PartialOrder[MMModule] # nested module hierarchy
138 var tmh
= new PartialOrder[MMModule] # top module import hierrchy
139 var ms
= mainmod
.mhe
.linear_extension
.reversed
141 if ms
== mainmod
then continue
142 m
.mnhe_
= mnh
.add
(m
, owns
[m
])
143 var pub
= new Array[MMModule]
144 for m2
in m
.mhe
.greaters
do
145 if m2
.toplevel_owner
!= m2
and m2
.toplevel_owner
!= m
.toplevel_owner
then continue
146 if m
.mnhe
<= m2
then continue
147 if m
.visibility_for
(m2
) <= 0 then
149 else if m
.visibility_for
(m2
) == 1 then
154 m
.tmhe_
= tmh
.add
(m
, pub
)
157 var head
= "<meta charset=\"utf-8\
">" +
158 "<script type=\"text
/javascript\
" src=\"scripts
/jquery-1
.7
.1.min
.js\
"></script>\n" +
159 "<script type=\"text
/javascript\
" src=\"scripts
/js-facilities
.js\
"></script>\n" +
160 "<link rel=\"stylesheet\
" href=\"styles
/main
.css\
" type=\"text
/css\
" media=\"screen\
" />"
162 var action_bar
= "<header><nav class='main'><ul><li class=\"current\
">Overview</li><li><a href='full-index.html'>Full Index</a></li></ul></nav></header>\n"
165 self.filename
= "index.html"
167 add
("<!DOCTYPE html>")
168 add
("<html><head>{head}<title>Index</title></head><body>\n")
170 add
("<div class=\"page\
">")
171 add
("<div class=\"content fullpage\
">")
172 add
("<h1>Modules</h1>\n<article class='overview'><ul>")
173 var modss
= mainmod
.mhe
.greaters_and_self
.to_a
176 if not mod
.is_toplevel
then continue
177 if not mod
.require_doc
(self) then continue
178 assert mod
isa MMSrcModule
179 add
("<li>{mod.html_link(self)} {mod.short_doc}</li>")
185 op
.append
("digraph dep \{ rankdir=BT; node[shape=none,margin=0,width=0,height=0,fontsize=10]; edge[dir=none,color=gray]; ranksep=0.2; nodesep=0.1;\n")
187 if not mod
.is_toplevel
then continue
188 if not mod
.require_doc
(self) then continue
189 op
.append
("\"{mod.name}\
"[URL=\"{mod.html_name}.html\
"];\n")
190 for mod2
in mod
.tmhe
.direct_greaters
do
191 if not modss
.has
(mod2
) then continue
192 op
.append
("\"{mod.name}\
"->\"{mod2.name}\
";\n")
196 self.gen_dot
(op
.to_s
, "dep", "Modules hierarchy")
197 add
("</article></div>")
198 add
("<div class='clear'></div>")
200 add
("</body></html>\n")
201 write_to
("{dir}/index.html")
203 # Generate page for modules
204 for mod
in modules
do
205 if mod
== mainmod
then continue
206 assert mod
isa MMSrcModule
207 if not mod
.require_doc
(self) then continue
208 self.filename
= mod
.html_name
209 action_bar
= "<header><nav class='main'><ul><li><a href='./'>Overview</a></li><li class=\"current\
">{mod.name}</li><li><a href='full-index.html'>Full Index</a></li></ul></nav></header>\n"
211 add
("<!DOCTYPE html>")
212 add
("<html><head>{head}<title>Module {mod.name}</title></head><body>\n")
214 add
("<div class=\"page\
">")
215 mod
.file_page_doc
(self)
217 add
("</body></html>\n")
218 write_to
("{dir}/{mod.html_name}.html")
221 # Generate pages for global classes
222 for c
in mainmod
.local_classes
do
223 if not c
.require_doc
(self) then continue
224 self.filename
= c
.html_name
225 action_bar
= "<header><nav class='main'><ul><li><a href='./'>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"
227 add
("<!DOCTYPE html>")
228 add
("<html><head>{head}<title>Class {c.name}</title></head><body>\n")
230 add
("<div class=\"page\
">")
231 c
.file_page_doc
(self)
233 add
("</body></html>\n")
234 write_to
("{dir}/{c.html_name}.html")
237 self.filename
= "fullindex"
238 action_bar
= "<header><nav class='main'><ul><li><a href='./'>Overview</a></li><li class=\"current\
">Full Index</li></ul></nav></header>\n"
240 add
("<!DOCTYPE html>")
241 add
("<html><head>{head}<title>Full Index</title></head><body>\n")
243 add
("<div class=\"page\
">")
244 add
("<div class=\"content fullpage\
">")
245 mainmod
.file_index_page_doc
(self)
248 add
("</body></html>\n")
249 write_to
("{dir}/full-index.html")
253 # Add a (source) link fo a given location
254 fun show_source
(l
: Location)
256 var s
= opt_source
.value
258 add
("in #{l.file.filename.simplify_path}")
260 # THIS IS JUST UGLY ! (but there is no replace yet)
261 var x
= s
.split_with
("%f")
262 s
= x
.join
(l
.file
.filename
.simplify_path
)
263 x
= s
.split_with
("%l")
264 s
= x
.join
(l
.line_start
.to_s
)
265 x
= s
.split_with
("%L")
266 s
= x
.join
(l
.line_end
.to_s
)
267 add
(" (<a href=\"{s}\
">show code</a>)")
271 # Generate a clicable graphiz image using a dot content.
272 # `name' refer to the filename (without extension) and the id name of the map.
273 # `name' must also match the name of the graph in the dot content (eg. digraph NAME {...)
274 fun gen_dot
(dot
: String, name
: String, alt
: String)
276 if opt_nodot
.value
then return
277 var f
= new OFStream.open
("{self.dir}/{name}.dot")
280 sys
.system
("\{ test -f {self.dir}/{name}.png && test -f {self.dir}/{name}.s.dot && diff {self.dir}/{name}.dot {self.dir}/{name}.s.dot >/dev/null 2>&1 ; \} || \{ cp {self.dir}/{name}.dot {self.dir}/{name}.s.dot && dot -Tpng -o{self.dir}/{name}.png -Tcmapx -o{self.dir}/{name}.map {self.dir}/{name}.s.dot ; \}")
281 self.add
("<article class=\"graph\
"><img src=\"{name}.png\
" usemap=\"#{name}\" style=\"margin:auto\" alt=\"{alt}\"/></article>")
282 var fmap
= new IFStream.open
("{self.dir}/{name}.map")
283 self.add
(fmap
.read_all
)
292 option_context
.add_option
(opt_public
)
293 option_context
.add_option
(opt_private
)
294 option_context
.add_option
(opt_dir
)
295 option_context
.add_option
(opt_source
)
296 option_context
.add_option
(opt_nodot
)
297 option_context
.add_option
(opt_sharedir
)
300 redef fun process_options
303 var d
= opt_dir
.value
304 if d
!= null then dir
= d
306 if not opt_nodot
.value
then
307 # Test if dot is runable
308 var res
= sys
.system
("sh -c dot </dev/null >/dev/null 2>&1")
310 stderr
.write
"--no-dot implied since `dot' is not available. Try to install graphviz.\n"
311 opt_nodot
.value
= true
315 sharedir
= opt_sharedir
.value
316 if sharedir
== null then
317 var dir
= once
("NIT_DIR".to_symbol
).environ
319 dir
= "{sys.program_name.dirname}/../share/nitdoc"
320 if dir
.file_exists
then sharedir
= dir
322 dir
= "{dir}/share/nitdoc"
323 if dir
.file_exists
then sharedir
= dir
325 if sharedir
== null then
326 fatal_error
(null, "Error: Cannot locate nitdoc shared files. Uses --sharedir or envvar NIT_DIR.")
328 dir
= "{sharedir.to_s}/scripts/js-facilities.js"
329 if sharedir
== null then
330 fatal_error
(null, "Error: Invalid nitdoc shared files. Check --sharedir or envvar NIT_DIR.")
336 redef fun handle_property_conflict
(lc
, impls
)
338 # THIS IS SO UGLY! See MMVirtualModule
339 if lc
.mmmodule
== self.mainmod
then
340 return # We just accept, so one in impls is arbitrary inherited
347 # Replace all occurence of pattern ith string
348 fun replace
(p
: Pattern, string
: String): String
350 return self.split_with
(p
).join
(string
)
353 # Escape the following characters < > & and " with their html counterpart
354 fun html_escape
: String
357 if ret
.has
('&') then ret
= ret
.replace
('&', "&")
358 if ret
.has
('<') then ret
= ret
.replace
('<', "<")
359 if ret
.has
('>') then ret
= ret
.replace
('>', ">")
360 if ret
.has
('"') then ret
= ret
.replace
('"', """)
364 # Remove "/./", "//" and "bla/../"
365 fun simplify_path
: String
367 var a
= self.split_with
("/")
368 var a2
= new Array[String]
370 if x
== "." then continue
371 if x
== "" and not a2
.is_empty
then continue
372 if x
== ".." and not a2
.is_empty
then
382 # A virtual module is used to work as an implicit main module that combine unrelated modules
383 # Since conflict may arrise in a virtual module (the main method for instance) conflicts are disabled
384 class MMVirtualModule
386 init(ctx
: MMContext, mods
: Array[MMModule])
388 # We need to compute the whole metamodel since there is no mmbuilder to do it
389 super(" main".to_symbol
, mods
.first
.directory
, ctx
, new Location(null,0,0,0,0))
390 ctx
.add_module
(self, mods
)
392 self.add_super_module
(m
, 1)
394 self.import_global_classes
395 self.import_local_classes
396 for c
in self.local_classes
do
397 c
.compute_super_classes
399 for c
in self.local_classes
do
404 redef fun require_doc
(dctx
) do return false
407 # Conditionnal part of the text content of a DocContext
409 # Content of the current stage
410 readable var _content
: Array[String] = new Array[String]
412 # Is a normal string already added?
413 readable writable var _validate
: Bool = false
415 # Parent stage is any
416 readable var _parent
: nullable StageContext = null
418 init(parent
: nullable StageContext) do _parent
= parent
422 # Efficiently sort object with their to_s method
423 class AlphaSorter[E
: Object]
424 super AbstractSorter[E
]
425 redef fun compare
(a
, b
)
445 # Keep track of to_s values
446 var _dico
: HashMap[Object, String] = new HashMap[Object, String]
451 # Generalization of metamodel entities
454 fun html_link
(dctx
: DocContext): String is abstract
456 # Return a one liner description
457 fun short_doc
: String do return " "
459 # The doc node from the AST
460 # Return null is none
461 fun doc
: nullable ADoc do return null
466 redef fun html_link
(dctx
) do
467 return "<a href=\"{html_name}.html\
" title=\"{short_doc}\
">{self}</a>"
470 fun require_doc
(dctx
: DocContext): Bool
472 if dctx
.public_only
and not is_toplevel
then return false
476 # Return true if the module is a top-level owner or a top-level module
477 fun is_toplevel
: Bool
479 var pd
= directory
.parent
480 return pd
== null or (pd
.owner
== null and directory
.owner
== self)
483 # Element in the module nesting tree
484 fun mnhe
: PartialOrderElement[MMModule] do return mnhe_
.as(not null)
485 var mnhe_
: nullable PartialOrderElement[MMModule] = null
487 # Element in the top level module importation hierarchy
488 fun tmhe
: PartialOrderElement[MMModule] do return tmhe_
.as(not null)
489 var tmhe_
: nullable PartialOrderElement[MMModule] = null
491 fun toplevel_owner
: MMModule
495 var ds
= m
.mnhe
.direct_smallers
496 if ds
.length
== 0 then return m
497 if ds
.length
== 1 then m
= ds
.first
else abort
501 fun html_name
: String
506 fun direct_owner
: nullable MMModule
509 while d
.owner
== self do d
= d
.parent
.as(not null)
513 # Fill the body for the page associated to the module
514 fun file_page_doc
(dctx
: DocContext)
516 dctx
.add
("<div class=\"menu\
">\n")
518 var mods
= new Array[MMModule]
519 mods
= self.mhe
.greaters
.to_a
523 dctx
.stage
("<nav>\n")
524 dctx
.stage
("<h3>Module Hierarchy</h3>\n")
525 dctx
.stage
("<h4>All dependencies</h4>\n")
528 if not mod
.require_doc
(dctx
) then continue
529 if self.mnhe
<= mod
then continue # do not want nested stuff
530 if mod
.direct_owner
!= null and not mod
.direct_owner
.mnhe
<= self then continue # not in the right nesting
531 dctx
.add
("<li>{mod.html_link(dctx)}</li>")
533 dctx
.stage
("</ul>\n")
535 mods
= self.mhe
.smallers
.to_a
537 dctx
.stage
("<h4>All clients</h4>\n")
540 if not mod
.require_doc
(dctx
) then continue
541 if self.mnhe
<= mod
then continue # do not want nested stuff
542 if mod
.direct_owner
!= null and not mod
.direct_owner
.mnhe
<= self then continue # not in the right nesting
543 dctx
.add
("<li>{mod.html_link(dctx)}</li>")
545 dctx
.stage
("</ul>\n")
546 dctx
.stage
("</nav>\n")
549 if not dctx
.public_only
then
550 mods
= self.mnhe
.direct_greaters
.to_a
553 dctx
.stage
("<nav>\n")
554 dctx
.stage
("<h3>Nested Modules</h3><ul>\n")
556 if not mod
.require_doc
(dctx
) then continue
557 dctx
.add
("<li>{mod.html_link(dctx)}</li>")
559 dctx
.stage
("</ul></nav>\n")
563 dctx
.add
("</div>") # metadata
565 dctx
.add
("<div class=\"content\
">\n")
566 dctx
.add
("<h1>{name}</h1>\n")
567 dctx
.add
("<div class='subtitle'>module ")
568 for m
in mnhe
.smallers
do
569 dctx
.add
("{m.html_link(dctx)}::")
571 dctx
.add
("{self.name}</div>\n")
573 dctx
.add
("<section class='description'>\n")
577 dctx
.add
("<div id=\"description\
">\n")
578 dctx
.add
("<pre>{doc.to_html}</pre>\n")
583 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")
584 var ms
= new Array[nullable MMModule]
586 var m0
: nullable MMModule = self
592 var cla
= new HashSet[MMModule]
594 for m0
in self.mhe
.greaters
do
595 if not m0
.require_doc
(dctx
) then continue
596 if self.visibility_for
(m0
) <= 1 then continue # private or hidden
597 if self.mnhe
<= m0
then continue # do not want nested stuff
598 if m0
.direct_owner
!= null and not m0
.direct_owner
.mnhe
<= self then continue # not in the right nesting
601 for m0
in self.mhe
.smallers
do
602 if not m0
.require_doc
(dctx
) then continue
603 if m0
.visibility_for
(self) <= 1 then continue # private or hidden
604 if m0
.direct_owner
!= null and not m0
.direct_owner
.mnhe
<= self then continue # not in the right nesting
607 for m0
in self.mnhe
.smallers
do
613 op
.append
("subgraph \"cluster_
{m0.name}\
"\{\n")
616 if c
.direct_owner
!= m0
then continue
618 op
.append
("\"{c.name}\
"[shape=box,margin=0.03];\n")
620 op
.append
("\"{c.name}\
"[URL=\"{c.html_name}.html\
"];\n")
624 op
.append
("\"{m0.name}\
"[URL=\"{m0.html_name}.html\
"];\n")
625 for c
in m0
.mhe
.direct_greaters
do
626 if not cla
.has
(c
) then continue
627 op
.append
("\"{m0.name}\
"->\"{c.name}\
";\n")
632 # Close the nesting subgraph
638 for c2
in c
.tmhe
.direct_greaters
do
639 if not cla
.has
(c2
) then continue
640 op
.append
("\"{c.name}\
"->\"{c2.name}\
";\n")
644 dctx
.gen_dot
(op
.to_s
, name
.to_s
, "Dependency graph for module {name}")
645 dctx
.add
("</section>")
647 var clas
= new Array[MMLocalClass]
648 var props
= new HashMap[MMGlobalProperty, Array[MMLocalProperty]]
649 var gprops
= new Array[MMLocalProperty]
652 for g
in m
.global_classes
do
654 if not lc
.require_doc
(dctx
) then continue
655 var im
= g
.intro
.mmmodule
656 if self.visibility_for
(im
) <= 1 then continue # private import or invisible import
658 for lc2
in lc
.crhe
.greaters_and_self
do
659 if not lc2
isa MMSrcLocalClass then continue
660 if not self.mnhe
<= lc2
.mmmodule
then continue # not introduced/redefined here/stolen
663 if not keep
then continue
665 lc
.compute_super_classes
666 for gp
in lc
.global_properties
do
667 if self.visibility_for
(gp
.intro
.local_class
.mmmodule
) <= 1 then continue # private import or invisible import
669 var mp
= lp
.local_class
.mmmodule
670 if not self.mnhe
<= mp
then continue # not introduced/redefined here/stolen
672 if not lp
.require_doc
(dctx
) then continue
673 if props
.has_key
(lp
.global
) then
674 if not props
[lp
.global
].has
(lp
) then
675 props
[lp
.global
].add
(lp
)
678 props
[lp
.global
] = [lp
]
679 gprops
.add
(lp
.global
.intro
)
684 dctx
.add
("<section class=\"module\
">\n")
686 dctx
.stage
("<article class=\"classes filterable\
">\n")
687 dctx
.stage
("<h2>Classes</h2>\n")
691 if self.mnhe
<= lc
.global
.intro
.mmmodule
then
692 dctx
.add
("<li class='intro'><span title='introduced in this module'>I</span> ")
694 dctx
.add
("<li class='redef'><span title='refined in this module'>R</span> ")
696 dctx
.add
("{lc.html_link(dctx)}</li>\n")
698 dctx
.stage
("</ul></article>\n")
702 dctx
.stage
("<article class=\"properties filterable\
">\n")
703 dctx
.stage
("<h2>Properties</h2>\n")
710 if gp
.intro
isa MMAttribute then continue
712 var lpi
= self[gp
.intro
.local_class
.global
][gp
]
715 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")
718 dctx
.add
("<li class='intro'><span title='introduction in this module'>I</span> {lpi.html_name}")
719 dctx
.add
(" ({lpi.local_class})</li>\n")
721 if lps
.length
>= 1 then
724 dctx
.add
("<li class='redef'><span title='redefinition'>R</span> {lp.html_open_link(dctx)}{lp.html_name} ({lp.local_class})</a></li>")
728 dctx
.stage
("</ul></article>\n")
730 dctx
.add
("</section>\n")
734 # Fill the body for the page associated to the full index
735 fun file_index_page_doc
(dctx
: DocContext)
738 dctx
.add
("<h1>Full Index</h1>\n")
740 var clas
= new Array[MMLocalClass]
741 var props
= new HashMap[MMGlobalProperty, Array[MMLocalProperty]]
742 var gprops
= new Array[MMLocalProperty]
743 var mods
= new Array[MMModule]
744 for m
in mhe
.greaters_and_self
do
745 if not m
.require_doc
(dctx
) then continue
748 for g
in global_classes
do
750 if not lc
.require_doc
(dctx
) then continue
752 for gp
in lc
.global_properties
do
754 if not lp
.require_doc
(dctx
) then continue
755 if props
.has_key
(lp
.global
) then
756 if not props
[lp
.global
].has
(lp
) then
757 props
[lp
.global
].add
(lp
)
760 props
[lp
.global
] = [lp
]
761 gprops
.add
(lp
.global
.intro
)
766 dctx
.stage
("<article class=\"modules filterable\
">\n")
767 dctx
.stage
("<h2>Modules</h2>\n")
771 dctx
.add
("<li>{m.html_link(dctx)}</li>")
773 dctx
.stage
("</ul></article>\n")
777 dctx
.stage
("<article class=\"classes filterable\
">\n")
778 dctx
.stage
("<h2>Classes</h2>\n")
782 dctx
.add
("<li>{lc.html_link(dctx)}</li>")
784 dctx
.stage
("</ul></article>\n")
788 dctx
.stage
("<article class=\"properties filterable\
">\n")
789 dctx
.stage
("<h2>Properties</h2>\n")
796 if gp
.intro
isa MMAttribute then continue
798 var lpi
= self[gp
.intro
.local_class
.global
][gp
]
801 dctx
.add
("<li class='intro'><span title='introduction'>I</span> {lpi.html_open_link(dctx)}{lpi.html_name} ({lpi.local_class})</a></li>\n")
802 if lps
.length
>= 1 then
805 dctx
.add
("<li class='redef'><span title='redefinition'>R</span> {lp.html_open_link(dctx)}{lp.html_name} ({lp.local_class})</a></li>\n")
809 dctx
.stage
("</ul></article>\n")
814 redef class MMLocalProperty
816 # Anchor of the property description in the module html file
817 fun html_anchor
: String
819 return "PROP_{local_class}_{cmangle(name)}"
822 fun html_open_link
(dctx
: DocContext): String
824 if not require_doc
(dctx
) then print
"not required {self}"
825 var title
= "{html_name}{signature.to_s}"
826 if short_doc
!= " " then
827 title
+= " #{short_doc}"
829 return "<a href=\"{local_class.html_name}.html
#{html_anchor}\" title=\"{title}\">"
832 fun html_name
: String
834 return self.name
.to_s
.html_escape
837 redef fun html_link
(dctx
)
839 if not require_doc
(dctx
) then print
"not required {self}"
840 var title
= "{html_name}{signature.to_s}"
841 if short_doc
!= " " then
842 title
+= " #{short_doc}"
844 return "<a href=\"{local_class.html_name}.html
#{html_anchor}\" title=\"{title}\">{html_name}</a>"
847 fun html_link_special
(dctx
: DocContext, lc
: MMLocalClass): String
849 if not require_doc
(dctx
) then print
"not required {self}"
850 var title
= "{html_name}{signature_for(lc.get_type)}"
851 if short_doc
!= " " then
852 title
+= " #{short_doc}"
854 return "<a href=\"{lc.html_name}.html
#{html_anchor}\" title=\"{title}\">{html_name}</a>"
857 # Kind of property (fun, attr, etc.)
858 fun kind
: String is abstract
865 else if global
.intro
== self then
868 return global
.intro
.short_doc
875 if n
== null or not n
isa APropdef then
882 if d
.n_comment
.is_empty
then
889 # The most specific module in the nesting hierarchy that exports the intro of self
890 fun intro_module
: MMModule
892 var m
= global
.intro
.mmmodule
893 var mo
= m
.direct_owner
894 while mo
!= null and mo
.visibility_for
(m
) >= 2 do
901 # Is the intro of self exported by the top-level module ?
902 fun is_toplevel
: Bool
905 return m
== m
.toplevel_owner
908 # Return true if the global property must be documented according to the visibility configured
909 fun require_doc
(dctx
: DocContext): Bool
911 if global
.visibility_level
== 3 and not dctx
.with_private
then return false # Private
912 if dctx
.public_only
then
914 if m
!= m
.toplevel_owner
then return false # Unexported
919 # Document the global property in the global class lc
920 fun full_documentation
(dctx
: DocContext, lc
: MMLocalClass)
922 var visibility
: String
923 if global
.visibility_level
== 1 then
924 visibility
= "public"
925 else if global
.visibility_level
== 2 then
926 visibility
= "protected"
927 else if global
.visibility_level
== 3 then
928 visibility
= "private"
933 var intro_class
= global
.intro
.local_class
934 var is_redef
= local_class
.global
!= intro_class
.global
or local_class
.mmmodule
.toplevel_owner
!= intro_class
.mmmodule
.toplevel_owner
936 dctx
.add
("<article id=\"{html_anchor}\
" class=\"{kind} {visibility} {if is_redef then "redef" else ""}\
">\n")
937 dctx
.add
("<h3 class=\"signature\
">{html_name}{signature.to_html(dctx, true)}</h3>\n")
938 dctx
.add
("<div class=\"info\
">\n")
939 #dctx.add("<p>LP: {self.mmmodule.html_link(dctx)}::{self.local_class.html_link(dctx)}::{self.html_link(dctx)}</p>")
944 if not is_toplevel
then
945 dctx
.add
("(unexported) ")
947 if global
.visibility_level
== 2 then
948 dctx
.add
("protected ")
949 else if global
.visibility_level
== 3 then
953 dctx
.add
(" {intro_class.mmmodule.toplevel_owner.name}")
954 if intro_class
.global
== lc
.global
then
955 dctx
.add
("::{lc.name}")
957 dctx
.add
("::{mmmodule[intro_class.global].html_link(dctx)}")
960 dctx
.add
("::{mmmodule[intro_class.global][global].html_link(dctx)}")
962 dctx
.add
("::{html_name}")
966 dctx
.add
("<div class=\"description\
">")
968 # Collect all refinement of the global property in the same global property
969 var lps
= new Array[MMLocalProperty]
970 for l
in prhe
.greaters_and_self
do
975 if global
.intro
.doc
!= null then
977 if lp
.doc
== null then introdoc
= true
981 dctx
.add
("<pre>{global.intro.doc.to_html}</pre>")
984 var tlmods
= new Array[MMModule]
986 var bm
= lp
.mmmodule
.toplevel_owner
987 var lcm
= lc
.global
.intro
.mmmodule
988 if lcm
.mhe
< lp
.mmmodule
then bm
= lcm
.toplevel_owner
989 if not tlmods
.has
(bm
) then tlmods
.add
(bm
)
993 # Document the top level property for the current top level module
995 if tm
.global_classes
.has
(lc
.global
) then
996 tlp
= tm
[lc
.global
][self.global
]
998 else if tm
.global_classes
.has
(self.local_class
.global
) then
999 # Self is the inherited property. Process it
1000 tlp
= tm
[self.local_class
.global
][self.global
]
1003 # We skip this module since the props defined by the module is
1007 var tlcm
= lc
.global
.intro
.mmmodule
.toplevel_owner
1008 if not tlcm
.mhe
<= tm
then
1009 dctx
.add
("<h4>In module {tm.html_link(dctx)} :</h4>")
1012 #dctx.add("<p>TLP: {tm} x {lc} : {tlp.full_name}</p>")
1015 if doc
!= null and (not introdoc
or global
.intro
.doc
!= doc
) then
1016 dctx
.add
("<pre>{doc.to_html}</pre>")
1019 if tlp
.local_class
.global
!= lc
.global
then
1020 dctx
.add
("inherited from {tlp.local_class.html_link(dctx)} ")
1022 if tm
!= tlp
.mmmodule
then
1023 dctx
.add
("defined by the module {tlp.mmmodule.html_link(dctx)} ")
1032 dctx
.stage
(". previously defined by:")
1034 var tl
= lp
.mmmodule
.toplevel_owner
1035 if tl
!= tm
then continue
1036 if lp
== tlp
then continue
1037 dctx
.add
(" {lp.mmmodule.html_link(dctx)}")
1038 if lp
.local_class
.global
!= lc
.global
then
1039 dctx
.add
(" for {lp.local_class.html_link(dctx)}")
1049 #if doc != null and (not introdoc or global.intro.doc != doc) then
1050 # dctx.add("<pre>{doc.to_html}</pre>")
1057 dctx
.add
("</article>")
1060 redef class MMMethod
1061 redef fun kind
do return if global
.is_init
then "init" else "fun"
1063 redef class MMAttribute
1064 redef fun kind
do return "var"
1066 redef class MMTypeProperty
1067 redef fun kind
do return "type"
1070 redef class MMSrcModule
1084 if n
.n_moduledecl
== null then
1087 var np
= n
.n_moduledecl
1092 if d
.n_comment
.is_empty
then
1101 # Html transcription of the doc
1104 var res
= new Buffer
1105 for c
in n_comment
do
1106 res
.append
(c
.text
.substring_from
(1))
1108 return res
.to_s
.html_escape
1111 # Oneliner transcription of the doc
1114 return n_comment
.first
.text
.substring_from
(1).html_escape
1118 redef class MMLocalClass
1121 # Anchor of the class description in the module html file
1122 fun html_anchor
: String do return "CLASS_{self}"
1124 fun html_name
: String do return "{self}"
1126 redef fun html_link
(dctx
)
1128 if not require_doc
(dctx
) then print
"{dctx.filename}: not required {self}"
1129 return "<a href=\"{html_name}.html\
" title=\"{short_doc}\
">{self}</a>"
1132 redef fun short_doc
do return global
.intro
.short_doc
1134 redef fun doc
do return global
.intro
.doc
1138 if global
.is_interface
then
1140 else if global
.is_abstract
then
1141 return "abstract class"
1142 else if global
.is_enum
then
1149 # The most specific module in the nesting hierarchy that exports the intro of self
1150 fun intro_module
: MMModule
1152 var m
= global
.intro
.mmmodule
1153 var mo
= m
.direct_owner
1154 while mo
!= null and mo
.visibility_for
(m
) >= 2 do
1161 fun menu_link
(dctx
: DocContext, p
: MMLocalProperty)
1163 if p
.local_class
.global
!= self.global
then
1164 if p
.global
.intro
.local_class
.name
== "Object".to_symbol
then return
1165 if p
.global
.is_init
or p
isa MMTypeProperty then
1166 dctx
.add
("<li class='inherit'><span title='Inherited'>H</span> {p.html_link_special(dctx, self)}</li>\n")
1168 dctx
.add
("<li class='inherit'><span title='Inherited'>H</span> {p.html_link(dctx)}</li>\n")
1170 else if p
.global
.intro
.local_class
.global
== self.global
then
1171 dctx
.add
("<li class='intro'><span title='Introduced'>I</span> {p.html_link_special(dctx, self)}</li>\n")
1173 dctx
.add
("<li class='redef'><span title='Redefined'>R</span> {p.html_link_special(dctx, self)}</li>\n")
1177 # Return true if the global class must be documented according to the visibility configured
1178 fun require_doc
(dctx
: DocContext): Bool
1180 if global
.visibility_level
== 3 and not dctx
.with_private
then return false # Private
1181 if dctx
.public_only
then
1182 var m
= intro_module
1183 if m
!= m
.toplevel_owner
then return false # Unexported
1188 # Fill the body for the page associated to the global class
1189 fun file_page_doc
(dctx
: DocContext)
1191 dctx
.add
("<div class=\"menu\
">\n")
1193 var props
= new Array[MMLocalProperty]
1194 var inh
= new HashMap[MMLocalClass, Array[MMLocalProperty]]
1195 var inhs
= new Array[MMLocalClass]
1196 for g
in global_properties
do
1198 if not p
.require_doc
(dctx
) then continue
1199 if p
.local_class
.global
== global
or g
.is_init_for
(self) or p
isa MMTypeProperty then
1202 var lc
= mmmodule
[p
.local_class
.global
]
1203 if inh
.has_key
(lc
) then
1214 dctx
.add
("<nav class=\"properties filterable\
">\n")
1215 dctx
.add
("<h3>Properties</h3>\n")
1217 dctx
.stage
("<h4>Virtual Types</h4>\n<ul>\n")
1219 if p
isa MMTypeProperty then
1223 dctx
.stage
("</ul>\n")
1226 dctx
.stage
("<h4>Constructors</h4>\n<ul>\n")
1228 if p
.global
.is_init_for
(self) then
1232 dctx
.stage
("</ul>\n")
1235 dctx
.stage
("<h4>Methods</h4>\n<ul>\n")
1237 if not p
.global
.is_init
and p
isa MMMethod then
1241 dctx
.stage
("</ul>\n")
1243 dctx
.add
("</nav>\n")
1245 dctx
.add
("<nav class=\"inheritance filterable\
">\n")
1246 dctx
.add
("<h3>Inheritance</h3>\n")
1247 dctx
.add
("<h4>Superclasses</h4>\n<ul>\n")
1248 for lc
in cshe
.linear_extension
do
1249 if lc
== self then continue
1250 if not lc
.require_doc
(dctx
) then continue
1251 dctx
.add
("<li>{lc.html_link(dctx)}</li>\n")
1254 if cshe
.smallers
.length
== 0 then
1255 dctx
.add
("<h4>No Known Subclasses</h4>\n")
1256 else if cshe
.smallers
.length
<= 100 then
1257 dctx
.add
("<h4>Subclasses</h4>\n")
1259 for lc
in cshe
.smallers
do
1260 if not lc
.require_doc
(dctx
) then continue
1261 dctx
.add
("<li>{lc.html_link(dctx)}</li>\n")
1264 else if cshe
.direct_smallers
.length
<= 100 then
1265 dctx
.add
("<h4>Direct Subclasses Only</h4>\n<ul>\n")
1266 for lc
in cshe
.direct_smallers
do
1267 if not lc
.require_doc
(dctx
) then continue
1268 dctx
.add
("<li>{lc.html_link(dctx)}</li>\n")
1272 dctx
.add
("<h4>Too much Subclasses to list</h4>\n")
1274 dctx
.add
("</nav>\n")
1276 dctx
.add
("</div>\n")
1279 dctx
.add
("<div class=\"content\
">\n")
1280 dctx
.add
("<h1>{name}</h1>\n")
1281 dctx
.add
("<div class='subtitle'>")
1282 if global
.visibility_level
== 2 then
1284 else if global
.visibility_level
== 3 then
1285 dctx
.add
("private ")
1286 else if self.global
.intro
.mmmodule
.toplevel_owner
.visibility_for
(self.global
.intro
.mmmodule
) <= 1 then
1287 dctx
.add
("(unexported) ")
1289 dctx
.add
("{kind} {global.intro.mmmodule.toplevel_owner.html_link(dctx)}::{name}</div>")
1291 dctx
.add
("<section class=\"description\
">\n")
1294 dctx
.add
("<pre>{doc.to_html}</pre>\n")
1297 var cla
= new HashSet[MMLocalClass]
1298 var sm
= new HashSet[MMLocalClass]
1299 var sm2
= new HashSet[MMLocalClass]
1301 while cla
.length
+ sm
.length
< 10 and sm
.length
> 0 do
1305 sm2
.add_all
(x
.cshe
.direct_smallers
)
1311 cla
.add_all
(cshe
.greaters_and_self
)
1314 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")
1317 op
.append
("\"{c.name}\
"[shape=box,margin=0.03];\n")
1319 op
.append
("\"{c.name}\
"[URL=\"{c.html_name}.html\
"];\n")
1321 for c2
in c
.cshe
.direct_greaters
do
1322 if not cla
.has
(c2
) then continue
1323 op
.append
("\"{c.name}\
"->\"{c2.name}\
";\n")
1325 if not c
.cshe
.direct_smallers
.is_empty
then
1327 for c2
in c
.cshe
.direct_smallers
do
1328 if cla
.has
(c2
) then others
= false
1331 op
.append
("\"{c.name}...\
"[label=\"\
"];\n")
1332 op
.append
("\"{c.name}...\
"->\"{c.name}\
"[style=dotted];\n")
1337 dctx
.gen_dot
(op
.to_s
, name
.to_s
, "Inheritance graph for class {name}")
1340 var mods
= new Array[MMModule]
1341 mods
.add
(global
.intro
.mmmodule
.toplevel_owner
)
1342 for lc
in crhe
.greaters
do
1343 if not lc
isa MMSrcLocalClass then continue
1344 var m
= lc
.mmmodule
.toplevel_owner
1345 if not mods
.has
(m
) then mods
.add
(m
)
1349 if m
== global
.intro
.mmmodule
.toplevel_owner
then
1350 dctx
.add
("<p>Introduced by {m.html_link(dctx)}")
1352 dctx
.add
("<p>Refined by {m.html_link(dctx)}")
1355 dctx
.stage
(". Definition in:")
1356 for lc
in crhe
.greaters
do
1357 if lc
.mmmodule
.toplevel_owner
!= m
then continue
1358 dctx
.add
(" {lc.mmmodule.html_link(dctx)}")
1359 assert lc
isa MMSrcLocalClass
1362 dctx
.show_source
(n
.location
)
1368 dctx
.add
("</section>\n")
1371 dctx
.stage
("<section class=\"types\
">\n")
1372 dctx
.stage
("<h2>Formal and Virtual Types</h2>\n")
1373 for i
in [0..arity
[ do
1374 var f
= get_formal
(i
)
1375 f
.full_documentation
(dctx
, self)
1378 if not p
isa MMTypeProperty then continue
1379 p
.full_documentation
(dctx
, self)
1381 dctx
.stage
("</section>\n")
1385 dctx
.stage
("<section class=\"constructors\
">\n")
1386 dctx
.stage
("<h2 class=\"section-header\
">Constructors</h2>\n")
1388 if not p
.global
.is_init_for
(self) then continue
1389 p
.full_documentation
(dctx
, self)
1391 dctx
.stage
("</section>\n")
1395 dctx
.stage
("<section class=\"methods\
">\n")
1396 dctx
.stage
("<h2 class=\"section-header\
">Methods</h2>\n")
1398 if p
.global
.is_init
then continue
1399 if p
.local_class
.global
!= self.global
then continue
1400 if not p
isa MMMethod then continue
1401 p
.full_documentation
(dctx
, self)
1403 if not inhs
.is_empty
then
1405 dctx
.stage
("<h3>Inherited Methods</h3>\n")
1408 dctx
.stage
("<p>Defined in {lc.html_link(dctx)}:")
1410 if p
.global
.is_init
then continue
1411 if not p
isa MMMethod then continue
1412 dctx
.add
(" {p.html_link(dctx)}")
1419 dctx
.add
("</section>\n")
1421 dctx
.add
("</div> <!-- end class {name} -->\n")
1425 redef class MMSrcLocalClass
1431 else if global
.intro
== self then
1434 var bc
= global
.intro
1442 if not n
isa AStdClassdef then
1449 if d
.n_comment
.is_empty
then
1457 redef class MMSignature
1458 # Htlm transcription of the signature (with nested links)
1459 fun to_html
(dctx
: DocContext, with_closure
: Bool): String
1461 var res
= new Buffer
1464 for i
in [0..arity
[ do
1465 if i
> 0 then res
.append
(", ")
1466 res
.append
(self.params
[i
].name
.to_s
)
1468 res
.append
(self[i
].html_link
(dctx
))
1469 if self.vararg_rank
== i
then
1475 if return_type
!= null then
1477 res
.append
(return_type
.html_link
(dctx
))
1479 if with_closure
then
1480 for c
in closures
do
1482 if c
.is_optional
then res
.append
("[")
1483 if c
.is_break
then res
.append
("break ")
1484 res
.append
("!{c.name}")
1485 res
.append
(c
.signature
.to_html
(dctx
, false))
1486 if c
.is_optional
then res
.append
("]")
1494 # Htlm transcription of the type (with nested links)
1495 fun html_link
(dctx
: DocContext): String do return to_s
1498 redef class MMTypeSimpleClass
1499 redef fun html_link
(dctx
) do return local_class
.html_link
(dctx
)
1502 redef class MMTypeGeneric
1503 redef fun html_link
(dctx
)
1505 var res
= new Buffer
1506 res
.append
(local_class
.html_link
(dctx
))
1508 res
.append
(params
[0].html_link
(dctx
))
1509 for i
in [1..params
.length
[ do
1511 res
.append
(params
[i
].html_link
(dctx
))
1518 redef class MMTypeFormalParameter
1519 fun html_anchor
: String
1521 return "FT_{local_class}_{cmangle(name)}"
1523 redef fun html_link
(dctx
)
1525 return "<a href=\"#{html_anchor}\">{name}</a>"
1527 fun full_documentation
(dctx
: DocContext, lc
: MMLocalClass)
1529 dctx
.add
("<article id=\"{html_anchor}\
">\n")
1530 dctx
.add
("<h3 class=\"signature\
">{name}: {bound.html_link(dctx)}</h3>\n")
1531 dctx
.add
("<div class=\"info\
">")
1532 dctx
.add
("formal generic type")
1534 dctx
.add
("</article>")
1538 redef class MMNullableType
1539 redef fun html_link
(dctx
) do return "nullable " + as_notnull
.html_link
(dctx
)
1542 redef class MMVirtualType
1543 redef fun html_link
(dctx
) do return property
.html_link
(dctx
)
1546 var c
= new DocContext