Browse Source

Got things working with monaco-editor-textmate.

Michael Bolin 5 years ago
parent
commit
8ea1ed8d56
3 changed files with 181 additions and 57 deletions
  1. 3 0
      package.json
  2. 87 52
      src/app.ts
  3. 91 5
      yarn.lock

+ 3 - 0
package.json

@@ -8,7 +8,10 @@
   },
   "dependencies": {
     "monaco-editor": "0.20.0",
+    "monaco-editor-textmate": "2.2.1",
+    "monaco-textmate": "3.0.1",
     "nullthrows": "1.1.1",
+    "onigasm": "2.2.4",
     "vscode-oniguruma": "1.3.0",
     "vscode-textmate": "5.1.1"
   },

+ 87 - 52
src/app.ts

@@ -15,53 +15,23 @@ import nullthrows from 'nullthrows';
 import {createGrammarStore} from './index';
 import {INITIAL} from 'vscode-textmate';
 
-async function main() {
-  // Note that Hack lists text.html.basic as an embedded grammar, so we must
-  // provide that grammar (and all of its transitive deps) as well.
-  //
-  // This sort of looks like:
-  // https://github.com/microsoft/vscode-textmate/blob/0730e8ef740d87401764d76e9193f74c6f458b37/test-cases/themes/grammars.json
-  const grammarConfigurations = [
-    {language: 'css', scopeName: 'source.css', url: '/grammars/css.plist'},
-    {language: 'hack', scopeName: 'source.hack', url: '/grammars/hack.json'},
-    {language: 'html', scopeName: 'text.html.basic', url: '/grammars/html.json'},
-    {language: 'javascript', scopeName: 'source.js', url: '/grammars/JavaScript.tmLanguage.json'},
-    {language: 'python', scopeName: 'source.python', url: '/grammars/MagicPython.tmLanguage.json'},
-    {language: 'smarty', scopeName: 'source.smarty', url: '/grammars/smarty.tmLanguage.json'},
-    {language: 'sql', scopeName: 'source.sql', url: '/grammars/SQL.plist'},
-  ];
-
-  // We have to register all of the languages with Monaco before we can configure them.
-  for (const {language} of grammarConfigurations) {
-    monaco.languages.register({
-      id: language,
-      extensions: [],
-    });
-  }
+// From monaco-editor-textmate README.
+import {Registry} from 'monaco-textmate';
+import {wireTmGrammars} from 'monaco-editor-textmate';
+import {loadWASM} from 'onigasm';
 
-  const scopeNameToTextMateGrammarURL: Map<string, string> = new Map(
-    grammarConfigurations.map(({scopeName, url}) => [scopeName, url]),
-  );
-  const grammarStore = await createGrammarStore(scopeNameToTextMateGrammarURL);
+type GrammarConfiguration = {language: string; scopeName: string; url: string};
 
-  for (const {language, scopeName} of grammarConfigurations) {
-    // const tokensProvider = await grammarStore.createTokensProvider(scopeName);
-    const tokensProvider = await grammarStore.createEncodedTokensProvider(scopeName);
-    monaco.languages.setTokensProvider(language, tokensProvider);
-  }
+const useEncodedTokens = false;
+main(useEncodedTokens, 'hack');
 
-  const options = [
-    {
-      language: 'hack',
-      value: `<?hh // strict
+const testOptions = {
+  hack: `<?hh // strict
 
 class Example {
 }
 `,
-    },
-    {
-      language: 'html',
-      value: `<!DOCTYPE HTML>
+  html: `<!DOCTYPE HTML>
 <html>
 <head>
 </head>
@@ -69,10 +39,7 @@ class Example {
 </body>
 </html>
 `,
-    },
-    {
-      language: 'javascript',
-      value: `
+  javascript: `
 const React = require('react');
 
 function create() {
@@ -83,23 +50,50 @@ function create() {
   );
 }
 `,
-    },
+};
+
+async function main(useEncodedTokens: boolean, testLanguage: keyof typeof testOptions) {
+  // Note that Hack lists text.html.basic as an embedded grammar, so we must
+  // provide that grammar (and all of its transitive deps) as well.
+  //
+  // This sort of looks like:
+  // https://github.com/microsoft/vscode-textmate/blob/0730e8ef740d87401764d76e9193f74c6f458b37/test-cases/themes/grammars.json
+  const grammarConfigurations: GrammarConfiguration[] = [
+    {language: 'css', scopeName: 'source.css', url: '/grammars/css.plist'},
+    {language: 'hack', scopeName: 'source.hack', url: '/grammars/hack.json'},
+    {language: 'html', scopeName: 'text.html.basic', url: '/grammars/html.json'},
+    {language: 'javascript', scopeName: 'source.js', url: '/grammars/JavaScript.tmLanguage.json'},
+    {language: 'python', scopeName: 'source.python', url: '/grammars/MagicPython.tmLanguage.json'},
+    {language: 'smarty', scopeName: 'source.smarty', url: '/grammars/smarty.tmLanguage.json'},
+    {language: 'sql', scopeName: 'source.sql', url: '/grammars/SQL.plist'},
   ];
-  const {language, value} = options[0];
+
+  // We have to register all of the languages with Monaco before we can configure them.
+  for (const {language} of grammarConfigurations) {
+    monaco.languages.register({
+      id: language,
+      extensions: [],
+    });
+  }
+
+  if (useEncodedTokens) {
+    await tryEncodedTokensProvider(grammarConfigurations);
+  } else {
+    await tryMonacoEditorTextMate(grammarConfigurations);
+  }
+
+  const value = testOptions[testLanguage];
 
   const theme = 'hackTheme';
   defineTheme(theme);
   monaco.editor.create(nullthrows(document.getElementById('container')), {
     value,
-    language,
-    // theme,
+    language: testLanguage,
+    theme,
     minimap: {
       enabled: false,
     },
   });
-
-  // Although the web demo doesn't work, this seems to have sensible output.
-  await tryCodeOnVSCodeTextMateReadme(grammarStore);
 }
 
 async function tryCodeOnVSCodeTextMateReadme(grammarStore: GrammarStore) {
@@ -126,7 +120,21 @@ class Example {
   }
 }
 
-main();
+async function tryEncodedTokensProvider(grammarConfigurations: GrammarConfiguration[]) {
+  const scopeNameToTextMateGrammarURL: Map<string, string> = new Map(
+    grammarConfigurations.map(({scopeName, url}) => [scopeName, url]),
+  );
+  const grammarStore = await createGrammarStore(scopeNameToTextMateGrammarURL);
+
+  for (const {language, scopeName} of grammarConfigurations) {
+    // const tokensProvider = await grammarStore.createTokensProvider(scopeName);
+    const tokensProvider = await grammarStore.createEncodedTokensProvider(scopeName);
+    monaco.languages.setTokensProvider(language, tokensProvider);
+  }
+
+  // Although the web demo doesn't work, this seems to have sensible output.
+  await tryCodeOnVSCodeTextMateReadme(grammarStore);
+}
 
 function defineTheme(name: string): void {
   // This code is ported from this playground:
@@ -144,3 +152,30 @@ function defineTheme(name: string): void {
     ],
   });
 }
+
+// Adapted from the README for monaco-editor-textmate.
+async function tryMonacoEditorTextMate(grammarConfigurations: GrammarConfiguration[]) {
+  await loadWASM('/node_modules/onigasm/lib/onigasm.wasm');
+
+  const registry = new Registry({
+    getGrammarDefinition: async (scopeName) => {
+      const config = grammarConfigurations.find((config) => config.scopeName === scopeName);
+      if (config == null) {
+        throw Error(`no URL for ${scopeName}`);
+      }
+
+      const {url} = config;
+      const format = url.endsWith('.json') ? 'json' : 'plist';
+      return {
+        format,
+        content: await (await fetch(url)).text(),
+      };
+    },
+  });
+
+  const grammars = new Map(
+    grammarConfigurations.map(({language, scopeName}) => [language, scopeName]),
+  );
+
+  await wireTmGrammars(monaco, registry, grammars);
+}

+ 91 - 5
yarn.lock

@@ -2,7 +2,7 @@
 # yarn lockfile v1
 
 
-"@babel/code-frame@^7.0.0-beta.36", "@babel/code-frame@^7.8.3":
+"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.0.0-beta.36", "@babel/code-frame@^7.8.3":
   version "7.8.3"
   resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.8.3.tgz#33e25903d7481181534e12ec0a25f16b6fcf419e"
   integrity sha512-a9gxpmdXtZEInkCSHUJDLHZVBgb1QS0jhss4cPP93EW7s+uC5bikET2twEF3KV+7rDblJcmNvTR7VJejqd2C2g==
@@ -434,6 +434,13 @@ aproba@^1.1.1:
   resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a"
   integrity sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==
 
+argparse@^1.0.7:
+  version "1.0.10"
+  resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911"
+  integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==
+  dependencies:
+    sprintf-js "~1.0.2"
+
 arr-diff@^4.0.0:
   version "4.0.0"
   resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520"
@@ -727,6 +734,11 @@ buffer@^4.3.0:
     ieee754 "^1.1.4"
     isarray "^1.0.0"
 
+builtin-modules@^1.1.1:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f"
+  integrity sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=
+
 builtin-status-codes@^3.0.0:
   version "3.0.0"
   resolved "https://registry.yarnpkg.com/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz#85982878e21b98e1c66425e03d0174788f569ee8"
@@ -884,7 +896,7 @@ color-name@1.1.3:
   resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25"
   integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=
 
-commander@^2.20.0:
+commander@^2.12.1, commander@^2.20.0:
   version "2.20.3"
   resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33"
   integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==
@@ -1209,6 +1221,11 @@ detect-node@^2.0.4:
   resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.0.4.tgz#014ee8f8f669c5c58023da64b8179c083a28c46c"
   integrity sha512-ZIzRpLJrOj7jjP2miAtgqIfmzbxa4ZOr5jJc601zklsfEx9oTzmmj2nVpIPRpNlRTIh8lc1kyViIY7BWSGNmKw==
 
+diff@^4.0.1:
+  version "4.0.2"
+  resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d"
+  integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==
+
 diffie-hellman@^5.0.0:
   version "5.0.3"
   resolved "https://registry.yarnpkg.com/diffie-hellman/-/diffie-hellman-5.0.3.tgz#40e8ee98f55a2149607146921c63e1ae5f3d2875"
@@ -1367,6 +1384,11 @@ eslint-scope@^4.0.3:
     esrecurse "^4.1.0"
     estraverse "^4.1.1"
 
+esprima@^4.0.0:
+  version "4.0.1"
+  resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71"
+  integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==
+
 esrecurse@^4.1.0:
   version "4.2.1"
   resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.2.1.tgz#007a3b9fdbc2b3bb87e4879ea19c92fdbd3942cf"
@@ -1517,6 +1539,11 @@ fast-json-stable-stringify@^2.0.0:
   resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633"
   integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==
 
+fast-plist@^0.1.2:
+  version "0.1.2"
+  resolved "https://registry.yarnpkg.com/fast-plist/-/fast-plist-0.1.2.tgz#a45aff345196006d406ca6cdcd05f69051ef35b8"
+  integrity sha1-pFr/NFGWAG1AbKbNzQX2kFHvNbg=
+
 faye-websocket@^0.10.0:
   version "0.10.0"
   resolved "https://registry.yarnpkg.com/faye-websocket/-/faye-websocket-0.10.0.tgz#4e492f8d04dfb6f89003507f6edbf2d501e7c6f4"
@@ -1713,7 +1740,7 @@ glob-parent@^3.1.0:
     is-glob "^3.1.0"
     path-dirname "^1.0.0"
 
-glob@^7.0.3, glob@^7.1.3, glob@^7.1.4:
+glob@^7.0.3, glob@^7.1.1, glob@^7.1.3, glob@^7.1.4:
   version "7.1.6"
   resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6"
   integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==
@@ -2271,6 +2298,14 @@ js-tokens@^4.0.0:
   resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
   integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==
 
+js-yaml@^3.13.1:
+  version "3.13.1"
+  resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.13.1.tgz#aff151b30bfdfa8e49e05da22e7415e9dfa37847"
+  integrity sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==
+  dependencies:
+    argparse "^1.0.7"
+    esprima "^4.0.0"
+
 jsesc@^2.5.1:
   version "2.5.2"
   resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4"
@@ -2594,6 +2629,11 @@ mkdirp@^0.5.1, mkdirp@^0.5.3:
   dependencies:
     minimist "^1.2.5"
 
+monaco-editor-textmate@2.2.1:
+  version "2.2.1"
+  resolved "https://registry.yarnpkg.com/monaco-editor-textmate/-/monaco-editor-textmate-2.2.1.tgz#93f3f1932061dd2311b92a42ea1c027cfeb3e439"
+  integrity sha512-RYTNNfvyjK15M0JA8WIi9UduU10eX5724UGNKnaA8MSetehjThGENctUTuKaxPk/k3pq59QzaQ/C06A44iJd3Q==
+
 monaco-editor-webpack-plugin@1.9.0:
   version "1.9.0"
   resolved "https://registry.yarnpkg.com/monaco-editor-webpack-plugin/-/monaco-editor-webpack-plugin-1.9.0.tgz#5b547281b9f404057dc5d8c5722390df9ac90be6"
@@ -2606,6 +2646,13 @@ monaco-editor@0.20.0:
   resolved "https://registry.yarnpkg.com/monaco-editor/-/monaco-editor-0.20.0.tgz#5d5009343a550124426cb4d965a4d27a348b4dea"
   integrity sha512-hkvf4EtPJRMQlPC3UbMoRs0vTAFAYdzFQ+gpMb8A+9znae1c43q8Mab9iVsgTcg/4PNiLGGn3SlDIa8uvK1FIQ==
 
+monaco-textmate@3.0.1:
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/monaco-textmate/-/monaco-textmate-3.0.1.tgz#b6d26d266aa12edaff7069dae0d6e3747cba5cd7"
+  integrity sha512-ZxxY3OsqUczYP1sGqo97tu+CJmMBwuSW+dL0WEBdDhOZ5G1zntw72hvBc68ZQAirosWvbDKgN1dL5k173QtFww==
+  dependencies:
+    fast-plist "^0.1.2"
+
 move-concurrently@^1.0.1:
   version "1.0.1"
   resolved "https://registry.yarnpkg.com/move-concurrently/-/move-concurrently-1.0.1.tgz#be2c005fda32e0b29af1f05d7c4b33214c701f92"
@@ -2826,6 +2873,14 @@ once@^1.3.0, once@^1.3.1, once@^1.4.0:
   dependencies:
     wrappy "1"
 
+onigasm@2.2.4:
+  version "2.2.4"
+  resolved "https://registry.yarnpkg.com/onigasm/-/onigasm-2.2.4.tgz#b0ad97e3d7c3080476a1e5daae4b4579a976cbba"
+  integrity sha512-BJKxCTsK0mrLh+A6AuNzknxaULZRKM5uywA2goluMLLCjfMm/PTUa0M7oSH1Ltb6CT1oKXn2atHR75Y3JQ0SSg==
+  dependencies:
+    lru-cache "^5.1.1"
+    tslint "^5.20.1"
+
 opn@^5.5.0:
   version "5.5.0"
   resolved "https://registry.yarnpkg.com/opn/-/opn-5.5.0.tgz#fc7164fab56d235904c51c3b27da6758ca3b9bfc"
@@ -3428,7 +3483,7 @@ selfsigned@^1.10.7:
   dependencies:
     node-forge "0.9.0"
 
-semver@^5.4.1, semver@^5.5.0, semver@^5.6.0:
+semver@^5.3.0, semver@^5.4.1, semver@^5.5.0, semver@^5.6.0:
   version "5.7.1"
   resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7"
   integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==
@@ -3659,6 +3714,11 @@ split-string@^3.0.1, split-string@^3.0.2:
   dependencies:
     extend-shallow "^3.0.0"
 
+sprintf-js@~1.0.2:
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c"
+  integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=
+
 ssri@^6.0.1:
   version "6.0.1"
   resolved "https://registry.yarnpkg.com/ssri/-/ssri-6.0.1.tgz#2a3c41b28dd45b62b63676ecb74001265ae9edd8"
@@ -3940,11 +4000,37 @@ ts-loader@7.0.2:
     micromatch "^4.0.0"
     semver "^6.0.0"
 
-tslib@^1.9.0:
+tslib@^1.8.0, tslib@^1.8.1, tslib@^1.9.0:
   version "1.11.1"
   resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.11.1.tgz#eb15d128827fbee2841549e171f45ed338ac7e35"
   integrity sha512-aZW88SY8kQbU7gpV19lN24LtXh/yD4ZZg6qieAJDDg+YBsJcSmLGK9QpnUjAKVG/xefmvJGd1WUmfpT/g6AJGA==
 
+tslint@^5.20.1:
+  version "5.20.1"
+  resolved "https://registry.yarnpkg.com/tslint/-/tslint-5.20.1.tgz#e401e8aeda0152bc44dd07e614034f3f80c67b7d"
+  integrity sha512-EcMxhzCFt8k+/UP5r8waCf/lzmeSyVlqxqMEDQE7rWYiQky8KpIBz1JAoYXfROHrPZ1XXd43q8yQnULOLiBRQg==
+  dependencies:
+    "@babel/code-frame" "^7.0.0"
+    builtin-modules "^1.1.1"
+    chalk "^2.3.0"
+    commander "^2.12.1"
+    diff "^4.0.1"
+    glob "^7.1.1"
+    js-yaml "^3.13.1"
+    minimatch "^3.0.4"
+    mkdirp "^0.5.1"
+    resolve "^1.3.2"
+    semver "^5.3.0"
+    tslib "^1.8.0"
+    tsutils "^2.29.0"
+
+tsutils@^2.29.0:
+  version "2.29.0"
+  resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-2.29.0.tgz#32b488501467acbedd4b85498673a0812aca0b99"
+  integrity sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA==
+  dependencies:
+    tslib "^1.8.1"
+
 tty-browserify@0.0.0:
   version "0.0.0"
   resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.0.tgz#a157ba402da24e9bf957f9aa69d524eed42901a6"