- # search for mpropdef returning keyword
- private fun search_returns(query: IndexQuery): Set[MProperty] do
- var matches = new HashSet[MProperty]
- for mproperty in model.mproperties do
- var intro = mproperty.intro
- if intro isa MMethodDef then
- if intro.msignature.return_mtype != null and intro.msignature.return_mtype.to_console.has_prefix(query.keyword) then matches.add(mproperty)
- else if intro isa MAttributeDef then
- if intro.static_mtype.to_console.has_prefix(query.keyword) then matches.add(mproperty)
- end
- end
- return matches
- end
-
- # search for mpropdef taking keyword as parameter
- private fun search_params(query: IndexQuery): Set[MProperty] do
- var matches = new HashSet[MProperty]
- for mproperty in model.mproperties do
- var intro = mproperty.intro
- if intro isa MMethodDef then
- var mparameters = intro.msignature.mparameters
- for mparameter in mparameters do
- if mparameter.mtype.to_console.has_prefix(query.keyword) then matches.add(mproperty)
- end
- else if intro isa MAttributeDef then
- if intro.static_mtype.to_console.has_prefix(query.keyword) then matches.add(mproperty)
- end
- end
- return matches
- end
-
- # search for mpropdef creating new instance of keyword
- private fun search_inits(query: IndexQuery): Set[MPropDef] do
- var mtype2mpropdefs = toolcontext.nitx_phase.mtype2mpropdefs
- var matches = new HashSet[MPropDef]
- for mtype in mtype2mpropdefs.keys do
- if mtype.to_console.has_prefix(query.keyword) then
- for mpropdef in mtype2mpropdefs[mtype] do
- matches.add(mpropdef)
- end
- end
- end
- return matches
- end
-end
-
-private class IndexQuery
- var string: String
- var keyword: String
- init(string: String, keyword: String) do
- self.string = string
- self.keyword = keyword
- end
-end
-
-private class IndexQueryPair
- super IndexQuery
- var category: String
- init(string: String, keyword: String, category: String) do
- super(string, keyword)
- self.category = category
- end
-end
-
-# A match to a query in the nit index
-private interface IndexMatch
- # Short preview of the result for result list display
- fun preview(index: NitIndex, output: Pager) is abstract
- fun content(index: NitIndex, output: Pager) is abstract
-end
-
-# Code Analysis
-
-redef class ToolContext
- private var nitx_phase: NitxPhase = new NitxPhase(self, [typing_phase])
-end
-
-# Compiler phase for nitx
-private class NitxPhase
- super Phase
-
- var mtype2mpropdefs = new HashMap[MType, Set[MPropDef]]
- redef fun process_npropdef(npropdef) do
- var visitor = new TypeInitVisitor
- visitor.enter_visit(npropdef)
- for mtype in visitor.inits do
- if not mtype2mpropdefs.has_key(mtype) then
- mtype2mpropdefs[mtype] = new HashSet[MPropDef]
- end
- mtype2mpropdefs[mtype].add(npropdef.mpropdef.as(not null))
- end
- end
-end
-
-# Visitor looking for initialized mtype (new T)
-private class TypeInitVisitor
- super Visitor
-
- var inits = new HashSet[MType]
- redef fun visit(node)
- do
- node.visit_all(self)
- # look for init
- if not node isa ANewExpr then return
- var mtype = node.n_type.mtype
- if mtype != null then inits.add(mtype)
- end
-end
-
-# Pager output for console
-
-private class PagerMatchesRenderer
- var index: NitIndex
- init(index: NitIndex) do self.index = index
-
- fun render_matches(query: IndexQuery, matches: Collection[IndexMatch]) do
- var pager = new Pager
- if matches.length == 1 then
- pager.add("= result for '{query.string}'".bold)
- pager.add("")
- pager.indent = pager.indent + 1
- matches.first.content(index, pager)
- pager.indent = pager.indent - 1
- else
- pager.add("= multiple results for '{query.string}'".bold)
- pager.indent = pager.indent + 1
- for match in matches do
- pager.add("")
- match.preview(index, pager)
- end
- pager.indent = pager.indent - 1
- end
- pager.render
- end
-
- private fun props_fulldoc(pager: Pager, raw_mprops: List[MProperty]) do
- # group by module
- var cats = new HashMap[MModule, Array[MProperty]]
- for mprop in raw_mprops do
- if mprop isa MAttribute then continue
- 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 MModuleNameSorter
- var sorted = new Array[MModule]
- sorted.add_all(cats.keys)
- sorter.sort(sorted)
- # display
- 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
-
- end
- pager.add_rule
- end
- end
-end
-
-private class Pager
- var content = new Buffer
- var indent = 0
- fun add(text: String) do
- add_indent
- addn("{text}\n")
- end
- fun add_indent do addn(" " * indent)
- 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
-
-redef class MModule
- super IndexMatch
- # prototype of the module
- # module name
- private fun prototype: String do return "module {name.bold}"
-
- # namespace of the module
- # project::name
- private fun namespace: String do
- if mgroup == null or mgroup.mproject.name == self.name then
- return self.name
- else
- return "{mgroup.mproject}::{self.name}"
- end
- end
-
- redef fun preview(index, pager) do
- if index.mbuilder.mmodule2nmodule.has_key(self) then
- var node = index.mbuilder.mmodule2nmodule[self]
- if node.n_moduledecl != null and not node.n_moduledecl.n_doc == null and not node.n_moduledecl.n_doc.short_comment.is_empty then
- pager.add(node.n_moduledecl.n_doc.short_comment.green)
- end
- end
- pager.add(prototype)
- pager.add("{namespace}".bold.gray + " (lines {location.lines})".gray)
- end
-
- redef fun content(index, pager) do
- if index.mbuilder.mmodule2nmodule.has_key(self) then
- var node = index.mbuilder.mmodule2nmodule[self]
- if node.n_moduledecl != null and not node.n_moduledecl.n_doc == null and not node.n_moduledecl.n_doc.comment.is_empty then
- for comment in node.n_moduledecl.n_doc.comment do pager.add(comment.green)
- end
- end
- pager.add(prototype)
- pager.add("{namespace}".bold.gray + " (lines {location.lines})".gray)
- pager.indent = pager.indent + 1
- var sorter = new MModuleNameSorter
- # imported modules
- var imports = new Array[MModule]
- for mmodule in in_importation.direct_greaters.to_a do
- imports.add(mmodule)
- end
- if not imports.is_empty then
- sorter.sort(imports)
- pager.add("")
- pager.add("== imported modules".bold)
- pager.indent = pager.indent + 1
- for mmodule in imports do
- pager.add("")
- mmodule.preview(index, pager)
- end
- pager.indent = pager.indent - 1
- end
- # mclassdefs
- var csorter = new MClassDefNameSorter
- var intros = new Array[MClassDef]
- var redefs = new Array[MClassDef]
- for mclassdef in mclassdefs do
- if mclassdef.is_intro then
- intros.add(mclassdef)
- else
- redefs.add(mclassdef)
- end
- end
- # introductions
- if not intros.is_empty then
- csorter.sort(intros)
- pager.add("")
- pager.add("== introduced classes".bold)
- pager.indent = pager.indent + 1
- for mclass in intros do
- pager.add("")
- mclass.preview(index, pager)
- end
- pager.indent = pager.indent - 1
- end
- # refinements
- if not redefs.is_empty then
- csorter.sort(redefs)
- pager.add("")
- pager.add("== refined classes".bold)
- pager.indent = pager.indent + 1
- for mclass in redefs do
- pager.add("")
- mclass.preview(index, pager)
- end
- pager.indent = pager.indent - 1
- end
- pager.indent = pager.indent - 1
- end
-end
-
-redef class MClass
- super IndexMatch
- # return the generic signature of the class
- # [E, F]
- private fun signature: String do
- var res = new Buffer
- if arity > 0 then
- res.append("[")
- for i in [0..intro.parameter_names.length[ do
- res.append(intro.parameter_names[i])
- if i < intro.parameter_names.length - 1 then res.append(", ")
- end
- res.append("]")
- end
- return res.to_s
- end
-
- # 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.namespace}::{name}"
- end
-
- redef fun preview(index, pager) do
- intro.preview(index, pager)
- end
-
- redef fun content(index, pager) do
- # intro comment
- if index.mbuilder.mclassdef2nclassdef.has_key(intro) then
- var node = index.mbuilder.mclassdef2nclassdef[intro]
- if node isa AStdClassdef and not node.n_doc == null and not node.n_doc.comment.is_empty then
- for comment in node.n_doc.comment do pager.add(comment.green)
- end
- end
- pager.add(intro.to_console)
- pager.add("{intro.namespace}".bold.gray + " (lines {intro.location.lines})".gray)
- pager.indent = pager.indent + 1
- # parents
- var supers = self.in_hierarchy(index.mainmodule).direct_greaters.to_a
- if not supers.is_empty then
- var csorter = new MClassNameSorter
- csorter.sort(supers)
- pager.add("")
- pager.add("== supers".bold)
- pager.indent = pager.indent + 1
- for mclass in supers do
- pager.add("")
- mclass.preview(index, pager)
- end
- pager.indent = pager.indent - 1
- end
- # formal types
- if not self.parameter_types.is_empty then
- pager.add("")
- pager.add("== formal types".bold)
- pager.indent = pager.indent + 1
- for ft, bound in self.parameter_types do
- pager.add("")
- pager.add("{ft.to_s.bold.green}: {bound.to_console}")
- end
- pager.indent = pager.indent - 1
- end
- # intro mproperties
- var psorter = new MPropDefNameSorter
- var mpropdefs = intro.mpropdefs
- index.mainmodule.linearize_mpropdefs(mpropdefs)
- for cat in intro.cats2mpropdefs.keys do
- var defs = intro.cats2mpropdefs[cat].to_a
- if defs.is_empty then continue
- psorter.sort(defs)
- pager.add("")
- pager.add("== {cat}".bold)
- pager.indent = pager.indent + 1
- for mpropdef in defs do
- pager.add("")
- mpropdef.preview(index, pager)
- end
- pager.indent = pager.indent - 1
- end
- # refinements
- if not self.mclassdefs.is_empty then
- pager.add("")
- pager.add("== refinements".bold)
- var mclassdefs = self.mclassdefs
- index.mainmodule.linearize_mclassdefs(mclassdefs)
- pager.indent = pager.indent + 1
- for mclassdef in mclassdefs do
- if not mclassdef.is_intro then
- pager.add("")
- mclassdef.content(index, pager)
- end
- end
- pager.indent = pager.indent - 1