X-Git-Url: http://nitlanguage.org diff --git a/src/highlight.nit b/src/highlight.nit index 65c98da..3005aa7 100644 --- a/src/highlight.nit +++ b/src/highlight.nit @@ -19,6 +19,103 @@ import frontend import html import pipeline import astutil +import serialization + +# Fully process a content as a nit source file. +fun hightlightcode(hl: HighlightVisitor, content: String): 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 + tc.opt_warn.value = -1 # no output, obviously + + # 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(hl, content, source) + + # Check syntax error + var eof = tree.n_eof + if eof isa AError then + mb.error(eof, eof.message) + hl.hightlight_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 + hl.enter_visit(amodule) + return hlcode +end + +# 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 = " {{{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 @@ -114,6 +211,22 @@ class HighlightVisitor if l.next_looses.not_empty then l = l.next_looses.last end + var line = first_line + if line != null then + while f.location.line_start < line do + f = f.next_token + if f == null then return + end + end + + line = last_line + if line != null then + while l.location.line_end > line do + l = l.prev_token + if l == null then return + end + end + if include_whole_lines then f = f.first_real_token_in_line l = l.last_real_token_in_line @@ -221,7 +334,7 @@ class HighlightVisitor end # Add the token - if c isa TEol then + if c isa TEol then html.append "\n" else var tag = full_tag(c, hv) @@ -258,8 +371,7 @@ class HighlightVisitor c = n end - #assert stack.is_empty - #assert stack2.is_empty + if not stack2.is_empty then html = stack2.first end # Return a default CSS content related to CSS classes used in the `html` tree.