ni: cleaned options context
[nit.git] / src / ni.nit
index d60e33c..76a40b6 100644 (file)
@@ -16,8 +16,7 @@
 
 module ni
 
-import toolcontext
-import exprbuilder
+import model_utils
 
 private class Pager
        var content: String = ""
@@ -37,9 +36,10 @@ class NitIndex
        init(toolcontext: ToolContext) do
                # We need a model to collect stufs
                self.toolcontext = toolcontext
+               self.toolcontext.option_context.options.clear
                self.arguments = toolcontext.option_context.rest
 
-               if arguments.length > 2 then
+               if arguments.is_empty or arguments.length > 2 then
                        print "usage: ni path/to/module.nit [expression]"
                        toolcontext.option_context.usage
                        exit(1)
@@ -83,179 +83,280 @@ class NitIndex
        end
 
        fun seek(entry: String) do
-               # quitting?
                if entry.is_empty then exit(0)
-
                var flag = false
-               for n in mbuilder.nmodules do
-                       var m = n.mmodule
-                       if m.name == entry then
+               # 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
-                               module_fulldoc(n)
+                               props_fulldoc(matches)
                        end
-               end
-               for c in model.mclasses do
-                       if c.name == entry then
-                               if not mbuilder.mclassdef2nclassdef[c.intro] isa AStdClassdef then continue
+               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
-                               doc_class(c)
+                               props_fulldoc(matches)
                        end
-               end
-               var matches = new List[MProperty]
-               for p in model.mproperties do
-                       if p.name == entry then
-                               flag = true
-                               matches.add(p)
+               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
                        end
+                       if not mmatches.is_empty then modules_fulldoc(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
+                       end
+                       if not cmatches.is_empty then classes_fulldoc(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
+                       end
+                       if not matches.is_empty then props_fulldoc(matches)
                end
-               #if not matches.is_empty then doc_properties
-
+               # no matches
                if not flag then print "Nothing known about '{entry}'"
                if arguments.length == 1 then prompt
        end
 
-       private fun module_fulldoc(nmodule: AModule) do
-               var mmodule = nmodule.mmodule
+       private fun modules_fulldoc(mmodules: List[MModule]) do
                var pager = new Pager
-               pager.add("# module {mmodule.name}".bold)
-               pager.add("")
-               pager.add("import {mmodule.in_importation.direct_greaters.join(", ")}")
-               pager.add_rule
-               pager.addn(mmodule.comment(nmodule).green)
-               pager.add_rule
-               if not mmodule.intro_mclasses.is_empty then
-                       pager.add("# introduced classes\n".bold)
-                       for mclass in mmodule.intro_mclasses do
-                               mclass_shortdoc(mclass, pager)
-                               pager.add("")
+               for mmodule in mmodules do
+                       var nmodule = mbuilder.mmodule2nmodule[mmodule]
+                       pager.add("# module {mmodule.namespace}\n".bold)
+                       if not mmodule.in_importation.direct_greaters.is_empty then
+                               pager.add("import ".bold + "{mmodule.in_importation.direct_greaters.join(", ")}\n")
                        end
-               end
-               if not mmodule.redef_mclasses.is_empty then
-                       pager.add("# refined classes\n".bold)
-                       for mclass in mmodule.redef_mclasses do
-                               mclass_shortdoc(mclass, pager)
-                               pager.add("")
+                       if not mmodule.in_importation.direct_smallers.is_empty then
+                               pager.add("known clients: ".bold + "{mmodule.in_importation.direct_smallers.join(", ")}\n")
+                       end
+                       pager.add_rule
+                       pager.addn(nmodule.comment.green)
+                       pager.add_rule
+
+                       var cats = new HashMap[String, Collection[MClass]]
+                       cats["introduced classes"] = mmodule.intro_mclasses
+                       cats["refined classes"] = mmodule.redef_mclasses
+                       cats["imported classes"] = mmodule.imported_mclasses
+
+                       for cat, list in cats do
+                               if not list.is_empty then
+                                       pager.add("\n# {cat}".bold)
+                                       #sort list
+                                       var sorted = new Array[MClass]
+                                       sorted.add_all(list)
+                                       var sorter = new ComparableSorter[MClass]
+                                       sorter.sort(sorted)
+                                       for mclass in sorted do
+                                               var nclass = mbuilder.mclassdef2nclassdef[mclass.intro].as(AStdClassdef)
+                                               pager.add("")
+                                               if not nclass.short_comment.is_empty then
+                                                       pager.add("\t# {nclass.short_comment}")
+                                               end
+                                               if cat == "refined classes" then
+                                                       pager.add("\tredef {mclass.short_doc}")
+                                               else
+                                                       pager.add("\t{mclass.short_doc}")
+                                               end
+                                               if cat != "introduced classes" then
+                                                       pager.add("\t\t" + "introduced in {mmodule.full_name}::{mclass}".gray)
+                                               end
+                                               for mclassdef in mclass.mclassdefs do
+                                                       if mclassdef != mclass.intro then
+                                                               pager.add("\t\t" + "refined in {mclassdef.namespace}".gray)
+                                                       end
+                                               end
+                                       end
+                               end
                        end
+                       pager.add_rule
                end
-               pager.add_rule
-               #TODO get mclass from nested modules
                pager.render
        end
 
-       fun doc_class(mclass: MClass) do
-               var nclass = mbuilder.mclassdef2nclassdef[mclass.intro].as(AStdClassdef)
+       private fun classes_fulldoc(mclasses: List[MClass]) do
                var pager = new Pager
-               pager.add("# {mclass.intro_mmodule.public_owner.name}::{mclass.name}".bold)
-               pager.add("")
-               # full signature
-               pager.addn("{mclass.visibility.to_s} ")
-               if mclass.is_abstract then pager.addn("abstract ")
-               if mclass.is_interface then pager.addn("interface ")
-               if mclass.is_enum then pager.addn("enum ")
-               if mclass.is_class then pager.addn("class ")
-               pager.addn("{mclass.ni_name} ")
-               pager.add("super {mclass.in_hierarchy(mainmodule).direct_greaters.join(", ")}")
-               pager.add_rule
-               # comment
-               pager.addn(mclass.comment(nclass).green)
-               pager.add_rule
-               # formal and virtual types
-               #TODO VT
-               pager.add_rule
-               # properties
-               if not mclass.constructors.is_empty then
-                       pager.add("# constructors\n".bold)
-                       display_methods(pager, mclass.constructors)
-               end
-               if not mclass.intro_methods.is_empty then
-                       pager.add("# methods\n".bold)
-                       display_methods(pager, mclass.intro_methods)
-               end
-               if not mclass.inherited_methods.is_empty then
-                       pager.add("# inherited methods\n".bold)
-                       display_methods(pager, mclass.inherited_methods)
+               for mclass in mclasses do
+                       var nclass = mbuilder.mclassdef2nclassdef[mclass.intro].as(AStdClassdef)
+
+                       pager.add("# {mclass.namespace}\n".bold)
+                       pager.add("{mclass.short_doc}")
+                       pager.add_rule
+                       pager.addn(nclass.comment.green)
+                       pager.add_rule
+                       if not mclass.parameter_types.is_empty then
+                               pager.add("# formal types".bold)
+                               for ft, bound in mclass.parameter_types do
+                                       pager.add("")
+                                       pager.add("\t{ft.to_s.green}: {bound}")
+                               end
+                       end
+                       if not mclass.virtual_types.is_empty then
+                               pager.add("# virtual types".bold)
+                               for vt in mclass.virtual_types do
+                                       pager.add("")
+                                       vt_fulldoc(pager, vt)
+                               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
+
+                       for cat, list in cats do
+                               if not list.is_empty then
+                                       #sort list
+                                       var sorted = new Array[MMethod]
+                                       sorted.add_all(list)
+                                       var sorter = new ComparableSorter[MMethod]
+                                       sorter.sort(sorted)
+                                       pager.add("\n# {cat}".bold)
+                                       for mprop in sorted do
+                                               pager.add("")
+                                               method_fulldoc(pager, mprop)
+                                       end
+                               end
+                       end
+                       pager.add_rule
                end
-               pager.add_rule
                pager.render
-               #TODO check inheritance methods
        end
 
-       private fun mclass_shortdoc(mclass: MClass, pager: Pager) do
-               var nclass = mbuilder.mclassdef2nclassdef[mclass.intro].as(AStdClassdef)
-
-               if not mclass.short_comment(nclass).is_empty then
-                       pager.add("\t# {mclass.short_comment(nclass)}")
-               end
-               pager.addn("\t")
-               if mclass.is_abstract then
-                       pager.addn("abstract ")
+       private fun props_fulldoc(raw_mprops: List[MProperty]) do
+               var pager = new Pager
+               # group by module
+               var cats = new HashMap[MClass, 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)
                end
-               if mclass.is_interface then
-                       pager.addn("interface ")
-               else if mclass.is_enum then
-                       pager.addn("enum ")
-               else
-                       pager.addn("class ")
+               #sort groups
+               var sorter = new ComparableSorter[MClass]
+               var sorted = new Array[MClass]
+               sorted.add_all(cats.keys)
+               sorter.sort(sorted)
+               # display
+               for mclass in sorted do
+                       var mprops = cats[mclass]
+                       pager.add("# {mclass.namespace}".bold)
+                       var sorterp = new ComparableSorter[MProperty]
+                       sorterp.sort(mprops)
+                       for mprop in mprops do
+                               if mprop isa MMethod and mbuilder.mpropdef2npropdef.has_key(mprop.intro) then
+                                       pager.add("")
+                                       method_fulldoc(pager, mprop)
+                               else if mprop isa MVirtualTypeProp then
+                                       pager.add("")
+                                       vt_fulldoc(pager, mprop)
+                               end
+                       end
+                       pager.add_rule
                end
-               if mclass.visibility.to_s == "public" then
-                       pager.addn("{mclass.ni_name} ".green)
-               else if mclass.visibility.to_s == "private" then
-                       pager.addn("{mclass.ni_name} ".red)
-               else
-                       pager.addn("{mclass.ni_name} ".yellow)
+               pager.render
+       end
+
+       private fun seek_returns(entry: String): List[MProperty] do
+               # TODO how to match with generic types?
+               var matches = new List[MProperty]
+               for mprop in model.mproperties do
+                       var intro = mprop.intro
+                       if intro isa MMethodDef then
+                               if intro.msignature.return_mtype != null and intro.msignature.return_mtype.to_s == entry then matches.add(mprop)
+                       else if intro isa MAttributeDef then
+                               if intro.static_mtype.to_s == entry then matches.add(mprop)
+                       end
                end
-               pager.addn("super {mclass.in_hierarchy(mainmodule).direct_greaters.join(", ")}\n")
+               return matches
        end
 
-       private fun display_methods(pager: Pager, methods: Set[MMethod]) do
-               for mmethod in methods do
-                       #TODO verifier cast
-                       var nmethod = mbuilder.mpropdef2npropdef[mmethod.intro].as(AMethPropdef)
-                       if not mmethod.short_comment(nmethod).is_empty then
-                               pager.add("\t# {mmethod.short_comment(nmethod)}")
+       private fun seek_params(entry: String): List[MProperty] do
+               # TODO how to match with generic types?
+               var matches = new List[MProperty]
+               for mprop in model.mproperties do
+                       var intro = mprop.intro
+                       if intro isa MMethodDef then
+                               var mparameters = intro.msignature.mparameters
+                               for mparameter in mparameters do
+                                       if mparameter.mtype.to_s == entry then matches.add(mprop)
+                               end
+                       else if intro isa MAttributeDef then
+                               if intro.static_mtype.to_s == entry then matches.add(mprop)
                        end
-                       #TODO replace Ft by names
-                       #TODO fun ou init
-                       pager.addn("\tfun ")
-                       if mmethod.visibility.to_s == "public" then pager.addn(mmethod.name.green)
-                       if mmethod.visibility.to_s == "private" then pager.addn(mmethod.name.red)
-                       if mmethod.visibility.to_s == "protected" then pager.addn(mmethod.name.yellow)
-
-                       pager.addn("{mmethod.intro.msignature.to_s} ")
-                       #pager.addn("{nmethod.collect_text} ")
-                       if nmethod isa ADeferredMethPropdef then pager.addn("is abstract ")
-                       if nmethod isa AInternMethPropdef then pager.addn("is intern ")
-                       if nmethod isa AExternMethPropdef then pager.addn("is extern ")
-                       #TODO si non local ajouter namespace
-                       pager.add("\n")
                end
+               return matches
        end
-end
 
-redef class MModule
-       # Get the list of mclasses refined in self
-       private fun redef_mclasses: Set[MClass] do
-               var mclasses = new HashSet[MClass]
-               for c in mclassdefs do
-                       if not c.is_intro and not mclasses.has(c.mclass) then
-                               mclasses.add(c.mclass)
+       private fun method_fulldoc(pager: Pager, mprop: MMethod) do
+               if mbuilder.mpropdef2npropdef.has_key(mprop.intro) then
+                       var nprop = mbuilder.mpropdef2npropdef[mprop.intro]
+                       if not nprop.short_comment.is_empty then
+                               pager.add("\t# {nprop.short_comment}")
+                       end
+                       if nprop isa AAttrPropdef then
+                               pager.add("\t{nprop.read_accessor}")
+                               pager.add("\t{nprop.write_accessor}")
+                       else if nprop isa AMethPropdef then
+                               pager.add("\t{nprop}")
+                       end
+                       pager.add("\t\t" + "introduced in {mprop.intro_mclassdef.namespace}".gray)
+                       for mpropdef in mprop.mpropdefs do
+                               if mpropdef != mprop.intro then
+                                       pager.add("\t\t" + "refined in {mpropdef.mclassdef.namespace}".gray)
+                               end
                        end
                end
-               return mclasses
        end
 
-       private fun comment(nmodule: AModule): String do
-               var ret = ""
-               for t in nmodule.n_moduledecl.n_doc.n_comment do
-                       ret += "{t.text.replace("# ", "")}"
+       private fun vt_fulldoc(pager: Pager, vt: MVirtualTypeProp) do
+               pager.add("\t{vt.short_doc}")
+               pager.add("\t\t" + "introduced in {vt.intro_mclassdef.namespace}::{vt}".gray)
+               for mpropdef in vt.mpropdefs do
+                       if mpropdef != vt.intro then
+                               pager.add("\t\t" + "refined in {mpropdef.mclassdef.namespace}".gray)
+                       end
                end
-               return ret
+       end
+end
+
+# Printing facilities
+
+redef class MModule
+       super Comparable
+       redef type OTHER: MModule
+       redef fun <(other: OTHER): Bool do return self.name < other.name
+
+       private fun namespace: String do
+               return full_name
        end
 end
 
 redef class MClass
+       super Comparable
+       redef type OTHER: MClass
+       redef fun <(other: OTHER): Bool do return self.name < other.name
 
-       private fun ni_name: String do
+       redef fun to_s: String do
                if arity > 0 then
                        return "{name}[{intro.parameter_names.join(", ")}]"
                else
@@ -263,49 +364,63 @@ redef class MClass
                end
        end
 
-       # Get the list of class constructors
-       private fun constructors: Set[MMethod] do
-               var res = new HashSet[MMethod]
-               for mclassdef in mclassdefs do
-                       for mpropdef in mclassdef.mpropdefs do
-                               if mpropdef isa MMethodDef then
-                                       if mpropdef.mproperty.is_init then res.add(mpropdef.mproperty)
-                               end
-                       end
+       private fun short_doc: String do
+               var ret = ""
+               if is_interface then ret = "interface {ret}"
+               if is_enum then ret = "enum {ret}"
+               if is_class then ret = "class {ret}"
+               if is_abstract then ret = "abstract {ret}"
+               if visibility.to_s == "public" then ret = "{ret}{to_s.green}"
+               if visibility.to_s == "private" then ret = "{ret}{to_s.red}"
+               if visibility.to_s == "protected" then ret = "{ret}{to_s.yellow}"
+               if not parents.is_empty then
+                       ret = "{ret} super {parents.join(", ")}"
                end
-               return res
+               return ret
        end
 
-       # Get the list of intro methods
-       private fun intro_methods: Set[MMethod] do
-               var res = new HashSet[MMethod]
-               for mclassdef in mclassdefs do
-                       for mpropdef in mclassdef.mpropdefs do
-                               if mpropdef isa MMethodDef then
-                                       if mpropdef.is_intro and not mpropdef.mproperty.is_init then res.add(mpropdef.mproperty)
-                               end
-                       end
-               end
-               return res
+       private fun namespace: String do
+               return "{intro_mmodule.public_owner.name}::{name}"
        end
+end
 
-       # Get the list of inherited methods
-       private fun inherited_methods: Set[MMethod] do
-               var res = new HashSet[MMethod]
-               for mclassdef in mclassdefs do
-                       for mpropdef in mclassdef.mpropdefs do
-                               if mpropdef isa MMethodDef then
-                                       if not mpropdef.is_intro and not mpropdef.mproperty.is_init then res.add(mpropdef.mproperty)
-                               end
-                       end
+redef class MClassDef
+       private fun namespace: String do
+               return "{mmodule.full_name}::{mclass.name}"
+       end
+end
+
+redef class MProperty
+       super Comparable
+       redef type OTHER: MProperty
+       redef fun <(other: OTHER): Bool do return self.name < other.name
+end
+
+redef class MVirtualTypeProp
+       private fun short_doc: String do
+               var ret = ""
+               if visibility.to_s == "public" then ret = "{to_s.green}: {intro.bound.to_s}"
+               if visibility.to_s == "private" then ret = "\t{to_s.red}: {intro.bound.to_s}"
+               if visibility.to_s == "protected" then ret = "\t{to_s.yellow}: {intro.bound.to_s}"
+               return ret
+       end
+end
+
+redef class AModule
+       private fun comment: String do
+               var ret = ""
+               for t in n_moduledecl.n_doc.n_comment do
+                       ret += "{t.text.replace("# ", "")}"
                end
-               return res
+               return ret
        end
+end
 
-       private fun comment(nclass: AStdClassdef): String do
+redef class AStdClassdef
+       private fun comment: String do
                var ret = ""
-               if nclass.n_doc != null then
-                       for t in nclass.n_doc.n_comment do
+               if n_doc != null then
+                       for t in n_doc.n_comment do
                                var txt = t.text.replace("# ", "")
                                txt = txt.replace("#", "")
                                ret += "{txt}"
@@ -314,45 +429,121 @@ redef class MClass
                return ret
        end
 
-       private fun short_comment(nclass: AStdClassdef): String do
+       private fun short_comment: String do
                var ret = ""
-               if nclass.n_doc != null then
-                       var txt = nclass.n_doc.n_comment.first.text
+               if n_doc != null then
+                       var txt = n_doc.n_comment.first.text
                        txt = txt.replace("# ", "")
                        txt = txt.replace("\n", "")
                        ret += txt
                end
                return ret
        end
+end
 
-       private fun is_class: Bool do
-               return self.kind == concrete_kind or self.kind == abstract_kind
-       end
+redef class APropdef
+       private fun short_comment: String is abstract
+end
 
-       private fun is_interface: Bool do
-               return self.kind == interface_kind
+redef class AAttrPropdef
+       redef fun short_comment do
+               var ret = ""
+               if n_doc != null then
+                       var txt = n_doc.n_comment.first.text
+                       txt = txt.replace("# ", "")
+                       txt = txt.replace("\n", "")
+                       ret += txt
+               end
+               return ret
        end
 
-       private fun is_enum: Bool do
-               return self.kind == enum_kind
+       private fun read_accessor: String do
+               var ret = "fun "
+               #FIXME bug with standard::stream::FDStream::fd
+               var name = mreadpropdef.mproperty.name
+               if mpropdef.mproperty.visibility.to_s == "public" then ret = "{ret}{name.green}"
+               if mpropdef.mproperty.visibility.to_s == "private" then ret = "{ret}{name.red}"
+               if mpropdef.mproperty.visibility.to_s == "protected" then ret = "{ret}{name.yellow}"
+               ret = "{ret}: {n_type.to_s}"
+               if n_kwredef != null then ret = "redef {ret}"
+               return ret
        end
 
-       private fun is_abstract: Bool do
-               return self.kind == abstract_kind
+       private fun write_accessor: String do
+               var ret = "fun "
+               var name = "{mreadpropdef.mproperty.name}="
+               if n_readable != null and n_readable.n_visibility != null then
+                       if n_readable.n_visibility isa APublicVisibility then ret = "{ret}{name.green}"
+                       if n_readable.n_visibility isa APrivateVisibility then ret = "{ret}{name.red}"
+                       if n_readable.n_visibility isa AProtectedVisibility then ret = "{ret}{name.yellow}"
+               else
+                       ret = "{ret}{name.red}"
+               end
+               ret = "{ret}({mreadpropdef.mproperty.name}: {n_type.to_s})"
+               if n_kwredef != null then ret = "redef {ret}"
+               return ret
        end
 end
 
-redef class MMethod
-       private fun short_comment(nmethod: AMethPropdef): String do
+redef class AMethPropdef
+       redef fun short_comment do
                var ret = ""
-               if nmethod.n_doc != null then
-                       var txt = nmethod.n_doc.n_comment.first.text
+               if n_doc != null then
+                       var txt = n_doc.n_comment.first.text
                        txt = txt.replace("# ", "")
                        txt = txt.replace("\n", "")
                        ret += txt
                end
                return ret
        end
+
+       redef fun to_s do
+               var ret = ""
+               if not mpropdef.mproperty.is_init then
+                       ret = "fun "
+               end
+               if mpropdef.mproperty.visibility.to_s == "public" then ret = "{ret}{mpropdef.mproperty.name.green}"
+               if mpropdef.mproperty.visibility.to_s == "private" then ret = "{ret}{mpropdef.mproperty.name.red}"
+               if mpropdef.mproperty.visibility.to_s == "protected" then ret = "{ret}{mpropdef.mproperty.name.yellow}"
+               if n_signature != null then ret = "{ret}{n_signature.to_s}"
+               if n_kwredef != null then ret = "redef {ret}"
+               if self isa ADeferredMethPropdef then ret = "{ret} is abstract"
+               if self isa AInternMethPropdef then ret = "{ret} is intern"
+               if self isa AExternMethPropdef then ret = "{ret} is extern"
+               return ret
+       end
+end
+
+redef class ASignature
+       redef fun to_s do
+               #TODO closures
+               var ret = ""
+               if not n_params.is_empty then
+                       ret = "{ret}({n_params.join(", ")})"
+               end
+               if n_type != null then ret += ": {n_type.to_s}"
+               return ret
+       end
+end
+
+redef class AParam
+       redef fun to_s do
+               var ret = "{n_id.text}"
+               if n_type != null then
+                       ret = "{ret}: {n_type.to_s}"
+                       if n_dotdotdot != null then ret = "{ret}..."
+               end
+               return ret
+       end
+end
+
+redef class AType
+       redef fun to_s do
+               var ret = n_id.text
+               if n_kwnullable != null then ret = "nullable {ret}"
+               if not n_types.is_empty then ret = "{ret}[{n_types.join(", ")}]"
+               return ret
+       end
 end
 
 # Redef String class to add a function to color the string
@@ -368,6 +559,7 @@ redef class String
        private fun green: String do return add_escape_char("{esc}[1;32m")
        private fun blue: String do return add_escape_char("{esc}[1;34m")
        private fun cyan: String do return add_escape_char("{esc}[1;36m")
+       private fun gray: String do return add_escape_char("{esc}[30;1m")
        private fun bold: String do return add_escape_char("{esc}[1m")
        private fun underline: String do return add_escape_char("{esc}[4m")
 
@@ -403,9 +595,7 @@ toolcontext.process_options
 var ni = new NitIndex(toolcontext)
 ni.start
 
-# TODO seek methods
-# TODO bornes sur les signatures génériques
-# TODO lister les methods qui retournent un certain type
-# TODO lister les methods qui utilisent un certain type
-# TODO lister les sous-types connus d'une type
-# TODO lister les prop adaptés à un type générique
+# TODO seek subclasses and super classes <.<class> >.<class>
+# TODO seek subclasses and super types <:<type> >:<type>
+# TODO seek with regexp
+# TODO standardize namespaces with private option