monaco使用vscode相关语法高亮在浏览器上显示

说明

  • 为了让monaco使用vscode的主题

尝试实现(弯路)

主题的直接转换

  • 刚开始本以为是两者主题的格式不同,尝试转换后发现还是不能正常使用
  • 结果发现两者的token根本不同,也就是分割代码每一部分的命名不同

monarch转换textmate

  • 发现monaco使用的是自己设计的monarch来实现语法高亮,但是vscode使用的是textmate的格式
textmate是苹果的那种
  • 于是想到如果实现一种转换逻辑,将textmate->monarch,那么monaco就可以使用vscode的主题了(因为token一样了)
  • 当学完双方的逻辑后,研究了posix与pcre正则的转换,进行事件时,发现一个致命问题..monach无法实现后行断言((?<=})),这就导致了普通的转换根本无法实现.(复杂的...可能有生之年系列吧)

最终解决方案

  • 使用vscode-textmate代替原monarch
  • 其实这个在开始研究的时候就有了,但是网上说因为不能直接调用c,所以使用wasm的效率比桌面端低,所以并没有有限考虑(有点自大了...)
  • 最终性能这块,看到了vscode-textmatebenchmark,测试了一波.发现除了js的解析比桌面端慢两倍,其他的甚至比桌面端快...有点费解了(不知道自己有没有研究错,如果有说的不对请拍砖)

jQuery v2.0.3

TOKENIZING 250971 lines using grammar source.js

Oniguruma: 550 ms., Onigasm: 381 ms. (1.4x faster)

Bootstrap CSS v3.1.1

TOKENIZING 127005 lines using grammar source.css

Oniguruma: 217 ms., Onigasm: 91 ms. (2.4x faster)

vscode.d.ts

TOKENIZING 264938 lines using grammar source.ts

Oniguruma: 356 ms., Onigasm: 191 ms. (1.9x faster)

JSON

TOKENIZING 103784 lines using grammar source.ts

Oniguruma: 312 ms., Onigasm: 185 ms. (1.7x faster)

Bootstrap CSS v3.1.1 minified

TOKENIZING 99967 lines using grammar source.css

Oniguruma: 231 ms., Onigasm: 167 ms. (1.4x faster)

jQuery v2.0.3 minified

TOKENIZING 83618 lines using grammar source.js

Oniguruma: 254 ms., Onigasm: 480 ms. (1.9x slower)

Bootstrap with multi-byte minified

TOKENIZING 116201 lines using grammar source.css

Oniguruma: 248 ms., Onigasm: 196 ms. (1.3x faster)

实现原理

  • 这个方案是从monaco-tm中得来的,但是最终完善了主题使用,可以从vscode中无缝移植主题,完善了语言插件,可以从vscode无缝迁移tmLanguage的插件,并且支持语言点注入
  • grammar是用来解析语法的,会在调用这个语言的时候,加载对应的语法文件
具体需要实现monaco.languages.EncodedTokensProvider接口传给setTokensProvider做参数

setTokensProvider代替了setMonarchTokensProvider

  • configuration是用来配置一些折叠,括号,注释等东西...和原来的monaco一样
  • theme就是用来请求加载主题的
因为语法的解析变成了vscode-textmate,所以不能使用传统的方式来加载主题,需要从Registry中拿到ColorMap然后定义给主题
  • 最后通过监听使用语言时加载对应的语法解析文件

使用

  • ng下已经封装好了依赖包的使用,非ng框架也可以稍作修改使用
  • 包地址cyia-ngx-common
  • 引入模块CyiaMonacoTextmateModule,组件中通过依赖注入拿到CyiaMonacoTextmateService服务

 this.service.setMonaco(monaco);

 this.service.init().then(async () => {

 const themeList = await this.service.getThemeList();

 this.themeList = themeList;

 this.selectedTheme = themeList[1];

 const name = await this.service.defineTheme(this.selectedTheme);

 this.instance = monaco.editor.create(

 this.containerElement?.nativeElement,

 {

 theme: name,

 value: `let a=6;`,

 language: this.selectedLanguage,

 minimap: {

 enabled: false,

 },

 automaticLayout: true,

 }

 );

 });

 //切换主题

 async change(e) {

 const name = await this.service.defineTheme(e);

 monaco.editor.setTheme(name);

 }

相关地址

阅读 115

推荐阅读