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.
20 import abstract_compiler
23 private var toolcontext
: ToolContext
24 private var model
: Model
25 private var modelbuilder
: ModelBuilder
26 private var mainmodule
: MModule
27 private var class_hierarchy
: POSet[MClass]
28 private var arguments
: Array[String]
29 private var output_dir
: nullable String
30 private var dot_dir
: nullable String
31 private var share_dir
: nullable String
32 private var source
: nullable String
34 private var opt_dir
= new OptionString("Directory where doc is generated", "-d", "--dir")
35 private var opt_source
= new OptionString("What link for source (%f for filename, %l for first line, %L for last line)", "--source")
36 private var opt_sharedir
= new OptionString("Directory containing the nitdoc files", "--sharedir")
37 private var opt_nodot
= new OptionBool("Do not generate graphes with graphiviz", "--no-dot")
39 init(toolcontext
: ToolContext) do
40 # We need a model to collect stufs
41 self.toolcontext
= toolcontext
42 self.arguments
= toolcontext
.option_context
.rest
43 toolcontext
.option_context
.options
.clear
44 toolcontext
.option_context
.add_option
(opt_dir
)
45 toolcontext
.option_context
.add_option
(opt_source
)
46 toolcontext
.option_context
.add_option
(opt_sharedir
)
47 toolcontext
.option_context
.add_option
(opt_nodot
)
48 toolcontext
.process_options
51 if arguments
.length
< 1 then
52 toolcontext
.option_context
.usage
57 modelbuilder
= new ModelBuilder(model
, toolcontext
)
59 # Here we load an process std modules
60 var mmodules
= modelbuilder
.parse_and_build
([arguments
.first
])
61 if mmodules
.is_empty
then return
62 modelbuilder
.full_propdef_semantic_analysis
63 assert mmodules
.length
== 1
64 self.mainmodule
= mmodules
.first
65 self.class_hierarchy
= mainmodule
.flatten_mclass_hierarchy
68 private fun process_options
do
69 if not opt_dir
.value
is null then
70 output_dir
= opt_dir
.value
74 if not opt_sharedir
.value
is null then
75 share_dir
= opt_sharedir
.value
77 var dir
= "NIT_DIR".environ
79 dir
= "{sys.program_name.dirname}/../share/nitdoc"
81 dir
= "{dir}/share/nitdoc"
84 if share_dir
is null then
85 print
"Error: Cannot locate nitdoc share files. Uses --sharedir or envvar NIT_DIR"
88 dir
= "{share_dir.to_s}/scripts/js-facilities.js"
89 if share_dir
is null then
90 print
"Error: Invalid nitdoc share files. Check --sharedir or envvar NIT_DIR"
94 if not opt_source
.value
is null then
97 source
= opt_source
.value
102 if arguments
.length
== 1 then
103 # Create destination dir if it's necessary
104 if not output_dir
.file_exists
then output_dir
.mkdir
105 sys
.system
("cp -r {share_dir.to_s}/* {output_dir.to_s}/")
107 if not opt_nodot
.value
then self.dot_dir
= output_dir
.to_s
117 var overviewpage
= new NitdocOverview(modelbuilder
, dot_dir
)
118 overviewpage
.save
("{output_dir.to_s}/index.html")
122 var fullindex
= new NitdocFullindex(model
.mmodules
)
123 fullindex
.save
("{output_dir.to_s}/full-index.html")
127 for mmodule
in model
.mmodules
do
128 var modulepage
= new NitdocModule(mmodule
, modelbuilder
, dot_dir
)
129 modulepage
.save
("{output_dir.to_s}/{mmodule.name}.html")
134 for mclass
in modelbuilder
.model
.mclasses
do
135 var classpage
= new NitdocClass(mclass
, self, dot_dir
, source
)
136 classpage
.save
("{output_dir.to_s}/{mclass.name}.html")
140 # Generate QuickSearch file
141 fun quicksearch_list
do
142 var file
= new OFStream.open
("{output_dir.to_s}/quicksearch-list.js")
143 var content
= new Buffer
144 content
.append
("var entries = \{ ")
145 for prop
in model
.mproperties
do
146 if not prop
isa MMethod then continue
147 content
.append
("\"{prop.name}\
": [")
148 for propdef
in prop
.mpropdefs
do
149 content
.append
("\{txt: \"{propdef.mproperty.full_name}\", url
:\
"{propdef.mproperty.anchor}\" \
}")
150 if not propdef is prop.mpropdefs.last then content.append(", ")
156 for mclass in model.mclasses do
157 content.append("\
"{mclass.name}\": [")
158 for mclassdef in mclass.mclassdefs do
159 content.append("\
{txt: \"{mclassdef.mclass.full_name}\
", url:\"{mclass.link_anchor}\
" \}")
160 if not mclassdef
is mclass
.mclassdefs
.last
then content
.append
(", ")
163 if not mclass
is model
.mclasses
.last
then content
.append
(", ")
166 content
.append
(" \};")
167 file
.write
(content
.to_s
)
174 abstract class NitdocPage
176 var dot_dir
: nullable String
177 var source
: nullable String
181 fun append
(str
: String) do html
.append
(str
)
182 var html
= new Buffer
185 append
("<meta charset='utf-8'/>")
186 append
("<script type='text/javascript' src='scripts/jquery-1.7.1.min.js'></script>")
187 append
("<script type='text/javascript' src='quicksearch-list.js'></script>")
188 append
("<script type='text/javascript' src='scripts/js-facilities.js'></script>")
189 append
("<link rel='stylesheet' href='styles/main.css' type='text/css' media='screen'/>")
196 append
("<nav class='main'>")
199 append
("<li id='liGitHub'>")
200 append
("<a class='btn' id='logGitHub'>")
201 append
("<img id='imgGitHub' src='resources/icons/github-icon.png' alt='GitHub'/>")
203 append
("<div class='popover bottom'>")
204 append
("<div class='arrow'> </div>")
205 append
("<div class='githubTitle'>")
206 append
("<h3>Github Sign In</h3>")
209 append
("<label id='lbloginGit'>Username</label>")
210 append
("<input id='loginGit' name='login' type='text'/>")
211 append
("<label id='logginMessage'>Hello ")
212 append
("<a id='githubAccount'><strong id='nickName'></strong></a>")
216 append
("<label id='lbpasswordGit'>Password</label>")
217 append
("<input id='passwordGit' name='password' type='password'/>")
218 append
("<div id='listBranches'>")
219 append
("<label id='lbBranches'>Branch</label>")
220 append
("<select class='dropdown' id='dropBranches' name='dropBranches' tabindex='1'></select>")
224 append
("<label id='lbrepositoryGit'>Repository</label>")
225 append
("<input id='repositoryGit' name='repository' type='text'/>")
228 append
("<label id='lbbranchGit'>Branch</label>")
229 append
("<input id='branchGit' name='branch' type='text'/>")
232 append
("<a id='signIn'>Sign In</a>")
241 fun content
is abstract
244 append
("<footer>Nit standard library. Version jenkins-component=stdlib-19.</footer>")
247 # Generate a clickable graphviz image using a dot content
248 fun generate_dot
(dot
: String, name
: String, alt
: String) do
249 var output_dir
= dot_dir
250 if output_dir
== null then return
251 var file
= new OFStream.open
("{output_dir}/{name}.dot")
254 sys
.system
("\{ test -f {output_dir}/{name}.png && test -f {output_dir}/{name}.s.dot && diff {output_dir}/{name}.dot {output_dir}/{name}.s.dot >/dev/null 2>&1 ; \} || \{ cp {output_dir}/{name}.dot {output_dir}/{name}.s.dot && dot -Tpng -o{output_dir}/{name}.png -Tcmapx -o{output_dir}/{name}.map {output_dir}/{name}.s.dot ; \}")
255 append
("<article class='graph'>")
256 append
("<img src='{name}.png' usemap='#{name}' style='margin:auto' alt='{alt}'/>")
258 var fmap
= new IFStream.open
("{output_dir}/{name}.map")
259 append
(fmap
.read_all
)
263 # Add a (source) link for a given location
264 fun show_source
(l
: Location): String
266 if source
== null then
267 return "({l.file.filename.simplify_path})"
269 # THIS IS JUST UGLY ! (but there is no replace yet)
270 var x
= source
.split_with
("%f")
271 source
= x
.join
(l
.file
.filename
.simplify_path
)
272 x
= source
.split_with
("%l")
273 source
= x
.join
(l
.line_start
.to_s
)
274 x
= source
.split_with
("%L")
275 source
= x
.join
(l
.line_end
.to_s
)
276 return " (<a href=\"{source.to_s}\
">show code</a>)"
280 # Render the page as a html string
281 fun render
: String do
282 append
("<!DOCTYPE html>")
288 append
("<div class='page'>")
296 # Save html page in the specified file
297 fun save
(file
: String) do
298 var out
= new OFStream.open
(file
)
307 private var mbuilder
: ModelBuilder
308 private var mmodules
= new Array[MModule]
310 init(mbuilder
: ModelBuilder, dot_dir
: nullable String) do
311 self.mbuilder
= mbuilder
312 self.dot_dir
= dot_dir
314 var mmodules
= new HashSet[MModule]
315 for mmodule
in mbuilder
.model
.mmodules
do
316 var owner
= mmodule
.public_owner
317 if owner
!= null then
320 mmodules
.add
(mmodule
)
324 var sorter
= new ComparableSorter[MModule]
325 self.mmodules
.add_all
(mmodules
)
326 sorter
.sort
(self.mmodules
)
331 append
("<title>Overview | Nit Standard Library</title>")
335 append
("<li class='current'>Overview</li>")
336 append
("<li><a href='full-index.html'>Full Index</a></li>")
340 append
("<div class='content fullpage'>")
341 append
("<h1>Nit Standard Library</h1>")
342 append
("<article class='overview'><p>Documentation for the standard library of Nit<br />Version jenkins-component=stdlib-19<br />Date: TODAY</p></article>")
343 append
("<article class='overview'>")
345 append
("<h2>Modules</h2>")
347 for mmodule
in mmodules
do
348 var amodule
= mbuilder
.mmodule2nmodule
[mmodule
]
349 append
("<li>{mmodule.link(mbuilder)} {amodule.short_comment}</li>")
358 fun process_generate_dot
do
360 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")
361 for mmodule
in mmodules
do
362 op
.append
("\"{mmodule.name}\
"[URL=\"{mmodule.name}.html\
"];\n")
363 for imported
in mmodule
.in_importation
.direct_greaters
do
364 if imported
.direct_owner
== null then
365 op
.append
("\"{mmodule.name}\
"->\"{imported.name}\
";\n")
370 generate_dot
(op
.to_s
, "dep", "Modules hierarchy")
374 # The full index page
375 class NitdocFullindex
378 private var mmodules
: Array[MModule]
380 init(mmodules
: Array[MModule]) do
381 self.mmodules
= mmodules
387 append
("<title>Full Index | Nit Standard Library</title>")
391 append
("<li><a href='index.html'>Overview</a></li>")
392 append
("<li class='current'>Full Index</li>")
396 append
("<div class='content fullpage'>")
397 append
("<h1>Full Index</h1>")
404 # Add to content modules column
406 var ls
= new List[nullable MModule]
407 var sorted
= mmodules
408 var sorterp
= new ComparableSorter[MModule]
410 append
("<article class='modules filterable'></article>")
411 append
("<h2>Modules</h2>")
413 for mmodule
in sorted
do
414 if mmodule
.public_owner
!= null and not ls
.has
(mmodule
.public_owner
) then
415 ls
.add
(mmodule
.public_owner
)
416 append
("<li><a href='{mmodule.public_owner.name}.html'>(mmodule.public_owner.name)</a></li>")
423 # Add to content classes modules
424 fun classes_column
do
425 var sorted
= mmodules
.first
.imported_mclasses
.to_a
426 var sorterp
= new ComparableSorter[MClass]
428 append
("<article class='classes filterable'>")
429 append
("<h2>Classes</h2>")
431 for mclass
in sorted
do
432 append
("<li><a href='{mclass}.html'>(mclass.name)</a></li>")
438 # Insert the properties column of fullindex page
439 fun properties_column
do
440 append
("<article class='classes filterable'>")
441 append
("<h2>Properties</h2>")
443 var sorted_imported
= mmodules
.first
.imported_methods
.to_a
444 var sorted_redef
= mmodules
.first
.redef_methods
.to_a
445 var sorterp
= new ComparableSorter[MProperty]
446 sorterp
.sort
(sorted_imported
)
447 sorterp
.sort
(sorted_redef
)
449 for method
in sorted_imported
do
450 if method
.visibility
is none_visibility
or method
.visibility
is intrude_visibility
then continue
451 append
("<li class='intro'</li>")
452 append
("<span title='introduction'>I</span> ")
453 append
("<a href='{method.local_class.name}.html' title=''>{method.name} ({method.local_class.name})</a>")
457 for method
in sorted_redef
do
458 if method
.visibility
is none_visibility
or method
.visibility
is intrude_visibility
then continue
459 append
("<li class='redef'>")
460 append
("<span title='redefinition'>R</span> ")
461 append
("<a href='{method.local_class.name}.html' title=''>{method.name} ({method.local_class.name})</span>")
474 private var mmodule
: MModule
475 private var mbuilder
: ModelBuilder
477 init(mmodule
: MModule, mbuilder
: ModelBuilder, dot_dir
: nullable String) do
478 self.mmodule
= mmodule
479 self.mbuilder
= mbuilder
480 self.dot_dir
= dot_dir
485 var amodule
= mbuilder
.mmodule2nmodule
[mmodule
]
486 append
("<title>{mmodule.name} module | {amodule.short_comment}</title>")
490 append
("<li><a href='index.html'>Overview</a></li>")
491 append
("<li class='current'>{mmodule.name}</li>")
492 append
("<li><a href='full-index.html'>Full Index</a></li>")
497 append
("<div class='content'>")
498 append
("<h1>{mmodule.name}</h1>")
499 append
("<div class='subtitle'>{mmodule.html_signature(mbuilder)}</div>")
500 append
(mmodule
.html_full_comment
(mbuilder
))
507 fun process_generate_dot
do
508 var name
= "dep_{mmodule.name}"
510 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")
511 for m
in mmodule
.in_importation
.poset
do
512 var public_owner
= m
.public_owner
513 if public_owner
== null then
516 op
.append
("\"{m.name}\
"[shape=box,margin=0.03];\n")
518 op
.append
("\"{m.name}\
"[URL=\"{m.name}.html\
"];\n")
521 for imported
in m
.in_importation
.direct_greaters
do
522 if imported
.public_owner
== null then
523 op
.append
("\"{public_owner.name}\
"->\"{imported.name}\
";\n")
528 generate_dot
(op
.to_s
, name
, "Dependency graph for module {mmodule.name}")
532 var amodule
= mbuilder
.mmodule2nmodule
[mmodule
]
533 append
("<div class='menu'>")
535 append
("<h3>Module Hierarchy</h3>")
536 var dependencies
= new Array[MModule]
537 for dep
in mmodule
.in_importation
.greaters
do
538 if dep
== mmodule
or dep
.public_owner
!= null then continue
539 dependencies
.add
(dep
)
541 if dependencies
.length
> 0 then
542 append
("<h4>All dependencies</h4>")
543 display_module_list
(dependencies
)
545 var clients
= new Array[MModule]
546 for dep
in mmodule
.in_importation
.smallers
do
547 if dep
== mmodule
or dep
.public_owner
!= null then continue
550 if clients
.length
> 0 then
551 append
("<h4>All clients</h4>")
552 display_module_list
(clients
)
555 if mmodule
.in_nesting
.direct_greaters
.length
> 0 then
557 append
("<h3>Nested Modules</h3>")
558 display_module_list
(mmodule
.in_nesting
.direct_greaters
.to_a
)
564 private fun display_module_list
(list
: Array[MModule]) do
566 var sorter
= new ComparableSorter[MModule]
568 for m
in list
do append
("<li>{m.link(mbuilder)}</li>")
572 # display the class column
574 var amodule
= mbuilder
.mmodule2nmodule
[mmodule
]
575 var intro_mclasses
= mmodule
.intro_mclasses
576 var redef_mclasses
= mmodule
.redef_mclasses
577 var all_mclasses
= new HashSet[MClass]
578 for m
in mmodule
.in_nesting
.greaters
do
579 all_mclasses
.add_all
(m
.intro_mclasses
)
580 all_mclasses
.add_all
(m
.redef_mclasses
)
582 all_mclasses
.add_all
(intro_mclasses
)
583 all_mclasses
.add_all
(redef_mclasses
)
585 var sorted
= new Array[MClass]
586 sorted
.add_all
(all_mclasses
)
587 var sorter
= new ComparableSorter[MClass]
589 append
("<div class='module'>")
590 append
("<article class='classes filterable'>")
591 append
("<h2>Classes</h2>")
594 if redef_mclasses
.has
(c
) and c
.intro_mmodule
.public_owner
!= mmodule
then
595 append
("<li class='redef'>")
596 append
("<span title='refined in this module'>R </span>")
598 append
("<li class='intro'>")
599 append
("<span title='introduced in this module'>I </span>")
601 append
(c
.link
(mbuilder
))
609 # display the property column
612 var amodule
= mbuilder
.mmodule2nmodule
[mmodule
]
613 var mpropdefs
= new HashSet[MPropDef]
614 for m
in mmodule
.in_nesting
.greaters
do
615 for c
in m
.mclassdefs
do mpropdefs
.add_all
(c
.mpropdefs
)
617 for c
in mmodule
.mclassdefs
do mpropdefs
.add_all
(c
.mpropdefs
)
618 var sorted
= mpropdefs
.to_a
619 var sorter
= new ComparableSorter[MPropDef]
621 # display properties in one column
622 append
("<article class='properties filterable'>")
623 append
("<h2>Properties</h2>")
625 for mprop
in sorted
do
626 if mprop
isa MAttributeDef then continue
627 if mprop
.mproperty
.visibility
<= none_visibility
then continue
628 append
(mprop
.html_list_item
(mbuilder
))
639 private var mclass
: MClass
640 private var mbuilder
: ModelBuilder
641 private var nitdoc
: Nitdoc
643 init(mclass
: MClass, nitdoc
: Nitdoc, dot_dir
: nullable String, source
: nullable String) do
645 self.mbuilder
= nitdoc
.modelbuilder
647 self.dot_dir
= dot_dir
653 var nclass
= mbuilder
.mclassdef2nclassdef
[mclass
.intro
]
654 if nclass
isa AStdClassdef then
655 append
("<title>{mclass.name} class | {nclass.short_comment}</title>")
657 append
("<title>{mclass.name} class</title>")
662 append
("<li><a href='index.html'>Overview</a></li>")
663 var public_owner
= mclass
.public_owner
664 if public_owner
is null then
665 append
("<li>{mclass.intro_mmodule.link(mbuilder)}</li>")
667 append
("<li>{public_owner.link(mbuilder)}</li>")
669 append
("<li class='current'>{mclass.name}</li>")
670 append
("<li><a href='full-index.html'>Full Index</a></li>")
674 append
("<div class='menu'>")
678 append
("<div class='content'>")
683 fun properties_column
do
684 var sorter
= new ComparableSorter[MPropDef]
685 append
("<nav class='properties filterable'>")
686 append
("<h3>Properties</h3>")
687 # get intro and redef properties
688 var vtypes
= new HashSet[MVirtualTypeDef]
689 var consts
= new HashSet[MMethodDef]
690 var meths
= new HashSet[MMethodDef]
691 for mclassdef
in mclass
.mclassdefs
do
692 for mpropdef
in mclassdef
.mpropdefs
do
693 if mpropdef
.mproperty
.visibility
<= none_visibility
then continue
694 if mpropdef
isa MVirtualTypeDef then vtypes
.add
(mpropdef
)
695 if mpropdef
isa MMethodDef then
696 if mpropdef
.mproperty
.is_init
then
704 # get inherited properties
705 for mprop
in mclass
.inherited_methods
do
706 var mpropdef
= mprop
.intro
707 if mprop
.visibility
<= none_visibility
then continue
708 if mprop
.intro_mclassdef
.mclass
.name
== "Object" then continue
712 if vtypes
.length
> 0 then
713 var vts
= new Array[MVirtualTypeDef]
716 append
("<h4>Virtual Types</h4>")
719 append
(mprop
.html_sidebar_item
(self))
724 if consts
.length
> 0 then
725 var cts
= new Array[MMethodDef]
728 append
("<h4>Constructors</h4>")
731 append
(mprop
.html_sidebar_item
(self))
736 if meths
.length
> 0 then
737 var mts
= new Array[MMethodDef]
740 append
("<h4>Methods</h4>")
743 append
(mprop
.html_sidebar_item
(self))
750 fun inheritance_column
do
751 var sorted
= new Array[MClass]
752 var sorterp
= new ComparableSorter[MClass]
754 append
("<h3>Inheritance</h3>")
755 if mclass
.ancestors
.length
> 1 then
756 sorted
= mclass
.ancestors
.to_a
758 append
("<h4>Superclasses</h4>")
761 if sup
== mclass
then continue
762 append
("<li><a href='{sup.name}.html'>{sup.name}</a></li>")
767 if mclass
.descendants
.length
<= 1 then
768 append
("<h4>No Known Subclasses</h4>")
769 else if mclass
.descendants
.length
<= 100 then
770 sorted
= mclass
.descendants
.to_a
772 append
("<h4>Subclasses</h4>")
775 if sub
== mclass
then continue
776 append
("<li><a href='{sub.name}.html'>{sub.name}</a></li>")
779 else if mclass
.children
.length
<= 100 then
780 sorted
= mclass
.children
.to_a
782 append
("<h4>Direct Subclasses Only</h4>")
785 if sub
== mclass
then continue
786 append
("<li><a href='{sub.name}.html'>{sub.name}</a></li>")
790 append
("<h4>Too much Subclasses to list</h4>")
797 append
("<h1>{mclass.html_signature}</h1>")
798 append
("<div class='subtitle'>")
800 if mclass
.visibility
is none_visibility
then subtitle
+= "private "
801 subtitle
+= "{mclass.kind} {mclass.public_owner.html_namespace(mbuilder)}::{mclass}"
805 var nclass
= mbuilder
.mclassdef2nclassdef
[mclass
.intro
]
806 append
("<div style=\"float
: right
;\
"><a id=\"lblDiffCommit\
"></a></div>")
807 append
("<section class='description'>")
808 if nclass
isa AStdClassdef and not nclass
.comment
.is_empty
then append
("<pre class=\"text_label\
" title=\"122\
" name=\"\
" tag=\"{mclass.mclassdefs.first.location.to_s}\
" type=\"2\
">{nclass.comment}</pre><textarea id=\"fileContent\
" class=\"edit\
" cols=\"76\
" rows=\"1\
" style=\"display
: none
;\
"></textarea><a id=\"cancelBtn\
" style=\"display
: none
;\
">Cancel</a><a id=\"commitBtn\
" style=\"display
: none
;\
">Commit</a><pre id=\"preSave\
" class=\"text_label\
" type=\"2\
"></pre>")
812 var sorted
= new Array[MModule]
813 sorted
.add_all
(mclass
.concerns
.keys
)
814 var sorterp
= new ComparableSorter[MModule]
816 append
("<section class='concerns'>")
817 append
("<h2 class='section-header'>Concerns</h2>")
819 for owner
in sorted
do
820 var nmodule
= mbuilder
.mmodule2nmodule
[owner
]
821 var childs
= mclass
.concerns
[owner
]
823 append
("<a href=\"#MOD_{owner.name}\">{owner.name}</a>: {nmodule.short_comment}")
824 if not childs
is null then
826 var sortedc
= childs
.to_a
827 var sorterpc
= new ComparableSorter[MModule]
828 sorterpc
.sort
(sortedc
)
829 for child
in sortedc
do
830 var nchild
= mbuilder
.mmodule2nmodule
[child
]
831 append
("<li><a href=\"#MOD_{child.name}\">{child.name}</a>: {nchild.short_comment} </li>")
840 var sorterprop
= new ComparableSorter[MProperty]
841 var sorterc
= new ComparableSorter[MClass]
842 var lmmodule
= new List[MModule]
843 # virtual and formal types
844 if mclass
.virtual_types
.length
> 0 or mclass
.arity
> 0 then
845 append
("<section class='types'>")
846 append
("<h2>Formal and Virtual Types</h2>")
847 if mclass
.virtual_types
.length
> 0 then for prop
in mclass
.virtual_types
do description
(prop
)
848 if mclass
.arity
> 0 and nclass
isa AStdClassdef then
849 for ft
, bound
in mclass
.parameter_types
do
850 append
("<article id='{ft}'>")
851 append
("<h3 class='signature'>{ft}: {bound.link(mbuilder)}</h3>")
852 append
("<div class=\"info\
">formal generic type</div>")
859 if mclass
.constructors
.length
> 0 then
860 var sortedc
= mclass
.constructors
.to_a
861 sorterprop
.sort
(sortedc
)
862 append
("<section class='constructors'>")
863 append
("<h2 class='section-header'>Constructors</h2>")
864 for prop
in sortedc
do description
(prop
)
868 append
("<section class='methods'>")
869 append
("<h2 class='section-header'>Methods</h2>")
870 for mmodule
, mmethods
in mclass
.all_methods
do
871 var nmodule
= mbuilder
.mmodule2nmodule
[mmodule
]
872 append
("<a id=\"MOD_{mmodule.name}\
"></a>")
873 if mmodule
!= mclass
.intro_mmodule
and mmodule
!= mclass
.public_owner
then
874 if mclass
.has_mmodule
(mmodule
) then
875 append
("<p class=\"concern-doc\
">{mmodule.name}: {nmodule.short_comment}</p>")
877 append
("<h3 class=\"concern-toplevel\
">Methods refined in {mmodule.link(mbuilder)}</h3><p class=\"concern-doc\
">{mmodule.name}: {nmodule.short_comment}</p>")
880 var sortedc
= mmethods
.to_a
881 sorterprop
.sort
(sortedc
)
882 for prop
in sortedc
do description
(prop
)
885 if mclass
.inherited_methods
.length
> 0 then
886 var sortedc
= new Array[MClass]
887 sortedc
.add_all
(mclass
.inherited
.keys
)
888 sorterc
.sort
(sortedc
)
889 append
("<h3>Inherited Methods</h3>")
890 for imclass
in sortedc
do
891 var sortedp
= mclass
.inherited
[imclass
].to_a
892 sorterprop
.sort
(sortedp
)
893 append
("<p>Defined in {imclass.link(mbuilder)}: ")
894 for method
in sortedp
do
895 #TODO link to inherited propdef
896 append
("<a href=\"\
">{method.name}</a>")
897 if method
!= sortedp
.last
then append
(", ")
905 fun description
(prop
: MProperty) do
906 if not mbuilder
.mpropdef2npropdef
.has_key
(prop
.intro
) then return
907 var nprop
= mbuilder
.mpropdef2npropdef
[prop
.intro
]
908 if not nprop
isa AMethPropdef then return
909 var classes
= new Array[String]
910 if nprop
isa AInitPropdef then
915 if prop
.is_redef
then classes
.add
("redef")
916 if prop
.visibility
== none_visibility
then
917 classes
.add
("private")
918 else if prop
.visibility
== protected_visibility
then
919 classes
.add
("protected")
921 classes
.add
("public")
923 append
("<article class='{classes.join(" ")}' id='{prop.anchor}'>")
925 append
("<h3 class='signature'>{prop.name}{nprop.signature}</h3>")
926 append
("<div class='info'>")
927 append
("{if prop.is_redef then "redef" else ""} fun {prop.intro_mclassdef.namespace(mclass)}::{prop.name}</div><div style=\"float
: right
;\
"><a id=\"lblDiffCommit\
"></a>")
929 append
("<div class='description'>")
930 if nprop
.comment
== "" then
931 append
("<a class=\"newComment\
" title=\"32\
" tag=\"\
">New Comment</a>")
933 append
("<pre class=\"text_label\
" title=\"\
" name=\"\
" tag=\"\
" type=\"1\
">{nprop.comment}</pre>")
935 append
("<textarea id=\"fileContent\
" class=\"edit\
" cols=\"76\
" rows=\"1\
" style=\"display
: none
;\
"></textarea><a id=\"cancelBtn\
" style=\"display
: none
;\
">Cancel</a><a id=\"commitBtn\
" style=\"display
: none
;\
">Commit</a><pre id=\"preSave\
" class=\"text_label\
" type=\"2\
"></pre>")
937 if prop
.local_class
!= mclass
then
938 var mredef
= prop
.local_class
.intro_mmodule
939 append
("inherited from {mredef.link(mbuilder)} ")
941 #TODO display show code if doc github
942 var mintro
= prop
.intro_mclassdef
.mmodule
943 append
("defined by the module {mintro.link(mbuilder)}{if prop.apropdef is null then "" else show_source(prop.apropdef.location)}.")
945 for parent
in mclass
.parents
do
946 var mparent
= parent
.intro_mmodule
947 if prop
isa MMethod then if parent
.constructors
.has
(prop
) then append
(" Previously defined by: {mparent.link(mbuilder)} for <a href=\"{parent.name}.html\
">{parent.name}</a>.")
954 fun process_generate_dot
do
955 var pe
= nitdoc
.class_hierarchy
[mclass
]
956 var cla
= new HashSet[MClass]
957 var sm
= new HashSet[MClass]
958 var sm2
= new HashSet[MClass]
960 while cla
.length
+ sm
.length
< 10 and sm
.length
> 0 do
964 sm2
.add_all
(pe
.poset
[x
].direct_smallers
)
970 cla
.add_all
(pe
.greaters
)
973 var name
= "dep_{mclass.name}"
974 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")
977 op
.append
("\"{c.name}\
"[shape=box,margin=0.03];\n")
979 op
.append
("\"{c.name}\
"[URL=\"{c.name}.html\
"];\n")
981 for c2
in pe
.poset
[c
].direct_greaters
do
982 if not cla
.has
(c2
) then continue
983 op
.append
("\"{c.name}\
"->\"{c2.name}\
";\n")
985 if not pe
.poset
[c
].direct_smallers
.is_empty
then
987 for c2
in pe
.poset
[c
].direct_smallers
do
988 if cla
.has
(c2
) then others
= false
991 op
.append
("\"{c.name}...\
"[label=\"\
"];\n")
992 op
.append
("\"{c.name}...\
"->\"{c.name}\
"[style=dotted];\n")
997 generate_dot
(op
.to_s
, name
, "Dependency graph for class {mclass.name}")
1002 private fun comment
: String do
1003 var ret
= new Buffer
1004 if n_moduledecl
is null or n_moduledecl
.n_doc
is null then ret
1005 if n_moduledecl
.n_doc
is null then return ""
1006 for t
in n_moduledecl
.n_doc
.n_comment
do
1007 ret
.append
(t
.text
.substring_from
(1))
1009 return ret
.to_s
.html_escape
1012 private fun short_comment
: String do
1013 var ret
= new Buffer
1014 if n_moduledecl
!= null and n_moduledecl
.n_doc
!= null then
1015 ret
.append
(n_moduledecl
.n_doc
.n_comment
.first
.text
.substring_from
(2).replace
("\n", ""))
1017 return ret
.to_s
.html_escape
1023 redef type OTHER: MModule
1024 redef fun <(other
: OTHER): Bool do return self.name
< other
.name
1026 # Get the list of all methods in a module
1027 fun imported_methods
: Set[MMethod] do
1028 var methods
= new HashSet[MMethod]
1029 for mclass
in imported_mclasses
do
1030 for method
in mclass
.intro_methods
do
1037 # Get the list aof all refined methods in a module
1038 fun redef_methods
: Set[MMethod] do
1039 var methods
= new HashSet[MMethod]
1040 for mclass
in redef_mclasses
do
1041 for method
in mclass
.intro_methods
do
1048 # Return a link (html a tag) to the nitdoc module page
1049 fun link
(mbuilder
: ModelBuilder): String do
1050 return "<a href='{name}.html' title='{mbuilder.mmodule2nmodule[self].short_comment}'>{name}</a>"
1053 # Return the module signature decorated with html
1054 fun html_signature
(mbuilder
: ModelBuilder): String do
1055 return "<span>module {html_namespace(mbuilder)}</span>"
1058 # Return the module namespace decorated with html
1059 fun html_namespace
(mbuilder
: ModelBuilder): String do
1060 var res
= new Buffer
1061 res
.append
("<span>")
1062 var mowner
= public_owner
1063 if mowner
!= null then
1064 res
.append
(public_owner
.html_namespace
(mbuilder
))
1067 res
.append
(self.link
(mbuilder
))
1068 res
.append
("</span>")
1072 # Return the full comment of the module decorated with html
1073 fun html_full_comment
(mbuilder
: ModelBuilder): String do
1074 var res
= new Buffer
1075 res
.append
("<div id='description'>")
1076 res
.append
("<pre class='text_label'>{mbuilder.mmodule2nmodule[self].comment}</pre>")
1077 res
.append
("<textarea class='edit' rows='1' cols='76' id='fileContent'></textarea>")
1078 res
.append
("<a id='cancelBtn'>Cancel</a>")
1079 res
.append
("<a id='commitBtn'>Commit</a>")
1080 res
.append
("<pre class='text_label' id='preSave' type='2'></pre>")
1081 res
.append
("</div>")
1085 redef class MPropDef
1087 redef type OTHER: MPropDef
1088 redef fun <(other
: OTHER): Bool do return self.mproperty
.name
< other
.mproperty
.name
1090 # Return a link (html a tag) to the nitdoc class page
1091 fun link
(mbuilder
: ModelBuilder): String do
1092 if mbuilder
.mpropdef2npropdef
.has_key
(self) then
1093 var nprop
= mbuilder
.mpropdef2npropdef
[self]
1094 return "<a href=\"{mclassdef.mclass.name}.html
#{mproperty.anchor}\" title=\"{nprop.short_comment}\">{mproperty.name}</a>"
1096 return "<a href=\"{mclassdef.mclass.name}.html
#{mproperty.anchor}\">{mproperty.name}</a>"
1100 # Return a list item for the mpropdef
1101 fun html_list_item
(mbuilder
: ModelBuilder): String do
1102 var res
= new Buffer
1104 res
.append
("<li class='intro'>")
1105 res
.append
("<span title='introduction'>I</span> {link(mbuilder)} ({mclassdef.mclass.name})")
1108 res
.append
("<li class='redef'>")
1109 res
.append
("<span title='redefinition'>R</span> {link(mbuilder)} ({mclassdef.mclass.name})")
1115 # Return a list item for the mpropdef
1116 fun html_sidebar_item
(page
: NitdocClass): String do
1117 var res
= new Buffer
1118 if is_intro
and mclassdef
.mclass
== page
.mclass
then
1119 res
.append
("<li class='intro'>")
1120 res
.append
("<span title='Introduced'>I</span>")
1121 else if is_intro
and mclassdef
.mclass
!= page
.mclass
then
1122 res
.append
("<li class='inherit'>")
1123 res
.append
("<span title='Inherited'>H</span>")
1125 res
.append
("<li class='redef'>")
1126 res
.append
("<span title='Redefined'>R</span>")
1128 res
.append
(link
(page
.mbuilder
))
1134 redef class MProperty
1136 redef type OTHER: MProperty
1137 redef fun <(other
: OTHER): Bool do return self.name
< other
.name
1140 var apropdef
: nullable APropdef
1142 redef init(intro_mclassdef
: MClassDef, name
: String, visibility
: MVisibility)
1148 fun local_class
: MClass do
1149 var classdef
= self.intro_mclassdef
1150 return classdef
.mclass
1153 fun anchor
: String do
1154 return "PROP_{c_name}"
1157 # Escape name for html output
1158 redef fun name
do return super.html_escape
1163 redef type OTHER: MClass
1164 redef fun <(other
: OTHER): Bool do return self.name
< other
.name
1166 # Add type parameters
1167 fun html_signature
: String do
1169 return "{name}[{intro.parameter_names.join(", ")}]"
1175 # Return a link (html a tag) to the nitdoc class page
1176 fun link
(mbuilder
: ModelBuilder): String do
1177 if mbuilder
.mclassdef2nclassdef
.has_key
(intro
) then
1178 var nclass
= mbuilder
.mclassdef2nclassdef
[intro
]
1179 if nclass
isa AStdClassdef then
1180 return "<a href='{name}.html' title=\"{nclass.short_comment}\
">{html_signature}</a>"
1182 return "<a href='{name}.html'>{html_signature}</a>"
1185 return "<a href='{name}.html'>{html_signature}</a>"
1189 # Associate all MMethods to each MModule concerns
1190 fun all_methods
: HashMap[MModule, Set[MMethod]] do
1191 var hm
= new HashMap[MModule, Set[MMethod]]
1192 for mmodule
, childs
in concerns
do
1193 if not hm
.has_key
(mmodule
) then hm
[mmodule
] = new HashSet[MMethod]
1194 for prop
in intro_methods
do
1195 if mmodule
== prop
.intro_mclassdef
.mmodule
then
1196 prop
.is_redef
= false
1197 hm
[mmodule
].add
(prop
)
1200 for prop
in redef_methods
do
1201 if mmodule
== prop
.intro_mclassdef
.mmodule
then
1202 prop
.is_redef
= true
1203 hm
[mmodule
].add
(prop
)
1207 if childs
!= null then
1208 for child
in childs
do
1209 if not hm
.has_key
(child
) then hm
[child
] = new HashSet[MMethod]
1210 for prop
in intro_methods
do
1211 if child
== prop
.intro_mclassdef
.mmodule
then
1212 prop
.is_redef
= false
1216 for prop
in redef_methods
do
1217 if child
== prop
.intro_mclassdef
.mmodule
then
1218 prop
.is_redef
= true
1228 fun public_owner
: MModule do
1229 var owner
= intro_mmodule
1230 if owner
.public_owner
is null then
1233 return owner
.public_owner
.as(not null)
1237 # Associate MClass to all MMethod include in 'inherited_methods'
1238 fun inherited
: HashMap[MClass, Set[MMethod]] do
1239 var hm
= new HashMap[MClass, Set[MMethod]]
1240 for method
in inherited_methods
do
1241 var mclass
= method
.intro_mclassdef
.mclass
1242 if not hm
.has_key
(mclass
) then hm
[mclass
] = new HashSet[MMethod]
1243 hm
[mclass
].add
(method
)
1248 # Return true if MModule concern contain subMModule
1249 fun has_mmodule
(sub
: MModule): Bool do
1250 for mmodule
, childs
in concerns
do
1251 if childs
is null then continue
1252 if childs
.has
(sub
) then return true
1257 fun mmethod
(mprop2npropdef
: Map[MProperty, APropdef]) do
1258 for const
in constructors
do
1259 if mprop2npropdef
.has_key
(const
)then
1260 const
.apropdef
= mprop2npropdef
[const
].as(AMethPropdef)
1264 for intro
in intro_methods
do
1265 if mprop2npropdef
.has_key
(intro
)then
1266 if mprop2npropdef
[intro
] isa AMethPropdef then intro
.apropdef
= mprop2npropdef
[intro
].as(AMethPropdef)
1270 for rd
in redef_methods
do
1271 if mprop2npropdef
.has_key
(rd
)then
1272 if mprop2npropdef
[rd
] isa AMethPropdef then rd
.apropdef
= mprop2npropdef
[rd
].as(AMethPropdef)
1277 fun link_anchor
: String do
1278 return "{name}.html"
1281 # Escape name for html output
1282 redef fun name
do return super.html_escape
1285 redef class AStdClassdef
1286 private fun comment
: String do
1287 var ret
= new Buffer
1288 if n_doc
!= null then
1289 for t
in n_doc
.n_comment
do ret
.append
(t
.text
.substring_from
(1))
1291 return ret
.to_s
.html_escape
1294 private fun short_comment
: String do
1295 var ret
= new Buffer
1296 if n_doc
!= null then ret
.append
(n_doc
.n_comment
.first
.text
.substring_from
(2).replace
("\n", ""))
1297 return ret
.to_s
.html_escape
1301 redef class ASignature
1305 if not n_params
.is_empty
then
1306 ret
= "{ret}({n_params.join(", ")})"
1308 if n_type
!= null and n_type
.to_s
!= "" then ret
+= ": {n_type.to_s}"
1315 var ret
= "{n_id.text}"
1316 if n_type
!= null then
1317 ret
= "{ret}: {n_type.to_s}"
1318 if n_dotdotdot
!= null then ret
= "{ret}..."
1325 fun link
(mbuilder
: ModelBuilder): String is abstract
1328 redef class MClassType
1329 redef fun link
(mbuilder
) do return mclass
.link
(mbuilder
)
1332 redef class MNullableType
1333 redef fun link
(mbuilder
) do return "nullable {mtype.link(mbuilder)}"
1338 var ret
= "<a href=\"{n_id.text}.html\
">{n_id.text}</a>"
1339 if n_kwnullable
!= null then ret
= "nullable {ret}"
1340 if not n_types
.is_empty
then ret
= "{ret}[{n_types.join(", ")}]"
1344 fun name
: String do return n_id
.text
.html_escape
1347 redef class APropdef
1348 private fun short_comment
: String is abstract
1349 private fun signature
: String is abstract
1350 private fun comment
: String is abstract
1353 redef class AAttrPropdef
1354 redef fun short_comment
do
1355 var ret
= new Buffer
1356 if n_doc
!= null then ret
.append
(n_doc
.n_comment
.first
.text
.substring_from
(1))
1357 return ret
.to_s
.html_escape
1361 redef class AMethPropdef
1362 redef fun short_comment
do
1363 var ret
= new Buffer
1364 if n_doc
!= null then ret
.append
(n_doc
.n_comment
.first
.text
.substring_from
(2).replace
("\n", ""))
1365 return ret
.to_s
.html_escape
1368 redef fun signature
: String do
1370 if n_signature
!= null then sign
= "{n_signature.to_s}"
1374 redef private fun comment
: String do
1375 var ret
= new Buffer
1376 if n_doc
!= null then
1377 for t
in n_doc
.n_comment
do ret
.append
(t
.text
.substring_from
(1))
1379 return ret
.to_s
.html_escape
1383 redef class MClassDef
1384 private fun namespace
(mclass
: MClass): String do
1386 if mmodule
.public_owner
is null then
1387 return "{mmodule.full_name}::{mclass.name}"
1388 else if mclass
is self.mclass
then
1389 return "{mmodule.public_owner.name}::{mclass.name}"
1391 return "{mmodule.public_owner.name}::<a href=\"{mclass.name}.html\
">{mclass.name}</a>"
1398 return to_a
[length-1
]
1402 # Create a tool context to handle options and paths
1403 var toolcontext
= new ToolContext
1405 # Here we launch the nit index
1406 var nitdoc
= new Nitdoc(toolcontext
)