如何为VSCode中的JavaScript添加{{custom}}宏语法支持?
我完全懂你这种头疼的感觉——直接改VS Code内置的JavaScript tmLanguage文件不仅是野路子,还经常出现各种奇怪的兼容问题:高亮时好时坏,错误提示还消不掉。别担心,咱们用正规的VS Code扩展开发就能彻底解决这个问题,我给你一步步拆解怎么做:
一、核心方案:开发注入式TextMate语法扩展
VS Code的语法高亮基于TextMate规则,我们不需要碰内置文件,而是可以开发一个注入式语法扩展,把自定义的{{...}}宏规则“贴”到JavaScript语法上,既安全又灵活。
1. 快速搭建扩展项目
用VS Code官方的Yeoman生成器搭架子,比从零写省事儿太多:
- 打开终端,先装依赖:
npm install -g yo generator-code - 运行
yo code,跟着向导选:- 选
New Language Support - 输入语言名称(比如
JS Custom Macro) - 关联文件类型选
JavaScript(让扩展对.js文件生效) - 关键一步:选
Inject into existing grammar,然后选source.js
- 选
2. 编写宏的语法规则
生成的项目里会有一个tmLanguage.json文件(推荐用JSON格式,比XML好写),把下面的规则填进去:
{ "scopeName": "source.js.custom-macro", "injectTo": ["source.js"], "patterns": [ { "name": "string.template.js.custom-macro", "begin": "(?:([_$[:alpha:]][_$[:alnum:]]*)?)({{)", "beginCaptures": { "1": { "name": "entity.name.function.tagged-template.js" }, "2": { "name": "punctuation.definition.string.template.begin.js" } }, "end": "}}", "endCaptures": { "0": { "name": "punctuation.definition.string.template.end.js" } }, "patterns": [ { "include": "#string-character-escape" }, // 这里可以加宏内部的自定义高亮规则,比如变量、关键字 { "match": "\\b([_$[:alpha:]][_$[:alnum:]]*)\\b", "name": "variable.other.js.custom-macro" } ] } ], "repository": { "string-character-escape": { "match": "\\\\(x[0-9A-Fa-f]{2}|u[0-9A-Fa-f]{4}|[0-2][0-7]{0,2}|3[0-6][0-7]?|37[0-7]?|[4-7][0-7]?|.|$)", "name": "constant.character.escape.js" } } }
给你解释下关键配置:
injectTo: 把这个语法规则注入到JavaScript语法里,所有.js文件都会生效begin/end: 精准匹配{{和}},如果前面有标识符(比如myFunc{{...}}),会自动识别成标签模板函数- 内部的
patterns: 先继承了字符串转义的规则,还能自定义宏内部的高亮(比如把宏里的变量标成蓝色)
3. 立刻测试效果
按F5启动扩展开发窗口,打开一个带{{custom}}宏的.js文件,你会发现宏已经被识别成模板字符串,语法高亮正常了!
二、解决烦人的错误标记问题
VS Code的JavaScript语言服务不认{{...}},所以会报错。咱们可以做个轻量的语言服务扩展,过滤掉这些无关错误:
1. 在package.json里加配置
先把语言服务和语法扩展的关联配置好:
"contributes": { "languages": [ { "id": "javascript", "configuration": "./language-configuration.json" } ], "grammars": [ { "language": "javascript", "scopeName": "source.js.custom-macro", "path": "./syntaxes/javascript-custom-macro.tmLanguage.json", "injectTo": ["source.js"] } ] }, "activationEvents": ["onLanguage:javascript"], "main": "./extension.js"
2. 写个简单的语言服务过滤错误
创建server.js文件,用来过滤宏相关的错误:
const { createConnection, TextDocuments } = require('vscode-languageserver/node'); const { TextDocument } = require('vscode-languageserver-textdocument'); const connection = createConnection(); const documents = new TextDocuments(TextDocument); documents.onDidChangeContent(change => { const document = change.document; // 请求原语言服务的诊断结果,然后过滤掉宏相关的错误 connection.sendRequest('textDocument/diagnostic', { textDocument: { uri: document.uri } }) .then(originalDiagnostics => { const filteredDiagnostics = originalDiagnostics.filter(diag => { const errorText = document.getText(diag.range); return !errorText.includes('{{') && !errorText.includes('}}'); }); connection.sendDiagnostics({ uri: document.uri, diagnostics: filteredDiagnostics }); }); }); connection.listen();
再创建extension.js启动这个语言服务:
const { LanguageClient } = require('vscode-languageclient/node'); const path = require('path'); function activate(context) { const serverPath = path.join(context.extensionPath, 'server.js'); const client = new LanguageClient( 'jsCustomMacro', 'JS Custom Macro Service', { run: { module: serverPath }, debug: { module: serverPath, options: { execArgv: ['--nolazy', '--inspect=6009'] } } }, { documentSelector: [{ language: 'javascript' }] } ); client.start(); } exports.activate = activate;
现在再打开带宏的.js文件,那些烦人的错误标记就消失了!
三、可选优化:添加宏代码片段
如果经常要写{{...}},可以加个代码片段提高效率:
在package.json的contributes里加:
"snippets": [ { "language": "javascript", "path": "./snippets/javascript.json" } ]
然后创建snippets/javascript.json:
{ "Custom Macro": { "prefix": "macro", "body": "{{$1}}", "description": "快速插入自定义宏" } }
以后输入macro按回车就能快速生成宏模板了。
总结
这种方式比改内置文件规范太多:
- 注入式语法不破坏VS Code原有配置,更新也不会被覆盖
- 语言服务过滤能彻底解决错误标记问题
- 还能随时扩展智能提示、格式化等功能
内容的提问来源于stack exchange,提问作者Michael S.

