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 var nclass
= mbuilder
.mclassdef2nclassdef
[c
.intro
].as(AStdClassdef)
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
(nclass
))
610 var amodule
= mbuilder
.mmodule2nmodule
[mmodule
]
611 var mpropdefs
= new HashSet[MPropDef]
612 for m
in mmodule
.in_nesting
.greaters
do
613 for c
in m
.mclassdefs
do mpropdefs
.add_all
(c
.mpropdefs
)
615 for c
in mmodule
.mclassdefs
do mpropdefs
.add_all
(c
.mpropdefs
)
616 var sorted
= mpropdefs
.to_a
617 var sorter
= new ComparableSorter[MPropDef]
619 append
("<article class='properties filterable'>")
620 append
("<h2>Properties</h2>")
623 if p
isa MAttributeDef then continue
624 if p
.mproperty
.visibility
<= none_visibility
then continue
625 if not mbuilder
.mpropdef2npropdef
.has_key
(p
) then continue
626 var nprop
= mbuilder
.mpropdef2npropdef
[p
]
628 append
("<li class='intro'>")
629 append
("<span title='introduction'>I</span> {p.link(nprop)} ({p.mclassdef.mclass.name})")
632 append
("<li class='redef'>")
633 append
("<span title='redefinition'>R</span> {p.link(nprop)} ({p.mclassdef.mclass.name})")
646 private var mclass
: MClass
647 private var mbuilder
: ModelBuilder
648 private var nitdoc
: Nitdoc
650 init(mclass
: MClass, nitdoc
: Nitdoc, dot_dir
: nullable String, source
: nullable String) do
652 self.mbuilder
= nitdoc
.modelbuilder
654 self.dot_dir
= dot_dir
660 var nclass
= mbuilder
.mclassdef2nclassdef
[mclass
.intro
]
661 if nclass
isa AStdClassdef then
662 append
("<title>{mclass.name} class | {nclass.short_comment}</title>")
664 append
("<title>{mclass.name} class</title>")
669 append
("<li><a href='index.html'>Overview</a></li>")
670 var public_owner
= mclass
.public_owner
671 if public_owner
is null then
672 append
("<li>{mclass.intro_mmodule.link(mbuilder)}</li>")
674 append
("<li>{public_owner.link(mbuilder)}</li>")
676 append
("<li class='current'>{mclass.name}</li>")
677 append
("<li><a href='full-index.html'>Full Index</a></li>")
681 append
("<div class='menu'>")
685 append
("<div class='content'>")
690 fun properties_column
do
691 var sorter
= new ComparableSorter[MPropDef]
692 append
("<nav class='properties filterable'>")
693 append
("<h3>Properties</h3>")
695 var vtypes
= new HashSet[MVirtualTypeDef]
696 var consts
= new HashSet[MMethodDef]
697 var meths
= new HashSet[MMethodDef]
698 for mclassdef
in mclass
.mclassdefs
do
699 for mpropdef
in mclassdef
.mpropdefs
do
700 if not mbuilder
.mpropdef2npropdef
.has_key
(mpropdef
) then continue
701 if mpropdef
.mproperty
.visibility
<= none_visibility
then continue
702 if mpropdef
isa MVirtualTypeDef then vtypes
.add
(mpropdef
)
703 if mpropdef
isa MMethodDef then
704 if mpropdef
.mproperty
.is_init
then
712 for mprop
in mclass
.inherited_methods
do
713 var mpropdef
= mprop
.intro
714 if not mbuilder
.mpropdef2npropdef
.has_key
(mpropdef
) then continue
715 if mprop
.visibility
<= none_visibility
then continue
716 if mprop
.intro_mclassdef
.mclass
.name
== "Object" then continue
720 if vtypes
.length
> 0 then
721 var vts
= new Array[MVirtualTypeDef]
724 append
("<h4>Virtual Types</h4>")
725 display_mpropdef_list
(vts
)
727 if consts
.length
> 0 then
728 var cts
= new Array[MMethodDef]
731 append
("<h4>Constructors</h4>")
732 display_mpropdef_list
(cts
)
734 if meths
.length
> 0 then
735 var mts
= new Array[MMethodDef]
738 append
("<h4>Methods</h4>")
739 display_mpropdef_list
(mts
)
744 private fun display_mpropdef_list
(list
: Array[MPropDef]) do
747 var nprop
= mbuilder
.mpropdef2npropdef
[prop
]
748 if prop
.is_intro
and prop
.mproperty
.intro_mclassdef
.mclass
!= mclass
then
749 append
("<li class='inherit'>")
750 append
("<span title='Inherited'>H</span>")
751 else if prop
.is_intro
then
752 append
("<li class='intro'>")
753 append
("<span title='Introduced'>I</span>")
755 append
("<li class='redef'>")
756 append
("<span title='Redefined'>R</span>")
758 append
(prop
.link
(nprop
))
764 fun inheritance_column
do
765 var sorted
= new Array[MClass]
766 var sorterp
= new ComparableSorter[MClass]
768 append
("<h3>Inheritance</h3>")
769 if mclass
.ancestors
.length
> 1 then
770 sorted
= mclass
.ancestors
.to_a
772 append
("<h4>Superclasses</h4>")
775 if sup
== mclass
then continue
776 append
("<li><a href='{sup.name}.html'>{sup.name}</a></li>")
781 if mclass
.descendants
.length
<= 1 then
782 append
("<h4>No Known Subclasses</h4>")
783 else if mclass
.descendants
.length
<= 100 then
784 sorted
= mclass
.descendants
.to_a
786 append
("<h4>Subclasses</h4>")
789 if sub
== mclass
then continue
790 append
("<li><a href='{sub.name}.html'>{sub.name}</a></li>")
793 else if mclass
.children
.length
<= 100 then
794 sorted
= mclass
.children
.to_a
796 append
("<h4>Direct Subclasses Only</h4>")
799 if sub
== mclass
then continue
800 append
("<li><a href='{sub.name}.html'>{sub.name}</a></li>")
804 append
("<h4>Too much Subclasses to list</h4>")
811 append
("<h1>{mclass.to_s}</h1>")
812 append
("<div class='subtitle'>")
814 if mclass
.visibility
is none_visibility
then subtitle
+= "private "
815 subtitle
+= "{mclass.kind} {mclass.public_owner.html_namespace(mbuilder)}::{mclass}"
819 var nclass
= mbuilder
.mclassdef2nclassdef
[mclass
.intro
]
820 append
("<div style=\"float
: right
;\
"><a id=\"lblDiffCommit\
"></a></div>")
821 append
("<section class='description'>")
822 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>")
826 var sorted
= new Array[MModule]
827 sorted
.add_all
(mclass
.concerns
.keys
)
828 var sorterp
= new ComparableSorter[MModule]
830 append
("<section class='concerns'>")
831 append
("<h2 class='section-header'>Concerns</h2>")
833 for owner
in sorted
do
834 var nmodule
= mbuilder
.mmodule2nmodule
[owner
]
835 var childs
= mclass
.concerns
[owner
]
837 append
("<a href=\"#MOD_{owner.name}\">{owner.name}</a>: {nmodule.short_comment}")
838 if not childs
is null then
840 var sortedc
= childs
.to_a
841 var sorterpc
= new ComparableSorter[MModule]
842 sorterpc
.sort
(sortedc
)
843 for child
in sortedc
do
844 var nchild
= mbuilder
.mmodule2nmodule
[child
]
845 append
("<li><a href=\"#MOD_{child.name}\">{child.name}</a>: {nchild.short_comment} </li>")
854 var sorterprop
= new ComparableSorter[MProperty]
855 var sorterc
= new ComparableSorter[MClass]
856 var lmmodule
= new List[MModule]
857 # virtual and formal types
858 if mclass
.virtual_types
.length
> 0 or mclass
.arity
> 0 then
859 append
("<section class='types'>")
860 append
("<h2>Formal and Virtual Types</h2>")
861 if mclass
.virtual_types
.length
> 0 then for prop
in mclass
.virtual_types
do description
(prop
)
862 #TODO this is incorrect
863 if mclass
.arity
> 0 and nclass
isa AStdClassdef then
864 for prop
in nclass
.n_formaldefs
do
865 append
("<article id='FT_Object_{prop.collect_text}'>")
866 append
("<h3 class='signature'>{prop.collect_text}: nullable ")
867 append
("<a title=\"The root of the
class hierarchy
.\
" href=\"Object.html\
">Object</a>")
869 append
("<div class=\"info\
">formal generic type</div>")
876 if mclass
.constructors
.length
> 0 then
877 var sortedc
= mclass
.constructors
.to_a
878 sorterprop
.sort
(sortedc
)
879 append
("<section class='constructors'>")
880 append
("<h2 class='section-header'>Constructors</h2>")
881 for prop
in sortedc
do description
(prop
)
885 append
("<section class='methods'>")
886 append
("<h2 class='section-header'>Methods</h2>")
887 for mmodule
, mmethods
in mclass
.all_methods
do
888 var nmodule
= mbuilder
.mmodule2nmodule
[mmodule
]
889 append
("<a id=\"MOD_{mmodule.name}\
"></a>")
890 if mmodule
!= mclass
.intro_mmodule
and mmodule
!= mclass
.public_owner
then
891 if mclass
.has_mmodule
(mmodule
) then
892 append
("<p class=\"concern-doc\
">{mmodule.name}: {nmodule.short_comment}</p>")
894 append
("<h3 class=\"concern-toplevel\
">Methods refined in {mmodule.link(mbuilder)}</h3><p class=\"concern-doc\
">{mmodule.name}: {nmodule.short_comment}</p>")
897 var sortedc
= mmethods
.to_a
898 sorterprop
.sort
(sortedc
)
899 for prop
in sortedc
do description
(prop
)
902 if mclass
.inherited_methods
.length
> 0 then
903 var sortedc
= new Array[MClass]
904 sortedc
.add_all
(mclass
.inherited
.keys
)
905 sorterc
.sort
(sortedc
)
906 append
("<h3>Inherited Methods</h3>")
907 for imclass
in sortedc
do
908 var inclass
= mbuilder
.mclassdef2nclassdef
[imclass
.intro
].as(AStdClassdef)
909 var sortedp
= mclass
.inherited
[imclass
].to_a
910 sorterprop
.sort
(sortedp
)
911 append
("<p>Defined in {imclass.link(inclass)}: ")
912 for method
in sortedp
do
913 #TODO link to inherited propdef
914 append
("<a href=\"\
">{method.name}</a>")
915 if method
!= sortedp
.last
then append
(", ")
923 fun description
(prop
: MProperty) do
924 if not mbuilder
.mpropdef2npropdef
.has_key
(prop
.intro
) then return
925 var nprop
= mbuilder
.mpropdef2npropdef
[prop
.intro
]
926 if not nprop
isa AMethPropdef then return
927 var classes
= new Array[String]
928 if nprop
isa AInitPropdef then
933 if prop
.is_redef
then classes
.add
("redef")
934 if prop
.visibility
== none_visibility
then
935 classes
.add
("private")
936 else if prop
.visibility
== protected_visibility
then
937 classes
.add
("protected")
939 classes
.add
("public")
941 append
("<article class='{classes.join(" ")}' id='{prop.anchor}'>")
943 append
("<h3 class='signature'>{prop.name}{nprop.signature}</h3>")
944 append
("<div class='info'>")
945 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>")
947 append
("<div class='description'>")
948 if nprop
.comment
== "" then
949 append
("<a class=\"newComment\
" title=\"32\
" tag=\"\
">New Comment</a>")
951 append
("<pre class=\"text_label\
" title=\"\
" name=\"\
" tag=\"\
" type=\"1\
">{nprop.comment}</pre>")
953 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>")
955 if prop
.local_class
!= mclass
then
956 var mredef
= prop
.local_class
.intro_mmodule
957 append
("inherited from {mredef.link(mbuilder)} ")
959 #TODO display show code if doc github
960 var mintro
= prop
.intro_mclassdef
.mmodule
961 append
("defined by the module {mintro.link(mbuilder)}{if prop.apropdef is null then "" else show_source(prop.apropdef.location)}.")
963 for parent
in mclass
.parents
do
964 var mparent
= parent
.intro_mmodule
965 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>.")
972 fun process_generate_dot
do
973 var pe
= nitdoc
.class_hierarchy
[mclass
]
974 var cla
= new HashSet[MClass]
975 var sm
= new HashSet[MClass]
976 var sm2
= new HashSet[MClass]
978 while cla
.length
+ sm
.length
< 10 and sm
.length
> 0 do
982 sm2
.add_all
(pe
.poset
[x
].direct_smallers
)
988 cla
.add_all
(pe
.greaters
)
991 var name
= "dep_{mclass.name}"
992 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")
995 op
.append
("\"{c.name}\
"[shape=box,margin=0.03];\n")
997 op
.append
("\"{c.name}\
"[URL=\"{c.name}.html\
"];\n")
999 for c2
in pe
.poset
[c
].direct_greaters
do
1000 if not cla
.has
(c2
) then continue
1001 op
.append
("\"{c.name}\
"->\"{c2.name}\
";\n")
1003 if not pe
.poset
[c
].direct_smallers
.is_empty
then
1005 for c2
in pe
.poset
[c
].direct_smallers
do
1006 if cla
.has
(c2
) then others
= false
1009 op
.append
("\"{c.name}...\
"[label=\"\
"];\n")
1010 op
.append
("\"{c.name}...\
"->\"{c.name}\
"[style=dotted];\n")
1015 generate_dot
(op
.to_s
, name
, "Dependency graph for class {mclass.name}")
1020 private fun comment
: String do
1021 var ret
= new Buffer
1022 if n_moduledecl
is null or n_moduledecl
.n_doc
is null then ret
1023 if n_moduledecl
.n_doc
is null then return ""
1024 for t
in n_moduledecl
.n_doc
.n_comment
do
1025 ret
.append
(t
.text
.substring_from
(1))
1027 return ret
.to_s
.html_escape
1030 private fun short_comment
: String do
1031 var ret
= new Buffer
1032 if n_moduledecl
!= null and n_moduledecl
.n_doc
!= null then
1033 ret
.append
(n_moduledecl
.n_doc
.n_comment
.first
.text
.substring_from
(2).replace
("\n", ""))
1035 return ret
.to_s
.html_escape
1041 redef type OTHER: MModule
1042 redef fun <(other
: OTHER): Bool do return self.name
< other
.name
1044 # Get the list of all methods in a module
1045 fun imported_methods
: Set[MMethod] do
1046 var methods
= new HashSet[MMethod]
1047 for mclass
in imported_mclasses
do
1048 for method
in mclass
.intro_methods
do
1055 # Get the list aof all refined methods in a module
1056 fun redef_methods
: Set[MMethod] do
1057 var methods
= new HashSet[MMethod]
1058 for mclass
in redef_mclasses
do
1059 for method
in mclass
.intro_methods
do
1066 # Return a link (html a tag) to the nitdoc module page
1067 fun link
(mbuilder
: ModelBuilder): String do
1068 return "<a href='{name}.html' title='{mbuilder.mmodule2nmodule[self].short_comment}'>{name}</a>"
1071 # Return the module signature decorated with html
1072 fun html_signature
(mbuilder
: ModelBuilder): String do
1073 return "<span>module {html_namespace(mbuilder)}</span>"
1076 # Return the module namespace decorated with html
1077 fun html_namespace
(mbuilder
: ModelBuilder): String do
1078 var res
= new Buffer
1079 res
.append
("<span>")
1080 var mowner
= public_owner
1081 if mowner
!= null then
1082 res
.append
(public_owner
.html_namespace
(mbuilder
))
1085 res
.append
(self.link
(mbuilder
))
1086 res
.append
("</span>")
1090 # Return the full comment of the module decorated with html
1091 fun html_full_comment
(mbuilder
: ModelBuilder): String do
1092 var res
= new Buffer
1093 res
.append
("<div id='description'>")
1094 res
.append
("<pre class='text_label'>{mbuilder.mmodule2nmodule[self].comment}</pre>")
1095 res
.append
("<textarea class='edit' rows='1' cols='76' id='fileContent'></textarea>")
1096 res
.append
("<a id='cancelBtn'>Cancel</a>")
1097 res
.append
("<a id='commitBtn'>Commit</a>")
1098 res
.append
("<pre class='text_label' id='preSave' type='2'></pre>")
1099 res
.append
("</div>")
1103 redef class MPropDef
1105 redef type OTHER: MPropDef
1106 redef fun <(other
: OTHER): Bool do return self.mproperty
.name
< other
.mproperty
.name
1108 # Return a link (html a tag) to the nitdoc class page
1109 fun link
(nprop
: APropdef): String do
1110 return "<a href=\"{mclassdef.mclass.name}.html
#{mproperty.anchor}\" title=\"{nprop.short_comment}\">{mproperty.name}</a>"
1114 redef class MProperty
1116 redef type OTHER: MProperty
1117 redef fun <(other
: OTHER): Bool do return self.name
< other
.name
1120 var apropdef
: nullable APropdef
1122 redef init(intro_mclassdef
: MClassDef, name
: String, visibility
: MVisibility)
1128 fun local_class
: MClass do
1129 var classdef
= self.intro_mclassdef
1130 return classdef
.mclass
1133 fun anchor
: String do
1134 return "PROP_{c_name}"
1137 # Escape name for html output
1138 redef fun name
do return super.html_escape
1143 redef type OTHER: MClass
1144 redef fun <(other
: OTHER): Bool do return self.name
< other
.name
1146 # Add type parameters
1147 fun html_signature
: String do
1149 return "{name}[{intro.parameter_names.join(", ")}]"
1155 # Return a link (html a tag) to the nitdoc class page
1156 fun link
(aclass
: AStdClassdef): String do
1157 return "<a href='{name}.html' title=\"{aclass.short_comment}\
">{html_signature}</a>"
1160 # Associate all MMethods to each MModule concerns
1161 fun all_methods
: HashMap[MModule, Set[MMethod]] do
1162 var hm
= new HashMap[MModule, Set[MMethod]]
1163 for mmodule
, childs
in concerns
do
1164 if not hm
.has_key
(mmodule
) then hm
[mmodule
] = new HashSet[MMethod]
1165 for prop
in intro_methods
do
1166 if mmodule
== prop
.intro_mclassdef
.mmodule
then
1167 prop
.is_redef
= false
1168 hm
[mmodule
].add
(prop
)
1171 for prop
in redef_methods
do
1172 if mmodule
== prop
.intro_mclassdef
.mmodule
then
1173 prop
.is_redef
= true
1174 hm
[mmodule
].add
(prop
)
1178 if childs
!= null then
1179 for child
in childs
do
1180 if not hm
.has_key
(child
) then hm
[child
] = new HashSet[MMethod]
1181 for prop
in intro_methods
do
1182 if child
== prop
.intro_mclassdef
.mmodule
then
1183 prop
.is_redef
= false
1187 for prop
in redef_methods
do
1188 if child
== prop
.intro_mclassdef
.mmodule
then
1189 prop
.is_redef
= true
1199 fun public_owner
: MModule do
1200 var owner
= intro_mmodule
1201 if owner
.public_owner
is null then
1204 return owner
.public_owner
.as(not null)
1208 # Associate MClass to all MMethod include in 'inherited_methods'
1209 fun inherited
: HashMap[MClass, Set[MMethod]] do
1210 var hm
= new HashMap[MClass, Set[MMethod]]
1211 for method
in inherited_methods
do
1212 var mclass
= method
.intro_mclassdef
.mclass
1213 if not hm
.has_key
(mclass
) then hm
[mclass
] = new HashSet[MMethod]
1214 hm
[mclass
].add
(method
)
1219 # Return true if MModule concern contain subMModule
1220 fun has_mmodule
(sub
: MModule): Bool do
1221 for mmodule
, childs
in concerns
do
1222 if childs
is null then continue
1223 if childs
.has
(sub
) then return true
1228 fun mmethod
(mprop2npropdef
: Map[MProperty, APropdef]) do
1229 for const
in constructors
do
1230 if mprop2npropdef
.has_key
(const
)then
1231 const
.apropdef
= mprop2npropdef
[const
].as(AMethPropdef)
1235 for intro
in intro_methods
do
1236 if mprop2npropdef
.has_key
(intro
)then
1237 if mprop2npropdef
[intro
] isa AMethPropdef then intro
.apropdef
= mprop2npropdef
[intro
].as(AMethPropdef)
1241 for rd
in redef_methods
do
1242 if mprop2npropdef
.has_key
(rd
)then
1243 if mprop2npropdef
[rd
] isa AMethPropdef then rd
.apropdef
= mprop2npropdef
[rd
].as(AMethPropdef)
1248 fun link_anchor
: String do
1249 return "{name}.html"
1252 # Escape name for html output
1253 redef fun name
do return super.html_escape
1256 redef class AStdClassdef
1257 private fun comment
: String do
1258 var ret
= new Buffer
1259 if n_doc
!= null then
1260 for t
in n_doc
.n_comment
do ret
.append
(t
.text
.substring_from
(1))
1262 return ret
.to_s
.html_escape
1265 private fun short_comment
: String do
1266 var ret
= new Buffer
1267 if n_doc
!= null then ret
.append
(n_doc
.n_comment
.first
.text
.substring_from
(2).replace
("\n", ""))
1268 return ret
.to_s
.html_escape
1272 redef class ASignature
1276 if not n_params
.is_empty
then
1277 ret
= "{ret}({n_params.join(", ")})"
1279 if n_type
!= null and n_type
.to_s
!= "" then ret
+= ": {n_type.to_s}"
1286 var ret
= "{n_id.text}"
1287 if n_type
!= null then
1288 ret
= "{ret}: {n_type.to_s}"
1289 if n_dotdotdot
!= null then ret
= "{ret}..."
1297 var ret
= "<a href=\"{n_id.text}.html\
">{n_id.text}</a>"
1298 if n_kwnullable
!= null then ret
= "nullable {ret}"
1299 if not n_types
.is_empty
then ret
= "{ret}[{n_types.join(", ")}]"
1304 redef class APropdef
1305 private fun short_comment
: String is abstract
1306 private fun signature
: String is abstract
1307 private fun comment
: String is abstract
1310 redef class AAttrPropdef
1311 redef fun short_comment
do
1312 var ret
= new Buffer
1313 if n_doc
!= null then ret
.append
(n_doc
.n_comment
.first
.text
.substring_from
(1))
1314 return ret
.to_s
.html_escape
1318 redef class AMethPropdef
1319 redef fun short_comment
do
1320 var ret
= new Buffer
1321 if n_doc
!= null then ret
.append
(n_doc
.n_comment
.first
.text
.substring_from
(2).replace
("\n", ""))
1322 return ret
.to_s
.html_escape
1325 redef fun signature
: String do
1327 if n_signature
!= null then sign
= "{n_signature.to_s}"
1331 redef private fun comment
: String do
1332 var ret
= new Buffer
1333 if n_doc
!= null then
1334 for t
in n_doc
.n_comment
do ret
.append
(t
.text
.substring_from
(1))
1336 return ret
.to_s
.html_escape
1340 redef class MClassDef
1341 private fun namespace
(mclass
: MClass): String do
1343 if mmodule
.public_owner
is null then
1344 return "{mmodule.full_name}::{mclass.name}"
1345 else if mclass
is self.mclass
then
1346 return "{mmodule.public_owner.name}::{mclass.name}"
1348 return "{mmodule.public_owner.name}::<a href=\"{mclass.name}.html\
">{mclass.name}</a>"
1355 return to_a
[length-1
]
1359 # Create a tool context to handle options and paths
1360 var toolcontext
= new ToolContext
1362 # Here we launch the nit index
1363 var nitdoc
= new Nitdoc(toolcontext
)