module nitlight_as_a_service
import frontend
-import highlight
+import htmlight
import nitcorn
import nitcorn::log
+import template
+import json::serialization_write
-# Fully process a content as a nit source file.
-fun hightlightcode(hl: HighlightVisitor, content: String): SourceFile
-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)
- var lexer = new Lexer(source)
- var parser = new Parser(lexer)
- var tree = parser.parse
-
- # Check syntax error
- var eof = tree.n_eof
- if eof isa AError then
- mb.error(eof, eof.message)
- hl.hightlight_source(source)
- return source
- 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 source
-end
-
-# Nitcorn service to hightlight code
+# Nitcorn service to highlight code
#
# It's a single stand-alone page that has to form to itself.
class HighlightAction
redef fun answer(http_request, turi)
do
+ var hl = new HtmlightVisitor
+ var page = new Template
+
+ # There is code? Process it
var code = http_request.post_args.get_or_null("code")
+ var hlcode = null
+ if code != null then hlcode = hl.highlightcode(code)
+
+ if http_request.post_args.get_or_null("json") == "true" and hlcode != null then
+ var response = new HttpResponse(200)
+ response.header["Content-Type"] = "text/json"
+ response.body = hlcode.to_json
+ return response
+ end
+
+ if http_request.post_args.get_or_null("ajax") == "true" and hlcode != null then
+ page.add hlcode.code_mirror_update
+ page.add """
+ document.getElementById("lightcode").innerHTML = "{{{hl.html.write_to_string.escape_to_c}}}";
+ nitmessage();
+ """
+
+ var response = new HttpResponse(200)
+ response.header["Content-Type"] = "application/javascript"
+ response.body = page.write_to_string
+ return response
+ end
- var hl = new HighlightVisitor
- var page = "<doctype html><html><head>{hl.head_content}<style>{hl.css_content} textarea \{width:100%;\}</style></head><body>"
+ page.add """
+ <!doctype html><html><head>{{{hl.head_content}}}
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.16.0/codemirror.css">
+ <style>
+ {{{hl.css_content}}}
+ textarea {width:100%;}
+ .lint-error {font-family: arial; font-size: 70%; background: #ffa; color: #a00; padding: 2px 5px 3px; }
+ .lint-error-icon {color: red; padding: 0 3px; margin-right: 7px;}
+ </style></head><body>
+ """
# Add the form+textarea
- page += """
- <form action="#light" method=post><textarea name=code rows=10>{{{code or else ""}}}</textarea><br><input type=submit></form>
+ page.add """
+ <form action="#light" method=post><textarea id=code name=code rows=10>{{{code or else ""}}}</textarea><br><input type=submit></form>
"""
- if code != null then
- # There is code? Process it
- var source = hightlightcode(hl, code)
-
+ if hlcode != null then
# Inject highlight
- page += "<pre id=light><code>"
- page += hl.html.write_to_string
- page += "</code></pre><hr>"
- page += "<ul>"
+ page.add "<pre id=light><code id=lightcode>"
+ page.add hl.html.write_to_string
+ page.add "</code></pre><hr>"
+ page.add "<ul>"
# List messages
- for m in source.messages do
- page += "<li>{m.location.as(not null)}: {m.text}</li>"
+ for m in hlcode.source.messages do
+ page.add "<li>{m.location.as(not null)}: {m.text}</li>"
end
- page += "</ul>"
+ page.add "</ul>"
+ else
+ page.add "<pre id=light><code id=lightcode></code></pre>"
end
- page += hl.foot_content
+ page.add hl.foot_content
+
+ # Call codemirror
+ page.add """
+ <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.16.0/codemirror.min.js"></script>
+ <script>
+ var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
+ lineNumbers: true
+ });
+ """
+
+ # Callback to update codemirror messages
+ if hlcode != null then
+ page.add hlcode.code_mirror_update
+ else
+ page.add "function nitmessage()\{\}"
+ end
+ page.add """
+ var widgets = [];
+ nitmessage();
+
+ function updatePage() {
+ $.post("", { ajax: true, code: editor.getValue()}, function(data) {
+ eval(data);
+ $(".popupable").popover({html:true, placement:'top'});
+ });
+ }
+
+ var waiting;
+ editor.on("change", function() {
+ clearTimeout(waiting);
+ waiting = setTimeout(updatePage, 500);
+ });
+ waiting = setTimeout(updatePage, 500);
+
+ </script>
+ </body></html>
+ """
var response = new HttpResponse(200)
response.header["Content-Type"] = "text/html"
- response.body = page
+ response.body = page.write_to_string
return response
end
end