Skip to content

Instantly share code, notes, and snippets.

@caisui
Last active December 16, 2015 01:19
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save caisui/5354494 to your computer and use it in GitHub Desktop.
Save caisui/5354494 to your computer and use it in GitHub Desktop.
(function () {
const EOF = {};
function iterLine(source) {
source += "\n";
var re = /\r\n?|\n/g;
var m;
var line = 1;
var offset = 0;
while (m = re.exec(source)) {
yield [line++, source.substring(offset, m.index)];
offset = re.lastIndex;
}
yield [, EOF];
}
const KEYWORD = Set([
"break",
"delete",
"import",
"this",
"case",
"do",
"in",
"throw",
"catch",
"else",
"instanceof",
"try",
"class",
"export",
"let",
"typeof",
"continue",
"finally",
"new",
"var",
"const",
"for",
"return",
"void",
"debugger",
"function",
"super",
"while",
"default",
"if",
"switch",
"with",
"yield",
"let",
"of",
"true",
"false",
]);
const reWORD = let (s = `\s\x00-\x23\x25-\x2f\x3a-\x40\x5b-\x60\x7b-\x7f`)
new RegExp(`([${s}]*)([^${s}]*)`, "y");
function wrapKeyword(src) {
reWORD.lastIndex = 0;
res = ``;
while (m = reWORD.exec(src)) {
if (!m[0]) break;
if (m[1]) res += xml`${m[1]}`;
if (m[2]) {
res += KEYWORD.has(m[2]) ? xml`<span class="word">${m[2]}</span>` : xml`${m[2]}`;
}
}
return res;
}
function wrap(className, str) {
return xml`<span class=${className}>${str}</span>`;
}
function showResult(source, error) {
var res = "";
var iter = iterLine(source);
var n, line, offset, i, j, c, close;
var re = /(\/\/|\/\*|\/[^\/]+\/|["'`])/g;
const CLOSE_LINE = `${"\n"}</span>`;
L_ROOT: while (1) {
[n, line] = iter.next();
if (line === EOF) break;
res += `<span id="L${n}" line="${n}">`;
offset = 0;
L_BODY: while (1) {
re.lastIndex = offset;
m = re.exec(line);
if (!m) {
res += wrapKeyword(line.substring(offset));
break;
} else if (m[1] === "//") {
res += wrapKeyword(line.substring(offset, m.index - 1))
+ wrap("comment", line.substring(re.lastIndex -2));
break;
} else if (m[1] === "/*") {
res += wrapKeyword(line.substring(offset, m.index - 1));
offset = m.index;
while (1) {
i = line.indexOf("*/", offset);
if (i === -1) {
res += wrap("comment", line.substring(offset));
} else {
i += 2;
res += wrap("comment", line.substring(offset, i));
offset = i;
continue L_BODY;
}
res += CLOSE_LINE;
[n, line] = line = iter.next();
if (line === EOF) break L_ROOT;
res += `<span id="L${n}" line="${n}">`;
offset = 0;
}
} else if (/^["'`]$/.test(m[1])) {
close = m[1];
let color = close === "`" ? "bquote" : "string";
res += wrapKeyword(line.substring(offset, re.lastIndex - 1));
L_STR: while (1) {
for (c = line[i = re.lastIndex]; c; c = line[++i]) {
if (c === "\\") {
i++;
} else if (c === close) {
res += wrap(color, line.substring(re.lastIndex - 1, ++i));
offset = i;
continue L_BODY;
}
}
res += wrap(color, line.substring(re.lastIndex - 1));
res += CLOSE_LINE;
[n, line] = iter.next();
if (line === EOF) break L_ROOT;
res += `<span id="L${n}" line="${n}">`;
offset = 0;
re.lastIndex = 0;
}
break;
} else {
res += wrapKeyword(line.substring(offset));
break;
}
}
res += CLOSE_LINE;
}
res =
`<!doctype html>
<html>
<head>
<style>
[line]:before {
content: attr(line);
display: inline-block;
text-align: right;
width: 3em;
padding-right: .5em;
color: gray;
}
.word {
color: #00a;
font-weight: bold;
}
.comment {
color: #a00;
}
.string {
color: green;
}
.bquote {
color: orange;
}
[line] {
display: block;
}
[line]:hover {
background-color: #eee;
}
[line]:target {
background-color: rgba(244, 244, 255, .5);
width: 100%;
}
.error {
color: red;
font-weight: bold;
}
</style>
</head>
<body>${
error ? let(n = error.lineNumber)
xml`<div class="error">${error}: <a href=${`#L${n}`}>${n}</a></div>` : ``
}<pre>
${res}
</pre>${
// XXX:hash が 上手くいかないので
error ?
xml`<script>
location.hash = "#L${error.lineNumber}";
</script>` : ""
}</html>`;
// hash が うまくいかない
var url = URL.createObjectURL(new content.window.Blob([res], {type:"text/html"}));
//if (error.lineNumber) {
// url += `#L${error.lineNumber}`;
//}
liberator.open(url);
}
commands.addUserCommand(["checkAndSource", "cas"], "file's syntax check. and execute",
function (args) {
var obj = {};
try {
Cu.import("resource://liberator/template.js", obj);
Cu.import("resource://gre/modules/reflect.jsm", obj);
var src = obj.convert(File(args[0]).read());
try {
obj.Reflect.parse(src);
if (args.bang) {
showResult(src);
}
liberator.echomsg(`validated: ${args[0]}`);
if (!args["--check-only"]) {
io.source(args[0]);
}
} catch (ex) {
showResult(src, ex);
liberator.echoerr(ex, null, `${args[0]}:${ex.lineNumber}: `);
}
} catch (ex) {
Cu.reportError(ex);
liberator.echoerr(ex);
}
}, {
bang: true,
literal: 0,
argCount: 1,
completer: function (context) { completion.file(context, true); },
options: [
[["--check-only", "-c"], commands.OPTION_NOARG],
],
}, true);
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment