1 # This file is part of NIT ( http://www.nitlanguage.org ).
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
7 # http://www.apache.org/licenses/LICENSE-2.0
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
15 # Nitdoc page generation
20 private import json
::static
22 redef class ToolContext
23 private var opt_dir
= new OptionString("output directory", "-d", "--dir")
24 private var opt_source
= new OptionString("link for source (%f for filename, %l for first line, %L for last line)", "--source")
25 private var opt_sharedir
= new OptionString("directory containing nitdoc assets", "--sharedir")
26 private var opt_shareurl
= new OptionString("use shareurl instead of copy shared files", "--shareurl")
27 private var opt_nodot
= new OptionBool("do not generate graphes with graphviz", "--no-dot")
28 private var opt_private
= new OptionBool("also generate private API", "--private")
30 private var opt_custom_title
= new OptionString("custom title for homepage", "--custom-title")
31 private var opt_custom_brand
= new OptionString("custom link to external site", "--custom-brand")
32 private var opt_custom_intro
= new OptionString("custom intro text for homepage", "--custom-overview-text")
33 private var opt_custom_footer
= new OptionString("custom footer text", "--custom-footer-text")
35 private var opt_github_upstream
= new OptionString("Git branch where edited commits will be pulled into (ex: user:repo:branch)", "--github-upstream")
36 private var opt_github_base_sha1
= new OptionString("Git sha1 of base commit used to create pull request", "--github-base-sha1")
37 private var opt_github_gitdir
= new OptionString("Git working directory used to resolve path name (ex: /home/me/myproject/)", "--github-gitdir")
39 private var opt_piwik_tracker
= new OptionString("Piwik tracker URL (ex: nitlanguage.org/piwik/)", "--piwik-tracker")
40 private var opt_piwik_site_id
= new OptionString("Piwik site ID", "--piwik-site-id")
42 private var output_dir
: String
43 private var min_visibility
: MVisibility
48 var opts
= option_context
49 opts
.add_option
(opt_dir
, opt_source
, opt_sharedir
, opt_shareurl
, opt_nodot
, opt_private
)
50 opts
.add_option
(opt_custom_title
, opt_custom_footer
, opt_custom_intro
, opt_custom_brand
)
51 opts
.add_option
(opt_github_upstream
, opt_github_base_sha1
, opt_github_gitdir
)
52 opts
.add_option
(opt_piwik_tracker
, opt_piwik_site_id
)
54 var tpl
= new Template
55 tpl
.add
"Usage: nitdoc [OPTION]... <file.nit>...\n"
56 tpl
.add
"Generates HTML pages of API documentation from Nit source files."
57 tooldescription
= tpl
.write_to_string
60 redef fun process_options
(args
) do
64 var output_dir
= opt_dir
.value
65 if output_dir
== null then
68 self.output_dir
= output_dir
70 if opt_private
.value
then
71 min_visibility
= none_visibility
73 min_visibility
= protected_visibility
76 var gh_upstream
= opt_github_upstream
.value
77 var gh_base_sha
= opt_github_base_sha1
.value
78 var gh_gitdir
= opt_github_gitdir
.value
79 if not gh_upstream
== null or not gh_base_sha
== null or not gh_gitdir
== null then
80 if gh_upstream
== null or gh_base_sha
== null or gh_gitdir
== null then
81 print
"Error: Options {opt_github_upstream.names.first}, {opt_github_base_sha1.names.first} and {opt_github_gitdir.names.first} are required to enable the GitHub plugin"
88 # The Nitdoc class explores the model and generate pages for each mentities found
92 var mainmodule
: MModule
105 private fun init_output_dir
do
106 # create destination dir if it's necessary
107 var output_dir
= ctx
.output_dir
108 if not output_dir
.file_exists
then output_dir
.mkdir
110 var sharedir
= ctx
.opt_sharedir
.value
111 if sharedir
== null then
112 var dir
= ctx
.nit_dir
113 sharedir
= dir
/"share/nitdoc"
114 if not sharedir
.file_exists
then
115 print
"Error: Cannot locate nitdoc share files. Uses --sharedir or envvar NIT_DIR"
120 if ctx
.opt_shareurl
.value
== null then
121 sys
.system
("cp -r -- {sharedir.to_s.escape_to_sh}/* {output_dir.to_s.escape_to_sh}/")
123 sys
.system
("cp -r -- {sharedir.to_s.escape_to_sh}/resources/ {output_dir.to_s.escape_to_sh}/resources/")
128 private fun overview
do
129 var page
= new NitdocOverview(ctx
, model
, mainmodule
)
130 page
.render
.write_to_file
("{ctx.output_dir.to_s}/{page.page_url}")
133 private fun search
do
134 var page
= new NitdocSearch(ctx
, model
, mainmodule
)
135 page
.render
.write_to_file
("{ctx.output_dir.to_s}/{page.page_url}")
138 private fun groups
do
139 for mproject
in model
.mprojects
do
140 for mgroup
in mproject
.mgroups
.to_a
do
141 var page
= new NitdocGroup(ctx
, model
, mainmodule
, mgroup
)
142 page
.render
.write_to_file
("{ctx.output_dir.to_s}/{page.page_url}")
147 private fun modules
do
148 for mmodule
in model
.mmodules
do
149 if mmodule
.is_fictive
then continue
150 var page
= new NitdocModule(ctx
, model
, mainmodule
, mmodule
)
151 page
.render
.write_to_file
("{ctx.output_dir.to_s}/{page.page_url}")
155 private fun classes
do
156 for mclass
in model
.mclasses
do
157 if mclass
.visibility
<= ctx
.min_visibility
then continue
158 var page
= new NitdocClass(ctx
, model
, mainmodule
, mclass
)
159 page
.render
.write_to_file
("{ctx.output_dir.to_s}/{page.page_url}")
163 private fun properties
do
164 for mproperty
in model
.mproperties
do
165 if mproperty
.visibility
<= ctx
.min_visibility
then continue
166 if mproperty
isa MInnerClass then continue
167 if mproperty
isa MAttribute then continue
168 var page
= new NitdocProperty(ctx
, model
, mainmodule
, mproperty
)
169 page
.render
.write_to_file
("{ctx.output_dir.to_s}/{page.page_url}")
173 private fun quicksearch_list
do
174 var quicksearch
= new QuickSearch(ctx
, model
)
175 quicksearch
.render
.write_to_file
("{ctx.output_dir.to_s}/quicksearch-list.js")
179 # Nitdoc QuickSearch list generator
181 # Create a JSON object containing links to:
185 # All entities are grouped by name to make the research easier.
188 private var table
= new QuickSearchTable
194 for mmodule
in model
.mmodules
do
195 if mmodule
.is_fictive
then continue
196 add_result_for
(mmodule
.name
, mmodule
.full_name
, mmodule
.nitdoc_url
)
198 for mclass
in model
.mclasses
do
199 if mclass
.visibility
< ctx
.min_visibility
then continue
200 add_result_for
(mclass
.name
, mclass
.full_name
, mclass
.nitdoc_url
)
202 for mproperty
in model
.mproperties
do
203 if mproperty
.visibility
< ctx
.min_visibility
then continue
204 if mproperty
isa MAttribute then continue
205 for mpropdef
in mproperty
.mpropdefs
do
206 var full_name
= mpropdef
.mclassdef
.mclass
.full_name
207 var cls_url
= mpropdef
.mclassdef
.mclass
.nitdoc_url
208 var def_url
= "{cls_url}#{mpropdef.mproperty.nitdoc_id}"
209 add_result_for
(mproperty
.name
, full_name
, def_url
)
214 private fun add_result_for
(query
: String, txt
: String, url
: String) do
215 table
[query
].add
new QuickSearchResult(txt
, url
)
218 fun render
: Template do
219 var tpl
= new Template
220 var buffer
= new RopeBuffer
222 buffer
.append
"var nitdocQuickSearchRawList="
223 table
.append_json buffer
229 # The result map for QuickSearch.
230 private class QuickSearchTable
231 super JsonMapRead[String, QuickSearchResultList]
232 super HashMap[String, QuickSearchResultList]
234 redef fun provide_default_value
(key
) do
235 var v
= new QuickSearchResultList
241 # A QuickSearch result list.
242 private class QuickSearchResultList
243 super JsonSequenceRead[QuickSearchResult]
244 super Array[QuickSearchResult]
247 # A QuickSearch result.
248 private class QuickSearchResult
251 # The text of the link.
254 # The destination of the link.
258 return "\{\"txt\":{txt.to_json},\"url\
":{url.to_json}\}"
263 # Define page structure and properties
264 abstract class NitdocPage
266 private var ctx
: ToolContext
267 private var model
: Model
268 private var mainmodule
: MModule
269 private var name_sorter
= new MEntityNameSorter
271 # Render the page as a html template
272 fun render
: Template do
274 if ctx
.opt_shareurl
.value
!= null then
275 shareurl
= ctx
.opt_shareurl
.value
.as(not null)
280 tpl
.title
= tpl_title
282 tpl
.shareurl
= shareurl
283 tpl
.topmenu
= tpl_topmenu
285 tpl
.footer
= ctx
.opt_custom_footer
.value
286 tpl
.body_attrs
.add
(new TagAttribute("data-bootstrap-share", shareurl
))
287 tpl
.sidebar
= tpl_sidebar
290 var tracker_url
= ctx
.opt_piwik_tracker
.value
291 var site_id
= ctx
.opt_piwik_site_id
.value
292 if tracker_url
!= null and site_id
!= null then
293 tpl
.scripts
.add
new TplPiwikScript(tracker_url
, site_id
)
299 fun page_url
: String is abstract
301 # Build page template
302 fun tpl_page
: TplPage is abstract
304 # Build page sidebar if any
305 fun tpl_sidebar
: nullable TplSidebar do return null
307 # Build page title string
308 fun tpl_title
: String do
309 if ctx
.opt_custom_title
.value
!= null then
310 return ctx
.opt_custom_title
.value
.to_s
315 # Build top menu template
316 fun tpl_topmenu
: TplTopMenu do
317 var topmenu
= new TplTopMenu(page_url
)
318 var brand
= ctx
.opt_custom_brand
.value
319 if brand
!= null then
320 var tpl
= new Template
321 tpl
.add
"<span class='navbar-brand'>"
326 topmenu
.add_link
new TplLink("index.html", "Overview")
327 topmenu
.add_link
new TplLink("search.html", "Index")
331 # Build page content template
332 fun tpl_content
is abstract
334 # Clickable graphviz image using dot format
335 # return null if no graph for this page
336 fun tpl_graph
(dot
: Buffer, name
: String, title
: nullable String): nullable TplArticle do
337 if ctx
.opt_nodot
.value
then return null
338 var output_dir
= ctx
.output_dir
339 var path
= output_dir
/ name
340 var path_sh
= path
.escape_to_sh
341 var file
= new OFStream.open
("{path}.dot")
344 sys
.system
("\{ test -f {path_sh}.png && test -f {path_sh}.s.dot && diff -- {path_sh}.dot {path_sh}.s.dot >/dev/null 2>&1 ; \} || \{ cp -- {path_sh}.dot {path_sh}.s.dot && dot -Tpng -o{path_sh}.png -Tcmapx -o{path_sh}.map {path_sh}.s.dot ; \}")
345 var fmap
= new IFStream.open
("{path}.map")
346 var map
= fmap
.read_all
349 var article
= new TplArticle("graph")
351 if title
!= null then
352 article
.title
= title
353 alt
= "alt='{title.html_escape}'"
355 article
.css_classes
.add
"text-center"
356 var content
= new Template
357 var name_html
= name
.html_escape
358 content
.add
"<img src='{name_html}.png' usemap='#{name_html}' style='margin:auto' {alt}/>"
360 article
.content
= content
364 # A (source) link template for a given location
365 fun tpl_showsource
(location
: nullable Location): nullable String
367 if location
== null then return null
368 var source
= ctx
.opt_source
.value
369 if source
== null then
370 var url
= location
.file
.filename
.simplify_path
371 return "<a target='_blank' title='Show source' href=\"{url}\
">View Source</a>"
373 # THIS IS JUST UGLY ! (but there is no replace yet)
374 var x
= source
.split_with
("%f")
375 source
= x
.join
(location
.file
.filename
.simplify_path
)
376 x
= source
.split_with
("%l")
377 source
= x
.join
(location
.line_start
.to_s
)
378 x
= source
.split_with
("%L")
379 source
= x
.join
(location
.line_end
.to_s
)
380 source
= source
.simplify_path
381 return "<a target='_blank' title='Show source' href=\"{source.to_s}\
">View Source</a>"
384 # MProject description template
385 fun tpl_mproject_article
(mproject
: MProject): TplArticle do
386 var article
= mproject
.tpl_article
387 article
.subtitle
= mproject
.tpl_declaration
388 article
.content
= mproject
.tpl_definition
389 if mproject
.mdoc
!= null then
390 article
.content
= mproject
.mdoc
.tpl_short_comment
395 # MGroup description template
396 fun tpl_mgroup_article
(mgroup
: MGroup): TplArticle do
397 var article
= mgroup
.tpl_article
398 article
.subtitle
= mgroup
.tpl_declaration
399 article
.content
= mgroup
.tpl_definition
403 # MModule description template
404 fun tpl_mmodule_article
(mmodule
: MModule): TplArticle do
405 var article
= mmodule
.tpl_article
406 article
.subtitle
= mmodule
.tpl_declaration
407 article
.content
= mmodule
.tpl_definition
409 var intros
= mmodule
.intro_mclassdefs
(ctx
.min_visibility
).to_a
410 if not intros
.is_empty
then
411 mainmodule
.linearize_mclassdefs
(intros
)
412 var intros_art
= new TplArticle.with_title
("{mmodule.nitdoc_id}_intros", "Introduces")
413 var intros_lst
= new TplList.with_classes
(["list-unstyled", "list-labeled"])
414 for mclassdef
in intros
do
415 intros_lst
.add_li mclassdef
.tpl_list_item
417 if not intros_lst
.is_empty
then
418 intros_art
.content
= intros_lst
419 article
.add_child intros_art
422 var redefs
= mmodule
.redef_mclassdefs
(ctx
.min_visibility
).to_a
423 if not redefs
.is_empty
then
424 mainmodule
.linearize_mclassdefs
(redefs
)
425 var redefs_art
= new TplArticle.with_title
("{mmodule.nitdoc_id}_redefs", "Redefines")
426 var redefs_lst
= new TplList.with_classes
(["list-unstyled", "list-labeled"])
427 for mclassdef
in redefs
do
428 redefs_lst
.add_li mclassdef
.tpl_list_item
430 if not redefs_lst
.is_empty
then
431 redefs_art
.content
= redefs_lst
432 article
.add_child redefs_art
438 # MClassDef description template
439 fun tpl_mclass_article
(mclass
: MClass, mclassdefs
: Array[MClassDef]): TplArticle do
440 var article
= mclass
.tpl_article
441 if not mclassdefs
.has
(mclass
.intro
) then
443 var intro_article
= mclass
.intro
.tpl_short_article
444 intro_article
.source_link
= tpl_showsource
(mclass
.intro
.location
)
445 article
.add_child intro_article
447 mainmodule
.linearize_mclassdefs
(mclassdefs
)
448 for mclassdef
in mclassdefs
do
449 # add mclassdef full description
450 var redef_article
= mclassdef
.tpl_article
451 redef_article
.source_link
= tpl_showsource
(mclassdef
.location
)
452 article
.add_child redef_article
454 var intros
= new TplArticle.with_title
("{mclassdef.nitdoc_id}_intros", "Introduces")
455 var intros_lst
= new TplList.with_classes
(["list-unstyled", "list-labeled"])
456 for mpropdef
in mclassdef
.collect_intro_mpropdefs
(ctx
.min_visibility
) do
457 intros_lst
.add_li mpropdef
.tpl_list_item
459 if not intros_lst
.is_empty
then
460 intros
.content
= intros_lst
461 redef_article
.add_child intros
463 var redefs
= new TplArticle.with_title
("{mclassdef.nitdoc_id}_redefs", "Redefines")
464 var redefs_lst
= new TplList.with_classes
(["list-unstyled", "list-labeled"])
465 for mpropdef
in mclassdef
.collect_redef_mpropdefs
(ctx
.min_visibility
) do
466 redefs_lst
.add_li mpropdef
.tpl_list_item
468 if not redefs_lst
.is_empty
then
469 redefs
.content
= redefs_lst
470 redef_article
.add_child redefs
476 # MClassDef description template
477 fun tpl_mclassdef_article
(mclassdef
: MClassDef): TplArticle do
478 var article
= mclassdef
.tpl_article
479 if mclassdef
.is_intro
then article
.content
= null
480 article
.source_link
= tpl_showsource
(mclassdef
.location
)
484 # MProp description template
486 # `main_mpropdef`: The most important mpropdef to display
487 # `local_mpropdefs`: List of other locally defined mpropdefs to display
488 # `lin`: full linearization from local_mpropdefs to intro (displayed in redef tree)
489 fun tpl_mprop_article
(main_mpropdef
: MPropDef, local_mpropdefs
: Array[MPropDef],
490 lin
: Array[MPropDef]): TplArticle do
491 var mprop
= main_mpropdef
.mproperty
492 var article
= new TplArticle(mprop
.nitdoc_id
)
493 var title
= new Template
494 title
.add mprop
.tpl_icon
495 title
.add
"<span id='{main_mpropdef.nitdoc_id}'></span>"
496 if main_mpropdef
.is_intro
then
497 title
.add mprop
.tpl_link
498 title
.add mprop
.intro
.tpl_signature
500 var cls_url
= mprop
.intro
.mclassdef
.mclass
.nitdoc_url
501 var def_url
= "{cls_url}#{mprop.nitdoc_id}"
502 var lnk
= new TplLink.with_title
(def_url
, mprop
.name
, "Go to introduction")
506 article
.title
= title
507 article
.title_classes
.add
"signature"
508 article
.summary_title
= "{mprop.nitdoc_name}"
509 article
.subtitle
= main_mpropdef
.tpl_namespace
510 if main_mpropdef
.mdoc
!= null then
511 article
.content
= main_mpropdef
.mdoc
.tpl_comment
513 var subarticle
= new TplArticle("{main_mpropdef.nitdoc_id}_redefs")
514 # Add redef in same `MClass`
515 if local_mpropdefs
.length
> 1 then
516 for mpropdef
in local_mpropdefs
do
517 if mpropdef
== main_mpropdef
then continue
518 var redef_article
= new TplArticle("{mpropdef.nitdoc_id}")
519 var redef_title
= new Template
520 redef_title
.add
"also redef in "
521 redef_title
.add mpropdef
.tpl_namespace
522 redef_article
.title
= redef_title
523 redef_article
.title_classes
.add
"signature info"
524 redef_article
.css_classes
.add
"nospace"
525 var redef_content
= new Template
526 if mpropdef
.mdoc
!= null then
527 redef_content
.add mpropdef
.mdoc
.tpl_comment
529 redef_article
.content
= redef_content
530 subarticle
.add_child redef_article
534 if lin
.length
> 1 then
535 var lin_article
= new TplArticle("{main_mpropdef.nitdoc_id}_lin")
536 lin_article
.title
= "Inheritance"
537 var lst
= new TplList.with_classes
(["list-unstyled", "list-labeled"])
538 for mpropdef
in lin
do
539 lst
.add_li mpropdef
.tpl_inheritance_item
541 lin_article
.content
= lst
542 subarticle
.add_child lin_article
544 article
.add_child subarticle
548 # MProperty description template
549 fun tpl_mpropdef_article
(mpropdef
: MPropDef): TplArticle do
550 var article
= mpropdef
.tpl_article
551 article
.source_link
= tpl_showsource
(mpropdef
.location
)
557 # Display a list of modules contained in program
561 private var page
= new TplPage
562 redef fun tpl_page
do return page
564 private var sidebar
= new TplSidebar
565 redef fun tpl_sidebar
do return sidebar
567 redef fun tpl_title
do
568 if ctx
.opt_custom_title
.value
!= null then
569 return ctx
.opt_custom_title
.value
.to_s
575 redef fun page_url
do return "index.html"
578 private fun tpl_intro
: TplSection do
579 var section
= new TplSection.with_title
("overview", tpl_title
)
580 var article
= new TplArticle("intro")
581 if ctx
.opt_custom_intro
.value
!= null then
582 article
.content
= ctx
.opt_custom_intro
.value
.to_s
584 section
.add_child article
589 private fun tpl_projects
(section
: TplSection) do
591 var mprojects
= model
.mprojects
.to_a
592 var sorter
= new MConcernRankSorter
593 sorter
.sort mprojects
594 var ssection
= new TplSection.with_title
("projects", "Projects")
595 for mproject
in mprojects
do
596 ssection
.add_child tpl_mproject_article
(mproject
)
598 section
.add_child ssection
601 redef fun tpl_content
do
604 tpl_page
.add_section top
609 # Display a list of modules, classes and properties
613 private var page
= new TplPage
614 redef fun tpl_page
do return page
616 redef fun tpl_title
do return "Index"
618 redef fun page_url
do return "search.html"
620 redef fun tpl_content
do
621 var tpl
= new TplSearchPage("search_all")
622 var section
= new TplSection("search")
626 for mmodule
in modules_list
do
627 tpl
.modules
.add mmodule
.tpl_link
630 for mclass
in classes_list
do
631 tpl
.classes
.add mclass
.tpl_link
634 for mproperty
in mprops_list
do
636 m
.add mproperty
.intro
.tpl_link
638 m
.add mproperty
.intro
.mclassdef
.mclass
.tpl_link
642 section
.add_child tpl
643 tpl_page
.add_section section
646 # Extract mmodule list to display (sorted by name)
647 private fun modules_list
: Array[MModule] do
648 var sorted
= new Array[MModule]
649 for mmodule
in model
.mmodule_importation_hierarchy
do
650 if mmodule
.is_fictive
then continue
653 name_sorter
.sort
(sorted
)
657 # Extract mclass list to display (sorted by name)
658 private fun classes_list
: Array[MClass] do
659 var sorted
= new Array[MClass]
660 for mclass
in model
.mclasses
do
661 if mclass
.visibility
< ctx
.min_visibility
then continue
664 name_sorter
.sort
(sorted
)
668 # Extract mproperty list to display (sorted by name)
669 private fun mprops_list
: Array[MProperty] do
670 var sorted
= new Array[MProperty]
671 for mproperty
in model
.mproperties
do
672 if mproperty
.visibility
< ctx
.min_visibility
then continue
673 if mproperty
isa MAttribute then continue
676 name_sorter
.sort
(sorted
)
682 # Display a flattened view of the group
686 private var mgroup
: MGroup
688 private var concerns
: ConcernsTree is noinit
689 private var intros
: Set[MClass] is noinit
690 private var redefs
: Set[MClass] is noinit
693 self.concerns
= model
.concerns_tree
(mgroup
.collect_mmodules
)
694 self.concerns
.sort_with
(new MConcernRankSorter)
695 self.intros
= mgroup
.in_nesting_intro_mclasses
(ctx
.min_visibility
)
696 var redefs
= new HashSet[MClass]
697 for rdef
in mgroup
.in_nesting_redef_mclasses
(ctx
.min_visibility
) do
698 if intros
.has
(rdef
) then continue
704 private var page
= new TplPage
705 redef fun tpl_page
do return page
707 private var sidebar
= new TplSidebar
708 redef fun tpl_sidebar
do return sidebar
710 redef fun tpl_title
do return mgroup
.nitdoc_name
712 redef fun page_url
do return mgroup
.nitdoc_url
714 redef fun tpl_topmenu
do
716 var mproject
= mgroup
.mproject
717 if not mgroup
.is_root
then
718 topmenu
.add_link
new TplLink(mproject
.nitdoc_url
, mproject
.nitdoc_name
)
720 topmenu
.add_link
new TplLink(page_url
, mproject
.nitdoc_name
)
724 # Class list to display in sidebar
725 fun tpl_sidebar_mclasses
do
726 var mclasses
= new HashSet[MClass]
727 mclasses
.add_all intros
728 mclasses
.add_all redefs
729 if mclasses
.is_empty
then return
730 var list
= new TplList.with_classes
(["list-unstyled", "list-labeled"])
732 var sorted
= mclasses
.to_a
733 name_sorter
.sort
(sorted
)
734 for mclass
in sorted
do
735 list
.add_li tpl_sidebar_item
(mclass
)
737 tpl_sidebar
.boxes
.add
new TplSideBox.with_content
("All classes", list
)
740 private fun tpl_sidebar_item
(def
: MClass): TplListItem do
741 var classes
= def
.intro
.tpl_css_classes
.to_a
742 if intros
.has
(def
) then
747 var lnk
= new Template
748 lnk
.add
new TplLabel.with_classes
(classes
)
750 return new TplListItem.with_content
(lnk
)
754 private fun tpl_intro
: TplSection do
755 var section
= new TplSection.with_title
("top", tpl_title
)
756 var article
= new TplArticle("intro")
758 if mgroup
.is_root
then
759 section
.subtitle
= mgroup
.mproject
.tpl_declaration
760 article
.content
= mgroup
.mproject
.tpl_definition
762 section
.subtitle
= mgroup
.tpl_declaration
763 article
.content
= mgroup
.tpl_definition
765 section
.add_child article
769 private fun tpl_concerns
(section
: TplSection) do
770 if concerns
.is_empty
then return
771 section
.add_child
new TplArticle.with_content
("concerns", "Concerns", concerns
.to_tpl
)
774 private fun tpl_groups
(parent
: TplSection) do
775 var lst
= concerns
.to_a
777 for mentity
in lst
do
778 if mentity
isa MProject then
779 section
.add_child
new TplSection(mentity
.nitdoc_id
)
780 else if mentity
isa MGroup then
781 section
.add_child
new TplSection(mentity
.nitdoc_id
)
782 else if mentity
isa MModule then
783 section
.add_child tpl_mmodule_article
(mentity
)
788 redef fun tpl_content
do
793 tpl_page
.add_section top
796 private fun sort_by_mclass
(mclassdefs
: Collection[MClassDef]): Map[MClass, Set[MClassDef]] do
797 var map
= new HashMap[MClass, Set[MClassDef]]
798 for mclassdef
in mclassdefs
do
799 var mclass
= mclassdef
.mclass
800 if not map
.has_key
(mclass
) then map
[mclass
] = new HashSet[MClassDef]
801 map
[mclass
].add mclassdef
808 # Display the list of introduced and redefined classes in module
812 private var mmodule
: MModule
813 private var concerns
: ConcernsTree is noinit
814 private var mclasses2mdefs
: Map[MClass, Set[MClassDef]] is noinit
815 private var mmodules2mclasses
: Map[MModule, Set[MClass]] is noinit
819 var mclassdefs
= new HashSet[MClassDef]
820 mclassdefs
.add_all mmodule
.intro_mclassdefs
(ctx
.min_visibility
)
821 mclassdefs
.add_all mmodule
.redef_mclassdefs
(ctx
.min_visibility
)
822 self.mclasses2mdefs
= sort_by_mclass
(mclassdefs
)
823 self.mmodules2mclasses
= group_by_mmodule
(mclasses2mdefs
.keys
)
824 self.concerns
= model
.concerns_tree
(mmodules2mclasses
.keys
)
826 mmodule
.mgroup
.mproject
.booster_rank
= -1000
827 mmodule
.mgroup
.booster_rank
= -1000
828 mmodule
.booster_rank
= -1000
829 self.concerns
.sort_with
(new MConcernRankSorter)
830 mmodule
.mgroup
.mproject
.booster_rank
= 0
831 mmodule
.mgroup
.booster_rank
= 0
832 mmodule
.booster_rank
= 0
835 private var page
= new TplPage
836 redef fun tpl_page
do return page
838 private var sidebar
= new TplSidebar
839 redef fun tpl_sidebar
do return sidebar
841 redef fun tpl_title
do return mmodule
.nitdoc_name
842 redef fun page_url
do return mmodule
.nitdoc_url
844 redef fun tpl_topmenu
do
846 var mproject
= mmodule
.mgroup
.mproject
847 topmenu
.add_link
new TplLink(mproject
.nitdoc_url
, mproject
.nitdoc_name
)
848 topmenu
.add_link
new TplLink(page_url
, mmodule
.nitdoc_name
)
852 # Class list to display in sidebar
853 fun tpl_sidebar_mclasses
do
854 var mclasses
= new HashSet[MClass]
855 mclasses
.add_all mmodule
.filter_intro_mclasses
(ctx
.min_visibility
)
856 mclasses
.add_all mmodule
.filter_redef_mclasses
(ctx
.min_visibility
)
857 if mclasses
.is_empty
then return
858 var list
= new TplList.with_classes
(["list-unstyled", "list-labeled"])
860 var sorted
= mclasses
.to_a
861 name_sorter
.sort
(sorted
)
862 for mclass
in sorted
do
863 list
.add_li tpl_sidebar_item
(mclass
)
865 tpl_sidebar
.boxes
.add
new TplSideBox.with_content
("All classes", list
)
868 private fun tpl_sidebar_item
(def
: MClass): TplListItem do
869 var classes
= def
.intro
.tpl_css_classes
.to_a
870 if def
.intro_mmodule
== mmodule
then
875 var lnk
= new Template
876 lnk
.add
new TplLabel.with_classes
(classes
)
878 return new TplListItem.with_content
(lnk
)
882 private fun tpl_intro
: TplSection do
883 var section
= new TplSection.with_title
("top", tpl_title
)
884 section
.subtitle
= mmodule
.tpl_declaration
886 var article
= new TplArticle("intro")
887 var def
= mmodule
.tpl_definition
888 var location
= mmodule
.location
889 article
.source_link
= tpl_showsource
(location
)
890 article
.content
= def
891 section
.add_child article
895 # inheritance section
896 private fun tpl_inheritance
(parent
: TplSection) do
897 # Extract relevent modules
898 var imports
= mmodule
.in_importation
.greaters
899 if imports
.length
> 10 then imports
= mmodule
.in_importation
.direct_greaters
900 var clients
= mmodule
.in_importation
.smallers
901 if clients
.length
> 10 then clients
= mmodule
.in_importation
.direct_smallers
904 var section
= new TplSection.with_title
("dependencies", "Dependencies")
907 var mmodules
= new HashSet[MModule]
908 mmodules
.add_all mmodule
.in_nesting
.direct_greaters
909 mmodules
.add_all imports
910 if clients
.length
< 10 then mmodules
.add_all clients
912 var graph
= tpl_dot
(mmodules
)
913 if graph
!= null then section
.add_child graph
916 var lst
= new Array[MModule]
917 for dep
in imports
do
918 if dep
.is_fictive
then continue
919 if dep
== mmodule
then continue
922 if not lst
.is_empty
then
924 section
.add_child tpl_list
("imports", "Imports", lst
)
928 lst
= new Array[MModule]
929 for dep
in clients
do
930 if dep
.is_fictive
then continue
931 if dep
== mmodule
then continue
934 if not lst
.is_empty
then
936 section
.add_child tpl_list
("clients", "Clients", lst
)
939 parent
.add_child section
942 private fun tpl_list
(id
: String, title
: String, mmodules
: Array[MModule]): TplArticle do
943 var article
= new TplArticle.with_title
(id
, title
)
944 var list
= new TplList.with_classes
(["list-unstyled", "list-definition"])
945 for mmodule
in mmodules
do list
.elts
.add mmodule
.tpl_list_item
946 article
.content
= list
950 private fun tpl_concerns
(parent
: TplSection) do
951 if concerns
.is_empty
then return
952 parent
.add_child
new TplArticle.with_content
("concerns", "Concerns", concerns
.to_tpl
)
955 private fun tpl_mclasses
(parent
: TplSection) do
956 for mentity
in concerns
do
957 if mentity
isa MProject then
958 parent
.add_child
new TplSection(mentity
.nitdoc_id
)
959 else if mentity
isa MGroup then
960 parent
.add_child
new TplSection(mentity
.nitdoc_id
)
961 else if mentity
isa MModule then
962 var section
= new TplSection(mentity
.nitdoc_id
)
963 var title
= new Template
964 if mentity
== mmodule
then
966 section
.summary_title
= "in {mentity.nitdoc_name}"
969 section
.summary_title
= "from {mentity.nitdoc_name}"
971 title
.add mentity
.tpl_namespace
972 section
.title
= title
974 var mclasses
= mmodules2mclasses
[mentity
].to_a
975 name_sorter
.sort
(mclasses
)
976 for mclass
in mclasses
do
977 section
.add_child tpl_mclass_article
(mclass
, mclasses2mdefs
[mclass
].to_a
)
979 parent
.add_child section
984 private fun group_by_mmodule
(mclasses
: Collection[MClass]): Map[MModule, Set[MClass]] do
985 var res
= new HashMap[MModule, Set[MClass]]
986 for mclass
in mclasses
do
987 var mmodule
= mclass
.intro_mmodule
988 if not res
.has_key
(mmodule
) then
989 res
[mmodule
] = new HashSet[MClass]
991 res
[mmodule
].add
(mclass
)
996 redef fun tpl_content
do
1002 tpl_page
.add_section top
1005 # Genrate dot hierarchy for class inheritance
1006 fun tpl_dot
(mmodules
: Collection[MModule]): nullable TplArticle do
1007 var poset
= new POSet[MModule]
1008 for mmodule
in mmodules
do
1009 if mmodule
.is_fictive
then continue
1010 poset
.add_node mmodule
1011 for omodule
in mmodules
do
1012 if mmodule
.is_fictive
then continue
1013 poset
.add_node mmodule
1014 if mmodule
.in_importation
< omodule
then
1015 poset
.add_edge
(mmodule
, omodule
)
1020 var op
= new RopeBuffer
1021 var name
= "dep_module_{mmodule.nitdoc_id}"
1022 op
.append
("digraph \"{name.escape_to_dot}\
" \{ 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")
1023 for mmodule
in poset
do
1024 if mmodule
== self.mmodule
then
1025 op
.append
("\"{mmodule.name.escape_to_dot}\
"[shape=box,margin=0.03];\n")
1027 op
.append
("\"{mmodule.name.escape_to_dot}\
"[URL=\"{mmodule.nitdoc_url.escape_to_dot}\
"];\n")
1029 for omodule
in poset
[mmodule
].direct_greaters
do
1030 op
.append
("\"{mmodule.name.escape_to_dot}\
"->\"{omodule.name.escape_to_dot}\
";\n")
1034 return tpl_graph
(op
, name
, null)
1037 private fun sort_by_mclass
(mclassdefs
: Collection[MClassDef]): Map[MClass, Set[MClassDef]] do
1038 var map
= new HashMap[MClass, Set[MClassDef]]
1039 for mclassdef
in mclassdefs
do
1040 var mclass
= mclassdef
.mclass
1041 if not map
.has_key
(mclass
) then map
[mclass
] = new HashSet[MClassDef]
1042 map
[mclass
].add mclassdef
1049 # Display a list properties defined or redefined for this class
1053 private var mclass
: MClass
1054 private var concerns
: ConcernsTree is noinit
1055 private var mprops2mdefs
: Map[MProperty, Set[MPropDef]] is noinit
1056 private var mmodules2mprops
: Map[MModule, Set[MProperty]] is noinit
1059 var mpropdefs
= new HashSet[MPropDef]
1060 mpropdefs
.add_all mclass
.intro_mpropdefs
(ctx
.min_visibility
)
1061 mpropdefs
.add_all mclass
.redef_mpropdefs
(ctx
.min_visibility
)
1062 self.mprops2mdefs
= sort_by_mproperty
(mpropdefs
)
1063 self.mmodules2mprops
= sort_by_mmodule
(mprops2mdefs
.keys
)
1064 self.concerns
= model
.concerns_tree
(mmodules2mprops
.keys
)
1065 self.concerns
.sort_with
(new MConcernRankSorter)
1068 private var page
= new TplPage
1069 redef fun tpl_page
do return page
1071 private var sidebar
= new TplSidebar
1072 redef fun tpl_sidebar
do return sidebar
1074 redef fun tpl_title
do return "{mclass.nitdoc_name}{mclass.tpl_signature.write_to_string}"
1075 redef fun page_url
do return mclass
.nitdoc_url
1077 redef fun tpl_topmenu
do
1079 var mproject
= mclass
.intro_mmodule
.mgroup
.mproject
1080 topmenu
.add_link
new TplLink("{mproject.nitdoc_url}", "{mproject.nitdoc_name}")
1081 topmenu
.add_link
new TplLink(page_url
, mclass
.nitdoc_name
)
1085 # Property list to display in sidebar
1086 fun tpl_sidebar_properties
do
1087 var kind_map
= sort_by_kind
(mclass_inherited_mprops
)
1088 var summary
= new TplList.with_classes
(["list-unstyled"])
1090 tpl_sidebar_list
("Virtual types", kind_map
["type"].to_a
, summary
)
1091 tpl_sidebar_list
("Constructors", kind_map
["init"].to_a
, summary
)
1092 tpl_sidebar_list
("Methods", kind_map
["fun"].to_a
, summary
)
1093 if not kind_map
["inner"].is_empty
then
1094 tpl_sidebar_list
("Inner classes", kind_map
["inner"].to_a
, summary
)
1096 tpl_sidebar
.boxes
.add
new TplSideBox.with_content
("All properties", summary
)
1099 private fun tpl_sidebar_list
(name
: String, mprops
: Array[MProperty], summary
: TplList) do
1100 if mprops
.is_empty
then return
1101 name_sorter
.sort
(mprops
)
1102 var entry
= new TplListItem.with_content
(name
)
1103 var list
= new TplList.with_classes
(["list-unstyled", "list-labeled"])
1104 for mprop
in mprops
do
1105 list
.add_li tpl_sidebar_item
(mprop
)
1108 summary
.elts
.add entry
1111 private fun tpl_sidebar_item
(mprop
: MProperty): TplListItem do
1112 var classes
= mprop
.intro
.tpl_css_classes
.to_a
1113 if not mprops2mdefs
.has_key
(mprop
) then
1114 classes
.add
"inherit"
1115 var cls_url
= mprop
.intro
.mclassdef
.mclass
.nitdoc_url
1116 var def_url
= "{cls_url}#{mprop.nitdoc_id}"
1117 var lnk
= new TplLink(def_url
, mprop
.name
)
1118 if mprop
.intro
.mdoc
!= null then lnk
.title
= mprop
.intro
.mdoc
.short_comment
1119 var item
= new Template
1120 item
.add
new TplLabel.with_classes
(classes
)
1122 return new TplListItem.with_content
(item
)
1124 var defs
= mprops2mdefs
[mprop
]
1125 if defs
.has
(mprop
.intro
) then
1130 var lnk
= new Template
1131 lnk
.add
new TplLabel.with_classes
(classes
)
1132 lnk
.add mprop
.tpl_anchor
1133 return new TplListItem.with_content
(lnk
)
1136 private fun tpl_intro
: TplSection do
1137 var section
= new TplSection.with_title
("top", tpl_title
)
1138 section
.subtitle
= mclass
.intro
.tpl_declaration
1139 var article
= new TplArticle("comment")
1140 if mclass
.mdoc
!= null then
1141 article
.content
= mclass
.mdoc
.tpl_comment
1143 section
.add_child article
1147 private fun tpl_concerns
(parent
: TplSection) do
1149 var section
= new TplSection.with_title
("intro", "Introduction")
1150 section
.summary_title
= "Introduction"
1151 section
.add_child tpl_mclassdef_article
(mclass
.intro
)
1152 parent
.add_child section
1154 if concerns
.is_empty
then return
1155 parent
.add_child
new TplArticle.with_content
("concerns", "Concerns", concerns
.to_tpl
)
1158 private fun tpl_inheritance
(parent
: TplSection) do
1160 var hparents
= new HashSet[MClass]
1161 for c
in mclass
.in_hierarchy
(mainmodule
).direct_greaters
do
1162 if c
.visibility
< ctx
.min_visibility
then continue
1167 var hancestors
= new HashSet[MClass]
1168 for c
in mclass
.in_hierarchy
(mainmodule
).greaters
do
1169 if c
== mclass
then continue
1170 if c
.visibility
< ctx
.min_visibility
then continue
1171 if hparents
.has
(c
) then continue
1176 var hchildren
= new HashSet[MClass]
1177 for c
in mclass
.in_hierarchy
(mainmodule
).direct_smallers
do
1178 if c
.visibility
< ctx
.min_visibility
then continue
1183 var hdescendants
= new HashSet[MClass]
1184 for c
in mclass
.in_hierarchy
(mainmodule
).smallers
do
1185 if c
== mclass
then continue
1186 if c
.visibility
< ctx
.min_visibility
then continue
1187 if hchildren
.has
(c
) then continue
1192 var section
= new TplSection.with_title
("inheritance", "Inheritance")
1195 var mclasses
= new HashSet[MClass]
1196 mclasses
.add_all hancestors
1197 mclasses
.add_all hparents
1198 mclasses
.add_all hchildren
1199 mclasses
.add_all hdescendants
1201 var graph
= tpl_dot
(mclasses
)
1202 if graph
!= null then section
.add_child graph
1205 if not hparents
.is_empty
then
1206 var lst
= hparents
.to_a
1207 name_sorter
.sort lst
1208 section
.add_child tpl_list
("parents", "Parents", lst
)
1212 if not hancestors
.is_empty
then
1213 var lst
= hancestors
.to_a
1214 name_sorter
.sort lst
1215 section
.add_child tpl_list
("ancestors", "Ancestors", lst
)
1219 if not hchildren
.is_empty
then
1220 var lst
= hchildren
.to_a
1221 name_sorter
.sort lst
1222 section
.add_child tpl_list
("children", "Children", lst
)
1226 if not hdescendants
.is_empty
then
1227 var lst
= hdescendants
.to_a
1228 name_sorter
.sort lst
1229 section
.add_child tpl_list
("descendants", "Descendants", lst
)
1232 parent
.add_child section
1235 private fun tpl_list
(id
: String, title
: String, elts
: Array[MClass]): TplArticle do
1236 var article
= new TplArticle.with_title
(id
, title
)
1237 if elts
.length
> 20 then
1238 var tpl
= new Template
1241 if e
!= elts
.last
then tpl
.add
", "
1243 article
.content
= tpl
1245 var list
= new TplList.with_classes
(["list-unstyled", "list-definition"])
1246 for elt
in elts
do list
.elts
.add elt
.tpl_list_item
1247 article
.content
= list
1252 private fun tpl_properties
(parent
: TplSection) do
1253 var lst
= concerns
.to_a
1254 for mentity
in lst
do
1255 if mentity
isa MProject then
1256 parent
.add_child
new TplSection(mentity
.nitdoc_id
)
1257 else if mentity
isa MGroup then
1258 parent
.add_child
new TplSection(mentity
.nitdoc_id
)
1259 else if mentity
isa MModule then
1260 var section
= new TplSection(mentity
.nitdoc_id
)
1261 var title
= new Template
1263 title
.add mentity
.tpl_namespace
1264 section
.title
= title
1265 section
.summary_title
= "in {mentity.nitdoc_name}"
1268 var mprops
= mmodules2mprops
[mentity
]
1269 var kind_map
= sort_by_kind
(mprops
)
1272 for article
in tpl_mproperty_articles
(kind_map
, "type") do
1273 section
.add_child article
1276 for article
in tpl_mproperty_articles
(kind_map
, "init") do
1277 section
.add_child article
1280 for article
in tpl_mproperty_articles
(kind_map
, "fun") do
1281 section
.add_child article
1284 for article
in tpl_mproperty_articles
(kind_map
, "inner") do
1285 section
.add_child article
1287 parent
.add_child section
1292 private fun tpl_mproperty_articles
(kind_map
: Map[String, Set[MProperty]],
1293 kind_name
: String): Sequence[TplArticle] do
1294 var articles
= new List[TplArticle]
1295 var elts
= kind_map
[kind_name
].to_a
1296 name_sorter
.sort
(elts
)
1298 var local_defs
= mprops2mdefs
[elt
]
1299 # var all_defs = elt.mpropdefs
1300 var all_defs
= new HashSet[MPropDef]
1301 for local_def
in local_defs
do
1302 all_defs
.add local_def
1303 var mpropdef
= local_def
1304 while not mpropdef
.is_intro
do
1305 mpropdef
= mpropdef
.lookup_next_definition
(mainmodule
, mpropdef
.mclassdef
.bound_mtype
)
1306 all_defs
.add mpropdef
1309 var loc_lin
= local_defs
.to_a
1310 mainmodule
.linearize_mpropdefs
(loc_lin
)
1311 var all_lin
= all_defs
.to_a
1312 mainmodule
.linearize_mpropdefs
(all_lin
)
1313 articles
.add tpl_mprop_article
(loc_lin
.first
, loc_lin
, all_lin
)
1318 redef fun tpl_content
do
1319 tpl_sidebar_properties
1321 tpl_inheritance
(top
)
1324 tpl_page
.add_section top
1327 private fun sort_by_mproperty
(mpropdefs
: Collection[MPropDef]): Map[MProperty, Set[MPropDef]] do
1328 var map
= new HashMap[MProperty, Set[MPropDef]]
1329 for mpropdef
in mpropdefs
do
1330 var mproperty
= mpropdef
.mproperty
1331 if not map
.has_key
(mproperty
) then map
[mproperty
] = new HashSet[MPropDef]
1332 map
[mproperty
].add mpropdef
1337 private fun sort_by_mmodule
(mprops
: Collection[MProperty]): Map[MModule, Set[MProperty]] do
1338 var map
= new HashMap[MModule, Set[MProperty]]
1339 for mprop
in mprops
do
1340 var mpropdefs
= mprops2mdefs
[mprop
].to_a
1341 mainmodule
.linearize_mpropdefs
(mpropdefs
)
1342 var mmodule
= mpropdefs
.first
.mclassdef
.mmodule
1343 if not map
.has_key
(mmodule
) then map
[mmodule
] = new HashSet[MProperty]
1344 map
[mmodule
].add mprop
1349 private fun sort_by_kind
(mprops
: Collection[MProperty]): Map[String, Set[MProperty]] do
1350 var map
= new HashMap[String, Set[MProperty]]
1351 map
["type"] = new HashSet[MProperty]
1352 map
["init"] = new HashSet[MProperty]
1353 map
["fun"] = new HashSet[MProperty]
1354 map
["inner"] = new HashSet[MProperty]
1355 for mprop
in mprops
do
1356 if mprop
isa MVirtualTypeProp then
1357 map
["type"].add mprop
1358 else if mprop
isa MMethod then
1359 if mprop
.is_init
then
1360 map
["init"].add mprop
1362 map
["fun"].add mprop
1364 else if mprop
isa MInnerClass then
1365 map
["inner"].add mprop
1371 private fun mclass_inherited_mprops
: Set[MProperty] do
1372 var res
= new HashSet[MProperty]
1373 var local
= mclass
.local_mproperties
(ctx
.min_visibility
)
1374 for mprop
in mclass
.inherited_mproperties
(mainmodule
, ctx
.min_visibility
) do
1375 if local
.has
(mprop
) then continue
1376 #if mprop isa MMethod and mprop.is_init then continue
1377 if mprop
.intro
.mclassdef
.mclass
.name
== "Object" and
1378 (mprop
.visibility
== protected_visibility
or
1379 mprop
.intro
.mclassdef
.mmodule
.name
!= "kernel") then continue
1386 private fun collect_mmodules
(mprops
: Collection[MProperty]): Set[MModule] do
1387 var res
= new HashSet[MModule]
1388 for mprop
in mprops
do
1389 if mprops2mdefs
.has_key
(mprop
) then
1390 for mpropdef
in mprops2mdefs
[mprop
] do res
.add mpropdef
.mclassdef
.mmodule
1396 # Generate dot hierarchy for classes
1397 fun tpl_dot
(mclasses
: Collection[MClass]): nullable TplArticle do
1398 var poset
= new POSet[MClass]
1400 for mclass
in mclasses
do
1401 poset
.add_node mclass
1402 for oclass
in mclasses
do
1403 if mclass
== oclass
then continue
1404 poset
.add_node oclass
1405 if mclass
.in_hierarchy
(mainmodule
) < oclass
then
1406 poset
.add_edge
(mclass
, oclass
)
1411 var op
= new RopeBuffer
1412 var name
= "dep_class_{mclass.nitdoc_id}"
1413 op
.append
("digraph \"{name.escape_to_dot}\
" \{ 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")
1414 var classes
= poset
.to_a
1415 var todo
= new Array[MClass]
1416 var done
= new HashSet[MClass]
1417 mainmodule
.linearize_mclasses
(classes
)
1418 if not classes
.is_empty
then todo
.add classes
.first
1419 while not todo
.is_empty
do
1421 if done
.has
(c
) then continue
1424 op
.append
("\"{c.name.escape_to_dot}\
"[shape=box,margin=0.03];\n")
1426 op
.append
("\"{c.name.escape_to_dot}\
"[URL=\"{c.nitdoc_url.escape_to_dot}\
"];\n")
1428 var smallers
= poset
[c
].direct_smallers
1429 if smallers
.length
< 10 then
1430 for c2
in smallers
do
1431 op
.append
("\"{c2.name.escape_to_dot}\
"->\"{c.name.escape_to_dot}\
";\n")
1433 todo
.add_all smallers
1435 op
.append
("\"...\
"->\"{c.name.escape_to_dot}\
";\n")
1439 return tpl_graph
(op
, name
, null)
1444 class NitdocProperty
1447 private var mproperty
: MProperty
1448 private var concerns
: ConcernsTree is noinit
1449 private var mmodules2mdefs
: Map[MModule, Set[MPropDef]] is noinit
1452 self.mproperty
= mproperty
1453 self.mmodules2mdefs
= sort_by_mmodule
(collect_mpropdefs
)
1454 self.concerns
= model
.concerns_tree
(mmodules2mdefs
.keys
)
1455 self.concerns
.sort_with
(new MConcernRankSorter)
1458 private fun collect_mpropdefs
: Set[MPropDef] do
1459 var res
= new HashSet[MPropDef]
1460 for mpropdef
in mproperty
.mpropdefs
do
1461 if not mpropdef
.is_intro
then res
.add mpropdef
1466 private var page
= new TplPage
1467 redef fun tpl_page
do return page
1469 private var sidebar
= new TplSidebar
1470 redef fun tpl_sidebar
do return sidebar
1472 redef fun tpl_title
do
1473 return "{mproperty.nitdoc_name}{mproperty.tpl_signature.write_to_string}"
1476 redef fun page_url
do return mproperty
.nitdoc_url
1478 redef fun tpl_topmenu
do
1480 var mmodule
= mproperty
.intro_mclassdef
.mmodule
1481 var mproject
= mmodule
.mgroup
.mproject
1482 var mclass
= mproperty
.intro_mclassdef
.mclass
1483 topmenu
.add_link
new TplLink("{mproject.nitdoc_url}", "{mproject.nitdoc_name}")
1484 topmenu
.add_link
new TplLink("{mclass.nitdoc_url}", "{mclass.nitdoc_name}")
1485 topmenu
.add_link
new TplLink(page_url
, mproperty
.nitdoc_name
)
1489 private fun tpl_intro
: TplSection do
1490 var title
= new Template
1491 title
.add mproperty
.nitdoc_name
1492 title
.add mproperty
.intro
.tpl_signature
1493 var section
= new TplSection.with_title
("top", title
)
1494 section
.subtitle
= mproperty
.tpl_namespace
1495 section
.summary_title
= mproperty
.nitdoc_name
1499 private fun tpl_properties
(parent
: TplSection) do
1501 var section
= new TplSection.with_title
("intro", "Introduction")
1502 section
.summary_title
= "Introduction"
1503 section
.add_child tpl_mpropdef_article
(mproperty
.intro
)
1504 parent
.add_child section
1507 if concerns
.is_empty
then return
1508 parent
.add_child
new TplArticle.with_content
("Concerns", "Concerns", concerns
.to_tpl
)
1511 var lst
= concerns
.to_a
1512 for mentity
in lst
do
1513 if mentity
isa MProject then
1514 parent
.add_child
new TplSection(mentity
.nitdoc_id
)
1515 else if mentity
isa MGroup then
1516 parent
.add_child
new TplSection(mentity
.nitdoc_id
)
1517 else if mentity
isa MModule then
1518 var ssection
= new TplSection(mentity
.nitdoc_id
)
1519 var title
= new Template
1521 title
.add mentity
.tpl_namespace
1522 ssection
.title
= title
1523 ssection
.summary_title
= "in {mentity.nitdoc_name}"
1526 var mpropdefs
= mmodules2mdefs
[mentity
].to_a
1527 name_sorter
.sort
(mpropdefs
)
1528 for mpropdef
in mpropdefs
do
1529 ssection
.add_child tpl_mpropdef_article
(mpropdef
)
1531 parent
.add_child ssection
1536 redef fun tpl_content
do
1539 tpl_page
.add_section top
1542 private fun sort_by_mmodule
(mpropdefs
: Collection[MPropDef]): Map[MModule, Set[MPropDef]] do
1543 var map
= new HashMap[MModule, Set[MPropDef]]
1544 for mpropdef
in mpropdefs
do
1545 var mmodule
= mpropdef
.mclassdef
.mmodule
1546 if not map
.has_key
(mmodule
) then map
[mmodule
] = new HashSet[MPropDef]
1547 map
[mmodule
].add mpropdef