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_no_attributes
= new OptionBool("ignore the attributes",
29 private var opt_nodot
= new OptionBool("do not generate graphes with graphviz", "--no-dot")
30 private var opt_private
= new OptionBool("also generate private API", "--private")
32 private var opt_custom_title
= new OptionString("custom title for homepage", "--custom-title")
33 private var opt_custom_brand
= new OptionString("custom link to external site", "--custom-brand")
34 private var opt_custom_intro
= new OptionString("custom intro text for homepage", "--custom-overview-text")
35 private var opt_custom_footer
= new OptionString("custom footer text", "--custom-footer-text")
37 private var opt_github_upstream
= new OptionString("Git branch where edited commits will be pulled into (ex: user:repo:branch)", "--github-upstream")
38 private var opt_github_base_sha1
= new OptionString("Git sha1 of base commit used to create pull request", "--github-base-sha1")
39 private var opt_github_gitdir
= new OptionString("Git working directory used to resolve path name (ex: /home/me/myproject/)", "--github-gitdir")
41 private var opt_piwik_tracker
= new OptionString("Piwik tracker URL (ex: nitlanguage.org/piwik/)", "--piwik-tracker")
42 private var opt_piwik_site_id
= new OptionString("Piwik site ID", "--piwik-site-id")
44 private var output_dir
: String
45 private var min_visibility
: MVisibility
50 var opts
= option_context
51 opts
.add_option
(opt_dir
, opt_source
, opt_sharedir
, opt_shareurl
,
52 opt_no_attributes
, opt_nodot
, opt_private
)
53 opts
.add_option
(opt_custom_title
, opt_custom_footer
, opt_custom_intro
, opt_custom_brand
)
54 opts
.add_option
(opt_github_upstream
, opt_github_base_sha1
, opt_github_gitdir
)
55 opts
.add_option
(opt_piwik_tracker
, opt_piwik_site_id
)
57 var tpl
= new Template
58 tpl
.add
"Usage: nitdoc [OPTION]... <file.nit>...\n"
59 tpl
.add
"Generates HTML pages of API documentation from Nit source files."
60 tooldescription
= tpl
.write_to_string
63 redef fun process_options
(args
) do
67 var output_dir
= opt_dir
.value
68 if output_dir
== null then
71 self.output_dir
= output_dir
73 if opt_private
.value
then
74 min_visibility
= none_visibility
76 min_visibility
= protected_visibility
79 var gh_upstream
= opt_github_upstream
.value
80 var gh_base_sha
= opt_github_base_sha1
.value
81 var gh_gitdir
= opt_github_gitdir
.value
82 if not gh_upstream
== null or not gh_base_sha
== null or not gh_gitdir
== null then
83 if gh_upstream
== null or gh_base_sha
== null or gh_gitdir
== null then
84 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"
90 # Filter the entity based on the options specified by the user.
92 # Return `true` if the specified entity has to be included in the generated
94 private fun filter_mclass
(mclass
: MClass): Bool do
95 return mclass
.visibility
>= min_visibility
98 # Filter the entity based on the options specified by the user.
100 # Return `true` if the specified entity has to be included in the generated
102 private fun filter_mproperty
(mproperty
: MProperty): Bool do
103 return mproperty
.visibility
>= min_visibility
and
104 not (opt_no_attributes
.value
and mproperty
isa MAttribute)
108 # The Nitdoc class explores the model and generate pages for each mentities found
112 var mainmodule
: MModule
125 private fun init_output_dir
do
126 # create destination dir if it's necessary
127 var output_dir
= ctx
.output_dir
128 if not output_dir
.file_exists
then output_dir
.mkdir
130 var sharedir
= ctx
.opt_sharedir
.value
131 if sharedir
== null then
132 var dir
= ctx
.nit_dir
133 sharedir
= dir
/"share/nitdoc"
134 if not sharedir
.file_exists
then
135 print
"Error: Cannot locate nitdoc share files. Uses --sharedir or envvar NIT_DIR"
140 if ctx
.opt_shareurl
.value
== null then
141 sys
.system
("cp -r -- {sharedir.to_s.escape_to_sh}/* {output_dir.to_s.escape_to_sh}/")
143 sys
.system
("cp -r -- {sharedir.to_s.escape_to_sh}/resources/ {output_dir.to_s.escape_to_sh}/resources/")
148 private fun overview
do
149 var page
= new NitdocOverview(ctx
, model
, mainmodule
)
150 page
.render
.write_to_file
("{ctx.output_dir.to_s}/{page.page_url}")
153 private fun search
do
154 var page
= new NitdocSearch(ctx
, model
, mainmodule
)
155 page
.render
.write_to_file
("{ctx.output_dir.to_s}/{page.page_url}")
158 private fun groups
do
159 for mproject
in model
.mprojects
do
160 for mgroup
in mproject
.mgroups
.to_a
do
161 var page
= new NitdocGroup(ctx
, model
, mainmodule
, mgroup
)
162 page
.render
.write_to_file
("{ctx.output_dir.to_s}/{page.page_url}")
167 private fun modules
do
168 for mmodule
in model
.mmodules
do
169 if mmodule
.is_fictive
then continue
170 var page
= new NitdocModule(ctx
, model
, mainmodule
, mmodule
)
171 page
.render
.write_to_file
("{ctx.output_dir.to_s}/{page.page_url}")
175 private fun classes
do
176 for mclass
in model
.mclasses
do
177 if not ctx
.filter_mclass
(mclass
) then continue
178 var page
= new NitdocClass(ctx
, model
, mainmodule
, mclass
)
179 page
.render
.write_to_file
("{ctx.output_dir.to_s}/{page.page_url}")
183 private fun properties
do
184 for mproperty
in model
.mproperties
do
185 if not ctx
.filter_mproperty
(mproperty
) then continue
186 if mproperty
isa MInnerClass then continue
187 var page
= new NitdocProperty(ctx
, model
, mainmodule
, mproperty
)
188 page
.render
.write_to_file
("{ctx.output_dir.to_s}/{page.page_url}")
192 private fun quicksearch_list
do
193 var quicksearch
= new QuickSearch(ctx
, model
)
194 quicksearch
.render
.write_to_file
("{ctx.output_dir.to_s}/quicksearch-list.js")
198 # Nitdoc QuickSearch list generator
200 # Create a JSON object containing links to:
204 # All entities are grouped by name to make the research easier.
207 private var table
= new QuickSearchTable
213 for mmodule
in model
.mmodules
do
214 if mmodule
.is_fictive
then continue
215 add_result_for
(mmodule
.name
, mmodule
.full_name
, mmodule
.nitdoc_url
)
217 for mclass
in model
.mclasses
do
218 if not ctx
.filter_mclass
(mclass
) then continue
219 add_result_for
(mclass
.name
, mclass
.full_name
, mclass
.nitdoc_url
)
221 for mproperty
in model
.mproperties
do
222 if not ctx
.filter_mproperty
(mproperty
) then continue
223 for mpropdef
in mproperty
.mpropdefs
do
224 var full_name
= mpropdef
.mclassdef
.mclass
.full_name
225 var cls_url
= mpropdef
.mclassdef
.mclass
.nitdoc_url
226 var def_url
= "{cls_url}#{mpropdef.mproperty.nitdoc_id}"
227 add_result_for
(mproperty
.name
, full_name
, def_url
)
232 private fun add_result_for
(query
: String, txt
: String, url
: String) do
233 table
[query
].add
new QuickSearchResult(txt
, url
)
236 fun render
: Template do
237 var tpl
= new Template
238 var buffer
= new RopeBuffer
240 buffer
.append
"var nitdocQuickSearchRawList="
241 table
.append_json buffer
247 # The result map for QuickSearch.
248 private class QuickSearchTable
249 super JsonMapRead[String, QuickSearchResultList]
250 super HashMap[String, QuickSearchResultList]
252 redef fun provide_default_value
(key
) do
253 var v
= new QuickSearchResultList
259 # A QuickSearch result list.
260 private class QuickSearchResultList
261 super JsonSequenceRead[QuickSearchResult]
262 super Array[QuickSearchResult]
265 # A QuickSearch result.
266 private class QuickSearchResult
269 # The text of the link.
272 # The destination of the link.
276 return "\{\"txt\":{txt.to_json},\"url\
":{url.to_json}\}"
281 # Define page structure and properties
282 abstract class NitdocPage
284 private var ctx
: ToolContext
285 private var model
: Model
286 private var mainmodule
: MModule
287 private var name_sorter
= new MEntityNameSorter
289 # Render the page as a html template
290 fun render
: Template do
292 if ctx
.opt_shareurl
.value
!= null then
293 shareurl
= ctx
.opt_shareurl
.value
.as(not null)
298 tpl
.title
= tpl_title
300 tpl
.shareurl
= shareurl
301 tpl
.topmenu
= tpl_topmenu
303 tpl
.footer
= ctx
.opt_custom_footer
.value
304 tpl
.body_attrs
.add
(new TagAttribute("data-bootstrap-share", shareurl
))
305 tpl
.sidebar
= tpl_sidebar
308 var tracker_url
= ctx
.opt_piwik_tracker
.value
309 var site_id
= ctx
.opt_piwik_site_id
.value
310 if tracker_url
!= null and site_id
!= null then
311 tpl
.scripts
.add
new TplPiwikScript(tracker_url
, site_id
)
317 fun page_url
: String is abstract
319 # Build page template
320 fun tpl_page
: TplPage is abstract
322 # Build page sidebar if any
323 fun tpl_sidebar
: nullable TplSidebar do return null
325 # Build page title string
326 fun tpl_title
: String do
327 if ctx
.opt_custom_title
.value
!= null then
328 return ctx
.opt_custom_title
.value
.to_s
333 # Build top menu template
334 fun tpl_topmenu
: TplTopMenu do
335 var topmenu
= new TplTopMenu(page_url
)
336 var brand
= ctx
.opt_custom_brand
.value
337 if brand
!= null then
338 var tpl
= new Template
339 tpl
.add
"<span class='navbar-brand'>"
344 topmenu
.add_link
new TplLink("index.html", "Overview")
345 topmenu
.add_link
new TplLink("search.html", "Index")
349 # Build page content template
350 fun tpl_content
is abstract
352 # Clickable graphviz image using dot format
353 # return null if no graph for this page
354 fun tpl_graph
(dot
: Buffer, name
: String, title
: nullable String): nullable TplArticle do
355 if ctx
.opt_nodot
.value
then return null
356 var output_dir
= ctx
.output_dir
357 var path
= output_dir
/ name
358 var path_sh
= path
.escape_to_sh
359 var file
= new OFStream.open
("{path}.dot")
362 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 ; \}")
363 var fmap
= new IFStream.open
("{path}.map")
364 var map
= fmap
.read_all
367 var article
= new TplArticle("graph")
369 if title
!= null then
370 article
.title
= title
371 alt
= "alt='{title.html_escape}'"
373 article
.css_classes
.add
"text-center"
374 var content
= new Template
375 var name_html
= name
.html_escape
376 content
.add
"<img src='{name_html}.png' usemap='#{name_html}' style='margin:auto' {alt}/>"
378 article
.content
= content
382 # A (source) link template for a given location
383 fun tpl_showsource
(location
: nullable Location): nullable String
385 if location
== null then return null
386 var source
= ctx
.opt_source
.value
387 if source
== null then
388 var url
= location
.file
.filename
.simplify_path
389 return "<a target='_blank' title='Show source' href=\"{url.html_escape}\
">View Source</a>"
391 # THIS IS JUST UGLY ! (but there is no replace yet)
392 var x
= source
.split_with
("%f")
393 source
= x
.join
(location
.file
.filename
.simplify_path
)
394 x
= source
.split_with
("%l")
395 source
= x
.join
(location
.line_start
.to_s
)
396 x
= source
.split_with
("%L")
397 source
= x
.join
(location
.line_end
.to_s
)
398 source
= source
.simplify_path
399 return "<a target='_blank' title='Show source' href=\"{source.to_s.html_escape}\
">View Source</a>"
402 # MProject description template
403 fun tpl_mproject_article
(mproject
: MProject): TplArticle do
404 var article
= mproject
.tpl_article
405 article
.subtitle
= mproject
.tpl_declaration
406 article
.content
= mproject
.tpl_definition
407 var mdoc
= mproject
.mdoc_or_fallback
409 article
.content
= mdoc
.tpl_short_comment
414 # MGroup description template
415 fun tpl_mgroup_article
(mgroup
: MGroup): TplArticle do
416 var article
= mgroup
.tpl_article
417 article
.subtitle
= mgroup
.tpl_declaration
418 article
.content
= mgroup
.tpl_definition
422 # MModule description template
423 fun tpl_mmodule_article
(mmodule
: MModule): TplArticle do
424 var article
= mmodule
.tpl_article
425 article
.subtitle
= mmodule
.tpl_declaration
426 article
.content
= mmodule
.tpl_definition
428 var intros
= mmodule
.intro_mclassdefs
(ctx
.min_visibility
).to_a
429 if not intros
.is_empty
then
430 mainmodule
.linearize_mclassdefs
(intros
)
431 var intros_art
= new TplArticle.with_title
("{mmodule.nitdoc_id}.intros", "Introduces")
432 var intros_lst
= new TplList.with_classes
(["list-unstyled", "list-labeled"])
433 for mclassdef
in intros
do
434 intros_lst
.add_li mclassdef
.tpl_list_item
436 if not intros_lst
.is_empty
then
437 intros_art
.content
= intros_lst
438 article
.add_child intros_art
441 var redefs
= mmodule
.redef_mclassdefs
(ctx
.min_visibility
).to_a
442 if not redefs
.is_empty
then
443 mainmodule
.linearize_mclassdefs
(redefs
)
444 var redefs_art
= new TplArticle.with_title
("{mmodule.nitdoc_id}.redefs", "Redefines")
445 var redefs_lst
= new TplList.with_classes
(["list-unstyled", "list-labeled"])
446 for mclassdef
in redefs
do
447 redefs_lst
.add_li mclassdef
.tpl_list_item
449 if not redefs_lst
.is_empty
then
450 redefs_art
.content
= redefs_lst
451 article
.add_child redefs_art
457 # MClassDef description template
458 fun tpl_mclass_article
(mclass
: MClass, mclassdefs
: Array[MClassDef]): TplArticle do
459 var article
= mclass
.tpl_article
460 if not mclassdefs
.has
(mclass
.intro
) then
462 var intro_article
= mclass
.intro
.tpl_short_article
463 intro_article
.source_link
= tpl_showsource
(mclass
.intro
.location
)
464 article
.add_child intro_article
466 mainmodule
.linearize_mclassdefs
(mclassdefs
)
467 for mclassdef
in mclassdefs
do
468 # add mclassdef full description
469 var redef_article
= mclassdef
.tpl_article
470 redef_article
.source_link
= tpl_showsource
(mclassdef
.location
)
471 article
.add_child redef_article
473 var intros
= new TplArticle.with_title
("{mclassdef.nitdoc_id}.intros", "Introduces")
474 var intros_lst
= new TplList.with_classes
(["list-unstyled", "list-labeled"])
475 for mpropdef
in mclassdef
.collect_intro_mpropdefs
(ctx
.min_visibility
) do
476 intros_lst
.add_li mpropdef
.tpl_list_item
478 if not intros_lst
.is_empty
then
479 intros
.content
= intros_lst
480 redef_article
.add_child intros
482 var redefs
= new TplArticle.with_title
("{mclassdef.nitdoc_id}.redefs", "Redefines")
483 var redefs_lst
= new TplList.with_classes
(["list-unstyled", "list-labeled"])
484 for mpropdef
in mclassdef
.collect_redef_mpropdefs
(ctx
.min_visibility
) do
485 redefs_lst
.add_li mpropdef
.tpl_list_item
487 if not redefs_lst
.is_empty
then
488 redefs
.content
= redefs_lst
489 redef_article
.add_child redefs
495 # MClassDef description template
496 fun tpl_mclassdef_article
(mclassdef
: MClassDef): TplArticle do
497 var article
= mclassdef
.tpl_article
498 if mclassdef
.is_intro
then article
.content
= null
499 article
.source_link
= tpl_showsource
(mclassdef
.location
)
503 # MProp description template
505 # `main_mpropdef`: The most important mpropdef to display
506 # `local_mpropdefs`: List of other locally defined mpropdefs to display
507 # `lin`: full linearization from local_mpropdefs to intro (displayed in redef tree)
508 fun tpl_mprop_article
(main_mpropdef
: MPropDef, local_mpropdefs
: Array[MPropDef],
509 lin
: Array[MPropDef]): TplArticle do
510 var mprop
= main_mpropdef
.mproperty
511 var article
= new TplArticle(mprop
.nitdoc_id
)
512 var title
= new Template
513 title
.add mprop
.tpl_icon
514 title
.add
"<span id='{main_mpropdef.nitdoc_id}'></span>"
515 if main_mpropdef
.is_intro
then
516 title
.add mprop
.tpl_link
517 title
.add mprop
.intro
.tpl_signature
519 var cls_url
= mprop
.intro
.mclassdef
.mclass
.nitdoc_url
520 var def_url
= "{cls_url}#{mprop.nitdoc_id}"
521 var lnk
= new TplLink.with_title
(def_url
, mprop
.nitdoc_name
,
522 "Go to introduction")
526 article
.title
= title
527 article
.title_classes
.add
"signature"
528 article
.summary_title
= "{mprop.nitdoc_name}"
529 article
.subtitle
= main_mpropdef
.tpl_namespace
530 if main_mpropdef
.mdoc_or_fallback
!= null then
531 article
.content
= main_mpropdef
.mdoc_or_fallback
.tpl_comment
533 var subarticle
= new TplArticle("{main_mpropdef.nitdoc_id}.redefs")
534 # Add redef in same `MClass`
535 if local_mpropdefs
.length
> 1 then
536 for mpropdef
in local_mpropdefs
do
537 if mpropdef
== main_mpropdef
then continue
538 var redef_article
= new TplArticle("{mpropdef.nitdoc_id}")
539 var redef_title
= new Template
540 redef_title
.add
"also redef in "
541 redef_title
.add mpropdef
.tpl_namespace
542 redef_article
.title
= redef_title
543 redef_article
.title_classes
.add
"signature info"
544 redef_article
.css_classes
.add
"nospace"
545 var redef_content
= new Template
546 if mpropdef
.mdoc
!= null then
547 redef_content
.add mpropdef
.mdoc
.tpl_comment
549 redef_article
.content
= redef_content
550 subarticle
.add_child redef_article
554 if lin
.length
> 1 then
555 var lin_article
= new TplArticle("{main_mpropdef.nitdoc_id}.lin")
556 lin_article
.title
= "Inheritance"
557 var lst
= new TplList.with_classes
(["list-unstyled", "list-labeled"])
558 for mpropdef
in lin
do
559 lst
.add_li mpropdef
.tpl_inheritance_item
561 lin_article
.content
= lst
562 subarticle
.add_child lin_article
564 article
.add_child subarticle
568 # MProperty description template
569 fun tpl_mpropdef_article
(mpropdef
: MPropDef): TplArticle do
570 var article
= mpropdef
.tpl_article
571 article
.source_link
= tpl_showsource
(mpropdef
.location
)
577 # Display a list of modules contained in program
581 private var page
= new TplPage
582 redef fun tpl_page
do return page
584 private var sidebar
= new TplSidebar
585 redef fun tpl_sidebar
do return sidebar
587 redef fun tpl_title
do
588 if ctx
.opt_custom_title
.value
!= null then
589 return ctx
.opt_custom_title
.value
.to_s
595 redef fun page_url
do return "index.html"
598 private fun tpl_intro
: TplSection do
599 var section
= new TplSection.with_title
("overview", tpl_title
)
600 var article
= new TplArticle("intro")
601 if ctx
.opt_custom_intro
.value
!= null then
602 article
.content
= ctx
.opt_custom_intro
.value
.to_s
604 section
.add_child article
609 private fun tpl_projects
(section
: TplSection) do
611 var mprojects
= model
.mprojects
.to_a
612 var sorter
= new MConcernRankSorter
613 sorter
.sort mprojects
614 var ssection
= new TplSection.with_title
("projects", "Projects")
615 for mproject
in mprojects
do
616 ssection
.add_child tpl_mproject_article
(mproject
)
618 section
.add_child ssection
621 redef fun tpl_content
do
624 tpl_page
.add_section top
629 # Display a list of modules, classes and properties
633 private var page
= new TplPage
634 redef fun tpl_page
do return page
636 redef fun tpl_title
do return "Index"
638 redef fun page_url
do return "search.html"
640 redef fun tpl_content
do
641 var tpl
= new TplSearchPage("search_all")
642 var section
= new TplSection("search")
646 for mmodule
in modules_list
do
647 tpl
.modules
.add mmodule
.tpl_link
650 for mclass
in classes_list
do
651 tpl
.classes
.add mclass
.tpl_link
654 for mproperty
in mprops_list
do
656 m
.add mproperty
.intro
.tpl_link
658 m
.add mproperty
.intro
.mclassdef
.mclass
.tpl_link
662 section
.add_child tpl
663 tpl_page
.add_section section
666 # Extract mmodule list to display (sorted by name)
667 private fun modules_list
: Array[MModule] do
668 var sorted
= new Array[MModule]
669 for mmodule
in model
.mmodule_importation_hierarchy
do
670 if mmodule
.is_fictive
then continue
673 name_sorter
.sort
(sorted
)
677 # Extract mclass list to display (sorted by name)
678 private fun classes_list
: Array[MClass] do
679 var sorted
= new Array[MClass]
680 for mclass
in model
.mclasses
do
681 if not ctx
.filter_mclass
(mclass
) then continue
684 name_sorter
.sort
(sorted
)
688 # Extract mproperty list to display (sorted by name)
689 private fun mprops_list
: Array[MProperty] do
690 var sorted
= new Array[MProperty]
691 for mproperty
in model
.mproperties
do
692 if ctx
.filter_mproperty
(mproperty
) then sorted
.add mproperty
694 name_sorter
.sort
(sorted
)
700 # Display a flattened view of the group
704 private var mgroup
: MGroup
706 private var concerns
: ConcernsTree is noinit
707 private var intros
: Set[MClass] is noinit
708 private var redefs
: Set[MClass] is noinit
711 self.concerns
= model
.concerns_tree
(mgroup
.collect_mmodules
)
712 self.concerns
.sort_with
(new MConcernRankSorter)
713 self.intros
= mgroup
.in_nesting_intro_mclasses
(ctx
.min_visibility
)
714 var redefs
= new HashSet[MClass]
715 for rdef
in mgroup
.in_nesting_redef_mclasses
(ctx
.min_visibility
) do
716 if intros
.has
(rdef
) then continue
722 private var page
= new TplPage
723 redef fun tpl_page
do return page
725 private var sidebar
= new TplSidebar
726 redef fun tpl_sidebar
do return sidebar
728 redef fun tpl_title
do return mgroup
.nitdoc_name
730 redef fun page_url
do return mgroup
.nitdoc_url
732 redef fun tpl_topmenu
do
734 var mproject
= mgroup
.mproject
735 if not mgroup
.is_root
then
736 topmenu
.add_link
new TplLink(mproject
.nitdoc_url
, mproject
.nitdoc_name
)
738 topmenu
.add_link
new TplLink(page_url
, mproject
.nitdoc_name
)
742 # Class list to display in sidebar
743 fun tpl_sidebar_mclasses
do
744 var mclasses
= new HashSet[MClass]
745 mclasses
.add_all intros
746 mclasses
.add_all redefs
747 if mclasses
.is_empty
then return
748 var list
= new TplList.with_classes
(["list-unstyled", "list-labeled"])
750 var sorted
= mclasses
.to_a
751 name_sorter
.sort
(sorted
)
752 for mclass
in sorted
do
753 list
.add_li tpl_sidebar_item
(mclass
)
755 tpl_sidebar
.boxes
.add
new TplSideBox.with_content
("All classes", list
)
758 private fun tpl_sidebar_item
(def
: MClass): TplListItem do
759 var classes
= def
.intro
.tpl_css_classes
.to_a
760 if intros
.has
(def
) then
765 var lnk
= new Template
766 lnk
.add
new TplLabel.with_classes
(classes
)
768 return new TplListItem.with_content
(lnk
)
772 private fun tpl_intro
: TplSection do
773 var section
= new TplSection.with_title
("top", tpl_title
)
774 var article
= new TplArticle("intro")
776 if mgroup
.is_root
then
777 section
.subtitle
= mgroup
.mproject
.tpl_declaration
778 article
.content
= mgroup
.mproject
.tpl_definition
780 section
.subtitle
= mgroup
.tpl_declaration
781 article
.content
= mgroup
.tpl_definition
783 section
.add_child article
787 private fun tpl_concerns
(section
: TplSection) do
788 if concerns
.is_empty
then return
789 section
.add_child
new TplArticle.with_content
("concerns", "Concerns", concerns
.to_tpl
)
792 private fun tpl_groups
(parent
: TplSection) do
793 var lst
= concerns
.to_a
795 for mentity
in lst
do
796 if mentity
isa MProject then
797 section
.add_child
new TplSection(mentity
.nitdoc_id
)
798 else if mentity
isa MGroup then
799 section
.add_child
new TplSection(mentity
.nitdoc_id
)
800 else if mentity
isa MModule then
801 section
.add_child tpl_mmodule_article
(mentity
)
806 redef fun tpl_content
do
811 tpl_page
.add_section top
814 private fun sort_by_mclass
(mclassdefs
: Collection[MClassDef]): Map[MClass, Set[MClassDef]] do
815 var map
= new HashMap[MClass, Set[MClassDef]]
816 for mclassdef
in mclassdefs
do
817 var mclass
= mclassdef
.mclass
818 if not map
.has_key
(mclass
) then map
[mclass
] = new HashSet[MClassDef]
819 map
[mclass
].add mclassdef
826 # Display the list of introduced and redefined classes in module
830 private var mmodule
: MModule
831 private var concerns
: ConcernsTree is noinit
832 private var mclasses2mdefs
: Map[MClass, Set[MClassDef]] is noinit
833 private var mmodules2mclasses
: Map[MModule, Set[MClass]] is noinit
837 var mclassdefs
= new HashSet[MClassDef]
838 mclassdefs
.add_all mmodule
.intro_mclassdefs
(ctx
.min_visibility
)
839 mclassdefs
.add_all mmodule
.redef_mclassdefs
(ctx
.min_visibility
)
840 self.mclasses2mdefs
= sort_by_mclass
(mclassdefs
)
841 self.mmodules2mclasses
= group_by_mmodule
(mclasses2mdefs
.keys
)
842 self.concerns
= model
.concerns_tree
(mmodules2mclasses
.keys
)
844 mmodule
.mgroup
.mproject
.booster_rank
= -1000
845 mmodule
.mgroup
.booster_rank
= -1000
846 mmodule
.booster_rank
= -1000
847 self.concerns
.sort_with
(new MConcernRankSorter)
848 mmodule
.mgroup
.mproject
.booster_rank
= 0
849 mmodule
.mgroup
.booster_rank
= 0
850 mmodule
.booster_rank
= 0
853 private var page
= new TplPage
854 redef fun tpl_page
do return page
856 private var sidebar
= new TplSidebar
857 redef fun tpl_sidebar
do return sidebar
859 redef fun tpl_title
do return mmodule
.nitdoc_name
860 redef fun page_url
do return mmodule
.nitdoc_url
862 redef fun tpl_topmenu
do
864 var mproject
= mmodule
.mgroup
.mproject
865 topmenu
.add_link
new TplLink(mproject
.nitdoc_url
, mproject
.nitdoc_name
)
866 topmenu
.add_link
new TplLink(page_url
, mmodule
.nitdoc_name
)
870 # Class list to display in sidebar
871 fun tpl_sidebar_mclasses
do
872 var mclasses
= new HashSet[MClass]
873 mclasses
.add_all mmodule
.filter_intro_mclasses
(ctx
.min_visibility
)
874 mclasses
.add_all mmodule
.filter_redef_mclasses
(ctx
.min_visibility
)
875 if mclasses
.is_empty
then return
876 var list
= new TplList.with_classes
(["list-unstyled", "list-labeled"])
878 var sorted
= mclasses
.to_a
879 name_sorter
.sort
(sorted
)
880 for mclass
in sorted
do
881 list
.add_li tpl_sidebar_item
(mclass
)
883 tpl_sidebar
.boxes
.add
new TplSideBox.with_content
("All classes", list
)
886 private fun tpl_sidebar_item
(def
: MClass): TplListItem do
887 var classes
= def
.intro
.tpl_css_classes
.to_a
888 if def
.intro_mmodule
== mmodule
then
893 var lnk
= new Template
894 lnk
.add
new TplLabel.with_classes
(classes
)
896 return new TplListItem.with_content
(lnk
)
900 private fun tpl_intro
: TplSection do
901 var section
= new TplSection.with_title
("top", tpl_title
)
902 section
.subtitle
= mmodule
.tpl_declaration
904 var article
= new TplArticle("intro")
905 var def
= mmodule
.tpl_definition
906 var location
= mmodule
.location
907 article
.source_link
= tpl_showsource
(location
)
908 article
.content
= def
909 section
.add_child article
913 # inheritance section
914 private fun tpl_inheritance
(parent
: TplSection) do
915 # Extract relevent modules
916 var imports
= mmodule
.in_importation
.greaters
917 if imports
.length
> 10 then imports
= mmodule
.in_importation
.direct_greaters
918 var clients
= mmodule
.in_importation
.smallers
919 if clients
.length
> 10 then clients
= mmodule
.in_importation
.direct_smallers
922 var section
= new TplSection.with_title
("dependencies", "Dependencies")
925 var mmodules
= new HashSet[MModule]
926 mmodules
.add_all mmodule
.nested_mmodules
927 mmodules
.add_all imports
928 if clients
.length
< 10 then mmodules
.add_all clients
930 var graph
= tpl_dot
(mmodules
)
931 if graph
!= null then section
.add_child graph
934 var lst
= new Array[MModule]
935 for dep
in imports
do
936 if dep
.is_fictive
then continue
937 if dep
== mmodule
then continue
940 if not lst
.is_empty
then
942 section
.add_child tpl_list
("imports", "Imports", lst
)
946 lst
= new Array[MModule]
947 for dep
in clients
do
948 if dep
.is_fictive
then continue
949 if dep
== mmodule
then continue
952 if not lst
.is_empty
then
954 section
.add_child tpl_list
("clients", "Clients", lst
)
957 parent
.add_child section
960 private fun tpl_list
(id
: String, title
: String, mmodules
: Array[MModule]): TplArticle do
961 var article
= new TplArticle.with_title
(id
, title
)
962 var list
= new TplList.with_classes
(["list-unstyled", "list-definition"])
963 for mmodule
in mmodules
do list
.elts
.add mmodule
.tpl_list_item
964 article
.content
= list
968 private fun tpl_concerns
(parent
: TplSection) do
969 if concerns
.is_empty
then return
970 parent
.add_child
new TplArticle.with_content
("concerns", "Concerns", concerns
.to_tpl
)
973 private fun tpl_mclasses
(parent
: TplSection) do
974 for mentity
in concerns
do
975 if mentity
isa MProject then
976 parent
.add_child
new TplSection(mentity
.nitdoc_id
)
977 else if mentity
isa MGroup then
978 parent
.add_child
new TplSection(mentity
.nitdoc_id
)
979 else if mentity
isa MModule then
980 var section
= new TplSection(mentity
.nitdoc_id
)
981 var title
= new Template
982 if mentity
== mmodule
then
984 section
.summary_title
= "in {mentity.nitdoc_name}"
987 section
.summary_title
= "from {mentity.nitdoc_name}"
989 title
.add mentity
.tpl_namespace
990 section
.title
= title
992 var mclasses
= mmodules2mclasses
[mentity
].to_a
993 name_sorter
.sort
(mclasses
)
994 for mclass
in mclasses
do
995 section
.add_child tpl_mclass_article
(mclass
, mclasses2mdefs
[mclass
].to_a
)
997 parent
.add_child section
1002 private fun group_by_mmodule
(mclasses
: Collection[MClass]): Map[MModule, Set[MClass]] do
1003 var res
= new HashMap[MModule, Set[MClass]]
1004 for mclass
in mclasses
do
1005 var mmodule
= mclass
.intro_mmodule
1006 if not res
.has_key
(mmodule
) then
1007 res
[mmodule
] = new HashSet[MClass]
1009 res
[mmodule
].add
(mclass
)
1014 redef fun tpl_content
do
1015 tpl_sidebar_mclasses
1017 tpl_inheritance
(top
)
1020 tpl_page
.add_section top
1023 # Genrate dot hierarchy for class inheritance
1024 fun tpl_dot
(mmodules
: Collection[MModule]): nullable TplArticle do
1025 var poset
= new POSet[MModule]
1026 for mmodule
in mmodules
do
1027 if mmodule
.is_fictive
then continue
1028 poset
.add_node mmodule
1029 for omodule
in mmodules
do
1030 if mmodule
.is_fictive
then continue
1031 poset
.add_node mmodule
1032 if mmodule
.in_importation
< omodule
then
1033 poset
.add_edge
(mmodule
, omodule
)
1038 var op
= new RopeBuffer
1039 var name
= "dep_module_{mmodule.nitdoc_id}"
1040 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")
1041 for mmodule
in poset
do
1042 if mmodule
== self.mmodule
then
1043 op
.append
("\"{mmodule.name.escape_to_dot}\
"[shape=box,margin=0.03];\n")
1045 op
.append
("\"{mmodule.name.escape_to_dot}\
"[URL=\"{mmodule.nitdoc_url.escape_to_dot}\
"];\n")
1047 for omodule
in poset
[mmodule
].direct_greaters
do
1048 op
.append
("\"{mmodule.name.escape_to_dot}\
"->\"{omodule.name.escape_to_dot}\
";\n")
1052 return tpl_graph
(op
, name
, null)
1055 private fun sort_by_mclass
(mclassdefs
: Collection[MClassDef]): Map[MClass, Set[MClassDef]] do
1056 var map
= new HashMap[MClass, Set[MClassDef]]
1057 for mclassdef
in mclassdefs
do
1058 var mclass
= mclassdef
.mclass
1059 if not map
.has_key
(mclass
) then map
[mclass
] = new HashSet[MClassDef]
1060 map
[mclass
].add mclassdef
1067 # Display a list properties defined or redefined for this class
1071 private var mclass
: MClass
1072 private var concerns
: ConcernsTree is noinit
1073 private var mprops2mdefs
: Map[MProperty, Set[MPropDef]] is noinit
1074 private var mmodules2mprops
: Map[MModule, Set[MProperty]] is noinit
1077 var mpropdefs
= new HashSet[MPropDef]
1078 mpropdefs
.add_all mclass
.intro_mpropdefs
(ctx
.min_visibility
)
1079 mpropdefs
.add_all mclass
.redef_mpropdefs
(ctx
.min_visibility
)
1080 self.mprops2mdefs
= sort_by_mproperty
(mpropdefs
)
1081 self.mmodules2mprops
= sort_by_mmodule
(mprops2mdefs
.keys
)
1082 self.concerns
= model
.concerns_tree
(mmodules2mprops
.keys
)
1083 self.concerns
.sort_with
(new MConcernRankSorter)
1086 private var page
= new TplPage
1087 redef fun tpl_page
do return page
1089 private var sidebar
= new TplSidebar
1090 redef fun tpl_sidebar
do return sidebar
1092 redef fun tpl_title
do return "{mclass.nitdoc_name}{mclass.tpl_signature.write_to_string}"
1093 redef fun page_url
do return mclass
.nitdoc_url
1095 redef fun tpl_topmenu
do
1097 var mproject
= mclass
.intro_mmodule
.mgroup
.mproject
1098 topmenu
.add_link
new TplLink("{mproject.nitdoc_url}", "{mproject.nitdoc_name}")
1099 topmenu
.add_link
new TplLink(page_url
, mclass
.nitdoc_name
)
1103 # Property list to display in sidebar
1104 fun tpl_sidebar_properties
do
1105 var by_kind
= new PropertiesByKind.with_elements
(mclass_inherited_mprops
)
1106 var summary
= new TplList.with_classes
(["list-unstyled"])
1108 by_kind
.sort_groups
(name_sorter
)
1109 for g
in by_kind
.groups
do tpl_sidebar_list
(g
, summary
)
1110 tpl_sidebar
.boxes
.add
new TplSideBox.with_content
("All properties", summary
)
1113 private fun tpl_sidebar_list
(mprops
: PropertyGroup[MProperty], summary
: TplList) do
1114 if mprops
.is_empty
then return
1115 var entry
= new TplListItem.with_content
(mprops
.title
)
1116 var list
= new TplList.with_classes
(["list-unstyled", "list-labeled"])
1117 for mprop
in mprops
do
1118 list
.add_li tpl_sidebar_item
(mprop
)
1121 summary
.elts
.add entry
1124 private fun tpl_sidebar_item
(mprop
: MProperty): TplListItem do
1125 var classes
= mprop
.intro
.tpl_css_classes
.to_a
1126 if not mprops2mdefs
.has_key
(mprop
) then
1127 classes
.add
"inherit"
1128 var cls_url
= mprop
.intro
.mclassdef
.mclass
.nitdoc_url
1129 var def_url
= "{cls_url}#{mprop.nitdoc_id}"
1130 var lnk
= new TplLink(def_url
, mprop
.nitdoc_name
)
1131 var mdoc
= mprop
.intro
.mdoc_or_fallback
1132 if mdoc
!= null then lnk
.title
= mdoc
.short_comment
1133 var item
= new Template
1134 item
.add
new TplLabel.with_classes
(classes
)
1136 return new TplListItem.with_content
(item
)
1138 var defs
= mprops2mdefs
[mprop
]
1139 if defs
.has
(mprop
.intro
) then
1144 var lnk
= new Template
1145 lnk
.add
new TplLabel.with_classes
(classes
)
1146 lnk
.add mprop
.tpl_anchor
1147 return new TplListItem.with_content
(lnk
)
1150 private fun tpl_intro
: TplSection do
1151 var section
= new TplSection.with_title
("top", tpl_title
)
1152 section
.subtitle
= mclass
.intro
.tpl_declaration
1153 var article
= new TplArticle("comment")
1154 var mdoc
= mclass
.mdoc_or_fallback
1155 if mdoc
!= null then
1156 article
.content
= mdoc
.tpl_comment
1158 section
.add_child article
1162 private fun tpl_concerns
(parent
: TplSection) do
1164 var section
= new TplSection.with_title
("intro", "Introduction")
1165 section
.summary_title
= "Introduction"
1166 section
.add_child tpl_mclassdef_article
(mclass
.intro
)
1167 parent
.add_child section
1169 if concerns
.is_empty
then return
1170 parent
.add_child
new TplArticle.with_content
("concerns", "Concerns", concerns
.to_tpl
)
1173 private fun tpl_inheritance
(parent
: TplSection) do
1175 var hparents
= new HashSet[MClass]
1176 for c
in mclass
.in_hierarchy
(mainmodule
).direct_greaters
do
1177 if ctx
.filter_mclass
(c
) then hparents
.add c
1181 var hancestors
= new HashSet[MClass]
1182 for c
in mclass
.in_hierarchy
(mainmodule
).greaters
do
1183 if c
== mclass
then continue
1184 if not ctx
.filter_mclass
(c
) then continue
1185 if hparents
.has
(c
) then continue
1190 var hchildren
= new HashSet[MClass]
1191 for c
in mclass
.in_hierarchy
(mainmodule
).direct_smallers
do
1192 if ctx
.filter_mclass
(c
) then hchildren
.add c
1196 var hdescendants
= new HashSet[MClass]
1197 for c
in mclass
.in_hierarchy
(mainmodule
).smallers
do
1198 if c
== mclass
then continue
1199 if not ctx
.filter_mclass
(c
) then continue
1200 if hchildren
.has
(c
) then continue
1205 var section
= new TplSection.with_title
("inheritance", "Inheritance")
1208 var mclasses
= new HashSet[MClass]
1209 mclasses
.add_all hancestors
1210 mclasses
.add_all hparents
1211 mclasses
.add_all hchildren
1212 mclasses
.add_all hdescendants
1214 var graph
= tpl_dot
(mclasses
)
1215 if graph
!= null then section
.add_child graph
1218 if not hparents
.is_empty
then
1219 var lst
= hparents
.to_a
1220 name_sorter
.sort lst
1221 section
.add_child tpl_list
("parents", "Parents", lst
)
1225 if not hancestors
.is_empty
then
1226 var lst
= hancestors
.to_a
1227 name_sorter
.sort lst
1228 section
.add_child tpl_list
("ancestors", "Ancestors", lst
)
1232 if not hchildren
.is_empty
then
1233 var lst
= hchildren
.to_a
1234 name_sorter
.sort lst
1235 section
.add_child tpl_list
("children", "Children", lst
)
1239 if not hdescendants
.is_empty
then
1240 var lst
= hdescendants
.to_a
1241 name_sorter
.sort lst
1242 section
.add_child tpl_list
("descendants", "Descendants", lst
)
1245 parent
.add_child section
1248 private fun tpl_list
(id
: String, title
: String, elts
: Array[MClass]): TplArticle do
1249 var article
= new TplArticle.with_title
(id
, title
)
1250 if elts
.length
> 20 then
1251 var tpl
= new Template
1254 if e
!= elts
.last
then tpl
.add
", "
1256 article
.content
= tpl
1258 var list
= new TplList.with_classes
(["list-unstyled", "list-definition"])
1259 for elt
in elts
do list
.elts
.add elt
.tpl_list_item
1260 article
.content
= list
1265 private fun tpl_properties
(parent
: TplSection) do
1266 var lst
= concerns
.to_a
1267 for mentity
in lst
do
1268 if mentity
isa MProject then
1269 parent
.add_child
new TplSection(mentity
.nitdoc_id
)
1270 else if mentity
isa MGroup then
1271 parent
.add_child
new TplSection(mentity
.nitdoc_id
)
1272 else if mentity
isa MModule then
1273 var section
= new TplSection(mentity
.nitdoc_id
)
1274 var title
= new Template
1276 title
.add mentity
.tpl_namespace
1277 section
.title
= title
1278 section
.summary_title
= "in {mentity.nitdoc_name}"
1281 var mprops
= mmodules2mprops
[mentity
]
1282 var by_kind
= new PropertiesByKind.with_elements
(mprops
)
1284 for g
in by_kind
.groups
do
1285 for article
in tpl_mproperty_articles
(g
) do
1286 section
.add_child article
1289 parent
.add_child section
1294 private fun tpl_mproperty_articles
(elts
: Collection[MProperty]):
1295 Sequence[TplArticle] do
1296 var articles
= new List[TplArticle]
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 mclass_inherited_mprops
: Set[MProperty] do
1350 var res
= new HashSet[MProperty]
1351 var local
= mclass
.local_mproperties
(ctx
.min_visibility
)
1352 for mprop
in mclass
.inherited_mproperties
(mainmodule
, ctx
.min_visibility
) do
1353 if local
.has
(mprop
) then continue
1354 #if mprop isa MMethod and mprop.is_init then continue
1355 if mprop
.intro
.mclassdef
.mclass
.name
== "Object" and
1356 (mprop
.visibility
== protected_visibility
or
1357 mprop
.intro
.mclassdef
.mmodule
.name
!= "kernel") then continue
1364 private fun collect_mmodules
(mprops
: Collection[MProperty]): Set[MModule] do
1365 var res
= new HashSet[MModule]
1366 for mprop
in mprops
do
1367 if mprops2mdefs
.has_key
(mprop
) then
1368 for mpropdef
in mprops2mdefs
[mprop
] do res
.add mpropdef
.mclassdef
.mmodule
1374 # Generate dot hierarchy for classes
1375 fun tpl_dot
(mclasses
: Collection[MClass]): nullable TplArticle do
1376 var poset
= new POSet[MClass]
1378 for mclass
in mclasses
do
1379 poset
.add_node mclass
1380 for oclass
in mclasses
do
1381 if mclass
== oclass
then continue
1382 poset
.add_node oclass
1383 if mclass
.in_hierarchy
(mainmodule
) < oclass
then
1384 poset
.add_edge
(mclass
, oclass
)
1389 var op
= new RopeBuffer
1390 var name
= "dep_class_{mclass.nitdoc_id}"
1391 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")
1392 var classes
= poset
.to_a
1393 var todo
= new Array[MClass]
1394 var done
= new HashSet[MClass]
1395 mainmodule
.linearize_mclasses
(classes
)
1396 if not classes
.is_empty
then todo
.add classes
.first
1397 while not todo
.is_empty
do
1399 if done
.has
(c
) then continue
1402 op
.append
("\"{c.name.escape_to_dot}\
"[shape=box,margin=0.03];\n")
1404 op
.append
("\"{c.name.escape_to_dot}\
"[URL=\"{c.nitdoc_url.escape_to_dot}\
"];\n")
1406 var smallers
= poset
[c
].direct_smallers
1407 if smallers
.length
< 10 then
1408 for c2
in smallers
do
1409 op
.append
("\"{c2.name.escape_to_dot}\
"->\"{c.name.escape_to_dot}\
";\n")
1411 todo
.add_all smallers
1413 op
.append
("\"...\
"->\"{c.name.escape_to_dot}\
";\n")
1417 return tpl_graph
(op
, name
, null)
1421 # Groups properties by kind.
1422 private class PropertiesByKind
1423 # The virtual types.
1424 var virtual_types
= new PropertyGroup[MVirtualTypeProp]("Virtual types")
1427 var constructors
= new PropertyGroup[MMethod]("Contructors")
1430 var attributes
= new PropertyGroup[MAttribute]("Attributes")
1433 var methods
= new PropertyGroup[MMethod]("Methods")
1435 # The inner classes.
1436 var inner_classes
= new PropertyGroup[MInnerClass]("Inner classes")
1440 # Sorted in the order they are displayed to the user.
1441 var groups
: SequenceRead[PropertyGroup[MProperty]] = [
1446 inner_classes
: PropertyGroup[MProperty]]
1448 # Add each the specified property to the appropriate list.
1449 init with_elements
(properties
: Collection[MProperty]) do add_all
(properties
)
1451 # Add the specified property to the appropriate list.
1452 fun add
(property
: MProperty) do
1453 if property
isa MMethod then
1454 if property
.is_init
then
1455 constructors
.add property
1457 methods
.add property
1459 else if property
isa MVirtualTypeProp then
1460 virtual_types
.add property
1461 else if property
isa MAttribute then
1462 attributes
.add property
1463 else if property
isa MInnerClass then
1464 inner_classes
.add property
1470 # Add each the specified property to the appropriate list.
1471 fun add_all
(properties
: Collection[MProperty]) do
1472 for p
in properties
do add
(p
)
1475 # Sort each group with the specified comparator.
1476 fun sort_groups
(comparator
: Comparator) do
1477 for g
in groups
do comparator
.sort
(g
)
1481 # A Group of properties of the same kind.
1482 private class PropertyGroup[E
: MProperty]
1485 # The title of the group, as displayed to the user.
1490 class NitdocProperty
1493 private var mproperty
: MProperty
1494 private var concerns
: ConcernsTree is noinit
1495 private var mmodules2mdefs
: Map[MModule, Set[MPropDef]] is noinit
1498 self.mproperty
= mproperty
1499 self.mmodules2mdefs
= sort_by_mmodule
(collect_mpropdefs
)
1500 self.concerns
= model
.concerns_tree
(mmodules2mdefs
.keys
)
1501 self.concerns
.sort_with
(new MConcernRankSorter)
1504 private fun collect_mpropdefs
: Set[MPropDef] do
1505 var res
= new HashSet[MPropDef]
1506 for mpropdef
in mproperty
.mpropdefs
do
1507 if not mpropdef
.is_intro
then res
.add mpropdef
1512 private var page
= new TplPage
1513 redef fun tpl_page
do return page
1515 private var sidebar
= new TplSidebar
1516 redef fun tpl_sidebar
do return sidebar
1518 redef fun tpl_title
do
1519 return "{mproperty.nitdoc_name}{mproperty.tpl_signature.write_to_string}"
1522 redef fun page_url
do return mproperty
.nitdoc_url
1524 redef fun tpl_topmenu
do
1526 var mmodule
= mproperty
.intro_mclassdef
.mmodule
1527 var mproject
= mmodule
.mgroup
.mproject
1528 var mclass
= mproperty
.intro_mclassdef
.mclass
1529 topmenu
.add_link
new TplLink("{mproject.nitdoc_url}", "{mproject.nitdoc_name}")
1530 topmenu
.add_link
new TplLink("{mclass.nitdoc_url}", "{mclass.nitdoc_name}")
1531 topmenu
.add_link
new TplLink(page_url
, mproperty
.nitdoc_name
)
1535 private fun tpl_intro
: TplSection do
1536 var title
= new Template
1537 title
.add mproperty
.nitdoc_name
1538 title
.add mproperty
.intro
.tpl_signature
1539 var section
= new TplSection.with_title
("top", title
)
1540 section
.subtitle
= mproperty
.tpl_namespace
1541 section
.summary_title
= mproperty
.nitdoc_name
1545 private fun tpl_properties
(parent
: TplSection) do
1547 var ns
= mproperty
.intro
.mclassdef
.mmodule
.tpl_namespace
1548 var section
= new TplSection("intro")
1549 var title
= new Template
1550 title
.add
"Introduction in "
1552 section
.title
= title
1553 section
.summary_title
= "Introduction"
1554 section
.add_child tpl_mpropdef_article
(mproperty
.intro
)
1555 parent
.add_child section
1558 if concerns
.is_empty
then return
1559 parent
.add_child
new TplArticle.with_content
("Concerns", "Concerns", concerns
.to_tpl
)
1562 var lst
= concerns
.to_a
1563 for mentity
in lst
do
1564 if mentity
isa MProject then
1565 parent
.add_child
new TplSection(mentity
.nitdoc_id
)
1566 else if mentity
isa MGroup then
1567 parent
.add_child
new TplSection(mentity
.nitdoc_id
)
1568 else if mentity
isa MModule then
1569 var ssection
= new TplSection(mentity
.nitdoc_id
)
1570 title
= new Template
1572 title
.add mentity
.tpl_namespace
1573 ssection
.title
= title
1574 ssection
.summary_title
= "in {mentity.nitdoc_name}"
1577 var mpropdefs
= mmodules2mdefs
[mentity
].to_a
1578 name_sorter
.sort
(mpropdefs
)
1579 for mpropdef
in mpropdefs
do
1580 ssection
.add_child tpl_mpropdef_article
(mpropdef
)
1582 parent
.add_child ssection
1587 redef fun tpl_content
do
1590 tpl_page
.add_section top
1593 private fun sort_by_mmodule
(mpropdefs
: Collection[MPropDef]): Map[MModule, Set[MPropDef]] do
1594 var map
= new HashMap[MModule, Set[MPropDef]]
1595 for mpropdef
in mpropdefs
do
1596 var mmodule
= mpropdef
.mclassdef
.mmodule
1597 if not map
.has_key
(mmodule
) then map
[mmodule
] = new HashSet[MPropDef]
1598 map
[mmodule
].add mpropdef