1 # This file is part of NIT ( http://www.nitlanguage.org ).
3 # Copyright 2008 Jean Privat <jean@pryen.org>
5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at
9 # http://www.apache.org/licenses/LICENSE-2.0
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
17 # The main module of the nitdoc program
25 # Store knowledge and facilities to generate files
27 super AbstractCompiler
28 # Destination directory
29 readable writable var _dir
: String = "doc"
31 # Content of a generated file
32 var _stage_context
: StageContext = new StageContext(null)
34 # Add a string in the content
36 _stage_context
.content
.add
(s
)
37 _stage_context
.validate
= true
40 # Add a string in the content iff some other string are added
41 fun stage
(s
: String) do _stage_context
.content
.add
(s
)
43 # Create a new stage in the content
44 fun open_stage
do _stage_context
= new StageContext(_stage_context
)
46 # Close the current stage in the content
49 var s
= _stage_context
.parent
50 if _stage_context
.validate
then
51 s
.content
.add_all
(_stage_context
.content
)
58 # Write the content to a new file
59 fun write_to
(filename
: String)
61 var f
= new OFStream.open
(filename
)
62 for s
in _stage_context
.content
do
71 _stage_context
= new StageContext(null)
74 # Sorter of entities in alphabetical order
75 var _sorter
: AlphaSorter[MMEntity] = new AlphaSorter[MMEntity]
77 # Sort entities in the alphabetical order
78 fun sort
(array
: Array[MMEntity])
83 readable var _opt_dir
: OptionString = new OptionString("Directory where doc is generated", "-d", "--dir")
84 readable var _opt_source
: OptionString = new OptionString("What link for source (%f for filename, %l for first line, %L for last line)", "--source")
85 readable var _opt_public
: OptionBool = new OptionBool("Generate only the public API", "--public")
89 if self._opt_public
.value
== true then return true
93 # The current processed filename
96 # The main virtual module
97 var mainmod
: nullable MMVirtualModule
99 redef fun perform_work
(mods
)
101 mainmod
= new MMVirtualModule(self, mods
)
105 # Compute the set of direct owned nested modules
106 var owns
= new HashMap[MMModule, Array[MMModule]]
107 for mod
in modules
do
108 owns
[mod
] = new Array[MMModule]# [mod]
110 for mod
in modules
do
111 if mod
== mainmod
then continue
112 var d
= mod
.directory
115 if o
!= null and o
!= mod
then
119 if dp
== null or dp
== d
then break
124 # Builds the various module hierarchies
125 var mnh
= new PartialOrder[MMModule] # nested module hierarchy
126 var tmh
= new PartialOrder[MMModule] # top module import hierrchy
127 var ms
= mainmod
.mhe
.linear_extension
.reversed
129 if ms
== mainmod
then continue
130 m
.mnhe_
= mnh
.add
(m
, owns
[m
])
131 var pub
= new Array[MMModule]
132 for m2
in m
.mhe
.greaters
do
133 if m2
.toplevel_owner
!= m2
and m2
.toplevel_owner
!= m
.toplevel_owner
then continue
134 if m
.mnhe
<= m2
then continue
135 if m
.visibility_for
(m2
) <= 0 then
137 else if m
.visibility_for
(m2
) == 1 then
142 m
.tmhe_
= tmh
.add
(m
, pub
)
145 var head
= "<script type=\"text
/javascript\
" src=\"http
://moz-concept
.com
/nitdoc
/scripts
/jquery-1
.7
.1.min
.js\
"></script>\n" +
146 "<script type=\"text
/javascript\
" src=\"http
://moz-concept
.com
/nitdoc
/scripts
/js-facilities
.js\
"></script>\n" +
147 "<link rel=\"stylesheet\
" href=\"http
://moz-concept
.com
/nitdoc
/styles
/main
.css\
" type=\"text
/css\
" media=\"screen\
">"
149 var action_bar
= "<header><nav class='main'><ul><li><a href='.'>Overview</a></li><li><a href='full-index.html'>Full Index</a></li></ul></nav></header>\n"
152 self.filename
= "index.html"
154 add
("<html><head>{head}</head><body>\n")
156 add
("<div class=\"page\
">")
157 add
("<div class=\"content fullpage\
">")
158 add
("<h1>Modules</h1>\n<article class='overview'><ul>")
159 var modss
= mainmod
.mhe
.greaters_and_self
.to_a
162 if not mod
.is_toplevel
then continue
163 if not mod
.require_doc
(self) then continue
164 assert mod
isa MMSrcModule
165 add
("<li>{mod.html_link(self)} {mod.short_doc}</li>")
171 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")
173 if not mod
.is_toplevel
then continue
174 if not mod
.require_doc
(self) then continue
175 op
.append
("\"{mod.name}\
"[URL=\"{mod.html_name}.html\
"];\n")
176 for mod2
in mod
.tmhe
.direct_greaters
do
177 if not modss
.has
(mod2
) then continue
178 op
.append
("\"{mod.name}\
"->\"{mod2.name}\
";\n")
182 self.gen_dot
(op
.to_s
, "dep")
183 add
("</article></div>")
184 add
("<div class='clear'></div>")
186 add
("</body></html>\n")
187 write_to
("{dir}/index.html")
189 # Generate page for modules
190 for mod
in modules
do
191 if mod
== mainmod
then continue
192 assert mod
isa MMSrcModule
193 if not mod
.require_doc
(self) then continue
194 self.filename
= mod
.html_name
196 add
("<html><head>{head}<title>Module {mod.name}</title></head><body>\n")
198 add
("<div class=\"page\
">")
199 mod
.file_page_doc
(self)
201 add
("</body></html>\n")
202 write_to
("{dir}/{mod.html_name}.html")
205 # Generate pages for global classes
206 for c
in mainmod
.local_classes
do
207 if not c
.require_doc
(self) then continue
208 self.filename
= c
.html_name
210 add
("<html><head>{head}<title>Class {c.name}</title></head><body>\n")
212 add
("<div class=\"page\
">")
213 c
.file_page_doc
(self)
215 add
("</body></html>\n")
216 write_to
("{dir}/{c.html_name}.html")
219 self.filename
= "fullindex"
221 add
("<html><head>{head}</head><body>\n")
223 add
("<div class=\"page\
">")
224 add
("<div class=\"content fullpage\
">")
225 mainmod
.file_index_page_doc
(self)
228 add
("</body></html>\n")
229 write_to
("{dir}/full-index.html")
233 # Add a (source) link fo a given location
234 fun show_source
(l
: Location)
236 var s
= opt_source
.value
238 add
("in #{l.file.filename}")
240 # THIS IS JUST UGLY ! (but there is no replace yet)
241 var x
= s
.split_with
("%f")
242 s
= x
.join
(l
.file
.filename
)
243 x
= s
.split_with
("%l")
244 s
= x
.join
(l
.line_start
.to_s
)
245 x
= s
.split_with
("%L")
246 s
= x
.join
(l
.line_end
.to_s
)
247 add
(" (<a href=\"{s}\
">show code</a>)")
251 # Generate a clicable graphiz image using a dot content.
252 # `name' refer to the filename (without extension) and the id name of the map.
253 # `name' must also match the name of the graph in the dot content (eg. digraph NAME {...)
254 fun gen_dot
(dot
: String, name
: String)
256 var f
= new OFStream.open
("{self.dir}/{name}.dot")
259 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 ; \}")
260 self.add
("<div><img src=\"{name}.png\
" usemap=\"#{name}\" style=\"margin:auto\"/></div>")
261 var fmap
= new IFStream.open
("{self.dir}/{name}.map")
262 self.add
(fmap
.read_all
)
271 option_context
.add_option
(opt_public
)
272 option_context
.add_option
(opt_dir
)
273 option_context
.add_option
(opt_source
)
276 redef fun process_options
279 var d
= opt_dir
.value
280 if d
!= null then dir
= d
283 redef fun handle_property_conflict
(lc
, impls
)
285 # THIS IS SO UGLY! See MMVirtualModule
286 if lc
.mmmodule
== self.mainmod
then
287 return # We just accept, so one in impls is arbitrary inherited
293 # A virtual module is used to work as an implicit main module that combine unrelated modules
294 # Since conflict may arrise in a virtual module (the main method for instance) conflicts are disabled
295 class MMVirtualModule
297 init(ctx
: MMContext, mods
: Array[MMModule])
299 # We need to compute the whole metamodel since there is no mmbuilder to do it
300 super(" main".to_symbol
, mods
.first
.directory
, ctx
, new Location(null,0,0,0,0))
301 ctx
.add_module
(self, mods
)
303 self.add_super_module
(m
, 1)
305 self.import_global_classes
306 self.import_local_classes
307 for c
in self.local_classes
do
308 c
.compute_super_classes
310 for c
in self.local_classes
do
315 redef fun require_doc
(dctx
) do return false
318 # Conditionnal part of the text content of a DocContext
320 # Content of the current stage
321 readable var _content
: Array[String] = new Array[String]
323 # Is a normal string already added?
324 readable writable var _validate
: Bool = false
326 # Parent stage is any
327 readable var _parent
: nullable StageContext = null
329 init(parent
: nullable StageContext) do _parent
= parent
333 # Efficiently sort object with their to_s method
334 class AlphaSorter[E
: Object]
335 super AbstractSorter[E
]
336 redef fun compare
(a
, b
)
356 # Keep track of to_s values
357 var _dico
: HashMap[Object, String] = new HashMap[Object, String]
362 # Generalization of metamodel entities
365 fun html_link
(dctx
: DocContext): String is abstract
367 # Return a one liner description
368 fun short_doc
: String do return " "
370 # The doc node from the AST
371 # Return null is none
372 fun doc
: nullable ADoc do return null
377 redef fun html_link
(dctx
) do
378 return "<a href=\"{html_name}.html\
">{self}</a>"
381 fun require_doc
(dctx
: DocContext): Bool
383 if dctx
.public_only
and not is_toplevel
then return false
387 # Return true if the module is a top-level owner or a top-level module
388 fun is_toplevel
: Bool
390 var pd
= directory
.parent
391 return pd
== null or (pd
.owner
== null and directory
.owner
== self)
394 # Element in the module nesting tree
395 fun mnhe
: PartialOrderElement[MMModule] do return mnhe_
.as(not null)
396 var mnhe_
: nullable PartialOrderElement[MMModule] = null
398 # Element in the top level module importation hierarchy
399 fun tmhe
: PartialOrderElement[MMModule] do return tmhe_
.as(not null)
400 var tmhe_
: nullable PartialOrderElement[MMModule] = null
402 fun toplevel_owner
: MMModule
406 var ds
= m
.mnhe
.direct_smallers
407 if ds
.length
== 0 then return m
408 if ds
.length
== 1 then m
= ds
.first
else abort
412 fun html_name
: String
417 fun direct_owner
: nullable MMModule
420 while d
.owner
== self do d
= d
.parent
.as(not null)
424 # Fill the body for the page associated to the module
425 fun file_page_doc
(dctx
: DocContext)
427 dctx
.add
("<div class=\"menu\
">\n")
429 var mods
= new Array[MMModule]
430 mods
= self.mhe
.greaters
.to_a
434 dctx
.stage
("<nav>\n")
435 dctx
.stage
("<h3>Module Hierarchy</h3>\n")
436 dctx
.stage
("<h4>All dependencies</h4>\n")
439 if not mod
.require_doc
(dctx
) then continue
440 if self.mnhe
<= mod
then continue # do not want nested stuff
441 if mod
.direct_owner
!= null and not mod
.direct_owner
.mnhe
<= self then continue # not in the right nesting
442 dctx
.add
("<li>{mod.html_link(dctx)}</li>")
444 dctx
.stage
("</ul>\n")
446 mods
= self.mhe
.smallers
.to_a
448 dctx
.stage
("<h4>All clients</h4>\n")
451 if not mod
.require_doc
(dctx
) then continue
452 if self.mnhe
<= mod
then continue # do not want nested stuff
453 if mod
.direct_owner
!= null and not mod
.direct_owner
.mnhe
<= self then continue # not in the right nesting
454 dctx
.add
("<li>{mod.html_link(dctx)}</li>")
456 dctx
.stage
("</ul>\n")
457 dctx
.stage
("</nav>\n")
460 if not dctx
.public_only
then
461 mods
= self.mnhe
.direct_greaters
.to_a
464 dctx
.stage
("<nav>\n")
465 dctx
.stage
("<h3>Nested Modules</h3><ul>\n")
467 if not mod
.require_doc
(dctx
) then continue
468 dctx
.add
("<li>{mod.html_link(dctx)}</li>")
470 dctx
.stage
("</ul></nav>\n")
474 dctx
.add
("</div>") # metadata
476 dctx
.add
("<div class=\"content\
">\n")
477 dctx
.add
("<h1>{name}</h1>\n")
478 dctx
.add
("<div class='subtitle'>module ")
479 for m
in mnhe
.smallers
do
480 dctx
.add
("{m.html_link(dctx)}::")
482 dctx
.add
("{self.name}</div>\n")
484 dctx
.add
("<section class='description'>\n")
488 dctx
.add
("<div id=\"description\
">\n")
489 dctx
.add
("<pre>{doc.to_html}</pre>\n")
494 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")
495 var ms
= new Array[nullable MMModule]
497 var m0
: nullable MMModule = self
503 var cla
= new HashSet[MMModule]
505 for m0
in self.mhe
.greaters
do
506 if not m0
.require_doc
(dctx
) then continue
507 if self.visibility_for
(m0
) <= 1 then continue # private or hidden
508 if self.mnhe
<= m0
then continue # do not want nested stuff
509 if m0
.direct_owner
!= null and not m0
.direct_owner
.mnhe
<= self then continue # not in the right nesting
512 for m0
in self.mhe
.smallers
do
513 if not m0
.require_doc
(dctx
) then continue
514 if m0
.visibility_for
(self) <= 1 then continue # private or hidden
515 if m0
.direct_owner
!= null and not m0
.direct_owner
.mnhe
<= self then continue # not in the right nesting
518 for m0
in self.mnhe
.smallers
do
524 op
.append
("subgraph \"cluster_
{m0.name}\
"\{\n")
527 if c
.direct_owner
!= m0
then continue
529 op
.append
("\"{c.name}\
"[shape=box,margin=0.03];\n")
531 op
.append
("\"{c.name}\
"[URL=\"{c.html_name}.html\
"];\n")
535 op
.append
("\"{m0.name}\
"[URL=\"{m0.html_name}.html\
"];\n")
536 for c
in m0
.mhe
.direct_greaters
do
537 if not cla
.has
(c
) then continue
538 op
.append
("\"{m0.name}\
"->\"{c.name}\
";\n")
543 # Close the nesting subgraph
549 for c2
in c
.tmhe
.direct_greaters
do
550 if not cla
.has
(c2
) then continue
551 op
.append
("\"{c.name}\
"->\"{c2.name}\
";\n")
555 dctx
.gen_dot
(op
.to_s
, name
.to_s
)
556 dctx
.add
("</section>")
558 var clas
= new Array[MMLocalClass]
559 var props
= new HashMap[MMGlobalProperty, Array[MMLocalProperty]]
560 var gprops
= new Array[MMLocalProperty]
563 for g
in m
.global_classes
do
565 if not lc
.require_doc
(dctx
) then continue
566 var im
= g
.intro
.mmmodule
567 if self.visibility_for
(im
) <= 1 then continue # private import or invisible import
569 for lc2
in lc
.crhe
.greaters_and_self
do
570 if not lc2
isa MMSrcLocalClass then continue
571 if not self.mnhe
<= lc2
.mmmodule
then continue # not introduced/redefined here/stolen
574 if not keep
then continue
576 for gp
in lc
.global_properties
do
577 if self.visibility_for
(gp
.intro
.local_class
.mmmodule
) <= 1 then continue # private import or invisible import
579 var mp
= lp
.local_class
.mmmodule
580 if not self.mnhe
<= mp
then continue # not introduced/redefined here/stolen
582 if not lp
.require_doc
(dctx
) then continue
583 if props
.has_key
(lp
.global
) then
584 if not props
[lp
.global
].has
(lp
) then
585 props
[lp
.global
].add
(lp
)
588 props
[lp
.global
] = [lp
]
589 gprops
.add
(lp
.global
.intro
)
594 dctx
.add
("<section class=\"module\
">\n")
596 dctx
.stage
("<article class=\"classes filterable\
">\n")
597 dctx
.stage
("<h2>Classes</h2>\n")
601 if self.mnhe
<= lc
.global
.intro
.mmmodule
then
602 dctx
.add
("<li class='intro'><span title='introduced in this module'>I</span> ")
604 dctx
.add
("<li class='redef'><span title='refined in this module'>R</span> ")
606 dctx
.add
("{lc.html_link(dctx)}</li>\n")
608 dctx
.stage
("</ul></article>\n")
612 dctx
.stage
("<article class=\"properties filterable\
">\n")
613 dctx
.stage
("<h2>Properties</h2>\n")
620 if gp
.intro
isa MMAttribute then continue
622 var lpi
= self[gp
.intro
.local_class
.global
][gp
]
625 dctx
.add
("<li class='intro'><span title='introduction in an other module'>I</span> <a href=\"{lpi.local_class.html_name}.html
#{lpi.html_anchor}\">{lpi} ({lpi.local_class})</a></li>\n")
628 dctx
.add
("<li class='intro'><span title='introduction in this module'>I</span> {lpi}")
629 dctx
.add
(" ({lpi.local_class})</li>\n")
631 if lps
.length
>= 1 then
634 dctx
.add
("<li class='redef'><span title='redefinition'>R</span> <a href=\"{lp.local_class.html_name}.html
#{lp.html_anchor}\">{lp} ({lp.local_class})</a></li>")
638 dctx
.stage
("</ul></article>\n")
646 # Fill the body for the page associated to the full index
647 fun file_index_page_doc
(dctx
: DocContext)
650 dctx
.add
("<h1>Full Index</h1>\n")
652 var clas
= new Array[MMLocalClass]
653 var props
= new HashMap[MMGlobalProperty, Array[MMLocalProperty]]
654 var gprops
= new Array[MMLocalProperty]
655 var mods
= new Array[MMModule]
656 for m
in mhe
.greaters_and_self
do
657 if not m
.require_doc
(dctx
) then continue
660 for g
in global_classes
do
662 if not lc
.require_doc
(dctx
) then continue
664 for gp
in lc
.global_properties
do
666 if not lp
.require_doc
(dctx
) then continue
667 if props
.has_key
(lp
.global
) then
668 if not props
[lp
.global
].has
(lp
) then
669 props
[lp
.global
].add
(lp
)
672 props
[lp
.global
] = [lp
]
673 gprops
.add
(lp
.global
.intro
)
678 dctx
.stage
("<article class=\"modules filterable\
">\n")
679 dctx
.stage
("<h2>Modules</h2>\n")
683 dctx
.add
("<li>{m.html_link(dctx)}</li>")
685 dctx
.stage
("</ul></article>\n")
689 dctx
.stage
("<article class=\"classes filterable\
">\n")
690 dctx
.stage
("<h2>Classes</h2>\n")
694 dctx
.add
("<li>{lc.html_link(dctx)}</li>")
696 dctx
.stage
("</ul></article>\n")
700 dctx
.stage
("<article class=\"properties filterable\
">\n")
701 dctx
.stage
("<h2>Properties</h2>\n")
708 if gp
.intro
isa MMAttribute then continue
710 var lpi
= self[gp
.intro
.local_class
.global
][gp
]
713 dctx
.add
("<li class='intro'><span title='introduction'>I</span> <a href=\"{lpi.local_class.html_name}.html
#{lpi.html_anchor}\">{lpi} ({lpi.local_class})</a></li>\n")
714 if lps
.length
>= 1 then
717 dctx
.add
("<li class='redef'><span title='redefinition'>R</span> <a href=\"{lp.local_class.html_name}.html
#{lp.html_anchor}\">{lp} ({lp.local_class})</a></li>\n")
721 dctx
.stage
("</ul></article>\n")
726 redef class MMLocalProperty
728 # Anchor of the property description in the module html file
729 fun html_anchor
: String
731 return "PROP_{local_class}_{cmangle(name)}"
734 redef fun html_link
(dctx
)
736 if not require_doc
(dctx
) then print
"not required {self}"
737 return "<a href=\"{local_class.html_name}.html
#{html_anchor}\">{self}</a>"
740 fun html_link_special
(dctx
: DocContext, lc
: MMLocalClass): String
742 if not require_doc
(dctx
) then print
"not required {self}"
743 return "<a href=\"{lc.html_name}.html
#{html_anchor}\">{self}</a>"
746 # Kind of property (fun, attr, etc.)
747 fun kind
: String is abstract
754 else if global
.intro
== self then
757 return global
.intro
.short_doc
764 if n
== null or not n
isa APropdef then
771 if d
.n_comment
.is_empty
then
778 # The most specific module in the nesting hierarchy that exports the intro of self
779 fun intro_module
: MMModule
781 var m
= global
.intro
.mmmodule
782 var mo
= m
.direct_owner
783 while mo
!= null and mo
.visibility_for
(m
) >= 2 do
790 # Is the intro of self exported by the top-level module ?
791 fun is_toplevel
: Bool
794 return m
== m
.toplevel_owner
797 # Return true if the global class must be documented according to the visibility configured
798 fun require_doc
(dctx
: DocContext): Bool
800 if global
.visibility_level
== 3 then return false # Private
801 if dctx
.public_only
then
803 if m
!= m
.toplevel_owner
then return false # Unexported
808 # Document the global property in the global class lc
809 fun full_documentation
(dctx
: DocContext, lc
: MMLocalClass)
811 var visibility
: String
812 if global
.visibility_level
== 1 then
813 visibility
= "public"
814 else if global
.visibility_level
== 2 then
815 visibility
= "protected"
816 else if global
.visibility_level
== 3 then
817 visibility
= "private"
822 var intro_class
= global
.intro
.local_class
823 var is_redef
= local_class
.global
!= intro_class
.global
or local_class
.mmmodule
.toplevel_owner
!= intro_class
.mmmodule
.toplevel_owner
825 dctx
.add
("<article id=\"{html_anchor}\
" class=\"{kind} {visibility} {if is_redef then "redef" else ""}\
">\n")
826 dctx
.add
("<h3 class=\"signature\
">{name}{signature.to_html(dctx, true)}</h3>\n")
827 dctx
.add
("<div class=\"info\
">\n")
828 #dctx.add("<p>LP: {self.mmmodule.html_link(dctx)}::{self.local_class.html_link(dctx)}::{self.html_link(dctx)}</p>")
833 if not is_toplevel
then
834 dctx
.add
("(unexported) ")
836 if global
.visibility_level
== 2 then
837 dctx
.add
("protected ")
838 else if global
.visibility_level
== 3 then
842 dctx
.add
(" {intro_class.mmmodule.toplevel_owner.name}")
843 if intro_class
.global
== lc
.global
then
844 dctx
.add
("::{lc.name}")
846 dctx
.add
("::{mmmodule[intro_class.global].html_link(dctx)}")
849 dctx
.add
("::{mmmodule[intro_class.global][global].html_link(dctx)}")
855 dctx
.add
("<div class=\"description\
">")
857 # Collect all refinement of the global property in the same global property
858 var lps
= new Array[MMLocalProperty]
859 for l
in prhe
.greaters_and_self
do
864 if global
.intro
.doc
!= null then
866 if lp
.doc
== null then introdoc
= true
870 dctx
.add
("<pre>{global.intro.doc.to_html}</pre>")
873 var tlmods
= new Array[MMModule]
875 var bm
= lp
.mmmodule
.toplevel_owner
876 var lcm
= lc
.global
.intro
.mmmodule
877 if lcm
.mhe
< lp
.mmmodule
then bm
= lcm
.toplevel_owner
878 if not tlmods
.has
(bm
) then tlmods
.add
(bm
)
882 # Document the top level property for the current top level module
884 if tm
.global_classes
.has
(lc
.global
) then
885 tlp
= tm
[lc
.global
][self.global
]
887 else if tm
.global_classes
.has
(self.local_class
.global
) then
888 # Self is the inherited property. Process it
889 tlp
= tm
[self.local_class
.global
][self.global
]
892 # We skip this module since the props defined by the module is
896 var tlcm
= lc
.global
.intro
.mmmodule
.toplevel_owner
897 if not tlcm
.mhe
<= tm
then
898 dctx
.add
("<h4>In module {tm.html_link(dctx)} :</h4>")
901 #dctx.add("<p>TLP: {tm} x {lc} : {tlp.full_name}</p>")
904 if doc
!= null and (not introdoc
or global
.intro
.doc
!= doc
) then
905 dctx
.add
("<pre>{doc.to_html}</pre>")
908 if tlp
.local_class
.global
!= lc
.global
then
909 dctx
.add
("inherited from {tlp.local_class.html_link(dctx)} ")
911 if tm
!= tlp
.mmmodule
then
912 dctx
.add
("defined by the module {tlp.mmmodule.html_link(dctx)} ")
921 dctx
.stage
(". previously defined by:")
923 var tl
= lp
.mmmodule
.toplevel_owner
924 if tl
!= tm
then continue
925 if lp
== tlp
then continue
926 dctx
.add
(" {lp.mmmodule.html_link(dctx)}")
927 if lp
.local_class
.global
!= lc
.global
then
928 dctx
.add
(" for {lp.local_class.html_link(dctx)}")
938 #if doc != null and (not introdoc or global.intro.doc != doc) then
939 # dctx.add("<pre>{doc.to_html}</pre>")
946 dctx
.add
("</article>")
950 redef fun kind
do return if global
.is_init
then "init" else "fun"
952 redef class MMAttribute
953 redef fun kind
do return "var"
955 redef class MMTypeProperty
956 redef fun kind
do return "type"
959 redef class MMSrcModule
973 if n
.n_moduledecl
== null then
976 var np
= n
.n_moduledecl
981 if d
.n_comment
.is_empty
then
990 # Html transcription of the doc
994 for c
in n_comment
do
995 res
.append
(c
.text
.substring_from
(1))
1000 # Oneliner transcription of the doc
1003 return n_comment
.first
.text
.substring_from
(1)
1007 redef class MMLocalClass
1010 # Anchor of the class description in the module html file
1011 fun html_anchor
: String do return "CLASS_{self}"
1013 fun html_name
: String do return "{self}"
1015 redef fun html_link
(dctx
)
1017 if not require_doc
(dctx
) then print
"{dctx.filename}: not required {self}"
1018 return "<a href=\"{html_name}.html\
">{self}</a>"
1021 redef fun short_doc
do return global
.intro
.short_doc
1023 redef fun doc
do return global
.intro
.doc
1027 if global
.is_interface
then
1029 else if global
.is_abstract
then
1030 return "abstract class"
1031 else if global
.is_enum
then
1038 # The most specific module in the nesting hierarchy that exports the intro of self
1039 fun intro_module
: MMModule
1041 var m
= global
.intro
.mmmodule
1042 var mo
= m
.direct_owner
1043 while mo
!= null and mo
.visibility_for
(m
) >= 2 do
1050 fun menu_link
(dctx
: DocContext, p
: MMLocalProperty)
1052 if p
.local_class
.global
!= self.global
then
1053 if p
.global
.intro
.local_class
.name
== "Object".to_symbol
then return
1054 if p
.global
.is_init
or p
isa MMTypeProperty then
1055 dctx
.add
("<li class='inherit'><span title='Inherited'>H</span> {p.html_link_special(dctx, self)}</li>\n")
1057 dctx
.add
("<li class='inherit'><span title='Inherited'>H</span> {p.html_link(dctx)}</li>\n")
1059 else if p
.global
.intro
.local_class
.global
== self.global
then
1060 dctx
.add
("<li class='intro'><span title='Introduced'>I</span> {p.html_link_special(dctx, self)}</li>\n")
1062 dctx
.add
("<li class='redef'><span title='Redefined'>R</span> {p.html_link_special(dctx, self)}</li>\n")
1066 # Return true if the global class must be documented according to the visibility configured
1067 fun require_doc
(dctx
: DocContext): Bool
1069 if global
.visibility_level
== 3 then return false # Private
1070 if dctx
.public_only
then
1071 var m
= intro_module
1072 if m
!= m
.toplevel_owner
then return false # Unexported
1077 # Fill the body for the page associated to the global class
1078 fun file_page_doc
(dctx
: DocContext)
1080 dctx
.add
("<div class=\"menu\
">\n")
1082 var props
= new Array[MMLocalProperty]
1083 var inh
= new HashMap[MMLocalClass, Array[MMLocalProperty]]
1084 var inhs
= new Array[MMLocalClass]
1085 for g
in global_properties
do
1087 if not p
.require_doc
(dctx
) then continue
1088 if p
.local_class
.global
== global
or g
.is_init_for
(self) or p
isa MMTypeProperty then
1091 var lc
= mmmodule
[p
.local_class
.global
]
1092 if inh
.has_key
(lc
) then
1103 dctx
.add
("<nav class=\"properties filterable\
">\n")
1104 dctx
.add
("<h3>Properties</h3>\n")
1106 dctx
.stage
("<h4>Virtual Types</h4>\n<ul>\n")
1108 if p
isa MMTypeProperty then
1112 dctx
.stage
("</ul>\n")
1115 dctx
.stage
("<h4>Constructors</h4>\n<ul>\n")
1117 if p
.global
.is_init_for
(self) then
1121 dctx
.stage
("</ul>\n")
1124 dctx
.stage
("<h4>Methods</h4>\n<ul>\n")
1126 if not p
.global
.is_init
and p
isa MMMethod then
1130 dctx
.stage
("</ul>\n")
1132 dctx
.add
("</nav>\n")
1134 dctx
.add
("<nav class=\"inheritance filterable\
">\n")
1135 dctx
.add
("<h3>Inheritance</h3>\n")
1136 dctx
.add
("<h4>Superclasses</h3>\n<ul>\n")
1137 for lc
in cshe
.linear_extension
do
1138 if lc
== self then continue
1139 if not lc
.require_doc
(dctx
) then continue
1140 dctx
.add
("<li>{lc.html_link(dctx)}</li>\n")
1143 if cshe
.smallers
.length
== 0 then
1144 dctx
.add
("<h4>No Known Subclasses</h4>\n")
1145 else if cshe
.smallers
.length
<= 100 then
1146 dctx
.add
("<h4>Subclasses</h4>\n")
1148 for lc
in cshe
.smallers
do
1149 if not lc
.require_doc
(dctx
) then continue
1150 dctx
.add
("<li>{lc.html_link(dctx)}</li>\n")
1153 else if cshe
.direct_smallers
.length
<= 100 then
1154 dctx
.add
("<h4>Direct Subclasses Only</h4>\n<ul>\n")
1155 for lc
in cshe
.direct_smallers
do
1156 if not lc
.require_doc
(dctx
) then continue
1157 dctx
.add
("<li>{lc.html_link(dctx)}</li>\n")
1161 dctx
.add
("<h4>Too much Subclasses to list</h4>\n")
1163 dctx
.add
("</nav>\n")
1165 dctx
.add
("</div>\n")
1168 dctx
.add
("<div class=\"content\
">\n")
1169 dctx
.add
("<h1>{name}</h1>\n")
1170 dctx
.add
("<div class='subtitle'>")
1171 if global
.visibility_level
== 2 then
1173 else if global
.visibility_level
== 3 then
1174 dctx
.add
("private ")
1175 else if self.global
.intro
.mmmodule
.toplevel_owner
.visibility_for
(self.global
.intro
.mmmodule
) <= 1 then
1176 dctx
.add
("(unexported) ")
1178 dctx
.add
("{kind} {global.intro.mmmodule.toplevel_owner.html_link(dctx)}::{name}</div>")
1180 dctx
.add
("<section class=\"description\
">\n")
1183 dctx
.add
("<pre>{doc.to_html}</pre>\n")
1186 var cla
= new HashSet[MMLocalClass]
1187 var sm
= new HashSet[MMLocalClass]
1188 var sm2
= new HashSet[MMLocalClass]
1190 while cla
.length
+ sm
.length
< 10 and sm
.length
> 0 do
1194 sm2
.add_all
(x
.cshe
.direct_smallers
)
1200 cla
.add_all
(cshe
.greaters_and_self
)
1203 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")
1206 op
.append
("\"{c.name}\
"[shape=box,margin=0.03];\n")
1208 op
.append
("\"{c.name}\
"[URL=\"{c.html_name}.html\
"];\n")
1210 for c2
in c
.cshe
.direct_greaters
do
1211 if not cla
.has
(c2
) then continue
1212 op
.append
("\"{c.name}\
"->\"{c2.name}\
";\n")
1214 if not c
.cshe
.direct_smallers
.is_empty
then
1216 for c2
in c
.cshe
.direct_smallers
do
1217 if cla
.has
(c2
) then others
= false
1220 op
.append
("\"{c.name}...\
"[label=\"\
"];\n")
1221 op
.append
("\"{c.name}...\
"->\"{c.name}\
"[style=dotted];\n")
1226 dctx
.gen_dot
(op
.to_s
, name
.to_s
)
1229 var mods
= new Array[MMModule]
1230 mods
.add
(global
.intro
.mmmodule
.toplevel_owner
)
1231 for lc
in crhe
.greaters
do
1232 if not lc
isa MMSrcLocalClass then continue
1233 var m
= lc
.mmmodule
.toplevel_owner
1234 if not mods
.has
(m
) then mods
.add
(m
)
1238 if m
== global
.intro
.mmmodule
.toplevel_owner
then
1239 dctx
.add
("<p>Introduced by {m.html_link(dctx)}")
1241 dctx
.add
("<p>Refined by {m.html_link(dctx)}")
1244 dctx
.stage
(". Definition in:")
1245 for lc
in crhe
.greaters
do
1246 if lc
.mmmodule
.toplevel_owner
!= m
then continue
1247 dctx
.add
(" {lc.mmmodule.html_link(dctx)}")
1248 assert lc
isa MMSrcLocalClass
1251 dctx
.show_source
(n
.location
)
1259 dctx
.add
("</section>\n")
1262 dctx
.stage
("<section class=\"types\
">\n")
1263 dctx
.stage
("<h2>Formal and Virtual Types</h2>\n")
1264 for i
in [0..arity
[ do
1265 var f
= get_formal
(i
)
1266 f
.full_documentation
(dctx
, self)
1269 if not p
isa MMTypeProperty then continue
1270 p
.full_documentation
(dctx
, self)
1272 dctx
.stage
("</section>\n")
1276 dctx
.stage
("<section class=\"constructors\
">\n")
1277 dctx
.stage
("<h2 class=\"section-header\
">Constructors</h2>\n")
1279 if not p
.global
.is_init_for
(self) then continue
1280 p
.full_documentation
(dctx
, self)
1282 dctx
.stage
("</section>\n")
1286 dctx
.stage
("<section class=\"methods\
">\n")
1287 dctx
.stage
("<h2 class=\"section-header\
">Methods</h2>\n")
1289 if p
.global
.is_init
then continue
1290 if p
.local_class
.global
!= self.global
then continue
1291 if not p
isa MMMethod then continue
1292 p
.full_documentation
(dctx
, self)
1294 if not inhs
.is_empty
then
1296 dctx
.stage
("<h3>Inherited Methods</h4>\n")
1299 dctx
.stage
("<p>Defined in {lc.html_link(dctx)}:")
1301 if p
.global
.is_init
then continue
1302 if not p
isa MMMethod then continue
1303 dctx
.add
(" {p.html_link(dctx)}")
1310 dctx
.add
("</section>\n")
1312 dctx
.add
("</div> <!-- end class {name} -->\n")
1316 redef class MMSrcLocalClass
1322 else if global
.intro
== self then
1325 var bc
= global
.intro
1333 if not n
isa AStdClassdef then
1340 if d
.n_comment
.is_empty
then
1348 redef class MMSignature
1349 # Htlm transcription of the signature (with nested links)
1350 fun to_html
(dctx
: DocContext, with_closure
: Bool): String
1352 var res
= new Buffer
1355 res
.append
(self.params
[0].name
.to_s
)
1357 res
.append
(self[0].html_link
(dctx
))
1358 for i
in [1..arity
[ do
1360 res
.append
(self.params
[i
].name
.to_s
)
1362 res
.append
(self[i
].html_link
(dctx
))
1366 if return_type
!= null then
1368 res
.append
(return_type
.html_link
(dctx
))
1370 if with_closure
then
1371 for c
in closures
do
1373 if c
.is_optional
then res
.append
("[")
1374 if c
.is_break
then res
.append
("break ")
1375 res
.append
("!{c.name}")
1376 res
.append
(c
.signature
.to_html
(dctx
, false))
1377 if c
.is_optional
then res
.append
("]")
1385 # Htlm transcription of the type (with nested links)
1386 fun html_link
(dctx
: DocContext): String do return to_s
1389 redef class MMTypeSimpleClass
1390 redef fun html_link
(dctx
) do return local_class
.html_link
(dctx
)
1393 redef class MMTypeGeneric
1394 redef fun html_link
(dctx
)
1396 var res
= new Buffer
1397 res
.append
(local_class
.html_link
(dctx
))
1399 res
.append
(params
[0].html_link
(dctx
))
1400 for i
in [1..params
.length
[ do
1402 res
.append
(params
[i
].html_link
(dctx
))
1409 redef class MMTypeFormalParameter
1410 fun html_anchor
: String
1412 return "FT_{local_class}_{cmangle(name)}"
1414 redef fun html_link
(dctx
)
1416 return "<a href=\"#{html_anchor}\">{name}</a>"
1418 fun full_documentation
(dctx
: DocContext, lc
: MMLocalClass)
1420 dctx
.add
("<article id=\"{html_anchor}\
">\n")
1421 dctx
.add
("<h3 class=\"signature\
">{name}: {bound.html_link(dctx)}</h3>\n")
1422 dctx
.add
("<div class=\"info\
">")
1423 dctx
.add
("formal generic type")
1425 dctx
.add
("</article>")
1429 redef class MMNullableType
1430 redef fun html_link
(dctx
) do return "nullable " + as_notnull
.html_link
(dctx
)
1433 redef class MMVirtualType
1434 redef fun html_link
(dctx
) do return property
.html_link
(dctx
)
1437 var c
= new DocContext