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

9
我正在尝试扩展Monaco Editor,以允许用户在同一文件中使用分隔符将JavaScript和另一种语言混合编写,类似于Markdown使用围栏代码块编写多种语言的方式。
区别在于我希望保留 Monaco 为 JavaScript 内建的所有 IDE 功能,例如通过 诊断 进行的 linting、智能自动完成跳转到定义自动格式化助手,以及与 Monaco 自带的 JavaScript 模式相伴随的所有其他 IDE 功能。我希望这些功能仍然能够在 Monaco 编辑的 JavaScript 部分内正常工作,并且在子语言部分禁用。
我的第一次尝试是调用setMonarchTokensProvider,传入一个修改过的TypeScript的令牌化规则版本。具体来说,我能够将起始栅栏分隔符添加到根规则中,并以同样的方式为子语言创建一个新规则,就像Monarch (Monaco's syntax highligher)文档描述的那样,使用@nextEmbedded。(出于测试目的,我一直在硬编码CSS作为嵌入式语言。)
当我像这样为语言"javascript"调用setMonarchTokensProvider时,它完全忽略了此语法突出显示的分词器,并将CSS的代码栅栏颜色设置为无效的JavaScript,表明您不能以这种方式覆盖内置的JavaScript模式。
当我使用新语言(例如“mylang”)调用setMonarchTokensProvider并将编辑器设置为使用该语言时,它提供了正确的语法突出显示(!)用于此CSS-in-JS混合语言。但是,在JavaScript模式中找到的所有其他高级功能都不再存在。编辑器没有任何智能自动完成方法,用于在同一文件中定义的类或任何无效语法的编辑器错误报告,也没有其标志性的JavaScript IDE功能
我的下一步尝试是修改预先捆绑的 Monaco 代码的 TypeScript 定义,以包括我的自定义语法高亮规则。当将语言设置为“typescript”时,这样可以完全正确地突出显示我的 CSS-in-JS 代码(!),并保留所有其他功能(!),包括诊断报告(实时验证和错误下划线)、自动完成等等。 (我没有尝试过“javascript”,但可以安全地假设它可能有效或者很容易使其有效,因为JavaScript 实际上是 Monaco 中 TypeScript 模式的变体配置。)不幸的是,它也认为其中的整个 CSS 部分(包括周围的栅栏)是无效的 JavaScript 代码。

The thing almost working.

我知道这在理论上是可行的,因为在HTML模式下,您可以嵌入CSS或JS,并且完全支持正确验证、自动完成和其他IDE功能;基本上,HTML文件中的每个子语言都像它在自己的文件中一样工作:HTML特性位于文件根目录中,CSS特性位于style标签中,JS特性位于script标签中。
但是,深入研究Monaco中的TypeScript插件实现时,无论是作为Monaco库的用户还是通过分叉并在必要时修补它,都不清楚从哪里开始编辑。我试图修改DiagnostcsAdapter [sic]并跟踪其实际实现位置,但我卡在两个函数调用深度处,似乎它推送了一个promise of syntax validation,返回稍后使用的值,但是getSyntacticDiagnostics的实现只是将工作分配给一些其他实现,我找不到任何其他地方的回购,也没有在monaco-languages repovscode repo中找到。
2个回答

2

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

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

然后你可以使用你的工具、解析器、IDE扩展等对它进行处理。最酷的部分是,你可以让VSCode按照你想要的方式进行语法高亮,这样它就不会像某些黑客那样。
这种方法是首选的,因为你的JS文件仍然保持100%有效。
如果你仍然不想把你的语法放到注释中,那么你应该创建自己的文件扩展名,比如.jsx/.tsx。在实践中,这意味着你需要创建一个带有语言服务器和其他东西的VSCode扩展。这并不容易,但文档很好。你可以在你的VSCode扩展中使用语言服务器组装自己的JS高亮代码: https://github.com/sourcegraph/javascript-typescript-langserver

如果问题被简化,那么这个解决方案是可行的,但实际上我想要朝着另一个方向添加更复杂的语法规则到JavaScript插件中。例如,如果我尝试为MDX创建Monaco插件,并使用我问题中的概念,那么这个解决方案根本不起作用。 - Steven
抱歉,我读了三遍后不确定我是否理解了你写的内容。但我可以肯定的是,除非你同时更改Javascript语言服务器(几乎不可能),否则在JS文件中添加非JS语法将会引入语法错误,并被IDE标记出来。 - Nurbol Alpysbayev
我主要使用TypeScript进行工作,即使它提供了一种编写语言服务器插件的方式,你仍然无法更改语法。在JS中没有找到类似的东西。 - Nurbol Alpysbayev
我已经缩小范围,需要修改tsWorker.js所包含的任何源代码,因为那里似乎实现了TS语言的其他功能。 - Steven

2

据Monaco的创建者所说:

在架构上,您可以执行以下操作:

  • 直接使用monaco-editor-core
  • 为编辑器定义一个新语言
  • fork monaco-typescript并将其更改为与您新定义的语言ID一起工作。然后,修改TS语言主机代码,不要将原始模型传递给TypeScript,而是首先运行预处理程序,从文本中剥离出您的自定义语言,然后仅将有效的TypeScript传递给TS编译器。一个想法是用空格替换每个删除的字符。这将使所有位置/偏移量计算工作无需任何努力即可完成。

祝你好运!


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接