X-Git-Url: http://nitlanguage.org diff --git a/src/ni.nit b/src/ni.nit index aad0b02..8c169f3 100644 --- a/src/ni.nit +++ b/src/ni.nit @@ -69,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 @@ -85,193 +92,293 @@ 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 - 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") + # 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 - if not mmodule.in_importation.direct_smallers.is_empty then - pager.add("known clients: ".bold + "{mmodule.in_importation.direct_smallers.join(", ")}\n") + 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.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 - 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 MClassNameSorter - 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 + # 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 + # 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? 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.short_doc}") - 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 @@ -304,62 +411,51 @@ 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 redef class MModule + # 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 - 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 - 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 @@ -369,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" @@ -389,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 @@ -450,16 +552,16 @@ redef class MVirtualType end redef class ADoc - private fun comment: String do - var res = new Buffer + private fun comment: List[String] do + var res = new List[String] for t in n_comment do - res.append(t.text.replace("# ", "").replace("#", "")) + res.add(t.text.replace("\n", "")) end - return res.to_s + 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 @@ -500,12 +602,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")