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")
848 var nclass
= mbuilder
.mclassdef2nclassdef
[mclass
.intro
]
849 var sorted
= new Array[MModule]
850 sorted
.add_all
(mclass
.concerns
.keys
)
851 var sorterp
= new ComparableSorter[MModule]
852 var sorterprop
= new ComparableSorter[MProperty]
853 var sorterc
= new ComparableSorter[MClass]
856 var lmmodule
= new List[MModule]
857 # Insert the subtitle part
858 add
("h1").text
(mclass
.to_s
)
859 open
("div").add_class
("subtitle")
860 if mclass
.visibility
is none_visibility
then subtitle
+= "private "
861 subtitle
+= "{mclass.kind} {mclass.public_owner.namespace(mbuilder)}::{mclass}"
864 add_html
("<div style=\"float
: right
;\
"><a id=\"lblDiffCommit\
"></a></div>")
865 # We add the class description
866 open
("section").add_class
("description")
867 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>")
870 open
("section").add_class
("concerns")
871 add
("h2").add_class
("section-header").text
("Concerns")
873 for owner
in sorted
do
874 var nmodule
= mbuilder
.mmodule2nmodule
[owner
]
875 var childs
= mclass
.concerns
[owner
]
877 add_html
("<a href=\"#MOD_{owner.name}\">{owner.name}</a>: {nmodule.short_comment}")
878 if not childs
is null then
880 var sortedc
= childs
.to_a
881 var sorterpc
= new ComparableSorter[MModule]
882 sorterpc
.sort
(sortedc
)
883 for child
in sortedc
do
884 var nchild
= mbuilder
.mmodule2nmodule
[child
]
885 add_html
("<li><a href=\"#MOD_{child.name}\">{child.name}</a>: {nchild.short_comment} </li>")
893 # Insert virtual types if there is almost one
894 if mclass
.virtual_types
.length
> 0 or mclass
.arity
> 0 then
895 open
("section").add_class
("types")
896 add
("h2").text
("Formal and Virtual Types")
897 if mclass
.virtual_types
.length
> 0 then for prop
in mclass
.virtual_types
do description
(prop
)
898 if mclass
.arity
> 0 and nclass
isa AStdClassdef then
899 for prop
in nclass
.n_formaldefs
do
900 open
("article").attr
("id", "FT_Object_{prop.collect_text}")
901 open
("h3").add_class
("signature").text
("{prop.collect_text}: nullable ")
902 add_html
("<a title=\"The root of the
class hierarchy
.\
" href=\"Object.html\
">Object</a>")
904 add_html
("<div class=\"info\
">formal generic type</div>")
911 if mclass
.constructors
.length
> 0 then
912 var sortedc
= mclass
.constructors
.to_a
913 sorterprop
.sort
(sortedc
)
914 open
("section").add_class
("constructors")
915 add
("h2").add_class
("section-header").text
("Constructors")
916 for prop
in sortedc
do description
(prop
)
920 open
("section").add_class
("methods")
921 add
("h2").add_class
("section-header").text
("Methods")
922 for mmodule
, mmethods
in mclass
.all_methods
do
923 var nmodule
= mbuilder
.mmodule2nmodule
[mmodule
]
924 add_html
("<a id=\"MOD_{mmodule.name}\
"></a>")
925 if mmodule
!= mclass
.intro_mmodule
and mmodule
!= mclass
.public_owner
then
926 if mclass
.has_mmodule
(mmodule
) then
927 add_html
("<p class=\"concern-doc\
">{mmodule.name}: {nmodule.short_comment}</p>")
929 add_html
("<h3 class=\"concern-toplevel\
">Methods refined in {mmodule.link(nmodule)}</h3><p class=\"concern-doc\
">{mmodule.name}: {nmodule.short_comment}</p>")
932 var sortedc
= mmethods
.to_a
933 sorterprop
.sort
(sortedc
)
934 for prop
in sortedc
do description
(prop
)
937 if mclass
.inherited_methods
.length
> 0 then
938 var sortedc
= new Array[MClass]
939 sortedc
.add_all
(mclass
.inherited
.keys
)
940 sorterc
.sort
(sortedc
)
941 add
("h3").text
("Inherited Methods")
942 for imclass
in sortedc
do
943 var inclass
= mbuilder
.mclassdef2nclassdef
[imclass
.intro
].as(AStdClassdef)
944 var sortedp
= mclass
.inherited
[imclass
].to_a
945 sorterprop
.sort
(sortedp
)
947 add_html
("Defined in {imclass.link(inclass)}: ")
948 for method
in sortedp
do
949 #TODO link to inherited propdef
950 add_html
("<a href=\"\
">{method.name}</a>")
951 if method
!= sortedp
.last
then add_html
(", ")
959 fun description
(prop
: MProperty) do
960 if not mbuilder
.mpropdef2npropdef
.has_key
(prop
.intro
) then return
961 var nprop
= mbuilder
.mpropdef2npropdef
[prop
.intro
]
962 if not nprop
isa AMethPropdef then return
963 var classes
= new Array[String]
964 if nprop
isa AInitPropdef then
969 if prop
.is_redef
then classes
.add
("redef")
970 if prop
.visibility
== none_visibility
then
971 classes
.add
("private")
972 else if prop
.visibility
== protected_visibility
then
973 classes
.add
("protected")
975 classes
.add
("public")
977 open
("article").add_classes
(classes
).attr
("id", "{prop.anchor}")
979 open
("h3").add_class
("signature")
980 add_html
("{prop.name}{nprop.signature}")
982 open
("div").add_class
("info")
983 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>")
985 open
("div").add_class
("description")
986 if nprop
.comment
== "" then
987 add_html
("<a class=\"newComment\
" title=\"32\
" tag=\"\
">New Comment</a>")
989 add_html
("<pre class=\"text_label\
" title=\"\
" name=\"\
" tag=\"\
" type=\"1\
">{nprop.comment}</pre>")
991 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>")
993 if prop
.local_class
!= mclass
then
994 var mredef
= prop
.local_class
.intro_mmodule
995 var nredef
= mbuilder
.mmodule2nmodule
[mredef
]
996 add_html
("inherited from {mredef.link(nredef)} ")
998 #TODO display show code if doc github
999 var mintro
= prop
.intro_mclassdef
.mmodule
1000 var nintro
= mbuilder
.mmodule2nmodule
[mintro
]
1001 add_html
("defined by the module {mintro.link(nintro)}{if prop.apropdef is null then "" else show_source(prop.apropdef.location)}.")
1003 for parent
in mclass
.parents
do
1004 var mparent
= parent
.intro_mmodule
1005 var nparent
= mbuilder
.mmodule2nmodule
[mparent
]
1006 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>.")
1014 fun process_generate_dot
do
1015 var pe
= nitdoc
.class_hierarchy
[mclass
]
1016 var cla
= new HashSet[MClass]
1017 var sm
= new HashSet[MClass]
1018 var sm2
= new HashSet[MClass]
1020 while cla
.length
+ sm
.length
< 10 and sm
.length
> 0 do
1024 sm2
.add_all
(pe
.poset
[x
].direct_smallers
)
1030 cla
.add_all
(pe
.greaters
)
1033 var name
= "dep_{mclass.name}"
1034 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")
1037 op
.append
("\"{c.name}\
"[shape=box,margin=0.03];\n")
1039 op
.append
("\"{c.name}\
"[URL=\"{c.name}.html\
"];\n")
1041 for c2
in pe
.poset
[c
].direct_greaters
do
1042 if not cla
.has
(c2
) then continue
1043 op
.append
("\"{c.name}\
"->\"{c2.name}\
";\n")
1045 if not pe
.poset
[c
].direct_smallers
.is_empty
then
1047 for c2
in pe
.poset
[c
].direct_smallers
do
1048 if cla
.has
(c2
) then others
= false
1051 op
.append
("\"{c.name}...\
"[label=\"\
"];\n")
1052 op
.append
("\"{c.name}...\
"->\"{c.name}\
"[style=dotted];\n")
1057 generate_dot
(op
.to_s
, name
, "Dependency graph for class {mclass.name}")
1062 private fun comment
: String do
1063 var ret
= new Buffer
1064 if n_moduledecl
is null or n_moduledecl
.n_doc
is null then ret
1065 if n_moduledecl
.n_doc
is null then return ""
1066 for t
in n_moduledecl
.n_doc
.n_comment
do
1067 ret
.append
(t
.text
.substring_from
(1))
1072 private fun short_comment
: String do
1073 var ret
= new Buffer
1074 if n_moduledecl
!= null and n_moduledecl
.n_doc
!= null then
1075 ret
.append
(n_moduledecl
.n_doc
.n_comment
.first
.text
.substring_from
(2).replace
("\n", ""))
1083 redef type OTHER: MModule
1084 redef fun <(other
: OTHER): Bool do return self.name
< other
.name
1086 # Get the list of all methods in a module
1087 fun imported_methods
: Set[MMethod] do
1088 var methods
= new HashSet[MMethod]
1089 for mclass
in imported_mclasses
do
1090 for method
in mclass
.intro_methods
do
1097 # Get the list aof all refined methods in a module
1098 fun redef_methods
: Set[MMethod] do
1099 var methods
= new HashSet[MMethod]
1100 for mclass
in redef_mclasses
do
1101 for method
in mclass
.intro_methods
do
1108 # Return a link (html a tag) to the nitdoc module page
1109 fun link
(amodule
: AModule): String do
1110 return "<a href=\"{name}.html\
" title=\"{amodule.short_comment}\
">{name}</a>"
1113 # Return the module namespace decorated with html
1114 fun namespace
(mbuilder
: ModelBuilder): String do
1115 var str
= new Buffer
1116 var mowner
= public_owner
1117 if mowner
!= null then
1118 var nowner
= mbuilder
.mmodule2nmodule
[mowner
]
1119 str
.append
(public_owner
.link
(nowner
))
1122 var nmodule
= mbuilder
.mmodule2nmodule
[self]
1123 str
.append
(self.link
(nmodule
))
1127 redef class MPropDef
1129 redef type OTHER: MPropDef
1130 redef fun <(other
: OTHER): Bool do return self.mproperty
.name
< other
.mproperty
.name
1132 # Return a link (html a tag) to the nitdoc class page
1133 fun link
(nprop
: APropdef): String do
1134 return "<a href=\"{mclassdef.mclass.name}.html
#{mproperty.anchor}\" title=\"{nprop.short_comment}\">{mproperty}</a>"
1138 redef class MProperty
1140 redef type OTHER: MProperty
1141 redef fun <(other
: OTHER): Bool do return self.name
< other
.name
1144 var apropdef
: nullable APropdef
1146 redef init(intro_mclassdef
: MClassDef, name
: String, visibility
: MVisibility)
1152 fun local_class
: MClass do
1153 var classdef
= self.intro_mclassdef
1154 return classdef
.mclass
1157 fun anchor
: String do
1158 return "PROP_{c_name}"
1165 redef type OTHER: MClass
1166 redef fun <(other
: OTHER): Bool do return self.name
< other
.name
1168 # Add type parameters
1171 return "{name}[{intro.parameter_names.join(", ")}]"
1177 # Return a link (html a tag) to the nitdoc class page
1178 fun link
(aclass
: AStdClassdef): String do
1179 return "<a href=\"{name}.html\
" title=\"{aclass.short_comment}\
">{self}</a>"
1182 # Associate all MMethods to each MModule concerns
1183 fun all_methods
: HashMap[MModule, Set[MMethod]] do
1184 var hm
= new HashMap[MModule, Set[MMethod]]
1185 for mmodule
, childs
in concerns
do
1186 if not hm
.has_key
(mmodule
) then hm
[mmodule
] = new HashSet[MMethod]
1187 for prop
in intro_methods
do
1188 if mmodule
== prop
.intro_mclassdef
.mmodule
then
1189 prop
.is_redef
= false
1190 hm
[mmodule
].add
(prop
)
1193 for prop
in redef_methods
do
1194 if mmodule
== prop
.intro_mclassdef
.mmodule
then
1195 prop
.is_redef
= true
1196 hm
[mmodule
].add
(prop
)
1200 if childs
!= null then
1201 for child
in childs
do
1202 if not hm
.has_key
(child
) then hm
[child
] = new HashSet[MMethod]
1203 for prop
in intro_methods
do
1204 if child
== prop
.intro_mclassdef
.mmodule
then
1205 prop
.is_redef
= false
1209 for prop
in redef_methods
do
1210 if child
== prop
.intro_mclassdef
.mmodule
then
1211 prop
.is_redef
= true
1221 fun public_owner
: MModule do
1222 var owner
= intro_mmodule
1223 if owner
.public_owner
is null then
1226 return owner
.public_owner
.as(not null)
1230 # Associate MClass to all MMethod include in 'inherited_methods'
1231 fun inherited
: HashMap[MClass, Set[MMethod]] do
1232 var hm
= new HashMap[MClass, Set[MMethod]]
1233 for method
in inherited_methods
do
1234 var mclass
= method
.intro_mclassdef
.mclass
1235 if not hm
.has_key
(mclass
) then hm
[mclass
] = new HashSet[MMethod]
1236 hm
[mclass
].add
(method
)
1241 # Return true if MModule concern contain subMModule
1242 fun has_mmodule
(sub
: MModule): Bool do
1243 for mmodule
, childs
in concerns
do
1244 if childs
is null then continue
1245 if childs
.has
(sub
) then return true
1250 fun mmethod
(mprop2npropdef
: Map[MProperty, APropdef]) do
1251 for const
in constructors
do
1252 if mprop2npropdef
.has_key
(const
)then
1253 const
.apropdef
= mprop2npropdef
[const
].as(AMethPropdef)
1257 for intro
in intro_methods
do
1258 if mprop2npropdef
.has_key
(intro
)then
1259 if mprop2npropdef
[intro
] isa AMethPropdef then intro
.apropdef
= mprop2npropdef
[intro
].as(AMethPropdef)
1263 for rd
in redef_methods
do
1264 if mprop2npropdef
.has_key
(rd
)then
1265 if mprop2npropdef
[rd
] isa AMethPropdef then rd
.apropdef
= mprop2npropdef
[rd
].as(AMethPropdef)
1270 fun link_anchor
: String do
1271 return "{name}.html"
1276 redef class AStdClassdef
1277 private fun comment
: String do
1278 var ret
= new Buffer
1279 if n_doc
!= null then
1280 for t
in n_doc
.n_comment
do ret
.append
(t
.text
.substring_from
(1))
1285 private fun short_comment
: String do
1286 var ret
= new Buffer
1287 if n_doc
!= null then ret
.append
(n_doc
.n_comment
.first
.text
.substring_from
(2).replace
("\n", ""))
1292 redef class ASignature
1296 if not n_params
.is_empty
then
1297 ret
= "{ret}({n_params.join(", ")})"
1299 if n_type
!= null and n_type
.to_s
!= "" then ret
+= ": {n_type.to_s}"
1306 var ret
= "{n_id.text}"
1307 if n_type
!= null then
1308 ret
= "{ret}: {n_type.to_s}"
1309 if n_dotdotdot
!= null then ret
= "{ret}..."
1317 var ret
= "<a href=\"{n_id.text}.html\
">{n_id.text}</a>"
1318 if n_kwnullable
!= null then ret
= "nullable {ret}"
1319 if not n_types
.is_empty
then ret
= "{ret}[{n_types.join(", ")}]"
1324 redef class APropdef
1325 private fun short_comment
: String is abstract
1326 private fun signature
: String is abstract
1327 private fun comment
: String is abstract
1330 redef class AAttrPropdef
1331 redef fun short_comment
do
1332 var ret
= new Buffer
1333 if n_doc
!= null then ret
.append
(n_doc
.n_comment
.first
.text
.substring_from
(1))
1338 redef class AMethPropdef
1339 redef fun short_comment
do
1340 var ret
= new Buffer
1341 if n_doc
!= null then ret
.append
(n_doc
.n_comment
.first
.text
.substring_from
(2).replace
("\n", ""))
1345 redef fun signature
: String do
1347 if n_signature
!= null then sign
= "{n_signature.to_s}"
1351 redef private fun comment
: String do
1352 var ret
= new Buffer
1353 if n_doc
!= null then
1354 for t
in n_doc
.n_comment
do ret
.append
(t
.text
.substring_from
(1))
1360 redef class MClassDef
1361 private fun namespace
(mclass
: MClass): String do
1363 if mmodule
.public_owner
is null then
1364 return "{mmodule.full_name}::{mclass.name}"
1365 else if mclass
is self.mclass
then
1366 return "{mmodule.public_owner.name}::{mclass.name}"
1368 return "{mmodule.public_owner.name}::<a href=\"{mclass.name}.html\
">{mclass.name}</a>"
1375 return to_a
[length-1
]
1379 # Create a tool context to handle options and paths
1380 var toolcontext
= new ToolContext
1382 # Here we launch the nit index
1383 var nitdoc
= new Nitdoc(toolcontext
)