VS Code 插件开发
Aix Trainee

Visual Studio Code (简称 VS Code) 是由微软推出的一款免费、开源的跨平台文本和代码编辑器。VSCode 支持多种编程语言,并通过扩展插件可以支持更多的语言和功能。VS Code 是用 Electron 框架(Electron 是一个开源的跨平台应用框架,可以使用 HTML、CSS 和 JavaScript 来开发跨平台的桌面应用。Electron 使用 Chromium 作为内置浏览器,并使用 Node.js 作为后端运行时)开发的,那么作为前端开发,想要在 VSCode 上开发一款扩展插件就很方便。

VS Code 插件可以做什么

  • 使用颜色或文件图标主题更改 VS Code 的外观 -主题

  • 自定义左侧功能面板和视图 -扩展工作台

  • 创建一个 Webview 以显示使用 HTML/CSS/JS 构建的自定义网页

  • 自定义跳转、自动补全、悬浮提示

  • 支持一种新的编程语言(代码高亮、语法解析、折叠、跳转、补全等)

  • 状态栏修改、通知提示、编辑器控制、git源代码控制、任务定义

  • ...

1. 第一步

1.1 脚手架

请先安装好Node.jsGit,然后安装YeomanVS Code Extension Generator

1
npm install -g yo generator-cod
1
2
3
4
5
6
7
8
9
10
yo code
# ? What type of extension do you want to create? New Extension (TypeScript)
# ? What's the name of your extension? HelloWorld
### Press <Enter> to choose default for all options below
#### ? What's the identifier of your extension? helloworld
# ? What's the description of your extension? LEAVE BLANK
# ? Initialize a git repository? Yes
# ? Bundle the source code with webpack? No
# ? Which package manager to use? npm
# ? Do you want to open the new folder with Visual Studio Code? Open with `code`

1.2 解析插件结构

  • 插件目录结构
1
2
3
4
5
6
7
8
9
10
.
├── .vscode
├── launch.json // 插件加载和调试的配置
│ └── tasks.json // 配置TypeScript编译任务
├── .gitignore // 忽略构建输出和node\_modules文件
├── README.md // 一个友好的插件文档
├── src
│ └── extension.ts // 插件源代码
├── package.json // 插件配置清单
├── tsconfig.json // TypeScript配置
  • 插件清单

每个 VS Code 插件都必须包含一个 package.json,它就是插件的配置清单。package.json 混合了 Node.js 字段,如:scriptsdependencies,还加入了一些 VS Code 独有的字段,如:publisheractivationEventscontributes 等。关于这些 VS Code 字段说明都在插件清单参考中可以找到。我们在本节介绍一些非常重要的字段:

  • name 和 publisher: VS Code 使用<publisher>.<name>作为一个插件的 ID。例如,Hello World 例子的 ID 就是 vscode-samples.helloworld-sample。VS Code 使用 ID 来区分各个不同的插件。
  • main: 插件的主入口。
  • activationEventscontributes: 激活事件 和 发布内容配置。
  • engines.vscode: 描述了这个插件依赖的最低 VS Code API 版本。
1
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
{
"name": "helloworld-sample", // 插件名称
"displayName": "helloworld-sample", // 插件市场的名称,安装后显示的名称
"description": "HelloWorld example for VS Code", // 描述
"version": "0.0.1", // 版本号
"publisher": "vscode-samples", //发布者
"repository": "https://github.com/microsoft/vscode-extension-samples/helloworld-sample",
"engines": {
"vscode": "^1.51.0" // 扩展所依赖的 VS Code 的最低版本
},
"categories": [ // 分类,发布到市场后显示的类别
"Other"
],
"activationEvents": [ // 激活事件
"onCommand:helloworld.helloWorld"
],
"main": "./out/extension.js", //插件的主入口
"contributes": { //内容配置项
"commands": [{ // 命令,ctrl+shift+p激活的命令面板输入的命令
"command": "helloworld.helloWorld",
"title": "Hello World"
}]
},
"scripts": {
"vscode:prepublish": "npm run compile",
"compile": "tsc -p ./",
"watch": "tsc -watch -p ./"
},
"devDependencies": {
"@types/node": "^8.10.25",
"@types/vscode": "^1.51.0",
"tslint": "^5.16.0",
"typescript": "^3.4.5"
}
}

  • 插件入口文件

插件入口文件会导出两个函数,activatedeactivate

注册的激活事件被触发之时执行 activatedeactivate 则提供了插件关闭前执行清理工作的机会。

1
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

// 'vscode'模块包含了VS Code extensibility API
// 按下述方式导入这个模块
import * as vscode from 'vscode';

// 一旦你的插件激活,vscode会立刻调用下述方法
export function activate(context: vscode.ExtensionContext) {
// 用console输出诊断信息(console.log)和错误(console.error)
// 下面的代码只会在你的插件激活时执行一次
console.log('Congratulations, your extension "helloworld-sample" is now active!');

// 入口命令已经在package.json文件中定义好了,现在调用registerCommand方法
// registerCommand中的参数必须与package.json中的command保持一致
let disposable = vscode.commands.registerCommand('helloworld.helloWorld', () => {
// 把你的代码写在这里,每次命令执行时都会调用这里的代码
// ...
// 给用户显示一个消息提示
vscode.window.showInformationMessage('Hello World!');
});

context.subscriptions.push(disposable);
}

// 当你的插件停用时调用此方法
export function deactivate() {}

2. 插件功能

2.1 常用功能

  • 命令

命令是 VS Code 运作的核心。你可以打开命令面板执行,用快捷键执行,还可以在菜单中鼠标右键执行。

一个插件应该:

  • 使用 vscode.commands 注册和执行命令
  • 配置 contributes.commands,确保命令面板中可以顺利执行你注册的命令
  • 配置

插件需要在 contributes.configuration 发布内容配置点发布内容配置点package.json 的一部分,用于配置插件启动命令、用户可更改的插件配置,可以理解为插件的主要配置文件。中填写有关的配置,你可以 workspace.getConfigurationAPI 中阅读有关内容。

  • 键位绑定

插件可以添加自定义键位映射,在 contributes.keybindings键绑定主题中阅读更多内容

  • 菜单

插件可以自定义上下文菜单项,菜单会根据用户右击 VS Code UI 的不同位置而各不相同。查看更多 contributes.menus 发布内容配置。

  • 数据存储

VS Code 中有三种数据储存方式:

插件的执行上下文在 activate 函数中,详见插件入口文件

  • 显示通知

几乎所有的插件都需要在某些时候为用户提示信息。VS Code 提供了 3 个 API 来展示不同重要程度的信息:

使用vscode.Progress将处理进度报告给用户。

通过ProgressLocation选项,进度可以显示在不同的区域:

  • 显示在通知区
  • 显示在源控制视图
  • VS Code 窗口中的通用进度条位置

详见进度 示例

2.2 主题

VS Code 中的主题分为三类

  • 色彩主题:UI 组件 ID 和文本符号 ID 到色彩间的映射。通过色彩主题你可以修改 VS Code UI 组和编辑器中的文本。
  • 图标主题:文件类型/名称到图片之间的映射。文件图标显示于 VS Code 的资源管理侧边栏、快速打开列表和编辑器 Tab 等 UI 中。
  • 产品图标主题:重新定义工作台中使用的所有内置图标。例如,过滤器操作按钮和视图图标中的图标、状态栏中的图标、树和编辑器中的断点和折叠图标。

2.3 扩展工作台

工作台”是指整个 VS Code UI 和其中包含的下列 UI 组件:

  • 标题栏
  • 活动栏
  • 侧边栏
  • 面板
  • 编辑器群
  • 状态栏

VS Code 提供了各式各样的 API 让在工作台你添加自己的组件。比如下图:

image

  • 活动栏:Azure App Service extension添加了一个视图容器
  • 视图容器: 在 contributes.viewsContainers 发布内容配置中,你可以添加新的视图容器在 5 个内置的视图容器中。
  • 侧边栏:内置的NPM 插件 添加了一个 Tree View 到资源管理器视图
  • Tree View(视图容器): 在 contributes.views 发布内容配置中,你可以添加在任何视图容器岁添加新的视图。
  • 编辑器群:内置的Markdown 插件 添加了一个 Webview 到编辑器的旁边
  • Webview:Webview 是使用 HTML/CSS/JS 高度定制的视图。它们显示在编辑器区域中。详见 Webview 指南。
  • 状态栏:VSCodeVim 插件 添加了一个状态栏项目
  • 插件可以创建自定义的StatusBarItem显示在状态栏中。状态栏项可以显示文本和图标,还可以在点击事件触发时运行命令。

3. 插件流程

整个流程大概如下图

image

Activation Events(激活事件)

onLanguage

打开特定语言文件时激活事件激活事件用于激活插件的 VSCode 事件钩子。和相关插件

1
2
3
...
"activationEvents": ["onLanguage:python"]
...

onLanguage 事件需要指定特定的语言标识符

也可以添加多种语言:

1
"activationEvents": ["onLanguage:json","onLanguage:markdown","onLanguage:typescript"]

onCommand

调用命令时激活

1
2
3
...
"activationEvents": ["onCommand:extension.sayHello"]
...

onDebug

调试会话(debug session)启动前激活

1
2
3
...
"activationEvents": ["onDebug"]
...

onDebugInitialConfigurations

onDebugResolve

这是两个粒度更细的onDebug激活事件:

  • DebugConfigurationProvider中的provideDebugConfigurationsonDebugInitialConfigurations之后触发
  • onDebugResolve:type在DebugConfigurationProviderresolveDebugConfiguration方法之前触发.

友情提示: 如果调试插件比较轻量, 使用onDebug, 相反, 根据DebugConfigurationProvider实现的对应方法(provideDebugConfigurationsresolveDebugConfiguration),使用onDebugInitialConfigurationsonDebugResolve

workspaceContains

文件夹打开后,且文件夹中至少包含一个符合 glob 模式的文件时触发.

1
"activationEvents": ["workspaceContains:**/.editorconfig"]

onFileSystem

以协议(scheme)打开文件或文件夹时触发。通常是 file-协议,也可以用自定义的文件供应器函数替换掉,比如 ftpssh.

1
2
3
...
"activationEvents": ["onFileSystem:sftp"]
...

onView

指定 id 的视图展开时触发:

1
2
3
...
"activationEvents": ["onView:nodeDependencies"]
...

onUri

插件的系统级 URI 打开时触发。这个 URI 协议需要带上 vscode 或者 vscode-insiders 协议。URI 主机名必须是插件的唯一标识,剩余的 URI 是可选的。

1
2
3
...
"activationEvents": ["onUri"]
...

如果 vscode.git 插件定义了 onUri 激活事件,那么下列任意 URI 打开时就会触发:

  • vscode://vscode.git/init
  • vscode://vscode.git/clone?url=https%3A%2F%2Fgithub.com%2FMicrosoft%2Fvscode-vsce.git
  • vscode-insiders://vscode.git/init(for VS Code Insiders)

onWebviewPanel

VS Code 需要恢复匹配到 viewTypewebview 视图时触发.

下面是一个例子:

1
2
3
4
"activationEvents": [
"...",
"onWebviewPanel:catCoding"
]

这会导致插件被激活. 调用 window.createWebviewPanel 时可以设置 viewType, 你可能会需要其它的激活事件(比如: onCommand)来创建 webview 视图.

Start up

当 VS Code 启动时触发。为了保证良好的用户体验,只在你的插件没有其他任何激活事件激活事件用于激活插件的 VSCode 事件钩子的前提下,添加这个激活事件。

1
2
3
...
"activationEvents": ["*"]
...

注意: 一个插件如果侦听了多个激活事件, 那么最好用"\*"替换掉.
注意: 插件必须从它的主模块中输出一个 activate()函数,当任意的激活事件触发时,VS Code 会仅仅调用一次这个函数。此外,插件也应该 导出一个 deactivate()函数,当 VS Code 关闭时执行清理的任务。如果清理进程是异步的,插件的 deactivate()必须返回一个 Promise。如果这个清理任务是同步的,那么 deactivate()可以返回 undefined。

4. 实战 demo

image

x-color-picker

5. 打包发布

vsce

安装官方工具 vsce (Visual Studio Code Extensions)

npm install -g vsce

打包

vsce package

  • 打包后项目根目录下会生成一个 vsix 文件
  • 需要在 package.json 中输入对应的 publisher (发布者名字)以及 version(版本号)
  • README.md 文件的内容会显示在市场的插件介绍详情区域
  • CHANGELOG.md 文件对应的是插件的 version history ,历史记录中

发布

  1. 创建发布者: https://aka.ms/vscode-create-publisher

image

  1. 上传发布、更新、

image

image

参考资料

 评论