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"
87 # Filter the entity based on the options specified by the user.
89 # Return `true` if the specified entity has to be included in the generated
91 private fun filter_mclass
(mclass
: MClass): Bool do
92 return mclass
.visibility
>= min_visibility
95 # Filter the entity based on the options specified by the user.
97 # Return `true` if the specified entity has to be included in the generated
99 private fun filter_mproperty
(mproperty
: MProperty): Bool do
100 return mproperty
.visibility
>= min_visibility
and
101 not mproperty
isa MAttribute
105 # The Nitdoc class explores the model and generate pages for each mentities found
109 var mainmodule
: MModule
122 private fun init_output_dir
do
123 # create destination dir if it's necessary
124 var output_dir
= ctx
.output_dir
125 if not output_dir
.file_exists
then output_dir
.mkdir
127 var sharedir
= ctx
.opt_sharedir
.value
128 if sharedir
== null then
129 var dir
= ctx
.nit_dir
130 sharedir
= dir
/"share/nitdoc"
131 if not sharedir
.file_exists
then
132 print
"Error: Cannot locate nitdoc share files. Uses --sharedir or envvar NIT_DIR"
137 if ctx
.opt_shareurl
.value
== null then
138 sys
.system
("cp -r -- {sharedir.to_s.escape_to_sh}/* {output_dir.to_s.escape_to_sh}/")
140 sys
.system
("cp -r -- {sharedir.to_s.escape_to_sh}/resources/ {output_dir.to_s.escape_to_sh}/resources/")
145 private fun overview
do
146 var page
= new NitdocOverview(ctx
, model
, mainmodule
)
147 page
.render
.write_to_file
("{ctx.output_dir.to_s}/{page.page_url}")
150 private fun search
do
151 var page
= new NitdocSearch(ctx
, model
, mainmodule
)
152 page
.render
.write_to_file
("{ctx.output_dir.to_s}/{page.page_url}")
155 private fun groups
do
156 for mproject
in model
.mprojects
do
157 for mgroup
in mproject
.mgroups
.to_a
do
158 var page
= new NitdocGroup(ctx
, model
, mainmodule
, mgroup
)
159 page
.render
.write_to_file
("{ctx.output_dir.to_s}/{page.page_url}")
164 private fun modules
do
165 for mmodule
in model
.mmodules
do
166 if mmodule
.is_fictive
then continue
167 var page
= new NitdocModule(ctx
, model
, mainmodule
, mmodule
)
168 page
.render
.write_to_file
("{ctx.output_dir.to_s}/{page.page_url}")
172 private fun classes
do
173 for mclass
in model
.mclasses
do
174 if not ctx
.filter_mclass
(mclass
) then continue
175 var page
= new NitdocClass(ctx
, model
, mainmodule
, mclass
)
176 page
.render
.write_to_file
("{ctx.output_dir.to_s}/{page.page_url}")
180 private fun properties
do
181 for mproperty
in model
.mproperties
do
182 if not ctx
.filter_mproperty
(mproperty
) then continue
183 if mproperty
isa MInnerClass then continue
184 var page
= new NitdocProperty(ctx
, model
, mainmodule
, mproperty
)
185 page
.render
.write_to_file
("{ctx.output_dir.to_s}/{page.page_url}")
189 private fun quicksearch_list
do
190 var quicksearch
= new QuickSearch(ctx
, model
)
191 quicksearch
.render
.write_to_file
("{ctx.output_dir.to_s}/quicksearch-list.js")
195 # Nitdoc QuickSearch list generator
197 # Create a JSON object containing links to:
201 # All entities are grouped by name to make the research easier.
204 private var table
= new QuickSearchTable
210 for mmodule
in model
.mmodules
do
211 if mmodule
.is_fictive
then continue
212 add_result_for
(mmodule
.name
, mmodule
.full_name
, mmodule
.nitdoc_url
)
214 for mclass
in model
.mclasses
do
215 if not ctx
.filter_mclass
(mclass
) then continue
216 add_result_for
(mclass
.name
, mclass
.full_name
, mclass
.nitdoc_url
)
218 for mproperty
in model
.mproperties
do
219 if not ctx
.filter_mproperty
(mproperty
) then continue
220 for mpropdef
in mproperty
.mpropdefs
do
221 var full_name
= mpropdef
.mclassdef
.mclass
.full_name
222 var cls_url
= mpropdef
.mclassdef
.mclass
.nitdoc_url
223 var def_url
= "{cls_url}#{mpropdef.mproperty.nitdoc_id}"
224 add_result_for
(mproperty
.name
, full_name
, def_url
)
229 private fun add_result_for
(query
: String, txt
: String, url
: String) do
230 table
[query
].add
new QuickSearchResult(txt
, url
)
233 fun render
: Template do
234 var tpl
= new Template
235 var buffer
= new RopeBuffer
237 buffer
.append
"var nitdocQuickSearchRawList="
238 table
.append_json buffer
244 # The result map for QuickSearch.
245 private class QuickSearchTable
246 super JsonMapRead[String, QuickSearchResultList]
247 super HashMap[String, QuickSearchResultList]
249 redef fun provide_default_value
(key
) do
250 var v
= new QuickSearchResultList
256 # A QuickSearch result list.
257 private class QuickSearchResultList
258 super JsonSequenceRead[QuickSearchResult]
259 super Array[QuickSearchResult]
262 # A QuickSearch result.
263 private class QuickSearchResult
266 # The text of the link.
269 # The destination of the link.
273 return "\{\"txt\":{txt.to_json},\"url\
":{url.to_json}\}"
278 # Define page structure and properties
279 abstract class NitdocPage
281 private var ctx
: ToolContext
282 private var model
: Model
283 private var mainmodule
: MModule
284 private var name_sorter
= new MEntityNameSorter
286 # Render the page as a html template
287 fun render
: Template do
289 if ctx
.opt_shareurl
.value
!= null then
290 shareurl
= ctx
.opt_shareurl
.value
.as(not null)
295 tpl
.title
= tpl_title
297 tpl
.shareurl
= shareurl
298 tpl
.topmenu
= tpl_topmenu
300 tpl
.footer
= ctx
.opt_custom_footer
.value
301 tpl
.body_attrs
.add
(new TagAttribute("data-bootstrap-share", shareurl
))
302 tpl
.sidebar
= tpl_sidebar
305 var tracker_url
= ctx
.opt_piwik_tracker
.value
306 var site_id
= ctx
.opt_piwik_site_id
.value
307 if tracker_url
!= null and site_id
!= null then
308 tpl
.scripts
.add
new TplPiwikScript(tracker_url
, site_id
)
314 fun page_url
: String is abstract
316 # Build page template
317 fun tpl_page
: TplPage is abstract
319 # Build page sidebar if any
320 fun tpl_sidebar
: nullable TplSidebar do return null
322 # Build page title string
323 fun tpl_title
: String do
324 if ctx
.opt_custom_title
.value
!= null then
325 return ctx
.opt_custom_title
.value
.to_s
330 # Build top menu template
331 fun tpl_topmenu
: TplTopMenu do
332 var topmenu
= new TplTopMenu(page_url
)
333 var brand
= ctx
.opt_custom_brand
.value
334 if brand
!= null then
335 var tpl
= new Template
336 tpl
.add
"<span class='navbar-brand'>"
341 topmenu
.add_link
new TplLink("index.html", "Overview")
342 topmenu
.add_link
new TplLink("search.html", "Index")
346 # Build page content template
347 fun tpl_content
is abstract
349 # Clickable graphviz image using dot format
350 # return null if no graph for this page
351 fun tpl_graph
(dot
: Buffer, name
: String, title
: nullable String): nullable TplArticle do
352 if ctx
.opt_nodot
.value
then return null
353 var output_dir
= ctx
.output_dir
354 var path
= output_dir
/ name
355 var path_sh
= path
.escape_to_sh
356 var file
= new OFStream.open
("{path}.dot")
359 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 ; \}")
360 var fmap
= new IFStream.open
("{path}.map")
361 var map
= fmap
.read_all
364 var article
= new TplArticle("graph")
366 if title
!= null then
367 article
.title
= title
368 alt
= "alt='{title.html_escape}'"
370 article
.css_classes
.add
"text-center"
371 var content
= new Template
372 var name_html
= name
.html_escape
373 content
.add
"<img src='{name_html}.png' usemap='#{name_html}' style='margin:auto' {alt}/>"
375 article
.content
= content
379 # A (source) link template for a given location
380 fun tpl_showsource
(location
: nullable Location): nullable String
382 if location
== null then return null
383 var source
= ctx
.opt_source
.value
384 if source
== null then
385 var url
= location
.file
.filename
.simplify_path
386 return "<a target='_blank' title='Show source' href=\"{url}\
">View Source</a>"
388 # THIS IS JUST UGLY ! (but there is no replace yet)
389 var x
= source
.split_with
("%f")
390 source
= x
.join
(location
.file
.filename
.simplify_path
)
391 x
= source
.split_with
("%l")
392 source
= x
.join
(location
.line_start
.to_s
)
393 x
= source
.split_with
("%L")
394 source
= x
.join
(location
.line_end
.to_s
)
395 source
= source
.simplify_path
396 return "<a target='_blank' title='Show source' href=\"{source.to_s}\
">View Source</a>"
399 # MProject description template
400 fun tpl_mproject_article
(mproject
: MProject): TplArticle do
401 var article
= mproject
.tpl_article
402 article
.subtitle
= mproject
.tpl_declaration
403 article
.content
= mproject
.tpl_definition
404 if mproject
.mdoc
!= null then
405 article
.content
= mproject
.mdoc
.tpl_short_comment
410 # MGroup description template
411 fun tpl_mgroup_article
(mgroup
: MGroup): TplArticle do
412 var article
= mgroup
.tpl_article
413 article
.subtitle
= mgroup
.tpl_declaration
414 article
.content
= mgroup
.tpl_definition
418 # MModule description template
419 fun tpl_mmodule_article
(mmodule
: MModule): TplArticle do
420 var article
= mmodule
.tpl_article
421 article
.subtitle
= mmodule
.tpl_declaration
422 article
.content
= mmodule
.tpl_definition
424 var intros
= mmodule
.intro_mclassdefs
(ctx
.min_visibility
).to_a
425 if not intros
.is_empty
then
426 mainmodule
.linearize_mclassdefs
(intros
)
427 var intros_art
= new TplArticle.with_title
("{mmodule.nitdoc_id}_intros", "Introduces")
428 var intros_lst
= new TplList.with_classes
(["list-unstyled", "list-labeled"])
429 for mclassdef
in intros
do
430 intros_lst
.add_li mclassdef
.tpl_list_item
432 if not intros_lst
.is_empty
then
433 intros_art
.content
= intros_lst
434 article
.add_child intros_art
437 var redefs
= mmodule
.redef_mclassdefs
(ctx
.min_visibility
).to_a
438 if not redefs
.is_empty
then
439 mainmodule
.linearize_mclassdefs
(redefs
)
440 var redefs_art
= new TplArticle.with_title
("{mmodule.nitdoc_id}_redefs", "Redefines")
441 var redefs_lst
= new TplList.with_classes
(["list-unstyled", "list-labeled"])
442 for mclassdef
in redefs
do
443 redefs_lst
.add_li mclassdef
.tpl_list_item
445 if not redefs_lst
.is_empty
then
446 redefs_art
.content
= redefs_lst
447 article
.add_child redefs_art
453 # MClassDef description template
454 fun tpl_mclass_article
(mclass
: MClass, mclassdefs
: Array[MClassDef]): TplArticle do
455 var article
= mclass
.tpl_article
456 if not mclassdefs
.has
(mclass
.intro
) then
458 var intro_article
= mclass
.intro
.tpl_short_article
459 intro_article
.source_link
= tpl_showsource
(mclass
.intro
.location
)
460 article
.add_child intro_article
462 mainmodule
.linearize_mclassdefs
(mclassdefs
)
463 for mclassdef
in mclassdefs
do
464 # add mclassdef full description
465 var redef_article
= mclassdef
.tpl_article
466 redef_article
.source_link
= tpl_showsource
(mclassdef
.location
)
467 article
.add_child redef_article
469 var intros
= new TplArticle.with_title
("{mclassdef.nitdoc_id}_intros", "Introduces")
470 var intros_lst
= new TplList.with_classes
(["list-unstyled", "list-labeled"])
471 for mpropdef
in mclassdef
.collect_intro_mpropdefs
(ctx
.min_visibility
) do
472 intros_lst
.add_li mpropdef
.tpl_list_item
474 if not intros_lst
.is_empty
then
475 intros
.content
= intros_lst
476 redef_article
.add_child intros
478 var redefs
= new TplArticle.with_title
("{mclassdef.nitdoc_id}_redefs", "Redefines")
479 var redefs_lst
= new TplList.with_classes
(["list-unstyled", "list-labeled"])
480 for mpropdef
in mclassdef
.collect_redef_mpropdefs
(ctx
.min_visibility
) do
481 redefs_lst
.add_li mpropdef
.tpl_list_item
483 if not redefs_lst
.is_empty
then
484 redefs
.content
= redefs_lst
485 redef_article
.add_child redefs
491 # MClassDef description template
492 fun tpl_mclassdef_article
(mclassdef
: MClassDef): TplArticle do
493 var article
= mclassdef
.tpl_article
494 if mclassdef
.is_intro
then article
.content
= null
495 article
.source_link
= tpl_showsource
(mclassdef
.location
)
499 # MProp description template
501 # `main_mpropdef`: The most important mpropdef to display
502 # `local_mpropdefs`: List of other locally defined mpropdefs to display
503 # `lin`: full linearization from local_mpropdefs to intro (displayed in redef tree)
504 fun tpl_mprop_article
(main_mpropdef
: MPropDef, local_mpropdefs
: Array[MPropDef],
505 lin
: Array[MPropDef]): TplArticle do
506 var mprop
= main_mpropdef
.mproperty
507 var article
= new TplArticle(mprop
.nitdoc_id
)
508 var title
= new Template
509 title
.add mprop
.tpl_icon
510 title
.add
"<span id='{main_mpropdef.nitdoc_id}'></span>"
511 if main_mpropdef
.is_intro
then
512 title
.add mprop
.tpl_link
513 title
.add mprop
.intro
.tpl_signature
515 var cls_url
= mprop
.intro
.mclassdef
.mclass
.nitdoc_url
516 var def_url
= "{cls_url}#{mprop.nitdoc_id}"
517 var lnk
= new TplLink.with_title
(def_url
, mprop
.name
, "Go to introduction")
521 article
.title
= title
522 article
.title_classes
.add
"signature"
523 article
.summary_title
= "{mprop.nitdoc_name}"
524 article
.subtitle
= main_mpropdef
.tpl_namespace
525 if main_mpropdef
.mdoc
!= null then
526 article
.content
= main_mpropdef
.mdoc
.tpl_comment
528 var subarticle
= new TplArticle("{main_mpropdef.nitdoc_id}_redefs")
529 # Add redef in same `MClass`
530 if local_mpropdefs
.length
> 1 then
531 for mpropdef
in local_mpropdefs
do
532 if mpropdef
== main_mpropdef
then continue
533 var redef_article
= new TplArticle("{mpropdef.nitdoc_id}")
534 var redef_title
= new Template
535 redef_title
.add
"also redef in "
536 redef_title
.add mpropdef
.tpl_namespace
537 redef_article
.title
= redef_title
538 redef_article
.title_classes
.add
"signature info"
539 redef_article
.css_classes
.add
"nospace"
540 var redef_content
= new Template
541 if mpropdef
.mdoc
!= null then
542 redef_content
.add mpropdef
.mdoc
.tpl_comment
544 redef_article
.content
= redef_content
545 subarticle
.add_child redef_article
549 if lin
.length
> 1 then
550 var lin_article
= new TplArticle("{main_mpropdef.nitdoc_id}_lin")
551 lin_article
.title
= "Inheritance"
552 var lst
= new TplList.with_classes
(["list-unstyled", "list-labeled"])
553 for mpropdef
in lin
do
554 lst
.add_li mpropdef
.tpl_inheritance_item
556 lin_article
.content
= lst
557 subarticle
.add_child lin_article
559 article
.add_child subarticle
563 # MProperty description template
564 fun tpl_mpropdef_article
(mpropdef
: MPropDef): TplArticle do
565 var article
= mpropdef
.tpl_article
566 article
.source_link
= tpl_showsource
(mpropdef
.location
)
572 # Display a list of modules contained in program
576 private var page
= new TplPage
577 redef fun tpl_page
do return page
579 private var sidebar
= new TplSidebar
580 redef fun tpl_sidebar
do return sidebar
582 redef fun tpl_title
do
583 if ctx
.opt_custom_title
.value
!= null then
584 return ctx
.opt_custom_title
.value
.to_s
590 redef fun page_url
do return "index.html"
593 private fun tpl_intro
: TplSection do
594 var section
= new TplSection.with_title
("overview", tpl_title
)
595 var article
= new TplArticle("intro")
596 if ctx
.opt_custom_intro
.value
!= null then
597 article
.content
= ctx
.opt_custom_intro
.value
.to_s
599 section
.add_child article
604 private fun tpl_projects
(section
: TplSection) do
606 var mprojects
= model
.mprojects
.to_a
607 var sorter
= new MConcernRankSorter
608 sorter
.sort mprojects
609 var ssection
= new TplSection.with_title
("projects", "Projects")
610 for mproject
in mprojects
do
611 ssection
.add_child tpl_mproject_article
(mproject
)
613 section
.add_child ssection
616 redef fun tpl_content
do
619 tpl_page
.add_section top
624 # Display a list of modules, classes and properties
628 private var page
= new TplPage
629 redef fun tpl_page
do return page
631 redef fun tpl_title
do return "Index"
633 redef fun page_url
do return "search.html"
635 redef fun tpl_content
do
636 var tpl
= new TplSearchPage("search_all")
637 var section
= new TplSection("search")
641 for mmodule
in modules_list
do
642 tpl
.modules
.add mmodule
.tpl_link
645 for mclass
in classes_list
do
646 tpl
.classes
.add mclass
.tpl_link
649 for mproperty
in mprops_list
do
651 m
.add mproperty
.intro
.tpl_link
653 m
.add mproperty
.intro
.mclassdef
.mclass
.tpl_link
657 section
.add_child tpl
658 tpl_page
.add_section section
661 # Extract mmodule list to display (sorted by name)
662 private fun modules_list
: Array[MModule] do
663 var sorted
= new Array[MModule]
664 for mmodule
in model
.mmodule_importation_hierarchy
do
665 if mmodule
.is_fictive
then continue
668 name_sorter
.sort
(sorted
)
672 # Extract mclass list to display (sorted by name)
673 private fun classes_list
: Array[MClass] do
674 var sorted
= new Array[MClass]
675 for mclass
in model
.mclasses
do
676 if not ctx
.filter_mclass
(mclass
) then continue
679 name_sorter
.sort
(sorted
)
683 # Extract mproperty list to display (sorted by name)
684 private fun mprops_list
: Array[MProperty] do
685 var sorted
= new Array[MProperty]
686 for mproperty
in model
.mproperties
do
687 if ctx
.filter_mproperty
(mproperty
) then sorted
.add mproperty
689 name_sorter
.sort
(sorted
)
695 # Display a flattened view of the group
699 private var mgroup
: MGroup
701 private var concerns
: ConcernsTree is noinit
702 private var intros
: Set[MClass] is noinit
703 private var redefs
: Set[MClass] is noinit
706 self.concerns
= model
.concerns_tree
(mgroup
.collect_mmodules
)
707 self.concerns
.sort_with
(new MConcernRankSorter)
708 self.intros
= mgroup
.in_nesting_intro_mclasses
(ctx
.min_visibility
)
709 var redefs
= new HashSet[MClass]
710 for rdef
in mgroup
.in_nesting_redef_mclasses
(ctx
.min_visibility
) do
711 if intros
.has
(rdef
) then continue
717 private var page
= new TplPage
718 redef fun tpl_page
do return page
720 private var sidebar
= new TplSidebar
721 redef fun tpl_sidebar
do return sidebar
723 redef fun tpl_title
do return mgroup
.nitdoc_name
725 redef fun page_url
do return mgroup
.nitdoc_url
727 redef fun tpl_topmenu
do
729 var mproject
= mgroup
.mproject
730 if not mgroup
.is_root
then
731 topmenu
.add_link
new TplLink(mproject
.nitdoc_url
, mproject
.nitdoc_name
)
733 topmenu
.add_link
new TplLink(page_url
, mproject
.nitdoc_name
)
737 # Class list to display in sidebar
738 fun tpl_sidebar_mclasses
do
739 var mclasses
= new HashSet[MClass]
740 mclasses
.add_all intros
741 mclasses
.add_all redefs
742 if mclasses
.is_empty
then return
743 var list
= new TplList.with_classes
(["list-unstyled", "list-labeled"])
745 var sorted
= mclasses
.to_a
746 name_sorter
.sort
(sorted
)
747 for mclass
in sorted
do
748 list
.add_li tpl_sidebar_item
(mclass
)
750 tpl_sidebar
.boxes
.add
new TplSideBox.with_content
("All classes", list
)
753 private fun tpl_sidebar_item
(def
: MClass): TplListItem do
754 var classes
= def
.intro
.tpl_css_classes
.to_a
755 if intros
.has
(def
) then
760 var lnk
= new Template
761 lnk
.add
new TplLabel.with_classes
(classes
)
763 return new TplListItem.with_content
(lnk
)
767 private fun tpl_intro
: TplSection do
768 var section
= new TplSection.with_title
("top", tpl_title
)
769 var article
= new TplArticle("intro")
771 if mgroup
.is_root
then
772 section
.subtitle
= mgroup
.mproject
.tpl_declaration
773 article
.content
= mgroup
.mproject
.tpl_definition
775 section
.subtitle
= mgroup
.tpl_declaration
776 article
.content
= mgroup
.tpl_definition
778 section
.add_child article
782 private fun tpl_concerns
(section
: TplSection) do
783 if concerns
.is_empty
then return
784 section
.add_child
new TplArticle.with_content
("concerns", "Concerns", concerns
.to_tpl
)
787 private fun tpl_groups
(parent
: TplSection) do
788 var lst
= concerns
.to_a
790 for mentity
in lst
do
791 if mentity
isa MProject then
792 section
.add_child
new TplSection(mentity
.nitdoc_id
)
793 else if mentity
isa MGroup then
794 section
.add_child
new TplSection(mentity
.nitdoc_id
)
795 else if mentity
isa MModule then
796 section
.add_child tpl_mmodule_article
(mentity
)
801 redef fun tpl_content
do
806 tpl_page
.add_section top
809 private fun sort_by_mclass
(mclassdefs
: Collection[MClassDef]): Map[MClass, Set[MClassDef]] do
810 var map
= new HashMap[MClass, Set[MClassDef]]
811 for mclassdef
in mclassdefs
do
812 var mclass
= mclassdef
.mclass
813 if not map
.has_key
(mclass
) then map
[mclass
] = new HashSet[MClassDef]
814 map
[mclass
].add mclassdef
821 # Display the list of introduced and redefined classes in module
825 private var mmodule
: MModule
826 private var concerns
: ConcernsTree is noinit
827 private var mclasses2mdefs
: Map[MClass, Set[MClassDef]] is noinit
828 private var mmodules2mclasses
: Map[MModule, Set[MClass]] is noinit
832 var mclassdefs
= new HashSet[MClassDef]
833 mclassdefs
.add_all mmodule
.intro_mclassdefs
(ctx
.min_visibility
)
834 mclassdefs
.add_all mmodule
.redef_mclassdefs
(ctx
.min_visibility
)
835 self.mclasses2mdefs
= sort_by_mclass
(mclassdefs
)
836 self.mmodules2mclasses
= group_by_mmodule
(mclasses2mdefs
.keys
)
837 self.concerns
= model
.concerns_tree
(mmodules2mclasses
.keys
)
839 mmodule
.mgroup
.mproject
.booster_rank
= -1000
840 mmodule
.mgroup
.booster_rank
= -1000
841 mmodule
.booster_rank
= -1000
842 self.concerns
.sort_with
(new MConcernRankSorter)
843 mmodule
.mgroup
.mproject
.booster_rank
= 0
844 mmodule
.mgroup
.booster_rank
= 0
845 mmodule
.booster_rank
= 0
848 private var page
= new TplPage
849 redef fun tpl_page
do return page
851 private var sidebar
= new TplSidebar
852 redef fun tpl_sidebar
do return sidebar
854 redef fun tpl_title
do return mmodule
.nitdoc_name
855 redef fun page_url
do return mmodule
.nitdoc_url
857 redef fun tpl_topmenu
do
859 var mproject
= mmodule
.mgroup
.mproject
860 topmenu
.add_link
new TplLink(mproject
.nitdoc_url
, mproject
.nitdoc_name
)
861 topmenu
.add_link
new TplLink(page_url
, mmodule
.nitdoc_name
)
865 # Class list to display in sidebar
866 fun tpl_sidebar_mclasses
do
867 var mclasses
= new HashSet[MClass]
868 mclasses
.add_all mmodule
.filter_intro_mclasses
(ctx
.min_visibility
)
869 mclasses
.add_all mmodule
.filter_redef_mclasses
(ctx
.min_visibility
)
870 if mclasses
.is_empty
then return
871 var list
= new TplList.with_classes
(["list-unstyled", "list-labeled"])
873 var sorted
= mclasses
.to_a
874 name_sorter
.sort
(sorted
)
875 for mclass
in sorted
do
876 list
.add_li tpl_sidebar_item
(mclass
)
878 tpl_sidebar
.boxes
.add
new TplSideBox.with_content
("All classes", list
)
881 private fun tpl_sidebar_item
(def
: MClass): TplListItem do
882 var classes
= def
.intro
.tpl_css_classes
.to_a
883 if def
.intro_mmodule
== mmodule
then
888 var lnk
= new Template
889 lnk
.add
new TplLabel.with_classes
(classes
)
891 return new TplListItem.with_content
(lnk
)
895 private fun tpl_intro
: TplSection do
896 var section
= new TplSection.with_title
("top", tpl_title
)
897 section
.subtitle
= mmodule
.tpl_declaration
899 var article
= new TplArticle("intro")
900 var def
= mmodule
.tpl_definition
901 var location
= mmodule
.location
902 article
.source_link
= tpl_showsource
(location
)
903 article
.content
= def
904 section
.add_child article
908 # inheritance section
909 private fun tpl_inheritance
(parent
: TplSection) do
910 # Extract relevent modules
911 var imports
= mmodule
.in_importation
.greaters
912 if imports
.length
> 10 then imports
= mmodule
.in_importation
.direct_greaters
913 var clients
= mmodule
.in_importation
.smallers
914 if clients
.length
> 10 then clients
= mmodule
.in_importation
.direct_smallers
917 var section
= new TplSection.with_title
("dependencies", "Dependencies")
920 var mmodules
= new HashSet[MModule]
921 mmodules
.add_all mmodule
.nested_mmodules
922 mmodules
.add_all imports
923 if clients
.length
< 10 then mmodules
.add_all clients
925 var graph
= tpl_dot
(mmodules
)
926 if graph
!= null then section
.add_child graph
929 var lst
= new Array[MModule]
930 for dep
in imports
do
931 if dep
.is_fictive
then continue
932 if dep
== mmodule
then continue
935 if not lst
.is_empty
then
937 section
.add_child tpl_list
("imports", "Imports", lst
)
941 lst
= new Array[MModule]
942 for dep
in clients
do
943 if dep
.is_fictive
then continue
944 if dep
== mmodule
then continue
947 if not lst
.is_empty
then
949 section
.add_child tpl_list
("clients", "Clients", lst
)
952 parent
.add_child section
955 private fun tpl_list
(id
: String, title
: String, mmodules
: Array[MModule]): TplArticle do
956 var article
= new TplArticle.with_title
(id
, title
)
957 var list
= new TplList.with_classes
(["list-unstyled", "list-definition"])
958 for mmodule
in mmodules
do list
.elts
.add mmodule
.tpl_list_item
959 article
.content
= list
963 private fun tpl_concerns
(parent
: TplSection) do
964 if concerns
.is_empty
then return
965 parent
.add_child
new TplArticle.with_content
("concerns", "Concerns", concerns
.to_tpl
)
968 private fun tpl_mclasses
(parent
: TplSection) do
969 for mentity
in concerns
do
970 if mentity
isa MProject then
971 parent
.add_child
new TplSection(mentity
.nitdoc_id
)
972 else if mentity
isa MGroup then
973 parent
.add_child
new TplSection(mentity
.nitdoc_id
)
974 else if mentity
isa MModule then
975 var section
= new TplSection(mentity
.nitdoc_id
)
976 var title
= new Template
977 if mentity
== mmodule
then
979 section
.summary_title
= "in {mentity.nitdoc_name}"
982 section
.summary_title
= "from {mentity.nitdoc_name}"
984 title
.add mentity
.tpl_namespace
985 section
.title
= title
987 var mclasses
= mmodules2mclasses
[mentity
].to_a
988 name_sorter
.sort
(mclasses
)
989 for mclass
in mclasses
do
990 section
.add_child tpl_mclass_article
(mclass
, mclasses2mdefs
[mclass
].to_a
)
992 parent
.add_child section
997 private fun group_by_mmodule
(mclasses
: Collection[MClass]): Map[MModule, Set[MClass]] do
998 var res
= new HashMap[MModule, Set[MClass]]
999 for mclass
in mclasses
do
1000 var mmodule
= mclass
.intro_mmodule
1001 if not res
.has_key
(mmodule
) then
1002 res
[mmodule
] = new HashSet[MClass]
1004 res
[mmodule
].add
(mclass
)
1009 redef fun tpl_content
do
1010 tpl_sidebar_mclasses
1012 tpl_inheritance
(top
)
1015 tpl_page
.add_section top
1018 # Genrate dot hierarchy for class inheritance
1019 fun tpl_dot
(mmodules
: Collection[MModule]): nullable TplArticle do
1020 var poset
= new POSet[MModule]
1021 for mmodule
in mmodules
do
1022 if mmodule
.is_fictive
then continue
1023 poset
.add_node mmodule
1024 for omodule
in mmodules
do
1025 if mmodule
.is_fictive
then continue
1026 poset
.add_node mmodule
1027 if mmodule
.in_importation
< omodule
then
1028 poset
.add_edge
(mmodule
, omodule
)
1033 var op
= new RopeBuffer
1034 var name
= "dep_module_{mmodule.nitdoc_id}"
1035 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")
1036 for mmodule
in poset
do
1037 if mmodule
== self.mmodule
then
1038 op
.append
("\"{mmodule.name.escape_to_dot}\
"[shape=box,margin=0.03];\n")
1040 op
.append
("\"{mmodule.name.escape_to_dot}\
"[URL=\"{mmodule.nitdoc_url.escape_to_dot}\
"];\n")
1042 for omodule
in poset
[mmodule
].direct_greaters
do
1043 op
.append
("\"{mmodule.name.escape_to_dot}\
"->\"{omodule.name.escape_to_dot}\
";\n")
1047 return tpl_graph
(op
, name
, null)
1050 private fun sort_by_mclass
(mclassdefs
: Collection[MClassDef]): Map[MClass, Set[MClassDef]] do
1051 var map
= new HashMap[MClass, Set[MClassDef]]
1052 for mclassdef
in mclassdefs
do
1053 var mclass
= mclassdef
.mclass
1054 if not map
.has_key
(mclass
) then map
[mclass
] = new HashSet[MClassDef]
1055 map
[mclass
].add mclassdef
1062 # Display a list properties defined or redefined for this class
1066 private var mclass
: MClass
1067 private var concerns
: ConcernsTree is noinit
1068 private var mprops2mdefs
: Map[MProperty, Set[MPropDef]] is noinit
1069 private var mmodules2mprops
: Map[MModule, Set[MProperty]] is noinit
1072 var mpropdefs
= new HashSet[MPropDef]
1073 mpropdefs
.add_all mclass
.intro_mpropdefs
(ctx
.min_visibility
)
1074 mpropdefs
.add_all mclass
.redef_mpropdefs
(ctx
.min_visibility
)
1075 self.mprops2mdefs
= sort_by_mproperty
(mpropdefs
)
1076 self.mmodules2mprops
= sort_by_mmodule
(mprops2mdefs
.keys
)
1077 self.concerns
= model
.concerns_tree
(mmodules2mprops
.keys
)
1078 self.concerns
.sort_with
(new MConcernRankSorter)
1081 private var page
= new TplPage
1082 redef fun tpl_page
do return page
1084 private var sidebar
= new TplSidebar
1085 redef fun tpl_sidebar
do return sidebar
1087 redef fun tpl_title
do return "{mclass.nitdoc_name}{mclass.tpl_signature.write_to_string}"
1088 redef fun page_url
do return mclass
.nitdoc_url
1090 redef fun tpl_topmenu
do
1092 var mproject
= mclass
.intro_mmodule
.mgroup
.mproject
1093 topmenu
.add_link
new TplLink("{mproject.nitdoc_url}", "{mproject.nitdoc_name}")
1094 topmenu
.add_link
new TplLink(page_url
, mclass
.nitdoc_name
)
1098 # Property list to display in sidebar
1099 fun tpl_sidebar_properties
do
1100 var by_kind
= new PropertiesByKind.with_elements
(mclass_inherited_mprops
)
1101 var summary
= new TplList.with_classes
(["list-unstyled"])
1103 by_kind
.sort_groups
(name_sorter
)
1104 for g
in by_kind
.groups
do tpl_sidebar_list
(g
, summary
)
1105 tpl_sidebar
.boxes
.add
new TplSideBox.with_content
("All properties", summary
)
1108 private fun tpl_sidebar_list
(mprops
: PropertyGroup[MProperty], summary
: TplList) do
1109 if mprops
.is_empty
then return
1110 var entry
= new TplListItem.with_content
(mprops
.title
)
1111 var list
= new TplList.with_classes
(["list-unstyled", "list-labeled"])
1112 for mprop
in mprops
do
1113 list
.add_li tpl_sidebar_item
(mprop
)
1116 summary
.elts
.add entry
1119 private fun tpl_sidebar_item
(mprop
: MProperty): TplListItem do
1120 var classes
= mprop
.intro
.tpl_css_classes
.to_a
1121 if not mprops2mdefs
.has_key
(mprop
) then
1122 classes
.add
"inherit"
1123 var cls_url
= mprop
.intro
.mclassdef
.mclass
.nitdoc_url
1124 var def_url
= "{cls_url}#{mprop.nitdoc_id}"
1125 var lnk
= new TplLink(def_url
, mprop
.name
)
1126 if mprop
.intro
.mdoc
!= null then lnk
.title
= mprop
.intro
.mdoc
.short_comment
1127 var item
= new Template
1128 item
.add
new TplLabel.with_classes
(classes
)
1130 return new TplListItem.with_content
(item
)
1132 var defs
= mprops2mdefs
[mprop
]
1133 if defs
.has
(mprop
.intro
) then
1138 var lnk
= new Template
1139 lnk
.add
new TplLabel.with_classes
(classes
)
1140 lnk
.add mprop
.tpl_anchor
1141 return new TplListItem.with_content
(lnk
)
1144 private fun tpl_intro
: TplSection do
1145 var section
= new TplSection.with_title
("top", tpl_title
)
1146 section
.subtitle
= mclass
.intro
.tpl_declaration
1147 var article
= new TplArticle("comment")
1148 if mclass
.mdoc
!= null then
1149 article
.content
= mclass
.mdoc
.tpl_comment
1151 section
.add_child article
1155 private fun tpl_concerns
(parent
: TplSection) do
1157 var section
= new TplSection.with_title
("intro", "Introduction")
1158 section
.summary_title
= "Introduction"
1159 section
.add_child tpl_mclassdef_article
(mclass
.intro
)
1160 parent
.add_child section
1162 if concerns
.is_empty
then return
1163 parent
.add_child
new TplArticle.with_content
("concerns", "Concerns", concerns
.to_tpl
)
1166 private fun tpl_inheritance
(parent
: TplSection) do
1168 var hparents
= new HashSet[MClass]
1169 for c
in mclass
.in_hierarchy
(mainmodule
).direct_greaters
do
1170 if ctx
.filter_mclass
(c
) then hparents
.add c
1174 var hancestors
= new HashSet[MClass]
1175 for c
in mclass
.in_hierarchy
(mainmodule
).greaters
do
1176 if c
== mclass
then continue
1177 if not ctx
.filter_mclass
(c
) then continue
1178 if hparents
.has
(c
) then continue
1183 var hchildren
= new HashSet[MClass]
1184 for c
in mclass
.in_hierarchy
(mainmodule
).direct_smallers
do
1185 if ctx
.filter_mclass
(c
) then hchildren
.add c
1189 var hdescendants
= new HashSet[MClass]
1190 for c
in mclass
.in_hierarchy
(mainmodule
).smallers
do
1191 if c
== mclass
then continue
1192 if not ctx
.filter_mclass
(c
) then continue
1193 if hchildren
.has
(c
) then continue
1198 var section
= new TplSection.with_title
("inheritance", "Inheritance")
1201 var mclasses
= new HashSet[MClass]
1202 mclasses
.add_all hancestors
1203 mclasses
.add_all hparents
1204 mclasses
.add_all hchildren
1205 mclasses
.add_all hdescendants
1207 var graph
= tpl_dot
(mclasses
)
1208 if graph
!= null then section
.add_child graph
1211 if not hparents
.is_empty
then
1212 var lst
= hparents
.to_a
1213 name_sorter
.sort lst
1214 section
.add_child tpl_list
("parents", "Parents", lst
)
1218 if not hancestors
.is_empty
then
1219 var lst
= hancestors
.to_a
1220 name_sorter
.sort lst
1221 section
.add_child tpl_list
("ancestors", "Ancestors", lst
)
1225 if not hchildren
.is_empty
then
1226 var lst
= hchildren
.to_a
1227 name_sorter
.sort lst
1228 section
.add_child tpl_list
("children", "Children", lst
)
1232 if not hdescendants
.is_empty
then
1233 var lst
= hdescendants
.to_a
1234 name_sorter
.sort lst
1235 section
.add_child tpl_list
("descendants", "Descendants", lst
)
1238 parent
.add_child section
1241 private fun tpl_list
(id
: String, title
: String, elts
: Array[MClass]): TplArticle do
1242 var article
= new TplArticle.with_title
(id
, title
)
1243 if elts
.length
> 20 then
1244 var tpl
= new Template
1247 if e
!= elts
.last
then tpl
.add
", "
1249 article
.content
= tpl
1251 var list
= new TplList.with_classes
(["list-unstyled", "list-definition"])
1252 for elt
in elts
do list
.elts
.add elt
.tpl_list_item
1253 article
.content
= list
1258 private fun tpl_properties
(parent
: TplSection) do
1259 var lst
= concerns
.to_a
1260 for mentity
in lst
do
1261 if mentity
isa MProject then
1262 parent
.add_child
new TplSection(mentity
.nitdoc_id
)
1263 else if mentity
isa MGroup then
1264 parent
.add_child
new TplSection(mentity
.nitdoc_id
)
1265 else if mentity
isa MModule then
1266 var section
= new TplSection(mentity
.nitdoc_id
)
1267 var title
= new Template
1269 title
.add mentity
.tpl_namespace
1270 section
.title
= title
1271 section
.summary_title
= "in {mentity.nitdoc_name}"
1274 var mprops
= mmodules2mprops
[mentity
]
1275 var by_kind
= new PropertiesByKind.with_elements
(mprops
)
1277 for g
in by_kind
.groups
do
1278 for article
in tpl_mproperty_articles
(g
) do
1279 section
.add_child article
1282 parent
.add_child section
1287 private fun tpl_mproperty_articles
(elts
: Collection[MProperty]):
1288 Sequence[TplArticle] do
1289 var articles
= new List[TplArticle]
1291 var local_defs
= mprops2mdefs
[elt
]
1292 # var all_defs = elt.mpropdefs
1293 var all_defs
= new HashSet[MPropDef]
1294 for local_def
in local_defs
do
1295 all_defs
.add local_def
1296 var mpropdef
= local_def
1297 while not mpropdef
.is_intro
do
1298 mpropdef
= mpropdef
.lookup_next_definition
(mainmodule
, mpropdef
.mclassdef
.bound_mtype
)
1299 all_defs
.add mpropdef
1302 var loc_lin
= local_defs
.to_a
1303 mainmodule
.linearize_mpropdefs
(loc_lin
)
1304 var all_lin
= all_defs
.to_a
1305 mainmodule
.linearize_mpropdefs
(all_lin
)
1306 articles
.add tpl_mprop_article
(loc_lin
.first
, loc_lin
, all_lin
)
1311 redef fun tpl_content
do
1312 tpl_sidebar_properties
1314 tpl_inheritance
(top
)
1317 tpl_page
.add_section top
1320 private fun sort_by_mproperty
(mpropdefs
: Collection[MPropDef]): Map[MProperty, Set[MPropDef]] do
1321 var map
= new HashMap[MProperty, Set[MPropDef]]
1322 for mpropdef
in mpropdefs
do
1323 var mproperty
= mpropdef
.mproperty
1324 if not map
.has_key
(mproperty
) then map
[mproperty
] = new HashSet[MPropDef]
1325 map
[mproperty
].add mpropdef
1330 private fun sort_by_mmodule
(mprops
: Collection[MProperty]): Map[MModule, Set[MProperty]] do
1331 var map
= new HashMap[MModule, Set[MProperty]]
1332 for mprop
in mprops
do
1333 var mpropdefs
= mprops2mdefs
[mprop
].to_a
1334 mainmodule
.linearize_mpropdefs
(mpropdefs
)
1335 var mmodule
= mpropdefs
.first
.mclassdef
.mmodule
1336 if not map
.has_key
(mmodule
) then map
[mmodule
] = new HashSet[MProperty]
1337 map
[mmodule
].add mprop
1342 private fun mclass_inherited_mprops
: Set[MProperty] do
1343 var res
= new HashSet[MProperty]
1344 var local
= mclass
.local_mproperties
(ctx
.min_visibility
)
1345 for mprop
in mclass
.inherited_mproperties
(mainmodule
, ctx
.min_visibility
) do
1346 if local
.has
(mprop
) then continue
1347 #if mprop isa MMethod and mprop.is_init then continue
1348 if mprop
.intro
.mclassdef
.mclass
.name
== "Object" and
1349 (mprop
.visibility
== protected_visibility
or
1350 mprop
.intro
.mclassdef
.mmodule
.name
!= "kernel") then continue
1357 private fun collect_mmodules
(mprops
: Collection[MProperty]): Set[MModule] do
1358 var res
= new HashSet[MModule]
1359 for mprop
in mprops
do
1360 if mprops2mdefs
.has_key
(mprop
) then
1361 for mpropdef
in mprops2mdefs
[mprop
] do res
.add mpropdef
.mclassdef
.mmodule
1367 # Generate dot hierarchy for classes
1368 fun tpl_dot
(mclasses
: Collection[MClass]): nullable TplArticle do
1369 var poset
= new POSet[MClass]
1371 for mclass
in mclasses
do
1372 poset
.add_node mclass
1373 for oclass
in mclasses
do
1374 if mclass
== oclass
then continue
1375 poset
.add_node oclass
1376 if mclass
.in_hierarchy
(mainmodule
) < oclass
then
1377 poset
.add_edge
(mclass
, oclass
)
1382 var op
= new RopeBuffer
1383 var name
= "dep_class_{mclass.nitdoc_id}"
1384 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")
1385 var classes
= poset
.to_a
1386 var todo
= new Array[MClass]
1387 var done
= new HashSet[MClass]
1388 mainmodule
.linearize_mclasses
(classes
)
1389 if not classes
.is_empty
then todo
.add classes
.first
1390 while not todo
.is_empty
do
1392 if done
.has
(c
) then continue
1395 op
.append
("\"{c.name.escape_to_dot}\
"[shape=box,margin=0.03];\n")
1397 op
.append
("\"{c.name.escape_to_dot}\
"[URL=\"{c.nitdoc_url.escape_to_dot}\
"];\n")
1399 var smallers
= poset
[c
].direct_smallers
1400 if smallers
.length
< 10 then
1401 for c2
in smallers
do
1402 op
.append
("\"{c2.name.escape_to_dot}\
"->\"{c.name.escape_to_dot}\
";\n")
1404 todo
.add_all smallers
1406 op
.append
("\"...\
"->\"{c.name.escape_to_dot}\
";\n")
1410 return tpl_graph
(op
, name
, null)
1414 # Groups properties by kind.
1415 private class PropertiesByKind
1416 # The virtual types.
1417 var virtual_types
= new PropertyGroup[MVirtualTypeProp]("Virtual types")
1420 var constructors
= new PropertyGroup[MMethod]("Contructors")
1423 var attributes
= new PropertyGroup[MAttribute]("Attributes")
1426 var methods
= new PropertyGroup[MMethod]("Methods")
1428 # The inner classes.
1429 var inner_classes
= new PropertyGroup[MInnerClass]("Inner classes")
1433 # Sorted in the order they are displayed to the user.
1434 var groups
: SequenceRead[PropertyGroup[MProperty]] = [
1439 inner_classes
: PropertyGroup[MProperty]]
1441 # Add each the specified property to the appropriate list.
1442 init with_elements
(properties
: Collection[MProperty]) do add_all
(properties
)
1444 # Add the specified property to the appropriate list.
1445 fun add
(property
: MProperty) do
1446 if property
isa MMethod then
1447 if property
.is_init
then
1448 constructors
.add property
1450 methods
.add property
1452 else if property
isa MVirtualTypeProp then
1453 virtual_types
.add property
1454 else if property
isa MAttribute then
1455 attributes
.add property
1456 else if property
isa MInnerClass then
1457 inner_classes
.add property
1463 # Add each the specified property to the appropriate list.
1464 fun add_all
(properties
: Collection[MProperty]) do
1465 for p
in properties
do add
(p
)
1468 # Sort each group with the specified comparator.
1469 fun sort_groups
(comparator
: Comparator) do
1470 for g
in groups
do comparator
.sort
(g
)
1474 # A Group of properties of the same kind.
1475 private class PropertyGroup[E
: MProperty]
1478 # The title of the group, as displayed to the user.
1483 class NitdocProperty
1486 private var mproperty
: MProperty
1487 private var concerns
: ConcernsTree is noinit
1488 private var mmodules2mdefs
: Map[MModule, Set[MPropDef]] is noinit
1491 self.mproperty
= mproperty
1492 self.mmodules2mdefs
= sort_by_mmodule
(collect_mpropdefs
)
1493 self.concerns
= model
.concerns_tree
(mmodules2mdefs
.keys
)
1494 self.concerns
.sort_with
(new MConcernRankSorter)
1497 private fun collect_mpropdefs
: Set[MPropDef] do
1498 var res
= new HashSet[MPropDef]
1499 for mpropdef
in mproperty
.mpropdefs
do
1500 if not mpropdef
.is_intro
then res
.add mpropdef
1505 private var page
= new TplPage
1506 redef fun tpl_page
do return page
1508 private var sidebar
= new TplSidebar
1509 redef fun tpl_sidebar
do return sidebar
1511 redef fun tpl_title
do
1512 return "{mproperty.nitdoc_name}{mproperty.tpl_signature.write_to_string}"
1515 redef fun page_url
do return mproperty
.nitdoc_url
1517 redef fun tpl_topmenu
do
1519 var mmodule
= mproperty
.intro_mclassdef
.mmodule
1520 var mproject
= mmodule
.mgroup
.mproject
1521 var mclass
= mproperty
.intro_mclassdef
.mclass
1522 topmenu
.add_link
new TplLink("{mproject.nitdoc_url}", "{mproject.nitdoc_name}")
1523 topmenu
.add_link
new TplLink("{mclass.nitdoc_url}", "{mclass.nitdoc_name}")
1524 topmenu
.add_link
new TplLink(page_url
, mproperty
.nitdoc_name
)
1528 private fun tpl_intro
: TplSection do
1529 var title
= new Template
1530 title
.add mproperty
.nitdoc_name
1531 title
.add mproperty
.intro
.tpl_signature
1532 var section
= new TplSection.with_title
("top", title
)
1533 section
.subtitle
= mproperty
.tpl_namespace
1534 section
.summary_title
= mproperty
.nitdoc_name
1538 private fun tpl_properties
(parent
: TplSection) do
1540 var ns
= mproperty
.intro
.mclassdef
.mmodule
.tpl_namespace
1541 var section
= new TplSection("intro")
1542 var title
= new Template
1543 title
.add
"Introduction in "
1545 section
.title
= title
1546 section
.summary_title
= "Introduction"
1547 section
.add_child tpl_mpropdef_article
(mproperty
.intro
)
1548 parent
.add_child section
1551 if concerns
.is_empty
then return
1552 parent
.add_child
new TplArticle.with_content
("Concerns", "Concerns", concerns
.to_tpl
)
1555 var lst
= concerns
.to_a
1556 for mentity
in lst
do
1557 if mentity
isa MProject then
1558 parent
.add_child
new TplSection(mentity
.nitdoc_id
)
1559 else if mentity
isa MGroup then
1560 parent
.add_child
new TplSection(mentity
.nitdoc_id
)
1561 else if mentity
isa MModule then
1562 var ssection
= new TplSection(mentity
.nitdoc_id
)
1563 title
= new Template
1565 title
.add mentity
.tpl_namespace
1566 ssection
.title
= title
1567 ssection
.summary_title
= "in {mentity.nitdoc_name}"
1570 var mpropdefs
= mmodules2mdefs
[mentity
].to_a
1571 name_sorter
.sort
(mpropdefs
)
1572 for mpropdef
in mpropdefs
do
1573 ssection
.add_child tpl_mpropdef_article
(mpropdef
)
1575 parent
.add_child ssection
1580 redef fun tpl_content
do
1583 tpl_page
.add_section top
1586 private fun sort_by_mmodule
(mpropdefs
: Collection[MPropDef]): Map[MModule, Set[MPropDef]] do
1587 var map
= new HashMap[MModule, Set[MPropDef]]
1588 for mpropdef
in mpropdefs
do
1589 var mmodule
= mpropdef
.mclassdef
.mmodule
1590 if not map
.has_key
(mmodule
) then map
[mmodule
] = new HashSet[MPropDef]
1591 map
[mmodule
].add mpropdef