如何用 vscode-textmate 加载语法文件:JSON 与 PLIST 两种格式全攻略
【免费下载链接】vscode-textmateA library that helps tokenize text using Text Mate grammars.项目地址: https://gitcode.com/gh_mirrors/vs/vscode-textmate
vscode-textmate 是一个用来按 TextMate 语法对代码进行分词(Tokenize)的开源库,也是 VS Code 语法高亮的底层引擎之一。对于想自己搭建编辑器、代码高亮工具或语法调试器的开发者来说,如何用 vscode-textmate 加载语法文件是入门第一步。本文将带你一次搞懂 JSON 与 PLIST 两种语法文件格式的加载方法、核心 API 和避坑要点,全程无门槛,跟着做就能跑通。
vscode-textmate 支持哪两种语法文件格式
TextMate 语法文件本质上是一套描述"如何给文本打标签"的规则,历史上主要有两种载体:
| 格式 | 文件扩展名 | 特点 |
|---|---|---|
| JSON 格式 | .json | 结构清晰、可读性好,社区新语法多用它 |
| PLIST 格式 | .plist/.tmLanguage | XML 结构,历史久远,老语法包常用它 |
vscode-textmate 对两种格式"通吃",你不需要自己判断文件类型,它内部会自动识别。核心判断逻辑在 src/parseRawGrammar.ts:只要传入的文件路径以.json结尾,就走 JSON 解析器;否则走 PLIST 解析器。
快速开始:三步完成语法文件加载
第一步:安装依赖
vscode-textmate 本身只负责语法解析,正则匹配依赖 oniguruma 引擎,所以还要装vscode-oniguruma:
npm install vscode-textmate vscode-oniguruma第二步:初始化 Registry 并加载语法
加载语法的入口是Registry,它负责按scopeName(作用域名,如source.js)找到并缓存语法规则。核心代码如下:
const vsctm = require('vscode-textmate'); const oniguruma = require('vscode-oniguruma'); const fs = require('fs'); // 加载 oniguruma 的 wasm 引擎 const wasmBin = fs.readFileSync( './node_modules/vscode-oniguruma/release/onig.wasm' ).buffer; const onigLib = oniguruma.loadWASM(wasmBin).then(() => ({ createOnigScanner(patterns) { return new oniguruma.OnigScanner(patterns); }, createOnigString(s) { return new oniguruma.OnigString(s); } })); // 创建 Registry,loadGrammar 回调负责按 scopeName 返回语法内容 const registry = new vsctm.Registry({ onigLib: onigLib, loadGrammar: (scopeName) => { if (scopeName === 'source.js') { const content = fs.readFileSync('./JavaScript.json', 'utf8'); return vsctm.parseRawGrammar(content, './JavaScript.json'); } return null; } }); registry.loadGrammar('source.js').then((grammar) => { console.log('语法加载成功!', grammar.scopeName); });第三步:用 tokenizeLine 对代码分词
加载成功后,调用grammar.tokenizeLine(line, prevState)逐行分词,ruleStack用于跨行状态传递:
let ruleStack = vsctm.INITIAL; const line = 'function sayHello(name) {'; const result = grammar.tokenizeLine(line, ruleStack); result.tokens.forEach((token) => { console.log(token.startIndex, token.endIndex, token.scopes.join(', ')); }); ruleStack = result.ruleStack;你会看到类似source.js, meta.function.js, storage.type.function.js这样的作用域输出,这正是语法高亮的基础数据。
JSON 与 PLIST 语法文件加载的核心差异
parseRawGrammar 自动识别格式
parseRawGrammar(content, filePath)是两种格式统一的人口。它只认扩展名,不检查文件内容,所以路径后缀一定要写对,否则会解析失败。相关实现见 parseRawGrammar.ts。
- 传入
xxx.json→ 使用 JSON 解析器 - 传入
xxx.plist或xxx.tmLanguage→ 使用 PLIST 解析器
JSON 语法文件长什么样
JSON 语法文件就是一份普通的 JSON 对象,包含scopeName、patterns、repository等字段。项目测试夹具里有一个非常直观的例子 hello.json,核心结构如下:
{ "name": "hello", "scopeName": "source.hello", "patterns": [ { "match": "hello", "name": "prefix.hello" }, { "match": "world(!?)", "name": "suffix.hello" } ] }PLIST 语法文件长什么样
PLIST 是 XML 风格,用<dict>、<key>、<array>、<string>标签描述同样的规则。见测试夹具 66.plist:
<?xml version="1.0" encoding="UTF-8"?> <plist version="1.0"> <dict> <key>scopeName</key> <string>text.test</string> <key>patterns</key> <array> <dict> <key>begin</key><string>^.</string> <key>name</key><string>comment</string> </dict> </array> </dict> </plist>加载语法文件的常见坑与解决方法
坑一:oniguruma 引擎没加载好
vscode-textmate 的所有正则匹配都要走 oniguruma,onigLib必须返回一个 Promise 对象,且必须包含createOnigScanner和createOnigString两个方法,缺一不可。定义见 onigLib.ts。
坑二:scopeName 对不上
loadGrammar回调里要根据scopeName精确匹配。语法文件里的scopeName字段和回调参数不一致时,会返回null,此时控制台会输出Unknown scope name提示。正确的分发逻辑可以参考 registry.ts。
坑三:文件路径后缀写错
.json文件路径不带.json后缀传入parseRawGrammar,会被当成 PLIST 解析而报错。这是新手最容易踩的坑,务必把完整文件名传进去。
深入:vscode-textmate 加载语法的内部原理
弄懂原理后,排查问题会轻松很多。整个加载链路是这样的:
Registry.loadGrammar(scopeName)发起加载,见 main.ts;- 回调
loadGrammar返回原始语法内容(JSON 或 PLIST 对象); parseRawGrammar根据扩展名解析成统一的IRawGrammar结构;- 解析结果存入
SyncRegistry,并处理include引用的其他语法(如source.js引用了source.js.regexp); - 最终创建出
Grammar实例,供tokenizeLine调用。
其中依赖处理很有意思:当某个语法include了外部语法时,Registry会通过ScopeDependencyProcessor自动递归加载,无需你手动处理。这也是它能支持复杂语法包的原因。
加载语法文件的实用建议
- 新项目优先用 JSON 格式:结构更清晰,也方便写测试断言;项目自带测试 tokenization.test.ts 就是直接读 JSON 语法做断言。
- 老语法包直接给路径:从网上拿到的
.tmLanguage或.plist语法包,无需转换,直接把文件名传给parseRawGrammar即可。 - 想要报错定位?开启调试模式后,JSON/PLIST 解析会附带行列位置信息(
$vscodeTextmateLocation),排查语法错误非常有用,实现见 json.ts。 - 性能敏感场景:PLIST 解析器是专为速度优化的极简实现,见 plist.ts,两者性能差异不大,按格式偏好选择即可。
总结
如何用 vscode-textmate 加载语法文件,核心就一句话:装好vscode-oniguruma,创建Registry,在loadGrammar回调里用parseRawGrammar(content, filePath)解析并返回语法内容。JSON 与 PLIST 两种格式都由parseRawGrammar根据文件扩展名自动识别,无需额外转换。掌握本文的加载流程和三个常见坑,你就能在自己的编辑器或高亮工具里顺利接入 TextMate 语法了。
【免费下载链接】vscode-textmateA library that helps tokenize text using Text Mate grammars.项目地址: https://gitcode.com/gh_mirrors/vs/vscode-textmate
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考