简介
简单的记录,详情参考 VSCode 官方文档
QuickStart
安装 nodejs & git ,详略;
安装 Yeoman (一个代码模版生成工具) 以及 vscode 插件的代码生成模版 generator-code
npm install -g yo generator-code
在需要的目录下生成代码模版:
yo code
运行后会有交互命令进行初始化:
生成后用 vscode 打开生成的工程,模版工程是一个 helloworld,F5 运行后,输入命令 helloworld 即可看到效果:
插件解析
目录结构
.
├── .vscode
│ ├── launch.json // Config for launching and debugging the extension
│ └── tasks.json // Config for build task that compiles TypeScript
├── .gitignore // Ignore build output and node_modules
├── README.md // Readable description of your extension's functionality
├── src
│ └── extension.ts // Extension source code
├── package.json // Extension manifest
├── tsconfig.json // TypeScript configuration
package.json 文件
package.json 文件即插件的描述文件,其中配置了插件的基本信息、依赖等各种数据,全部的配置可以参考 Extension-Manifest。
下面给出一个 package.json 文件的示例:
{
"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.34.0"
},
"categories": ["Other"],
"activationEvents": ["onCommand:extension.helloWorld"],
"main": "./out/extension.js",
"contributes": {
"commands": [
{
"command": "extension.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.34.0",
"tslint": "^5.16.0",
"typescript": "^3.4.5"
}
}
配置文件包含 Node.js 的配置(比如 scripts
、devDependencies
等)以及 VSCode 的配置,下面列举一些关键性的配置:
name
和publisher
:VSCode 使用<publisher>.<name>
来作为插件的唯一 ID,用于标识插件main
:插件的入口activationEvents
:插件的激活事件,例如 onLanguage(在当前文件为对应 language 时激活),onCommand(运行对应 command 时激活),所有支持的配置可参考 Activation Eventscontributes
:用于注册插件的功能,比如 command、keybindings、configuration 等等,所有的配置可参考 Contribution Points
插件入口文件
即 package.json 中的 main 配置,默认情况下即 extension.js 文件:
// The module 'vscode' contains the VS Code extensibility API
// Import the module and reference it with the alias vscode in your code below
import * as vscode from 'vscode';
// this method is called when your extension is activated
// your extension is activated the very first time the command is executed
export function activate(context: vscode.ExtensionContext) {
// Use the console to output diagnostic information (console.log) and errors (console.error)
// This line of code will only be executed once when your extension is activated
console.log('Congratulations, your extension "helloworld-sample" is now active!');
// The command has been defined in the package.json file
// Now provide the implementation of the command with registerCommand
// The commandId parameter must match the command field in package.json
let disposable = vscode.commands.registerCommand('extension.helloWorld', () => {
// The code you place here will be executed every time your command is executed
// Display a message box to the user
vscode.window.showInformationMessage('Hello World!');
});
context.subscriptions.push(disposable);
}
// this method is called when your extension is deactivated
export function deactivate() {}
模版 extension.json 文件中,实现了两个接口:
activate
:定义于 package.json 文件中的 activationEvents,在激活插件时会调用此接口deactivate
:用于在插件关闭时清理相关数据
写一个 naive 插件
接下来以一个简单的插件示例,记录插件开发的流程;准备实现的插件名为 QuickCommand,目标功能为:
- 能够通过快捷的方式执行特定命令
- 可执行的命令能够进行配置
实现逻辑:
- 读取配置好的命令
- 激活插件时,通过 QuickPick 显示所有的配置命令
- 选择对应的命令执行
具体代码见 Github Repo QuickCommand。下面简列一些关键的实现:
执行命令的功能
// 创建 terminal 并执行 ‘echo’ 命令
let term = vscode.window.createTerminal({ name: 'QuickCommand' });
term.show();
term.sendText("echo hello");
配置的实现
package.json 文件中,contributes 字段定义插件的配置如下:
"contributes": {
// 激活插件的命令
"commands": [
{
"command": "extension.quickcommand",
"title": "Quick Command",
"category": "Quick Command"
}
],
// 插件的配置定义
"configuration": {
"type": "object",
"title": "configuration for QuickCommand",
"properties": {
"quickcommand.commands": {
"type": [
"array",
"null"
],
"items": {
"type": "object",
"properties": {
"label": {
"type": "string",
"description": "name of current cfg"
},
"description": {
"type": "string"
},
"command": {
"type": "string",
"description": "command to run, such as 'ehco hello'"
}
}
},
// 插件的默认配置
"default": [
{
"label": "Hello",
"description": "echo hello",
"command": "echo hello"
}
],
"description": "Quick run commands"
}
}
}
}
配置选择列表
let selectItem: vscode.QuickPickItem | null = null;
let quickPick = vscode.window.createQuickPick();
quickPick.title = "Quick Pick List";
quickPick.items = [ // 选项列表
{ label: "AAA", description: "aaa" },
{ label: "BBB", description: "bbb" },
{ label: "CCC", description: "ccc" },
];
quickPick.onDidHide(() => quickPick.dispose());
quickPick.onDidChangeActive((items) => {
if (items[0]) {
selectItem = items[0];
}
});
quickPick.onDidAccept(() => {
if (selectItem) {
vscode.window.showInformationMessage("Select: " + selectItem.label);
}
quickPick.hide();
selectItem = null;
});
quickPick.show();
实现效果
发布插件
本地使用
发布插件有多种形式,如果只是自己使用,可以直接将插件项目的文件拷贝到 ~/.vscode/extensions/
目录下,重启 VSCode 即可,对应平台的目录为:
- Windows %USERPROFILE%.vscode\extensions
- macOS ~/.vscode/extensions
- Linux ~/.vscode/extensions
打包 vsix
如果需要共享给其他人使用,需要对插件进行打包,首先安装 vsce(Visual Studio Code Extensions):
npm install -g vsce
在 package.json 文件中配置 publisher:
{
"publisher": "someone",
}
进入插件目录:
cd myExtension
vsce package
# myExtension.vsix generated
vsce publish
# .myExtension published to VS Code MarketPlace
成功后会在目录下生成类似 extension-0.0.1.vsix 的文件,如果生成失败,按照提示信息完善配置即可(比如配置 publisher 信息、安装依赖等等)。
vsix 文件可以使用以下命令进行安装:
code --install-extension extension-0.0.1.vsix
也可以直接在 VSCode 中,执行 Extensions: Install from VSIX 命令,选择 vsix 文件打开进行安装。
发布到网络
获取 Personal access tokens:
注册 Azure 开发者账号 https://dev.azure.com/,并选择 Personal access tokens:
创建新的 token 并复制:
登录 publisher:
使用 vsce 创建并登录 publisher:
vsce create-publisher (publisher name)
vsce login (publisher name)
设置 token:
vsce publish -p
发布插件:
发布:
vsce publish 2.0.1
取消发布:
vsce unpublish (publisher name).(extension name)
总结
我果然是太年轻了,原本只是想着提升一下平常的开发效率开始研究 VSCode 插件的开发,也没准备做深入的研究,只想着快速撸一波能用就行;
结果开工之后发现里面坑还是挺大的,至今有许多坑点没有搞懂和填上,此文仅作为参考,如果自己将来还需要做插件开发,以便快速上手;存在的坑就将来慢慢填吧(并不