model: use the robust `intro_mmodule` instead of `intro.mmodule`.
[nit.git] / src / doc / doc_phases / doc_structure.nit
index 384f603..d84a739 100644 (file)
@@ -16,6 +16,7 @@
 module doc_structure
 
 import doc_concerns
+import modelize
 
 # StructurePhase populates the DocPage content with section and article.
 #
@@ -32,10 +33,8 @@ class StructurePhase
 
        # Populates the given DocModel.
        redef fun apply do
-               for page in doc.pages do page.apply_structure(self, doc)
+               for page in doc.pages.values do page.apply_structure(self, doc)
        end
-
-       # TODO index and search page should also be structured here
 end
 
 redef class DocPage
@@ -48,79 +47,94 @@ end
 
 redef class OverviewPage
        redef fun apply_structure(v, doc) do
-               var article = new HomeArticle
+               var article = new HomeArticle("home.article", "Home")
                root.add_child article
-               # Projects list
-               var mprojects = doc.model.mprojects.to_a
+               # Packages list
+               var mpackages = doc.model.mpackages.to_a
                var sorter = new MConcernRankSorter
-               sorter.sort mprojects
-               var section = new ProjectsSection
-               for mproject in mprojects do
-                       section.add_child new DefinitionArticle(mproject)
+               sorter.sort mpackages
+               var section = new DocSection("packages.section", "Packages")
+               for mpackage in mpackages do
+                       section.add_child new DefinitionArticle("{mpackage.nitdoc_id}.definition", null, mpackage)
                end
                article.add_child section
        end
 end
 
+redef class SearchPage
+       redef fun apply_structure(v, doc) do
+               var mmodules = doc.mmodules.to_a
+               v.name_sorter.sort(mmodules)
+               var mclasses = doc.mclasses.to_a
+               v.name_sorter.sort(mclasses)
+               var mprops = doc.mproperties.to_a
+               v.name_sorter.sort(mprops)
+               root.add_child new IndexArticle("index.article", null, mmodules, mclasses, mprops)
+       end
+end
+
 redef class MGroupPage
        redef fun apply_structure(v, doc) do
-               var section = new MEntitySection(mentity)
+               var section = new MEntitySection("{mentity.nitdoc_name}.section", null, mentity)
                root.add_child section
                if mentity.is_root then
-                       section.add_child new IntroArticle(mentity.mproject)
+                       section.add_child new IntroArticle("{mentity.mpackage.nitdoc_id}.intro", null, mentity.mpackage)
                else
-                       section.add_child new IntroArticle(mentity)
+                       section.add_child new IntroArticle("{mentity.nitdoc_id}.intro", null, mentity)
                end
                var concerns = self.concerns
                if concerns == null or concerns.is_empty then return
                # FIXME avoid diff
-               mentity.mproject.booster_rank = -1000
+               mentity.mpackage.booster_rank = -1000
                mentity.booster_rank = -1000
                concerns.sort_with(v.concerns_sorter)
-               mentity.mproject.booster_rank = 0
+               mentity.mpackage.booster_rank = 0
                mentity.booster_rank = 0
-               section.add_child new ConcernsArticle(mentity, concerns)
+               section.add_child new ConcernsArticle("{mentity.nitdoc_id}.concerns", null, mentity, concerns)
                for mentity in concerns do
+                       var ssection = new ConcernSection("{mentity.nitdoc_id}.concern", null, mentity)
                        if mentity isa MModule then
-                               section.add_child new DefinitionArticle(mentity)
-                       else
-                               section.add_child new ConcernSection(mentity)
+                               ssection.add_child new DefinitionArticle("{mentity.nitdoc_id}.definition", null, mentity)
                        end
+                       section.add_child ssection
                end
        end
 end
 
 redef class MModulePage
        redef fun apply_structure(v, doc) do
-               var section = new MEntitySection(mentity)
+               var section = new MEntitySection("{mentity.nitdoc_name}.section", null, mentity)
                root.add_child section
-               section.add_child new IntroArticle(mentity)
+               section.add_child new IntroArticle("{mentity.nitdoc_id}.intro", null, mentity)
                var concerns = self.concerns
                if concerns == null or concerns.is_empty then return
                # FIXME avoid diff
-               mentity.mgroup.mproject.booster_rank = -1000
+               mentity.mgroup.mpackage.booster_rank = -1000
                mentity.mgroup.booster_rank = -1000
                mentity.booster_rank = -1000
                concerns.sort_with(v.concerns_sorter)
-               mentity.mgroup.mproject.booster_rank = 0
+               mentity.mgroup.mpackage.booster_rank = 0
                mentity.mgroup.booster_rank = 0
                mentity.booster_rank = 0
-               section.add_child new ConcernsArticle(mentity, concerns)
+               section.add_child new ConcernsArticle("{mentity.nitdoc_id}.concerns", null, mentity, concerns)
                # reference list
                for mentity in concerns do
-                       var ssection = new ConcernSection(mentity)
+                       var ssection = new ConcernSection("{mentity.nitdoc_id}.concern", null, mentity)
                        if mentity isa MModule then
                                var mclasses = mclasses_for_mmodule(mentity).to_a
                                v.name_sorter.sort(mclasses)
                                for mclass in mclasses do
-                                       var article = new DefinitionArticle(mclass)
+                                       var article = new DefinitionListArticle(
+                                               "{mclass.intro.nitdoc_id}.definition-list", null, mclass)
                                        var mclassdefs = mclassdefs_for(mclass).to_a
                                        if not mclassdefs.has(mclass.intro) then
-                                               article.add_child(new DefinitionArticle(mclass.intro))
+                                               article.add_child(new DefinitionArticle(
+                                                       "{mclass.intro.nitdoc_id}.definition", null, mclass.intro))
                                        end
                                        doc.mainmodule.linearize_mclassdefs(mclassdefs)
                                        for mclassdef in mclassdefs do
-                                               article.add_child(new DefinitionArticle(mclassdef))
+                                               article.add_child(new DefinitionArticle(
+                                                       "{mclassdef.nitdoc_id}.definition", null, mclassdef))
                                        end
                                        ssection.add_child article
                                end
@@ -133,7 +147,7 @@ redef class MModulePage
        private fun mclasses_for_mmodule(mmodule: MModule): Set[MClass] do
                var mclasses = new HashSet[MClass]
                for mclass in self.mclasses do
-                       if mclass.intro.mmodule == mmodule then
+                       if mclass.intro_mmodule == mmodule then
                                mclasses.add mclass
                        end
                end
@@ -154,22 +168,28 @@ end
 
 redef class MClassPage
        redef fun apply_structure(v, doc) do
-               var section = new MEntitySection(mentity)
+               var section = new MEntitySection("{mentity.nitdoc_name}.section", null, mentity)
                root.add_child section
-               section.add_child new IntroArticle(mentity)
+               section.add_child new IntroArticle("{mentity.nitdoc_id}.intro", null, mentity)
                var concerns = self.concerns
                if concerns == null or concerns.is_empty then return
                # FIXME diff hack
-               mentity.intro_mmodule.mgroup.mproject.booster_rank = -1000
+               mentity.intro_mmodule.mgroup.mpackage.booster_rank = -1000
                mentity.intro_mmodule.mgroup.booster_rank = -1000
                mentity.intro_mmodule.booster_rank = -1000
                concerns.sort_with(v.concerns_sorter)
-               mentity.intro_mmodule.mgroup.mproject.booster_rank = 0
+               mentity.intro_mmodule.mgroup.mpackage.booster_rank = 0
                mentity.intro_mmodule.mgroup.booster_rank = 0
                mentity.intro_mmodule.booster_rank = 0
-               section.add_child new ConcernsArticle(mentity, concerns)
+               var constructors = new DocSection("{mentity.nitdoc_id}.constructors", "Constructors")
+               var minit = mentity.root_init
+               if minit != null then
+                       constructors.add_child new DefinitionArticle("{minit.nitdoc_id}.definition", null, minit)
+               end
+               section.add_child constructors
+               section.add_child new ConcernsArticle("{mentity.nitdoc_id}.concerns", null, mentity, concerns)
                for mentity in concerns do
-                       var ssection = new ConcernSection(mentity)
+                       var ssection = new ConcernSection("{mentity.nitdoc_id}.concern", null, mentity)
                        if mentity isa MModule then
                                var mprops = mproperties_for(mentity)
                                var by_kind = new PropertiesByKind.with_elements(mprops)
@@ -177,7 +197,14 @@ redef class MClassPage
                                        v.name_sorter.sort(group)
                                        for mprop in group do
                                                for mpropdef in mpropdefs_for(mprop, mentity) do
-                                                       ssection.add_child new DefinitionArticle(mpropdef)
+                                                       if mpropdef isa MMethodDef and mpropdef.mproperty.is_init then
+                                                               if mpropdef == minit then continue
+                                                               constructors.add_child new DefinitionArticle(
+                                                                       "{mpropdef.nitdoc_id}.definition", null, mpropdef)
+                                                       else
+                                                               ssection.add_child new DefinitionArticle(
+                                                                       "{mpropdef.nitdoc_id}.definition", null, mpropdef)
+                                                       end
                                                end
                                        end
                                end
@@ -216,28 +243,29 @@ end
 
 redef class MPropertyPage
        redef fun apply_structure(v, doc) do
-               var section = new MEntitySection(mentity)
+               var section = new MEntitySection("{mentity.nitdoc_name}.section", null, mentity)
                root.add_child section
-               section.add_child new IntroArticle(mentity)
+               section.add_child new IntroArticle("{mentity.nitdoc_id}.intro", null, mentity)
                var concerns = self.concerns
                if concerns == null or concerns.is_empty then return
                # FIXME diff hack
-               mentity.intro.mclassdef.mmodule.mgroup.mproject.booster_rank = -1000
+               mentity.intro.mclassdef.mmodule.mgroup.mpackage.booster_rank = -1000
                mentity.intro.mclassdef.mmodule.mgroup.booster_rank = -1000
                mentity.intro.mclassdef.mmodule.booster_rank = -1000
                concerns.sort_with(v.concerns_sorter)
-               mentity.intro.mclassdef.mmodule.mgroup.mproject.booster_rank = 0
+               mentity.intro.mclassdef.mmodule.mgroup.mpackage.booster_rank = 0
                mentity.intro.mclassdef.mmodule.mgroup.booster_rank = 0
                mentity.intro.mclassdef.mmodule.booster_rank = 0
-               section.add_child new ConcernsArticle(mentity, concerns)
+               section.add_child new ConcernsArticle("{mentity.nitdoc_id}.concerns", null, mentity, concerns)
                for mentity in concerns do
-                       var ssection = new ConcernSection(mentity)
+                       var ssection = new ConcernSection("{mentity.nitdoc_id}.concern", null, mentity)
                        if mentity isa MModule then
                                # Add mproperties
                                var mpropdefs = mpropdefs_for(mentity).to_a
                                v.name_sorter.sort(mpropdefs)
                                for mpropdef in mpropdefs do
-                                       ssection.add_child new DefinitionArticle(mpropdef)
+                                       ssection.add_child new DefinitionArticle(
+                                               "{mpropdef.nitdoc_id}.definition", null, mpropdef)
                                end
                        end
                        section.add_child ssection
@@ -256,10 +284,24 @@ redef class MPropertyPage
        end
 end
 
+# A group of sections that can be displayed together in a tab.
+#
+# Display the first child and hide less relevant data in other panels.
+class TabbedGroup
+       super DocSection
+end
+
+# A group of sections that can be displayed together in a tab panel.
+class PanelGroup
+       super DocSection
+end
+
 # A DocComposite element about a MEntity.
 class MEntityComposite
        super DocComposite
 
+       redef fun title do return mentity.nitdoc_name
+
        # MEntity documented by this page element.
        var mentity: MEntity
 end
@@ -270,6 +312,8 @@ end
 class ConcernSection
        super MEntityComposite
        super DocSection
+
+       redef fun is_toc_hidden do return is_hidden
 end
 
 # An article about a Mentity.
@@ -280,6 +324,17 @@ abstract class MEntityArticle
        super DocArticle
 end
 
+# An article that displays a list of mentities.
+class MEntitiesListArticle
+       super DocArticle
+
+       # MEntities to display.
+       var mentities: Array[MEntity]
+
+       redef fun is_hidden do return mentities.is_empty
+end
+
+
 # A section about a Mentity.
 #
 # Used to regroup content about a MEntity.
@@ -294,6 +349,9 @@ end
 class IntroArticle
        super MEntityComposite
        super DocArticle
+
+       redef var is_hidden = false
+       redef var is_toc_hidden = true
 end
 
 # An article that display a ConcernsTreee as a list.
@@ -302,19 +360,114 @@ class ConcernsArticle
 
        # Concerns to list in this article.
        var concerns: ConcernsTree
+
+       redef fun is_hidden do return concerns.is_empty
+end
+
+# An article that displays a list of definition belonging to a MEntity.
+class DefinitionListArticle
+       super TabbedGroup
+       super MEntityArticle
 end
 
 # An article that display the definition text of a MEntity.
 class DefinitionArticle
        super MEntityArticle
+
+       redef var is_hidden = false
 end
 
-# The main project article.
+# The main package article.
 class HomeArticle
        super DocArticle
 end
 
-# The project list.
-class ProjectsSection
+# An article that display an index of mmodules, mclasses and mproperties.
+class IndexArticle
        super DocArticle
+
+       # List of mmodules to display.
+       var mmodules: Array[MModule]
+
+       # List of mclasses to display.
+       var mclasses: Array[MClass]
+
+       # List of mproperties to display.
+       var mprops: Array[MProperty]
+
+       redef fun is_hidden do
+               return mmodules.is_empty and mclasses.is_empty and mprops.is_empty
+       end
+end
+
+# Concerns ranking
+
+# Sort MConcerns based on the module importation hierarchy ranking
+# see also: `MConcern::concern_rank` and `MConcern::booster_rank`
+#
+# Comparison is made with the formula:
+#
+# ~~~nitish
+# a.concern_rank + a.booster_rank <=> b.concern_rank + b.booster_ran
+# ~~~
+#
+# If both `a` and `b` have the same ranking,
+# ordering is based on lexicographic comparison of `a.name` and `b.name`
+class MConcernRankSorter
+       super Comparator
+       redef type COMPARED: MConcern
+
+       redef fun compare(a, b) do
+               if a.concern_rank == b.concern_rank then
+                       return a.name <=> b.name
+               end
+               return a.concern_rank + a.booster_rank <=> b.concern_rank + b.booster_rank
+       end
+end
+
+redef class MConcern
+
+       # Boost a MConcern rank
+       # see: `MConcernRankSorter`
+       # Use a positive booster to push down a result in the list
+       # A negative booster can be used to push up the result
+       var booster_rank: Int = 0 is writable
+
+       # Concern ranking used for ordering
+       # see: `MConcernRankSorter`
+       # Rank can be positive or negative
+       fun concern_rank: Int is abstract
+end
+
+redef class MPackage
+       redef var concern_rank is lazy do
+               var max = 0
+               for mgroup in mgroups do
+                       var mmax = mgroup.concern_rank
+                       if mmax > max then max = mmax
+               end
+               return max + 1
+       end
+end
+
+redef class MGroup
+       redef var concern_rank is lazy do
+               var max = 0
+               for mmodule in mmodules do
+                       var mmax = mmodule.concern_rank
+                       if mmax > max then max = mmax
+               end
+               return max + 1
+       end
+end
+
+redef class MModule
+       redef var concern_rank is lazy do
+               var max = 0
+               for p in in_importation.direct_greaters do
+                       var pmax = p.concern_rank
+                       if pmax > max then max = pmax
+               end
+               return max + 1
+       end
 end