highlight: extract HTML stuff from highlight into htmlight
[nit.git] / src / examples / nitlight_as_a_service.nit
index 08d6980..85f6c7e 100644 (file)
 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
@@ -71,37 +32,107 @@ 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