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 readable var _opt_overview_text
: OptionString = new OptionString("Text displayed as introduction of Overview page", "--overview-text")
90 readable var _opt_footer_text
: OptionString = new OptionString("Text displayed as footer of all pages", "--footer-text")
91 var sharedir
: nullable String
95 if self._opt_public
.value
== true then return true
99 fun with_private
: Bool
101 if self._opt_private
.value
== true then return true
105 # The current processed filename
108 # The main virtual module
109 var mainmod
: nullable MMVirtualModule
111 redef fun perform_work
(mods
)
113 mainmod
= new MMVirtualModule(self, mods
)
117 sys
.system
("cp -r '{sharedir.to_s}'/* {dir}/")
119 # Compute the set of direct owned nested modules
120 var owns
= new HashMap[MMModule, Array[MMModule]]
121 for mod
in modules
do
122 owns
[mod
] = new Array[MMModule]# [mod]
124 for mod
in modules
do
125 if mod
== mainmod
then continue
126 var d
= mod
.directory
129 if o
!= null and o
!= mod
then
133 if dp
== null or dp
== d
then break
138 # Builds the various module hierarchies
139 var mnh
= new PartialOrder[MMModule] # nested module hierarchy
140 var tmh
= new PartialOrder[MMModule] # top module import hierrchy
141 var ms
= mainmod
.mhe
.linear_extension
.reversed
143 if ms
== mainmod
then continue
144 m
.mnhe_
= mnh
.add
(m
, owns
[m
])
145 var pub
= new Array[MMModule]
146 for m2
in m
.mhe
.greaters
do
147 if m2
.toplevel_owner
!= m2
and m2
.toplevel_owner
!= m
.toplevel_owner
then continue
148 if m
.mnhe
<= m2
then continue
149 if m
.visibility_for
(m2
) <= 0 then
151 else if m
.visibility_for
(m2
) == 1 then
156 m
.tmhe_
= tmh
.add
(m
, pub
)
159 var head
= "<meta charset=\"utf-8\
">" +
160 "<script type=\"text
/javascript\
" src=\"scripts
/jquery-1
.7
.1.min
.js\
"></script>\n" +
161 "<script type=\"text
/javascript\
" src=\"scripts
/js-facilities
.js\
"></script>\n" +
162 "<link rel=\"stylesheet\
" href=\"styles
/main
.css\
" type=\"text
/css\
" media=\"screen\
" />"
164 var action_bar
= "<header><nav class='main'><ul><li class=\"current\
">Overview</li><li><a href='full-index.html'>Full Index</a></li><li><a href=\"help
.html\
">Help</a></li></ul></nav></header>\n"
166 var overview_text
= ""
167 if self._opt_overview_text
.value
!= null then overview_text
= self._opt_overview_text
.value
.as(not null)
170 if self._opt_footer_text
.value
!= null then footer_text
= self._opt_footer_text
.value
.as(not null)
173 self.filename
= "index.html"
175 add
("<!DOCTYPE html>")
176 add
("<html><head>{head}<title>Index</title></head><body>\n")
178 add
("<div class=\"page\
">")
179 add
("<div class=\"content fullpage\
">")
180 add
("<h1>Modules</h1>\n<article class='overview'>{overview_text}<ul>")
181 var modss
= mainmod
.mhe
.greaters_and_self
.to_a
184 if not mod
.is_toplevel
then continue
185 if not mod
.require_doc
(self) then continue
186 assert mod
isa MMSrcModule
187 add
("<li>{mod.html_link(self)} {mod.short_doc}</li>")
193 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")
195 if not mod
.is_toplevel
then continue
196 if not mod
.require_doc
(self) then continue
197 op
.append
("\"{mod.name}\
"[URL=\"{mod.html_name}.html\
"];\n")
198 for mod2
in mod
.tmhe
.direct_greaters
do
199 if not modss
.has
(mod2
) then continue
200 op
.append
("\"{mod.name}\
"->\"{mod2.name}\
";\n")
204 self.gen_dot
(op
.to_s
, "dep", "Modules hierarchy")
205 add
("</article></div>")
206 add
("<div class='clear'></div>")
208 add
("<footer>{footer_text}</footer>")
209 add
("</body></html>\n")
210 write_to
("{dir}/index.html")
212 # Generate page for modules
213 for mod
in modules
do
214 if mod
== mainmod
then continue
215 assert mod
isa MMSrcModule
216 if not mod
.require_doc
(self) then continue
217 self.filename
= mod
.html_name
218 action_bar
= "<header><nav class='main'><ul><li><a href='./index.html'>Overview</a></li><li class=\"current\
">{mod.name}</li><li><a href='full-index.html'>Full Index</a></li><li><a href=\"help
.html\
">Help</a></li></ul></nav></header>\n"
220 add
("<!DOCTYPE html>")
221 add
("<html><head>{head}<title>Module {mod.name}</title></head><body>\n")
223 add
("<div class=\"page\
">")
224 mod
.file_page_doc
(self)
226 add
("<footer>{footer_text}</footer>")
227 add
("</body></html>\n")
228 write_to
("{dir}/{mod.html_name}.html")
231 # Generate pages for global classes
232 for c
in mainmod
.local_classes
do
233 if not c
.require_doc
(self) then continue
234 self.filename
= c
.html_name
235 action_bar
= "<header><nav class='main'><ul><li><a href='./index.html'>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><li><a href=\"help
.html\
">Help</a></li></ul></nav></header>\n"
237 add
("<!DOCTYPE html>")
238 add
("<html><head>{head}<title>Class {c.name}</title></head><body>\n")
240 add
("<div class=\"page\
">")
241 c
.file_page_doc
(self)
243 add
("<footer>{footer_text}</footer>")
244 add
("</body></html>\n")
245 write_to
("{dir}/{c.html_name}.html")
248 self.filename
= "fullindex"
249 action_bar
= "<header><nav class='main'><ul><li><a href='./index.html'>Overview</a></li><li class=\"current\
">Full Index</li><li><a href=\"help
.html\
">Help</a></li></ul></nav></header>\n"
251 add
("<!DOCTYPE html>")
252 add
("<html><head>{head}<title>Full Index</title></head><body>\n")
254 add
("<div class=\"page\
">")
255 add
("<div class=\"content fullpage\
">")
256 mainmod
.file_index_page_doc
(self)
259 add
("<footer>{footer_text}</footer>")
260 add
("</body></html>\n")
261 write_to
("{dir}/full-index.html")
265 # Add a (source) link fo a given location
266 fun show_source
(l
: Location)
268 var s
= opt_source
.value
270 add
("in {l.file.filename.simplify_path}")
272 # THIS IS JUST UGLY ! (but there is no replace yet)
273 var x
= s
.split_with
("%f")
274 s
= x
.join
(l
.file
.filename
.simplify_path
)
275 x
= s
.split_with
("%l")
276 s
= x
.join
(l
.line_start
.to_s
)
277 x
= s
.split_with
("%L")
278 s
= x
.join
(l
.line_end
.to_s
)
279 add
(" (<a href=\"{s}\
">show code</a>)")
283 # Generate a clicable graphiz image using a dot content.
284 # `name' refer to the filename (without extension) and the id name of the map.
285 # `name' must also match the name of the graph in the dot content (eg. digraph NAME {...)
286 fun gen_dot
(dot
: String, name
: String, alt
: String)
288 if opt_nodot
.value
then return
289 var f
= new OFStream.open
("{self.dir}/{name}.dot")
292 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 ; \}")
293 self.add
("<article class=\"graph\
"><img src=\"{name}.png\
" usemap=\"#{name}\" style=\"margin:auto\" alt=\"{alt}\"/></article>")
294 var fmap
= new IFStream.open
("{self.dir}/{name}.map")
295 self.add
(fmap
.read_all
)
304 option_context
.add_option
(opt_public
)
305 option_context
.add_option
(opt_private
)
306 option_context
.add_option
(opt_dir
)
307 option_context
.add_option
(opt_source
)
308 option_context
.add_option
(opt_nodot
)
309 option_context
.add_option
(opt_sharedir
)
310 option_context
.add_option
(opt_overview_text
)
311 option_context
.add_option
(opt_footer_text
)
314 redef fun process_options
317 var d
= opt_dir
.value
318 if d
!= null then dir
= d
320 if not opt_nodot
.value
then
321 # Test if dot is runable
322 var res
= sys
.system
("sh -c dot </dev/null >/dev/null 2>&1")
324 stderr
.write
"--no-dot implied since `dot' is not available. Try to install graphviz.\n"
325 opt_nodot
.value
= true
329 sharedir
= opt_sharedir
.value
330 if sharedir
== null then
331 var dir
= once
("NIT_DIR".to_symbol
).environ
333 dir
= "{sys.program_name.dirname}/../share/nitdoc"
334 if dir
.file_exists
then sharedir
= dir
336 dir
= "{dir}/share/nitdoc"
337 if dir
.file_exists
then sharedir
= dir
339 if sharedir
== null then
340 fatal_error
(null, "Error: Cannot locate nitdoc shared files. Uses --sharedir or envvar NIT_DIR.")
342 dir
= "{sharedir.to_s}/scripts/js-facilities.js"
343 if sharedir
== null then
344 fatal_error
(null, "Error: Invalid nitdoc shared files. Check --sharedir or envvar NIT_DIR.")
350 redef fun handle_property_conflict
(lc
, impls
)
352 # THIS IS SO UGLY! See MMVirtualModule
353 if lc
.mmmodule
== self.mainmod
then
354 return # We just accept, so one in impls is arbitrary inherited
360 # A virtual module is used to work as an implicit main module that combine unrelated modules
361 # Since conflict may arrise in a virtual module (the main method for instance) conflicts are disabled
362 class MMVirtualModule
364 init(ctx
: MMContext, mods
: Array[MMModule])
366 # We need to compute the whole metamodel since there is no mmbuilder to do it
367 super(" main".to_symbol
, mods
.first
.directory
, ctx
, new Location(null,0,0,0,0))
368 ctx
.add_module
(self, mods
)
370 self.add_super_module
(m
, 1)
372 self.import_global_classes
373 self.import_local_classes
374 for c
in self.local_classes
do
375 c
.compute_super_classes
377 for c
in self.local_classes
do
382 redef fun require_doc
(dctx
) do return false
385 # Conditionnal part of the text content of a DocContext
387 # Content of the current stage
388 readable var _content
: Array[String] = new Array[String]
390 # Is a normal string already added?
391 readable writable var _validate
: Bool = false
393 # Parent stage is any
394 readable var _parent
: nullable StageContext = null
396 init(parent
: nullable StageContext) do _parent
= parent
400 # Efficiently sort object with their to_s method
401 class AlphaSorter[E
: Object]
402 super AbstractSorter[E
]
403 redef fun compare
(a
, b
)
423 # Keep track of to_s values
424 var _dico
: HashMap[Object, String] = new HashMap[Object, String]
429 # Generalization of metamodel entities
432 fun html_link
(dctx
: DocContext): String is abstract
434 # Return a one liner description
435 fun short_doc
: String do return " "
437 # The doc node from the AST
438 # Return null is none
439 fun doc
: nullable ADoc do return null
444 redef fun html_link
(dctx
) do
445 return "<a href=\"{html_name}.html\
" title=\"{short_doc}\
">{self}</a>"
448 fun require_doc
(dctx
: DocContext): Bool
450 if dctx
.public_only
and not is_toplevel
then return false
454 # Return true if the module is a top-level owner or a top-level module
455 fun is_toplevel
: Bool
457 var pd
= directory
.parent
458 return pd
== null or (pd
.owner
== null and directory
.owner
== self)
461 # Element in the module nesting tree
462 fun mnhe
: PartialOrderElement[MMModule] do return mnhe_
.as(not null)
463 var mnhe_
: nullable PartialOrderElement[MMModule] = null
465 # Element in the top level module importation hierarchy
466 fun tmhe
: PartialOrderElement[MMModule] do return tmhe_
.as(not null)
467 var tmhe_
: nullable PartialOrderElement[MMModule] = null
469 fun toplevel_owner
: MMModule
473 var ds
= m
.mnhe
.direct_smallers
474 if ds
.length
== 0 then return m
475 if ds
.length
== 1 then m
= ds
.first
else abort
479 fun html_name
: String
484 fun direct_owner
: nullable MMModule
487 while d
.owner
== self do d
= d
.parent
.as(not null)
491 # Fill the body for the page associated to the module
492 fun file_page_doc
(dctx
: DocContext)
494 dctx
.add
("<div class=\"menu\
">\n")
496 var mods
= new Array[MMModule]
497 mods
= self.mhe
.greaters
.to_a
501 dctx
.stage
("<nav>\n")
502 dctx
.stage
("<h3>Module Hierarchy</h3>\n")
503 dctx
.stage
("<h4>All dependencies</h4>\n")
506 if not mod
.require_doc
(dctx
) then continue
507 if self.mnhe
<= mod
then continue # do not want nested stuff
508 if mod
.direct_owner
!= null and not mod
.direct_owner
.mnhe
<= self then continue # not in the right nesting
509 dctx
.add
("<li>{mod.html_link(dctx)}</li>")
511 dctx
.stage
("</ul>\n")
513 mods
= self.mhe
.smallers
.to_a
515 dctx
.stage
("<h4>All clients</h4>\n")
518 if not mod
.require_doc
(dctx
) then continue
519 if self.mnhe
<= mod
then continue # do not want nested stuff
520 if mod
.direct_owner
!= null and not mod
.direct_owner
.mnhe
<= self then continue # not in the right nesting
521 dctx
.add
("<li>{mod.html_link(dctx)}</li>")
523 dctx
.stage
("</ul>\n")
524 dctx
.stage
("</nav>\n")
527 if not dctx
.public_only
then
528 mods
= self.mnhe
.direct_greaters
.to_a
531 dctx
.stage
("<nav>\n")
532 dctx
.stage
("<h3>Nested Modules</h3><ul>\n")
534 if not mod
.require_doc
(dctx
) then continue
535 dctx
.add
("<li>{mod.html_link(dctx)}</li>")
537 dctx
.stage
("</ul></nav>\n")
541 dctx
.add
("</div>") # metadata
543 dctx
.add
("<div class=\"content\
">\n")
544 dctx
.add
("<h1>{name}</h1>\n")
545 dctx
.add
("<div class='subtitle'>module ")
546 for m
in mnhe
.smallers
do
547 dctx
.add
("{m.html_link(dctx)}::")
549 dctx
.add
("{self.name}</div>\n")
551 dctx
.add
("<section class='description'>\n")
555 dctx
.add
("<div id=\"description\
">\n")
556 dctx
.add
("<pre>{doc.to_html}</pre>\n")
561 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")
562 var ms
= new Array[nullable MMModule]
564 var m0
: nullable MMModule = self
570 var cla
= new HashSet[MMModule]
572 for m0
in self.mhe
.greaters
do
573 if not m0
.require_doc
(dctx
) then continue
574 if self.visibility_for
(m0
) <= 1 then continue # private or hidden
575 if self.mnhe
<= m0
then continue # do not want nested stuff
576 if m0
.direct_owner
!= null and not m0
.direct_owner
.mnhe
<= self then continue # not in the right nesting
579 for m0
in self.mhe
.smallers
do
580 if not m0
.require_doc
(dctx
) then continue
581 if m0
.visibility_for
(self) <= 1 then continue # private or hidden
582 if m0
.direct_owner
!= null and not m0
.direct_owner
.mnhe
<= self then continue # not in the right nesting
585 for m0
in self.mnhe
.smallers
do
591 op
.append
("subgraph \"cluster_
{m0.name}\
"\{\n")
594 if c
.direct_owner
!= m0
then continue
596 op
.append
("\"{c.name}\
"[shape=box,margin=0.03];\n")
598 op
.append
("\"{c.name}\
"[URL=\"{c.html_name}.html\
"];\n")
602 op
.append
("\"{m0.name}\
"[URL=\"{m0.html_name}.html\
"];\n")
603 for c
in m0
.mhe
.direct_greaters
do
604 if not cla
.has
(c
) then continue
605 op
.append
("\"{m0.name}\
"->\"{c.name}\
";\n")
610 # Close the nesting subgraph
616 for c2
in c
.tmhe
.direct_greaters
do
617 if not cla
.has
(c2
) then continue
618 op
.append
("\"{c.name}\
"->\"{c2.name}\
";\n")
622 dctx
.gen_dot
(op
.to_s
, name
.to_s
, "Dependency graph for module {name}")
623 dctx
.add
("</section>")
625 var clas
= new Array[MMLocalClass]
626 var props
= new HashMap[MMGlobalProperty, Array[MMLocalProperty]]
627 var gprops
= new Array[MMLocalProperty]
630 for g
in m
.global_classes
do
632 if not lc
.require_doc
(dctx
) then continue
633 var im
= g
.intro
.mmmodule
634 if self.visibility_for
(im
) <= 1 then continue # private import or invisible import
636 for lc2
in lc
.crhe
.greaters_and_self
do
637 if not lc2
isa MMSrcLocalClass then continue
638 if not self.mnhe
<= lc2
.mmmodule
then continue # not introduced/redefined here/stolen
641 if not keep
then continue
643 lc
.compute_super_classes
644 for gp
in lc
.global_properties
do
645 if self.visibility_for
(gp
.intro
.local_class
.mmmodule
) <= 1 then continue # private import or invisible import
647 var mp
= lp
.local_class
.mmmodule
648 if not self.mnhe
<= mp
then continue # not introduced/redefined here/stolen
650 if not lp
.require_doc
(dctx
) then continue
651 if props
.has_key
(lp
.global
) then
652 if not props
[lp
.global
].has
(lp
) then
653 props
[lp
.global
].add
(lp
)
656 props
[lp
.global
] = [lp
]
657 gprops
.add
(lp
.global
.intro
)
662 dctx
.add
("<section class=\"module\
">\n")
664 dctx
.stage
("<article class=\"classes filterable\
">\n")
665 dctx
.stage
("<h2>Classes</h2>\n")
669 if self.mnhe
<= lc
.global
.intro
.mmmodule
then
670 dctx
.add
("<li class='intro'><span title='introduced in this module'>I</span> ")
672 dctx
.add
("<li class='redef'><span title='refined in this module'>R</span> ")
674 dctx
.add
("{lc.html_link(dctx)}</li>\n")
676 dctx
.stage
("</ul></article>\n")
680 dctx
.stage
("<article class=\"properties filterable\
">\n")
681 dctx
.stage
("<h2>Properties</h2>\n")
688 if gp
.intro
isa MMAttribute then continue
690 var lpi
= self[gp
.intro
.local_class
.global
][gp
]
693 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")
696 dctx
.add
("<li class='intro'><span title='introduction in this module'>I</span> {lpi.html_name}")
697 dctx
.add
(" ({lpi.local_class})</li>\n")
699 if lps
.length
>= 1 then
702 dctx
.add
("<li class='redef'><span title='redefinition'>R</span> {lp.html_open_link(dctx)}{lp.html_name} ({lp.local_class})</a></li>")
706 dctx
.stage
("</ul></article>\n")
708 dctx
.add
("</section>\n")
712 # Fill the body for the page associated to the full index
713 fun file_index_page_doc
(dctx
: DocContext)
716 dctx
.add
("<h1>Full Index</h1>\n")
718 var clas
= new Array[MMLocalClass]
719 var props
= new HashMap[MMGlobalProperty, Array[MMLocalProperty]]
720 var gprops
= new Array[MMLocalProperty]
721 var mods
= new Array[MMModule]
722 for m
in mhe
.greaters_and_self
do
723 if not m
.require_doc
(dctx
) then continue
726 for g
in global_classes
do
728 if not lc
.require_doc
(dctx
) then continue
730 for gp
in lc
.global_properties
do
732 if not lp
.require_doc
(dctx
) then continue
733 if props
.has_key
(lp
.global
) then
734 if not props
[lp
.global
].has
(lp
) then
735 props
[lp
.global
].add
(lp
)
738 props
[lp
.global
] = [lp
]
739 gprops
.add
(lp
.global
.intro
)
744 dctx
.stage
("<article class=\"modules filterable\
">\n")
745 dctx
.stage
("<h2>Modules</h2>\n")
749 dctx
.add
("<li>{m.html_link(dctx)}</li>")
751 dctx
.stage
("</ul></article>\n")
755 dctx
.stage
("<article class=\"classes filterable\
">\n")
756 dctx
.stage
("<h2>Classes</h2>\n")
760 dctx
.add
("<li>{lc.html_link(dctx)}</li>")
762 dctx
.stage
("</ul></article>\n")
766 dctx
.stage
("<article class=\"properties filterable\
">\n")
767 dctx
.stage
("<h2>Properties</h2>\n")
774 if gp
.intro
isa MMAttribute then continue
776 var lpi
= self[gp
.intro
.local_class
.global
][gp
]
779 dctx
.add
("<li class='intro'><span title='introduction'>I</span> {lpi.html_open_link(dctx)}{lpi.html_name} ({lpi.local_class})</a></li>\n")
780 if lps
.length
>= 1 then
783 dctx
.add
("<li class='redef'><span title='redefinition'>R</span> {lp.html_open_link(dctx)}{lp.html_name} ({lp.local_class})</a></li>\n")
787 dctx
.stage
("</ul></article>\n")
792 redef class MMLocalProperty
794 # Anchor of the property description in the module html file
795 fun html_anchor
: String
797 return "PROP_{local_class}_{cmangle(name)}"
800 fun html_open_link
(dctx
: DocContext): String
802 if not require_doc
(dctx
) then print
"not required {self}"
803 var title
= "{html_name}{signature.to_s}"
804 if short_doc
!= " " then
805 title
+= " #{short_doc}"
807 return "<a href=\"{local_class.html_name}.html
#{html_anchor}\" title=\"{title}\">"
810 fun html_name
: String
812 return self.name
.to_s
.html_escape
815 redef fun html_link
(dctx
)
817 if not require_doc
(dctx
) then print
"not required {self}"
818 var title
= "{html_name}{signature.to_s}"
819 if short_doc
!= " " then
820 title
+= " #{short_doc}"
822 return "<a href=\"{local_class.html_name}.html
#{html_anchor}\" title=\"{title}\">{html_name}</a>"
825 fun html_link_special
(dctx
: DocContext, lc
: MMLocalClass): String
827 if not require_doc
(dctx
) then print
"not required {self}"
828 var title
= "{html_name}{signature_for(lc.get_type)}"
829 if short_doc
!= " " then
830 title
+= " #{short_doc}"
832 return "<a href=\"{lc.html_name}.html
#{html_anchor}\" title=\"{title}\">{html_name}</a>"
835 # Kind of property (fun, attr, etc.)
836 fun kind
: String is abstract
843 else if global
.intro
== self then
846 return global
.intro
.short_doc
853 if n
== null or not n
isa APropdef then
860 if d
.n_comment
.is_empty
then
867 # The most specific module in the nesting hierarchy that exports the intro of self
868 fun intro_module
: MMModule
870 var m
= global
.intro
.mmmodule
871 var mo
= m
.direct_owner
872 while mo
!= null and mo
.visibility_for
(m
) >= 2 do
879 # Is the intro of self exported by the top-level module ?
880 fun is_toplevel
: Bool
883 return m
== m
.toplevel_owner
886 # Return true if the global property must be documented according to the visibility configured
887 fun require_doc
(dctx
: DocContext): Bool
889 if global
.visibility_level
== 3 and not dctx
.with_private
then return false # Private
890 if dctx
.public_only
then
892 if m
!= m
.toplevel_owner
then return false # Unexported
897 # Document the global property in the global class lc
898 fun full_documentation
(dctx
: DocContext, lc
: MMLocalClass)
900 var visibility
: String
901 if global
.visibility_level
== 1 then
902 visibility
= "public"
903 else if global
.visibility_level
== 2 then
904 visibility
= "protected"
905 else if global
.visibility_level
== 3 then
906 visibility
= "private"
911 var intro_class
= global
.intro
.local_class
912 var is_redef
= local_class
.global
!= intro_class
.global
or local_class
.mmmodule
.toplevel_owner
!= intro_class
.mmmodule
.toplevel_owner
914 dctx
.add
("<article id=\"{html_anchor}\
" class=\"{kind} {visibility} {if is_redef then "redef" else ""}\
">\n")
915 dctx
.add
("<h3 class=\"signature\
">{html_name}{signature.to_html(dctx, true)}</h3>\n")
916 dctx
.add
("<div class=\"info\
">\n")
917 #dctx.add("<p>LP: {self.mmmodule.html_link(dctx)}::{self.local_class.html_link(dctx)}::{self.html_link(dctx)}</p>")
922 if not is_toplevel
then
923 dctx
.add
("(unexported) ")
925 if global
.visibility_level
== 2 then
926 dctx
.add
("protected ")
927 else if global
.visibility_level
== 3 then
931 dctx
.add
(" {intro_class.mmmodule.toplevel_owner.name}")
932 if intro_class
.global
== lc
.global
then
933 dctx
.add
("::{lc.name}")
935 dctx
.add
("::{mmmodule[intro_class.global].html_link(dctx)}")
938 dctx
.add
("::{mmmodule[intro_class.global][global].html_link(dctx)}")
940 dctx
.add
("::{html_name}")
944 dctx
.add
("<div class=\"description\
">")
946 # Collect all refinement of the global property in the same global property
947 var lps
= new Array[MMLocalProperty]
948 for l
in prhe
.greaters_and_self
do
953 if global
.intro
.doc
!= null then
955 if lp
.doc
== null then introdoc
= true
959 dctx
.add
("<pre>{global.intro.doc.to_html}</pre>")
962 var tlmods
= new Array[MMModule]
964 var bm
= lp
.mmmodule
.toplevel_owner
965 var lcm
= lc
.global
.intro
.mmmodule
966 if lcm
.mhe
< lp
.mmmodule
then bm
= lcm
.toplevel_owner
967 if not tlmods
.has
(bm
) then tlmods
.add
(bm
)
971 # Document the top level property for the current top level module
973 if tm
.global_classes
.has
(lc
.global
) then
974 tlp
= tm
[lc
.global
][self.global
]
976 else if tm
.global_classes
.has
(self.local_class
.global
) then
977 # Self is the inherited property. Process it
978 tlp
= tm
[self.local_class
.global
][self.global
]
981 # We skip this module since the props defined by the module is
985 var tlcm
= lc
.global
.intro
.mmmodule
.toplevel_owner
986 if not tlcm
.mhe
<= tm
then
987 dctx
.add
("<h4>In module {tm.html_link(dctx)} :</h4>")
990 #dctx.add("<p>TLP: {tm} x {lc} : {tlp.full_name}</p>")
993 if doc
!= null and (not introdoc
or global
.intro
.doc
!= doc
) then
994 dctx
.add
("<pre>{doc.to_html}</pre>")
997 if tlp
.local_class
.global
!= lc
.global
then
998 dctx
.add
("inherited from {tlp.local_class.html_link(dctx)} ")
1000 if tm
!= tlp
.mmmodule
then
1001 dctx
.add
("defined by the module {tlp.mmmodule.html_link(dctx)} ")
1010 dctx
.stage
(". previously defined by:")
1012 var tl
= lp
.mmmodule
.toplevel_owner
1013 if tl
!= tm
then continue
1014 if lp
== tlp
then continue
1015 dctx
.add
(" {lp.mmmodule.html_link(dctx)}")
1016 if lp
.local_class
.global
!= lc
.global
then
1017 dctx
.add
(" for {lp.local_class.html_link(dctx)} ")
1027 #if doc != null and (not introdoc or global.intro.doc != doc) then
1028 # dctx.add("<pre>{doc.to_html}</pre>")
1035 dctx
.add
("</article>")
1038 redef class MMMethod
1039 redef fun kind
do return if global
.is_init
then "init" else "fun"
1041 redef class MMAttribute
1042 redef fun kind
do return "var"
1044 redef class MMTypeProperty
1045 redef fun kind
do return "type"
1048 redef class MMSrcModule
1062 if n
.n_moduledecl
== null then
1065 var np
= n
.n_moduledecl
1070 if d
.n_comment
.is_empty
then
1079 # Html transcription of the doc
1082 var res
= new Buffer
1083 for c
in n_comment
do
1084 res
.append
(c
.text
.substring_from
(1))
1086 return res
.to_s
.html_escape
1089 # Oneliner transcription of the doc
1092 return n_comment
.first
.text
.substring_from
(1).html_escape
1096 redef class MMLocalClass
1099 # Anchor of the class description in the module html file
1100 fun html_anchor
: String do return "CLASS_{self}"
1102 fun html_name
: String do return "{self}"
1104 redef fun html_link
(dctx
)
1106 if not require_doc
(dctx
) then print
"{dctx.filename}: not required {self}"
1107 return "<a href=\"{html_name}.html\
" title=\"{short_doc}\
">{self}</a>"
1110 redef fun short_doc
do return global
.intro
.short_doc
1112 redef fun doc
do return global
.intro
.doc
1116 if global
.is_interface
then
1118 else if global
.is_abstract
then
1119 return "abstract class"
1120 else if global
.is_enum
then
1127 # The most specific module in the nesting hierarchy that exports the intro of self
1128 fun intro_module
: MMModule
1130 var m
= global
.intro
.mmmodule
1131 var mo
= m
.direct_owner
1132 while mo
!= null and mo
.visibility_for
(m
) >= 2 do
1139 fun menu_link
(dctx
: DocContext, p
: MMLocalProperty)
1141 if p
.local_class
.global
!= self.global
then
1142 if p
.global
.intro
.local_class
.name
== "Object".to_symbol
then return
1143 if p
.global
.is_init
or p
isa MMTypeProperty then
1144 dctx
.add
("<li class='inherit'><span title='Inherited'>H</span> {p.html_link_special(dctx, self)}</li>\n")
1146 dctx
.add
("<li class='inherit'><span title='Inherited'>H</span> {p.html_link(dctx)}</li>\n")
1148 else if p
.global
.intro
.local_class
.global
== self.global
then
1149 dctx
.add
("<li class='intro'><span title='Introduced'>I</span> {p.html_link_special(dctx, self)}</li>\n")
1151 dctx
.add
("<li class='redef'><span title='Redefined'>R</span> {p.html_link_special(dctx, self)}</li>\n")
1155 # Return true if the global class must be documented according to the visibility configured
1156 fun require_doc
(dctx
: DocContext): Bool
1158 if global
.visibility_level
== 3 and not dctx
.with_private
then return false # Private
1159 if dctx
.public_only
then
1160 var m
= intro_module
1161 if m
!= m
.toplevel_owner
then return false # Unexported
1166 # Fill the body for the page associated to the global class
1167 fun file_page_doc
(dctx
: DocContext)
1169 dctx
.add
("<div class=\"menu\
">\n")
1171 var props
= new Array[MMLocalProperty]
1172 var inh
= new HashMap[MMLocalClass, Array[MMLocalProperty]]
1173 var inhs
= new Array[MMLocalClass]
1174 for g
in global_properties
do
1176 if not p
.require_doc
(dctx
) then continue
1177 if p
.local_class
.global
== global
or g
.is_init_for
(self) or p
isa MMTypeProperty then
1180 var lc
= mmmodule
[p
.local_class
.global
]
1181 if inh
.has_key
(lc
) then
1192 dctx
.add
("<nav class=\"properties filterable\
">\n")
1193 dctx
.add
("<h3>Properties</h3>\n")
1195 dctx
.stage
("<h4>Virtual Types</h4>\n<ul>\n")
1197 if p
isa MMTypeProperty then
1201 dctx
.stage
("</ul>\n")
1204 dctx
.stage
("<h4>Constructors</h4>\n<ul>\n")
1206 if p
.global
.is_init_for
(self) then
1210 dctx
.stage
("</ul>\n")
1213 dctx
.stage
("<h4>Methods</h4>\n<ul>\n")
1215 if not p
.global
.is_init
and p
isa MMMethod then
1219 dctx
.stage
("</ul>\n")
1221 dctx
.add
("</nav>\n")
1223 dctx
.add
("<nav class=\"inheritance filterable\
">\n")
1224 dctx
.add
("<h3>Inheritance</h3>\n")
1225 dctx
.add
("<h4>Superclasses</h4>\n<ul>\n")
1226 for lc
in cshe
.linear_extension
do
1227 if lc
== self then continue
1228 if not lc
.require_doc
(dctx
) then continue
1229 dctx
.add
("<li>{lc.html_link(dctx)}</li>\n")
1232 if cshe
.smallers
.length
== 0 then
1233 dctx
.add
("<h4>No Known Subclasses</h4>\n")
1234 else if cshe
.smallers
.length
<= 100 then
1235 dctx
.add
("<h4>Subclasses</h4>\n")
1237 for lc
in cshe
.smallers
do
1238 if not lc
.require_doc
(dctx
) then continue
1239 dctx
.add
("<li>{lc.html_link(dctx)}</li>\n")
1242 else if cshe
.direct_smallers
.length
<= 100 then
1243 dctx
.add
("<h4>Direct Subclasses Only</h4>\n<ul>\n")
1244 for lc
in cshe
.direct_smallers
do
1245 if not lc
.require_doc
(dctx
) then continue
1246 dctx
.add
("<li>{lc.html_link(dctx)}</li>\n")
1250 dctx
.add
("<h4>Too much Subclasses to list</h4>\n")
1252 dctx
.add
("</nav>\n")
1254 dctx
.add
("</div>\n")
1257 dctx
.add
("<div class=\"content\
">\n")
1258 dctx
.add
("<h1>{name}</h1>\n")
1259 dctx
.add
("<div class='subtitle'>")
1260 if global
.visibility_level
== 2 then
1262 else if global
.visibility_level
== 3 then
1263 dctx
.add
("private ")
1264 else if self.global
.intro
.mmmodule
.toplevel_owner
.visibility_for
(self.global
.intro
.mmmodule
) <= 1 then
1265 dctx
.add
("(unexported) ")
1267 dctx
.add
("{kind} {global.intro.mmmodule.toplevel_owner.html_link(dctx)}::{name}</div>")
1269 dctx
.add
("<section class=\"description\
">\n")
1272 dctx
.add
("<pre>{doc.to_html}</pre>\n")
1275 var cla
= new HashSet[MMLocalClass]
1276 var sm
= new HashSet[MMLocalClass]
1277 var sm2
= new HashSet[MMLocalClass]
1279 while cla
.length
+ sm
.length
< 10 and sm
.length
> 0 do
1283 sm2
.add_all
(x
.cshe
.direct_smallers
)
1289 cla
.add_all
(cshe
.greaters_and_self
)
1292 var name
= "class_{name}"
1293 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")
1296 op
.append
("\"{c.name}\
"[shape=box,margin=0.03];\n")
1298 op
.append
("\"{c.name}\
"[URL=\"{c.html_name}.html\
"];\n")
1300 for c2
in c
.cshe
.direct_greaters
do
1301 if not cla
.has
(c2
) then continue
1302 op
.append
("\"{c.name}\
"->\"{c2.name}\
";\n")
1304 if not c
.cshe
.direct_smallers
.is_empty
then
1306 for c2
in c
.cshe
.direct_smallers
do
1307 if cla
.has
(c2
) then others
= false
1310 op
.append
("\"{c.name}...\
"[label=\"\
"];\n")
1311 op
.append
("\"{c.name}...\
"->\"{c.name}\
"[style=dotted];\n")
1316 dctx
.gen_dot
(op
.to_s
, name
.to_s
, "Inheritance graph for class {name}")
1319 var mods
= new Array[MMModule]
1320 mods
.add
(global
.intro
.mmmodule
.toplevel_owner
)
1321 for lc
in crhe
.greaters
do
1322 if not lc
isa MMSrcLocalClass then continue
1323 var m
= lc
.mmmodule
.toplevel_owner
1324 if not mods
.has
(m
) then mods
.add
(m
)
1328 if m
== global
.intro
.mmmodule
.toplevel_owner
then
1329 dctx
.add
("<p>Introduced by {m.html_link(dctx)}")
1331 dctx
.add
("<p>Refined by {m.html_link(dctx)}")
1334 dctx
.stage
(". Definition in:")
1335 for lc
in crhe
.greaters
do
1336 if lc
.mmmodule
.toplevel_owner
!= m
then continue
1337 dctx
.add
(" {lc.mmmodule.html_link(dctx)} ")
1338 assert lc
isa MMSrcLocalClass
1341 dctx
.show_source
(n
.location
)
1347 dctx
.add
("</section>\n")
1350 dctx
.stage
("<section class=\"types\
">\n")
1351 dctx
.stage
("<h2>Formal and Virtual Types</h2>\n")
1352 for i
in [0..arity
[ do
1353 var f
= get_formal
(i
)
1354 f
.full_documentation
(dctx
, self)
1357 if not p
isa MMTypeProperty then continue
1358 p
.full_documentation
(dctx
, self)
1360 dctx
.stage
("</section>\n")
1364 dctx
.stage
("<section class=\"constructors\
">\n")
1365 dctx
.stage
("<h2 class=\"section-header\
">Constructors</h2>\n")
1367 if not p
.global
.is_init_for
(self) then continue
1368 p
.full_documentation
(dctx
, self)
1370 dctx
.stage
("</section>\n")
1374 dctx
.stage
("<section class=\"methods\
">\n")
1375 dctx
.stage
("<h2 class=\"section-header\
">Methods</h2>\n")
1377 if p
.global
.is_init
then continue
1378 if p
.local_class
.global
!= self.global
then continue
1379 if not p
isa MMMethod then continue
1380 p
.full_documentation
(dctx
, self)
1382 if not inhs
.is_empty
then
1384 dctx
.stage
("<h3>Inherited Methods</h3>\n")
1387 dctx
.stage
("<p>Defined in {lc.html_link(dctx)}:")
1389 if p
.global
.is_init
then continue
1390 if not p
isa MMMethod then continue
1391 dctx
.add
(" {p.html_link(dctx)}")
1398 dctx
.add
("</section>\n")
1400 dctx
.add
("</div> <!-- end class {name} -->\n")
1404 redef class MMSrcLocalClass
1410 else if global
.intro
== self then
1413 var bc
= global
.intro
1421 if not n
isa AStdClassdef then
1428 if d
.n_comment
.is_empty
then
1436 redef class MMSignature
1437 # Htlm transcription of the signature (with nested links)
1438 fun to_html
(dctx
: DocContext, with_closure
: Bool): String
1440 var res
= new Buffer
1443 for i
in [0..arity
[ do
1444 if i
> 0 then res
.append
(", ")
1445 res
.append
(self.params
[i
].name
.to_s
)
1447 res
.append
(self[i
].html_link
(dctx
))
1448 if self.vararg_rank
== i
then
1454 if return_type
!= null then
1456 res
.append
(return_type
.html_link
(dctx
))
1458 if with_closure
then
1459 for c
in closures
do
1461 if c
.is_optional
then res
.append
("[")
1462 if c
.is_break
then res
.append
("break ")
1463 res
.append
("!{c.name}")
1464 res
.append
(c
.signature
.to_html
(dctx
, false))
1465 if c
.is_optional
then res
.append
("]")
1473 # Htlm transcription of the type (with nested links)
1474 fun html_link
(dctx
: DocContext): String do return to_s
1477 redef class MMTypeSimpleClass
1478 redef fun html_link
(dctx
) do return local_class
.html_link
(dctx
)
1481 redef class MMTypeGeneric
1482 redef fun html_link
(dctx
)
1484 var res
= new Buffer
1485 res
.append
(local_class
.html_link
(dctx
))
1487 res
.append
(params
[0].html_link
(dctx
))
1488 for i
in [1..params
.length
[ do
1490 res
.append
(params
[i
].html_link
(dctx
))
1497 redef class MMTypeFormalParameter
1498 fun html_anchor
: String
1500 return "FT_{local_class}_{cmangle(name)}"
1502 redef fun html_link
(dctx
)
1504 return "<a href=\"#{html_anchor}\">{name}</a>"
1506 fun full_documentation
(dctx
: DocContext, lc
: MMLocalClass)
1508 dctx
.add
("<article id=\"{html_anchor}\
">\n")
1509 dctx
.add
("<h3 class=\"signature\
">{name}: {bound.html_link(dctx)}</h3>\n")
1510 dctx
.add
("<div class=\"info\
">")
1511 dctx
.add
("formal generic type")
1513 dctx
.add
("</article>")
1517 redef class MMNullableType
1518 redef fun html_link
(dctx
) do return "nullable " + as_notnull
.html_link
(dctx
)
1521 redef class MMVirtualType
1522 redef fun html_link
(dctx
) do return property
.html_link
(dctx
)
1525 var c
= new DocContext