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 # The NitdocContext contains all the knowledge used for doc generation
22 private var opt_dir
= new OptionString("output directory", "-d", "--dir")
23 private var opt_source
= new OptionString("link for source (%f for filename, %l for first line, %L for last line)", "--source")
24 private var opt_sharedir
= new OptionString("directory containing nitdoc assets", "--sharedir")
25 private var opt_shareurl
= new OptionString("use shareurl instead of copy shared files", "--shareurl")
26 private var opt_nodot
= new OptionBool("do not generate graphes with graphviz", "--no-dot")
27 private var opt_private
= new OptionBool("also generate private API", "--private")
29 private var opt_custom_title
= new OptionString("custom title for homepage", "--custom-title")
30 private var opt_custom_brand
= new OptionString("custom link to external site", "--custom-brand")
31 private var opt_custom_intro
= new OptionString("custom intro text for homepage", "--custom-overview-text")
32 private var opt_custom_footer
= new OptionString("custom footer text", "--custom-footer-text")
34 private var opt_github_upstream
= new OptionString("Git branch where edited commits will be pulled into (ex: user:repo:branch)", "--github-upstream")
35 private var opt_github_base_sha1
= new OptionString("Git sha1 of base commit used to create pull request", "--github-base-sha1")
36 private var opt_github_gitdir
= new OptionString("Git working directory used to resolve path name (ex: /home/me/myproject/)", "--github-gitdir")
38 private var opt_piwik_tracker
= new OptionString("Piwik tracker URL (ex: nitlanguage.org/piwik/)", "--piwik-tracker")
39 private var opt_piwik_site_id
= new OptionString("Piwik site ID", "--piwik-site-id")
41 private var output_dir
: String
42 private var min_visibility
: MVisibility
43 var toolcontext
: ToolContext
45 init(toolcontext
: ToolContext) do
46 self.toolcontext
= toolcontext
48 var opts
= toolcontext
.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 toolcontext
.tooldescription
= tpl
.write_to_string
60 fun process_options
(args
: Sequence[String]) do
61 toolcontext
.process_options
(args
)
63 var output_dir
= opt_dir
.value
64 if output_dir
== null then
67 self.output_dir
= output_dir
69 if opt_private
.value
then
70 min_visibility
= none_visibility
72 min_visibility
= protected_visibility
75 var gh_upstream
= opt_github_upstream
.value
76 var gh_base_sha
= opt_github_base_sha1
.value
77 var gh_gitdir
= opt_github_gitdir
.value
78 if not gh_upstream
== null or not gh_base_sha
== null or not gh_gitdir
== null then
79 if gh_upstream
== null or gh_base_sha
== null or gh_gitdir
== null then
80 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"
87 # The Nitdoc class explores the model and generate pages for each mentities found
90 var mainmodule
: MModule
91 var ctx
: NitdocContext
93 init(ctx
: NitdocContext, model
: Model, mainmodule
: MModule) do
96 self.mainmodule
= mainmodule
110 private fun init_output_dir
do
111 # create destination dir if it's necessary
112 var output_dir
= ctx
.output_dir
113 if not output_dir
.file_exists
then output_dir
.mkdir
115 var sharedir
= ctx
.opt_sharedir
.value
116 if sharedir
== null then
117 var dir
= ctx
.toolcontext
.nit_dir
119 print
"Error: Cannot locate nitdoc share files. Uses --sharedir or envvar NIT_DIR"
122 sharedir
= "{dir}/share/nitdoc"
123 if not sharedir
.file_exists
then
124 print
"Error: Cannot locate nitdoc share files. Uses --sharedir or envvar NIT_DIR"
129 if ctx
.opt_shareurl
.value
== null then
130 sys
.system
("cp -r {sharedir.to_s}/* {output_dir.to_s}/")
132 sys
.system
("cp -r {sharedir.to_s}/resources/ {output_dir.to_s}/resources/")
137 private fun overview
do
138 var overviewpage
= new NitdocOverview(ctx
, model
, mainmodule
)
139 overviewpage
.render
.write_to_file
("{ctx.output_dir.to_s}/index.html")
142 private fun search
do
143 var searchpage
= new NitdocSearch(ctx
, model
, mainmodule
)
144 searchpage
.render
.write_to_file
("{ctx.output_dir.to_s}/search.html")
147 private fun groups
do
148 for mproject
in model
.mprojects
do
149 for mgroup
in mproject
.mgroups
.to_a
do
150 var page
= new NitdocGroup(ctx
, model
, mainmodule
, mgroup
)
151 page
.render
.write_to_file
("{ctx.output_dir.to_s}/{mgroup.nitdoc_url}")
156 private fun modules
do
157 for mmodule
in model
.mmodules
do
158 if mmodule
.name
== "<main>" then continue
159 var modulepage
= new NitdocModule(ctx
, model
, mainmodule
, mmodule
)
160 modulepage
.render
.write_to_file
("{ctx.output_dir.to_s}/{mmodule.nitdoc_url}")
164 private fun classes
do
165 for mclass
in model
.mclasses
do
166 var classpage
= new NitdocClass(ctx
, model
, mainmodule
, mclass
)
167 classpage
.render
.write_to_file
("{ctx.output_dir.to_s}/{mclass.nitdoc_url}")
171 private fun properties
do
172 for mproperty
in model
.mproperties
do
173 var page
= new NitdocProperty(ctx
, model
, mainmodule
, mproperty
)
174 page
.render
.write_to_file
("{ctx.output_dir.to_s}/{mproperty.nitdoc_url}")
178 private fun quicksearch_list
do
179 var quicksearch
= new QuickSearch(ctx
, model
)
180 quicksearch
.render
.write_to_file
("{ctx.output_dir.to_s}/quicksearch-list.js")
184 # Nitdoc QuickSearch list generator
186 # Create a JSON object containing links to:
190 # All entities are grouped by name to make the research easier.
193 private var mmodules
= new HashSet[MModule]
194 private var mclasses
= new HashSet[MClass]
195 private var mpropdefs
= new HashMap[String, Set[MPropDef]]
197 init(ctx
: NitdocContext, model
: Model) do
198 for mmodule
in model
.mmodules
do
199 if mmodule
.name
== "<main>" then continue
202 for mclass
in model
.mclasses
do
203 if mclass
.visibility
< ctx
.min_visibility
then continue
206 for mproperty
in model
.mproperties
do
207 if mproperty
.visibility
< ctx
.min_visibility
then continue
208 if mproperty
isa MAttribute then continue
209 if not mpropdefs
.has_key
(mproperty
.name
) then
210 mpropdefs
[mproperty
.name
] = new HashSet[MPropDef]
212 mpropdefs
[mproperty
.name
].add_all
(mproperty
.mpropdefs
)
216 fun render
: Template do
217 var tpl
= new Template
218 tpl
.add
"var nitdocQuickSearchRawList=\{ "
219 for mmodule
in mmodules
do
220 tpl
.add
"\"{mmodule.name}\
":["
221 tpl
.add
"\{txt:\"{mmodule.full_name}\",url
:\
"{mmodule.nitdoc_url}\"\
},"
224 for mclass in mclasses do
225 var full_name = mclass.intro.mmodule.full_name
226 tpl.add "\
"{mclass.name}\":["
227 tpl.add "\
{txt:\"{full_name}\
",url:\"{mclass.nitdoc_url}\
"\},"
230 for mproperty
, mprops
in mpropdefs
do
231 tpl
.add
"\"{mproperty}\
":["
232 for mpropdef
in mprops
do
233 var full_name
= mpropdef
.mclassdef
.mclass
.full_name
234 tpl
.add
"\{txt:\"{full_name}\",url
:\
"{mpropdef.nitdoc_url}\"\
},"
244 # Define page structure and properties
245 abstract class NitdocPage
247 private var ctx: NitdocContext
248 private var model: Model
249 private var mainmodule: MModule
250 private var name_sorter = new MEntityNameSorter
252 init(ctx: NitdocContext, model: Model, mainmodule: MModule) do
255 self.mainmodule = mainmodule
258 # Render the page as a html template
259 fun render: Template do
261 if ctx.opt_shareurl.value != null then
262 shareurl = ctx.opt_shareurl.value.as(not null)
267 tpl.title = tpl_title
268 tpl.shareurl = shareurl
269 tpl.topmenu = tpl_topmenu
271 tpl.footer = ctx.opt_custom_footer.value
272 tpl.body_attrs.add(new TagAttribute("data-bootstrap-share
", shareurl))
273 tpl.sidebar = tpl_sidebar
276 var tracker_url = ctx.opt_piwik_tracker.value
277 var site_id = ctx.opt_piwik_site_id.value
278 if tracker_url != null and site_id != null then
279 tpl.scripts.add new TplPiwikScript(tracker_url, site_id)
284 # Build page template
285 fun tpl_page: TplPage is abstract
287 # Build page sidebar if any
288 fun tpl_sidebar: nullable TplSidebar do return null
290 # Build page title string
291 fun tpl_title: String do
292 if ctx.opt_custom_title.value != null then
293 return ctx.opt_custom_title.value.to_s
298 # Build top menu template
299 fun tpl_topmenu: TplTopMenu do
300 var topmenu = new TplTopMenu
301 var brand = ctx.opt_custom_brand.value
302 if brand != null then
303 var tpl = new Template
304 tpl.add "<span
class='navbar-brand'>"
312 # Build page content template
313 fun tpl_content is abstract
315 # Clickable graphviz image using dot format
316 # return null if no graph for this page
317 fun tpl_graph(dot: FlatBuffer, name: String, title: nullable String): nullable TplArticle do
318 if ctx.opt_nodot.value then return null
319 var output_dir = ctx.output_dir
320 var file = new OFStream.open("{output_dir}/{name}.dot
")
323 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
; \
}")
324 var fmap = new IFStream.open("{output_dir}/{name}.map
")
325 var map = fmap.read_all
328 var article = new TplArticle("graph
")
330 if title != null then
331 article.title = title
332 alt = "alt
='{title}'"
334 article.css_classes.add "text-center
"
335 var content = new Template
336 content.add "<img src
='{name}.png' usemap
='#{name}' style
='margin:auto' {alt}/>"
338 article.content = content
342 # A (source) link template for a given location
343 fun tpl_showsource(location: nullable Location): nullable String
345 if location == null then return null
346 var source = ctx.opt_source.value
347 if source == null then return "{location.file.filename.simplify_path}"
348 # THIS IS JUST UGLY ! (but there is no replace yet)
349 var x = source.split_with("%f
")
350 source = x.join(location.file.filename.simplify_path)
351 x = source.split_with("%l
")
352 source = x.join(location.line_start.to_s)
353 x = source.split_with("%L
")
354 source = x.join(location.line_end.to_s)
355 source = source.simplify_path
356 return "<a target
='_blank' title
='Show source' href
=\
"{source.to_s}\">View Source</a
>"
359 # MProject description template
360 fun tpl_mproject_article(mproject: MProject): TplArticle do
361 var article = mproject.tpl_article
362 article.subtitle = mproject.tpl_declaration
363 article.content = mproject.tpl_definition
364 if mproject.mdoc != null then
365 article.content = mproject.mdoc.tpl_short_comment
370 # MGroup description template
371 fun tpl_mgroup_article(mgroup: MGroup): TplArticle do
372 var article = mgroup.tpl_article
373 article.subtitle = mgroup.tpl_declaration
374 article.content = mgroup.tpl_definition
378 # MModule description template
379 fun tpl_mmodule_article(mmodule: MModule): TplArticle do
380 var article = mmodule.tpl_article
381 article.subtitle = mmodule.tpl_declaration
382 article.content = mmodule.tpl_definition
384 var intros = mmodule.intro_mclassdefs(ctx.min_visibility).to_a
385 mainmodule.linearize_mclassdefs(intros)
386 var intros_art = new TplArticle.with_title("{mmodule.nitdoc_id}_intros
", "Introduces")
387 var intros_lst = new TplList.with_classes(["list-unstyled
", "list-labeled
"])
388 for mclassdef in intros do
389 intros_lst.add_li new TplListItem.with_content(mclassdef.tpl_list_item)
391 if not intros_lst.is_empty then
392 intros_art.content = intros_lst
393 article.add_child intros_art
395 var redefs = mmodule.redef_mclassdefs(ctx.min_visibility).to_a
396 mainmodule.linearize_mclassdefs(redefs)
397 var redefs_art = new TplArticle.with_title("{mmodule.nitdoc_id}_redefs
", "Redefines")
398 var redefs_lst = new TplList.with_classes(["list-unstyled
", "list-labeled
"])
399 for mclassdef in redefs do
400 redefs_lst.add_li new TplListItem.with_content(mclassdef.tpl_list_item)
402 if not redefs_lst.is_empty then
403 redefs_art.content = redefs_lst
404 article.add_child redefs_art
409 # MClassDef description template
410 fun tpl_mclass_article(mclass: MClass, mclassdefs: Array[MClassDef]): TplArticle do
411 var article = mclass.tpl_article
412 if not mclassdefs.has(mclass.intro) then
414 var intro_article = mclass.intro.tpl_short_article
415 intro_article.source_link = tpl_showsource(mclass.intro.location)
416 article.add_child intro_article
418 mainmodule.linearize_mclassdefs(mclassdefs)
419 for mclassdef in mclassdefs do
420 # add mclassdef full description
421 var redef_article = mclassdef.tpl_article
422 redef_article.source_link = tpl_showsource(mclassdef.location)
423 article.add_child redef_article
425 var intros = new TplArticle.with_title("{mclassdef.nitdoc_id}_intros
", "Introduces")
426 var intros_lst = new TplList.with_classes(["list-unstyled
", "list-labeled
"])
427 for mpropdef in mclassdef.collect_intro_mpropdefs(ctx.min_visibility) do
428 intros_lst.add_li new TplListItem.with_content(mpropdef.tpl_list_item)
430 if not intros_lst.is_empty then
431 intros.content = intros_lst
432 redef_article.add_child intros
434 var redefs = new TplArticle.with_title("{mclassdef.nitdoc_id}_redefs
", "Redefines")
435 var redefs_lst = new TplList.with_classes(["list-unstyled
", "list-labeled
"])
436 for mpropdef in mclassdef.collect_redef_mpropdefs(ctx.min_visibility) do
437 redefs_lst.add_li new TplListItem.with_content(mpropdef.tpl_list_item)
439 if not redefs_lst.is_empty then
440 redefs.content = redefs_lst
441 redef_article.add_child redefs
447 # MClassDef description template
448 fun tpl_mclassdef_article(mclassdef: MClassDef): TplArticle do
449 var article = mclassdef.tpl_article
450 if mclassdef.is_intro then article.content = null
451 article.source_link = tpl_showsource(mclassdef.location)
455 # MProp description template
456 fun tpl_mprop_article(mproperty: MProperty, mpropdefs: Array[MPropDef]): TplArticle do
457 var article = mproperty.tpl_article
458 if not mpropdefs.has(mproperty.intro) then
460 var intro_article = mproperty.intro.tpl_short_article
461 intro_article.source_link = tpl_showsource(mproperty.intro.location)
462 article.add_child intro_article
464 mainmodule.linearize_mpropdefs(mpropdefs)
465 for mpropdef in mpropdefs do
466 # add mpropdef description
467 var redef_article = mpropdef.tpl_article
468 redef_article.source_link = tpl_showsource(mpropdef.location)
469 article.add_child redef_article
474 # MProperty description template
475 fun tpl_mpropdef_article(mpropdef: MPropDef): TplArticle do
476 var article = mpropdef.tpl_article
477 if mpropdef.is_intro then article.content = null
478 article.source_link = tpl_showsource(mpropdef.location)
484 # Display a list of modules contained in program
488 private var page = new TplPage
489 redef fun tpl_page do return page
491 private var sidebar = new TplSidebar
492 redef fun tpl_sidebar do return sidebar
494 redef fun tpl_title do
495 if ctx.opt_custom_title.value != null then
496 return ctx.opt_custom_title.value.to_s
502 redef fun tpl_topmenu do
504 topmenu.add_item(new TplLink("#", "Overview"), true)
505 topmenu
.add_item
(new TplLink("search.html", "Index"), false)
510 private fun tpl_intro
: TplSection do
511 var section
= new TplSection.with_title
("overview", tpl_title
)
512 var article
= new TplArticle("intro")
513 if ctx
.opt_custom_intro
.value
!= null then
514 article
.content
= ctx
.opt_custom_intro
.value
.to_s
516 section
.add_child article
521 private fun tpl_projects
(section
: TplSection) do
523 var mprojects
= model
.mprojects
.to_a
524 var sorter
= new MConcernRankSorter
525 sorter
.sort mprojects
526 var ssection
= new TplSection.with_title
("projects", "Projects")
527 for mproject
in mprojects
do
528 ssection
.add_child tpl_mproject_article
(mproject
)
530 section
.add_child ssection
533 redef fun tpl_content
do
536 tpl_page
.add_section top
541 # Display a list of modules, classes and properties
545 private var page
= new TplPage
546 redef fun tpl_page
do return page
548 redef fun tpl_title
do return "Index"
550 redef fun tpl_topmenu
do
552 topmenu
.add_item
(new TplLink("index.html", "Overview"), false)
553 topmenu
.add_item
(new TplLink("#", "Index"), true)
557 redef fun tpl_content
do
558 var tpl
= new TplSearchPage("search_all")
559 var section
= new TplSection("search")
563 for mmodule
in modules_list
do
564 tpl
.modules
.add mmodule
.tpl_link
567 for mclass
in classes_list
do
568 tpl
.classes
.add mclass
.tpl_link
571 for mproperty
in mprops_list
do
573 m
.add mproperty
.intro
.tpl_link
575 m
.add mproperty
.intro
.mclassdef
.mclass
.tpl_link
579 section
.add_child tpl
580 tpl_page
.add_section section
583 # Extract mmodule list to display (sorted by name)
584 private fun modules_list
: Array[MModule] do
585 var sorted
= new Array[MModule]
586 for mmodule
in model
.mmodule_importation_hierarchy
do
587 if mmodule
.name
== "<main>" then continue
590 name_sorter
.sort
(sorted
)
594 # Extract mclass list to display (sorted by name)
595 private fun classes_list
: Array[MClass] do
596 var sorted
= new Array[MClass]
597 for mclass
in model
.mclasses
do
598 if mclass
.visibility
< ctx
.min_visibility
then continue
601 name_sorter
.sort
(sorted
)
605 # Extract mproperty list to display (sorted by name)
606 private fun mprops_list
: Array[MProperty] do
607 var sorted
= new Array[MProperty]
608 for mproperty
in model
.mproperties
do
609 if mproperty
.visibility
< ctx
.min_visibility
then continue
610 if mproperty
isa MAttribute then continue
613 name_sorter
.sort
(sorted
)
619 # Display a flattened view of the group
623 private var mgroup
: MGroup
625 private var concerns
: ConcernsTree
626 private var intros
: Set[MClass]
627 private var redefs
: Set[MClass]
629 init(ctx
: NitdocContext, model
: Model, mainmodule
: MModule, mgroup
: MGroup) do
632 self.concerns
= model
.concerns_tree
(mgroup
.collect_mmodules
)
633 self.concerns
.sort_with
(new MConcernRankSorter)
634 self.intros
= mgroup
.in_nesting_intro_mclasses
(ctx
.min_visibility
)
635 var redefs
= new HashSet[MClass]
636 for rdef
in mgroup
.in_nesting_redef_mclasses
(ctx
.min_visibility
) do
637 if intros
.has
(rdef
) then continue
643 private var page
= new TplPage
644 redef fun tpl_page
do return page
646 private var sidebar
= new TplSidebar
647 redef fun tpl_sidebar
do return sidebar
649 redef fun tpl_title
do return "{mgroup.nitdoc_name}"
651 redef fun tpl_topmenu
do
653 var mproject
= mgroup
.mproject
654 topmenu
.add_item
(new TplLink("index.html", "Overview"), false)
655 if mgroup
.is_root
then
656 topmenu
.add_item
(new TplLink("#", "{mproject.nitdoc_name}"), true)
658 topmenu
.add_item
(new TplLink(mproject
.nitdoc_url
, "{mproject.nitdoc_name}"), false)
659 topmenu
.add_item
(new TplLink("#", "{mgroup.nitdoc_name}"), true)
661 topmenu
.add_item
(new TplLink("search.html", "Index"), false)
665 # Class list to display in sidebar
666 fun tpl_sidebar_mclasses
do
667 var mclasses
= new HashSet[MClass]
668 mclasses
.add_all intros
669 mclasses
.add_all redefs
670 if mclasses
.is_empty
then return
671 var list
= new TplList.with_classes
(["list-unstyled", "list-labeled"])
673 var sorted
= mclasses
.to_a
674 name_sorter
.sort
(sorted
)
675 for mclass
in sorted
do
676 list
.add_li tpl_sidebar_item
(mclass
)
678 tpl_sidebar
.boxes
.add
new TplSideBox.with_content
("All classes", list
)
681 private fun tpl_sidebar_item
(def
: MClass): Template do
682 var classes
= def
.intro
.tpl_css_classes
.to_a
683 if intros
.has
(def
) then
688 var lnk
= new Template
689 lnk
.add
new TplLabel.with_classes
(classes
)
695 private fun tpl_intro
: TplSection do
696 var section
= new TplSection.with_title
("top", tpl_title
)
697 var article
= new TplArticle("intro")
699 if mgroup
.is_root
then
700 section
.subtitle
= mgroup
.mproject
.tpl_declaration
701 article
.content
= mgroup
.mproject
.tpl_definition
703 section
.subtitle
= mgroup
.tpl_declaration
704 article
.content
= mgroup
.tpl_definition
706 section
.add_child article
710 private fun tpl_concerns
(section
: TplSection) do
711 if concerns
.is_empty
then return
712 section
.add_child
new TplArticle.with_content
("concerns", "Concerns", concerns
.to_tpl
)
715 private fun tpl_groups
(parent
: TplSection) do
716 var lst
= concerns
.to_a
718 for mentity
in lst
do
719 if mentity
isa MProject then
720 section
.add_child
new TplSection(mentity
.nitdoc_id
)
721 else if mentity
isa MGroup then
722 section
.add_child
new TplSection(mentity
.nitdoc_id
)
723 else if mentity
isa MModule then
724 section
.add_child tpl_mmodule_article
(mentity
)
729 redef fun tpl_content
do
734 tpl_page
.add_section top
737 private fun sort_by_mclass
(mclassdefs
: Collection[MClassDef]): Map[MClass, Set[MClassDef]] do
738 var map
= new HashMap[MClass, Set[MClassDef]]
739 for mclassdef
in mclassdefs
do
740 var mclass
= mclassdef
.mclass
741 if not map
.has_key
(mclass
) then map
[mclass
] = new HashSet[MClassDef]
742 map
[mclass
].add mclassdef
749 # Display the list of introduced and redefined classes in module
753 private var mmodule
: MModule
754 private var concerns
: ConcernsTree
755 private var mclasses2mdefs
: Map[MClass, Set[MClassDef]]
756 private var mmodules2mclasses
: Map[MModule, Set[MClass]]
759 init(ctx
: NitdocContext, model
: Model, mainmodule
: MModule, mmodule
: MModule) do
761 self.mmodule
= mmodule
762 var mclassdefs
= new HashSet[MClassDef]
763 mclassdefs
.add_all mmodule
.intro_mclassdefs
(ctx
.min_visibility
)
764 mclassdefs
.add_all mmodule
.redef_mclassdefs
(ctx
.min_visibility
)
765 self.mclasses2mdefs
= sort_by_mclass
(mclassdefs
)
766 self.mmodules2mclasses
= group_by_mmodule
(mclasses2mdefs
.keys
)
767 self.concerns
= model
.concerns_tree
(mmodules2mclasses
.keys
)
769 mmodule
.mgroup
.mproject
.booster_rank
= -1000
770 mmodule
.mgroup
.booster_rank
= -1000
771 mmodule
.booster_rank
= -1000
772 self.concerns
.sort_with
(new MConcernRankSorter)
773 mmodule
.mgroup
.mproject
.booster_rank
= 0
774 mmodule
.mgroup
.booster_rank
= 0
775 mmodule
.booster_rank
= 0
778 private var page
= new TplPage
779 redef fun tpl_page
do return page
781 private var sidebar
= new TplSidebar
782 redef fun tpl_sidebar
do return sidebar
784 redef fun tpl_title
do return "{mmodule.nitdoc_name}"
786 redef fun tpl_topmenu
do
788 var mproject
= mmodule
.mgroup
.mproject
789 topmenu
.add_item
(new TplLink("index.html", "Overview"), false)
790 topmenu
.add_item
(new TplLink("{mproject.nitdoc_url}", "{mproject.nitdoc_name}"), false)
791 topmenu
.add_item
(new TplLink("#", "{mmodule.nitdoc_name}"), true)
792 topmenu
.add_item
(new TplLink("search.html", "Index"), false)
796 # Class list to display in sidebar
797 fun tpl_sidebar_mclasses
do
798 var mclasses
= new HashSet[MClass]
799 mclasses
.add_all mmodule
.filter_intro_mclasses
(ctx
.min_visibility
)
800 mclasses
.add_all mmodule
.filter_redef_mclasses
(ctx
.min_visibility
)
801 if mclasses
.is_empty
then return
802 var list
= new TplList.with_classes
(["list-unstyled", "list-labeled"])
804 var sorted
= mclasses
.to_a
805 name_sorter
.sort
(sorted
)
806 for mclass
in sorted
do
807 list
.add_li tpl_sidebar_item
(mclass
)
809 tpl_sidebar
.boxes
.add
new TplSideBox.with_content
("All classes", list
)
812 private fun tpl_sidebar_item
(def
: MClass): Template do
813 var classes
= def
.intro
.tpl_css_classes
.to_a
814 if def
.intro_mmodule
== mmodule
then
819 var lnk
= new Template
820 lnk
.add
new TplLabel.with_classes
(classes
)
826 private fun tpl_intro
: TplSection do
827 var section
= new TplSection.with_title
("top", tpl_title
)
828 section
.subtitle
= mmodule
.tpl_declaration
830 var article
= new TplArticle("intro")
831 var def
= mmodule
.tpl_definition
832 var location
= mmodule
.location
833 article
.source_link
= tpl_showsource
(location
)
834 article
.content
= def
835 section
.add_child article
839 # inheritance section
840 private fun tpl_inheritance
(parent
: TplSection) do
841 # Extract relevent modules
842 var imports
= mmodule
.in_importation
.greaters
843 if imports
.length
> 10 then imports
= mmodule
.in_importation
.direct_greaters
844 var clients
= mmodule
.in_importation
.smallers
845 if clients
.length
> 10 then clients
= mmodule
.in_importation
.direct_smallers
848 var section
= new TplSection.with_title
("dependencies", "Dependencies")
851 var mmodules
= new HashSet[MModule]
852 mmodules
.add_all mmodule
.in_nesting
.direct_greaters
853 mmodules
.add_all imports
854 if clients
.length
< 10 then mmodules
.add_all clients
856 var graph
= tpl_dot
(mmodules
)
857 if graph
!= null then section
.add_child graph
860 var lst
= new Array[MModule]
861 for dep
in imports
do
862 if dep
.is_fictive
then continue
863 if dep
== mmodule
then continue
866 if not lst
.is_empty
then
868 section
.add_child tpl_list
("imports", "Imports", lst
)
872 lst
= new Array[MModule]
873 for dep
in clients
do
874 if dep
.is_fictive
then continue
875 if dep
== mmodule
then continue
878 if not lst
.is_empty
then
880 section
.add_child tpl_list
("clients", "Clients", lst
)
883 parent
.add_child section
886 private fun tpl_list
(id
: String, title
: String, mmodules
: Array[MModule]): TplArticle do
887 var article
= new TplArticle.with_title
(id
, title
)
888 var list
= new TplList.with_classes
(["list-unstyled", "list-definition"])
889 for mmodule
in mmodules
do list
.elts
.add mmodule
.tpl_list_item
890 article
.content
= list
894 private fun tpl_concerns
(parent
: TplSection) do
895 if concerns
.is_empty
then return
896 parent
.add_child
new TplArticle.with_content
("concerns", "Concerns", concerns
.to_tpl
)
899 private fun tpl_mclasses
(parent
: TplSection) do
900 for mentity
in concerns
do
901 if mentity
isa MProject then
902 parent
.add_child
new TplSection(mentity
.nitdoc_id
)
903 else if mentity
isa MGroup then
904 parent
.add_child
new TplSection(mentity
.nitdoc_id
)
905 else if mentity
isa MModule then
906 var section
= new TplSection(mentity
.nitdoc_id
)
907 var title
= new Template
908 if mentity
== mmodule
then
910 section
.summary_title
= "in {mentity.nitdoc_name}"
913 section
.summary_title
= "from {mentity.nitdoc_name}"
915 title
.add mentity
.tpl_namespace
916 section
.title
= title
918 var mclasses
= mmodules2mclasses
[mentity
].to_a
919 name_sorter
.sort
(mclasses
)
920 for mclass
in mclasses
do
921 section
.add_child tpl_mclass_article
(mclass
, mclasses2mdefs
[mclass
].to_a
)
923 parent
.add_child section
928 private fun group_by_mmodule
(mclasses
: Collection[MClass]): Map[MModule, Set[MClass]] do
929 var res
= new HashMap[MModule, Set[MClass]]
930 for mclass
in mclasses
do
931 var mmodule
= mclass
.intro_mmodule
932 if not res
.has_key
(mmodule
) then
933 res
[mmodule
] = new HashSet[MClass]
935 res
[mmodule
].add
(mclass
)
940 redef fun tpl_content
do
946 tpl_page
.add_section top
949 # Genrate dot hierarchy for class inheritance
950 fun tpl_dot
(mmodules
: Collection[MModule]): nullable TplArticle do
951 var poset
= new POSet[MModule]
952 for mmodule
in mmodules
do
953 if mmodule
.is_fictive
then continue
954 poset
.add_node mmodule
955 for omodule
in mmodules
do
956 if mmodule
.is_fictive
then continue
957 poset
.add_node mmodule
958 if mmodule
.in_importation
< omodule
then
959 poset
.add_edge
(mmodule
, omodule
)
964 var op
= new FlatBuffer
965 var name
= "dep_{mmodule.name}"
966 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")
967 for mmodule
in poset
do
968 if mmodule
== self.mmodule
then
969 op
.append
("\"{mmodule.name}\
"[shape=box,margin=0.03];\n")
971 op
.append
("\"{mmodule.name}\
"[URL=\"{mmodule.nitdoc_url}\
"];\n")
973 for omodule
in poset
[mmodule
].direct_greaters
do
974 op
.append
("\"{mmodule.name}\
"->\"{omodule.name}\
";\n")
978 return tpl_graph
(op
, name
, null)
981 private fun sort_by_mclass
(mclassdefs
: Collection[MClassDef]): Map[MClass, Set[MClassDef]] do
982 var map
= new HashMap[MClass, Set[MClassDef]]
983 for mclassdef
in mclassdefs
do
984 var mclass
= mclassdef
.mclass
985 if not map
.has_key
(mclass
) then map
[mclass
] = new HashSet[MClassDef]
986 map
[mclass
].add mclassdef
993 # Display a list properties defined or redefined for this class
997 private var mclass
: MClass
998 private var concerns
: ConcernsTree
999 private var mprops2mdefs
: Map[MProperty, Set[MPropDef]]
1000 private var mmodules2mprops
: Map[MModule, Set[MProperty]]
1002 init(ctx
: NitdocContext, model
: Model, mainmodule
: MModule, mclass
: MClass) do
1004 self.mclass
= mclass
1005 var mpropdefs
= new HashSet[MPropDef]
1006 mpropdefs
.add_all mclass
.intro_mpropdefs
(ctx
.min_visibility
)
1007 mpropdefs
.add_all mclass
.redef_mpropdefs
(ctx
.min_visibility
)
1008 self.mprops2mdefs
= sort_by_mproperty
(mpropdefs
)
1009 self.mmodules2mprops
= sort_by_mmodule
(mprops2mdefs
.keys
)
1010 self.concerns
= model
.concerns_tree
(mmodules2mprops
.keys
)
1011 self.concerns
.sort_with
(new MConcernRankSorter)
1014 private var page
= new TplPage
1015 redef fun tpl_page
do return page
1017 private var sidebar
= new TplSidebar
1018 redef fun tpl_sidebar
do return sidebar
1020 redef fun tpl_title
do return "{mclass.nitdoc_name}{mclass.tpl_signature.write_to_string}"
1022 redef fun tpl_topmenu
do
1024 var mproject
= mclass
.intro_mmodule
.mgroup
.mproject
1025 topmenu
.add_item
(new TplLink("index.html", "Overview"), false)
1026 topmenu
.add_item
(new TplLink("{mproject.nitdoc_url}", "{mproject.nitdoc_name}"), false)
1027 topmenu
.add_item
(new TplLink("#", "{mclass.nitdoc_name}"), true)
1028 topmenu
.add_item
(new TplLink("search.html", "Index"), false)
1032 # Property list to display in sidebar
1033 fun tpl_sidebar_properties
do
1034 var kind_map
= sort_by_kind
(mclass_inherited_mprops
)
1035 var summary
= new TplList.with_classes
(["list-unstyled"])
1037 tpl_sidebar_list
("Virtual types", kind_map
["type"].to_a
, summary
)
1038 tpl_sidebar_list
("Constructors", kind_map
["init"].to_a
, summary
)
1039 tpl_sidebar_list
("Methods", kind_map
["fun"].to_a
, summary
)
1040 tpl_sidebar
.boxes
.add
new TplSideBox.with_content
("All properties", summary
)
1043 private fun tpl_sidebar_list
(name
: String, mprops
: Array[MProperty], summary
: TplList) do
1044 if mprops
.is_empty
then return
1045 name_sorter
.sort
(mprops
)
1046 var entry
= new TplListItem.with_content
(name
)
1047 var list
= new TplList.with_classes
(["list-unstyled", "list-labeled"])
1048 for mprop
in mprops
do
1049 list
.add_li tpl_sidebar_item
(mprop
)
1052 summary
.elts
.add entry
1055 private fun tpl_sidebar_item
(mprop
: MProperty): Template do
1056 var classes
= mprop
.intro
.tpl_css_classes
.to_a
1057 if not mprops2mdefs
.has_key
(mprop
) then
1058 classes
.add
"inherit"
1059 var lnk
= new Template
1060 lnk
.add
new TplLabel.with_classes
(classes
)
1061 lnk
.add mprop
.intro
.tpl_link
1064 var defs
= mprops2mdefs
[mprop
]
1065 if defs
.has
(mprop
.intro
) then
1070 var lnk
= new Template
1071 lnk
.add
new TplLabel.with_classes
(classes
)
1072 lnk
.add mprop
.intro
.tpl_anchor
1076 private fun tpl_intro
: TplSection do
1077 var section
= new TplSection.with_title
("top", tpl_title
)
1078 section
.subtitle
= mclass
.intro
.tpl_declaration
1079 var article
= new TplArticle("comment")
1080 if mclass
.mdoc
!= null then
1081 article
.content
= mclass
.mdoc
.tpl_comment
1083 section
.add_child article
1087 private fun tpl_concerns
(parent
: TplSection) do
1089 var section
= new TplSection.with_title
("intro", "Introduction")
1090 section
.summary_title
= "Introduction"
1091 section
.add_child tpl_mclassdef_article
(mclass
.intro
)
1092 parent
.add_child section
1094 if concerns
.is_empty
then return
1095 parent
.add_child
new TplArticle.with_content
("concerns", "Concerns", concerns
.to_tpl
)
1098 private fun tpl_inheritance
(parent
: TplSection) do
1100 var hparents
= new HashSet[MClass]
1101 for c
in mclass
.in_hierarchy
(mainmodule
).direct_greaters
do
1102 if c
.visibility
< ctx
.min_visibility
then continue
1107 var hancestors
= new HashSet[MClass]
1108 for c
in mclass
.in_hierarchy
(mainmodule
).greaters
do
1109 if c
== mclass
then continue
1110 if c
.visibility
< ctx
.min_visibility
then continue
1111 if hparents
.has
(c
) then continue
1116 var hchildren
= new HashSet[MClass]
1117 for c
in mclass
.in_hierarchy
(mainmodule
).direct_smallers
do
1118 if c
.visibility
< ctx
.min_visibility
then continue
1123 var hdescendants
= new HashSet[MClass]
1124 for c
in mclass
.in_hierarchy
(mainmodule
).smallers
do
1125 if c
== mclass
then continue
1126 if c
.visibility
< ctx
.min_visibility
then continue
1127 if hchildren
.has
(c
) then continue
1132 var section
= new TplSection.with_title
("inheritance", "Inheritance")
1135 var mclasses
= new HashSet[MClass]
1136 mclasses
.add_all hancestors
1137 mclasses
.add_all hparents
1138 if hchildren
.length
< 10 then mclasses
.add_all hchildren
1139 if hdescendants
.length
< 10 then mclasses
.add_all hdescendants
1141 var graph
= tpl_dot
(mclasses
)
1142 if graph
!= null then section
.add_child graph
1145 if not hparents
.is_empty
then
1146 var lst
= hparents
.to_a
1147 name_sorter
.sort lst
1148 section
.add_child tpl_list
("parents", "Parents", lst
)
1152 if not hancestors
.is_empty
then
1153 var lst
= hancestors
.to_a
1154 name_sorter
.sort lst
1155 section
.add_child tpl_list
("ancestors", "Ancestors", lst
)
1159 if not hchildren
.is_empty
and hchildren
.length
< 15 then
1160 var lst
= hchildren
.to_a
1161 name_sorter
.sort lst
1162 section
.add_child tpl_list
("children", "Children", lst
)
1166 if not hdescendants
.is_empty
and hchildren
.length
< 15 then
1167 var lst
= hdescendants
.to_a
1168 name_sorter
.sort lst
1169 section
.add_child tpl_list
("descendants", "Descendants", lst
)
1172 parent
.add_child section
1175 private fun tpl_list
(id
: String, title
: String, elts
: Array[MClass]): TplArticle do
1176 var article
= new TplArticle.with_title
(id
, title
)
1177 var list
= new TplList.with_classes
(["list-unstyled", "list-definition"])
1178 for elt
in elts
do list
.elts
.add elt
.tpl_list_item
1179 article
.content
= list
1183 private fun tpl_properties
(parent
: TplSection) do
1184 var lst
= concerns
.to_a
1185 for mentity
in lst
do
1186 if mentity
isa MProject then
1187 parent
.add_child
new TplSection(mentity
.nitdoc_id
)
1188 else if mentity
isa MGroup then
1189 parent
.add_child
new TplSection(mentity
.nitdoc_id
)
1190 else if mentity
isa MModule then
1191 var section
= new TplSection(mentity
.nitdoc_id
)
1192 var title
= new Template
1194 title
.add mentity
.tpl_namespace
1195 section
.title
= title
1196 section
.summary_title
= "in {mentity.nitdoc_name}"
1199 var mprops
= mmodules2mprops
[mentity
]
1200 var kind_map
= sort_by_kind
(mprops
)
1203 var elts
= kind_map
["type"].to_a
1204 name_sorter
.sort
(elts
)
1206 var defs
= mprops2mdefs
[elt
].to_a
1207 section
.add_child tpl_mprop_article
(elt
, defs
)
1211 elts
= kind_map
["init"].to_a
1212 name_sorter
.sort
(elts
)
1214 var defs
= mprops2mdefs
[elt
].to_a
1215 section
.add_child tpl_mprop_article
(elt
, defs
)
1219 elts
= kind_map
["fun"].to_a
1220 name_sorter
.sort
(elts
)
1222 var defs
= mprops2mdefs
[elt
].to_a
1223 section
.add_child tpl_mprop_article
(elt
, defs
)
1225 parent
.add_child section
1230 redef fun tpl_content
do
1231 tpl_sidebar_properties
1233 tpl_inheritance
(top
)
1236 tpl_page
.add_section top
1239 private fun sort_by_mproperty
(mpropdefs
: Collection[MPropDef]): Map[MProperty, Set[MPropDef]] do
1240 var map
= new HashMap[MProperty, Set[MPropDef]]
1241 for mpropdef
in mpropdefs
do
1242 var mproperty
= mpropdef
.mproperty
1243 if not map
.has_key
(mproperty
) then map
[mproperty
] = new HashSet[MPropDef]
1244 map
[mproperty
].add mpropdef
1249 private fun sort_by_mmodule
(mprops
: Collection[MProperty]): Map[MModule, Set[MProperty]] do
1250 var map
= new HashMap[MModule, Set[MProperty]]
1251 for mprop
in mprops
do
1252 var mpropdefs
= mprops2mdefs
[mprop
].to_a
1253 mainmodule
.linearize_mpropdefs
(mpropdefs
)
1254 var mmodule
= mpropdefs
.first
.mclassdef
.mmodule
1255 if not map
.has_key
(mmodule
) then map
[mmodule
] = new HashSet[MProperty]
1256 map
[mmodule
].add mprop
1261 private fun sort_by_kind
(mprops
: Collection[MProperty]): Map[String, Set[MProperty]] do
1262 var map
= new HashMap[String, Set[MProperty]]
1263 map
["type"] = new HashSet[MProperty]
1264 map
["init"] = new HashSet[MProperty]
1265 map
["fun"] = new HashSet[MProperty]
1266 for mprop
in mprops
do
1267 if mprop
isa MVirtualTypeProp then
1268 map
["type"].add mprop
1269 else if mprop
isa MMethod then
1270 if mprop
.is_init
then
1271 map
["init"].add mprop
1273 map
["fun"].add mprop
1280 private fun mclass_inherited_mprops
: Set[MProperty] do
1281 var res
= new HashSet[MProperty]
1282 var local
= mclass
.local_mproperties
(ctx
.min_visibility
)
1283 for mprop
in mclass
.inherited_mproperties
(mainmodule
, ctx
.min_visibility
) do
1284 if local
.has
(mprop
) then continue
1285 #if mprop isa MMethod and mprop.is_init then continue
1286 if mprop
.intro
.mclassdef
.mclass
.name
== "Object" and
1287 (mprop
.visibility
== protected_visibility
or
1288 mprop
.intro
.mclassdef
.mmodule
.name
!= "kernel") then continue
1295 private fun collect_mmodules
(mprops
: Collection[MProperty]): Set[MModule] do
1296 var res
= new HashSet[MModule]
1297 for mprop
in mprops
do
1298 if mprops2mdefs
.has_key
(mprop
) then
1299 for mpropdef
in mprops2mdefs
[mprop
] do res
.add mpropdef
.mclassdef
.mmodule
1305 private fun sort_by_public_owner
(mmodules
: Collection[MModule]): Map[MModule, Set[MModule]] do
1306 var map
= new HashMap[MModule, Set[MModule]]
1307 for mmodule
in mmodules
do
1309 if mmodule
.public_owner
!= null then owner
= mmodule
.public_owner
.as(not null)
1310 if not map
.has_key
(owner
) then map
[owner
] = new HashSet[MModule]
1311 map
[owner
].add mmodule
1316 # Generate dot hierarchy for classes
1317 fun tpl_dot
(mclasses
: Collection[MClass]): nullable TplArticle do
1318 var poset
= new POSet[MClass]
1320 for mclass
in mclasses
do
1321 poset
.add_node mclass
1322 for oclass
in mclasses
do
1323 poset
.add_node oclass
1324 if mclass
.in_hierarchy
(mainmodule
) < oclass
then
1325 poset
.add_edge
(mclass
, oclass
)
1330 var op
= new FlatBuffer
1331 var name
= "dep_{mclass.name}"
1332 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")
1335 op
.append
("\"{c.name}\
"[shape=box,margin=0.03];\n")
1337 op
.append
("\"{c.name}\
"[URL=\"{c.nitdoc_url}\
"];\n")
1339 for c2
in poset
[c
].direct_greaters
do
1340 op
.append
("\"{c.name}\
"->\"{c2.name}\
";\n")
1344 return tpl_graph
(op
, name
, null)
1349 class NitdocProperty
1352 private var mproperty
: MProperty
1353 private var concerns
: ConcernsTree
1354 private var mmodules2mdefs
: Map[MModule, Set[MPropDef]]
1356 init(ctx
: NitdocContext, model
: Model, mainmodule
: MModule, mproperty
: MProperty) do
1358 self.mproperty
= mproperty
1359 self.mmodules2mdefs
= sort_by_mmodule
(collect_mpropdefs
)
1360 self.concerns
= model
.concerns_tree
(mmodules2mdefs
.keys
)
1361 self.concerns
.sort_with
(new MConcernRankSorter)
1364 private fun collect_mpropdefs
: Set[MPropDef] do
1365 var res
= new HashSet[MPropDef]
1366 for mpropdef
in mproperty
.mpropdefs
do
1367 if not mpropdef
.is_intro
then res
.add mpropdef
1372 private var page
= new TplPage
1373 redef fun tpl_page
do return page
1375 private var sidebar
= new TplSidebar
1376 redef fun tpl_sidebar
do return sidebar
1378 redef fun tpl_title
do
1379 return "{mproperty.nitdoc_name}{mproperty.tpl_signature.write_to_string}"
1382 redef fun tpl_topmenu
do
1384 var mmodule
= mproperty
.intro_mclassdef
.mmodule
1385 var mproject
= mmodule
.mgroup
.mproject
1386 var mclass
= mproperty
.intro_mclassdef
.mclass
1387 topmenu
.add_item
(new TplLink("index.html", "Overview"), false)
1388 topmenu
.add_item
(new TplLink("{mproject.nitdoc_url}", "{mproject.nitdoc_name}"), false)
1389 topmenu
.add_item
(new TplLink("{mclass.nitdoc_url}", "{mclass.nitdoc_name}"), false)
1390 topmenu
.add_item
(new TplLink("#", "{mproperty.nitdoc_name}"), true)
1391 topmenu
.add_item
(new TplLink("search.html", "Index"), false)
1395 private fun tpl_intro
: TplSection do
1396 var section
= new TplSection.with_title
("top", tpl_title
)
1397 section
.subtitle
= mproperty
.tpl_declaration
1398 var article
= new TplArticle("comment")
1399 if mproperty
.intro
.mdoc
!= null then
1400 article
.content
= mproperty
.intro
.mdoc
.tpl_comment
1402 section
.add_child article
1406 private fun tpl_properties
(parent
: TplSection) do
1408 var section
= new TplSection.with_title
("intro", "Introduction")
1409 section
.summary_title
= "Introduction"
1410 section
.add_child tpl_mpropdef_article
(mproperty
.intro
)
1411 parent
.add_child section
1414 if concerns
.is_empty
then return
1415 parent
.add_child
new TplArticle.with_content
("Concerns", "Concerns", concerns
.to_tpl
)
1418 var lst
= concerns
.to_a
1419 for mentity
in lst
do
1420 if mentity
isa MProject then
1421 parent
.add_child
new TplSection(mentity
.nitdoc_id
)
1422 else if mentity
isa MGroup then
1423 parent
.add_child
new TplSection(mentity
.nitdoc_id
)
1424 else if mentity
isa MModule then
1425 var ssection
= new TplSection(mentity
.nitdoc_id
)
1426 var title
= new Template
1428 title
.add mentity
.tpl_namespace
1429 ssection
.title
= title
1430 ssection
.summary_title
= "in {mentity.nitdoc_name}"
1433 var mpropdefs
= mmodules2mdefs
[mentity
].to_a
1434 name_sorter
.sort
(mpropdefs
)
1435 for mpropdef
in mpropdefs
do
1436 ssection
.add_child tpl_mpropdef_article
(mpropdef
)
1438 parent
.add_child ssection
1443 redef fun tpl_content
do
1446 tpl_page
.add_section top
1449 private fun sort_by_mmodule
(mpropdefs
: Collection[MPropDef]): Map[MModule, Set[MPropDef]] do
1450 var map
= new HashMap[MModule, Set[MPropDef]]
1451 for mpropdef
in mpropdefs
do
1452 var mmodule
= mpropdef
.mclassdef
.mmodule
1453 if not map
.has_key
(mmodule
) then map
[mmodule
] = new HashSet[MPropDef]
1454 map
[mmodule
].add mpropdef