add JSON-defined syntax highlighting in dynamic highlighter
This commit is contained in:
parent
daa35af5b9
commit
7fa202ac5f
|
@ -35,77 +35,10 @@ function getLiterateProgramWorkerCommands(name, count) {
|
||||||
return commands;
|
return commands;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const javascriptJson = await (await fetch(`${TREEHOUSE_SITE}/static/syntax/javascript.json`)).text();
|
||||||
|
|
||||||
class InputMode {
|
class InputMode {
|
||||||
static JAVASCRIPT = compileSyntax({
|
static JAVASCRIPT = compileSyntax(JSON.parse(javascriptJson));
|
||||||
patterns: [
|
|
||||||
{ regex: /\/\/.*/, as: "comment" },
|
|
||||||
{ regex: /\/\*.*?\*\//ms, as: "comment" },
|
|
||||||
{ regex: /[A-Z_][a-zA-Z0-9_]*/, as: "keyword2" },
|
|
||||||
{ regex: /[a-zA-Z_][a-zA-Z0-9_]*(?=\()/, as: "function" },
|
|
||||||
{ regex: /[a-zA-Z_][a-zA-Z0-9_]*/, as: "identifier" },
|
|
||||||
{ regex: /0[bB][01_]+n?/, as: "literal" },
|
|
||||||
{ regex: /0[oO][0-7_]+n?/, as: "literal" },
|
|
||||||
{ regex: /0[xX][0-9a-fA-F_]+n?/, as: "literal" },
|
|
||||||
{ regex: /[0-9_]+n/, as: "literal" },
|
|
||||||
{ regex: /[0-9_]+(\.[0-9_]*([eE][-+]?[0-9_]+)?)?/, as: "literal" },
|
|
||||||
{ regex: /'(\\'|[^'])*'/, as: "string" },
|
|
||||||
{ regex: /"(\\"|[^"])*"/, as: "string" },
|
|
||||||
{ regex: /`(\\`|[^"])*`/, as: "string" },
|
|
||||||
// TODO: RegExp literals?
|
|
||||||
{ regex: /[+=/*^%<>!~|&\.?:-]+/, as: "operator" },
|
|
||||||
{ regex: /[,;]/, as: "punct" },
|
|
||||||
],
|
|
||||||
keywords: new Map([
|
|
||||||
["as", { into: "keyword1", onlyReplaces: "identifier" }],
|
|
||||||
["async", { into: "keyword1", onlyReplaces: "identifier" }],
|
|
||||||
["await", { into: "keyword1" }],
|
|
||||||
["break", { into: "keyword1" }],
|
|
||||||
["case", { into: "keyword1" }],
|
|
||||||
["catch", { into: "keyword1" }],
|
|
||||||
["class", { into: "keyword1" }],
|
|
||||||
["const", { into: "keyword1" }],
|
|
||||||
["continue", { into: "keyword1" }],
|
|
||||||
["debugger", { into: "keyword1" }],
|
|
||||||
["default", { into: "keyword1" }],
|
|
||||||
["delete", { into: "keyword1" }],
|
|
||||||
["do", { into: "keyword1" }],
|
|
||||||
["else", { into: "keyword1" }],
|
|
||||||
["export", { into: "keyword1" }],
|
|
||||||
["extends", { into: "keyword1" }],
|
|
||||||
["finally", { into: "keyword1" }],
|
|
||||||
["for", { into: "keyword1" }],
|
|
||||||
["from", { into: "keyword1", onlyReplaces: "identifier" }],
|
|
||||||
["function", { into: "keyword1" }],
|
|
||||||
["get", { into: "keyword1", onlyReplaces: "identifier" }],
|
|
||||||
["if", { into: "keyword1" }],
|
|
||||||
["import", { into: "keyword1" }],
|
|
||||||
["in", { into: "keyword1" }],
|
|
||||||
["instanceof", { into: "keyword1" }],
|
|
||||||
["let", { into: "keyword1" }],
|
|
||||||
["new", { into: "keyword1" }],
|
|
||||||
["of", { into: "keyword1", onlyReplaces: "identifier" }],
|
|
||||||
["return", { into: "keyword1" }],
|
|
||||||
["set", { into: "keyword1", onlyReplaces: "identifier" }],
|
|
||||||
["static", { into: "keyword1" }],
|
|
||||||
["switch", { into: "keyword1" }],
|
|
||||||
["throw", { into: "keyword1" }],
|
|
||||||
["try", { into: "keyword1" }],
|
|
||||||
["typeof", { into: "keyword1" }],
|
|
||||||
["var", { into: "keyword1" }],
|
|
||||||
["void", { into: "keyword1" }],
|
|
||||||
["while", { into: "keyword1" }],
|
|
||||||
["with", { into: "keyword1" }],
|
|
||||||
["yield", { into: "keyword1" }],
|
|
||||||
|
|
||||||
["super", { into: "keyword2" }],
|
|
||||||
["this", { into: "keyword2" }],
|
|
||||||
|
|
||||||
["false", { into: "literal" }],
|
|
||||||
["true", { into: "literal" }],
|
|
||||||
["undefined", { into: "literal" }],
|
|
||||||
["null", { into: "literal" }],
|
|
||||||
]),
|
|
||||||
})
|
|
||||||
|
|
||||||
constructor(frame) {
|
constructor(frame) {
|
||||||
this.frame = frame;
|
this.frame = frame;
|
||||||
|
|
|
@ -6,12 +6,15 @@
|
||||||
|
|
||||||
export function compileSyntax(def) {
|
export function compileSyntax(def) {
|
||||||
for (let pattern of def.patterns) {
|
for (let pattern of def.patterns) {
|
||||||
// Remove g (global) flag as it would interfere with the lexis process. We only want to match
|
let flags = "dy";
|
||||||
// the first token at the cursor.
|
if (pattern.flags != null) {
|
||||||
let flags = pattern.regex.flags.replace("g", "");
|
if ("dotMatchesNewline" in pattern.flags) {
|
||||||
// Add d (indices) and y (sticky) flags so that we can tell where the matches start and end.
|
flags += "s";
|
||||||
pattern.regex = new RegExp(pattern.regex, "y" + flags);
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
pattern.regex = new RegExp(pattern.regex, flags);
|
||||||
|
}
|
||||||
|
def.keywords = new Map(Object.entries(def.keywords));
|
||||||
return def;
|
return def;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,7 +37,18 @@ function tokenize(text, syntax) {
|
||||||
let match;
|
let match;
|
||||||
pattern.regex.lastIndex = i;
|
pattern.regex.lastIndex = i;
|
||||||
if ((match = pattern.regex.exec(text)) != null) {
|
if ((match = pattern.regex.exec(text)) != null) {
|
||||||
pushToken(tokens, pattern.is, match[0]); // TODO
|
if (typeof pattern.is == "object") {
|
||||||
|
let lastMatchEnd = i;
|
||||||
|
for (let i = 1; i < match.indices.length; ++i) {
|
||||||
|
let [start, end] = match.indices[i];
|
||||||
|
if (match.indices[i] != null) {
|
||||||
|
pushToken(tokens, pattern.is.default, text.substring(lastMatchEnd, start));
|
||||||
|
pushToken(tokens, pattern.is.captures[i], text.substring(start, end));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
pushToken(tokens, pattern.is, match[0]);
|
||||||
|
}
|
||||||
i = pattern.regex.lastIndex;
|
i = pattern.regex.lastIndex;
|
||||||
hadMatch = true;
|
hadMatch = true;
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -17,9 +17,9 @@
|
||||||
{ "regex": "0[xX][0-9a-fA-F_]+n?", "is": "literal" },
|
{ "regex": "0[xX][0-9a-fA-F_]+n?", "is": "literal" },
|
||||||
{ "regex": "[0-9_]+n", "is": "literal" },
|
{ "regex": "[0-9_]+n", "is": "literal" },
|
||||||
{ "regex": "[0-9_]+(\\.[0-9_]*([eE][-+]?[0-9_]+)?)?", "is": "literal" },
|
{ "regex": "[0-9_]+(\\.[0-9_]*([eE][-+]?[0-9_]+)?)?", "is": "literal" },
|
||||||
{ "regex": "'(\\'|[^'])*'", "is": "string" },
|
{ "regex": "'(\\\\'|[^'])*'", "is": "string" },
|
||||||
{ "regex": "\"(\\\"|[^\"])*\"", "is": "string" },
|
{ "regex": "\"(\\\\\"|[^\"])*\"", "is": "string" },
|
||||||
{ "regex": "`(\\`|[^`])*`", "is": "string" },
|
{ "regex": "`(\\\\`|[^`])*`", "is": "string" },
|
||||||
{ "regex": "[+=/*^%<>!~|&\\.?:-]+", "is": "operator" },
|
{ "regex": "[+=/*^%<>!~|&\\.?:-]+", "is": "operator" },
|
||||||
{ "regex": "[,;]", "is": "punct" }
|
{ "regex": "[,;]", "is": "punct" }
|
||||||
],
|
],
|
||||||
|
|
Loading…
Reference in a new issue