ni: fixed display of multiple search results
[nit.git] / src / ni.nit
index 398b1ed..8c169f3 100644 (file)
@@ -92,58 +92,46 @@ class NitIndex
 
        fun seek(entry: String) do
                if entry.is_empty then exit(0)
-               var flag = false
+               var pager = new Pager
                # seek return types
                if entry.has_prefix("return:") then
                        var ret = entry.split_with(":")[1].replace(" ", "")
                        var matches = seek_returns(ret)
-                       if not matches.is_empty then
-                               flag = true
-                               props_fulldoc(matches)
-                       end
+                       props_fulldoc(pager, matches)
                else if entry.has_prefix("param:") then
                        var param = entry.split_with(":")[1].replace(" ", "")
                        var matches = seek_params(param)
-                       if not matches.is_empty then
-                               flag = true
-                               props_fulldoc(matches)
-                       end
+                       props_fulldoc(pager, matches)
                else
                        # seek for modules
                        var mmatches = new List[MModule]
                        for m in model.mmodules do
-                               if m.name == entry then
-                                       flag = true
-                                       mmatches.add(m)
-                               end
+                               if m.name == entry then mmatches.add(m)
                        end
-                       if not mmatches.is_empty then modules_fulldoc(mmatches)
+                       if not mmatches.is_empty then modules_fulldoc(pager, mmatches)
                        # seek for classes
                        var cmatches = new List[MClass]
                        for c in model.mclasses do
-                               if c.name == entry then
-                                       flag = true
-                                       cmatches.add(c)
-                               end
+                               if c.name == entry then cmatches.add(c)
                        end
-                       if not cmatches.is_empty then classes_fulldoc(cmatches)
+                       if not cmatches.is_empty then classes_fulldoc(pager, cmatches)
                        # seek for properties
                        var matches = new List[MProperty]
                        for p in model.mproperties do
-                               if p.name == entry then
-                                       flag = true
-                                       matches.add(p)
-                               end
+                               if p.name == entry then matches.add(p)
                        end
-                       if not matches.is_empty then props_fulldoc(matches)
+                       if not matches.is_empty then props_fulldoc(pager, matches)
                end
                # no matches
-               if not flag then print "Nothing known about '{entry}'"
+               if pager.content.is_empty then
+                       print "Nothing known about '{entry}'"
+               else
+                       pager.render
+               end
                if arguments.length == 1 then prompt
        end
 
-       private fun modules_fulldoc(mmodules: List[MModule]) do
-               var pager = new Pager
+       private fun modules_fulldoc(pager: Pager, mmodules: List[MModule]) do
                for mmodule in mmodules do
                        # name and prototype
                        pager.add("# {mmodule.namespace}\n".bold)
@@ -154,14 +142,13 @@ class NitIndex
                                        for comment in nmodule.n_moduledecl.n_doc.comment do pager.add(comment.green)
                                end
                        end
-                       pager.add("{mmodule.prototype}")
-                       pager.add_rule
+                       pager.add("{mmodule.prototype}\n")
                        # imports
                        var msorter = new MModuleNameSorter
                        var ms = mmodule.in_importation.greaters.to_a
                        if ms.length > 1 then
                                msorter.sort(ms)
-                               pager.add("# imported modules".bold)
+                               pager.add("## imported modules".bold)
                                pager.addn("\t")
                                for i in [0..ms.length[ do
                                        if ms[i] == mmodule then continue
@@ -174,7 +161,7 @@ class NitIndex
                        ms = mmodule.in_importation.smallers.to_a
                        if ms.length > 1 then
                                msorter.sort(ms)
-                               pager.add("# known modules".bold)
+                               pager.add("## known modules".bold)
                                pager.addn("\t")
                                for i in [0..ms.length[ do
                                        if ms[i] == mmodule then continue
@@ -197,7 +184,7 @@ class NitIndex
                        # intro
                        if not intro_mclassdefs.is_empty then
                                sorter.sort(intro_mclassdefs)
-                               pager.add("\n# introduced classes".bold)
+                               pager.add("\n## introduced classes".bold)
                                for mclassdef in intro_mclassdefs do
                                        pager.add("")
                                        var nclass = mbuilder.mclassdef2nclassdef[mclassdef]
@@ -211,7 +198,7 @@ class NitIndex
                        # redefs
                        if not redef_mclassdefs.is_empty then
                                sorter.sort(redef_mclassdefs)
-                               pager.add("\n# refined classes".bold)
+                               pager.add("\n## refined classes".bold)
                                for mclassdef in redef_mclassdefs do
                                        pager.add("")
                                        #TODO intro comment?
@@ -228,92 +215,170 @@ class NitIndex
                                end
                        end
                        #TODO add inherited classes?
+                       pager.add_rule
                end
-               pager.render
        end
 
-       private fun classes_fulldoc(mclasses: List[MClass]) do
-               var pager = new Pager
+       private fun classes_fulldoc(pager: Pager, mclasses: List[MClass]) do
                for mclass in mclasses do
-                       var nclass = mbuilder.mclassdef2nclassdef[mclass.intro].as(AStdClassdef)
-
+                       # title
                        pager.add("# {mclass.namespace}\n".bold)
-                       pager.add("{mclass.prototype}")
-                       if not nclass.n_doc == null then
-                               pager.add_rule
-                               pager.addn(nclass.n_doc.comment.green)
+                       # comment
+                       if mbuilder.mclassdef2nclassdef.has_key(mclass.intro) then
+                               var nclass = mbuilder.mclassdef2nclassdef[mclass.intro]
+                               if nclass isa AStdClassdef and not nclass.n_doc == null then
+                                       for comment in nclass.n_doc.comment do pager.add(comment.green)
+                               end
                        end
-                       pager.add_rule
+                       pager.addn("{mclass.prototype}")
+                       if mclass.in_hierarchy(mainmodule).direct_greaters.length > 1 then
+                               var supers = mclass.in_hierarchy(mainmodule).direct_greaters.to_a
+                               pager.addn(" super ")
+                               for i in [0..supers.length[ do
+                                       if supers[i] == mclass then continue
+                                       pager.addn(supers[i].name)
+                                       if i < mclass.in_hierarchy(mainmodule).direct_greaters.length -1 then pager.addn(", ")
+                               end
+                               pager.add("\n")
+                       end
+                       # formal types
                        if not mclass.parameter_types.is_empty then
-                               pager.add("# formal types".bold)
+                               pager.add("## formal types".bold)
                                for ft, bound in mclass.parameter_types do
                                        pager.add("")
                                        pager.add("\t{ft.to_s.green}: {bound}")
                                end
+                               pager.add("")
                        end
-                       if not mclass.virtual_types.is_empty then
-                               pager.add("# virtual types".bold)
-                               for vt in mclass.virtual_types do
-                                       pager.add("")
-                                       mpropdef_fulldoc(pager, vt.intro)
+                       # get properties
+                       var cats = new ArrayMap[String, Set[MPropDef]]
+                       cats["virtual types"] = new HashSet[MPropDef]
+                       cats["constructors"] = new HashSet[MPropDef]
+                       cats["introduced methods"] = new HashSet[MPropDef]
+                       cats["refined methods"] = new HashSet[MPropDef]
+
+                       for mclassdef in mclass.mclassdefs do
+                               for mpropdef in mclassdef.mpropdefs do
+                                       if mpropdef isa MAttributeDef then continue
+                                       if mpropdef isa MVirtualTypeDef then cats["virtual types"].add(mpropdef)
+                                       if mpropdef isa MMethodDef then
+                                               if mpropdef.mproperty.is_init then
+                                                       cats["constructors"].add(mpropdef)
+                                               else if mpropdef.is_intro then
+                                                       cats["introduced methods"].add(mpropdef)
+                                               else
+                                                       cats["refined methods"].add(mpropdef)
+                                               end
+                                       end
                                end
                        end
-                       pager.add_rule
-
-                       var cats = new HashMap[String, Collection[MMethod]]
-                       cats["constructors"] = mclass.constructors
-                       cats["introduced methods"] = mclass.intro_methods
-                       cats["refined methods"] = mclass.redef_methods
-                       cats["inherited methods"] = mclass.inherited_methods
-
+                       # local mproperties
                        for cat, list in cats do
                                if not list.is_empty then
                                        #sort list
-                                       var sorted = new Array[MMethod]
+                                       var sorted = new Array[MPropDef]
                                        sorted.add_all(list)
-                                       var sorter = new MPropertyNameSorter
+                                       var sorter = new MPropDefNameSorter
                                        sorter.sort(sorted)
-                                       pager.add("\n# {cat}".bold)
-                                       for mprop in sorted do
+                                       pager.add("## {cat}".bold)
+                                       for mpropdef in sorted do
                                                pager.add("")
-                                               mpropdef_fulldoc(pager, mprop.intro)
+                                               if mbuilder.mpropdef2npropdef.has_key(mpropdef) then
+                                                       var nprop = mbuilder.mpropdef2npropdef[mpropdef]
+                                                       if not nprop.n_doc == null and not nprop.n_doc.comment.is_empty then
+                                                               for comment in nprop.n_doc.comment do pager.add("\t{comment.green}")
+                                                       else
+                                                               nprop = mbuilder.mpropdef2npropdef[mpropdef.mproperty.intro]
+                                                               if not nprop.n_doc == null and not nprop.n_doc.comment.is_empty then
+                                                                       for comment in nprop.n_doc.comment do pager.add("\t{comment.green}")
+                                                               end
+                                                       end
+                                               end
+                                               pager.add("\t{mpropdef}")
+                                               mainmodule.linearize_mpropdefs(mpropdef.mproperty.mpropdefs)
+                                               var previous_defs = new Array[MPropDef]
+                                               for def in mpropdef.mproperty.mpropdefs do
+                                                       if def == mpropdef then continue
+                                                       if def.is_intro then continue
+                                                       if mclass.in_hierarchy(mainmodule) < def.mclassdef.mclass then
+                                                               previous_defs.add(def)
+                                                       end
+                                               end
+                                               if not mpropdef.is_intro then
+                                                       pager.add("\t\t" + "introduced by {mpropdef.mproperty.intro.mclassdef.namespace.bold}".gray)
+                                               end
+                                               if not previous_defs.is_empty then
+                                                       for def in previous_defs do pager.add("\t\t" + "inherited from {def.mclassdef.namespace.bold}".gray)
+                                               end
                                        end
+                                       pager.add("")
+                               end
+                       end
+                       # inherited mproperties
+                       var inhs = new ArrayMap[MClass, Array[MProperty]]
+                       var ancestors = mclass.in_hierarchy(mainmodule).greaters.to_a
+                       mainmodule.linearize_mclasses(ancestors)
+                       for a in ancestors do
+                               if a == mclass then continue
+                               for c in a.mclassdefs do
+                                       for p in c.intro_mproperties do
+                                               if p.intro_mclassdef == c then
+                                                       if not inhs.has_key(a) then inhs[a] = new Array[MProperty]
+                                                       inhs[a].add(p)
+                                               end
+                                       end
+                               end
+                       end
+                       if not inhs.is_empty then
+                               pager.add("## inherited properties".bold)
+                               for a, ps in inhs do
+                                       pager.add("\n\tfrom {a.namespace.bold}: {ps.join(", ")}")
                                end
                        end
                        pager.add_rule
                end
-               pager.render
        end
 
-       private fun props_fulldoc(raw_mprops: List[MProperty]) do
-               var pager = new Pager
+       private fun props_fulldoc(pager: Pager, raw_mprops: List[MProperty]) do
                # group by module
-               var cats = new HashMap[MClass, Array[MProperty]]
+               var cats = new HashMap[MModule, Array[MProperty]]
                for mprop in raw_mprops do
-                       if not mbuilder.mpropdef2npropdef.has_key(mprop.intro) then continue
                        if mprop isa MAttribute then continue
-                       var mclass = mprop.intro_mclassdef.mclass
-                       if not cats.has_key(mclass) then cats[mclass] = new Array[MProperty]
-                       cats[mclass].add(mprop)
+                       var key = mprop.intro.mclassdef.mmodule
+                       if not cats.has_key(key) then cats[key] = new Array[MProperty]
+                       cats[key].add(mprop)
                end
                #sort groups
-               var sorter = new MClassNameSorter
-               var sorted = new Array[MClass]
+               var sorter = new MModuleNameSorter
+               var sorted = new Array[MModule]
                sorted.add_all(cats.keys)
                sorter.sort(sorted)
                # display
-               for mclass in sorted do
-                       var mprops = cats[mclass]
-                       pager.add("# {mclass.namespace}".bold)
+               for mmodule in sorted do
+                       var mprops = cats[mmodule]
+                       pager.add("# matches in module {mmodule.namespace.bold}")
                        var sorterp = new MPropertyNameSorter
                        sorterp.sort(mprops)
                        for mprop in mprops do
                                pager.add("")
-                               mpropdef_fulldoc(pager, mprop.intro)
+                               if mbuilder.mpropdef2npropdef.has_key(mprop.intro) then
+                                       var nprop = mbuilder.mpropdef2npropdef[mprop.intro]
+                                       if not nprop.n_doc == null and not nprop.n_doc.comment.is_empty then
+                                               for comment in nprop.n_doc.comment do pager.add("\t{comment.green}")
+                                       end
+                               end
+                               pager.add("\t{mprop.intro}")
+                               pager.add("\t\t" + "introduced in {mprop.intro_mclassdef.namespace.bold}".gray)
+                               var mpropdefs = mprop.mpropdefs
+                               mainmodule.linearize_mpropdefs(mpropdefs)
+                               for mpdef in mpropdefs do
+                                       if not mpdef.is_intro then
+                                               pager.add("\t\t" + "refined in {mpdef.mclassdef.namespace.bold}".gray)
+                                       end
+                               end
                        end
                        pager.add_rule
                end
-               pager.render
        end
 
        private fun seek_returns(entry: String): List[MProperty] do
@@ -346,22 +411,6 @@ class NitIndex
                end
                return matches
        end
-
-       private fun mpropdef_fulldoc(pager: Pager, mpropdef: MPropDef) do
-               if mbuilder.mpropdef2npropdef.has_key(mpropdef) then
-                       var nprop = mbuilder.mpropdef2npropdef[mpropdef]
-                       if not nprop.n_doc == null and not nprop.n_doc.short_comment.is_empty then
-                               pager.add("\t# {nprop.n_doc.short_comment}")
-                       end
-               end
-               pager.add("\t{mpropdef}")
-               pager.add("\t\t" + "introduced in {mpropdef.mproperty.intro_mclassdef.namespace}".gray)
-               for mpdef in mpropdef.mproperty.mpropdefs do
-                       if not mpdef.is_intro then
-                               pager.add("\t\t" + "refined in {mpdef.mclassdef.namespace}".gray)
-                       end
-               end
-       end
 end
 
 # Printing facilities
@@ -406,11 +455,7 @@ redef class MClass
        end
 
        private fun namespace: String do
-               if not intro_mmodule.public_owner == null then
-                       return "{intro_mmodule.public_owner.name}::{name}"
-               else
-                       return "{intro_mmodule.name}::{name}"
-               end
+               return "{intro_mmodule.namespace}::{name}"
        end
 end
 
@@ -420,14 +465,21 @@ redef class MClassDef
        end
 end
 
+redef class MProperty
+       redef fun to_s do
+               if visibility.to_s == "public" then return name.green
+               if visibility.to_s == "private" then return name.red
+               if visibility.to_s == "protected" then return name.yellow
+               return name.bold
+       end
+end
+
 redef class MMethodDef
        redef fun to_s do
                var res = new Buffer
                if not is_intro then res.append("redef ")
                if not mproperty.is_init then res.append("fun ")
-               if mproperty.visibility.to_s == "public" then res.append(mproperty.name.green)
-               if mproperty.visibility.to_s == "private" then res.append(mproperty.name.red)
-               if mproperty.visibility.to_s == "protected" then res.append(mproperty.name.yellow)
+               res.append(mproperty.to_s.bold)
                if msignature != null then res.append(msignature.to_s)
                # FIXME: modifiers should be accessible via the model
                #if self isa ADeferredMethPropdef then ret = "{ret} is abstract"
@@ -440,9 +492,8 @@ end
 redef class MVirtualTypeDef
        redef fun to_s do
                var res = new Buffer
-               if mproperty.visibility.to_s == "public" then res.append(mproperty.name.green)
-               if mproperty.visibility.to_s == "private" then res.append(mproperty.name.red)
-               if mproperty.visibility.to_s == "protected" then res.append(mproperty.name.yellow)
+               res.append("type ")
+               res.append(mproperty.to_s.bold)
                res.append(": {bound.to_s}")
                return res.to_s
        end