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
24 private var toolcontext
: ToolContext
25 private var model
: Model
26 private var modelbuilder
: ModelBuilder
27 private var mainmodule
: MModule
28 private var class_hierarchy
: POSet[MClass]
29 private var arguments
: Array[String]
30 private var output_dir
: nullable String
31 private var dot_dir
: nullable String
32 private var share_dir
: nullable String
33 private var source
: nullable String
35 private var opt_dir
= new OptionString("Directory where doc is generated", "-d", "--dir")
36 private var opt_source
= new OptionString("What link for source (%f for filename, %l for first line, %L for last line)", "--source")
37 private var opt_sharedir
= new OptionString("Directory containing the nitdoc files", "--sharedir")
38 private var opt_nodot
= new OptionBool("Do not generate graphes with graphiviz", "--no-dot")
40 init(toolcontext
: ToolContext) do
41 # We need a model to collect stufs
42 self.toolcontext
= toolcontext
43 self.arguments
= toolcontext
.option_context
.rest
44 toolcontext
.option_context
.options
.clear
45 toolcontext
.option_context
.add_option
(opt_dir
)
46 toolcontext
.option_context
.add_option
(opt_source
)
47 toolcontext
.option_context
.add_option
(opt_sharedir
)
48 toolcontext
.option_context
.add_option
(opt_nodot
)
49 toolcontext
.process_options
52 if arguments
.length
< 1 then
53 toolcontext
.option_context
.usage
58 modelbuilder
= new ModelBuilder(model
, toolcontext
)
60 # Here we load an process std modules
61 var mmodules
= modelbuilder
.parse_and_build
([arguments
.first
])
62 if mmodules
.is_empty
then return
63 modelbuilder
.full_propdef_semantic_analysis
64 assert mmodules
.length
== 1
65 self.mainmodule
= mmodules
.first
66 self.class_hierarchy
= mainmodule
.flatten_mclass_hierarchy
69 private fun process_options
do
70 if not opt_dir
.value
is null then
71 output_dir
= opt_dir
.value
75 if not opt_sharedir
.value
is null then
76 share_dir
= opt_sharedir
.value
78 var dir
= "NIT_DIR".environ
80 dir
= "{sys.program_name.dirname}/../share/nitdoc"
82 dir
= "{dir}/share/nitdoc"
85 if share_dir
is null then
86 print
"Error: Cannot locate nitdoc share files. Uses --sharedir or envvar NIT_DIR"
89 dir
= "{share_dir.to_s}/scripts/js-facilities.js"
90 if share_dir
is null then
91 print
"Error: Invalid nitdoc share files. Check --sharedir or envvar NIT_DIR"
95 if not opt_source
.value
is null then
98 source
= opt_source
.value
103 if arguments
.length
== 1 then
104 # Create destination dir if it's necessary
105 if not output_dir
.file_exists
then output_dir
.mkdir
106 sys
.system
("cp -r {share_dir.to_s}/* {output_dir.to_s}/")
108 if not opt_nodot
.value
then self.dot_dir
= output_dir
.to_s
118 var overviewpage
= new NitdocOverview(modelbuilder
, dot_dir
)
119 overviewpage
.save
("{output_dir.to_s}/index.html")
123 var fullindex
= new NitdocFullindex(model
.mmodules
)
124 fullindex
.save
("{output_dir.to_s}/full-index.html")
128 for mmodule
in model
.mmodules
do
129 var modulepage
= new NitdocModule(mmodule
, modelbuilder
, dot_dir
)
130 modulepage
.save
("{output_dir.to_s}/{mmodule.name}.html")
135 for mclass
in modelbuilder
.model
.mclasses
do
136 var classpage
= new NitdocClass(mclass
, self, dot_dir
, source
)
137 classpage
.save
("{output_dir.to_s}/{mclass.name}.html")
141 # Generate QuickSearch file
142 fun quicksearch_list
do
143 var file
= new OFStream.open
("{output_dir.to_s}/quicksearch-list.js")
144 var content
= new Buffer
145 content
.append
("var entries = \{ ")
146 for prop
in model
.mproperties
do
147 if not prop
isa MMethod then continue
148 content
.append
("\"{prop.name}\
": [")
149 for propdef
in prop
.mpropdefs
do
150 content
.append
("\{txt: \"{propdef.mproperty.full_name}\", url
:\
"{propdef.mproperty.anchor}\" \
}")
151 if not propdef is prop.mpropdefs.last then content.append(", ")
157 for mclass in model.mclasses do
158 content.append("\
"{mclass.name}\": [")
159 for mclassdef in mclass.mclassdefs do
160 content.append("\
{txt: \"{mclassdef.mclass.full_name}\
", url:\"{mclass.link_anchor}\
" \}")
161 if not mclassdef
is mclass
.mclassdefs
.last
then content
.append
(", ")
164 if not mclass
is model
.mclasses
.last
then content
.append
(", ")
167 content
.append
(" \};")
168 file
.write
(content
.to_s
)
175 abstract class NitdocPage
178 var dot_dir
: nullable String
179 var source
: nullable String
182 add
("meta").attr
("charset", "utf-8")
183 add
("script").attr
("type", "text/javascript").attr
("src", "scripts/jquery-1.7.1.min.js")
184 add
("script").attr
("type", "text/javascript").attr
("src", "quicksearch-list.js")
185 add
("script").attr
("type", "text/javascript").attr
("src", "scripts/js-facilities.js")
186 add
("link").attr
("rel", "stylesheet").attr
("href", "styles/main.css").attr
("type", "text/css").attr
("media", "screen")
191 open
("div").add_class
("page")
201 open
("nav").add_class
("main")
204 open
("li").attr
("id", "liGitHub")
205 open
("a").add_class
("btn").attr
("id", "logGitHub")
206 add
("img").attr
("id", "imgGitHub").attr
("src", "resources/icons/github-icon.png")
208 open
("div").add_class
("popover bottom")
209 add
("div").add_class
("arrow").text
(" ")
210 open
("div").add_class
("githubTitle")
211 add
("h3").text
("Github Sign In")
214 add
("label").attr
("id", "lbloginGit").text
("Username")
215 add
("input").attr
("id", "loginGit").attr
("name", "login").attr
("type", "text")
216 open
("label").attr
("id", "logginMessage").text
("Hello ")
217 open
("a").attr
("id", "githubAccount")
218 add
("strong").attr
("id", "nickName").text
(" ")
223 add
("label").attr
("id", "lbpasswordGit").text
("Password")
224 add
("input").attr
("id", "passwordGit").attr
("name", "password").attr
("type", "password")
225 open
("div").attr
("id", "listBranches")
226 add
("label").attr
("id", "lbBranches").text
("Branch")
227 add
("select").add_class
("dropdown").attr
("id", "dropBranches").attr
("name", "dropBranches").attr
("tabindex", "1").text
(" ")
231 add
("label").attr
("id", "lbrepositoryGit").text
("Repository")
232 add
("input").attr
("id", "repositoryGit").attr
("name", "repository").attr
("type", "text")
235 add
("label").attr
("id", "lbbranchGit").text
("Branch")
236 add
("input").attr
("id", "branchGit").attr
("name", "branch").attr
("type", "text")
239 add
("a").attr
("id", "signIn").text
("Sign In")
248 fun content
is abstract
251 add
("footer").text
("Nit standard library. Version jenkins-component=stdlib-19.")
254 # Generate a clickable graphviz image using a dot content
255 fun generate_dot
(dot
: String, name
: String, alt
: String) do
256 var output_dir
= dot_dir
257 if output_dir
== null then return
258 var file
= new OFStream.open
("{output_dir}/{name}.dot")
261 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 ; \}")
262 open
("article").add_class
("graph")
263 add
("img").attr
("src", "{name}.png").attr
("usemap", "#{name}").attr
("style", "margin:auto").attr
("alt", "{alt}")
265 var fmap
= new IFStream.open
("{output_dir}/{name}.map")
266 add_html
(fmap
.read_all
)
270 # Add a (source) link for a given location
271 fun show_source
(l
: Location): String
273 if source
== null then
274 return "({l.file.filename.simplify_path})"
276 # THIS IS JUST UGLY ! (but there is no replace yet)
277 var x
= source
.split_with
("%f")
278 source
= x
.join
(l
.file
.filename
.simplify_path
)
279 x
= source
.split_with
("%l")
280 source
= x
.join
(l
.line_start
.to_s
)
281 x
= source
.split_with
("%L")
282 source
= x
.join
(l
.line_end
.to_s
)
283 return " (<a href=\"{source.to_s}\
">show code</a>)"
291 private var mbuilder
: ModelBuilder
292 private var mmodules
= new Array[MModule]
294 init(mbuilder
: ModelBuilder, dot_dir
: nullable String) do
295 self.mbuilder
= mbuilder
296 self.dot_dir
= dot_dir
298 var mmodules
= new HashSet[MModule]
299 for mmodule
in mbuilder
.model
.mmodules
do
300 var owner
= mmodule
.public_owner
301 if owner
!= null then
304 mmodules
.add
(mmodule
)
308 var sorter
= new ComparableSorter[MModule]
309 self.mmodules
.add_all
(mmodules
)
310 sorter
.sort
(self.mmodules
)
315 add
("title").text
("Overview | Nit Standard Library")
319 add
("li").add_class
("current").text
("Overview")
321 add
("a").attr
("href", "full-index.html").text
("Full Index")
326 open
("div").add_class
("content fullpage")
327 add
("h1").text
("Nit Standard Library")
328 open
("article").add_class
("overview")
329 add_html
("<p>Documentation for the standard library of Nit<br />Version jenkins-component=stdlib-19<br />Date: TODAY</p>")
331 open
("article").add_class
("overview")
333 add
("h2").text
("Modules")
335 for mmodule
in mmodules
do
336 var amodule
= mbuilder
.mmodule2nmodule
[mmodule
]
338 add_html
("{mmodule.link(amodule)} {amodule.short_comment}")
348 fun process_generate_dot
do
350 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")
351 for mmodule
in mmodules
do
352 op
.append
("\"{mmodule.name}\
"[URL=\"{mmodule.name}.html\
"];\n")
353 for imported
in mmodule
.in_importation
.direct_greaters
do
354 if imported
.direct_owner
== null then
355 op
.append
("\"{mmodule.name}\
"->\"{imported.name}\
";\n")
360 generate_dot
(op
.to_s
, "dep", "Modules hierarchy")
364 # The full index page
365 class NitdocFullindex
368 private var mmodules
: Array[MModule]
370 init(mmodules
: Array[MModule]) do
371 self.mmodules
= mmodules
377 add
("title").text
("Full Index | Nit Standard Library")
382 add
("a").attr
("href", "index.html").text
("Overview")
384 add
("li").add_class
("current").text
("Full Index")
388 open
("div").add_class
("content fullpage")
389 add
("h1").text
("Full Index")
396 # Add to content modules column
398 var ls
= new List[nullable MModule]
399 var sorted
= mmodules
400 var sorterp
= new ComparableSorter[MModule]
402 open
("article").add_class
("modules filterable")
403 add
("h2").text
("Modules")
405 for mmodule
in sorted
do
406 if mmodule
.public_owner
!= null and not ls
.has
(mmodule
.public_owner
) then
407 ls
.add
(mmodule
.public_owner
)
409 add
("a").attr
("href", "{mmodule.public_owner.name}.html").text
(mmodule
.public_owner
.name
)
417 # Add to content classes modules
418 fun classes_column
do
419 var sorted
= mmodules
.first
.imported_mclasses
.to_a
420 var sorterp
= new ComparableSorter[MClass]
422 open
("article").add_class
("classes filterable")
423 add
("h2").text
("Classes")
426 for mclass
in sorted
do
428 add
("a").attr
("href", "{mclass}.html").text
(mclass
.name
)
436 # Insert the properties column of fullindex page
437 fun properties_column
do
438 open
("article").add_class
("properties filterable")
439 add
("h2").text
("Properties")
441 var sorted_imported
= mmodules
.first
.imported_methods
.to_a
442 var sorted_redef
= mmodules
.first
.redef_methods
.to_a
443 var sorterp
= new ComparableSorter[MProperty]
444 sorterp
.sort
(sorted_imported
)
445 sorterp
.sort
(sorted_redef
)
447 for method
in sorted_imported
do
448 if method
.visibility
is none_visibility
or method
.visibility
is intrude_visibility
then continue
449 open
("li").add_class
("intro")
450 add
("span").attr
("title", "introduction").text
("I")
452 add
("a").attr
("href", "{method.local_class.name}.html").attr
("title", "").text
("{method.name} ({method.local_class.name})")
456 for method
in sorted_redef
do
457 if method
.visibility
is none_visibility
or method
.visibility
is intrude_visibility
then continue
458 open
("li").add_class
("redef")
459 add
("span").attr
("title", "redefinition").text
("R")
461 add
("a").attr
("href", "{method.local_class.name}.html").attr
("title", "").text
("{method.name} ({method.local_class.name})")
475 private var mmodule
: MModule
476 private var mbuilder
: ModelBuilder
478 init(mmodule
: MModule, mbuilder
: ModelBuilder, dot_dir
: nullable String) do
479 self.mmodule
= mmodule
480 self.mbuilder
= mbuilder
481 self.dot_dir
= dot_dir
486 var amodule
= mbuilder
.mmodule2nmodule
[mmodule
]
487 add
("title").text
("{mmodule.name} module | {amodule.short_comment}")
492 add
("a").attr
("href", "index.html").text
("Overview")
494 add
("li").add_class
("current").text
(mmodule
.name
)
496 add
("a").attr
("href", "full-index.html").text
("Full Index")
502 open
("div").add_class
("content")
503 add
("h1").text
(mmodule
.name
)
504 add
("div").add_class
("subtitle")
505 add_html
("module {mmodule.namespace(mbuilder)}")
513 # Insert module comment in the content
514 fun module_comment
do
515 var amodule
= mbuilder
.mmodule2nmodule
[mmodule
]
516 var doc
= amodule
.comment
517 open
("div").attr
("id", "description")
518 add
("pre").add_class
("text_label").text
(doc
)
519 add
("textarea").add_class
("edit").attr
("rows", "1").attr
("cols", "76").attr
("id", "fileContent").text
(" ")
520 add
("a").attr
("id", "cancelBtn").text
("Cancel")
521 add
("a").attr
("id", "commitBtn").text
("Commit")
522 add
("pre").add_class
("text_label").attr
("id", "preSave").attr
("type", "2")
526 fun process_generate_dot
do
527 var name
= "dep_{mmodule.name}"
529 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")
530 for m
in mmodule
.in_importation
.poset
do
531 var public_owner
= m
.public_owner
532 if public_owner
== null then
535 op
.append
("\"{m.name}\
"[shape=box,margin=0.03];\n")
537 op
.append
("\"{m.name}\
"[URL=\"{m.name}.html\
"];\n")
540 for imported
in m
.in_importation
.direct_greaters
do
541 if imported
.public_owner
== null then
542 op
.append
("\"{public_owner.name}\
"->\"{imported.name}\
";\n")
547 generate_dot
(op
.to_s
, name
, "Dependency graph for module {mmodule.name}")
551 var amodule
= mbuilder
.mmodule2nmodule
[mmodule
]
552 open
("div").add_class
("menu")
554 add
("h3").text
("Module Hierarchy")
555 var dependencies
= new Array[MModule]
556 for dep
in mmodule
.in_importation
.greaters
do
557 if dep
== mmodule
or dep
.public_owner
!= null then continue
558 dependencies
.add
(dep
)
560 if dependencies
.length
> 0 then
561 add
("h4").text
("All dependencies")
562 display_module_list
(dependencies
)
564 var clients
= new Array[MModule]
565 for dep
in mmodule
.in_importation
.smallers
do
566 if dep
== mmodule
or dep
.public_owner
!= null then continue
569 if clients
.length
> 0 then
570 add
("h4").text
("All clients")
571 display_module_list
(clients
)
574 if mmodule
.in_nesting
.direct_greaters
.length
> 0 then
576 add
("h3").text
("Nested Modules")
577 display_module_list
(mmodule
.in_nesting
.direct_greaters
.to_a
)
583 private fun display_module_list
(list
: Array[MModule]) do
585 var sorter
= new ComparableSorter[MModule]
588 var am
= mbuilder
.mmodule2nmodule
[m
]
597 var amodule
= mbuilder
.mmodule2nmodule
[mmodule
]
598 var intro_mclasses
= mmodule
.intro_mclasses
599 var redef_mclasses
= mmodule
.redef_mclasses
600 var all_mclasses
= new HashSet[MClass]
601 for m
in mmodule
.in_nesting
.greaters
do
602 all_mclasses
.add_all
(m
.intro_mclasses
)
603 all_mclasses
.add_all
(m
.redef_mclasses
)
605 all_mclasses
.add_all
(intro_mclasses
)
606 all_mclasses
.add_all
(redef_mclasses
)
608 var sorted
= new Array[MClass]
609 sorted
.add_all
(all_mclasses
)
610 var sorter
= new ComparableSorter[MClass]
612 open
("div").add_class
("module")
613 open
("article").add_class
("classes filterable")
614 add
("h2").text
("Classes")
617 var nclass
= mbuilder
.mclassdef2nclassdef
[c
.intro
].as(AStdClassdef)
618 if redef_mclasses
.has
(c
) and c
.intro_mmodule
.public_owner
!= mmodule
then
619 open
("li").add_class
("redef")
620 add
("span").attr
("title", "refined in this module").text
("R ")
622 open
("li").add_class
("intro")
623 add
("span").attr
("title", "introduced in this module").text
("I ")
625 add_html
(c
.link
(nclass
))
634 var amodule
= mbuilder
.mmodule2nmodule
[mmodule
]
635 var mpropdefs
= new HashSet[MPropDef]
636 for m
in mmodule
.in_nesting
.greaters
do
637 for c
in m
.mclassdefs
do mpropdefs
.add_all
(c
.mpropdefs
)
639 for c
in mmodule
.mclassdefs
do mpropdefs
.add_all
(c
.mpropdefs
)
640 var sorted
= mpropdefs
.to_a
641 var sorter
= new ComparableSorter[MPropDef]
643 open
("article").add_class
("properties filterable")
644 add
("h2").text
("Properties")
647 if p
isa MAttributeDef then continue
648 if p
.mproperty
.visibility
<= none_visibility
then continue
649 if not mbuilder
.mpropdef2npropdef
.has_key
(p
) then continue
650 var nprop
= mbuilder
.mpropdef2npropdef
[p
]
652 open
("li").add_class
("intro")
653 add
("span").attr
("title", "introduction").text
("I")
655 open
("li").add_class
("redef")
656 add
("span").attr
("title", "redefinition").text
("R")
658 add_html
(" {p.link(nprop)} ({p.mclassdef.mclass.name})")
670 private var mclass
: MClass
671 private var mbuilder
: ModelBuilder
672 private var nitdoc
: Nitdoc
674 init(mclass
: MClass, nitdoc
: Nitdoc, dot_dir
: nullable String, source
: nullable String) do
676 self.mbuilder
= nitdoc
.modelbuilder
678 self.dot_dir
= dot_dir
684 var nclass
= mbuilder
.mclassdef2nclassdef
[mclass
.intro
]
685 if nclass
isa AStdClassdef then
686 add
("title").text
("{mclass.name} class | {nclass.short_comment}")
688 add
("title").text
("{mclass.name} class")
694 add
("a").attr
("href", "index.html").text
("Overview")
697 var public_owner
= mclass
.public_owner
698 if public_owner
is null then
699 var am
= mbuilder
.mmodule2nmodule
[mclass
.intro_mmodule
]
700 add_html
(mclass
.intro_mmodule
.link
(am
))
702 var am
= mbuilder
.mmodule2nmodule
[public_owner
]
703 add_html
(public_owner
.link
(am
))
706 add
("li").add_class
("current").text
(mclass
.name
)
708 add
("a").attr
("href", "full-index.html").text
("Full Index")
713 open
("div").add_class
("menu")
717 open
("div").add_class
("content")
722 fun properties_column
do
723 var sorter
= new ComparableSorter[MPropDef]
724 open
("nav").add_class
("properties filterable")
725 add
("h3").text
("Properties")
727 var vtypes
= new HashSet[MVirtualTypeDef]
728 var consts
= new HashSet[MMethodDef]
729 var meths
= new HashSet[MMethodDef]
730 for mclassdef
in mclass
.mclassdefs
do
731 for mpropdef
in mclassdef
.mpropdefs
do
732 if not mbuilder
.mpropdef2npropdef
.has_key
(mpropdef
) then continue
733 if mpropdef
.mproperty
.visibility
<= none_visibility
then continue
734 if mpropdef
isa MVirtualTypeDef then vtypes
.add
(mpropdef
)
735 if mpropdef
isa MMethodDef then
736 if mpropdef
.mproperty
.is_init
then
744 for mprop
in mclass
.inherited_methods
do
745 var mpropdef
= mprop
.intro
746 if not mbuilder
.mpropdef2npropdef
.has_key
(mpropdef
) then continue
747 if mprop
.visibility
<= none_visibility
then continue
748 if mprop
.intro_mclassdef
.mclass
.name
== "Object" then continue
752 if vtypes
.length
> 0 then
753 var vts
= new Array[MVirtualTypeDef]
756 add
("h4").text
("Virtual Types")
757 display_mpropdef_list
(vts
)
759 if consts
.length
> 0 then
760 var cts
= new Array[MMethodDef]
763 add
("h4").text
("Constructors")
764 display_mpropdef_list
(cts
)
766 if meths
.length
> 0 then
767 var mts
= new Array[MMethodDef]
770 add
("h4").text
("Methods")
771 display_mpropdef_list
(mts
)
776 private fun display_mpropdef_list
(list
: Array[MPropDef]) do
779 var nprop
= mbuilder
.mpropdef2npropdef
[prop
]
780 if prop
.is_intro
and prop
.mproperty
.intro_mclassdef
.mclass
!= mclass
then
781 open
("li").add_class
("inherit")
782 add
("span").attr
("title", "Inherited").text
("H")
783 else if prop
.is_intro
then
784 open
("li").add_class
("intro")
785 add
("span").attr
("title", "Introduced").text
("I")
787 open
("li").add_class
("redef")
788 add
("span").attr
("title", "Redefined").text
("R")
790 add_html
(prop
.link
(nprop
))
796 fun inheritance_column
do
797 var sorted
= new Array[MClass]
798 var sorterp
= new ComparableSorter[MClass]
800 add
("h3").text
("Inheritance")
801 if mclass
.ancestors
.length
> 1 then
802 sorted
= mclass
.ancestors
.to_a
804 add
("h4").text
("Superclasses")
807 if sup
== mclass
then continue
809 add
("a").attr
("href", "{sup.name}.html").text
(sup
.name
)
815 if mclass
.descendants
.length
<= 1 then
816 add
("h4").text
("No Known Subclasses")
817 else if mclass
.descendants
.length
<= 100 then
818 sorted
= mclass
.descendants
.to_a
820 add
("h4").text
("Subclasses")
823 if sub
== mclass
then continue
825 add
("a").attr
("href", "{sub.name}.html").text
(sub
.name
)
829 else if mclass
.children
.length
<= 100 then
830 sorted
= mclass
.children
.to_a
832 add
("h4").text
("Direct Subclasses Only")
835 if sub
== mclass
then continue
837 add
("a").attr
("href", "{sub.name}.html").text
(sub
.name
)
842 add
("h4").text
("Too much Subclasses to list")
849 add
("h1").text
(mclass
.to_s
)
850 open
("div").add_class
("subtitle")
852 if mclass
.visibility
is none_visibility
then subtitle
+= "private "
853 subtitle
+= "{mclass.kind} {mclass.public_owner.namespace(mbuilder)}::{mclass}"
857 var nclass
= mbuilder
.mclassdef2nclassdef
[mclass
.intro
]
858 add_html
("<div style=\"float
: right
;\
"><a id=\"lblDiffCommit\
"></a></div>")
859 open
("section").add_class
("description")
860 if nclass
isa AStdClassdef and not nclass
.comment
.is_empty
then add_html
("<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>")
864 var sorted
= new Array[MModule]
865 sorted
.add_all
(mclass
.concerns
.keys
)
866 var sorterp
= new ComparableSorter[MModule]
868 open
("section").add_class
("concerns")
869 add
("h2").add_class
("section-header").text
("Concerns")
871 for owner
in sorted
do
872 var nmodule
= mbuilder
.mmodule2nmodule
[owner
]
873 var childs
= mclass
.concerns
[owner
]
875 add_html
("<a href=\"#MOD_{owner.name}\">{owner.name}</a>: {nmodule.short_comment}")
876 if not childs
is null then
878 var sortedc
= childs
.to_a
879 var sorterpc
= new ComparableSorter[MModule]
880 sorterpc
.sort
(sortedc
)
881 for child
in sortedc
do
882 var nchild
= mbuilder
.mmodule2nmodule
[child
]
883 add_html
("<li><a href=\"#MOD_{child.name}\">{child.name}</a>: {nchild.short_comment} </li>")
892 var sorterprop
= new ComparableSorter[MProperty]
893 var sorterc
= new ComparableSorter[MClass]
894 var lmmodule
= new List[MModule]
895 # virtual and formal types
896 if mclass
.virtual_types
.length
> 0 or mclass
.arity
> 0 then
897 open
("section").add_class
("types")
898 add
("h2").text
("Formal and Virtual Types")
899 if mclass
.virtual_types
.length
> 0 then for prop
in mclass
.virtual_types
do description
(prop
)
900 #TODO this is incorrect
901 if mclass
.arity
> 0 and nclass
isa AStdClassdef then
902 for prop
in nclass
.n_formaldefs
do
903 open
("article").attr
("id", "FT_Object_{prop.collect_text}")
904 open
("h3").add_class
("signature").text
("{prop.collect_text}: nullable ")
905 add_html
("<a title=\"The root of the
class hierarchy
.\
" href=\"Object.html\
">Object</a>")
907 add_html
("<div class=\"info\
">formal generic type</div>")
914 if mclass
.constructors
.length
> 0 then
915 var sortedc
= mclass
.constructors
.to_a
916 sorterprop
.sort
(sortedc
)
917 open
("section").add_class
("constructors")
918 add
("h2").add_class
("section-header").text
("Constructors")
919 for prop
in sortedc
do description
(prop
)
923 open
("section").add_class
("methods")
924 add
("h2").add_class
("section-header").text
("Methods")
925 for mmodule
, mmethods
in mclass
.all_methods
do
926 var nmodule
= mbuilder
.mmodule2nmodule
[mmodule
]
927 add_html
("<a id=\"MOD_{mmodule.name}\
"></a>")
928 if mmodule
!= mclass
.intro_mmodule
and mmodule
!= mclass
.public_owner
then
929 if mclass
.has_mmodule
(mmodule
) then
930 add_html
("<p class=\"concern-doc\
">{mmodule.name}: {nmodule.short_comment}</p>")
932 add_html
("<h3 class=\"concern-toplevel\
">Methods refined in {mmodule.link(nmodule)}</h3><p class=\"concern-doc\
">{mmodule.name}: {nmodule.short_comment}</p>")
935 var sortedc
= mmethods
.to_a
936 sorterprop
.sort
(sortedc
)
937 for prop
in sortedc
do description
(prop
)
940 if mclass
.inherited_methods
.length
> 0 then
941 var sortedc
= new Array[MClass]
942 sortedc
.add_all
(mclass
.inherited
.keys
)
943 sorterc
.sort
(sortedc
)
944 add
("h3").text
("Inherited Methods")
945 for imclass
in sortedc
do
946 var inclass
= mbuilder
.mclassdef2nclassdef
[imclass
.intro
].as(AStdClassdef)
947 var sortedp
= mclass
.inherited
[imclass
].to_a
948 sorterprop
.sort
(sortedp
)
950 add_html
("Defined in {imclass.link(inclass)}: ")
951 for method
in sortedp
do
952 #TODO link to inherited propdef
953 add_html
("<a href=\"\
">{method.name}</a>")
954 if method
!= sortedp
.last
then add_html
(", ")
962 fun description
(prop
: MProperty) do
963 if not mbuilder
.mpropdef2npropdef
.has_key
(prop
.intro
) then return
964 var nprop
= mbuilder
.mpropdef2npropdef
[prop
.intro
]
965 if not nprop
isa AMethPropdef then return
966 var classes
= new Array[String]
967 if nprop
isa AInitPropdef then
972 if prop
.is_redef
then classes
.add
("redef")
973 if prop
.visibility
== none_visibility
then
974 classes
.add
("private")
975 else if prop
.visibility
== protected_visibility
then
976 classes
.add
("protected")
978 classes
.add
("public")
980 open
("article").add_classes
(classes
).attr
("id", "{prop.anchor}")
982 open
("h3").add_class
("signature")
983 add_html
("{prop.name}{nprop.signature}")
985 open
("div").add_class
("info")
986 add_html
("{if prop.is_redef then "redef" else ""} fun {prop.intro_mclassdef.namespace(mclass)}::{prop.name}</div><div style=\"float
: right
;\
"><a id=\"lblDiffCommit\
"></a>")
988 open
("div").add_class
("description")
989 if nprop
.comment
== "" then
990 add_html
("<a class=\"newComment\
" title=\"32\
" tag=\"\
">New Comment</a>")
992 add_html
("<pre class=\"text_label\
" title=\"\
" name=\"\
" tag=\"\
" type=\"1\
">{nprop.comment}</pre>")
994 add_html
("<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>")
996 if prop
.local_class
!= mclass
then
997 var mredef
= prop
.local_class
.intro_mmodule
998 var nredef
= mbuilder
.mmodule2nmodule
[mredef
]
999 add_html
("inherited from {mredef.link(nredef)} ")
1001 #TODO display show code if doc github
1002 var mintro
= prop
.intro_mclassdef
.mmodule
1003 var nintro
= mbuilder
.mmodule2nmodule
[mintro
]
1004 add_html
("defined by the module {mintro.link(nintro)}{if prop.apropdef is null then "" else show_source(prop.apropdef.location)}.")
1006 for parent
in mclass
.parents
do
1007 var mparent
= parent
.intro_mmodule
1008 var nparent
= mbuilder
.mmodule2nmodule
[mparent
]
1009 if prop
isa MMethod then if parent
.constructors
.has
(prop
) then add_html
(" Previously defined by: {mparent.link(nparent)} for <a href=\"{parent.name}.html\
">{parent.name}</a>.")
1017 fun process_generate_dot
do
1018 var pe
= nitdoc
.class_hierarchy
[mclass
]
1019 var cla
= new HashSet[MClass]
1020 var sm
= new HashSet[MClass]
1021 var sm2
= new HashSet[MClass]
1023 while cla
.length
+ sm
.length
< 10 and sm
.length
> 0 do
1027 sm2
.add_all
(pe
.poset
[x
].direct_smallers
)
1033 cla
.add_all
(pe
.greaters
)
1036 var name
= "dep_{mclass.name}"
1037 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")
1040 op
.append
("\"{c.name}\
"[shape=box,margin=0.03];\n")
1042 op
.append
("\"{c.name}\
"[URL=\"{c.name}.html\
"];\n")
1044 for c2
in pe
.poset
[c
].direct_greaters
do
1045 if not cla
.has
(c2
) then continue
1046 op
.append
("\"{c.name}\
"->\"{c2.name}\
";\n")
1048 if not pe
.poset
[c
].direct_smallers
.is_empty
then
1050 for c2
in pe
.poset
[c
].direct_smallers
do
1051 if cla
.has
(c2
) then others
= false
1054 op
.append
("\"{c.name}...\
"[label=\"\
"];\n")
1055 op
.append
("\"{c.name}...\
"->\"{c.name}\
"[style=dotted];\n")
1060 generate_dot
(op
.to_s
, name
, "Dependency graph for class {mclass.name}")
1065 private fun comment
: String do
1066 var ret
= new Buffer
1067 if n_moduledecl
is null or n_moduledecl
.n_doc
is null then ret
1068 if n_moduledecl
.n_doc
is null then return ""
1069 for t
in n_moduledecl
.n_doc
.n_comment
do
1070 ret
.append
(t
.text
.substring_from
(1))
1075 private fun short_comment
: String do
1076 var ret
= new Buffer
1077 if n_moduledecl
!= null and n_moduledecl
.n_doc
!= null then
1078 ret
.append
(n_moduledecl
.n_doc
.n_comment
.first
.text
.substring_from
(2).replace
("\n", ""))
1086 redef type OTHER: MModule
1087 redef fun <(other
: OTHER): Bool do return self.name
< other
.name
1089 # Get the list of all methods in a module
1090 fun imported_methods
: Set[MMethod] do
1091 var methods
= new HashSet[MMethod]
1092 for mclass
in imported_mclasses
do
1093 for method
in mclass
.intro_methods
do
1100 # Get the list aof all refined methods in a module
1101 fun redef_methods
: Set[MMethod] do
1102 var methods
= new HashSet[MMethod]
1103 for mclass
in redef_mclasses
do
1104 for method
in mclass
.intro_methods
do
1111 # Return a link (html a tag) to the nitdoc module page
1112 fun link
(amodule
: AModule): String do
1113 return "<a href=\"{name}.html\
" title=\"{amodule.short_comment}\
">{name}</a>"
1116 # Return the module namespace decorated with html
1117 fun namespace
(mbuilder
: ModelBuilder): String do
1118 var str
= new Buffer
1119 var mowner
= public_owner
1120 if mowner
!= null then
1121 var nowner
= mbuilder
.mmodule2nmodule
[mowner
]
1122 str
.append
(public_owner
.link
(nowner
))
1125 var nmodule
= mbuilder
.mmodule2nmodule
[self]
1126 str
.append
(self.link
(nmodule
))
1130 redef class MPropDef
1132 redef type OTHER: MPropDef
1133 redef fun <(other
: OTHER): Bool do return self.mproperty
.name
< other
.mproperty
.name
1135 # Return a link (html a tag) to the nitdoc class page
1136 fun link
(nprop
: APropdef): String do
1137 return "<a href=\"{mclassdef.mclass.name}.html
#{mproperty.anchor}\" title=\"{nprop.short_comment}\">{mproperty}</a>"
1141 redef class MProperty
1143 redef type OTHER: MProperty
1144 redef fun <(other
: OTHER): Bool do return self.name
< other
.name
1147 var apropdef
: nullable APropdef
1149 redef init(intro_mclassdef
: MClassDef, name
: String, visibility
: MVisibility)
1155 fun local_class
: MClass do
1156 var classdef
= self.intro_mclassdef
1157 return classdef
.mclass
1160 fun anchor
: String do
1161 return "PROP_{c_name}"
1168 redef type OTHER: MClass
1169 redef fun <(other
: OTHER): Bool do return self.name
< other
.name
1171 # Add type parameters
1174 return "{name}[{intro.parameter_names.join(", ")}]"
1180 # Return a link (html a tag) to the nitdoc class page
1181 fun link
(aclass
: AStdClassdef): String do
1182 return "<a href=\"{name}.html\
" title=\"{aclass.short_comment}\
">{self}</a>"
1185 # Associate all MMethods to each MModule concerns
1186 fun all_methods
: HashMap[MModule, Set[MMethod]] do
1187 var hm
= new HashMap[MModule, Set[MMethod]]
1188 for mmodule
, childs
in concerns
do
1189 if not hm
.has_key
(mmodule
) then hm
[mmodule
] = new HashSet[MMethod]
1190 for prop
in intro_methods
do
1191 if mmodule
== prop
.intro_mclassdef
.mmodule
then
1192 prop
.is_redef
= false
1193 hm
[mmodule
].add
(prop
)
1196 for prop
in redef_methods
do
1197 if mmodule
== prop
.intro_mclassdef
.mmodule
then
1198 prop
.is_redef
= true
1199 hm
[mmodule
].add
(prop
)
1203 if childs
!= null then
1204 for child
in childs
do
1205 if not hm
.has_key
(child
) then hm
[child
] = new HashSet[MMethod]
1206 for prop
in intro_methods
do
1207 if child
== prop
.intro_mclassdef
.mmodule
then
1208 prop
.is_redef
= false
1212 for prop
in redef_methods
do
1213 if child
== prop
.intro_mclassdef
.mmodule
then
1214 prop
.is_redef
= true
1224 fun public_owner
: MModule do
1225 var owner
= intro_mmodule
1226 if owner
.public_owner
is null then
1229 return owner
.public_owner
.as(not null)
1233 # Associate MClass to all MMethod include in 'inherited_methods'
1234 fun inherited
: HashMap[MClass, Set[MMethod]] do
1235 var hm
= new HashMap[MClass, Set[MMethod]]
1236 for method
in inherited_methods
do
1237 var mclass
= method
.intro_mclassdef
.mclass
1238 if not hm
.has_key
(mclass
) then hm
[mclass
] = new HashSet[MMethod]
1239 hm
[mclass
].add
(method
)
1244 # Return true if MModule concern contain subMModule
1245 fun has_mmodule
(sub
: MModule): Bool do
1246 for mmodule
, childs
in concerns
do
1247 if childs
is null then continue
1248 if childs
.has
(sub
) then return true
1253 fun mmethod
(mprop2npropdef
: Map[MProperty, APropdef]) do
1254 for const
in constructors
do
1255 if mprop2npropdef
.has_key
(const
)then
1256 const
.apropdef
= mprop2npropdef
[const
].as(AMethPropdef)
1260 for intro
in intro_methods
do
1261 if mprop2npropdef
.has_key
(intro
)then
1262 if mprop2npropdef
[intro
] isa AMethPropdef then intro
.apropdef
= mprop2npropdef
[intro
].as(AMethPropdef)
1266 for rd
in redef_methods
do
1267 if mprop2npropdef
.has_key
(rd
)then
1268 if mprop2npropdef
[rd
] isa AMethPropdef then rd
.apropdef
= mprop2npropdef
[rd
].as(AMethPropdef)
1273 fun link_anchor
: String do
1274 return "{name}.html"
1279 redef class AStdClassdef
1280 private fun comment
: String do
1281 var ret
= new Buffer
1282 if n_doc
!= null then
1283 for t
in n_doc
.n_comment
do ret
.append
(t
.text
.substring_from
(1))
1288 private fun short_comment
: String do
1289 var ret
= new Buffer
1290 if n_doc
!= null then ret
.append
(n_doc
.n_comment
.first
.text
.substring_from
(2).replace
("\n", ""))
1295 redef class ASignature
1299 if not n_params
.is_empty
then
1300 ret
= "{ret}({n_params.join(", ")})"
1302 if n_type
!= null and n_type
.to_s
!= "" then ret
+= ": {n_type.to_s}"
1309 var ret
= "{n_id.text}"
1310 if n_type
!= null then
1311 ret
= "{ret}: {n_type.to_s}"
1312 if n_dotdotdot
!= null then ret
= "{ret}..."
1320 var ret
= "<a href=\"{n_id.text}.html\
">{n_id.text}</a>"
1321 if n_kwnullable
!= null then ret
= "nullable {ret}"
1322 if not n_types
.is_empty
then ret
= "{ret}[{n_types.join(", ")}]"
1327 redef class APropdef
1328 private fun short_comment
: String is abstract
1329 private fun signature
: String is abstract
1330 private fun comment
: String is abstract
1333 redef class AAttrPropdef
1334 redef fun short_comment
do
1335 var ret
= new Buffer
1336 if n_doc
!= null then ret
.append
(n_doc
.n_comment
.first
.text
.substring_from
(1))
1341 redef class AMethPropdef
1342 redef fun short_comment
do
1343 var ret
= new Buffer
1344 if n_doc
!= null then ret
.append
(n_doc
.n_comment
.first
.text
.substring_from
(2).replace
("\n", ""))
1348 redef fun signature
: String do
1350 if n_signature
!= null then sign
= "{n_signature.to_s}"
1354 redef private fun comment
: String do
1355 var ret
= new Buffer
1356 if n_doc
!= null then
1357 for t
in n_doc
.n_comment
do ret
.append
(t
.text
.substring_from
(1))
1363 redef class MClassDef
1364 private fun namespace
(mclass
: MClass): String do
1366 if mmodule
.public_owner
is null then
1367 return "{mmodule.full_name}::{mclass.name}"
1368 else if mclass
is self.mclass
then
1369 return "{mmodule.public_owner.name}::{mclass.name}"
1371 return "{mmodule.public_owner.name}::<a href=\"{mclass.name}.html\
">{mclass.name}</a>"
1378 return to_a
[length-1
]
1382 # Create a tool context to handle options and paths
1383 var toolcontext
= new ToolContext
1385 # Here we launch the nit index
1386 var nitdoc
= new Nitdoc(toolcontext
)