highlight: remove useless `self` parameter (some crazy previous refactor?)
[nit.git] / src / highlight.nit
index 9d6dbcd..1dfbb8f 100644 (file)
@@ -19,6 +19,60 @@ import frontend
 import html
 import pipeline
 import astutil
+import serialization
+
+# A standalone highlighted piece of code
+class HLCode
+       super Serializable
+
+       # The highlighter used
+       var hl: HighlightVisitor
+
+       # The raw code source
+       var content: String
+
+       # The pseudo source-file
+       var source: SourceFile
+
+       # JavaScript code to update an existing codemirror editor.
+       fun code_mirror_update: Template
+       do
+
+               var res = new Template
+               res.add """
+       function nitmessage() {
+               editor.operation(function(){
+                       for (var i = 0; i < widgets.length; ++i)
+                             editor.removeLineWidget(widgets[i]);
+                       widgets.length = 0;
+"""
+
+               for m in source.messages do
+                       res.add """
+                       var l = document.createElement("div");
+                       l.className = "lint-error"
+                       l.innerHTML = "<span class='glyphicon glyphicon-warning-sign lint-error-icon'></span> {{{m.text.html_escape}}}";
+                       var w = editor.addLineWidget({{{m.location.line_start-1}}}, l);
+                       widgets.push(w);
+"""
+               end
+               res.add """});}"""
+               return res
+       end
+
+       redef fun core_serialize_to(v)
+       do
+               v.serialize_attribute("code", hl.html.write_to_string)
+               var msgs = new Array[Map[String, Serializable]]
+               for m in source.messages do
+                       var o = new Map[String, Serializable]
+                       msgs.add o
+                       o["line"] = m.location.line_start-1
+                       o["message"] = m.text
+               end
+               v.serialize_attribute("messages", msgs)
+       end
+end
 
 # Visitor used to produce a HTML tree based on a AST on a `Source`
 class HighlightVisitor
@@ -89,9 +143,8 @@ class HighlightVisitor
        # Default: false
        var include_whole_lines = false is writable
 
-       # The entry-point of the highlighting.
-       # Will fill `html` with the generated HTML content.
-       fun enter_visit(n: ANode)
+       # Highlight a AST element.
+       fun highlight_node(n: ANode)
        do
                n.parentize_tokens
 
@@ -135,18 +188,18 @@ class HighlightVisitor
                        l = l.last_real_token_in_line
                end
 
-               htmlize(f, l)
+               do_highlight(f, l)
        end
 
-       private fun full_tag(anode: ANode, hv: HighlightVisitor): nullable HTMLTag
+       private fun full_tag(anode: ANode): nullable HTMLTag
        do
-               var tag = anode.make_tag(hv)
+               var tag = anode.make_tag(self)
                if tag == null then return null
-               var infobox = anode.infobox(hv)
+               var infobox = anode.infobox(self)
                if infobox == null and anode isa Token then
                        var pa = anode.parent
                        if pa != null then
-                               infobox = pa.decorate_tag(hv, tag, anode)
+                               infobox = pa.decorate_tag(self, tag, anode)
                        end
                end
                if infobox != null and not show_infobox then
@@ -158,7 +211,7 @@ class HighlightVisitor
                if messages != null and show_messages then
                        tag.css("border-bottom", "solid 2px red")
                        if infobox == null then
-                               infobox = new HInfoBox(hv, "Messages")
+                               infobox = new HInfoBox(self, "Messages")
                        end
                        var c = infobox.new_dropdown("{messages.length} message(s)", "")
                        for m in messages do
@@ -174,19 +227,18 @@ class HighlightVisitor
        # Highlight a full lexed source file.
        #
        # REQUIRE `source.first_token != null`
-       fun hightlight_source(source: SourceFile)
+       fun highlight_source(source: SourceFile)
        do
-               htmlize(source.first_token.as(not null), null)
+               do_highlight(source.first_token.as(not null), null)
        end
 
-       # Produce HTML between two tokens
-       protected fun htmlize(first_token: Token, last_token: nullable Token)
+       # Low-level highlighting between 2 tokens
+       protected fun do_highlight(first_token: Token, last_token: nullable Token)
        do
                var stack2 = new Array[HTMLTag]
                var stack = new Array[Prod]
                var line = 0
                var c: nullable Token = first_token
-               var hv = self
                while c != null do
                        var starting
 
@@ -201,7 +253,7 @@ class HighlightVisitor
                                if c0 != null then starting = c0.starting_prods
                                if starting != null then for p in starting do
                                        if not p.is_block then continue
-                                       var tag = full_tag(p, hv)
+                                       var tag = full_tag(p)
                                        if tag == null then continue
                                        tag.add_class("foldable")
                                        stack2.add(html)
@@ -228,7 +280,7 @@ class HighlightVisitor
                        starting = c.starting_prods
                        if starting != null then for p in starting do
                                if not p.is_span then continue
-                               var tag = full_tag(p, hv)
+                               var tag = full_tag(p)
                                if tag == null then continue
                                stack2.add(html)
                                html.add tag
@@ -240,7 +292,7 @@ class HighlightVisitor
                        if c isa TEol then
                                html.append "\n"
                        else
-                               var tag = full_tag(c, hv)
+                               var tag = full_tag(c)
                                if tag != null then html.add tag
                        end
 
@@ -334,6 +386,51 @@ class HighlightVisitor
 <script src="http://netdna.bootstrapcdn.com/bootstrap/3.1.1/js/bootstrap.min.js"></script>
 <script>$(".popupable").popover({html:true, placement:'top'})/*initialize bootstrap popover*/</script>"""
        end
+
+       # Fully process `content` as a Nit source file.
+       #
+       # Set `print_errors = true` to print errors in the code to the console.
+       fun highlightcode(content: String, print_errors: nullable Bool): HLCode
+       do
+               # Prepare a stand-alone tool context
+               var tc = new ToolContext
+               tc.nit_dir = tc.locate_nit_dir # still use the common lib to have core
+               tc.keep_going = true # no exit, obviously
+               if print_errors != true then tc.opt_warn.value = -1 # no output
+
+               # Prepare an stand-alone model and model builder.
+               # Unfortunately, models are enclosing and append-only.
+               # There is no way (yet?) to have a shared module `core` with
+               # isolated and throwable user modules.
+               var model = new Model
+               var mb = new ModelBuilder(model, tc)
+
+               # Parse the code
+               var source = new SourceFile.from_string("", content + "\n")
+               var lexer = new Lexer(source)
+               var parser = new Parser(lexer)
+               var tree = parser.parse
+
+               var hlcode = new HLCode(self, content, source)
+
+               # Check syntax error
+               var eof = tree.n_eof
+               if eof isa AError then
+                       mb.error(eof, eof.message)
+                       highlight_source(source)
+                       return hlcode
+               end
+               var amodule = tree.n_base.as(not null)
+
+               # Load the AST as a module in the model
+               # Then process it
+               mb.load_rt_module(null, amodule, "")
+               mb.run_phases
+
+               # Highlight the processed module
+               highlight_node(amodule)
+               return hlcode
+       end
 end
 
 redef class HTMLTag