ni_nitdoc: added fast copy past utility to signatures.
[nit.git] / src / ni_nitdoc.nit
index 812267a..535614b 100644 (file)
 module ni_nitdoc
 
 import model_utils
-import abstract_compiler
+import modelize_property
 
 # 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
@@ -46,30 +46,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
+               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)
+               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
 
                if arguments.length < 1 then
-                       option_context.usage
+                       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
@@ -79,10 +79,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
@@ -157,19 +157,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
@@ -179,15 +177,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
 
@@ -195,21 +191,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 = ""
@@ -232,43 +229,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>")
@@ -311,12 +271,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
@@ -328,15 +288,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
@@ -375,7 +338,9 @@ class NitdocOverview
        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
@@ -450,7 +415,9 @@ class NitdocFullindex
        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}'>")
                append("<h1>Full Index</h1>")
                module_column
                classes_column
@@ -548,7 +515,9 @@ class NitdocModule
 
        redef fun content do
                sidebar
-               append("<div class='content'>")
+               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)
@@ -735,18 +704,23 @@ class NitdocClass
                        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 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
 
@@ -781,7 +755,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
@@ -889,9 +865,7 @@ class NitdocClass
                append("</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>")
                process_generate_dot
                append("</section>")
                # concerns
@@ -956,9 +930,9 @@ 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
@@ -1100,36 +1074,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
@@ -1167,10 +1155,6 @@ redef class MModule
                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>")
                end
        end
@@ -1196,15 +1180,21 @@ redef class MClass
 
        # 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}\"")
+               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(">{signature}</a>")
+                       html_link_cache = res.to_s
                end
-               page.append(">{signature}</a>")
+               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
@@ -1215,7 +1205,7 @@ redef class MClass
        end
 
        fun url: String do
-               return "class_{public_owner}_{c_name}.html"
+               return "class_{public_owner}_{name}.html"
        end
 
        # Escape name for html output
@@ -1283,18 +1273,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}_{c_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
+
+       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 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>")
+               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
+               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_list_item(page: NitdocPage) do
@@ -1398,26 +1407,25 @@ redef class MPropDef
                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
+               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>from ")
+                       page.append("<p class='info'>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>")
+                               page.append("<span class=\"noComment\">No comment</span>")
                        else
-                               page.append("<pre class=\"text_label\" title=\"\" name=\"\" tag=\"\" type=\"1\">{intro_nprop.full_comment}</pre>")
+                               page.append("<pre>{intro_nprop.full_comment}</pre>")
                        end
-                       page.append("<p>from ")
+                       page.append("<p class='info'>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>")
+                       page.append("<span class=\"noComment\">No comment</span>")
                else
-                       page.append("<pre class=\"text_label\" title=\"\" name=\"\" tag=\"\" type=\"1\">{nprop.full_comment}</pre>")
+                       page.append("<pre>{nprop.full_comment}</pre>")
                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
@@ -1436,13 +1444,15 @@ 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_comment(page)
@@ -1460,7 +1470,6 @@ redef class MMethodDef
                end
                mproperty.html_namespace(page)
                page.append("</div>")
-               page.append("<div style=\"float: right;\"><a id=\"lblDiffCommit\"></a></div>")
        end
 end
 
@@ -1472,9 +1481,9 @@ redef class MVirtualTypeDef
                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>")
+               page.append("</span></h3>")
                html_info(page)
                html_comment(page)
                page.append("</article>")
@@ -1486,7 +1495,6 @@ redef class MVirtualTypeDef
                page.append("type ")
                mproperty.html_namespace(page)
                page.append("</div>")
-               page.append("<div style=\"float: right;\"><a id=\"lblDiffCommit\"></a></div>")
        end
 end
 
@@ -1505,6 +1513,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