-# A module page
-# Display the list of introduced and redefined classes in module
-class NitdocModule
- super NitdocPage
-
- private var mmodule: MModule
- private var intro_mclassdefs: Set[MClassDef]
- private var redef_mclassdefs: Set[MClassDef]
- private var sorted_intro_mclassdefs: Array[MClassDef]
- private var sorted_redef_mclassdefs: Array[MClassDef]
-
- init(mmodule: MModule, ctx: NitdocContext) do
- self.mmodule = mmodule
- var sorter = new MClassDefNameSorter
- intro_mclassdefs = in_nesting_intro_mclassdefs(ctx.min_visibility)
- sorted_intro_mclassdefs = intro_mclassdefs.to_a
- sorter.sort sorted_intro_mclassdefs
- redef_mclassdefs = in_nesting_redef_mclassdefs(ctx.min_visibility)
- sorted_redef_mclassdefs = redef_mclassdefs.to_a
- sorter.sort sorted_redef_mclassdefs
- super(ctx)
- end
-
- redef fun tpl_title do
- if mmodule.mdoc != null then
- return "{mmodule.nitdoc_name} module | {mmodule.mdoc.short_comment} | {super}"
- else
- return "{mmodule.nitdoc_name} module | {super}"
- end
- end
-
- redef fun tpl_topmenu do
- var topmenu = super
- topmenu.add_elt("index.html", "Overview", false)
- topmenu.add_elt("#", "{mmodule.nitdoc_name}", true)
- topmenu.add_elt("search.html", "Search", false)
- return topmenu
- end
-
- redef fun tpl_sidebar do
- var sidebar = new TplSidebar
- tpl_sidebar_classes(sidebar)
- tpl_sidebar_inheritance(sidebar)
- return sidebar
- end
-
- # Classes to display on sidebar
- fun tpl_sidebar_classes(sidebar: TplSidebar) do
- var box = new TplSidebarBox("Class Definitions")
- var group = new TplSidebarGroup("Introductions")
- for mclassdef in sorted_intro_mclassdefs do
- tpl_sidebar_item(mclassdef, group)
- end
- box.elts.add group
- group = new TplSidebarGroup("Refinements")
- for mclassdef in sorted_redef_mclassdefs do
- if intro_mclassdefs.has(mclassdef.mclass.intro) then continue
- tpl_sidebar_item(mclassdef, group)
- end
- box.elts.add group
- sidebar.boxes.add box
- end
-
- # Module inheritance to display on sidebar
- fun tpl_sidebar_inheritance(sidebar: TplSidebar) do
- var box = new TplSidebarBox("Module Hierarchy")
- box.elts.add tpl_sidebar_group("Nested Modules", mmodule.in_nesting.direct_greaters.to_a)
- var dependencies = new Array[MModule]
- for dep in mmodule.in_importation.greaters do
- if dep == mmodule or
- dep.direct_owner == mmodule or
- dep.public_owner == mmodule then continue
- dependencies.add(dep)
- end
- if dependencies.length > 0 then
- box.elts.add tpl_sidebar_group("All dependencies", dependencies)
- end
- var clients = new Array[MModule]
- for dep in mmodule.in_importation.smallers do
- if dep.name == "<main>" then continue
- if dep == mmodule then continue
- clients.add(dep)
- end
- if clients.length > 0 then
- box.elts.add tpl_sidebar_group("All clients", clients)
- end
- sidebar.boxes.add box
- end
-
- private fun tpl_sidebar_item(mclassdef: MClassDef, group: TplSidebarGroup) do
- if mclassdef.is_intro then
- group.add_bullet("I", "Introduced", mclassdef.tpl_link_anchor, ["intro"])
- else
- group.add_bullet("R", "Redefined", mclassdef.tpl_link_anchor, ["redef"])
- end
- end
-
- private fun tpl_sidebar_group(name: String, elts: Array[MModule]): TplSidebarGroup do
- var group = new TplSidebarGroup(name)
- for elt in elts do
- group.add_elt(elt.tpl_link, new Array[String])
- end
- return group
- end
-
- redef fun tpl_content do
- var class_sorter = new MClassNameSorter
- var tpl = new TplModulePage
- tpl.title = mmodule.nitdoc_name
- tpl.subtitle = mmodule.tpl_signature
- tpl.definition = mmodule.tpl_definition
- var location = mmodule.location
- tpl.definition.location = tpl_showsource(location)
- tpl.definition.github_area = tpl_github(mmodule.full_namespace, mmodule.mdoc, location)
- tpl.graph = tpl_dot
- for mclassdef in sorted_intro_mclassdefs do tpl.intros.add tpl_mclassdef_article(mclassdef)
- for mclassdef in sorted_redef_mclassdefs do
- if intro_mclassdefs.has(mclassdef.mclass.intro) then continue
- tpl.redefs.add tpl_mclassdef_article(mclassdef)
- end
- return tpl
- end
-
- # Genrate dot hierarchy for class inheritance
- fun tpl_dot: nullable TplGraph do
- # build poset with public owners
- var poset = new POSet[MModule]
- for mmodule in self.mmodule.in_importation.poset do
- if mmodule.name == "<main>" then continue
- #if mmodule.public_owner != null then continue
- if not mmodule.in_importation < self.mmodule and not self.mmodule.in_importation < mmodule and mmodule != self.mmodule then continue
- poset.add_node(mmodule)
- for omodule in mmodule.in_importation.poset do
- if mmodule == omodule then continue
- if omodule.name == "<main>" then continue
- if not omodule.in_importation < self.mmodule and not self.mmodule.in_importation < omodule then continue
- if omodule.in_importation < mmodule then
- poset.add_node(omodule)
- poset.add_edge(omodule, mmodule)
- end
- if mmodule.in_importation < omodule then
- poset.add_node(omodule)
- poset.add_edge(mmodule, omodule)
- end
- #if omodule.public_owner != null then continue
- #if mmodule.in_importation < omodule then
- #poset.add_node(omodule)
- #poset.add_edge(mmodule, omodule)
- #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")
- for mmodule in poset do
- if mmodule == self.mmodule then
- op.append("\"{mmodule.name}\"[shape=box,margin=0.03];\n")
- else
- op.append("\"{mmodule.name}\"[URL=\"{mmodule.nitdoc_url}\"];\n")
- end
- for omodule in poset[mmodule].direct_greaters do
- op.append("\"{mmodule.name}\"->\"{omodule.name}\";\n")
- end
- end
- op.append("\}\n")
- return tpl_graph(op, name, "Dependency graph for module {mmodule.name}")
- end
-
- private fun in_nesting_intro_mclassdefs(min_visibility: MVisibility): Set[MClassDef] do
- var res = new HashSet[MClassDef]
- for mmodule in self.mmodule.in_nesting.greaters do
- res.add_all mmodule.intro_mclassdefs(min_visibility)
- end
- return res
- end
-
- private fun in_nesting_redef_mclassdefs(min_visibility: MVisibility): Set[MClassDef] do
- var res = new HashSet[MClassDef]
- for mmodule in self.mmodule.in_nesting.greaters do
- res.add_all mmodule.redef_mclassdefs(min_visibility)
- end
- return res
- end
-end
-
-# A class page
-# Display a list properties defined or redefined for this class
-class NitdocClass
- super NitdocPage
-
- private var mclass: MClass
- private var inherited_mpropdefs: Set[MPropDef]
- private var intro_mpropdefs: Set[MPropDef]
- private var redef_mpropdefs: Set[MPropDef]
- private var all_mpropdefs: Set[MPropDef]
-
- init(mclass: MClass, ctx: NitdocContext) do
- self.mclass = mclass
- super(ctx)
- intro_mpropdefs = mclass_intro_mpropdefs
- redef_mpropdefs = mclass_redef_mpropdefs
- inherited_mpropdefs = in_nesting_inherited_mpropedefs
- all_mpropdefs = new HashSet[MPropDef]
- all_mpropdefs.add_all intro_mpropdefs
- all_mpropdefs.add_all redef_mpropdefs
- all_mpropdefs.add_all inherited_mpropdefs
- end
-
- private fun in_nesting_inherited_mpropedefs: Set[MPropDef] do
- var res = new HashSet[MPropDef]
- var local = mclass.local_mproperties(ctx.min_visibility)
- for mprop in mclass.inherited_mproperties(ctx.mainmodule, ctx.min_visibility) do
- if local.has(mprop) then continue
- if mprop isa MMethod and mprop.is_init then continue
- res.add mprop.intro
- end
- return res
- end
-
- private fun mclass_intro_mpropdefs: Set[MPropDef] do
- var res = new HashSet[MPropDef]
- for mclassdef in mclass.mclassdefs do
- if mclassdef != mclass.intro then continue
- for mpropdef in mclassdef.mpropdefs do
- var mprop = mpropdef.mproperty
- if mprop isa MMethod and mprop.is_init and mclass.is_abstract then continue
- if mprop.visibility < ctx.min_visibility then continue
- res.add mpropdef
- end
- end
- return res
- end
-
- private fun mclass_redef_mpropdefs: Set[MPropDef] do
- var res = new HashSet[MPropDef]
- for mclassdef in mclass.mclassdefs do
- if mclassdef == mclass.intro then continue
- for mpropdef in mclassdef.mpropdefs do
- if mclassdef.mmodule.public_owner == mclass.public_owner then continue
- if mpropdef.mproperty.visibility < ctx.min_visibility then continue
- res.add mpropdef
- end
- end
- return res
- end
-
- redef fun tpl_title do
- if mclass.mdoc != null then
- return "{mclass.nitdoc_name} class | {mclass.mdoc.short_comment} | {super}"
- else
- return "{mclass.nitdoc_name} class | {super}"
- end
- end
-
- redef fun tpl_topmenu do
- var topmenu = super
- var mmodule: MModule
- if mclass.public_owner == null then
- mmodule = mclass.intro_mmodule
- else
- mmodule = mclass.public_owner.as(not null)
- end
- topmenu.add_elt("index.html", "Overview", false)
- topmenu.add_elt("{mmodule.nitdoc_url}", "{mmodule.nitdoc_name}", false)
- topmenu.add_elt("#", "{mclass.nitdoc_name}", true)
- topmenu.add_elt("search.html", "Search", false)
- return topmenu
- end
-
- redef fun tpl_sidebar do
- var sidebar = new TplSidebar
- tpl_sidebar_properties(sidebar)
- tpl_sidebar_inheritance(sidebar)
- return sidebar
- end
-
- # Property list to display in sidebar
- fun tpl_sidebar_properties(sidebar: TplSidebar) do
- var kind_map = sort_by_kind(all_mpropdefs)
- var sorter = new MPropDefNameSorter
- var box = new TplSidebarBox("Properties")
- # virtual types
- var elts = kind_map["type"].to_a
- sorter.sort(elts)
- var group = new TplSidebarGroup("Virtual Types")
- for mprop in elts do
- tpl_sidebar_item(mprop, group)
- end
- box.elts.add group
- # constructors
- elts = kind_map["init"].to_a
- sorter.sort(elts)
- group = new TplSidebarGroup("Constructors")
- for mprop in elts do
- tpl_sidebar_item(mprop, group)
- end
- box.elts.add group
- # methods
- elts = kind_map["fun"].to_a
- sorter.sort(elts)
- group = new TplSidebarGroup("Methods")
- for mprop in elts do
- tpl_sidebar_item(mprop, group)
- end
- box.elts.add group
- sidebar.boxes.add box
- end
-
- # Class inheritance to display in sidebar
- fun tpl_sidebar_inheritance(sidebar: TplSidebar) do
- var sorted = new Array[MClass]
- var sorterp = new MClassNameSorter
- var box = new TplSidebarBox("Inheritance")
- var greaters = mclass.in_hierarchy(ctx.mainmodule).greaters.to_a
- if greaters.length > 1 then
- ctx.mainmodule.linearize_mclasses(greaters)
- box.elts.add tpl_sidebar_group("Superclasses", greaters)
- end
- var smallers = mclass.in_hierarchy(ctx.mainmodule).smallers.to_a
- var direct_smallers = mclass.in_hierarchy(ctx.mainmodule).direct_smallers.to_a
- if smallers.length <= 1 then
- box.elts.add(new TplSidebarGroup("No Known Subclasses"))
- else if smallers.length <= 100 then
- ctx.mainmodule.linearize_mclasses(smallers)
- box.elts.add tpl_sidebar_group("Subclasses", smallers)
- else if direct_smallers.length <= 100 then
- ctx.mainmodule.linearize_mclasses(direct_smallers)
- box.elts.add tpl_sidebar_group("Direct Subclasses Only", direct_smallers)
- else
- box.elts.add(new TplSidebarGroup("Too much Subclasses to list"))
- end
- sidebar.boxes.add box
- end
-
- private fun tpl_sidebar_item(mprop: MPropDef, group: TplSidebarGroup) do
- if mprop.is_intro and mprop.mclassdef.mclass == mclass then
- group.add_bullet("I", "Introduced", mprop.tpl_link, ["intro"])
- else if mprop.is_intro and mprop.mclassdef.mclass != mclass then
- group.add_bullet("H", "Inherited", mprop.tpl_link, ["inherit"])
- else
- group.add_bullet("R", "Redefined", mprop.tpl_link, ["redef"])
- end
- end
-
- private fun tpl_sidebar_group(name: String, elts: Array[MClass]): TplSidebarGroup do
- var group = new TplSidebarGroup(name)
- for elt in elts do
- if elt == mclass then continue
- group.add_elt(elt.tpl_link, new Array[String])
- end
- return group
- end
-
- redef fun tpl_content do
- var intro = mclass.intro
- var tpl = new TplClassPage
- tpl.title = "{mclass.nitdoc_name}{mclass.tpl_short_signature}"
- tpl.subtitle = mclass.tpl_namespace_with_signature
- tpl.definition = intro.tpl_definition
- var location = intro.location
- tpl.definition.location = tpl_showsource(location)
- tpl.definition.github_area = tpl_github(intro.full_namespace, intro.mdoc, location)
- tpl.graph = tpl_dot
-
- # properties
- var prop_sorter = new MPropDefNameSorter
- var kind_map = sort_by_kind(intro_mpropdefs)
-
- # virtual types
- var elts = kind_map["type"].to_a
- prop_sorter.sort(elts)
- for elt in elts do tpl.types.add tpl_mpropdef_article(elt)
-
- # constructors
- elts = kind_map["init"].to_a
- prop_sorter.sort(elts)
- for elt in elts do tpl.inits.add tpl_mpropdef_article(elt)
-
- # intro methods
- elts = kind_map["fun"].to_a
- prop_sorter.sort(elts)
- for elt in elts do tpl.methods.add tpl_mpropdef_article(elt)
-
- # redef methods
- kind_map = sort_by_kind(redef_mpropdefs)
- var module_sorter = new MModuleNameSorter
- var module_map = sort_by_mmodule(kind_map["fun"])
- var owner_map = sort_by_public_owner(module_map.keys)
- var owners = owner_map.keys.to_a
- module_sorter.sort owners
-
- var ctpl = new TplConcernList
- var mtpl = new Template
- for owner in owners do
- # concerns list
- var octpl = new TplConcernListElt
- octpl.anchor = "#{owner.nitdoc_anchor}"
- octpl.name = owner.nitdoc_name
- if owner.mdoc != null then
- octpl.comment = owner.mdoc.short_comment
- end
- ctpl.elts.add octpl
- # concern section
- var otpl = new TplTopConcern
- otpl.anchor = owner.nitdoc_anchor
- otpl.concern = owner.tpl_link
- mtpl.add otpl
-
- var mmodules = owner_map[owner].to_a
- module_sorter.sort mmodules
- var stpl = new TplConcernList
- for mmodule in mmodules do
- # concerns list
- var mctpl = new TplConcernListElt
- mctpl.anchor = "#{mmodule.nitdoc_anchor}"
- mctpl.name = mmodule.nitdoc_name
- if mmodule.mdoc != null then
- mctpl.comment = mmodule.mdoc.short_comment
- end
- stpl.elts.add mctpl
- # concern sectionm
- var cctpl = new TplConcern
- cctpl.anchor = mmodule.nitdoc_anchor
- cctpl.concern = mmodule.tpl_link
- if mmodule.mdoc != null then
- cctpl.comment = mmodule.mdoc.short_comment
- end
- mtpl.add cctpl
-
- var mprops = module_map[mmodule].to_a
- prop_sorter.sort mprops
- for mprop in mprops do mtpl.add tpl_mpropdef_article(mprop)
- end
- ctpl.elts.add stpl
- end
- if not owners.is_empty then
- tpl.concerns = ctpl
- end
- tpl.methods.add mtpl
- return tpl
- end
-
- private fun sort_by_kind(mpropdefs: Set[MPropDef]): Map[String, Set[MPropDef]] do
- var map = new HashMap[String, Set[MPropDef]]
- map["type"] = new HashSet[MPropDef]
- map["init"] = new HashSet[MPropDef]
- map["fun"] = new HashSet[MPropDef]
- for mpropdef in mpropdefs do
- if mpropdef isa MVirtualTypeDef then
- map["type"].add mpropdef
- else if mpropdef isa MMethodDef then
- if mpropdef.mproperty.is_init then
- map["init"].add mpropdef
- else
- map["fun"].add mpropdef