Browse Source

add basic syntax highlighting

Getty Ritter 1 year ago
parent
commit
07c128a917
5 changed files with 137 additions and 4 deletions
  1. 1 1
      Makefile
  2. 6 2
      js/index.js
  3. 128 0
      js/language.js
  4. 1 0
      package.json
  5. 1 1
      yarn.lock

+ 1 - 1
Makefile

@@ -3,7 +3,7 @@ all: out/index.html out/dist/main.js
 matzo_web_bg.wasm: src/lib.rs Cargo.toml Cargo.lock
 	wasm-pack build --target web
 
-dist/main.js: js/index.js package.json
+dist/main.js: js/*.js package.json
 	yarn build
 
 out/index.html: index.html build.py

+ 6 - 2
js/index.js

@@ -1,5 +1,7 @@
 import init, {matzo_run} from '../pkg/matzo_web.js';
-import {EditorView, basicSetup} from "codemirror"
+import {EditorView, basicSetup} from "codemirror";
+import {StreamLanguage} from "@codemirror/language";
+import {matzoLang} from "./language.js";
 
 window.onload = () => {
   const run = document.getElementById('run');
@@ -41,8 +43,10 @@ window.onload = () => {
         timer = setTimeout(updateCode, 500);
       });
 
+      console.log(`Lang: ${matzoLang}`);
+
       const editor = new EditorView({
-        extensions: [basicSetup, editListener],
+        extensions: [basicSetup, editListener, StreamLanguage.define(matzoLang)],
         parent: src,
       });
 

+ 128 - 0
js/language.js

@@ -0,0 +1,128 @@
+const prefixRE = (words) => {
+  return new RegExp("^(?:" + words.join("|") + ")", "i");
+}
+const wordRE = (words) => {
+  return new RegExp("^(?:" + words.join("|") + ")$", "i");
+}
+
+const builtins = wordRE([
+  // useful helpers
+  "rep",
+
+  // string manipulation
+  "str/upper",
+  "str/lower",
+  "str/capitalize",
+  "wd", "se",
+
+  // arithmetic
+  "add", "sub", "mul",
+
+  // tuple stuff
+  "tuple/len", "tuple/concat", "tuple/flatten", "tuple/join",
+  "tuple/index", "tuple/rep", "tuple/replace", "tuple/fold",
+  "tuple/map",
+]);
+
+const keywords = wordRE([
+  "puts",
+  "case",
+  "let",
+  "in",
+  "fix",
+  "record",
+]);
+
+const normal = (stream, state) => {
+  let ch = stream.next();
+  if (ch == "(") {
+    if (stream.eat("*")) {
+      comment(stream, state);
+      return "comment";
+    }
+  }
+
+  if (ch == "\"" || ch == "'")
+    return (state.cur = string(ch))(stream, state);
+  if (ch == "[" && /[\[=]/.test(stream.peek()))
+    return (state.cur = bracketed(readBracket(stream), "string"))(stream, state);
+  if (/\d/.test(ch)) {
+    stream.eatWhile(/[\w.%]/);
+    return "number";
+  }
+  if (/[\w_]/.test(ch)) {
+    stream.eatWhile(/[\w\\\-_.]/);
+    return "variable";
+  }
+  return null;
+}
+
+const comment = (stream, state) => {
+  let ch;
+  while (ch = stream.next()) {
+    if (ch == "*" && stream.next() == ")") {
+      state.cur = normal;
+      return "comment";
+    }
+  }
+  state.cur = comment;
+};
+
+const bracketed = (level, style) => {
+  return (stream, state) => {
+    let curlev = null, ch;
+    while ((ch = stream.next()) != null) {
+      if (curlev == null) {
+        if (ch == "]") curlev = 0;
+      } else if (ch == "=") {
+        ++curlev;
+      } else if (ch == "]" && curlev == level) {
+        state.cur = normal;
+        break;
+      } else {
+        curlev = null;
+      }
+    }
+    return style;
+  };
+}
+
+const string = (quote) => {
+  return (stream, state) => {
+    let escaped = false, ch;
+    while ((ch = stream.next()) != null) {
+      if (ch == quote && !escaped) break;
+      escaped = !escaped && ch == "\\";
+    }
+    if (!escaped)
+      state.cur = normal;
+    return "string";
+  };
+}
+
+export const matzoLang = {
+  startState: (basecol) => {
+    return {cur: normal};
+  },
+
+  token: (stream, state) => {
+    if (stream.eatSpace())
+      return null;
+
+    let style = state.cur(stream, state);
+    const word = stream.current();
+
+    if (style == "variable") {
+      if (keywords.test(word))
+        style = "keyword";
+      else if (builtins.test(word))
+        style = "builtin";
+    }
+
+    return style;
+  },
+
+  languageData: {
+    commentTokens: {block: {open: "(\*", close: "\*)"}}
+  }
+};

+ 1 - 0
package.json

@@ -9,6 +9,7 @@
     "start": "webpack serve --progress --color"
   },
   "dependencies": {
+    "@codemirror/language": "^6.2.1",
     "codemirror": "^6.0.1"
   },
   "devDependencies": {

+ 1 - 1
yarn.lock

@@ -22,7 +22,7 @@
     "@codemirror/view" "^6.0.0"
     "@lezer/common" "^1.0.0"
 
-"@codemirror/language@^6.0.0":
+"@codemirror/language@^6.0.0", "@codemirror/language@^6.2.1":
   version "6.2.1"
   resolved "https://registry.yarnpkg.com/@codemirror/language/-/language-6.2.1.tgz#cb10cd785a76e50ecd2fe2dc59ff66af8a41b87a"
   integrity sha512-MC3svxuvIj0MRpFlGHxLS6vPyIdbTr2KKPEW46kCoCXw2ktb4NTkpkPBI/lSP/FoNXLCBJ0mrnUi1OoZxtpW1Q==