Merge branch 'doc_on_collection'
authorJean Privat <jean@pryen.org>
Thu, 20 Mar 2014 21:54:55 +0000 (17:54 -0400)
committerJean Privat <jean@pryen.org>
Thu, 20 Mar 2014 21:54:55 +0000 (17:54 -0400)
26 files changed:
Makefile
lib/html.nit
lib/standard/kernel.nit
src/Makefile
src/markdown.nit
src/model/mdoc.nit [new file with mode: 0644]
src/model/mmodule.nit
src/model/model.nit
src/model/model_base.nit
src/model/mproject.nit
src/modelbuilder.nit
src/modelize_class.nit
src/modelize_property.nit
src/nitdoc.nit
src/nitls.nit [new file with mode: 0644]
src/nitunit.nit
src/nitx.nit
src/test_markdown.nit
tests/nitls.args [new file with mode: 0644]
tests/sav/error_mod_unk.res
tests/sav/nitls.res [new file with mode: 0644]
tests/sav/nitls_args1.res [new file with mode: 0644]
tests/sav/nitls_args2.res [new file with mode: 0644]
tests/sav/nitunit_args1.res
tests/sav/test_markdown_args1.res
tests/testfull.sh

index d3eb558..4f03abf 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -27,11 +27,14 @@ tools:
 bin/nitdoc:
        cd src; make ../bin/nitdoc
 
-doc/stdlib/index.html: bin/nitdoc
+bin/nitls:
+       cd src; make ../bin/nitls
+
+doc/stdlib/index.html: bin/nitdoc bin/nitls
        @echo '***************************************************************'
        @echo '* Generate doc for NIT standard library                       *'
        @echo '***************************************************************'
-       bin/nitdoc lib/*.nit $$(find lib/*/*.nit -maxdepth 0 -type f ) -d doc/stdlib \
+       bin/nitdoc $$(bin/nitls lib -r) -d doc/stdlib \
                --custom-title "Nit Standard Library" \
                --custom-menu-items "<li><a href=\"http://nitlanguage.org/\">Nitlanguage.org</a></li>" \
                --custom-overview-text "<p>Documentation for the standard library of Nit<br/>Version $$(git describe)<br/>Date: $$(git show --format="%cd" | head -1)</p>" \
@@ -44,7 +47,7 @@ doc/stdlib/index.html: bin/nitdoc
                --piwik-site-id "2"
 
 doc/nitc/index.html: bin/nitdoc
-       bin/nitdoc src/nit.nit src/nitmetrics.nit src/nitg.nit src/nitx.nit src/nitunit.nit src/nitlight.nit src/dbgcli.nit src/netdbg.nit -d doc/nitc \
+       bin/nitdoc src/nit*.nit src/dbgcli.nit src/netdbg.nit -d doc/nitc \
                --private \
                --custom-title "Nit Compilers and Tools" \
                --custom-menu-items "<li><a href=\"http://nitlanguage.org/\">Nitlanguage.org</a></li>" \
index 729f529..515a871 100644 (file)
@@ -95,6 +95,9 @@ class HTMLTag
        end
 
        # Is the HTML element a void element?
+       #
+       #     assert new HTMLTag("img").is_void    == true
+       #     assert new HTMLTag("p").is_void      == false
        var is_void: Bool
 
        init with_attrs(tag: String, attrs: Map[String, String]) do
@@ -106,37 +109,48 @@ class HTMLTag
        var attrs: Map[String, String] = new HashMap[String, String]
 
        # Get the attributed value of 'prop' or null if 'prop' is undifened
+       #     var img = new HTMLTag("img")
+       #     img.attr("src", "./image.png").attr("alt", "image")
+       #     assert img.get_attr("src")     == "./image.png"
        fun get_attr(key: String): nullable String do
                if not attrs.has_key(key) then return null
                return attrs[key]
        end
 
        # Set a 'value' for 'key'
-       # var img = new HTMLTag("img")
-       # img.attr("src", "./image.png").attr("alt", "image")
+       #     var img = new HTMLTag("img")
+       #     img.attr("src", "./image.png").attr("alt", "image")
+       #     assert img.write_to_string      == """<img src="./image.png" alt="image"/>"""
        fun attr(key: String, value: String): HTMLTag do
                attrs[key] = value
                return self
        end
 
        # Add a CSS class to the HTML tag
-       # var img = new HTMLTag("img")
-       # img.add_class("logo").add_class("fullpage")
+       #     var img = new HTMLTag("img")
+       #     img.add_class("logo").add_class("fullpage")
+       #     assert img.write_to_string      == """<img class="logo fullpage"/>"""
        fun add_class(klass: String): HTMLTag do
                classes.add(klass)
                return self
        end
+
+       # CSS classes
        var classes: Set[String] = new HashSet[String]
 
        # Add multiple CSS classes
+       #     var img = new HTMLTag("img")
+       #     img.add_classes(["logo", "fullpage"])
+       #     assert img.write_to_string      == """<img class="logo fullpage"/>"""
        fun add_classes(classes: Collection[String]): HTMLTag do
                self.classes.add_all(classes)
                return self
        end
 
        # Set a CSS 'value' for 'prop'
-       # var img = new HTMLTag("img")
-       # img.css("border", "2px solid black").css("position", "absolute")
+       #     var img = new HTMLTag("img")
+       #     img.css("border", "2px solid black").css("position", "absolute")
+       #     assert img.write_to_string      == """<img style="border: 2px solid black; position: absolute"/>"""
        fun css(prop: String, value: String): HTMLTag do
                css_props[prop] = value
                return self
@@ -144,14 +158,19 @@ class HTMLTag
        private var css_props: Map[String, String] = new HashMap[String, String]
 
        # Get CSS value for 'prop'
+       #     var img = new HTMLTag("img")
+       #     img.css("border", "2px solid black").css("position", "absolute")
+       #     assert img.get_css("border")    == "2px solid black"
+       #     assert img.get_css("color")     == null
        fun get_css(prop: String): nullable String do
                if not css_props.has_key(prop) then return null
                return css_props[prop]
        end
 
        # Add a HTML 'child' to self
-       # var ul = new HTMLTag("ul")
-       # ul.add(new HTMLTag("li"))
+       #     var ul = new HTMLTag("ul")
+       #     ul.add(new HTMLTag("li"))
+       #     assert ul.write_to_string    == "<ul><li></li></ul>"
        fun add(child: HTMLTag) do children.add(child)
 
        # List of children HTML elements
@@ -235,7 +254,7 @@ class HTMLTag
 
                if attrs.has_key("style") or not css_props.is_empty then
                        res.add " style=\""
-                       for k, v in attrs do
+                       for k, v in css_props do
                                res.add k.html_escape
                                res.add ": "
                                res.add v.html_escape
index d47cf58..19da7f8 100644 (file)
@@ -209,7 +209,10 @@ universal Bool
        redef fun ==(b) is intern
        redef fun !=(b) is intern
        redef fun output is intern
-       redef fun hash
+       redef fun hash do return to_i
+
+       # 1 if true and 0 if false
+       fun to_i: Int
        do
                if self then
                        return 1
index e24d047..c46614c 100644 (file)
@@ -16,7 +16,7 @@
 
 NITCOPT=
 
-all: ../bin/nitdoc ../bin/nitmetrics ../bin/nitg ../bin/nit ../bin/nitx ../bin/nitunit ../bin/nitlight
+all: ../bin/nitdoc ../bin/nitmetrics ../bin/nitg ../bin/nit ../bin/nitx ../bin/nitunit ../bin/nitlight ../bin/nitls
 
 ../bin/nitg: ../c_src/nitg parser/parser.nit
        @echo '***************************************************************'
@@ -67,6 +67,13 @@ all: ../bin/nitdoc ../bin/nitmetrics ../bin/nitg ../bin/nit ../bin/nitx ../bin/n
        ./git-gen-version.sh
        ../bin/nitg ${NITCOPT} -o ../bin/nitlight -v nitlight.nit
 
+../bin/nitls : ../bin/nitg
+       @echo '***************************************************************'
+       @echo '* Compile nitls from NIT source files                         *'
+       @echo '***************************************************************'
+       ./git-gen-version.sh
+       ../bin/nitg ${NITCOPT} -o ../bin/nitls -v nitls.nit
+
 ../c_src/nitg: ../c_src/*.c ../c_src/*.h ../c_src/Makefile
        @echo '***************************************************************'
        @echo '* Compile nitg from C source files                            *'
index d4b7a81..344f469 100644 (file)
@@ -26,7 +26,7 @@ private class Doc2Mdwn
        # The lines of the current code block, empty is no current code block
        var curblock = new Array[String]
 
-       fun work(ndoc: ADoc): HTMLTag
+       fun work(mdoc: MDoc): HTMLTag
        do
                var root = new HTMLTag("div")
                root.add_class("nitdoc")
@@ -43,20 +43,19 @@ private class Doc2Mdwn
                # The current ul element (if any)
                var ul: nullable HTMLTag = null
 
+               var is_first_line = true
                # Local variable to benefit adaptive typing
-               for c in ndoc.n_comment do
-                       # Remove the starting `#`
-                       var text = c.text.substring_from(1)
-
+               for text in mdoc.content do
                        # Count the number of spaces
                        lastindent = indent
                        indent = 0
                        while text.length > indent and text.chars[indent] == ' ' do indent += 1
 
                        # Is codeblock? Then just collect them
-                       if indent > 4 then
+                       if indent >= 4 then
                                var part = text.substring_from(4)
                                curblock.add(part)
+                               curblock.add("\n")
                                continue
                        end
 
@@ -115,9 +114,10 @@ private class Doc2Mdwn
                        process_line(n, text)
 
                        # Special case, the fist line is the synopsys and is in its own paragraph
-                       if c == ndoc.n_comment.first then
+                       if is_first_line then
                                n.add_class("synopsys")
                                n = null
+                               is_first_line = false
                        end
                end
 
@@ -127,9 +127,9 @@ private class Doc2Mdwn
                return root
        end
 
-       fun short_work(ndoc: ADoc): HTMLTag
+       fun short_work(mdoc: MDoc): HTMLTag
        do
-                       var text = ndoc.n_comment.first.text.substring_from(1)
+                       var text = mdoc.content.first
                        var n = new HTMLTag("span")
                        n.add_class("synopsys")
                        n.add_class("nitdoc")
@@ -188,20 +188,32 @@ private class Doc2Mdwn
        end
 end
 
-redef class ADoc
+redef class MDoc
        # Build a `<div>` element that contains the full documentation in HTML
        fun full_markdown: HTMLTag
        do
+               var res = full_markdown_cache
+               if res != null then return res
                var tc = new ToolContext
                var d2m = new Doc2Mdwn(tc)
-               return d2m.work(self)
+               res = d2m.work(self)
+               full_markdown_cache = res
+               return res
        end
 
+       private var full_markdown_cache: nullable HTMLTag
+
        # Build a `<span>` element that contains the synopsys in HTML
        fun short_markdown: HTMLTag
        do
+               var res = short_markdown_cache
+               if res != null then return res
                var tc = new ToolContext
                var d2m = new Doc2Mdwn(tc)
-               return d2m.short_work(self)
+               res = d2m.short_work(self)
+               short_markdown_cache = res
+               return res
        end
+
+       private var short_markdown_cache: nullable HTMLTag
 end
diff --git a/src/model/mdoc.nit b/src/model/mdoc.nit
new file mode 100644 (file)
index 0000000..919b48c
--- /dev/null
@@ -0,0 +1,31 @@
+# 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.
+
+# Documentation of model entities
+module mdoc
+
+import model_base
+
+# Structured documentation of a `MEntity` object
+class MDoc
+       # Raw content, line by line
+       # The starting `#` and first space are stripped.
+       # The trailing `\n` are chomped.
+       var content = new Array[String]
+end
+
+redef class MEntity
+       # The documentation assiciated to the entity
+       var mdoc: nullable MDoc writable
+end
index d2750ed..60a7c92 100644 (file)
@@ -69,6 +69,8 @@ end
 
 # A Nit module is usually associated with a Nit source file.
 class MModule
+       super MEntity
+
        # The model considered
        var model: Model
 
index ad1c325..79fee97 100644 (file)
@@ -32,6 +32,7 @@ module model
 import poset
 import location
 import mmodule
+import mdoc
 private import more_collections
 
 redef class Model
@@ -287,6 +288,8 @@ end
 # belong to a hierarchy since the property and the
 # hierarchy of a class depends of a module.
 class MClass
+       super MEntity
+
        # The module that introduce the class
        # While classes are not bound to a specific module,
        # the introducing module is used for naming an visibility
@@ -412,6 +415,8 @@ end
 # class. Unlike `MClass`, a `MClassDef` is a local definition that belong to
 # a specific module
 class MClassDef
+       super MEntity
+
        # The module where the definition is
        var mmodule: MModule
 
@@ -542,6 +547,7 @@ end
 #  * foo(anchor, mmodule, othertype)
 #  * foo(othertype, mmodule, anchor)
 abstract class MType
+       super MEntity
 
        # The model of the type
        fun model: Model is abstract
@@ -1482,6 +1488,8 @@ end
 # of any dynamic type).
 # For instance, a call site "x.foo" is associated to a `MProperty`.
 abstract class MProperty
+       super MEntity
+
        # The associated MPropDef subclass.
        # The two specialization hierarchy are symmetric.
        type MPROPDEF: MPropDef
@@ -1745,6 +1753,7 @@ end
 # Unlike `MProperty`, a `MPropDef` is a local definition that belong to a
 # specific class definition (which belong to a specific module)
 abstract class MPropDef
+       super MEntity
 
        # The associated `MProperty` subclass.
        # the two specialization hierarchy are symmetric
index dda72bb..409b66b 100644 (file)
@@ -22,6 +22,11 @@ module model_base
 class Model
 end
 
+# A named and possibly documented entity in the model.
+# This class is usefull to generalize presentation of entities to the human.
+abstract class MEntity
+end
+
 # A visibility (for modules, class and properties)
 # Valid visibility are:
 #
index 9c1765f..cad2e39 100644 (file)
@@ -21,6 +21,8 @@ import poset
 
 # A Nit project, thas encompass a product
 class MProject
+       super MEntity
+
        # The name of the project
        var name: String
 
@@ -46,6 +48,8 @@ end
 
 # A group of modules in a project
 class MGroup
+       super MEntity
+
        # The name of the group
        # empty name for a default group in a single-module project
        var name: String
index a97535e..1daf410 100644 (file)
@@ -252,9 +252,6 @@ class ModelBuilder
        # FIXME: add a way to handle module name conflict
        fun get_mmodule_by_name(anode: ANode, mmodule: nullable MModule, name: String): nullable MModule
        do
-               # what path where tried to display on error message
-               var tries = new Array[String]
-
                # First, look in groups of the module
                if mmodule != null then
                        var mgroup = mmodule.mgroup
@@ -265,7 +262,6 @@ class ModelBuilder
 
                                # Second, try the directory to find a file
                                var try_file = dirname + "/" + name + ".nit"
-                               tries.add try_file
                                if try_file.file_exists then
                                        var res = self.load_module(try_file.simplify_path)
                                        if res == null then return null # Forward error
@@ -301,10 +297,28 @@ class ModelBuilder
                        end
                end
 
+               var candidate = search_module_in_paths(anode.hot_location, name, lookpaths)
+
+               if candidate == null then
+                       if mmodule != null then
+                               error(anode, "Error: cannot find module {name} from {mmodule}. tried {lookpaths.join(", ")}")
+                       else
+                               error(anode, "Error: cannot find module {name}. tried {lookpaths.join(", ")}")
+                       end
+                       return null
+               end
+               var res = self.load_module(candidate)
+               if res == null then return null # Forward error
+               return res.mmodule.as(not null)
+       end
+
+       # Search a module `name` from path `lookpaths`.
+       # If found, the path of the file is returned
+       private fun search_module_in_paths(location: nullable Location, name: String, lookpaths: Collection[String]): nullable String
+       do
                var candidate: nullable String = null
                for dirname in lookpaths do
                        var try_file = (dirname + "/" + name + ".nit").simplify_path
-                       tries.add try_file
                        if try_file.file_exists then
                                if candidate == null then
                                        candidate = try_file
@@ -313,7 +327,7 @@ class ModelBuilder
                                        var abs_candidate = module_absolute_path(candidate)
                                        var abs_try_file = module_absolute_path(try_file)
                                        if abs_candidate != abs_try_file then
-                                               error(anode, "Error: conflicting module file for {name}: {candidate} {try_file}")
+                                               toolcontext.error(location, "Error: conflicting module file for {name}: {candidate} {try_file}")
                                        end
                                end
                        end
@@ -326,22 +340,12 @@ class ModelBuilder
                                        var abs_candidate = module_absolute_path(candidate)
                                        var abs_try_file = module_absolute_path(try_file)
                                        if abs_candidate != abs_try_file then
-                                               error(anode, "Error: conflicting module file for {name}: {candidate} {try_file}")
+                                               toolcontext.error(location, "Error: conflicting module file for {name}: {candidate} {try_file}")
                                        end
                                end
                        end
                end
-               if candidate == null then
-                       if mmodule != null then
-                               error(anode, "Error: cannot find module {name} from {mmodule}. tried {tries.join(", ")}")
-                       else
-                               error(anode, "Error: cannot find module {name}. tried {tries.join(", ")}")
-                       end
-                       return null
-               end
-               var res = self.load_module(candidate)
-               if res == null then return null # Forward error
-               return res.mmodule.as(not null)
+               return candidate
        end
 
        # cache for `identify_file` by realpath
@@ -351,9 +355,25 @@ class ModelBuilder
        # Load the associated project and groups if required
        private fun identify_file(path: String): nullable ModulePath
        do
-               if not path.file_exists then
-                       toolcontext.error(null, "Error: `{path}` does not exists")
-                       return null
+               # special case for not a nit file
+               if path.file_extension != "nit" then
+                       # search in known -I paths
+                       var candidate = search_module_in_paths(null, path, self.paths)
+
+                       # Found nothins? maybe it is a group...
+                       if candidate == null and path.file_exists then
+                               var mgroup = get_mgroup(path)
+                               if mgroup != null then
+                                       var owner_path = mgroup.filepath.join_path(mgroup.name + ".nit")
+                                       if owner_path.file_exists then candidate = owner_path
+                               end
+                       end
+
+                       if candidate == null then
+                               toolcontext.error(null, "Error: cannot find module `{path}`.")
+                               return null
+                       end
+                       path = candidate
                end
 
                # Fast track, the path is already known
@@ -375,6 +395,7 @@ class ModelBuilder
                end
 
                var res = new ModulePath(pn, path, mgroup)
+               mgroup.module_paths.add(res)
 
                identified_files[rp] = res
                return res
@@ -474,7 +495,7 @@ class ModelBuilder
                end
 
                # Load it manually
-               var nmodule = load_module_ast(filename)
+               var nmodule = load_module_ast(file.filepath)
                if nmodule == null then return null # forward error
 
                # build the mmodule and load imported modules
@@ -529,6 +550,11 @@ class ModelBuilder
                nmodules.add(nmodule)
                self.mmodule2nmodule[mmodule] = nmodule
 
+               if decl != null then
+                       var ndoc = decl.n_doc
+                       if ndoc != null then mmodule.mdoc = ndoc.to_mdoc
+               end
+
                return mmodule
        end
 
@@ -627,6 +653,10 @@ private class ModulePath
        redef fun to_s do return filepath
 end
 
+redef class MGroup
+       # modules paths associated with the group
+       private var module_paths = new Array[ModulePath]
+end
 
 redef class AStdImport
        # The imported module once determined
@@ -656,3 +686,30 @@ end
 redef class APrivateVisibility
        redef fun mvisibility do return private_visibility
 end
+
+redef class ADoc
+       private var mdoc_cache: nullable MDoc
+       fun to_mdoc: MDoc
+       do
+               var res = mdoc_cache
+               if res != null then return res
+               res = new MDoc
+               for c in n_comment do
+                       var text = c.text
+                       if text.length < 2 then
+                               res.content.add ""
+                               continue
+                       end
+                       assert text.chars[0] == '#'
+                       if text.chars[1] == ' ' then
+                               text = text.substring_from(2) # eat starting `#` and space
+                       else
+                               text = text.substring_from(1) # eat atarting `#` only
+                       end
+                       if text.chars.last == '\n' then text = text.substring(0, text.length-1) # drop \n
+                       res.content.add(text)
+               end
+               mdoc_cache = res
+               return res
+       end
+end
index e8a207b..34b5c28 100644 (file)
@@ -161,6 +161,11 @@ redef class ModelBuilder
                nclassdef.mclassdef = mclassdef
                self.mclassdef2nclassdef[mclassdef] = nclassdef
 
+               if nclassdef isa AStdClassdef then
+                       var ndoc = nclassdef.n_doc
+                       if ndoc != null then mclassdef.mdoc = ndoc.to_mdoc
+               end
+
                if mclassdef.is_intro then
                        self.toolcontext.info("{mclassdef} introduces new {mclass.kind} {mclass.full_name}", 3)
                else
index 980dfc7..1245af5 100644 (file)
@@ -238,6 +238,12 @@ redef class APropdef
                return mvisibility
        end
 
+       private fun set_doc(mpropdef: MPropDef)
+       do
+               var ndoc = self.n_doc
+               if ndoc != null then mpropdef.mdoc = ndoc.to_mdoc
+       end
+
        private fun check_redef_property_visibility(modelbuilder: ModelBuilder, nclassdef: AClassdef, nvisibility: nullable AVisibility, mprop: MProperty)
        do
                if nvisibility == null then return
@@ -416,6 +422,8 @@ redef class AMethPropdef
 
                mclassdef.propdef_names.add(mpropdef.mproperty.name)
 
+               set_doc(mpropdef)
+
                self.mpropdef = mpropdef
                modelbuilder.mpropdef2npropdef[mpropdef] = self
                if mpropdef.is_intro then
@@ -594,6 +602,7 @@ redef class AAttrPropdef
                        var mpropdef = new MAttributeDef(mclassdef, mprop, self.location)
                        self.mpropdef = mpropdef
                        modelbuilder.mpropdef2npropdef[mpropdef] = self
+                       set_doc(mpropdef)
 
                        var nreadable = self.n_readable
                        if nreadable != null then
@@ -612,6 +621,7 @@ redef class AAttrPropdef
                                var mreadpropdef = new MMethodDef(mclassdef, mreadprop, self.location)
                                self.mreadpropdef = mreadpropdef
                                modelbuilder.mpropdef2npropdef[mreadpropdef] = self
+                               mreadpropdef.mdoc = mpropdef.mdoc
                        end
 
                        var nwritable = self.n_writable
@@ -631,6 +641,7 @@ redef class AAttrPropdef
                                var mwritepropdef = new MMethodDef(mclassdef, mwriteprop, self.location)
                                self.mwritepropdef = mwritepropdef
                                modelbuilder.mpropdef2npropdef[mwritepropdef] = self
+                               mwritepropdef.mdoc = mpropdef.mdoc
                        end
                else
                        # New attribute style
@@ -639,6 +650,7 @@ redef class AAttrPropdef
                        var mpropdef = new MAttributeDef(mclassdef, mprop, self.location)
                        self.mpropdef = mpropdef
                        modelbuilder.mpropdef2npropdef[mpropdef] = self
+                       set_doc(mpropdef)
 
                        var readname = name
                        var mreadprop = modelbuilder.try_get_mproperty_by_name(nid2, mclassdef, readname).as(nullable MMethod)
@@ -655,6 +667,7 @@ redef class AAttrPropdef
                        var mreadpropdef = new MMethodDef(mclassdef, mreadprop, self.location)
                        self.mreadpropdef = mreadpropdef
                        modelbuilder.mpropdef2npropdef[mreadpropdef] = self
+                       mreadpropdef.mdoc = mpropdef.mdoc
 
                        var writename = name + "="
                        var nwritable = self.n_writable
@@ -681,6 +694,7 @@ redef class AAttrPropdef
                        var mwritepropdef = new MMethodDef(mclassdef, mwriteprop, self.location)
                        self.mwritepropdef = mwritepropdef
                        modelbuilder.mpropdef2npropdef[mwritepropdef] = self
+                       mwritepropdef.mdoc = mpropdef.mdoc
                end
        end
 
@@ -869,6 +883,7 @@ redef class ATypePropdef
 
                var mpropdef = new MVirtualTypeDef(mclassdef, mprop, self.location)
                self.mpropdef = mpropdef
+               set_doc(mpropdef)
        end
 
        redef fun build_signature(modelbuilder, nclassdef)
index 4eadd19..344aac6 100644 (file)
@@ -1814,7 +1814,7 @@ redef class AModule
 
        private fun full_markdown: String do
                if n_moduledecl != null and n_moduledecl.n_doc != null then
-                       return n_moduledecl.n_doc.full_markdown.write_to_string
+                       return n_moduledecl.n_doc.to_mdoc.full_markdown.write_to_string
                end
                return ""
        end
@@ -1841,7 +1841,7 @@ redef class AStdClassdef
        end
 
        private fun full_markdown: String do
-               if n_doc != null then return n_doc.full_markdown.write_to_string
+               if n_doc != null then return n_doc.to_mdoc.full_markdown.write_to_string
                return ""
        end
 
@@ -1865,7 +1865,7 @@ redef class APropdef
        end
 
        private fun full_markdown: String do
-               if n_doc != null then return n_doc.full_markdown.write_to_string
+               if n_doc != null then return n_doc.to_mdoc.full_markdown.write_to_string
                return ""
        end
 
diff --git a/src/nitls.nit b/src/nitls.nit
new file mode 100644 (file)
index 0000000..6e266d9
--- /dev/null
@@ -0,0 +1,120 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Copyright 2012 Jean Privat <jean@pryen.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.
+
+# Simple tool to list Nit source files
+module nitls
+
+intrude import modelbuilder
+import ordered_tree
+
+var tc = new ToolContext
+var model = new Model
+var mb = new ModelBuilder(model, tc)
+
+var opt_keep = new OptionBool("Ignore errors and files that are not a Nit source file", "-k", "--keep")
+var opt_recursive = new OptionBool("Process directories recussively", "-r", "--recursive")
+var opt_tree = new OptionBool("List source files in their groups and projects", "-t", "--tree")
+var opt_source = new OptionBool("List source files", "-s", "--source")
+var opt_project = new OptionBool("List projects paths (default)", "-p", "--project")
+var opt_depends = new OptionBool("List dependencies of given modules", "-M", "--depends")
+
+tc.option_context.add_option(opt_keep, opt_recursive, opt_tree, opt_source, opt_project, opt_depends)
+
+tc.process_options
+
+var sum = opt_tree.value.to_i + opt_source.value.to_i + opt_project.value.to_i + opt_depends.value.to_i
+if sum > 1 or tc.option_context.rest.is_empty or tc.opt_help.value then
+       print "Usage: nitls [OPTION].. [FILES]..."
+       print "List Nit source files"
+       tc.option_context.usage
+       exit 0
+end
+
+if opt_depends.value then
+       if opt_recursive.value then
+               print "-M incompatible with -r"
+               exit 1
+       end
+
+       mb.parse(tc.option_context.rest)
+       for x in model.mmodules do
+               print x.location.file.filename
+       end
+end
+
+if sum == 0 then opt_project.value = true
+
+var files
+if opt_recursive.value then
+       files = new Array[String]
+       for d in tc.option_context.rest do
+               var pipe = new IProcess("find", d, "-name", "*.nit")
+               while not pipe.eof do
+                       var l = pipe.read_line
+                       if l == "" then break # last line
+                       l = l.substring(0,l.length-1) # strip last oef
+                       files.add l
+               end
+               pipe.close
+               pipe.wait
+               if pipe.status != 0 and not opt_keep.value then exit 1
+       end
+else
+       files = tc.option_context.rest
+end
+
+for a in files do
+       var mp = mb.identify_file(a)
+       if mp == null then
+               if not opt_keep.value then tc.check_errors
+       end
+end
+
+if opt_tree.value then
+       var ot = new OrderedTree[Object]
+       for p in model.mprojects do
+               for g in p.mgroups do
+                       ot.add(g.parent, g)
+                       for mp in g.module_paths do
+                               ot.add(g, mp)
+                       end
+               end
+       end
+       ot.sort_with(new CachedAlphaComparator)
+       ot.write_to(stdout)
+end
+
+if opt_source.value then
+       var list = new Array[String]
+       for p in model.mprojects do
+               for g in p.mgroups do
+                       for mp in g.module_paths do
+                               list.add(mp.filepath)
+                       end
+               end
+       end
+       alpha_comparator.sort(list)
+       for l in list do print l
+end
+
+if opt_project.value then
+       var list = new Array[String]
+       for p in model.mprojects do
+               list.add(p.root.filepath.as(not null))
+       end
+       alpha_comparator.sort(list)
+       for l in list do print l
+end
index 54e9302..5a96471 100644 (file)
@@ -70,7 +70,7 @@ class NitUnitExecutor
        do
                block.clear
 
-               work(ndoc)
+               work(ndoc.to_mdoc)
 
                if block.is_empty then return
 
index 9db4abd..a57af8b 100644 (file)
@@ -383,22 +383,18 @@ redef class MModule
        end
 
        redef fun preview(index, pager) do
-               if index.mbuilder.mmodule2nmodule.has_key(self) then
-                       var node = index.mbuilder.mmodule2nmodule[self]
-                       if node.n_moduledecl != null and not node.n_moduledecl.n_doc == null and not node.n_moduledecl.n_doc.short_comment.is_empty then
-                               pager.add(node.n_moduledecl.n_doc.short_comment.green)
-                       end
+               var mdoc = self.mdoc
+               if mdoc != null then
+                       pager.add(mdoc.short_comment.green)
                end
                pager.add(prototype)
                pager.add("{namespace}".bold.gray + " (lines {location.lines})".gray)
        end
 
        redef fun content(index, pager) do
-               if index.mbuilder.mmodule2nmodule.has_key(self) then
-                       var node = index.mbuilder.mmodule2nmodule[self]
-                       if node.n_moduledecl != null and not node.n_moduledecl.n_doc == null and not node.n_moduledecl.n_doc.comment.is_empty then
-                               for comment in node.n_moduledecl.n_doc.comment do pager.add(comment.green)
-                       end
+               var mdoc = self.mdoc
+               if mdoc != null then
+                       for comment in mdoc.content do pager.add(comment.green)
                end
                pager.add(prototype)
                pager.add("{namespace}".bold.gray + " (lines {location.lines})".gray)
@@ -498,11 +494,9 @@ redef class MClass
 
        redef fun content(index, pager) do
                # intro comment
-               if index.mbuilder.mclassdef2nclassdef.has_key(intro) then
-                       var node = index.mbuilder.mclassdef2nclassdef[intro]
-                       if node isa AStdClassdef and not node.n_doc == null and not node.n_doc.comment.is_empty then
-                               for comment in node.n_doc.comment do pager.add(comment.green)
-                       end
+               var mdoc = intro.mdoc
+               if mdoc != null then
+                       for comment in mdoc.content do pager.add(comment.green)
                end
                pager.add(intro.to_console)
                pager.add("{intro.namespace}".bold.gray + " (lines {intro.location.lines})".gray)
@@ -583,22 +577,18 @@ redef class MClassDef
        end
 
        redef fun preview(index, pager) do
-               if index.mbuilder.mclassdef2nclassdef.has_key(self) then
-                       var node = index.mbuilder.mclassdef2nclassdef[self]
-                       if node isa AStdClassdef and not node.n_doc == null and not node.n_doc.short_comment.is_empty then
-                               pager.add(node.n_doc.short_comment.green)
-                       end
+               var mdoc = self.mdoc
+               if mdoc != null then
+                       pager.add(mdoc.short_comment.green)
                end
                pager.add(to_console)
                pager.add("{namespace}".bold.gray + " (lines {location.lines})".gray)
        end
 
        redef fun content(index, pager) do
-               if index.mbuilder.mclassdef2nclassdef.has_key(self) then
-                       var node = index.mbuilder.mclassdef2nclassdef[self]
-                       if node isa AStdClassdef and not node.n_doc == null and not node.n_doc.comment.is_empty then
-                               for comment in node.n_doc.comment do pager.add(comment.green)
-                       end
+               var mdoc = self.mdoc
+               if mdoc != null then
+                       for comment in mdoc.content do pager.add(comment.green)
                end
                pager.add(to_console)
                pager.add("{namespace}".bold.gray + " (lines {location.lines})".gray)
@@ -684,22 +674,18 @@ redef class MPropDef
        end
 
        redef fun preview(index, pager) do
-               if index.mbuilder.mpropdef2npropdef.has_key(self) then
-                       var nprop = index.mbuilder.mpropdef2npropdef[self]
-                       if not nprop.n_doc == null and not nprop.n_doc.short_comment.is_empty then
-                               pager.add(nprop.n_doc.short_comment.green)
-                       end
+               var mdoc = self.mdoc
+               if mdoc != null then
+                       pager.add(mdoc.short_comment.green)
                end
                pager.add(to_console)
                pager.add("{namespace}".bold.gray + " (lines {location.lines})".gray)
        end
 
        redef fun content(index, pager) do
-               if index.mbuilder.mpropdef2npropdef.has_key(self) then
-                       var nprop = index.mbuilder.mpropdef2npropdef[self]
-                       if not nprop.n_doc == null and not nprop.n_doc.comment.is_empty then
-                               for comment in nprop.n_doc.comment do pager.add(comment.green)
-                       end
+               var mdoc = self.mdoc
+               if mdoc != null then
+                       for comment in mdoc.content do pager.add(comment.green)
                end
                pager.add(to_console)
                pager.add("{namespace}".bold.gray + " (lines {location.lines})".gray)
@@ -797,17 +783,9 @@ redef class MVirtualType
        redef fun to_console do return mproperty.name
 end
 
-redef class ADoc
-       private fun comment: List[String] do
-               var res = new List[String]
-               for t in n_comment do
-                       res.add(t.text.replace("\n", ""))
-               end
-               return res
-       end
-
+redef class MDoc
        private fun short_comment: String do
-               return n_comment.first.text.replace("\n", "")
+               return content.first
        end
 end
 
index d956656..b89d802 100644 (file)
@@ -24,32 +24,27 @@ redef class ModelBuilder
                page.add_raw_html "<a id='{mmodule.full_name}'></a>"
                page.add_raw_html "<h1>module {mmodule}</h1>"
                if mmodule2nmodule.has_key(mmodule) then
-                       var nmodule = mmodule2nmodule[mmodule]
                        do
-                               var nmoduledecl = nmodule.n_moduledecl
-                               if nmoduledecl == null then break label x
-                               var ndoc = nmoduledecl.n_doc
-                               if ndoc == null then break label x
-                               page.add ndoc.full_markdown
+                               var mdoc = mmodule.mdoc
+                               if mdoc == null then break label x
+                               page.add mdoc.full_markdown
                        end label x
-                       for nclassdef in nmodule.n_classdefs do
-                               var mclassdef = nclassdef.mclassdef.as(not null)
-                               if nclassdef isa AStdClassdef then
-                                       var ndoc = nclassdef.n_doc
-                                       if ndoc != null then
+                       for mclassdef in mmodule.mclassdefs do
+                               do
+                                       var mdoc = mclassdef.mdoc
+                                       if mdoc != null then
                                                if mclassdef.mclass.intro == mclassdef then page.add_raw_html "<a id='{mclassdef.mclass.full_name}'></a>"
                                                page.add_raw_html "<h2>class {mclassdef}</h2>"
-                                               page.add ndoc.full_markdown
+                                               page.add mdoc.full_markdown
                                        end
                                end
-                               for npropdef in nclassdef.n_propdefs do
-                                       var mpropdef = npropdef.mpropdef.as(not null)
-                                       var ndoc = npropdef.n_doc
-                                       if ndoc != null then
+                               for mpropdef in mclassdef.mpropdefs do
+                                       var mdoc = mpropdef.mdoc
+                                       if mdoc != null then
                                                if mpropdef.mproperty.intro == mpropdef then page.add_raw_html "<a id='{mpropdef.mproperty.full_name}'></a>"
 
                                                page.add_raw_html "<h3>prop {mpropdef}</h3>"
-                                               page.add ndoc.full_markdown
+                                               page.add mdoc.full_markdown
                                        end
                                end
                        end
@@ -116,4 +111,4 @@ else
 end
 
 page.add_raw_html "</body>"
-print page.html
+page.write_to(stdout)
diff --git a/tests/nitls.args b/tests/nitls.args
new file mode 100644 (file)
index 0000000..77606fa
--- /dev/null
@@ -0,0 +1,2 @@
+base_simple3.nit
+-t base_simple3.nit
index 6df8be4..6f9cec9 100644 (file)
@@ -1 +1 @@
-error_mod_unk.nit:17,8--11: Error: cannot find module dfgd from error_mod_unk. tried dfgd.nit, ../lib/standard/dfgd.nit, ../lib/standard/collection/dfgd.nit, alt/dfgd.nit, ../lib/dfgd.nit, ../lib/dfgd.nit
+error_mod_unk.nit:17,8--11: Error: cannot find module dfgd from error_mod_unk. tried ., ../lib/standard, ../lib/standard/collection, alt, ../lib, ../lib
diff --git a/tests/sav/nitls.res b/tests/sav/nitls.res
new file mode 100644 (file)
index 0000000..06aa3b2
--- /dev/null
@@ -0,0 +1,20 @@
+Usage: nitls [OPTION].. [FILES]...
+List Nit source files
+  -W, --warn              Show warnings
+  -q, --quiet             Do not show warnings
+  --stop-on-first-error   Stop on first error
+  --no-color              Do not use color to display errors and warnings
+  --log                   Generate various log files
+  --log-dir               Directory where to generate log files
+  -h, -?, --help          Show Help (This screen)
+  --version               Show version and exit
+  -v, --verbose           Verbose
+  -I, --path              Set include path for loaders (may be used more than once)
+  --only-parse            Only proceed to parse step of loaders
+  --only-metamodel        Stop after meta-model processing
+  -k, --keep              Ignore errors and files that are not a Nit source file
+  -r, --recursive         Process directories recussively
+  -t, --tree              List source files in their groups and projects
+  -s, --source            List source files
+  -p, --project           List projects paths (default)
+  -M, --depends           List dependencies of given modules
diff --git a/tests/sav/nitls_args1.res b/tests/sav/nitls_args1.res
new file mode 100644 (file)
index 0000000..5f3aa2c
--- /dev/null
@@ -0,0 +1 @@
+base_simple3.nit
diff --git a/tests/sav/nitls_args2.res b/tests/sav/nitls_args2.res
new file mode 100644 (file)
index 0000000..18465e3
--- /dev/null
@@ -0,0 +1,2 @@
+base_simple3
+`--base_simple3.nit
index b37f396..b7686bd 100644 (file)
@@ -1,10 +1,10 @@
 test_nitunit.nit:20,1--22,0: ERROR: test_nitunit.test_nitunit::X.<class> (in .nitunit/test_nitunit2.nit): Runtime error: Assert failed (.nitunit/test_nitunit2.nit:5)
 
-test_nitunit.nit:23,2--25,0: FAILURE: test_nitunit.test_nitunit::X.test_nitunit::X::toto (in .nitunit/test_nitunit3.nit): .nitunit/test_nitunit3.nit:5,9--28: Error: Method or variable 'undefined_identifier' unknown in Sys.
+test_nitunit.nit:23,2--25,0: FAILURE: test_nitunit.test_nitunit::X.test_nitunit::X::toto (in .nitunit/test_nitunit3.nit): .nitunit/test_nitunit3.nit:5,8--27: Error: Method or variable 'undefined_identifier' unknown in Sys.
 
-<testsuites><testsuite package="test_nitunit"><testcase classname="test_nitunit.&lt;module&gt;" name="&lt;module&gt;"><system-err></system-err><system-out> assert true
-</system-out></testcase><testcase classname="test_nitunit.test_nitunit::X" name="&lt;class&gt;"><system-err></system-err><system-out> assert false
+<testsuites><testsuite package="test_nitunit"><testcase classname="test_nitunit.&lt;module&gt;" name="&lt;module&gt;"><system-err></system-err><system-out>assert true
+</system-out></testcase><testcase classname="test_nitunit.test_nitunit::X" name="&lt;class&gt;"><system-err></system-err><system-out>assert false
 </system-out><error message="Runtime error: Assert failed (.nitunit/test_nitunit2.nit:5)
-"></error></testcase><testcase classname="test_nitunit.test_nitunit::X" name="test_nitunit::X::toto"><system-err></system-err><system-out> assert undefined_identifier
-</system-out><failure message=".nitunit/test_nitunit3.nit:5,9--28: Error: Method or variable 'undefined_identifier' unknown in Sys.
+"></error></testcase><testcase classname="test_nitunit.test_nitunit::X" name="test_nitunit::X::toto"><system-err></system-err><system-out>assert undefined_identifier
+</system-out><failure message=".nitunit/test_nitunit3.nit:5,8--27: Error: Method or variable 'undefined_identifier' unknown in Sys.
 "></failure></testcase></testsuite></testsuites>
\ No newline at end of file
index da9e001..a639d0b 100644 (file)
@@ -1,5 +1,4 @@
-<html>
-<head>
+<html><head>
 <meta charset="utf-8">
 <style type="text/css">
 code {margin: 0 2px;
@@ -16,14 +15,47 @@ overflow: auto;
 padding: 6px 6px;
 border-radius: 3px;
 }
+.rawcode[title] {
+border-color: red;
+}
+.nitcode a { color: inherit; text-decoration: inherit; } /* hide links */
+.nitcode a:hover { text-decoration: underline; } /* underline links */
+.nitcode span[title]:hover { text-decoration: underline; } /* underline titles */
+/* lexical raw tokens. independent of usage or semantic: */
+.nitcode .nc_c { color: gray; font-style: italic; } /* comment */
+.nitcode .nc_d { color: #3D8127; font-style: italic; } /* documentation comments */
+.nitcode .nc_k { font-weight: bold; } /* keyword */
+.nitcode .nc_o {} /* operator */
+.nitcode .nc_i {} /* standard identifier */
+.nitcode .nc_t { color: #445588; font-weight: bold; } /* type/class identifier */
+.nitcode .nc_a { color: #445588; font-style: italic; } /* old style attribute identifier */
+.nitcode .nc_l { color: #009999; } /* char and number literal */
+.nitcode .nc_s { color: #8F1546; } /* string literal */
+/* syntactic token usage. added because of their position in the AST */
+.nitcode .nc_ast { color: blue; } /* assert label */
+.nitcode .nc_la { color: blue; } /* break/continue label */
+.nitcode .nc_m { color: #445588; } /* module name */
+/* syntactic groups */
+.nitcode .nc_def { font-weight: bold; color: blue; } /* name used in a definition */
+  .nitcode .nc_def.nc_a { color: blue; } /* name used in a attribute definition */
+  .nitcode .nc_def.nc_t { color: blue; } /* name used in a class or vt definition */
+.nitcode .nc_ss { color: #9E6BEB; } /* superstrings */
+.nitcode .nc_cdef {} /* A whole class definition */
+.nitcode .nc_pdef {} /* A whole property definition */
+/* semantic token usage */
+.nitcode .nc_v { font-style: italic; } /* local variable or parameter */
+.nitcode .nc_vt { font-style: italic; } /* virtual type or formal type */
+
+.nitcode .nc_error { border: 1px red solid;} /* not used */
+
 </style>
 </head><body>
 <a id='test_doc'></a><h1>module test_doc</h1><a id='test_doc::A'></a><h2>class test_doc#A</h2><div class="nitdoc"><p class="synopsys">Synopsys</p><p>Paragraph
-same paragraph</p><p>Other paragraph with <code>code</code></p><ul><li>bullet</li><li>other buller</li><li>last
+same paragraph</p><p>Other paragraph with <code class="nitcode"><span class="nitcode"><span class="nc_i">code</span></span></code></p><ul><li>bullet</li><li>other buller</li><li>last
 but long
-bullet</li></ul><pre> some
- block
-</pre><p>a first example</p><pre> assert 1 + 1 == 2
-</pre><p>and a last example to illustrate the <code>to_s</code> method on <code>A</code>.</p><pre> var a = new A
- assert a.to_s == &quot;A&quot;
-</pre></div></body></html>
+bullet</li></ul><pre class="nitcode"><span class="nitcode"><span class="nc_pdef"><span class="nc_i">some</span>
+<span class="nc_i">block</span></span>
+</span></pre><p>a first example</p><pre class="nitcode"><span class="nitcode"><span class="nc_pdef"><span class="nc_k">assert</span> <span class="nc_l">1</span> <span class="nc_o">+</span> <span class="nc_l">1</span> <span class="nc_o">==</span> <span class="nc_l">2</span></span>
+</span></pre><p>and a last example to illustrate the <code class="nitcode"><span class="nitcode"><span class="nc_i">to_s</span></span></code> method on <code class="nitcode"><span class="nitcode"><span class="nc_k"></span><span class="nc_v nc_i"></span><span class="nc_t"></span><span class="nc_t">A</span></span></code>.</p><pre class="nitcode"><span class="nitcode"><span class="nc_pdef"><span class="nc_k">var</span> <span class="nc_v nc_i">a</span> = <span class="nc_k">new</span> <span class="nc_t">A</span>
+<span class="nc_k">assert</span> <span class="nc_i">a</span><span class="nc_o">.</span><span class="nc_i">to_s</span> <span class="nc_o">==</span> <span class="nc_s">&quot;A&quot;</span></span>
+</span></pre></div></body></html>
\ No newline at end of file
index b5b20b5..5857c00 100755 (executable)
@@ -13,14 +13,8 @@ done
        ../examples/*/src/*_android.nit \
        ../examples/*/src/*_linux.nit \
        ../lib/*.nit $list \
-       ../src/nitdoc.nit \
-       ../src/test_parser.nit \
-       ../src/test_phase.nit \
-       ../src/nit.nit \
-       ../src/nitmetrics.nit \
-       ../src/nitg.nit \
-       ../src/nitx.nit \
-       ../src/nitunit.nit \
+       ../src/nit*.nit \
+       ../src/test_*.nit \
        ../src/netdbg.nit \
        ../src/nitlight.nit \
        ../contrib/sort_downloads/src/sort_downloads.nit