nitx: no more refinement of to_s methods
[nit.git] / src / ni_nitdoc.nit
index f0d7ce5..017f09f 100644 (file)
@@ -18,6 +18,7 @@ module ni_nitdoc
 
 import model_utils
 import modelize_property
+import markdown
 
 # The NitdocContext contains all the knowledge used for doc generation
 class NitdocContext
@@ -46,8 +47,6 @@ class NitdocContext
        private var opt_custom_footer_text: OptionString = new OptionString("Text displayed as footer of all pages", "--custom-footer-text")
 
        init do
-               self.arguments = toolcontext.option_context.rest
-               toolcontext.option_context.options.clear
                toolcontext.option_context.add_option(opt_dir)
                toolcontext.option_context.add_option(opt_source)
                toolcontext.option_context.add_option(opt_sharedir)
@@ -58,8 +57,10 @@ class NitdocContext
                toolcontext.option_context.add_option(opt_custom_overview_text)
                toolcontext.option_context.add_option(opt_custom_menu_items)
                toolcontext.process_options
+               self.arguments = toolcontext.option_context.rest
 
                if arguments.length < 1 then
+                       print "usage: nitdoc [options] file..."
                        toolcontext.option_context.usage
                        exit(1)
                end
@@ -93,9 +94,9 @@ class NitdocContext
                else
                        var dir = "NIT_DIR".environ
                        if dir.is_empty then
-                               dir = "{sys.program_name.dirname}/../share/nitdoc"
+                               dir = "{sys.program_name.dirname}/../share/ni_nitdoc"
                        else
-                               dir = "{dir}/share/nitdoc"
+                               dir = "{dir}/share/ni_nitdoc"
                        end
                        share_dir = dir
                        if share_dir is null then
@@ -209,6 +210,7 @@ abstract class NitdocPage
                append("<script type='text/javascript' src='scripts/github.js'></script>")
                append("<script type='text/javascript' src='scripts/js-facilities.js'></script>")
                append("<link rel='stylesheet' href='styles/main.css' type='text/css' media='screen'/>")
+               append("<link rel='stylesheet' href='styles/github.css' type='text/css' media='screen'/>")
                var title = ""
                if ctx.opt_custom_title.value != null then
                        title = " | {ctx.opt_custom_title.value.to_s}"
@@ -489,12 +491,37 @@ class NitdocModule
 
        private var mmodule: MModule
        private var mbuilder: ModelBuilder
+       private var local_mclasses = new HashSet[MClass]
+       private var intro_mclasses = new HashSet[MClass]
+       private var redef_mclasses = new HashSet[MClass]
+       private var inherited_mclasses = new HashSet[MClass]
 
        init(mmodule: MModule, ctx: NitdocContext, dot_dir: nullable String) do
                super(ctx)
                self.mmodule = mmodule
                self.mbuilder = ctx.mbuilder
                self.dot_dir = dot_dir
+               # get local mclasses
+               for m in mmodule.in_nesting.greaters do
+                       for mclassdef in m.mclassdefs do
+                               if mclassdef.mclass.visibility < ctx.min_visibility then continue
+                               if mclassdef.is_intro then
+                                       intro_mclasses.add(mclassdef.mclass)
+                               else
+                                       redef_mclasses.add(mclassdef.mclass)
+                               end
+                               local_mclasses.add(mclassdef.mclass)
+                       end
+               end
+               # get inherited mclasses
+               for m in mmodule.in_importation.greaters do
+                       if m == mmodule then continue
+                       for mclassdef in m.mclassdefs do
+                               if mclassdef.mclass.visibility < ctx.min_visibility then continue
+                               if local_mclasses.has(mclassdef.mclass) then continue
+                               inherited_mclasses.add(mclassdef.mclass)
+                       end
+               end
        end
 
        redef fun title do
@@ -514,59 +541,34 @@ class NitdocModule
        end
 
        redef fun content do
-               sidebar
+               append("<div class='menu'>")
+               classes_column
+               importation_column
+               append("</div>")
                var footed = ""
                if ctx.opt_custom_footer_text.value != null then footed = "footed"
                append("<div class='content {footed}'>")
-               append("<h1>{mmodule.name}</h1>")
-               append("<div class='subtitle info'>")
-               mmodule.html_signature(self)
-               append("</div>")
-               mmodule.html_full_comment(self)
-               process_generate_dot
-               classes
-               properties
+               module_doc
                append("</div>")
        end
 
-       private fun process_generate_dot 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 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 Buffer
-               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.url}\"];\n")
-                       end
-                       for omodule in poset[mmodule].direct_greaters do
-                               op.append("\"{mmodule.name}\"->\"{omodule.name}\";\n")
-                       end
+       private fun classes_column do
+               var sorter = new MClassNameSorter
+               var sorted = new Array[MClass]
+               sorted.add_all(local_mclasses)
+               sorter.sort(sorted)
+               if not sorted.is_empty then
+                       append("<nav class='properties filterable'>")
+                       append("<h3>Classes</h3>")
+                       append("<h4>Classes</h4>")
+                       append("<ul>")
+                       for mclass in sorted do mclass.html_sidebar_item(self)
+                       append("</ul>")
+                       append("</nav>")
                end
-               op.append("\}\n")
-               generate_dot(op.to_s, name, "Dependency graph for module {mmodule.name}")
        end
 
-       private fun sidebar do
-               append("<div class='menu'>")
+       private fun importation_column do
                append("<nav>")
                append("<h3>Module Hierarchy</h3>")
                var dependencies = new Array[MModule]
@@ -574,6 +576,10 @@ class NitdocModule
                        if dep == mmodule or dep.public_owner != null then continue
                        dependencies.add(dep)
                end
+               if mmodule.in_nesting.direct_greaters.length > 0 then
+                       append("<h4>Nested Modules</h4>")
+                       display_module_list(mmodule.in_nesting.direct_greaters.to_a)
+               end
                if dependencies.length > 0 then
                        append("<h4>All dependencies</h4>")
                        display_module_list(dependencies)
@@ -589,15 +595,6 @@ class NitdocModule
                        display_module_list(clients)
                end
                append("</nav>")
-               if ctx.min_visibility < protected_visibility then
-                       if mmodule.in_nesting.direct_greaters.length > 0 then
-                               append("<nav>")
-                               append("<h3>Nested Modules</h3>")
-                               display_module_list(mmodule.in_nesting.direct_greaters.to_a)
-                               append("</nav>")
-                       end
-               end
-               append("</div>")
        end
 
        private fun display_module_list(list: Array[MModule]) do
@@ -612,65 +609,106 @@ class NitdocModule
                append("</ul>")
        end
 
-       # display the class column
-       private fun classes do
-               var intro_mclasses = mmodule.intro_mclasses
-               var redef_mclasses = mmodule.redef_mclasses
-               var all_mclasses = new HashSet[MClass]
-               for m in mmodule.in_nesting.greaters do
-                       all_mclasses.add_all(m.intro_mclasses)
-                       all_mclasses.add_all(m.redef_mclasses)
+       private fun module_doc do
+               # title
+               append("<h1>{mmodule.name}</h1>")
+               append("<div class='subtitle info'>")
+               mmodule.html_signature(self)
+               append("</div>")
+               # comment
+               var nmodule = ctx.mbuilder.mmodule2nmodule[mmodule]
+               append("<section class='description'>")
+               if not nmodule.full_comment.is_empty then append("<div>{nmodule.full_comment}</div>")
+               process_generate_dot
+               append("</section>")
+               # classes
+               var class_sorter = new MClassNameSorter
+               # intro
+               if not intro_mclasses.is_empty then
+                       var sorted = new Array[MClass]
+                       sorted.add_all(intro_mclasses)
+                       class_sorter.sort(sorted)
+                       append("<section class='classes'>")
+                       append("<h2 class='section-header'>Introduced classes</h2>")
+                       for mclass in sorted do mclass.html_full_desc(self)
+                       append("</section>")
                end
-               all_mclasses.add_all(intro_mclasses)
-               all_mclasses.add_all(redef_mclasses)
-
-               var sorted = new Array[MClass]
-               sorted.add_all(all_mclasses)
-               var sorter = new MClassNameSorter
-               sorter.sort(sorted)
-               append("<div class='module'>")
-               append("<article class='classes filterable'>")
-               append("<h2>Classes</h2>")
-               append("<ul>")
-               for c in sorted do
-                       if c.visibility < ctx.min_visibility then continue
-                       if redef_mclasses.has(c) and c.intro_mmodule.public_owner != mmodule then
-                               append("<li class='redef'>")
-                               append("<span title='refined in this module'>R </span>")
-                       else
-                               append("<li class='intro'>")
-                               append("<span title='introduced in this module'>I </span>")
+               # redefs
+               var redefs = new Array[MClass]
+               for mclass in redef_mclasses do if not intro_mclasses.has(mclass) then redefs.add(mclass)
+               class_sorter.sort(redefs)
+               if not redefs.is_empty then
+                       append("<section class='classes'>")
+                       append("<h2 class='section-header'>Refined classes</h2>")
+                       for mclass in redefs do mclass.html_full_desc(self)
+                       append("</section>")
+               end
+               # inherited properties
+               var inherited = new Array[MClass]
+               inherited.add_all(inherited_mclasses)
+               if inherited_mclasses.length > 0 then
+                       var modules2classes = new ArrayMap[MModule, Array[MClass]]
+                       for mclass in inherited_mclasses do
+                               if not modules2classes.has_key(mclass.intro_mmodule) then modules2classes[mclass.intro_mmodule] = new Array[MClass]
+                               modules2classes[mclass.intro_mmodule].add(mclass)
                        end
-                       c.html_link(self)
-                       append("</li>")
+                       append("<section class='classes'>")
+                       append("<h2 class='section-header'>Inherited Classes</h2>")
+                       var mmodules = new Array[MModule]
+                       mmodules.add_all(modules2classes.keys)
+                       var msorter = new MModuleNameSorter
+                       msorter.sort(mmodules)
+                       for m in mmodules do
+                               var mclasses = modules2classes[m]
+                               class_sorter.sort(mclasses)
+                               append("<p>Defined in ")
+                               m.html_link(self)
+                               append(": ")
+                               for i in [0..mclasses.length[ do
+                                       var mclass = mclasses[i]
+                                       mclass.html_link(self)
+                                       if i <= mclasses.length - 1 then append(", ")
+                               end
+                       append("</p>")
+                       end
+                       append("</section>")
                end
-               append("</ul>")
-               append("</article>")
-               append("</div>")
        end
 
-       # display the property column
-       private fun properties do
-               # get properties
-               var mpropdefs = new HashSet[MPropDef]
-               for m in mmodule.in_nesting.greaters do
-                       for c in m.mclassdefs do mpropdefs.add_all(c.mpropdefs)
+       private fun process_generate_dot 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 omodule.public_owner != null then continue
+                               if mmodule.in_importation < omodule then
+                                       poset.add_node(omodule)
+                                       poset.add_edge(mmodule, omodule)
+                               end
+                       end
                end
-               for c in mmodule.mclassdefs do mpropdefs.add_all(c.mpropdefs)
-               var sorted = mpropdefs.to_a
-               var sorter = new MPropDefNameSorter
-               sorter.sort(sorted)
-               # display properties in one column
-               append("<article class='properties filterable'>")
-               append("<h2>Properties</h2>")
-               append("<ul>")
-               for mprop in sorted do
-                       if mprop isa MAttributeDef then continue
-                       if mprop.mproperty.visibility < ctx.min_visibility then continue
-                       mprop.html_list_item(self)
+               # build graph
+               var op = new Buffer
+               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.url}\"];\n")
+                       end
+                       for omodule in poset[mmodule].direct_greaters do
+                               op.append("\"{mmodule.name}\"->\"{omodule.name}\";\n")
+                       end
                end
-               append("</ul>")
-               append("</article>")
+               op.append("\}\n")
+               generate_dot(op.to_s, name, "Dependency graph for module {mmodule.name}")
        end
 end
 
@@ -690,6 +728,7 @@ class NitdocClass
                self.dot_dir = dot_dir
                self.source = source
                # load properties
+               var locals = new HashSet[MProperty]
                for mclassdef in mclass.mclassdefs do
                        for mpropdef in mclassdef.mpropdefs do
                                if mpropdef.mproperty.visibility < ctx.min_visibility then continue
@@ -701,6 +740,7 @@ class NitdocClass
                                                meths.add(mpropdef)
                                        end
                                end
+                               locals.add(mpropdef.mproperty)
                        end
                end
                # get inherited properties
@@ -710,6 +750,7 @@ class NitdocClass
                                for mprop in pclassdef.intro_mproperties do
                                        var mpropdef = mprop.intro
                                        if mprop.visibility < ctx.min_visibility then continue
+                                       if locals.has(mprop) then continue
                                        if mpropdef isa MVirtualTypeDef then vtypes.add(mpropdef)
                                        if mpropdef isa MMethodDef then
                                                if mpropdef.mproperty.is_init then
@@ -859,13 +900,16 @@ class NitdocClass
 
        private fun class_doc do
                # title
-               append("<h1>{mclass.signature}</h1>")
+               append("<h1>{mclass.name}{mclass.html_short_signature}</h1>")
                append("<div class='subtitle info'>")
-               mclass.html_full_signature(self)
-               append("</div>")
+               if mclass.visibility < public_visibility then append("{mclass.visibility.to_s} ")
+               append("{mclass.kind.to_s} ")
+               mclass.html_namespace(self)
+               append("{mclass.html_short_signature}</div>")
                # comment
                var nclass = ctx.mbuilder.mclassdef2nclassdef[mclass.intro]
                append("<section class='description'>")
+               if nclass isa AStdClassdef and not nclass.full_comment.is_empty then append("<div>{nclass.full_comment}</div>")
                process_generate_dot
                append("</section>")
                # concerns
@@ -939,7 +983,7 @@ class NitdocClass
                        end
                        # virtual types
                        prop_sorter.sort(local_vtypes)
-                       for prop in local_vtypes do prop.html_full_desc(self)
+                       for prop in local_vtypes do prop.html_full_desc(self, self.mclass)
                        append("</section>")
                end
                # constructors
@@ -949,7 +993,7 @@ class NitdocClass
                if local_consts.length > 0 then
                        append("<section class='constructors'>")
                        append("<h2 class='section-header'>Constructors</h2>")
-                       for prop in local_consts do prop.html_full_desc(self)
+                       for prop in local_consts do prop.html_full_desc(self, self.mclass)
                        append("</section>")
                end
                # methods
@@ -973,7 +1017,7 @@ class NitdocClass
                                if concern2meths.has_key(owner) then
                                        var mmethods = concern2meths[owner]
                                        prop_sorter.sort(mmethods)
-                                       for prop in mmethods do prop.html_full_desc(self)
+                                       for prop in mmethods do prop.html_full_desc(self, self.mclass)
                                end
                                for mmodule in mmodules do
                                        append("<a id=\"{mmodule.anchor}\"></a>")
@@ -988,9 +1032,10 @@ class NitdocClass
                                        end
                                        var mmethods = concern2meths[mmodule]
                                        prop_sorter.sort(mmethods)
-                                       for prop in mmethods do prop.html_full_desc(self)
+                                       for prop in mmethods do prop.html_full_desc(self, self.mclass)
                                end
                        end
+                       append("</section>")
                end
                # inherited properties
                if inherited.length > 0 then
@@ -1003,7 +1048,8 @@ class NitdocClass
                                if not classes.has_key(mclass) then classes[mclass] = new Array[MPropDef]
                                classes[mclass].add(mmethod)
                        end
-                       append("<h3>Inherited Properties</h3>")
+                       append("<section class='inherited'>")
+                       append("<h2 class='section-header'>Inherited Properties</h2>")
                        for c, mmethods in classes do
                                prop_sorter.sort(mmethods)
                                append("<p>Defined in ")
@@ -1016,8 +1062,8 @@ class NitdocClass
                                end
                                append("</p>")
                        end
+                       append("</section>")
                end
-               append("</section>")
        end
 
        private fun process_generate_dot do
@@ -1154,30 +1200,81 @@ redef class MModule
        fun html_full_comment(page: NitdocPage) do
                if page.ctx.mbuilder.mmodule2nmodule.has_key(self) then
                        page.append("<div id='description'>")
-                       page.append("<pre class='text_label'>{page.ctx.mbuilder.mmodule2nmodule[self].full_comment}</pre>")
+                       page.append("<div>{page.ctx.mbuilder.mmodule2nmodule[self].full_comment}</div>")
                        page.append("</div>")
                end
        end
+
+       private fun has_mclassdef_for(mclass: MClass): Bool do
+               for mmodule in self.in_nesting.greaters do
+                       for mclassdef in mmodule.mclassdefs do
+                               if mclassdef.mclass == mclass then return true
+                       end
+               end
+               return false
+       end
+
+       private fun has_mclassdef(mclassdef: MClassDef): Bool do
+               for mmodule in self.in_nesting.greaters do
+                       for oclassdef in mmodule.mclassdefs do
+                               if mclassdef == oclassdef then return true
+                       end
+               end
+               return false
+       end
 end
 
 redef class MClass
-       # Return the module signature decorated with html
-       fun html_full_signature(page: NitdocPage) do
-               if visibility < public_visibility then page.append("{visibility.to_s} ")
-               page.append("{kind} ")
-               html_namespace(page)
+       # return the generic signature of the class
+       #       [E, F]
+       private fun html_short_signature: String do
+               if arity > 0 then
+                       return "[{intro.parameter_names.join(", ")}]"
+               else
+                       return ""
+               end
        end
 
-       # name with formal parameter
-       # Foo[A, B]
-       private fun signature: String do
+       # return the generic signature of the class with bounds
+       #       [E: <a>MType</a>, F: <a>MType</a>]
+       private fun html_signature(page: NitdocPage) do
                if arity > 0 then
-                       return "{name}[{intro.parameter_names.join(", ")}]"
-               else
-                       return name
+                       page.append("[")
+                       for i in [0..intro.parameter_names.length[ do
+                               page.append("{intro.parameter_names[i]}: ")
+                               intro.bound_mtype.arguments[i].html_link(page)
+                               if i < intro.parameter_names.length - 1 then page.append(", ")
+                       end
+                       page.append("]")
                end
        end
 
+       # Return the class namespace decorated with html
+       private fun html_namespace(page: NitdocPage) do
+               intro_mmodule.html_namespace(page)
+               page.append("::<span>")
+               html_short_link(page)
+               page.append("</span>")
+       end
+
+       # Return a link (html a tag) to the nitdoc class page
+       fun html_short_link(page: NitdocPage) do
+               if html_short_link_cache == null then
+                       var res = new Buffer
+                       res.append("<a href='{url}'")
+                       if page.ctx.mbuilder.mclassdef2nclassdef.has_key(intro) then
+                               var nclass = page.ctx.mbuilder.mclassdef2nclassdef[intro]
+                               if nclass isa AStdClassdef then
+                                       res.append(" title=\"{nclass.short_comment}\"")
+                               end
+                       end
+                       res.append(">{name}</a>")
+                       html_short_link_cache = res.to_s
+               end
+               page.append(html_short_link_cache.as(not null))
+       end
+       private var html_short_link_cache: nullable String
+
        # Return a link (html a tag) to the nitdoc class page
        fun html_link(page: NitdocPage) do
                if html_link_cache == null then
@@ -1189,20 +1286,37 @@ redef class MClass
                                        res.append(" title=\"{nclass.short_comment}\"")
                                end
                        end
-                       res.append(">{signature}</a>")
+                       res.append(">{name}{html_short_signature}</a>")
                        html_link_cache = res.to_s
                end
                page.append(html_link_cache.as(not null))
        end
        private var html_link_cache: nullable String
 
-       # Return the class namespace decorated with html
-       fun html_namespace(page: NitdocPage) do
-               intro_mmodule.html_namespace(page)
-               page.append("::<span>")
-               html_link(page)
-               page.append("</span>")
+       fun html_anchor(page: NitdocPage) do
+               if html_anchor_cache == null then
+                       var res = new Buffer
+                       res.append("<a href='#{anchor}'")
+                       if page.ctx.mbuilder.mclassdef2nclassdef.has_key(intro) then
+                               var nclass = page.ctx.mbuilder.mclassdef2nclassdef[intro]
+                               if nclass isa AStdClassdef then
+                                       res.append(" title=\"{nclass.short_comment}\"")
+                               end
+                       end
+                       res.append(">{name}{html_short_signature}</a>")
+                       html_anchor_cache = res.to_s
+               end
+               page.append(html_anchor_cache.as(not null))
        end
+       private var html_anchor_cache: nullable String
+
+       fun anchor: String do
+               if anchor_cache == null then
+                       anchor_cache = "CLASS_{public_owner.name}_{name}"
+               end
+               return anchor_cache.as(not null)
+       end
+       private var anchor_cache: nullable String
 
        fun url: String do
                return "class_{public_owner}_{name}.html"
@@ -1210,12 +1324,101 @@ redef class MClass
 
        # Escape name for html output
        redef fun name do return super.html_escape
+
+       # Return a list item for the mclass
+       private fun html_sidebar_item(page: NitdocModule) do
+               if page.mmodule.in_nesting.greaters.has(intro.mmodule) then
+                       page.append("<li class='intro'>")
+                       page.append("<span title='Introduced'>I</span>")
+                       html_anchor(page)
+               else if page.mmodule.has_mclassdef_for(self) then
+                       page.append("<li class='redef'>")
+                       page.append("<span title='Redefined'>R</span>")
+                       html_anchor(page)
+               else
+                       page.append("<li class='inherit'>")
+                       page.append("<span title='Inherited'>H</span>")
+                       html_link(page)
+               end
+               page.append("</li>")
+       end
+
+       private fun html_full_desc(page: NitdocModule) do
+               var classes = new Array[String]
+               classes.add(kind.to_s)
+               if not page.mmodule.in_nesting.greaters.has(intro.mmodule) then classes.add("redef")
+               classes.add(visibility.to_s)
+               page.append("<article class='{classes.join(" ")}' id='{anchor}'>")
+               page.append("<h3 class='signature' data-untyped-signature='{name}{html_short_signature}'>")
+               page.append("<span>")
+               html_short_link(page)
+               html_signature(page)
+               page.append("</span></h3>")
+               html_info(page)
+               html_comment(page)
+               html_redefs(page)
+               page.append("</article>")
+       end
+
+       private fun html_info(page: NitdocModule) do
+               page.append("<div class='info'>")
+               if visibility < public_visibility then page.append("{visibility.to_s} ")
+               if not page.mmodule.in_nesting.greaters.has(intro.mmodule) then page.append("redef ")
+               page.append("{kind} ")
+               html_namespace(page)
+               page.append("{html_short_signature}</div>")
+       end
+
+       private fun html_comment(page: NitdocModule) do
+               page.mmodule.linearize_mclassdefs(mclassdefs)
+               page.append("<div class='description'>")
+               # comments for each mclassdef contained in current mmodule
+               for mclassdef in mclassdefs do
+                       if not mclassdef.is_intro and not page.mmodule.mclassdefs.has(mclassdef) then continue
+                       if page.ctx.mbuilder.mclassdef2nclassdef.has_key(mclassdef) then
+                               var nclass = page.ctx.mbuilder.mclassdef2nclassdef[mclassdef]
+                               if nclass isa AStdClassdef then
+                                       if nclass.full_comment == "" then
+                                               page.append("<p class='info inheritance'>")
+                                               page.append("<span class=\"noComment\">no comment for </span>")
+                                       else
+                                               page.append("<div>{nclass.full_comment}</div>")
+                                               page.append("<p class='info inheritance'>")
+                                       end
+                                       if mclassdef.is_intro then
+                                               page.append("introduction in ")
+                                       else
+                                               page.append("refinement in ")
+                                       end
+                                       mclassdef.mmodule.html_full_namespace(page)
+                                       page.append(" {page.show_source(nclass.location)}</p>")
+                               end
+                       end
+               end
+               page.append("</div>")
+       end
+       
+       private fun html_redefs(page: NitdocModule) do
+               page.mmodule.linearize_mclassdefs(mclassdefs)
+               page.append("<div class='refinements'>")
+               # comments for each mclassdef contained in current mmodule
+               for mclassdef in mclassdefs do
+                       if not page.mmodule.mclassdefs.has(mclassdef) then continue
+                       if mclassdef.is_intro then continue
+                       for mpropdef in mclassdef.mpropdefs do
+                               if mpropdef isa MAttributeDef then continue
+                               mpropdef.html_full_desc(page, self)
+                       end
+               end
+               page.append("</div>")
+       end
 end
 
 redef class MProperty
        # Return the property namespace decorated with html
        fun html_namespace(page: NitdocPage) do
                intro_mclassdef.mclass.html_namespace(page)
+               page.append(intro_mclassdef.mclass.html_short_signature)
                page.append("::<span>")
                intro.html_link(page)
                page.append("</span>")
@@ -1306,22 +1509,6 @@ redef class MPropDef
        private var html_link_cache: nullable String
 
        # Return a list item for the mpropdef
-       private fun html_list_item(page: NitdocPage) do
-               if is_intro then
-                       page.append("<li class='intro'>")
-                       page.append("<span title='introduction'>I</span>&nbsp;")
-               else
-                       page.append("<li class='redef'>")
-                       page.append("<span title='redefinition'>R</span>&nbsp;")
-               end
-               html_link(page)
-               page.append("(")
-               mclassdef.mclass.html_link(page)
-               page.append(")")
-               page.append("</li>")
-       end
-
-       # Return a list item for the mpropdef
        private fun html_sidebar_item(page: NitdocClass) do
                if is_intro and mclassdef.mclass == page.mclass then
                        page.append("<li class='intro'>")
@@ -1337,104 +1524,55 @@ redef class MPropDef
                page.append("</li>")
        end
 
-       private fun html_full_desc(page: NitdocClass) is abstract
-       private fun html_info(page: NitdocClass) is abstract
+       private fun html_full_desc(page: NitdocPage, ctx: MClass) is abstract
+       private fun html_info(page: NitdocPage, ctx: MClass) is abstract
 
        fun full_name: String do
                return "{mclassdef.mclass.public_owner.name}::{mclassdef.mclass.name}::{mproperty.name}"
        end
 
-       private fun html_inheritance(page: NitdocClass) do
-               # definitions block
-               page.append("<p class='info'>")
-               page.ctx.mainmodule.linearize_mpropdefs(mproperty.mpropdefs)
-               var previous_defs = new Array[MPropDef]
-               var next_defs = new Array[MPropDef]
-               var self_passed = false
-               for def in mproperty.mpropdefs do
-                       if def == self then
-                               self_passed = true
-                               continue
-                       end
-                       if not self_passed then
-                               if def.mclassdef.mclass.in_hierarchy(page.ctx.mainmodule) < page.mclass then continue
-                               if def.is_intro then continue
-                               previous_defs.add(def)
-                       else
-                               if page.mclass.in_hierarchy(page.ctx.mainmodule) < def.mclassdef.mclass then continue
-                               next_defs.add(def)
-                       end
-               end
-               page.append("defined by ")
-               mclassdef.mmodule.html_full_namespace(page)
-               if page.ctx.mbuilder.mpropdef2npropdef.has_key(self) then
-                       page.append(" {page.show_source(page.ctx.mbuilder.mpropdef2npropdef[self].location)}")
-               end
+       private fun html_comment(page: NitdocPage) do
+               page.append("<div class='description'>")
                if not is_intro then
-                       page.append(", introduced by ")
-                       mproperty.intro.mclassdef.mclass.html_link(page)
-                       if page.ctx.mbuilder.mpropdef2npropdef.has_key(self) then
-                               page.append(" {page.show_source(page.ctx.mbuilder.mpropdef2npropdef[self].location)}")
-                       end
-               end
-               if not previous_defs.is_empty then
-                       page.append(", inherited from ")
-                       for i in [0..previous_defs.length[ do
-                               var def = previous_defs[i]
-                               def.mclassdef.mclass.html_link(page)
-                               if page.ctx.mbuilder.mpropdef2npropdef.has_key(def) then
-                                       page.append(" {page.show_source(page.ctx.mbuilder.mpropdef2npropdef[def].location)}")
+                       if page.ctx.mbuilder.mpropdef2npropdef.has_key(mproperty.intro) then
+                               var intro_nprop = page.ctx.mbuilder.mpropdef2npropdef[mproperty.intro]
+                               if intro_nprop.full_comment.is_empty then
+                                       page.append("<p class='info inheritance'>")
+                                       page.append("<span class=\"noComment\">no comment for </span>")
+                               else
+                                       page.append("<div>{intro_nprop.full_comment}</div>")
+                                       page.append("<p class='info inheritance'>")
                                end
-
-                               if i < previous_defs.length - 1 then page.append(", ")
+                               page.append("introduction in ")
+                               mproperty.intro.mclassdef.html_namespace(page)
+                               page.append(" {page.show_source(intro_nprop.location)}</p>")
                        end
                end
-               if not next_defs.is_empty then
-                       page.append(", redefined by ")
-                       for i in [0..next_defs.length[ do
-                               var def = next_defs[i]
-                               def.mclassdef.mclass.html_link(page)
-                               if page.ctx.mbuilder.mpropdef2npropdef.has_key(def) then
-                                       page.append(" {page.show_source(page.ctx.mbuilder.mpropdef2npropdef[def].location)}")
-                               end
-                               if i < next_defs.length - 1 then page.append(", ")
-                       end
-               end
-               page.append(".</p>")
-       end
-
-       private fun html_comment(page: NitdocClass) do
-               if not page.ctx.mbuilder.mpropdef2npropdef.has_key(self) then return
-               var nprop = page.ctx.mbuilder.mpropdef2npropdef[self]
-               page.append("<div class='description'>")
-               if not is_intro and page.ctx.mbuilder.mpropdef2npropdef.has_key(mproperty.intro) then
-                       var intro_nprop = page.ctx.mbuilder.mpropdef2npropdef[mproperty.intro]
-                       page.append("<p class='info'>from ")
-                       mproperty.html_namespace(page)
-                       page.append("</p>")
-                       if intro_nprop.full_comment == "" then
-                               page.append("<span class=\"noComment\">No comment</span>")
+               if page.ctx.mbuilder.mpropdef2npropdef.has_key(self) then
+                       var nprop = page.ctx.mbuilder.mpropdef2npropdef[self]
+                       if nprop.full_comment == "" then
+                               page.append("<p class='info inheritance'>")
+                               page.append("<span class=\"noComment\">no comment for </span>")
                        else
-                               page.append("<pre>{intro_nprop.full_comment}</pre>")
+                               page.append("<div>{nprop.full_comment}</div>")
+                               page.append("<p class='info inheritance'>")
+                       end
+                       if is_intro then
+                               page.append("introduction in ")
+                       else 
+                               page.append("redefinition in ")
                        end
-                       page.append("<p class='info'>from ")
                        mclassdef.html_namespace(page)
-                       page.append("</p>")
+                       page.append(" {page.show_source(nprop.location)}</p>")
                end
-               if nprop.full_comment == "" then
-                       page.append("<span class=\"noComment\">No comment</span>")
-               else
-                       page.append("<pre>{nprop.full_comment}</pre>")
-               end
-               html_inheritance(page)
                page.append("</div>")
        end
 end
 
 redef class MMethodDef
-       redef fun html_full_desc(page) do
+       redef fun html_full_desc(page, ctx) do
                var classes = new Array[String]
-               var is_redef = mproperty.intro_mclassdef.mclass != page.mclass
+               var is_redef = mproperty.intro_mclassdef.mclass != ctx
                if mproperty.is_init then
                        classes.add("init")
                else
@@ -1454,15 +1592,15 @@ redef class MMethodDef
                        msignature.html_signature(page)
                        page.append("</span></h3>")
                end
-               html_info(page)
+               html_info(page, ctx)
                html_comment(page)
                page.append("</article>")
        end
-
-       redef fun html_info(page) do
+       
+       redef fun html_info(page, ctx) do
                page.append("<div class='info'>")
                if mproperty.visibility < public_visibility then page.append("{mproperty.visibility.to_s} ")
-               if mproperty.intro_mclassdef.mclass != page.mclass then page.append("redef ")
+               if mproperty.intro_mclassdef.mclass != ctx then page.append("redef ")
                if mproperty.is_init then
                        page.append("init ")
                else
@@ -1474,8 +1612,8 @@ redef class MMethodDef
 end
 
 redef class MVirtualTypeDef
-       redef fun html_full_desc(page) do
-               var is_redef = mproperty.intro_mclassdef.mclass != page.mclass
+       redef fun html_full_desc(page, ctx) do
+               var is_redef = mproperty.intro_mclassdef.mclass != ctx
                var classes = new Array[String]
                classes.add("type")
                if is_redef then classes.add("redef")
@@ -1484,14 +1622,14 @@ redef class MVirtualTypeDef
                page.append("<h3 class='signature' data-untyped-signature='{mproperty.name}'><span>{mproperty.name}: ")
                bound.html_link(page)
                page.append("</span></h3>")
-               html_info(page)
+               html_info(page, ctx)
                html_comment(page)
                page.append("</article>")
        end
 
-       redef fun html_info(page) do
+       redef fun html_info(page, ctx) do
                page.append("<div class='info'>")
-               if mproperty.intro_mclassdef.mclass != page.mclass then page.append("redef ")
+               if mproperty.intro_mclassdef.mclass != ctx then page.append("redef ")
                page.append("type ")
                mproperty.html_namespace(page)
                page.append("</div>")
@@ -1549,13 +1687,10 @@ redef class AModule
        end
 
        private fun full_comment: String do
-               var res = new Buffer
                if n_moduledecl != null and n_moduledecl.n_doc != null then
-                       for t in n_moduledecl.n_doc.n_comment do
-                               res.append(t.text.substring_from(1).html_escape)
-                       end
+                       return n_moduledecl.n_doc.full_markdown.html
                end
-               return res.to_s
+               return ""
        end
 end
 
@@ -1566,11 +1701,8 @@ redef class AStdClassdef
        end
 
        private fun full_comment: String do
-               var res = new Buffer
-               if n_doc != null then
-                       for t in n_doc.n_comment do res.append(t.text.substring_from(1).html_escape)
-               end
-               return res.to_s
+               if n_doc != null then return n_doc.full_markdown.html
+               return ""
        end
 end
 
@@ -1581,11 +1713,8 @@ redef class APropdef
        end
 
        private fun full_comment: String do
-               var res = new Buffer
-               if n_doc != null then
-                       for t in n_doc.n_comment do res.append(t.text.substring_from(1).html_escape)
-               end
-               return res.to_s
+               if n_doc != null then return n_doc.full_markdown.html
+               return ""
        end
 end