src/doc: introduce option --no-render in HTML phase.
[nit.git] / src / doc / doc_phases / doc_html.nit
index 20bf2c4..30a15c2 100644 (file)
@@ -46,7 +46,7 @@ redef class ToolContext
        # Display a custom brand or logo in the documentation top menu.
        var opt_custom_brand = new OptionString("custom link to external site", "--custom-brand")
 
-       # Display a custom introduction text before the projects overview.
+       # Display a custom introduction text before the packages overview.
        var opt_custom_intro = new OptionString("custom intro text for homepage", "--custom-overview-text")
        # Display a custom footer on each documentation page.
        #
@@ -68,7 +68,10 @@ redef class ToolContext
        # FIXME redo the plugin
        var opt_github_base_sha1 = new OptionString("Git sha1 of base commit used to create pull request", "--github-base-sha1")
        # FIXME redo the plugin
-       var opt_github_gitdir = new OptionString("Git working directory used to resolve path name (ex: /home/me/myproject/)", "--github-gitdir")
+       var opt_github_gitdir = new OptionString("Git working directory used to resolve path name (ex: /home/me/mypackage/)", "--github-gitdir")
+
+       # Do not produce HTML files
+       var opt_no_render = new OptionBool("do not render HTML files", "--no-render")
 
        redef init do
                super
@@ -77,7 +80,8 @@ redef class ToolContext
                        opt_source, opt_sharedir, opt_shareurl, opt_custom_title,
                        opt_custom_footer, opt_custom_intro, opt_custom_brand,
                        opt_github_upstream, opt_github_base_sha1, opt_github_gitdir,
-                       opt_piwik_tracker, opt_piwik_site_id)
+                       opt_piwik_tracker, opt_piwik_site_id,
+                       opt_no_render)
        end
 
        redef fun process_options(args) do
@@ -103,8 +107,9 @@ class RenderHTMLPhase
        var name_sorter = new MEntityNameSorter
 
        redef fun apply do
+               if ctx.opt_no_render.value then return
                init_output_dir
-               for page in doc.pages do
+               for page in doc.pages.values do
                        page.render(self, doc).write_to_file("{ctx.output_dir.to_s}/{page.html_url}")
                end
        end
@@ -133,8 +138,8 @@ class RenderHTMLPhase
 
        end
 
-       # A source link template for a given location
-       fun tpl_showsource(location: nullable Location): nullable String
+       # Returns a HTML link for a given `location`.
+       fun html_source_link(location: nullable Location): nullable String
        do
                if location == null then return null
                var source = ctx.opt_source.value
@@ -170,9 +175,9 @@ redef class DocPage
 
                # build page
                init_title(v, doc)
-               init_sidebar(v, doc)
                init_topmenu(v, doc)
                init_content(v, doc)
+               init_sidebar(v, doc)
 
                # piwik tracking
                var tracker_url = v.ctx.opt_piwik_tracker.value
@@ -187,19 +192,12 @@ redef class DocPage
        # all properties below are roughly copied from `doc_pages`
 
        # Build page title string
-       fun init_title(v: RenderHTMLPhase, doc: DocModel) is abstract
+       fun init_title(v: RenderHTMLPhase, doc: DocModel) do end
 
        # Build top menu template if any.
        fun init_topmenu(v: RenderHTMLPhase, doc: DocModel) do
                topmenu = new DocTopMenu
-               var brand = v.ctx.opt_custom_brand.value
-               if brand != null then
-                       var tpl = new Template
-                       tpl.add "<span class='navbar-brand'>"
-                       tpl.add brand
-                       tpl.add "</span>"
-                       topmenu.brand = tpl
-               end
+               topmenu.brand = v.ctx.opt_custom_brand.value
                var title = "Overview"
                if v.ctx.opt_custom_title.value != null then
                        title = v.ctx.opt_custom_title.value.to_s
@@ -211,11 +209,14 @@ redef class DocPage
 
        # Build page sidebar if any.
        fun init_sidebar(v: RenderHTMLPhase, doc: DocModel) do
-               sidebar = new TplSidebar
+               sidebar = new DocSideBar
+               sidebar.boxes.add new DocSideBox("Summary", html_toc)
        end
 
        # Build page content template.
-       fun init_content(v: RenderHTMLPhase, doc: DocModel) do end
+       fun init_content(v: RenderHTMLPhase, doc: DocModel) do
+               root.init_html_render(v, doc, self)
+       end
 end
 
 redef class OverviewPage
@@ -227,36 +228,6 @@ redef class OverviewPage
                        title = v.ctx.opt_custom_title.value.to_s
                end
        end
-
-       # TODO this should be done in StructurePhase.
-       redef fun init_content(v, doc) do
-               # intro text
-               var section = new TplSection.with_title("overview", title)
-               var article = new TplArticle("intro")
-               if v.ctx.opt_custom_intro.value != null then
-                       article.content = v.ctx.opt_custom_intro.value.to_s
-               end
-               section.add_child article
-               # Projects list
-               var mprojects = doc.model.mprojects.to_a
-               var sorter = new MConcernRankSorter
-               sorter.sort mprojects
-               var ssection = new TplSection.with_title("projects", "Projects")
-               for mproject in mprojects do
-                       var sarticle = mproject.tpl_article
-                       sarticle.subtitle = mproject.html_declaration
-                       sarticle.content = mproject.tpl_definition
-                       var comment = mproject.html_short_comment
-                       if comment != null then
-                               sarticle.content = comment
-                       end
-                       ssection.add_child sarticle
-               end
-               section.add_child ssection
-               self.add_section section
-       end
-
-       redef fun init_sidebar(v, doc) do sidebar = new TplSidebar
 end
 
 redef class SearchPage
@@ -269,116 +240,96 @@ redef class SearchPage
        end
 
        redef fun init_sidebar(v, doc) do end
+end
 
-       # TODO this should be done in StructurePhase.
-       redef fun init_content(v, doc) do
-               var tpl = new TplSearchPage("search_all")
-               var section = new TplSection("search")
-               # title
-               tpl.title = "Index"
-               # modules list
-               for mmodule in modules_list(v, doc) do
-                       tpl.modules.add mmodule.html_link
-               end
-               # classes list
-               for mclass in classes_list(v, doc) do
-                       tpl.classes.add mclass.html_link
-               end
-               # properties list
-               for mproperty in mprops_list(v, doc) do
-                       var m = new Template
-                       m.add mproperty.intro.html_link
-                       m.add " ("
-                       m.add mproperty.intro.mclassdef.mclass.html_link
-                       m.add ")"
-                       tpl.props.add m
-               end
-               section.add_child tpl
-               self.add_section section
-       end
-
-       # Extract mmodule list to display (sorted by name)
-       private fun modules_list(v: RenderHTMLPhase, doc: DocModel): Array[MModule] do
-               var sorted = new Array[MModule]
-               for mmodule in doc.model.mmodule_importation_hierarchy do
-                       if mmodule.is_fictive or mmodule.is_test_suite then continue
-                       sorted.add mmodule
+redef class MEntityPage
+       redef var html_url is lazy do
+               if mentity isa MGroup and mentity.mdoc != null then
+                       return "api_{mentity.nitdoc_url}"
                end
-               v.name_sorter.sort(sorted)
-               return sorted
+               return mentity.nitdoc_url
        end
 
-       # Extract mclass list to display (sorted by name)
-       private fun classes_list(v: RenderHTMLPhase, doc: DocModel): Array[MClass] do
-               var sorted = doc.mclasses.to_a
-               v.name_sorter.sort(sorted)
-               return sorted
-       end
-
-       # Extract mproperty list to display (sorted by name)
-       private fun mprops_list(v: RenderHTMLPhase, doc: DocModel): Array[MProperty] do
-               var sorted = doc.mproperties.to_a
-               v.name_sorter.sort(sorted)
-               return sorted
-       end
-end
-
-redef class MEntityPage
-       redef var html_url is lazy do return mentity.nitdoc_url
        redef fun init_title(v, doc) do title = mentity.html_name
-       redef fun init_content(v, doc) do add_section root.start_rendering(v, doc, self)
 end
 
 # FIXME all clases below are roughly copied from `doc_pages` and adapted to new
 # doc phases. This is to preserve the compatibility with the current
 # `doc_templates` module.
 
+redef class ReadmePage
+       redef var html_url is lazy do return mentity.nitdoc_url
+
+       redef fun init_topmenu(v, doc) do
+               super
+               var mpackage = mentity.mpackage
+               if not mentity.is_root then
+                       topmenu.add_li new ListItem(new Link(mpackage.nitdoc_url, mpackage.html_name))
+               end
+               topmenu.add_li new ListItem(new Link(html_url, mpackage.html_name))
+               topmenu.active_item = topmenu.items.last
+       end
+
+       redef fun init_sidebar(v, doc) do
+               super
+               var api_lnk = """<a href="api_{{{mentity.nitdoc_url}}}">Go to API</a>"""
+               sidebar.boxes.unshift new DocSideBox(api_lnk, "")
+       end
+end
+
 redef class MGroupPage
        redef fun init_topmenu(v, doc) do
                super
-               var mproject = mentity.mproject
+               var mpackage = mentity.mpackage
                if not mentity.is_root then
-                       topmenu.add_li new ListItem(new Link(mproject.nitdoc_url, mproject.html_name))
+                       topmenu.add_li new ListItem(new Link(mpackage.nitdoc_url, mpackage.html_name))
                end
-               topmenu.add_li new ListItem(new Link(html_url, mproject.html_name))
+               topmenu.add_li new ListItem(new Link(html_url, mpackage.html_name))
                topmenu.active_item = topmenu.items.last
        end
 
        redef fun init_sidebar(v, doc) do
                super
+               # README link
+               if mentity.mdoc != null then
+                       var doc_lnk = """<a href="{{{mentity.nitdoc_url}}}">Go to README</a>"""
+                       sidebar.boxes.unshift new DocSideBox(doc_lnk, "")
+               end
+               # MClasses list
                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 list = new UnorderedList
+               list.css_classes.add "list-unstyled list-labeled"
                var sorted = mclasses.to_a
                v.name_sorter.sort(sorted)
                for mclass in sorted do
                        list.add_li tpl_sidebar_item(mclass)
                end
-               sidebar.boxes.add new TplSideBox.with_content("All classes", list)
+               sidebar.boxes.add new DocSideBox("All classes", list)
+               sidebar.boxes.last.is_open = false
        end
 
-       private fun tpl_sidebar_item(def: MClass): TplListItem do
-               var classes = def.intro.tpl_css_classes.to_a
+       private fun tpl_sidebar_item(def: MClass): ListItem do
+               var classes = def.intro.css_classes
                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 new DocHTMLLabel.with_classes(classes)
                lnk.add def.html_link
-               return new TplListItem.with_content(lnk)
+               return new ListItem(lnk)
        end
 end
 
 redef class MModulePage
        redef fun init_topmenu(v, doc) do
                super
-               var mproject = mentity.mproject
-               topmenu.add_li new ListItem(new Link(mproject.nitdoc_url, mproject.html_name))
+               var mpackage = mentity.mpackage
+               topmenu.add_li new ListItem(new Link(mpackage.nitdoc_url, mpackage.html_name))
                topmenu.add_li new ListItem(new Link(mentity.nitdoc_url, mentity.html_name))
                topmenu.active_item = topmenu.items.last
        end
@@ -388,30 +339,32 @@ redef class MModulePage
                # TODO filter here?
                super
                var mclasses = new HashSet[MClass]
-               mclasses.add_all mentity.filter_intro_mclasses(v.ctx.min_visibility)
-               mclasses.add_all mentity.filter_redef_mclasses(v.ctx.min_visibility)
+               mclasses.add_all mentity.collect_intro_mclasses(v.ctx.min_visibility)
+               mclasses.add_all mentity.collect_redef_mclasses(v.ctx.min_visibility)
                if mclasses.is_empty then return
-               var list = new TplList.with_classes(["list-unstyled", "list-labeled"])
+               var list = new UnorderedList
+               list.css_classes.add "list-unstyled list-labeled"
 
                var sorted = mclasses.to_a
                v.name_sorter.sort(sorted)
                for mclass in sorted do
                        list.add_li tpl_sidebar_item(mclass)
                end
-               sidebar.boxes.add new TplSideBox.with_content("All classes", list)
+               sidebar.boxes.add new DocSideBox("All classes", list)
+               sidebar.boxes.last.is_open = false
        end
 
-       private fun tpl_sidebar_item(def: MClass): TplListItem do
-               var classes = def.intro.tpl_css_classes.to_a
+       private fun tpl_sidebar_item(def: MClass): ListItem do
+               var classes = def.intro.css_classes
                if def.intro_mmodule == self.mentity then
                        classes.add "intro"
                else
                        classes.add "redef"
                end
                var lnk = new Template
-               lnk.add new TplLabel.with_classes(classes)
+               lnk.add new DocHTMLLabel.with_classes(classes)
                lnk.add def.html_link
-               return new TplListItem.with_content(lnk)
+               return new ListItem(lnk)
        end
 end
 
@@ -419,8 +372,8 @@ redef class MClassPage
 
        redef fun init_topmenu(v, doc) do
                super
-               var mproject = mentity.intro_mmodule.mgroup.mproject
-               topmenu.add_li new ListItem(new Link(mproject.nitdoc_url, mproject.html_name))
+               var mpackage = mentity.intro_mmodule.mgroup.mpackage
+               topmenu.add_li new ListItem(new Link(mpackage.nitdoc_url, mpackage.html_name))
                topmenu.add_li new ListItem(new Link(html_url, mentity.html_name))
                topmenu.active_item = topmenu.items.last
        end
@@ -428,53 +381,74 @@ redef class MClassPage
        redef fun init_sidebar(v, doc) do
                super
                var by_kind = new PropertiesByKind.with_elements(mclass_inherited_mprops(v, doc))
-               var summary = new TplList.with_classes(["list-unstyled"])
+               var summary = new UnorderedList
+               summary.css_classes.add "list-unstyled"
 
                by_kind.sort_groups(v.name_sorter)
                for g in by_kind.groups do tpl_sidebar_list(g, summary)
-               sidebar.boxes.add new TplSideBox.with_content("All properties", summary)
+               sidebar.boxes.add new DocSideBox("All properties", summary)
+               sidebar.boxes.last.is_open = false
        end
 
-       private fun tpl_sidebar_list(mprops: PropertyGroup[MProperty], summary: TplList) do
+       private fun tpl_sidebar_list(mprops: PropertyGroup[MProperty], summary: UnorderedList) do
                if mprops.is_empty then return
-               var entry = new TplListItem.with_content(mprops.title)
-               var list = new TplList.with_classes(["list-unstyled", "list-labeled"])
+               var list = new UnorderedList
+               list.css_classes.add "list-unstyled list-labeled"
                for mprop in mprops do
                        list.add_li tpl_sidebar_item(mprop)
                end
-               entry.append list
-               summary.elts.add entry
+               var content = new Template
+               content.add mprops.title
+               content.add list
+               var li = new ListItem(content)
+               summary.add_li li
        end
 
-       private fun tpl_sidebar_item(mprop: MProperty): TplListItem do
-               var classes = mprop.intro.tpl_css_classes.to_a
+       private fun tpl_sidebar_item(mprop: MProperty): ListItem do
+               var classes = mprop.intro.css_classes
                if not mprop_is_local(mprop) then
                        classes.add "inherit"
                        var cls_url = mprop.intro.mclassdef.mclass.nitdoc_url
-                       var def_url = "{cls_url}#{mprop.nitdoc_id}"
-                       var lnk = new TplLink(def_url, mprop.html_name)
+                       var def_url = "{cls_url}#{mprop.nitdoc_id}.definition"
+                       var lnk = new Link(def_url, mprop.html_name)
                        var mdoc = mprop.intro.mdoc_or_fallback
-                       if mdoc != null then lnk.title = mdoc.short_comment
+                       if mdoc != null then lnk.title = mdoc.synopsis
                        var item = new Template
-                       item.add new TplLabel.with_classes(classes)
+                       item.add new DocHTMLLabel.with_classes(classes)
                        item.add lnk
-                       return new TplListItem.with_content(item)
+                       return new ListItem(item)
                end
                if mpropdefs.has(mprop.intro) then
                        classes.add "intro"
                else
                        classes.add "redef"
                end
+               var def = select_mpropdef(mprop)
+               var anc = def.html_link_to_anchor
+               anc.href = "#{def.nitdoc_id}.definition"
                var lnk = new Template
-               lnk.add new TplLabel.with_classes(classes)
-               lnk.add mprop.html_link_to_anchor
-               return new TplListItem.with_content(lnk)
+               lnk.add new DocHTMLLabel.with_classes(classes)
+               lnk.add anc
+               return new ListItem(lnk)
+       end
+
+       # Get the mpropdef contained in `self` page for a mprop.
+       #
+       # FIXME this method is used to translate a mprop into a mpropdefs for
+       # section linking. A better page structure should avoid this...
+       private fun select_mpropdef(mprop: MProperty): MPropDef do
+               for mclassdef in mentity.mclassdefs do
+                       for mpropdef in mclassdef.mpropdefs do
+                               if mpropdef.mproperty == mprop then return mpropdef
+                       end
+               end
+               abort # FIXME is there a case where the prop is not found?
        end
 
        private fun mclass_inherited_mprops(v: RenderHTMLPhase, doc: DocModel): Set[MProperty] do
                var res = new HashSet[MProperty]
-               var local = mentity.local_mproperties(v.ctx.min_visibility)
-               for mprop in mentity.inherited_mproperties(doc.mainmodule, v.ctx.min_visibility) do
+               var local = mentity.collect_local_mproperties(v.ctx.min_visibility)
+               for mprop in mentity.collect_inherited_mproperties(v.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
@@ -502,9 +476,9 @@ redef class MPropertyPage
        redef fun init_topmenu(v, doc) do
                super
                var mmodule = mentity.intro_mclassdef.mmodule
-               var mproject = mmodule.mgroup.mproject
+               var mpackage = mmodule.mgroup.mpackage
                var mclass = mentity.intro_mclassdef.mclass
-               topmenu.add_li new ListItem(new Link(mproject.nitdoc_url, mproject.html_name))
+               topmenu.add_li new ListItem(new Link(mpackage.nitdoc_url, mpackage.html_name))
                topmenu.add_li new ListItem(new Link(mclass.nitdoc_url, mclass.html_name))
                topmenu.add_li new ListItem(new Link(html_url, mentity.html_name))
                topmenu.active_item = topmenu.items.last
@@ -512,626 +486,155 @@ redef class MPropertyPage
 end
 
 redef class DocComposite
-       # Render this DocComposite as HTML.
+       # Prepares the HTML rendering for this element.
        #
-       # FIXME needed to maintain TplSection compatibility.
-       fun render(v: RenderHTMLPhase, doc: DocModel, page: MEntityPage, parent: TplSectionElt) is abstract
+       # This visit is mainly used to set template attributes before rendering.
+       fun init_html_render(v: RenderHTMLPhase, doc: DocModel, page: DocPage) do
+               for child in children do child.init_html_render(v, doc, page)
+       end
 end
 
-redef class DocRoot
-
-       # Start the rendering from root.
-       #
-       # FIXME needed to maintain TplSection compatibility.
-       fun start_rendering(v: RenderHTMLPhase, doc: DocModel, page: MEntityPage): TplSection do
-               var section = new TplSection("top")
-               var mentity = page.mentity
-               section.title = mentity.html_name
-               section.subtitle = mentity.html_declaration
-               # FIXME ugly hack to avoid diff
+# FIXME hideous hacks to avoid diff
+redef class MEntitySection
+       redef fun init_html_render(v, doc, page) do
+               if not page isa MEntityPage then return
+               var mentity = self.mentity
                if mentity isa MGroup and mentity.is_root then
-                       section.title = mentity.mproject.html_name
-                       section.subtitle = mentity.mproject.html_declaration
+                       html_title = mentity.mpackage.html_name
+                       html_subtitle = mentity.mpackage.html_declaration
                else if mentity isa MProperty then
-                       section.title = "{mentity.html_name}{mentity.intro.html_signature.write_to_string}"
-                       section.subtitle = mentity.html_namespace
-                       section.summary_title = mentity.html_name
-               end
-               render(v, doc, page, section)
-               return section
-       end
-
-       redef fun render(v, doc, page, parent) do
-               for child in children do
-                       child.render(v, doc, page, parent)
+                       var title = new Template
+                       title.add mentity.html_name
+                       title.add mentity.html_signature
+                       html_title = title
+                       html_subtitle = mentity.html_namespace
+                       html_toc_title = mentity.html_name
                end
+               super
        end
 end
 
+# FIXME hideous hacks to avoid diff
 redef class ConcernSection
-       redef fun render(v, doc, page, parent) do
-               var section = new TplSection(mentity.nitdoc_id)
+       redef fun init_html_render(v, doc, page) do
+               if not page isa MEntityPage then return
                var mentity = self.mentity
-               # FIXME hideous hacks to avoid diff
-               if page.mentity isa MModule and mentity isa MModule then
-                       render_concern_mmodule(page, section, mentity)
-               else if page.mentity isa MClass and mentity isa MModule then
-                       render_concern_other(page, section, mentity)
-               else if page.mentity isa MProperty and mentity isa MModule then
-                       render_concern_other(page, section, mentity)
-               end
-               for child in children do
-                       child.render(v, doc, page, section)
-               end
-               parent.add_child section
-       end
-
-       private fun render_concern_mmodule(page: MEntityPage, section: TplSection, mmodule: MModule) do
-               var title = new Template
-               if mmodule == page.mentity then
+               if page isa MGroupPage then
+                       html_title = null
+                       html_toc_title = mentity.html_name
+                       is_toc_hidden = false
+               else if page.mentity isa MModule and mentity isa MModule then
+                       var title = new Template
+                       if mentity == page.mentity then
+                               title.add "in "
+                               html_toc_title = "in {mentity.html_name}"
+                       else
+                               title.add "from "
+                               html_toc_title = "from {mentity.html_name}"
+                       end
+                       title.add mentity.html_namespace
+                       html_title = title
+               else if (page.mentity isa MClass and mentity isa MModule) or
+                               (page.mentity isa MProperty and mentity isa MModule) then
+                       var title = new Template
                        title.add "in "
-                       section.summary_title = "in {mmodule.html_name}"
-               else
-                       title.add "from "
-                       section.summary_title = "from {mmodule.html_name}"
+                       title.add mentity.html_namespace
+                       html_title = title
+                       html_toc_title = "in {mentity.html_name}"
                end
-               title.add mmodule.html_namespace
-               section.title = title
-       end
-
-       private fun render_concern_other(page: MEntityPage, section: TplSection, mmodule: MModule) do
-               var title = new Template
-               title.add "in "
-               title.add mmodule.html_namespace
-               section.title = title
-               section.summary_title = "in {mmodule.html_name}"
-       end
-end
-
-redef class MEntitySection
-       redef fun render(v, doc, page, parent) do
-               for child in children do child.render(v, doc, page, parent)
+               super
        end
 end
 
+# TODO redo showlink
 redef class IntroArticle
-       redef fun render(v, doc, page, parent) do
-               var article = new TplArticle("intro")
+       redef fun init_html_render(v, doc, page) do
                var mentity = self.mentity
                if mentity isa MModule then
-                       article.source_link = v.tpl_showsource(mentity.location)
+                       html_source_link = v.html_source_link(mentity.location)
                else if mentity isa MClassDef then
-                       article.source_link = v.tpl_showsource(mentity.location)
+                       html_source_link = v.html_source_link(mentity.location)
                else if mentity isa MPropDef then
-                       article.source_link = v.tpl_showsource(mentity.location)
+                       html_source_link = v.html_source_link(mentity.location)
                end
-               # article.subtitle = mentity.html_declaration
-               article.content = write_to_string
-               parent.add_child article
-       end
-end
-
-redef class ConcernsArticle
-       redef fun render(v, doc, page, parent) do
-               parent.add_child new TplArticle.
-                       with_content("concerns", "Concerns", write_to_string)
        end
 end
 
+# FIXME less hideous hacks...
 redef class DefinitionArticle
-       redef fun render(v, doc, page, parent) do
-               var article: TplArticle
+       redef fun init_html_render(v, doc, page) do
                var mentity = self.mentity
-               # FIXME hideous hacks...
-               if mentity isa MModule then
-                       article = mentity.tpl_article
-                       article.subtitle = mentity.html_declaration
-                       article.content = mentity.tpl_definition
-               else if mentity isa MClass then
-                       article = make_mclass_article(v, page)
-               else if mentity isa MClassDef then
-                       article = make_mclassdef_article(v, page)
-                       article.source_link = v.tpl_showsource(mentity.location)
-               else if mentity isa MPropDef and page.mentity isa MClass then
-                       article = make_mpropdef_article(v, doc, page)
-               else
-                       article = mentity.tpl_article
-                       article.subtitle = mentity.html_declaration
-                       if mentity isa MPropDef then
-                               article.source_link = v.tpl_showsource(mentity.location)
-                       end
-               end
-               for child in children do
-                       child.render(v, doc, page, article)
-               end
-               parent.add_child article
-       end
-
-       # FIXME avoid diff while preserving TplArticle compatibility.
-
-       private fun make_mclass_article(v: RenderHTMLPhase, page: MEntityPage): TplArticle do
-               var article = mentity.tpl_article
-               article.subtitle = mentity.html_namespace
-               article.content = null
-               return article
-       end
-
-       private fun make_mclassdef_article(v: RenderHTMLPhase, page: MEntityPage): TplArticle do
-               var mclassdef = mentity.as(MClassDef)
-               var article = mentity.tpl_article
-               if mclassdef.is_intro and mclassdef.mmodule != page.mentity then
-                       article = mentity.tpl_short_article
-               end
-               var title = new Template
-               title.add "in "
-               title.add mclassdef.mmodule.html_namespace
-               article.subtitle = title
-               return article
-       end
-
-       private fun make_mpropdef_article(v: RenderHTMLPhase, doc: DocModel, page: MEntityPage): TplArticle
-       do
-               var mpropdef = mentity.as(MPropDef)
-               var mprop = mpropdef.mproperty
-               var article = new TplArticle(mprop.nitdoc_id)
-               var title = new Template
-               title.add mprop.tpl_icon
-               title.add "<span id='{mpropdef.nitdoc_id}'></span>"
-               if mpropdef.is_intro then
-                       title.add mprop.html_link
-                       title.add mprop.intro.html_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.html_name,
-                                       "Go to introduction")
-                       title.add "redef "
-                       title.add lnk
-               end
-               article.title = title
-               article.title_classes.add "signature"
-               article.summary_title = "{mprop.html_name}"
-               article.subtitle = mpropdef.html_namespace
-               var comment = mpropdef.html_comment
-               if comment != null then
-                       article.content = comment
-               end
-               # TODO move in its own phase? let's see after doc_template refactoring.
-               # Add linearization
-               var all_defs = new HashSet[MPropDef]
-               for local_def in local_defs(page.as(MClassPage), mprop) do
-                       all_defs.add local_def
-                       var smpropdef = local_def
-                       while not smpropdef.is_intro do
-                               smpropdef = smpropdef.lookup_next_definition(
-                                       doc.mainmodule, smpropdef.mclassdef.bound_mtype)
-                               all_defs.add smpropdef
+               if mentity isa MPackage or mentity isa MModule then
+                       var title = new Template
+                       title.add mentity.html_icon
+                       title.add mentity.html_namespace
+                       html_title = title
+                       html_toc_title = mentity.html_name
+                       if mentity isa MModule then
+                               html_source_link = v.html_source_link(mentity.location)
                        end
-               end
-               var lin = all_defs.to_a
-               doc.mainmodule.linearize_mpropdefs(lin)
-               if lin.length > 1 then
-                       var lin_article = new TplArticle("{mpropdef.nitdoc_id}.lin")
-                       lin_article.title = "Inheritance"
-                       var lst = new TplList.with_classes(["list-unstyled", "list-labeled"])
-                       for smpropdef in lin do
-                               lst.add_li smpropdef.tpl_inheritance_item
+               else if mentity isa MClassDef then
+                       var title = new Template
+                       title.add "in "
+                       title.add mentity.mmodule.html_namespace
+                       html_title = mentity.html_declaration
+                       html_subtitle = title
+                       html_toc_title = "in {mentity.html_name}"
+                       html_source_link = v.html_source_link(mentity.location)
+                       if page isa MEntityPage and mentity.is_intro and mentity.mmodule != page.mentity then
+                               is_short_comment = true
                        end
-                       lin_article.content = lst
-                       article.add_child lin_article
-               end
-               return article
-       end
-
-       # Filter `page.mpropdefs` for this `mpropertie`.
-       #
-       # FIXME compatability with current templates.
-       private fun local_defs(page: MClassPage, mproperty: MProperty): HashSet[MPropDef] do
-               var mpropdefs = new HashSet[MPropDef]
-               for mpropdef in page.mpropdefs do
-                       if mpropdef.mproperty == mproperty then
-                               mpropdefs.add mpropdef
+                       if page isa MModulePage then is_toc_hidden = true
+               else if mentity isa MPropDef then
+                       if page isa MClassPage then
+                               var title = new Template
+                               title.add mentity.html_icon
+                               title.add mentity.html_declaration
+                               html_title = title
+                               html_subtitle = mentity.html_namespace
+                               html_toc_title = mentity.html_name
+                       else
+                               var title = new Template
+                               title.add "in "
+                               title.add mentity.mclassdef.html_link
+                               html_title = title
+                               html_toc_title = "in {mentity.mclassdef.html_name}"
                        end
+                       html_source_link = v.html_source_link(mentity.location)
                end
-               return mpropdefs
-       end
-end
-
-redef class IntrosRedefsListArticle
-       redef fun render(v, doc, page, parent) do
-               if mentities.is_empty then return
-               var title = list_title
-               # FIXME diff hack
-               var id = "intros"
-               if title == "Redefines" then id = "redefs"
-               var article = new TplArticle.with_title("{mentity.nitdoc_id}.{id}", title)
-               var list = new TplList.with_classes(["list-unstyled", "list-labeled"])
-               for mentity in mentities do
-                       list.add_li mentity.tpl_list_item
+               if page isa MGroupPage and mentity isa MModule then
+                       is_toc_hidden = true
                end
-               article.content = list
-               parent.add_child article
-       end
-end
-
-# FIXME compatibility with doc_templates.
-redef class ImportationListSection
-       redef fun render(v, doc, page, parent) do
-               var section = new TplSection.with_title("dependencies", "Dependencies")
-               for child in children do
-                       child.render(v, doc, page, section)
-               end
-               parent.add_child section
-       end
-end
-
-# FIXME compatibility with doc_templates.
-redef class InheritanceListSection
-       redef fun render(v, doc, page, parent) do
-               var section = new TplSection.with_title("inheritance", "Inheritance")
-               for child in children do
-                       child.render(v, doc, page, section)
-               end
-               parent.add_child section
+               super
        end
 end
 
-# FIXME compatibility with doc_templates.
-redef class HierarchyListArticle
-       redef fun render(v, doc, page, parent) do
-               if mentities.is_empty then return
-               var title = list_title
-               var id = list_title.to_lower
-               var article = new TplArticle.with_title(id, title)
-               var list = new TplList.with_classes(["list-unstyled", "list-definition"])
-               for mentity in mentities do
-                       list.elts.add mentity.tpl_list_item
+redef class HomeArticle
+       redef fun init_html_render(v, doc, page) do
+               if v.ctx.opt_custom_title.value != null then
+                       self.html_title = v.ctx.opt_custom_title.value.to_s
+                       self.html_toc_title = v.ctx.opt_custom_title.value.to_s
                end
-               article.content = list
-               parent.add_child article
+               self.content = v.ctx.opt_custom_intro.value
+               super
        end
 end
 
 redef class GraphArticle
-       redef fun render(v, doc, page, parent) do
-               var output_dir = v.ctx.output_dir
-               var path = output_dir / id
-               var path_sh = path.escape_to_sh
+       redef fun init_html_render(v, doc, page) do
+               var path = v.ctx.output_dir / graph_id
                var file = new FileWriter.open("{path}.dot")
                file.write(dot)
                file.close
-               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 FileReader.open("{path}.map")
-               var map = fmap.read_all
-               fmap.close
-
-               var article = new TplArticle("graph")
-               var alt = ""
-               # FIXME diff hack
-               # if title != null then
-                       # article.title = title
-                       # alt = "alt='{title.html_escape}'"
-               # end
-               article.css_classes.add "text-center"
-               var content = new Template
-               var name_html = id.html_escape
-               content.add "<img src='{name_html}.png' usemap='#{name_html}' style='margin:auto' {alt}/>"
-               content.add map
-               article.content = content
-               parent.add_child article
-       end
-end
-
-redef class Location
-       # Github url based on this location
-       fun github(gitdir: String): String do
-               var base_dir = getcwd.join_path(gitdir).simplify_path
-               var file_loc = getcwd.join_path(file.filename).simplify_path
-               var gith_loc = file_loc.substring(base_dir.length + 1, file_loc.length)
-               return "{gith_loc}:{line_start},{column_start}--{line_end},{column_end}"
-       end
-end
-
-redef class MEntity
-       # A template article that briefly describe the entity
-       fun tpl_short_article: TplArticle do
-               var tpl = tpl_article
-               var comment = html_short_comment
-               if comment != null then
-                       tpl.content = comment
-               end
-               return tpl
-       end
-
-       # A template article that describe the entity
-       fun tpl_article: TplArticle do
-               var tpl = new TplArticle.with_title(nitdoc_id, tpl_title)
-               tpl.title_classes.add "signature"
-               tpl.subtitle = html_namespace
-               tpl.summary_title = html_name
-               return tpl
-       end
-
-       # A template definition of the mentity
-       # include name, sysnopsys, comment and namespace
-       fun tpl_definition: TplDefinition is abstract
-
-       # A li element that can go in a list
-       fun tpl_list_item: TplListItem do
-               var lnk = new Template
-               lnk.add new TplLabel.with_classes(tpl_css_classes)
-               lnk.add html_link
-               var comment = html_short_comment
-               if comment != null then
-                       lnk.add ": "
-                       lnk.add comment
-               end
-               return new TplListItem.with_content(lnk)
-       end
-
-       var tpl_css_classes = new Array[String]
-
-       # Box title for this mentity
-       fun tpl_title: Template do
-               var title = new Template
-               title.add tpl_icon
-               title.add html_namespace
-               return title
-       end
-
-       # Icon that will be displayed before the title
-       fun tpl_icon: TplIcon do
-               var icon = new TplIcon.with_icon("tag")
-               icon.css_classes.add_all(tpl_css_classes)
-               return icon
-       end
-end
-
-redef class MConcern
-       # Return a li element for `self` that can be displayed in a concern list
-       private fun tpl_concern_item: TplListItem do
-               var lnk = new Template
-               lnk.add html_link_to_anchor
-               var comment = html_short_comment
-               if comment != null then
-                       lnk.add ": "
-                       lnk.add comment
-               end
-               return new TplListItem.with_content(lnk)
-       end
-end
-
-redef class MProject
-       redef fun tpl_definition do
-               var tpl = new TplDefinition
-                       var comment = html_comment
-               if comment != null then
-                       tpl.comment = comment
-               end
-               return tpl
-       end
-
-       redef fun tpl_css_classes do return ["public"]
-end
-
-redef class MGroup
-       redef fun tpl_definition do
-               var tpl = new TplDefinition
-               var comment = html_comment
-               if comment != null then
-                       tpl.comment = comment
-               end
-               return tpl
-       end
-end
-
-redef class MModule
-       redef fun tpl_definition do
-               var tpl = new TplClassDefinition
-               var comment = html_comment
-               if comment != null then
-                       tpl.comment = comment
-               end
-               return tpl
-       end
-
-       redef fun tpl_css_classes do return ["public"]
-end
-
-redef class MClass
-       redef fun tpl_definition do return intro.tpl_definition
-
-       redef fun tpl_title do
-               var title = new Template
-               title.add tpl_icon
-               title.add html_link
-               return title
-       end
-
-       redef fun tpl_icon do return intro.tpl_icon
-       redef fun tpl_css_classes do return intro.tpl_css_classes
-end
-
-redef class MClassDef
-       redef fun tpl_article do
-               var tpl = new TplArticle(nitdoc_id)
-               tpl.summary_title = "in {mmodule.html_name}"
-               tpl.title = html_declaration
-               tpl.title_classes.add "signature"
-               var title = new Template
-               title.add "in "
-               title.add mmodule.html_namespace
-               tpl.subtitle = title
-               var comment = html_comment
-               if comment != null then
-                       tpl.content = comment
-               end
-               return tpl
-       end
-
-       redef fun tpl_title do
-               var title = new Template
-               title.add tpl_icon
-               title.add html_link
-               return title
-       end
-
-       redef fun tpl_definition do
-               var tpl = new TplClassDefinition
-               var comment = html_comment
-               if comment != null then
-                       tpl.comment = comment
-               end
-               return tpl
-       end
-
-       redef fun tpl_css_classes do
-               var set = new HashSet[String]
-               if is_intro then set.add "intro"
-               for m in mclass.intro.modifiers do set.add m.to_cmangle
-               for m in modifiers do set.add m.to_cmangle
-               return set.to_a
-       end
-
-       fun tpl_modifiers: Template do
-               var tpl = new Template
-               for modifier in modifiers do
-                       if modifier == "public" then continue
-                       tpl.add "{modifier.html_escape} "
-               end
-               return tpl
-       end
-end
-
-redef class MProperty
-       redef fun tpl_title do return intro.tpl_title
-       redef fun tpl_icon do return intro.tpl_icon
-       redef fun tpl_css_classes do return intro.tpl_css_classes
-end
-
-redef class MPropDef
-       redef fun tpl_article do
-               var tpl = new TplArticle(nitdoc_id)
-               tpl.summary_title = "in {mclassdef.html_name}"
-               var title = new Template
-               title.add "in "
-               title.add mclassdef.html_link
-               tpl.title = title
-               tpl.subtitle = html_declaration
-               var comment = html_comment
-               if comment != null then
-                       tpl.content = comment
-               end
-               return tpl
-       end
-
-       redef fun tpl_definition do
-               var tpl = new TplDefinition
-               var comment = html_comment
-               if comment != null then
-                       tpl.comment = comment
-               end
-               return tpl
-       end
-
-       redef fun tpl_css_classes do
-               var set = new HashSet[String]
-               if is_intro then set.add "intro"
-               for m in mproperty.intro.modifiers do set.add m.to_cmangle
-               for m in modifiers do set.add m.to_cmangle
-               return set.to_a
-       end
-
-       fun tpl_modifiers: Template do
-               var tpl = new Template
-               for modifier in modifiers do
-                       if modifier == "public" then continue
-                       tpl.add "{modifier.html_escape} "
-               end
-               return tpl
-       end
-
-       redef fun tpl_list_item do
-               var lnk = new Template
-               lnk.add new TplLabel.with_classes(tpl_css_classes.to_a)
-               var atext = html_link.text
-               var ahref = "{mclassdef.mclass.nitdoc_url}#{mproperty.nitdoc_id}"
-               var atitle = html_link.title
-               var anchor = new Link.with_title(ahref, atext, atitle)
-               lnk.add anchor
-               var comment = html_short_comment
-               if comment != null then
-                       lnk.add ": "
-                       lnk.add comment
-               end
-               return new TplListItem.with_content(lnk)
-       end
-
-       fun tpl_inheritance_item: TplListItem do
-               var lnk = new Template
-               lnk.add new TplLabel.with_classes(tpl_css_classes.to_a)
-               lnk.add mclassdef.mmodule.html_namespace
-               lnk.add "::"
-               var atext = mclassdef.html_link.text
-               var ahref = "{mclassdef.mclass.nitdoc_url}#{mproperty.nitdoc_id}"
-               var atitle = mclassdef.html_link.title
-               var anchor = new Link.with_title(ahref, atext, atitle)
-               lnk.add anchor
-               var comment = html_short_comment
-               if comment != null then
-                       lnk.add ": "
-                       lnk.add comment
-               end
-               var li = new TplListItem.with_content(lnk)
-               li.css_classes.add "signature"
-               return li
-       end
-end
-
-redef class ConcernsTree
-
-       private var seen = new HashSet[MConcern]
-
-       redef fun add(p, e) do
-               if seen.has(e) then return
-               seen.add e
-               super(p, e)
-       end
-
-       fun to_tpl: TplList do
-               var lst = new TplList.with_classes(["list-unstyled", "list-definition"])
-               for r in roots do
-                       var li = r.tpl_concern_item
-                       lst.add_li li
-                       build_list(r, li)
-               end
-               return lst
-       end
-
-       private fun build_list(e: MConcern, li: TplListItem) do
-               if not sub.has_key(e) then return
-               var subs = sub[e]
-               var lst = new TplList.with_classes(["list-unstyled", "list-definition"])
-               for e2 in subs do
-                       if e2 isa MGroup and e2.is_root then
-                               build_list(e2, li)
-                       else
-                               var sli = e2.tpl_concern_item
-                               lst.add_li sli
-                               build_list(e2, sli)
-                       end
-               end
-               li.append lst
-       end
-end
-
-redef class MInnerClassDef
-       redef fun tpl_definition do
-               var tpl = new TplClassDefinition
-               var comment = html_comment
-               if comment != null then
-                       tpl.comment = comment
-               end
-               return tpl
+               var proc = new ProcessReader("dot", "-Tsvg", "-Tcmapx", "{path}.dot")
+               var svg = new Buffer
+               var i = 0
+               while not proc.eof do
+                       i += 1
+                       if i < 6 then continue # skip dot default header
+                       svg.append proc.read_line
+               end
+               proc.close
+               self.svg = svg.write_to_string
        end
 end