这是VS Code官方文档的第二章节,主要内容是通过创建一个
Hello World插件来作为插件编写入门
Hello World
建立框架
进行VS Code插件开发的前提是安装了Node.js和Git,并且需要安装Yeoman和VS Code Extension Generator来生成插件框架
npm install -g yo generator-code
然后可以通过执行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
该框架具备基本的功能,我们用VS Code刚刚创建的项目,按下F5键(此时不要打开任何文件),会自动开启一个新的VS Code界面,在这个界面中我们按下Ctrl+Shift+P组合键唤醒Command Palette,然后输入Hello Word命令:
之后我们会在页面的右下角见到Hello World from HelloWord!提示:
修改源码
我们可以试着尝试修改下上述的框架里的代码
定位到src/extension.ts:
// 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 "helloword" 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('helloword.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 from HelloWord!');
});
context.subscriptions.push(disposable);
}
// this method is called when your extension is deactivated
export function deactivate() {}
我们可以将vscode.window.showInformationMessage('Hello World from HelloWord!');做修改,改为vscode.window.showInformationMessage('这是第一个插件!');,保存修改后,在调试窗口里执行Developer: Reload Window命令:
再次执行Hello World命令,可以看到提示信息发生了变化:
除此之外,我们还可以通过修改package.json的contributes字段信息,来修改命令的名称,如:
"contributes": {
"commands": [{
"command": "helloword.helloWorld",
+ "title": "Clock"
}]
},
将命令名称改为Clock,则执行命令时会看到Command Palette里的名称已经发生改变
可以尝试一个练习,修改提示的内容,比如显示当前时间。还可以通过查阅vscode-api试着用一些新的api,看看执行效果。例如我在这里就试着运行了一下vscode.window.showErrorMessage接口,这种尝试很有趣
调试
我们可以在源码上直接打断点,运行的时候会自动停止,而且我们可以将鼠标放在变量上,看到变量的具体取值。如果有过浏览器调试经验的话,应该不会感到困难
Hello World 进阶
我们在此继续对上面的hello world示例作进一步的分析
功能实现原理
细看起来上面的Hello World插件干了三件事:
-
在
package.json中注册onCommand活动事件(Activation Event),以便当用户运行Hello World命令时唤醒(activated)插件"activationEvents": [ "onCommand:helloword.helloWorld" ] -
在
package.json中注册contributes.commands(Contribution Point),以便可以在Command Palette中使用"contributes": { "commands": [{ "command": "helloword.helloWorld", "title": "Clock" }] } -
在
extension.ts中用commands.registerCommand(VS Code API)给Hello World命令绑定一个具体的函数let disposable = vscode.commands.registerCommand('helloword.helloWorld', () => { // The code you place here will be executed every time your command is executed // Display a message box to the user vscode.window.showErrorMessage(new Date().toLocaleString()); });
通过上述分析可知,通常一个插件就是Contribution Points、VS Code API的组合。官方的Extensions Capabilities Overview文档可以帮助你寻找到适合你自己插件的Contribution Points和VS Code API
项目结构
Hello World插件是以如下结构组织起来的:
.
├── .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、extension.ts,这里是理解Hello World插件的关键
插件清单(Extension Manifest)
每个VS Code插件都必须有一个package.json作为它的 Extension Manifest,这个package.json文件除了包含常见的Node.js用到的scripts、devDependencies等字段外,还有VS Code插件所特有的contributes、publisher、activationEvents等字段。你可以在官方的 Extension Manifest 文档中找到所有的VS Code插件字段。
对于Hello World插件来说,package.json文件内容是这样的:
{
"name": "helloword",
"displayName": "HelloWord",
"description": "",
"version": "0.0.1",
"publisher": "vscode-lamengduo-samples",
"engines": {
"vscode": "^1.56.0"
},
"categories": [
"Other"
],
"activationEvents": [
"onCommand:helloword.helloWorld"
],
"main": "./dist/extension.js",
"contributes": {
"commands": [{
"command": "helloword.helloWorld",
"title": "Clock"
}]
},
"scripts": {
"vscode:prepublish": "yarn run package",
"compile": "webpack",
"watch": "webpack --watch",
"package": "webpack --mode production --devtool hidden-source-map",
"test-compile": "tsc -p ./",
"test-watch": "tsc -watch -p ./",
"pretest": "yarn run test-compile && yarn run lint",
"lint": "eslint src --ext ts",
"test": "node ./out/test/runTest.js"
},
"devDependencies": {
"@types/vscode": "^1.56.0",
"@types/glob": "^7.1.3",
"@types/mocha": "^8.0.4",
"@types/node": "14.x",
"eslint": "^7.19.0",
"@typescript-eslint/eslint-plugin": "^4.14.1",
"@typescript-eslint/parser": "^4.14.1",
"glob": "^7.1.6",
"mocha": "^8.2.1",
"typescript": "^4.1.3",
"vscode-test": "^1.5.0",
"ts-loader": "^8.0.14",
"webpack": "^5.19.0",
"webpack-cli": "^4.4.0"
}
}
这些字段中有几个比较重要,这里单独说一说:
name、publisher:VS Code会把<publisher>.<name>作为插件的唯一ID,例如这个插件的ID就是vscode-lamengduo-samples.hellowordmain:指明了插件的入口activationEvents、contributes:对应 Activation Events 和 Contribution Pointsengines.vscode:标记当前插件需要的VS Code最低版本
入口文件
每个VS Code插件都有一个入口文件(由package.json中的main字段指定),VS Code规范要求插件的入口文件需要导出两个函数activate、deactivate。当开发者注册的Activation Event被触发时,将会执行activate函数。deactivate函数则主要是给插件开发者一个在插件停止工作之前一个执行清理的机会。对很多应用来说,deactivate其实不是必须的,可以删掉。不过如果你希望当VS Code关闭、插件不可用、插件卸载时做点什么的话,这个方法就有用了。
VS Code的插件API在 @types/vscode 包中做了类型声明,这个文件将会根据package.json文件中的engines.vscode提供智能提示等服务(如果插件框架是通过yo命令生成的,则@types/vscode会默认安装好)