纯词法高亮只需TextMate语法文件(.tmLanguage.json);要支持跳转、类型提示、诊断等语义功能,必须实现语言服务器(LSP)。

VSCode 插件市场里所谓“面向特定领域语言的语法高亮插件”,绝大多数不是靠写代码实现的,而是靠配置 TextMate 语法文件(.tmLanguage.json)+ 正确注册语言 ID + 绑定文件扩展名——真正需要写 TypeScript 的部分,只在你要加语义功能(如跳转、补全)时才出现。
怎么判断该用语法定义还是语言服务器?
纯词法高亮(关键词、字符串、注释变色)→ 只需 .tmLanguage.json;要支持变量引用跳转、类型提示、错误诊断 → 必须写语言服务器(Language Server),光靠语法文件做不到。
- 比如为一个自定义配置语言(如
.env.*)做高亮:装mikestead.dotenv就够了,它只解析结构,不跑服务 - 但为 Protobuf(
.proto)做高亮+import跳转+跨文件校验:必须用hbenl.vscode-protobuf,它背后是真实 protoc 解析器 - 如果你发现某插件装了但
Ctrl+Click跳不到定义,说明它只是语法高亮层,没上 LSP
package.json 里 language 和 grammar 的关键字段不能错
新手常把 languages.id 和 grammars.language 写成不同值,导致高亮完全不触发。它们必须严格一致,且全小写、无空格、无特殊字符。
- 正确示例:
"id": "dotenv"对应"language": "dotenv",不是"dotenv-file"或"env" -
extensions数组里写".env.local",不代表".env"也会被识别——得单独加进去 -
aliases是给用户手动选语言时用的(右下角点击后看到的名称),不影响匹配逻辑
tmLanguage.json 中 scope 名影响 editor.tokenColorCustomizations 生效
你后续想用 editor.tokenColorCustomizations 改某个 token 颜色,前提是这个 token 确实被语法文件打了 scope。而 scope 名不是随便起的,它决定了你在 settings.json 里能匹配到什么。
- 比如你想高亮所有数字字面量,语法文件里得写
"name": "constant.numeric.mylang",否则你配"constant.numeric"就无效 - scope 名越具体越好(如
keyword.control.js),避免泛匹配(如keyword)被主题默认规则覆盖 - 用
Ctrl+Shift+P → Developer: Inspect Editor Tokens and Scopes查当前 token 的真实 scope,别猜
发布前必须验证文件关联和空文件夹行为
很多插件在单文件打开时高亮正常,一进工作区就失效——因为 VSCode 默认只在有打开文件夹(workspace)时加载某些插件的激活事件。
- 测试方式:用
code --disable-extensions /path/to/your/file.mylang启动,再手动启用你的插件 - 确保
activationEvents包含"onLanguage:mylang",而不是只靠"*"(太重,拖慢启动) - 在空文件夹中新建
test.mylang,检查右下角是否自动显示你的语言名;不显示,说明files.associations没生效或语言 ID 注册失败
最常被忽略的一点:语法高亮插件一旦发布,用户不会去改 settings.json,所以 files.associations 必须在插件内部通过 contributes.configuration 提供默认绑定,或者文档里明确写出要用户手动加——指望用户自己查扩展名对应关系,等于放弃 80% 的潜在使用者。


















