通过完全集成在摩纳哥编辑器中扩展 JavaScript 语法

Extending JavaScript syntax in Monaco Editor with full integration

我正在尝试扩展 Monaco Editor 以允许用户使用 JavaScript 和另一种语言的混合编写,使用定界符将它们分隔在同一文件中,类似于 Markdown 允许编写的方式使用围栏代码块的多种语言。

不同之处在于,我想保留 Monaco 为 JavaScript 内置的所有其他 IDE 功能,例如 linting(通过 diagnostics), smart auto-completion, jump-to-definition, auto-formatting helpers 完成)和所有其他 IDE 特性是 Monaco 的内置 JavaScript 模式。我希望这些特性在 Monaco 正在编辑的代码的 JavaScript 部分仍然有效,并为 sub 禁用-语言部分。

我的第一次尝试是打电话给 setMonarchTokensProvider, passing in a modified version of TypeScript's tokenizer rules. Specifically, I was able to add the beginning-fence delimiter to the root rule and create a new rule for the sub-language in the same way the documentation for Monarch (Monaco's syntax highligher) describes, using @nextEmbedded。 (出于测试目的,我一直将 CSS 硬编码为嵌入式语言。)

当我像这样为 the language "javascript" 调用 setMonarchTokensProvider 时,它完全忽略了这种语法高亮分词器,并将 CSS 的代码围栏标记为无效 JavaScript,表明您不能以这种方式覆盖内置 JavaScript 模式。

当我用一种新语言(例如 "mylang")调用 setMonarchTokensProvider 并将编辑器设置为使用该语言时,它会为这个 CSS-in-JS 混合体提供正确的语法突出显示(!)语。但是在 JavaScript 模式中找到的所有其他高级功能都不再存在。对于同一文件中 类 上定义的方法,编辑器没有任何智能自动完成功能,也没有针对无效语法的任何编辑器内错误报告,或其任何商标 JavaScript IDE features.

因此,我的下一次尝试是修改预捆绑的 Monaco 代码的 TypeScript 定义,以包含我的自定义语法突出显示规则。这正确地完全突出显示了我的 CSS-in-JS 代码(!),当将语言设置为 "typescript"、 时,所有其他功能保持不变(!)包括诊断报告(实时验证和错误下划线)、自动完成,全部! (我没有用 "javascript" 尝试过,但可以肯定的是,它可能有效,或者让它有效,因为 JavaScript is actually implemented as a variant configuration of the TypeScript mode in Monaco。)

不幸的是,它还认为它的整个 CSS 部分,包括它周围的栅栏,都是无效的 JavaScript 代码。

我知道这在理论上是可行的,因为在 HTML 模式下,您可以嵌入 CSS 或 JS,完全支持正确的验证和自动完成以及所有其他 IDE特征;基本上,HTML 文件中的每个子语言都像在自己的文件中一样工作:文件根目录中的 HTML 特性,样式标签中的 CSS 特性,脚本标签中的 JS 特性.

但是深入研究 TypeScript 插件在 Monaco 中的实现,不清楚从哪里开始编辑它,或者作为 Monaco 库的用户,或者通过分叉它并在必要时修补它。我开始尝试修改 DiagnostcsAdapter [sic] and tracing where it's actually implemented, but I got stuck two function-calls deep, where it seems to push a promise of syntax validation that returns a value that's used later, but the implementation of getSyntacticDiagnostics just shells the work out to some other implementation that I can't find anywhere else in the repo, nor in the monaco-languages repo or the vscode repo.

我也做过类似的东西。我的解决方案是将非 JS 代码放在块注释中:

regularJsCode()
/* 
[your-syntax-identifying-start-token]
place any syntax you want here
[your-syntax-identifying-end-token]
*/
regularJsCode()

然后您可以使用您的工具、解析器、IDE 扩展等对其进行处理。最酷的部分是您可以 VSCode 按照您的意愿对其进行语法高亮显示,这样它就不会出现像一些骇客。

这种方法更可取,因为您的 JS 文件仍然是 100% 有效的 JS 文件。

如果您仍然不想将语法放入注释中,那么您应该创建自己的文件扩展名,例如 .jsx/.tsx。实际上,VSCode 术语意味着您需要使用语言服务器和其他东西创建 VSCode 扩展 。这不是那么容易,但是文档很好。您可以 assemble 使用语言服务器在 VSCode 扩展中 assemble 自己的 JS 突出显示代码:https://github.com/sourcegraph/javascript-typescript-langserver

According to the creator of Monaco:

Architecturally, you can do the following:

  • use monaco-editor-core directly
  • define a new language to the editor
  • fork monaco-typescript and change it to work with your newly defined langauge id. Then, modify the TS language host code to not pass the original models to TypeScript, but first run a preprocess which strips your custom language out of the text, and then only passes on valid TypeScript to the TS compiler. One idea is to replace each character that you remove with a space. This will leave all the position/offset computation work without any effort on your side.

Good luck!