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
28 # Destination directory
29 readable writable attr _dir
: String
31 # Content of a generated file
32 attr _stage_context
: StageContext = new StageContext(null)
34 # Add a string in the content
35 meth add
(s
: String) do
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 meth stage
(s
: String) do _stage_context
.content
.add
(s
)
43 # Create a new stage in the content
44 meth 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
)
57 # Write the content to a new file
58 meth write_to
(filename
: String)
60 print
"Generate {filename}"
61 var f
= new OFStream.open
(filename
)
62 for s
in _stage_context
.content
do
68 # Currently computed module
69 readable attr _module
: MMSrcModule
71 # Is the current directory module computed as a simple modude ?
72 readable writable attr _inside_mode
: Bool
74 # Is the current module computed as a intruded one ?
75 readable writable attr _intrude_mode
: Bool
77 # Compued introducing entities (for the index)
78 attr _entities
: Array[MMEntity] = new Array[MMEntity]
80 # Register an entity (for the index)
81 meth register
(e
: MMEntity)
84 if e
isa MMSrcModule then
92 _stage_context
= new StageContext(null)
97 # Generate common files (frames, index, overview)
98 meth extract_other_doc
104 add
("<html><body>\n")
105 add
("<a href=\"overview
.html\
" target=\"mainFrame\
">Overview</a><br/>\n")
106 add
("<a href=\"index-1
.html\
" target=\"mainFrame\
">Index</a><br/>\n")
107 var modules
= modules
.to_a
110 var rootdirs
= new Array[MMDirectory]
113 if md
.parent
== null and not rootdirs
.has
(md
) then
118 var done
= new Array[MMModule]
119 for root
in rootdirs
do
120 var dirstack
= [root
]
122 add
("{root.name}<br/>\n")
123 var indent
= " "
124 while not dirstack
.is_empty
do
127 if done
.has
(m
) then continue
129 if md
.owner
== m
and md
.parent
== curdir
then
130 # It's a directory module
131 add
("{indent}<a href=\"{m}.html\
" target=\"mainFrame\
">{m}</a><br/>\n")
133 dirstack
.push
(curdir
)
134 indent
= "  " * dirstack
.length
136 break # restart to preserve alphabetic order
137 else if md
== curdir
then
138 if md
.owner
== m
then
139 add
("{indent}<a href=\"{m}_
.html\
" target=\"mainFrame\
">{m}</a><br/>\n")
141 add
("{indent}<a href=\"{m}.html\
" target=\"mainFrame\
">{m}</a><br/>\n")
149 if not dirstack
.is_empty
then
150 curdir
= dirstack
[dirstack
.length-1
]
151 indent
= "  " * dirstack
.length
156 add
("</body></html>\n")
157 write_to
("{dir}/menu-frame.html")
163 for e
in _entities
do
164 add
("<dt><b>{e.html_link(self)}</b> - {e.prototype_head(self)} <b>{e}</b>{e.prototype_body(self)} {e.locate(self)}<dd>{e.short_doc}\n")
166 add
("</dl></body></html>\n")
167 write_to
("{dir}/index-1.html")
170 add_header
("Overview")
171 add
("<table border=\"1\
" width=\"100%\
" cellpadding=\"3\
" cellspacing=\"0\
">\n")
172 add
("<tr bgcolor=\"#CCCCFF\"><th colspan=\"2\"><big>Overview of all Modules</big></th><tr>\n")
174 add
("<tr><td width=\"20%\
" align=\"right\
">{m.html_link(self)}</td><td>{m.short_doc}</td><tr>\n")
176 add
("</table></body></html>\n")
177 write_to
("{dir}/overview.html")
180 add
("<html>\n<frameset cols=\"20%,80%\
">\n<frame src=\"menu-frame
.html\
" name=\"menuFrame\
" title=\"Menu\
">\n<frame src=\"overview
.html\
" name=\"mainFrame\
" title=\"Main\
" scrolling=\"yes\
">\n</frameset></html>\n")
181 write_to
("{dir}/index.html")
184 meth add_header
(title
: String)
186 add
("<html><head><title>{title}</title></head>\n<body>\n")
187 add
("<table border=\"0\
" width=\"100%\
" cellpadding=\"1\
" cellspacing=\"0\
"><tr><td bgcolor=\"#eeeeff\">\n")
188 add
("<a href=\"overview
.html\
"><b>Overview</b></a> <a href=\"index-1
.html\
"><b>Index</b></a> <a href=\"index
.html\
" target=\"_top\
"><b>With Frames</b></a>\n")
189 add
("</td></tr></table>")
191 if (not inside_mode
and not intrude_mode
) or module == null then
192 add
("<b>Public</b> ")
194 add
("<a href=\"{module}.html\
"><b>Public</b></a> ")
196 if inside_mode
or module == null then
197 add
("<b>Inside</b> ")
198 else if module.directory
.owner
!= module then
199 add
("<strike><b>Inside</b></strike> ")
201 add
("<a href=\"{module}_
.html\
"><b>Inside</b></a> ")
203 if intrude_mode
or module == null then
204 add
("<b>Intrude</b> ")
206 add
("<a href=\"{module}__
.html\
"><b>Intrude</b></a> ")
211 # Sorter of entities in alphabetical order
212 attr _sorter
: AlphaSorter[MMEntity] = new AlphaSorter[MMEntity]
214 # Sort entities in the alphabetical order
215 meth sort
(array
: Array[MMEntity])
220 readable writable attr _owned_modules
: Array[MMModule]
222 # Return the known_owner for current module
223 # if inside_mode is set, it could be a different result
224 meth known_owner_of
(m
: MMModule): MMModule
226 if module == null then return m
227 var res
= module.known_owner_of
(m
)
228 if not inside_mode
and not intrude_mode
and res
.directory
.owner
== module then
236 # Conditionnal part of the text content of a DocContext
238 # Content of the current stage
239 readable attr _content
: Array[String] = new Array[String]
241 # Is a normal string already added?
242 readable writable attr _validate
: Bool
244 # Parent stage is any
245 readable attr _parent
: StageContext
247 init(parent
: StageContext) do _parent
= parent
251 # Efficiently sort object with their to_s method
252 class AlphaSorter[E
: Object]
253 special AbstractSorter[E
]
254 redef meth compare
(a
, b
)
274 # Keep track of to_s values
275 attr _dico
: HashMap[Object, String] = new HashMap[Object, String]
280 # Generalization of metamodel entities
283 meth html_link
(dctx
: DocContext): String is abstract
285 # Is the entity should appear in the generaed doc
286 meth need_doc
(dctx
: DocContext): Bool is abstract
288 # Return a one liner description
289 meth short_doc
: String do return " "
291 # The doc node from the AST
292 # Return null is none
293 meth doc
: ADoc do return null
295 # Human redable location of the entity (module/class/property)
296 meth locate
(dctx
: DocContext): String do return ""
298 # Part of the prototype before the name (kind, modifiers, qualifier)
299 meth prototype_head
(dctx
: DocContext): String is abstract
301 # Part of the property after the name (signature, modifiers)
302 meth prototype_body
(dctx
: DocContext): String do return ""
307 redef meth html_link
(dctx
) do
308 if dctx
.module == self then
311 return "<a href=\"{self}.html\
">{self}</a>"
314 redef meth need_doc
(dctx
) do return true
315 redef meth prototype_head
(dctx
) do return "module "
317 attr _known_owner_of_cache
: Map[MMModule, MMModule] = new HashMap[MMModule, MMModule]
318 meth known_owner_of
(module: MMModule): MMModule
320 if _known_owner_of_cache
.has_key
(module) then return _known_owner_of_cache
[module]
322 if mhe
< module and visibility_for
(module) != 0 then
323 res
= known_owner_of_intern
(module, self, false)
325 res
= module.owner
(self)
327 _known_owner_of_cache
[module] = res
331 # Return the most general module that own self
332 meth owner
(from
: MMModule): MMModule
336 while d
!= null and d
!= from
.directory
do
338 if o
!= null and o
.mhe
<= res
then res
= o
344 private meth known_owner_of_intern
(module: MMModule, from
: MMModule, as_owner
: Bool): MMModule
346 if module == self then return self
347 var candidates
= new Array[MMModule]
348 for m
in explicit_imported_modules
do
349 if from
.visibility_for
(m
) == 0 then continue
350 if not m
.mhe
<= module then continue
351 candidates
.add
(m
.known_owner_of_intern
(module, from
, true))
353 assert not candidates
.is_empty
354 var max
= candidates
.first
355 for m
in candidates
do
356 if max
.mhe
< m
then max
= m
358 if as_owner
and max
.directory
.owner
== self then
367 redef class MMLocalProperty
369 # Anchor of the property description in the module html file
370 meth html_anchor
: String
372 return "PROP_{local_class}_{cmangle(name)}"
375 redef meth html_link
(dctx
)
378 if not need_doc
(dctx
) then m
= global
.intro
.module
379 var m
= dctx
.known_owner_of
(m
)
380 if m
== dctx
.module then
381 return "<a href=\"#{html_anchor}\">{self}</a>"
383 return "<a href=\"{m}.html
#{html_anchor}\">{self}</a>"
387 redef meth short_doc
do return concrete_property
.short_doc
389 redef meth doc
do return concrete_property
.doc
391 redef meth need_doc
(dctx
) do return false
393 # Kind of property (meth, attr, etc.)
394 meth kind
: String is abstract
396 redef meth locate
(dctx
)
398 return "in {module.html_link(dctx)}::{local_class.html_link(dctx)}"
401 meth known_intro_class
(dctx
: DocContext): MMLocalClass
403 var mod
= dctx
.known_owner_of
(global
.intro
.local_class
.module)
404 var cla
= mod
[global
.intro
.local_class
.global
]
408 redef meth prototype_head
(dctx
)
411 var intro_class
= known_intro_class
(dctx
)
412 var is_redef
= local_class
!= intro_class
414 if is_redef
then res
.append
("redef ")
415 if global
.visibility_level
== 2 then
416 res
.append
("protected ")
417 else if global
.visibility_level
== 3 then
418 res
.append
("private ")
422 var gp
= global
.intro
423 if intro_class
.global
!= local_class
.global
then
424 res
.append
(" {module[intro_class.global].html_link(dctx)}::")
425 else if intro_class
.module != module then
426 res
.append
(" {intro_class.module.html_link(dctx)}::")
432 redef meth prototype_body
(dctx
)
434 var res
= signature
.to_html
(dctx
)
436 if s
isa MMSrcLocalProperty then
437 if s
.node
isa ADeferredMethPropdef then
438 res
.append
(" is abstract")
439 else if s
.node
isa AInternMethPropdef then
440 res
.append
(" is intern")
447 redef meth kind
do return if global
.is_init
then "init" else "meth"
449 redef class MMAttribute
450 redef meth kind
do return "attr"
452 redef class MMTypeProperty
453 redef meth kind
do return "type"
456 redef class MMSrcModule
457 # Extract doc for the module and its supermodules
458 meth extract_all_modules_doc
(dctx
: DocContext)
460 for m
in mhe
.greaters_and_self
do
461 assert m
isa MMSrcModule
462 m
.extract_module_doc
(dctx
)
466 # Extract and generate html file fhe the module
467 meth extract_module_doc
(dctx
: DocContext)
469 if dctx
.modules
.has
(self) then return
474 extract_module_doc_inside
(dctx
)
475 dctx
.write_to
("{dctx.dir}/{name}.html")
477 dctx
.intrude_mode
= true
479 extract_module_doc_inside
(dctx
)
480 dctx
.write_to
("{dctx.dir}/{name}__.html")
481 dctx
.intrude_mode
= false
483 if directory
.owner
== self then
484 dctx
.inside_mode
= true
486 extract_module_doc_inside
(dctx
)
487 dctx
.write_to
("{dctx.dir}/{name}_.html")
488 dctx
.inside_mode
= false
492 meth extract_module_doc_inside
(dctx
: DocContext)
494 dctx
.add_header
("Module {self}")
495 dctx
.add
("<h1>Module {self}</h1>\n<dl>")
499 if d
.owner
!= null and (d
.owner
!= self or dctx
.inside_mode
or dctx
.intrude_mode
) then
500 s
= "{d.owner.html_link(dctx)}::{s}"
504 dctx
.add
("{s}<br/>{prototype_head(dctx)}<b>{self}</b>{prototype_body(dctx)}<br/>\n")
506 var strs
= new Array[String]
507 var intrude_modules
= new Array[MMModule]
508 var public_modules
= new Array[MMModule]
509 var private_modules
= new Array[MMModule]
510 var owned_modules
= new Array[MMModule]
511 dctx
.owned_modules
= owned_modules
512 for m
in mhe
.greaters
do
513 var v
= visibility_for
(m
)
514 if not dctx
.inside_mode
and not dctx
.intrude_mode
and m
.directory
.owner
== self then
515 if v
>= 2 then owned_modules
.add
(m
)
519 intrude_modules
.add
(m
)
521 public_modules
.add
(m
)
523 private_modules
.add
(m
)
526 if not intrude_modules
.is_empty
then
527 var mods
= mhe
.order
.select_smallests
(intrude_modules
)
528 for i
in mods
do strs
.add
(i
.html_link
(dctx
))
529 dctx
.add
("<dt>Intruded modules: <dd>{strs.join(", ")}\n")
531 if not public_modules
.is_empty
then
533 var mods
= mhe
.order
.select_smallests
(public_modules
)
534 for i
in mods
do strs
.add
(i
.html_link
(dctx
))
535 dctx
.add
("<dt>Imported modules: <dd>{strs.join(", ")}\n")
537 if not private_modules
.is_empty
then
539 var mods
= mhe
.order
.select_smallests
(private_modules
)
540 for i
in mods
do strs
.add
(i
.html_link
(dctx
))
541 dctx
.add
("<dt>Privatly imported modules: <dd>{strs.join(", ")}\n")
546 if doc
!= null then dctx
.add
("<pre>{doc.to_html}</pre>\n")
548 var new_classes
= new Array[MMLocalClass]
549 for c
in local_classes
do
550 if c
.need_doc
(dctx
) then
552 if c
.global
.intro
== c
then
556 for m
in owned_modules
do
558 if mc
!= null and mc
.need_doc
(dctx
) then
566 if not new_classes
.is_empty
then
567 dctx
.sort
(new_classes
)
568 dctx
.add
("<table border=\"1\
" width=\"100%\
" cellpadding=\"3\
" cellspacing=\"0\
">\n")
569 dctx
.add
("<tr bgcolor=\"#CCCCFF\"><th colspan=\"2\"><big>Class Summary of {self}</big></th><tr>\n")
570 for c
in new_classes
do
571 dctx
.add
("<tr><td width=\"20%\
" align=\"right\
">{c.prototype_head(dctx)}</td><td><b>{c.html_link(dctx)}</b>{c.prototype_body(dctx)}<br/>{c.short_doc}</td><tr>\n")
573 dctx
.add
("</table><br/>\n")
576 if not new_classes
.is_empty
then
577 dctx
.add
("<table border=\"1\
" width=\"100%\
" cellpadding=\"3\
" cellspacing=\"0\
">\n")
578 dctx
.add
("<tr bgcolor=\"#CCCCFF\"><th><big>Class Detail of {self}</big></th><tr>\n")
579 dctx
.add
("</table>\n")
581 for c
in new_classes
do
582 c
.extract_class_doc
(dctx
)
586 dctx
.add
("</body></html>\n")
602 if not n
isa AModule then
606 if n
.n_packagedecl
== null then
609 var np
= n
.n_packagedecl
610 assert np
isa APackagedecl
616 if d
.n_comment
.is_empty
then
625 # Html transcription of the doc
629 for c
in n_comment
do
630 res
.append
(c
.text
.substring_from
(1))
635 # Oneliner transcription of the doc
638 return n_comment
.first
.text
.substring_from
(1)
642 redef class MMLocalClass
644 # Anchor of the class description in the module html file
645 meth html_anchor
: String do return "CLASS_{self}"
647 redef meth html_link
(dctx
)
650 if not need_doc
(dctx
) then m
= global
.module
651 var m
= dctx
.known_owner_of
(m
)
652 if m
== dctx
.module then
653 return "<a href=\"#{html_anchor}\">{self}</a>"
655 return "<a href=\"{m}.html
#{html_anchor}\">{self}</a>"
659 redef meth short_doc
do return global
.intro
.short_doc
661 redef meth doc
do return global
.intro
.doc
663 redef meth need_doc
(dctx
) do
664 if module == dctx
.module then
665 for m
in dctx
.owned_modules
do
667 if c
!= null and c
.need_doc
(dctx
) then return true
673 redef meth locate
(dctx
) do return "in {module.html_link(dctx)}"
675 meth known_intro
(dctx
: DocContext): MMLocalClass do return dctx
.known_owner_of
(global
.intro
.module)[global
]
677 redef meth prototype_head
(dctx
)
680 var ki
= known_intro
(dctx
)
681 var is_redef
= ki
!= self
682 if is_redef
then res
.append
("redef ")
683 if global
.visibility_level
== 3 then res
.append
("private ")
685 if is_redef
then res
.append
("{ki.module.html_link(dctx)}::")
689 redef meth prototype_body
(dctx
)
694 for i
in [0..arity
[ do
695 var t
= get_formal
(i
)
696 res
.append
(t
.name
.to_s
)
698 res
.append
(t
.bound
.html_link
(dctx
))
705 # Extract the doc of a class
706 meth extract_class_doc
(dctx
: DocContext)
708 dctx
.add
("<a name=\"{html_anchor}\
"></a><h2>{self}</h2><small>{module.html_link(dctx)}::</small><br/>{prototype_head(dctx)}<b>{self}</b>{prototype_body(dctx)}\n")
709 dctx
.add
("<blockquote>\n")
712 var sup2
= new Array[String]
713 var intro_module
= dctx
.known_owner_of
(global
.module)
714 if intro_module
!= module then
715 dctx
.add
("<dt>Refine {self} from: <dd>{intro_module.html_link(dctx)}\n")
717 var mods
= new Array[MMModule]
718 for c
in crhe
.greaters
do
719 if c
.need_doc
(dctx
) then
720 var km
= dctx
.known_owner_of
(c
.module)
721 if km
!= module and km
!= intro_module
and not mods
.has
(km
) then
726 for c
in crhe
.linear_extension
do
727 if mods
.has
(c
.module) then sup2
.add
(c
.module.html_link
(dctx
))
729 if not sup2
.is_empty
then dctx
.add
("<dt>Previous refinements in: <dd>{sup2.join(", ")}\n")
731 if not cshe
.greaters
.is_empty
then
733 var clas
= new Array[MMLocalClass]
734 for c
in cshe
.direct_greaters
do
735 sup2
.add
(c
.html_link
(dctx
))
737 dctx
.add
("<dt>Direct superclasses: <dd>{sup2.join(", ")}\n")
739 for c
in cshe
.linear_extension
do
740 if c
!= self then sup2
.add
(c
.html_link
(dctx
))
742 dctx
.add
("<dt>All superclasses: <dd>{sup2.join(", ")}\n")
744 if not cshe
.direct_smallers
.is_empty
then
746 for c
in cshe
.direct_smallers
do
747 sup2
.add
(c
.html_link
(dctx
))
749 dctx
.add
("<dt>Direct subclasses: <dd>{sup2.join(", ")}\n")
752 for c
in crhe
.smallers
do
753 c
.compute_super_classes
754 for c2
in c
.module.local_classes
do
755 if not c2
isa MMConcreteClass then continue
756 c2
.compute_super_classes
758 c2
.inherit_global_properties
760 for c2
in c
.cshe
.direct_smallers
do
761 if c2
.global
.intro
== c2
then
762 sup2
.add
("{c2.html_link(dctx)}")
766 if not sup2
.is_empty
then
767 dctx
.add
("<dt>Other direct subclasses in known modules: <dd>{sup2.join(", ")}\n")
770 for c
in crhe
.order
do
771 if not module.mhe
<= c
.module and c
.need_doc
(dctx
) then
772 sup2
.add
(c
.module.html_link
(dctx
))
775 if not sup2
.is_empty
then
776 dctx
.add
("<dt>Refinements in known modules: <dd>{sup2.join(", ")}\n")
782 dctx
.add
("<pre>{doc.to_html}</pre>\n")
785 var details
= new Array[Array[MMLocalProperty]]
786 for i
in [0..4[ do details
.add
(property_summary
(dctx
, i
))
787 for i
in [0..4[ do property_detail
(dctx
, i
, details
[i
])
789 dctx
.add
("</blockquote><hr/>\n")
792 meth pass_name
(pass
: Int): String
794 var names
= once
["Virtual Types", "Consructors", "Methods", "Attributes"]
798 meth accept_prop
(p
: MMLocalProperty, pass
: Int): Bool
801 return p
isa MMTypeProperty
802 else if pass
== 1 then
803 return p
.global
.is_init
804 else if pass
== 2 then
805 return p
isa MMMethod and not p
.global
.is_init
806 else if pass
== 3 then
807 return p
isa MMAttribute
812 meth property_summary
(dctx
: DocContext, pass
: Int): Array[MMLocalProperty]
814 var passname
= pass_name
(pass
)
816 dctx
.stage
("<table border=\"1\
" width=\"100%\
" cellpadding=\"3\
" cellspacing=\"0\
">\n")
817 dctx
.stage
("<tr bgcolor=\"#CCCCFF\"><th colspan=\"2\">{passname} Summary of {self}</th><tr>\n")
819 var new_props
= new Array[MMLocalProperty]
820 for g
in global_properties
do
821 if not accept_prop
(g
.intro
, pass
) then continue
822 if module.visibility_for
(g
.intro
.module) < g
.visibility_level
then continue
824 if not p
.need_doc
(dctx
) then
825 var cla
= new Array[MMLocalClass]
826 for m
in dctx
.owned_modules
do
828 if c
== null or not c
isa MMConcreteClass then continue
830 if p2
== null or not p2
.need_doc
(dctx
) then continue
833 if cla
.is_empty
then continue
834 cla
= crhe
.order
.select_smallests
(cla
)
838 if p
.global
.intro
== p
then
843 for p
in new_props
do
844 dctx
.add
("<tr><td width=\"20%\
" align=\"right\
">{p.prototype_head(dctx)}</td><td><b>{p.html_link(dctx)}</b>{p.prototype_body(dctx)}<br/> {p.short_doc}</td><tr>\n")
846 dctx
.stage
("</table><br/>\n")
849 dctx
.stage
("<table border=\"1\
" width=\"100%\
" cellpadding=\"3\
" cellspacing=\"0\
">\n")
851 # skip pass 1 because constructors are not inherited
852 var cmap
= new HashMap[MMLocalClass, Array[MMLocalProperty]]
853 var mmap
= new HashMap[MMModule, Array[MMLocalProperty]]
854 var props
= new Array[MMLocalClass]
855 for c
in che
.greaters
do
856 if c
isa MMSrcLocalClass then
857 var km
= dctx
.known_owner_of
(c
.module)
858 var kc
= km
[c
.global
]
859 if kc
== self or not c
isa MMConcreteClass then continue
860 var props
: Array[MMLocalProperty]
862 if cmap
.has_key
(kc
) then
865 props
= new Array[MMLocalProperty]
869 if mmap
.has_key
(km
) then
872 props
= new Array[MMLocalProperty]
876 for g
in c
.global_properties
do
878 if p
.need_doc
(dctx
) and accept_prop
(p
, pass
) then
885 dctx
.stage
("<tr bgcolor=\"#EEEEFF\"><th colspan=\"2\"><small>Inherited {passname}</small></th><tr>\n")
886 for c
in cshe
.linear_extension
do
887 if not cmap
.has_key
(c
) then continue
889 if props
.is_empty
then continue
891 var properties
= new Array[String]
892 for p
in props
do properties
.add
(p
.html_link
(dctx
))
893 dctx
.add
("<tr><td width=\"20%\
"><small>from {c.html_link(dctx)}</small></td><td><small>{properties.join(", ")}</small></td><tr>\n")
898 dctx
.stage
("<tr bgcolor=\"#EEEEFF\"><th colspan=\"2\"><small>Imported {passname}</small></th><tr>\n")
899 for m
in module.mhe
.linear_extension
do
900 if not mmap
.has_key
(m
) then continue
902 if props
.is_empty
then continue
904 var properties
= new Array[String]
905 for p
in props
do properties
.add
(p
.html_link
(dctx
))
906 dctx
.add
("<tr><td width=\"20%\
"><small>from {m.html_link(dctx)}</small></td><td><small>{properties.join(", ")}</small></td><tr>\n")
911 var mmap
= new HashMap[MMModule, Array[MMLocalProperty]]
912 var props
= new Array[MMLocalClass]
913 for c
in crhe
.order
do
914 if module.mhe
<= c
.module or dctx
.owned_modules
.has
(c
.module) or not c
isa MMSrcLocalClass then continue
915 var km
= dctx
.known_owner_of
(c
.module)
916 if module.mhe
<= km
then continue
917 var kc
= km
[c
.global
]
918 var props
: Array[MMLocalProperty]
919 if mmap
.has_key
(km
) then
922 props
= new Array[MMLocalProperty]
925 for g
in c
.global_properties
do
927 if p
.need_doc
(dctx
) and accept_prop
(p
, pass
) then
929 if not props
.has
(kp
) then props
.add
(kp
)
932 # c.properties_inherited_from(dctx, self, pass)
935 dctx
.stage
("<tr bgcolor=\"#EEEEFF\"><th colspan=\"2\"><small>Added {passname} in known modules</small></th><tr>\n")
936 for c
in crhe
.order
do
938 if not mmap
.has_key
(m
) then continue
940 if props
.is_empty
then continue
942 var properties
= new Array[String]
943 for p
in props
do properties
.add
(p
.html_link
(dctx
))
944 dctx
.add
("<tr><td width=\"20%\
"><small>in {m.html_link(dctx)}</small></td><td><small>{properties.join(", ")}</small></td><tr>\n")
947 dctx
.stage
("</table><br/><br/>\n")
954 meth property_detail
(dctx
: DocContext, pass
: Int, new_props
: Array[MMLocalProperty])
956 var passname
= pass_name
(pass
)
958 dctx
.stage
("<table border=\"1\
" width=\"100%\
" cellpadding=\"3\
" cellspacing=\"0\
">\n")
959 dctx
.stage
("<tr bgcolor=\"#CCCCFF\"><th>{passname} Detail of {self}</th><tr>\n")
960 dctx
.stage
("</table>\n")
963 for p
in new_props
do
964 dctx
.add
("<a name=\"{p.html_anchor}\
"></a><h3>{p}</h3><p><small>{p.module.html_link(dctx)}::{p.local_class.html_link(dctx)}::</small><br/>{p.prototype_head(dctx)} <b>{p.name}</b>{p.prototype_body(dctx)}</p>\n")
965 dctx
.add
("<blockquote>")
968 dctx
.add
("<pre>{doc.to_html}</pre>\n")
970 dctx
.stage
("</blockquote>\n")
974 dctx
.stage
("<hr/>\n")
981 # Add rows for properties inheriterd to some heirs
982 meth properties_inherited_from
(dctx
: DocContext, heir
: MMLocalClass, pass
: Int)
984 var properties
= new Array[String]
985 for g
in global_properties
do
987 if p
.need_doc
(dctx
) and accept_prop
(p
, pass
) then
988 properties
.add
(p
.html_link
(dctx
))
991 if not properties
.is_empty
then
993 if heir
.global
== global
then
994 s
= module.html_link
(dctx
)
996 s
= self.html_link
(dctx
)
998 dctx
.add
("<tr><td width=\"20%\
"><small>in {s}</small></td><td><small>{properties.join(", ")}</small></td><tr>\n")
1003 redef class MMSrcLocalClass
1004 redef meth short_doc
1009 else if global
.intro
== self then
1012 var bc
= global
.intro
1020 if not n
isa AClassdef then
1023 assert n
isa AClassdef
1029 if d
.n_comment
.is_empty
then
1036 redef meth need_doc
(dctx
)
1038 if global
.visibility_level
>= 3 then
1039 if not dctx
.intrude_mode
then return false
1040 if dctx
.module.visibility_for
(module) == 0 then return false
1042 if global
.intro
== self then
1045 for p
in src_local_properties
do
1046 if p
.need_doc
(dctx
) then
1054 redef class MMSrcLocalProperty
1055 redef meth need_doc
(dctx
)
1057 if global
.visibility_level
>= 3 or self isa MMAttribute then
1058 if not dctx
.intrude_mode
then return false
1059 if dctx
.module.visibility_for
(module) == 0 then return false
1061 if global
.intro
== self then
1067 redef meth short_doc
1072 else if global
.intro
== self then
1075 return global
.intro
.short_doc
1082 if not node
isa PPropdef then
1085 assert n
isa PPropdef
1091 if d
.n_comment
.is_empty
then
1099 redef class MMSignature
1100 # Htlm transcription of the signature (with nested links)
1101 meth to_html
(dctx
: DocContext): String
1103 var res
= new String
1106 res
.append
(self[0].html_link
(dctx
))
1107 for i
in [1..arity
[ do
1109 res
.append
(self[i
].html_link
(dctx
))
1113 if return_type
!= null then
1115 res
.append
(return_type
.html_link
(dctx
))
1122 # Htlm transcription of the type (with nested links)
1123 meth html_link
(dctx
: DocContext): String do return to_s
1126 redef class MMTypeSimpleClass
1127 redef meth html_link
(dctx
) do return local_class
.html_link
(dctx
)
1130 redef class MMTypeGeneric
1131 redef meth html_link
(dctx
)
1133 var res
= local_class
.html_link
(dctx
)
1135 res
.append
(params
[0].html_link
(dctx
))
1136 for i
in [1..params
.length
[ do
1138 res
.append
(params
[i
].html_link
(dctx
))
1146 # The main class of the nitdoc program
1148 special AbstractCompiler
1149 readable attr _opt_dir
: OptionString = new OptionString("Directory where doc is generated", "-d", "--dir")
1151 redef meth perform_work
(mods
)
1154 assert dctx
isa DocContext
1159 assert mod
isa MMSrcModule
1160 mod
.extract_all_modules_doc
(dctx
)
1162 dctx
.extract_other_doc
1168 option_context
.add_option
(opt_dir
)
1171 redef meth process_options
1174 var dctx
= new DocContext
1175 dctx
.dir
= opt_dir
.value
1176 if dctx
.dir
== null then dctx
.dir
= "."