--- /dev/null
+# NAME
+
+nitweb - provide a web API to nit model and source code.
+
+
+# SYNOPSIS
+
+nitweb [*options*] FILE...
+
+
+# DESCRIPTION
+
+`nitweb` use `nitcorn` actions to provide an API to loaded model and source code.
+
+Usage:
+
+~~~sh
+nitweb --host localhost --port 3000 lib/core/
+~~~
+
+### `GET /` HOME
+Show the home page of the webserver.
+Display all the loaded model entities in a tree.
+
+### `GET /search/:namespace` SEARCH BY NAMESPACE
+Search all model entities matching `namespace`.
+
+It is possible to retrieve the result as a JsonArray instead of raw html
+using the uri param `json=true` (default `false`).
+
+### `GET /code/:namespace` SHOW SOURCE CODE
+Display the source code of the entity matching `namespace`.
+
+### `GET /doc/:namespace` DOCUMENTATION PAGE
+Display a short documentation page about the entity matching `namespace`.
+
+### `GET /random/` RANDOM LIST
+Display a random list of entities found in the model.
+
+The list is parametrable with the following uri params:
+* `n=10` size of the list (default `10`)
+* `k=modules` kind of entities in the list (default `modules`)
+
+It is possible to retrieve the result as a JsonArray instead of raw html
+using the uri param `json=true` (default `false`).
+
+# OPTIONS
+
+### `--host`
+The host to bind the web server on.
+
+### `--port`
+Port number to use
+
+### `-h`, `-?`, `--help`
+Show Help (the list of options).
+
+# SEE ALSO
+
+* nitcorn
+* nitdoc
module html_model
import doc_base
-import doc_down
import html_components
-import html::bootstrap
import ordered_tree
-import model::model_collect
+import web::model_html
redef class MEntity
# URL of this entity’s Nitdoc page.
fun nitdoc_url: String is abstract
- # Returns the mentity name without short signature.
- #
- # * MPackage: `foo`
- # * MGroup: `foo`
- # * MModule: `foo`
- # * MClass: `Foo[E]`
- # * MClassDef: `Foo[E]`
- # * MProperty: `foo(e)`
- # * MPropdef: `foo(e)`
- var html_name: String is lazy do return name.html_escape
-
# Returns a Link to the mentity `html_url`.
#
# Example: `<a href="html_url" title="mdoc.short_comment">html_short_name</a>
- var html_link: Link is lazy do
+ redef var html_link is lazy do
var tpl = new Link(nitdoc_url, html_name)
var mdoc = mdoc_or_fallback
if mdoc != null then
return tpl
end
- # Returns the list of keyword used in `self` declaration.
- fun html_modifiers: Array[String] is abstract
-
- # Returns the complete MEntity declaration decorated with HTML.
- #
- # * MPackage: `package foo`
- # * MGroup: `group foo`
- # * MModule: `module foo`
- # * MClass: `private abstract class Foo[E: Object]`
- # * MClassDef: `redef class Foo[E]`
- # * MProperty: `private fun foo(e: Object): Int`
- # * MPropdef: `redef fun foo(e)`
- fun html_declaration: Template do
- var tpl = new Template
- tpl.add "<span>"
- tpl.add html_modifiers.join(" ")
- tpl.add " "
- tpl.add html_link
- tpl.add "</span>"
- return tpl
- end
-
- # Returns `self` namespace decorated with HTML links.
- #
- # * MPackage: `mpackage`
- # * MGroup: `mpackage(::group)`
- # * MModule: `mgroup::mmodule`
- # * MClass: `mpackage::mclass`
- # * MClassDef: `mmodule::mclassdef`
- # * MProperty: `mclass::mprop`
- # * MPropdef: `mclassdef:mpropdef`
- fun html_namespace: Template is abstract
-
- # Returns the synopsis and the comment of this MEntity formatted as HTML.
- var html_documentation: nullable Writable is lazy do
- var mdoc = mdoc_or_fallback
- if mdoc == null then return null
- return mdoc.html_documentation
- end
-
- # Returns the synopsis of this MEntity formatted as HTML.
- var html_synopsis: nullable Writable is lazy do
- var mdoc = mdoc_or_fallback
- if mdoc == null then return null
- return mdoc.html_synopsis
- end
-
- # Returns the the comment without the synopsis formatted as HTML.
- var html_comment: nullable Writable is lazy do
- var mdoc = mdoc_or_fallback
- if mdoc == null then return null
- return mdoc.html_comment
- end
-
- # Icon that will be displayed before the title
- fun html_icon: BSIcon do
- var icon = new BSIcon("tag")
- icon.css_classes.add_all(css_classes)
- return icon
- end
-
- # CSS classes used to decorate `self`.
- #
- # Mainly used for icons.
- var css_classes = new Array[String]
-
# A li element that can go in a `HTMLList`.
fun html_list_item: ListItem do
var tpl = new Template
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 = ["package"]
- redef fun html_namespace do return html_link
- redef var css_classes = ["public"]
+
+ redef fun nitdoc_url do
+ var root = self.root
+ if root == null then return super
+ return root.nitdoc_url
+ end
end
redef class MGroup
redef var nitdoc_id is lazy do
+ var parent = self.parent
if parent != null then
return "{parent.nitdoc_id}__{name.to_cmangle}"
end
end
redef fun nitdoc_url do return "group_{nitdoc_id}.html"
- redef var html_modifiers = ["group"]
-
- # Depends if `self` is root or not.
- #
- # * If root `mpackage`.
- # * Else `mpackage::self`.
- redef fun html_namespace do
- var tpl = new Template
- tpl.add mpackage.html_namespace
- if mpackage.root != self then
- tpl.add "::"
- tpl.add html_link
- end
- return tpl
- end
-
- redef var css_classes = ["public"]
end
redef class MModule
redef var nitdoc_id is lazy do
+ var mgroup = self.mgroup
if mgroup != null then
if mgroup.mmodules.length == 1 then
return "{mgroup.nitdoc_id}-"
end
redef fun nitdoc_url do return "module_{nitdoc_id}.html"
- redef var html_modifiers = ["module"]
-
- # Depends if `self` belongs to a MGroup.
- #
- # * If mgroup `mgroup::self`.
- # * Else `self`.
- redef fun html_namespace do
- var tpl = new Template
- if mgroup != null then
- tpl.add mgroup.html_namespace
- tpl.add "::"
- end
- tpl.add html_link
- return tpl
- end
-
- redef var css_classes = ["public"]
end
redef class MClass
redef var nitdoc_id = "{intro_mmodule.nitdoc_id}__{name.to_cmangle}" is lazy
redef fun nitdoc_url do return "class_{nitdoc_id}.html"
- redef fun mdoc_or_fallback do return intro.mdoc
-
- # Format: `Foo[E]`
- redef var html_name is lazy do
- var tpl = new Template
- tpl.add name.html_escape
- if arity > 0 then
- tpl.add "["
- var parameter_names = new Array[String]
- for p in mparameters do
- parameter_names.add(p.html_name)
- end
- tpl.add parameter_names.join(", ")
- tpl.add "]"
- end
- return tpl.write_to_string
- end
-
- redef fun html_modifiers do return intro.html_modifiers
- redef fun html_declaration do return intro.html_declaration
-
- # Returns `mpackage::self`.
- redef fun html_namespace do
- var tpl = new Template
- tpl.add intro_mmodule.mgroup.mpackage.html_namespace
- tpl.add "::<span>"
- tpl.add html_link
- tpl.add "</span>"
- return tpl
- end
-
- # Returns `intro.html_short_signature`.
- fun html_short_signature: Template do return intro.html_short_signature
-
- # Returns `intro.html_signature`.
- fun html_signature: Template do return intro.html_signature
-
- redef fun html_icon do return intro.html_icon
- redef fun css_classes do return intro.css_classes
end
redef class MClassDef
redef var nitdoc_id = "{mmodule.nitdoc_id}__{name.to_cmangle}" is lazy
redef fun nitdoc_url do return "{mclass.nitdoc_url}#{nitdoc_id}"
- redef fun mdoc_or_fallback do return mdoc or else mclass.mdoc_or_fallback
-
- # Depends if `self` is an intro or not.
- #
- # * If intro contains the visibility and kind.
- # * If redef contains the `redef` keyword and kind.
- redef fun html_modifiers do
- var res = new Array[String]
- if not is_intro then
- res.add "redef"
- else
- if mclass.visibility != public_visibility then
- res.add mclass.visibility.to_s
- end
- end
- res.add mclass.kind.to_s
- return res
- end
-
- # Depends if `self` is an intro or not.
- #
- # For intro: `private abstract class Foo[E: Object]`
- # For redef: `redef class Foo[E]`
- redef fun html_declaration do
- var tpl = new Template
- tpl.add "<span>"
- tpl.add html_modifiers.join(" ")
- tpl.add " "
- tpl.add html_link
- if is_intro then
- tpl.add html_signature
- else
- tpl.add html_short_signature
- end
- tpl.add "</span>"
- return tpl
- end
-
- # Returns `mmodule::self`
- redef fun html_namespace do
- var tpl = new Template
- tpl.add mmodule.html_namespace
- tpl.add "::<span>"
- tpl.add mclass.html_link
- tpl.add "</span>"
- return tpl
- end
-
- # Returns the MClassDef generic signature without static bounds.
- fun html_short_signature: Template do
- var tpl = new Template
- var mparameters = mclass.mparameters
- if not mparameters.is_empty then
- tpl.add "["
- for i in [0..mparameters.length[ do
- tpl.add mparameters[i].html_name
- if i < mparameters.length - 1 then tpl.add ", "
- end
- tpl.add "]"
- end
- return tpl
- end
-
- # Returns the MClassDef generic signature with static bounds.
- fun html_signature: Template do
- var tpl = new Template
- var mparameters = mclass.mparameters
- if not mparameters.is_empty then
- tpl.add "["
- for i in [0..mparameters.length[ do
- tpl.add "{mparameters[i].html_name}: "
- tpl.add bound_mtype.arguments[i].html_signature
- if i < mparameters.length - 1 then tpl.add ", "
- end
- tpl.add "]"
- end
- return tpl
- end
-
- redef fun css_classes do
- var set = new HashSet[String]
- if is_intro then set.add "intro"
- for m in mclass.intro.collect_modifiers do set.add m.to_cmangle
- for m in collect_modifiers do set.add m.to_cmangle
- return set.to_a
- end
end
redef class MProperty
redef var nitdoc_id = "{intro_mclassdef.mclass.nitdoc_id}__{name.to_cmangle}" is lazy
redef fun nitdoc_url do return "property_{nitdoc_id}.html"
- redef fun mdoc_or_fallback do return intro.mdoc
- redef fun html_modifiers do return intro.html_modifiers
- redef fun html_declaration do return intro.html_declaration
-
- # Returns `mclass::self`.
- redef fun html_namespace do
- var tpl = new Template
- tpl.add intro_mclassdef.mclass.html_namespace
- tpl.add "::<span>"
- tpl.add intro.html_link
- tpl.add "</span>"
- return tpl
- end
-
- # Returns `intro.html_short_signature`.
- fun html_short_signature: Template do return intro.html_short_signature
-
- # Returns `intro.html_signature`.
- fun html_signature: Template do return intro.html_signature
-
- redef fun css_classes do return intro.css_classes
end
redef class MPropDef
redef var nitdoc_id = "{mclassdef.nitdoc_id}__{name.to_cmangle}" is lazy
redef fun nitdoc_url do return "{mproperty.nitdoc_url}#{nitdoc_id}"
- redef fun mdoc_or_fallback do return mdoc or else mproperty.mdoc_or_fallback
-
- # Depends if `self` is an intro or not.
- #
- # * If intro contains the visibility and kind.
- # * If redef contains the `redef` keyword and kind.
- redef fun html_modifiers do
- var res = new Array[String]
- if not is_intro then
- res.add "redef"
- else
- if mproperty.visibility != public_visibility then
- res.add mproperty.visibility.to_s
- end
- end
- return res
- end
-
- # Depends if `self` is an intro or not.
- #
- # For intro: `private fun foo(e: Object): Bar is abstract`
- # For redef: `redef fun foo(e) is cached`
- redef fun html_declaration do
- var tpl = new Template
- tpl.add "<span>"
- tpl.add html_modifiers.join(" ")
- tpl.add " "
- if is_intro then
- tpl.add html_link
- tpl.add html_signature
- else
- tpl.add mproperty.intro.html_link
- tpl.add html_short_signature
- end
- tpl.add "</span>"
- return tpl
- end
-
- # Returns `mclassdef::self`
- redef fun html_namespace do
- var tpl = new Template
- tpl.add mclassdef.html_namespace
- tpl.add "::"
- tpl.add html_link
- return tpl
- end
-
- # Returns the MPropdDef signature without static types.
- fun html_short_signature: Template is abstract
-
- # Returns the MPropDef signature with static types.
- fun html_signature: Template is abstract
-
- redef fun css_classes do
- var set = new HashSet[String]
- if is_intro then set.add "intro"
- for m in mproperty.intro.collect_modifiers do set.add m.to_cmangle
- for m in collect_modifiers do set.add m.to_cmangle
- return set.to_a
- end
end
redef class MAttributeDef
redef fun html_short_signature do return new Template
redef fun html_signature do
+ var static_mtype = self.static_mtype
var tpl = new Template
if static_mtype != null then
tpl.add ": "
end
end
-redef class MMethodDef
-
- # FIXME annotation should be handled in their own way
- redef fun html_modifiers do
- if mproperty.is_init then
- var res = new Array[String]
- if mproperty.visibility != public_visibility then
- res.add mproperty.visibility.to_s
- end
- return res
- end
- var res = super
- if is_abstract then
- res.add "abstract"
- else if is_intern then
- res.add "intern"
- end
- res.add "fun"
- return res
- end
-
- redef fun html_declaration do
- if mproperty.is_init then
- var tpl = new Template
- tpl.add "<span>"
- tpl.add html_modifiers.join(" ")
- tpl.add " "
- tpl.add html_link
- tpl.add html_signature
- tpl.add "</span>"
- return tpl
- end
- return super
- end
-
- redef fun html_short_signature do
- if mproperty.is_root_init and new_msignature != null then
- return new_msignature.html_short_signature
- end
- return msignature.html_short_signature
- end
-
- redef fun html_signature do
- if mproperty.is_root_init and new_msignature != null then
- return new_msignature.html_signature
- end
- return msignature.html_signature
- end
-end
-
-redef class MVirtualTypeProp
- redef fun html_link do return mvirtualtype.html_link
-end
-
-redef class MVirtualTypeDef
-
- redef fun html_modifiers do
- var res = super
- res.add "type"
- return res
- end
-
- redef fun html_short_signature do return new Template
-
- redef fun html_signature do
- var tpl = new Template
- if bound == null then return tpl
- tpl.add ": "
- tpl.add bound.html_signature
- return tpl
- end
-end
-
-redef class MType
- # Returns the signature of this type whithout bounds.
- fun html_short_signature: Template is abstract
-
- # Returns the signature of this type.
- fun html_signature: Template is abstract
-end
-
-redef class MClassType
- redef fun html_link do return mclass.html_link
- redef fun html_short_signature do return html_link
- redef fun html_signature do return html_link
-end
-
-redef class MNullableType
-
- redef fun html_short_signature do
- var tpl = new Template
- tpl.add "nullable "
- tpl.add mtype.html_short_signature
- return tpl
- end
-
- redef fun html_signature do
- var tpl = new Template
- tpl.add "nullable "
- tpl.add mtype.html_signature
- return tpl
- end
-end
-
-redef class MGenericType
- redef fun html_short_signature do
- var lnk = html_link
- var tpl = new Template
- tpl.add new Link.with_title(lnk.href, mclass.name.html_escape, lnk.title)
- tpl.add "["
- for i in [0..arguments.length[ do
- tpl.add arguments[i].html_short_signature
- if i < arguments.length - 1 then tpl.add ", "
- end
- tpl.add "]"
- return tpl
- end
-
- redef fun html_signature do
- var lnk = html_link
- var tpl = new Template
- tpl.add new Link.with_title(lnk.href, mclass.name.html_escape, lnk.title)
- tpl.add "["
- for i in [0..arguments.length[ do
- tpl.add arguments[i].html_signature
- if i < arguments.length - 1 then tpl.add ", "
- end
- tpl.add "]"
- return tpl
- end
-end
-
redef class MParameterType
redef fun html_link do
return new Link.with_title("{mclass.nitdoc_url}#FT_{name.to_cmangle}", name, "formal type")
end
-
- redef fun html_short_signature do return html_link
- redef fun html_signature do return html_link
end
redef class MVirtualType
redef fun html_link do return mproperty.intro.html_link
- redef fun html_signature do return html_link
-end
-
-redef class MSignature
-
- redef fun html_short_signature do
- var tpl = new Template
- if not mparameters.is_empty then
- tpl.add "("
- for i in [0..mparameters.length[ do
- tpl.add mparameters[i].html_short_signature
- if i < mparameters.length - 1 then tpl.add ", "
- end
- tpl.add ")"
- end
- return tpl
- end
-
- redef fun html_signature do
- var tpl = new Template
- if not mparameters.is_empty then
- tpl.add "("
- for i in [0..mparameters.length[ do
- tpl.add mparameters[i].html_signature
- if i < mparameters.length - 1 then tpl.add ", "
- end
- tpl.add ")"
- end
- if return_mtype != null then
- tpl.add ": "
- tpl.add return_mtype.html_signature
- end
- return tpl
- end
-end
-
-redef class MParameter
-
- # Returns `self` name and ellipsys if any.
- fun html_short_signature: Template do
- var tpl = new Template
- tpl.add name
- if is_vararg then tpl.add "..."
- return tpl
- end
-
- # Returns `self` name with it's static type and ellipsys if any.
- fun html_signature: Template do
- var tpl = new Template
- tpl.add "{name}: "
- tpl.add mtype.html_signature
- if is_vararg then tpl.add "..."
- return tpl
- end
end
redef class ConcernsTree
import model
+redef class MEntity
+
+ # Collect mentities with a fully qualified `namespace`.
+ fun collect_by_namespace(namespace: String): Array[MEntity] is abstract
+
+ private fun lookup_in(mentities: Collection[MEntity], namespace: String, res: Array[MEntity]) do
+ var parts = namespace.split_once_on("::")
+ var name = parts.shift
+ for mentity in mentities do
+ if mentity.name != name then continue
+ if parts.is_empty then
+ res.add mentity
+ else
+ res.add_all mentity.collect_by_namespace(parts.first)
+ end
+ end
+ end
+end
+
+redef class Model
+ redef fun collect_by_namespace(namespace) do
+ var res = new Array[MEntity]
+ var parts = namespace.split_once_on("::")
+ var name = parts.shift
+ for mentity in mpackages do
+ if mentity.name != name then continue
+ if parts.is_empty then
+ res.add mentity
+ else
+ res.add_all mentity.collect_by_namespace(parts.first)
+ end
+ end
+ return res
+ end
+end
+
+redef class MPackage
+ redef fun collect_by_namespace(namespace) do
+ var res = new Array[MEntity]
+ var root = self.root
+ if root == null then return res
+ lookup_in([root], namespace, res)
+ return res
+ end
+end
+
+redef class MGroup
+ redef fun collect_by_namespace(namespace) do
+ var res = new Array[MEntity]
+ lookup_in(in_nesting.direct_smallers, namespace, res)
+ lookup_in(mmodules, namespace, res)
+ return res
+ end
+end
+
redef class MModule
+ redef fun collect_by_namespace(namespace) do
+ var res = new Array[MEntity]
+ lookup_in(mclassdefs, namespace, res)
+ return res
+ end
+
# Collect mclassdefs introduced in `self` with `visibility >= to min_visibility`.
fun collect_intro_mclassdefs(min_visibility: MVisibility): Set[MClassDef] do
var res = new HashSet[MClassDef]
end
redef class MClassDef
+
+ redef fun collect_by_namespace(namespace) do
+ var res = new Array[MEntity]
+ lookup_in(mpropdefs, namespace, res)
+ return res
+ end
+
# Collect mpropdefs in 'self' with `visibility >= min_visibility`.
fun collect_mpropdefs(min_visibility: MVisibility): Set[MPropDef] do
var res = new HashSet[MPropDef]
module modelize
import modelize_property
+
+redef class ModelBuilder
+ # Retrieve the associated AST node of a mentity.
+ # This method is used to associate model entity with syntactic entities.
+ #
+ # If the mentity is not associated with a node, returns null.
+ # This is always the case for MPackage, Mgroup, MClass and MProperty.
+ # MModule, MClassDef and MPropDef can also have no node associated
+ # (like fictive modules of generated attributes/methods).
+ fun mentity2node(mentity: MEntity): nullable ANode
+ do
+ if mentity isa MModule then
+ return mmodule2node(mentity)
+ else if mentity isa MClassDef then
+ return mclassdef2node(mentity)
+ else if mentity isa MPropDef then
+ return mpropdef2node(mentity)
+ end
+ return null
+ end
+end
--- /dev/null
+# 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.
+
+# Runs a webserver based on nitcorn that render things from model.
+module nitweb
+
+import frontend
+import web
+
+redef class ToolContext
+
+ # Host name to bind on.
+ var opt_host = new OptionString("Host to bind the server on", "--host")
+
+ # Port number to bind on.
+ var opt_port = new OptionInt("Port number to use", 3000, "--port")
+
+ # Web rendering phase.
+ var webphase: Phase = new NitwebPhase(self, null)
+
+ init do
+ super
+ option_context.add_option(opt_host, opt_port)
+ end
+end
+
+# Phase that builds the model and wait for http request to serve pages.
+private class NitwebPhase
+ super Phase
+ redef fun process_mainmodule(mainmodule, mmodules)
+ do
+ var model = mainmodule.model
+ var modelbuilder = toolcontext.modelbuilder
+
+ # Run the server
+ var host = toolcontext.opt_host.value or else "localhost"
+ var port = toolcontext.opt_port.value
+
+ var srv = new NitServer(host, port.to_i)
+ srv.routes.add new Route("/random", new RandomAction(srv, model))
+ srv.routes.add new Route("/doc/:namespace", new DocAction(srv, model, modelbuilder))
+ srv.routes.add new Route("/code/:namespace", new CodeAction(srv, model, modelbuilder))
+ srv.routes.add new Route("/search/:namespace", new SearchAction(srv, model))
+ srv.routes.add new Route("/", new TreeAction(srv, model))
+
+ srv.listen
+ end
+end
+
+# build toolcontext
+var toolcontext = new ToolContext
+var tpl = new Template
+tpl.add "Usage: nitweb [OPTION]... <file.nit>...\n"
+tpl.add "Run a webserver based on nitcorn that serve pages about model."
+toolcontext.tooldescription = tpl.write_to_string
+
+# process options
+toolcontext.process_options(args)
+var arguments = toolcontext.option_context.rest
+
+# build model
+var model = new Model
+var mbuilder = new ModelBuilder(model, toolcontext)
+var mmodules = mbuilder.parse_full(arguments)
+
+# process
+if mmodules.is_empty then return
+mbuilder.run_phases
+toolcontext.run_global_phases(mmodules)
--- /dev/null
+# 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.
+
+# Translate mentities to html blocks.
+module model_html
+
+import model
+import model::model_collect
+import doc::doc_down
+import html::bootstrap
+
+redef class MEntity
+
+ # Returns the MEntity name escaped for html.
+ #
+ # * MPackage: `foo`
+ # * MGroup: `foo`
+ # * MModule: `foo`
+ # * MClass: `Foo[E]`
+ # * MClassDef: `Foo[E]`
+ # * MProperty: `foo(e)`
+ # * MPropdef: `foo(e)`
+ var html_name: String is lazy do return name.html_escape
+
+ # MEntity namespace escaped for html.
+ fun html_raw_namespace: String is abstract
+
+ # Link to MEntity in the web server.
+ # TODO this should be parameterizable... but how?
+ fun html_link: Link do return new Link("/doc/{html_raw_namespace}", html_name)
+
+ # Returns the list of keyword used in `self` declaration.
+ fun html_modifiers: Array[String] is abstract
+
+ # Returns the complete MEntity declaration decorated with HTML.
+ #
+ # * MPackage: `package foo`
+ # * MGroup: `group foo`
+ # * MModule: `module foo`
+ # * MClass: `private abstract class Foo[E: Object]`
+ # * MClassDef: `redef class Foo[E]`
+ # * MProperty: `private fun foo(e: Object): Int`
+ # * MPropdef: `redef fun foo(e)`
+ fun html_declaration: Template do
+ var tpl = new Template
+ tpl.add "<span>"
+ tpl.add html_modifiers.join(" ")
+ tpl.add " "
+ tpl.add html_link
+ tpl.add "</span>"
+ return tpl
+ end
+
+ # Returns `self` namespace decorated with HTML links.
+ #
+ # * MPackage: `mpackage`
+ # * MGroup: `mpackage(::group)`
+ # * MModule: `mgroup::mmodule`
+ # * MClass: `mpackage::mclass`
+ # * MClassDef: `mmodule::mclassdef`
+ # * MProperty: `mclass::mprop`
+ # * MPropdef: `mclassdef:mpropdef`
+ fun html_namespace: Template is abstract
+
+ # Returns the synopsis and the comment of this MEntity formatted as HTML.
+ var html_documentation: nullable Writable is lazy do
+ var mdoc = mdoc_or_fallback
+ if mdoc == null then return null
+ return mdoc.html_documentation
+ end
+
+ # Returns the synopsis of this MEntity formatted as HTML.
+ var html_synopsis: nullable Writable is lazy do
+ var mdoc = mdoc_or_fallback
+ if mdoc == null then return null
+ return mdoc.html_synopsis
+ end
+
+ # Returns the the comment without the synopsis formatted as HTML.
+ var html_comment: nullable Writable is lazy do
+ var mdoc = mdoc_or_fallback
+ if mdoc == null then return null
+ return mdoc.html_comment
+ end
+
+ # Icon that will be displayed before the title
+ fun html_icon: BSIcon do
+ var icon = new BSIcon("tag")
+ icon.css_classes.add_all(css_classes)
+ return icon
+ end
+
+ # CSS classes used to decorate `self`.
+ #
+ # Mainly used for icons.
+ var css_classes = new Array[String]
+
+ # HTML Tree containing all the nested element of `self`.
+ #
+ # The nested elements depend on the type of `self`:
+ # `MPackage`: root mgroup
+ # `MGroup`: directly nested mgroups, mmodules
+ # `MModule`: mclassdefs
+ # `MClassDef`: mpropdefs
+ fun html_tree: UnorderedList do
+ var list = new UnorderedList
+ list.add_li html_tree_li
+ return list
+ end
+
+ # HTML Tree list item used by `html_tree`.
+ private fun html_tree_li: ListItem do return new ListItem(html_link)
+end
+
+
+redef class MPackage
+ redef fun html_raw_namespace do return html_name
+
+ redef fun html_tree_li do
+ var tpl = new Template
+ tpl.add html_link
+ var list = new UnorderedList
+ var root = self.root
+ if root != null then
+ list.add_li root.html_tree_li
+ end
+ tpl.add list
+ return new ListItem(tpl)
+ end
+
+ redef var html_modifiers = ["package"]
+ redef fun html_namespace do return html_link
+ redef var css_classes = ["public"]
+end
+
+redef class MGroup
+ redef fun html_raw_namespace do
+ var parent = self.parent
+ if parent != null then
+ return "{parent.html_raw_namespace}::{html_name}"
+ end
+ return "{mpackage.html_raw_namespace}::{html_name}"
+ end
+
+ redef var html_modifiers = ["group"]
+
+ # Depends if `self` is root or not.
+ #
+ # * If root `mpackage`.
+ # * Else `mpackage::self`.
+ redef fun html_namespace do
+ var tpl = new Template
+ tpl.add mpackage.html_namespace
+ if mpackage.root != self then
+ tpl.add "::"
+ tpl.add html_link
+ end
+ return tpl
+ end
+
+ redef var css_classes = ["public"]
+
+ redef fun html_tree_li do
+ var tpl = new Template
+ tpl.add html_link
+ var list = new UnorderedList
+ for mgroup in in_nesting.direct_smallers do
+ list.add_li mgroup.html_tree_li
+ end
+ for mmodule in mmodules do
+ list.add_li mmodule.html_tree_li
+ end
+ tpl.add list
+ return new ListItem(tpl)
+ end
+end
+
+redef class MModule
+
+ redef var html_modifiers = ["module"]
+
+ # Depends if `self` belongs to a MGroup.
+ #
+ # * If mgroup `mgroup::self`.
+ # * Else `self`.
+ redef fun html_namespace do
+ var mgroup = self.mgroup
+ var tpl = new Template
+ if mgroup != null then
+ tpl.add mgroup.html_namespace
+ tpl.add "::"
+ end
+ tpl.add html_link
+ return tpl
+ end
+
+ redef fun html_raw_namespace do
+ var mpackage = self.mpackage
+ var mgroup = self.mgroup
+ if mgroup != null then
+ return "{mgroup.html_raw_namespace}::{html_name}"
+ else if mpackage != null then
+ return "{mpackage.html_raw_namespace}::{html_name}"
+ end
+ return html_name
+ end
+
+ redef var css_classes = ["public"]
+
+ redef fun html_tree_li do
+ var tpl = new Template
+ tpl.add html_link
+ var list = new UnorderedList
+ for mclassdef in mclassdefs do
+ list.add_li mclassdef.html_tree_li
+ end
+ tpl.add list
+ return new ListItem(tpl)
+ end
+end
+
+redef class MClass
+ redef fun mdoc_or_fallback do return intro.mdoc
+
+ # Format: `Foo[E]`
+ redef var html_name is lazy do
+ var tpl = new Template
+ tpl.add name.html_escape
+ if arity > 0 then
+ tpl.add "["
+ var parameter_names = new Array[String]
+ for p in mparameters do
+ parameter_names.add(p.html_name)
+ end
+ tpl.add parameter_names.join(", ")
+ tpl.add "]"
+ end
+ return tpl.write_to_string
+ end
+
+ redef fun html_modifiers do return intro.html_modifiers
+ redef fun html_declaration do return intro.html_declaration
+
+ # Returns `mpackage::self`.
+ redef fun html_namespace do
+ var mgroup = intro_mmodule.mgroup
+ var tpl = new Template
+ if mgroup != null then
+ tpl.add mgroup.mpackage.html_namespace
+ tpl.add "::"
+ end
+ tpl.add "<span>"
+ tpl.add html_link
+ tpl.add "</span>"
+ return tpl
+ end
+
+ redef fun html_raw_namespace do return intro.html_raw_namespace
+
+ # Returns `intro.html_short_signature`.
+ fun html_short_signature: Template do return intro.html_short_signature
+
+ # Returns `intro.html_signature`.
+ fun html_signature: Template do return intro.html_signature
+
+ redef fun html_icon do return intro.html_icon
+ redef fun css_classes do return intro.css_classes
+end
+
+redef class MClassDef
+ redef fun html_raw_namespace do return "{mmodule.html_raw_namespace}::{html_name}"
+
+ redef fun html_tree_li do
+ var tpl = new Template
+ tpl.add html_link
+ var list = new UnorderedList
+ for mpropdef in mpropdefs do
+ list.add_li mpropdef.html_tree_li
+ end
+ tpl.add list
+ return new ListItem(tpl)
+ end
+
+ redef fun mdoc_or_fallback do return mdoc or else mclass.mdoc_or_fallback
+
+ # Depends if `self` is an intro or not.
+ #
+ # * If intro contains the visibility and kind.
+ # * If redef contains the `redef` keyword and kind.
+ redef fun html_modifiers do
+ var res = new Array[String]
+ if not is_intro then
+ res.add "redef"
+ else
+ if mclass.visibility != public_visibility then
+ res.add mclass.visibility.to_s
+ end
+ end
+ res.add mclass.kind.to_s
+ return res
+ end
+
+ # Depends if `self` is an intro or not.
+ #
+ # For intro: `private abstract class Foo[E: Object]`
+ # For redef: `redef class Foo[E]`
+ redef fun html_declaration do
+ var tpl = new Template
+ tpl.add "<span>"
+ tpl.add html_modifiers.join(" ")
+ tpl.add " "
+ tpl.add html_link
+ if is_intro then
+ tpl.add html_signature
+ else
+ tpl.add html_short_signature
+ end
+ tpl.add "</span>"
+ return tpl
+ end
+
+ # Returns `mmodule::self`
+ redef fun html_namespace do
+ var tpl = new Template
+ tpl.add mmodule.html_namespace
+ tpl.add "::<span>"
+ tpl.add mclass.html_link
+ tpl.add "</span>"
+ return tpl
+ end
+
+ # Returns the MClassDef generic signature without static bounds.
+ fun html_short_signature: Template do
+ var tpl = new Template
+ var mparameters = mclass.mparameters
+ if not mparameters.is_empty then
+ tpl.add "["
+ for i in [0..mparameters.length[ do
+ tpl.add mparameters[i].html_name
+ if i < mparameters.length - 1 then tpl.add ", "
+ end
+ tpl.add "]"
+ end
+ return tpl
+ end
+
+ # Returns the MClassDef generic signature with static bounds.
+ fun html_signature: Template do
+ var tpl = new Template
+ var mparameters = mclass.mparameters
+ if not mparameters.is_empty then
+ tpl.add "["
+ for i in [0..mparameters.length[ do
+ tpl.add "{mparameters[i].html_name}: "
+ tpl.add bound_mtype.arguments[i].html_signature
+ if i < mparameters.length - 1 then tpl.add ", "
+ end
+ tpl.add "]"
+ end
+ return tpl
+ end
+
+ redef fun css_classes do
+ var set = new HashSet[String]
+ if is_intro then set.add "intro"
+ for m in mclass.intro.collect_modifiers do set.add m.to_cmangle
+ for m in collect_modifiers do set.add m.to_cmangle
+ return set.to_a
+ end
+end
+
+redef class MProperty
+ redef fun mdoc_or_fallback do return intro.mdoc
+ redef fun html_modifiers do return intro.html_modifiers
+ redef fun html_declaration do return intro.html_declaration
+
+ # Returns `mclass::self`.
+ redef fun html_namespace do
+ var tpl = new Template
+ tpl.add intro_mclassdef.mclass.html_namespace
+ tpl.add "::<span>"
+ tpl.add intro.html_link
+ tpl.add "</span>"
+ return tpl
+ end
+
+ redef fun html_raw_namespace do return intro.html_raw_namespace
+
+ # Returns `intro.html_short_signature`.
+ fun html_short_signature: Template do return intro.html_short_signature
+
+ # Returns `intro.html_signature`.
+ fun html_signature: Template do return intro.html_signature
+
+ redef fun css_classes do return intro.css_classes
+end
+
+redef class MPropDef
+ redef fun html_raw_namespace do return "{mclassdef.html_raw_namespace}::{html_name}"
+ redef fun mdoc_or_fallback do return mdoc or else mproperty.mdoc_or_fallback
+
+ # Depends if `self` is an intro or not.
+ #
+ # * If intro contains the visibility and kind.
+ # * If redef contains the `redef` keyword and kind.
+ redef fun html_modifiers do
+ var res = new Array[String]
+ if not is_intro then
+ res.add "redef"
+ else
+ if mproperty.visibility != public_visibility then
+ res.add mproperty.visibility.to_s
+ end
+ end
+ return res
+ end
+
+ # Depends if `self` is an intro or not.
+ #
+ # For intro: `private fun foo(e: Object): Bar is abstract`
+ # For redef: `redef fun foo(e) is cached`
+ redef fun html_declaration do
+ var tpl = new Template
+ tpl.add "<span>"
+ tpl.add html_modifiers.join(" ")
+ tpl.add " "
+ if is_intro then
+ tpl.add html_link
+ tpl.add html_signature
+ else
+ tpl.add mproperty.intro.html_link
+ tpl.add html_short_signature
+ end
+ tpl.add "</span>"
+ return tpl
+ end
+
+ # Returns `mclassdef::self`
+ redef fun html_namespace do
+ var tpl = new Template
+ tpl.add mclassdef.html_namespace
+ tpl.add "::"
+ tpl.add html_link
+ return tpl
+ end
+
+ # Returns the MPropdDef signature without static types.
+ fun html_short_signature: Template is abstract
+
+ # Returns the MPropDef signature with static types.
+ fun html_signature: Template is abstract
+
+ redef fun css_classes do
+ var set = new HashSet[String]
+ if is_intro then set.add "intro"
+ for m in mproperty.intro.collect_modifiers do set.add m.to_cmangle
+ for m in collect_modifiers do set.add m.to_cmangle
+ return set.to_a
+ end
+end
+
+redef class MAttributeDef
+
+ redef fun html_modifiers do
+ var res = super
+ res.add "var"
+ return res
+ end
+
+ redef fun html_short_signature do return new Template
+
+ redef fun html_signature do
+ var static_mtype = self.static_mtype
+ var tpl = new Template
+ if static_mtype != null then
+ tpl.add ": "
+ tpl.add static_mtype.html_signature
+ end
+ return tpl
+ end
+end
+
+redef class MMethodDef
+
+ # FIXME annotation should be handled in their own way
+ redef fun html_modifiers do
+ if mproperty.is_init then
+ var res = new Array[String]
+ if mproperty.visibility != public_visibility then
+ res.add mproperty.visibility.to_s
+ end
+ return res
+ end
+ var res = super
+ if is_abstract then
+ res.add "abstract"
+ else if is_intern then
+ res.add "intern"
+ end
+ res.add "fun"
+ return res
+ end
+
+ redef fun html_declaration do
+ if mproperty.is_init then
+ var tpl = new Template
+ tpl.add "<span>"
+ tpl.add html_modifiers.join(" ")
+ tpl.add " "
+ tpl.add html_link
+ tpl.add html_signature
+ tpl.add "</span>"
+ return tpl
+ end
+ return super
+ end
+
+ redef fun html_short_signature do
+ var new_msignature = self.new_msignature
+ if mproperty.is_root_init and new_msignature != null then
+ return new_msignature.html_short_signature
+ end
+ return msignature.as(not null).html_short_signature
+ end
+
+ redef fun html_signature do
+ var new_msignature = self.new_msignature
+ if mproperty.is_root_init and new_msignature != null then
+ return new_msignature.html_signature
+ end
+ return msignature.as(not null).html_signature
+ end
+end
+
+redef class MVirtualTypeProp
+ redef fun html_link do return mvirtualtype.html_link
+end
+
+redef class MVirtualTypeDef
+
+ redef fun html_modifiers do
+ var res = super
+ res.add "type"
+ return res
+ end
+
+ redef fun html_short_signature do return new Template
+
+ redef fun html_signature do
+ var bound = self.bound
+ var tpl = new Template
+ if bound == null then return tpl
+ tpl.add ": "
+ tpl.add bound.html_signature
+ return tpl
+ end
+end
+
+redef class MType
+ # Returns the signature of this type whithout bounds.
+ fun html_short_signature: Template is abstract
+
+ # Returns the signature of this type.
+ fun html_signature: Template is abstract
+end
+
+redef class MClassType
+ redef fun html_link do return mclass.html_link
+ redef fun html_short_signature do return html_link
+ redef fun html_signature do return html_link
+end
+
+redef class MNullableType
+ redef fun html_short_signature do
+ var tpl = new Template
+ tpl.add "nullable "
+ tpl.add mtype.html_short_signature
+ return tpl
+ end
+
+ redef fun html_signature do
+ var tpl = new Template
+ tpl.add "nullable "
+ tpl.add mtype.html_signature
+ return tpl
+ end
+end
+
+redef class MGenericType
+ redef fun html_short_signature do
+ var lnk = html_link
+ var tpl = new Template
+ tpl.add new Link.with_title(lnk.href, mclass.name.html_escape, lnk.title)
+ tpl.add "["
+ for i in [0..arguments.length[ do
+ tpl.add arguments[i].html_short_signature
+ if i < arguments.length - 1 then tpl.add ", "
+ end
+ tpl.add "]"
+ return tpl
+ end
+
+ redef fun html_signature do
+ var lnk = html_link
+ var tpl = new Template
+ tpl.add new Link.with_title(lnk.href, mclass.name.html_escape, lnk.title)
+ tpl.add "["
+ for i in [0..arguments.length[ do
+ tpl.add arguments[i].html_signature
+ if i < arguments.length - 1 then tpl.add ", "
+ end
+ tpl.add "]"
+ return tpl
+ end
+end
+
+redef class MParameterType
+ redef fun html_short_signature do return html_link
+ redef fun html_signature do return html_link
+ redef fun html_raw_namespace do return html_name
+end
+
+redef class MVirtualType
+ redef fun html_signature do return html_link
+ redef fun html_raw_namespace do return html_name
+end
+
+redef class MSignature
+ redef fun html_short_signature do
+ var tpl = new Template
+ if not mparameters.is_empty then
+ tpl.add "("
+ for i in [0..mparameters.length[ do
+ tpl.add mparameters[i].html_short_signature
+ if i < mparameters.length - 1 then tpl.add ", "
+ end
+ tpl.add ")"
+ end
+ return tpl
+ end
+
+ redef fun html_signature do
+ var tpl = new Template
+ if not mparameters.is_empty then
+ tpl.add "("
+ for i in [0..mparameters.length[ do
+ tpl.add mparameters[i].html_signature
+ if i < mparameters.length - 1 then tpl.add ", "
+ end
+ tpl.add ")"
+ end
+ var return_mtype = self.return_mtype
+ if return_mtype != null then
+ tpl.add ": "
+ tpl.add return_mtype.html_signature
+ end
+ return tpl
+ end
+end
+
+redef class MParameter
+
+ # Returns `self` name and ellipsys if any.
+ fun html_short_signature: Template do
+ var tpl = new Template
+ tpl.add name
+ if is_vararg then tpl.add "..."
+ return tpl
+ end
+
+ # Returns `self` name with it's static type and ellipsys if any.
+ fun html_signature: Template do
+ var tpl = new Template
+ tpl.add "{name}: "
+ tpl.add mtype.html_signature
+ if is_vararg then tpl.add "..."
+ return tpl
+ end
+end
--- /dev/null
+# 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.
+
+# Components required to build a web server about the nit model.
+module web
+
+import web_actions
--- /dev/null
+# 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.
+
+# Nitcorn actions used by the nitweb server.
+module web_actions
+
+import web_views
+import model::model_collect
+
+# Display the tree of all loaded mentities.
+class TreeAction
+ super NitAction
+
+ # Model to explore and render.
+ var model: Model
+
+ # View to render.
+ var view = new HtmlHomePage(model) is lazy
+
+ redef fun answer(request, url) do return render_view(view)
+end
+
+# Display the list of mentities matching `namespace`.
+class SearchAction
+ super NitAction
+
+ # Model to explore and render.
+ var model: Model
+
+ # TODO handle more than full namespaces.
+ redef fun answer(request, url) do
+ var namespace = request.param("namespace")
+ if namespace == null or namespace.is_empty then
+ return render_error(400, "Missing :namespace.")
+ end
+ var mentities = model.collect_by_namespace(namespace)
+ if request.is_json_asked then
+ var json = new JsonArray
+ for mentity in mentities do
+ json.add mentity.to_json
+ end
+ return render_json(json)
+ end
+ var view = new HtmlResultPage(namespace, mentities)
+ return render_view(view)
+ end
+end
+
+# Display a MEntity source code.
+class CodeAction
+ super NitAction
+
+ # Model to explore and render.
+ var model: Model
+
+ # Modelbuilder used to access sources.
+ var modelbuilder: ModelBuilder
+
+ # TODO handle more than full namespaces.
+ redef fun answer(request, url) do
+ var namespace = request.param("namespace")
+ if namespace == null or namespace.is_empty then
+ return render_error(400, "Missing :namespace.")
+ end
+ var mentities = model.collect_by_namespace(namespace)
+ if mentities.is_empty then
+ return render_error(404, "No mentity matching this namespace.")
+ end
+ var view = new HtmlSourcePage(modelbuilder, mentities.first)
+ return render_view(view)
+ end
+end
+
+# Display the doc of a MEntity.
+class DocAction
+ super NitAction
+
+ # Model to explore and render.
+ var model: Model
+
+ # Modelbuilder used to access sources.
+ var modelbuilder: ModelBuilder
+
+ # TODO handle more than full namespaces.
+ redef fun answer(request, url) do
+ var namespace = request.param("namespace")
+ if namespace == null or namespace.is_empty then
+ return render_error(400, "Missing :namespace.")
+ end
+ var mentities = model.collect_by_namespace(namespace)
+ if mentities.is_empty then
+ return render_error(404, "No mentity matching this namespace.")
+ end
+ var view = new HtmlDocPage(modelbuilder, mentities.first)
+ return render_view(view)
+ end
+end
+
+# Return a random list of MEntities.
+class RandomAction
+ super NitAction
+
+ # Model to explore and render.
+ var model: Model
+
+ # TODO handle more than full namespaces.
+ redef fun answer(request, url) do
+ var n = request.int_arg("n") or else 10
+ var k = request.string_arg("k") or else "modules"
+ var mentities: Array[MEntity]
+ if k == "modules" then
+ mentities = model.mmodules.to_a
+ else if k == "classdefs" then
+ mentities = new Array[MClassDef]
+ for mclass in model.mclasses do
+ mentities.add_all(mclass.mclassdefs)
+ end
+ else
+ mentities = new Array[MPropDef]
+ for mprop in model.mproperties do
+ mentities.add_all(mprop.mpropdefs)
+ end
+ end
+ mentities.shuffle
+ mentities = mentities.sub(0, n)
+ if request.is_json_asked then
+ var json = new JsonArray
+ for mentity in mentities do
+ json.add mentity.to_json
+ end
+ return render_json(json)
+ end
+ var view = new HtmlResultPage("random", mentities)
+ return render_view(view)
+ end
+end
+
+redef class MEntity
+
+ # Return `self` as a JsonObject.
+ fun to_json: JsonObject do
+ var obj = new JsonObject
+ obj["name"] = html_name
+ obj["namespace"] = html_raw_namespace
+ var mdoc = self.mdoc
+ if mdoc != null then
+ obj["synopsis"] = mdoc.content.first.html_escape
+ obj["mdoc"] = mdoc.content.join("\n").html_escape
+ end
+ return obj
+ end
+end
--- /dev/null
+# 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.
+
+# Base classes used by `nitweb`.
+module web_base
+
+import frontend
+import nitcorn
+import json
+
+# Nitcorn server runned by `nitweb`.
+#
+# Usage:
+#
+# ~~~nitish
+# var srv = new NitServer("localhost", 3000)
+# srv.routes.add new Route("/", new MyAction)
+# src.listen
+# ~~~
+class NitServer
+
+ # Host to bind.
+ var host: String
+
+ # Port to use.
+ var port: Int
+
+ # Routes knwon by the server.
+ var routes = new Array[Route]
+
+ # Start listen on `host:port`.
+ fun listen do
+ var iface = "{host}:{port}"
+ print "Launching server on http://{iface}/"
+
+ var vh = new VirtualHost(iface)
+ for route in routes do vh.routes.add route
+
+ var fac = new HttpFactory.and_libevent
+ fac.config.virtual_hosts.add vh
+ fac.run
+ end
+end
+
+# Specific nitcorn Action for nitweb.
+class NitAction
+ super Action
+
+ # Link to the NitServer that runs this action.
+ var srv: NitServer
+
+ # Build a custom http response for errors.
+ fun render_error(code: Int, message: String): HttpResponse do
+ var response = new HttpResponse(code)
+ var tpl = new Template
+ tpl.add "<h1>Error {code}</h1>"
+ tpl.add "<pre><code>{message.html_escape}</code></pre>"
+ response.body = tpl.write_to_string
+ return response
+ end
+
+ # Render a view as a HttpResponse 200.
+ fun render_view(view: NitView): HttpResponse do
+ var response = new HttpResponse(200)
+ response.body = view.render(srv).write_to_string
+ return response
+ end
+
+ # Return a HttpResponse containing `json`.
+ fun render_json(json: Jsonable): HttpResponse do
+ var response = new HttpResponse(200)
+ response.body = json.to_json
+ return response
+ end
+end
+
+# A NitView is rendered by an action.
+interface NitView
+ # Renders this view and returns something that can be written to a HTTP response.
+ fun render(srv: NitServer): Writable is abstract
+end
+
+redef class HttpRequest
+ # Does the client asked for a json formatted response?
+ #
+ # Checks the URL get parameter `?json=true`.
+ fun is_json_asked: Bool do return bool_arg("json") or else false
+end
--- /dev/null
+# 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.
+
+# Nitcorn actions used by the nitweb server.
+module web_views
+
+import web_base
+import model_html
+import highlight
+import markdown
+
+# Html homepage for the `nitweb` server.
+class HtmlHomePage
+ super NitView
+
+ # Loaded model to display.
+ var model: Model
+
+ redef fun render(srv) do
+ var tpl = new Template
+ tpl.add new Header(1, "Loaded model")
+ for mpackage in model.mpackages do
+ tpl.add new Header(3, "Packages")
+ tpl.add mpackage.html_tree
+ end
+ return tpl
+ end
+end
+
+# Display a search results list.
+class HtmlResultPage
+ super NitView
+
+ # Initial query.
+ var query: String
+
+ # Result set
+ var results: Array[MEntity]
+
+ redef fun render(srv) do
+ var tpl = new Template
+ tpl.add new Header(1, "Results for {query}")
+ if results.is_empty then
+ tpl.add "<p>No result for {query}.<p>"
+ return tpl
+ end
+ var list = new UnorderedList
+ for mentity in results do
+ var link = mentity.html_link
+ link.text = mentity.html_raw_namespace
+ list.add_li new ListItem(link)
+ end
+ tpl.add list
+ return tpl
+ end
+end
+
+# Display the source for each mentities
+class HtmlSourcePage
+ super NitView
+
+ # Modelbuilder used to access sources.
+ var modelbuilder: ModelBuilder
+
+ # MEntity to display
+ var mentity: MEntity
+
+ # HiglightVisitor used to hilight the source code
+ var hl = new HighlightVisitor
+
+ redef fun render(srv) do
+ var tpl = new Template
+ tpl.add new Header(1, "Source Code")
+ tpl.add render_source
+ return tpl
+ end
+
+ private fun render_source: Template do
+ var node = modelbuilder.mentity2node(mentity)
+ var tpl = new Template
+ tpl.add new Header(3, "Source code")
+ if node == null then
+ tpl.add "<p>Source for {mentity.html_name} not found.<p>"
+ else
+ hl.enter_visit node
+ tpl.add "<pre><code>"
+ tpl.add hl.html
+ tpl.add "</code></pre>"
+ end
+ return tpl
+ end
+end
+
+# Display the mdoc of the mentities.
+class HtmlDocPage
+ super HtmlSourcePage
+
+ redef fun render(srv) do
+ var tpl = new Template
+ tpl.add new Header(1, mentity.html_name)
+ tpl.add "<p>"
+ tpl.add mentity.html_declaration
+ tpl.add "</p>"
+ tpl.add "<br>"
+ var mdoc = mentity.mdoc
+ if mdoc != null then
+ tpl.add mdoc.content.join("\n").md_to_html
+ end
+ tpl.add "<br>"
+ tpl.add render_source
+ return tpl
+ end
+end
--- /dev/null
+Usage: nitweb [OPTION]... <file.nit>...
+Run a webserver based on nitcorn that serve pages about model.
+Use --help for help