tool: new program nitunit.nit
[nit.git] / src / ni_nitdoc.nit
index 59a9745..dc27b69 100644 (file)
 module ni_nitdoc
 
 import model_utils
+import modelize_property
+import markdown
 
 # The NitdocContext contains all the knowledge used for doc generation
 class NitdocContext
-       super ToolContext
 
+       private var toolcontext = new ToolContext
        private var model: Model
        private var mbuilder: ModelBuilder
        private var mainmodule: MModule
@@ -45,30 +47,30 @@ class NitdocContext
        private var opt_custom_footer_text: OptionString = new OptionString("Text displayed as footer of all pages", "--custom-footer-text")
 
        init do
-               super
-               self.arguments = option_context.rest
-               option_context.options.clear
-               option_context.add_option(opt_dir)
-               option_context.add_option(opt_source)
-               option_context.add_option(opt_sharedir)
-               option_context.add_option(opt_nodot)
-               option_context.add_option(opt_private)
-               option_context.add_option(opt_custom_title)
-               option_context.add_option(opt_custom_footer_text)
-               option_context.add_option(opt_custom_overview_text)
-               option_context.add_option(opt_custom_menu_items)
-               process_options
+               toolcontext.option_context.add_option(opt_dir)
+               toolcontext.option_context.add_option(opt_source)
+               toolcontext.option_context.add_option(opt_sharedir)
+               toolcontext.option_context.add_option(opt_nodot)
+               toolcontext.option_context.add_option(opt_private)
+               toolcontext.option_context.add_option(opt_custom_title)
+               toolcontext.option_context.add_option(opt_custom_footer_text)
+               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
-                       option_context.usage
+                       print "usage: nitdoc [options] file..."
+                       toolcontext.option_context.usage
                        exit(1)
                end
 
                model = new Model
-               mbuilder = new ModelBuilder(model, self)
+               mbuilder = new ModelBuilder(model, toolcontext)
                # Here we load an process all modules passed on the command line
-               var mmodules = mbuilder.parse_and_build(arguments)
+               var mmodules = mbuilder.parse(arguments)
                if mmodules.is_empty then return
+               mbuilder.run_phases
 
                if mmodules.length == 1 then
                        mainmodule = mmodules.first
@@ -78,10 +80,10 @@ class NitdocContext
                        mainmodule.set_imported_mmodules(mmodules)
                end
                self.class_hierarchy = mainmodule.flatten_mclass_hierarchy
+               self.process_options
        end
 
-       redef fun process_options do
-               super
+       private fun process_options do
                if not opt_dir.value is null then
                        output_dir = opt_dir.value
                else
@@ -123,7 +125,7 @@ class NitdocContext
                self.dot_dir = null
                if not opt_nodot.value then self.dot_dir = output_dir.to_s
                overview
-               fullindex
+               search
                modules
                classes
                quicksearch_list
@@ -134,9 +136,9 @@ class NitdocContext
                overviewpage.save("{output_dir.to_s}/index.html")
        end
 
-       private fun fullindex do
-               var fullindex = new NitdocFullindex(self)
-               fullindex.save("{output_dir.to_s}/full-index.html")
+       private fun search do
+               var searchpage = new NitdocSearch(self)
+               searchpage.save("{output_dir.to_s}/search.html")
        end
 
        private fun modules do
@@ -156,19 +158,17 @@ class NitdocContext
 
        private fun quicksearch_list do
                var file = new OFStream.open("{output_dir.to_s}/quicksearch-list.js")
-               var content = new Buffer
-               content.append("var entries = \{ ")
-
+               file.write("var entries = \{ ")
                for mmodule in model.mmodules do
-                       content.append("\"{mmodule.name}\": [")
-                       content.append("\{txt: \"{mmodule.name}\", url:\"{mmodule.url}\" \},")
-                       content.append("],")
+                       file.write("\"{mmodule.name}\": [")
+                       file.write("\{txt: \"{mmodule.name}\", url:\"{mmodule.url}\" \},")
+                       file.write("],")
                end
                for mclass in model.mclasses do
                        if mclass.visibility < min_visibility then continue
-                       content.append("\"{mclass.name}\": [")
-                       content.append("\{txt: \"{mclass.name}\", url:\"{mclass.url}\" \},")
-                       content.append("],")
+                       file.write("\"{mclass.name}\": [")
+                       file.write("\{txt: \"{mclass.name}\", url:\"{mclass.url}\" \},")
+                       file.write("],")
                end
                var name2mprops = new HashMap[String, Set[MPropDef]]
                for mproperty in model.mproperties do
@@ -178,15 +178,13 @@ class NitdocContext
                        name2mprops[mproperty.name].add_all(mproperty.mpropdefs)
                end
                for mproperty, mpropdefs in name2mprops do
-                       content.append("\"{mproperty}\": [")
+                       file.write("\"{mproperty}\": [")
                        for mpropdef in mpropdefs do
-                               content.append("\{txt: \"{mpropdef.full_name}\", url:\"{mpropdef.url}\" \},")
+                               file.write("\{txt: \"{mpropdef.full_name}\", url:\"{mpropdef.url}\" \},")
                        end
-                       content.append("],")
+                       file.write("],")
                end
-
-               content.append(" \};")
-               file.write(content.to_s)
+               file.write(" \};")
                file.close
        end
 
@@ -194,21 +192,22 @@ end
 
 # Nitdoc base page
 abstract class NitdocPage
-       super Buffer
 
        var dot_dir: nullable String
        var source: nullable String
        var ctx: NitdocContext
 
        init(ctx: NitdocContext) do
-               super
                self.ctx = ctx
        end
 
        protected fun head do
                append("<meta charset='utf-8'/>")
                append("<script type='text/javascript' src='scripts/jquery-1.7.1.min.js'></script>")
+               append("<script type='text/javascript' src='scripts/ZeroClipboard.min.js'></script>")
                append("<script type='text/javascript' src='quicksearch-list.js'></script>")
+               append("<script type='text/javascript' src='scripts/base64.js'></script>")
+               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'/>")
                var title = ""
@@ -231,43 +230,6 @@ abstract class NitdocPage
                append("<nav class='main'>")
                append("<ul>")
                menu
-               append("<li id='liGitHub'>")
-               append("<a class='btn' id='logGitHub'>")
-               append("<img id='imgGitHub' src='resources/icons/github-icon.png' alt='GitHub'/>")
-               append("</a>")
-               append("<div class='popover bottom'>")
-               append("<div class='arrow'>&nbsp;</div>")
-               append("<div class='githubTitle'>")
-               append("<h3>Github Sign In</h3>")
-               append("</div>")
-               append("<div>")
-               append("<label id='lbloginGit'>Username</label>")
-               append("<input id='loginGit' name='login' type='text'/>")
-               append("<label id='logginMessage'>Hello ")
-               append("<a id='githubAccount'><strong id='nickName'></strong></a>")
-               append("</label>")
-               append("</div>")
-               append("<div>")
-               append("<label id='lbpasswordGit'>Password</label>")
-               append("<input id='passwordGit' name='password' type='password'/>")
-               append("<div id='listBranches'>")
-               append("<label id='lbBranches'>Branch</label>")
-               append("<select class='dropdown' id='dropBranches' name='dropBranches' tabindex='1'></select>")
-               append("</div>")
-               append("</div>")
-               append("<div>")
-               append("<label id='lbrepositoryGit'>Repository</label>")
-               append("<input id='repositoryGit' name='repository' type='text'/>")
-               append("</div>")
-               append("<div>")
-               append("<label id='lbbranchGit'>Branch</label>")
-               append("<input id='branchGit' name='branch' type='text'/>")
-               append("</div>")
-               append("<div>")
-               append("<a id='signIn'>Sign In</a>")
-               append("</div>")
-               append("</div>")
-               append("</li>")
                append("</ul>")
                append("</nav>")
                append("</header>")
@@ -310,12 +272,12 @@ abstract class NitdocPage
                        source = x.join(l.line_start.to_s)
                        x = source.split_with("%L")
                        source = x.join(l.line_end.to_s)
-                       return " (<a href=\"{source.to_s}\">source</a>)"
+                       return " (<a target='_blank' title='Show source' href=\"{source.to_s}\">source</a>)"
                end
        end
 
        # Render the page as a html string
-       fun render: String do
+       protected fun render do
                append("<!DOCTYPE html>")
                append("<head>")
                head
@@ -327,15 +289,18 @@ abstract class NitdocPage
                append("</div>")
                footer
                append("</body>")
-               return to_s
        end
 
+       # Append a string to the page
+       fun append(s: String) do out.write(s)
+
        # Save html page in the specified file
        fun save(file: String) do
-               var out = new OFStream.open(file)
-               out.write(render)
-               out.close
+               self.out = new OFStream.open(file)
+               render
+               self.out.close
        end
+       private var out: nullable OFStream
 end
 
 # The overview page
@@ -370,11 +335,13 @@ class NitdocOverview
        redef fun menu do
                super
                append("<li class='current'>Overview</li>")
-               append("<li><a href='full-index.html'>Full Index</a></li>")
+               append("<li><a href='search.html'>Search</a></li>")
        end
 
        redef fun content do
-               append("<div class='content fullpage'>")
+               var footed = ""
+               if ctx.opt_custom_footer_text.value != null then footed = "footed"
+               append("<div class='content fullpage {footed}'>")
                var title = "Overview"
                if ctx.opt_custom_title.value != null then
                        title = ctx.opt_custom_title.value.to_s
@@ -431,8 +398,8 @@ class NitdocOverview
        end
 end
 
-# The full index page
-class NitdocFullindex
+# The search page
+class NitdocSearch
        super NitdocPage
 
        init(ctx: NitdocContext) do
@@ -440,17 +407,19 @@ class NitdocFullindex
                self.dot_dir = null
        end
 
-       redef fun title do return "Full Index"
+       redef fun title do return "Search"
 
        redef fun menu do
                super
                append("<li><a href='index.html'>Overview</a></li>")
-               append("<li class='current'>Full Index</li>")
+               append("<li class='current'>Search</li>")
        end
 
        redef fun content do
-               append("<div class='content fullpage'>")
-               append("<h1>Full Index</h1>")
+               var footed = ""
+               if ctx.opt_custom_footer_text.value != null then footed = "footed"
+               append("<div class='content fullpage {footed}'>")
+               append("<h1>{title}</h1>")
                module_column
                classes_column
                properties_column
@@ -521,12 +490,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
@@ -542,61 +536,38 @@ class NitdocModule
                super
                append("<li><a href='index.html'>Overview</a></li>")
                append("<li class='current'>{mmodule.name}</li>")
-               append("<li><a href='full-index.html'>Full Index</a></li>")
+               append("<li><a href='search.html'>Search</a></li>")
        end
 
        redef fun content do
-               sidebar
-               append("<div class='content'>")
-               append("<h1>{mmodule.name}</h1>")
-               append("<div class='subtitle info'>")
-               mmodule.html_signature(self)
+               append("<div class='menu'>")
+               classes_column
+               importation_column
                append("</div>")
-               mmodule.html_full_comment(self)
-               process_generate_dot
-               classes
-               properties
+               var footed = ""
+               if ctx.opt_custom_footer_text.value != null then footed = "footed"
+               append("<div class='content {footed}'>")
+               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]
@@ -604,6 +575,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)
@@ -619,15 +594,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
@@ -642,65 +608,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
 
@@ -720,6 +727,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
@@ -731,21 +739,28 @@ class NitdocClass
                                                meths.add(mpropdef)
                                        end
                                end
+                               locals.add(mpropdef.mproperty)
                        end
                end
                # get inherited properties
-               for mprop in mclass.inherited_mproperties do
-                       var mpropdef = mprop.intro
-                       if mprop.visibility < ctx.min_visibility then continue
-                       if mpropdef isa MVirtualTypeDef then vtypes.add(mpropdef)
-                       if mpropdef isa MMethodDef then
-                               if mpropdef.mproperty.is_init then
-                                       consts.add(mpropdef)
-                               else
-                                       meths.add(mpropdef)
+               for pclass in mclass.in_hierarchy(ctx.mainmodule).greaters do
+                       if pclass == mclass then continue
+                       for pclassdef in pclass.mclassdefs do
+                               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
+                                                       consts.add(mpropdef)
+                                               else
+                                                       meths.add(mpropdef)
+                                               end
+                                       end
+                                       inherited.add(mpropdef)
                                end
                        end
-                       inherited.add(mpropdef)
                end
        end
 
@@ -772,7 +787,7 @@ class NitdocClass
                        append("</li>")
                end
                append("<li class='current'>{mclass.name}</li>")
-               append("<li><a href='full-index.html'>Full Index</a></li>")
+               append("<li><a href='search.html'>Search</a></li>")
        end
 
        redef fun content do
@@ -780,7 +795,9 @@ class NitdocClass
                properties_column
                inheritance_column
                append("</div>")
-               append("<div class='content'>")
+               var footed = ""
+               if ctx.opt_custom_footer_text.value != null then footed = "footed"
+               append("<div class='content {footed}'>")
                class_doc
                append("</div>")
        end
@@ -882,15 +899,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("<div style=\"float: right;\"><a id=\"lblDiffCommit\"></a></div>")
                append("<section class='description'>")
-               if nclass isa AStdClassdef and not nclass.full_comment.is_empty then append("<pre class=\"text_label\" title=\"122\" name=\"\" tag=\"{mclass.mclassdefs.first.location.to_s}\" type=\"2\">{nclass.full_comment}</pre><textarea id=\"fileContent\" class=\"edit\" cols=\"76\" rows=\"1\" style=\"display: none;\"></textarea><a id=\"cancelBtn\" style=\"display: none;\">Cancel</a><a id=\"commitBtn\" style=\"display: none;\">Commit</a><pre id=\"preSave\" class=\"text_label\" type=\"2\"></pre>")
+               if nclass isa AStdClassdef and not nclass.full_comment.is_empty then append("<div>{nclass.full_comment}</div>")
                process_generate_dot
                append("</section>")
                # concerns
@@ -955,16 +973,16 @@ class NitdocClass
                        if mclass.arity > 0 and nclass isa AStdClassdef then
                                for ft, bound in mclass.parameter_types do
                                        append("<article id='FT_{ft}'>")
-                                       append("<h3 class='signature'>{ft}: ")
+                                       append("<h3 class='signature' data-untyped-signature='{ft.to_s}'><span>{ft}: ")
                                        bound.html_link(self)
-                                       append("</h3>")
+                                       append("</span></h3>")
                                        append("<div class=\"info\">formal generic type</div>")
                                        append("</article>")
                                end
                        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
@@ -974,7 +992,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
@@ -998,7 +1016,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>")
@@ -1013,9 +1031,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
@@ -1028,7 +1047,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 ")
@@ -1041,8 +1061,8 @@ class NitdocClass
                                end
                                append("</p>")
                        end
+                       append("</section>")
                end
-               append("</section>")
        end
 
        private fun process_generate_dot do
@@ -1099,36 +1119,50 @@ end
 redef class MModule
        # URL to nitdoc page
        fun url: String do
-               var res = new Buffer
-               res.append("module_")
-               var mowner = public_owner
-               if mowner != null then
-                       res.append("{public_owner.name}_")
+               if url_cache == null then
+                       var res = new Buffer
+                       res.append("module_")
+                       var mowner = public_owner
+                       if mowner != null then
+                               res.append("{public_owner.name}_")
+                       end
+                       res.append("{self.name}.html")
+                       url_cache = res.to_s
                end
-               res.append("{self.name}.html")
-               return res.to_s
+               return url_cache.as(not null)
        end
+       private var url_cache: nullable String
 
        # html anchor id to the module in a nitdoc page
        fun anchor: String do
-               var res = new Buffer
-               res.append("MOD_")
-               var mowner = public_owner
-               if mowner != null then
-                       res.append("{public_owner.name}_")
+               if anchor_cache == null then
+                       var res = new Buffer
+                       res.append("MOD_")
+                       var mowner = public_owner
+                       if mowner != null then
+                               res.append("{public_owner.name}_")
+                       end
+                       res.append(self.name)
+                       anchor_cache = res.to_s
                end
-               res.append(self.name)
-               return res.to_s
+               return anchor_cache.as(not null)
        end
+       private var anchor_cache: nullable String
 
        # Return a link (html a tag) to the nitdoc module page
        fun html_link(page: NitdocPage) do
-               if page.ctx.mbuilder.mmodule2nmodule.has_key(self) then
-                       page.append("<a href='{url}' title='{page.ctx.mbuilder.mmodule2nmodule[self].short_comment}'>{name}</a>")
-               else
-                       page.append("<a href='{url}'>{name}</a>")
+               if html_link_cache == null then
+                       var res = new Buffer
+                       if page.ctx.mbuilder.mmodule2nmodule.has_key(self) then
+                               res.append("<a href='{url}' title='{page.ctx.mbuilder.mmodule2nmodule[self].short_comment}'>{name}</a>")
+                       else
+                               res.append("<a href='{url}'>{name}</a>")
+                       end
+                       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 module signature decorated with html
        fun html_signature(page: NitdocPage) do
@@ -1165,66 +1199,225 @@ 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("<textarea class='edit' rows='1' cols='76' id='fileContent'></textarea>")
-                       page.append("<a id='cancelBtn'>Cancel</a>")
-                       page.append("<a id='commitBtn'>Commit</a>")
-                       page.append("<pre class='text_label' id='preSave' type='2'></pre>")
+                       page.append("<div>{page.ctx.mbuilder.mmodule2nmodule[self].full_comment}</div>")
                        page.append("</div>")
                end
        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)
+       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
 
-       # name with formal parameter
-       # Foo[A, B]
-       private fun signature: String do
+       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 generic signature of the class
+       #       [E, F]
+       private fun html_short_signature: String do
                if arity > 0 then
-                       return "{name}[{intro.parameter_names.join(", ")}]"
+                       return "[{intro.parameter_names.join(", ")}]"
                else
-                       return name
+                       return ""
                end
        end
 
-       # Return a link (html a tag) to the nitdoc class page
-       fun html_link(page: NitdocPage) do
-               page.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
-                               page.append(" title=\"{nclass.short_comment}\"")
+       # 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
+                       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
-               page.append(">{signature}</a>")
        end
 
        # Return the class namespace decorated with html
-       fun html_namespace(page: NitdocPage) do
+       private fun html_namespace(page: NitdocPage) do
                intro_mmodule.html_namespace(page)
                page.append("::<span>")
-               html_link(page)
+               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
+                       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}{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
+
+       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"
        end
 
        # 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>")
@@ -1282,34 +1475,37 @@ redef class MClassDef
 end
 
 redef class MPropDef
-       fun url: String do return "{mclassdef.mclass.url}#{anchor}"
-       fun anchor: String do return "PROP_{mclassdef.mclass.public_owner.name}_{mproperty.name}"
+       fun url: String do
+               if url_cache == null then
+                       url_cache = "{mclassdef.mclass.url}#{anchor}"
+               end
+               return url_cache.as(not null)
+       end
+       private var url_cache: nullable String
 
-       # Return a link (html a tag) to the nitdoc class page
-       fun html_link(page: NitdocPage) do
-               if page.ctx.mbuilder.mpropdef2npropdef.has_key(self) then
-                       var nprop = page.ctx.mbuilder.mpropdef2npropdef[self]
-                       page.append("<a href=\"{url}\" title=\"{nprop.short_comment}\">{mproperty.name}</a>")
-               else
-                       page.append("<a href=\"{url}\">{mproperty.name}</a>")
+       fun anchor: String do
+               if anchor_cache == null then
+                       anchor_cache = "PROP_{mclassdef.mclass.public_owner.name}_{mproperty.name}"
                end
+               return anchor_cache.as(not null)
        end
+       private var anchor_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;")
+       # Return a link (html a tag) to the nitdoc class page
+       fun html_link(page: NitdocPage) do
+               if html_link_cache == null then
+                       var res = new Buffer
+                       if page.ctx.mbuilder.mpropdef2npropdef.has_key(self) then
+                               var nprop = page.ctx.mbuilder.mpropdef2npropdef[self]
+                               res.append("<a href=\"{url}\" title=\"{nprop.short_comment}\">{mproperty.name}</a>")
+                       else
+                               res.append("<a href=\"{url}\">{mproperty.name}</a>")
+                       end
+                       html_link_cache = res.to_s
                end
-               html_link(page)
-               page.append("(")
-               mclassdef.mclass.html_link(page)
-               page.append(")")
-               page.append("</li>")
+               page.append(html_link_cache.as(not null))
        end
+       private var html_link_cache: nullable String
 
        # Return a list item for the mpropdef
        private fun html_sidebar_item(page: NitdocClass) do
@@ -1327,105 +1523,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)}")
-                               end
-
-                               if i < previous_defs.length - 1 then page.append(", ")
-                       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)}")
+                       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 < next_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
-               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 then
-                       var intro_nprop = page.ctx.mbuilder.mpropdef2npropdef[mproperty.intro]
-                       page.append("<p>from ")
-                       mproperty.html_namespace(page)
-                       page.append("</p>")
-                       if intro_nprop.full_comment == "" then
-                               page.append("<a class=\"newComment\" title=\"32\" tag=\"\">New Comment</a>")
+               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 class=\"text_label\" title=\"\" name=\"\" tag=\"\" type=\"1\">{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>from ")
                        mclassdef.html_namespace(page)
-                       page.append("</p>")
-               end
-               if nprop.full_comment == "" then
-                       page.append("<a class=\"newComment\" title=\"32\" tag=\"\">New Comment</a>")
-               else
-                       page.append("<pre class=\"text_label\" title=\"\" name=\"\" tag=\"\" type=\"1\">{nprop.full_comment}</pre>")
+                       page.append(" {page.show_source(nprop.location)}</p>")
                end
-               page.append("<textarea id=\"fileContent\" class=\"edit\" cols=\"76\" rows=\"1\" style=\"display: none;\"></textarea><a id=\"cancelBtn\" style=\"display: none;\">Cancel</a><a id=\"commitBtn\" style=\"display: none;\">Commit</a><pre id=\"preSave\" class=\"text_label\" type=\"2\"></pre>")
-               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
@@ -1435,23 +1581,25 @@ redef class MMethodDef
                classes.add(mproperty.visibility.to_s)
                page.append("<article class='{classes.join(" ")}' id='{anchor}'>")
                if page.ctx.mbuilder.mpropdef2npropdef.has_key(self) then
-                       page.append("<h3 class='signature'>{mproperty.name}")
+                       page.append("<h3 class='signature' data-untyped-signature='{mproperty.name}{msignature.untyped_signature(page)}'>")
+                       page.append("<span>{mproperty.name}")
                        msignature.html_signature(page)
-                       page.append("</h3>")
+                       page.append("</span></h3>")
                else
-                       page.append("<h3 class='signature'>init")
+                       page.append("<h3 class='signature' data-untyped-signature='init{msignature.untyped_signature(page)}'>")
+                       page.append("<span>init")
                        msignature.html_signature(page)
-                       page.append("</h3>")
+                       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
@@ -1459,33 +1607,31 @@ redef class MMethodDef
                end
                mproperty.html_namespace(page)
                page.append("</div>")
-               page.append("<div style=\"float: right;\"><a id=\"lblDiffCommit\"></a></div>")
        end
 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")
                classes.add(mproperty.visibility.to_s)
                page.append("<article class='{classes.join(" ")}' id='{anchor}'>")
-               page.append("<h3 class='signature'>{mproperty.name}: ")
+               page.append("<h3 class='signature' data-untyped-signature='{mproperty.name}'><span>{mproperty.name}: ")
                bound.html_link(page)
-               page.append("</h3>")
-               html_info(page)
+               page.append("</span></h3>")
+               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>")
-               page.append("<div style=\"float: right;\"><a id=\"lblDiffCommit\"></a></div>")
        end
 end
 
@@ -1504,6 +1650,19 @@ redef class MSignature
                        return_mtype.html_link(page)
                end
        end
+
+       private fun untyped_signature(page: NitdocPage): String do
+               var res = new Buffer
+               if not mparameters.is_empty then
+                       res.append("(")
+                       for i in [0..mparameters.length[ do
+                               res.append(mparameters[i].name)
+                               if i < mparameters.length - 1 then res.append(", ")
+                       end
+                       res.append(")")
+               end
+               return res.to_s
+       end
 end
 
 redef class MParameter
@@ -1527,13 +1686,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
 
@@ -1544,11 +1700,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
 
@@ -1559,11 +1712,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