ni: better mclass page display
[nit.git] / src / ni.nit
index d860f39..141a676 100644 (file)
@@ -18,13 +18,16 @@ module ni
 import model_utils
 
 private class Pager
-       var content: String = ""
+       var content = new Buffer
        fun add(text: String) do addn("{text}\n")
-       fun addn(text: String) do content += text.escape
+       fun addn(text: String) do content.append(text.escape)
        fun add_rule do add("\n---\n")
        fun render do sys.system("echo \"{content}\" | pager -r")
 end
 
+# Main class of the nit index tool
+# NitIndex build the model using the toolcontext argument
+# then wait for query on std in to display documentation
 class NitIndex
        private var toolcontext: ToolContext
        private var model: Model
@@ -52,7 +55,6 @@ class NitIndex
                #var mmodules = modelbuilder.parse_and_build(["{dir}/lib/standard/standard.nit"])
                var mmodules = mbuilder.parse_and_build([arguments.first])
                if mmodules.is_empty then return
-               mbuilder.full_propdef_semantic_analysis
                assert mmodules.length == 1
                self.mainmodule = mmodules.first
        end
@@ -67,13 +69,20 @@ class NitIndex
        end
 
        fun welcome do
-               print "Welcome in Nit Index.\n"
-               print "Loaded modules"
-               for m in mbuilder.nmodules do
-                       print " - {m.mmodule.name}"
+               print "Welcome in the Nit Index."
+               print "\nCommands:"
+               print "\tname\t\tlookup module, class and property with the corresponding 'name'"
+               print "\tparam: Type\tlookup methods using the corresponding 'Type' as parameter"
+               print "\treturn: Type\tlookup methods returning the corresponding 'Type'"
+               print "\tEnter a blank line to exit.\n"
+               print "\nLoaded modules:"
+               var mmodules = new Array[MModule]
+               mmodules.add_all(model.mmodules)
+               var sorter = new MModuleNameSorter
+               sorter.sort(mmodules)
+               for m in mmodules do
+                       print "\t{m.name}"
                end
-               print "\nEnter the module, class or property name you want to look up."
-               print "Enter a blank line to exit.\n"
        end
 
        fun prompt do
@@ -136,54 +145,89 @@ class NitIndex
        private fun modules_fulldoc(mmodules: List[MModule]) do
                var pager = new Pager
                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
-                       if not mmodule.in_importation.direct_smallers.is_empty then
-                               pager.add("known clients: ".bold + "{mmodule.in_importation.direct_smallers.join(", ")}\n")
+                       # name and prototype
+                       pager.add("# {mmodule.namespace}\n".bold)
+                       # comment
+                       if mbuilder.mmodule2nmodule.has_key(mmodule) then
+                               var nmodule = mbuilder.mmodule2nmodule[mmodule]
+                               if not nmodule.n_moduledecl.n_doc == null then
+                                       for comment in nmodule.n_moduledecl.n_doc.comment do pager.add(comment.green)
+                               end
                        end
+                       pager.add("{mmodule.prototype}")
                        pager.add_rule
-                       pager.addn(nmodule.n_moduledecl.n_doc.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.n_doc == null and not nclass.n_doc.short_comment.is_empty then
-                                                       pager.add("\t# {nclass.n_doc.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
+                       # 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.addn("\t")
+                               for i in [0..ms.length[ do
+                                       if ms[i] == mmodule then continue
+                                       pager.addn(ms[i].name)
+                                       if i < ms.length - 1 then pager.addn(", ")
+                               end
+                               pager.add("\n")
+                       end
+                       # clients
+                       ms = mmodule.in_importation.smallers.to_a
+                       if ms.length > 1 then
+                               msorter.sort(ms)
+                               pager.add("# known modules".bold)
+                               pager.addn("\t")
+                               for i in [0..ms.length[ do
+                                       if ms[i] == mmodule then continue
+                                       pager.addn(ms[i].name)
+                                       if i < ms.length - 1 then pager.addn(", ") 
+                               end
+                               pager.add("\n")
+                       end
+                       # local classes and interfaces
+                       var sorter = new MClassDefNameSorter
+                       var intro_mclassdefs = new Array[MClassDef]
+                       var redef_mclassdefs = new Array[MClassDef]
+                       for mclassdef in mmodule.mclassdefs do
+                               if mclassdef.is_intro then
+                                       intro_mclassdefs.add(mclassdef)
+                               else
+                                       redef_mclassdefs.add(mclassdef)
+                               end
+                       end
+                       # intro
+                       if not intro_mclassdefs.is_empty then
+                               sorter.sort(intro_mclassdefs)
+                               pager.add("\n# introduced classes".bold)
+                               for mclassdef in intro_mclassdefs do
+                                       pager.add("")
+                                       var nclass = mbuilder.mclassdef2nclassdef[mclassdef]
+                                       if nclass isa AStdClassdef and not nclass.n_doc == null and not nclass.n_doc.short_comment.is_empty then
+                                               pager.add("\t{nclass.n_doc.short_comment.green}")
                                        end
+                                       pager.add("\t{mclassdef.mclass.prototype}")
+                                       #TODO add redefs?
                                end
                        end
-                       pager.add_rule
+                       # redefs
+                       if not redef_mclassdefs.is_empty then
+                               sorter.sort(redef_mclassdefs)
+                               pager.add("\n# refined classes".bold)
+                               for mclassdef in redef_mclassdefs do
+                                       pager.add("")
+                                       #TODO intro comment?
+                                       var nclass = mbuilder.mclassdef2nclassdef[mclassdef]
+                                       if nclass isa AStdClassdef and not nclass.n_doc == null and not nclass.n_doc.short_comment.is_empty then
+                                               pager.add("\t# {nclass.n_doc.short_comment.green}")
+                                       end
+                                       pager.add("\t{mclassdef.mclass.prototype}")
+                                       pager.add("\t\t" + "introduced in {mclassdef.mclass.intro.mmodule.namespace.bold}".gray)
+                                       for odef in mclassdef.mclass.mclassdefs do
+                                               if odef.is_intro or odef == mclassdef or mclassdef.mmodule == mmodule then continue
+                                               pager.add("\t\t" + "refined in {mclassdef.mmodule.namespace.bold}".gray)
+                                       end
+                               end
+                       end
+                       #TODO add inherited classes?
                end
                pager.render
        end
@@ -191,54 +235,145 @@ class NitIndex
        private fun classes_fulldoc(mclasses: List[MClass]) do
                var pager = new Pager
                for mclass in mclasses do
-                       var nclass = mbuilder.mclassdef2nclassdef[mclass.intro].as(AStdClassdef)
-
+                       # title
                        pager.add("# {mclass.namespace}\n".bold)
-                       pager.add("{mclass.short_doc}")
-                       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.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("")
+                       end
                        pager.add_rule
+                       # formal types
                        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
+                               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("")
-                                       vt_fulldoc(pager, vt)
+                       # 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 ComparableSorter[MMethod]
+                                       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("")
-                                               method_fulldoc(pager, mprop)
+                                               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 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.comment.is_empty then
+                               for comment in nprop.n_doc.comment do pager.add("\t{comment.green}")
+                       end
+               end
+               pager.add("\t{mpropdef}")
+               if not mpropdef.is_intro then
+                       pager.add("\t\t" + "introduced in {mpropdef.mproperty.intro_mclassdef.namespace.bold}".gray)
+               end
+               var mpropdefs = mpropdef.mproperty.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
+
        private fun props_fulldoc(raw_mprops: List[MProperty]) do
                var pager = new Pager
                # group by module
@@ -251,7 +386,7 @@ class NitIndex
                        cats[mclass].add(mprop)
                end
                #sort groups
-               var sorter = new ComparableSorter[MClass]
+               var sorter = new MClassNameSorter
                var sorted = new Array[MClass]
                sorted.add_all(cats.keys)
                sorter.sort(sorted)
@@ -259,16 +394,11 @@ class NitIndex
                for mclass in sorted do
                        var mprops = cats[mclass]
                        pager.add("# {mclass.namespace}".bold)
-                       var sorterp = new ComparableSorter[MProperty]
+                       var sorterp = new MPropertyNameSorter
                        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
+                               pager.add("")
+                               mpropdef_fulldoc(pager, mprop.intro)
                        end
                        pager.add_rule
                end
@@ -305,81 +435,51 @@ class NitIndex
                end
                return matches
        end
-
-       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.n_doc == null and not nprop.n_doc.short_comment.is_empty then
-                               pager.add("\t# {nprop.n_doc.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
-       end
-
-       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
-       end
 end
 
 # Printing facilities
 
 redef class MModule
-       super Comparable
-       redef type OTHER: MModule
-       redef fun <(other: OTHER): Bool do return self.name < other.name
+       # prototype of the module
+       #       module ownername::name
+       private fun prototype: String do return "module {name}"
 
+       # namespace of the module
+       #       ownername::name
        private fun namespace: String do
-               return full_name
+               if public_owner == null then
+                       return self.name
+               else
+                       return "{public_owner.namespace}::{self.name}"
+               end
        end
 end
 
 redef class MClass
-       super Comparable
-       redef type OTHER: MClass
-       redef fun <(other: OTHER): Bool do return self.name < other.name
-
-       redef fun to_s: String do
+       # return the generic signature of the class
+       #       [E, F]
+       private fun signature: String do
                if arity > 0 then
-                       return "{name}[{intro.parameter_names.join(", ")}]"
+                       return "[{intro.parameter_names.join(", ")}]"
                else
-                       return name
+                       return ""
                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 ret
+       # return the prototype of the class
+       # class name is displayed with colors depending on visibility
+       #       abstract interface Foo[E]
+       private fun prototype: String do
+               var res = new Buffer
+               res.append("{kind} ")
+               if visibility.to_s == "public" then res.append("{name}{signature}".bold.green)
+               if visibility.to_s == "private" then res.append("{name}{signature}".bold.red)
+               if visibility.to_s == "protected" then res.append("{name}{signature}".bold.yellow)
+               return res.to_s
        end
 
        private fun namespace: String do
-               return "{intro_mmodule.public_owner.name}::{name}"
+               return "{intro_mmodule.namespace}::{name}"
        end
 end
 
@@ -390,32 +490,102 @@ redef class MClassDef
 end
 
 redef class MProperty
-       super Comparable
-       redef type OTHER: MProperty
-       redef fun <(other: OTHER): Bool do return self.name < other.name
+       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 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
+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 ")
+               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"
+               #if self isa AInternMethPropdef then ret = "{ret} is intern"
+               #if self isa AExternMethPropdef then ret = "{ret} is extern"
+               return res.to_s
        end
 end
 
-redef class ADoc
-       private fun comment: String do
+redef class MVirtualTypeDef
+       redef fun to_s do
                var res = new Buffer
-               for t in n_comment do
-                       res.append(t.text.replace("# ", "").replace("#", ""))
+               res.append("type ")
+               res.append(mproperty.to_s.bold)
+               res.append(": {bound.to_s}")
+               return res.to_s
+       end
+end
+
+redef class MSignature
+       redef fun to_s do
+               var res = new Buffer
+               if not mparameters.is_empty then
+                       res.append("(")
+                       for i in [0..mparameters.length[ do
+                               res.append(mparameters[i].to_s)
+                               if i < mparameters.length - 1 then res.append(", ")
+                       end
+                       res.append(")")
+               end
+               if return_mtype != null then
+                       res.append(": {return_mtype.to_s}")
                end
                return res.to_s
        end
+end
+
+redef class MParameter
+       redef fun to_s do
+               var res = new Buffer
+               res.append("{name}: {mtype}")
+               if is_vararg then res.append("...")
+               return res.to_s
+       end
+end
+
+redef class MNullableType
+       redef fun to_s do return "nullable {mtype}"
+end
+
+redef class MGenericType
+       redef fun to_s do
+               var res = new Buffer
+               res.append("{mclass.name}[")
+               for i in [0..arguments.length[ do
+                       res.append(arguments[i].to_s)
+                       if i < arguments.length - 1 then res.append(", ")
+               end
+               res.append("]")
+               return res.to_s
+       end
+end
+
+redef class MParameterType
+       redef fun to_s do return mclass.intro.parameter_names[rank]
+end
+
+redef class MVirtualType
+       redef fun to_s do return mproperty.intro.to_s
+end
+
+redef class ADoc
+       private fun comment: List[String] do
+               var res = new List[String]
+               for t in n_comment do
+                       res.add(t.text.replace("\n", ""))
+               end
+               return res
+       end
 
        private fun short_comment: String do
-               return n_comment.first.text.replace("# ", "").replace("\n", "")
+               return n_comment.first.text.replace("\n", "")
        end
 end
 
@@ -448,56 +618,6 @@ redef class AAttrPropdef
        end
 end
 
-redef class AMethPropdef
-       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
 redef class String
 
@@ -506,12 +626,14 @@ redef class String
        end
 
        private fun esc: Char do return 27.ascii
-       private fun red: String do return add_escape_char("{esc}[1;31m")
-       private fun yellow: String do return add_escape_char("{esc}[1;33m")
-       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 gray: String do return add_escape_char("{esc}[30m")
+       private fun red: String do return add_escape_char("{esc}[31m")
+       private fun green: String do return add_escape_char("{esc}[32m")
+       private fun yellow: String do return add_escape_char("{esc}[33m")
+       private fun blue: String do return add_escape_char("{esc}[34m")
+       private fun purple: String do return add_escape_char("{esc}[35m")
+       private fun cyan: String do return add_escape_char("{esc}[36m")
+       private fun light_gray: String do return add_escape_char("{esc}[37m")
        private fun bold: String do return add_escape_char("{esc}[1m")
        private fun underline: String do return add_escape_char("{esc}[4m")