X-Git-Url: http://nitlanguage.org diff --git a/src/doc/doc_phases/doc_console.nit b/src/doc/doc_phases/doc_console.nit index c304dab..b6d08dc 100644 --- a/src/doc/doc_phases/doc_console.nit +++ b/src/doc/doc_phases/doc_console.nit @@ -19,6 +19,8 @@ module doc_console import semantize +import doc_extract +import doc_poset import doc::console_templates # Nitx handles console I/O. @@ -57,11 +59,24 @@ class Nitx # Displays the list of available commands. fun help do - print "\nCommands:" - print "\tname\t\tlookup module, class and property with the corresponding 'name'" + print "\nCommands:\n" + print "\tname\t\t\tlookup module, class and property with the corresponding 'name'" print "\tdoc: \tdisplay the documentation page of 'namespace'" - print "\t:h\t\tdisplay this help message" - print "\t:q\t\tquit interactive mode" + print "\nType lookup:" + print "\tparam: \t\tlookup methods using the corresponding 'Type' as parameter" + print "\treturn: \t\tlookup methods returning the corresponding 'Type'" + print "\tnew: \t\tlookup methods creating new instances of 'Type'" + print "\tcall: \t\tlookup methods calling 'name'" + print "\nHierarchy lookup:" + print "\tparents: \tlist direct parents of 'Class'" + print "\tancestors: \tlist all ancestors of 'Class'" + print "\tchildren: \tlist direct children of 'Class'" + print "\tdescendants: \tlist all descendants of 'Class'" + print "\nCode lookup:" + print "\tcode: \t\tdisplay the source code associated to the 'name' entity" + print "\n" + print "\t:h\t\t\tdisplay this help message" + print "\t:q\t\t\tquit interactive mode" print "" end @@ -74,19 +89,14 @@ class Nitx # Processes the query string and performs it. fun do_query(str: String) do - var query = parse_query(str) - var res = query.perform(self, doc) - var page = query.make_results(self, res) - print page.write_to_string - end - - # Returns an `NitxQuery` from a raw query string. - fun parse_query(str: String): NitxQuery do var query = new NitxQuery(str) if query isa NitxCommand then query.execute(self) + return end - return query + var res = query.perform(self, doc) + var page = query.make_results(self, res) + print page.write_to_string end end @@ -113,6 +123,24 @@ interface NitxQuery return new CommentQuery(query_string) else if query_string.has_prefix("doc:") then return new DocQuery(query_string) + else if query_string.has_prefix("param:") then + return new ParamQuery(query_string) + else if query_string.has_prefix("return:") then + return new ReturnQuery(query_string) + else if query_string.has_prefix("new:") then + return new NewQuery(query_string) + else if query_string.has_prefix("call:") then + return new CallQuery(query_string) + else if query_string.has_prefix("code:") then + return new CodeQuery(query_string) + else if query_string.has_prefix("parents:") then + return new ParentsQuery(query_string) + else if query_string.has_prefix("ancestors:") then + return new AncestorsQuery(query_string) + else if query_string.has_prefix("children:") then + return new ChildrenQuery(query_string) + else if query_string.has_prefix("descendants:") then + return new DescendantsQuery(query_string) end return new CommentQuery("comment: {query_string}") end @@ -122,8 +150,8 @@ interface NitxQuery # Pretty prints the results for the console. fun make_results(nitx: Nitx, results: Array[NitxMatch]): DocPage do - var page = new DocPage("Results") - page.root.add_child(new QueryResultArticle(self, results)) + var page = new DocPage("results", "Results") + page.root.add_child(new QueryResultArticle("results.article", "Results", self, results)) return page end @@ -187,7 +215,7 @@ class CommentQuery redef fun perform(nitx, doc) do var name = args.first var res = new Array[NitxMatch] - for mentity in doc.search_mentities(name) do + for mentity in doc.mentities_by_name(name) do res.add new MEntityMatch(self, mentity) end return res @@ -198,8 +226,8 @@ class CommentQuery if len == 1 then var res = results.first.as(MEntityMatch) var mentity = res.mentity - var page = new DocPage("Results") - var article = new DefinitionArticle(mentity) + var page = new DocPage("results", "Results") + var article = new DefinitionArticle("results.article", "Results", mentity) article.cs_title = mentity.name article.cs_subtitle = mentity.cs_declaration page.root.add_child article @@ -210,6 +238,90 @@ class CommentQuery end end +# A query to search signatures using a specific `MType` as parameter. +class ParamQuery + super MetaQuery + + redef fun perform(nitx, doc) do + var res = new Array[NitxMatch] + var mtype_name = args.first + for mproperty in doc.mproperties do + if not mproperty isa MMethod then continue + var msignature = mproperty.intro.msignature + if msignature != null then + for mparam in msignature.mparameters do + if mparam.mtype.name == mtype_name then + res.add new MEntityMatch(self, mproperty) + end + end + end + end + return res + end +end + +# A query to search signatures using a specific `MType` as return. +class ReturnQuery + super MetaQuery + + redef fun perform(nitx, doc) do + var res = new Array[NitxMatch] + var mtype_name = args.first + for mproperty in doc.mproperties do + if not mproperty isa MMethod then continue + var msignature = mproperty.intro.msignature + if msignature != null then + var mreturn = msignature.return_mtype + if mreturn != null and mreturn.name == mtype_name then + res.add new MEntityMatch(self, mproperty) + end + end + end + return res + end +end + +# A query to search methods creating new instances of a specific `MType`. +class NewQuery + super MetaQuery + + redef fun perform(nitx, doc) do + var res = new Array[NitxMatch] + var mtype_name = args.first + for mpropdef in doc.mpropdefs do + var visitor = new TypeInitVisitor(mtype_name) + var npropdef = nitx.ctx.modelbuilder.mpropdef2node(mpropdef) + if npropdef == null then continue + visitor.enter_visit(npropdef) + for i in visitor.inits do + res.add new MEntityMatch(self, mpropdef) + end + end + return res + end +end + +# A query to search methods calling a specific `MProperty`. +class CallQuery + super MetaQuery + + redef fun perform(nitx, doc) do + var res = new Array[NitxMatch] + var mprop_name = args.first + for mpropdef in doc.mpropdefs do + var visitor = new MPropertyCallVisitor + var npropdef = nitx.ctx.modelbuilder.mpropdef2node(mpropdef) + if npropdef == null then continue + visitor.enter_visit(npropdef) + for mprop in visitor.calls do + if mprop.name != mprop_name then continue + res.add new MEntityMatch(self, mpropdef) + end + end + return res + end +end + # A query to search a Nitdoc documentation page by its name. class DocQuery super MetaQuery @@ -217,7 +329,7 @@ class DocQuery redef fun perform(nitx, doc) do var res = new Array[NitxMatch] var name = args.first - for page in doc.pages do + for page in doc.pages.values do if name == "*" then # FIXME dev only res.add new PageMatch(self, page) else if page.title == name then @@ -260,6 +372,124 @@ class PageMatch end end +# Search in class or module hierarchy of a `MEntity`. +# +# It actually searches for pages about the mentity and extracts the +# pre-calculated hierarchies by the `doc_post` phase. +abstract class HierarchiesQuery + super DocQuery + + redef fun make_results(nitx, results) do + var page = new DocPage("hierarchy", "Hierarchy") + for result in results do + if not result isa PageMatch then continue + var rpage = result.page + if not rpage isa MClassPage then continue + page.root.add_child build_article(rpage) + end + return page + end + + # Build an article containing the hierarchy list depending on subclasses. + private fun build_article(page: MClassPage): DocArticle is abstract +end + +# List all parents of a `MClass`. +class AncestorsQuery + super HierarchiesQuery + + redef fun build_article(page) do + return new MEntitiesListArticle( + "ancerstors", + "Ancestors for {page.mentity.name}", + page.ancestors.to_a) + end +end + +# List direct parents of a `MClass`. +class ParentsQuery + super HierarchiesQuery + + redef fun build_article(page) do + return new MEntitiesListArticle( + "parents", + "Parents for {page.mentity.name}", + page.parents.to_a) + end +end + +# List direct children of a `MClass`. +class ChildrenQuery + super HierarchiesQuery + + redef fun build_article(page) do + return new MEntitiesListArticle( + "children", + "Children for {page.mentity.name}", + page.children.to_a) + end +end + +# List all descendants of a `MClass`. +class DescendantsQuery + super HierarchiesQuery + + redef fun build_article(page) do + return new MEntitiesListArticle( + "descendants", + "Descendants for {page.mentity.name}", + page.children.to_a) + end +end + +# A query to search source code from a file name. +class CodeQuery + super MetaQuery + + # FIXME refactor this! + redef fun perform(nitx, doc) do + var res = new Array[NitxMatch] + var name = args.first + # if name is an existing sourcefile, opens it + if name.file_exists then + var fr = new FileReader.open(name) + var content = fr.read_all + fr.close + res.add new CodeMatch(self, name, content) + return res + end + # else, lookup the model by name + for mentity in doc.mentities_by_name(name) do + if mentity isa MClass then continue + if mentity isa MProperty then continue + res.add new CodeMatch(self, mentity.cs_location, mentity.cs_source_code) + end + return res + end + + redef fun make_results(nitx, results) do + var page = new DocPage("results", "Code Results") + for res in results do + page.add new CodeQueryArticle("results.article", "Results", self, res.as(CodeMatch)) + end + return page + end +end + +# A match between a piece of code and a string. +class CodeMatch + super NitxMatch + + # Location of the code match. + var location: String + + # Piece of code matched. + var content: String + + redef fun make_list_item do return "* {location}" +end + + # A query that contains a nitx command. # # These commands are prefixed with `:` and are used to control the execution of @@ -287,29 +517,38 @@ end ## exploration -redef class DocModel - - # Lists all MEntities in the model. - private var mentities: Collection[MEntity] is lazy do - var res = new HashSet[MEntity] - res.add_all mprojects - res.add_all mgroups - res.add_all mmodules - res.add_all mclasses - res.add_all mclassdefs - res.add_all mproperties - res.add_all mpropdefs - return res +# Visitor looking for initialized `MType` (new T). +# +# See `NewQuery`. +private class TypeInitVisitor + super Visitor + + # `MType` name to look for. + var mtype_name: String + + 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 and mtype.name == mtype_name then inits.add(mtype) end +end - # Search MEntities that match `name` by their name or namespace. - private fun search_mentities(name: String): Array[MEntity] do - var res = new Array[MEntity] - for mentity in mentities do - if mentity.name != name and mentity.cs_namespace != name then continue - res.add mentity - end - return res +# Visitor looking for calls to a `MProperty` (new T). +# +# See `CallQuery`. +private class MPropertyCallVisitor + super Visitor + + var calls = new HashSet[MProperty] + redef fun visit(node) + do + node.visit_all(self) + if not node isa ASendExpr then return + calls.add node.callsite.mproperty end end @@ -343,6 +582,24 @@ private class QueryResultArticle end end +# An article that displays a piece of code. +private class CodeQueryArticle + super DocArticle + + # The query linked to the result to display. + var query: NitxQuery + + # The result to display. + var result: CodeMatch + + redef fun render_body do + addn "" + addn "in {result.location}".gray.bold + addn "" + add result.content + end +end + # A Pager is used to display data into a unix `less` container. private class Pager