2005 字
10 分钟
为自己的脚本语言编写VSCode支持扩展:从零到发布完整指南
为自己的脚本语言编写VSCode支持扩展:从零到发布完整指南
作者:colaSensei | 发布时间:2026年1月
最近我为自己设计的游戏脚本语言PGNCode开发了VSCode扩展,过程中积累了不少经验。如果你也有自己的DSL(领域特定语言)或脚本语言,这篇文章将带你完整走过为它创建VSCode扩展的每一个步骤。
为什么需要为自定义语言开发VSCode扩展?
在我开发PaperVisualNovel引擎时,设计了PGNCode脚本语言。编写游戏需要编辑.pgn文件,但遇到了一些问题:
- 没有语法高亮:所有文本都是同一个颜色,难以区分命令、变量和注释
- 没有代码提示:需要记忆所有命令和参数格式
- 没有错误检查:语法错误只能在运行时发现
- 开发体验差:缺少现代IDE应有的功能
这些问题严重影响了开发效率。于是,我决定为PGNCode创建VSCode扩展。
准备工作
技术栈需求
- Node.js (>= 14.x)(这个应该都有吧)
- Visual Studio Code (用于开发和测试,这个不可能没有吧)
- 基础的前端知识 (JSON, 正则表达式)
开发工具
# 安装VSCode扩展开发工具npm install -g yo generator-code第一步:创建扩展项目
使用官方生成器创建基础项目:
# 创建项目目录mkdir my-language-extensioncd my-language-extension
# 运行生成器yo code在交互式界面中选择:
- New Language Support (新语言支持)
- 输入扩展名称、描述
- 指定语言ID、文件扩展名
这会生成一个基础的项目结构。
第二步:理解项目结构
生成的项目包含以下核心文件:
my-language-extension/├── package.json # 扩展清单├── syntaxes/│ └── language.tmLanguage.json # 语法定义├── language-configuration.json # 语言配置└── README.md # 说明文档1. package.json - 扩展清单
这是扩展的”身份证”,定义了扩展的基本信息和功能。
{ "name": "my-language-support", "displayName": "My Language Support", "description": "Syntax highlighting for My Language", "version": "1.0.0", "publisher": "your-name", "engines": { "vscode": "^1.75.0" }, "categories": ["Programming Languages"], "contributes": { "languages": [{ "id": "mylang", "aliases": ["My Language", "mylang"], "extensions": [".mylang", ".ml"], "configuration": "./language-configuration.json" }], "grammars": [{ "language": "mylang", "scopeName": "source.mylang", "path": "./syntaxes/mylang.tmLanguage.json" }] }}2. 语法定义文件 (TextMate语法)
这是最核心的部分,定义了如何高亮代码。VSCode使用TextMate语法系统。
{ "$schema": "https://raw.githubusercontent.com/martinring/tmlanguage/master/tmlanguage.json", "scopeName": "source.mylang", "patterns": [ { "name": "comment.line.mylang", "match": "//.*" }, { "name": "keyword.control.mylang", "match": "\\b(if|else|while|for|return)\\b" }, { "name": "constant.numeric.mylang", "match": "\\b\\d+(\\.\\d+)?\\b" } ]}关键概念:
scopeName: 语法的根作用域patterns: 匹配规则数组name: 作用域名称,决定高亮颜色match: 正则表达式匹配模式
3. 语言配置文件
定义语言的编辑特性:
{ "comments": { "lineComment": "//", "blockComment": ["/*", "*/"] }, "brackets": [ ["{", "}"], ["[", "]"], ["(", ")"] ], "autoClosingPairs": [ { "open": "{", "close": "}" }, { "open": "[", "close": "]" }, { "open": "(", "close": ")" }, { "open": "\"", "close": "\"" } ], "indentationRules": { "increaseIndentPattern": "^.*\\{[^}\"]*$|^.*\\([^)\"]*$", "decreaseIndentPattern": "^\\s*\\}|^\\s*\\)" }}第三步:设计语法高亮规则
分析语言特性
以我的PGNCode为例,我需要识别:
- 注释:
// 这是注释 - 命令:
say,wait,set,if等 - 变量:
${variable}格式 - 数字:整数和小数
- 字符串:引号内的文本
- 标签:
LABEL_NAME:格式
编写匹配规则
{ "scopeName": "source.pgn", "patterns": [ // 注释 { "name": "comment.line.double-slash.pgn", "match": "//.*" },
// 命令(小心处理边界) { "name": "keyword.control.pgn", "match": "(?<!\\$\\{)\\b(say|wait|set|if|choose)\\b(?!\\})" },
// 变量引用 { "name": "variable.parameter.pgn", "begin": "\\$\\{", "end": "\\}", "patterns": [ { "name": "variable.other.pgn", "match": "[a-zA-Z_][a-zA-Z0-9_]*" } ] },
// 标签定义(行首的单词后跟冒号) { "name": "entity.name.tag.pgn", "match": "^\\s*[A-Za-z_][A-Za-z0-9_]*:" } ]}技巧:
- 使用
begin/end处理嵌套结构 - 使用负向零宽断言避免错误匹配
- 从简单规则开始,逐步完善
第四步:添加代码片段
代码片段可以极大提高编码效率:
{ "If Command": { "prefix": ["if", "IF"], "body": [ "if ${1:variable} ${2|==,!=,>,<,>=,<=|} ${3:value} ${4:LABEL_NAME}" ], "description": "Conditional jump" }, "Say Command": { "prefix": "say", "body": [ "say ${1:text} ${2:0.5} ${3|white,black,blue,green,red,yellow|}" ], "description": "Display text with typing effect" }}特性:
prefix: 触发补全的文本body: 插入的代码,支持占位符${n:default}- 选择列表:
${1|option1,option2|} - 变量:
${TM_FILENAME}等内置变量
第五步:本地测试
启动调试
- 在VSCode中打开扩展项目
- 按
F5启动扩展开发主机 - 在新窗口中创建测试文件
- 验证语法高亮和代码片段
常见问题调试
问题1:语法高亮不工作
- 检查
.tmLanguage.json格式 - 验证正则表达式是否正确
- 检查文件扩展名关联
问题2:代码片段不出现
- 检查
snippets/*.json文件格式 - 确认
snippet的language字段正确 - 重启扩展主机
问题3:扩展无法激活
- 检查
package.json中的activationEvents - 查看”输出”面板的”扩展主机”日志
第六步:高级功能
1. 添加命令和配置
{ "contributes": { "commands": [{ "command": "mylang.formatDocument", "title": "Format MyLang Document" }], "configuration": { "title": "My Language", "properties": { "mylang.enableSyntaxHighlighting": { "type": "boolean", "default": true, "description": "Enable syntax highlighting" } } } }, "activationEvents": [ "onLanguage:mylang", "onCommand:mylang.formatDocument" ]}2. 创建语言服务器(可选)
对于复杂的语言功能(代码补全、诊断、跳转定义),可以考虑实现Language Server:
// 创建Language Serverimport * as vscode from 'vscode';import * as lsp from 'vscode-languageclient';
export function activate(context: vscode.ExtensionContext) { const serverOptions: lsp.ServerOptions = { command: 'node', args: [context.asAbsolutePath('server/server.js')] };
const clientOptions: lsp.LanguageClientOptions = { documentSelector: [{ scheme: 'file', language: 'mylang' }] };
const client = new lsp.LanguageClient( 'mylangServer', 'My Language Server', serverOptions, clientOptions );
client.start();}第七步:打包和发布
1. 安装打包工具
npm install -g @vscode/vsce2. 准备发布
# 更新版本号# 完善README.md# 添加LICENSE# 更新CHANGELOG.md3. 打包
vsce package# 生成: my-language-support-1.0.0.vsix4. 发布到市场
方法A:直接发布
vsce publish# 需要发布者令牌方法B:手动上传
- 访问 VS Code Marketplace
- 点击”上传扩展”
- 选择生成的
.vsix文件
第八步:持续维护
监控反馈
- 关注GitHub Issues
- 查看市场评价
- 收集用户需求
版本更新流程
- 修改代码
- 更新版本号
- 更新CHANGELOG
- 测试
- 打包
- 发布
最佳实践
- 渐进增强:先实现语法高亮,再逐步添加高级功能
- 测试驱动:为每个功能创建测试用例
- 文档完善:清晰的README和注释
- 性能优化:避免复杂的正则表达式
- 向后兼容:谨慎修改现有功能
实战经验分享
踩过的坑
正则表达式性能问题
// 错误:过于复杂的正则"match": "\\b(say|wait|show|end|set|random|jump|if|choose|endname|SAY|WAIT|SHOW|END|SET|RANDOM|JUMP|IF|CHOOSE|ENDNAME)\\b"
// 优化:使用忽略大小写标志"match": "(?i)\\b(say|wait|show|end|set|random|jump|if|choose|endname)\\b"作用域冲突
// 变量引用内部的文本不应该被当作命令高亮// 错误:${say} 中的 "say" 被高亮为命令// 解决:在命令匹配中使用负向零宽断言"match": "(?<!\\$\\{)\\b(say|wait|set)\\b(?!\\})"效率技巧
-
使用开发工具:
-
模板化开发:
// 自动生成代码片段的脚本const commands = [{ name: 'say', desc: 'Display text' },{ name: 'set', desc: 'Set variable' }];const snippets = {};commands.forEach(cmd => {snippets[cmd.name] = {prefix: cmd.name,body: [`${cmd.name} \${1:placeholder}`],description: cmd.desc};}); -
测试用例: 创建测试文件覆盖所有语法特性:
test-cases.mylang├── 注释测试├── 命令测试├── 变量测试└── 边界情况测试
成果展示
完成扩展后,我的PGNCode开发体验得到了极大改善:
之前:
- 纯文本编辑
- 需要查手册
- 运行时才发现错误
之后:
- 彩色语法高亮
- 智能代码补全
- 实时错误提示
- 开发效率提升300%(哈哈)
资源推荐
- 官方文档:VSCode Extension API
- 示例项目:VSCode Extension Samples
- 语法参考:TextMate Language Grammars
- 正则测试:Regex101
结语
为自己的脚本语言开发VSCode扩展是一项很有价值的工作。它不仅提升了开发体验,也让你的语言看起来更加”专业”。整个过程虽然有些技术细节需要处理,但收获的成就感是巨大的。
关键点回顾:
- 从简单的语法高亮开始
- 逐步添加代码片段、配置等高级功能
- 充分测试,特别关注边界情况
- 文档完善,便于他人使用
- 持续维护,响应用户反馈
希望这篇文章能帮助你也为自己的语言创建出色的开发工具。
为自己的脚本语言编写VSCode支持扩展:从零到发布完整指南
https://clina.sylu.cc/posts/script-language-vscode-extension/