# Nitdoc page generation
module doc_pages
+import toolcontext
import doc_model
+private import json::static
-# The NitdocContext contains all the knowledge used for doc generation
-class NitdocContext
+redef class ToolContext
private var opt_dir = new OptionString("output directory", "-d", "--dir")
private var opt_source = new OptionString("link for source (%f for filename, %l for first line, %L for last line)", "--source")
private var opt_sharedir = new OptionString("directory containing nitdoc assets", "--sharedir")
private var opt_shareurl = new OptionString("use shareurl instead of copy shared files", "--shareurl")
+ private var opt_no_attributes = new OptionBool("ignore the attributes",
+ "--no-attributes")
private var opt_nodot = new OptionBool("do not generate graphes with graphviz", "--no-dot")
private var opt_private = new OptionBool("also generate private API", "--private")
private var opt_piwik_tracker = new OptionString("Piwik tracker URL (ex: nitlanguage.org/piwik/)", "--piwik-tracker")
private var opt_piwik_site_id = new OptionString("Piwik site ID", "--piwik-site-id")
- private var toolcontext = new ToolContext
- private var mbuilder: ModelBuilder
- private var mainmodule: MModule
private var output_dir: String
private var min_visibility: MVisibility
- init do
- var opts = toolcontext.option_context
- opts.add_option(opt_dir, opt_source, opt_sharedir, opt_shareurl, opt_nodot, opt_private)
+ redef init do
+ super
+
+ var opts = option_context
+ opts.add_option(opt_dir, opt_source, opt_sharedir, opt_shareurl,
+ opt_no_attributes, opt_nodot, opt_private)
opts.add_option(opt_custom_title, opt_custom_footer, opt_custom_intro, opt_custom_brand)
opts.add_option(opt_github_upstream, opt_github_base_sha1, opt_github_gitdir)
opts.add_option(opt_piwik_tracker, opt_piwik_site_id)
var tpl = new Template
tpl.add "Usage: nitdoc [OPTION]... <file.nit>...\n"
tpl.add "Generates HTML pages of API documentation from Nit source files."
- toolcontext.tooldescription = tpl.write_to_string
- toolcontext.process_options(args)
-
- self.process_options
- self.parse(toolcontext.option_context.rest)
+ tooldescription = tpl.write_to_string
end
- private fun process_options do
+ redef fun process_options(args) do
+ super
+
+ # output dir
+ var output_dir = opt_dir.value
+ if output_dir == null then
+ output_dir = "doc"
+ end
+ self.output_dir = output_dir
+ # min visibility
if opt_private.value then
min_visibility = none_visibility
else
min_visibility = protected_visibility
end
+ # github urls
var gh_upstream = opt_github_upstream.value
var gh_base_sha = opt_github_base_sha1.value
var gh_gitdir = opt_github_gitdir.value
end
end
- private fun parse(arguments: Array[String]) do
- var model = new Model
- mbuilder = new ModelBuilder(model, toolcontext)
- var mmodules = mbuilder.parse(arguments)
- if mmodules.is_empty then return
- mbuilder.run_phases
- if mmodules.length == 1 then
- mainmodule = mmodules.first
- else
- mainmodule = new MModule(model, null, "<main>", new Location(null, 0, 0, 0, 0))
- mainmodule.is_fictive = true
- mainmodule.set_imported_mmodules(mmodules)
- end
+ # Filter the entity based on the options specified by the user.
+ #
+ # Return `true` if the specified entity has to be included in the generated
+ # documentation
+ private fun filter_mclass(mclass: MClass): Bool do
+ return mclass.visibility >= min_visibility
+ end
+
+ # Filter the entity based on the options specified by the user.
+ #
+ # Return `true` if the specified entity has to be included in the generated
+ # documentation
+ private fun filter_mproperty(mproperty: MProperty): Bool do
+ return mproperty.visibility >= min_visibility and
+ not (opt_no_attributes.value and mproperty isa MAttribute)
end
+end
+
+# The Nitdoc class explores the model and generate pages for each mentities found
+class Nitdoc
+ var ctx: ToolContext
+ var model: Model
+ var mainmodule: MModule
- fun generate_nitdoc do
+ fun generate do
init_output_dir
overview
search
+ groups
modules
classes
+ properties
quicksearch_list
end
private fun init_output_dir do
- # location output dir
- var output_dir = opt_dir.value
- if output_dir == null then
- output_dir = "doc"
- end
- self.output_dir = output_dir
# create destination dir if it's necessary
+ var output_dir = ctx.output_dir
if not output_dir.file_exists then output_dir.mkdir
# locate share dir
- var sharedir = opt_sharedir.value
+ var sharedir = ctx.opt_sharedir.value
if sharedir == null then
- var dir = toolcontext.nit_dir
- if dir == null then
- print "Error: Cannot locate nitdoc share files. Uses --sharedir or envvar NIT_DIR"
- abort
- end
- sharedir = "{dir}/share/nitdoc"
+ var dir = ctx.nit_dir
+ sharedir = dir/"share/nitdoc"
if not sharedir.file_exists then
print "Error: Cannot locate nitdoc share files. Uses --sharedir or envvar NIT_DIR"
abort
end
end
# copy shared files
- if opt_shareurl.value == null then
- sys.system("cp -r {sharedir.to_s}/* {output_dir.to_s}/")
+ if ctx.opt_shareurl.value == null then
+ sys.system("cp -r -- {sharedir.to_s.escape_to_sh}/* {output_dir.to_s.escape_to_sh}/")
else
- sys.system("cp -r {sharedir.to_s}/resources/ {output_dir.to_s}/resources/")
+ sys.system("cp -r -- {sharedir.to_s.escape_to_sh}/resources/ {output_dir.to_s.escape_to_sh}/resources/")
end
end
private fun overview do
- var overviewpage = new NitdocOverview(self)
- overviewpage.render.write_to_file("{output_dir.to_s}/index.html")
+ var page = new NitdocOverview(ctx, model, mainmodule)
+ page.render.write_to_file("{ctx.output_dir.to_s}/{page.page_url}")
end
private fun search do
- var searchpage = new NitdocSearch(self)
- searchpage.render.write_to_file("{output_dir.to_s}/search.html")
+ var page = new NitdocSearch(ctx, model, mainmodule)
+ page.render.write_to_file("{ctx.output_dir.to_s}/{page.page_url}")
+ end
+
+ private fun groups do
+ for mproject in model.mprojects do
+ for mgroup in mproject.mgroups.to_a do
+ var page = new NitdocGroup(ctx, model, mainmodule, mgroup)
+ page.render.write_to_file("{ctx.output_dir.to_s}/{page.page_url}")
+ end
+ end
end
private fun modules do
- for mmodule in mbuilder.model.mmodules do
- if mmodule.name == "<main>" then continue
- var modulepage = new NitdocModule(mmodule, self)
- modulepage.render.write_to_file("{output_dir.to_s}/{mmodule.nitdoc_url}")
+ for mmodule in model.mmodules do
+ if mmodule.is_fictive then continue
+ var page = new NitdocModule(ctx, model, mainmodule, mmodule)
+ page.render.write_to_file("{ctx.output_dir.to_s}/{page.page_url}")
end
end
private fun classes do
- for mclass in mbuilder.model.mclasses do
- var classpage = new NitdocClass(mclass, self)
- classpage.render.write_to_file("{output_dir.to_s}/{mclass.nitdoc_url}")
+ for mclass in model.mclasses do
+ if not ctx.filter_mclass(mclass) then continue
+ var page = new NitdocClass(ctx, model, mainmodule, mclass)
+ page.render.write_to_file("{ctx.output_dir.to_s}/{page.page_url}")
+ end
+ end
+
+ private fun properties do
+ for mproperty in model.mproperties do
+ if not ctx.filter_mproperty(mproperty) then continue
+ if mproperty isa MInnerClass then continue
+ var page = new NitdocProperty(ctx, model, mainmodule, mproperty)
+ page.render.write_to_file("{ctx.output_dir.to_s}/{page.page_url}")
end
end
private fun quicksearch_list do
- var quicksearch = new QuickSearch(self)
- quicksearch.render.write_to_file("{output_dir.to_s}/quicksearch-list.js")
+ var quicksearch = new QuickSearch(ctx, model)
+ quicksearch.render.write_to_file("{ctx.output_dir.to_s}/quicksearch-list.js")
end
end
# All entities are grouped by name to make the research easier.
class QuickSearch
- private var mmodules = new HashSet[MModule]
- private var mclasses = new HashSet[MClass]
- private var mpropdefs = new HashMap[String, Set[MPropDef]]
+ private var table = new QuickSearchTable
+
+ var ctx: ToolContext
+ var model: Model
- init(ctx: NitdocContext) do
- for mmodule in ctx.mbuilder.model.mmodules do
- if mmodule.name == "<main>" then continue
- mmodules.add mmodule
+ init do
+ for mmodule in model.mmodules do
+ if mmodule.is_fictive then continue
+ add_result_for(mmodule.name, mmodule.full_name, mmodule.nitdoc_url)
end
- for mclass in ctx.mbuilder.model.mclasses do
- if mclass.visibility < ctx.min_visibility then continue
- mclasses.add mclass
+ for mclass in model.mclasses do
+ if not ctx.filter_mclass(mclass) then continue
+ add_result_for(mclass.name, mclass.full_name, mclass.nitdoc_url)
end
- for mproperty in ctx.mbuilder.model.mproperties do
- if mproperty.visibility < ctx.min_visibility then continue
- if mproperty isa MAttribute then continue
- if not mpropdefs.has_key(mproperty.name) then
- mpropdefs[mproperty.name] = new HashSet[MPropDef]
+ for mproperty in model.mproperties do
+ if not ctx.filter_mproperty(mproperty) then continue
+ for mpropdef in mproperty.mpropdefs do
+ var full_name = mpropdef.mclassdef.mclass.full_name
+ var cls_url = mpropdef.mclassdef.mclass.nitdoc_url
+ var def_url = "{cls_url}#{mpropdef.mproperty.nitdoc_id}"
+ add_result_for(mproperty.name, full_name, def_url)
end
- mpropdefs[mproperty.name].add_all(mproperty.mpropdefs)
end
end
+ private fun add_result_for(query: String, txt: String, url: String) do
+ table[query].add new QuickSearchResult(txt, url)
+ end
+
fun render: Template do
var tpl = new Template
- tpl.add "var nitdocQuickSearchRawList=\{ "
- for mmodule in mmodules do
- tpl.add "\"{mmodule.name}\":["
- tpl.add "\{txt:\"{mmodule.full_name}\",url:\"{mmodule.nitdoc_url}\"\},"
- tpl.add "],"
- end
- for mclass in mclasses do
- var full_name = mclass.intro.mmodule.full_name
- tpl.add "\"{mclass.name}\":["
- tpl.add "\{txt:\"{full_name}\",url:\"{mclass.nitdoc_url}\"\},"
- tpl.add "],"
- end
- for mproperty, mprops in mpropdefs do
- tpl.add "\"{mproperty}\":["
- for mpropdef in mprops do
- var full_name = mpropdef.mclassdef.mclass.full_name
- tpl.add "\{txt:\"{full_name}\",url:\"{mpropdef.nitdoc_url}\"\},"
- end
- tpl.add "],"
- end
- tpl.add " \};"
+ var buffer = new RopeBuffer
+ tpl.add buffer
+ buffer.append "var nitdocQuickSearchRawList="
+ table.append_json buffer
+ buffer.append ";"
return tpl
end
end
+# The result map for QuickSearch.
+private class QuickSearchTable
+ super JsonMapRead[String, QuickSearchResultList]
+ super HashMap[String, QuickSearchResultList]
+
+ redef fun provide_default_value(key) do
+ var v = new QuickSearchResultList
+ self[key] = v
+ return v
+ end
+end
+
+# A QuickSearch result list.
+private class QuickSearchResultList
+ super JsonSequenceRead[QuickSearchResult]
+ super Array[QuickSearchResult]
+end
+
+# A QuickSearch result.
+private class QuickSearchResult
+ super Jsonable
+
+ # The text of the link.
+ var txt: String
+
+ # The destination of the link.
+ var url: String
+
+ redef fun to_json do
+ return "\{\"txt\":{txt.to_json},\"url\":{url.to_json}\}"
+ end
+end
+
# Nitdoc base page
# Define page structure and properties
abstract class NitdocPage
- private var ctx: NitdocContext
+ private var ctx: ToolContext
private var model: Model
+ private var mainmodule: MModule
private var name_sorter = new MEntityNameSorter
- init(ctx: NitdocContext) do
- self.ctx = ctx
- self.model = ctx.mbuilder.model
- end
-
# Render the page as a html template
fun render: Template do
var shareurl = "."
# build page
var tpl = tpl_page
tpl.title = tpl_title
+ tpl.url = page_url
tpl.shareurl = shareurl
tpl.topmenu = tpl_topmenu
tpl_content
return tpl
end
+ # URL to this page.
+ fun page_url: String is abstract
+
# Build page template
fun tpl_page: TplPage is abstract
# Build top menu template
fun tpl_topmenu: TplTopMenu do
- var topmenu = new TplTopMenu
+ var topmenu = new TplTopMenu(page_url)
var brand = ctx.opt_custom_brand.value
if brand != null then
var tpl = new Template
tpl.add "</span>"
topmenu.brand = tpl
end
+ topmenu.add_link new TplLink("index.html", "Overview")
+ topmenu.add_link new TplLink("search.html", "Index")
return topmenu
end
# Clickable graphviz image using dot format
# return null if no graph for this page
- fun tpl_graph(dot: FlatBuffer, name: String, title: String): nullable TplArticle do
+ fun tpl_graph(dot: Buffer, name: String, title: nullable String): nullable TplArticle do
if ctx.opt_nodot.value then return null
var output_dir = ctx.output_dir
- var file = new OFStream.open("{output_dir}/{name}.dot")
+ var path = output_dir / name
+ var path_sh = path.escape_to_sh
+ var file = new OFStream.open("{path}.dot")
file.write(dot)
file.close
- sys.system("\{ test -f {output_dir}/{name}.png && test -f {output_dir}/{name}.s.dot && diff {output_dir}/{name}.dot {output_dir}/{name}.s.dot >/dev/null 2>&1 ; \} || \{ cp {output_dir}/{name}.dot {output_dir}/{name}.s.dot && dot -Tpng -o{output_dir}/{name}.png -Tcmapx -o{output_dir}/{name}.map {output_dir}/{name}.s.dot ; \}")
- var fmap = new IFStream.open("{output_dir}/{name}.map")
+ 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 ; \}")
+ var fmap = new IFStream.open("{path}.map")
var map = fmap.read_all
fmap.close
- var article = new TplArticle.with_title("graph", title)
+ var article = new TplArticle("graph")
+ var alt = ""
+ if title != null then
+ article.title = title
+ alt = "alt='{title.html_escape}'"
+ end
+ article.css_classes.add "text-center"
var content = new Template
- content.add "<img src='{name}.png' usemap='#{name}' style='margin:auto' alt='{title}'/>"
+ var name_html = name.html_escape
+ content.add "<img src='{name_html}.png' usemap='#{name_html}' style='margin:auto' {alt}/>"
content.add map
article.content = content
return article
do
if location == null then return null
var source = ctx.opt_source.value
- if source == null then return "({location.file.filename.simplify_path})"
+ if source == null then
+ var url = location.file.filename.simplify_path
+ return "<a target='_blank' title='Show source' href=\"{url.html_escape}\">View Source</a>"
+ end
# THIS IS JUST UGLY ! (but there is no replace yet)
var x = source.split_with("%f")
source = x.join(location.file.filename.simplify_path)
x = source.split_with("%L")
source = x.join(location.line_end.to_s)
source = source.simplify_path
- return " (<a target='_blank' title='Show source' href=\"{source.to_s}\">source</a>)"
+ return "<a target='_blank' title='Show source' href=\"{source.to_s.html_escape}\">View Source</a>"
+ end
+
+ # MProject description template
+ fun tpl_mproject_article(mproject: MProject): TplArticle do
+ var article = mproject.tpl_article
+ article.subtitle = mproject.tpl_declaration
+ article.content = mproject.tpl_definition
+ var mdoc = mproject.mdoc_or_fallback
+ if mdoc != null then
+ article.content = mdoc.tpl_short_comment
+ end
+ return article
+ end
+
+ # MGroup description template
+ fun tpl_mgroup_article(mgroup: MGroup): TplArticle do
+ var article = mgroup.tpl_article
+ article.subtitle = mgroup.tpl_declaration
+ article.content = mgroup.tpl_definition
+ return article
+ end
+
+ # MModule description template
+ fun tpl_mmodule_article(mmodule: MModule): TplArticle do
+ var article = mmodule.tpl_article
+ article.subtitle = mmodule.tpl_declaration
+ article.content = mmodule.tpl_definition
+ # mclassdefs list
+ var intros = mmodule.intro_mclassdefs(ctx.min_visibility).to_a
+ if not intros.is_empty then
+ mainmodule.linearize_mclassdefs(intros)
+ var intros_art = new TplArticle.with_title("{mmodule.nitdoc_id}.intros", "Introduces")
+ var intros_lst = new TplList.with_classes(["list-unstyled", "list-labeled"])
+ for mclassdef in intros do
+ intros_lst.add_li mclassdef.tpl_list_item
+ end
+ if not intros_lst.is_empty then
+ intros_art.content = intros_lst
+ article.add_child intros_art
+ end
+ end
+ var redefs = mmodule.redef_mclassdefs(ctx.min_visibility).to_a
+ if not redefs.is_empty then
+ mainmodule.linearize_mclassdefs(redefs)
+ var redefs_art = new TplArticle.with_title("{mmodule.nitdoc_id}.redefs", "Redefines")
+ var redefs_lst = new TplList.with_classes(["list-unstyled", "list-labeled"])
+ for mclassdef in redefs do
+ redefs_lst.add_li mclassdef.tpl_list_item
+ end
+ if not redefs_lst.is_empty then
+ redefs_art.content = redefs_lst
+ article.add_child redefs_art
+ end
+ end
+ return article
end
# MClassDef description template
fun tpl_mclass_article(mclass: MClass, mclassdefs: Array[MClassDef]): TplArticle do
- var article = new TplArticle(mclass.nitdoc_id)
- var title = new Template
- var icon = new TplIcon.with_icon("tag")
- icon.css_classes.add_all(mclass.intro.tpl_css_classes)
- title.add icon
- title.add mclass.tpl_link
- title.add mclass.intro.tpl_signature
- article.title = title
- article.title_classes.add "signature"
- article.subtitle = mclass.tpl_declaration
- article.summary_title = "{mclass.nitdoc_name}{mclass.tpl_signature.write_to_string}"
- #article.subtitle = new Template
- #article.subtitle.add mprop.intro.tpl_modifiers
- #article.subtitle.add mprop.intro.tpl_namespace
- var content = new Template
-
+ var article = mclass.tpl_article
if not mclassdefs.has(mclass.intro) then
# add intro synopsys
- var intro = mclass.intro
- var location = intro.location
- var sourcelink = tpl_showsource(location)
- var intro_def = intro.tpl_definition
- intro_def.location = sourcelink
- content.add intro_def
- end
- ctx.mainmodule.linearize_mclassdefs(mclassdefs)
+ var intro_article = mclass.intro.tpl_short_article
+ intro_article.source_link = tpl_showsource(mclass.intro.location)
+ article.add_child intro_article
+ end
+ mainmodule.linearize_mclassdefs(mclassdefs)
for mclassdef in mclassdefs do
# add mclassdef full description
- var location = mclassdef.location
- var sourcelink = tpl_showsource(location)
- var prop_def = mclassdef.tpl_definition.as(TplClassDefinition)
- prop_def.location = sourcelink
- for mpropdef in mclassdef.mpropdefs do
- var intro = mpropdef.mproperty.intro
- if mpropdef isa MAttributeDef then continue
- if mpropdef.mproperty.visibility < ctx.min_visibility then continue
-
- var lnk = new Template
- lnk.add new TplLabel.with_classes(mpropdef.tpl_css_classes.to_a)
- lnk.add mpropdef.tpl_link
- if intro.mdoc != null then
- lnk.add ": "
- lnk.add intro.mdoc.short_comment
- end
- if mpropdef.is_intro then
- prop_def.intros.add new TplListItem.with_content(lnk)
- else
- prop_def.redefs.add new TplListItem.with_content(lnk)
- end
+ var redef_article = mclassdef.tpl_article
+ redef_article.source_link = tpl_showsource(mclassdef.location)
+ article.add_child redef_article
+ # mpropdefs list
+ var intros = new TplArticle.with_title("{mclassdef.nitdoc_id}.intros", "Introduces")
+ var intros_lst = new TplList.with_classes(["list-unstyled", "list-labeled"])
+ for mpropdef in mclassdef.collect_intro_mpropdefs(ctx.min_visibility) do
+ intros_lst.add_li mpropdef.tpl_list_item
+ end
+ if not intros_lst.is_empty then
+ intros.content = intros_lst
+ redef_article.add_child intros
+ end
+ var redefs = new TplArticle.with_title("{mclassdef.nitdoc_id}.redefs", "Redefines")
+ var redefs_lst = new TplList.with_classes(["list-unstyled", "list-labeled"])
+ for mpropdef in mclassdef.collect_redef_mpropdefs(ctx.min_visibility) do
+ redefs_lst.add_li mpropdef.tpl_list_item
+ end
+ if not redefs_lst.is_empty then
+ redefs.content = redefs_lst
+ redef_article.add_child redefs
end
- content.add prop_def
end
return article
end
end
# MProp description template
- fun tpl_mprop_article(mproperty: MProperty, mpropdefs: Array[MPropDef]): TplArticle do
- var article = mproperty.tpl_article
- if not mpropdefs.has(mproperty.intro) then
- # add intro synopsys
- var intro_article = mproperty.intro.tpl_short_article
- intro_article.source_link = tpl_showsource(mproperty.intro.location)
- article.add_child intro_article
+ #
+ # `main_mpropdef`: The most important mpropdef to display
+ # `local_mpropdefs`: List of other locally defined mpropdefs to display
+ # `lin`: full linearization from local_mpropdefs to intro (displayed in redef tree)
+ fun tpl_mprop_article(main_mpropdef: MPropDef, local_mpropdefs: Array[MPropDef],
+ lin: Array[MPropDef]): TplArticle do
+ var mprop = main_mpropdef.mproperty
+ var article = new TplArticle(mprop.nitdoc_id)
+ var title = new Template
+ title.add mprop.tpl_icon
+ title.add "<span id='{main_mpropdef.nitdoc_id}'></span>"
+ if main_mpropdef.is_intro then
+ title.add mprop.tpl_link
+ title.add mprop.intro.tpl_signature
+ else
+ var cls_url = mprop.intro.mclassdef.mclass.nitdoc_url
+ var def_url = "{cls_url}#{mprop.nitdoc_id}"
+ var lnk = new TplLink.with_title(def_url, mprop.name, "Go to introduction")
+ title.add "redef "
+ title.add lnk
end
- ctx.mainmodule.linearize_mpropdefs(mpropdefs)
- for mpropdef in mpropdefs do
- # add mpropdef description
- var redef_article = mpropdef.tpl_article
- redef_article.source_link = tpl_showsource(mpropdef.location)
- article.add_child redef_article
+ article.title = title
+ article.title_classes.add "signature"
+ article.summary_title = "{mprop.nitdoc_name}"
+ article.subtitle = main_mpropdef.tpl_namespace
+ if main_mpropdef.mdoc_or_fallback != null then
+ article.content = main_mpropdef.mdoc_or_fallback.tpl_comment
end
+ var subarticle = new TplArticle("{main_mpropdef.nitdoc_id}.redefs")
+ # Add redef in same `MClass`
+ if local_mpropdefs.length > 1 then
+ for mpropdef in local_mpropdefs do
+ if mpropdef == main_mpropdef then continue
+ var redef_article = new TplArticle("{mpropdef.nitdoc_id}")
+ var redef_title = new Template
+ redef_title.add "also redef in "
+ redef_title.add mpropdef.tpl_namespace
+ redef_article.title = redef_title
+ redef_article.title_classes.add "signature info"
+ redef_article.css_classes.add "nospace"
+ var redef_content = new Template
+ if mpropdef.mdoc_or_fallback != null then
+ redef_content.add mpropdef.mdoc_or_fallback.tpl_comment
+ end
+ redef_article.content = redef_content
+ subarticle.add_child redef_article
+ end
+ end
+ # Add linearization
+ if lin.length > 1 then
+ var lin_article = new TplArticle("{main_mpropdef.nitdoc_id}.lin")
+ lin_article.title = "Inheritance"
+ var lst = new TplList.with_classes(["list-unstyled", "list-labeled"])
+ for mpropdef in lin do
+ lst.add_li mpropdef.tpl_inheritance_item
+ end
+ lin_article.content = lst
+ subarticle.add_child lin_article
+ end
+ article.add_child subarticle
return article
end
# MProperty description template
fun tpl_mpropdef_article(mpropdef: MPropDef): TplArticle do
var article = mpropdef.tpl_article
- if mpropdef.is_intro then article.content = null
article.source_link = tpl_showsource(mpropdef.location)
return article
end
class NitdocOverview
super NitdocPage
- init(ctx: NitdocContext) do super(ctx)
-
private var page = new TplPage
redef fun tpl_page do return page
end
end
- redef fun tpl_topmenu do
- var topmenu = super
- topmenu.add_item(new TplLink("#", "Overview"), true)
- topmenu.add_item(new TplLink("search.html", "Index"), false)
- return topmenu
- end
+ redef fun page_url do return "index.html"
# intro text
private fun tpl_intro: TplSection do
class NitdocSearch
super NitdocPage
- init(ctx: NitdocContext) do super(ctx)
-
private var page = new TplPage
redef fun tpl_page do return page
redef fun tpl_title do return "Index"
- redef fun tpl_topmenu do
- var topmenu = super
- topmenu.add_item(new TplLink("index.html", "Overview"), false)
- topmenu.add_item(new TplLink("#", "Index"), true)
- return topmenu
- end
+ redef fun page_url do return "search.html"
redef fun tpl_content do
var tpl = new TplSearchPage("search_all")
# Extract mmodule list to display (sorted by name)
private fun modules_list: Array[MModule] do
var sorted = new Array[MModule]
- for mmodule in ctx.mbuilder.model.mmodule_importation_hierarchy do
- if mmodule.name == "<main>" then continue
+ for mmodule in model.mmodule_importation_hierarchy do
+ if mmodule.is_fictive then continue
sorted.add mmodule
end
name_sorter.sort(sorted)
# Extract mclass list to display (sorted by name)
private fun classes_list: Array[MClass] do
var sorted = new Array[MClass]
- for mclass in ctx.mbuilder.model.mclasses do
- if mclass.visibility < ctx.min_visibility then continue
+ for mclass in model.mclasses do
+ if not ctx.filter_mclass(mclass) then continue
sorted.add mclass
end
name_sorter.sort(sorted)
# Extract mproperty list to display (sorted by name)
private fun mprops_list: Array[MProperty] do
var sorted = new Array[MProperty]
- for mproperty in ctx.mbuilder.model.mproperties do
- if mproperty.visibility < ctx.min_visibility then continue
- if mproperty isa MAttribute then continue
- sorted.add mproperty
+ for mproperty in model.mproperties do
+ if ctx.filter_mproperty(mproperty) then sorted.add mproperty
end
name_sorter.sort(sorted)
return sorted
end
end
+# A group page
+# Display a flattened view of the group
+class NitdocGroup
+ super NitdocPage
+
+ private var mgroup: MGroup
+
+ private var concerns: ConcernsTree is noinit
+ private var intros: Set[MClass] is noinit
+ private var redefs: Set[MClass] is noinit
+
+ init do
+ self.concerns = model.concerns_tree(mgroup.collect_mmodules)
+ self.concerns.sort_with(new MConcernRankSorter)
+ self.intros = mgroup.in_nesting_intro_mclasses(ctx.min_visibility)
+ var redefs = new HashSet[MClass]
+ for rdef in mgroup.in_nesting_redef_mclasses(ctx.min_visibility) do
+ if intros.has(rdef) then continue
+ redefs.add rdef
+ end
+ self.redefs = redefs
+ end
+
+ private var page = new TplPage
+ redef fun tpl_page do return page
+
+ private var sidebar = new TplSidebar
+ redef fun tpl_sidebar do return sidebar
+
+ redef fun tpl_title do return mgroup.nitdoc_name
+
+ redef fun page_url do return mgroup.nitdoc_url
+
+ redef fun tpl_topmenu do
+ var topmenu = super
+ var mproject = mgroup.mproject
+ if not mgroup.is_root then
+ topmenu.add_link new TplLink(mproject.nitdoc_url, mproject.nitdoc_name)
+ end
+ topmenu.add_link new TplLink(page_url, mproject.nitdoc_name)
+ return topmenu
+ end
+
+ # Class list to display in sidebar
+ fun tpl_sidebar_mclasses do
+ var mclasses = new HashSet[MClass]
+ mclasses.add_all intros
+ mclasses.add_all redefs
+ if mclasses.is_empty then return
+ var list = new TplList.with_classes(["list-unstyled", "list-labeled"])
+
+ var sorted = mclasses.to_a
+ name_sorter.sort(sorted)
+ for mclass in sorted do
+ list.add_li tpl_sidebar_item(mclass)
+ end
+ tpl_sidebar.boxes.add new TplSideBox.with_content("All classes", list)
+ end
+
+ private fun tpl_sidebar_item(def: MClass): TplListItem do
+ var classes = def.intro.tpl_css_classes.to_a
+ if intros.has(def) then
+ classes.add "intro"
+ else
+ classes.add "redef"
+ end
+ var lnk = new Template
+ lnk.add new TplLabel.with_classes(classes)
+ lnk.add def.tpl_link
+ return new TplListItem.with_content(lnk)
+ end
+
+ # intro text
+ private fun tpl_intro: TplSection do
+ var section = new TplSection.with_title("top", tpl_title)
+ var article = new TplArticle("intro")
+
+ if mgroup.is_root then
+ section.subtitle = mgroup.mproject.tpl_declaration
+ article.content = mgroup.mproject.tpl_definition
+ else
+ section.subtitle = mgroup.tpl_declaration
+ article.content = mgroup.tpl_definition
+ end
+ section.add_child article
+ return section
+ end
+
+ private fun tpl_concerns(section: TplSection) do
+ if concerns.is_empty then return
+ section.add_child new TplArticle.with_content("concerns", "Concerns", concerns.to_tpl)
+ end
+
+ private fun tpl_groups(parent: TplSection) do
+ var lst = concerns.to_a
+ var section = parent
+ for mentity in lst do
+ if mentity isa MProject then
+ section.add_child new TplSection(mentity.nitdoc_id)
+ else if mentity isa MGroup then
+ section.add_child new TplSection(mentity.nitdoc_id)
+ else if mentity isa MModule then
+ section.add_child tpl_mmodule_article(mentity)
+ end
+ end
+ end
+
+ redef fun tpl_content do
+ tpl_sidebar_mclasses
+ var top = tpl_intro
+ tpl_concerns(top)
+ tpl_groups(top)
+ tpl_page.add_section top
+ end
+
+ private fun sort_by_mclass(mclassdefs: Collection[MClassDef]): Map[MClass, Set[MClassDef]] do
+ var map = new HashMap[MClass, Set[MClassDef]]
+ for mclassdef in mclassdefs do
+ var mclass = mclassdef.mclass
+ if not map.has_key(mclass) then map[mclass] = new HashSet[MClassDef]
+ map[mclass].add mclassdef
+ end
+ return map
+ end
+end
+
# A module page
# Display the list of introduced and redefined classes in module
class NitdocModule
super NitdocPage
private var mmodule: MModule
+ private var concerns: ConcernsTree is noinit
+ private var mclasses2mdefs: Map[MClass, Set[MClassDef]] is noinit
+ private var mmodules2mclasses: Map[MModule, Set[MClass]] is noinit
+
- init(mmodule: MModule, ctx: NitdocContext) do
- self.mmodule = mmodule
- super(ctx)
+ init do
+ var mclassdefs = new HashSet[MClassDef]
+ mclassdefs.add_all mmodule.intro_mclassdefs(ctx.min_visibility)
+ mclassdefs.add_all mmodule.redef_mclassdefs(ctx.min_visibility)
+ self.mclasses2mdefs = sort_by_mclass(mclassdefs)
+ self.mmodules2mclasses = group_by_mmodule(mclasses2mdefs.keys)
+ self.concerns = model.concerns_tree(mmodules2mclasses.keys)
+ # rank concerns
+ mmodule.mgroup.mproject.booster_rank = -1000
+ mmodule.mgroup.booster_rank = -1000
+ mmodule.booster_rank = -1000
+ self.concerns.sort_with(new MConcernRankSorter)
+ mmodule.mgroup.mproject.booster_rank = 0
+ mmodule.mgroup.booster_rank = 0
+ mmodule.booster_rank = 0
end
private var page = new TplPage
private var sidebar = new TplSidebar
redef fun tpl_sidebar do return sidebar
- redef fun tpl_title do return "{mmodule.nitdoc_name}"
+ redef fun tpl_title do return mmodule.nitdoc_name
+ redef fun page_url do return mmodule.nitdoc_url
redef fun tpl_topmenu do
var topmenu = super
var mproject = mmodule.mgroup.mproject
- topmenu.add_item(new TplLink("index.html", "Overview"), false)
- topmenu.add_item(new TplLink("{mproject.nitdoc_url}", "{mproject.nitdoc_name}"), false)
- topmenu.add_item(new TplLink("#", "{mmodule.nitdoc_name}"), true)
- topmenu.add_item(new TplLink("search.html", "Index"), false)
+ topmenu.add_link new TplLink(mproject.nitdoc_url, mproject.nitdoc_name)
+ topmenu.add_link new TplLink(page_url, mmodule.nitdoc_name)
return topmenu
end
tpl_sidebar.boxes.add new TplSideBox.with_content("All classes", list)
end
- private fun tpl_sidebar_item(def: MClass): Template do
+ private fun tpl_sidebar_item(def: MClass): TplListItem do
var classes = def.intro.tpl_css_classes.to_a
if def.intro_mmodule == mmodule then
classes.add "intro"
var lnk = new Template
lnk.add new TplLabel.with_classes(classes)
lnk.add def.tpl_link
- return lnk
+ return new TplListItem.with_content(lnk)
end
# intro text
# Graph
var mmodules = new HashSet[MModule]
- mmodules.add_all mmodule.in_nesting.direct_greaters
+ mmodules.add_all mmodule.nested_mmodules
mmodules.add_all imports
if clients.length < 10 then mmodules.add_all clients
mmodules.add mmodule
return article
end
+ private fun tpl_concerns(parent: TplSection) do
+ if concerns.is_empty then return
+ parent.add_child new TplArticle.with_content("concerns", "Concerns", concerns.to_tpl)
+ end
+
private fun tpl_mclasses(parent: TplSection) do
- var mclassdefs = new HashSet[MClassDef]
- mclassdefs.add_all mmodule.intro_mclassdefs(ctx.min_visibility)
- mclassdefs.add_all mmodule.redef_mclassdefs(ctx.min_visibility)
- var mclasses2mdefs = sort_by_mclass(mclassdefs)
- var mmodules2mclasses = group_by_mmodule(mclasses2mdefs.keys)
-
- var sorted_mmodules = mmodules2mclasses.keys.to_a
- model.mmodule_importation_hierarchy.linearize(sorted_mmodules)
-
- for mmodule in sorted_mmodules do
- var section = new TplSection(mmodule.nitdoc_anchor)
- var title = new Template
- if mmodule == sorted_mmodules.first then
- title.add "Introductions in "
- section.summary_title = "In {mmodule.nitdoc_name}"
- else
- title.add "Redefinitions from "
- section.summary_title = "From {mmodule.nitdoc_name}"
- end
- title.add mmodule.tpl_link
- section.title = title
+ for mentity in concerns do
+ if mentity isa MProject then
+ parent.add_child new TplSection(mentity.nitdoc_id)
+ else if mentity isa MGroup then
+ parent.add_child new TplSection(mentity.nitdoc_id)
+ else if mentity isa MModule then
+ var section = new TplSection(mentity.nitdoc_id)
+ var title = new Template
+ if mentity == mmodule then
+ title.add "in "
+ section.summary_title = "in {mentity.nitdoc_name}"
+ else
+ title.add "from "
+ section.summary_title = "from {mentity.nitdoc_name}"
+ end
+ title.add mentity.tpl_namespace
+ section.title = title
- var mclasses = mmodules2mclasses[mmodule].to_a
- name_sorter.sort(mclasses)
- for mclass in mclasses do
- section.add_child tpl_mclass_article(mclass, mclasses2mdefs[mclass].to_a)
+ var mclasses = mmodules2mclasses[mentity].to_a
+ name_sorter.sort(mclasses)
+ for mclass in mclasses do
+ section.add_child tpl_mclass_article(mclass, mclasses2mdefs[mclass].to_a)
+ end
+ parent.add_child section
end
- parent.add_child section
end
end
tpl_sidebar_mclasses
var top = tpl_intro
tpl_inheritance(top)
+ tpl_concerns(top)
tpl_mclasses(top)
tpl_page.add_section top
end
end
end
# build graph
- var op = new FlatBuffer
- var name = "dep_{mmodule.name}"
- op.append("digraph {name} \{ rankdir=BT; node[shape=none,margin=0,width=0,height=0,fontsize=10]; edge[dir=none,color=gray]; ranksep=0.2; nodesep=0.1;\n")
+ var op = new RopeBuffer
+ var name = "dep_module_{mmodule.nitdoc_id}"
+ 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")
for mmodule in poset do
if mmodule == self.mmodule then
- op.append("\"{mmodule.name}\"[shape=box,margin=0.03];\n")
+ op.append("\"{mmodule.name.escape_to_dot}\"[shape=box,margin=0.03];\n")
else
- op.append("\"{mmodule.name}\"[URL=\"{mmodule.nitdoc_url}\"];\n")
+ op.append("\"{mmodule.name.escape_to_dot}\"[URL=\"{mmodule.nitdoc_url.escape_to_dot}\"];\n")
end
for omodule in poset[mmodule].direct_greaters do
- op.append("\"{mmodule.name}\"->\"{omodule.name}\";\n")
+ op.append("\"{mmodule.name.escape_to_dot}\"->\"{omodule.name.escape_to_dot}\";\n")
end
end
op.append("\}\n")
- return tpl_graph(op, name, "Dependency graph")
+ return tpl_graph(op, name, null)
end
private fun sort_by_mclass(mclassdefs: Collection[MClassDef]): Map[MClass, Set[MClassDef]] do
super NitdocPage
private var mclass: MClass
- private var mprops2mdefs: Map[MProperty, Set[MPropDef]]
+ private var concerns: ConcernsTree is noinit
+ private var mprops2mdefs: Map[MProperty, Set[MPropDef]] is noinit
+ private var mmodules2mprops: Map[MModule, Set[MProperty]] is noinit
- init(mclass: MClass, ctx: NitdocContext) do
- self.mclass = mclass
- super(ctx)
+ init do
var mpropdefs = new HashSet[MPropDef]
mpropdefs.add_all mclass.intro_mpropdefs(ctx.min_visibility)
mpropdefs.add_all mclass.redef_mpropdefs(ctx.min_visibility)
- mprops2mdefs = sort_by_mproperty(mpropdefs)
+ self.mprops2mdefs = sort_by_mproperty(mpropdefs)
+ self.mmodules2mprops = sort_by_mmodule(mprops2mdefs.keys)
+ self.concerns = model.concerns_tree(mmodules2mprops.keys)
+ self.concerns.sort_with(new MConcernRankSorter)
end
private var page = new TplPage
redef fun tpl_sidebar do return sidebar
redef fun tpl_title do return "{mclass.nitdoc_name}{mclass.tpl_signature.write_to_string}"
+ redef fun page_url do return mclass.nitdoc_url
redef fun tpl_topmenu do
var topmenu = super
var mproject = mclass.intro_mmodule.mgroup.mproject
- topmenu.add_item(new TplLink("index.html", "Overview"), false)
- topmenu.add_item(new TplLink("{mproject.nitdoc_url}", "{mproject.nitdoc_name}"), false)
- topmenu.add_item(new TplLink("#", "{mclass.nitdoc_name}"), true)
- topmenu.add_item(new TplLink("search.html", "Index"), false)
+ topmenu.add_link new TplLink("{mproject.nitdoc_url}", "{mproject.nitdoc_name}")
+ topmenu.add_link new TplLink(page_url, mclass.nitdoc_name)
return topmenu
end
# Property list to display in sidebar
fun tpl_sidebar_properties do
- var kind_map = sort_by_kind(mclass_inherited_mprops)
+ var by_kind = new PropertiesByKind.with_elements(mclass_inherited_mprops)
var summary = new TplList.with_classes(["list-unstyled"])
- tpl_sidebar_list("Virtual types", kind_map["type"].to_a, summary)
- tpl_sidebar_list("Constructors", kind_map["init"].to_a, summary)
- tpl_sidebar_list("Methods", kind_map["fun"].to_a, summary)
+ by_kind.sort_groups(name_sorter)
+ for g in by_kind.groups do tpl_sidebar_list(g, summary)
tpl_sidebar.boxes.add new TplSideBox.with_content("All properties", summary)
end
- private fun tpl_sidebar_list(name: String, mprops: Array[MProperty], summary: TplList) do
+ private fun tpl_sidebar_list(mprops: PropertyGroup[MProperty], summary: TplList) do
if mprops.is_empty then return
- name_sorter.sort(mprops)
- var entry = new TplListItem.with_content(name)
+ var entry = new TplListItem.with_content(mprops.title)
var list = new TplList.with_classes(["list-unstyled", "list-labeled"])
for mprop in mprops do
list.add_li tpl_sidebar_item(mprop)
summary.elts.add entry
end
- private fun tpl_sidebar_item(mprop: MProperty): Template do
+ private fun tpl_sidebar_item(mprop: MProperty): TplListItem do
var classes = mprop.intro.tpl_css_classes.to_a
if not mprops2mdefs.has_key(mprop) then
classes.add "inherit"
- var lnk = new Template
- lnk.add new TplLabel.with_classes(classes)
- lnk.add mprop.intro.tpl_link
- return lnk
+ var cls_url = mprop.intro.mclassdef.mclass.nitdoc_url
+ var def_url = "{cls_url}#{mprop.nitdoc_id}"
+ var lnk = new TplLink(def_url, mprop.name)
+ var mdoc = mprop.intro.mdoc_or_fallback
+ if mdoc != null then lnk.title = mdoc.short_comment
+ var item = new Template
+ item.add new TplLabel.with_classes(classes)
+ item.add lnk
+ return new TplListItem.with_content(item)
end
var defs = mprops2mdefs[mprop]
if defs.has(mprop.intro) then
end
var lnk = new Template
lnk.add new TplLabel.with_classes(classes)
- lnk.add mprop.intro.tpl_anchor
- return lnk
+ lnk.add mprop.tpl_anchor
+ return new TplListItem.with_content(lnk)
end
private fun tpl_intro: TplSection do
var section = new TplSection.with_title("top", tpl_title)
- var subtitle = new Template
- subtitle.add "introduction in "
- subtitle.add mclass.intro.mmodule.tpl_namespace
- section.subtitle = subtitle
- section.add_child tpl_mclassdef_article(mclass.intro)
+ section.subtitle = mclass.intro.tpl_declaration
+ var article = new TplArticle("comment")
+ var mdoc = mclass.mdoc_or_fallback
+ if mdoc != null then
+ article.content = mdoc.tpl_comment
+ end
+ section.add_child article
return section
end
- private fun tpl_concerns(section: TplSection) do
- var mmodules = collect_mmodules(mprops2mdefs.keys)
- var owner_map = sort_by_public_owner(mmodules)
- var owners = owner_map.keys.to_a
-
- if not owners.is_empty then
- var article = new TplArticle.with_title("concerns", "Concerns")
- name_sorter.sort owners
- var list = new TplList.with_classes(["list-unstyled", "list-definition"])
- for owner in owners do
- var li = new Template
- li.add owner.tpl_anchor
- if owner.mdoc != null then
- li.add ": "
- li.add owner.mdoc.short_comment
- end
- var smmodules = owner_map[owner].to_a
- #if not smmodules.length >= 1 then
- var slist = new TplList.with_classes(["list-unstyled", "list-definition"])
- name_sorter.sort smmodules
- for mmodule in smmodules do
- if mmodule == owner then continue
- var sli = new Template
- sli.add mmodule.tpl_anchor
- if mmodule.mdoc != null then
- sli.add ": "
- sli.add mmodule.mdoc.short_comment
- end
- slist.add_li(sli)
- end
- li.add slist
- list.add_li li
- #end
- end
- article.content = list
- section.add_child article
- end
+ private fun tpl_concerns(parent: TplSection) do
+ # intro title
+ var section = new TplSection.with_title("intro", "Introduction")
+ section.summary_title = "Introduction"
+ section.add_child tpl_mclassdef_article(mclass.intro)
+ parent.add_child section
+ # concerns
+ if concerns.is_empty then return
+ parent.add_child new TplArticle.with_content("concerns", "Concerns", concerns.to_tpl)
end
private fun tpl_inheritance(parent: TplSection) do
# parents
var hparents = new HashSet[MClass]
- for c in mclass.in_hierarchy(ctx.mainmodule).direct_greaters do
- if c.visibility < ctx.min_visibility then continue
- hparents.add c
+ for c in mclass.in_hierarchy(mainmodule).direct_greaters do
+ if ctx.filter_mclass(c) then hparents.add c
end
# ancestors
var hancestors = new HashSet[MClass]
- for c in mclass.in_hierarchy(ctx.mainmodule).greaters do
+ for c in mclass.in_hierarchy(mainmodule).greaters do
if c == mclass then continue
- if c.visibility < ctx.min_visibility then continue
+ if not ctx.filter_mclass(c) then continue
if hparents.has(c) then continue
hancestors.add c
end
# children
var hchildren = new HashSet[MClass]
- for c in mclass.in_hierarchy(ctx.mainmodule).direct_smallers do
- if c.visibility < ctx.min_visibility then continue
- hchildren.add c
+ for c in mclass.in_hierarchy(mainmodule).direct_smallers do
+ if ctx.filter_mclass(c) then hchildren.add c
end
# descendants
var hdescendants = new HashSet[MClass]
- for c in mclass.in_hierarchy(ctx.mainmodule).smallers do
+ for c in mclass.in_hierarchy(mainmodule).smallers do
if c == mclass then continue
- if c.visibility < ctx.min_visibility then continue
+ if not ctx.filter_mclass(c) then continue
if hchildren.has(c) then continue
hdescendants.add c
end
var mclasses = new HashSet[MClass]
mclasses.add_all hancestors
mclasses.add_all hparents
- if hchildren.length < 10 then mclasses.add_all hchildren
- if hdescendants.length < 10 then mclasses.add_all hdescendants
+ mclasses.add_all hchildren
+ mclasses.add_all hdescendants
mclasses.add mclass
var graph = tpl_dot(mclasses)
if graph != null then section.add_child graph
end
# children
- if not hchildren.is_empty and hchildren.length < 15 then
+ if not hchildren.is_empty then
var lst = hchildren.to_a
name_sorter.sort lst
section.add_child tpl_list("children", "Children", lst)
end
# descendants
- if not hdescendants.is_empty and hchildren.length < 15 then
+ if not hdescendants.is_empty then
var lst = hdescendants.to_a
name_sorter.sort lst
section.add_child tpl_list("descendants", "Descendants", lst)
private fun tpl_list(id: String, title: String, elts: Array[MClass]): TplArticle do
var article = new TplArticle.with_title(id, title)
- var list = new TplList.with_classes(["list-unstyled", "list-definition"])
- for elt in elts do list.elts.add elt.tpl_list_item
- article.content = list
+ if elts.length > 20 then
+ var tpl = new Template
+ for e in elts do
+ tpl.add e.tpl_link
+ if e != elts.last then tpl.add ", "
+ end
+ article.content = tpl
+ else
+ var list = new TplList.with_classes(["list-unstyled", "list-definition"])
+ for elt in elts do list.elts.add elt.tpl_list_item
+ article.content = list
+ end
return article
end
private fun tpl_properties(parent: TplSection) do
- var mod_map = sort_by_mmodule(mprops2mdefs.keys)
- var owner_map = sort_by_public_owner(mod_map.keys)
- var owners = owner_map.keys.to_a
-
- for owner in owners do
- var section = new TplSection(owner.nitdoc_anchor)
- var title = new Template
- title.add "Introductions in "
- title.add owner.tpl_link
- section.title = title
- section.summary_title = "In {owner.nitdoc_name}"
- for mmodule in owner_map[owner] do
+ var lst = concerns.to_a
+ for mentity in lst do
+ if mentity isa MProject then
+ parent.add_child new TplSection(mentity.nitdoc_id)
+ else if mentity isa MGroup then
+ parent.add_child new TplSection(mentity.nitdoc_id)
+ else if mentity isa MModule then
+ var section = new TplSection(mentity.nitdoc_id)
+ var title = new Template
+ title.add "in "
+ title.add mentity.tpl_namespace
+ section.title = title
+ section.summary_title = "in {mentity.nitdoc_name}"
+
# properties
- var mprops = mod_map[mmodule]
- var kind_map = sort_by_kind(mprops)
-
- # virtual types
- var elts = kind_map["type"].to_a
- name_sorter.sort(elts)
- for elt in elts do
- var defs = mprops2mdefs[elt].to_a
- section.add_child tpl_mprop_article(elt, defs)
- end
+ var mprops = mmodules2mprops[mentity]
+ var by_kind = new PropertiesByKind.with_elements(mprops)
- # constructors
- elts = kind_map["init"].to_a
- name_sorter.sort(elts)
- for elt in elts do
- var defs = mprops2mdefs[elt].to_a
- section.add_child tpl_mprop_article(elt, defs)
+ for g in by_kind.groups do
+ for article in tpl_mproperty_articles(g) do
+ section.add_child article
+ end
end
+ parent.add_child section
+ end
+ end
+ end
- # methods
- elts = kind_map["fun"].to_a
- name_sorter.sort(elts)
- for elt in elts do
- var defs = mprops2mdefs[elt].to_a
- section.add_child tpl_mprop_article(elt, defs)
+ private fun tpl_mproperty_articles(elts: Collection[MProperty]):
+ Sequence[TplArticle] do
+ var articles = new List[TplArticle]
+ for elt in elts do
+ var local_defs = mprops2mdefs[elt]
+ # var all_defs = elt.mpropdefs
+ var all_defs = new HashSet[MPropDef]
+ for local_def in local_defs do
+ all_defs.add local_def
+ var mpropdef = local_def
+ while not mpropdef.is_intro do
+ mpropdef = mpropdef.lookup_next_definition(mainmodule, mpropdef.mclassdef.bound_mtype)
+ all_defs.add mpropdef
end
end
- parent.add_child section
+ var loc_lin = local_defs.to_a
+ mainmodule.linearize_mpropdefs(loc_lin)
+ var all_lin = all_defs.to_a
+ mainmodule.linearize_mpropdefs(all_lin)
+ articles.add tpl_mprop_article(loc_lin.first, loc_lin, all_lin)
end
+ return articles
end
redef fun tpl_content do
tpl_sidebar_properties
var top = tpl_intro
- tpl_concerns(top)
tpl_inheritance(top)
+ tpl_concerns(top)
tpl_properties(top)
tpl_page.add_section top
end
var map = new HashMap[MModule, Set[MProperty]]
for mprop in mprops do
var mpropdefs = mprops2mdefs[mprop].to_a
- ctx.mainmodule.linearize_mpropdefs(mpropdefs)
+ mainmodule.linearize_mpropdefs(mpropdefs)
var mmodule = mpropdefs.first.mclassdef.mmodule
if not map.has_key(mmodule) then map[mmodule] = new HashSet[MProperty]
map[mmodule].add mprop
return map
end
- private fun sort_by_kind(mprops: Collection[MProperty]): Map[String, Set[MProperty]] do
- var map = new HashMap[String, Set[MProperty]]
- map["type"] = new HashSet[MProperty]
- map["init"] = new HashSet[MProperty]
- map["fun"] = new HashSet[MProperty]
- for mprop in mprops do
- if mprop isa MVirtualTypeProp then
- map["type"].add mprop
- else if mprop isa MMethod then
- if mprop.is_init then
- map["init"].add mprop
- else
- map["fun"].add mprop
- end
- end
- end
- return map
- end
-
private fun mclass_inherited_mprops: Set[MProperty] do
var res = new HashSet[MProperty]
var local = mclass.local_mproperties(ctx.min_visibility)
- for mprop in mclass.inherited_mproperties(ctx.mainmodule, ctx.min_visibility) do
+ for mprop in mclass.inherited_mproperties(mainmodule, ctx.min_visibility) do
if local.has(mprop) then continue
#if mprop isa MMethod and mprop.is_init then continue
if mprop.intro.mclassdef.mclass.name == "Object" and
return res
end
- private fun sort_by_public_owner(mmodules: Collection[MModule]): Map[MModule, Set[MModule]] do
- var map = new HashMap[MModule, Set[MModule]]
- for mmodule in mmodules do
- var owner = mmodule
- if mmodule.public_owner != null then owner = mmodule.public_owner.as(not null)
- if not map.has_key(owner) then map[owner] = new HashSet[MModule]
- map[owner].add mmodule
- end
- return map
- end
-
# Generate dot hierarchy for classes
fun tpl_dot(mclasses: Collection[MClass]): nullable TplArticle do
var poset = new POSet[MClass]
for mclass in mclasses do
poset.add_node mclass
for oclass in mclasses do
+ if mclass == oclass then continue
poset.add_node oclass
- if mclass.in_hierarchy(ctx.mainmodule) < oclass then
+ if mclass.in_hierarchy(mainmodule) < oclass then
poset.add_edge(mclass, oclass)
end
end
end
- var op = new FlatBuffer
- var name = "dep_{mclass.name}"
- op.append("digraph {name} \{ rankdir=BT; node[shape=none,margin=0,width=0,height=0,fontsize=10]; edge[dir=none,color=gray]; ranksep=0.2; nodesep=0.1;\n")
- for c in poset do
+ var op = new RopeBuffer
+ var name = "dep_class_{mclass.nitdoc_id}"
+ 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")
+ var classes = poset.to_a
+ var todo = new Array[MClass]
+ var done = new HashSet[MClass]
+ mainmodule.linearize_mclasses(classes)
+ if not classes.is_empty then todo.add classes.first
+ while not todo.is_empty do
+ var c = todo.shift
+ if done.has(c) then continue
+ done.add c
if c == mclass then
- op.append("\"{c.name}\"[shape=box,margin=0.03];\n")
+ op.append("\"{c.name.escape_to_dot}\"[shape=box,margin=0.03];\n")
else
- op.append("\"{c.name}\"[URL=\"{c.nitdoc_url}\"];\n")
+ op.append("\"{c.name.escape_to_dot}\"[URL=\"{c.nitdoc_url.escape_to_dot}\"];\n")
end
- for c2 in poset[c].direct_greaters do
- op.append("\"{c.name}\"->\"{c2.name}\";\n")
+ var smallers = poset[c].direct_smallers
+ if smallers.length < 10 then
+ for c2 in smallers do
+ op.append("\"{c2.name.escape_to_dot}\"->\"{c.name.escape_to_dot}\";\n")
+ end
+ todo.add_all smallers
+ else
+ op.append("\"...\"->\"{c.name.escape_to_dot}\";\n")
end
end
op.append("\}\n")
- return tpl_graph(op, name, "Inheritance graph")
+ return tpl_graph(op, name, null)
+ end
+end
+
+# Groups properties by kind.
+private class PropertiesByKind
+ # The virtual types.
+ var virtual_types = new PropertyGroup[MVirtualTypeProp]("Virtual types")
+
+ # The constructors.
+ var constructors = new PropertyGroup[MMethod]("Contructors")
+
+ # The attributes.
+ var attributes = new PropertyGroup[MAttribute]("Attributes")
+
+ # The methods.
+ var methods = new PropertyGroup[MMethod]("Methods")
+
+ # The inner classes.
+ var inner_classes = new PropertyGroup[MInnerClass]("Inner classes")
+
+ # All the groups.
+ #
+ # Sorted in the order they are displayed to the user.
+ var groups: SequenceRead[PropertyGroup[MProperty]] = [
+ virtual_types,
+ constructors,
+ attributes,
+ methods,
+ inner_classes: PropertyGroup[MProperty]]
+
+ # Add each the specified property to the appropriate list.
+ init with_elements(properties: Collection[MProperty]) do add_all(properties)
+
+ # Add the specified property to the appropriate list.
+ fun add(property: MProperty) do
+ if property isa MMethod then
+ if property.is_init then
+ constructors.add property
+ else
+ methods.add property
+ end
+ else if property isa MVirtualTypeProp then
+ virtual_types.add property
+ else if property isa MAttribute then
+ attributes.add property
+ else if property isa MInnerClass then
+ inner_classes.add property
+ else
+ abort
+ end
+ end
+
+ # Add each the specified property to the appropriate list.
+ fun add_all(properties: Collection[MProperty]) do
+ for p in properties do add(p)
+ end
+
+ # Sort each group with the specified comparator.
+ fun sort_groups(comparator: Comparator) do
+ for g in groups do comparator.sort(g)
+ end
+end
+
+# A Group of properties of the same kind.
+private class PropertyGroup[E: MProperty]
+ super Array[E]
+
+ # The title of the group, as displayed to the user.
+ var title: String
+end
+
+# A MProperty page
+class NitdocProperty
+ super NitdocPage
+
+ private var mproperty: MProperty
+ private var concerns: ConcernsTree is noinit
+ private var mmodules2mdefs: Map[MModule, Set[MPropDef]] is noinit
+
+ init do
+ self.mproperty = mproperty
+ self.mmodules2mdefs = sort_by_mmodule(collect_mpropdefs)
+ self.concerns = model.concerns_tree(mmodules2mdefs.keys)
+ self.concerns.sort_with(new MConcernRankSorter)
+ end
+
+ private fun collect_mpropdefs: Set[MPropDef] do
+ var res = new HashSet[MPropDef]
+ for mpropdef in mproperty.mpropdefs do
+ if not mpropdef.is_intro then res.add mpropdef
+ end
+ return res
+ end
+
+ private var page = new TplPage
+ redef fun tpl_page do return page
+
+ private var sidebar = new TplSidebar
+ redef fun tpl_sidebar do return sidebar
+
+ redef fun tpl_title do
+ return "{mproperty.nitdoc_name}{mproperty.tpl_signature.write_to_string}"
+ end
+
+ redef fun page_url do return mproperty.nitdoc_url
+
+ redef fun tpl_topmenu do
+ var topmenu = super
+ var mmodule = mproperty.intro_mclassdef.mmodule
+ var mproject = mmodule.mgroup.mproject
+ var mclass = mproperty.intro_mclassdef.mclass
+ topmenu.add_link new TplLink("{mproject.nitdoc_url}", "{mproject.nitdoc_name}")
+ topmenu.add_link new TplLink("{mclass.nitdoc_url}", "{mclass.nitdoc_name}")
+ topmenu.add_link new TplLink(page_url, mproperty.nitdoc_name)
+ return topmenu
+ end
+
+ private fun tpl_intro: TplSection do
+ var title = new Template
+ title.add mproperty.nitdoc_name
+ title.add mproperty.intro.tpl_signature
+ var section = new TplSection.with_title("top", title)
+ section.subtitle = mproperty.tpl_namespace
+ section.summary_title = mproperty.nitdoc_name
+ return section
+ end
+
+ private fun tpl_properties(parent: TplSection) do
+ # intro title
+ var ns = mproperty.intro.mclassdef.mmodule.tpl_namespace
+ var section = new TplSection("intro")
+ var title = new Template
+ title.add "Introduction in "
+ title.add ns
+ section.title = title
+ section.summary_title = "Introduction"
+ section.add_child tpl_mpropdef_article(mproperty.intro)
+ parent.add_child section
+
+ # concerns
+ if concerns.is_empty then return
+ parent.add_child new TplArticle.with_content("Concerns", "Concerns", concerns.to_tpl)
+
+ # redef list
+ var lst = concerns.to_a
+ for mentity in lst do
+ if mentity isa MProject then
+ parent.add_child new TplSection(mentity.nitdoc_id)
+ else if mentity isa MGroup then
+ parent.add_child new TplSection(mentity.nitdoc_id)
+ else if mentity isa MModule then
+ var ssection = new TplSection(mentity.nitdoc_id)
+ title = new Template
+ title.add "in "
+ title.add mentity.tpl_namespace
+ ssection.title = title
+ ssection.summary_title = "in {mentity.nitdoc_name}"
+
+ # properties
+ var mpropdefs = mmodules2mdefs[mentity].to_a
+ name_sorter.sort(mpropdefs)
+ for mpropdef in mpropdefs do
+ ssection.add_child tpl_mpropdef_article(mpropdef)
+ end
+ parent.add_child ssection
+ end
+ end
+ end
+
+ redef fun tpl_content do
+ var top = tpl_intro
+ tpl_properties(top)
+ tpl_page.add_section top
+ end
+
+ private fun sort_by_mmodule(mpropdefs: Collection[MPropDef]): Map[MModule, Set[MPropDef]] do
+ var map = new HashMap[MModule, Set[MPropDef]]
+ for mpropdef in mpropdefs do
+ var mmodule = mpropdef.mclassdef.mmodule
+ if not map.has_key(mmodule) then map[mmodule] = new HashSet[MPropDef]
+ map[mmodule].add mpropdef
+ end
+ return map
end
end