目录
插件在 VSCode 中能做什么
1、发布应用市场
1、申请Microsoft账号
2、创建Azure DevOps组织
3、创建令牌
4、创建发布账号
5、发布应用市场
2、本地打包不发布
1、本地打包
2、导入应用商店
编辑
3、插件开发前的环境准备
2、项目初始化
3、运行项目
4、文件介绍
1、package.json
1、main
2、activationEvents
3、contributes
2、extension.js
activate:这是插件被激活时执行的函数
deactivate:这是插件被销毁时调用的方法,比如释放内存等。
5、实战-小试牛刀
1、package.json
2、extension.ts文件
6、webview详解Webview API | Visual Studio Code Extension API
1、实现一个简单的webview功能
2、加载本地资源
1、线引入头文件
2、替换路径
3、执行函数
3、消息通信
1、实现消息发送:
2、简单通信封装
4、生命周期
5、实现webiew的状态保持
6、调试
7、菜单
1、菜单出现的位置
2、菜单出现的条件when
3、控制菜单的分组和排序group
1、editor/context中的默认组:
2、explorer/context中的默认组:
对于一个初学者来说,我们先了解下vscode的应用市场,做好开发前的准备工作
Visual Studio Code的应用市场基于微软自己的Azure DevOps
,插件的身份验证、托管和管理都是在这里。
publisher
账号;Azure DevOps
组织;Azure
账号;Azure
账号首先得有Microsoft
账号;我们来梳理下:
Azure
组织;publisher
账号;PAT
(Personal Access Token
,个人访问令牌);访问 Sign in to your Microsoft account 登录你的Microsoft
账号,没有的先注册一个
Azure DevOps
组织访问: https://aka.ms/SignupAzureDevOps
点击继续,默认会创建一个以邮箱前缀为名的组织。
进入组织的主页后,点击右上角的Security,
点击创建新的个人访问令牌,这里特别要注意Organization
要选择all accessible organizations
,Scopes
要选择Full access
,否则后面发布会失败。
创建令牌成功后你需要本地记下来,因为网站是不会帮你保存的,后面有可能会用到,如果没保存,后面需要用到的话,就只能重新创建令牌了
访问https://aka.ms/vscode-create-publisher
保存无反应,可以f12看下控制台报什么错误,如果是无法加载recaptcha,可以下载安装火狐浏览器,使用firefox浏览器下载插件gooreplacer – 下载 Firefox 扩展(zh-CN)
安装完成后就可在firefox浏览器右上角看到此插件
输入完成后点击Submit完成后,接下来再试试,之前无法加载的recaptcha应该就正常了 ;
这里需要注意,使用vsce命令创建会报错,只能使用上面的网页方式
具体步骤如下:
先全局安装vsce
npm i vsce -g
创建发布者:
vsce create-publisher fuyun
lzfuyun是发布者的名字,然后就会报如下错误,提示让走网页方式创建:
上面一切准备好后,package.json中添加刚刚创建的发布者,就可以发布了
对应项目目录终端输入命令
vsce publish
等个几分钟就可以看到发布的应用了
本地打包安装是在不能公开的,私密性比较高的应用,使用本地打包后,把包发给需要使用的人,手动导入安装到自己的vscode中;
打包之前需要在package.json中配置发布人: “publisher”:“fuyun”
注意:如果不需要发布应用市场的话,这里的publisher可以随便取个名字,也不需要想上面发布应用市场一样申请一堆东西的长流程。
然后把README.md删干净,随便添加一句话就行,如果不删除会报错提示你打包之前需要先编辑README.md文件
准备就绪,就可以打包了,终端执行命令:
vsce package
选择本地刚刚生成的vsix文件,就安装成功了
在前面我们已经准备好了发布的账号、Personal Access Token、以及创建发布者后,我们就可以开始准备我们的开发环境了
1、安装依赖
官方为了方便开发人员进行vscode插件的开发,提供了对yo应的脚手架来生成对应的项目。vscode 扩展开发官方文档
// 全局安装需要的包
npm install -g yo generator-code
在 mac 安装失败,报错没有权限 permission denied
字眼的时候,可以加 sudo
来授权
// 全局安装需要的包
sudo npm install -g yo generator-code
上述命令其实安装了两个包(yo
和 generator-code
),这两个包用途如下:
// 运行
yo code
JavaScript
)demo
demo
learn vscode plugin
Yes
Yes
Yes
在项目生成之后,目录结构如下所示
然后,在编辑器中,按F5
。这将在新的扩展开发主机窗口中编译和运行扩展。
在新窗口中从命令面板 ( shift + win + p )运行Hello World
命令:
您 vscode 界面会看到Hello World from HelloWorld!
显示的通知。成功!
注意:如果按键F5无法启动台调试,鼠标点击debug
该文件是vscode扩展的清单文件,里面有很多字段,官方 (opens new window)对每个字段都进行了详细阐述,本次我们重点阐述以下初始化后期清单文件。
{
"name": "demo", // 插件名
"displayName": "demo", // 显示在应用市场的名字
"description": "learn vscode plugin", // 具体描述
"version": "0.0.1", // 插件的版本号
"publisher": "lzfuyun", // 发布publisher账户名
"engines": {
"vscode": "^1.60.0" // 最低支持的vscode版本
},
"categories": [
"Other" // 扩展类别
],
// 激活事件组,在那些事件情况下被激活
"activationEvents": [
"onCommand:hello.helloWorld"
],
// 插件的主入口文件
"main": "./extension.js",
// 贡献点
"contributes": {
// 命令
"commands": [
{
"command": "hello.helloWorld",
"title": "Hello World"
}
]
},
"scripts": {
"lint": "eslint .",
"pretest": "npm run lint",
"test": "node ./test/runTest.js"
},
// 开发依赖项
"devDependencies": {
"@types/vscode": "^1.63.0",
"@types/glob": "^7.1.4",
"@types/mocha": "^9.0.0",
"@types/node": "14.x",
"eslint": "^8.1.0",
"glob": "^7.1.7",
"mocha": "^9.1.3",
"typescript": "^4.4.4",
"@vscode/test-electron": "^1.6.2"
}
}
{
// 插件的名字,应全部小写,不能有空格
"name": "vscode-plugin-demo",
// 插件的友好显示名称,用于显示在应用市场,支持中文
"displayName": "VSCode插件demo",
// 描述
"description": "VSCode插件demo集锦",
// 关键字,用于应用市场搜索
"keywords": ["vscode", "plugin", "demo"],
// 版本号
"version": "1.0.0",
// 发布者,如果要发布到应用市场的话,这个名字必须与发布者一致
"publisher": "sxei",
// 表示插件最低支持的vscode版本
"engines": {
"vscode": "^1.27.0"
},
// 插件应用市场分类,可选值: [Programming Languages, Snippets, Linters, Themes, Debuggers, Formatters, Keymaps, SCM Providers, Other, Extension Packs, Language Packs]
"categories": [
"Other"
],
// 插件图标,至少128x128像素
"icon": "images/icon.png",
// 扩展的激活事件数组,可以被哪些事件激活扩展,后文有详细介绍
"activationEvents": [
"onCommand:extension.sayHello"
],
// 插件的主入口
"main": "./src/extension",
// 贡献点,整个插件最重要最多的配置项
"contributes": {
// 插件配置项
"configuration": {
"type": "object",
// 配置项标题,会显示在vscode的设置页
"title": "vscode-plugin-demo",
"properties": {
// 这里我随便写了2个设置,配置你的昵称
"vscodePluginDemo.yourName": {
"type": "string",
"default": "guest",
"description": "你的名字"
},
// 是否在启动时显示提示
"vscodePluginDemo.showTip": {
"type": "boolean",
"default": true,
"description": "是否在每次启动时显示欢迎提示!"
}
}
},
// 命令
"commands": [
{
"command": "extension.sayHello",
"title": "Hello World"
}
],
// 快捷键绑定
"keybindings": [
{
"command": "extension.sayHello",
"key": "ctrl+f10",
"mac": "cmd+f10",
"when": "editorTextFocus"
}
],
// 菜单
"menus": {
// 编辑器右键菜单
"editor/context": [
{
// 表示只有编辑器具有焦点时才会在菜单中出现
"when": "editorFocus",
"command": "extension.sayHello",
// navigation是一个永远置顶的分组,后面的@6是人工进行组内排序
"group": "navigation@6"
},
{
"when": "editorFocus",
"command": "extension.demo.getCurrentFilePath",
"group": "navigation@5"
},
{
// 只有编辑器具有焦点,并且打开的是JS文件才会出现
"when": "editorFocus && resourceLangId == javascript",
"command": "extension.demo.testMenuShow",
"group": "z_commands"
},
{
"command": "extension.demo.openWebview",
"group": "navigation"
}
],
// 编辑器右上角图标,不配置图片就显示文字
"editor/title": [
{
"when": "editorFocus && resourceLangId == javascript",
"command": "extension.demo.testMenuShow",
"group": "navigation"
}
],
// 编辑器标题右键菜单
"editor/title/context": [
{
"when": "resourceLangId == javascript",
"command": "extension.demo.testMenuShow",
"group": "navigation"
}
],
// 资源管理器右键菜单
"explorer/context": [
{
"command": "extension.demo.getCurrentFilePath",
"group": "navigation"
},
{
"command": "extension.demo.openWebview",
"group": "navigation"
}
]
},
// 代码片段
"snippets": [
{
"language": "javascript",
"path": "./snippets/javascript.json"
},
{
"language": "html",
"path": "./snippets/html.json"
}
],
// 自定义新的activitybar图标,也就是左侧侧边栏大的图标
"viewsContainers": {
"activitybar": [
{
"id": "beautifulGirl",
"title": "美女",
"icon": "images/beautifulGirl.svg"
}
]
},
// 自定义侧边栏内view的实现
"views": {
// 和 viewsContainers 的id对应
"beautifulGirl": [
{
"id": "beautifulGirl1",
"name": "国内美女"
},
{
"id": "beautifulGirl2",
"name": "国外美女"
},
{
"id": "beautifulGirl3",
"name": "人妖"
}
]
},
// 图标主题
"iconThemes": [
{
"id": "testIconTheme",
"label": "测试图标主题",
"path": "./theme/icon-theme.json"
}
]
},
// 同 npm scripts
"scripts": {
"postinstall": "node ./node_modules/vscode/bin/install",
"test": "node ./node_modules/vscode/bin/test"
},
// 开发依赖
"devDependencies": {
"typescript": "^2.6.1",
"vscode": "^1.1.6",
"eslint": "^4.11.0",
"@types/node": "^7.0.43",
"@types/mocha": "^2.2.42"
},
// 后面这几个应该不用介绍了
"license": "SEE LICENSE IN LICENSE.txt",
"bugs": {
"url": "https://github.com/sxei/vscode-plugin-demo/issues"
},
"repository": {
"type": "git",
"url": "https://github.com/sxei/vscode-plugin-demo"
},
// 主页
"homepage": "https://github.com/sxei/vscode-plugin-demo/blob/master/README.md"
}
在这package.json
文件中,重点关注的主要有三部分内容:activationEvents
、main
以及contributes
,其是整个文件中的重中之重。
指明了该插件的主入口在哪,只有找到主入口整个项目才能正常的运转
指明该插件在何种情况下才会被激活,因为只有激活后插件才能被正常使用,官网已经指明了激活的时机 (opens new window),这样我们就可以按需设置对应时机。(具体每个时机用的时候详细查看即可)
通过扩展注册contributes用来扩展Visual Studio Code中的各项技能,其有多个配置,如下所示:
该文件时其入口文件,即 package.json
中 main
字段对应的文件(不一定叫extension.js这个名字),该文件中将导出两个方法:activate
和deactivate
,两个方法的执行时机如下所示:
需求:实现简单的选中大小写转换(document-editing)
{
"name": "demo",
"displayName": "demo",
"description": "demo",
"version": "0.0.1",
"engines": {
"vscode": "^1.69.0"
},
"categories": [
"Other"
],
"activationEvents": [
"*"
],
"main": "./extension",
"contributes": {
"commands": [
{
"command": "extension.toLowerCase",
"title": "Lower"
},
{
"command": "extension.toUpperCase",
"title": "Upper"
}
]
},
"scripts": {
"vscode:prepublish": "npm run compile",
"compile": "tsc -p ./",
"lint": "eslint . --ext .ts,.tsx",
"watch": "tsc -watch -p ./"
},
"devDependencies": {
"@types/glob": "^7.2.0",
"@types/mocha": "^9.1.1",
"@types/node": "16.x",
"@types/vscode": "^1.69.0",
"@vscode/test-electron": "^2.1.5",
"eslint": "^8.18.0",
"glob": "^8.0.3",
"mocha": "^10.0.0",
"typescript": "^4.7.4"
}
}
配置两个命令一个转大些,一个转小写,如果有多个事件组,activationEvents就可以用✳️代替
"activationEvents": [
"*"
],
/*
* @Descripttion: automobile
* @version: 1.0
* @Author: 刘钊
* @Date: 2022-07-23 10:51:31
*/
const vscode = require('vscode');
/**
* @param {vscode.ExtensionContext} context
*/
function activate(context) {
let lowerCase = vscode.commands.registerCommand('extension.toLowerCase',toLowerCase);
let upperCase = vscode.commands.registerCommand('extension.toUpperCase',toUpperCase);
context.subscriptions.push(lowerCase);
context.subscriptions.push(upperCase);
}
function toLowerCase() {
toLowerCaseOrUpperCase('toLowerCase');
}
function toUpperCase() {
toLowerCaseOrUpperCase('toUpperCase');
}
//转小写
function toLowerCaseOrUpperCase(command) {
//获取activeTextEditor
const editor = vscode.window.activeTextEditor;
if (editor) {
const document = editor.document;
const selection = editor.selection;
//获取选中单词文本
const word = document.getText(selection);
//文本转大小写
const newWord = command == 'toLowerCase' ? word.toLowerCase() : word.toUpperCase();
//替换原来文本
editor.edit((editBuilder) => {
editBuilder.replace(selection, newWord);
});
}
}
// this method is called when your extension is deactivated
function deactivate() {}
module.exports = {
activate,
deactivate,
};
我们运行看看效果
整个VSCode编辑器就是一张大的网页,其实,我们还可以在Visual Studio Code
中创建完全自定义的、可以间接和nodejs
通信的特殊网页(通过一个acquireVsCodeApi
特殊方法),这个网页就叫WebView
。内置的Markdown
的预览就是使用WebView
实现的。使用Webview
可以构建复杂的、支持本地文件操作的用户界面。
VSCode插件的WebView类似于iframe的实现,但并不是真正的iframe(我猜底层应该还是基于iframe实现的,只不过上层包装了一层),通过开发者工具可以看到:
const vscode = require('vscode');
/**
* @param {vscode.ExtensionContext} context
*/
function activate(context) {
let disposable = vscode.commands.registerCommand(
'demo1.webview',
showWebview
);
context.subscriptions.push(disposable);
}
function showWebview() {
// 创建webview
const panel = vscode.window.createWebviewPanel(
'testWebview', // viewType
'WebView演示', // 视图标题
vscode.ViewColumn.One, // 显示在编辑器的哪个部位
{
enableScripts: true, // 启用JS,默认禁用
retainContextWhenHidden: true, // webview被隐藏时保持状态,避免被重置
}
);
panel.webview.html = `你好,我是Webview`;
}
function deactivate() {}
module.exports = {
activate,
deactivate,
};
可以看到创建一个panel,然后直接写html就可以了,是不是很简单,package.json配置好后,看看运行效果
JavaScript
,但可以通过传入enableScripts: true
选项轻松启用;retainContextWhenHidden: true
会一直保存,但会占用较大内存开销,仅在需要时开启;出于安全考虑,Webview默认无法直接访问本地资源,它在一个孤立的上下文中运行,想要加载本地图片、js、css等必须通过特殊的vscode-resource:
协议,网页里面所有的静态资源都要转换成这种格式,否则无法被正常加载。
vscode-resource:
协议类似于file:
协议,但它只允许访问特定的本地文件。和file:
一样,vscode-resource:
从磁盘加载绝对路径的资源
默认情况下,vscode-resource:
只能访问以下位置中的资源:
dataURI
直接在Webview中嵌入资源,这种方式没有限制;因此我们先抽个加载资源的函数:
import { posix } from 'path';
const fs = require('fs');
/**
* 从某个HTML文件读取能被Webview加载的HTML内容
* @param {*} context 上下文
* @param {*} templatePath 相对于插件根目录的html文件相对路径
*/
function getWebViewContent(context, templatePath) {
const resourcePath = posix.join(context.extensionPath, templatePath);
const dirPath = posix.dirname(resourcePath);
let html = fs.readFileSync(resourcePath, 'utf-8');
// vscode不支持直接加载本地资源,需要替换成其专有路径格式,这里只是简单的将样式和JS的路径替换
html = html.replace(/( {
return $1 + vscode.Uri.file(posix.resolve(dirPath, $2)).with({ scheme: 'vscode-resource' }).toString() + '"';
});
return html;
}
运行这段代码之后,会自动将HTML文件中link
、href
、script
、img
的资源相对路径全部替换成正确的vscode-resource:
绝对路径,例如:
./src/view/index.html
变成
vscode-resource:/Users/liuzhao/Documents/liuzhao/01_learn/15_vscode插件开发/demo1/src/view/index.html
panel.webview.html = getWebViewContent(context, 'src/view/index.html');
/*
* @Descripttion: automobile
* @version: 1.0
* @Author: 刘钊
* @Date: 2022-07-21 19:22:34
*/
/*
* @Descripttion: automobile
* @version: 1.0
* @Author: 刘钊
* @Date: 2022-07-21 19:22:34
*/
const vscode = require('vscode');
const { posix } = require('path');
// import { posix } from 'path';
const fs = require('fs');
/**
* @param {vscode.ExtensionContext} context
*/
function activate(context) {
let disposable = vscode.commands.registerCommand('demo1.webview', () => {
// 创建webview
const panel = vscode.window.createWebviewPanel(
'testWebview', // viewType
'WebView演示', // 视图标题
vscode.ViewColumn.One, // 显示在编辑器的哪个部位
{
enableScripts: true, // 启用JS,默认禁用
retainContextWhenHidden: true, // webview被隐藏时保持状态,避免被重置
}
);
// panel.webview.html = `你好,我是Webview`;
panel.webview.html = getWebViewContent(context, 'src/view/index.html');
});
context.subscriptions.push(disposable);
}
function deactivate() {}
/**
* 从某个HTML文件读取能被Webview加载的HTML内容
* @param {*} context 上下文
* @param {*} templatePath 相对于插件根目录的html文件相对路径
*/
function getWebViewContent(context, templatePath) {
const resourcePath = posix.join(context.extensionPath, templatePath);
const dirPath = posix.dirname(resourcePath);
let html = fs.readFileSync(resourcePath, 'utf-8');
// vscode不支持直接加载本地资源,需要替换成其专有路径格式,这里只是简单的将样式和JS的路径替换
html = html.replace(
/( {
return (
$1 +
vscode.Uri.file(posix.resolve(dirPath, $2))
.with({ scheme: 'vscode-resource' })
.toString() +
'"'
);
}
);
return html;
}
module.exports = {
activate,
deactivate,
};
webview
内部不允许发送ajax请求,所有ajax
请求都是跨域的,因为webview
本身是没有host
的
而VSCode
并不会让我们接触electron
配置,所以通过简单的electron
配置webSecurity: false
就可以开放跨域权限是行不通的,那么该如何实现网络请求呢?
webview
和普通网页一样,并不能直接调用任何VSCode API
。但是,它唯一特别之处就在于多了一个名叫acquireVsCodeApi
的方法,执行这个方法会返回一个简易版的vscode
对象,具有如下三个方法:
这样的话,我们可以发消息让extension
去帮我们发送http
请求!
// 插件给Webview发送消息(支持发送任意可以被JSON化的数据)
panel.webview.postMessage(message);
// webview接收消息
window.addEventListener('message', event => {
const message = event.data;
console.log('Webview接收到的消息:', message);
};
// Webview主动发送消息给插件
const vscode = acquireVsCodeApi();
vscode.postMessage(message);
// 插件端接收消息
panel.webview.onDidReceiveMessage(message => {
console.log('插件收到的消息:', message);
}, undefined, context.subscriptions);
Webview端:
const callbacks = {}; // 存放所有的回调函数
/**
* 调用vscode原生api
* @param data 可以是类似 {cmd: 'xxx', param1: 'xxx'},也可以直接是 cmd 字符串
* @param cb 可选的回调函数
*/
function callVscode(data, cb) {
if (typeof data === 'string') {
data = { cmd: data };
}
if (cb) {
// 时间戳加上5位随机数
const cbid = Date.now() + '' + Math.round(Math.random() * 100000);
// 将回调函数分配一个随机cbid然后存起来,后续需要执行的时候再捞起来
callbacks[cbid] = cb;
data.cbid = cbid;
}
vscode.postMessage(data);
}
window.addEventListener('message', event => {
const message = event.data;
switch (message.cmd) {
// 来自vscode的回调
case 'vscodeCallback':
console.log(message.data);
(callbacks[message.cbid] || function () { })(message.data);
delete callbacks[message.cbid]; // 执行完回调删除
break;
default: break;
}
});
插件端:
let global = { projectPath, panel};
panel.webview.onDidReceiveMessage(message => {
if (messageHandler[message.cmd]) {
// cmd表示要执行的方法名称
messageHandler[message.cmd](global, message);
} else {
util.showError(`未找到名为 ${message.cmd} 的方法!`);
}
}, undefined, context.subscriptions);
/**
* 存放所有消息回调函数,根据 message.cmd 来决定调用哪个方法,
* 想调用什么方法,就在这里写一个和cmd同名的方法实现即可
*/
const messageHandler = {
// 弹出提示
alert(global, message) {
util.showInfo(message.info);
},
// 显示错误提示
error(global, message) {
util.showError(message.info);
},
// 回调示例:获取工程名
getProjectName(global, message) {
invokeCallback(global.panel, message, util.getProjectName(global.projectPath));
}
}
/**
* 执行回调函数
* @param {*} panel
* @param {*} message
* @param {*} resp
*/
function invokeCallback(panel, message, resp) {
console.log('回调消息:', resp);
// 错误码在400-600之间的,默认弹出错误提示
if (typeof resp == 'object' && resp.code && resp.code >= 400 && resp.code < 600) {
util.showError(resp.message || '发生未知错误!');
}
panel.webview.postMessage({cmd: 'vscodeCallback', cbid: message.cbid, data: resp});
}
webview
由创建它的扩展程序所有,返回的panel
对象你必须自己保存,如果你的扩展程序丢失了这个引用,那么将无法再次重新访问该webview
,即使Web视图继续显示在vscode
中。
用户也可以随时关闭webview
面板。当用户关闭webview面板时,webview本身将被销毁,此时不能再使用panel引用,否则将会出现异常,可以通过监听onDidDispose
事件在这里面做一些销毁操作。
可以通过panel.dispose()
方法主动关闭webview。
当webview移动到后台又再次显示时,webview中的任何状态都将丢失。
解决此问题的最佳方法是使你的webview无状态,通过消息传递来保存webview的状态。
1、在webview的js中我们可以使用vscode.getState()
和vscode.setState()
方法来保存和恢复JSON可序列化状态对象。当webview被隐藏时,即使webview内容本身被破坏,这些状态仍然会保存。当然了,当webview被销毁时,状态将被销毁。
2、通过注册WebviewPanelSerializer
可以实现在VScode
重启后自动恢复你的webview
,当然,序列化其实也是建立在getState
和setState
之上的。
注册方法:vscode.window.registerWebviewPanelSerializer
3、对于具有非常复杂的UI或状态且无法快速保存和恢复的webview
,我们可以直接使用retainContextWhenHidden
选项。设置retainContextWhenHidden: true
后即使webview被隐藏到后台其状态也不会丢失。
尽管retainContextWhenHidden
很有吸引力,但它需要很高的内存开销,一般建议在实在没办法的时候才启用。getState
和setState
是持久化的首选方式,因为它们的性能开销要比retainContextWhenHidden
低得多。
按下Ctrl+Shift+P
然后执行打开Webview开发工具
,英文版应该是Open Webview Developer Tools:
菜单配置是在 package.json
的 contributes
中添加:
"menus": {
"editor/title": [{
"when": "editorFocus",
"command": "plugin-demo.helloWorld",
"alt": "",
"group": "navigation"
}]
}
以上是一个菜单项的完整配置.
editor/title:
定义这个菜单出现在哪里,这里是定义出现在编辑标题菜单栏。when:
菜单在什么时候出现,这里是有光标的时候出现command:
点击这个菜单要执行的命令alt:
按住alt
再选择菜单时应该执行的命令group:
定义菜单分组
多个条件可以通过与或非进行组合,例如:editorFocus && isWindows && resourceLangId == javascript
不同的菜单拥有不同的默认分组
快捷键的设置比较简单,其执行功能同样依赖于其关联的命令command
。
"keybindings": [
{
"command": "plugin-demo.helloWorld",
"key": "ctrl+h",
"mac": "cmd+h",
"when": "editorTextFocus"
}
]
command:
快捷键关联的命令key:
Windows平台对应的快捷键mac:
mac平台对应的快捷键when:
什么时候快捷键有效当插件被激活后,并且满足快捷键有效的时间,按快捷键就可以找到extension.js
中与快捷键关联的command
所不绑定的事件并执行。