Merge: Test compilation of OS X and iOS programs, on OS X
authorJean Privat <jean@pryen.org>
Thu, 2 Apr 2015 16:53:38 +0000 (23:53 +0700)
committerJean Privat <jean@pryen.org>
Thu, 2 Apr 2015 16:53:38 +0000 (23:53 +0700)
The results of the compilation of iOS apps by XCode are directories. This PR fix tests.sh to detect those directory and report them cleanly.

Also intro a script for running OS X specific tests.

Pull-Request: #1232
Reviewed-by: Jean Privat <jean@pryen.org>
Reviewed-by: Alexandre Terrasa <alexandre@moz-code.org>

17 files changed:
VERSION
benchmarks/markdown/bench_markdown.sh
benchmarks/markdown/engines/nitmd/Makefile
lib/html/bootstrap.nit [new file with mode: 0644]
lib/standard/string.nit
src/compiler/abstract_compiler.nit
src/doc/doc_base.nit
src/doc/doc_phases/doc_graphs.nit
src/doc/doc_phases/doc_hierarchies.nit
src/doc/doc_phases/doc_html.nit
src/doc/doc_phases/doc_structure.nit
src/doc/html_templates/html_components.nit
src/doc/html_templates/html_model.nit
src/doc/html_templates/html_templates.nit
src/interpreter/naive_interpreter.nit
src/loader.nit
src/test_phase.nit

diff --git a/VERSION b/VERSION
index 2c0a9c7..3d105a6 100644 (file)
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-v0.7.2
+v0.7.3
index 4cb0f15..be58d55 100755 (executable)
@@ -74,7 +74,7 @@ engdir="./engines"
 bncdir="./benches/out"
 mkdir -p $outdir
 
-s=50
+s=200
 
 function bench_nitmd()
 {
@@ -88,6 +88,18 @@ function bench_nitmd()
 }
 bench_nitmd
 
+function bench_nitmd-o()
+{
+       name="$FUNCNAME"
+       skip_test "$name" && return
+       prepare_res $outdir/nitmd-o.dat "nitmd-o" "nitmd-o"
+       for file in $bncdir/*.md; do
+               bench=`basename $file .md`
+               bench_command "$bench" "" "$engdir/nitmd/nitmd-o" "$file" "$s"
+       done
+}
+bench_nitmd-o
+
 function bench_txtmark()
 {
        name="$FUNCNAME"
index aa79fbc..6424382 100644 (file)
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+all: nitmd nitmd-o
+
 nitmd:
        nitc nitmd.nit
 
-test: nitmd
+nitmd-o:
+       nitc --semi-global nitmd.nit -o $@
+
+test: all
        ./nitmd ../../benches/hello.md 5
+       ./nitmd-o ../../benches/hello.md 5
 
 clean:
-       rm -rf nitmd
+       rm -rf nitmd nitmd-o
diff --git a/lib/html/bootstrap.nit b/lib/html/bootstrap.nit
new file mode 100644 (file)
index 0000000..66befa3
--- /dev/null
@@ -0,0 +1,466 @@
+# 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.
+
+# HTML templates for Bootstrap components.
+#
+# See http://getbootstrap.com/components/
+module bootstrap
+
+import template
+
+# Bootstrap component abstraction.
+#
+# Mainly used to factoryze CSS treatments.
+# Can be used in the future to handle generic stuff like attributes or escaping.
+#
+# TODO merge with html::HTMTag without init conflict?
+# HTMLTag requires the main init to pass a tagname,
+# this was so much verbose here.
+abstract class BSComponent
+       super Template
+
+       # CSS classes to add on this element.
+       var css_classes = new Array[String]
+
+       # Render `self` css clases as a `class` attribute.
+       fun render_css_classes: String do
+               if css_classes.is_empty then return ""
+               return " class=\"{css_classes.join(" ")}\""
+       end
+end
+
+# A `<a>` tag.
+#
+# Not really a Bootstrap component but used in other components
+# that it required its own abstraction.
+#
+# Example:
+# ~~~
+# var lnk = new Link("http://nitlanguage.org", "Nit")
+# assert lnk.write_to_string == "<a href=\"http://nitlanguage.org\">Nit</a>"
+# ~~~
+#
+# Creates a link with a title attribute:
+# ~~~
+# lnk = new Link.with_title("http://nitlanguage.org", "Nit", "Nit homepage")
+# assert lnk.write_to_string == "<a href=\"http://nitlanguage.org\" title=\"Nit homepage\">Nit</a>"
+# ~~~
+class Link
+       super BSComponent
+
+       # URL pointed by this link.
+       var href: String is writable
+
+       # Displayed text.
+       var text: Writable is writable
+
+       # Optional title.
+       var title: nullable String is noinit, writable
+
+       # Creates a link with a `title` attribute.
+       init with_title(href: String, text: Writable, title: nullable String) do
+               self.href = href
+               self.text = text
+               self.title = title
+       end
+
+       redef fun rendering do
+               add "<a{render_css_classes} href=\"{href}\""
+               if title != null then add " title=\"{title.write_to_string}\""
+               add ">{text}</a>"
+       end
+end
+
+# A `<h1>` to `<h6>` tag.
+#
+# Not really a Bootstrap component but used in other components
+# that it required its own abstraction.
+#
+# Example:
+# ~~~
+# var h1 = new Header(1, "Title")
+# assert h1.write_to_string == "<h1>Title</h1>"
+# ~~~
+#
+# With subtext:
+# ~~~
+# var h6 = new Header.with_subtext(6, "Title", "with subtext")
+# assert h6.write_to_string == "<h6>Title<small>with subtext</small></h6>"
+# ~~~
+class Header
+       super BSComponent
+
+       # Header level between 1 and 6.
+       var level: Int
+
+       # Displayed text.
+       var text: Writable
+
+       # Optional subtext.
+       var subtext: nullable Writable is noinit, writable
+
+       # Creates a link with a `title` attribute.
+       init with_subtext(level: Int, text: Writable, subtext: String) do
+               self.level = level
+               self.text = text
+               self.subtext = subtext
+       end
+
+       redef fun rendering do
+               add "<h{level}{render_css_classes}>{text.write_to_string}"
+               if subtext != null then add "<small>{subtext.write_to_string}</small>"
+               add "</h{level}>"
+       end
+end
+
+# An abstract HTML list.
+#
+# Many Bootstrap components are built around a HTML list.
+#
+# Used to factorize behavior between OrderedList and UnorderedList.
+abstract class HTMLList
+       super BSComponent
+
+       # A list contains `<li>` tags as children.
+       #
+       # See ListItem.
+       var items = new Array[ListItem]
+
+       # Adds a new ListItem to `self`.
+       fun add_li(item: ListItem) do items.add item
+
+       # Does `self` contains no items?
+       fun is_empty: Bool do return items.is_empty
+end
+
+# A `<ol>` list tag.
+#
+# Example:
+#
+# ~~~
+# var lst = new OrderedList
+# lst.add_li(new ListItem("foo"))
+# lst.add_li(new ListItem("bar"))
+# lst.add_li(new ListItem("baz"))
+#
+# assert lst.write_to_string == """
+# <ol>
+# <li>foo</li>
+# <li>bar</li>
+# <li>baz</li>
+# </ol>
+# """
+# ~~~
+class OrderedList
+       super HTMLList
+
+       redef fun rendering do
+               addn "<ol{render_css_classes}>"
+               for item in items do add item
+               addn "</ol>"
+       end
+end
+
+# A `<ul>` list tag.
+#
+# Example:
+#
+# ~~~
+# var lst = new UnorderedList
+# lst.add_li(new ListItem("foo"))
+# lst.add_li(new ListItem("bar"))
+# lst.add_li(new ListItem("baz"))
+#
+# assert lst.write_to_string == """
+# <ul>
+# <li>foo</li>
+# <li>bar</li>
+# <li>baz</li>
+# </ul>
+# """
+# ~~~
+class UnorderedList
+       super HTMLList
+
+       redef fun rendering do
+               addn "<ul{render_css_classes}>"
+               for item in items do add item
+               addn "</ul>"
+       end
+end
+
+# A `<li>` tag.
+class ListItem
+       super BSComponent
+
+       # Content to display in this list item.
+       var text: Writable is writable
+
+       redef fun rendering do addn "<li{render_css_classes}>{text.write_to_string}</li>"
+end
+
+# A Boostrap icon.
+#
+# See http://getbootstrap.com/components/#glyphicons
+#
+# Example:
+#
+# ~~~
+# var icon = new BSIcon("star")
+# assert icon.write_to_string == "<span class=\"glyphicon glyphicon-star\" aria-hidden=\"true\"></span>"
+# ~~~
+class BSIcon
+       super BSComponent
+
+       # Glyphicon name to display.
+       #
+       # See full list at http://getbootstrap.com/components/#glyphicons.
+       var icon: String
+
+       init do css_classes.add "glyphicon glyphicon-{icon}"
+
+       redef fun rendering do
+               add "<span{render_css_classes} aria-hidden=\"true\"></span>"
+       end
+end
+
+# A Bootstrap breadcrumbs component.
+#
+# See http://getbootstrap.com/components/#breadcrumbs
+#
+# Example:
+#
+# ~~~
+# var bc = new BSBreadCrumbs
+# bc.add_li(new ListItem("foo"))
+# bc.add_li(new ListItem("bar"))
+# bc.add_li(new ListItem("baz"))
+#
+# assert bc.write_to_string == """
+# <ol class=\"breadcrumbs\">
+# <li>foo</li>
+# <li>bar</li>
+# <li class=\"active\">baz</li>
+# </ol>
+# """
+# ~~~
+class BSBreadCrumbs
+       super OrderedList
+
+       init do css_classes.add "breadcrumbs"
+
+       redef fun rendering do
+               items.last.css_classes.add "active"
+               super
+       end
+end
+
+# A Bootstrap label component.
+#
+# See http://getbootstrap.com/components/#labels
+#
+# Example:
+#
+# ~~~
+# var lbl = new BSLabel("danger", "Danger!")
+# assert lbl.write_to_string == "<span class=\"label label-danger\">Danger!</span>"
+# ~~~
+class BSLabel
+       super BSComponent
+
+       # Class used to change the color of the label.
+       #
+       # Can be one of `default`, `primary`, `success`, `info`, `warning` or `danger`.
+       var color: String
+
+       # Text to display in the label.
+       var text: Writable
+
+       init do css_classes.add "label label-{color}"
+
+       redef fun rendering do
+               add "<span{render_css_classes}>{text.write_to_string}</span>"
+       end
+end
+
+# A Bootstrap badge component.
+#
+# See http://getbootstrap.com/components/#badges
+#
+# Example:
+#
+# ~~~
+# var b = new BSBadge("42 messages")
+# assert b.write_to_string == "<span class=\"badge\">42 messages</span>"
+# ~~~
+class BSBadge
+       super BSComponent
+
+       # Text to display in the label.
+       var text: Writable
+
+       init do css_classes.add "badge"
+
+       redef fun rendering do
+               add "<span{render_css_classes}>{text.write_to_string}</span>"
+       end
+end
+
+# A Bootstrap page header component.
+#
+# See http://getbootstrap.com/components/#page-header
+#
+# Example:
+#
+# ~~~
+# var h = new BSPageHeader("Welcome")
+# assert h.write_to_string == """
+# <div class=\"page-header\">
+# Welcome
+# </div>
+# """
+# ~~~
+class BSPageHeader
+       super BSComponent
+
+       # Text to display as title.
+       var text: Writable
+
+       init do css_classes.add "page-header"
+
+       redef fun rendering do
+               addn "<div{render_css_classes}>"
+               addn text.write_to_string
+               addn "</div>"
+       end
+end
+
+# A Bootstrap alert component.
+#
+# See http://getbootstrap.com/components/#alerts
+#
+# Example:
+#
+# ~~~
+# var alert = new BSAlert("danger", "Danger!")
+# assert alert.write_to_string == """
+# <div class="alert alert-danger">
+# Danger!
+# </div>
+# """
+# ~~~
+class BSAlert
+       super BSComponent
+
+       # Class used to change the color of the alert.
+       #
+       # Can be one of `primary`, `success`, `info`, `warning` or `danger`.
+       var color: String
+
+       # Text to display in the alert.
+       var text: Writable
+
+       # Can the alert be dismissed by clicking the close button?
+       #
+       # See http://getbootstrap.com/components/#alerts-dismissible
+       #
+       # Default is `false`.
+       var is_dismissible = false
+
+       init do css_classes.add "alert alert-{color}"
+
+       redef fun rendering do
+               addn "<div{render_css_classes}>"
+               if is_dismissible then
+                       add "<button type=\"button\" class=\"close\" data-dismiss=\"alert\""
+                       add "aria-label=\"Close\"><span aria-hidden=\"true\">&times;</span>"
+                       addn "</button>"
+               end
+               addn text.write_to_string
+               addn "</div>"
+       end
+end
+
+# A Bootstrap panel component.
+#
+# See http://getbootstrap.com/components/#panels
+#
+# Example:
+#
+# ~~~
+# var p = new BSPanel("default", "Panel content")
+#
+# assert p.write_to_string == """
+# <div class="panel panel-default">
+# <div class="panel-body">
+# Panel content
+# </div>
+# </div>
+# """
+# ~~~
+#
+# Panel with heading:
+#
+# ~~~
+# p = new BSPanel("danger", "Panel content")
+# p.heading = "Panel heading"
+#
+# assert p.write_to_string == """
+# <div class="panel panel-danger">
+# <div class="panel-heading">
+# Panel heading
+# </div>
+# <div class="panel-body">
+# Panel content
+# </div>
+# </div>
+# """
+# ~~~
+class BSPanel
+       super BSComponent
+
+       # Panel color.
+       #
+       # Can be one of `default`, `primary`, `success`, `info`, `warning` or `danger`.
+       var color: String
+
+       # Panel header if any.
+       var heading: nullable Writable is noinit, writable
+
+       # Body to display in the panel.
+       var body: Writable
+
+       # Panel footer is any.
+       var footer: nullable Writable is noinit, writable
+
+       init do css_classes.add "panel panel-{color}"
+
+       redef fun rendering do
+               addn "<div{render_css_classes}>"
+               if heading != null then
+                       addn "<div class=\"panel-heading\">"
+                       addn heading.write_to_string
+                       addn "</div>"
+               end
+               addn "<div class=\"panel-body\">"
+               addn body.write_to_string
+               addn "</div>"
+               if footer != null then
+                       addn "<div class=\"panel-footer\">"
+                       addn footer.write_to_string
+                       addn "</div>"
+               end
+               addn "</div>"
+       end
+end
index e974d91..409b4ed 100644 (file)
@@ -864,6 +864,23 @@ abstract class FlatText
        # Real items, used as cache for to_cstring is called
        private var real_items: nullable NativeString = null
 
+       # Returns a char* starting at position `index_from`
+       #
+       # WARNING: If you choose to use this service, be careful of the following.
+       #
+       # Strings and NativeString are *ideally* always allocated through a Garbage Collector.
+       # Since the GC tracks the use of the pointer for the beginning of the char*, it may be
+       # deallocated at any moment, rendering the pointer returned by this function invalid.
+       # Any access to freed memory may very likely cause undefined behaviour or a crash.
+       # (Failure to do so will most certainly result in long and painful debugging hours)
+       #
+       # The only safe use of this pointer is if it is ephemeral (e.g. read in a C function
+       # then immediately return).
+       #
+       # As always, do not modify the content of the String in C code, if this is what you want
+       # copy locally the char* as Nit Strings are immutable.
+       private fun fast_cstring: NativeString is abstract
+
        redef var length: Int = 0
 
        redef fun output
@@ -1119,6 +1136,8 @@ class FlatString
                return native.to_s_with_length(self.length)
        end
 
+       redef fun fast_cstring do return items.fast_cstring(index_from)
+
        redef fun substring(from, count)
        do
                assert count >= 0
@@ -1567,6 +1586,8 @@ class FlatBuffer
 
        private var capacity: Int = 0
 
+       redef fun fast_cstring do return items.fast_cstring(0)
+
        redef fun substrings do return new FlatSubstringsIter(self)
 
        # Re-copies the `NativeString` into a new one and sets it as the new `Buffer`
@@ -2289,6 +2310,12 @@ extern class NativeString `{ char* `}
        # Creates a new NativeString with a capacity of `length`
        new(length: Int) is intern
 
+       # Returns a char* starting at `index`.
+       #
+       # WARNING: Unsafe for extern code, use only for temporary
+       # pointer manipulation purposes (e.g. write to file or such)
+       fun fast_cstring(index: Int): NativeString is intern
+
        # Get char at `index`.
        fun [](index: Int): Char is intern
 
index 43fd172..1a551d6 100644 (file)
@@ -2204,6 +2204,9 @@ redef class AMethPropdef
                        else if pname == "atoi" then
                                v.ret(v.new_expr("atoi({arguments[0]});", ret.as(not null)))
                                return true
+                       else if pname == "fast_cstring" then
+                               v.ret(v.new_expr("{arguments[0]} + {arguments[1]}", ret.as(not null)))
+                               return true
                        else if pname == "new" then
                                v.ret(v.new_expr("(char*)nit_alloc({arguments[1]})", ret.as(not null)))
                                return true
index e947ee2..64b2022 100644 (file)
@@ -68,7 +68,7 @@ end
 abstract class DocComposite
 
        # Parent element.
-       var parent: nullable DocComposite = null
+       var parent: nullable DocComposite = null is writable
 
        # Does `self` have a `parent`?
        fun is_root: Bool do return parent == null
@@ -85,6 +85,7 @@ abstract class DocComposite
        #
        # Shortcut for `children.add`.
        fun add_child(child: DocComposite) do
+               child.parent = self
                children.add child
        end
 end
index aff25d4..66ef564 100644 (file)
@@ -41,7 +41,8 @@ class GraphPhase
                        if article == null then continue
                        # FIXME avoid diff
                        # page.root.add article
-                       page.root.children[1].children.insert(article, 0)
+                       article.parent = page.root.children.first.children[1]
+                       page.root.children.first.children[1].children.insert(article, 0)
                end
        end
 end
index 39ad273..23da906 100644 (file)
@@ -47,7 +47,8 @@ redef class MModulePage
                var clients = self.clients.to_a
                v.name_sorter.sort(clients)
                section.add_child new HierarchyListArticle(mentity, "Clients", clients)
-               root.children.insert(section, 1)
+               section.parent = root.children.first
+               root.children.first.children.insert(section, 1)
        end
 end
 
@@ -66,7 +67,8 @@ redef class MClassPage
                var descendants = self.descendants.to_a
                v.name_sorter.sort(descendants)
                section.add_child new HierarchyListArticle(mentity, "Descendants", descendants)
-               root.children.insert(section, 1)
+               section.parent = root.children.first
+               root.children.first.children.insert(section, 1)
        end
 end
 
index a11e187..7d38bc0 100644 (file)
@@ -191,7 +191,7 @@ redef class DocPage
 
        # Build top menu template if any.
        fun init_topmenu(v: RenderHTMLPhase, doc: DocModel) do
-               topmenu = new TplTopMenu(html_url)
+               topmenu = new DocTopMenu
                var brand = v.ctx.opt_custom_brand.value
                if brand != null then
                        var tpl = new Template
@@ -200,8 +200,13 @@ redef class DocPage
                        tpl.add "</span>"
                        topmenu.brand = tpl
                end
-               topmenu.add_link new TplLink("index.html", "Overview")
-               topmenu.add_link new TplLink("search.html", "Index")
+               var title = "Overview"
+               if v.ctx.opt_custom_title.value != null then
+                       title = v.ctx.opt_custom_title.value.to_s
+               end
+               topmenu.add_li new ListItem(new Link("index.html", title))
+               topmenu.add_li new ListItem(new Link("search.html", "Index"))
+               topmenu.active_item = topmenu.items.first
        end
 
        # Build page sidebar if any.
@@ -257,6 +262,12 @@ end
 redef class SearchPage
        redef var html_url = "search.html"
        redef fun init_title(v, doc) do title = "Index"
+
+       redef fun init_topmenu(v, doc) do
+               super
+               topmenu.active_item = topmenu.items.last
+       end
+
        redef fun init_sidebar(v, doc) do end
 
        # TODO this should be done in StructurePhase.
@@ -314,7 +325,7 @@ end
 
 redef class MEntityPage
        redef var html_url is lazy do return mentity.nitdoc_url
-       redef fun init_title(v, doc) do title = mentity.nitdoc_name
+       redef fun init_title(v, doc) do title = mentity.html_name
        redef fun init_content(v, doc) do add_section root.start_rendering(v, doc, self)
 end
 
@@ -327,9 +338,10 @@ redef class MGroupPage
                super
                var mproject = mentity.mproject
                if not mentity.is_root then
-                       topmenu.add_link new TplLink(mproject.nitdoc_url, mproject.nitdoc_name)
+                       topmenu.add_li new ListItem(new Link(mproject.nitdoc_url, mproject.html_name))
                end
-               topmenu.add_link new TplLink(html_url, mproject.nitdoc_name)
+               topmenu.add_li new ListItem(new Link(html_url, mproject.html_name))
+               topmenu.active_item = topmenu.items.last
        end
 
        redef fun init_sidebar(v, doc) do
@@ -366,8 +378,9 @@ redef class MModulePage
        redef fun init_topmenu(v, doc) do
                super
                var mproject = mentity.mproject
-               topmenu.add_link new TplLink(mproject.nitdoc_url, mproject.nitdoc_name)
-               topmenu.add_link new TplLink(mentity.nitdoc_url, mentity.nitdoc_name)
+               topmenu.add_li new ListItem(new Link(mproject.nitdoc_url, mproject.html_name))
+               topmenu.add_li new ListItem(new Link(mentity.nitdoc_url, mentity.html_name))
+               topmenu.active_item = topmenu.items.last
        end
 
        # Class list to display in sidebar
@@ -404,15 +417,12 @@ end
 
 redef class MClassPage
 
-       redef fun init_title(v, doc) do
-               title = "{mentity.nitdoc_name}{mentity.tpl_signature.write_to_string}"
-       end
-
        redef fun init_topmenu(v, doc) do
                super
                var mproject = mentity.intro_mmodule.mgroup.mproject
-               topmenu.add_link new TplLink("{mproject.nitdoc_url}", "{mproject.nitdoc_name}")
-               topmenu.add_link new TplLink(html_url, mentity.nitdoc_name)
+               topmenu.add_li new ListItem(new Link(mproject.nitdoc_url, mproject.html_name))
+               topmenu.add_li new ListItem(new Link(html_url, mentity.html_name))
+               topmenu.active_item = topmenu.items.last
        end
 
        redef fun init_sidebar(v, doc) do
@@ -442,7 +452,7 @@ redef class MClassPage
                        classes.add "inherit"
                        var cls_url = mprop.intro.mclassdef.mclass.nitdoc_url
                        var def_url = "{cls_url}#{mprop.nitdoc_id}"
-                       var lnk = new TplLink(def_url, mprop.nitdoc_name)
+                       var lnk = new TplLink(def_url, mprop.html_name)
                        var mdoc = mprop.intro.mdoc_or_fallback
                        if mdoc != null then lnk.title = mdoc.short_comment
                        var item = new Template
@@ -486,7 +496,7 @@ end
 
 redef class MPropertyPage
        redef fun init_title(v, doc) do
-               title = "{mentity.nitdoc_name}{mentity.tpl_signature.write_to_string}"
+               title = "{mentity.html_name}{mentity.tpl_signature.write_to_string}"
        end
 
        redef fun init_topmenu(v, doc) do
@@ -494,9 +504,10 @@ redef class MPropertyPage
                var mmodule = mentity.intro_mclassdef.mmodule
                var mproject = mmodule.mgroup.mproject
                var mclass = mentity.intro_mclassdef.mclass
-               topmenu.add_link new TplLink("{mproject.nitdoc_url}", "{mproject.nitdoc_name}")
-               topmenu.add_link new TplLink("{mclass.nitdoc_url}", "{mclass.nitdoc_name}")
-               topmenu.add_link new TplLink(html_url, mentity.nitdoc_name)
+               topmenu.add_li new ListItem(new Link(mproject.nitdoc_url, mproject.html_name))
+               topmenu.add_li new ListItem(new Link(mclass.nitdoc_url, mclass.html_name))
+               topmenu.add_li new ListItem(new Link(html_url, mentity.html_name))
+               topmenu.active_item = topmenu.items.last
        end
 end
 
@@ -515,18 +526,16 @@ redef class DocRoot
        fun start_rendering(v: RenderHTMLPhase, doc: DocModel, page: MEntityPage): TplSection do
                var section = new TplSection("top")
                var mentity = page.mentity
-               section.title = mentity.nitdoc_name
+               section.title = mentity.html_name
                section.subtitle = mentity.tpl_declaration
                # FIXME ugly hack to avoid diff
                if mentity isa MGroup and mentity.is_root then
-                       section.title = mentity.mproject.nitdoc_name
+                       section.title = mentity.mproject.html_name
                        section.subtitle = mentity.mproject.tpl_declaration
-               else if mentity isa MClass then
-                       section.title = "{mentity.nitdoc_name}{mentity.tpl_signature.write_to_string}"
                else if mentity isa MProperty then
-                       section.title = "{mentity.nitdoc_name}{mentity.intro.tpl_signature.write_to_string}"
+                       section.title = "{mentity.html_name}{mentity.intro.tpl_signature.write_to_string}"
                        section.subtitle = mentity.tpl_namespace
-                       section.summary_title = mentity.nitdoc_name
+                       section.summary_title = mentity.html_name
                end
                render(v, doc, page, section)
                return section
@@ -561,10 +570,10 @@ redef class ConcernSection
                var title = new Template
                if mmodule == page.mentity then
                        title.add "in "
-                       section.summary_title = "in {mmodule.nitdoc_name}"
+                       section.summary_title = "in {mmodule.html_name}"
                else
                        title.add "from "
-                       section.summary_title = "from {mmodule.nitdoc_name}"
+                       section.summary_title = "from {mmodule.html_name}"
                end
                title.add mmodule.tpl_namespace
                section.title = title
@@ -575,7 +584,13 @@ redef class ConcernSection
                title.add "in "
                title.add mmodule.tpl_namespace
                section.title = title
-               section.summary_title = "in {mmodule.nitdoc_name}"
+               section.summary_title = "in {mmodule.html_name}"
+       end
+end
+
+redef class MEntitySection
+       redef fun render(v, doc, page, parent) do
+               for child in children do child.render(v, doc, page, parent)
        end
 end
 
@@ -690,14 +705,14 @@ redef class DefinitionArticle
                else
                        var cls_url = mprop.intro.mclassdef.mclass.nitdoc_url
                        var def_url = "{cls_url}#{mprop.nitdoc_id}"
-                       var lnk = new TplLink.with_title(def_url, mprop.nitdoc_name,
+                       var lnk = new TplLink.with_title(def_url, mprop.html_name,
                                        "Go to introduction")
                        title.add "redef "
                        title.add lnk
                end
                article.title = title
                article.title_classes.add "signature"
-               article.summary_title = "{mprop.nitdoc_name}"
+               article.summary_title = "{mprop.html_name}"
                article.subtitle = mpropdef.tpl_namespace
                if mpropdef.mdoc_or_fallback != null then
                        article.content = mpropdef.mdoc_or_fallback.tpl_comment
index 1e0d773..9c32c8c 100644 (file)
@@ -50,10 +50,12 @@ end
 
 redef class MGroupPage
        redef fun apply_structure(v, doc) do
+               var section = new MEntitySection(mentity)
+               root.add_child section
                if mentity.is_root then
-                       root.add_child new IntroArticle(mentity.mproject)
+                       section.add_child new IntroArticle(mentity.mproject)
                else
-                       root.add_child new IntroArticle(mentity)
+                       section.add_child new IntroArticle(mentity)
                end
                var concerns = self.concerns
                if concerns == null or concerns.is_empty then return
@@ -63,12 +65,12 @@ redef class MGroupPage
                concerns.sort_with(v.concerns_sorter)
                mentity.mproject.booster_rank = 0
                mentity.booster_rank = 0
-               root.add_child new ConcernsArticle(mentity, concerns)
+               section.add_child new ConcernsArticle(mentity, concerns)
                for mentity in concerns do
                        if mentity isa MModule then
-                               root.add_child new DefinitionArticle(mentity)
+                               section.add_child new DefinitionArticle(mentity)
                        else
-                               root.add_child new ConcernSection(mentity)
+                               section.add_child new ConcernSection(mentity)
                        end
                end
        end
@@ -76,7 +78,9 @@ end
 
 redef class MModulePage
        redef fun apply_structure(v, doc) do
-               root.add_child new IntroArticle(mentity)
+               var section = new MEntitySection(mentity)
+               root.add_child section
+               section.add_child new IntroArticle(mentity)
                var concerns = self.concerns
                if concerns == null or concerns.is_empty then return
                # FIXME avoid diff
@@ -87,10 +91,10 @@ redef class MModulePage
                mentity.mgroup.mproject.booster_rank = 0
                mentity.mgroup.booster_rank = 0
                mentity.booster_rank = 0
-               root.add_child new ConcernsArticle(mentity, concerns)
+               section.add_child new ConcernsArticle(mentity, concerns)
                # reference list
                for mentity in concerns do
-                       var section = new ConcernSection(mentity)
+                       var ssection = new ConcernSection(mentity)
                        if mentity isa MModule then
                                var mclasses = mclasses_for_mmodule(mentity).to_a
                                v.name_sorter.sort(mclasses)
@@ -104,10 +108,10 @@ redef class MModulePage
                                        for mclassdef in mclassdefs do
                                                article.add_child(new DefinitionArticle(mclassdef))
                                        end
-                                       section.add_child article
+                                       ssection.add_child article
                                end
                        end
-                       root.add_child section
+                       section.add_child ssection
                end
        end
 
@@ -136,7 +140,9 @@ end
 
 redef class MClassPage
        redef fun apply_structure(v, doc) do
-               root.add_child new IntroArticle(mentity)
+               var section = new MEntitySection(mentity)
+               root.add_child section
+               section.add_child new IntroArticle(mentity)
                var concerns = self.concerns
                if concerns == null or concerns.is_empty then return
                # FIXME diff hack
@@ -147,9 +153,9 @@ redef class MClassPage
                mentity.intro_mmodule.mgroup.mproject.booster_rank = 0
                mentity.intro_mmodule.mgroup.booster_rank = 0
                mentity.intro_mmodule.booster_rank = 0
-               root.add_child new ConcernsArticle(mentity, concerns)
+               section.add_child new ConcernsArticle(mentity, concerns)
                for mentity in concerns do
-                       var section = new ConcernSection(mentity)
+                       var ssection = new ConcernSection(mentity)
                        if mentity isa MModule then
                                var mprops = mproperties_for(mentity)
                                var by_kind = new PropertiesByKind.with_elements(mprops)
@@ -157,12 +163,12 @@ redef class MClassPage
                                        v.name_sorter.sort(group)
                                        for mprop in group do
                                                for mpropdef in mpropdefs_for(mprop, mentity) do
-                                                       section.add_child new DefinitionArticle(mpropdef)
+                                                       ssection.add_child new DefinitionArticle(mpropdef)
                                                end
                                        end
                                end
                        end
-                       root.add_child section
+                       section.add_child ssection
                end
        end
 
@@ -196,7 +202,9 @@ end
 
 redef class MPropertyPage
        redef fun apply_structure(v, doc) do
-               root.add_child new IntroArticle(mentity)
+               var section = new MEntitySection(mentity)
+               root.add_child section
+               section.add_child new IntroArticle(mentity)
                var concerns = self.concerns
                if concerns == null or concerns.is_empty then return
                # FIXME diff hack
@@ -207,18 +215,18 @@ redef class MPropertyPage
                mentity.intro.mclassdef.mmodule.mgroup.mproject.booster_rank = 0
                mentity.intro.mclassdef.mmodule.mgroup.booster_rank = 0
                mentity.intro.mclassdef.mmodule.booster_rank = 0
-               root.add_child new ConcernsArticle(mentity, concerns)
+               section.add_child new ConcernsArticle(mentity, concerns)
                for mentity in concerns do
-                       var section = new ConcernSection(mentity)
+                       var ssection = new ConcernSection(mentity)
                        if mentity isa MModule then
                                # Add mproperties
                                var mpropdefs = mpropdefs_for(mentity).to_a
                                v.name_sorter.sort(mpropdefs)
                                for mpropdef in mpropdefs do
-                                       section.add_child new DefinitionArticle(mpropdef)
+                                       ssection.add_child new DefinitionArticle(mpropdef)
                                end
                        end
-                       root.add_child section
+                       section.add_child ssection
                end
        end
 
@@ -258,6 +266,14 @@ abstract class MEntityArticle
        super DocArticle
 end
 
+# A section about a Mentity.
+#
+# Used to regroup content about a MEntity.
+class MEntitySection
+       super MEntityComposite
+       super DocSection
+end
+
 # An introduction article about a MEntity.
 #
 # Used at the top of a documentation page to introduce the documented MEntity.
index c3126f7..e65059b 100644 (file)
@@ -24,70 +24,6 @@ import json::static
 # general layout elements
 #########################
 
-# Top menu bar template
-class TplTopMenu
-       super Template
-
-       # Brand link to display in first position of the top menu
-       private var brand: nullable Writable = null is writable
-       # Elements of the topmenu
-       private var elts = new Array[Writable]
-
-       # The page url where the top menu is displayed.
-       #
-       # Used to select the active link.
-       private var current_url: String
-
-       # Add a new link to the menu.
-       fun add_link(content: TplLink) do
-               var is_active = content.href == current_url
-               add_item(content, is_active)
-       end
-
-       # Add a content between `<li>` tags
-       fun add_item(content: Writable, is_active: Bool) do
-               var tpl = new Template
-               tpl.add "<li"
-               if is_active then
-                       tpl.add " class=\"active\""
-               end
-               tpl.add ">"
-               tpl.add content
-               tpl.addn "</li>"
-               add_raw(tpl)
-       end
-
-       # Add a raw content to the menu
-       fun add_raw(content: Writable) do
-               elts.add content
-       end
-
-       redef fun rendering do
-               if brand == null and elts.is_empty then return
-               addn "<nav id='topmenu' class='navbar navbar-default navbar-fixed-top' role='navigation'>"
-               addn " <div class='container-fluid'>"
-               addn "  <div class='navbar-header'>"
-               add "   <button type='button' class='navbar-toggle' "
-               addn "       data-toggle='collapse' data-target='#topmenu-collapse'>"
-               addn "    <span class='sr-only'>Toggle menu</span>"
-               addn "    <span class='icon-bar'></span>"
-               addn "    <span class='icon-bar'></span>"
-               addn "    <span class='icon-bar'></span>"
-               addn "   </button>"
-               if brand != null then add brand.as(not null)
-               addn "  </div>"
-               addn "  <div class='collapse navbar-collapse' id='topmenu-collapse'>"
-               if not elts.is_empty then
-                       addn "<ul class='nav navbar-nav'>"
-                       for elt in elts do add elt
-                       addn "</ul>"
-               end
-               addn "  </div>"
-               addn " </div>"
-               addn "</nav>"
-       end
-end
-
 # A sidebar template
 class TplSidebar
        super Template
index 15b2963..2908fad 100644 (file)
@@ -45,9 +45,20 @@ redef class MEntity
        # URL of this entity’s Nitdoc page.
        fun nitdoc_url: String is abstract
 
+       # Returns the mentity name without short signature.
+       #
+       # * MProject: `foo`
+       # * MGroup: `foo`
+       # * MModule: `foo`
+       # * MClass: `Foo[E]`
+       # * MClassDef: `Foo[E]`
+       # * MProperty: `foo(e)`
+       # * MPropdef: `foo(e)`
+       var html_name: String is lazy do return name.html_escape
+
        # A template link to the mentity `nitdoc_id`
        fun tpl_anchor: TplLink do
-               var tpl = new TplLink("#{nitdoc_id}", nitdoc_name)
+               var tpl = new TplLink("#{nitdoc_id}", html_name)
                var mdoc = mdoc_or_fallback
                if mdoc != null then
                        tpl.title = mdoc.short_comment
@@ -57,7 +68,7 @@ redef class MEntity
 
        # A template link to the mentity `nitdoc_url`
        fun tpl_link: TplLink do
-               var tpl = new TplLink(nitdoc_url, nitdoc_name)
+               var tpl = new TplLink(nitdoc_url, html_name)
                var mdoc = mdoc_or_fallback
                if mdoc != null then
                        tpl.title = mdoc.short_comment
@@ -80,7 +91,7 @@ redef class MEntity
                var tpl = new TplArticle.with_title(nitdoc_id, tpl_title)
                tpl.title_classes.add "signature"
                tpl.subtitle = tpl_namespace
-               tpl.summary_title = nitdoc_name
+               tpl.summary_title = html_name
                return tpl
        end
 
@@ -252,6 +263,22 @@ redef class MClass
        redef fun nitdoc_url do return "class_{nitdoc_id}.html"
        redef fun mdoc_or_fallback do return intro.mdoc
 
+       # Format: `Foo[E]`
+       redef var html_name is lazy do
+               var tpl = new Template
+               tpl.add name.html_escape
+               if arity > 0 then
+                       tpl.add "["
+                       var parameter_names = new Array[String]
+                       for p in mparameters do
+                               parameter_names.add(p.html_name)
+                       end
+                       tpl.add parameter_names.join(", ")
+                       tpl.add "]"
+               end
+               return tpl.write_to_string
+       end
+
        redef fun tpl_declaration do return intro.tpl_declaration
        redef fun tpl_definition do return intro.tpl_definition
 
@@ -268,7 +295,6 @@ redef class MClass
                var title = new Template
                title.add tpl_icon
                title.add tpl_link
-               title.add tpl_signature
                return title
        end
 
@@ -280,7 +306,7 @@ redef class MClass
                        tpl.add "["
                        var parameter_names = new Array[String]
                        for p in mparameters do
-                               parameter_names.add(p.nitdoc_name)
+                               parameter_names.add(p.html_name)
                        end
                        tpl.add parameter_names.join(", ")
                        tpl.add "]"
@@ -288,12 +314,6 @@ redef class MClass
                return tpl
        end
 
-       redef fun tpl_article do
-               var tpl = super
-               tpl.summary_title = "{nitdoc_name}{tpl_signature.write_to_string}"
-               return tpl
-       end
-
        redef fun tpl_css_classes do return intro.tpl_css_classes
 end
 
@@ -314,7 +334,7 @@ redef class MClassDef
 
        redef fun tpl_article do
                var tpl = new TplArticle(nitdoc_id)
-               tpl.summary_title = "in {mmodule.nitdoc_name}"
+               tpl.summary_title = "in {mmodule.html_name}"
                tpl.title = tpl_declaration
                tpl.title_classes.add "signature"
                var title = new Template
@@ -332,7 +352,6 @@ redef class MClassDef
                var title = new Template
                title.add tpl_icon
                title.add tpl_link
-               title.add tpl_signature
                return title
        end
 
@@ -350,7 +369,7 @@ redef class MClassDef
                if not mparameters.is_empty then
                        tpl.add "["
                        for i in [0..mparameters.length[ do
-                               tpl.add "{mparameters[i].nitdoc_name}: "
+                               tpl.add "{mparameters[i].html_name}: "
                                tpl.add bound_mtype.arguments[i].tpl_signature
                                if i < mparameters.length - 1 then tpl.add ", "
                        end
@@ -428,7 +447,7 @@ redef class MPropDef
 
        redef fun tpl_article do
                var tpl = new TplArticle(nitdoc_id)
-               tpl.summary_title = "in {mclassdef.nitdoc_name}"
+               tpl.summary_title = "in {mclassdef.html_name}"
                var title = new Template
                title.add "in "
                title.add mclassdef.tpl_link
@@ -577,7 +596,9 @@ end
 redef class MGenericType
        redef fun tpl_signature do
                var tpl = new Template
-               tpl.add tpl_link
+               var lnk = tpl_link
+               lnk.text = mclass.name.html_escape
+               tpl.add lnk
                tpl.add "["
                for i in [0..arguments.length[ do
                        tpl.add arguments[i].tpl_signature
index 83c1842..53fc0cf 100644 (file)
@@ -16,6 +16,7 @@
 module html_templates
 
 import html_model
+import html::bootstrap
 
 # Renders the page as HTML.
 redef class DocPage
@@ -31,7 +32,7 @@ redef class DocPage
        var body_attrs = new Array[TagAttribute]
 
        # Top menu template if any.
-       var topmenu: TplTopMenu is writable, noinit
+       var topmenu: DocTopMenu is writable, noinit
 
        # Sidebar template if any.
        var sidebar: nullable TplSidebar = null is writable
@@ -74,13 +75,6 @@ redef class DocPage
                addn ">"
        end
 
-       # Renders the topmenu template.
-       private fun render_topmenu do
-               addn " <div class='row'>"
-               add topmenu
-               addn " </div>"
-       end
-
        # Renders the sidebar template.
        #
        # Sidebar is automatically populated with a summary of all sections
@@ -129,7 +123,9 @@ redef class DocPage
        redef fun rendering do
                render_head
                addn "<div class='container-fluid'>"
-               render_topmenu
+               addn " <div class='row'>"
+               add topmenu
+               addn " </div>"
                addn " <div class='row' id='content'>"
                if sidebar != null then
                        addn "<div class='col col-xs-3 col-lg-2'>"
@@ -148,3 +144,55 @@ redef class DocPage
                render_footer
        end
 end
+
+# Top menu bar template.
+#
+# FIXME should be a Bootstrap component template
+# At this moment, the topmenu structure stills to specific to Nitdoc to use the
+# generic component.
+class DocTopMenu
+       super UnorderedList
+
+       # Brand link to display in first position of the top menu.
+       #
+       # This is where you want to put your logo.
+       var brand: nullable Writable is noinit, writable
+
+       # Active menu item.
+       #
+       # Depends on the current page, this allows to hilighted the current item.
+       #
+       # FIXME should be using Boostrap breadcrumbs component.
+       # This will still like this to avoid diff and be changed in further fixes
+       # when we will modify the output.
+       var active_item: nullable ListItem is noinit, writable
+
+       redef fun rendering do
+               addn "<nav id='topmenu' class='navbar navbar-default navbar-fixed-top' role='navigation'>"
+               addn " <div class='container-fluid'>"
+               addn "  <div class='navbar-header'>"
+               add "   <button type='button' class='navbar-toggle' "
+               addn "       data-toggle='collapse' data-target='#topmenu-collapse'>"
+               addn "    <span class='sr-only'>Toggle menu</span>"
+               addn "    <span class='icon-bar'></span>"
+               addn "    <span class='icon-bar'></span>"
+               addn "    <span class='icon-bar'></span>"
+               addn "   </button>"
+               if brand != null then
+                       add "<span class='navbar-brand'>"
+                       add brand.write_to_string
+                       add "</span>"
+               end
+               addn "  </div>"
+               addn "  <div class='collapse navbar-collapse' id='topmenu-collapse'>"
+               addn "   <ul class='nav navbar-nav'>"
+               for item in items do
+                       if item == active_item then item.css_classes.add "active"
+                       add item.write_to_string
+               end
+               addn "   </ul>"
+               addn "  </div>"
+               addn " </div>"
+               addn "</nav>"
+       end
+end
index aba779a..8818874 100644 (file)
@@ -1016,6 +1016,9 @@ redef class AMethPropdef
                                return v.int_instance(res)
                        else if pname == "atof" then
                                return v.float_instance(recvval.to_f)
+                       else if pname == "fast_cstring" then
+                               var ns = recvval.to_cstring.to_s.substring_from(args[1].to_i)
+                               return v.native_string_instance(ns)
                        end
                else if cname == "String" then
                        var cs = v.send(v.force_get_primitive_method("to_cstring", args.first.mtype), [args.first])
index 492584b..9d1297b 100644 (file)
@@ -108,8 +108,19 @@ redef class ModelBuilder
        end
 
        # Load a bunch of modules and groups.
-       # Each name can be a module or a group.
-       # If it is a group then recursively all its modules are parsed.
+       #
+       # Each name can be:
+       #
+       # * a path to a module, a group or a directory of projects.
+       # * a short name of a module or a group that are looked in the `paths` (-I)
+       #
+       # Then, for each entry, if it is:
+       #
+       # * a module, then is it parser and returned.
+       # * a group then recursively all its modules are parsed.
+       # * a directory of projects then all the modules of all projects are parsed.
+       # * else an error is displayed.
+       #
        # See `parse` for details.
        fun parse_full(names: Sequence[String]): Array[MModule]
        do
@@ -118,11 +129,39 @@ redef class ModelBuilder
                self.toolcontext.info("*** PARSE ***", 1)
                var mmodules = new ArraySet[MModule]
                for a in names do
+                       # Case of a group
                        var mgroup = self.get_mgroup(a)
                        if mgroup != null then
                                mmodules.add_all parse_group(mgroup)
                                continue
                        end
+
+                       # Case of a directory that is not a group
+                       var stat = a.to_path.stat
+                       if stat != null and stat.is_dir then
+                               self.toolcontext.info("look in directory {a}", 2)
+                               var fs = a.files
+                               # Try each entry as a group or a module
+                               for f in fs do
+                                       var af = a/f
+                                       mgroup = get_mgroup(af)
+                                       if mgroup != null then
+                                               mmodules.add_all parse_group(mgroup)
+                                               continue
+                                       end
+                                       var mp = identify_file(af)
+                                       if mp != null then
+                                               var nmodule = self.load_module(af)
+                                               if nmodule == null then continue # Skip error
+                                               build_module_importation(nmodule)
+                                               mmodules.add(nmodule.mmodule.as(not null))
+                                       else
+                                               self.toolcontext.info("ignore file {af}", 2)
+                                       end
+                               end
+                               continue
+                       end
+
                        var nmodule = self.load_module(a)
                        if nmodule == null then continue # Skip error
                        # Load imported module
@@ -350,12 +389,15 @@ redef class ModelBuilder
                        return mgroups[rdp]
                end
 
-               # Hack, a group is determined by:
+               # Hack, a group is determined by one of the following:
                # * the presence of a honomymous nit file
                # * the fact that the directory is named `src`
+               # * the fact that there is a sub-directory named `src`
                var pn = rdp.basename(".nit")
                var mp = dirpath.join_path(pn + ".nit").simplify_path
 
+               # dirpath2 is the root directory
+               # dirpath is the src subdirectory directory, if any, else it is the same that dirpath2
                var dirpath2 = dirpath
                if not mp.file_exists then
                        if pn == "src" then
@@ -363,12 +405,17 @@ redef class ModelBuilder
                                dirpath2 = rdp.dirname
                                pn = dirpath2.basename("")
                        else
-                               return null
+                               # Check a `src` subdirectory
+                               dirpath = dirpath2 / "src"
+                               if not dirpath.file_exists then
+                                       # All rules failed, so return null
+                                       return null
+                               end
                        end
                end
 
                # check parent directory
-               var parentpath = dirpath.join_path("..").simplify_path
+               var parentpath = dirpath2.join_path("..").simplify_path
                var parent = get_mgroup(parentpath)
 
                var mgroup
@@ -382,15 +429,22 @@ redef class ModelBuilder
                        mgroup = new MGroup(pn, parent.mproject, parent)
                        toolcontext.info("found sub group `{mgroup.full_name}` at {dirpath}", 2)
                end
-               var readme = dirpath2.join_path("README.md")
+
+               # search documentation
+               # in src first so the documentation of the project code can be distinct for the documentation of the project usage
+               var readme = dirpath.join_path("README.md")
+               if not readme.file_exists then readme = dirpath.join_path("README")
+               if not readme.file_exists then readme = dirpath2.join_path("README.md")
                if not readme.file_exists then readme = dirpath2.join_path("README")
                if readme.file_exists then
                        var mdoc = load_markdown(readme)
                        mgroup.mdoc = mdoc
                        mdoc.original_mentity = mgroup
                end
+
                mgroup.filepath = dirpath
-               mgroups[rdp] = mgroup
+               mgroups[module_absolute_path(dirpath)] = mgroup
+               mgroups[module_absolute_path(dirpath2)] = mgroup
                return mgroup
        end
 
index 8fd5908..767cf95 100644 (file)
@@ -62,6 +62,6 @@ var model = new Model
 var modelbuilder = new ModelBuilder(model, toolcontext)
 
 # Here we load an process all modules passed on the command line
-var mmodules = modelbuilder.parse(arguments)
+var mmodules = modelbuilder.parse_full(arguments)
 modelbuilder.run_phases
 toolcontext.run_global_phases(mmodules)