1 # This file is part of NIT ( http://www.nitlanguage.org ).
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
7 # http://www.apache.org/licenses/LICENSE-2.0
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
15 # Nitdoc page generation
20 private import json
::static
22 redef class ToolContext
23 private var opt_dir
= new OptionString("output directory", "-d", "--dir")
24 private var opt_source
= new OptionString("link for source (%f for filename, %l for first line, %L for last line)", "--source")
25 private var opt_sharedir
= new OptionString("directory containing nitdoc assets", "--sharedir")
26 private var opt_shareurl
= new OptionString("use shareurl instead of copy shared files", "--shareurl")
27 private var opt_nodot
= new OptionBool("do not generate graphes with graphviz", "--no-dot")
28 private var opt_private
= new OptionBool("also generate private API", "--private")
30 private var opt_custom_title
= new OptionString("custom title for homepage", "--custom-title")
31 private var opt_custom_brand
= new OptionString("custom link to external site", "--custom-brand")
32 private var opt_custom_intro
= new OptionString("custom intro text for homepage", "--custom-overview-text")
33 private var opt_custom_footer
= new OptionString("custom footer text", "--custom-footer-text")
35 private var opt_github_upstream
= new OptionString("Git branch where edited commits will be pulled into (ex: user:repo:branch)", "--github-upstream")
36 private var opt_github_base_sha1
= new OptionString("Git sha1 of base commit used to create pull request", "--github-base-sha1")
37 private var opt_github_gitdir
= new OptionString("Git working directory used to resolve path name (ex: /home/me/myproject/)", "--github-gitdir")
39 private var opt_piwik_tracker
= new OptionString("Piwik tracker URL (ex: nitlanguage.org/piwik/)", "--piwik-tracker")
40 private var opt_piwik_site_id
= new OptionString("Piwik site ID", "--piwik-site-id")
42 private var output_dir
: String
43 private var min_visibility
: MVisibility
48 var opts
= option_context
49 opts
.add_option
(opt_dir
, opt_source
, opt_sharedir
, opt_shareurl
, opt_nodot
, opt_private
)
50 opts
.add_option
(opt_custom_title
, opt_custom_footer
, opt_custom_intro
, opt_custom_brand
)
51 opts
.add_option
(opt_github_upstream
, opt_github_base_sha1
, opt_github_gitdir
)
52 opts
.add_option
(opt_piwik_tracker
, opt_piwik_site_id
)
54 var tpl
= new Template
55 tpl
.add
"Usage: nitdoc [OPTION]... <file.nit>...\n"
56 tpl
.add
"Generates HTML pages of API documentation from Nit source files."
57 tooldescription
= tpl
.write_to_string
60 redef fun process_options
(args
) do
64 var output_dir
= opt_dir
.value
65 if output_dir
== null then
68 self.output_dir
= output_dir
70 if opt_private
.value
then
71 min_visibility
= none_visibility
73 min_visibility
= protected_visibility
76 var gh_upstream
= opt_github_upstream
.value
77 var gh_base_sha
= opt_github_base_sha1
.value
78 var gh_gitdir
= opt_github_gitdir
.value
79 if not gh_upstream
== null or not gh_base_sha
== null or not gh_gitdir
== null then
80 if gh_upstream
== null or gh_base_sha
== null or gh_gitdir
== null then
81 print
"Error: Options {opt_github_upstream.names.first}, {opt_github_base_sha1.names.first} and {opt_github_gitdir.names.first} are required to enable the GitHub plugin"
88 # The Nitdoc class explores the model and generate pages for each mentities found
92 var mainmodule
: MModule
105 private fun init_output_dir
do
106 # create destination dir if it's necessary
107 var output_dir
= ctx
.output_dir
108 if not output_dir
.file_exists
then output_dir
.mkdir
110 var sharedir
= ctx
.opt_sharedir
.value
111 if sharedir
== null then
112 var dir
= ctx
.nit_dir
113 sharedir
= dir
/"share/nitdoc"
114 if not sharedir
.file_exists
then
115 print
"Error: Cannot locate nitdoc share files. Uses --sharedir or envvar NIT_DIR"
120 if ctx
.opt_shareurl
.value
== null then
121 sys
.system
("cp -r -- {sharedir.to_s.escape_to_sh}/* {output_dir.to_s.escape_to_sh}/")
123 sys
.system
("cp -r -- {sharedir.to_s.escape_to_sh}/resources/ {output_dir.to_s.escape_to_sh}/resources/")
128 private fun overview
do
129 var page
= new NitdocOverview(ctx
, model
, mainmodule
)
130 page
.render
.write_to_file
("{ctx.output_dir.to_s}/{page.page_url}")
133 private fun search
do
134 var page
= new NitdocSearch(ctx
, model
, mainmodule
)
135 page
.render
.write_to_file
("{ctx.output_dir.to_s}/{page.page_url}")
138 private fun groups
do
139 for mproject
in model
.mprojects
do
140 for mgroup
in mproject
.mgroups
.to_a
do
141 var page
= new NitdocGroup(ctx
, model
, mainmodule
, mgroup
)
142 page
.render
.write_to_file
("{ctx.output_dir.to_s}/{page.page_url}")
147 private fun modules
do
148 for mmodule
in model
.mmodules
do
149 if mmodule
.is_fictive
then continue
150 var page
= new NitdocModule(ctx
, model
, mainmodule
, mmodule
)
151 page
.render
.write_to_file
("{ctx.output_dir.to_s}/{page.page_url}")
155 private fun classes
do
156 for mclass
in model
.mclasses
do
157 if mclass
.visibility
<= ctx
.min_visibility
then continue
158 var page
= new NitdocClass(ctx
, model
, mainmodule
, mclass
)
159 page
.render
.write_to_file
("{ctx.output_dir.to_s}/{page.page_url}")
163 private fun properties
do
164 for mproperty
in model
.mproperties
do
165 if mproperty
.visibility
<= ctx
.min_visibility
then continue
166 var page
= new NitdocProperty(ctx
, model
, mainmodule
, mproperty
)
167 page
.render
.write_to_file
("{ctx.output_dir.to_s}/{page.page_url}")
171 private fun quicksearch_list
do
172 var quicksearch
= new QuickSearch(ctx
, model
)
173 quicksearch
.render
.write_to_file
("{ctx.output_dir.to_s}/quicksearch-list.js")
177 # Nitdoc QuickSearch list generator
179 # Create a JSON object containing links to:
183 # All entities are grouped by name to make the research easier.
186 private var table
= new QuickSearchTable
192 for mmodule
in model
.mmodules
do
193 if mmodule
.is_fictive
then continue
194 add_result_for
(mmodule
.name
, mmodule
.full_name
, mmodule
.nitdoc_url
)
196 for mclass
in model
.mclasses
do
197 if mclass
.visibility
< ctx
.min_visibility
then continue
198 add_result_for
(mclass
.name
, mclass
.full_name
, mclass
.nitdoc_url
)
200 for mproperty
in model
.mproperties
do
201 if mproperty
.visibility
< ctx
.min_visibility
then continue
202 if mproperty
isa MAttribute then continue
203 for mpropdef
in mproperty
.mpropdefs
do
204 var full_name
= mpropdef
.mclassdef
.mclass
.full_name
205 var cls_url
= mpropdef
.mclassdef
.mclass
.nitdoc_url
206 var def_url
= "{cls_url}#{mpropdef.mproperty.nitdoc_id}"
207 add_result_for
(mproperty
.name
, full_name
, def_url
)
212 private fun add_result_for
(query
: String, txt
: String, url
: String) do
213 table
[query
].add
new QuickSearchResult(txt
, url
)
216 fun render
: Template do
217 var tpl
= new Template
218 var buffer
= new RopeBuffer
220 buffer
.append
"var nitdocQuickSearchRawList="
221 table
.append_json buffer
227 # The result map for QuickSearch.
228 private class QuickSearchTable
229 super JsonMapRead[String, QuickSearchResultList]
230 super HashMap[String, QuickSearchResultList]
232 redef fun provide_default_value
(key
) do
233 var v
= new QuickSearchResultList
239 # A QuickSearch result list.
240 private class QuickSearchResultList
241 super JsonSequenceRead[QuickSearchResult]
242 super Array[QuickSearchResult]
245 # A QuickSearch result.
246 private class QuickSearchResult
249 # The text of the link.
252 # The destination of the link.
256 return "\{\"txt\":{txt.to_json},\"url\
":{url.to_json}\}"
261 # Define page structure and properties
262 abstract class NitdocPage
264 private var ctx
: ToolContext
265 private var model
: Model
266 private var mainmodule
: MModule
267 private var name_sorter
= new MEntityNameSorter
269 # Render the page as a html template
270 fun render
: Template do
272 if ctx
.opt_shareurl
.value
!= null then
273 shareurl
= ctx
.opt_shareurl
.value
.as(not null)
278 tpl
.title
= tpl_title
280 tpl
.shareurl
= shareurl
281 tpl
.topmenu
= tpl_topmenu
283 tpl
.footer
= ctx
.opt_custom_footer
.value
284 tpl
.body_attrs
.add
(new TagAttribute("data-bootstrap-share", shareurl
))
285 tpl
.sidebar
= tpl_sidebar
288 var tracker_url
= ctx
.opt_piwik_tracker
.value
289 var site_id
= ctx
.opt_piwik_site_id
.value
290 if tracker_url
!= null and site_id
!= null then
291 tpl
.scripts
.add
new TplPiwikScript(tracker_url
, site_id
)
297 fun page_url
: String is abstract
299 # Build page template
300 fun tpl_page
: TplPage is abstract
302 # Build page sidebar if any
303 fun tpl_sidebar
: nullable TplSidebar do return null
305 # Build page title string
306 fun tpl_title
: String do
307 if ctx
.opt_custom_title
.value
!= null then
308 return ctx
.opt_custom_title
.value
.to_s
313 # Build top menu template
314 fun tpl_topmenu
: TplTopMenu do
315 var topmenu
= new TplTopMenu(page_url
)
316 var brand
= ctx
.opt_custom_brand
.value
317 if brand
!= null then
318 var tpl
= new Template
319 tpl
.add
"<span class='navbar-brand'>"
324 topmenu
.add_link
new TplLink("index.html", "Overview")
325 topmenu
.add_link
new TplLink("search.html", "Index")
329 # Build page content template
330 fun tpl_content
is abstract
332 # Clickable graphviz image using dot format
333 # return null if no graph for this page
334 fun tpl_graph
(dot
: Buffer, name
: String, title
: nullable String): nullable TplArticle do
335 if ctx
.opt_nodot
.value
then return null
336 var output_dir
= ctx
.output_dir
337 var path
= output_dir
/ name
338 var path_sh
= path
.escape_to_sh
339 var file
= new OFStream.open
("{path}.dot")
342 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 ; \}")
343 var fmap
= new IFStream.open
("{path}.map")
344 var map
= fmap
.read_all
347 var article
= new TplArticle("graph")
349 if title
!= null then
350 article
.title
= title
351 alt
= "alt='{title.html_escape}'"
353 article
.css_classes
.add
"text-center"
354 var content
= new Template
355 var name_html
= name
.html_escape
356 content
.add
"<img src='{name_html}.png' usemap='#{name_html}' style='margin:auto' {alt}/>"
358 article
.content
= content
362 # A (source) link template for a given location
363 fun tpl_showsource
(location
: nullable Location): nullable String
365 if location
== null then return null
366 var source
= ctx
.opt_source
.value
367 if source
== null then
368 var url
= location
.file
.filename
.simplify_path
369 return "<a target='_blank' title='Show source' href=\"{url}\
">View Source</a>"
371 # THIS IS JUST UGLY ! (but there is no replace yet)
372 var x
= source
.split_with
("%f")
373 source
= x
.join
(location
.file
.filename
.simplify_path
)
374 x
= source
.split_with
("%l")
375 source
= x
.join
(location
.line_start
.to_s
)
376 x
= source
.split_with
("%L")
377 source
= x
.join
(location
.line_end
.to_s
)
378 source
= source
.simplify_path
379 return "<a target='_blank' title='Show source' href=\"{source.to_s}\
">View Source</a>"
382 # MProject description template
383 fun tpl_mproject_article
(mproject
: MProject): TplArticle do
384 var article
= mproject
.tpl_article
385 article
.subtitle
= mproject
.tpl_declaration
386 article
.content
= mproject
.tpl_definition
387 if mproject
.mdoc
!= null then
388 article
.content
= mproject
.mdoc
.tpl_short_comment
393 # MGroup description template
394 fun tpl_mgroup_article
(mgroup
: MGroup): TplArticle do
395 var article
= mgroup
.tpl_article
396 article
.subtitle
= mgroup
.tpl_declaration
397 article
.content
= mgroup
.tpl_definition
401 # MModule description template
402 fun tpl_mmodule_article
(mmodule
: MModule): TplArticle do
403 var article
= mmodule
.tpl_article
404 article
.subtitle
= mmodule
.tpl_declaration
405 article
.content
= mmodule
.tpl_definition
407 var intros
= mmodule
.intro_mclassdefs
(ctx
.min_visibility
).to_a
408 if not intros
.is_empty
then
409 mainmodule
.linearize_mclassdefs
(intros
)
410 var intros_art
= new TplArticle.with_title
("{mmodule.nitdoc_id}_intros", "Introduces")
411 var intros_lst
= new TplList.with_classes
(["list-unstyled", "list-labeled"])
412 for mclassdef
in intros
do
413 intros_lst
.add_li mclassdef
.tpl_list_item
415 if not intros_lst
.is_empty
then
416 intros_art
.content
= intros_lst
417 article
.add_child intros_art
420 var redefs
= mmodule
.redef_mclassdefs
(ctx
.min_visibility
).to_a
421 if not redefs
.is_empty
then
422 mainmodule
.linearize_mclassdefs
(redefs
)
423 var redefs_art
= new TplArticle.with_title
("{mmodule.nitdoc_id}_redefs", "Redefines")
424 var redefs_lst
= new TplList.with_classes
(["list-unstyled", "list-labeled"])
425 for mclassdef
in redefs
do
426 redefs_lst
.add_li mclassdef
.tpl_list_item
428 if not redefs_lst
.is_empty
then
429 redefs_art
.content
= redefs_lst
430 article
.add_child redefs_art
436 # MClassDef description template
437 fun tpl_mclass_article
(mclass
: MClass, mclassdefs
: Array[MClassDef]): TplArticle do
438 var article
= mclass
.tpl_article
439 if not mclassdefs
.has
(mclass
.intro
) then
441 var intro_article
= mclass
.intro
.tpl_short_article
442 intro_article
.source_link
= tpl_showsource
(mclass
.intro
.location
)
443 article
.add_child intro_article
445 mainmodule
.linearize_mclassdefs
(mclassdefs
)
446 for mclassdef
in mclassdefs
do
447 # add mclassdef full description
448 var redef_article
= mclassdef
.tpl_article
449 redef_article
.source_link
= tpl_showsource
(mclassdef
.location
)
450 article
.add_child redef_article
452 var intros
= new TplArticle.with_title
("{mclassdef.nitdoc_id}_intros", "Introduces")
453 var intros_lst
= new TplList.with_classes
(["list-unstyled", "list-labeled"])
454 for mpropdef
in mclassdef
.collect_intro_mpropdefs
(ctx
.min_visibility
) do
455 intros_lst
.add_li mpropdef
.tpl_list_item
457 if not intros_lst
.is_empty
then
458 intros
.content
= intros_lst
459 redef_article
.add_child intros
461 var redefs
= new TplArticle.with_title
("{mclassdef.nitdoc_id}_redefs", "Redefines")
462 var redefs_lst
= new TplList.with_classes
(["list-unstyled", "list-labeled"])
463 for mpropdef
in mclassdef
.collect_redef_mpropdefs
(ctx
.min_visibility
) do
464 redefs_lst
.add_li mpropdef
.tpl_list_item
466 if not redefs_lst
.is_empty
then
467 redefs
.content
= redefs_lst
468 redef_article
.add_child redefs
474 # MClassDef description template
475 fun tpl_mclassdef_article
(mclassdef
: MClassDef): TplArticle do
476 var article
= mclassdef
.tpl_article
477 if mclassdef
.is_intro
then article
.content
= null
478 article
.source_link
= tpl_showsource
(mclassdef
.location
)
482 # MProp description template
484 # `main_mpropdef`: The most important mpropdef to display
485 # `local_mpropdefs`: List of other locally defined mpropdefs to display
486 # `lin`: full linearization from local_mpropdefs to intro (displayed in redef tree)
487 fun tpl_mprop_article
(main_mpropdef
: MPropDef, local_mpropdefs
: Array[MPropDef],
488 lin
: Array[MPropDef]): TplArticle do
489 var mprop
= main_mpropdef
.mproperty
490 var article
= new TplArticle(mprop
.nitdoc_id
)
491 var title
= new Template
492 title
.add mprop
.tpl_icon
493 title
.add
"<span id='{main_mpropdef.nitdoc_id}'></span>"
494 if main_mpropdef
.is_intro
then
495 title
.add mprop
.tpl_link
496 title
.add mprop
.intro
.tpl_signature
498 var cls_url
= mprop
.intro
.mclassdef
.mclass
.nitdoc_url
499 var def_url
= "{cls_url}#{mprop.nitdoc_id}"
500 var lnk
= new TplLink.with_title
(def_url
, mprop
.name
, "Go to introduction")
504 article
.title
= title
505 article
.title_classes
.add
"signature"
506 article
.summary_title
= "{mprop.nitdoc_name}"
507 article
.subtitle
= main_mpropdef
.tpl_namespace
508 if main_mpropdef
.mdoc
!= null then
509 article
.content
= main_mpropdef
.mdoc
.tpl_comment
511 var subarticle
= new TplArticle("{main_mpropdef.nitdoc_id}_redefs")
512 # Add redef in same `MClass`
513 if local_mpropdefs
.length
> 1 then
514 for mpropdef
in local_mpropdefs
do
515 if mpropdef
== main_mpropdef
then continue
516 var redef_article
= new TplArticle("{mpropdef.nitdoc_id}")
517 var redef_title
= new Template
518 redef_title
.add
"also redef in "
519 redef_title
.add mpropdef
.tpl_namespace
520 redef_article
.title
= redef_title
521 redef_article
.title_classes
.add
"signature info"
522 redef_article
.css_classes
.add
"nospace"
523 var redef_content
= new Template
524 if mpropdef
.mdoc
!= null then
525 redef_content
.add mpropdef
.mdoc
.tpl_comment
527 redef_article
.content
= redef_content
528 subarticle
.add_child redef_article
532 if lin
.length
> 1 then
533 var lin_article
= new TplArticle("{main_mpropdef.nitdoc_id}_lin")
534 lin_article
.title
= "Inheritance"
535 var lst
= new TplList.with_classes
(["list-unstyled", "list-labeled"])
536 for mpropdef
in lin
do
537 lst
.add_li mpropdef
.tpl_inheritance_item
539 lin_article
.content
= lst
540 subarticle
.add_child lin_article
542 article
.add_child subarticle
546 # MProperty description template
547 fun tpl_mpropdef_article
(mpropdef
: MPropDef): TplArticle do
548 var article
= mpropdef
.tpl_article
549 article
.source_link
= tpl_showsource
(mpropdef
.location
)
555 # Display a list of modules contained in program
559 private var page
= new TplPage
560 redef fun tpl_page
do return page
562 private var sidebar
= new TplSidebar
563 redef fun tpl_sidebar
do return sidebar
565 redef fun tpl_title
do
566 if ctx
.opt_custom_title
.value
!= null then
567 return ctx
.opt_custom_title
.value
.to_s
573 redef fun page_url
do return "index.html"
576 private fun tpl_intro
: TplSection do
577 var section
= new TplSection.with_title
("overview", tpl_title
)
578 var article
= new TplArticle("intro")
579 if ctx
.opt_custom_intro
.value
!= null then
580 article
.content
= ctx
.opt_custom_intro
.value
.to_s
582 section
.add_child article
587 private fun tpl_projects
(section
: TplSection) do
589 var mprojects
= model
.mprojects
.to_a
590 var sorter
= new MConcernRankSorter
591 sorter
.sort mprojects
592 var ssection
= new TplSection.with_title
("projects", "Projects")
593 for mproject
in mprojects
do
594 ssection
.add_child tpl_mproject_article
(mproject
)
596 section
.add_child ssection
599 redef fun tpl_content
do
602 tpl_page
.add_section top
607 # Display a list of modules, classes and properties
611 private var page
= new TplPage
612 redef fun tpl_page
do return page
614 redef fun tpl_title
do return "Index"
616 redef fun page_url
do return "search.html"
618 redef fun tpl_content
do
619 var tpl
= new TplSearchPage("search_all")
620 var section
= new TplSection("search")
624 for mmodule
in modules_list
do
625 tpl
.modules
.add mmodule
.tpl_link
628 for mclass
in classes_list
do
629 tpl
.classes
.add mclass
.tpl_link
632 for mproperty
in mprops_list
do
634 m
.add mproperty
.intro
.tpl_link
636 m
.add mproperty
.intro
.mclassdef
.mclass
.tpl_link
640 section
.add_child tpl
641 tpl_page
.add_section section
644 # Extract mmodule list to display (sorted by name)
645 private fun modules_list
: Array[MModule] do
646 var sorted
= new Array[MModule]
647 for mmodule
in model
.mmodule_importation_hierarchy
do
648 if mmodule
.is_fictive
then continue
651 name_sorter
.sort
(sorted
)
655 # Extract mclass list to display (sorted by name)
656 private fun classes_list
: Array[MClass] do
657 var sorted
= new Array[MClass]
658 for mclass
in model
.mclasses
do
659 if mclass
.visibility
< ctx
.min_visibility
then continue
662 name_sorter
.sort
(sorted
)
666 # Extract mproperty list to display (sorted by name)
667 private fun mprops_list
: Array[MProperty] do
668 var sorted
= new Array[MProperty]
669 for mproperty
in model
.mproperties
do
670 if mproperty
.visibility
< ctx
.min_visibility
then continue
671 if mproperty
isa MAttribute then continue
674 name_sorter
.sort
(sorted
)
680 # Display a flattened view of the group
684 private var mgroup
: MGroup
686 private var concerns
: ConcernsTree is noinit
687 private var intros
: Set[MClass] is noinit
688 private var redefs
: Set[MClass] is noinit
691 self.concerns
= model
.concerns_tree
(mgroup
.collect_mmodules
)
692 self.concerns
.sort_with
(new MConcernRankSorter)
693 self.intros
= mgroup
.in_nesting_intro_mclasses
(ctx
.min_visibility
)
694 var redefs
= new HashSet[MClass]
695 for rdef
in mgroup
.in_nesting_redef_mclasses
(ctx
.min_visibility
) do
696 if intros
.has
(rdef
) then continue
702 private var page
= new TplPage
703 redef fun tpl_page
do return page
705 private var sidebar
= new TplSidebar
706 redef fun tpl_sidebar
do return sidebar
708 redef fun tpl_title
do return mgroup
.nitdoc_name
710 redef fun page_url
do return mgroup
.nitdoc_url
712 redef fun tpl_topmenu
do
714 var mproject
= mgroup
.mproject
715 if not mgroup
.is_root
then
716 topmenu
.add_link
new TplLink(mproject
.nitdoc_url
, mproject
.nitdoc_name
)
718 topmenu
.add_link
new TplLink(page_url
, mproject
.nitdoc_name
)
722 # Class list to display in sidebar
723 fun tpl_sidebar_mclasses
do
724 var mclasses
= new HashSet[MClass]
725 mclasses
.add_all intros
726 mclasses
.add_all redefs
727 if mclasses
.is_empty
then return
728 var list
= new TplList.with_classes
(["list-unstyled", "list-labeled"])
730 var sorted
= mclasses
.to_a
731 name_sorter
.sort
(sorted
)
732 for mclass
in sorted
do
733 list
.add_li tpl_sidebar_item
(mclass
)
735 tpl_sidebar
.boxes
.add
new TplSideBox.with_content
("All classes", list
)
738 private fun tpl_sidebar_item
(def
: MClass): TplListItem do
739 var classes
= def
.intro
.tpl_css_classes
.to_a
740 if intros
.has
(def
) then
745 var lnk
= new Template
746 lnk
.add
new TplLabel.with_classes
(classes
)
748 return new TplListItem.with_content
(lnk
)
752 private fun tpl_intro
: TplSection do
753 var section
= new TplSection.with_title
("top", tpl_title
)
754 var article
= new TplArticle("intro")
756 if mgroup
.is_root
then
757 section
.subtitle
= mgroup
.mproject
.tpl_declaration
758 article
.content
= mgroup
.mproject
.tpl_definition
760 section
.subtitle
= mgroup
.tpl_declaration
761 article
.content
= mgroup
.tpl_definition
763 section
.add_child article
767 private fun tpl_concerns
(section
: TplSection) do
768 if concerns
.is_empty
then return
769 section
.add_child
new TplArticle.with_content
("concerns", "Concerns", concerns
.to_tpl
)
772 private fun tpl_groups
(parent
: TplSection) do
773 var lst
= concerns
.to_a
775 for mentity
in lst
do
776 if mentity
isa MProject then
777 section
.add_child
new TplSection(mentity
.nitdoc_id
)
778 else if mentity
isa MGroup then
779 section
.add_child
new TplSection(mentity
.nitdoc_id
)
780 else if mentity
isa MModule then
781 section
.add_child tpl_mmodule_article
(mentity
)
786 redef fun tpl_content
do
791 tpl_page
.add_section top
794 private fun sort_by_mclass
(mclassdefs
: Collection[MClassDef]): Map[MClass, Set[MClassDef]] do
795 var map
= new HashMap[MClass, Set[MClassDef]]
796 for mclassdef
in mclassdefs
do
797 var mclass
= mclassdef
.mclass
798 if not map
.has_key
(mclass
) then map
[mclass
] = new HashSet[MClassDef]
799 map
[mclass
].add mclassdef
806 # Display the list of introduced and redefined classes in module
810 private var mmodule
: MModule
811 private var concerns
: ConcernsTree is noinit
812 private var mclasses2mdefs
: Map[MClass, Set[MClassDef]] is noinit
813 private var mmodules2mclasses
: Map[MModule, Set[MClass]] is noinit
817 var mclassdefs
= new HashSet[MClassDef]
818 mclassdefs
.add_all mmodule
.intro_mclassdefs
(ctx
.min_visibility
)
819 mclassdefs
.add_all mmodule
.redef_mclassdefs
(ctx
.min_visibility
)
820 self.mclasses2mdefs
= sort_by_mclass
(mclassdefs
)
821 self.mmodules2mclasses
= group_by_mmodule
(mclasses2mdefs
.keys
)
822 self.concerns
= model
.concerns_tree
(mmodules2mclasses
.keys
)
824 mmodule
.mgroup
.mproject
.booster_rank
= -1000
825 mmodule
.mgroup
.booster_rank
= -1000
826 mmodule
.booster_rank
= -1000
827 self.concerns
.sort_with
(new MConcernRankSorter)
828 mmodule
.mgroup
.mproject
.booster_rank
= 0
829 mmodule
.mgroup
.booster_rank
= 0
830 mmodule
.booster_rank
= 0
833 private var page
= new TplPage
834 redef fun tpl_page
do return page
836 private var sidebar
= new TplSidebar
837 redef fun tpl_sidebar
do return sidebar
839 redef fun tpl_title
do return mmodule
.nitdoc_name
840 redef fun page_url
do return mmodule
.nitdoc_url
842 redef fun tpl_topmenu
do
844 var mproject
= mmodule
.mgroup
.mproject
845 topmenu
.add_link
new TplLink(mproject
.nitdoc_url
, mproject
.nitdoc_name
)
846 topmenu
.add_link
new TplLink(page_url
, mmodule
.nitdoc_name
)
850 # Class list to display in sidebar
851 fun tpl_sidebar_mclasses
do
852 var mclasses
= new HashSet[MClass]
853 mclasses
.add_all mmodule
.filter_intro_mclasses
(ctx
.min_visibility
)
854 mclasses
.add_all mmodule
.filter_redef_mclasses
(ctx
.min_visibility
)
855 if mclasses
.is_empty
then return
856 var list
= new TplList.with_classes
(["list-unstyled", "list-labeled"])
858 var sorted
= mclasses
.to_a
859 name_sorter
.sort
(sorted
)
860 for mclass
in sorted
do
861 list
.add_li tpl_sidebar_item
(mclass
)
863 tpl_sidebar
.boxes
.add
new TplSideBox.with_content
("All classes", list
)
866 private fun tpl_sidebar_item
(def
: MClass): TplListItem do
867 var classes
= def
.intro
.tpl_css_classes
.to_a
868 if def
.intro_mmodule
== mmodule
then
873 var lnk
= new Template
874 lnk
.add
new TplLabel.with_classes
(classes
)
876 return new TplListItem.with_content
(lnk
)
880 private fun tpl_intro
: TplSection do
881 var section
= new TplSection.with_title
("top", tpl_title
)
882 section
.subtitle
= mmodule
.tpl_declaration
884 var article
= new TplArticle("intro")
885 var def
= mmodule
.tpl_definition
886 var location
= mmodule
.location
887 article
.source_link
= tpl_showsource
(location
)
888 article
.content
= def
889 section
.add_child article
893 # inheritance section
894 private fun tpl_inheritance
(parent
: TplSection) do
895 # Extract relevent modules
896 var imports
= mmodule
.in_importation
.greaters
897 if imports
.length
> 10 then imports
= mmodule
.in_importation
.direct_greaters
898 var clients
= mmodule
.in_importation
.smallers
899 if clients
.length
> 10 then clients
= mmodule
.in_importation
.direct_smallers
902 var section
= new TplSection.with_title
("dependencies", "Dependencies")
905 var mmodules
= new HashSet[MModule]
906 mmodules
.add_all mmodule
.in_nesting
.direct_greaters
907 mmodules
.add_all imports
908 if clients
.length
< 10 then mmodules
.add_all clients
910 var graph
= tpl_dot
(mmodules
)
911 if graph
!= null then section
.add_child graph
914 var lst
= new Array[MModule]
915 for dep
in imports
do
916 if dep
.is_fictive
then continue
917 if dep
== mmodule
then continue
920 if not lst
.is_empty
then
922 section
.add_child tpl_list
("imports", "Imports", lst
)
926 lst
= new Array[MModule]
927 for dep
in clients
do
928 if dep
.is_fictive
then continue
929 if dep
== mmodule
then continue
932 if not lst
.is_empty
then
934 section
.add_child tpl_list
("clients", "Clients", lst
)
937 parent
.add_child section
940 private fun tpl_list
(id
: String, title
: String, mmodules
: Array[MModule]): TplArticle do
941 var article
= new TplArticle.with_title
(id
, title
)
942 var list
= new TplList.with_classes
(["list-unstyled", "list-definition"])
943 for mmodule
in mmodules
do list
.elts
.add mmodule
.tpl_list_item
944 article
.content
= list
948 private fun tpl_concerns
(parent
: TplSection) do
949 if concerns
.is_empty
then return
950 parent
.add_child
new TplArticle.with_content
("concerns", "Concerns", concerns
.to_tpl
)
953 private fun tpl_mclasses
(parent
: TplSection) do
954 for mentity
in concerns
do
955 if mentity
isa MProject then
956 parent
.add_child
new TplSection(mentity
.nitdoc_id
)
957 else if mentity
isa MGroup then
958 parent
.add_child
new TplSection(mentity
.nitdoc_id
)
959 else if mentity
isa MModule then
960 var section
= new TplSection(mentity
.nitdoc_id
)
961 var title
= new Template
962 if mentity
== mmodule
then
964 section
.summary_title
= "in {mentity.nitdoc_name}"
967 section
.summary_title
= "from {mentity.nitdoc_name}"
969 title
.add mentity
.tpl_namespace
970 section
.title
= title
972 var mclasses
= mmodules2mclasses
[mentity
].to_a
973 name_sorter
.sort
(mclasses
)
974 for mclass
in mclasses
do
975 section
.add_child tpl_mclass_article
(mclass
, mclasses2mdefs
[mclass
].to_a
)
977 parent
.add_child section
982 private fun group_by_mmodule
(mclasses
: Collection[MClass]): Map[MModule, Set[MClass]] do
983 var res
= new HashMap[MModule, Set[MClass]]
984 for mclass
in mclasses
do
985 var mmodule
= mclass
.intro_mmodule
986 if not res
.has_key
(mmodule
) then
987 res
[mmodule
] = new HashSet[MClass]
989 res
[mmodule
].add
(mclass
)
994 redef fun tpl_content
do
1000 tpl_page
.add_section top
1003 # Genrate dot hierarchy for class inheritance
1004 fun tpl_dot
(mmodules
: Collection[MModule]): nullable TplArticle do
1005 var poset
= new POSet[MModule]
1006 for mmodule
in mmodules
do
1007 if mmodule
.is_fictive
then continue
1008 poset
.add_node mmodule
1009 for omodule
in mmodules
do
1010 if mmodule
.is_fictive
then continue
1011 poset
.add_node mmodule
1012 if mmodule
.in_importation
< omodule
then
1013 poset
.add_edge
(mmodule
, omodule
)
1018 var op
= new RopeBuffer
1019 var name
= "dep_module_{mmodule.nitdoc_id}"
1020 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")
1021 for mmodule
in poset
do
1022 if mmodule
== self.mmodule
then
1023 op
.append
("\"{mmodule.name.escape_to_dot}\
"[shape=box,margin=0.03];\n")
1025 op
.append
("\"{mmodule.name.escape_to_dot}\
"[URL=\"{mmodule.nitdoc_url.escape_to_dot}\
"];\n")
1027 for omodule
in poset
[mmodule
].direct_greaters
do
1028 op
.append
("\"{mmodule.name.escape_to_dot}\
"->\"{omodule.name.escape_to_dot}\
";\n")
1032 return tpl_graph
(op
, name
, null)
1035 private fun sort_by_mclass
(mclassdefs
: Collection[MClassDef]): Map[MClass, Set[MClassDef]] do
1036 var map
= new HashMap[MClass, Set[MClassDef]]
1037 for mclassdef
in mclassdefs
do
1038 var mclass
= mclassdef
.mclass
1039 if not map
.has_key
(mclass
) then map
[mclass
] = new HashSet[MClassDef]
1040 map
[mclass
].add mclassdef
1047 # Display a list properties defined or redefined for this class
1051 private var mclass
: MClass
1052 private var concerns
: ConcernsTree is noinit
1053 private var mprops2mdefs
: Map[MProperty, Set[MPropDef]] is noinit
1054 private var mmodules2mprops
: Map[MModule, Set[MProperty]] is noinit
1057 var mpropdefs
= new HashSet[MPropDef]
1058 mpropdefs
.add_all mclass
.intro_mpropdefs
(ctx
.min_visibility
)
1059 mpropdefs
.add_all mclass
.redef_mpropdefs
(ctx
.min_visibility
)
1060 self.mprops2mdefs
= sort_by_mproperty
(mpropdefs
)
1061 self.mmodules2mprops
= sort_by_mmodule
(mprops2mdefs
.keys
)
1062 self.concerns
= model
.concerns_tree
(mmodules2mprops
.keys
)
1063 self.concerns
.sort_with
(new MConcernRankSorter)
1066 private var page
= new TplPage
1067 redef fun tpl_page
do return page
1069 private var sidebar
= new TplSidebar
1070 redef fun tpl_sidebar
do return sidebar
1072 redef fun tpl_title
do return "{mclass.nitdoc_name}{mclass.tpl_signature.write_to_string}"
1073 redef fun page_url
do return mclass
.nitdoc_url
1075 redef fun tpl_topmenu
do
1077 var mproject
= mclass
.intro_mmodule
.mgroup
.mproject
1078 topmenu
.add_link
new TplLink("{mproject.nitdoc_url}", "{mproject.nitdoc_name}")
1079 topmenu
.add_link
new TplLink(page_url
, mclass
.nitdoc_name
)
1083 # Property list to display in sidebar
1084 fun tpl_sidebar_properties
do
1085 var kind_map
= sort_by_kind
(mclass_inherited_mprops
)
1086 var summary
= new TplList.with_classes
(["list-unstyled"])
1088 tpl_sidebar_list
("Virtual types", kind_map
["type"].to_a
, summary
)
1089 tpl_sidebar_list
("Constructors", kind_map
["init"].to_a
, summary
)
1090 tpl_sidebar_list
("Methods", kind_map
["fun"].to_a
, summary
)
1091 tpl_sidebar
.boxes
.add
new TplSideBox.with_content
("All properties", summary
)
1094 private fun tpl_sidebar_list
(name
: String, mprops
: Array[MProperty], summary
: TplList) do
1095 if mprops
.is_empty
then return
1096 name_sorter
.sort
(mprops
)
1097 var entry
= new TplListItem.with_content
(name
)
1098 var list
= new TplList.with_classes
(["list-unstyled", "list-labeled"])
1099 for mprop
in mprops
do
1100 list
.add_li tpl_sidebar_item
(mprop
)
1103 summary
.elts
.add entry
1106 private fun tpl_sidebar_item
(mprop
: MProperty): TplListItem do
1107 var classes
= mprop
.intro
.tpl_css_classes
.to_a
1108 if not mprops2mdefs
.has_key
(mprop
) then
1109 classes
.add
"inherit"
1110 var cls_url
= mprop
.intro
.mclassdef
.mclass
.nitdoc_url
1111 var def_url
= "{cls_url}#{mprop.nitdoc_id}"
1112 var lnk
= new TplLink(def_url
, mprop
.name
)
1113 if mprop
.intro
.mdoc
!= null then lnk
.title
= mprop
.intro
.mdoc
.short_comment
1114 var item
= new Template
1115 item
.add
new TplLabel.with_classes
(classes
)
1117 return new TplListItem.with_content
(item
)
1119 var defs
= mprops2mdefs
[mprop
]
1120 if defs
.has
(mprop
.intro
) then
1125 var lnk
= new Template
1126 lnk
.add
new TplLabel.with_classes
(classes
)
1127 lnk
.add mprop
.tpl_anchor
1128 return new TplListItem.with_content
(lnk
)
1131 private fun tpl_intro
: TplSection do
1132 var section
= new TplSection.with_title
("top", tpl_title
)
1133 section
.subtitle
= mclass
.intro
.tpl_declaration
1134 var article
= new TplArticle("comment")
1135 if mclass
.mdoc
!= null then
1136 article
.content
= mclass
.mdoc
.tpl_comment
1138 section
.add_child article
1142 private fun tpl_concerns
(parent
: TplSection) do
1144 var section
= new TplSection.with_title
("intro", "Introduction")
1145 section
.summary_title
= "Introduction"
1146 section
.add_child tpl_mclassdef_article
(mclass
.intro
)
1147 parent
.add_child section
1149 if concerns
.is_empty
then return
1150 parent
.add_child
new TplArticle.with_content
("concerns", "Concerns", concerns
.to_tpl
)
1153 private fun tpl_inheritance
(parent
: TplSection) do
1155 var hparents
= new HashSet[MClass]
1156 for c
in mclass
.in_hierarchy
(mainmodule
).direct_greaters
do
1157 if c
.visibility
< ctx
.min_visibility
then continue
1162 var hancestors
= new HashSet[MClass]
1163 for c
in mclass
.in_hierarchy
(mainmodule
).greaters
do
1164 if c
== mclass
then continue
1165 if c
.visibility
< ctx
.min_visibility
then continue
1166 if hparents
.has
(c
) then continue
1171 var hchildren
= new HashSet[MClass]
1172 for c
in mclass
.in_hierarchy
(mainmodule
).direct_smallers
do
1173 if c
.visibility
< ctx
.min_visibility
then continue
1178 var hdescendants
= new HashSet[MClass]
1179 for c
in mclass
.in_hierarchy
(mainmodule
).smallers
do
1180 if c
== mclass
then continue
1181 if c
.visibility
< ctx
.min_visibility
then continue
1182 if hchildren
.has
(c
) then continue
1187 var section
= new TplSection.with_title
("inheritance", "Inheritance")
1190 var mclasses
= new HashSet[MClass]
1191 mclasses
.add_all hancestors
1192 mclasses
.add_all hparents
1193 mclasses
.add_all hchildren
1194 mclasses
.add_all hdescendants
1196 var graph
= tpl_dot
(mclasses
)
1197 if graph
!= null then section
.add_child graph
1200 if not hparents
.is_empty
then
1201 var lst
= hparents
.to_a
1202 name_sorter
.sort lst
1203 section
.add_child tpl_list
("parents", "Parents", lst
)
1207 if not hancestors
.is_empty
then
1208 var lst
= hancestors
.to_a
1209 name_sorter
.sort lst
1210 section
.add_child tpl_list
("ancestors", "Ancestors", lst
)
1214 if not hchildren
.is_empty
then
1215 var lst
= hchildren
.to_a
1216 name_sorter
.sort lst
1217 section
.add_child tpl_list
("children", "Children", lst
)
1221 if not hdescendants
.is_empty
then
1222 var lst
= hdescendants
.to_a
1223 name_sorter
.sort lst
1224 section
.add_child tpl_list
("descendants", "Descendants", lst
)
1227 parent
.add_child section
1230 private fun tpl_list
(id
: String, title
: String, elts
: Array[MClass]): TplArticle do
1231 var article
= new TplArticle.with_title
(id
, title
)
1232 if elts
.length
> 20 then
1233 var tpl
= new Template
1236 if e
!= elts
.last
then tpl
.add
", "
1238 article
.content
= tpl
1240 var list
= new TplList.with_classes
(["list-unstyled", "list-definition"])
1241 for elt
in elts
do list
.elts
.add elt
.tpl_list_item
1242 article
.content
= list
1247 private fun tpl_properties
(parent
: TplSection) do
1248 var lst
= concerns
.to_a
1249 for mentity
in lst
do
1250 if mentity
isa MProject then
1251 parent
.add_child
new TplSection(mentity
.nitdoc_id
)
1252 else if mentity
isa MGroup then
1253 parent
.add_child
new TplSection(mentity
.nitdoc_id
)
1254 else if mentity
isa MModule then
1255 var section
= new TplSection(mentity
.nitdoc_id
)
1256 var title
= new Template
1258 title
.add mentity
.tpl_namespace
1259 section
.title
= title
1260 section
.summary_title
= "in {mentity.nitdoc_name}"
1263 var mprops
= mmodules2mprops
[mentity
]
1264 var kind_map
= sort_by_kind
(mprops
)
1267 for article
in tpl_mproperty_articles
(kind_map
, "type") do
1268 section
.add_child article
1271 for article
in tpl_mproperty_articles
(kind_map
, "init") do
1272 section
.add_child article
1275 for article
in tpl_mproperty_articles
(kind_map
, "fun") do
1276 section
.add_child article
1278 parent
.add_child section
1283 private fun tpl_mproperty_articles
(kind_map
: Map[String, Set[MProperty]],
1284 kind_name
: String): Sequence[TplArticle] do
1285 var articles
= new List[TplArticle]
1286 var elts
= kind_map
[kind_name
].to_a
1287 name_sorter
.sort
(elts
)
1289 var local_defs
= mprops2mdefs
[elt
]
1290 # var all_defs = elt.mpropdefs
1291 var all_defs
= new HashSet[MPropDef]
1292 for local_def
in local_defs
do
1293 all_defs
.add local_def
1294 var mpropdef
= local_def
1295 while not mpropdef
.is_intro
do
1296 mpropdef
= mpropdef
.lookup_next_definition
(mainmodule
, mpropdef
.mclassdef
.bound_mtype
)
1297 all_defs
.add mpropdef
1300 var loc_lin
= local_defs
.to_a
1301 mainmodule
.linearize_mpropdefs
(loc_lin
)
1302 var all_lin
= all_defs
.to_a
1303 mainmodule
.linearize_mpropdefs
(all_lin
)
1304 articles
.add tpl_mprop_article
(loc_lin
.first
, loc_lin
, all_lin
)
1309 redef fun tpl_content
do
1310 tpl_sidebar_properties
1312 tpl_inheritance
(top
)
1315 tpl_page
.add_section top
1318 private fun sort_by_mproperty
(mpropdefs
: Collection[MPropDef]): Map[MProperty, Set[MPropDef]] do
1319 var map
= new HashMap[MProperty, Set[MPropDef]]
1320 for mpropdef
in mpropdefs
do
1321 var mproperty
= mpropdef
.mproperty
1322 if not map
.has_key
(mproperty
) then map
[mproperty
] = new HashSet[MPropDef]
1323 map
[mproperty
].add mpropdef
1328 private fun sort_by_mmodule
(mprops
: Collection[MProperty]): Map[MModule, Set[MProperty]] do
1329 var map
= new HashMap[MModule, Set[MProperty]]
1330 for mprop
in mprops
do
1331 var mpropdefs
= mprops2mdefs
[mprop
].to_a
1332 mainmodule
.linearize_mpropdefs
(mpropdefs
)
1333 var mmodule
= mpropdefs
.first
.mclassdef
.mmodule
1334 if not map
.has_key
(mmodule
) then map
[mmodule
] = new HashSet[MProperty]
1335 map
[mmodule
].add mprop
1340 private fun sort_by_kind
(mprops
: Collection[MProperty]): Map[String, Set[MProperty]] do
1341 var map
= new HashMap[String, Set[MProperty]]
1342 map
["type"] = new HashSet[MProperty]
1343 map
["init"] = new HashSet[MProperty]
1344 map
["fun"] = new HashSet[MProperty]
1345 for mprop
in mprops
do
1346 if mprop
isa MVirtualTypeProp then
1347 map
["type"].add mprop
1348 else if mprop
isa MMethod then
1349 if mprop
.is_init
then
1350 map
["init"].add mprop
1352 map
["fun"].add mprop
1359 private fun mclass_inherited_mprops
: Set[MProperty] do
1360 var res
= new HashSet[MProperty]
1361 var local
= mclass
.local_mproperties
(ctx
.min_visibility
)
1362 for mprop
in mclass
.inherited_mproperties
(mainmodule
, ctx
.min_visibility
) do
1363 if local
.has
(mprop
) then continue
1364 #if mprop isa MMethod and mprop.is_init then continue
1365 if mprop
.intro
.mclassdef
.mclass
.name
== "Object" and
1366 (mprop
.visibility
== protected_visibility
or
1367 mprop
.intro
.mclassdef
.mmodule
.name
!= "kernel") then continue
1374 private fun collect_mmodules
(mprops
: Collection[MProperty]): Set[MModule] do
1375 var res
= new HashSet[MModule]
1376 for mprop
in mprops
do
1377 if mprops2mdefs
.has_key
(mprop
) then
1378 for mpropdef
in mprops2mdefs
[mprop
] do res
.add mpropdef
.mclassdef
.mmodule
1384 # Generate dot hierarchy for classes
1385 fun tpl_dot
(mclasses
: Collection[MClass]): nullable TplArticle do
1386 var poset
= new POSet[MClass]
1388 for mclass
in mclasses
do
1389 poset
.add_node mclass
1390 for oclass
in mclasses
do
1391 if mclass
== oclass
then continue
1392 poset
.add_node oclass
1393 if mclass
.in_hierarchy
(mainmodule
) < oclass
then
1394 poset
.add_edge
(mclass
, oclass
)
1399 var op
= new RopeBuffer
1400 var name
= "dep_class_{mclass.nitdoc_id}"
1401 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")
1402 var classes
= poset
.to_a
1403 var todo
= new Array[MClass]
1404 var done
= new HashSet[MClass]
1405 mainmodule
.linearize_mclasses
(classes
)
1406 if not classes
.is_empty
then todo
.add classes
.first
1407 while not todo
.is_empty
do
1409 if done
.has
(c
) then continue
1412 op
.append
("\"{c.name.escape_to_dot}\
"[shape=box,margin=0.03];\n")
1414 op
.append
("\"{c.name.escape_to_dot}\
"[URL=\"{c.nitdoc_url.escape_to_dot}\
"];\n")
1416 var smallers
= poset
[c
].direct_smallers
1417 if smallers
.length
< 10 then
1418 for c2
in smallers
do
1419 op
.append
("\"{c2.name.escape_to_dot}\
"->\"{c.name.escape_to_dot}\
";\n")
1421 todo
.add_all smallers
1423 op
.append
("\"...\
"->\"{c.name.escape_to_dot}\
";\n")
1427 return tpl_graph
(op
, name
, null)
1432 class NitdocProperty
1435 private var mproperty
: MProperty
1436 private var concerns
: ConcernsTree is noinit
1437 private var mmodules2mdefs
: Map[MModule, Set[MPropDef]] is noinit
1440 self.mproperty
= mproperty
1441 self.mmodules2mdefs
= sort_by_mmodule
(collect_mpropdefs
)
1442 self.concerns
= model
.concerns_tree
(mmodules2mdefs
.keys
)
1443 self.concerns
.sort_with
(new MConcernRankSorter)
1446 private fun collect_mpropdefs
: Set[MPropDef] do
1447 var res
= new HashSet[MPropDef]
1448 for mpropdef
in mproperty
.mpropdefs
do
1449 if not mpropdef
.is_intro
then res
.add mpropdef
1454 private var page
= new TplPage
1455 redef fun tpl_page
do return page
1457 private var sidebar
= new TplSidebar
1458 redef fun tpl_sidebar
do return sidebar
1460 redef fun tpl_title
do
1461 return "{mproperty.nitdoc_name}{mproperty.tpl_signature.write_to_string}"
1464 redef fun page_url
do return mproperty
.nitdoc_url
1466 redef fun tpl_topmenu
do
1468 var mmodule
= mproperty
.intro_mclassdef
.mmodule
1469 var mproject
= mmodule
.mgroup
.mproject
1470 var mclass
= mproperty
.intro_mclassdef
.mclass
1471 topmenu
.add_link
new TplLink("{mproject.nitdoc_url}", "{mproject.nitdoc_name}")
1472 topmenu
.add_link
new TplLink("{mclass.nitdoc_url}", "{mclass.nitdoc_name}")
1473 topmenu
.add_link
new TplLink(page_url
, mproperty
.nitdoc_name
)
1477 private fun tpl_intro
: TplSection do
1478 var title
= new Template
1479 title
.add mproperty
.nitdoc_name
1480 title
.add mproperty
.intro
.tpl_signature
1481 var section
= new TplSection.with_title
("top", title
)
1482 section
.subtitle
= mproperty
.tpl_namespace
1483 section
.summary_title
= mproperty
.nitdoc_name
1487 private fun tpl_properties
(parent
: TplSection) do
1489 var section
= new TplSection.with_title
("intro", "Introduction")
1490 section
.summary_title
= "Introduction"
1491 section
.add_child tpl_mpropdef_article
(mproperty
.intro
)
1492 parent
.add_child section
1495 if concerns
.is_empty
then return
1496 parent
.add_child
new TplArticle.with_content
("Concerns", "Concerns", concerns
.to_tpl
)
1499 var lst
= concerns
.to_a
1500 for mentity
in lst
do
1501 if mentity
isa MProject then
1502 parent
.add_child
new TplSection(mentity
.nitdoc_id
)
1503 else if mentity
isa MGroup then
1504 parent
.add_child
new TplSection(mentity
.nitdoc_id
)
1505 else if mentity
isa MModule then
1506 var ssection
= new TplSection(mentity
.nitdoc_id
)
1507 var title
= new Template
1509 title
.add mentity
.tpl_namespace
1510 ssection
.title
= title
1511 ssection
.summary_title
= "in {mentity.nitdoc_name}"
1514 var mpropdefs
= mmodules2mdefs
[mentity
].to_a
1515 name_sorter
.sort
(mpropdefs
)
1516 for mpropdef
in mpropdefs
do
1517 ssection
.add_child tpl_mpropdef_article
(mpropdef
)
1519 parent
.add_child ssection
1524 redef fun tpl_content
do
1527 tpl_page
.add_section top
1530 private fun sort_by_mmodule
(mpropdefs
: Collection[MPropDef]): Map[MModule, Set[MPropDef]] do
1531 var map
= new HashMap[MModule, Set[MPropDef]]
1532 for mpropdef
in mpropdefs
do
1533 var mmodule
= mpropdef
.mclassdef
.mmodule
1534 if not map
.has_key
(mmodule
) then map
[mmodule
] = new HashSet[MPropDef]
1535 map
[mmodule
].add mpropdef