- # search for modules
- private fun search_modules(query: IndexQuery): Set[MModule] do
- var matches = new HashSet[MModule]
- for mmodule in model.mmodules do
- if mmodule.name == query.keyword then matches.add(mmodule)
- end
- return matches
- end
-
- # search for classes
- private fun search_classes(query: IndexQuery): Set[MClass] do
- var matches = new HashSet[MClass]
- for mclass in model.mclasses do
- if mclass.name == query.keyword then matches.add(mclass)
- end
- return matches
- end
-
- # search for properties
- private fun search_properties(query: IndexQuery): Set[MProperty] do
- var matches = new HashSet[MProperty]
- for mproperty in model.mproperties do
- if mproperty.name == query.keyword then matches.add(mproperty)
- end
- return matches
- end
-
- # 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 ownername::name
- private fun prototype: String do return "module {name.bold}"
-
- # namespace of the module
- # ownername::name
- private fun namespace: String do
- if public_owner == null then
- return self.name
- else
- return "{public_owner.namespace}::{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
- if not in_nesting.direct_greaters.has(mmodule) then 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
- # nested modules
- var nested = in_nesting.direct_greaters.to_a
- if not nested.is_empty then
- sorter.sort(nested)
- pager.add("")
- pager.add("== nested modules".bold)
- pager.indent = pager.indent + 1
- for mmodule in nested 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