vscode插件开发
简单的中英翻译的vscode插件实现全过程介绍
# 一、环境准备及项目初始化
# 1. 准备环境
先使用的是 centsos 开发环境,但是会一直有权限问题,所以切换到了 mac 开发环境
确保安装了 Node.js 和 Git,安装以下工具:
npm install -g yo generator-code
# 2. 初始化插件项目
生成器搭建一个准备开发的 TypeScript 或 JavaScript 项目。运行生成器并为 TypeScript 项目填写几个字段:
> yo code
_-----_ ╭──────────────────────────╮
| | │ Welcome to the Visual │
|--(o)--| │ Studio Code Extension │
`---------´ │ generator! │
( _´U`_ ) ╰──────────────────────────╯
/___A___\ /
| ~ |
__'.___.'__
´ ` |° ´ Y `
? What type of extension do you want to create? New Extension (TypeScript)
? What's the name of your extension? WordTranslate
? What's the identifier of your extension? wordtranslate
? What's the description of your extension?
? Initialize a git repository? Yes
? Bundle the source code with webpack? Yes
? Which package manager to use? npm
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 3. 插件运行及调试
项目生成完后,在编辑器中,按 F5 ,会弹出配置提示,选择【配置任务】,随后选择 【npm:compile】即可
完成后编辑器会开启一个新的窗口,标题为 [扩展开发宿主机], 在这个窗口中已经加载了我们的插件,就可以使用了
打出组合键 ⇧⌘P,输入 >Hello World 随后回车,在编辑器右下角,就可以看到我们的插件的通知了
# 4. 开发初试
# a. 修改Hello World命令行为
修改 src/extension.ts 中 Hello World from WordTranslate!为 Hello vscode !,随后调出命令preload,选择 【开发人员:重新加载窗口】,重新加载插件,随后 执行Hello Wold命令,查看变化
以上是以 Hello World 命令做出一个普通提示框。也可以自定义其他命令做出其他操作
# b. 定义命令弹出警告框
package.json
"commands": [
{
"command": "wordtranslate.helloWorld",
"title": "Hello World"
},
// 新增 DoNotSupport 命令
{
"command": "wordtranslate.doNotSupport",
"title": "DoNotSupport"
}
]
2
3
4
5
6
7
8
9
10
11
src/extension.ts
// 增加 doNotSupport 命令的注册
let doNotSupport = vscode.commands.registerCommand('wordtranslate.doNotSupport', () => {
vscode.window.showWarningMessage('您当前编辑器不支持此版本插件!');
});
context.subscriptions.push(doNotSupport);
2
3
4
5
6
重新加载窗口,执行命令 doNotSupport,可看到警告框
注: 以下为 package.json 中命令的配置参数示例,更多详细信息可参考 Contribution Points | Visual Studio Code Extension API (opens new window)
{
"contributes": {
"commands": [
{
"command": "extension.sayHello",
"title": "Hello World",
"category": "Hello",
"icon": {
"light": "path/to/light/icon.svg",
"dark": "path/to/dark/icon.svg"
}
}
]
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
至此,项目就跑起来了
# 二、了解插件能力及项目架构
插件就是利用 vscode 给我们开放的一些API的基础上进行扩展功能的开发,从而解决开发中的一些问题,提高生产效率。这种插件化思想一方面使该代码编辑器更轻量化;另一方面能够充分利用社区的力量,为其提供更加多元化的插件。
# 1. 插件能干什么
# a. 插件通用功能
可以在任何扩展中使用的核心功能,主要包括以下几点:
能够添加命令、配置项、快捷键、菜单项、右键菜单;
存储工作区或全局数据;
展示通知信息;
使用快速选择收集用户的输入;
打开文件选择器让用户去选择文件或文件夹;
使用Progress API去阐述长时间运行的操作;
# b. 主题化
控制vscode的外观,包括编辑器中源代码的颜色和vscode ui的颜色,其主要包含三种类型的主题:
颜色主题:其允许将颜色应用于VS Code UI组件和编辑器中的文本;
文件图标主题:文件图标显示在VS Code UI中的位置,例如文件资源管理器、快速打开列表和编辑器选项卡;
产品图标主题:在整个UI中使用的一组图标
# c. 声明性语言特性
声明性语言功能为编程语言添加了基本的文本编辑支持,例如括号匹配、自动缩进和语法突出显示。
# d. 程序语言特性
编程语言功能添加了丰富的编程语言支持,例如悬停、转到定义、诊断错误、IntelliSense 和 CodeLens。
# e. 扩展工作台
工作台是指包含标题栏、活动栏、侧边栏、控制板、编辑组、状态栏等UI组件的整体Visual Studio Code UI。VS Code提供了各种API,允许将自己的组件添加到工作台。
# f. 调试
可以通过编写将 VS Code 的调试 UI 连接到特定调试器或运行时的调试器扩展来利用 VS Code 的调试功能。
# 2. 项目结构
以下是初始化项目完成后的目录结构,其中重要的就是 extension.ts 和 package.json 两个文件
# a. package.json
{
"name": "wordtranslate", // 插件名称
"displayName": "WordTranslate", // 显示在应用市场的名字
"description": "", // 插件描述
"version": "0.0.1", // 插件版本号
"engines": {
"vscode": "^1.77.0" // 最低支持的vscode版本
},
"categories": [
"Other" // 扩展类别
],
"activationEvents": [], // 激活事件组,在哪些事件下会被激活
"main": "./dist/extension.js", // 插件的主入口文件
"contributes": { // 贡献点
"commands": [ // 命令
{
"command": "wordtranslate.helloWorld",
"title": "Hello World"
},
{
"command": "wordtranslate.doNotSupport",
"title": "DoNotSupport"
}
]
},
"scripts": {
"vscode:prepublish": "npm run package",
"compile": "webpack",
"watch": "webpack --watch",
"package": "webpack --mode production --devtool hidden-source-map",
"compile-tests": "tsc -p . --outDir out",
"watch-tests": "tsc -p . -w --outDir out",
"pretest": "npm run compile-tests && npm run compile && npm run lint",
"lint": "eslint src --ext ts",
"test": "node ./out/test/runTest.js"
},
"devDependencies": { // 开发依赖项
"@types/vscode": "^1.77.0",
"@types/glob": "^8.1.0",
"@types/mocha": "^10.0.1",
"@types/node": "16.x",
"@typescript-eslint/eslint-plugin": "^5.56.0",
"@typescript-eslint/parser": "^5.56.0",
"eslint": "^8.36.0",
"glob": "^8.1.0",
"mocha": "^10.2.0",
"typescript": "^4.9.5",
"ts-loader": "^9.4.2",
"webpack": "^5.76.3",
"webpack-cli": "^5.0.1",
"@vscode/test-electron": "^2.3.0"
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
文件中 activationEvents、main、contributes 这三个配置项需要格外关注
# 1)main
标明了插件的入口在哪,只有找对了入口,项目才能正确运行
# 2)activationEvents
标明该插件在何种情况下会被激活,只有激活后插件才能正常使用,官网已经指明了激活的时机,我们只需要设置对应的时机去激活插件就可以了。
- onLanguage: 打开解析为特定的语言文件时被激活,如:onLanguage: python
- onCommand: 在调用命令时激活
- onDebug: 在启动调试之前被激活
- onDebugInitialConfigurations
- onDebugResolve
- workspaceContains: 每当打开文件夹并且该文件夹包含至少一个与glob模式匹配的文件时
- onFileSystem: 每当读取来自特定方案的文件和文件夹时
- onView: 当 vscode 侧栏中展开指定 id 的视图
- onUri: 当打开该扩展的系统范围的 Uri 时
- onWebviewPanel
- onCustomEditor
- onAuthenticationRequest
- *:只要一启动 vscode,该插件就被激活
- onStartupFinished
# 3)contributes
- breakpoints:断点,可列出将启用断点的语言文件类型
- colors:颜色,提供新的主题颜色
- commands:命令,可设置由标题、类别、图标和启用状态组成的命令ui
- configuration:配置,提供将向用户开放的配置键
- configurationDefaults:为其他已注册的配置提供默认值并覆盖其默认值
- customEditors:标识自定义编辑器的信息
- debuggers:调试器
- grammars:语法
- icons:按插件id设置新图标和一个默认图标
- iconThemes:文件图标主题
- jsonValidation:为特定类型的文件提供验证框架
- keybindings:键绑定规则
- languages:编程语言的定义
- menus:菜单
- problemMatchers:问题匹配器
- problemPatterns:问题匹配器中使用的命名问题模式
- productIconThemes:产品图标主题
- resourceLabelFormatters:语义标记修饰符
- semanticTokenModifiers:语义标记类型和修饰符与范围之间的映射,作为回退或支持特定语言的主题
- semanticTokenScopes
- semanticTokenTypes
- snippets
- submenus
- taskDefinitions
- terminal
- themes
- typescriptServerPlugins
- views
- viewsContainers
- viewsWelcome
- walkthroughs
# 三、开发实战
# 1. 插件目标
看名释意: WordTranslate 词汇翻译
预期实现:选择一段文字后,右键可以增加一个翻译的菜单,进行中英翻译
# 2. 目标实现
# a. 增加右键菜单
官方文档:(Contribution Points | Visual Studio Code Extension API)[https://code.visualstudio.com/api/references/contribution-points#contributes.menus]
package.json 文件修改
"contributes": {
"commands": [
{
"command": "wordtranslate.helloWorld",
"title": "Hello World"
},
{
"command": "wordtranslate.doNotSupport",
"title": "DoNotSupport"
}
],
// 增加按钮配置内容
"menus": {
"editor/context": [
{
"command": "wordtranslate.helloWorld",
"group": "navigation"
}
]
}
},
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
运行插件,右键 可看到增加的 Hello Wold 菜单,点击可看到右下角弹框提示
# b. 程序获取用户选择文本
src/extension.ts 修改
let disposable = vscode.commands.registerCommand('wordtranslate.helloWorld', () => {
// vscode.window.showInformationMessage('Hello vscode !');
// 获取当前激活的文本编辑器实例
const editor = vscode.window.activeTextEditor;
if (editor) {
// 获取当前用户选中的文本
const selection = editor.selection;
const selectedText = editor.document.getText(selection);
vscode.window.showInformationMessage(`选中的文本是:${selectedText}`);
} else {
vscode.window.showInformationMessage(`当前没有打开的文本编辑器。`);
}
});
2
3
4
5
6
7
8
9
10
11
12
13
14
以上代码实例将原本的 Hello vscode提示,修改为根据用户选择文本进行提示。效果如下:
# c. 用户选择文本后自动弹出提示
失败方案,通过右键菜单点击后提示弹框,展示不方便,所以换成以下方案
思路:利用鼠标移上hover弹出provider,包含选择的文本
src/extension.ts 修改
// 定义一个HoverProvider
const hoverProvider = {
provideHover(document: any, position: any) {
const editor = vscode.window.activeTextEditor;
if (editor) {
// 获取当前用户选中的文本
const selection = editor.selection;
const selectedText = editor.document.getText(selection);
if (selectedText) {
return new vscode.Hover('选择文本:' + selectedText);
}
}
},
};
// 注册HoverProvider
const languageSelector = [ // 匹配到对应的文件才激活HoverProvider
{ language: 'javascript', scheme: 'file' },
];
const showTranslate = vscode.languages.registerHoverProvider(languageSelector, hoverProvider);
context.subscriptions.push(showTranslate);
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
但是上述文件在 activate 中,即插件激活后才会被启动,打开调试后右键菜单点击Hello World之后,插件激活后可以查看效果,若需要编辑器启动即启动插件,则需要增加相应的配置
package.json 修改
"activationEvents": [
"onLanguage:javascript" // 检测到打开js文件时启动插件
],
2
3
这样当编辑器打开js文件时,插件就会启动,效果如下:
# d. 实现翻译
使用第三方翻译API,这里使用百度翻译API
首先注册成为开发者,地址:百度翻译开放平台 (baidu.com) (opens new window)
接入百度翻译API
const hoverProvider = {
async provideHover(document: any, position: any) {
const editor = vscode.window.activeTextEditor;
if (editor) {
// 获取当前用户选中的文本
const selection = editor.selection;
const selectedText = editor.document.getText(selection);
if (selectedText) {
const translation = await translate(selectedText);
if (translation) {
return new vscode.Hover("翻译文本:" + translation);
} else {
return new vscode.Hover("选择文本:" + selectedText);
}
}
}
},
};
// 注册HoverProvider
const languageSelector = [{ language: "javascript", scheme: "file" }];
const showTranslate = vscode.languages.registerHoverProvider(
languageSelector,
hoverProvider
);
async function translate(text: string) {
// 百度翻译的 API 地址和 APP ID 与密钥
const apiEndpoint = "https://fanyi-api.baidu.com/api/trans/vip/translate";
const appid = "your_own_appid"; // 此处替换为你自己的开发者appid
const key = "your_own_key"; // 此处替换为你自己的额开发者key
// 设置 API 请求参数
const sourceLang = "auto";
const targetLang = "zh";
const query = text;
const salt = Math.round(Math.random() * 100000); // 随机数,用于签名
const sign = baiduSign(query, appid, salt, key);
const params = `?q=${encodeURIComponent(
query
)}&from=${sourceLang}&to=${targetLang}&appid=${appid}&salt=${salt}&sign=${sign}`;
// 发送 HTTP 请求获取翻译结果
return new Promise<string | undefined>((resolve, reject) => {
const req = https.get(apiEndpoint + params, (res) => {
let data = "";
res.on("data", (chunk) => {
data += chunk;
});
res.on("end", () => {
const result = JSON.parse(data);
if (result?.trans_result?.length > 0) {
resolve(result.trans_result[0].dst);
} else {
reject("Translation failed!");
}
});
});
req.on("error", (error) => {
console.error('error', error);
reject(error);
});
});
}
function baiduSign(query: string, appid: string, salt: number, key: string) {
// 计算百度翻译 API 的签名,用于 API 认证
const signString = `${appid}${query}${salt}${key}`;
const md5 = require("md5");
return md5(signString);
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
效果如下:
基于以上内容,我们可以获取用户选择的文本,并且接入百度翻译API翻译成指定语言的文本,并在鼠标hover时展示,目标功能基本完成
# 四、发布
# 1. 发布方式
# a. 本地文件
直接把文件夹发给别人,让别人找到 vscode 插件存放目录放进去,然后重启 vscode,一般不推荐
# b. 打包成 vsix 插件
打包成vsix插件,发给别人安装,如果插件涉及到机密不方便发送到应用市场,可以尝试使用这种方式
# c. 发布到官网应用市场
注册开发者账号,发布到官网应用市场,这个发布和npm一样是不需要审核的。
# 2. 打包成 vsix 插件
打包需要用到 vsce
npm install vsce -g
打包,打包前需修改 README.md , 并且在 package.json 文件中增加 repository 配置
vsce package
安装时需 从插件右上角,从 VSIX 安装
安装完成后就可以正常使用了,从已安装的插件中也可以找到
# 3. 发布到官网
发布过程未经过实操,可参考 VSCode插件开发全攻略(十)打包、发布、升级 - 我是小茗同学 - 博客园 (cnblogs.com) (opens new window)