Merge: nitx: use doc commands
authorJean Privat <jean@pryen.org>
Tue, 19 Dec 2017 15:17:37 +0000 (10:17 -0500)
committerJean Privat <jean@pryen.org>
Tue, 19 Dec 2017 15:17:37 +0000 (10:17 -0500)
Three things in this PR:
* `nitx` now uses doc-commands (and related cleaning), bye bye the heavy `DocModel` with pre built `DocPages`
* More tests for `nitx`
* Move `nitx` to the `doc` tools suite, the group is now known as `doc::term`

Pull-Request: #2591
Reviewed-by: Jean Privat <jean@pryen.org>

46 files changed:
share/man/nitx.md
src/doc/commands/commands_model.nit
src/doc/commands/commands_parser.nit
src/doc/console_templates/console_model.nit [deleted file]
src/doc/console_templates/console_templates.nit [deleted file]
src/doc/doc_phases/doc_console.nit [deleted file]
src/doc/templates/templates_term.nit [new file with mode: 0644]
src/doc/term/term.nit [new file with mode: 0644]
src/doc/term/tests/test_term.nit [new file with mode: 0644]
src/doc/term/tests/test_term.sav/test_ancestors.res [new file with mode: 0644]
src/doc/term/tests/test_term.sav/test_ancestors_without_parents.res [new file with mode: 0644]
src/doc/term/tests/test_term.sav/test_call.res [new file with mode: 0644]
src/doc/term/tests/test_term.sav/test_children.res [new file with mode: 0644]
src/doc/term/tests/test_term.sav/test_code.res [new file with mode: 0644]
src/doc/term/tests/test_term.sav/test_comment.res [new file with mode: 0644]
src/doc/term/tests/test_term.sav/test_comment_no_fallback.res [new file with mode: 0644]
src/doc/term/tests/test_term.sav/test_comment_short.res [new file with mode: 0644]
src/doc/term/tests/test_term.sav/test_descendants.res [new file with mode: 0644]
src/doc/term/tests/test_term.sav/test_descendants_without_children.res [new file with mode: 0644]
src/doc/term/tests/test_term.sav/test_features.res [new file with mode: 0644]
src/doc/term/tests/test_term.sav/test_init.res [new file with mode: 0644]
src/doc/term/tests/test_term.sav/test_lin.res [new file with mode: 0644]
src/doc/term/tests/test_term.sav/test_lin_no_lin.res [new file with mode: 0644]
src/doc/term/tests/test_term.sav/test_mentity_conflict.res [new file with mode: 0644]
src/doc/term/tests/test_term.sav/test_mentity_empty.res [new file with mode: 0644]
src/doc/term/tests/test_term.sav/test_mentity_full_name.res [new file with mode: 0644]
src/doc/term/tests/test_term.sav/test_mentity_name.res [new file with mode: 0644]
src/doc/term/tests/test_term.sav/test_mentity_not_found.res [new file with mode: 0644]
src/doc/term/tests/test_term.sav/test_param.res [new file with mode: 0644]
src/doc/term/tests/test_term.sav/test_parents.res [new file with mode: 0644]
src/doc/term/tests/test_term.sav/test_return.res [new file with mode: 0644]
src/doc/term/tests/test_term.sav/test_search.res [new file with mode: 0644]
src/doc/term/tests/test_term.sav/test_search_no_query.res [new file with mode: 0644]
src/doc/term/tests/test_term.sav/test_term_catalog.res [new file with mode: 0644]
src/doc/term/tests/test_term.sav/test_term_catalog_contrib.res [new file with mode: 0644]
src/doc/term/tests/test_term.sav/test_term_catalog_maintain.res [new file with mode: 0644]
src/doc/term/tests/test_term.sav/test_term_catalog_search.res [new file with mode: 0644]
src/doc/term/tests/test_term.sav/test_term_catalog_stats.res [new file with mode: 0644]
src/doc/term/tests/test_term.sav/test_term_catalog_tag.res [new file with mode: 0644]
src/doc/term/tests/test_term.sav/test_term_catalog_tags.res [new file with mode: 0644]
src/nitx.nit
tests/nitx.args
tests/sav/nitx.res
tests/sav/nitx_args1.res
tests/sav/nitx_args2.res
tests/sav/nitx_args3.res

index fc2f8e6..755649e 100644 (file)
@@ -57,6 +57,11 @@ Ignore the attributes.
 ### `--private`
 Also generate private API.
 
+### `--catalog`
+Use catalog.
+
+Allow queries to catalog data (can be long on large code base).
+
 # SEE ALSO
 
 The Nit language documentation and the source code of its tools and libraries may be downloaded from <http://nitlanguage.org>
index 230bf81..1e88381 100644 (file)
@@ -398,7 +398,7 @@ class CmdCode
        # Rendering format
        #
        # Set the output format for this piece of code.
-       # Can be "raw" or "html".
+       # Can be "raw", "html" or "ansi".
        # Default is "raw".
        #
        # This format can be different than the format used in the command response.
@@ -431,9 +431,14 @@ class CmdCode
                        var hl = new HtmlightVisitor
                        hl.highlight_node node
                        return hl.html
+               else if format == "ansi" then
+                       var hl = new AnsiHighlightVisitor
+                       hl.highlight_node node
+                       return hl.result
                end
-               # TODO make a raw visitor
-               return node.to_s
+               var mentity = self.mentity
+               if mentity == null then return null
+               return mentity.location.text
        end
 end
 
index af75cbe..182ca53 100644 (file)
@@ -41,6 +41,35 @@ class CommandParser
        "param", "return", "new", "call", "defs", "list", "random",
        "catalog", "stats", "tags", "tag", "person", "contrib", "maintain"] is writable
 
+       # List of commands usage and documentation
+       var commands_usage: Map[String, String] do
+               var usage = new ArrayMap[String, String]
+               usage["search: <string>"] = "list entities matching `string`"
+               usage["doc: <name>"] = "display the documentation for `name`"
+               usage["defs: <name>"] = "list all definitions for `name`"
+               usage["code: <name>"] = "display the code for `name`"
+               usage["lin: <name>"] = "display the linearization for `name`"
+               usage["uml: <name>"] = "display the UML diagram for `name`"
+               usage["graph: <name>"] = "display the inheritance graph for `name`"
+               usage["parents: <name>"] = "list the direct parents of `name`"
+               usage["ancestors: <name>"] = "list all ancestors of `name`"
+               usage["children: <name>"] = "list direct children of `name`"
+               usage["descendants: <name>"] = "list all descendants of `name`"
+               usage["param: <type>"] = "list all methods accepting `type` as parameter"
+               usage["return: <type>"] = "list all methods returning `type`"
+               usage["new: <class>"] = "list all methods initializing `class`"
+               usage["call: <property>"] = "list all methods calling `property`"
+               usage["list: <kind>"] = "list all entities of `kind` from the model"
+               usage["random: <kind>"] = "list random entities of `kind` from the model"
+               usage["catalog:"] = "list packages from catalog"
+               usage["stats:"] = "display catalog statistics"
+               usage["tags:"] = "list all tabs from catalog"
+               usage["tag: <tag>"] = "list all packages with `tag`"
+               usage["maintain: <person>"] = "list all packages maintained by `person`"
+               usage["contrib: <person>"] = "list all packages contributed by `person`"
+               return usage
+       end
+
        # Parse `string` as a DocCommand
        #
        # Returns `null` if the string cannot be parsed.
diff --git a/src/doc/console_templates/console_model.nit b/src/doc/console_templates/console_model.nit
deleted file mode 100644 (file)
index cacac49..0000000
+++ /dev/null
@@ -1,668 +0,0 @@
-# This file is part of NIT ( http://www.nitlanguage.org ).
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-# Console templates for Nit model MEntities.
-#
-# This module introduces console rendering services in model entities.
-module console_model
-
-import console
-import doc_base
-import ordered_tree
-
-redef class MDoc
-       # Returns the full comment formatted for the console.
-       fun cs_comment: String do
-               var res = new FlatBuffer
-               for line in content do
-                       res.append "    {line}\n"
-               end
-               return res.write_to_string
-       end
-
-       # Returns the synopsys formatted for the console.
-       fun cs_short_comment: String do return content.first
-end
-
-redef class MEntity
-
-       # Returns the mentity name with short signature.
-       #
-       # * MPackage: `foo`
-       # * MGroup: `foo`
-       # * MModule: `foo`
-       # * MClass: `Foo[E]`
-       # * MClassDef: `Foo[E]`
-       # * MProperty: `foo(e)`
-       # * MPropdef: `foo(e)`
-       var cs_name: String is lazy do return name
-
-       # Returns the list of keyword used in `self` declaration.
-       fun cs_modifiers: Array[String] is abstract
-
-       # Returns the complete MEntity declaration (modifiers + name + signature).
-       #
-       # * MPackage: `package foo`
-       # * MGroup: `group foo`
-       # * MModule: `module foo`
-       # * MClass: `private abstract class Foo[E: Object]`
-       # * MClassDef: `redef class Foo[E]`
-       # * MProperty: `private fun foo(e: Object): Int`
-       # * MPropdef: `redef fun foo(e)`
-       var cs_declaration: String is lazy do
-               var tpl = new FlatBuffer
-               tpl.append cs_modifiers.join(" ")
-               tpl.append " "
-               tpl.append cs_name
-               return tpl.write_to_string
-       end
-
-       # Returns `self` namespace formatted for console.
-       #
-       # * MPackage: `mpackage`
-       # * MGroup: `mpackage(::group)`
-       # * MModule: `mgroup::mmodule`
-       # * MClass: `mpackage::mclass`
-       # * MClassDef: `mmodule::mclassdef`
-       # * MProperty: `mclass::mprop`
-       # * MPropdef: `mclassdef:mpropdef`
-       fun cs_namespace: String is abstract
-
-       # Returns the comment of this MEntity formatted for console.
-       var cs_comment: nullable String is lazy do
-               var mdoc = mdoc_or_fallback
-               if mdoc == null then return null
-               # FIXME add markdown for console
-               return mdoc.cs_comment
-       end
-
-       # Returns the comment of this MEntity formatted for console.
-       var cs_short_comment: nullable String is lazy do
-               var mdoc = mdoc_or_fallback
-               if mdoc == null then return null
-               return mdoc.cs_short_comment
-       end
-
-       # Returns `self` as a list element that can be displayed in console.
-       #
-       # Displays `cs_icon`, `cs_name`, `cs_short_comment, `cs_namespace`,
-       # `cs_declaration` and `cs_location`.
-       fun cs_list_item: String do
-               var tpl = new FlatBuffer
-               tpl.append " {cs_visibility_color(cs_icon).bold} {cs_name.blue.bold}"
-               var comment = cs_short_comment
-               if comment != null then
-                       tpl.append " # {comment}".green
-               end
-               tpl.append "\n   "
-               tpl.append cs_namespace.gray.bold
-               tpl.append "\n   "
-               tpl.append cs_declaration
-               tpl.append "\n   "
-               tpl.append cs_location.gray
-               return tpl.write_to_string
-       end
-
-       # Returns `self` as a short list element that can be displayed in console.
-       # Displays `cs_icon`, `cs_name`, and `cs_short_comment.
-       fun cs_short_list_item: String do
-               var tpl = new FlatBuffer
-               tpl.append " {cs_visibility_color(cs_icon).bold} {cs_name.blue.bold}"
-               var comment = cs_short_comment
-               if comment != null then
-                       tpl.append " # {comment}".green
-               end
-               return tpl.write_to_string
-       end
-
-       # ASCII icon to be displayed in front of the list item.
-       fun cs_icon: String do return "*"
-
-       # Source code location of this MEntity formatted for console.
-       fun cs_location: String is abstract
-
-       # Sets text color depending on visibility.
-       #
-       # See module `console`.
-       fun cs_visibility_color(string: String): String do return string.green
-
-       # Source code associated to this MEntity.
-       #
-       # Uses `cs_location` to locate the source code.
-       fun cs_source_code: String do
-               # FIXME up location to mentity
-               var loc = new Location.from_string(cs_location)
-               var fr = new FileReader.open(loc.file.filename)
-               var content = new FlatBuffer
-               var i = 0
-               while not fr.eof do
-                       i += 1
-                       var line = fr.read_line
-                       if i < loc.line_start or i > loc.line_end then continue
-                       # FIXME add nitlight for console
-                       content.append "{line}\n"
-               end
-               fr.close
-               return content.write_to_string
-       end
-end
-
-redef class MPackage
-       redef var cs_modifiers = ["package"]
-       redef fun cs_namespace do return cs_name
-       redef fun cs_icon do return "P"
-       redef fun cs_location do return root.mmodules.first.location.to_s
-end
-
-redef class MGroup
-       redef var cs_modifiers = ["group"]
-       redef fun cs_icon do return "G"
-
-       # Depends if `self` is root or not.
-       #
-       # * If root `mpackage`.
-       # * Else `mpackage::self`.
-       redef fun cs_namespace do
-               var tpl = new FlatBuffer
-               tpl.append mpackage.cs_namespace
-               if mpackage.root != self then
-                       tpl.append "::"
-                       tpl.append cs_name
-               end
-               return tpl.write_to_string
-       end
-
-       redef fun cs_location do return mmodules.first.location.to_s
-end
-
-redef class MModule
-       redef var cs_modifiers = ["module"]
-       redef fun cs_icon do return "M"
-
-       # Depends if `self` belongs to a MGroup.
-       #
-       # * If mgroup `mgroup::self`.
-       # * Else `self`.
-       redef fun cs_namespace do
-               var tpl = new FlatBuffer
-               if mgroup != null then
-                       tpl.append mgroup.cs_namespace
-                       tpl.append "::"
-               end
-               tpl.append cs_name
-               return tpl.write_to_string
-       end
-
-       redef fun cs_location do return location.to_s
-end
-
-redef class MClass
-       redef fun cs_icon do return intro.cs_icon
-
-       # Format: `Foo[E]`
-       redef var cs_name is lazy do
-               var tpl = new FlatBuffer
-               tpl.append name
-               if arity > 0 then
-                       tpl.append "["
-                       var parameter_names = new Array[String]
-                       for p in mparameters do
-                               parameter_names.add(p.cs_name)
-                       end
-                       tpl.append parameter_names.join(", ")
-                       tpl.append "]"
-               end
-               return tpl.write_to_string
-       end
-
-       redef fun cs_modifiers do return intro.cs_modifiers
-       redef fun cs_declaration do return intro.cs_declaration
-
-       # Returns `mpackage::self`.
-       redef fun cs_namespace do
-               var tpl = new FlatBuffer
-               tpl.append intro_mmodule.mgroup.mpackage.cs_namespace
-               tpl.append "::"
-               tpl.append cs_name
-               return tpl.write_to_string
-       end
-
-       # Returns `intro.cs_short_signature`.
-       fun cs_short_signature: String do return intro.cs_short_signature
-
-       # Returns `intro.cs_signature`.
-       fun cs_signature: String do return intro.cs_signature
-
-       redef fun cs_visibility_color(string) do
-               if visibility == private_visibility then
-                       return string.red
-               else if visibility == protected_visibility then
-                       return string.yellow
-               end
-               return string.green
-       end
-
-       redef fun cs_location do return intro.location.to_s
-end
-
-redef class MClassDef
-       redef fun cs_icon do return "C"
-
-       # Depends if `self` is an intro or not.
-       #
-       # * If intro contains the visibility and kind.
-       # * If redef contains the `redef` keyword and kind.
-       redef fun cs_modifiers do
-               var res = new Array[String]
-               if not is_intro then
-                       res.add "redef"
-               else
-                       if mclass.visibility != public_visibility then
-                               res.add mclass.visibility.to_s
-                       end
-               end
-               res.add mclass.kind.to_s
-               return res
-       end
-
-       # Depends if `self` is an intro or not.
-       #
-       # For intro: `private abstract class Foo[E: Object]`
-       # For redef: `redef class Foo[E]`
-       redef fun cs_declaration do
-               var tpl = new FlatBuffer
-               tpl.append cs_modifiers.join(" ")
-               tpl.append " "
-               tpl.append cs_name
-               if is_intro then
-                       tpl.append cs_signature
-               else
-                       tpl.append cs_short_signature
-               end
-               return tpl.write_to_string.write_to_string.write_to_string
-       end
-
-       # Returns `mmodule::self`
-       redef fun cs_namespace do
-               var tpl = new FlatBuffer
-               tpl.append mmodule.cs_namespace
-               tpl.append "::"
-               tpl.append mclass.cs_name
-               return tpl.write_to_string.write_to_string
-       end
-
-       # Returns the MClassDef generic signature without static bounds.
-       fun cs_short_signature: String do
-               var tpl = new FlatBuffer
-               var mparameters = mclass.mparameters
-               if not mparameters.is_empty then
-                       tpl.append "["
-                       for i in [0..mparameters.length[ do
-                               tpl.append mparameters[i].cs_name
-                               if i < mparameters.length - 1 then tpl.append ", "
-                       end
-                       tpl.append "]"
-               end
-               return tpl.write_to_string
-       end
-
-       # Returns the MClassDef generic signature with static bounds.
-       fun cs_signature: String do
-               var tpl = new FlatBuffer
-               var mparameters = mclass.mparameters
-               if not mparameters.is_empty then
-                       tpl.append "["
-                       for i in [0..mparameters.length[ do
-                               tpl.append "{mparameters[i].cs_name}: "
-                               tpl.append bound_mtype.arguments[i].cs_signature
-                               if i < mparameters.length - 1 then tpl.append ", "
-                       end
-                       tpl.append "]"
-               end
-               return tpl.write_to_string
-       end
-
-       redef fun cs_location do return location.to_s
-end
-
-redef class MProperty
-       redef fun cs_modifiers do return intro.cs_modifiers
-       redef fun cs_declaration do return intro.cs_declaration
-       redef fun cs_icon do return intro.cs_icon
-
-       # Returns `mclass::self`.
-       redef fun cs_namespace do
-               var tpl = new FlatBuffer
-               tpl.append intro_mclassdef.mclass.cs_namespace
-               tpl.append "::"
-               tpl.append intro.cs_name
-               return tpl.write_to_string
-       end
-
-       # Returns `intro.cs_short_signature`.
-       fun cs_short_signature: String do return intro.cs_short_signature
-
-       # Returns `intro.cs_signature`.
-       fun cs_signature: String do return intro.cs_signature
-
-       redef fun cs_visibility_color(string) do
-               if visibility == private_visibility then
-                       return string.red
-               else if visibility == protected_visibility then
-                       return string.yellow
-               end
-               return string.green
-       end
-
-       # Returns `intro.cs_location`.
-       redef fun cs_location do return intro.location.to_s
-end
-
-redef class MPropDef
-       # Depends if `self` is an intro or not.
-       #
-       # * If intro contains the visibility and kind.
-       # * If redef contains the `redef` keyword and kind.
-       redef fun cs_modifiers do
-               var res = new Array[String]
-               if not is_intro then
-                       res.add "redef"
-               else
-                       if mproperty.visibility != public_visibility then
-                               res.add mproperty.visibility.to_s
-                       end
-               end
-               return res
-       end
-
-       # Depends if `self` is an intro or not.
-       #
-       # For intro: `private fun foo(e: Object): Bar is abstract`
-       # For redef: `redef fun foo(e) is cached`
-       redef fun cs_declaration do
-               var tpl = new FlatBuffer
-               tpl.append cs_modifiers.join(" ")
-               tpl.append " "
-               if is_intro then
-                       tpl.append cs_name
-                       tpl.append cs_signature
-               else
-                       tpl.append mproperty.intro.cs_name
-                       tpl.append cs_short_signature
-               end
-               return tpl.write_to_string
-       end
-
-       # Returns `mclassdef::self`
-       redef fun cs_namespace do
-               var tpl = new FlatBuffer
-               tpl.append mclassdef.cs_namespace
-               tpl.append "::"
-               tpl.append cs_name
-               return tpl.write_to_string
-       end
-
-       redef fun cs_location do return location.to_s
-
-       # Returns the MPropdDef signature without static types.
-       fun cs_short_signature: String is abstract
-
-       # Returns the MPropDef signature with static types.
-       fun cs_signature: String is abstract
-end
-
-redef class MAttributeDef
-
-       redef fun cs_modifiers do
-               var res = super
-               res.add "var"
-               return res
-       end
-
-       redef fun cs_short_signature do return ""
-
-       redef fun cs_signature do
-               var tpl = new FlatBuffer
-               if static_mtype != null then
-                       tpl.append ": "
-                       tpl.append static_mtype.cs_signature
-               end
-               return tpl.write_to_string
-       end
-
-       redef fun cs_icon do return "A"
-end
-
-redef class MMethodDef
-
-       redef fun cs_modifiers do
-               if mproperty.is_init then
-                       var res = new Array[String]
-                       if mproperty.visibility != public_visibility then
-                               res.add mproperty.visibility.to_s
-                       end
-                       return res
-               end
-               var res = super
-               if is_abstract then
-                       res.add "abstract"
-               else if is_intern then
-                       res.add "intern"
-               end
-               res.add "fun"
-               return res
-       end
-
-       redef fun cs_declaration do
-               if mproperty.is_init then
-                       var tpl = new FlatBuffer
-                       if not cs_modifiers.is_empty then
-                               tpl.append cs_modifiers.join(" ")
-                               tpl.append " "
-                       end
-                       tpl.append cs_name
-                       tpl.append cs_signature
-                       return tpl.write_to_string
-               end
-               return super
-       end
-
-       redef fun cs_short_signature do
-               if mproperty.is_root_init then
-                       return new_msignature.cs_short_signature
-               end
-               return msignature.cs_short_signature
-       end
-
-       redef fun cs_signature do
-               if mproperty.is_root_init then
-                       return new_msignature.cs_signature
-               end
-               return msignature.cs_signature
-       end
-
-       redef fun cs_icon do
-               if mproperty.is_init then
-                       return "I"
-               end
-               return "F"
-       end
-end
-
-redef class MVirtualTypeDef
-
-       redef fun cs_modifiers do
-               var res = super
-               res.add "type"
-               return res
-       end
-
-       # Short signature for `MVirtualType` is always empty.
-       redef fun cs_short_signature do return ""
-
-       redef fun cs_signature do
-               var tpl = new FlatBuffer
-               if bound == null then return tpl.write_to_string
-               tpl.append ": "
-               tpl.append bound.cs_signature
-               return tpl.write_to_string
-       end
-       redef fun cs_icon do return "V"
-end
-
-redef class MType
-       # Returns the signature of this type whithout bounds.
-       fun cs_short_signature: String is abstract
-
-       # Returns the signature of this type.
-       fun cs_signature: String is abstract
-
-       redef fun cs_icon do return "T"
-end
-
-redef class MClassType
-       redef fun cs_short_signature do return cs_name
-       redef fun cs_signature do return cs_name
-end
-
-redef class MNullableType
-
-       redef fun cs_short_signature do
-               var tpl = new FlatBuffer
-               tpl.append "nullable "
-               tpl.append mtype.cs_short_signature
-               return tpl.write_to_string
-       end
-
-       redef fun cs_signature do
-               var tpl = new FlatBuffer
-               tpl.append "nullable "
-               tpl.append mtype.cs_signature
-               return tpl.write_to_string
-       end
-end
-
-redef class MGenericType
-       redef fun cs_short_signature do
-               var tpl = new FlatBuffer
-               tpl.append name
-               tpl.append "["
-               for i in [0..arguments.length[ do
-                       tpl.append arguments[i].cs_short_signature
-                       if i < arguments.length - 1 then tpl.append ", "
-               end
-               tpl.append "]"
-               return tpl.write_to_string
-       end
-
-       redef fun cs_signature do
-               var tpl = new FlatBuffer
-               tpl.append mclass.name
-               tpl.append "["
-               for i in [0..arguments.length[ do
-                       tpl.append arguments[i].cs_signature
-                       if i < arguments.length - 1 then tpl.append ", "
-               end
-               tpl.append "]"
-               return tpl.write_to_string
-       end
-end
-
-redef class MParameterType
-       redef fun cs_short_signature do return cs_name
-       redef fun cs_signature do return cs_name
-end
-
-redef class MVirtualType
-       redef fun cs_signature do return cs_name
-end
-
-redef class MSignature
-
-       redef fun cs_short_signature do
-               var tpl = new FlatBuffer
-               if not mparameters.is_empty then
-                       tpl.append "("
-                       for i in [0..mparameters.length[ do
-                               tpl.append mparameters[i].cs_short_signature
-                               if i < mparameters.length - 1 then tpl.append ", "
-                       end
-                       tpl.append ")"
-               end
-               return tpl.write_to_string
-       end
-
-       redef fun cs_signature do
-               var tpl = new FlatBuffer
-               if not mparameters.is_empty then
-                       tpl.append "("
-                       for i in [0..mparameters.length[ do
-                               tpl.append mparameters[i].cs_signature
-                               if i < mparameters.length - 1 then tpl.append ", "
-                       end
-                       tpl.append ")"
-               end
-               if return_mtype != null then
-                       tpl.append ": "
-                       tpl.append return_mtype.cs_signature
-               end
-               return tpl.write_to_string
-       end
-end
-
-redef class MParameter
-
-       # Returns `self` name and ellipsys if any.
-       fun cs_short_signature: String do
-               var tpl = new FlatBuffer
-               tpl.append name
-               if is_vararg then tpl.append "..."
-               return tpl.write_to_string
-       end
-
-       # Returns `self` name with it's static type and ellipsys if any.
-       fun cs_signature: String do
-               var tpl = new FlatBuffer
-               tpl.append "{name}: "
-               tpl.append mtype.cs_signature
-               if is_vararg then tpl.append "..."
-               return tpl.write_to_string
-       end
-end
-
-################################################################################
-# Additions to `model_ext`.
-
-redef class MRawType
-       redef fun cs_signature do
-               var tpl = new FlatBuffer
-
-               for part in parts do
-                       if part.target != null then
-                               tpl.append part.target.as(not null).cs_name
-                       else
-                               tpl.append part.text
-                       end
-               end
-               return tpl.write_to_string
-       end
-end
-
-redef class MInnerClass
-       redef fun cs_signature do return inner.cs_signature
-end
-
-redef class MInnerClassDef
-       redef fun cs_signature do return inner.cs_signature
-end
diff --git a/src/doc/console_templates/console_templates.nit b/src/doc/console_templates/console_templates.nit
deleted file mode 100644 (file)
index fbeea29..0000000
+++ /dev/null
@@ -1,139 +0,0 @@
-# This file is part of NIT ( http://www.nitlanguage.org ).
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-# Introduces templates that compose the documentation in console rendering.
-module console_templates
-
-import console_model
-import doc_phases::doc_structure
-
-# Renders the page displayable as ASCII.
-redef class DocPage
-       super Template
-
-       # Renders the footer and content.
-       private fun render_content do add root
-
-       # Renders the whole page
-       redef fun rendering do render_content
-end
-
-redef class DocComposite
-       super Template
-
-       # Title that can be decorated for console display.
-       #
-       # Set as `null` if you don't want to display a title.
-       var cs_title: nullable String is writable, lazy do return title
-
-       # Subtitle that can be decorated for console display.
-       #
-       # Set as `null` if you don't want to display a subtitle.
-       var cs_subtitle: nullable String is noinit, writable
-
-       # Renders the element `cs_title` and `cs_subtitle` as any.
-       fun render_title do
-               if cs_title != null then
-                       add "{"#" * depth} ".blue.bold
-                       addn cs_title.blue.bold
-               end
-               if cs_subtitle != null then
-                       addn cs_subtitle.gray.bold
-               end
-               if cs_title != null or cs_subtitle != null then addn ""
-       end
-
-       # Renders the element body.
-       fun render_body do for child in children do add child.write_to_string
-
-       redef fun rendering do
-               render_title
-               render_body
-       end
-end
-
-redef class DocRoot
-       redef fun rendering do render_body
-end
-
-redef class ConcernSection
-       redef var cs_title is lazy do return "in {mentity.cs_namespace}"
-       redef var cs_subtitle is lazy do return mentity.cs_declaration
-
-       redef fun rendering do
-               var mentity = self.mentity
-               if mentity isa MGroup and mentity.mpackage.root == mentity then
-                       render_body
-               else
-                       super
-               end
-       end
-end
-
-redef class MEntityComposite
-       redef var cs_title is lazy do return mentity.cs_name
-       redef var cs_subtitle is lazy do return mentity.cs_namespace
-end
-
-redef class IntroArticle
-       redef fun render_body do
-               addn "    {mentity.cs_declaration.bold}"
-               addn "    {mentity.cs_location.gray.bold}"
-               addn ""
-               var comment = mentity.cs_comment
-               if comment != null then
-                       add comment
-               end
-               addn ""
-               super
-       end
-end
-
-redef class ConcernsArticle
-       redef fun render_body do
-               var w = new StringWriter
-               concerns.write_to(w)
-               addn w.to_s
-       end
-end
-
-redef class DefinitionArticle
-       # If short, displays only synopsyses.
-       var is_short = false is writable
-
-       redef fun render_body do
-               addn "    {mentity.cs_visibility_color(mentity.cs_declaration).bold}"
-               addn "    {mentity.cs_location.gray.bold}"
-               addn ""
-               var comment
-               if is_short then
-                       comment = mentity.cs_short_comment
-               else
-                       comment = mentity.cs_comment
-               end
-               if comment != null then
-                       add comment
-               end
-               addn ""
-               super
-       end
-end
-
-redef class MEntitiesListArticle
-       redef fun render_body do
-               for mentity in mentities do
-                       addn mentity.cs_short_list_item
-               end
-       end
-end
diff --git a/src/doc/doc_phases/doc_console.nit b/src/doc/doc_phases/doc_console.nit
deleted file mode 100644 (file)
index 6a5d045..0000000
+++ /dev/null
@@ -1,549 +0,0 @@
-# This file is part of NIT ( http://www.nitlanguage.org ).
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-# Nitx related components
-#
-# This module is a place holder for `nitx` related services.
-# No `doc_phase` can be found here, only components used by Nitx tool.
-module doc_console
-
-import semantize
-import doc_commands
-import doc_poset
-import doc::console_templates
-import model::model_index
-
-# Nitx handles console I/O.
-#
-# Using `prompt`, the command line can be turned on an interactive tool.
-class Nitx
-
-       # ToolContext used to access options.
-       var ctx: ToolContext
-
-       # DocModel that contains the informations to display.
-       var doc: DocModel
-
-       # Comparator used to sort MEntities.
-       var sorter = new MEntityNameSorter
-
-       # Displays the welcome message and start prompt.
-       fun start do
-               welcome
-               prompt
-       end
-
-       # Displays the welcome message and the list of loaded modules.
-       fun welcome do
-               print "Welcome in the Nit Index."
-               print ""
-               print "Loaded modules:"
-               var mmodules = doc.mmodules.to_a
-               sorter.sort(mmodules)
-               for m in mmodules do
-                       print "\t{m.name}"
-               end
-               print ""
-               help
-       end
-
-       # Displays the list of available commands.
-       fun help do
-               print "\nCommands:\n"
-               print "\tname\t\t\tlookup module, class and property with the corresponding 'name'"
-               print "\tdoc: <name::space>\tdisplay the documentation page of 'namespace'"
-               print "\nType lookup:"
-               print "\tparam: <Type>\t\tlookup methods using the corresponding 'Type' as parameter"
-               print "\treturn: <Type>\t\tlookup methods returning the corresponding 'Type'"
-               print "\tnew: <Type>\t\tlookup methods creating new instances of 'Type'"
-               print "\tcall: <name>\t\tlookup methods calling 'name'"
-               print "\nHierarchy lookup:"
-               print "\tparents: <Class>\tlist direct parents of 'Class'"
-               print "\tancestors: <Class>\tlist all ancestors of 'Class'"
-               print "\tchildren: <Class>\tlist direct children of 'Class'"
-               print "\tdescendants: <Class>\tlist all descendants of 'Class'"
-               print "\nCode lookup:"
-               print "\tcode: <name>\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
-
-       # Prompts the user for a command.
-       fun prompt do
-               printn ">> "
-               do_query(sys.stdin.read_line)
-               prompt
-       end
-
-       # Parser used to process doc commands
-       var parser: DocCommandParser is lazy do
-               var parser = new DocCommandParser
-               parser.allowed_commands = ["doc", "comment", "list", "param", "return",
-                       "new", "call", "code"]
-               return parser
-       end
-
-       # Processes the query string and performs it.
-       fun do_query(str: String) do
-               if str == ":q" then
-                       exit 0
-               else if str == ":h" then
-                       help
-                       return
-               end
-               var query = parser.parse(str)
-               if query == null then
-                       query = new CommentCommand(str)
-                       query.arg = str
-               end
-               var res = query.perform(self, doc)
-               var suggest = null
-               if res.is_empty then
-                       suggest = query.suggest(self, doc)
-               end
-               var page = query.make_results(self, res, suggest)
-               print page.write_to_string
-       end
-end
-
-redef class DocCommand
-
-       # Looks up the `doc` model and returns possible matches.
-       fun perform(nitx: Nitx, doc: DocModel): Array[NitxMatch] is abstract
-
-       # Looks up the `doc` model and returns possible suggestions.
-       fun suggest(nitx: Nitx, doc: DocModel): nullable Array[MEntity] do
-               return find_suggestions(doc, arg)
-       end
-
-       # Pretty prints the results for the console.
-       fun make_results(nitx: Nitx, results: Array[NitxMatch], suggest: nullable Array[MEntity]): DocPage do
-               var page = new DocPage("results", "Results")
-               page.root.add_child(new QueryResultArticle("results", "Results", self, results, suggest))
-               return page
-       end
-
-       # Lookup mentities based on a `query` string.
-       #
-       # 1- lookup by first name (returns always one value)
-       # 2- lookup by name (can return conflicts)
-       fun find_mentities(doc: DocModel, query: String): Array[MEntityMatch] do
-               var res = new Array[MEntityMatch]
-
-               # First lookup by full_name
-               var mentity = doc.mentity_by_full_name(query)
-               if mentity != null then
-                       res.add new MEntityMatch(self, mentity)
-                       return res
-               end
-
-               # If no results, lookup by name
-               for m in doc.mentities_by_name(query) do
-                       res.add new MEntityMatch(self, m)
-               end
-
-               return res
-       end
-
-       # Suggest some mentities based on a `query` string.
-       fun find_suggestions(doc: DocModel, query: String): Array[MEntity] do
-               return doc.find(query, 3)
-       end
-end
-
-# Something that matches a `DocCommand`.
-abstract class NitxMatch
-
-       # Query matched by `self`.
-       var query: DocCommand
-
-       # Pretty prints `self` for console.
-       fun make_list_item: String is abstract
-end
-
-# A match between a `DocCommand` and a `MEntity`.
-class MEntityMatch
-       super NitxMatch
-
-       # MEntity matched.
-       var mentity: MEntity
-
-       redef fun make_list_item do return mentity.cs_list_item
-end
-
-redef class CommentCommand
-       redef fun perform(nitx, doc) do return find_mentities(doc, arg)
-
-       redef fun make_results(nitx, results, suggest) do
-               var len = results.length
-               if len == 1 then
-                       var res = results.first.as(MEntityMatch)
-                       var mentity = res.mentity
-                       var page = new DocPage("resultats", "Results")
-                       var article = new DefinitionArticle("results", "Results", mentity)
-                       article.cs_title = mentity.name
-                       article.cs_subtitle = mentity.cs_declaration
-                       page.root.add_child article
-                       return page
-               else
-                       return super
-               end
-       end
-end
-
-# A query to search signatures using a specific `MType` as parameter.
-redef class ParamCommand
-       redef fun perform(nitx, doc) do
-               var res = new Array[NitxMatch]
-               var mtype_name = arg
-               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.
-redef class ReturnCommand
-       redef fun perform(nitx, doc) do
-               var res = new Array[NitxMatch]
-               var mtype_name = arg
-               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`.
-redef class NewCommand
-       redef fun perform(nitx, doc) do
-               var res = new Array[NitxMatch]
-               var mtype_name = arg
-               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`.
-redef class CallCommand
-       redef fun perform(nitx, doc) do
-               var res = new Array[NitxMatch]
-               var mprop_name = arg
-               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 match between a `DocPage` and a `MEntity`.
-class PageMatch
-       super NitxMatch
-
-       # `DocPage` matched.
-       var page: DocPage
-
-       redef fun make_list_item do
-               var page = self.page
-               if page isa MEntityPage then
-                       return page.mentity.cs_list_item
-               end
-               return " * {page.title}"
-       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 DocCommand
-
-       redef fun make_results(nitx, results, suggest) 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.
-redef class CodeCommand
-       # FIXME refactor this!
-       redef fun perform(nitx, doc) do
-               var res = new Array[NitxMatch]
-               var name = arg
-               # 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 match in find_mentities(doc, name) do
-                       if match.mentity isa MClass then continue
-                       if match.mentity isa MProperty then continue
-                       res.add new CodeMatch(self, match.mentity.cs_location, match.mentity.cs_source_code)
-               end
-               return res
-       end
-
-       redef fun make_results(nitx, results, suggest) do
-               var page = new DocPage("results", "Code Results")
-               for res in results do
-                       page.add new CodeQueryArticle("results", "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
-
-## exploration
-
-# 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
-
-# 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.as(not null).mproperty
-       end
-end
-
-# display
-
-# A `DocArticle` that displays query results.
-private class QueryResultArticle
-       super DocArticle
-
-       # Query linked to the results to display.
-       var query: DocCommand
-
-       # Results to display.
-       var results: Array[NitxMatch]
-
-       # Optional suggestion when no matches where found
-       var suggest: nullable Array[MEntity] = null is optional
-
-       redef fun render_title do
-               var len = results.length
-               if len == 0 then
-                       addn "No result found for '{query.string}'..."
-                       var suggest = self.suggest
-                       if suggest != null and suggest.not_empty then
-                               add "\nDid you mean "
-                               var i = 0
-                               for s in suggest do
-                                       add "`{s.full_name}`"
-                                       if i == suggest.length - 2 then add ", "
-                                       if i == suggest.length - 1 then add " or "
-                                       i += 1
-                               end
-                               add "?"
-                       end
-               else
-                       add "# {len} result(s) for '{query.string}'".green.bold
-               end
-       end
-
-       redef fun render_body do
-               addn ""
-               for result in results do
-                       addn ""
-                       addn result.make_list_item
-               end
-       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: DocCommand
-
-       # 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
-
-       # Content to display.
-       var content = new FlatBuffer
-
-       # Adds text to the pager.
-       fun add(text: String) do
-               content.append(escape(text))
-       end
-
-       fun render do sys.system("echo \"{content}\" | less -r")
-
-       fun escape(str: String): String
-       do
-               var b = new FlatBuffer
-               for c in str.chars do
-                       if c == '\n' then
-                               b.append("\\n")
-                       else if c == '\0' then
-                               b.append("\\0")
-                       else if c == '"' then
-                               b.append("\\\"")
-                       else if c == '\\' then
-                               b.append("\\\\")
-                       else if c == '`' then
-                               b.append("'")
-                       else if c.code_point < 32 then
-                               b.append("\\{c.code_point.to_base(8)}")
-                       else
-                               b.add(c)
-                       end
-               end
-               return b.to_s
-       end
-end
diff --git a/src/doc/templates/templates_term.nit b/src/doc/templates/templates_term.nit
new file mode 100644 (file)
index 0000000..b4fc2fe
--- /dev/null
@@ -0,0 +1,311 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Markdown templates for Nit model MEntities.
+#
+# This module introduces Markdown rendering services in model entities.
+# With the `no_color` option set to `false`, the output can be highlighted for console.
+module templates_term
+
+import model_collect
+import console
+
+redef class MDoc
+       # Returns the full comment formatted for the console
+       fun cs_comment(no_color: nullable Bool, indent: nullable Int): String do
+               var res = new FlatBuffer
+               indent = indent or else 0
+               for line in content do
+                       res.append "{" " * indent}{line}\n"
+               end
+               if no_color == null or not no_color then
+                       return res.write_to_string.green
+               end
+               return res.write_to_string
+       end
+
+       # Returns the synopsys formatted for the console
+       fun cs_short_comment(no_color: nullable Bool): String do
+               if no_color == null or not no_color then
+                       return content.first.green
+               end
+               return content.first
+       end
+end
+
+redef class MEntity
+
+       # Text icon to be displayed in front of the entity
+       fun cs_icon(no_color: nullable Bool): String do
+               return public_visibility.cs_icon(no_color)
+       end
+
+       # Source code location of this MEntity formatted for console
+       fun cs_location(no_color: nullable Bool): String do
+               if no_color == null or not no_color then
+                       return location.to_s.bold.gray
+               end
+               return location.to_s
+       end
+
+       # Returns `self.full_name` formatted for console
+       fun cs_full_name(no_color: nullable Bool): String do
+               if no_color == null or not no_color then
+                       return full_name.bold.blue
+               end
+               return full_name
+       end
+
+       # Returns `self` signature formatted for console.
+       fun cs_signature(no_color: nullable Bool): String do return ""
+
+       # Returns the comment of this MEntity formatted for console.
+       fun cs_comment(no_color: nullable Bool): nullable String do
+               var mdoc = mdoc_or_fallback
+               if mdoc == null then return null
+               # FIXME add markdown for console
+               return mdoc.cs_comment(no_color)
+       end
+
+       # Returns the comment of this MEntity formatted for console.
+       fun cs_short_comment(no_color: nullable Bool): nullable String do
+               var mdoc = mdoc_or_fallback
+               if mdoc == null then return null
+               return mdoc.cs_short_comment(no_color)
+       end
+
+       # Returns the complete MEntity declaration (modifiers + name + signature).
+       #
+       # * MPackage: `package foo`
+       # * MGroup: `group foo`
+       # * MModule: `module foo`
+       # * MClass: `private abstract class Foo[E: Object]`
+       # * MClassDef: `redef class Foo[E]`
+       # * MProperty: `private fun foo(e: Object): Int`
+       # * MPropdef: `redef fun foo(e)`
+       fun cs_declaration(no_color: nullable Bool): String do
+               var tpl = new FlatBuffer
+               tpl.append collect_modifiers.join(" ")
+               tpl.append " "
+               tpl.append name
+               tpl.append cs_signature(no_color)
+               if no_color == null or not no_color then
+                       return tpl.write_to_string.bold
+               end
+               return tpl.write_to_string
+       end
+
+       # Returns `self` as a list element that can be displayed in console.
+       #
+       # Displays `cs_icon`, `cs_name`, `cs_short_comment, `cs_namespace`,
+       # `cs_declaration` and `cs_location`.
+       fun cs_list_item(no_color: nullable Bool): String do
+               var tpl = new FlatBuffer
+               tpl.append " "
+               tpl.append cs_icon(no_color)
+               tpl.append " "
+               tpl.append cs_full_name(no_color)
+               var comment = cs_short_comment(no_color)
+               if comment != null then
+                       tpl.append "\n   "
+                       if no_color == null or not no_color then
+                               tpl.append "# ".green
+                       else
+                               tpl.append "# "
+                       end
+                       tpl.append comment
+               end
+               tpl.append "\n   "
+               tpl.append cs_declaration(no_color)
+               tpl.append "\n   "
+               tpl.append cs_location(no_color)
+               return tpl.write_to_string
+       end
+
+       # Source code associated to this MEntity.
+       #
+       # Uses `cs_location` to locate the source code.
+       fun cs_source_code: String do
+               var tpl = new Buffer
+               tpl.append "\n~~~\n"
+               tpl.append location.text
+               tpl.append "\n~~~\n"
+               return tpl.write_to_string
+       end
+end
+
+redef class MClass
+       redef fun cs_icon(no_color) do return intro.cs_icon(no_color)
+       redef fun cs_signature(no_color) do return intro.cs_signature(no_color)
+end
+
+redef class MClassDef
+       redef fun cs_icon(no_color) do
+               if is_intro then return visibility.cs_icon(no_color)
+               return visibility.cs_visibility_color("*")
+       end
+
+       # Returns the MClassDef generic signature with static bounds.
+       redef fun cs_signature(no_color) do
+               var tpl = new FlatBuffer
+               var mparameters = mclass.mparameters
+               if not mparameters.is_empty then
+                       tpl.append "["
+                       for i in [0..mparameters.length[ do
+                               tpl.append "{mparameters[i].name}: "
+                               tpl.append bound_mtype.arguments[i].cs_signature(no_color)
+                               if i < mparameters.length - 1 then tpl.append ", "
+                       end
+                       tpl.append "]"
+               end
+               return tpl.write_to_string
+       end
+end
+
+redef class MProperty
+       redef fun cs_icon(no_color) do return intro.cs_icon(no_color)
+       redef fun cs_signature(no_color) do return intro.cs_signature(no_color)
+end
+
+redef class MPropDef
+       redef fun cs_icon(no_color) do
+               if is_intro then return visibility.cs_icon(no_color)
+               return visibility.cs_visibility_color("*", no_color)
+       end
+end
+
+redef class MAttributeDef
+       redef fun cs_signature(no_color) do
+               var tpl = new FlatBuffer
+               var static_mtype = self.static_mtype
+               if static_mtype != null then
+                       tpl.append ": "
+                       tpl.append static_mtype.cs_signature(no_color)
+               end
+               return tpl.write_to_string
+       end
+end
+
+redef class MMethodDef
+       redef fun cs_signature(no_color) do
+               if mproperty.is_root_init then
+                       return new_msignature.as(not null).cs_signature(no_color)
+               end
+               return msignature.as(not null).cs_signature(no_color)
+       end
+end
+
+redef class MVirtualTypeDef
+       redef fun cs_signature(no_color) do
+               var tpl = new FlatBuffer
+               var bound = self.bound
+               if bound == null then return tpl.write_to_string
+               tpl.append ": "
+               tpl.append bound.cs_signature(no_color)
+               return tpl.write_to_string
+       end
+end
+
+redef class MClassType
+       redef fun cs_signature(no_color) do return name
+end
+
+redef class MNullableType
+       redef fun cs_signature(no_color) do
+               var tpl = new FlatBuffer
+               tpl.append "nullable "
+               tpl.append mtype.cs_signature(no_color)
+               return tpl.write_to_string
+       end
+end
+
+redef class MGenericType
+       redef fun cs_signature(no_color) do
+               var tpl = new FlatBuffer
+               tpl.append mclass.name
+               tpl.append "["
+               for i in [0..arguments.length[ do
+                       tpl.append arguments[i].cs_signature(no_color)
+                       if i < arguments.length - 1 then tpl.append ", "
+               end
+               tpl.append "]"
+               return tpl.write_to_string
+       end
+end
+
+redef class MParameterType
+       redef fun cs_signature(no_color) do return name
+end
+
+redef class MVirtualType
+       redef fun cs_signature(no_color) do return name
+end
+
+redef class MSignature
+       redef fun cs_signature(no_color) do
+               var tpl = new FlatBuffer
+               if not mparameters.is_empty then
+                       tpl.append "("
+                       for i in [0..mparameters.length[ do
+                               tpl.append mparameters[i].cs_signature(no_color)
+                               if i < mparameters.length - 1 then tpl.append ", "
+                       end
+                       tpl.append ")"
+               end
+               var return_mtype = self.return_mtype
+               if return_mtype != null then
+                       tpl.append ": "
+                       tpl.append return_mtype.cs_signature(no_color)
+               end
+               return tpl.write_to_string
+       end
+end
+
+redef class MParameter
+       redef fun cs_signature(no_color) do
+               var tpl = new FlatBuffer
+               tpl.append "{name}: "
+               tpl.append mtype.cs_signature(no_color)
+               if is_vararg then tpl.append "..."
+               return tpl.write_to_string
+       end
+end
+
+redef class MVisibility
+       # Visibility icon
+       fun cs_icon(no_color: nullable Bool): String do
+               var icon
+               if self == private_visibility then
+                       icon = cs_visibility_color("-", no_color)
+               else if self == protected_visibility then
+                       icon = cs_visibility_color("#", no_color)
+               else
+                       icon = cs_visibility_color("+", no_color)
+               end
+               if no_color != null and no_color then return icon
+               return icon.bold
+       end
+
+       # Colorize `string` depending on the visibility
+       fun cs_visibility_color(string: String, no_color: nullable Bool): String do
+               if no_color != null and no_color then return string
+               if self == private_visibility then
+                       return string.red
+               else if self == protected_visibility then
+                       return string.yellow
+               else
+                       return string.green
+               end
+       end
+end
diff --git a/src/doc/term/term.nit b/src/doc/term/term.nit
new file mode 100644 (file)
index 0000000..61d5206
--- /dev/null
@@ -0,0 +1,349 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+module term
+
+import commands::commands_parser
+import templates::templates_term
+
+redef class CommandParser
+
+       fun execute(query: String, no_color: nullable Bool) do
+               var cmd = self.parse(query)
+               var error = self.error
+
+               # If not a command, try a comment query
+               if cmd == null and error isa CmdParserError then
+                       error = null
+                       cmd = new CmdComment(view, mentity_name = query)
+                       var opts = new HashMap[String, String]
+                       var status = cmd.parser_init(query, opts)
+                       if not status isa CmdSuccess then error = status
+               end
+
+               if error isa CmdError or error isa CmdWarning then
+                       error.print_message(no_color)
+                       print ""
+               end
+               cmd.as(not null).execute(no_color)
+       end
+end
+
+redef class DocCommand
+       fun execute(no_color: nullable Bool) is abstract
+end
+
+redef class CmdMessage
+       fun print_message(no_color: nullable Bool) do print to_s
+end
+
+redef class CmdError
+       redef fun print_message(no_color) do
+               var res = "Error: {to_s}"
+               if no_color == null or not no_color then res = res.bold.red
+               print res
+       end
+end
+
+redef class CmdWarning
+       redef fun print_message(no_color) do
+               var res = "Warning: {to_s}"
+               if no_color == null or not no_color then res = res.bold.yellow
+               print res
+       end
+end
+
+# Model queries
+
+redef class ErrorMEntityNotFound
+       redef fun print_message(no_color) do
+               if no_color == null or not no_color then
+                       print "No result found for `{mentity_name.blue}`...".bold
+               else
+                       print "No result found for `{mentity_name}`..."
+               end
+               print ""
+               if suggestions.not_empty then
+                       print "Did you mean?"
+                       print ""
+                       for s in suggestions do
+                               print s.cs_list_item(no_color)
+                               print ""
+                       end
+               end
+       end
+end
+
+redef class ErrorMEntityConflict
+       redef fun print_message(no_color) do
+               if no_color == null or not no_color then
+                       print "Multiple results found for `{mentity_name.blue}`...".bold
+               else
+                       print "Multiple results found for `{mentity_name}`..."
+               end
+               print ""
+               if conflicts.not_empty then
+                       print "Did you mean?"
+                       print ""
+                       for s in conflicts do
+                               print s.cs_list_item(no_color)
+                               print ""
+                       end
+               end
+       end
+end
+
+redef class CmdList
+       fun print_list(list_title: nullable String, list_items: nullable Array[MEntity], no_color: nullable Bool) do
+               if list_title != null then
+                       if no_color == null or not no_color then
+                               print list_title.bold
+                       else
+                               print list_title
+                       end
+                       print ""
+               end
+               if list_items != null and list_items.not_empty then
+                       for mentity in list_items do
+                               print mentity.cs_list_item(no_color)
+                               print ""
+                       end
+               else
+                       print "None."
+               end
+       end
+end
+
+redef class CmdComment
+       redef fun execute(no_color) do
+               var mentity = self.mentity
+               if mentity == null then return
+
+               var full_name = mentity.cs_full_name(no_color)
+               if no_color == null or not no_color then
+                       print "Documentation for `{full_name}`:".bold
+               else
+                       print "Documentation for `{full_name}`:"
+               end
+               print ""
+               print " {mentity.cs_icon(no_color)} {mentity.cs_full_name(no_color)}"
+               print "   {mentity.cs_declaration(no_color)}"
+               print "   {mentity.cs_location(no_color)}"
+               print ""
+               var mdoc = self.mdoc
+               if mdoc == null then return
+               if full_doc then
+                       print mdoc.cs_comment(no_color, 3)
+               else
+                       print "   {mdoc.cs_short_comment(no_color)}\n"
+               end
+       end
+end
+
+redef class CmdAncestors
+       redef fun execute(no_color) do
+               var full_name = mentity.as(not null).cs_full_name(no_color)
+               print_list("Ancestors for `{full_name}`:", results, no_color)
+       end
+end
+
+redef class CmdParents
+       redef fun execute(no_color) do
+               var full_name = mentity.as(not null).cs_full_name(no_color)
+               print_list("Parents for `{full_name}`:", results, no_color)
+       end
+end
+
+redef class CmdChildren
+       redef fun execute(no_color) do
+               var full_name = mentity.as(not null).cs_full_name(no_color)
+               print_list("Children for `{full_name}`:", results, no_color)
+       end
+end
+
+redef class CmdDescendants
+       redef fun execute(no_color) do
+               var full_name = mentity.as(not null).cs_full_name(no_color)
+               print_list("Descendants for `{full_name}`:", results, no_color)
+       end
+end
+
+redef class CmdLinearization
+       redef fun execute(no_color) do
+               var full_name = mentity.as(not null).cs_full_name(no_color)
+               print_list("Linearization for `{full_name}`:", results, no_color)
+       end
+end
+
+redef class CmdSearch
+       redef fun execute(no_color) do
+               print_list("Search results for `{query.as(not null)}`:", results, no_color)
+       end
+end
+
+redef class CmdModelEntities
+       redef fun execute(no_color) do
+               var kind = self.kind
+               if no_color != null and not no_color then kind = kind.blue
+               print_list("MEntities for kind `{kind}`:", results, no_color)
+       end
+end
+
+redef class CmdFeatures
+       redef fun execute(no_color) do
+               var full_name = mentity.as(not null).cs_full_name(no_color)
+               print_list("Features for `{full_name}`:", results, no_color)
+       end
+end
+
+redef class CmdCode
+
+       redef var format = "ansi" is optional
+
+       redef fun execute(no_color) do
+               var mentity = self.mentity
+               if mentity == null then return
+
+               var title = "Code for `{mentity.cs_full_name(no_color)}`:"
+               if no_color == null or not no_color then
+                       print title.bold
+               else
+                       print title
+               end
+               if no_color == null or not no_color then
+                       var ansi = render
+                       if ansi != null then
+                               print "~~~"
+                               print ansi.write_to_string
+                               print "~~~"
+                       end
+               else
+                       printn mentity.cs_source_code
+               end
+       end
+end
+
+redef class CmdGraph
+       redef fun execute(no_color) do
+               format = "dot"
+               var dot = self.render
+               if dot == null then return
+               var f = new ProcessWriter("dot", "-Txlib")
+               f.write dot.write_to_string
+               f.close
+               f.wait
+       end
+end
+
+# CmdUsage
+
+redef class CmdCall
+       redef fun execute(no_color) do
+               var full_name = mentity.as(not null).cs_full_name(no_color)
+               print_list("Methods calling `{full_name}`:", results, no_color)
+       end
+end
+
+redef class CmdNew
+       redef fun execute(no_color) do
+               var full_name = mentity.as(not null).cs_full_name(no_color)
+               print_list("Methods intializing `{full_name}`:", results, no_color)
+       end
+end
+
+redef class CmdReturn
+       redef fun execute(no_color) do
+               var full_name = mentity.as(not null).cs_full_name(no_color)
+               print_list("Methods returning `{full_name}`:", results, no_color)
+       end
+end
+
+redef class CmdParam
+       redef fun execute(no_color) do
+               var full_name = mentity.as(not null).cs_full_name(no_color)
+               print_list("Methods accepting `{full_name}` as parameter:", results, no_color)
+       end
+end
+
+# CmdCatalog
+
+redef class CmdCatalogPackages
+       redef fun execute(no_color) do
+               print_list("Packages from catalog:", results, no_color)
+       end
+end
+
+redef class CmdCatalogStats
+       redef fun execute(no_color) do
+               if no_color == null or not no_color then
+                       print "Catalog statistics:".bold
+               else
+                       print "Catalog statistics:"
+               end
+
+               var stats = self.stats.as(not null)
+               print " * {stats.packages} packages"
+               print " * {stats.modules} modules"
+               print " * {stats.methods} methods"
+               print " * {stats.classes} classes"
+               print " * {stats.loc} lines of code"
+               print " * {stats.contributors} contributors"
+               print " * {stats.maintainers} maintainers"
+               print " * {stats.tags} tags"
+       end
+end
+
+redef class CmdCatalogTags
+       redef fun execute(no_color) do
+               if no_color == null or not no_color then
+                       print "Tags from catalog:".bold
+               else
+                       print "Tags from catalog:"
+               end
+
+               print ""
+               var counts = self.packages_count_by_tags.as(not null)
+               for tag, count in counts do
+                       if no_color == null or not no_color then
+                               print " * {tag.blue.bold}: {count} packages"
+                       else
+                               print " * {tag}: {count} packages"
+                       end
+               end
+       end
+end
+
+redef class CmdCatalogTag
+       redef fun execute(no_color) do
+               var tag = self.tag.as(not null)
+               if no_color == null or not no_color then tag = tag.blue.bold
+               print_list("Packages tagged with `{tag}`:", results, no_color)
+       end
+end
+
+redef class CmdCatalogMaintaining
+       redef fun execute(no_color) do
+               var name = self.person_name.as(not null)
+               if no_color == null or not no_color then name = name.blue.bold
+               print_list("Packages maintained by `{name}`:", results, no_color)
+       end
+end
+
+redef class CmdCatalogContributing
+       redef fun execute(no_color) do
+               var name = self.person_name.as(not null)
+               if no_color == null or not no_color then name = name.blue.bold
+               print_list("Packages contributed by `{name}`:", results, no_color)
+       end
+end
diff --git a/src/doc/term/tests/test_term.nit b/src/doc/term/tests/test_term.nit
new file mode 100644 (file)
index 0000000..08530da
--- /dev/null
@@ -0,0 +1,202 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+module test_term is test
+
+import term
+import commands::test_commands_catalog
+
+# Nitunit test suite specific to commands
+class TestTerm
+       super TestCommandsCatalog
+       test
+
+       # CmdEntity
+
+       fun test_mentity_full_name is test do
+               var parser = new CommandParser(test_view, test_builder)
+               parser.execute("test_prog::Character", true)
+       end
+
+       fun test_mentity_name is test do
+               var parser = new CommandParser(test_view, test_builder)
+               parser.execute("Character", true)
+       end
+
+       fun test_mentity_empty is test do
+               var parser = new CommandParser(test_view, test_builder)
+               parser.execute("", true)
+       end
+
+       fun test_mentity_not_found is test do
+               var parser = new CommandParser(test_view, test_builder)
+               parser.execute("Caracter", true)
+       end
+
+       fun test_mentity_conflict is test do
+               var parser = new CommandParser(test_view, test_builder)
+               parser.execute("+", true)
+       end
+
+       # CmdDoc
+
+       fun test_comment is test do
+               var parser = new CommandParser(test_view, test_builder)
+               parser.execute("doc: Character", true)
+       end
+
+       fun test_comment_short is test do
+               var parser = new CommandParser(test_view, test_builder)
+               parser.execute("doc: Character | only-synopsis", true)
+       end
+
+       fun test_comment_no_fallback is test do
+               var parser = new CommandParser(test_view, test_builder)
+               parser.execute("doc: Character | no-fallback", true)
+       end
+
+       # CmdInheritance
+
+       fun test_ancestors is test do
+               var parser = new CommandParser(test_view, test_builder)
+               parser.execute("ancestors: Warrior | parents: true", true)
+       end
+
+       fun test_ancestors_without_parents is test do
+               var parser = new CommandParser(test_view, test_builder)
+               parser.execute("ancestors: Warrior | parents: false", true)
+       end
+
+       fun test_parents is test do
+               var parser = new CommandParser(test_view, test_builder)
+               parser.execute("parents: Warrior", true)
+       end
+
+       fun test_children is test do
+               var parser = new CommandParser(test_view, test_builder)
+               parser.execute("children: Career", true)
+       end
+
+       fun test_descendants is test do
+               var parser = new CommandParser(test_view, test_builder)
+               parser.execute("descendants: Career", true)
+       end
+
+       fun test_descendants_without_children is test do
+               var parser = new CommandParser(test_view, test_builder)
+               parser.execute("descendants: Career | children: false", true)
+       end
+
+       # CmdLin
+
+       fun test_lin is test do
+               var parser = new CommandParser(test_view, test_builder)
+               parser.execute("lin: init | limit: 2", true)
+       end
+
+       fun test_lin_no_lin is test do
+               var parser = new CommandParser(test_view, test_builder)
+               parser.execute("lin: test_prog", true)
+       end
+
+       # CmdSearch
+
+       fun test_search is test do
+               var parser = new CommandParser(test_view, test_builder)
+               parser.execute("search: Caracter | limit: 2", true)
+       end
+
+       fun test_search_no_query is test do
+               var parser = new CommandParser(test_view, test_builder)
+               parser.execute("search: | limit: 1", true)
+       end
+
+       # CmdDefs
+
+       fun test_features is test do
+               var parser = new CommandParser(test_view, test_builder)
+               parser.execute("defs: Character | limit: 3", true)
+       end
+
+       # CmdCode
+
+       fun test_code is test do
+               var parser = new CommandParser(test_view, test_builder)
+               parser.execute("code: Character", true)
+       end
+
+       # CmdUsage
+
+       fun test_init is test do
+               var parser = new CommandParser(test_view, test_builder)
+               parser.execute("new: Elf | limit: 2", true)
+       end
+
+       fun test_call is test do
+               var parser = new CommandParser(test_view, test_builder)
+               parser.execute("call: endurance_bonus", true)
+       end
+
+       fun test_return is test do
+               var parser = new CommandParser(test_view, test_builder)
+               parser.execute("return: Int | limit: 3", true)
+       end
+
+       fun test_param is test do
+               var parser = new CommandParser(test_view, test_builder)
+               parser.execute("param: Career | limit: 3", true)
+       end
+
+       # CmdCatalog
+
+       fun test_term_catalog is test do
+               var parser = new CommandParser(test_view, test_builder, test_catalog)
+               parser.execute("catalog:", true)
+       end
+
+       fun test_term_catalog_search is test do
+               var parser = new CommandParser(test_view, test_builder, test_catalog)
+               parser.execute("search: Caracter | limit: 3", true)
+       end
+
+       fun test_term_catalog_stats is test do
+               var parser = new CommandParser(test_view, test_builder, test_catalog)
+               parser.execute("stats:", true)
+       end
+
+       fun test_term_catalog_tags is test do
+               var parser = new CommandParser(test_view, test_builder, test_catalog)
+               parser.execute("tags:", true)
+       end
+
+       fun test_term_catalog_tag is test do
+               var parser = new CommandParser(test_view, test_builder, test_catalog)
+               parser.execute("tag: game", true)
+       end
+
+       fun test_term_catalog_maintain is test do
+               var parser = new CommandParser(test_view, test_builder, test_catalog)
+               parser.execute("maintain: Alexandre Terrasa", true)
+       end
+
+       fun test_term_catalog_contrib is test do
+               var parser = new CommandParser(test_view, test_builder, test_catalog)
+               parser.execute("contrib: Alexandre Terrasa", true)
+       end
+end
+
+redef class nitc::Location
+       # Avoid location diffs
+       redef fun to_s do return "test_location"
+end
diff --git a/src/doc/term/tests/test_term.sav/test_ancestors.res b/src/doc/term/tests/test_term.sav/test_ancestors.res
new file mode 100644 (file)
index 0000000..eeefbdf
--- /dev/null
@@ -0,0 +1,12 @@
+Ancestors for `test_prog::Warrior`:
+
+ + test_prog::Career
+   # A `Career` gives a characteristic bonus or malus to the character.
+   abstract class Career
+   test_location
+
+ + test_prog::Object
+   # Root of everything.
+   interface Object
+   test_location
+
diff --git a/src/doc/term/tests/test_term.sav/test_ancestors_without_parents.res b/src/doc/term/tests/test_term.sav/test_ancestors_without_parents.res
new file mode 100644 (file)
index 0000000..548c77c
--- /dev/null
@@ -0,0 +1,7 @@
+Ancestors for `test_prog::Warrior`:
+
+ + test_prog::Object
+   # Root of everything.
+   interface Object
+   test_location
+
diff --git a/src/doc/term/tests/test_term.sav/test_call.res b/src/doc/term/tests/test_term.sav/test_call.res
new file mode 100644 (file)
index 0000000..ac3c732
--- /dev/null
@@ -0,0 +1,11 @@
+Methods calling `test_prog::Career::endurance_bonus`:
+
+ * test_prog$Character$Object::init
+   redef init init(race: Race, name: String, age: Int, sex: Bool)
+   test_location
+
+ + test_prog$Character$total_endurance
+   # The actual endurance of the character.
+   fun total_endurance: Int
+   test_location
+
diff --git a/src/doc/term/tests/test_term.sav/test_children.res b/src/doc/term/tests/test_term.sav/test_children.res
new file mode 100644 (file)
index 0000000..7c3a626
--- /dev/null
@@ -0,0 +1,17 @@
+Children for `test_prog::Career`:
+
+ + test_prog::Alcoholic
+   # Alcoholics are good to nothing escept taking punches.
+   class Alcoholic
+   test_location
+
+ + test_prog::Magician
+   # Magicians know magic and how to use it.
+   class Magician
+   test_location
+
+ + test_prog::Warrior
+   # Warriors are good for fighting.
+   class Warrior
+   test_location
+
diff --git a/src/doc/term/tests/test_term.sav/test_code.res b/src/doc/term/tests/test_term.sav/test_code.res
new file mode 100644 (file)
index 0000000..0ce0299
--- /dev/null
@@ -0,0 +1,52 @@
+Code for `test_prog::Character`:
+
+~~~
+# Characters can be played by both the human or the machine.
+class Character
+
+       # The `Race` of the character.
+       var race: Race
+
+       # The current `Career` of the character.
+       # Returns `null` if character is unemployed.
+       var career: nullable Career = null is writable
+
+       fun quit do
+               career = null
+       end
+
+       var name: String
+       var age: Int
+       var sex: Bool
+
+       # The actual strength of the character.
+       #
+       # Returns `race.base_strength + career.strength_bonus` or just `race.base_strength` is unemployed.
+       fun total_strengh: Int do
+               if career != null then return race.base_strength + career.strength_bonus
+               return race.base_strength
+       end
+
+       # The actual endurance of the character.
+       fun total_endurance: Int do
+               if career != null then return race.base_endurance + career.endurance_bonus
+               return race.base_endurance
+       end
+
+       # The acutal intelligence of the character.
+       fun total_intelligence: Int do
+               if career != null then return race.base_intelligence + career.intelligence_bonus
+               return race.base_intelligence
+       end
+
+       # Maximum health of the character.
+       #
+       # Based on `total endurance * 10`.
+       fun max_health: Int do return total_endurance * 10
+
+       # The current `health` of the character.
+       #
+       # Starts at `max_health`.
+       var health: Int = max_health
+end
+~~~
diff --git a/src/doc/term/tests/test_term.sav/test_comment.res b/src/doc/term/tests/test_term.sav/test_comment.res
new file mode 100644 (file)
index 0000000..7dd578d
--- /dev/null
@@ -0,0 +1,8 @@
+Documentation for `test_prog::Character`:
+
+ + test_prog::Character
+   class Character
+   test_location
+
+   Characters can be played by both the human or the machine.
+
diff --git a/src/doc/term/tests/test_term.sav/test_comment_no_fallback.res b/src/doc/term/tests/test_term.sav/test_comment_no_fallback.res
new file mode 100644 (file)
index 0000000..54c0e88
--- /dev/null
@@ -0,0 +1,8 @@
+Warning: No documentation for `test_prog::Character`.
+
+Documentation for `test_prog::Character`:
+
+ + test_prog::Character
+   class Character
+   test_location
+
diff --git a/src/doc/term/tests/test_term.sav/test_comment_short.res b/src/doc/term/tests/test_term.sav/test_comment_short.res
new file mode 100644 (file)
index 0000000..7dd578d
--- /dev/null
@@ -0,0 +1,8 @@
+Documentation for `test_prog::Character`:
+
+ + test_prog::Character
+   class Character
+   test_location
+
+   Characters can be played by both the human or the machine.
+
diff --git a/src/doc/term/tests/test_term.sav/test_descendants.res b/src/doc/term/tests/test_term.sav/test_descendants.res
new file mode 100644 (file)
index 0000000..288bb38
--- /dev/null
@@ -0,0 +1,17 @@
+Descendants for `test_prog::Career`:
+
+ + test_prog::Alcoholic
+   # Alcoholics are good to nothing escept taking punches.
+   class Alcoholic
+   test_location
+
+ + test_prog::Magician
+   # Magicians know magic and how to use it.
+   class Magician
+   test_location
+
+ + test_prog::Warrior
+   # Warriors are good for fighting.
+   class Warrior
+   test_location
+
diff --git a/src/doc/term/tests/test_term.sav/test_descendants_without_children.res b/src/doc/term/tests/test_term.sav/test_descendants_without_children.res
new file mode 100644 (file)
index 0000000..04c1fd9
--- /dev/null
@@ -0,0 +1,3 @@
+Descendants for `test_prog::Career`:
+
+None.
diff --git a/src/doc/term/tests/test_term.sav/test_features.res b/src/doc/term/tests/test_term.sav/test_features.res
new file mode 100644 (file)
index 0000000..1a12c90
--- /dev/null
@@ -0,0 +1,16 @@
+Features for `test_prog::Character`:
+
+ - test_prog::character::Character::_age
+   private var _age: Int
+   test_location
+
+ - test_prog::character::Character::_career
+   # The current `Career` of the character.
+   private var _career: nullable Career
+   test_location
+
+ - test_prog::character::Character::_health
+   # The current `health` of the character.
+   private var _health: Int
+   test_location
+
diff --git a/src/doc/term/tests/test_term.sav/test_init.res b/src/doc/term/tests/test_term.sav/test_init.res
new file mode 100644 (file)
index 0000000..45ed0a3
--- /dev/null
@@ -0,0 +1,3 @@
+Methods intializing `test_prog::Elf`:
+
+None.
diff --git a/src/doc/term/tests/test_term.sav/test_lin.res b/src/doc/term/tests/test_term.sav/test_lin.res
new file mode 100644 (file)
index 0000000..23e94dc
--- /dev/null
@@ -0,0 +1,10 @@
+Linearization for `test_prog::Object::init`:
+
+ + test_prog$Object$init
+   init init
+   test_location
+
+ * test_prog$Race$Object::init
+   redef init init(base_strength: Int, base_endurance: Int, base_intelligence: Int)
+   test_location
+
diff --git a/src/doc/term/tests/test_term.sav/test_lin_no_lin.res b/src/doc/term/tests/test_term.sav/test_lin_no_lin.res
new file mode 100644 (file)
index 0000000..6543a17
--- /dev/null
@@ -0,0 +1,5 @@
+Warning: No linearization for `test_prog`
+
+Linearization for `test_prog`:
+
+None.
diff --git a/src/doc/term/tests/test_term.sav/test_mentity_conflict.res b/src/doc/term/tests/test_term.sav/test_mentity_conflict.res
new file mode 100644 (file)
index 0000000..b66c27f
--- /dev/null
@@ -0,0 +1,13 @@
+Multiple results found for `+`...
+
+Did you mean?
+
+ + test_prog::Int::+
+   intern fun +(i: Int): Int
+   test_location
+
+ + test_prog::Float::+
+   intern fun +(f: Float): Float
+   test_location
+
+
diff --git a/src/doc/term/tests/test_term.sav/test_mentity_empty.res b/src/doc/term/tests/test_term.sav/test_mentity_empty.res
new file mode 100644 (file)
index 0000000..eed622c
--- /dev/null
@@ -0,0 +1,17 @@
+No result found for ``...
+
+Did you mean?
+
+ + test_prog::Int::*
+   intern fun *(i: Int): Int
+   test_location
+
+ + test_prog::Float::*
+   intern fun *(f: Float): Float
+   test_location
+
+ + test_prog::Float::+
+   intern fun +(f: Float): Float
+   test_location
+
+
diff --git a/src/doc/term/tests/test_term.sav/test_mentity_full_name.res b/src/doc/term/tests/test_term.sav/test_mentity_full_name.res
new file mode 100644 (file)
index 0000000..7dd578d
--- /dev/null
@@ -0,0 +1,8 @@
+Documentation for `test_prog::Character`:
+
+ + test_prog::Character
+   class Character
+   test_location
+
+   Characters can be played by both the human or the machine.
+
diff --git a/src/doc/term/tests/test_term.sav/test_mentity_name.res b/src/doc/term/tests/test_term.sav/test_mentity_name.res
new file mode 100644 (file)
index 0000000..7dd578d
--- /dev/null
@@ -0,0 +1,8 @@
+Documentation for `test_prog::Character`:
+
+ + test_prog::Character
+   class Character
+   test_location
+
+   Characters can be played by both the human or the machine.
+
diff --git a/src/doc/term/tests/test_term.sav/test_mentity_not_found.res b/src/doc/term/tests/test_term.sav/test_mentity_not_found.res
new file mode 100644 (file)
index 0000000..ff87303
--- /dev/null
@@ -0,0 +1,20 @@
+No result found for `Caracter`...
+
+Did you mean?
+
+ + test_prog::Character
+   # Characters can be played by both the human or the machine.
+   class Character
+   test_location
+
+ + test_prog::character
+   # Characters are playable entity in the world.
+   module character
+   test_location
+
+ + test_prog::Career
+   # A `Career` gives a characteristic bonus or malus to the character.
+   abstract class Career
+   test_location
+
+
diff --git a/src/doc/term/tests/test_term.sav/test_param.res b/src/doc/term/tests/test_term.sav/test_param.res
new file mode 100644 (file)
index 0000000..5f65e7f
--- /dev/null
@@ -0,0 +1,7 @@
+Methods accepting `test_prog::Career` as parameter:
+
+ + test_prog::Character::career=
+   # The current `Career` of the character.
+   fun career=(career: nullable Career)
+   test_location
+
diff --git a/src/doc/term/tests/test_term.sav/test_parents.res b/src/doc/term/tests/test_term.sav/test_parents.res
new file mode 100644 (file)
index 0000000..814f320
--- /dev/null
@@ -0,0 +1,7 @@
+Parents for `test_prog::Warrior`:
+
+ + test_prog::Career
+   # A `Career` gives a characteristic bonus or malus to the character.
+   abstract class Career
+   test_location
+
diff --git a/src/doc/term/tests/test_term.sav/test_return.res b/src/doc/term/tests/test_term.sav/test_return.res
new file mode 100644 (file)
index 0000000..ce6c68f
--- /dev/null
@@ -0,0 +1,14 @@
+Methods returning `test_prog::Int`:
+
+ + test_prog::Int::*
+   intern fun *(i: Int): Int
+   test_location
+
+ + test_prog::Int::+
+   intern fun +(i: Int): Int
+   test_location
+
+ + test_prog::Int::-
+   intern fun -(i: Int): Int
+   test_location
+
diff --git a/src/doc/term/tests/test_term.sav/test_search.res b/src/doc/term/tests/test_term.sav/test_search.res
new file mode 100644 (file)
index 0000000..965f6dc
--- /dev/null
@@ -0,0 +1,12 @@
+Search results for `Caracter`:
+
+ + test_prog::Character
+   # Characters can be played by both the human or the machine.
+   class Character
+   test_location
+
+ + test_prog::character
+   # Characters are playable entity in the world.
+   module character
+   test_location
+
diff --git a/src/doc/term/tests/test_term.sav/test_search_no_query.res b/src/doc/term/tests/test_term.sav/test_search_no_query.res
new file mode 100644 (file)
index 0000000..591c48b
--- /dev/null
@@ -0,0 +1,6 @@
+Search results for ``:
+
+ + test_prog::Int::*
+   intern fun *(i: Int): Int
+   test_location
+
diff --git a/src/doc/term/tests/test_term.sav/test_term_catalog.res b/src/doc/term/tests/test_term.sav/test_term_catalog.res
new file mode 100644 (file)
index 0000000..79ba492
--- /dev/null
@@ -0,0 +1,11 @@
+Packages from catalog:
+
+ + test_prog
+   # Test program for model tools.
+   package test_prog
+   test_location
+
+ + excluded
+   package excluded
+   test_location
+
diff --git a/src/doc/term/tests/test_term.sav/test_term_catalog_contrib.res b/src/doc/term/tests/test_term.sav/test_term_catalog_contrib.res
new file mode 100644 (file)
index 0000000..60ce480
--- /dev/null
@@ -0,0 +1,7 @@
+Packages contributed by `Alexandre Terrasa`:
+
+ + test_prog
+   # Test program for model tools.
+   package test_prog
+   test_location
+
diff --git a/src/doc/term/tests/test_term.sav/test_term_catalog_maintain.res b/src/doc/term/tests/test_term.sav/test_term_catalog_maintain.res
new file mode 100644 (file)
index 0000000..4dfedb2
--- /dev/null
@@ -0,0 +1,11 @@
+Packages maintained by `Alexandre Terrasa`:
+
+ + test_prog
+   # Test program for model tools.
+   package test_prog
+   test_location
+
+ + excluded
+   package excluded
+   test_location
+
diff --git a/src/doc/term/tests/test_term.sav/test_term_catalog_search.res b/src/doc/term/tests/test_term.sav/test_term_catalog_search.res
new file mode 100644 (file)
index 0000000..ae5fe51
--- /dev/null
@@ -0,0 +1,17 @@
+Search results for `Caracter`:
+
+ + test_prog::Character
+   # Characters can be played by both the human or the machine.
+   class Character
+   test_location
+
+ + test_prog::character
+   # Characters are playable entity in the world.
+   module character
+   test_location
+
+ + test_prog::Career
+   # A `Career` gives a characteristic bonus or malus to the character.
+   abstract class Career
+   test_location
+
diff --git a/src/doc/term/tests/test_term.sav/test_term_catalog_stats.res b/src/doc/term/tests/test_term.sav/test_term_catalog_stats.res
new file mode 100644 (file)
index 0000000..fd8b8ba
--- /dev/null
@@ -0,0 +1,9 @@
+Catalog statistics:
+ * 2 packages
+ * 10 modules
+ * 75 methods
+ * 23 classes
+ * 471 lines of code
+ * 6 contributors
+ * 1 maintainers
+ * 2 tags
diff --git a/src/doc/term/tests/test_term.sav/test_term_catalog_tag.res b/src/doc/term/tests/test_term.sav/test_term_catalog_tag.res
new file mode 100644 (file)
index 0000000..143fd74
--- /dev/null
@@ -0,0 +1,7 @@
+Packages tagged with `game`:
+
+ + test_prog
+   # Test program for model tools.
+   package test_prog
+   test_location
+
diff --git a/src/doc/term/tests/test_term.sav/test_term_catalog_tags.res b/src/doc/term/tests/test_term.sav/test_term_catalog_tags.res
new file mode 100644 (file)
index 0000000..ced4b52
--- /dev/null
@@ -0,0 +1,4 @@
+Tags from catalog:
+
+ * game: 1 packages
+ * test: 1 packages
index ff97784..061b44e 100644 (file)
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-# `nitx`, is a command tool that displays useful informations about the code.
+# `nitx`, a command tool that displays useful data about Nit code
 #
 # Features:
 #
-# * Display comment from name/namespace
-# * Display documentation page from Nitdoc in console
+# * Display documentation from name/namespace
 # * Find type usage in parameters, returns and news.
-# * Find usage of a specific property.
+# * Find usage (calls) of a specific property.
 # * Find source code related to class/property by its name.
+# * Display inheritance lists
 module nitx
 
-import modelbuilder
-import doc::doc_phases::doc_console
+import frontend
+import doc::term
+import readline
 
 redef class ToolContext
 
-       # Nittx generation phase.
-       var docx: Phase = new NitxPhase(self, null)
-
        # Used to shortcut the prompt and display directly the result in console.
        var opt_command = new OptionString("Nitx command to perform", "-c", "--command")
 
-       init do option_context.add_option opt_command
+       # Compute and use the catalog
+       var opt_catalog = new OptionBool("Use catalog", "--catalog")
+
+       init do option_context.add_option(opt_command, opt_catalog)
 end
 
-# Nitx phase explores the model and prepares the console rendering.
-private class NitxPhase
-       super Phase
-       redef fun process_mainmodule(mainmodule, mmodules)
-       do
-               var doc = new DocModel(mainmodule.model, mainmodule)
-
-               var phases = [
-                       new MakePagePhase(toolcontext, doc),
-                       new ConcernsPhase(toolcontext, doc),
-                       new StructurePhase(toolcontext, doc),
-                       new POSetPhase(toolcontext, doc): DocPhase]
-
-               for phase in phases do
-                       toolcontext.info("# {phase.class_name}", 1)
-                       phase.apply
+# Nitx handles console queries
+#
+# Using `prompt`, the command line can be turned on an interactive tool.
+class Nitx
+
+       # ModelView that contains the informations to display
+       var view: ModelView
+
+       # ModelBuilder to access AST nodes
+       var modelbuilder: ModelBuilder
+
+       # Catalog if any
+       var catalog: nullable Catalog = null is optional
+
+       # Do not use colors in the output
+       var no_color = false is optional
+
+       # Displays the welcome message and start prompt.
+       fun start do
+               welcome
+               prompt
+       end
+
+       # Displays the welcome message and the list of loaded modules.
+       fun welcome do
+               print "Welcome in the Nit Index!"
+               print ""
+               print "Loaded packages:\n"
+               var cmd = new CmdModelEntities(view, kind = "packages")
+               cmd.init_command
+               for mpackage in cmd.results.as(not null) do
+                       print " * {mpackage.full_name}"
+               end
+               help
+       end
+
+       # Displays the list of available queries.
+       fun help do
+               # TODO automatize that
+               print "\nCommands:\n"
+               for usage, doc in parser.commands_usage do
+                       var l = usage.length / 8
+                       print "\t{usage}{"\t" * (3 - l)}{doc}"
+               end
+               print "\n"
+               print "\t:h\t\t\tdisplay this help message"
+               print "\t:q\t\t\tquit interactive mode"
+               print ""
+       end
+
+       # Prompts the user for a query.
+       fun prompt do
+               var line = readline(">> ", true)
+               if line != null then
+                       do_command(line)
                end
+               prompt
+       end
+
+       # Parser used to process doc commands
+       var parser = new CommandParser(view, modelbuilder, catalog) is lazy
 
-               # start nitx
-               var nitx = new Nitx(toolcontext, doc)
-               var q = toolcontext.opt_command.value
-               if q != null then # shortcut prompt
-                       print ""
-                       nitx.do_query(q)
+       # Processes the query string and performs it.
+       fun do_command(str: String) do
+               if str == ":q" then
+                       exit 0
+               else if str == ":h" then
+                       help
                        return
                end
-               nitx.start
+               parser.execute(str, no_color)
+       end
+end
+
+redef class Catalog
+       # Build the catalog for Nitx
+       private fun build_catalog(view: ModelView) do
+               # Compute the poset
+               for p in view.mpackages do
+                       var g = p.root
+                       assert g != null
+                       modelbuilder.scan_group(g)
+
+                       deps.add_node(p)
+                       for gg in p.mgroups do for m in gg.mmodules do
+                               for im in m.in_importation.direct_greaters do
+                                       var ip = im.mpackage
+                                       if ip == null or ip == p then continue
+                                       deps.add_edge(p, ip)
+                               end
+                       end
+               end
+               # Build the catalog
+               for mpackage in view.mpackages do
+                       package_page(mpackage)
+                       git_info(mpackage)
+                       mpackage_stats(mpackage)
+               end
        end
 end
 
@@ -71,7 +143,7 @@ end
 var toolcontext = new ToolContext
 var tpl = new Template
 tpl.add "Usage: nitx [OPTION]... <file.nit>... [query]\n"
-tpl.add "Displays specific pieces of API information from Nit source files."
+tpl.add "Displays pieces of API information from Nit source files."
 toolcontext.tooldescription = tpl.write_to_string
 
 # process options
@@ -87,3 +159,22 @@ var mmodules = mbuilder.parse_full(arguments)
 if mmodules.is_empty then return
 mbuilder.run_phases
 toolcontext.run_global_phases(mmodules)
+var mainmodule = toolcontext.make_main_module(mmodules)
+
+# build views
+var view = new ModelView(model, mainmodule)
+var catalog = null
+if toolcontext.opt_catalog.value then
+       catalog = new Catalog(mbuilder)
+       catalog.build_catalog(view)
+end
+
+# start nitx
+var nitx = new Nitx(view, mbuilder, catalog, toolcontext.opt_no_color.value)
+var q = toolcontext.opt_command.value
+if q != null then # shortcut prompt
+       print ""
+       nitx.do_command(q)
+       return
+end
+nitx.start
index 79da3ab..3bc599d 100644 (file)
@@ -1,3 +1,3 @@
-base_simple3.nit -c A
-base_simple3.nit -c foo
-base_simple3.nit -c base_simple3
+base_simple3.nit -c A --no-color
+base_simple3.nit -c foo --no-color
+base_simple3.nit -c "defs: base_simple3::base_simple3" --no-color
index ec462a0..4a0ef7e 100644 (file)
@@ -1,3 +1,3 @@
 Usage: nitx [OPTION]... <file.nit>... [query]
-Displays specific pieces of API information from Nit source files.
+Displays pieces of API information from Nit source files.
 Use --help for help
index d9ab058..040663e 100644 (file)
@@ -1,9 +1,9 @@
 
-\e[1m\e[34m# \e[m\e[m\e[1m\e[34mA\e[m\e[m
-\e[1m\e[30mclass A\e[m\e[m
-
-    \e[1m\e[32mclass A\e[m\e[m
-    \e[1m\e[30mbase_simple3.nit:29,1--32,3\e[m\e[m
+Warning: No documentation for `base_simple3::A`.
 
+Documentation for `base_simple3::A`:
 
+ + base_simple3::A
+   class A
+   base_simple3.nit:29,1--32,3
 
index 3f6b1f1..48c2f5f 100644 (file)
@@ -1,9 +1,9 @@
 
-\e[1m\e[34m# \e[m\e[m\e[1m\e[34mfoo\e[m\e[m
-\e[1m\e[30mfun foo\e[m\e[m
-
-    \e[1m\e[32mfun foo\e[m\e[m
-    \e[1m\e[30mbase_simple3.nit:49,1--19\e[m\e[m
+Warning: No documentation for `base_simple3::Sys::foo`.
 
+Documentation for `base_simple3::Sys::foo`:
 
+ + base_simple3::Sys::foo
+   fun foo
+   base_simple3.nit:49,1--19
 
index 9d71d91..e191640 100644 (file)
@@ -1,9 +1,31 @@
 
-\e[1m\e[34m# \e[m\e[m\e[1m\e[34mbase_simple3\e[m\e[m
-\e[1m\e[30mpackage base_simple3\e[m\e[m
+Features for `base_simple3::base_simple3`:
 
-    \e[1m\e[32mpackage base_simple3\e[m\e[m
-    \e[1m\e[30mbase_simple3.nit:17,1--66,13\e[m\e[m
+ + base_simple3$A
+   class A
+   base_simple3.nit:29,1--32,3
 
+ + base_simple3$B
+   class B
+   base_simple3.nit:34,1--42,3
 
+ + base_simple3$Bool
+   enum Bool
+   base_simple3.nit:22,1--23,3
+
+ + base_simple3$C
+   class C
+   base_simple3.nit:44,1--47,3
+
+ + base_simple3$Int
+   enum Int
+   base_simple3.nit:25,1--27,3
+
+ + base_simple3$Object
+   interface Object
+   base_simple3.nit:19,1--20,3
+
+ + base_simple3$Sys
+   class Sys
+   base_simple3.nit:49,1--19