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>")
573 var amodule
= mbuilder
.mmodule2nmodule
[mmodule
]
574 var intro_mclasses
= mmodule
.intro_mclasses
575 var redef_mclasses
= mmodule
.redef_mclasses
576 var all_mclasses
= new HashSet[MClass]
577 for m
in mmodule
.in_nesting
.greaters
do
578 all_mclasses
.add_all
(m
.intro_mclasses
)
579 all_mclasses
.add_all
(m
.redef_mclasses
)
581 all_mclasses
.add_all
(intro_mclasses
)
582 all_mclasses
.add_all
(redef_mclasses
)
584 var sorted
= new Array[MClass]
585 sorted
.add_all
(all_mclasses
)
586 var sorter
= new ComparableSorter[MClass]
588 append
("<div class='module'>")
589 append
("<article class='classes filterable'>")
590 append
("<h2>Classes</h2>")
593 if redef_mclasses
.has
(c
) and c
.intro_mmodule
.public_owner
!= mmodule
then
594 append
("<li class='redef'>")
595 append
("<span title='refined in this module'>R </span>")
597 append
("<li class='intro'>")
598 append
("<span title='introduced in this module'>I </span>")
600 append
(c
.link
(mbuilder
))
609 var amodule
= mbuilder
.mmodule2nmodule
[mmodule
]
610 var mpropdefs
= new HashSet[MPropDef]
611 for m
in mmodule
.in_nesting
.greaters
do
612 for c
in m
.mclassdefs
do mpropdefs
.add_all
(c
.mpropdefs
)
614 for c
in mmodule
.mclassdefs
do mpropdefs
.add_all
(c
.mpropdefs
)
615 var sorted
= mpropdefs
.to_a
616 var sorter
= new ComparableSorter[MPropDef]
618 append
("<article class='properties filterable'>")
619 append
("<h2>Properties</h2>")
622 if p
isa MAttributeDef then continue
623 if p
.mproperty
.visibility
<= none_visibility
then continue
624 if not mbuilder
.mpropdef2npropdef
.has_key
(p
) then continue
625 var nprop
= mbuilder
.mpropdef2npropdef
[p
]
627 append
("<li class='intro'>")
628 append
("<span title='introduction'>I</span> {p.link(nprop)} ({p.mclassdef.mclass.name})")
631 append
("<li class='redef'>")
632 append
("<span title='redefinition'>R</span> {p.link(nprop)} ({p.mclassdef.mclass.name})")
645 private var mclass
: MClass
646 private var mbuilder
: ModelBuilder
647 private var nitdoc
: Nitdoc
649 init(mclass
: MClass, nitdoc
: Nitdoc, dot_dir
: nullable String, source
: nullable String) do
651 self.mbuilder
= nitdoc
.modelbuilder
653 self.dot_dir
= dot_dir
659 var nclass
= mbuilder
.mclassdef2nclassdef
[mclass
.intro
]
660 if nclass
isa AStdClassdef then
661 append
("<title>{mclass.name} class | {nclass.short_comment}</title>")
663 append
("<title>{mclass.name} class</title>")
668 append
("<li><a href='index.html'>Overview</a></li>")
669 var public_owner
= mclass
.public_owner
670 if public_owner
is null then
671 append
("<li>{mclass.intro_mmodule.link(mbuilder)}</li>")
673 append
("<li>{public_owner.link(mbuilder)}</li>")
675 append
("<li class='current'>{mclass.name}</li>")
676 append
("<li><a href='full-index.html'>Full Index</a></li>")
680 append
("<div class='menu'>")
684 append
("<div class='content'>")
689 fun properties_column
do
690 var sorter
= new ComparableSorter[MPropDef]
691 append
("<nav class='properties filterable'>")
692 append
("<h3>Properties</h3>")
694 var vtypes
= new HashSet[MVirtualTypeDef]
695 var consts
= new HashSet[MMethodDef]
696 var meths
= new HashSet[MMethodDef]
697 for mclassdef
in mclass
.mclassdefs
do
698 for mpropdef
in mclassdef
.mpropdefs
do
699 if not mbuilder
.mpropdef2npropdef
.has_key
(mpropdef
) then continue
700 if mpropdef
.mproperty
.visibility
<= none_visibility
then continue
701 if mpropdef
isa MVirtualTypeDef then vtypes
.add
(mpropdef
)
702 if mpropdef
isa MMethodDef then
703 if mpropdef
.mproperty
.is_init
then
711 for mprop
in mclass
.inherited_methods
do
712 var mpropdef
= mprop
.intro
713 if not mbuilder
.mpropdef2npropdef
.has_key
(mpropdef
) then continue
714 if mprop
.visibility
<= none_visibility
then continue
715 if mprop
.intro_mclassdef
.mclass
.name
== "Object" then continue
719 if vtypes
.length
> 0 then
720 var vts
= new Array[MVirtualTypeDef]
723 append
("<h4>Virtual Types</h4>")
724 display_mpropdef_list
(vts
)
726 if consts
.length
> 0 then
727 var cts
= new Array[MMethodDef]
730 append
("<h4>Constructors</h4>")
731 display_mpropdef_list
(cts
)
733 if meths
.length
> 0 then
734 var mts
= new Array[MMethodDef]
737 append
("<h4>Methods</h4>")
738 display_mpropdef_list
(mts
)
743 private fun display_mpropdef_list
(list
: Array[MPropDef]) do
746 var nprop
= mbuilder
.mpropdef2npropdef
[prop
]
747 if prop
.is_intro
and prop
.mproperty
.intro_mclassdef
.mclass
!= mclass
then
748 append
("<li class='inherit'>")
749 append
("<span title='Inherited'>H</span>")
750 else if prop
.is_intro
then
751 append
("<li class='intro'>")
752 append
("<span title='Introduced'>I</span>")
754 append
("<li class='redef'>")
755 append
("<span title='Redefined'>R</span>")
757 append
(prop
.link
(nprop
))
763 fun inheritance_column
do
764 var sorted
= new Array[MClass]
765 var sorterp
= new ComparableSorter[MClass]
767 append
("<h3>Inheritance</h3>")
768 if mclass
.ancestors
.length
> 1 then
769 sorted
= mclass
.ancestors
.to_a
771 append
("<h4>Superclasses</h4>")
774 if sup
== mclass
then continue
775 append
("<li><a href='{sup.name}.html'>{sup.name}</a></li>")
780 if mclass
.descendants
.length
<= 1 then
781 append
("<h4>No Known Subclasses</h4>")
782 else if mclass
.descendants
.length
<= 100 then
783 sorted
= mclass
.descendants
.to_a
785 append
("<h4>Subclasses</h4>")
788 if sub
== mclass
then continue
789 append
("<li><a href='{sub.name}.html'>{sub.name}</a></li>")
792 else if mclass
.children
.length
<= 100 then
793 sorted
= mclass
.children
.to_a
795 append
("<h4>Direct Subclasses Only</h4>")
798 if sub
== mclass
then continue
799 append
("<li><a href='{sub.name}.html'>{sub.name}</a></li>")
803 append
("<h4>Too much Subclasses to list</h4>")
810 append
("<h1>{mclass.html_signature}</h1>")
811 append
("<div class='subtitle'>")
813 if mclass
.visibility
is none_visibility
then subtitle
+= "private "
814 subtitle
+= "{mclass.kind} {mclass.public_owner.html_namespace(mbuilder)}::{mclass}"
818 var nclass
= mbuilder
.mclassdef2nclassdef
[mclass
.intro
]
819 append
("<div style=\"float
: right
;\
"><a id=\"lblDiffCommit\
"></a></div>")
820 append
("<section class='description'>")
821 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>")
825 var sorted
= new Array[MModule]
826 sorted
.add_all
(mclass
.concerns
.keys
)
827 var sorterp
= new ComparableSorter[MModule]
829 append
("<section class='concerns'>")
830 append
("<h2 class='section-header'>Concerns</h2>")
832 for owner
in sorted
do
833 var nmodule
= mbuilder
.mmodule2nmodule
[owner
]
834 var childs
= mclass
.concerns
[owner
]
836 append
("<a href=\"#MOD_{owner.name}\">{owner.name}</a>: {nmodule.short_comment}")
837 if not childs
is null then
839 var sortedc
= childs
.to_a
840 var sorterpc
= new ComparableSorter[MModule]
841 sorterpc
.sort
(sortedc
)
842 for child
in sortedc
do
843 var nchild
= mbuilder
.mmodule2nmodule
[child
]
844 append
("<li><a href=\"#MOD_{child.name}\">{child.name}</a>: {nchild.short_comment} </li>")
853 var sorterprop
= new ComparableSorter[MProperty]
854 var sorterc
= new ComparableSorter[MClass]
855 var lmmodule
= new List[MModule]
856 # virtual and formal types
857 if mclass
.virtual_types
.length
> 0 or mclass
.arity
> 0 then
858 append
("<section class='types'>")
859 append
("<h2>Formal and Virtual Types</h2>")
860 if mclass
.virtual_types
.length
> 0 then for prop
in mclass
.virtual_types
do description
(prop
)
861 if mclass
.arity
> 0 and nclass
isa AStdClassdef then
862 for ft
, bound
in mclass
.parameter_types
do
863 append
("<article id='{ft}'>")
864 append
("<h3 class='signature'>{ft}: {bound.link(mbuilder)}</h3>")
865 append
("<div class=\"info\
">formal generic type</div>")
872 if mclass
.constructors
.length
> 0 then
873 var sortedc
= mclass
.constructors
.to_a
874 sorterprop
.sort
(sortedc
)
875 append
("<section class='constructors'>")
876 append
("<h2 class='section-header'>Constructors</h2>")
877 for prop
in sortedc
do description
(prop
)
881 append
("<section class='methods'>")
882 append
("<h2 class='section-header'>Methods</h2>")
883 for mmodule
, mmethods
in mclass
.all_methods
do
884 var nmodule
= mbuilder
.mmodule2nmodule
[mmodule
]
885 append
("<a id=\"MOD_{mmodule.name}\
"></a>")
886 if mmodule
!= mclass
.intro_mmodule
and mmodule
!= mclass
.public_owner
then
887 if mclass
.has_mmodule
(mmodule
) then
888 append
("<p class=\"concern-doc\
">{mmodule.name}: {nmodule.short_comment}</p>")
890 append
("<h3 class=\"concern-toplevel\
">Methods refined in {mmodule.link(mbuilder)}</h3><p class=\"concern-doc\
">{mmodule.name}: {nmodule.short_comment}</p>")
893 var sortedc
= mmethods
.to_a
894 sorterprop
.sort
(sortedc
)
895 for prop
in sortedc
do description
(prop
)
898 if mclass
.inherited_methods
.length
> 0 then
899 var sortedc
= new Array[MClass]
900 sortedc
.add_all
(mclass
.inherited
.keys
)
901 sorterc
.sort
(sortedc
)
902 append
("<h3>Inherited Methods</h3>")
903 for imclass
in sortedc
do
904 var sortedp
= mclass
.inherited
[imclass
].to_a
905 sorterprop
.sort
(sortedp
)
906 append
("<p>Defined in {imclass.link(mbuilder)}: ")
907 for method
in sortedp
do
908 #TODO link to inherited propdef
909 append
("<a href=\"\
">{method.name}</a>")
910 if method
!= sortedp
.last
then append
(", ")
918 fun description
(prop
: MProperty) do
919 if not mbuilder
.mpropdef2npropdef
.has_key
(prop
.intro
) then return
920 var nprop
= mbuilder
.mpropdef2npropdef
[prop
.intro
]
921 if not nprop
isa AMethPropdef then return
922 var classes
= new Array[String]
923 if nprop
isa AInitPropdef then
928 if prop
.is_redef
then classes
.add
("redef")
929 if prop
.visibility
== none_visibility
then
930 classes
.add
("private")
931 else if prop
.visibility
== protected_visibility
then
932 classes
.add
("protected")
934 classes
.add
("public")
936 append
("<article class='{classes.join(" ")}' id='{prop.anchor}'>")
938 append
("<h3 class='signature'>{prop.name}{nprop.signature}</h3>")
939 append
("<div class='info'>")
940 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>")
942 append
("<div class='description'>")
943 if nprop
.comment
== "" then
944 append
("<a class=\"newComment\
" title=\"32\
" tag=\"\
">New Comment</a>")
946 append
("<pre class=\"text_label\
" title=\"\
" name=\"\
" tag=\"\
" type=\"1\
">{nprop.comment}</pre>")
948 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>")
950 if prop
.local_class
!= mclass
then
951 var mredef
= prop
.local_class
.intro_mmodule
952 append
("inherited from {mredef.link(mbuilder)} ")
954 #TODO display show code if doc github
955 var mintro
= prop
.intro_mclassdef
.mmodule
956 append
("defined by the module {mintro.link(mbuilder)}{if prop.apropdef is null then "" else show_source(prop.apropdef.location)}.")
958 for parent
in mclass
.parents
do
959 var mparent
= parent
.intro_mmodule
960 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>.")
967 fun process_generate_dot
do
968 var pe
= nitdoc
.class_hierarchy
[mclass
]
969 var cla
= new HashSet[MClass]
970 var sm
= new HashSet[MClass]
971 var sm2
= new HashSet[MClass]
973 while cla
.length
+ sm
.length
< 10 and sm
.length
> 0 do
977 sm2
.add_all
(pe
.poset
[x
].direct_smallers
)
983 cla
.add_all
(pe
.greaters
)
986 var name
= "dep_{mclass.name}"
987 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")
990 op
.append
("\"{c.name}\
"[shape=box,margin=0.03];\n")
992 op
.append
("\"{c.name}\
"[URL=\"{c.name}.html\
"];\n")
994 for c2
in pe
.poset
[c
].direct_greaters
do
995 if not cla
.has
(c2
) then continue
996 op
.append
("\"{c.name}\
"->\"{c2.name}\
";\n")
998 if not pe
.poset
[c
].direct_smallers
.is_empty
then
1000 for c2
in pe
.poset
[c
].direct_smallers
do
1001 if cla
.has
(c2
) then others
= false
1004 op
.append
("\"{c.name}...\
"[label=\"\
"];\n")
1005 op
.append
("\"{c.name}...\
"->\"{c.name}\
"[style=dotted];\n")
1010 generate_dot
(op
.to_s
, name
, "Dependency graph for class {mclass.name}")
1015 private fun comment
: String do
1016 var ret
= new Buffer
1017 if n_moduledecl
is null or n_moduledecl
.n_doc
is null then ret
1018 if n_moduledecl
.n_doc
is null then return ""
1019 for t
in n_moduledecl
.n_doc
.n_comment
do
1020 ret
.append
(t
.text
.substring_from
(1))
1022 return ret
.to_s
.html_escape
1025 private fun short_comment
: String do
1026 var ret
= new Buffer
1027 if n_moduledecl
!= null and n_moduledecl
.n_doc
!= null then
1028 ret
.append
(n_moduledecl
.n_doc
.n_comment
.first
.text
.substring_from
(2).replace
("\n", ""))
1030 return ret
.to_s
.html_escape
1036 redef type OTHER: MModule
1037 redef fun <(other
: OTHER): Bool do return self.name
< other
.name
1039 # Get the list of all methods in a module
1040 fun imported_methods
: Set[MMethod] do
1041 var methods
= new HashSet[MMethod]
1042 for mclass
in imported_mclasses
do
1043 for method
in mclass
.intro_methods
do
1050 # Get the list aof all refined methods in a module
1051 fun redef_methods
: Set[MMethod] do
1052 var methods
= new HashSet[MMethod]
1053 for mclass
in redef_mclasses
do
1054 for method
in mclass
.intro_methods
do
1061 # Return a link (html a tag) to the nitdoc module page
1062 fun link
(mbuilder
: ModelBuilder): String do
1063 return "<a href='{name}.html' title='{mbuilder.mmodule2nmodule[self].short_comment}'>{name}</a>"
1066 # Return the module signature decorated with html
1067 fun html_signature
(mbuilder
: ModelBuilder): String do
1068 return "<span>module {html_namespace(mbuilder)}</span>"
1071 # Return the module namespace decorated with html
1072 fun html_namespace
(mbuilder
: ModelBuilder): String do
1073 var res
= new Buffer
1074 res
.append
("<span>")
1075 var mowner
= public_owner
1076 if mowner
!= null then
1077 res
.append
(public_owner
.html_namespace
(mbuilder
))
1080 res
.append
(self.link
(mbuilder
))
1081 res
.append
("</span>")
1085 # Return the full comment of the module decorated with html
1086 fun html_full_comment
(mbuilder
: ModelBuilder): String do
1087 var res
= new Buffer
1088 res
.append
("<div id='description'>")
1089 res
.append
("<pre class='text_label'>{mbuilder.mmodule2nmodule[self].comment}</pre>")
1090 res
.append
("<textarea class='edit' rows='1' cols='76' id='fileContent'></textarea>")
1091 res
.append
("<a id='cancelBtn'>Cancel</a>")
1092 res
.append
("<a id='commitBtn'>Commit</a>")
1093 res
.append
("<pre class='text_label' id='preSave' type='2'></pre>")
1094 res
.append
("</div>")
1098 redef class MPropDef
1100 redef type OTHER: MPropDef
1101 redef fun <(other
: OTHER): Bool do return self.mproperty
.name
< other
.mproperty
.name
1103 # Return a link (html a tag) to the nitdoc class page
1104 fun link
(nprop
: APropdef): String do
1105 return "<a href=\"{mclassdef.mclass.name}.html
#{mproperty.anchor}\" title=\"{nprop.short_comment}\">{mproperty.name}</a>"
1109 redef class MProperty
1111 redef type OTHER: MProperty
1112 redef fun <(other
: OTHER): Bool do return self.name
< other
.name
1115 var apropdef
: nullable APropdef
1117 redef init(intro_mclassdef
: MClassDef, name
: String, visibility
: MVisibility)
1123 fun local_class
: MClass do
1124 var classdef
= self.intro_mclassdef
1125 return classdef
.mclass
1128 fun anchor
: String do
1129 return "PROP_{c_name}"
1132 # Escape name for html output
1133 redef fun name
do return super.html_escape
1138 redef type OTHER: MClass
1139 redef fun <(other
: OTHER): Bool do return self.name
< other
.name
1141 # Add type parameters
1142 fun html_signature
: String do
1144 return "{name}[{intro.parameter_names.join(", ")}]"
1150 # Return a link (html a tag) to the nitdoc class page
1151 fun link
(mbuilder
: ModelBuilder): String do
1152 if mbuilder
.mclassdef2nclassdef
.has_key
(intro
) then
1153 var nclass
= mbuilder
.mclassdef2nclassdef
[intro
]
1154 if nclass
isa AStdClassdef then
1155 return "<a href='{name}.html' title=\"{nclass.short_comment}\
">{html_signature}</a>"
1157 return "<a href='{name}.html'>{html_signature}</a>"
1160 return "<a href='{name}.html'>{html_signature}</a>"
1164 # Associate all MMethods to each MModule concerns
1165 fun all_methods
: HashMap[MModule, Set[MMethod]] do
1166 var hm
= new HashMap[MModule, Set[MMethod]]
1167 for mmodule
, childs
in concerns
do
1168 if not hm
.has_key
(mmodule
) then hm
[mmodule
] = new HashSet[MMethod]
1169 for prop
in intro_methods
do
1170 if mmodule
== prop
.intro_mclassdef
.mmodule
then
1171 prop
.is_redef
= false
1172 hm
[mmodule
].add
(prop
)
1175 for prop
in redef_methods
do
1176 if mmodule
== prop
.intro_mclassdef
.mmodule
then
1177 prop
.is_redef
= true
1178 hm
[mmodule
].add
(prop
)
1182 if childs
!= null then
1183 for child
in childs
do
1184 if not hm
.has_key
(child
) then hm
[child
] = new HashSet[MMethod]
1185 for prop
in intro_methods
do
1186 if child
== prop
.intro_mclassdef
.mmodule
then
1187 prop
.is_redef
= false
1191 for prop
in redef_methods
do
1192 if child
== prop
.intro_mclassdef
.mmodule
then
1193 prop
.is_redef
= true
1203 fun public_owner
: MModule do
1204 var owner
= intro_mmodule
1205 if owner
.public_owner
is null then
1208 return owner
.public_owner
.as(not null)
1212 # Associate MClass to all MMethod include in 'inherited_methods'
1213 fun inherited
: HashMap[MClass, Set[MMethod]] do
1214 var hm
= new HashMap[MClass, Set[MMethod]]
1215 for method
in inherited_methods
do
1216 var mclass
= method
.intro_mclassdef
.mclass
1217 if not hm
.has_key
(mclass
) then hm
[mclass
] = new HashSet[MMethod]
1218 hm
[mclass
].add
(method
)
1223 # Return true if MModule concern contain subMModule
1224 fun has_mmodule
(sub
: MModule): Bool do
1225 for mmodule
, childs
in concerns
do
1226 if childs
is null then continue
1227 if childs
.has
(sub
) then return true
1232 fun mmethod
(mprop2npropdef
: Map[MProperty, APropdef]) do
1233 for const
in constructors
do
1234 if mprop2npropdef
.has_key
(const
)then
1235 const
.apropdef
= mprop2npropdef
[const
].as(AMethPropdef)
1239 for intro
in intro_methods
do
1240 if mprop2npropdef
.has_key
(intro
)then
1241 if mprop2npropdef
[intro
] isa AMethPropdef then intro
.apropdef
= mprop2npropdef
[intro
].as(AMethPropdef)
1245 for rd
in redef_methods
do
1246 if mprop2npropdef
.has_key
(rd
)then
1247 if mprop2npropdef
[rd
] isa AMethPropdef then rd
.apropdef
= mprop2npropdef
[rd
].as(AMethPropdef)
1252 fun link_anchor
: String do
1253 return "{name}.html"
1256 # Escape name for html output
1257 redef fun name
do return super.html_escape
1260 redef class AStdClassdef
1261 private fun comment
: String do
1262 var ret
= new Buffer
1263 if n_doc
!= null then
1264 for t
in n_doc
.n_comment
do ret
.append
(t
.text
.substring_from
(1))
1266 return ret
.to_s
.html_escape
1269 private fun short_comment
: String do
1270 var ret
= new Buffer
1271 if n_doc
!= null then ret
.append
(n_doc
.n_comment
.first
.text
.substring_from
(2).replace
("\n", ""))
1272 return ret
.to_s
.html_escape
1276 redef class ASignature
1280 if not n_params
.is_empty
then
1281 ret
= "{ret}({n_params.join(", ")})"
1283 if n_type
!= null and n_type
.to_s
!= "" then ret
+= ": {n_type.to_s}"
1290 var ret
= "{n_id.text}"
1291 if n_type
!= null then
1292 ret
= "{ret}: {n_type.to_s}"
1293 if n_dotdotdot
!= null then ret
= "{ret}..."
1300 fun link
(mbuilder
: ModelBuilder): String is abstract
1303 redef class MClassType
1304 redef fun link
(mbuilder
) do return mclass
.link
(mbuilder
)
1307 redef class MNullableType
1308 redef fun link
(mbuilder
) do return "nullable {mtype.link(mbuilder)}"
1313 var ret
= "<a href=\"{n_id.text}.html\
">{n_id.text}</a>"
1314 if n_kwnullable
!= null then ret
= "nullable {ret}"
1315 if not n_types
.is_empty
then ret
= "{ret}[{n_types.join(", ")}]"
1319 fun name
: String do return n_id
.text
.html_escape
1322 redef class APropdef
1323 private fun short_comment
: String is abstract
1324 private fun signature
: String is abstract
1325 private fun comment
: String is abstract
1328 redef class AAttrPropdef
1329 redef fun short_comment
do
1330 var ret
= new Buffer
1331 if n_doc
!= null then ret
.append
(n_doc
.n_comment
.first
.text
.substring_from
(1))
1332 return ret
.to_s
.html_escape
1336 redef class AMethPropdef
1337 redef fun short_comment
do
1338 var ret
= new Buffer
1339 if n_doc
!= null then ret
.append
(n_doc
.n_comment
.first
.text
.substring_from
(2).replace
("\n", ""))
1340 return ret
.to_s
.html_escape
1343 redef fun signature
: String do
1345 if n_signature
!= null then sign
= "{n_signature.to_s}"
1349 redef private fun comment
: String do
1350 var ret
= new Buffer
1351 if n_doc
!= null then
1352 for t
in n_doc
.n_comment
do ret
.append
(t
.text
.substring_from
(1))
1354 return ret
.to_s
.html_escape
1358 redef class MClassDef
1359 private fun namespace
(mclass
: MClass): String do
1361 if mmodule
.public_owner
is null then
1362 return "{mmodule.full_name}::{mclass.name}"
1363 else if mclass
is self.mclass
then
1364 return "{mmodule.public_owner.name}::{mclass.name}"
1366 return "{mmodule.public_owner.name}::<a href=\"{mclass.name}.html\
">{mclass.name}</a>"
1373 return to_a
[length-1
]
1377 # Create a tool context to handle options and paths
1378 var toolcontext
= new ToolContext
1380 # Here we launch the nit index
1381 var nitdoc
= new Nitdoc(toolcontext
)