Merge: Clean UTF-8 string update
authorJean Privat <jean@pryen.org>
Tue, 15 Sep 2015 16:57:16 +0000 (12:57 -0400)
committerJean Privat <jean@pryen.org>
Tue, 15 Sep 2015 16:57:16 +0000 (12:57 -0400)
Since quite some time now we've had the cleaning function for Bytes that ensured that what was coming from the exterior was clean and could be transformed safely to a String.

This is now generalized to any NativeString, and the clean function will be called each time a NativeString is `to_s`'d

At the same time, `clean_utf8` is now better performing (for `Files::read_all`, Ir per call is roughly 40% less than before), which limits the impacts of the new strategy.

Furthermore, the string produced by `NativeString::clean_utf8` has its length calculated which saves time on later operations on the string.

It also limits the number of calls by avoiding allocations if not necessary (if the string is already clean, which should happen a lot more often than not).

As for performances,

Valgrind `./bin/nitc src/nitc.nit`:
Before: 14.040 GIr
After: 13.859 GIr

Time, best of 10 for `./bin/nitc src/nitc.nit -o bin/nitc`:
Before: 0m4.989s
After: 0m4.933s

Time, best of 10 for `./bin/nitc --semi-global src/nitc.nit -o bin/nitc`:
Before: 0m4.696s
After: 0m4.691s

Pretty much equivalent in real time, and a bit better in Valgrind, not bad considering every String is now cleaner than ever !

Pull-Request: #1705
Reviewed-by: Jean Privat <jean@pryen.org>
Reviewed-by: Alexis Laferrière <alexis.laf@xymus.net>

248 files changed:
contrib/benitlux/package.ini [moved from contrib/benitlux/project.ini with 97% similarity]
contrib/brainfuck/package.ini [moved from contrib/brainfuck/project.ini with 96% similarity]
contrib/crazy_moles/Makefile
contrib/crazy_moles/package.ini [moved from contrib/crazy_moles/project.ini with 97% similarity]
contrib/friendz/Makefile
contrib/friendz/package.ini [moved from contrib/friendz/project.ini with 96% similarity]
contrib/friendz/res/raw/music.ogg [new file with mode: 0644]
contrib/github_merge.ini
contrib/github_search_for_jni/package.ini [moved from contrib/github_search_for_jni/project.ini with 97% similarity]
contrib/header_keeper/package.ini [moved from contrib/header_keeper/project.ini with 97% similarity]
contrib/inkscape_tools/package.ini [moved from contrib/inkscape_tools/project.ini with 97% similarity]
contrib/inkscape_tools/tests/packages.ini [moved from contrib/inkscape_tools/tests/projects.ini with 100% similarity]
contrib/jwrapper/Makefile
contrib/jwrapper/examples/packages.ini [moved from contrib/jwrapper/tests/projects.ini with 100% similarity]
contrib/jwrapper/package.ini [moved from contrib/jwrapper/project.ini with 97% similarity]
contrib/jwrapper/tests/packages.ini [moved from contrib/nitcc/tests/projects.ini with 100% similarity]
contrib/mnit_test/Makefile
contrib/mnit_test/package.ini [moved from contrib/mnit_test/project.ini with 97% similarity]
contrib/neo_doxygen/package.ini [moved from contrib/neo_doxygen/project.ini with 97% similarity]
contrib/nitcc/package.ini [moved from contrib/nitcc/project.ini with 96% similarity]
contrib/nitcc/tests/package.ini [moved from contrib/projects.ini with 100% similarity]
contrib/nitester/package.ini [moved from contrib/nitester/project.ini with 97% similarity]
contrib/nitiwiki/examples/nitiwiki/config.ini
contrib/nitiwiki/examples/nitiwiki/highlighter.sh [new file with mode: 0755]
contrib/nitiwiki/examples/nitiwiki/pages/block.md [new file with mode: 0644]
contrib/nitiwiki/package.ini [moved from contrib/nitiwiki/project.ini with 97% similarity]
contrib/nitiwiki/src/markdown_highlight.nit [new file with mode: 0644]
contrib/nitiwiki/src/nitiwiki.nit
contrib/nitiwiki/src/wiki_base.nit
contrib/nitiwiki/src/wiki_links.nit
contrib/nitrpg/package.ini [moved from contrib/nitrpg/project.ini with 97% similarity]
contrib/objcwrapper/package.ini [moved from contrib/objcwrapper/project.ini with 97% similarity]
contrib/online_ide/package.ini [moved from contrib/online_ide/project.ini with 97% similarity]
contrib/opportunity/package.ini [moved from contrib/opportunity/project.ini with 97% similarity]
contrib/packages.ini [moved from examples/projects.ini with 100% similarity]
contrib/pep8analysis/package.ini [moved from contrib/pep8analysis/project.ini with 97% similarity]
contrib/physical_interface_for_mpd_on_rpi/package.ini [moved from contrib/physical_interface_for_mpd_on_rpi/project.ini with 97% similarity]
contrib/refund/package.ini [moved from contrib/refund/project.ini with 97% similarity]
contrib/rss_downloader/package.ini [moved from contrib/rss_downloader/project.ini with 97% similarity]
contrib/simplan/package.ini [moved from contrib/simplan/project.ini with 96% similarity]
contrib/sort_downloads/package.ini [moved from contrib/sort_downloads/project.ini with 97% similarity]
contrib/tinks/Makefile
contrib/tinks/art/icon.svg
contrib/tinks/package.ini [moved from contrib/tinks/project.ini with 96% similarity]
contrib/tnitter/package.ini [moved from contrib/tnitter/project.ini with 96% similarity]
contrib/wiringPi/package.ini [moved from contrib/wiringPi/project.ini with 97% similarity]
examples/calculator/art/icon.svg
examples/calculator/package.ini [moved from examples/calculator/project.ini with 97% similarity]
examples/circular_list.ini
examples/clock.ini
examples/clock_more.ini
examples/draw_operation.ini
examples/extern_methods.ini
examples/fibonacci.ini
examples/hello_world.ini
examples/int_stack.ini
examples/leapfrog/package.ini [moved from examples/leapfrog/project.ini with 96% similarity]
examples/mnit_ballz/Makefile
examples/mnit_ballz/assets/images/horizontal_wall.png [new file with mode: 0644]
examples/mnit_ballz/assets/images/vertical_wall.png [new file with mode: 0644]
examples/mnit_ballz/package.ini [moved from examples/mnit_ballz/project.ini with 97% similarity]
examples/mnit_ballz/res/raw/bounce.ogg [new file with mode: 0644]
examples/mnit_ballz/res/raw/walld.wav [new file with mode: 0644]
examples/mnit_ballz/src/assets.nit [new file with mode: 0644]
examples/mnit_ballz/src/ballz_android.nit
examples/mnit_ballz/src/ballz_linux.nit [new file with mode: 0644]
examples/mnit_ballz/src/collision.nit [new file with mode: 0644]
examples/mnit_ballz/src/display.nit [new file with mode: 0644]
examples/mnit_ballz/src/game_logic.nit
examples/mnit_ballz/src/objects.nit [new file with mode: 0644]
examples/mnit_dino/Makefile
examples/mnit_dino/package.ini [moved from examples/mnit_dino/project.ini with 97% similarity]
examples/montecarlo.ini
examples/packages.ini [moved from lib/projects.ini with 100% similarity]
examples/print_arguments.ini
examples/procedural_array.ini
examples/rosettacode/package.ini [moved from examples/rosettacode/project.ini with 97% similarity]
examples/shoot/Makefile
examples/shoot/package.ini [moved from examples/shoot/project.ini with 96% similarity]
lib/a_star.ini
lib/ai/package.ini [moved from lib/ai/project.ini with 96% similarity]
lib/android/audio.nit
lib/android/native_app_glue.nit
lib/android/package.ini [moved from lib/android/project.ini with 96% similarity]
lib/android/sensors.nit
lib/app/package.ini [moved from lib/app/project.ini with 96% similarity]
lib/array_debug.ini
lib/base64.ini
lib/bcm2835/package.ini [moved from lib/bcm2835/project.ini with 96% similarity]
lib/binary/package.ini [moved from lib/binary/project.ini with 96% similarity]
lib/bitmap/package.ini [moved from lib/bitmap/project.ini with 96% similarity]
lib/bucketed_game.ini
lib/buffered_ropes.ini
lib/c.ini
lib/c.nit
lib/cartesian.ini
lib/cocoa/package.ini [moved from lib/cocoa/project.ini with 96% similarity]
lib/combinations.ini
lib/console.ini
lib/core/package.ini [moved from lib/core/project.ini with 96% similarity]
lib/counter.ini
lib/cpp.ini
lib/crypto.ini
lib/csv/package.ini [moved from lib/csv/project.ini with 96% similarity]
lib/curl/package.ini [moved from lib/curl/project.ini with 96% similarity]
lib/curses/package.ini [moved from lib/curses/project.ini with 96% similarity]
lib/date.ini
lib/deriving.ini
lib/dom/package.ini [moved from lib/dom/project.ini with 96% similarity]
lib/dummy_array.ini
lib/egl.ini
lib/egl.nit
lib/emscripten/package.ini [moved from lib/emscripten/project.ini with 97% similarity]
lib/filter_stream.ini
lib/for_abuse.ini
lib/gamnit/display.nit [new file with mode: 0644]
lib/gamnit/display_android.nit [new file with mode: 0644]
lib/gamnit/display_linux.nit [new file with mode: 0644]
lib/gamnit/egl.nit [new file with mode: 0644]
lib/gamnit/examples/triangle/Makefile [new file with mode: 0644]
lib/gamnit/examples/triangle/art/icon.svg [new file with mode: 0644]
lib/gamnit/examples/triangle/bin/.gitignore [new file with mode: 0644]
lib/gamnit/examples/triangle/package.ini [new file with mode: 0644]
lib/gamnit/examples/triangle/res/.gitignore [new file with mode: 0644]
lib/gamnit/examples/triangle/src/portable_triangle.nit [new file with mode: 0644]
lib/gamnit/examples/triangle/src/standalone_triangle.nit [new file with mode: 0644]
lib/gamnit/gamnit.nit
lib/gamnit/gamnit_android.nit [new file with mode: 0644]
lib/gamnit/package.ini [moved from lib/gamnit/project.ini with 96% similarity]
lib/geometry/package.ini [moved from lib/geometry/project.ini with 96% similarity]
lib/gettext/package.ini [moved from lib/gettext/project.ini with 96% similarity]
lib/github/package.ini [moved from lib/github/project.ini with 96% similarity]
lib/glesv2/examples/opengles2_hello_triangle.nit
lib/glesv2/glesv2.nit
lib/glesv2/package.ini [moved from lib/glesv2/project.ini with 97% similarity]
lib/graphs/package.ini [moved from lib/graphs/project.ini with 97% similarity]
lib/gtk/package.ini [moved from lib/gtk/project.ini with 96% similarity]
lib/hash_debug.ini
lib/html/package.ini [moved from lib/html/project.ini with 96% similarity]
lib/ini.ini
lib/ios/package.ini [moved from lib/ios/project.ini with 96% similarity]
lib/java/package.ini [moved from lib/java/project.ini with 96% similarity]
lib/json/package.ini [moved from lib/json/project.ini with 96% similarity]
lib/jvm.ini
lib/libevent.ini
lib/linux/linux.nit
lib/linux/package.ini [moved from lib/linux/project.ini with 96% similarity]
lib/markdown/markdown.nit
lib/markdown/package.ini [moved from lib/markdown/project.ini with 96% similarity]
lib/md5.ini
lib/meta.ini
lib/mnit/linux/linux_app.nit
lib/mnit/package.ini [moved from lib/mnit/project.ini with 96% similarity]
lib/mongodb/package.ini [moved from lib/mongodb/project.ini with 96% similarity]
lib/more_collections.ini
lib/mpd.ini
lib/mpi/package.ini [moved from lib/mpi/project.ini with 96% similarity]
lib/neo4j/package.ini [moved from lib/neo4j/project.ini with 96% similarity]
lib/nitcc_runtime.ini
lib/nitcorn/package.ini [moved from lib/nitcorn/project.ini with 96% similarity]
lib/niti_runtime.ini
lib/noise.ini
lib/opts.ini
lib/ordered_tree.ini
lib/packages.ini [moved from tests/alt/projects.ini with 100% similarity]
lib/parser_base.ini
lib/perfect_hashing.ini
lib/performance_analysis.ini
lib/pipeline.ini
lib/pnacl/package.ini [moved from lib/pnacl/project.ini with 96% similarity]
lib/poset.ini
lib/posix_ext.ini
lib/privileges/package.ini [moved from lib/privileges/project.ini with 96% similarity]
lib/progression.ini
lib/pthreads/package.ini [moved from lib/pthreads/project.ini with 97% similarity]
lib/realtime.ini
lib/ropes_debug.ini
lib/sax/package.ini [moved from lib/sax/project.ini with 97% similarity]
lib/saxophonit/package.ini [moved from lib/saxophonit/project.ini with 97% similarity]
lib/scene2d.ini
lib/sdl.ini
lib/sdl2/package.ini [moved from lib/sdl2/project.ini with 96% similarity]
lib/sendmail.ini
lib/serialization/package.ini [moved from lib/serialization/project.ini with 97% similarity]
lib/sexp.ini
lib/sha1.ini
lib/signals.ini
lib/socket/package.ini [moved from lib/socket/project.ini with 96% similarity]
lib/sqlite3/package.ini [moved from lib/sqlite3/project.ini with 96% similarity]
lib/standard.ini
lib/symbol.ini
lib/template/package.ini [moved from lib/template/project.ini with 96% similarity]
lib/test_suite.ini
lib/trees/package.ini [moved from lib/trees/project.ini with 96% similarity]
lib/websocket/package.ini [moved from lib/websocket/project.ini with 96% similarity]
lib/x11.ini
lib/xdg_basedir/package.ini [moved from lib/xdg_basedir/project.ini with 97% similarity]
misc/vim/plugin/nit.vim
share/man/nitls.md
src/compiler/compiler_ffi/compiler_ffi.nit
src/doc/console_templates/console_model.nit
src/doc/console_templates/console_templates.nit
src/doc/doc_down.nit
src/doc/doc_phases/doc_extract.nit
src/doc/doc_phases/doc_html.nit
src/doc/doc_phases/doc_readme.nit
src/doc/doc_phases/doc_structure.nit
src/doc/html_templates/html_model.nit
src/doc/html_templates/html_templates.nit
src/ffi/extra_java_files.nit
src/loader.nit
src/metrics/detect_covariance.nit
src/metrics/generate_hierarchies.nit
src/metrics/inheritance_metrics.nit
src/metrics/mclasses_metrics.nit
src/metrics/mmodules_metrics.nit
src/metrics/model_hyperdoc.nit
src/metrics/nullables_metrics.nit
src/model/mdoc.nit
src/model/mmodule.nit
src/model/model.nit
src/model/model_viz.nit
src/model/mpackage.nit [moved from src/model/mproject.nit with 65% similarity]
src/modelize/modelize_class.nit
src/modelize/modelize_property.nit
src/neo.nit
src/nitcatalog.nit
src/nitls.nit
src/nitserial.nit
src/package.ini [moved from src/project.ini with 96% similarity]
src/parser/parser_nodes.nit
src/platform/android.nit
src/test_neo.nit
src/test_test_phase.nit
src/testing/testing_doc.nit
src/toolcontext.nit
tests/alt/packages.ini [moved from tests/project1/project.ini with 100% similarity]
tests/nitiwiki.args
tests/packages.ini [moved from tests/project1/project2/project.ini with 100% similarity]
tests/project1/package.ini [moved from tests/projects.ini with 100% similarity]
tests/project1/project2/package.ini [new file with mode: 0644]
tests/sav/Darwin/todo
tests/sav/ballz_linux.res [new file with mode: 0644]
tests/sav/nitdoc_args4.res
tests/sav/nitmetrics_args1.res
tests/sav/nitx_args3.res
tests/sav/test_neo_args1.res
tests/sav/test_test_phase_args1.res

similarity index 97%
rename from contrib/benitlux/project.ini
rename to contrib/benitlux/package.ini
index a9eff3b..53acc9d 100644 (file)
@@ -1,4 +1,4 @@
-[project]
+[package]
 name=benitlux
 tags=network
 maintainer=Alexis Laferrière <alexis.laf@xymus.net>
similarity index 96%
rename from contrib/brainfuck/project.ini
rename to contrib/brainfuck/package.ini
index 440c8d5..59c69b6 100644 (file)
@@ -1,4 +1,4 @@
-[project]
+[package]
 name=brainfuck
 tags=language
 maintainer=Lucas Bajolet <r4pass@hotmail.com>
index 3fc90f7..049e851 100644 (file)
@@ -4,11 +4,14 @@ bin/moles: $(shell ../../bin/nitls -M src/moles_linux.nit) assets/images/drawing
        mkdir -p bin
        ../../bin/nitc -o bin/moles src/moles_linux.nit
 
+android: bin/moles.apk
 bin/moles.apk: android-icons $(shell ../../bin/nitls -M src/moles_android.nit) assets/images/drawing.png
        mkdir -p bin
        ../../bin/nitc -o bin/moles.apk src/moles_android.nit
 
-android: bin/moles.apk
+android-release: android-icons $(shell ../../bin/nitls -M src/moles_android.nit) assets/images/drawing.png
+       mkdir -p bin
+       ../../bin/nitc -o bin/moles.apk src/moles_android.nit --release
 
 ../inkscape_tools/bin/svg_to_icons:
        $(MAKE) -C ../inkscape_tools
similarity index 97%
rename from contrib/crazy_moles/project.ini
rename to contrib/crazy_moles/package.ini
index 0369bd7..42eae16 100644 (file)
@@ -1,4 +1,4 @@
-[project]
+[package]
 name=crazy_moles
 tags=game
 maintainer=Alexis Laferrière <alexis.laf@xymus.net>
index f236a1d..0cedb4c 100644 (file)
@@ -4,11 +4,18 @@ linux:
        mkdir -p bin
        ../../bin/nitc -o bin/friendz src/friendz_linux.nit
 
-android:
-       mkdir -p bin res
-       ../inkscape_tools/bin/svg_to_icons art/icon.svg --android --out res/
+android: res/drawable-hdpi/icon.png
+       mkdir -p bin
        ../../bin/nitc -o bin/friendz.apk src/friendz_android.nit
 
+android-release: res/drawable-hdpi/icon.png
+       mkdir -p bin
+       ../../bin/nitc -o bin/friendz.apk src/friendz_android.nit --release
+
+res/drawable-hdpi/icon.png: art/icon.svg
+       mkdir -p res
+       ../inkscape_tools/bin/svg_to_icons art/icon.svg --android --out res/
+
 doc:
        mkdir -p doc
        ../../bin/nitdoc -d doc/ src/friendz.nit src/friendz_linux.nit
similarity index 96%
rename from contrib/friendz/project.ini
rename to contrib/friendz/package.ini
index dfb04ba..b1398f2 100644 (file)
@@ -1,4 +1,4 @@
-[project]
+[package]
 name=friendz
 tags=game
 maintainer=Jean Privat <jean@pryen.org>
diff --git a/contrib/friendz/res/raw/music.ogg b/contrib/friendz/res/raw/music.ogg
new file mode 100644 (file)
index 0000000..8dcfa3b
Binary files /dev/null and b/contrib/friendz/res/raw/music.ogg differ
index 0615986..8f206bf 100644 (file)
@@ -1,4 +1,4 @@
-[project]
+[package]
 name=github_merge
 tags=cli
 maintainer=Jean Privat <jean@pryen.org>
similarity index 97%
rename from contrib/github_search_for_jni/project.ini
rename to contrib/github_search_for_jni/package.ini
index 5b5c36b..0196d6f 100644 (file)
@@ -1,4 +1,4 @@
-[project]
+[package]
 name=github_search_for_jni
 tags=cli
 maintainer=Alexis Laferrière <alexis.laf@xymus.net>
similarity index 97%
rename from contrib/header_keeper/project.ini
rename to contrib/header_keeper/package.ini
index f2783c0..549bbb6 100644 (file)
@@ -1,4 +1,4 @@
-[project]
+[package]
 name=header_keeper
 tags=devel,cli
 maintainer=Alexis Laferrière <alexis.laf@xymus.net>
similarity index 97%
rename from contrib/inkscape_tools/project.ini
rename to contrib/inkscape_tools/package.ini
index d8cc3c4..f553cd5 100644 (file)
@@ -1,4 +1,4 @@
-[project]
+[package]
 name=inkscape_tools
 tags=devel,cli
 maintainer=Alexis Laferrière <alexis.laf@xymus.net>
index 34faa7a..7c41505 100644 (file)
@@ -10,7 +10,7 @@ src/javap_test_parser.nit: ../nitcc/src/nitcc grammar/javap.sablecc
        mv javap* gen/
 
 src/serial.nit: $(shell ../../bin/nitls -M src/jwrapper.nit)
-       ../../bin/nitserial -o src/serial.nit -d project src/jwrapper.nit
+       ../../bin/nitserial -o src/serial.nit -d package src/jwrapper.nit
 
 bin/jwrapper: src/javap_test_parser.nit src/serial.nit $(shell ../../bin/nitls -M src/jwrapper.nit) ../../bin/nitc
        mkdir -p bin
similarity index 97%
rename from contrib/jwrapper/project.ini
rename to contrib/jwrapper/package.ini
index b43cd0e..adaed16 100644 (file)
@@ -1,4 +1,4 @@
-[project]
+[package]
 name=jwrapper
 tags=java,devel,cli
 maintainer=Alexis Laferrière <alexis.laf@xymus.net>
index 73ed663..a198c27 100644 (file)
@@ -9,5 +9,10 @@ android:
        ../../bin/nitc -o bin/complete.apk src/complete_simple_android.nit --semi-global
        ../../bin/nitc -o bin/minimal.apk src/simple_android.nit --semi-global
 
+android-release:
+       mkdir -p bin
+       ../../bin/nitc -o bin/complete.apk src/complete_simple_android.nit --semi-global --release
+       ../../bin/nitc -o bin/minimal.apk src/simple_android.nit --semi-global --release
+
 clean:
        rm -rf bin
similarity index 97%
rename from contrib/mnit_test/project.ini
rename to contrib/mnit_test/package.ini
index e595abe..29856ff 100644 (file)
@@ -1,4 +1,4 @@
-[project]
+[package]
 name=mnit_test
 tags=
 maintainer=Alexis Laferrière <alexis.laf@xymus.net>
similarity index 97%
rename from contrib/neo_doxygen/project.ini
rename to contrib/neo_doxygen/package.ini
index 9f5ceaf..7ca5877 100644 (file)
@@ -1,4 +1,4 @@
-[project]
+[package]
 name=neo_doxygen
 tags=devel,cli
 maintainer=Jean-Christophe Beaupré <jcbrinfo@users.noreply.github.com>
similarity index 96%
rename from contrib/nitcc/project.ini
rename to contrib/nitcc/package.ini
index bdc1258..900f9d7 100644 (file)
@@ -1,4 +1,4 @@
-[project]
+[package]
 name=nitcc
 tags=devel,cli
 maintainer=Jean Privat <jean@pryen.org>
similarity index 97%
rename from contrib/nitester/project.ini
rename to contrib/nitester/package.ini
index 10897ac..8c73e01 100644 (file)
@@ -1,4 +1,4 @@
-[project]
+[package]
 name=nitester
 tags=devel,cli
 maintainer=Alexis Laferrière <alexis.laf@xymus.net>
index 315462d..bc96f38 100644 (file)
@@ -3,3 +3,4 @@ wiki.desc=proudly powered by nit
 wiki.logo=assets/logo.png
 wiki.root_dir=.
 wiki.rsync_dir=moz-code.org:nitiwiki/
+wiki.highlighter=./highlighter.sh "$1"
diff --git a/contrib/nitiwiki/examples/nitiwiki/highlighter.sh b/contrib/nitiwiki/examples/nitiwiki/highlighter.sh
new file mode 100755 (executable)
index 0000000..57aaf45
--- /dev/null
@@ -0,0 +1,36 @@
+#!/bin/sh
+
+# 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.
+
+# Example of an external highlighter that dispatch on various command
+# according to the argument
+
+# meta is the argument
+meta=$1
+
+# raw is a synonym of txt
+test "$meta" = "raw" && meta=txt
+
+# if `pandoc` then process through the `pandoc` command.
+if test "$meta" = "pandoc"; then
+       exec pandoc -t html
+fi
+
+# Else, try `highlight`
+highlight --fragment -S "$meta" --inline-css --enclose-pre ||
+       # Or `source-highlight`
+       source-highlight -s "$meta"
+out=$?
+exit $out
diff --git a/contrib/nitiwiki/examples/nitiwiki/pages/block.md b/contrib/nitiwiki/examples/nitiwiki/pages/block.md
new file mode 100644 (file)
index 0000000..d0daaba
--- /dev/null
@@ -0,0 +1,36 @@
+# Test of code highlighting
+
+A basic block.
+
+    print(["hello", "world"].join(", "))
+
+A fenced block.
+
+~~~
+print(["hello", "world"].join(", "))
+~~~
+
+A fenced block with metainfo, so it can be highlighted with an external tool.
+
+~~~html
+<table class="hello"><tr>
+<td>Hello</td>
+<td>World</td>
+</tr></table>
+~~~
+
+A special block where the rendering is delegated to pandoc.
+For instance, to render tables.
+
+~~~pandoc
+what     how
+------ -----
+hello     10
+world   9001
+~~~
+
+This try some exploit
+~~~raw'"; echo pwned >&2 #
+Hello<br/>
+World
+~~~
similarity index 97%
rename from contrib/nitiwiki/project.ini
rename to contrib/nitiwiki/package.ini
index 0ebf3a8..83efead 100644 (file)
@@ -1,4 +1,4 @@
-[project]
+[package]
 name=nitiwiki
 tags=web,cli
 maintainer=Alexandre Terrasa <alexandre@moz-code.org>
diff --git a/contrib/nitiwiki/src/markdown_highlight.nit b/contrib/nitiwiki/src/markdown_highlight.nit
new file mode 100644 (file)
index 0000000..08751b0
--- /dev/null
@@ -0,0 +1,99 @@
+# 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.
+
+# Extends the wiki with an external highlighter (or any processor) for code blocks
+module markdown_highlight
+import wiki_links
+
+redef class WikiConfig
+       # External highlighter command called to process block code.
+       #
+       # * key: `wiki.highlighter`
+       # * default: empty string, that means no external highlighter
+       # * example: `highlight --fragment -S "$1" --inline-css --enclose-pre`
+       #
+       # The external highlighter is a shell command invoked with `sh -c`.
+       # The meta information of the fence is passed as `$1`.
+       # *Important*: `$1` is given as is, thus is tainted. You SHOULD protect it with quotes in the command.
+       #
+       # By default, the highlighter is only called on fenced block code with a meta information.
+       # See `wiki.highlighter.default` to force the invocation of the highlighter on any code block.
+       #
+       # The output of the command will be inserted as is in the generated document.
+       # Therefore it is expected that the command returns a valid, complete and balanced HTML fragment.
+       # If the highlighter returns nothing (empty output), the internal rendering is used as a fall-back
+       # (as if the option was not set).
+       #
+       # Advanced usages can invoke a custom shell script instead of a standard command to
+       # check the argument, filter it, dispatch to various advanced commands, implement ad-hoc behaviors, etc.
+       var highlighter: String is lazy do
+               return value_or_default("wiki.highlighter", "")
+       end
+
+       # Default meta (i.e. language) to use to call the external highlighter.
+       #
+       # * key: `wiki.highlighter.default`
+       # * default: empty string, that means no default meta information.
+       # * example: `nit`
+       #
+       # When set, this configuration forces the external highlighter (see `wiki.highlighter`)
+       # to be called also on basic code block (with the indentation) and plain fenced code
+       # blocks (without meta information).
+       #
+       # The value is used as the `$1` argument of the configured highlighter command.
+       #
+       # Note: has no effect if `wiki.highlighter` is not set.
+       var highlighter_default: String is lazy do
+               return value_or_default("wiki.highlighter.default", "")
+       end
+end
+
+redef class NitiwikiDecorator
+       # Extends special cases for meta in fences
+       redef fun add_code(v, block) do
+               var highlighter = wiki.config.highlighter
+
+               # No highlighter, then defaults
+               if highlighter.is_empty then
+                       super
+                       return
+               end
+
+               var code = block.raw_content
+               var meta = block.meta or else wiki.config.highlighter_default
+
+               # No meta nor forced meta, then defaults
+               if meta.is_empty then
+                       super
+                       return
+               end
+
+               # Execute the command
+               wiki.message("Executing `{highlighter}` `{meta}` (in {context.src_path.as(not null)})", 2)
+               var proc = new ProcessDuplex("sh", "-c", highlighter, "", meta.to_s)
+               var res = proc.write_and_read(code)
+               if proc.status != 0 then
+                       wiki.message("Warning: `{highlighter}` `{meta}` returned {proc.status} (in {context.src_path.as(not null)})", 0)
+               end
+
+               # Check the result
+               if res.is_empty then
+                       # No result, then defaults
+                       wiki.message("  `{highlighter}` produced nothing, process internally instead (in {context.src_path.as(not null)})", 2)
+                       super
+                       return
+               end
+               v.add(res)
+       end
+end
index 71ab129..c5c6ebe 100644 (file)
@@ -16,6 +16,7 @@
 module nitiwiki
 
 import wiki_html
+import markdown_highlight
 
 # Locate nit directory
 private fun compute_nit_dir(opt_nit_dir: OptionString): String do
index 5f093a0..70cf35f 100644 (file)
@@ -615,7 +615,7 @@ class WikiConfig
        super ConfigTree
 
        # Returns the config value at `key` or return `default` if no key was found.
-       private fun value_or_default(key: String, default: String): String do
+       protected fun value_or_default(key: String, default: String): String do
                return self[key] or else default
        end
 
index 340ec74..efb9f78 100644 (file)
@@ -214,7 +214,8 @@ class NitiwikiMdProcessor
        end
 end
 
-private class NitiwikiDecorator
+# The decorator associated to `MarkdownProcessor`.
+class NitiwikiDecorator
        super HTMLDecorator
 
        # Wiki used to resolve links.
similarity index 97%
rename from contrib/nitrpg/project.ini
rename to contrib/nitrpg/package.ini
index e697771..125e96c 100644 (file)
@@ -1,4 +1,4 @@
-[project]
+[package]
 name=nitrpg
 tags=devel,web,cli
 maintainer=Alexandre Terrasa <alexandre@moz-code.org>
similarity index 97%
rename from contrib/objcwrapper/project.ini
rename to contrib/objcwrapper/package.ini
index 4359608..e2ef8d3 100644 (file)
@@ -1,4 +1,4 @@
-[project]
+[package]
 name=objcwrapper
 tags=devel,cli
 maintainer=Alexis Laferrière <alexis.laf@xymus.net>
similarity index 97%
rename from contrib/online_ide/project.ini
rename to contrib/online_ide/package.ini
index 2729576..ee1afbd 100644 (file)
@@ -1,4 +1,4 @@
-[project]
+[package]
 name=online_ide
 tags=devel,web
 maintainer=Johan Kayser <johan.kayser@viacesi.fr>
similarity index 97%
rename from contrib/opportunity/project.ini
rename to contrib/opportunity/package.ini
index f19f154..9e3dae9 100644 (file)
@@ -1,4 +1,4 @@
-[project]
+[package]
 name=opportunity
 tags=web
 maintainer=Lucas Bajolet <r4pass@hotmail.com>
similarity index 100%
rename from examples/projects.ini
rename to contrib/packages.ini
similarity index 97%
rename from contrib/pep8analysis/project.ini
rename to contrib/pep8analysis/package.ini
index 9a50402..5f5fba5 100644 (file)
@@ -1,4 +1,4 @@
-[project]
+[package]
 name=pep8analysis
 tags=educ,web,cli
 maintainer=Alexis Laferrière <alexis.laf@xymus.net>
@@ -1,4 +1,4 @@
-[project]
+[package]
 name=physical_interface_for_mpd_on_rpi
 tags=embedded,cli
 maintainer=Alexis Laferrière <alexis.laf@xymus.net>
similarity index 97%
rename from contrib/refund/project.ini
rename to contrib/refund/package.ini
index 6e7591b..9332fd0 100644 (file)
@@ -1,4 +1,4 @@
-[project]
+[package]
 name=refund
 tags=example,cli
 maintainer=Alexandre Terrasa <alexandre@moz-code.org>
similarity index 97%
rename from contrib/rss_downloader/project.ini
rename to contrib/rss_downloader/package.ini
index 162816a..2dee4f0 100644 (file)
@@ -1,4 +1,4 @@
-[project]
+[package]
 name=rss_downloader
 tags=network,cli
 maintainer=Alexis Laferrière <alexis.laf@xymus.net>
similarity index 96%
rename from contrib/simplan/project.ini
rename to contrib/simplan/package.ini
index bab2310..1f4e49a 100644 (file)
@@ -1,4 +1,4 @@
-[project]
+[package]
 name=simplan
 tags=ai,example,cli
 maintainer=Jean Privat <jean@pryen.org>
similarity index 97%
rename from contrib/sort_downloads/project.ini
rename to contrib/sort_downloads/package.ini
index acd2fe2..2f75eb3 100644 (file)
@@ -1,4 +1,4 @@
-[project]
+[package]
 name=sort_downloads
 tags=cli
 maintainer=Alexis Laferrière <alexis.laf@xymus.net>
index b22453a..ee13360 100644 (file)
@@ -32,9 +32,12 @@ src/server/server_serialize.nit: $(shell ../../bin/nitls -M src/server/dedicated
        ../../bin/nitserial -o src/server/server_serialize.nit src/server/dedicated.nit
 
 # Android
+android: bin/tinks.apk
 bin/tinks.apk: assets/images/drawing.png src/client/client_serialize.nit res/drawable-ldpi/icon.png $(shell ../../bin/nitls -M src/client/android_client.nit)
-       ../../bin/nitc -o bin/tinks.apk src/client/android_client.nit -m src/client/client_serialize.nit --compile-dir nit_compile
-       adb install -r bin/tinks.apk
+       ../../bin/nitc -o bin/tinks.apk src/client/android_client.nit -m src/client/client_serialize.nit
+
+android-release: assets/images/drawing.png src/client/client_serialize.nit res/drawable-ldpi/icon.png $(shell ../../bin/nitls -M src/client/android_client.nit)
+       ../../bin/nitc -o bin/tinks.apk src/client/android_client.nit -m src/client/client_serialize.nit --release
 
 res/drawable-ldpi/icon.png: art/icon.svg
        ../inkscape_tools/bin/svg_to_icons art/icon.svg --android --out res/
index 20a590d..32229e4 100644 (file)
      inkscape:pageopacity="0.0"
      inkscape:pageshadow="2"
      inkscape:zoom="1.979899"
-     inkscape:cx="107.98668"
-     inkscape:cy="65.759563"
+     inkscape:cx="357.89925"
+     inkscape:cy="19.247995"
      inkscape:document-units="px"
      inkscape:current-layer="0splash"
      showgrid="false"
          transform="matrix(0.9571749,0,0,0.9571749,14.241487,126.08446)">
         <path
            style="font-size:52.50814056px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:-1px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Armalite Rifle;-inkscape-font-specification:Armalite Rifle"
-           d="m 258.625,595.8125 c -4.89966,1.4313 -12.56953,-1.70866 -15.1875,4.5625 -0.4775,5.90634 -3.5509,14.50575 2.71875,18.6875 2.28891,1.18746 5.12,1.54986 7.5625,0.59375 0.52227,3.72431 1.0541,7.99473 -2.03125,10.59375 -3.51238,6.69348 3.86364,14.87896 10.90625,12.96875 6.54546,1.2404 16.20527,-0.87285 16.34375,-9 1.15076,-4.65522 -4.58661,-6.69297 -3.46875,-11.1875 -0.95739,-2.94159 3.31489,-1.69978 4.46875,-3.78125 5.83868,-2.11249 5.55685,-9.07334 5.53125,-14.34375 1.81324,-6.47371 -5.8435,-9.85183 -11.15625,-8.5625 -4.34595,0.15294 -9.06169,-1.83389 -13.21875,-0.125 0.0516,-2.21144 -1.36209,-0.68823 -2.46875,-0.40625 z"
+           d="m 258.625,595.8125 c -4.89966,1.4313 -12.56953,-1.70866 -15.1875,4.5625 -0.4775,5.90634 -3.5509,14.50575 2.71875,18.6875 2.28891,1.18746 5.12,1.54986 7.5625,0.59375 0.52227,3.72431 1.0541,7.99473 -2.03125,10.59375 -3.51238,6.69348 3.86364,14.87896 10.90625,12.96875 6.54546,1.2404 16.20527,-0.87285 16.34375,-9 1.15076,-4.65522 0.20769,-5.09487 1.32555,-9.5894 -0.95739,-2.94159 -1.47941,-3.29788 -0.32555,-5.37935 5.83868,-2.11249 5.55685,-9.07334 5.53125,-14.34375 1.81324,-6.47371 -5.8435,-9.85183 -11.15625,-8.5625 -4.34595,0.15294 -9.06169,-1.83389 -13.21875,-0.125 0.0516,-2.21144 -1.36209,-0.68823 -2.46875,-0.40625 z"
            id="path3211"
-           inkscape:connector-curvature="0" />
+           inkscape:connector-curvature="0"
+           sodipodi:nodetypes="ccccccccccccc" />
         <path
            style="font-size:52.50814056px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:-1px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Armalite Rifle;-inkscape-font-specification:Armalite Rifle"
            d="m 286.25,592.6875 c -2.39783,0.63195 -3.74457,2.90332 -6.59375,2.8125 -5.4632,2.29227 -6.35616,10.35289 -2.0625,14.25 -0.60542,4.15669 0.70607,8.39731 0.4375,12.3125 -0.0599,3.57375 -1.98208,6.31549 -3.3125,9.34375 -1.62554,5.38708 2.55698,12.80186 8.96875,10.96875 6.47834,0.22337 16.30714,2.49861 19.125,-5.53125 1.23942,-3.73894 -0.38135,-7.90712 -3.59375,-10.09375 0.3082,-5.37065 -0.71586,-11.3191 0.59375,-16.375 6.74005,-4.69817 1.76294,-18.17585 -6.625,-15.0625 -2.79844,0.69065 -4.06188,-3.31293 -6.9375,-2.625 z"
            inkscape:connector-curvature="0" />
         <path
            style="font-size:52.50814056px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:-1px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Armalite Rifle;-inkscape-font-specification:Armalite Rifle"
-           d="m 362.71875,595.53125 c -4.88629,0.1191 -10.06204,0.70685 -14.78125,0.75 -5.47787,-0.76679 -11.36437,-0.40783 -16.78125,-0.15625 -5.17104,2.08849 -5.75771,9.90066 -1.65625,13.3125 -0.73815,5.29915 0.55713,11.35287 -0.28125,16.21875 -1.57391,2.43976 0.0174,5.43494 -1.9375,7.65625 -1.21338,8.01052 8.60308,12.27891 15.15625,10.1875 4.10866,1.15111 8.03361,-0.96492 11.90625,0.75 4.70244,-0.0919 9.41322,-0.76127 13.9375,-1.21875 6.34357,-2.47232 7.27867,-12.62071 1.1875,-15.90625 -2.84504,-3.85906 -6.71699,-8.25024 -7.5,-12.8125 2.57537,-4.33547 10.38664,-3.74912 10.125,-10.0625 0.19504,-4.87459 -4.47645,-9.43549 -9.375,-8.71875 z"
+           d="m 362.71875,595.53125 c -4.88629,0.1191 -10.06204,0.70685 -14.78125,0.75 -5.47787,-0.76679 -11.36437,-0.40783 -16.78125,-0.15625 -5.17104,2.08849 -5.75771,9.90066 -1.65625,13.3125 -0.73815,5.29915 0.55713,11.35287 -0.28125,16.21875 -1.57391,2.43976 0.0174,5.43494 -1.9375,7.65625 -1.21338,8.01052 8.60308,12.27891 15.15625,10.1875 4.10866,1.15111 8.03361,-0.96492 11.90625,0.75 4.70244,-0.0919 9.41322,-0.76127 13.9375,-1.21875 6.34357,-2.47232 7.27867,-12.62071 1.1875,-15.90625 -2.84504,-3.85906 -3.69836,-8.25024 -4.48137,-12.8125 2.57537,-4.33547 7.36801,-3.74912 7.10637,-10.0625 0.19504,-4.87459 -4.47645,-9.43549 -9.375,-8.71875 z"
            id="path3217"
-           inkscape:connector-curvature="0" />
+           inkscape:connector-curvature="0"
+           sodipodi:nodetypes="ccccccccccccc" />
         <path
            style="font-size:52.50814056px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:-1px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Armalite Rifle;-inkscape-font-specification:Armalite Rifle"
            d="m 387.9375,595.15625 c -4.67722,2.02978 -9.78906,-1.62403 -14.46875,1.25 -9.65979,4.02935 -13.06716,17.5954 -7.09375,25.71875 -5.60204,3.65765 -3.86108,11.71823 -2.5625,17.15625 1.89135,4.23664 7.4795,4.74734 11.125,3.125 3.94271,1.07416 7.9082,-0.0824 11.78125,1.1875 12.90654,0.16282 22.05847,-17.35307 13.34375,-27.46875 4.21701,-4.46396 3.58479,-12.34862 1.53125,-17.90625 -3.12179,-4.23683 -8.89538,-1.69513 -13.1875,-3.09375 l -0.46875,0.0312 z"
            inkscape:connector-curvature="0" />
         <path
            style="font-size:52.50814056px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:-1px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Armalite Rifle;-inkscape-font-specification:Armalite Rifle"
-           d="m 413.09375,593.625 c -5.989,0.79809 -12.31873,3.77439 -13.59375,10.28125 -2.37552,6.92367 2.58427,13.98287 3.0625,20.28125 -6.66505,6.69348 -1.32209,20.82556 8.75,19.25 7.10297,0.39661 12.84047,-7.75209 9.8125,-14.21875 0.3156,-2.89071 -3.70654,-4.76237 -1.46875,-7.53125 2.44848,-7.39695 6.24638,-18.36454 -1.53125,-23.75 -0.23875,-2.6484 -2.19852,-4.85675 -5.03125,-4.3125 z"
+           d="m 413.09375,593.625 c -5.989,0.79809 -12.31873,3.77439 -13.59375,10.28125 -2.77433,6.83505 1.00514,13.63195 3.0625,20.28125 -6.66505,6.69348 -1.32209,20.82556 8.75,19.25 7.10297,0.39661 12.84047,-7.75209 9.8125,-14.21875 0.3156,-2.89071 -3.70654,-4.76237 -1.46875,-7.53125 2.44848,-7.39695 6.24638,-18.36454 -1.53125,-23.75 -0.23875,-2.6484 -2.19852,-4.85675 -5.03125,-4.3125 z"
            id="path3221"
-           inkscape:connector-curvature="0" />
+           inkscape:connector-curvature="0"
+           sodipodi:nodetypes="cccccccc" />
       </g>
       <g
          style="stroke:#000000;stroke-width:3.85294461;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
            x="251.05626"
            id="tspan2996"
            sodipodi:role="line">TINKS!</tspan></text>
+      <text
+         xml:space="preserve"
+         style="font-size:50.25947571px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#e6e6e6;fill-opacity:1;stroke:none;font-family:Sans"
+         x="251.05626"
+         y="809.98505"
+         id="text3032"
+         sodipodi:linespacing="125%"><tspan
+           sodipodi:role="line"
+           id="tspan3034"
+           x="251.05626"
+           y="809.98505"
+           style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;letter-spacing:-0.9571749px;fill:#e6e6e6;fill-opacity:1;font-family:Armalite Rifle;-inkscape-font-specification:Armalite Rifle">TINKS!</tspan></text>
     </g>
   </g>
 </svg>
similarity index 96%
rename from contrib/tinks/project.ini
rename to contrib/tinks/package.ini
index ec34d3a..dc04026 100644 (file)
@@ -1,4 +1,4 @@
-[project]
+[package]
 name=tinks
 tags=game
 maintainer=Alexis Laferrière <alexis.laf@xymus.net>
similarity index 96%
rename from contrib/tnitter/project.ini
rename to contrib/tnitter/package.ini
index d589d1f..42a426c 100644 (file)
@@ -1,4 +1,4 @@
-[project]
+[package]
 name=tnitter
 tags=web
 maintainer=Alexis Laferrière <alexis.laf@xymus.net>
similarity index 97%
rename from contrib/wiringPi/project.ini
rename to contrib/wiringPi/package.ini
index b4c8c48..8afbf8b 100644 (file)
@@ -1,4 +1,4 @@
-[project]
+[package]
 name=wiringPi
 tags=embedded,wrapper
 maintainer=Alexandre Terrasa <alexandre@moz-code.org>
index ccd533c..618dc3d 100644 (file)
@@ -24,9 +24,9 @@
      borderopacity="1.0"
      inkscape:pageopacity="0.0"
      inkscape:pageshadow="2"
-     inkscape:zoom="0.9899495"
-     inkscape:cx="58.64005"
-     inkscape:cy="380.00465"
+     inkscape:zoom="1.4"
+     inkscape:cx="160.56125"
+     inkscape:cy="282.40083"
      inkscape:document-units="px"
      inkscape:current-layer="layer1"
      showgrid="false"
        width="211.42856"
        id="rect2995"
        style="fill:#cccccc;fill-opacity:1;stroke:#000000;stroke-opacity:1;stroke-width:5;stroke-miterlimit:4;stroke-dasharray:none" />
-    <text
-       xml:space="preserve"
+    <g
        style="font-size:269.1137085px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Droid Sans;-inkscape-font-specification:Droid Sans"
-       x="299.74573"
-       y="770.06946"
-       id="text2997"
-       sodipodi:linespacing="125%"><tspan
-         sodipodi:role="line"
-         id="tspan2999"
-         x="299.74573"
-         y="770.06946">+</tspan></text>
+       id="text2997">
+      <path
+         d="m 364.00188,685.0516 -50.85303,0 0,-19.71047 50.85303,0 0,-51.11584 19.71048,0 0,51.11584 50.85303,0 0,19.71047 -50.85303,0 0,50.59023 -19.71048,0 0,-50.59023"
+         style=""
+         id="path2996" />
+    </g>
     <path
        inkscape:connector-curvature="0"
        id="path3018"
        id="path2997"
        style="font-size:202.30386353px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Droid Sans;-inkscape-font-specification:Droid Sans"
        d="m 179.68975,735.88154 c -1e-5,-2.50244 0.32926,-4.60977 0.98782,-6.32199 0.65852,-1.77805 1.54755,-3.19391 2.66709,-4.2476 1.1195,-1.11949 2.43658,-1.90974 3.95125,-2.37074 1.51462,-0.52681 3.16097,-0.79023 4.93905,-0.79025 1.71218,2e-5 3.32561,0.26344 4.84028,0.79025 1.58047,0.461 2.93048,1.25125 4.05003,2.37074 1.11948,1.05369 2.00851,2.46955 2.66709,4.2476 0.65851,1.71222 0.98778,3.81955 0.98782,6.32199 -4e-5,2.43661 -0.32931,4.54394 -0.98782,6.322 -0.65858,1.71221 -1.54761,3.12807 -2.66709,4.24759 -1.11955,1.11952 -2.46956,1.94269 -4.05003,2.46953 -1.51467,0.52683 -3.1281,0.79024 -4.84028,0.79025 -1.77808,-10e-6 -3.42443,-0.26342 -4.93905,-0.79025 -1.51467,-0.52684 -2.83175,-1.35001 -3.95125,-2.46953 -1.11954,-1.11952 -2.00857,-2.53538 -2.66709,-4.24759 -0.65856,-1.77806 -0.98783,-3.88539 -0.98782,-6.322" />
-    <text
-       xml:space="preserve"
+    <g
        style="font-size:269.1137085px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Droid Sans;-inkscape-font-specification:Droid Sans"
-       x="64.031456"
-       y="1006.8839"
-       id="text3013"
-       sodipodi:linespacing="125%"><tspan
-         sodipodi:role="line"
-         id="tspan3015"
-         x="64.031456"
-         y="1006.8839">=</tspan></text>
+       id="text3013">
+      <path
+         d="m 77.43458,894.9284 0,-19.57907 121.41654,0 0,19.57907 -121.41654,0 m 0,53.87531 0,-19.71048 121.41654,0 0,19.71048 -121.41654,0"
+         style=""
+         id="path2999" />
+    </g>
   </g>
 </svg>
similarity index 97%
rename from examples/calculator/project.ini
rename to examples/calculator/package.ini
index 28b52fb..adeb755 100644 (file)
@@ -1,4 +1,4 @@
-[project]
+[package]
 name=calculator
 tags=example
 maintainer=Alexis Laferrière <alexis.laf@xymus.net>
index c5ac8ce..0cffc3a 100644 (file)
@@ -1,4 +1,4 @@
-[project]
+[package]
 name=circular_list
 tags=algo,example
 maintainer=Jean Privat <jean@pryen.org>
index 4edb9d3..5438b51 100644 (file)
@@ -1,4 +1,4 @@
-[project]
+[package]
 name=clock
 tags=example
 maintainer=Jean Privat <jean@pryen.org>
index 669c71d..d57de66 100644 (file)
@@ -1,4 +1,4 @@
-[project]
+[package]
 name=clock_more
 tags=example
 maintainer=Jean Privat <jean@pryen.org>
index 31772ef..189e88d 100644 (file)
@@ -1,4 +1,4 @@
-[project]
+[package]
 name=draw_operation
 tags=
 maintainer=Alexis Laferrière <alexis.laf@xymus.net>
index 460e02b..bba626e 100644 (file)
@@ -1,4 +1,4 @@
-[project]
+[package]
 name=extern_methods
 tags=wrapper,example
 maintainer=Alexis Laferrière <alexis.laf@xymus.net>
index 303d9ed..4508f69 100644 (file)
@@ -1,4 +1,4 @@
-[project]
+[package]
 name=fibonacci
 tags=example
 maintainer=Jean Privat <jean@pryen.org>
index d666cf2..72f0fb6 100644 (file)
@@ -1,4 +1,4 @@
-[project]
+[package]
 name=hello_world
 tags=example
 maintainer=Jean Privat <jean@pryen.org>
index 7b8b9fc..6248cbe 100644 (file)
@@ -1,4 +1,4 @@
-[project]
+[package]
 name=int_stack
 tags=example
 maintainer=Jean Privat <jean@pryen.org>
similarity index 96%
rename from examples/leapfrog/project.ini
rename to examples/leapfrog/package.ini
index 56c05d5..eefa485 100644 (file)
@@ -1,4 +1,4 @@
-[project]
+[package]
 name=leapfrog
 tags=game,terminal
 maintainer=Jean Privat <jean@pryen.org>
index 337c69a..b9a0dfc 100644 (file)
@@ -1,4 +1,4 @@
-default: android
+default: linux
 
 ../../contrib/inkscape_tools/bin/svg_to_icons:
        $(MAKE) -C ../../contrib/inkscape_tools
@@ -7,6 +7,14 @@ android: icon
        mkdir -p bin
        ../../bin/nitc -o bin/ballz.apk src/ballz_android.nit
 
+android-release: icon
+       mkdir -p bin
+       ../../bin/nitc -o bin/ballz.apk src/ballz_android.nit --release
+
+linux:
+       mkdir -p bin
+       ../../bin/nitc -o bin/ballz src/ballz_linux.nit
+
 icon: ../../contrib/inkscape_tools/bin/svg_to_icons
        mkdir -p res
        ../../contrib/inkscape_tools/bin/svg_to_icons art/ball.svg --android --out res/
diff --git a/examples/mnit_ballz/assets/images/horizontal_wall.png b/examples/mnit_ballz/assets/images/horizontal_wall.png
new file mode 100644 (file)
index 0000000..7ba6c68
Binary files /dev/null and b/examples/mnit_ballz/assets/images/horizontal_wall.png differ
diff --git a/examples/mnit_ballz/assets/images/vertical_wall.png b/examples/mnit_ballz/assets/images/vertical_wall.png
new file mode 100644 (file)
index 0000000..da42302
Binary files /dev/null and b/examples/mnit_ballz/assets/images/vertical_wall.png differ
similarity index 97%
rename from examples/mnit_ballz/project.ini
rename to examples/mnit_ballz/package.ini
index 7a252c1..7314aeb 100644 (file)
@@ -1,4 +1,4 @@
-[project]
+[package]
 name=mnit_ballz
 tags=game
 maintainer=Romain Chanoir <romain.chanoir@viacesi.fr>
diff --git a/examples/mnit_ballz/res/raw/bounce.ogg b/examples/mnit_ballz/res/raw/bounce.ogg
new file mode 100644 (file)
index 0000000..bcd66dd
Binary files /dev/null and b/examples/mnit_ballz/res/raw/bounce.ogg differ
diff --git a/examples/mnit_ballz/res/raw/walld.wav b/examples/mnit_ballz/res/raw/walld.wav
new file mode 100644 (file)
index 0000000..f61d065
Binary files /dev/null and b/examples/mnit_ballz/res/raw/walld.wav differ
diff --git a/examples/mnit_ballz/src/assets.nit b/examples/mnit_ballz/src/assets.nit
new file mode 100644 (file)
index 0000000..e823284
--- /dev/null
@@ -0,0 +1,49 @@
+# 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.
+
+
+# All the assets needed by the appplication, regrouped in one class
+module assets
+
+import app::audio
+import mnit::assets
+
+
+# Contains all the assets
+class Assets
+
+       # Sound for the wall destruction
+       var wall_destruction = new Sound("walld.wav")
+
+       # Sound when the ball bounce
+       var bounce = new Sound("bounce.ogg")
+
+       # Image of the ball
+       var ball: Image is noinit
+
+       # Image for the horizontal walls
+       var horizontal_wall: Image is noinit
+
+       # Image for the vertical walls
+       var vertical_wall: Image is noinit
+
+       # Loads all the assets
+       fun load do
+               ball = app.load_image("images/ball.png")
+               horizontal_wall = app.load_image("images/horizontal_wall.png")
+               vertical_wall = app.load_image("images/vertical_wall.png")
+               wall_destruction.load
+               bounce.load
+       end
+end
index 249ee68..dc934e7 100644 (file)
@@ -1,7 +1,5 @@
 # this file is part of NIT ( http://www.nitlanguage.org ).
 #
-# Copyright 2014 Romain Chanoir <romain.chanoir@viacesi.fr>
-#
 # 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
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+
+# Android part of mnit_ballz
 module ballz_android is
-       app_version(1, 0, git_revision)
+       app_version(0, 2, git_revision)
        app_name("Ballz")
+       app_namespace "org.nitlanguage.ballz"
+       android_api_target 19
 end
 
 import android::portrait
-
-import game_logic
+import android::sensors
+import display
+import mnit::android
 
 redef class App
 
-       var screen: nullable Screen
+       # The game
+       var game: nullable Game is noautoinit
 
-       redef fun run
-       do
-               sensors_support_enabled = true
+       redef fun run do
                accelerometer.enabled = true
                accelerometer.event_rate = 10000
                magnetic_field.enabled = true
@@ -37,33 +39,72 @@ redef class App
                light.enabled = true
                proximity.enabled = true
                maximum_fps = 50
-
+               sensors_support_enabled = true
                super
        end
 
        redef fun on_create
        do
                super
-               screen = new Screen(self, display.as(Display))
+               game = new Game(display.width.to_f, display.height.to_f)
        end
 
        redef fun frame_core(display)
        do
-               var screen = self.screen
-               if screen != null then
-                       screen.game.do_turn
-                       screen.do_frame(display)
+               var game = game
+               if game != null then
+                       game.do_turn
+                       game.draw(display, assets)
                end
        end
 
        redef fun input(ie)
-       do      
-               if ie isa QuitEvent then 
+       do
+               if paused then return false
+               if ie isa QuitEvent then
                        quit = true
                        return true
                end
-               if screen != null then
-                       return screen.input(ie)
+               var game = game
+               if game != null then
+                       return game.input(ie)
+               end
+               return false
+       end
+end
+
+redef class Ball
+
+       redef fun intercepts(event)
+       do
+               if event isa ASensorAccelerometer then
+                       acceleration(event.x, event.y)
+               else if event isa ASensorMagneticField then
+                       #deal with Magnetic field sensor
+                       #print "ASensorMagneticField : x = " + event.x.to_s + " y = " + event.y.to_s + " z = " + event.z.to_s
+               else if event isa ASensorGyroscope then
+                       #deal with Gyroscope sensor
+                       #print "ASensorGyroscope : x = " + event.x.to_s + " y = " + event.y.to_s + " z = " + event.z.to_s
+               else if event isa ASensorLight then
+                       #deal with light sensor
+                       #print "ASensorLight : light = " + event.light.to_s
+               else if event isa ASensorProximity then
+                       #deal with proximity sensor
+                       #print "ASensorProximity : distance = " + event.distance.to_s
+               else if event isa MotionEvent then
+               end
+               return true
+       end
+end
+
+
+redef class Game
+
+       redef fun input(ie)
+       do
+               if ie isa ASensorAccelerometer or ie isa MotionEvent then
+                       ball.intercepts(ie)
+                       return true
                end
                return false
        end
diff --git a/examples/mnit_ballz/src/ballz_linux.nit b/examples/mnit_ballz/src/ballz_linux.nit
new file mode 100644 (file)
index 0000000..6f089a8
--- /dev/null
@@ -0,0 +1,104 @@
+# 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.
+
+# Linux part of mnit_ballz
+module ballz_linux
+
+import mnit::linux
+import display
+
+
+redef class App
+
+       private var up_arrow_down = false
+       private var down_arrow_down = false
+       private var left_arrow_down = false
+       private var right_arrow_down = false
+       private var game: nullable Game is noautoinit
+
+       redef fun run
+       do
+               maximum_fps = 50
+               super
+       end
+
+       redef fun on_create
+       do
+               super
+               game = new Game(display.width.to_f, display.height.to_f)
+       end
+
+       redef fun frame_core(display)
+       do
+               if up_arrow_down then input(new SDLKeyEvent("up", true))
+               if down_arrow_down then input(new SDLKeyEvent("down", true))
+               if left_arrow_down then input(new SDLKeyEvent("left", true))
+               if right_arrow_down then input(new SDLKeyEvent("right", true))
+
+               var game = game
+               if game != null then
+                       game.do_turn
+                       game.draw(display, assets)
+               end
+       end
+
+       redef fun input(ie)
+       do
+               if ie isa QuitEvent then
+                       quit = true
+                       return true
+               end
+               var game = game
+               if game != null then
+                       return game.input(ie)
+               end
+               return false
+       end
+end
+
+redef class Ball
+
+       redef fun intercepts(event)
+       do
+               var value = 5.0
+               if event isa SDLKeyEvent then
+                       if event.is_arrow_left then
+                               acceleration(value, 0.0)
+                               app.left_arrow_down = event.is_down
+                       end
+                       if event.is_arrow_right then
+                               acceleration(-value, 0.0)
+                               app.right_arrow_down = event.is_down
+                       end
+                       if event.is_arrow_up then
+                               acceleration(0.0, -value)
+                               app.up_arrow_down = event.is_down
+                       end
+                       if event.is_arrow_down then
+                               acceleration(0.0, value)
+                               app.down_arrow_down = event.is_down
+                       end
+               end
+               return false
+       end
+end
+
+redef class Game
+
+       redef fun input(ie)
+       do
+               ball.intercepts(ie)
+               return false
+       end
+end
diff --git a/examples/mnit_ballz/src/collision.nit b/examples/mnit_ballz/src/collision.nit
new file mode 100644 (file)
index 0000000..825cedc
--- /dev/null
@@ -0,0 +1,87 @@
+# 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.
+
+# Geometric computations around vectors and points for collision detection
+module collision
+
+import geometry
+
+# trigonometry
+
+# Get the distance between `p1` and `p2`
+fun distance(p1, p2: Point[Float]): Float
+do
+       var x = p1.x - p2.x
+       var y = p1.y - p2.y
+       return ( x * x + y * y ).sqrt
+end
+
+# Get the magnitude (length) of `vector`
+fun magnitude(vector: Point[Float]): Float do return ( vector.x * vector.x + vector.y * vector.y ).sqrt
+
+# Get the unit vector of `vector`
+fun unit_vector(vector: Point[Float]): Point[Float] do return new Point[Float](vector.x / magnitude(vector), vector.y / magnitude(vector))
+
+# Get the dot product of vectors `v1` and `v2`
+fun dot_product(v1, v2: Point[Float]): Float do return v1.x * v2.x + v1.y * v2.y
+
+# Get the vector between `start_point` and `end_point`
+fun vector_between(start_point, end_point: Point[Float]): Point[Float] do return new Point[Float](end_point.x - start_point.x, end_point.y - start_point.y)
+
+# Returns the point on a line with endpoints `l1` and `l2` closest to `center`
+fun point_closest_to_line(center, l1, l2: Point[Float]): Point[Float]
+do
+       var luvector = unit_vector(vector_between(l1, l2))
+       var l_to_ball = vector_between(l1, center)
+
+       var projection = dot_product(l_to_ball, luvector)
+
+       if projection <= 0.0 then return l1
+       if projection >= distance(l1, l2) then return l2
+       return new Point[Float](l1.x + luvector.x * projection, l1.y + luvector.y * projection)
+end
+
+# Is the ball with the `center` and `radius` intersecting the line with the endpoints `l1` and `l2`?
+fun is_intersecting(center, l1, l2: Point[Float], radius: Float): Bool
+do
+       var closest = point_closest_to_line(center, l1, l2)
+       var distance = distance(center, closest)
+       return distance < radius
+end
+
+# Bouncing function, returns the new point of the center of the ball
+fun bounce(center, l1, l2, offset: Point[Float]): Point[Float]
+do
+       var bln = bounce_line_normal(center, l1, l2)
+       var dot = dot_product(offset, bln)
+       return new Point[Float](offset.x - (2.0 * dot * bln.x), offset.y - (2.0 * dot * bln.y))
+end
+
+private fun bounce_line_normal(center, l1, l2: Point[Float]): Point[Float]
+do
+       var p = point_closest_to_line(center, l1, l2)
+       var v = vector_between(p, center)
+       return unit_vector(v)
+end
+
+# Rotate `p` around `center` through `angle`
+fun rotate_point(p, center: Point[Float], angle: Float): Point[Float]
+do
+       var s = angle.sin
+       var c = angle.cos
+
+       var nx = c * (p.x - center.x) - s * (p.y - center.y) + center.x
+       var ny = s * (p.x - center.x) + c * (p.y - center.y) + center.y
+       return new Point[Float](nx, ny)
+end
diff --git a/examples/mnit_ballz/src/display.nit b/examples/mnit_ballz/src/display.nit
new file mode 100644 (file)
index 0000000..1d63189
--- /dev/null
@@ -0,0 +1,47 @@
+# 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.
+
+# Handles the drawing of all the game
+module display
+
+import game_logic
+
+redef class Ball
+
+       # Draw `self` onto `display` with image from `assets`
+       fun draw(display: Display, assets: Assets)
+       do
+               display.blit_centered(assets.ball, center.x, center.y)
+       end
+end
+
+redef class Wall
+
+       # Draw `self` onto `display` with image from `assets`
+       fun draw(display: Display, assets: Assets)
+       do
+               display.blit_rotated(assets.vertical_wall, center.x, center.y, angle)
+       end
+end
+
+redef class Game
+
+       # Draw all the entities onto `display`
+       fun draw(display: Display, assets: Assets)
+       do
+               display.clear (0.0, 0.0, 0.0)
+               ball.draw(display, assets)
+               for wall in walls do wall.draw(display, assets)
+       end
+end
index 7ece167..38d7682 100644 (file)
@@ -1,7 +1,5 @@
 #this file is part of NIT ( http://www.nitlanguage.org ).
 #
-# Copyright 2014 Romain Chanoir <romain.chanoir@viacesi.fr>
-#
 # 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
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+# All the logic of the game
 module game_logic
 
-import mnit::android
-import android::sensors
+import assets
+import objects
+import geometry::quadtree
+import collision
 
-class Ball
-       var x: Float
-       var y: Float
-       var dim: Int
-       var walls_activated: Bool
-       var offset_x = 0.0
-       var offset_y = 0.0
-       var going_left: Bool
-       var going_down: Bool
+redef class Ball
 
-       var game: Game
+       # Scale for drawing the image of `self`
+       var scale = 1.0
 
-       init(game: Game, x,y: Float, walls: Bool)
-       do
-               self.x = x
-               self.y = y
-               self.dim = 20
-               self.game = game
-               self.walls_activated = walls
-       end
+       # ASensorProximity value for modifying `scale`
+       # Not used yet
+       var scale_proximity_modifier = 6.0
+
+       # Radius of `self`
+       var radius = 32.0
+
+       # Movement vector of `self`
+       var offset = new Point[Float](0.0, 0.0)
 
-       # not very useful at this time
-       fun do_turn
+       # Calculates the acceleration of `self`
+       fun acceleration(x,y: Float)
        do
+               var max_offset = 10.0
+               var max_value = 9.80
+               var offset_x = offset.x - x/max_value
+               var offset_y = offset.y + y/max_value
+               if offset_x > max_offset then offset_x = max_offset
+               if offset_x < -max_offset then offset_x = -max_offset
+               if offset_y > max_offset then offset_y = max_offset
+               if offset_y < -max_offset then offset_y = -max_offset
+               offset = new Point[Float](offset_x, offset_y)
        end
 
-       fun intercepts(event: InputEvent): Bool
+       # Do the collision detection, then move `self`consequently
+       fun do_turn(game: Game)
        do
-               if event isa ASensorAccelerometer then
-                       do_move(event)
-               else if event isa ASensorMagneticField then
-                       #deal with Magnetic field sensor
-                       print "ASensorMagneticField : x = " + event.x.to_s + " y = " + event.y.to_s + " z = " + event.z.to_s
-               else if event isa ASensorGyroscope then
-                       #deal with Gyroscope sensor
-                       print "ASensorGyroscope : x = " + event.x.to_s + " y = " + event.y.to_s + " z = " + event.z.to_s
-               else if event isa ASensorLight then
-                       #deal with light sensor
-                       print "ASensorLight : light = " + event.light.to_s
-               else if event isa ASensorProximity then
-                       #deal with proximity sensor
-                       print "ASensorProximity : distance = " + event.distance.to_s
-               else if event isa MotionEvent then
-                       activate_walls(event)
+               offset = new Point[Float](offset.x * 0.98, offset.y * 0.98)
+               var np = collision(game.quadtree)
+               if np != null then
+                       offset = np
+                       center = new Point[Float](center.x + offset.x, center.y + offset.y)
+               else
+                       center = new Point[Float](center.x + offset.x, center.y + offset.y)
                end
-               return true
        end
 
-       fun do_move (event: ASensorAccelerometer)
+       # Collision detection
+       fun collision(quadtree: SQuadTree[OrientedLine]): nullable Point[Float]
        do
-               # acceleration value
-               var vx = event.x
-               var vy = event.y
 
-               var gw = game.width
-               var gh = game.height
-
-               # acceleration
-               var max_value = 9.80
-               var acceleration_x = vx/max_value
-               var acceleration_y = vy/max_value
-               offset_x -= (acceleration_x/10.0)*(vx.abs) + offset_x/125.0
-               offset_y += (acceleration_y/10.0)*(vy.abs) - offset_y/125.0
-               var nx = self.x + offset_x
-               var ny = self.y + offset_y
-               going_left = offset_x > 0.0
-               going_down = offset_y > 0.0
-
-               # x value
-               if nx >= 0.0 and nx <= gw then
-                       self.x = nx
-               else if nx < 0.0 then
-                       if not walls_activated then self.x = gw else do_bounce(1)
-               else if nx > gw then
-                       if not walls_activated then self.x = 0.0 else do_bounce(1)
+               var nx = self.center.x + offset.x
+               var ny = self.center.y + offset.y
+               var new_center = new Point[Float](nx, ny)
+               var effective_radius = radius*scale
+               # Lines intersecting with the ball
+               var intersecting_lines = new Array[OrientedLine]
+
+               # Line intersecting closest to the ball
+               var intersecting_line: nullable OrientedLine = null
+
+               # closest point of the intersecting line
+               var closest_point: nullable Point[Float] = null
+
+               # get the intersecting lines with help of the quadtree
+               var lines = quadtree.items_overlapping(new_center.padded(effective_radius))
+               for l in lines do
+                       if is_intersecting(new_center, l.point_left, l.point_right, effective_radius) then
+                               intersecting_lines.add(l)
+                       end
                end
 
-               # y value
-               if ny >= 0.0 and ny <= gh then
-                       self.y = ny
-               else if ny < 0.0 then
-                       if not walls_activated then self.y = gh else do_bounce(2)
-               else if ny > gh then
-                       if not walls_activated then self.y = 0.0 else do_bounce(2)
+               # get the line closest to the ball from the intersecting lines, setting the closest point
+               var min_dist = 100.0
+               if intersecting_lines.length >= 2 then
+                       for l in intersecting_lines do
+                               var closest = point_closest_to_line(new_center, l.point_left, l.point_right)
+                               var distance = distance(closest, new_center)
+                               if distance < min_dist then
+                                       min_dist = distance
+                                       intersecting_line = l
+                                       closest_point = closest
+                               end
+                       end
+               else if intersecting_lines.length == 1 then
+                       intersecting_line = intersecting_lines[0]
+                       closest_point = point_closest_to_line(new_center, intersecting_line.point_left, intersecting_line.point_right)
                end
-       end
 
-       # bounce in function of the position of the wall relative to the ball: 1=left or right, 2=top or down
-       fun do_bounce(wall_position: Int)
-       do
-               if wall_position == 1 then
-                       offset_x = -offset_x*0.85
-               else if wall_position == 2 then
-                       offset_y = -offset_y*0.85
-               end
-               if offset_x.abs > 1.0 and offset_y.abs > 1.0 then
-               self.x += offset_x
-               self.y += offset_y
+               if intersecting_line != null and closest_point != null then
+                       return bounce(center, intersecting_line.point_left, intersecting_line.point_right, offset)
                end
+               return null
        end
 
-       fun activate_walls(event: MotionEvent)
-       do
-               if event.just_went_down then
-                       walls_activated = not walls_activated
-               end
-       end
+       # Event interception
+       fun intercepts(event: InputEvent): Bool is abstract
 end
 
-class Screen
-       var ball_img: Image
-       var game: Game
-
-       init(app: App, display: Display)
-       do
-               game = new Game(display)
-               ball_img = app.load_asset("images/ball.png").as(Image)
-               var scale = game.img_dim.to_f / game.img_ori_dim.to_f
-               ball_img.scale = scale
-               ball_img.scale = 3.0
-       end
+# The core of the game
+class Game
 
-       fun do_frame(display: Display)
-       do
-               display.clear(0.0, 0.0, 0.0)
-               display.blit_rotated(ball_img, game.ball.x, game.ball.y, 0.0)
-       end
+       # The Ball!
+       var ball: Ball is noinit
 
-       fun input(ie: InputEvent): Bool
-       do
-               if ie isa ASensorProximity then
-                       if ie.distance == 0.0 then ball_img.scale = 6.0 else ball_img.scale = 3.0
-               else
-                       game.ball.intercepts(ie)
-               end
-               return true
-       end
-end
+       # List of walls in the level
+       var walls: Array[Wall] is noinit
 
-class Game
-       var ball: Ball
+       # Width of the display
        var width: Float
+
+       # Heightof the display
        var height: Float
 
-       var img_ori_dim: Int = 256
-       fun img_dim: Int do return 210
+       # Quadtree used for collision detection
+       var quadtree: SQuadTree[OrientedLine] is noinit
 
-       init(display: Display)
+       init
        do
-               width = display.width.to_f
-               height = display.height.to_f
-               ball = new Ball(self, width/2.0, height/2.0, false)
+               ball = new Ball(new Point[Float](width/2.0, height/2.0))
+               # Walls initialisation
+               var walla = new Wall(new Point[Float](width/4.0, height/4.0), pi/3.0, 1.0)
+               var wallb = new Wall(new Point[Float](width*0.75, height/4.0), 0.0, 1.0)
+               var wallc = new Wall(new Point[Float](width/4.0, height*0.75), 0.0, 1.0)
+               var walld = new Wall(new Point[Float](width*0.75, height*0.75), pi/3.0, 1.0)
+               walls = new Array[Wall].with_items(walla, wallb, wallc, walld)
+
+               # adding screen bordures
+               var i = new Point[Float](0.0,0.0)
+               var a = new Point[Float](0.0, height/2.0)
+               var b = new Point[Float](width/2.0, 0.0)
+               var c = new Point[Float](width, height/2.0)
+               var d = new Point[Float](width/2.0, height)
+
+               var l1 = new OrientedLine(i, i, pi/2.0, height, a)
+               var l2 = new OrientedLine(i, i, 0.0, width, b)
+               var l3 = new OrientedLine(i, i, pi/2.0, height, c)
+               var l4 = new OrientedLine(i, i, 0.0, width, d)
+
+               quadtree = new SQuadTree[OrientedLine](5, width, height)
+               for w in walls do for l in w.lines do
+                       quadtree.add(l)
+               end
+               quadtree.add(l1)
+               quadtree.add(l2)
+               quadtree.add(l3)
+               quadtree.add(l4)
        end
 
-       fun do_turn
-       do
-       ball.do_turn
+       # Only calls `do_turn` of the ball for the moment
+       fun do_turn do ball.do_turn(self)
+
+       # Input gestion
+       fun input(ie: InputEvent): Bool do return false
+end
+
+redef class App
+
+       # Assets used in all the app
+       var assets = new Assets
+
+       redef fun on_create do
+               super
+               assets.load
        end
 end
diff --git a/examples/mnit_ballz/src/objects.nit b/examples/mnit_ballz/src/objects.nit
new file mode 100644 (file)
index 0000000..d8e1686
--- /dev/null
@@ -0,0 +1,100 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Module containing all objects of the game
+module objects
+
+import geometry
+import geometry::polygon
+import geometry::boxes
+import collision
+
+# The ball is the main character of the game!
+class Ball
+       # Center of the ball
+       var center: Point[Float] is writable
+end
+
+# Walls make the ball bounce on them
+class Wall
+       # Coordinates of the center of the wall
+       var center: Point[Float]
+
+       # Angle in radian
+       var angle: Float
+
+       # Scale for drawing `self`
+       var scale: Float
+
+       # Width of `self`
+       var width: Float is noautoinit
+
+       # Height of `self`
+       var height: Float is noautoinit
+
+       # Lines composing `self`
+       var lines: Array[OrientedLine] is noautoinit
+
+       # Initialize `self` with all its lines from `center` and `angle`
+       init do
+               self.height = 128.0
+               self.width = 32.0
+               var i = new Point[Float](0.0, 0.0)
+               var j = new Point[Float](0.0, 0.0)
+
+               var a = new Point[Float]((center.x - width/2.0), center.y)
+               var b = new Point[Float]((center.x), (center.y - height/2.0))
+               var c = new Point[Float]((center.x + width/2.0), center.y)
+               var d = new Point[Float]((center.x), (center.y + height/2.0))
+
+               var l1 = new OrientedLine(i, j, angle - pi/2.0, height * scale.to_f, rotate_point(a, center, angle))
+               var l2 = new OrientedLine(i, j, angle, width * scale.to_f, rotate_point(b, center, angle))
+               var l3 = new OrientedLine(i, j, angle - pi/2.0, height * scale.to_f, rotate_point(c, center, angle))
+               var l4 = new OrientedLine(i, j, angle, width * scale.to_f, rotate_point(d, center, angle))
+               lines = new Array[OrientedLine]
+               lines.add_all([l1, l2, l3, l4])
+       end
+end
+
+# A line represented with a center and an angle
+class OrientedLine
+       super Line[Float]
+       redef type P: Point[Float]
+
+       # Angle in radian
+       var angle: Float is writable
+
+       # Length
+       var length: Float
+
+       # Center
+       var center: Point[Float]
+
+       redef fun point_left
+       do
+               var luv = unit_vector(new Point[Float](angle.cos, angle.sin))
+               var offset_from_center = new Point[Float](luv.x * (length / 2.0), luv.y * (length / 2.0))
+               return new Point[Float](center.x + offset_from_center.x, center.y + offset_from_center.y)
+       end
+
+       redef fun point_right
+       do
+               var luv = unit_vector(new Point[Float](angle.cos, angle.sin))
+               var offset_from_center = new Point[Float](luv.x * length / 2.0, luv.y * length / 2.0)
+               return new Point[Float](center.x - offset_from_center.x, center.y - offset_from_center.y)
+       end
+
+       redef fun left do return point_left.x.min(point_right.x)
+       redef fun right do return point_left.x.max(point_right.x)
+end
index 42364bf..14faa98 100644 (file)
@@ -8,6 +8,10 @@ android: android-icons
        mkdir -p bin
        ../../bin/nitc -o bin/dino.apk src/dino_android.nit
 
+android-release: android-icons
+       mkdir -p bin
+       ../../bin/nitc -o bin/dino.apk src/dino_android.nit --release
+
 ../../contrib/inkscape_tools/bin/svg_to_icons:
        $(MAKE) -C ../../contrib/inkscape_tools
 
similarity index 97%
rename from examples/mnit_dino/project.ini
rename to examples/mnit_dino/package.ini
index a4a5c6c..fbd7d4f 100644 (file)
@@ -1,4 +1,4 @@
-[project]
+[package]
 name=mnit_dino
 tags=game
 maintainer=Alexis Laferrière <alexis.laf@xymus.net>
index d789aa4..30f7263 100644 (file)
@@ -1,4 +1,4 @@
-[project]
+[package]
 name=montecarlo
 tags=example
 maintainer=Jean Privat <jean@pryen.org>
similarity index 100%
rename from lib/projects.ini
rename to examples/packages.ini
index 888fd2b..3ca7f26 100644 (file)
@@ -1,4 +1,4 @@
-[project]
+[package]
 name=print_arguments
 tags=example
 maintainer=Jean Privat <jean@pryen.org>
index 90e31a7..cf32ba0 100644 (file)
@@ -1,4 +1,4 @@
-[project]
+[package]
 name=procedural_array
 tags=example
 maintainer=Jean Privat <jean@pryen.org>
similarity index 97%
rename from examples/rosettacode/project.ini
rename to examples/rosettacode/package.ini
index 3452885..523694e 100644 (file)
@@ -1,4 +1,4 @@
-[project]
+[package]
 name=rosettacode
 tags=example
 maintainer=Jean Privat <jean@pryen.org>
index 5e564d7..a42ffde 100644 (file)
@@ -8,6 +8,10 @@ android:
        mkdir -p bin
        ../../bin/nitc -o bin/shoot.apk src/shoot_android.nit
 
+android-release:
+       mkdir -p bin
+       ../../bin/nitc -o bin/shoot.apk src/shoot_android.nit --release
+
 null:
        mkdir -p bin
        ../../bin/nitc -o bin/shoot_null src/shoot_null.nit
similarity index 96%
rename from examples/shoot/project.ini
rename to examples/shoot/package.ini
index a2ea7c3..0fe112a 100644 (file)
@@ -1,4 +1,4 @@
-[project]
+[package]
 name=shoot
 tags=game
 maintainer=Jean Privat <jean@pryen.org>
index 64e1f61..5ec2a3d 100644 (file)
@@ -1,4 +1,4 @@
-[project]
+[package]
 name=a_star
 tags=algo,lib
 maintainer=Alexis Laferrière <alexis.laf@xymus.net>
similarity index 96%
rename from lib/ai/project.ini
rename to lib/ai/package.ini
index cff8fc6..3e9fdf8 100644 (file)
@@ -1,4 +1,4 @@
-[project]
+[package]
 name=ai
 tags=ai,algo,lib
 maintainer=Jean Privat <jean@pryen.org>
index c70dd40..b361b4f 100644 (file)
@@ -138,7 +138,6 @@ private extern class NativeMediaPlayer in "Java" `{ android.media.MediaPlayer `}
                        self.setDataSource(fd, start_offset, length);
                        return 1;
                }catch(Exception e) {
-                       Log.e("Error loading the Media Player with a file descriptor", e.getMessage());
                        return 0;
                }
        `}
@@ -483,7 +482,7 @@ class MediaPlayer
 end
 
 redef class PlayableAudio
-       redef init do app.add_to_sounds(self)
+       redef init do add_to_sounds(self)
 end
 
 redef class Sound
@@ -537,8 +536,8 @@ redef class Sound
        end
 
        redef fun play do
-               if self.error != null then return
                if not is_loaded then load
+               if self.error != null then return
                soundpool.play(soundpool_id)
        end
 
@@ -599,8 +598,8 @@ redef class Music
        end
 
        redef fun play do
-               if self.error != null then return
                if not is_loaded then load
+               if self.error != null then return
                media_player.start
        end
 
@@ -617,9 +616,6 @@ end
 
 redef class App
 
-       # Sounds handled by the application, when you load a sound, it's added to this list.
-       # This array is used in `pause` and `resume`
-       private var sounds = new Array[PlayableAudio]
 
        # Returns the default MediaPlayer of the application.
        # When you load a music, it goes in this MediaPlayer.
@@ -676,12 +672,6 @@ redef class App
                return add_to_sounds(default_mediaplayer.load_sound(resource_manager.raw_id(music), self.native_activity)).as(Music)
        end
 
-       # Factorizes `sounds.add` to use it in `load_music`, `load_sound`, `load_music_from_res` and `load_sound_from_res`
-       private fun add_to_sounds(sound: PlayableAudio): PlayableAudio do
-               sounds.add(sound)
-               return sound
-       end
-
        redef fun on_pause do
                super
                for s in sounds do s.pause
@@ -700,3 +690,16 @@ redef class App
                for s in sounds do s.resume
        end
 end
+
+redef class Sys
+
+       # Sounds handled by the application, when you load a sound, it's added to this list.
+       # This array is used in `pause` and `resume`
+       private var sounds = new Array[PlayableAudio]
+
+       # Factorizes `sounds.add` to use it in `load_music`, `load_sound`, `load_music_from_res` and `load_sound_from_res`
+       private fun add_to_sounds(sound: PlayableAudio): PlayableAudio do
+               sounds.add(sound)
+               return sound
+       end
+end
index 2202827..d99f5a9 100644 (file)
@@ -368,4 +368,13 @@ end
 
 # Android NDK's structure to control the native window for drawing
 extern class ANativeWindow `{ ANativeWindow* `}
+       # Change the format and size of the window buffers
+       #
+       # All arguments can be set to 0 to use the default devices values.
+       # `width` and `height` must both be set to 0 or have significant values.
+       #
+       # `format` is a value specified by EGL.
+       fun set_buffers_geometry(width, height, format: Int): Bool `{
+               return ANativeWindow_setBuffersGeometry(self, (int32_t)width, (int32_t)height, (int32_t)format);
+       `}
 end
similarity index 96%
rename from lib/android/project.ini
rename to lib/android/package.ini
index d378b05..6912264 100644 (file)
@@ -1,4 +1,4 @@
-[project]
+[package]
 name=android
 tags=platform,lib
 maintainer=Alexis Laferrière <alexis.laf@xymus.net>
index 3ee9765..b969389 100644 (file)
 #
 # ~~~~nitish
 # #FIXME rewrite the example
-# var app = new MyApp
-# app.sensors_support_enabled = true
-# app.accelerometer.enabled = true
-# app.accelerometer.eventrate = 10000
-# app.magnetic_field.enabled = true
-# app.gyroscope.enabled = true
-# app.light.enabled = true
-# app.proximity.enabled = true
-# app.main_loop
+# redef class App
+#      sensors_support_enabled = true
+#      accelerometer.enabled = true
+#      accelerometer.eventrate = 10000
+#      magnetic_field.enabled = true
+#      gyroscope.enabled = true
+#      light.enabled = true
+#      proximity.enabled = true
+# end
 # ~~~~
 #
-# In this example, we enable the sensor support, then enable all types of sensors supported, before running the app.
-# The result is you get all type of SensorEvent (ASensorAccelerometer, ASensorMagneticField ...) in the input method of your app
+# In this example, we enable the sensor support, then enable all types of sensors supported by the API, directly with `App` attributes
+# As a result, you get all type of SensorEvent (ASensorAccelerometer, ASensorMagneticField ...) in the `input` callback of `App`
 module sensors
 
 import android
@@ -270,8 +270,8 @@ redef class App
        private fun enable_accelerometer
        do
                accelerometer.asensor = sensormanager.get_default_sensor(new ASensorType.accelerometer)
-               if accelerometer.asensor.address_is_null then 
-                               print "Accelerometer sensor unavailable" 
+               if accelerometer.asensor.address_is_null then
+                               print "Accelerometer sensor unavailable"
                else
                                if eventqueue.enable_sensor(accelerometer.asensor) < 0 then print "Accelerometer enabling failed"
                        eventqueue.set_event_rate(accelerometer.asensor, accelerometer.event_rate)
@@ -314,7 +314,7 @@ redef class App
        private fun enable_proximity
        do
                proximity.asensor = sensormanager.get_default_sensor(new ASensorType.proximity)
-               if proximity.asensor.address_is_null then 
+               if proximity.asensor.address_is_null then
                                print "Proximity sensor unavailable"
                else
                        if eventqueue.enable_sensor(proximity.asensor) < 0 then print "Proximity enabling failed"
similarity index 96%
rename from lib/app/project.ini
rename to lib/app/package.ini
index 7032d20..d5c48c1 100644 (file)
@@ -1,4 +1,4 @@
-[project]
+[package]
 name=app
 tags=lib
 maintainer=Alexis Laferrière <alexis.laf@xymus.net>
index 8317cf9..467aeae 100644 (file)
@@ -1,4 +1,4 @@
-[project]
+[package]
 name=array_debug
 tags=debug,lib
 maintainer=Alexandre Terrasa <alexandre@moz-code.org>
index 629c07b..7009786 100644 (file)
@@ -1,4 +1,4 @@
-[project]
+[package]
 name=base64
 tags=encoding,lib
 maintainer=Lucas Bajolet <r4pass@hotmail.com>
similarity index 96%
rename from lib/bcm2835/project.ini
rename to lib/bcm2835/package.ini
index 07ade4d..928a8e6 100644 (file)
@@ -1,4 +1,4 @@
-[project]
+[package]
 name=bcm2835
 tags=embedded,lib
 maintainer=Alexis Laferrière <alexis.laf@xymus.net>
similarity index 96%
rename from lib/binary/project.ini
rename to lib/binary/package.ini
index c9f47da..227e529 100644 (file)
@@ -1,4 +1,4 @@
-[project]
+[package]
 name=binary
 tags=io,lib
 maintainer=Alexis Laferrière <alexis.laf@xymus.net>
similarity index 96%
rename from lib/bitmap/project.ini
rename to lib/bitmap/package.ini
index 54ff7c2..21ecf9a 100644 (file)
@@ -1,4 +1,4 @@
-[project]
+[package]
 name=bitmap
 tags=lib
 maintainer=Lucas Bajolet <r4pass@hotmail.com>
index b419878..4824079 100644 (file)
@@ -1,4 +1,4 @@
-[project]
+[package]
 name=bucketed_game
 tags=game,lib
 maintainer=Alexis Laferrière <alexis.laf@xymus.net>
index b221516..280bea6 100644 (file)
@@ -1,4 +1,4 @@
-[project]
+[package]
 name=buffered_ropes
 tags=algo,text,lib
 maintainer=Lucas Bajolet <r4pass@hotmail.com>
index 415a61b..22850fc 100644 (file)
--- a/lib/c.ini
+++ b/lib/c.ini
@@ -1,4 +1,4 @@
-[project]
+[package]
 name=c
 tags=language,wrapper,lib
 maintainer=Alexis Laferrière <alexis.laf@xymus.net>
index deb6765..a9b04e1 100644 (file)
--- a/lib/c.nit
+++ b/lib/c.nit
@@ -93,8 +93,8 @@ class CIntArray
                super size
        end
 
-       # Build from an `Array[Int]`
-       new from(array: Array[Int])
+       # Create from an `SequenceRead[Int]`
+       new from(array: SequenceRead[Int])
        do
                var carray = new CIntArray(array.length)
                for i in array.length.times do
@@ -129,7 +129,7 @@ class CByteArray
                super size
        end
 
-       # Build from a `SequenceRead[Byte]`
+       # Create from a `SequenceRead[Byte]`
        new from(array: SequenceRead[Byte])
        do
                var carray = new CByteArray(array.length)
@@ -166,8 +166,8 @@ class CNativeStringArray
                super size
        end
 
-       # Build from an `Array[NativeString]`
-       new from(array: Array[NativeString])
+       # Create from an `SequenceRead[NativeString]`
+       new from(array: SequenceRead[NativeString])
        do
                var carray = new CNativeStringArray(array.length)
                for i in array.length.times do
index 7dd61d7..fbdc2c4 100644 (file)
@@ -1,4 +1,4 @@
-[project]
+[package]
 name=cartesian
 tags=algo,lib
 maintainer=Jean Privat <jean@pryen.org>
similarity index 96%
rename from lib/cocoa/project.ini
rename to lib/cocoa/package.ini
index ceee0f1..44c18eb 100644 (file)
@@ -1,4 +1,4 @@
-[project]
+[package]
 name=cocoa
 tags=wrapper,lib
 maintainer=Alexis Laferrière <alexis.laf@xymus.net>
index bf0cda4..f97a0ed 100644 (file)
@@ -1,4 +1,4 @@
-[project]
+[package]
 name=combinations
 tags=algo,lib
 maintainer=Jean Privat <jean@pryen.org>
index ba89925..10ec43b 100644 (file)
@@ -1,4 +1,4 @@
-[project]
+[package]
 name=console
 tags=terminal,lib
 maintainer=Jean-Christophe Beaupré <jcbrinfo@users.noreply.github.com>
similarity index 96%
rename from lib/core/project.ini
rename to lib/core/package.ini
index 652d22e..9b4db38 100644 (file)
@@ -1,4 +1,4 @@
-[project]
+[package]
 name=core
 tags=lib
 maintainer=Jean Privat <jean@pryen.org>
index cde38a3..09bda32 100644 (file)
@@ -1,4 +1,4 @@
-[project]
+[package]
 name=counter
 tags=algo,lib
 maintainer=Jean Privat <jean@pryen.org>
index 7839cf6..a317f35 100644 (file)
@@ -1,4 +1,4 @@
-[project]
+[package]
 name=cpp
 tags=language,wrapper,lib
 maintainer=Alexis Laferrière <alexis.laf@xymus.net>
index 6487e51..e8b4cf1 100644 (file)
@@ -1,4 +1,4 @@
-[project]
+[package]
 name=crypto
 tags=crypto,algo,lib
 maintainer=Lucas Bajolet <r4pass@hotmail.com>
similarity index 96%
rename from lib/csv/project.ini
rename to lib/csv/package.ini
index b8008e0..abbb852 100644 (file)
@@ -1,4 +1,4 @@
-[project]
+[package]
 name=csv
 tags=format,lib
 maintainer=Alexandre Terrasa <alexandre@moz-code.org>
similarity index 96%
rename from lib/curl/project.ini
rename to lib/curl/package.ini
index d399756..bc8502d 100644 (file)
@@ -1,4 +1,4 @@
-[project]
+[package]
 name=curl
 tags=network,wrapper,lib
 maintainer=Alexis Laferrière <alexis.laf@xymus.net>
similarity index 96%
rename from lib/curses/project.ini
rename to lib/curses/package.ini
index 58813c5..cd3c99e 100644 (file)
@@ -1,4 +1,4 @@
-[project]
+[package]
 name=curses
 tags=ui,terminal,wrapper,lib
 maintainer=Jean Privat <jean@pryen.org>
index 148d496..ac74d2d 100644 (file)
@@ -1,4 +1,4 @@
-[project]
+[package]
 name=date
 tags=lib
 maintainer=Mehdi Ait Younes <overpex@gmail.com>
index a9205b6..44690f8 100644 (file)
@@ -1,4 +1,4 @@
-[project]
+[package]
 name=deriving
 tags=lib
 maintainer=Jean Privat <jean@pryen.org>
similarity index 96%
rename from lib/dom/project.ini
rename to lib/dom/package.ini
index 7b5938c..64a1947 100644 (file)
@@ -1,4 +1,4 @@
-[project]
+[package]
 name=dom
 tags=xml,lib
 maintainer=Lucas Bajolet <r4pass@hotmail.com>
index b4db4f7..cc510fc 100644 (file)
@@ -1,4 +1,4 @@
-[project]
+[package]
 name=dummy_array
 tags=algo,lib
 maintainer=Floréal Morandat <morandat@lirmm.fr>
index b3bb784..c77b5f8 100644 (file)
@@ -1,4 +1,4 @@
-[project]
+[package]
 name=egl
 tags=graphics,wrapper,lib
 maintainer=Alexis Laferrière <alexis.laf@xymus.net>
index 8934b7e..69df8e5 100644 (file)
@@ -454,3 +454,6 @@ end
 fun egl_bind_opengl_api: Bool `{ return eglBindAPI(EGL_OPENGL_API); `}
 fun egl_bind_opengl_es_api: Bool `{ return eglBindAPI(EGL_OPENGL_ES_API); `}
 fun egl_bind_openvg_api: Bool `{ return eglBindAPI(EGL_OPENVG_API); `}
+
+# Handle to the default display to use with EGL
+fun egl_default_display: Pointer `{ return EGL_DEFAULT_DISPLAY; `}
similarity index 97%
rename from lib/emscripten/project.ini
rename to lib/emscripten/package.ini
index 9789637..458a8bc 100644 (file)
@@ -1,4 +1,4 @@
-[project]
+[package]
 name=emscripten
 tags=platform,lib
 maintainer=Alexis Laferrière <alexis.laf@xymus.net>
index 5ba5b32..c279e04 100644 (file)
@@ -1,4 +1,4 @@
-[project]
+[package]
 name=filter_stream
 tags=io,lib
 maintainer=Floréal Morandat <morandat@lirmm.fr>
index c88d7e9..2b768d4 100644 (file)
@@ -1,4 +1,4 @@
-[project]
+[package]
 name=for_abuse
 tags=algo,lib
 maintainer=Jean Privat <jean@pryen.org>
diff --git a/lib/gamnit/display.nit b/lib/gamnit/display.nit
new file mode 100644 (file)
index 0000000..94ece8a
--- /dev/null
@@ -0,0 +1,49 @@
+# 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.
+
+# Abstract display services
+module display
+
+import ::glesv2
+
+import display_linux is conditional(linux)
+import display_android is conditional(android)
+
+# Should Gamnit be more verbose?
+fun debug_gamnit: Bool do return false
+
+# General display class, is sized and drawable
+class GamnitDisplay
+
+       # Width of the display, in pixels
+       fun width: Int is abstract
+
+       # Height of the display, in pixels
+       fun height: Int is abstract
+
+       # Prepare this display
+       #
+       # The implementation varies per platform.
+       fun setup is abstract
+
+       # Close this display and free underlying resources
+       #
+       # The implementation varies per platform.
+       fun close do end
+
+       # Flip the display buffers
+       #
+       # The implementation varies per platform.
+       fun flip do end
+end
diff --git a/lib/gamnit/display_android.nit b/lib/gamnit/display_android.nit
new file mode 100644 (file)
index 0000000..d0e5235
--- /dev/null
@@ -0,0 +1,47 @@
+# 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.
+
+# Gamnit display implementation for Android
+#
+# Generated APK files require OpenGL ES 2.0.
+#
+# This modules uses `android::native_app_glue` and the Android NDK.
+module display_android is
+       android_manifest """<uses-feature android:glEsVersion="0x00020000"/>"""
+end
+
+import ::android
+
+private import gamnit::egl
+
+redef class GamnitDisplay
+
+       redef fun setup
+       do
+               var native_display = egl_default_display
+               var native_window = app.native_app_glue.window
+
+               setup_egl_display native_display
+
+               # We need 8 bits per color for selection by color
+               select_egl_config(8, 8, 8, 0, 8, 0, 0)
+
+               var format = egl_config.attribs(egl_display).native_visual_id
+               native_window.set_buffers_geometry(0, 0, format)
+
+               setup_egl_context native_window
+       end
+
+       redef fun close do close_egl
+end
diff --git a/lib/gamnit/display_linux.nit b/lib/gamnit/display_linux.nit
new file mode 100644 (file)
index 0000000..109ff51
--- /dev/null
@@ -0,0 +1,91 @@
+# 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.
+
+# Gamnit display implementation for GNU/Linux using `egl`, `sdl` and `x11`
+module display_linux
+
+import sdl
+import x11
+
+import egl # local to gamnit
+import display
+
+redef class GamnitDisplay
+
+       # Actual width or desired width of the window, can be set before calling `setup`
+       fun width=(value: Int) do requested_width = value
+       private var requested_width = 1920
+
+       # Actual height or desired height of the window, can be set before calling `setup`
+       fun height=(value: Int) do requested_height = value
+       private var requested_height = 1080
+
+       # Setup SDL, X11, EGL in order
+       redef fun setup
+       do
+               if debug_gamnit then print "Setting up SDL"
+               self.sdl_display = setup_sdl(requested_width, requested_height)
+
+               if debug_gamnit then print "Setting up X11"
+               var x11_display = setup_x11
+               var window_handle = window_handle
+               setup_egl_display x11_display
+
+               if debug_gamnit then print "Setting up EGL context"
+               select_egl_config(8, 8, 8, 8, 8, 0, 0)
+               setup_egl_context window_handle
+       end
+
+       # Close EGL and SDL in reverse order of `setup` (nothing to do for X11)
+       redef fun close
+       do
+               close_egl
+               close_sdl
+       end
+
+       # ---
+       # SDL
+
+       # The SDL display managing the window and events
+       var sdl_display: SDLDisplay is noautoinit
+
+       # Setup the SDL display and lib
+       fun setup_sdl(window_width, window_height: Int): SDLDisplay
+       do
+               var sdl_display = new SDLDisplay(window_width, window_height)
+               assert not sdl_display.address_is_null else print "Opening SDL display failed"
+               return sdl_display
+       end
+
+       # Close the SDL display
+       fun close_sdl do sdl_display.destroy
+
+       # Get a native handle to the current SDL window
+       fun window_handle: Pointer
+       do
+               var sdl_wm_info = new SDLSystemWindowManagerInfo
+               return sdl_wm_info.x11_window_handle
+       end
+
+       # ---
+       # X11
+
+       # Get a native handle to the current X11 display
+       fun setup_x11: Pointer
+       do
+               var x11_display = x_open_default_display
+               assert not x11_display.address_is_null else print "Opening X11 display failed"
+               return x11_display
+       end
+end
diff --git a/lib/gamnit/egl.nit b/lib/gamnit/egl.nit
new file mode 100644 (file)
index 0000000..3fcb8c8
--- /dev/null
@@ -0,0 +1,115 @@
+# 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.
+
+# Use of EGL to implement Gamnit on GNU/Linux and Android
+module egl
+
+import ::egl
+
+import gamnit::display
+
+redef class GamnitDisplay
+
+       # The EGL display
+       var egl_display: EGLDisplay is noautoinit
+
+       # The EGL context
+       var egl_context: EGLContext is noautoinit
+
+       # The EGL surface for the window
+       var window_surface: EGLSurface is noautoinit
+
+       # The selected EGL configuration
+       var egl_config: EGLConfig is noautoinit
+
+       # Setup the EGL display for the given `x11_display`
+       protected fun setup_egl_display(x11_display: Pointer)
+       do
+               var egl_display = new EGLDisplay(x11_display)
+               assert egl_display.is_valid else print "new EGL display is not valid"
+
+               egl_display.initialize
+               assert egl_display.is_valid else print "EGL initialize error: {egl_display.error}"
+
+               self.egl_display = egl_display
+       end
+
+       # Select an EGL config
+       protected fun select_egl_config(blue, green, red, alpha, depth, stencil, sample: Int)
+       do
+               var config_chooser = new EGLConfigChooser
+               config_chooser.renderable_type_egl
+               config_chooser.surface_type_egl
+               config_chooser.blue_size = blue
+               config_chooser.green_size = green
+               config_chooser.red_size = red
+               if alpha > 0 then config_chooser.alpha_size = alpha
+               if depth > 0 then config_chooser.depth_size = depth
+               if stencil > 0 then config_chooser.stencil_size = stencil
+               if sample > 0 then config_chooser.sample_buffers = sample
+               config_chooser.close
+
+               var configs = config_chooser.choose(egl_display)
+               assert configs != null else print "Choosing EGL config failed: {egl_display.error}"
+               assert not configs.is_empty else print "Found no EGL config"
+
+               if debug_gamnit then
+                       print "EGL available configurations:"
+                       for config in configs do
+                               var attribs = config.attribs(egl_display)
+                               print "* Conformant to: {attribs.conformant}"
+                               print "  Caveats: {attribs.caveat}"
+                               print "  Size of RGBA: {attribs.red_size} {attribs.green_size} {attribs.blue_size} {attribs.alpha_size}"
+                               print "  Buffer, depth, stencil: {attribs.buffer_size} {attribs.depth_size} {attribs.stencil_size}"
+                       end
+               end
+
+               # We use the first one, it is recommended
+               self.egl_config = configs.first
+       end
+
+       # Setup the EGL context for the given `window_handle`
+       protected fun setup_egl_context(window_handle: Pointer)
+       do
+               var window_surface = egl_display.create_window_surface(egl_config, window_handle, [0])
+               assert window_surface.is_ok else print "Creating EGL window surface failed: {egl_display.error}"
+               self.window_surface = window_surface
+
+               egl_context = egl_display.create_context(egl_config)
+               assert egl_context.is_ok else print "Creating EGL context failed: {egl_display.error}"
+
+               var make_current_res = egl_display.make_current(window_surface, window_surface, egl_context)
+               assert make_current_res else print "Creating EGL make current failed: {egl_display.error}"
+
+               # TODO make the API selection configurable per platform
+               assert egl_bind_opengl_es_api else print "EGL bind API failed: {egl_display.error}"
+       end
+
+       redef fun width do return window_surface.attribs(egl_display).width
+
+       redef fun height do return window_surface.attribs(egl_display).height
+
+       # Close the EGL context
+       fun close_egl
+       do
+               egl_display.make_current(new EGLSurface.none, new EGLSurface.none, new EGLContext.none)
+               egl_display.destroy_context(egl_context)
+               egl_display.destroy_surface(window_surface)
+       end
+
+       redef fun flip
+       do
+               egl_display.swap_buffers(window_surface)
+       end
+end
diff --git a/lib/gamnit/examples/triangle/Makefile b/lib/gamnit/examples/triangle/Makefile
new file mode 100644 (file)
index 0000000..22172de
--- /dev/null
@@ -0,0 +1,21 @@
+NITC=../../../../bin/nitc
+NITLS=../../../../bin/nitls
+
+all: bin/standalone_triangle bin/triangle bin/triangle.apk
+
+bin/standalone_triangle: $(shell ${NITLS} -M src/standalone_triangle.nit linux) ${NITC}
+       ${NITC} src/standalone_triangle.nit -m linux -o $@
+
+bin/triangle: $(shell ${NITLS} -M src/portable_triangle.nit linux) ${NITC}
+       ${NITC} src/portable_triangle.nit -m linux -o $@
+
+check: bin/standalone_triangle bin/triangle
+       bin/standalone_triangle
+       bin/triangle
+
+android: bin/triangle.apk
+bin/triangle.apk: $(shell ${NITLS} -M src/portable_triangle.nit android) ${NITC} res/drawable-hdpi/icon.png
+       ${NITC} src/portable_triangle.nit -m android -o $@
+
+res/drawable-hdpi/icon.png: art/icon.svg
+       ../../../../contrib/inkscape_tools/bin/svg_to_icons --out res --android art/icon.svg
diff --git a/lib/gamnit/examples/triangle/art/icon.svg b/lib/gamnit/examples/triangle/art/icon.svg
new file mode 100644 (file)
index 0000000..26f7c04
--- /dev/null
@@ -0,0 +1,82 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="512"
+   height="512"
+   id="svg2"
+   version="1.1"
+   inkscape:version="0.48.5 r10040"
+   sodipodi:docname="New document 1">
+  <defs
+     id="defs4" />
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="0.98994949"
+     inkscape:cx="292.54393"
+     inkscape:cy="311.81525"
+     inkscape:document-units="px"
+     inkscape:current-layer="layer1"
+     showgrid="false"
+     inkscape:window-width="1279"
+     inkscape:window-height="1379"
+     inkscape:window-x="3840"
+     inkscape:window-y="27"
+     inkscape:window-maximized="0" />
+  <metadata
+     id="metadata7">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title></dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     id="layer1"
+     transform="translate(0,-540.36218)">
+    <rect
+       style="fill:#ab00cf;fill-opacity:1;stroke:none"
+       id="rect2985"
+       width="512"
+       height="512"
+       x="0"
+       y="540.36218"
+       ry="69.507881"
+       rx="69.507881" />
+    <path
+       sodipodi:type="star"
+       style="fill:#ff001b;fill-opacity:1;stroke:none"
+       id="path3755"
+       sodipodi:sides="3"
+       sodipodi:cx="22.857143"
+       sodipodi:cy="-299.06638"
+       sodipodi:r1="235.13782"
+       sodipodi:r2="118.85303"
+       sodipodi:arg1="-1.5707963"
+       sodipodi:arg2="-0.52359875"
+       inkscape:flatsided="false"
+       inkscape:rounded="0"
+       inkscape:randomized="0"
+       d="m 22.85715,-534.20419 102.92974,175.7113 100.70557,176.99543 -203.63532,1.28411 -203.63532,-1.28412 100.705584,-176.99542 z"
+       inkscape:transform-center-y="-22.453664"
+       transform="translate(232.85714,1144.2857)" />
+  </g>
+</svg>
diff --git a/lib/gamnit/examples/triangle/bin/.gitignore b/lib/gamnit/examples/triangle/bin/.gitignore
new file mode 100644 (file)
index 0000000..72e8ffc
--- /dev/null
@@ -0,0 +1 @@
+*
diff --git a/lib/gamnit/examples/triangle/package.ini b/lib/gamnit/examples/triangle/package.ini
new file mode 100644 (file)
index 0000000..f673878
--- /dev/null
@@ -0,0 +1,11 @@
+[package]
+name=triangle
+tags=example
+maintainer=Alexis Laferrière <alexis.laf@xymus.net>
+license=Apache-2.0
+[upstream]
+browse=https://github.com/nitlang/nit/tree/master/lib/gamnit/examples/triangle/
+git=https://github.com/nitlang/nit.git
+git.directory=lib/gamnit/examples/triangle/
+homepage=http://nitlanguage.org
+issues=https://github.com/nitlang/nit/issues
diff --git a/lib/gamnit/examples/triangle/res/.gitignore b/lib/gamnit/examples/triangle/res/.gitignore
new file mode 100644 (file)
index 0000000..72e8ffc
--- /dev/null
@@ -0,0 +1 @@
+*
diff --git a/lib/gamnit/examples/triangle/src/portable_triangle.nit b/lib/gamnit/examples/triangle/src/portable_triangle.nit
new file mode 100644 (file)
index 0000000..ac8e0e6
--- /dev/null
@@ -0,0 +1,138 @@
+# 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.
+
+# Portable example of using Gamnit with custom calls to OpenGL ES 2.0
+#
+# References:
+# * The book OpenGL ES 2.0 Programming Guide
+# * https://code.google.com/p/opengles-book-samples/source/browse/trunk/LinuxX11/Chapter_2/Hello_Triangle/Hello_Triangle.c
+module portable_triangle is
+       app_name "gamnit Triangle"
+       app_namespace "org.nitlanguage.triangle"
+       app_version(1, 0, git_revision)
+end
+
+import gamnit
+
+redef class App
+
+       # Our only program for the graphic card
+       var program: GLProgram is noautoinit
+
+       # The only vertex sharder
+       var vertex_shader: GLVertexShader is noautoinit
+
+       # The only fragment sharder
+       var fragment_shader: GLFragmentShader is noautoinit
+
+       # Vertex data for the triangle
+       var vertex_array: VertexArray is noautoinit
+
+       redef fun on_create
+       do
+               super
+
+               var display = display
+               assert display != null
+
+               print "Width: {display.width}"
+               print "Height: {display.height}"
+
+               assert_no_gl_error
+               assert gl.shader_compiler else print "Cannot compile shaders"
+
+               # GL program
+               program = new GLProgram
+               if not program.is_ok then
+                       print "Program is not ok: {gl.error.to_s}\nLog:"
+                       print program.info_log
+                       abort
+               end
+               assert_no_gl_error
+
+               # Vertex shader
+               vertex_shader = new GLVertexShader
+               assert vertex_shader.is_ok else print "Vertex shader is not ok: {gl.error}"
+               vertex_shader.source = """
+               attribute vec4 vPosition;
+               void main()
+               {
+                 gl_Position = vPosition;
+               }
+               """@glsl_vertex_shader.to_cstring
+               vertex_shader.compile
+               assert vertex_shader.is_compiled else print "Vertex shader compilation failed with: {vertex_shader.info_log} {program.info_log}"
+               assert_no_gl_error
+
+               # Fragment shader
+               fragment_shader = new GLFragmentShader
+               assert fragment_shader.is_ok else print "Fragment shader is not ok: {gl.error}"
+               fragment_shader.source = """
+               precision mediump float;
+               void main()
+               {
+                       gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
+               }
+               """@glsl_fragment_shader.to_cstring
+               fragment_shader.compile
+               assert fragment_shader.is_compiled else print "Fragment shader compilation failed with: {fragment_shader.info_log}"
+               assert_no_gl_error
+
+               # Attach to program
+               program.attach_shader vertex_shader
+               program.attach_shader fragment_shader
+               program.bind_attrib_location(0, "vPosition")
+               program.link
+               assert program.is_linked else print "Linking failed: {program.info_log}"
+               assert_no_gl_error
+
+               # Draw!
+               var vertices = [0.0, 0.5, 0.0, -0.5, -0.5, 0.0, 0.5, -0.5, 0.0]
+               vertex_array = new VertexArray(0, 3, vertices)
+               vertex_array.attrib_pointer
+       end
+
+       redef fun frame_core
+       do
+               var display = display
+               if display != null then
+                       gl.clear_color(0.5, 0.0, 0.5, 1.0)
+
+                       assert_no_gl_error
+                       gl.viewport(0, 0, display.width, display.height)
+                       gl.clear((new GLBuffer).color)
+                       program.use
+                       vertex_array.enable
+
+                       glDrawArrays(new GLDrawMode.triangles, 0, 3)
+
+                       display.flip
+               end
+       end
+
+       redef fun on_stop
+       do
+               # Clean up
+               program.delete
+               vertex_shader.delete
+               fragment_shader.delete
+
+               # Close gamnit
+               var display = display
+               if display != null then display.close
+       end
+end
+
+if "NIT_TESTING".environ == "true" then exit(0)
+super
diff --git a/lib/gamnit/examples/triangle/src/standalone_triangle.nit b/lib/gamnit/examples/triangle/src/standalone_triangle.nit
new file mode 100644 (file)
index 0000000..04e14db
--- /dev/null
@@ -0,0 +1,112 @@
+# 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.
+
+# Example of using `GamnitDisplay` to setup a screen for custom calls to OpenGL ES 2.0
+#
+# This example does not support the lifecycle of mobile platforms, as such it only works on desktop computers.
+#
+# References:
+# * The book OpenGL ES 2.0 Programming Guide
+# * https://code.google.com/p/opengles-book-samples/source/browse/trunk/LinuxX11/Chapter_2/Hello_Triangle/Hello_Triangle.c
+module standalone_triangle
+
+import app
+import gamnit::display
+
+if "NIT_TESTING".environ == "true" then exit(0)
+
+# Setup gamnit
+var display = new GamnitDisplay
+display.setup
+
+var width = display.width
+var height = display.height
+print "Width: {width}"
+print "Height: {height}"
+
+# Custom calls to OpenGL ES 2.0
+assert_no_gl_error
+assert gl.shader_compiler else print "Cannot compile shaders"
+
+# GL program
+print gl.error.to_s
+var program = new GLProgram
+if not program.is_ok then
+       print "Program is not ok: {gl.error.to_s}\nLog:"
+       print program.info_log
+       abort
+end
+assert_no_gl_error
+
+# Vertex shader
+var vertex_shader = new GLVertexShader
+assert vertex_shader.is_ok else print "Vertex shader is not ok: {gl.error}"
+vertex_shader.source = """
+attribute vec4 vPosition;
+void main()
+{
+  gl_Position = vPosition;
+}
+"""@glsl_vertex_shader.to_cstring
+vertex_shader.compile
+assert vertex_shader.is_compiled else print "Vertex shader compilation failed with: {vertex_shader.info_log} {program.info_log}"
+assert_no_gl_error
+
+# Fragment shader
+var fragment_shader = new GLFragmentShader
+assert fragment_shader.is_ok else print "Fragment shader is not ok: {gl.error}"
+fragment_shader.source = """
+precision mediump float;
+void main()
+{
+       gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
+}
+"""@glsl_fragment_shader.to_cstring
+fragment_shader.compile
+assert fragment_shader.is_compiled else print "Fragment shader compilation failed with: {fragment_shader.info_log}"
+assert_no_gl_error
+
+# Attach to program
+program.attach_shader vertex_shader
+program.attach_shader fragment_shader
+program.bind_attrib_location(0, "vPosition")
+program.link
+assert program.is_linked else print "Linking failed: {program.info_log}"
+assert_no_gl_error
+
+# Draw!
+var vertices = [0.0, 0.5, 0.0, -0.5, -0.5, 0.0, 0.5, -0.5, 0.0]
+var vertex_array = new VertexArray(0, 3, vertices)
+vertex_array.attrib_pointer
+gl.clear_color(0.5, 0.0, 0.5, 1.0)
+for i in [0..1000[ do
+       printn "."
+       assert_no_gl_error
+       gl.viewport(0, 0, width, height)
+       gl.clear((new GLBuffer).color)
+       program.use
+       vertex_array.enable
+
+       glDrawArrays(new GLDrawMode.triangles, 0, 3)
+
+       display.flip
+end
+
+# Clean up
+program.delete
+vertex_shader.delete
+fragment_shader.delete
+
+# Close gamnit
+display.close
index 2fa5b8e..43ec95c 100644 (file)
 
 # Game and multimedia framework for Nit
 module gamnit
+
+import app
+
+import display
+
+import gamnit_android is conditional(android)
+
+redef class App
+
+       # Main `GamnitDisplay` initialized by `on_create`
+       var display: nullable GamnitDisplay = null
+
+       redef fun on_create
+       do
+               super
+
+               var display = new GamnitDisplay
+               display.setup
+               self.display = display
+       end
+
+       # Core of the frame logic, executed only when the display is visible
+       #
+       # This method should be redefined by user modules to customize the behavior of the game.
+       protected fun frame_core do end
+
+       # Full frame logic, executed even if the display is not visible
+       #
+       # This method wraps `frame_core` and other services to be executed in the main app loop.
+       #
+       # To customize the behavior on each turn, it is preferable to redefined `frame_core`.
+       # Still, `frame_full` can be redefined with care for more control.
+       protected fun frame_full
+       do
+               var display = display
+               if display != null then frame_core
+
+               feed_events
+       end
+
+       redef fun run
+       do
+               # TODO manage exit condition
+               loop frame_full
+       end
+
+       # Loop on available events and feed them back to the app
+       #
+       # The implementation varies per platform.
+       private fun feed_events do end
+end
diff --git a/lib/gamnit/gamnit_android.nit b/lib/gamnit/gamnit_android.nit
new file mode 100644 (file)
index 0000000..647c741
--- /dev/null
@@ -0,0 +1,24 @@
+# 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.
+
+# Support services for Gamnit on Android
+module gamnit_android
+
+import android
+
+intrude import gamnit
+
+redef class App
+       redef fun feed_events do app.poll_looper 0
+end
similarity index 96%
rename from lib/gamnit/project.ini
rename to lib/gamnit/package.ini
index 8a930eb..ad9c8cb 100644 (file)
@@ -1,4 +1,4 @@
-[project]
+[package]
 name=gamnit
 tags=game,lib
 maintainer=Alexis Laferrière <alexis.laf@xymus.net>
similarity index 96%
rename from lib/geometry/project.ini
rename to lib/geometry/package.ini
index 2340920..077c7b6 100644 (file)
@@ -1,4 +1,4 @@
-[project]
+[package]
 name=geometry
 tags=algo,lib
 maintainer=Romain Chanoir <romain.chanoir@viacesi.fr>
similarity index 96%
rename from lib/gettext/project.ini
rename to lib/gettext/package.ini
index f16b6c4..d4f369e 100644 (file)
@@ -1,4 +1,4 @@
-[project]
+[package]
 name=gettext
 tags=i18n,lib
 maintainer=Lucas Bajolet <r4pass@hotmail.com>
similarity index 96%
rename from lib/github/project.ini
rename to lib/github/package.ini
index 611019c..030bbd7 100644 (file)
@@ -1,4 +1,4 @@
-[project]
+[package]
 name=github
 tags=web,lib
 maintainer=Alexandre Terrasa <alexandre@moz-code.org>
index 48d49ab..3a1e1c5 100644 (file)
@@ -168,7 +168,7 @@ for i in [0..10000[ do
        gl.clear((new GLBuffer).color)
        program.use
        vertex_array.enable
-       vertex_array.draw_arrays_triangles
+       glDrawArrays(new GLDrawMode.triangles, 0, 3)
        egl_display.swap_buffers(surface)
 end
 
index 4e71e1f..9c3e1d7 100644 (file)
@@ -37,6 +37,7 @@ module glesv2 is
 end
 
 import android::aware
+intrude import c
 
 in "C Header" `{
        #include <GLES2/gl2.h>
@@ -296,38 +297,106 @@ class VertexArray
        # Number of data per vertex
        var count: Int
 
-       protected var glfloat_array: GLfloatArray
+       protected var glfloat_array: NativeGLfloatArray
 
        init(index, count: Int, array: Array[Float])
        do
                self.index = index
                self.count = count
-               self.glfloat_array = new GLfloatArray(array)
+               self.glfloat_array = new NativeGLfloatArray(array.length)
+               for k in [0..array.length[ do
+                       glfloat_array[k] = array[k]
+               end
        end
 
        fun attrib_pointer do attrib_pointer_intern(index, count, glfloat_array)
-       private fun attrib_pointer_intern(index, count: Int, array: GLfloatArray) `{
+       private fun attrib_pointer_intern(index, count: Int, array: NativeGLfloatArray) `{
                glVertexAttribPointer(index, count, GL_FLOAT, GL_FALSE, 0, array);
        `}
 
-       fun enable do enable_intern(index)
-       private fun enable_intern(index: Int) `{ glEnableVertexAttribArray(index); `}
+       # Enable this vertex attribute array
+       fun enable do glEnableVertexAttribArray(index)
 
-       fun draw_arrays_triangles do draw_arrays_triangles_intern(index, count)
-       private fun draw_arrays_triangles_intern(index, count: Int) `{
-               glDrawArrays(GL_TRIANGLES, index, count);
-       `}
+       # Disable this vertex attribute array
+       fun disable do glDisableVertexAttribArray(index)
 end
 
+# Enable the generic vertex attribute array at `index`
+fun glEnableVertexAttribArray(index: Int) `{ glEnableVertexAttribArray(index); `}
+
+# Disable the generic vertex attribute array at `index`
+fun glDisableVertexAttribArray(index: Int) `{ glDisableVertexAttribArray(index); `}
+
+# Render primitives from array data
+fun glDrawArrays(mode: GLDrawMode, from, count: Int) `{ glDrawArrays(mode, from, count); `}
+
+# Define an array of generic vertex attribute data
+fun glVertexAttribPointer(index, size: Int, typ: GLDataType, normalized: Bool, stride: Int, array: NativeGLfloatArray) `{
+       glVertexAttribPointer(index, size, typ, normalized, stride, array);
+`}
+
+# Specify the value of a generic vertex attribute
+fun glVertexAttrib1f(index: Int, x: Float) `{ glVertexAttrib1f(index, x); `}
+
+# Specify the value of a generic vertex attribute
+fun glVertexAttrib2f(index: Int, x, y: Float) `{ glVertexAttrib2f(index, x, y); `}
+
+# Specify the value of a generic vertex attribute
+fun glVertexAttrib3f(index: Int, x, y, z: Float) `{ glVertexAttrib3f(index, x, y, z); `}
+
+# Specify the value of a generic vertex attribute
+fun glVertexAttrib4f(index: Int, x, y, z, w: Float) `{ glVertexAttrib4f(index, x, y, z, w); `}
+
+# Specify the value of a uniform variable for the current program object
+fun glUniform1i(index, x: Int) `{ glUniform1i(index, x); `}
+
+# Specify the value of a uniform variable for the current program object
+fun glUniform2i(index, x, y: Int) `{ glUniform2i(index, x, y); `}
+
+# Specify the value of a uniform variable for the current program object
+fun glUniform3i(index, x, y, z: Int) `{ glUniform3i(index, x, y, z); `}
+
+# Specify the value of a uniform variable for the current program object
+fun glUniform4i(index, x, y, z, w: Int) `{ glUniform4i(index, x, y, z, w); `}
+
+# TODO glUniform*f
+
 # Low level array of `Float`
-extern class GLfloatArray `{GLfloat *`}
-       new (array: Array[Float]) import Array[Float].length, Array[Float].[] `{
-               int i;
-               int len = Array_of_Float_length(array);
-               GLfloat *vertex_array = malloc(sizeof(GLfloat)*len);
-               for (i = 0; i < len; i ++) vertex_array[i] = Array_of_Float__index(array, i);
-               return vertex_array;
-       `}
+class GLfloatArray
+       super CArray[Float]
+       redef type NATIVE: NativeGLfloatArray
+
+       init do native_array = new NativeGLfloatArray(length)
+
+       # Create with the content of `array`
+       new from(array: Array[Float])
+       do
+               var arr = new GLfloatArray(array.length)
+               arr.fill_from array
+               return arr
+       end
+
+       # Fill with the content of `array`
+       fun fill_from(array: Array[Float])
+       do
+               assert length >= array.length
+               for k in [0..array.length[ do
+                       self[k] = array[k]
+               end
+       end
+end
+
+# An array of `GLfloat` in C (`GLfloat*`)
+extern class NativeGLfloatArray `{ GLfloat* `}
+       super NativeCArray
+       redef type E: Float
+
+       new(size: Int) `{ return calloc(size, sizeof(GLfloat)); `}
+
+       redef fun [](index) `{ return self[index]; `}
+       redef fun []=(index, val) `{ self[index] = val; `}
+
+       redef fun +(offset) `{ return self + offset; `}
 end
 
 # General type for OpenGL enumerations
@@ -375,30 +444,47 @@ do
        end
 end
 
-# Texture minifying function
-#
-# Used by: `GLES::tex_parameter_min_filter`
-extern class GLTextureMinFilter
-       super GLEnum
+# Does `name` corresponds to a texture?
+fun glIsTexture(name: Int): Bool `{ return glIsTexture(name); `}
 
-       new nearest `{ return GL_NEAREST; `}
-       new linear `{ return GL_LINEAR; `}
-end
+# Bind the named `texture` to a `target`
+fun glBindTexture(target: GLTextureTarget, texture: Int) `{ glBindTexture(target, texture); `}
 
-# Texture magnification function
-#
-# Used by: `GLES::tex_parameter_mag_filter`
-extern class GLTextureMagFilter
+# Set pixel storage modes
+fun glPixelStorei(parameter: GLPack, val: Int) `{ glPixelStorei(parameter, val); `}
+
+# Symbolic name of the parameter to be set with `glPixelStorei`
+extern class GLPack
        super GLEnum
+end
+
+# Parameter to specify the alignment requirements for the start of each pixel row in memory
+fun gl_PACK_ALIGNEMENT: GLPack `{ return GL_PACK_ALIGNMENT; `}
+
+# Parameter to specify the alignment requirements for the start of each pixel row in memory
+fun gl_UNPACK_ALIGNEMENT: GLPack `{ return GL_UNPACK_ALIGNMENT; `}
+
+# TODO GL_PACK_ROW_LENGTH, GL_PACK_IMAGE_HEIGHT, GL_PACK_SKIP_PIXELS, GL_PACK_SKIP_ROWS, GL_PACK_SKIP_IMAGES
+# GL_UNPACK_ROW_LENGTH, GL_UNPACK_IMAGE_HEIGHT, GL_UNPACK_SKIP_PIXELS, GL_UNPACK_SKIP_ROWS, GL_UNPACK_SKIP_IMAGES
 
-       new nearest `{ return GL_NEAREST; `}
-       new linear `{ return GL_LINEAR; `}
-       new nearest_mipmap_nearest `{ return GL_NEAREST_MIPMAP_NEAREST; `}
-       new linear_mipmap_nearest `{ return GL_LINEAR_MIPMAP_NEAREST; `}
-       new nearest_mipmap_linear `{ return GL_NEAREST_MIPMAP_LINEAR; `}
-       new linear_mipmap_linear `{ return GL_LINEAR_MIPMAP_LINEAR; `}
+# Specify a two-dimensional texture image
+fun glTexImage2D(target: GLTextureTarget, level, internalformat, width, height, border: Int,
+                 format: GLPixelFormat, typ: GLPixelType, data: NativeCByteArray) `{
+       glTexImage2D(target, level, internalformat, width, height, border, format, typ, data);
+`}
+
+# Texture minifying and magnifying function
+extern class GLTextureFilter
+       super GLEnum
 end
 
+fun gl_NEAREST: GLTextureFilter `{ return GL_NEAREST; `}
+fun gl_LINEAR: GLTextureFilter `{ return GL_LINEAR; `}
+fun gl_NEAREST_MIPMAP_NEAREST: GLTextureFilter `{ return GL_NEAREST_MIPMAP_NEAREST; `}
+fun gl_LINEAR_MIPMAP_NEAREST: GLTextureFilter `{ return GL_LINEAR_MIPMAP_NEAREST; `}
+fun gl_NEAREST_MIPMAP_NINEAR: GLTextureFilter `{ return GL_NEAREST_MIPMAP_LINEAR; `}
+fun gl_LINEAR_MIPMAP_LINEAR: GLTextureFilter `{ return GL_LINEAR_MIPMAP_LINEAR; `}
+
 # Wrap parameter of a texture
 #
 # Used by: `tex_parameter_wrap_*`
@@ -411,15 +497,19 @@ extern class GLTextureWrap
 end
 
 # Target texture
-#
-# Used by: `tex_parameter_*`
 extern class GLTextureTarget
        super GLEnum
-
-       new flat `{ return GL_TEXTURE_2D; `}
-       new cube_map `{ return GL_TEXTURE_CUBE_MAP; `}
 end
 
+# Two-dimensional texture
+fun gl_TEXTURE_2D: GLTextureTarget `{ return GL_TEXTURE_2D; `}
+
+# Cube map texture
+fun gl_TEXTURE_CUBE_MAP: GLTextureTarget `{ return GL_TEXTURE_CUBE_MAP; `}
+
+# TODO GL_TEXTURE_CUBE_MAP_POSITIVE_X, GL_TEXTURE_CUBE_MAP_NEGATIVE_X, GL_TEXTURE_CUBE_MAP_POSITIVE_Y,
+# GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, GL_TEXTURE_CUBE_MAP_POSITIVE_Z, GL_TEXTURE_CUBE_MAP_NEGATIVE_Z
+
 # A server-side capability
 class GLCap
 
@@ -439,6 +529,52 @@ class GLCap
        redef fun hash do return val
        redef fun ==(o) do return o != null and is_same_type(o) and o.hash == self.hash
 end
+
+# Attach a renderbuffer object to a framebuffer object
+fun glFramebufferRenderbuffer(target: GLFramebufferTarget, attachment: GLAttachment,
+                              renderbuffertarget: GLRenderbufferTarget, renderbuffer: Int) `{
+       glFramebufferRenderbuffer(target, attachment, renderbuffertarget, renderbuffer);
+`}
+
+# Establish data storage, `format` and dimensions of the `target` renderbuffer object's image
+fun glRenderbufferStorage(target: GLRenderbufferTarget, format: GLRenderbufferFormat, width, height: Int) `{
+       glRenderbufferStorage(GL_RENDERBUFFER, format, width, height);
+`}
+
+# Format for a renderbuffer
+extern class GLRenderbufferFormat
+       super GLEnum
+end
+
+# 4 red, 4 green, 4 blue, 4 alpha bits format
+fun gl_RGBA4: GLRenderbufferFormat `{ return GL_RGBA4; `}
+
+# 5 red, 6 green, 5 blue bits format
+fun gl_RGB565: GLRenderbufferFormat `{ return GL_RGB565; `}
+
+# 5 red, 5 green, 5 blue, 1 alpha bits format
+fun gl_RGB_A1: GLRenderbufferFormat `{ return GL_RGB5_A1; `}
+
+# 16 depth bits format
+fun gl_DEPTH_COMPNENT16: GLRenderbufferFormat `{ return GL_DEPTH_COMPONENT16; `}
+
+# 8 stencil bits format
+fun gl_STENCIL_INDEX8: GLRenderbufferFormat `{ return GL_STENCIL_INDEX8; `}
+
+# Renderbuffer attachment point to a framebuffer
+extern class GLAttachment
+       super GLEnum
+end
+
+# First color attachment point
+fun gl_COLOR_ATTACHMENT0: GLAttachment `{ return GL_COLOR_ATTACHMENT0; `}
+
+# Depth attachment point
+fun gl_DEPTH_ATTACHMENT: GLAttachment `{ return GL_DEPTH_ATTACHMENT; `}
+
+# Stencil attachment
+fun gl_STENCIL_ATTACHMENT: GLAttachment `{ return GL_STENCIL_ATTACHMENT; `}
+
 redef class Sys
        private var gles = new GLES is lazy
 end
@@ -544,20 +680,20 @@ class GLES
        #
        # Foreign: glReadPixel
        fun read_pixels(x, y, width, height: Int, format: GLPixelFormat, typ: GLPixelType, data: Pointer) `{
-               glReadPixels(x, y, width, height, GL_RGBA, GL_UNSIGNED_BYTE, data);
+               glReadPixels(x, y, width, height, format, typ, data);
        `}
 
        # Set the texture minifying function
        #
        # Foreign: glTexParameter with GL_TEXTURE_MIN_FILTER
-       fun tex_parameter_min_filter(target: GLTextureTarget, value: GLTextureMinFilter) `{
+       fun tex_parameter_min_filter(target: GLTextureTarget, value: GLTextureFilter) `{
                glTexParameteri(target, GL_TEXTURE_MIN_FILTER, value);
        `}
 
        # Set the texture magnification function
        #
        # Foreign: glTexParameter with GL_TEXTURE_MAG_FILTER
-       fun tex_parameter_mag_filter(target: GLTextureTarget, value: GLTextureMagFilter) `{
+       fun tex_parameter_mag_filter(target: GLTextureTarget, value: GLTextureFilter) `{
                glTexParameteri(target, GL_TEXTURE_MAG_FILTER, value);
        `}
 
@@ -619,6 +755,23 @@ fun glHint(target: GLHintTarget, mode: GLHintMode) `{
        glHint(target, mode);
 `}
 
+# Generate and fill set of mipmaps for the texture object `target`
+fun glGenerateMipmap(target: GLTextureTarget) `{ glGenerateMipmap(target); `}
+
+# Bind the named `buffer` object
+fun glBindBuffer(target: GLArrayBuffer, buffer: Int) `{ glBindBuffer(target, buffer); `}
+
+# Target to which bind the buffer with `glBindBuffer`
+extern class GLArrayBuffer
+       super GLEnum
+end
+
+# Array buffer target
+fun gl_ARRAY_BUFFER: GLArrayBuffer `{ return GL_ARRAY_BUFFER; `}
+
+# Element array buffer
+fun gl_ELEMENT_ARRAY_BUFFER: GLArrayBuffer `{ return GL_ELEMENT_ARRAY_BUFFER; `}
+
 # Completeness status of a framebuffer object
 fun glCheckFramebufferStatus(target: GLFramebufferTarget): GLFramebufferStatus `{
        return glCheckFramebufferStatus(target);
@@ -686,6 +839,12 @@ fun gl_NICEST: GLHintMode `{ return GL_NICEST; `}
 # No preference
 fun gl_DONT_CARE: GLHintMode `{ return GL_DONT_CARE; `}
 
+# Attach a level of a texture object as a logical buffer to the currently bound framebuffer object
+fun glFramebufferTexture2D(target: GLFramebufferTarget, attachment: GLAttachment,
+                           texture_target: GLTextureTarget,  texture, level: Int) `{
+       glFramebufferTexture2D(target, attachment, texture_target, texture, level);
+`}
+
 # Entry point to OpenGL server-side capabilities
 class GLCapabilities
 
similarity index 97%
rename from lib/glesv2/project.ini
rename to lib/glesv2/package.ini
index 9dec9a4..5fcd07e 100644 (file)
@@ -1,4 +1,4 @@
-[project]
+[package]
 name=glesv2
 tags=graphics,wrapper,lib
 maintainer=Alexis Laferrière <alexis.laf@xymus.net>
similarity index 97%
rename from lib/graphs/project.ini
rename to lib/graphs/package.ini
index a8c1513..41dde41 100644 (file)
@@ -1,4 +1,4 @@
-[project]
+[package]
 name=graphs
 tags=algo,lib
 maintainer=Alexandre Blondin Massé <alexandre.blondin.masse@gmail.com>
similarity index 96%
rename from lib/gtk/project.ini
rename to lib/gtk/package.ini
index a31bf4d..1b7d4f4 100644 (file)
@@ -1,4 +1,4 @@
-[project]
+[package]
 name=gtk
 tags=ui,wrapper,lib
 maintainer=Alexis Laferrière <alexis.laf@xymus.net>
index d1ca440..075ff53 100644 (file)
@@ -1,4 +1,4 @@
-[project]
+[package]
 name=hash_debug
 tags=debug,lib
 maintainer=Jean Privat <jean@pryen.org>
similarity index 96%
rename from lib/html/project.ini
rename to lib/html/package.ini
index 098a6b1..42df9f4 100644 (file)
@@ -1,4 +1,4 @@
-[project]
+[package]
 name=html
 tags=format,lib
 maintainer=Alexandre Terrasa <alexandre@moz-code.org>
index 205c91a..bc1adff 100644 (file)
@@ -1,4 +1,4 @@
-[project]
+[package]
 name=ini
 tags=format,lib
 maintainer=Alexandre Terrasa <alexandre@moz-code.org>
similarity index 96%
rename from lib/ios/project.ini
rename to lib/ios/package.ini
index 9f72e4d..22034ae 100644 (file)
@@ -1,4 +1,4 @@
-[project]
+[package]
 name=ios
 tags=wrapper,lib
 maintainer=Alexis Laferrière <alexis.laf@xymus.net>
similarity index 96%
rename from lib/java/project.ini
rename to lib/java/package.ini
index 59aa607..41d7e23 100644 (file)
@@ -1,4 +1,4 @@
-[project]
+[package]
 name=java
 tags=java,wrapper,lib
 maintainer=Alexis Laferrière <alexis.laf@xymus.net>
similarity index 96%
rename from lib/json/project.ini
rename to lib/json/package.ini
index 0f67a08..41483ef 100644 (file)
@@ -1,4 +1,4 @@
-[project]
+[package]
 name=json
 tags=format,lib
 maintainer=Alexis Laferrière <alexis.laf@xymus.net>
index 2db3b5c..c3a50c1 100644 (file)
@@ -1,4 +1,4 @@
-[project]
+[package]
 name=jvm
 tags=java,wrapper,lib
 maintainer=Alexis Laferrière <alexis.laf@xymus.net>
index 28443b8..2c8ffea 100644 (file)
@@ -1,4 +1,4 @@
-[project]
+[package]
 name=libevent
 tags=wrapper,lib
 maintainer=Alexis Laferrière <alexis.laf@xymus.net>
index 8b90102..04a0c5d 100644 (file)
 module linux
 
 import app
+
+redef class App
+       redef fun setup
+       do
+               super
+
+               on_create
+               on_restore_state
+               on_start
+               on_resume
+       end
+
+       redef fun run
+       do
+               super
+
+               on_pause
+               on_save_state
+               on_stop
+               on_destroy
+       end
+end
similarity index 96%
rename from lib/linux/project.ini
rename to lib/linux/package.ini
index 8a8f7e5..11f52d8 100644 (file)
@@ -1,4 +1,4 @@
-[project]
+[package]
 name=linux
 tags=lib
 maintainer=Alexis Laferrière <alexis.laf@xymus.net>
index 1bb8815..b9e2f6a 100644 (file)
@@ -758,8 +758,11 @@ class HTMLDecorator
        end
 
        redef fun add_code(v, block) do
-               if block isa BlockFence and block.meta != null then
-                       v.add "<pre class=\"{block.meta.to_s}\"><code>"
+               var meta = block.meta
+               if meta != null then
+                       v.add "<pre class=\""
+                       append_value(v, meta)
+                       v.add "\"><code>"
                else
                        v.add "<pre><code>"
                end
@@ -1173,6 +1176,26 @@ abstract class Block
                        block = block.next
                end
        end
+
+       # The raw content of the block as a multi-line string.
+       fun raw_content: String do
+               var infence = self isa BlockFence
+               var text = new FlatBuffer
+               var line = self.block.first_line
+               while line != null do
+                       if not line.is_empty then
+                               var str = line.value
+                               if not infence and str.has_prefix("    ") then
+                                       text.append str.substring(4, str.length - line.trailing)
+                               else
+                                       text.append str
+                               end
+                       end
+                       text.append "\n"
+                       line = line.next
+               end
+               return text.write_to_string
+       end
 end
 
 # A block without any markdown specificities.
@@ -1213,6 +1236,9 @@ end
 class BlockCode
        super Block
 
+       # Any string found after fence token.
+       var meta: nullable Text
+
        # Number of char to skip at the beginning of the line.
        #
        # Block code lines start at 4 spaces.
@@ -1239,9 +1265,6 @@ end
 class BlockFence
        super BlockCode
 
-       # Any string found after fence token.
-       var meta: nullable Text
-
        # Fence code lines start at 0 spaces.
        redef var line_start = 0
 end
similarity index 96%
rename from lib/markdown/project.ini
rename to lib/markdown/package.ini
index 89446e0..c66f5a6 100644 (file)
@@ -1,4 +1,4 @@
-[project]
+[package]
 name=markdown
 tags=format,lib
 maintainer=Alexandre Terrasa <alexandre@moz-code.org>
index 24082f0..c24d0d6 100644 (file)
@@ -1,4 +1,4 @@
-[project]
+[package]
 name=md5
 tags=encoding,lib
 maintainer=Alexis Laferrière <alexis.laf@xymus.net>
index f2bee33..cc1da56 100644 (file)
@@ -1,4 +1,4 @@
-[project]
+[package]
 name=meta
 tags=lib
 maintainer=Jean Privat <jean@pryen.org>
index 938bfd8..7bc03a0 100644 (file)
@@ -35,21 +35,6 @@ redef class App
                display = new Opengles1Display
 
                super
-
-               on_create
-               on_restore_state
-               on_start
-               on_resume
-       end
-
-       redef fun run
-       do
-               super
-
-               on_pause
-               on_save_state
-               on_stop
-               on_destroy
        end
 
        redef fun generate_input
similarity index 96%
rename from lib/mnit/project.ini
rename to lib/mnit/package.ini
index 8b19d29..2239f95 100644 (file)
@@ -1,4 +1,4 @@
-[project]
+[package]
 name=mnit
 tags=lib
 maintainer=Alexis Laferrière <alexis.laf@xymus.net>
similarity index 96%
rename from lib/mongodb/project.ini
rename to lib/mongodb/package.ini
index 5c13675..f492aa4 100644 (file)
@@ -1,4 +1,4 @@
-[project]
+[package]
 name=mongodb
 tags=database,lib
 maintainer=Alexandre Terrasa <alexandre@moz-code.org>
index 0f4e4e3..44b4af9 100644 (file)
@@ -1,4 +1,4 @@
-[project]
+[package]
 name=more_collections
 tags=algo,lib
 maintainer=Jean Privat <jean@pryen.org>
index c687789..730b993 100644 (file)
@@ -1,4 +1,4 @@
-[project]
+[package]
 name=mpd
 tags=sound,lib
 maintainer=Alexis Laferrière <alexis.laf@xymus.net>
similarity index 96%
rename from lib/mpi/project.ini
rename to lib/mpi/package.ini
index 8a3f9cd..40a0e31 100644 (file)
@@ -1,4 +1,4 @@
-[project]
+[package]
 name=mpi
 tags=parallelism,lib
 maintainer=Alexis Laferrière <alexis.laf@xymus.net>
similarity index 96%
rename from lib/neo4j/project.ini
rename to lib/neo4j/package.ini
index 981b3ec..9cab771 100644 (file)
@@ -1,4 +1,4 @@
-[project]
+[package]
 name=neo4j
 tags=database,lib
 maintainer=Alexandre Terrasa <alexandre@moz-code.org>
index ae672b3..e905712 100644 (file)
@@ -1,4 +1,4 @@
-[project]
+[package]
 name=nitcc_runtime
 tags=lib
 maintainer=Jean Privat <jean@pryen.org>
similarity index 96%
rename from lib/nitcorn/project.ini
rename to lib/nitcorn/package.ini
index 4dd2c83..0ea320a 100644 (file)
@@ -1,4 +1,4 @@
-[project]
+[package]
 name=nitcorn
 tags=network,lib
 maintainer=Alexis Laferrière <alexis.laf@xymus.net>
index 200dbd0..7103e49 100644 (file)
@@ -1,4 +1,4 @@
-[project]
+[package]
 name=niti_runtime
 tags=lib
 maintainer=Jean Privat <jean@pryen.org>
index 2c1968d..3917ab3 100644 (file)
@@ -1,4 +1,4 @@
-[project]
+[package]
 name=noise
 tags=algo,lib
 maintainer=Alexis Laferrière <alexis.laf@xymus.net>
index b7e8fc8..ed8a3ca 100644 (file)
@@ -1,4 +1,4 @@
-[project]
+[package]
 name=opts
 tags=cli,lib
 maintainer=Jean Privat <jean@pryen.org>
index abb5df0..840bb11 100644 (file)
@@ -1,4 +1,4 @@
-[project]
+[package]
 name=ordered_tree
 tags=algo,lib
 maintainer=Jean Privat <jean@pryen.org>
similarity index 100%
rename from tests/alt/projects.ini
rename to lib/packages.ini
index db32dbd..28d65d4 100644 (file)
@@ -1,4 +1,4 @@
-[project]
+[package]
 name=parser_base
 tags=format,lib
 maintainer=Lucas Bajolet <r4pass@hotmail.com>
index d309a96..f4ce782 100644 (file)
@@ -1,4 +1,4 @@
-[project]
+[package]
 name=perfect_hashing
 tags=algo,lib
 maintainer=Julien Pagès <julien.projet@gmail.com>
index a6977ec..bcd67ff 100644 (file)
@@ -1,4 +1,4 @@
-[project]
+[package]
 name=performance_analysis
 tags=debug,lib
 maintainer=Alexis Laferrière <alexis.laf@xymus.net>
index 1a558a0..6d11449 100644 (file)
@@ -1,4 +1,4 @@
-[project]
+[package]
 name=pipeline
 tags=algo,lib
 maintainer=Jean Privat <jean@pryen.org>
similarity index 96%
rename from lib/pnacl/project.ini
rename to lib/pnacl/package.ini
index dd0b3da..c3e650b 100644 (file)
@@ -1,4 +1,4 @@
-[project]
+[package]
 name=pnacl
 tags=platform,lib
 maintainer=Johan Kayser <johan.kayser@viacesi.fr>
index e5b5d3f..df6546f 100644 (file)
@@ -1,4 +1,4 @@
-[project]
+[package]
 name=poset
 tags=algo,lib
 maintainer=Jean Privat <jean@pryen.org>
index 16b1708..680e8ee 100644 (file)
@@ -1,4 +1,4 @@
-[project]
+[package]
 name=posix_ext
 tags=wrapper,lib
 maintainer=Alexis Laferrière <alexis.laf@xymus.net>
similarity index 96%
rename from lib/privileges/project.ini
rename to lib/privileges/package.ini
index e92dfbc..7c09a7c 100644 (file)
@@ -1,4 +1,4 @@
-[project]
+[package]
 name=privileges
 tags=lib
 maintainer=Alexis Laferrière <alexis.laf@xymus.net>
index 5297892..63800ab 100644 (file)
@@ -1,4 +1,4 @@
-[project]
+[package]
 name=progression
 tags=lib
 maintainer=Jean-Christophe Beaupré <jcbrinfo@users.noreply.github.com>
similarity index 97%
rename from lib/pthreads/project.ini
rename to lib/pthreads/package.ini
index 292b853..bb5bd5f 100644 (file)
@@ -1,4 +1,4 @@
-[project]
+[package]
 name=pthreads
 tags=parallelism,wrapper,lib
 maintainer=Alexis Laferrière <alexis.laf@xymus.net>
index e80fb32..7ca1264 100644 (file)
@@ -1,4 +1,4 @@
-[project]
+[package]
 name=realtime
 tags=lib
 maintainer=Alexis Laferrière <alexis.laf@xymus.net>
index 8fa6a63..e221815 100644 (file)
@@ -1,4 +1,4 @@
-[project]
+[package]
 name=ropes_debug
 tags=debug,lib
 maintainer=Lucas Bajolet <r4pass@hotmail.com>
similarity index 97%
rename from lib/sax/project.ini
rename to lib/sax/package.ini
index 71d9bc2..d2cd8b3 100644 (file)
@@ -1,4 +1,4 @@
-[project]
+[package]
 name=sax
 tags=xml,format,lib
 maintainer=Jean-Christophe Beaupré <jcbrinfo@users.noreply.github.com>
similarity index 97%
rename from lib/saxophonit/project.ini
rename to lib/saxophonit/package.ini
index 30e6534..47bbfd0 100644 (file)
@@ -1,4 +1,4 @@
-[project]
+[package]
 name=saxophonit
 tags=xml,format,lib
 maintainer=Jean-Christophe Beaupré <jcbrinfo@users.noreply.github.com>
index 8633dcd..c25d427 100644 (file)
@@ -1,4 +1,4 @@
-[project]
+[package]
 name=scene2d
 tags=game,lib
 maintainer=Jean Privat <jean@pryen.org>
index 4020e46..a61fc18 100644 (file)
@@ -1,4 +1,4 @@
-[project]
+[package]
 name=sdl
 tags=graphics,wrapper,lib
 maintainer=Alexis Laferrière <alexis.laf@xymus.net>
similarity index 96%
rename from lib/sdl2/project.ini
rename to lib/sdl2/package.ini
index 5a919d5..688490d 100644 (file)
@@ -1,4 +1,4 @@
-[project]
+[package]
 name=sdl2
 tags=graphics,wrapper,lib
 maintainer=Alexis Laferrière <alexis.laf@xymus.net>
index 09e35a1..5b714a3 100644 (file)
@@ -1,4 +1,4 @@
-[project]
+[package]
 name=sendmail
 tags=network,lib
 maintainer=Alexis Laferrière <alexis.laf@xymus.net>
similarity index 97%
rename from lib/serialization/project.ini
rename to lib/serialization/package.ini
index b124e84..7bcdcc1 100644 (file)
@@ -1,4 +1,4 @@
-[project]
+[package]
 name=serialization
 tags=lib
 maintainer=Alexis Laferrière <alexis.laf@xymus.net>
index ff6a8e7..bb9de0d 100644 (file)
@@ -1,4 +1,4 @@
-[project]
+[package]
 name=sexp
 tags=format,lib
 maintainer=Lucas Bajolet <r4pass@hotmail.com>
index 3b0a2e2..5d1c7d5 100644 (file)
@@ -1,4 +1,4 @@
-[project]
+[package]
 name=sha1
 tags=encoding,lib
 maintainer=Lucas Bajolet <r4pass@hotmail.com>
index 8dc022a..24d8750 100644 (file)
@@ -1,4 +1,4 @@
-[project]
+[package]
 name=signals
 tags=wrapper,lib
 maintainer=Alexis Laferrière <alexis.laf@xymus.net>
similarity index 96%
rename from lib/socket/project.ini
rename to lib/socket/package.ini
index 425c71e..746114b 100644 (file)
@@ -1,4 +1,4 @@
-[project]
+[package]
 name=socket
 tags=network,lib
 maintainer=Alexis Laferrière <alexis.laf@xymus.net>
similarity index 96%
rename from lib/sqlite3/project.ini
rename to lib/sqlite3/package.ini
index f995fb3..969906b 100644 (file)
@@ -1,4 +1,4 @@
-[project]
+[package]
 name=sqlite3
 tags=database,lib
 maintainer=Alexis Laferrière <alexis.laf@xymus.net>
index 4e237cc..f726f17 100644 (file)
@@ -1,4 +1,4 @@
-[project]
+[package]
 name=standard
 tags=lib
 maintainer=Jean Privat <jean@pryen.org>
index e26d60d..671b668 100644 (file)
@@ -1,4 +1,4 @@
-[project]
+[package]
 name=symbol
 tags=lib
 maintainer=Jean Privat <jean@pryen.org>
similarity index 96%
rename from lib/template/project.ini
rename to lib/template/package.ini
index 110f7d1..583add3 100644 (file)
@@ -1,4 +1,4 @@
-[project]
+[package]
 name=template
 tags=lib
 maintainer=Jean Privat <jean@pryen.org>
index 2004d3c..a32a29c 100644 (file)
@@ -1,4 +1,4 @@
-[project]
+[package]
 name=test_suite
 tags=devel,lib
 maintainer=Alexandre Terrasa <alexandre@moz-code.org>
similarity index 96%
rename from lib/trees/project.ini
rename to lib/trees/package.ini
index 20467d4..5cd0e35 100644 (file)
@@ -1,4 +1,4 @@
-[project]
+[package]
 name=trees
 tags=algo,lib
 maintainer=Alexandre Terrasa <alexandre@moz-code.org>
similarity index 96%
rename from lib/websocket/project.ini
rename to lib/websocket/package.ini
index e6bd0fc..842ea3c 100644 (file)
@@ -1,4 +1,4 @@
-[project]
+[package]
 name=websocket
 tags=network,lib
 maintainer=Lucas Bajolet <r4pass@hotmail.com>
index 12fa59e..d103b5c 100644 (file)
@@ -1,4 +1,4 @@
-[project]
+[package]
 name=x11
 tags=ui,lib
 maintainer=Alexis Laferrière <alexis.laf@xymus.net>
similarity index 97%
rename from lib/xdg_basedir/project.ini
rename to lib/xdg_basedir/package.ini
index cf51920..8d154ae 100644 (file)
@@ -1,4 +1,4 @@
-[project]
+[package]
 name=xdg_basedir
 tags=wrapper,lib
 maintainer=Alexis Laferrière <alexis.laf@xymus.net>
index bb8dd13..363a8f9 100644 (file)
@@ -53,7 +53,7 @@ function NitComplete()
                let g:acp_behaviorKeywordIgnores = ['new', 'var', 'in', 'do', 'els', 'end', 'ret', 'for', 'fun']
 
                " Use nitls to compute all interesting files from the current directory and the standard library
-               for file in split(system('nitls -M standard .', '\n'))
+               for file in split(system('nitls -M core .', '\n'))
                        silent let &complete = &complete . ',s' . file
                        silent set complete?
                endfor
index b7fffc9..5fa7f48 100644 (file)
@@ -1,6 +1,6 @@
 # NAME
 
-nitls - lists the projects, groups and paths of Nit sources files.
+nitls - lists the packages, groups and paths of Nit sources files.
 
 # SYNOPSIS
 
@@ -8,7 +8,7 @@ nitls [*options*] [*FILE*]...
 
 # DESCRIPTION
 
-`nitls` is used to list Nit files in directories and extract the module-group-project relation.
+`nitls` is used to list Nit files in directories and extract the module-group-package relation.
 
 It is basically a `ls` or a simple `find` specialized on `.nit` source files.
 
@@ -31,7 +31,7 @@ Show the tree of modules from the current directory.
 
     $ nitls -t
 
-Show the list of projects imported by the modules of the current directory.
+Show the list of packages imported by the modules of the current directory.
 
     $ nitls -d -P *.nit
 
@@ -43,24 +43,24 @@ Each combination of option
 
 Three presentation modes are available.
 
-### `-P`, `--project`
-List projects in a flat list (default).
+### `-P`, `--package`
+List packages in a flat list (default).
 
-Only project are displayed (and not the individual files).
+Only package are displayed (and not the individual files).
 
 ### `-t`, `--tree`
-List source files in their groups and projects.
+List source files in their groups and packages.
 
-Each `.nit` file is presented in a tree of projects and groups.
+Each `.nit` file is presented in a tree of packages and groups.
 
 ### `-s`, `--source`
 List source files in a flat list.
 
-Each `.nit` file is presented indivitually.
+Each `.nit` file is presented individually.
 
 The three modes are exclusives.
 
-The default mode is `--project` unless one on the argument is a group, then it is `--group`.
+The default mode is `--package` unless one on the argument is a group, then it is `--group`.
 
 ## COLLECT
 
@@ -74,12 +74,12 @@ List dependencies of given modules
 
 All imported modules are also considered.
 
-In --tree and --source modes, the modules direclty imported are also displayed.
+In --tree and --source modes, the modules directly imported are also displayed.
 
 ### `-k`, `--keep`
 Ignore errors and files that are not a Nit source file.
 
-When a file that is not a valid Nit module is encoutered, it is ignored and the rest of the files are
+When a file that is not a valid Nit module is encountered, it is ignored and the rest of the files are
 processed.
 
 Without this option, an error message is displayed and nitls terminates on such a case.
index edf0a16..79c2f14 100644 (file)
@@ -280,7 +280,7 @@ redef class MExplicitCast
 
                        var from_var = nitni_visitor.var_from_c("from", from)
                        from_var = nitni_visitor.box_extern(from_var, from)
-                       var recv_var = nitni_visitor.type_test(from_var, to, "FFI isa")
+                       var recv_var = nitni_visitor.type_test(from_var, to, "isa")
                        nitni_visitor.add("return {recv_var};")
 
                        nitni_visitor.add("\}")
@@ -316,7 +316,7 @@ redef class MExplicitCast
                        from_var = nitni_visitor.box_extern(from_var, from)
 
                        ## test type
-                       var check = nitni_visitor.type_test(from_var, to, "FFI cast")
+                       var check = nitni_visitor.type_test(from_var, to, "as")
                        nitni_visitor.add("if (!{check}) \{")
                        nitni_visitor.add_abort("FFI cast failed")
                        nitni_visitor.add("\}")
index 5d693b1..96b1a40 100644 (file)
@@ -39,7 +39,7 @@ redef class MEntity
 
        # Returns the mentity name with short signature.
        #
-       # * MProject: `foo`
+       # * MPackage: `foo`
        # * MGroup: `foo`
        # * MModule: `foo`
        # * MClass: `Foo[E]`
@@ -53,7 +53,7 @@ redef class MEntity
 
        # Returns the complete MEntity declaration (modifiers + name + signature).
        #
-       # * MProject: `project foo`
+       # * MPackage: `package foo`
        # * MGroup: `group foo`
        # * MModule: `module foo`
        # * MClass: `private abstract class Foo[E: Object]`
@@ -70,10 +70,10 @@ redef class MEntity
 
        # Returns `self` namespace formatted for console.
        #
-       # * MProject: `mproject`
-       # * MGroup: `mproject(::group)`
+       # * MPackage: `mpackage`
+       # * MGroup: `mpackage(::group)`
        # * MModule: `mgroup::mmodule`
-       # * MClass: `mproject::mclass`
+       # * MClass: `mpackage::mclass`
        # * MClassDef: `mmodule::mclassdef`
        # * MProperty: `mclass::mprop`
        # * MPropdef: `mclassdef:mpropdef`
@@ -158,8 +158,8 @@ redef class MEntity
        end
 end
 
-redef class MProject
-       redef var cs_modifiers = ["project"]
+redef class MPackage
+       redef var cs_modifiers = ["package"]
        redef fun cs_namespace do return cs_name
        redef fun cs_icon do return "P"
        redef fun cs_location do return root.mmodules.first.location.to_s
@@ -171,12 +171,12 @@ redef class MGroup
 
        # Depends if `self` is root or not.
        #
-       # * If root `mproject`.
-       # * Else `mproject::self`.
+       # * If root `mpackage`.
+       # * Else `mpackage::self`.
        redef fun cs_namespace do
                var tpl = new FlatBuffer
-               tpl.append mproject.cs_namespace
-               if mproject.root != self then
+               tpl.append mpackage.cs_namespace
+               if mpackage.root != self then
                        tpl.append "::"
                        tpl.append cs_name
                end
@@ -230,10 +230,10 @@ redef class MClass
        redef fun cs_modifiers do return intro.cs_modifiers
        redef fun cs_declaration do return intro.cs_declaration
 
-       # Returns `mproject::self`.
+       # Returns `mpackage::self`.
        redef fun cs_namespace do
                var tpl = new FlatBuffer
-               tpl.append intro_mmodule.mgroup.mproject.cs_namespace
+               tpl.append intro_mmodule.mgroup.mpackage.cs_namespace
                tpl.append "::"
                tpl.append cs_name
                return tpl.write_to_string
index 6e8f03e..fbeea29 100644 (file)
@@ -73,7 +73,7 @@ redef class ConcernSection
 
        redef fun rendering do
                var mentity = self.mentity
-               if mentity isa MGroup and mentity.mproject.root == mentity then
+               if mentity isa MGroup and mentity.mpackage.root == mentity then
                        render_body
                else
                        super
index 5284dc1..e04abb9 100644 (file)
@@ -99,10 +99,8 @@ private class NitdocDecorator
        var toolcontext = new ToolContext
 
        redef fun add_code(v, block) do
-               var meta = "nit"
-               if block isa BlockFence and block.meta != null then
-                       meta = block.meta.to_s
-               end
+               var meta = block.meta or else "nit"
+
                # Do not try to highlight non-nit code.
                if meta != "nit" and meta != "nitish" then
                        v.add "<pre class=\"{meta}\"><code>"
@@ -111,7 +109,7 @@ private class NitdocDecorator
                        return
                end
                # Try to parse code
-               var code = code_from_block(block)
+               var code = block.raw_content
                var ast = toolcontext.parse_something(code)
                if ast isa AError then
                        v.add "<pre class=\"{meta}\"><code>"
@@ -150,25 +148,6 @@ private class NitdocDecorator
                for i in [from..to[ do out.add buffer[i]
                return out.write_to_string
        end
-
-       fun code_from_block(block: BlockCode): String do
-               var infence = block isa BlockFence
-               var text = new FlatBuffer
-               var line = block.block.first_line
-               while line != null do
-                       if not line.is_empty then
-                               var str = line.value
-                               if not infence and str.has_prefix("    ") then
-                                       text.append str.substring(4, str.length - line.trailing)
-                               else
-                                       text.append str
-                               end
-                       end
-                       text.append "\n"
-                       line = line.next
-               end
-               return text.write_to_string
-       end
 end
 
 # Decorator for span elements.
index 456d545..d35abfa 100644 (file)
@@ -55,7 +55,7 @@ class ExtractionPhase
                doc.populate(self)
        end
 
-       # Should we exclude this `mproject` from the documentation?
+       # Should we exclude this `mpackage` from the documentation?
        fun ignore_mentity(mentity: MEntity): Bool do
                if mentity isa MModule then
                        return mentity.is_fictive or mentity.is_test_suite
@@ -79,8 +79,8 @@ end
 # TODO Should I rebuild a new Model from filtered data?
 redef class DocModel
 
-       # MProjects that will be documented.
-       var mprojects = new HashSet[MProject]
+       # MPackages that will be documented.
+       var mpackages = new HashSet[MPackage]
 
        # MGroups that will be documented.
        var mgroups = new HashSet[MGroup]
@@ -102,17 +102,17 @@ redef class DocModel
 
        # Populate `self` from internal `model`.
        fun populate(v: ExtractionPhase) do
-               populate_mprojects(v)
+               populate_mpackages(v)
                populate_mclasses(v)
                populate_mproperties(v)
        end
 
-       # Populates the `mprojects` set.
-       private fun populate_mprojects(v: ExtractionPhase) do
-               for mproject in model.mprojects do
-                       if v.ignore_mentity(mproject) then continue
-                       self.mprojects.add mproject
-                       for mgroup in mproject.mgroups do
+       # Populates the `mpackages` set.
+       private fun populate_mpackages(v: ExtractionPhase) do
+               for mpackage in model.mpackages do
+                       if v.ignore_mentity(mpackage) then continue
+                       self.mpackages.add mpackage
+                       for mgroup in mpackage.mgroups do
                                if v.ignore_mentity(mgroup) then continue
                                self.mgroups.add mgroup
                                for mmodule in mgroup.mmodules do
@@ -152,7 +152,7 @@ redef class DocModel
        # FIXME invalidate cache if `self` is modified.
        var mentities: Collection[MEntity] is lazy do
                var res = new HashSet[MEntity]
-               res.add_all mprojects
+               res.add_all mpackages
                res.add_all mgroups
                res.add_all mmodules
                res.add_all mclasses
@@ -178,7 +178,7 @@ redef class DocModel
        #
        # Path can be the shortest possible to disambiguise like `Class::property`.
        # In case of larger conflicts, a more complex namespace can be given like
-       # `project::module::Class::prop`.
+       # `package::module::Class::prop`.
        fun mentities_by_namespace(namespace: String): Array[MEntity] do
                var res = new Array[MEntity]
                for mentity in mentities do
@@ -206,7 +206,7 @@ redef class MEntity
        end
 end
 
-redef class MProject
+redef class MPackage
        redef fun mentities_by_namespace(namespace, res) do lookup_in(mgroups, namespace, res)
 end
 
index 722724b..ebc1193 100644 (file)
@@ -46,7 +46,7 @@ redef class ToolContext
        # Display a custom brand or logo in the documentation top menu.
        var opt_custom_brand = new OptionString("custom link to external site", "--custom-brand")
 
-       # Display a custom introduction text before the projects overview.
+       # Display a custom introduction text before the packages overview.
        var opt_custom_intro = new OptionString("custom intro text for homepage", "--custom-overview-text")
        # Display a custom footer on each documentation page.
        #
@@ -68,7 +68,7 @@ redef class ToolContext
        # FIXME redo the plugin
        var opt_github_base_sha1 = new OptionString("Git sha1 of base commit used to create pull request", "--github-base-sha1")
        # FIXME redo the plugin
-       var opt_github_gitdir = new OptionString("Git working directory used to resolve path name (ex: /home/me/myproject/)", "--github-gitdir")
+       var opt_github_gitdir = new OptionString("Git working directory used to resolve path name (ex: /home/me/mypackage/)", "--github-gitdir")
 
        redef init do
                super
@@ -257,11 +257,11 @@ redef class ReadmePage
 
        redef fun init_topmenu(v, doc) do
                super
-               var mproject = mentity.mproject
+               var mpackage = mentity.mpackage
                if not mentity.is_root then
-                       topmenu.add_li new ListItem(new Link(mproject.nitdoc_url, mproject.html_name))
+                       topmenu.add_li new ListItem(new Link(mpackage.nitdoc_url, mpackage.html_name))
                end
-               topmenu.add_li new ListItem(new Link(html_url, mproject.html_name))
+               topmenu.add_li new ListItem(new Link(html_url, mpackage.html_name))
                topmenu.active_item = topmenu.items.last
        end
 
@@ -275,11 +275,11 @@ end
 redef class MGroupPage
        redef fun init_topmenu(v, doc) do
                super
-               var mproject = mentity.mproject
+               var mpackage = mentity.mpackage
                if not mentity.is_root then
-                       topmenu.add_li new ListItem(new Link(mproject.nitdoc_url, mproject.html_name))
+                       topmenu.add_li new ListItem(new Link(mpackage.nitdoc_url, mpackage.html_name))
                end
-               topmenu.add_li new ListItem(new Link(html_url, mproject.html_name))
+               topmenu.add_li new ListItem(new Link(html_url, mpackage.html_name))
                topmenu.active_item = topmenu.items.last
        end
 
@@ -323,8 +323,8 @@ end
 redef class MModulePage
        redef fun init_topmenu(v, doc) do
                super
-               var mproject = mentity.mproject
-               topmenu.add_li new ListItem(new Link(mproject.nitdoc_url, mproject.html_name))
+               var mpackage = mentity.mpackage
+               topmenu.add_li new ListItem(new Link(mpackage.nitdoc_url, mpackage.html_name))
                topmenu.add_li new ListItem(new Link(mentity.nitdoc_url, mentity.html_name))
                topmenu.active_item = topmenu.items.last
        end
@@ -367,8 +367,8 @@ redef class MClassPage
 
        redef fun init_topmenu(v, doc) do
                super
-               var mproject = mentity.intro_mmodule.mgroup.mproject
-               topmenu.add_li new ListItem(new Link(mproject.nitdoc_url, mproject.html_name))
+               var mpackage = mentity.intro_mmodule.mgroup.mpackage
+               topmenu.add_li new ListItem(new Link(mpackage.nitdoc_url, mpackage.html_name))
                topmenu.add_li new ListItem(new Link(html_url, mentity.html_name))
                topmenu.active_item = topmenu.items.last
        end
@@ -471,9 +471,9 @@ redef class MPropertyPage
        redef fun init_topmenu(v, doc) do
                super
                var mmodule = mentity.intro_mclassdef.mmodule
-               var mproject = mmodule.mgroup.mproject
+               var mpackage = mmodule.mgroup.mpackage
                var mclass = mentity.intro_mclassdef.mclass
-               topmenu.add_li new ListItem(new Link(mproject.nitdoc_url, mproject.html_name))
+               topmenu.add_li new ListItem(new Link(mpackage.nitdoc_url, mpackage.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
@@ -495,8 +495,8 @@ redef class MEntitySection
                if not page isa MEntityPage then return
                var mentity = self.mentity
                if mentity isa MGroup and mentity.is_root then
-                       html_title = mentity.mproject.html_name
-                       html_subtitle = mentity.mproject.html_declaration
+                       html_title = mentity.mpackage.html_name
+                       html_subtitle = mentity.mpackage.html_declaration
                else if mentity isa MProperty then
                        var title = new Template
                        title.add mentity.html_name
@@ -559,7 +559,7 @@ end
 redef class DefinitionArticle
        redef fun init_html_render(v, doc, page) do
                var mentity = self.mentity
-               if mentity isa MProject or mentity isa MModule then
+               if mentity isa MPackage or mentity isa MModule then
                        var title = new Template
                        title.add mentity.html_icon
                        title.add mentity.html_namespace
index 4e5e2dc..605ddac 100644 (file)
@@ -235,7 +235,7 @@ redef class ArticleCommand
        private fun filter_results(res: Array[MEntity]): Array[MEntity] do
                var out = new Array[MEntity]
                for e in res do
-                       if e isa MProject then continue
+                       if e isa MPackage then continue
                        if e isa MGroup then continue
                        out.add e
                end
index aaf137f..f2686e6 100644 (file)
@@ -49,13 +49,13 @@ redef class OverviewPage
        redef fun apply_structure(v, doc) do
                var article = new HomeArticle("home.article", "Home")
                root.add_child article
-               # Projects list
-               var mprojects = doc.model.mprojects.to_a
+               # Packages list
+               var mpackages = doc.model.mpackages.to_a
                var sorter = new MConcernRankSorter
-               sorter.sort mprojects
-               var section = new DocSection("projects.section", "Projects")
-               for mproject in mprojects do
-                       section.add_child new DefinitionArticle("{mproject.nitdoc_id}.definition", null, mproject)
+               sorter.sort mpackages
+               var section = new DocSection("packages.section", "Packages")
+               for mpackage in mpackages do
+                       section.add_child new DefinitionArticle("{mpackage.nitdoc_id}.definition", null, mpackage)
                end
                article.add_child section
        end
@@ -78,17 +78,17 @@ redef class MGroupPage
                var section = new MEntitySection("{mentity.nitdoc_name}.section", null, mentity)
                root.add_child section
                if mentity.is_root then
-                       section.add_child new IntroArticle("{mentity.mproject.nitdoc_id}.intro", null, mentity.mproject)
+                       section.add_child new IntroArticle("{mentity.mpackage.nitdoc_id}.intro", null, mentity.mpackage)
                else
                        section.add_child new IntroArticle("{mentity.nitdoc_id}.intro", null, mentity)
                end
                var concerns = self.concerns
                if concerns == null or concerns.is_empty then return
                # FIXME avoid diff
-               mentity.mproject.booster_rank = -1000
+               mentity.mpackage.booster_rank = -1000
                mentity.booster_rank = -1000
                concerns.sort_with(v.concerns_sorter)
-               mentity.mproject.booster_rank = 0
+               mentity.mpackage.booster_rank = 0
                mentity.booster_rank = 0
                section.add_child new ConcernsArticle("{mentity.nitdoc_id}.concerns", null, mentity, concerns)
                for mentity in concerns do
@@ -109,11 +109,11 @@ redef class MModulePage
                var concerns = self.concerns
                if concerns == null or concerns.is_empty then return
                # FIXME avoid diff
-               mentity.mgroup.mproject.booster_rank = -1000
+               mentity.mgroup.mpackage.booster_rank = -1000
                mentity.mgroup.booster_rank = -1000
                mentity.booster_rank = -1000
                concerns.sort_with(v.concerns_sorter)
-               mentity.mgroup.mproject.booster_rank = 0
+               mentity.mgroup.mpackage.booster_rank = 0
                mentity.mgroup.booster_rank = 0
                mentity.booster_rank = 0
                section.add_child new ConcernsArticle("{mentity.nitdoc_id}.concerns", null, mentity, concerns)
@@ -174,11 +174,11 @@ redef class MClassPage
                var concerns = self.concerns
                if concerns == null or concerns.is_empty then return
                # FIXME diff hack
-               mentity.intro_mmodule.mgroup.mproject.booster_rank = -1000
+               mentity.intro_mmodule.mgroup.mpackage.booster_rank = -1000
                mentity.intro_mmodule.mgroup.booster_rank = -1000
                mentity.intro_mmodule.booster_rank = -1000
                concerns.sort_with(v.concerns_sorter)
-               mentity.intro_mmodule.mgroup.mproject.booster_rank = 0
+               mentity.intro_mmodule.mgroup.mpackage.booster_rank = 0
                mentity.intro_mmodule.mgroup.booster_rank = 0
                mentity.intro_mmodule.booster_rank = 0
                var constructors = new DocSection("{mentity.nitdoc_id}.constructors", "Constructors")
@@ -249,11 +249,11 @@ redef class MPropertyPage
                var concerns = self.concerns
                if concerns == null or concerns.is_empty then return
                # FIXME diff hack
-               mentity.intro.mclassdef.mmodule.mgroup.mproject.booster_rank = -1000
+               mentity.intro.mclassdef.mmodule.mgroup.mpackage.booster_rank = -1000
                mentity.intro.mclassdef.mmodule.mgroup.booster_rank = -1000
                mentity.intro.mclassdef.mmodule.booster_rank = -1000
                concerns.sort_with(v.concerns_sorter)
-               mentity.intro.mclassdef.mmodule.mgroup.mproject.booster_rank = 0
+               mentity.intro.mclassdef.mmodule.mgroup.mpackage.booster_rank = 0
                mentity.intro.mclassdef.mmodule.mgroup.booster_rank = 0
                mentity.intro.mclassdef.mmodule.booster_rank = 0
                section.add_child new ConcernsArticle("{mentity.nitdoc_id}.concerns", null, mentity, concerns)
@@ -377,7 +377,7 @@ class DefinitionArticle
        redef var is_hidden = false
 end
 
-# The main project article.
+# The main package article.
 class HomeArticle
        super DocArticle
 end
@@ -439,7 +439,7 @@ redef class MConcern
        fun concern_rank: Int is abstract
 end
 
-redef class MProject
+redef class MPackage
        redef var concern_rank is lazy do
                var max = 0
                for mgroup in mgroups do
index ed895ee..b8727de 100644 (file)
@@ -28,7 +28,7 @@ redef class MEntity
 
        # Returns the mentity name without short signature.
        #
-       # * MProject: `foo`
+       # * MPackage: `foo`
        # * MGroup: `foo`
        # * MModule: `foo`
        # * MClass: `Foo[E]`
@@ -66,7 +66,7 @@ redef class MEntity
 
        # Returns the complete MEntity declaration decorated with HTML.
        #
-       # * MProject: `project foo`
+       # * MPackage: `package foo`
        # * MGroup: `group foo`
        # * MModule: `module foo`
        # * MClass: `private abstract class Foo[E: Object]`
@@ -85,10 +85,10 @@ redef class MEntity
 
        # Returns `self` namespace decorated with HTML links.
        #
-       # * MProject: `mproject`
-       # * MGroup: `mproject(::group)`
+       # * MPackage: `mpackage`
+       # * MGroup: `mpackage(::group)`
        # * MModule: `mgroup::mmodule`
-       # * MClass: `mproject::mclass`
+       # * MClass: `mpackage::mclass`
        # * MClassDef: `mmodule::mclassdef`
        # * MProperty: `mclass::mprop`
        # * MPropdef: `mclassdef:mpropdef`
@@ -141,10 +141,10 @@ redef class MEntity
        end
 end
 
-redef class MProject
+redef class MPackage
        redef var nitdoc_id = name.to_cmangle is lazy
        redef fun nitdoc_url do return root.nitdoc_url
-       redef var html_modifiers = ["project"]
+       redef var html_modifiers = ["package"]
        redef fun html_namespace do return html_link
        redef var css_classes = ["public"]
 end
@@ -162,12 +162,12 @@ redef class MGroup
 
        # Depends if `self` is root or not.
        #
-       # * If root `mproject`.
-       # * Else `mproject::self`.
+       # * If root `mpackage`.
+       # * Else `mpackage::self`.
        redef fun html_namespace do
                var tpl = new Template
-               tpl.add mproject.html_namespace
-               if mproject.root != self then
+               tpl.add mpackage.html_namespace
+               if mpackage.root != self then
                        tpl.add "::"
                        tpl.add html_link
                end
@@ -233,10 +233,10 @@ redef class MClass
        redef fun html_modifiers do return intro.html_modifiers
        redef fun html_declaration do return intro.html_declaration
 
-       # Returns `mproject::self`.
+       # Returns `mpackage::self`.
        redef fun html_namespace do
                var tpl = new Template
-               tpl.add intro_mmodule.mgroup.mproject.html_namespace
+               tpl.add intro_mmodule.mgroup.mpackage.html_namespace
                tpl.add "::<span>"
                tpl.add html_link
                tpl.add "</span>"
index a497ad3..290f04b 100644 (file)
@@ -449,7 +449,7 @@ redef class IntroArticle
        redef fun render_body do
                var tabs = new DocTabs("{html_id}.tabs", "")
                var comment = mentity.html_documentation
-               if mentity isa MProject then
+               if mentity isa MPackage then
                        comment = mentity.html_synopsis
                end
                if comment != null then
@@ -506,7 +506,7 @@ redef class DefinitionArticle
                var tabs = new DocTabs("{html_id}.tabs", "")
                if not is_no_body then
                        var comment
-                       if is_short_comment or mentity isa MProject then
+                       if is_short_comment or mentity isa MPackage then
                                comment = mentity.html_synopsis
                        else
                                comment = mentity.html_documentation
index 0e093a0..e6dfca2 100644 (file)
@@ -28,7 +28,7 @@ redef class ToolContext
 end
 
 redef class MModule
-       # Extra Java files to compile with the project
+       # Extra Java files to compile with the module
        private var extra_java_files: nullable Array[JavaFile] = null
 end
 
index eb3d06d..a59ccf0 100644 (file)
@@ -116,14 +116,14 @@ redef class ModelBuilder
        #
        # Each name can be:
        #
-       # * a path to a module, a group or a directory of projects.
+       # * a path to a module, a group or a directory of packages.
        # * 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.
+       # * a directory of packages then all the modules of all packages are parsed.
        # * else an error is displayed.
        #
        # See `parse` for details.
@@ -205,7 +205,7 @@ redef class ModelBuilder
                # First, look in groups
                var c = mgroup
                if c != null then
-                       var r = c.mproject.root
+                       var r = c.mpackage.root
                        assert r != null
                        scan_group(r)
                        var res = r.mmodule_paths_by_name(name)
@@ -215,10 +215,10 @@ redef class ModelBuilder
                # Look at some known directories
                var lookpaths = self.paths
 
-               # Look in the directory of the group project also (even if not explicitly in the path)
+               # Look in the directory of the group package also (even if not explicitly in the path)
                if mgroup != null then
                        # path of the root group
-                       var dirname = mgroup.mproject.root.filepath
+                       var dirname = mgroup.mpackage.root.filepath
                        if dirname != null then
                                dirname = dirname.join_path("..").simplify_path
                                if not lookpaths.has(dirname) and dirname.file_exists then
@@ -308,7 +308,7 @@ redef class ModelBuilder
        # See `identify_file`.
        var identified_files = new Array[ModulePath]
 
-       # Identify a source file and load the associated project and groups if required.
+       # Identify a source file and load the associated package and groups if required.
        #
        # This method does what the user expects when giving an argument to a Nit tool.
        #
@@ -317,7 +317,7 @@ redef class ModelBuilder
        # * If `path` is a directory (with a `/`),
        #   then the ModulePath of its default module is returned (if any)
        # * If `path` is a simple identifier (eg. `digraph`),
-       #   then the main module of the project `digraph` is searched in `paths` and returned.
+       #   then the main module of the package `digraph` is searched in `paths` and returned.
        #
        # Silently return `null` if `path` does not exists or cannot be identified.
        fun identify_file(path: String): nullable ModulePath
@@ -361,18 +361,18 @@ redef class ModelBuilder
                var mgroup = get_mgroup(mgrouppath)
 
                if mgroup == null then
-                       # singleton project
-                       var mproject = new MProject(pn, model)
-                       mgroup = new MGroup(pn, mproject, null) # same name for the root group
+                       # singleton package
+                       var mpackage = new MPackage(pn, model)
+                       mgroup = new MGroup(pn, mpackage, null) # same name for the root group
                        mgroup.filepath = path
-                       mproject.root = mgroup
-                       toolcontext.info("found singleton project `{pn}` at {path}", 2)
+                       mpackage.root = mgroup
+                       toolcontext.info("found singleton package `{pn}` at {path}", 2)
 
-                       # Attach homonymous `ini` file to the project
+                       # Attach homonymous `ini` file to the package
                        var inipath = path.dirname / "{pn}.ini"
                        if inipath.file_exists then
                                var ini = new ConfigTree(inipath)
-                               mproject.ini = ini
+                               mpackage.ini = ini
                        end
                end
 
@@ -416,13 +416,13 @@ redef class ModelBuilder
                        return null
                end
 
-               # By default, the name of the project or group is the base_name of the directory
+               # By default, the name of the package or group is the base_name of the directory
                var pn = rdp.basename(".nit")
 
-               # Check `project.ini` that indicate a project
+               # Check `package.ini` that indicate a package
                var ini = null
                var parent = null
-               var inipath = dirpath / "project.ini"
+               var inipath = dirpath / "package.ini"
                if inipath.file_exists then
                        ini = new ConfigTree(inipath)
                end
@@ -436,16 +436,16 @@ redef class ModelBuilder
                                return null
                        end
 
-                       # Special stopper `projects.ini`
-                       if (dirpath/"projects.ini").file_exists then
-                               # dirpath cannot be a project since it is a project directory
+                       # Special stopper `packages.ini`
+                       if (dirpath/"packages.ini").file_exists then
+                               # dirpath cannot be a package since it is a package directory
                                mgroups[rdp] = null
                                return null
                        end
 
                        # check the parent directory (if it does not contain the stopper file)
                        var parentpath = dirpath.join_path("..").simplify_path
-                       var stopper = parentpath / "projects.ini"
+                       var stopper = parentpath / "packages.ini"
                        if not stopper.file_exists then
                                # Recursively get the parent group
                                parent = get_mgroup(parentpath)
@@ -459,20 +459,20 @@ redef class ModelBuilder
 
                var mgroup
                if parent == null then
-                       # no parent, thus new project
-                       if ini != null then pn = ini["project.name"] or else pn
-                       var mproject = new MProject(pn, model)
-                       mgroup = new MGroup(pn, mproject, null) # same name for the root group
-                       mproject.root = mgroup
-                       toolcontext.info("found project `{mproject}` at {dirpath}", 2)
-                       mproject.ini = ini
+                       # no parent, thus new package
+                       if ini != null then pn = ini["package.name"] or else pn
+                       var mpackage = new MPackage(pn, model)
+                       mgroup = new MGroup(pn, mpackage, null) # same name for the root group
+                       mpackage.root = mgroup
+                       toolcontext.info("found package `{mpackage}` at {dirpath}", 2)
+                       mpackage.ini = ini
                else
-                       mgroup = new MGroup(pn, parent.mproject, parent)
+                       mgroup = new MGroup(pn, parent.mpackage, parent)
                        toolcontext.info("found sub group `{mgroup.full_name}` at {dirpath}", 2)
                end
 
                # search documentation
-               # in src first so the documentation of the project code can be distinct for the documentation of the project usage
+               # in src first so the documentation of the package code can be distinct for the documentation of the package usage
                var readme = dirpath.join_path("README.md")
                if not readme.file_exists then readme = dirpath.join_path("README")
                if readme.file_exists then
@@ -524,8 +524,8 @@ redef class ModelBuilder
                for f in p.files do
                        var fp = p/f
                        var g = get_mgroup(fp)
-                       # Recursively scan for groups of the same project
-                       if g != null and g.mproject == mgroup.mproject then
+                       # Recursively scan for groups of the same package
+                       if g != null and g.mpackage == mgroup.mpackage then
                                scan_group(g)
                        end
                        identify_file(fp)
@@ -668,11 +668,11 @@ redef class ModelBuilder
                        end
                end
 
-               # Check for conflicting module names in the project
+               # Check for conflicting module names in the package
                if mgroup != null then
                        var others = model.get_mmodules_by_name(mod_name)
                        if others != null then for other in others do
-                               if other.mgroup!= null and other.mgroup.mproject == mgroup.mproject then
+                               if other.mgroup!= null and other.mgroup.mpackage == mgroup.mpackage then
                                        var node: ANode
                                        if decl == null then node = nmodule else node = decl.n_name
                                        error(node, "Error: a module named `{other.full_name}` already exists at {other.location}.")
@@ -728,8 +728,8 @@ redef class ModelBuilder
 
                # If qualified and in a group
                if mgroup != null then
-                       # First search in the project
-                       var r = mgroup.mproject.root
+                       # First search in the package
+                       var r = mgroup.mpackage.root
                        assert r != null
                        scan_group(r)
                        # Get all modules with the final name
@@ -1012,7 +1012,7 @@ class ModulePath
        # The human path of the module
        var filepath: String
 
-       # The group (and the project) of the possible module
+       # The group (and the package) of the possible module
        var mgroup: MGroup
 
        # The loaded module (if any)
@@ -1021,12 +1021,12 @@ class ModulePath
        redef fun to_s do return filepath
 end
 
-redef class MProject
+redef class MPackage
        # The associated `.ini` file, if any
        #
        # The `ini` file is given as is and might contain invalid or missing information.
        #
-       # Some projects, like stand-alone projects or virtual projects have no `ini` file associated.
+       # Some packages, like stand-alone packages or virtual packages have no `ini` file associated.
        var ini: nullable ConfigTree = null
 end
 
@@ -1036,7 +1036,7 @@ redef class MGroup
 
        # Is the group interesting for a final user?
        #
-       # Groups are mandatory in the model but for simple projects they are not
+       # Groups are mandatory in the model but for simple packages they are not
        # always interesting.
        #
        # A interesting group has, at least, one of the following true:
index 746ad9e..25463ad 100644 (file)
@@ -204,7 +204,7 @@ private class DetectCovariancePhase
 
                ## ONLY covariance remains here
 
-               cpt_modules.inc(mmodule.mgroup.mproject.name)
+               cpt_modules.inc(mmodule.mgroup.mpackage.name)
                cpt_classes.inc(sub.mclass)
 
                # Track if `cpt_explanations` is already decided (used to fallback on unknown)
index 6193b9c..ecbba30 100644 (file)
@@ -44,20 +44,20 @@ end
 fun generate_module_hierarchy(toolcontext: ToolContext, given_mmodules: Collection[MModule])
 do
        var model = given_mmodules.first.model
-       var dot = new MProjectDot(model)
+       var dot = new MPackageDot(model)
 
-       # Collect requested projects
+       # Collect requested packages
        for m in given_mmodules do
                var g = m.mgroup
                if g == null then continue
-               dot.mprojects.add(g.mproject)
+               dot.mpackages.add(g.mpackage)
        end
-       var projectpath = toolcontext.output_dir.join_path("project_hierarchy.dot")
-       print "generating project_hierarchy.dot"
-       dot.write_to_file(projectpath)
+       var packagepath = toolcontext.output_dir.join_path("package_hierarchy.dot")
+       print "generating package_hierarchy.dot"
+       dot.write_to_file(packagepath)
 
        var modulepath = toolcontext.output_dir.join_path("module_hierarchy.dot")
-       dot.mprojects.add_all(model.mprojects)
+       dot.mpackages.add_all(model.mpackages)
        print "generating module_hierarchy.dot"
        dot.write_to_file(modulepath)
 end
index d475562..1287c0f 100644 (file)
@@ -59,11 +59,11 @@ private class InheritanceMetricsPhase
                var model = toolcontext.modelbuilder.model
                var mmodules = new HashSet[MModule]
                var mclasses = new HashSet[MClass]
-               for mproject in model.mprojects do
+               for mpackage in model.mpackages do
 
-                       print toolcontext.format_h2("\n ## project {mproject}")
+                       print toolcontext.format_h2("\n ## package {mpackage}")
 
-                       for mgroup in mproject.mgroups do
+                       for mgroup in mpackage.mgroups do
                                if mgroup.mmodules.is_empty then continue
 
                                # Scalar metrics
index ed41a9f..69b5b40 100644 (file)
@@ -55,11 +55,11 @@ private class MClassesMetricsPhase
 
                var model = toolcontext.modelbuilder.model
                var mclasses = new HashSet[MClass]
-               for mproject in model.mprojects do
+               for mpackage in model.mpackages do
 
-                       print toolcontext.format_h2("\n ## project {mproject}")
+                       print toolcontext.format_h2("\n ## package {mpackage}")
 
-                       for mgroup in mproject.mgroups do
+                       for mgroup in mpackage.mgroups do
                                if mgroup.mmodules.is_empty then continue
                                metrics.clear
 
index a7ac696..335831c 100644 (file)
@@ -41,10 +41,10 @@ private class MModulesMetricsPhase
 
                var model = toolcontext.modelbuilder.model
                var mmodules = new HashSet[MModule]
-               for mproject in model.mprojects do
+               for mpackage in model.mpackages do
 
-                       print  toolcontext.format_h2("\n ## project {mproject}")
-                       for mgroup in mproject.mgroups do
+                       print  toolcontext.format_h2("\n ## package {mpackage}")
+                       for mgroup in mpackage.mgroups do
                                if mgroup.mmodules.is_empty then continue
 
                                # Scalar metrics
index 9e66e73..ed91198 100644 (file)
@@ -40,24 +40,24 @@ do
        buf.append("<html>\n<body>\n")
        buf.append("<h1>Model</h1>\n")
 
-       buf.append("<h2>Projects</h2>\n")
-       for mproject in model.mprojects do
-               buf.append("<h3 id='project-{mproject}'>Project {mproject}</h3>\n")
+       buf.append("<h2>Packages</h2>\n")
+       for mpackage in model.mpackages do
+               buf.append("<h3 id='package-{mpackage}'>Package {mpackage}</h3>\n")
                buf.append("<dl>\n")
                buf.append("<dt>groups</dt>\n")
-               for x in mproject.mgroups do
+               for x in mpackage.mgroups do
                        buf.append("<dd>{linkto(x)}</dd>\n")
                end
                buf.append("</dl>\n")
        end
 
        buf.append("<h2>Groups</h2>\n")
-       for mproject in model.mprojects do
-               for mgroup in mproject.mgroups do
+       for mpackage in model.mpackages do
+               for mgroup in mpackage.mgroups do
                        buf.append("<h3 id='group-{mgroup}'>Group {mgroup}</h3>\n")
                        buf.append("<dl>\n")
-                       buf.append("<dt>project</dt>\n")
-                       buf.append("<dd>{linkto(mproject)}</dd>\n")
+                       buf.append("<dt>package</dt>\n")
+                       buf.append("<dd>{linkto(mpackage)}</dd>\n")
                        buf.append("<dt>filepath</dt>\n")
                        buf.append("<dd>{mgroup.filepath.to_s}</dd>\n")
                        var p = mgroup.parent
@@ -193,8 +193,8 @@ end
 
 private fun linkto(o: Object): String
 do
-       if o isa MProject then
-               return "<a href='#project-{o}'>{o}</a>"
+       if o isa MPackage then
+               return "<a href='#package-{o}'>{o}</a>"
        else if o isa MGroup then
                return "<a href='#group-{o}'>{o}</a>"
        else if o isa MModule then
index 62c8f71..6e9d7ff 100644 (file)
@@ -44,11 +44,11 @@ private class NullablesMetricsPhase
 
                var model = toolcontext.modelbuilder.model
                var mclasses = new HashSet[MClass]
-               for mproject in model.mprojects do
+               for mpackage in model.mpackages do
 
-                       print toolcontext.format_h2("\n ## project {mproject}")
+                       print toolcontext.format_h2("\n ## package {mpackage}")
 
-                       for mgroup in mproject.mgroups do
+                       for mgroup in mpackage.mgroups do
                                if mgroup.mmodules.is_empty then continue
                                metrics.clear
 
index 4e8c565..2035b06 100644 (file)
@@ -39,7 +39,7 @@ redef class MEntity
 
        # The documentation associated to the entity or their main nested entity.
        #
-       # MProject fall-back to their root MGroup
+       # MPackage fall-back to their root MGroup
        # MGroup fall-back to their default_mmodule
        # Other entities do not fall-back
        #
index 659660b..7e2e9b3 100644 (file)
@@ -18,7 +18,7 @@
 module mmodule
 
 import location
-import mproject
+import mpackage
 private import more_collections
 
 # The container class of a Nit object-oriented model.
@@ -73,15 +73,15 @@ class MModule
        # The model considered
        redef var model: Model
 
-       # The group of module in the project if any
+       # The group of module in the package if any
        var mgroup: nullable MGroup
 
-       # The project of the module if any
-       # Safe alias for `mgroup.mproject`
-       fun mproject: nullable MProject
+       # The package of the module if any
+       # Safe alias for `mgroup.mpackage`
+       fun mpackage: nullable MPackage
        do
                var g = mgroup
-               if g == null then return null else return g.mproject
+               if g == null then return null else return g.mpackage
        end
 
        # The short name of the module
@@ -98,24 +98,24 @@ class MModule
 
        # The canonical name of the module.
        #
-       # It is usually the `name` prefixed by the project's name.
-       # Example: `"project::name"`
+       # It is usually the `name` prefixed by the package's name.
+       # Example: `"package::name"`
        #
-       # If both names are the same (of if the module is project-less), then
+       # If both names are the same (of if the module is package-less), then
        # the short-name is used alone.
        redef var full_name is lazy do
                var mgroup = self.mgroup
-               if mgroup == null or mgroup.mproject.name == self.name then
+               if mgroup == null or mgroup.mpackage.name == self.name then
                        return self.name
                else
-                       return "{mgroup.mproject.name}::{self.name}"
+                       return "{mgroup.mpackage.name}::{self.name}"
                end
        end
 
        # The namespace used for entities according to their visibility `v`.
        #
-       # Public entities use only the project as a namespace.
-       # Private entities use the `full_name` (i.e. "project::module")
+       # Public entities use only the package as a namespace.
+       # Private entities use the `full_name` (i.e. "package::module")
        #
        # This method is used by entities to implement their `full_name`.
        fun namespace_for(v: MVisibility): String do
@@ -124,7 +124,7 @@ class MModule
                if mgroup == null then
                        return full_name
                else
-                       return mgroup.mproject.full_name
+                       return mgroup.mpackage.full_name
                end
        end
 
@@ -133,8 +133,8 @@ class MModule
        redef var c_name: String is lazy do
                var g = mgroup
                var res
-               if g != null and g.mproject.name != name then
-                       res = g.mproject.name.to_cmangle + "__" + name.to_cmangle
+               if g != null and g.mpackage.name != name then
+                       res = g.mpackage.name.to_cmangle + "__" + name.to_cmangle
                else
                        res = name.to_cmangle
                end
@@ -151,7 +151,7 @@ class MModule
                if mgroup == null then
                        return c_name
                else
-                       return mgroup.mproject.c_name
+                       return mgroup.mpackage.c_name
                end
        end
 
index e0c3280..8d6bf7a 100644 (file)
@@ -614,7 +614,7 @@ class MClassDef
                        # public gives 'p#A'
                        # private gives 'p::m#A'
                        return "{mmodule.namespace_for(mclass.visibility)}#{mclass.name}"
-               else if mclass.intro_mmodule.mproject != mmodule.mproject then
+               else if mclass.intro_mmodule.mpackage != mmodule.mpackage then
                        # public gives 'q::n#p::A'
                        # private gives 'q::n#p::m::A'
                        return "{mmodule.full_name}#{mclass.full_name}"
@@ -630,7 +630,7 @@ class MClassDef
        redef var c_name is lazy do
                if is_intro then
                        return "{mmodule.c_namespace_for(mclass.visibility)}___{mclass.c_name}"
-               else if mclass.intro_mmodule.mproject == mmodule.mproject and mclass.visibility > private_visibility then
+               else if mclass.intro_mmodule.mpackage == mmodule.mpackage and mclass.visibility > private_visibility then
                        return "{mmodule.c_name}___{mclass.name.to_cmangle}"
                else
                        return "{mmodule.c_name}___{mclass.c_name}"
@@ -1932,7 +1932,7 @@ abstract class MProperty
        # The canonical name of the property.
        #
        # It is the short-`name` prefixed by the short-name of the class and the full-name of the module.
-       # Example: "my_project::my_module::MyClass::my_method"
+       # Example: "my_package::my_module::MyClass::my_method"
        redef var full_name is lazy do
                return "{intro_mclassdef.mmodule.namespace_for(visibility)}::{intro_mclassdef.mclass.name}::{name}"
        end
@@ -2250,14 +2250,14 @@ abstract class MPropDef
                        res.append name
                else
                        # Just try to simplify each part
-                       if mclassdef.mmodule.mproject != mproperty.intro_mclassdef.mmodule.mproject then
+                       if mclassdef.mmodule.mpackage != mproperty.intro_mclassdef.mmodule.mpackage then
                                # precise "p::m" only if "p" != "r"
                                res.append mproperty.intro_mclassdef.mmodule.full_name
                                res.append "::"
                        else if mproperty.visibility <= private_visibility then
-                               # Same project ("p"=="q"), but private visibility,
+                               # Same package ("p"=="q"), but private visibility,
                                # does the module part ("::m") need to be displayed
-                               if mclassdef.mmodule.namespace_for(mclassdef.mclass.visibility) != mproperty.intro_mclassdef.mmodule.mproject then
+                               if mclassdef.mmodule.namespace_for(mclassdef.mclass.visibility) != mproperty.intro_mclassdef.mmodule.mpackage then
                                        res.append "::"
                                        res.append mproperty.intro_mclassdef.mmodule.name
                                        res.append "::"
index 305cd23..66ab460 100644 (file)
@@ -18,9 +18,9 @@ module model_viz
 import model
 import ordered_tree
 
-# A simple specialisation of OrderedTree to display projects, groups and modules
+# A simple specialisation of OrderedTree to display packages, groups and modules
 # FIXME do not use Object, but a better common interface of MModule and MGroup
-class MProjectTree
+class MPackageTree
        super OrderedTree[Object]
 
        # The model where to look for information
@@ -28,7 +28,7 @@ class MProjectTree
 
        redef fun display(a) do
                if a isa MGroup then
-                       if a.parent == null then return "{a.mproject.name} ({a.filepath.to_s})"
+                       if a.parent == null then return "{a.mpackage.name} ({a.filepath.to_s})"
                        return a.name + " (group)"
                else if a isa MModule then
                        return a.name
@@ -115,11 +115,11 @@ private class LinexComparator
 end
 
 redef class Model
-       # Generate a MProjectTree based on the projects, groups and modules known in the model
-       fun to_mproject_tree: MProjectTree
+       # Generate a MPackageTree based on the packages, groups and modules known in the model
+       fun to_mpackage_tree: MPackageTree
        do
-               var res = new MProjectTree(self)
-               for p in mprojects do
+               var res = new MPackageTree(self)
+               for p in mpackages do
                        for g in p.mgroups do
                                res.add(g.parent, g)
                                for m in g.mmodules do
@@ -131,19 +131,19 @@ redef class Model
        end
 end
 
-# Generate graphiz files based on projects, groups and modules
+# Generate graphiz files based on packages, groups and modules
 #
 # Interesting elements must be selected. See `mmodules`, ``
-# Display configuration can be set. See `cluster_group`, `project_group`
-class MProjectDot
+# Display configuration can be set. See `cluster_group`, `package_group`
+class MPackageDot
        super Writable
 
        # The model where to look for information
        var model: Model
 
-       # Set of projects to expand fully (ie all groups and modules are displayed)
-       # Initially empty, projects can be added
-       var mprojects = new HashSet[MProject]
+       # Set of packages to expand fully (ie all groups and modules are displayed)
+       # Initially empty, packages can be added
+       var mpackages = new HashSet[MPackage]
 
        # Set of modules to display
        # Initially empty, modules can be added
@@ -157,17 +157,17 @@ class MProjectDot
        # Should groups be shown as clusters?
        var cluster_group = true is writable
 
-       # Should projects be shown as clusters?
-       var project_group = true is writable
+       # Should packages be shown as clusters?
+       var package_group = true is writable
 
        # Recursively generate node and clusters for a mgroup
        private fun dot_cluster(o: Writer, mgroup: MGroup)
        do
                # Open the cluster, if required
                if mgroup.parent == null then
-                       # is is a root group, so display the project
-                       if project_group then
-                               o.write("subgraph cluster_{mgroup.object_id} \{\nlabel=\"{mgroup.mproject.name}\\n({mgroup.filepath.to_s})\"\ncolor=black\nstyle=dotted\n")
+                       # is is a root group, so display the package
+                       if package_group then
+                               o.write("subgraph cluster_{mgroup.object_id} \{\nlabel=\"{mgroup.mpackage.name}\\n({mgroup.filepath.to_s})\"\ncolor=black\nstyle=dotted\n")
                        end
                else
                        if cluster_group then
@@ -188,13 +188,13 @@ class MProjectDot
 
                # close the cluster if required
                if mgroup.parent == null then
-                       if project_group then o.write("\}\n")
+                       if package_group then o.write("\}\n")
                else
                        if cluster_group then o.write("\}\n")
                end
        end
 
-       # Extends the set of `mmodules` by recursively adding the most specific imported modules of foreign projects
+       # Extends the set of `mmodules` by recursively adding the most specific imported modules of foreign packages
        fun collect_important_importation
        do
                var todo = new List[MModule]
@@ -203,9 +203,9 @@ class MProjectDot
                        var m = todo.pop
 
                        for psm in m.in_importation.greaters do
-                               if m.mgroup.mproject != psm.mgroup.mproject then continue
+                               if m.mgroup.mpackage != psm.mgroup.mpackage then continue
                                for ssm in psm.in_importation.direct_greaters do
-                                       if psm.mgroup.mproject == ssm.mgroup.mproject then continue
+                                       if psm.mgroup.mpackage == ssm.mgroup.mpackage then continue
                                        mmodules.add(ssm)
                                        todo.add(ssm)
                                end
@@ -218,9 +218,9 @@ class MProjectDot
        do
                # Collect interesting nodes
                for m in model.mmodules do
-                       # filter out modules outside wanted projects
+                       # filter out modules outside wanted packages
                        if m.mgroup == null then continue
-                       if not mprojects.has(m.mgroup.mproject) then continue
+                       if not mpackages.has(m.mgroup.mpackage) then continue
 
                        mmodules.add(m)
                end
@@ -241,7 +241,7 @@ class MProjectDot
                stream.write("digraph g \{\n")
                stream.write("rankdir=BT;node[shape=box];\n")
                # Generate the nodes
-               for p in model.mprojects do
+               for p in model.mpackages do
                        dot_cluster(stream, p.root.as(not null))
                end
                # Generate the edges
similarity index 65%
rename from src/model/mproject.nit
rename to src/model/mpackage.nit
index 283d54c..c1625ee 100644 (file)
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-# Modelisation of a Nit project
-module mproject
+# Modelisation of a Nit package
+module mpackage
 
 import model_base
 private import more_collections
 import poset
 import mdoc
 
-# A Nit project, that encompass a product
-class MProject
+# A Nit package, that encompass a product
+class MPackage
        super MConcern
 
-       # The name of the project
+       # The name of the package
        redef var name: String
 
        redef fun full_name do return name
 
        redef var c_name = name.to_cmangle is lazy
 
-       # The model of the project
+       # The model of the package
        redef var model: Model
 
        # The root of the group tree
@@ -44,11 +44,11 @@ class MProject
 
        init
        do
-               model.mprojects.add(self)
-               model.mproject_by_name.add_one(name, self)
+               model.mpackages.add(self)
+               model.mpackage_by_name.add_one(name, self)
        end
 
-       # MProject are always roots of the concerns hierarchy
+       # MPackage are always roots of the concerns hierarchy
        redef fun parent_concern do return null
 
        redef fun mdoc_or_fallback
@@ -58,16 +58,16 @@ class MProject
        end
 end
 
-# A group of modules in a project
+# A group of modules in a package
 class MGroup
        super MConcern
 
        # The name of the group
-       # empty name for a default group in a single-module project
+       # empty name for a default group in a single-module package
        redef var name: String
 
-       # The enclosing project
-       var mproject: MProject
+       # The enclosing package
+       var mpackage: MPackage
 
        # The parent group if any
        # see `in_nesting` for more
@@ -82,20 +82,20 @@ class MGroup
                return "{p.full_name}/{name}"
        end
 
-       # The group is the group tree on the project (`mproject.mgroups`)
+       # The group is the group tree on the package (`mpackage.mgroups`)
        # nested groups (children) are smaller
        # nesting group (see `parent`) is bigger
        var in_nesting: POSetElement[MGroup] is noinit
 
-       # Is `self` the root of its project?
-       fun is_root: Bool do return mproject.root == self
+       # Is `self` the root of its package?
+       fun is_root: Bool do return mpackage.root == self
 
        # The filepath (usually a directory) of the group, if any
        var filepath: nullable String = null is writable
 
        init
        do
-               var tree = mproject.mgroups
+               var tree = mpackage.mgroups
                self.in_nesting = tree.add_node(self)
                var parent = self.parent
                if parent != null then
@@ -103,29 +103,29 @@ class MGroup
                end
        end
 
-       redef fun model do return mproject.model
+       redef fun model do return mpackage.model
 
        redef fun parent_concern do
                if not is_root then return parent
-               return mproject
+               return mpackage
        end
 
        redef fun to_s do return name
 end
 
 redef class Model
-       # projects of the model
-       var mprojects = new Array[MProject]
+       # packages of the model
+       var mpackages = new Array[MPackage]
 
-       # Collections of project grouped by their names
-       private var mproject_by_name = new MultiHashMap[String, MProject]
+       # Collections of package grouped by their names
+       private var mpackage_by_name = new MultiHashMap[String, MPackage]
 
-       # Return all project named `name`
-       # If such a project is not yet loaded, null is returned (instead of an empty array)
-       fun get_mprojects_by_name(name: String): nullable Array[MProject]
+       # Return all package named `name`
+       # If such a package is not yet loaded, null is returned (instead of an empty array)
+       fun get_mpackages_by_name(name: String): nullable Array[MPackage]
        do
-               if mproject_by_name.has_key(name) then
-                       return mproject_by_name[name]
+               if mpackage_by_name.has_key(name) then
+                       return mpackage_by_name[name]
                else
                        return null
                end
index 5fd0381..14c8e94 100644 (file)
@@ -99,11 +99,11 @@ redef class ModelBuilder
                                return
                        end
 
-                       # Check for conflicting class full-names in the project
+                       # Check for conflicting class full-names in the package
                        if mmodule.mgroup != null and mvisibility >= protected_visibility then
                                var mclasses = model.get_mclasses_by_name(name)
                                if mclasses != null then for other in mclasses do
-                                       if other.intro_mmodule.mgroup != null and other.intro_mmodule.mgroup.mproject == mmodule.mgroup.mproject then
+                                       if other.intro_mmodule.mgroup != null and other.intro_mmodule.mgroup.mpackage == mmodule.mgroup.mpackage then
                                                # Skip classes that are buggy
                                                if other.try_intro == null then continue
                                                warning(nclassdef, "full-name-conflict", "Error: a class named `{other.full_name}` is already defined in module `{other.intro_mmodule}` at {other.intro.location}.")
index 97312f2..eec36f4 100644 (file)
@@ -629,12 +629,12 @@ redef class APropdef
                                return false
                        end
 
-                       # Check for full-name conflicts in the project.
-                       # A public property should have a unique qualified name `project::class::prop`.
+                       # Check for full-name conflicts in the package.
+                       # A public property should have a unique qualified name `package::class::prop`.
                        if mprop.intro_mclassdef.mmodule.mgroup != null and mprop.visibility >= protected_visibility then
                                var others = modelbuilder.model.get_mproperties_by_name(mprop.name)
                                if others != null then for other in others do
-                                       if other != mprop and other.intro_mclassdef.mmodule.mgroup != null and other.intro_mclassdef.mmodule.mgroup.mproject == mprop.intro_mclassdef.mmodule.mgroup.mproject and other.intro_mclassdef.mclass.name == mprop.intro_mclassdef.mclass.name and other.visibility >= protected_visibility then
+                                       if other != mprop and other.intro_mclassdef.mmodule.mgroup != null and other.intro_mclassdef.mmodule.mgroup.mpackage == mprop.intro_mclassdef.mmodule.mgroup.mpackage and other.intro_mclassdef.mclass.name == mprop.intro_mclassdef.mclass.name and other.visibility >= protected_visibility then
                                                modelbuilder.advice(self, "full-name-conflict", "Warning: A property named `{other.full_name}` is already defined in module `{other.intro_mclassdef.mmodule}` for the class `{other.intro_mclassdef.mclass.name}`.")
                                                break
                                        end
index 79799e8..c110468 100644 (file)
 #
 # Note : All nodes described here are MEntities.
 #
-# `MProject`
+# `MPackage`
 #
-# * labels: `MProject`, `model_name` and `MEntity`.
-# * `(:MProject)-[:ROOT]->(:MGroup)`: root of the group tree.
+# * labels: `MPackage`, `model_name` and `MEntity`.
+# * `(:MPackage)-[:ROOT]->(:MGroup)`: root of the group tree.
 #
 # `MGroup`
 #
 # * labels: `MGroup`, `model_name` and `MEntity`.
-# * `(:MGroup)-[:PROJECT]->(:MProject)`: associated project.
+# * `(:MGroup)-[:PROJECT]->(:MPackage)`: associated package.
 # * `(:MGroup)-[:PARENT]->(:MGroup)`: parent group. Does not exist for the root
 # group.
 # * `(:MGroup)-[:DECLARES]->(:MModule)`: modules that are direct children of
@@ -233,9 +233,9 @@ class NeoModel
        fun load(model: Model): Model do
                var nodes: Array[NeoNode]
 
-               toolcontext.info("Loading project node...", 1)
-               nodes = client.nodes_with_labels([model_name, "MProject"])
-               for node in nodes do to_mproject(model, node)
+               toolcontext.info("Loading package node...", 1)
+               nodes = client.nodes_with_labels([model_name, "MPackage"])
+               for node in nodes do to_mpackage(model, node)
                toolcontext.info("Loading groups...", 1)
                nodes = client.nodes_with_labels([model_name, "MGroup"])
                for node in nodes do to_mgroup(model, node)
@@ -304,9 +304,9 @@ class NeoModel
 
        # Collect all nodes from the current `model`.
        private fun collect_model_nodes(model: Model): Collection[NeoNode] do
-               for mproject in model.mprojects do
-                       to_node(mproject)
-                       for mgroup in mproject.mgroups do to_node(mgroup)
+               for mpackage in model.mpackages do
+                       to_node(mpackage)
+                       for mgroup in mpackage.mgroups do to_node(mgroup)
                end
                return nodes.values
        end
@@ -332,7 +332,7 @@ class NeoModel
        # `mentities` are stored locally to avoid duplication.
        fun to_node(mentity: MEntity): NeoNode do
                if nodes.has_key(mentity) then return nodes[mentity]
-               if mentity isa MProject then return mproject_node(mentity)
+               if mentity isa MPackage then return mpackage_node(mentity)
                if mentity isa MGroup then return mgroup_node(mentity)
                if mentity isa MModule then return mmodule_node(mentity)
                if mentity isa MClass then return mclass_node(mentity)
@@ -346,7 +346,7 @@ class NeoModel
 
        # Get the `MEntity` associated with `node`.
        fun to_mentity(model: Model, node: NeoNode): MEntity do
-               if node.labels.has("MProject") then return to_mproject(model, node)
+               if node.labels.has("MPackage") then return to_mpackage(model, node)
                if node.labels.has("MGroup") then return to_mgroup(model, node)
                if node.labels.has("MModule") then return to_mmodule(model, node)
                if node.labels.has("MClass") then return to_mclass(model, node)
@@ -372,30 +372,30 @@ class NeoModel
                return node
        end
 
-       # Build a `NeoNode` representing `mproject`.
-       private fun mproject_node(mproject: MProject): NeoNode do
-               var node = make_node(mproject)
-               node.labels.add "MProject"
-               var root = mproject.root
+       # Build a `NeoNode` representing `mpackage`.
+       private fun mpackage_node(mpackage: MPackage): NeoNode do
+               var node = make_node(mpackage)
+               node.labels.add "MPackage"
+               var root = mpackage.root
                if root != null then
                        node.out_edges.add(new NeoEdge(node, "ROOT", to_node(root)))
                end
                return node
        end
 
-       # Build a new `MProject` from a `node`.
+       # Build a new `MPackage` from a `node`.
        #
-       # REQUIRE `node.labels.has("MProject")`
-       private fun to_mproject(model: Model, node: NeoNode): MProject do
+       # REQUIRE `node.labels.has("MPackage")`
+       private fun to_mpackage(model: Model, node: NeoNode): MPackage do
                var m = mentities.get_or_null(node.id.as(Int))
-               if m isa MProject then return m
+               if m isa MPackage then return m
 
-               assert node.labels.has("MProject")
-               var mproject = new MProject(node["name"].to_s, model)
-               mentities[node.id.as(Int)] = mproject
-               set_doc(node, mproject)
-               mproject.root = to_mgroup(model, node.out_nodes("ROOT").first)
-               return mproject
+               assert node.labels.has("MPackage")
+               var mpackage = new MPackage(node["name"].to_s, model)
+               mentities[node.id.as(Int)] = mpackage
+               set_doc(node, mpackage)
+               mpackage.root = to_mgroup(model, node.out_nodes("ROOT").first)
+               return mpackage
        end
 
        # Build a `NeoNode` representing `mgroup`.
@@ -403,7 +403,7 @@ class NeoModel
                var node = make_node(mgroup)
                node.labels.add "MGroup"
                var parent = mgroup.parent
-               node.out_edges.add(new NeoEdge(node, "PROJECT", to_node(mgroup.mproject)))
+               node.out_edges.add(new NeoEdge(node, "PROJECT", to_node(mgroup.mpackage)))
                if parent != null then
                        node.out_edges.add(new NeoEdge(node, "PARENT", to_node(parent)))
                end
@@ -424,13 +424,13 @@ class NeoModel
                if m isa MGroup then return m
 
                assert node.labels.has("MGroup")
-               var mproject = to_mproject(model, node.out_nodes("PROJECT").first)
+               var mpackage = to_mpackage(model, node.out_nodes("PROJECT").first)
                var parent: nullable MGroup = null
                var out = node.out_nodes("PARENT")
                if not out.is_empty then
                        parent = to_mgroup(model, out.first)
                end
-               var mgroup = new MGroup(node["name"].to_s, mproject, parent)
+               var mgroup = new MGroup(node["name"].to_s, mpackage, parent)
                mentities[node.id.as(Int)] = mgroup
                set_doc(node, mgroup)
                return mgroup
index 6aba6f1..ba0cb1c 100644 (file)
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-# Basic catalog generator for Nit projects
+# Basic catalog generator for Nit packages
 #
 # See: <http://nitlanguage.org/catalog/>
 #
-# The tool scans projects and generates the HTML files of a catalog.
+# The tool scans packages and generates the HTML files of a catalog.
 #
 # ## Features
 #
-# * [X] scan projects and their `.ini`
-# * [X] generate lists of projects
-# * [X] generate a page per project with the readme and most metadata
+# * [X] scan packages and their `.ini`
+# * [X] generate lists of packages
+# * [X] generate a page per package with the readme and most metadata
 # * [ ] link/include/be included in the documentation
-# * [ ] propose `related projects`
-# * [ ] show directory content (a la nitls)
+# * [ ] propose `related packages`
+# * [X] show directory content (a la nitls)
 # * [X] gather git information from the working directory
 # * [ ] gather git information from the repository
-# * [ ] gather project information from github
+# * [ ] gather package information from github
 # * [ ] gather people information from github
 # * [ ] reify people
 # * [ ] separate information gathering from rendering
 # * [ ] move up information gathering in (existing or new) service modules
-# * [ ] add command line options
+# * [X] add command line options
 # * [ ] harden HTML (escaping, path injection, etc)
 # * [ ] nitcorn server with RESTful API
 #
 # How to use the tool as the basis of a Nit code archive on the web usable with a package manager is not clear.
 module nitcatalog
 
-import loader # Scan&load projects, groups and modules
+import loader # Scan&load packages, groups and modules
 import doc::doc_down # Display mdoc
 import md5 # To get gravatar images
 import counter # For statistics
 import modelize # To process and count classes and methods
 
-redef class MProject
+redef class MPackage
        # Return the associated metadata from the `ini`, if any
        fun metadata(key: String): nullable String
        do
@@ -139,7 +139,7 @@ class CatalogPage
 end
 
 redef class Int
-       # Returns `log(self+1)`. Used to compute score of projects
+       # Returns `log(self+1)`. Used to compute score of packages
        fun score: Float do return (self+1).to_f.log
 end
 
@@ -150,46 +150,46 @@ class Catalog
        # used to access the files and count source lines of code
        var modelbuilder: ModelBuilder
 
-       # Projects by tag
-       var tag2proj = new MultiHashMap[String, MProject]
+       # Packages by tag
+       var tag2proj = new MultiHashMap[String, MPackage]
 
-       # Projects by category
-       var cat2proj = new MultiHashMap[String, MProject]
+       # Packages by category
+       var cat2proj = new MultiHashMap[String, MPackage]
 
-       # Projects by maintainer
-       var maint2proj = new MultiHashMap[String, MProject]
+       # Packages by maintainer
+       var maint2proj = new MultiHashMap[String, MPackage]
 
-       # Projects by contributors
-       var contrib2proj = new MultiHashMap[String, MProject]
+       # Packages by contributors
+       var contrib2proj = new MultiHashMap[String, MPackage]
 
-       # Dependency between projects
-       var deps = new POSet[MProject]
+       # Dependency between packages
+       var deps = new POSet[MPackage]
 
-       # Number of modules by project
-       var mmodules = new Counter[MProject]
+       # Number of modules by package
+       var mmodules = new Counter[MPackage]
 
-       # Number of classes by project
-       var mclasses = new Counter[MProject]
+       # Number of classes by package
+       var mclasses = new Counter[MPackage]
 
-       # Number of methods by project
-       var mmethods = new Counter[MProject]
+       # Number of methods by package
+       var mmethods = new Counter[MPackage]
 
-       # Number of line of code by project
-       var loc = new Counter[MProject]
+       # Number of line of code by package
+       var loc = new Counter[MPackage]
 
-       # Number of commits by project
-       var commits = new Counter[MProject]
+       # Number of commits by package
+       var commits = new Counter[MPackage]
 
-       # Score by project
+       # Score by package
        #
        # The score is loosely computed using other metrics
-       var score = new Counter[MProject]
+       var score = new Counter[MPackage]
 
-       # Scan, register and add a contributor to a project
-       fun add_contrib(person: String, mproject: MProject, res: Template)
+       # Scan, register and add a contributor to a package
+       fun add_contrib(person: String, mpackage: MPackage, res: Template)
        do
                var projs = contrib2proj[person]
-               if not projs.has(mproject) then projs.add mproject
+               if not projs.has(mpackage) then projs.add mpackage
                var name = person
                var email = null
                var page = null
@@ -238,45 +238,90 @@ class Catalog
                res.add "</li>"
        end
 
+       # Recursively generate a level in the file tree of the *content* section
+       private fun gen_content_level(ot: OrderedTree[Object], os: Array[Object], res: Template)
+       do
+               res.add "<ul>\n"
+               for o in os do
+                       res.add "<li>"
+                       if o isa MGroup then
+                               var d = ""
+                               var mdoc = o.mdoc
+                               if mdoc != null then d = ": {mdoc.html_synopsis.write_to_string}"
+                               res.add "<strong>{o.name}</strong>{d} ({o.filepath.to_s})"
+                       else if o isa ModulePath then
+                               var d = ""
+                               var m = o.mmodule
+                               if m != null then
+                                       var mdoc = m.mdoc
+                                       if mdoc != null then d = ": {mdoc.html_synopsis.write_to_string}"
+                               end
+                               res.add "<strong>{o.name}</strong>{d} ({o.filepath.to_s})"
+                       else
+                               abort
+                       end
+                       var subs = ot.sub.get_or_null(o)
+                       if subs != null then gen_content_level(ot, subs, res)
+                       res.add "</li>\n"
+               end
+               res.add "</ul>\n"
+       end
 
-       # Compute information and generate a full HTML page for a project
-       fun project_page(mproject: MProject): Writable
+       # Compute information and generate a full HTML page for a package
+       fun package_page(mpackage: MPackage): Writable
        do
                var res = new CatalogPage
-               var score = score[mproject].to_f
-               var name = mproject.name.html_escape
+               var score = score[mpackage].to_f
+               var name = mpackage.name.html_escape
                res.more_head.add """<title>{{{name}}}</title>"""
 
                res.add """
 <div class="content">
 <h1 class="package-name">{{{name}}}</h1>
 """
-               var mdoc = mproject.mdoc_or_fallback
+               var mdoc = mpackage.mdoc_or_fallback
                if mdoc != null then
                        score += 100.0
                        res.add mdoc.html_documentation
                        score += mdoc.content.length.score
                end
+
+               res.add "<h2>Content</h2>"
+               var ot = new OrderedTree[Object]
+               for g in mpackage.mgroups do
+                       var pa = g.parent
+                       if g.is_interesting then
+                               ot.add(pa, g)
+                               pa = g
+                       end
+                       for mp in g.module_paths do
+                               ot.add(pa, mp)
+                       end
+               end
+               ot.sort_with(alpha_comparator)
+               gen_content_level(ot, ot.roots, res)
+
+
                res.add """
 </div>
 <div class="sidebar">
 <ul class="box">
 """
-               var homepage = mproject.metadata("upstream.homepage")
+               var homepage = mpackage.metadata("upstream.homepage")
                if homepage != null then
                        score += 5.0
                        var e = homepage.html_escape
                        res.add "<li><a href=\"{e}\">{e}</a></li>\n"
                end
-               var maintainer = mproject.metadata("project.maintainer")
+               var maintainer = mpackage.metadata("package.maintainer")
                if maintainer != null then
                        score += 5.0
-                       add_contrib(maintainer, mproject, res)
-                       mproject.maintainers.add maintainer
+                       add_contrib(maintainer, mpackage, res)
+                       mpackage.maintainers.add maintainer
                        var projs = maint2proj[maintainer]
-                       if not projs.has(mproject) then projs.add mproject
+                       if not projs.has(mpackage) then projs.add mpackage
                end
-               var license = mproject.metadata("project.license")
+               var license = mpackage.metadata("package.license")
                if license != null then
                        score += 5.0
                        var e = license.html_escape
@@ -285,35 +330,35 @@ class Catalog
                res.add "</ul>\n"
 
                res.add "<h3>Source Code</h3>\n<ul class=\"box\">\n"
-               var browse = mproject.metadata("upstream.browse")
+               var browse = mpackage.metadata("upstream.browse")
                if browse != null then
                        score += 5.0
                        var e = browse.html_escape
                        res.add "<li><a href=\"{e}\">{e}</a></li>\n"
                end
-               var git = mproject.metadata("upstream.git")
+               var git = mpackage.metadata("upstream.git")
                if git != null then
                        var e = git.html_escape
                        res.add "<li><tt>{e}</tt></li>\n"
                end
-               var last_date = mproject.last_date
+               var last_date = mpackage.last_date
                if last_date != null then
                        var e = last_date.html_escape
                        res.add "<li>most recent commit: {e}</li>\n"
                end
-               var first_date = mproject.first_date
+               var first_date = mpackage.first_date
                if first_date != null then
                        var e = first_date.html_escape
                        res.add "<li>oldest commit: {e}</li>\n"
                end
-               var commits = commits[mproject]
+               var commits = commits[mpackage]
                if commits != 0 then
                        res.add "<li>{commits} commits</li>\n"
                end
                res.add "</ul>\n"
 
                res.add "<h3>Tags</h3>\n"
-               var tags = mproject.metadata("project.tags")
+               var tags = mpackage.metadata("package.tags")
                var ts2 = new Array[String]
                var cat = null
                if tags != null then
@@ -322,7 +367,7 @@ class Catalog
                                t = t.trim
                                if t == "" then continue
                                if cat == null then cat = t
-                               tag2proj[t].add mproject
+                               tag2proj[t].add mpackage
                                t = t.html_escape
                                ts2.add "<a href=\"index.html#tag_{t}\">{t}</a>"
                        end
@@ -331,62 +376,64 @@ class Catalog
                if ts2.is_empty then
                        var t = "none"
                        cat = t
-                       tag2proj[t].add mproject
+                       tag2proj[t].add mpackage
                        res.add "<a href=\"index.html#tag_{t}\">{t}</a>"
                end
-               if cat != null then cat2proj[cat].add mproject
+               if cat != null then cat2proj[cat].add mpackage
                score += ts2.length.score
 
-               var reqs = deps[mproject].greaters.to_a
-               reqs.remove(mproject)
-               alpha_comparator.sort(reqs)
-               res.add "<h3>Requirements</h3>\n"
-               if reqs.is_empty then
-                       res.add "none"
-               else
-                       var list = new Array[String]
-                       for r in reqs do
-                               var direct = deps.has_direct_edge(mproject, r)
-                               var s = "<a href=\"{r}.html\">"
-                               if direct then s += "<strong>"
-                               s += r.to_s
-                               if direct then s += "</strong>"
-                               s += "</a>"
-                               list.add s
+               if deps.has(mpackage) then
+                       var reqs = deps[mpackage].greaters.to_a
+                       reqs.remove(mpackage)
+                       alpha_comparator.sort(reqs)
+                       res.add "<h3>Requirements</h3>\n"
+                       if reqs.is_empty then
+                               res.add "none"
+                       else
+                               var list = new Array[String]
+                               for r in reqs do
+                                       var direct = deps.has_direct_edge(mpackage, r)
+                                       var s = "<a href=\"{r}.html\">"
+                                       if direct then s += "<strong>"
+                                       s += r.to_s
+                                       if direct then s += "</strong>"
+                                       s += "</a>"
+                                       list.add s
+                               end
+                               res.add_list(list, ", ", " and ")
                        end
-                       res.add_list(list, ", ", " and ")
-               end
 
-               reqs = deps[mproject].smallers.to_a
-               reqs.remove(mproject)
-               alpha_comparator.sort(reqs)
-               res.add "<h3>Clients</h3>\n"
-               if reqs.is_empty then
-                       res.add "none"
-               else
-                       var list = new Array[String]
-                       for r in reqs do
-                               var direct = deps.has_direct_edge(r, mproject)
-                               var s = "<a href=\"{r}.html\">"
-                               if direct then s += "<strong>"
-                               s += r.to_s
-                               if direct then s += "</strong>"
-                               s += "</a>"
-                               list.add s
+                       reqs = deps[mpackage].smallers.to_a
+                       reqs.remove(mpackage)
+                       alpha_comparator.sort(reqs)
+                       res.add "<h3>Clients</h3>\n"
+                       if reqs.is_empty then
+                               res.add "none"
+                       else
+                               var list = new Array[String]
+                               for r in reqs do
+                                       var direct = deps.has_direct_edge(r, mpackage)
+                                       var s = "<a href=\"{r}.html\">"
+                                       if direct then s += "<strong>"
+                                       s += r.to_s
+                                       if direct then s += "</strong>"
+                                       s += "</a>"
+                                       list.add s
+                               end
+                               res.add_list(list, ", ", " and ")
                        end
-                       res.add_list(list, ", ", " and ")
-               end
 
-               score += deps[mproject].greaters.length.score
-               score += deps[mproject].direct_greaters.length.score
-               score += deps[mproject].smallers.length.score
-               score += deps[mproject].direct_smallers.length.score
+                       score += deps[mpackage].greaters.length.score
+                       score += deps[mpackage].direct_greaters.length.score
+                       score += deps[mpackage].smallers.length.score
+                       score += deps[mpackage].direct_smallers.length.score
+               end
 
-               var contributors = mproject.contributors
+               var contributors = mpackage.contributors
                if not contributors.is_empty then
                        res.add "<h3>Contributors</h3>\n<ul class=\"box\">"
                        for c in contributors do
-                               add_contrib(c, mproject, res)
+                               add_contrib(c, mpackage, res)
                        end
                        res.add "</ul>"
                end
@@ -396,7 +443,7 @@ class Catalog
                var mclasses = 0
                var mmethods = 0
                var loc = 0
-               for g in mproject.mgroups do
+               for g in mpackage.mgroups do
                        mmodules += g.module_paths.length
                        for m in g.mmodules do
                                var am = modelbuilder.mmodule2node(m)
@@ -415,10 +462,10 @@ class Catalog
                                end
                        end
                end
-               self.mmodules[mproject] = mmodules
-               self.mclasses[mproject] = mclasses
-               self.mmethods[mproject] = mmethods
-               self.loc[mproject] = loc
+               self.mmodules[mpackage] = mmodules
+               self.mclasses[mpackage] = mclasses
+               self.mmethods[mpackage] = mmethods
+               self.loc[mpackage] = loc
 
                #score += mmodules.score
                score += mclasses.score
@@ -438,15 +485,15 @@ class Catalog
                res.add """
 </div>
 """
-               self.score[mproject] = score.to_i
+               self.score[mpackage] = score.to_i
 
                return res
        end
 
-       # Return a short HTML sequence for a project
+       # Return a short HTML sequence for a package
        #
        # Intended to use in lists.
-       fun li_project(p: MProject): String
+       fun li_package(p: MPackage): String
        do
                var res = ""
                var f = "{p.name}.html"
@@ -456,14 +503,14 @@ class Catalog
                return res
        end
 
-       # List projects by group.
+       # List packages by group.
        #
        # For each key of the `map` a `<h3>` is generated.
-       # Each project is then listed.
+       # Each package is then listed.
        #
        # The list of keys is generated first to allow fast access to the correct `<h3>`.
        # `id_prefix` is used to give an id to the `<h3>` element.
-       fun list_by(map: MultiHashMap[String, MProject], id_prefix: String): Template
+       fun list_by(map: MultiHashMap[String, MPackage], id_prefix: String): Template
        do
                var res = new Template
                var keys = map.keys.to_a
@@ -478,7 +525,7 @@ class Catalog
                        res.add "<h3 id=\"{id_prefix}{e}\">{e} ({projs.length})</h3>\n<ul>\n"
                        for p in projs do
                                res.add "<li>"
-                               res.add li_project(p)
+                               res.add li_package(p)
                                res.add "</li>"
                        end
                        res.add "</ul>"
@@ -486,8 +533,8 @@ class Catalog
                return res
        end
 
-       # List the 10 best projects from `cpt`
-       fun list_best(cpt: Counter[MProject]): Template
+       # List the 10 best packages from `cpt`
+       fun list_best(cpt: Counter[MPackage]): Template
        do
                var res = new Template
                res.add "<ul>"
@@ -496,7 +543,7 @@ class Catalog
                        if i > best.length then break
                        var p = best[best.length-i]
                        res.add "<li>"
-                       res.add li_project(p)
+                       res.add li_package(p)
                        # res.add " ({cpt[p]})"
                        res.add "</li>"
                end
@@ -504,10 +551,10 @@ class Catalog
                return res
        end
 
-       # Collect more information on a project using the `git` tool.
-       fun git_info(mproject: MProject)
+       # Collect more information on a package using the `git` tool.
+       fun git_info(mpackage: MPackage)
        do
-               var ini = mproject.ini
+               var ini = mpackage.ini
                if ini == null then return
 
                # TODO use real git info
@@ -515,7 +562,7 @@ class Catalog
                #var branch = ini.get_or_null("upstream.git.branch")
                #var directory = ini.get_or_null("upstream.git.directory")
 
-               var dirpath = mproject.root.filepath
+               var dirpath = mpackage.root.filepath
                if dirpath == null then return
 
                # Collect commits info
@@ -523,57 +570,61 @@ class Catalog
                var contributors = new Counter[String]
                var commits = res.split("\n")
                if commits.not_empty and commits.last == "" then commits.pop
-               self.commits[mproject] = commits.length
+               self.commits[mpackage] = commits.length
                for l in commits do
                        var s = l.split_once_on(';')
                        if s.length != 2 or s.last == "" then continue
 
                        # Collect date of last and first commit
-                       if mproject.last_date == null then mproject.last_date = s.first
-                       mproject.first_date = s.first
+                       if mpackage.last_date == null then mpackage.last_date = s.first
+                       mpackage.first_date = s.first
 
                        # Count contributors
                        contributors.inc(s.last)
                end
                for c in contributors.sort.reverse_iterator do
-                       mproject.contributors.add c
+                       mpackage.contributors.add c
                end
 
        end
 
-       # Produce a HTML table containig information on the projects
+       # Produce a HTML table containig information on the packages
        #
-       # `project_page` must have been called before so that information is computed.
-       fun table_projects(mprojects: Array[MProject]): Template
+       # `package_page` must have been called before so that information is computed.
+       fun table_packages(mpackages: Array[MPackage]): Template
        do
-               alpha_comparator.sort(mprojects)
+               alpha_comparator.sort(mpackages)
                var res = new Template
                res.add "<table data-toggle=\"table\" data-sort-name=\"name\" data-sort-order=\"desc\" width=\"100%\">\n"
                res.add "<thead><tr>\n"
                res.add "<th data-field=\"name\" data-sortable=\"true\">name</th>\n"
                res.add "<th data-field=\"maint\" data-sortable=\"true\">maint</th>\n"
                res.add "<th data-field=\"contrib\" data-sortable=\"true\">contrib</th>\n"
-               res.add "<th data-field=\"reqs\" data-sortable=\"true\">reqs</th>\n"
-               res.add "<th data-field=\"dreqs\" data-sortable=\"true\">direct<br>reqs</th>\n"
-               res.add "<th data-field=\"cli\" data-sortable=\"true\">clients</th>\n"
-               res.add "<th data-field=\"dcli\" data-sortable=\"true\">direct<br>clients</th>\n"
+               if deps.not_empty then
+                       res.add "<th data-field=\"reqs\" data-sortable=\"true\">reqs</th>\n"
+                       res.add "<th data-field=\"dreqs\" data-sortable=\"true\">direct<br>reqs</th>\n"
+                       res.add "<th data-field=\"cli\" data-sortable=\"true\">clients</th>\n"
+                       res.add "<th data-field=\"dcli\" data-sortable=\"true\">direct<br>clients</th>\n"
+               end
                res.add "<th data-field=\"mod\" data-sortable=\"true\">modules</th>\n"
                res.add "<th data-field=\"cla\" data-sortable=\"true\">classes</th>\n"
                res.add "<th data-field=\"met\" data-sortable=\"true\">methods</th>\n"
                res.add "<th data-field=\"loc\" data-sortable=\"true\">lines</th>\n"
                res.add "<th data-field=\"score\" data-sortable=\"true\">score</th>\n"
                res.add "</tr></thead>"
-               for p in mprojects do
+               for p in mpackages do
                        res.add "<tr>"
                        res.add "<td><a href=\"{p.name}.html\">{p.name}</a></td>"
                        var maint = "?"
                        if p.maintainers.not_empty then maint = p.maintainers.first
                        res.add "<td>{maint}</td>"
                        res.add "<td>{p.contributors.length}</td>"
-                       res.add "<td>{deps[p].greaters.length-1}</td>"
-                       res.add "<td>{deps[p].direct_greaters.length}</td>"
-                       res.add "<td>{deps[p].smallers.length-1}</td>"
-                       res.add "<td>{deps[p].direct_smallers.length}</td>"
+                       if deps.not_empty then
+                               res.add "<td>{deps[p].greaters.length-1}</td>"
+                               res.add "<td>{deps[p].direct_greaters.length}</td>"
+                               res.add "<td>{deps[p].smallers.length-1}</td>"
+                               res.add "<td>{deps[p].direct_smallers.length}</td>"
+                       end
                        res.add "<td>{mmodules[p]}</td>"
                        res.add "<td>{mclasses[p]}</td>"
                        res.add "<td>{mmethods[p]}</td>"
@@ -600,6 +651,13 @@ end
 var model = new Model
 var tc = new ToolContext
 
+var opt_dir = new OptionString("Directory where the HTML files are generated", "-d", "--dir")
+var opt_no_git = new OptionBool("Do not gather git information from the working directory", "--no-git")
+var opt_no_parse = new OptionBool("Do not parse nit files (no importation information)", "--no-parse")
+var opt_no_model = new OptionBool("Do not analyse nit files (no class/method information)", "--no-model")
+
+tc.option_context.add_option(opt_dir, opt_no_git, opt_no_parse, opt_no_model)
+
 tc.process_options(sys.args)
 tc.keep_going = true
 
@@ -612,31 +670,36 @@ for a in tc.option_context.rest do
        modelbuilder.identify_file(a)
 end
 
-# Scan projects and compute information
-for p in model.mprojects do
+# Scan packages and compute information
+for p in model.mpackages do
        var g = p.root
        assert g != null
        modelbuilder.scan_group(g)
 
        # Load the module to process importation information
+       if opt_no_parse.value then continue
        modelbuilder.parse_group(g)
 
        catalog.deps.add_node(p)
        for gg in p.mgroups do for m in gg.mmodules do
                for im in m.in_importation.direct_greaters do
-                       var ip = im.mproject
+                       var ip = im.mpackage
                        if ip == null or ip == p then continue
                        catalog.deps.add_edge(p, ip)
                end
        end
+end
 
+if not opt_no_git.value then for p in model.mpackages do
        catalog.git_info(p)
 end
 
 # Run phases to modelize classes and properties (so we can count them)
-#modelbuilder.run_phases
+if not opt_no_model.value then
+       modelbuilder.run_phases
+end
 
-var out = "out"
+var out = opt_dir.value or else "catalog.out"
 out.mkdir
 
 # Generate the css (hard coded)
@@ -741,31 +804,33 @@ css.write_to_file(out/"style.css")
 
 # PAGES
 
-for p in model.mprojects do
+for p in model.mpackages do
        # print p
        var f = "{p.name}.html"
-       catalog.project_page(p).write_to_file(out/f)
+       catalog.package_page(p).write_to_file(out/f)
 end
 
 # INDEX
 
 var index = new CatalogPage
-index.more_head.add "<title>Projects in Nit</title>"
+index.more_head.add "<title>Packages in Nit</title>"
 
 index.add """
 <div class="content">
-<h1>Projects in Nit</h1>
+<h1>Packages in Nit</h1>
 """
 
-index.add "<h2>Highlighted Projects</h2>\n"
+index.add "<h2>Highlighted Packages</h2>\n"
 index.add catalog.list_best(catalog.score)
 
-index.add "<h2>Most Required</h2>\n"
-var reqs = new Counter[MProject]
-for p in model.mprojects do
-       reqs[p] = catalog.deps[p].smallers.length - 1
+if catalog.deps.not_empty then
+       index.add "<h2>Most Required</h2>\n"
+       var reqs = new Counter[MPackage]
+       for p in model.mpackages do
+               reqs[p] = catalog.deps[p].smallers.length - 1
+       end
+       index.add catalog.list_best(reqs)
 end
-index.add catalog.list_best(reqs)
 
 index.add "<h2>By First Tag</h2>\n"
 index.add catalog.list_by(catalog.cat2proj, "cat_")
@@ -778,7 +843,7 @@ index.add """
 <div class="sidebar">
 <h3>Stats</h3>
 <ul class="box">
-<li>{{{model.mprojects.length}}} projects</li>
+<li>{{{model.mpackages.length}}} packages</li>
 <li>{{{catalog.maint2proj.length}}} maintainers</li>
 <li>{{{catalog.contrib2proj.length}}} contributors</li>
 <li>{{{catalog.tag2proj.length}}} tags</li>
@@ -810,6 +875,6 @@ page = new CatalogPage
 page.more_head.add "<title>Projets of Nit</title>"
 page.add """<div class="content">\n<h1>People of Nit</h1>\n"""
 page.add "<h2>Table of Projets</h2>\n"
-page.add catalog.table_projects(model.mprojects)
+page.add catalog.table_packages(model.mpackages)
 page.add "</div>\n"
 page.write_to_file(out/"table.html")
index 7bbe3aa..1b492c4 100644 (file)
@@ -63,7 +63,7 @@ class ProjTree
                                if o.mmodule != null and not o.mmodule.in_importation.direct_greaters.is_empty then
                                        var ms = new Array[String]
                                        for m in o.mmodule.in_importation.direct_greaters do
-                                               if m.mgroup.mproject == o.mmodule.mgroup.mproject then
+                                               if m.mgroup.mpackage == o.mmodule.mgroup.mpackage then
                                                        ms.add m.name
                                                else
                                                        ms.add m.full_name
@@ -109,15 +109,15 @@ var tc = new ToolContext
 
 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_tree = new OptionBool("List source files in their groups and packages", "-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_package = new OptionBool("List packages paths (default)", "-P", "--package")
 var opt_depends = new OptionBool("List dependencies of given modules", "-d", "--depends")
 var opt_make = new OptionBool("List dependencies suitable for a rule in a Makefile. Alias for -d, -p and -s", "-M")
 var opt_paths = new OptionBool("List only path (instead of name + path)", "-p", "--path")
 
-tc.option_context.add_option(opt_keep, opt_recursive, opt_tree, opt_source, opt_project, opt_depends, opt_paths, opt_make)
-tc.tooldescription = "Usage: nitls [OPTION]... <file.nit|directory>...\nLists the projects and/or paths of Nit sources files."
+tc.option_context.add_option(opt_keep, opt_recursive, opt_tree, opt_source, opt_package, opt_depends, opt_paths, opt_make)
+tc.tooldescription = "Usage: nitls [OPTION]... <file.nit|directory>...\nLists the packages and/or paths of Nit sources files."
 tc.accept_no_arguments = true
 tc.process_options(args)
 
@@ -127,13 +127,13 @@ if opt_make.value then
        opt_source.value = true
 end
 
-var sum = opt_tree.value.to_i + opt_source.value.to_i + opt_project.value.to_i
+var sum = opt_tree.value.to_i + opt_source.value.to_i + opt_package.value.to_i
 if sum > 1 then
-       print "Error: options --tree, --source, and --project are exclusive."
+       print "Error: options --tree, --source, and --package are exclusive."
        print tc.tooldescription
        exit 1
 end
-if sum == 0 then opt_project.value = true
+if sum == 0 then opt_package.value = true
 tc.keep_going = opt_keep.value
 
 var model = new Model
@@ -159,12 +159,12 @@ else
 end
 
 if sum == 0 then
-       # If one of the file is a group, default is `opt_tree` instead of `opt_project`
+       # If one of the file is a group, default is `opt_tree` instead of `opt_package`
        for a in files do
                var g = mb.get_mgroup(a)
                if g != null then
                        opt_tree.value = true
-                       opt_project.value = false
+                       opt_package.value = false
                        break
                end
        end
@@ -174,7 +174,7 @@ end
 for a in files do
        var g = mb.get_mgroup(a)
        var mp = mb.identify_file(a)
-       if g != null and not opt_project.value then
+       if g != null and not opt_package.value then
                mb.scan_group(g)
        end
        if g == null and mp == null then
@@ -182,7 +182,7 @@ for a in files do
                var fs = a.files
                for f in fs do
                        g = mb.get_mgroup(a/f)
-                       if g != null and not opt_project.value then
+                       if g != null and not opt_package.value then
                                mb.scan_group(g)
                        end
                        mp = mb.identify_file(a/f)
@@ -207,7 +207,7 @@ var ot = new ProjTree(tc)
 var sorter = new AlphaEntityComparator
 if opt_tree.value then
        ot.opt_paths = opt_paths.value
-       for p in model.mprojects do
+       for p in model.mpackages do
                for g in p.mgroups do
                        var pa = g.parent
                        if g.is_interesting then
@@ -225,7 +225,7 @@ end
 
 if opt_source.value then
        var list = new Array[ModulePath]
-       for p in model.mprojects do
+       for p in model.mpackages do
                for g in p.mgroups do
                        for mp in g.module_paths do
                                list.add mp
@@ -242,9 +242,9 @@ if opt_source.value then
        end
 end
 
-if opt_project.value then
+if opt_package.value then
        var list = new Array[MGroup]
-       for p in model.mprojects do
+       for p in model.mpackages do
                list.add p.root.as(not null)
        end
        sorter.sort(list)
index fcaf8fb..83b697e 100644 (file)
@@ -69,7 +69,7 @@ redef class ToolContext
        var opt_dir: OptionString = new OptionString("Output directory", "--dir")
 
        # Depth of the visit and generation
-       var opt_depth = new OptionEnum(["module", "group", "project"],
+       var opt_depth = new OptionEnum(["module", "group", "package"],
                "Depth of the visit and generation", 0, "-d", "--depth")
 
        redef init
@@ -163,11 +163,11 @@ for mmodule in mmodules do
                modelbuilder.scan_group mgroup
                target_modules = mgroup.mmodules
        else if toolcontext.opt_depth.value == 2 then
-               # project
+               # package
                target_modules = new Array[MModule]
                importations = new Array[MModule]
                if mgroup != null then
-                       for g in mgroup.mproject.mgroups do
+                       for g in mgroup.mpackage.mgroups do
                                target_modules.add_all g.mmodules
                        end
 
similarity index 96%
rename from src/project.ini
rename to src/package.ini
index 065ad8f..292ff28 100644 (file)
@@ -1,4 +1,4 @@
-[project]
+[package]
 name=nitc
 tags=devel,cli
 maintainer=Jean Privat <jean@pryen.org>
index 0990d6a..5204376 100644 (file)
@@ -2811,7 +2811,7 @@ class AModuleName
        # The starting quad (`::`)
        var n_quad: nullable TQuad = null is writable
 
-       # The list of quad-separated project/group identifiers
+       # The list of quad-separated package/group identifiers
        var n_path = new ANodes[TId](self)
 
        # The final module identifier
@@ -2847,7 +2847,7 @@ class AQualified
        # The starting quad (`::`)
        var n_quad: nullable TQuad = null is writable
 
-       # The list of quad-separated project/group/module identifiers
+       # The list of quad-separated package/group/module identifiers
        var n_id = new ANodes[TId](self)
 
        # A class identifier
index a925c88..1a6f458 100644 (file)
@@ -260,9 +260,9 @@ $(call import-module,android/native_app_glue)
                # Copy assets, resources and libs where expected by the SDK
 
                var project_root = "."
-               var mproject = compiler.mainmodule.first_real_mmodule.mproject
-               if mproject != null then
-                       var root = mproject.root
+               var mpackage = compiler.mainmodule.first_real_mmodule.mpackage
+               if mpackage != null then
+                       var root = mpackage.root
                        if root != null then
                                var filepath = root.filepath
                                if filepath != null then
@@ -337,11 +337,16 @@ $(call import-module,android/native_app_glue)
                        var tsa_server= "TSA_SERVER".environ
 
                        if key_alias.is_empty then
-                               toolcontext.error(null,
-                                       "Error: the environment variable `KEY_ALIAS` must be set to use the `--release` option on Android projects.")
+                               toolcontext.warning(null, "key-alias",
+                                       "Warning: the environment variable `KEY_ALIAS` is not set, the APK file will not be signed.")
+
+                               # Just move the unsigned APK to outname
+                               args = ["mv", apk_path, outname]
+                               toolcontext.exec_and_check(args, "Android project error")
                                return
                        end
 
+                       # We have a key_alias, try to sign the APK
                        args = ["jarsigner", "-sigalg", "MD5withRSA", "-digestalg", "SHA1", apk_path, key_alias]
 
                        ## Use a custom keystore
index 4366aac..854eb3a 100644 (file)
@@ -57,14 +57,14 @@ read_model.load(neo_model)
 # Compare model
 var sorter = new MEntityNameSorter
 
-print "# mprojects:"
-var org_mprojects = org_model.mprojects.to_a
-sorter.sort org_mprojects
-print org_mprojects.join(" ")
+print "# mpackages:"
+var org_mpackages = org_model.mpackages.to_a
+sorter.sort org_mpackages
+print org_mpackages.join(" ")
 print "------------------------------------"
-var neo_mprojects = neo_model.mprojects.to_a
-sorter.sort neo_mprojects
-print neo_mprojects.join(" ")
+var neo_mpackages = neo_model.mpackages.to_a
+sorter.sort neo_mpackages
+print neo_mpackages.join(" ")
 
 print "\n# mmodules:"
 var org_mmodules = org_model.mmodules.to_a
index ba43e00..22fc750 100644 (file)
@@ -31,7 +31,7 @@ redef fun do_work(mainmodule, given_mmodules, modelbuilder)
 do
        print "It works"
        var model = modelbuilder.model
-       print "I have {model.mprojects.length} projects"
+       print "I have {model.mpackages.length} packages"
        print "I have {model.mmodules.length} modules"
        var mclasses = mainmodule.flatten_mclass_hierarchy
        print "I have {mclasses.length} classes"
index 4a4e33c..6bd8f0b 100644 (file)
@@ -290,11 +290,8 @@ private class NitunitDecorator
        var executor: NitUnitExecutor
 
        redef fun add_code(v, block) do
-               var code = code_from_block(block)
-               var meta = "nit"
-               if block isa BlockFence and block.meta != null then
-                       meta = block.meta.to_s
-               end
+               var code = block.raw_content
+               var meta = block.meta or else "nit"
                # Do not try to test non-nit code.
                if meta != "nit" then return
                # Try to parse code blocks
@@ -321,26 +318,6 @@ private class NitunitDecorator
                # Add it to the file
                executor.blocks.last.append code
        end
-
-       # Extracts code as String from a `BlockCode`.
-       fun code_from_block(block: BlockCode): String do
-               var infence = block isa BlockFence
-               var text = new FlatBuffer
-               var line = block.block.first_line
-               while line != null do
-                       if not line.is_empty then
-                               var str = line.value
-                               if not infence and str.has_prefix("    ") then
-                                       text.append str.substring(4, str.length - line.trailing)
-                               else
-                                       text.append str
-                               end
-                       end
-                       text.append "\n"
-                       line = line.next
-               end
-               return text.write_to_string
-       end
 end
 
 # A unit-test to run
@@ -381,10 +358,10 @@ redef class ModelBuilder
                # usualy, only the original module must be imported in the unit test.
                var o = mmodule
                var g = o.mgroup
-               if g != null and g.mproject.name == "core" then
+               if g != null and g.mpackage.name == "core" then
                        # except for a unit test in a module of `core`
                        # in this case, the whole `core` must be imported
-                       o = get_mmodule_by_name(nmodule, g, g.mproject.name).as(not null)
+                       o = get_mmodule_by_name(nmodule, g, g.mpackage.name).as(not null)
                end
 
                ts.attr("package", mmodule.full_name)
index 93479ea..8be85d4 100644 (file)
@@ -518,7 +518,7 @@ The Nit language documentation and the source code of its tools and libraries ma
                return sys.program_name.basename
        end
 
-       # The identified root directory of the Nit project
+       # The identified root directory of the Nit package
        var nit_dir: String is noinit
 
        private fun compute_nit_dir: String
@@ -580,7 +580,7 @@ end
 #
 # $ nitls --[TAB][TAB]
 # --bash-toolname        --keep                 --path                 --tree
-# --depends              --log                  --project              --verbose
+# --depends              --log                  --package              --verbose
 # --disable-phase        --log-dir              --quiet                --version
 # --gen-bash-completion  --no-color             --recursive            --warn
 # --help                 --only-metamodel       --source
index ae082af..1ca2cf0 100644 (file)
@@ -1,2 +1,2 @@
-nitiwiki --config ../contrib/nitiwiki/tests/wiki1/config2.ini --clean --status
-nitiwiki --config ../contrib/nitiwiki/tests/wiki1/config2.ini --clean --render -v
+--config ../contrib/nitiwiki/tests/wiki1/config2.ini --clean --status
+--config ../contrib/nitiwiki/tests/wiki1/config2.ini --clean --render -v ; rm -r ../contrib/nitiwiki/tests/wiki1/out/
diff --git a/tests/project1/project2/package.ini b/tests/project1/project2/package.ini
new file mode 100644 (file)
index 0000000..e69de29
index c3eac84..5a6669c 100644 (file)
@@ -1,4 +1,5 @@
 fatal error: 'endian.h' file not found
 Error: package `glesv1_cm` unknown by `pkg-config`, make sure the development package is be installed
 Error: package `glesv2` unknown by `pkg-config`, make sure the development package is be installed
+Error: package `egl` unknown by `pkg-config`, make sure the development package is be installed
 fatal error: 'libintl.h' file not found
diff --git a/tests/sav/ballz_linux.res b/tests/sav/ballz_linux.res
new file mode 100644 (file)
index 0000000..18bfeab
--- /dev/null
@@ -0,0 +1,2 @@
+../lib/mnit/linux/linux_app.nit:29,16--31: Redef Error: a virtual type cannot be refined.
+../lib/mnit/linux/linux_app.nit:30,16--29: Redef Error: a virtual type cannot be refined.
index 03c32db..01782ba 100644 (file)
@@ -1,6 +1,6 @@
 OverviewPage Overview
        # home.article
-               ## projects.section
+               ## packages.section
                        ### test_prog.definition
 
 ReadmePage test_prog
@@ -1026,5 +1026,5 @@ Found 182 mentities
   MGroup: 4 (2.19%)
   MVirtualTypeDef: 1 (0.54%)
   MVirtualTypeProp: 1 (0.54%)
-  MProject: 1 (0.54%)
+  MPackage: 1 (0.54%)
 quicksearch-list.js
index 9b3545d..cb5affc 100644 (file)
@@ -2,7 +2,7 @@
 
 # MModules metrics
 
- ## project base_simple3
+ ## package base_simple3
   `- group base_simple3
        mnoa: number of ancestor modules
          avg: 0.0
@@ -364,7 +364,7 @@ Distribution of direct smallers
 
 # MClasses metrics
 
- ## project base_simple3
+ ## package base_simple3
   `- group base_simple3
        cnoa: number of ancestor classes
          avg: 0.0
@@ -488,12 +488,12 @@ Distribution of direct smallers
          min: Object (0)
          std: 0.926
          sum: 6
-generating project_hierarchy.dot
+generating package_hierarchy.dot
 generating module_hierarchy.dot
 
 # Inheritance metrics
 
- ## project base_simple3
+ ## package base_simple3
   `- group base_simple3
        cnoac: number of class_kind ancestor
          avg: 0.0
@@ -751,7 +751,7 @@ Statistics of type usage:
 
 # Nullable metrics
 
- ## project base_simple3
+ ## package base_simple3
   `- group base_simple3
        cnba: number of accessible attributes (inherited + local)
          avg: 0.0
@@ -910,5 +910,5 @@ mmodules/
 model.html
 module_hierarchy.dot
 nullables/
-project_hierarchy.dot
+package_hierarchy.dot
 rta/
index b1fdd02..6bf30a6 100644 (file)
@@ -3,7 +3,7 @@
 
  \e[1m\e[32mP\e[m\e[m \e[1m\e[34mbase_simple3\e[m\e[m
    \e[1m\e[30mbase_simple3\e[m\e[m
-   project base_simple3
+   package base_simple3
    \e[30mbase_simple3.nit:17,1--66,13\e[m
 
  \e[1m\e[32mG\e[m\e[m \e[1m\e[34mbase_simple3\e[m\e[m
index 6106689..4ac86da 100644 (file)
@@ -1,4 +1,4 @@
-# mprojects:
+# mpackages:
 test_prog
 ------------------------------------
 test_prog
index 6e70412..03cf44d 100644 (file)
@@ -1,5 +1,5 @@
 It works
-I have 1 projects
+I have 1 packages
 I have 1 modules
 I have 7 classes
 For 7 definitions of classes