vscode插件快餐教程(1) - 从写命令开始
大致从2017年开始,vscode就越来越流行。vscode能够流行起来,除了功能强大、微软不断升级给力之外,优秀的插件机制也是非常重要的一环。vscode中相当多的功能也是通过自身的插件机制实现的。
比起使用coffeescript为主要开发语言的atom IDE,vscode使用越来越有王者气质的typescript做为主要的开发语言,这也为vscode插件开发提供了良好的助力。
随着插件机制的不断完善,文档、示例与脚手架工具等也日渐成熟。相关的文章与教程也非常丰富,现在写vscode的plugin已经是件比较容易的事情了。
自己的业务开发,只有自己最了解,作为程序员,写自己的plugin来加速自己的开发效率,现在正是好时机。
vscode的plugin种类非常丰富,我们先从最传统的定义新命令说起吧。
使用脚手架生成骨架
与其他主流前端工程一样,我们通过脚手架来生成插件的骨架。微软提供了基于脚手架生成工具yeoman的脚本。
我们通过npm来安装vscode plugin脚手架:
npm install -g yo generator-code
然后我们就可以通过yo code命令来生成vscode plugin骨架代码了。
yo code
脚手架会提示选择生成的plugin的类型:
_-----_ ╭──────────────────────────╮
| | │ Welcome to the Visual │
|--(o)--| │ Studio Code Extension │
`---------´ │ generator! │
( _´U`_ ) ╰──────────────────────────╯
/___A___\ /
| ~ |
__'.___.'__
´ ` |° ´ Y `
? What type of extension do you want to create? (Use arrow keys)
New Extension (TypeScript)
New Extension (JavaScript)
New Color Theme
New Language Support
New Code Snippets
New Keymap
New Extension Pack
我们就选择New Extension (Typescript)。关于其他选择我们后面的文章会继续介绍。
我们从最简单的移动光标开始做起吧。比如写一个将光标移动到编辑区首,比如一篇文章或代码的首部,用emacs的命令叫做move-beginning-of-buffer。
光标移动命令实践
同是编辑器,都有相似的功能。这种移动到文章首的功能,肯定不用我们自己开发,vscode早就为我们做好了。在vscode中定义了一大堆光标控制的命令,比如这条就叫做cursorTop。
- cursorTop: 移动到文章首
- cursorBottom: 移动到文章尾
- cursorRight: 光标向右移,相当于emacs的forward-char
- cursorLeft: 光标左移,相当于emacs的backward-char
- cursorDown: 向下移一行,相当于emacs的next-line
- cursorUp: 向上移一行,相当于emacs的previous-line
- cursorLineStart: 移至行首,相当于emacs的move-beginning-of-line
- cursorLineEnd: 移至行尾,相当于emacs的move-end-of-line
我们新建一个move.ts,用于实现光标移动的功能。我们先以移动到文章首为例。我们通过vscode.commands.executeCommand函数来执行命令。
例:
import * as vscode from 'vscode';
export function moveBeginningOfBuffer(): void {
vscode.commands.executeCommand('cursorTop');
}
在主文件extension.ts中,我们先把move.ts这个包引入进来:
import * as move from './move';
然后在activate函数中,注册这个命令:
let disposable_begin_buffer = vscode.commands.registerCommand('extension.littleemacs.moveBeginningOfBuffer',
move.moveBeginningOfBuffer);
context.subscriptions.push(disposable_begin_buffer);
最后我们在package.json中给其绑定一个快捷键。'<'和'>'在键盘中是上排键,我们就不用它们了,比如绑定到alt-[上。
修改contributes部分如下:
"contributes": {
"commands": [{
"command": "extension.littleemacs.moveBeginningOfBuffer",
"title": "move-beginning-of-buffer"
}],
"keybindings": [{
"command": "extension.littleemacs.moveBeginningOfBuffer",
"key": "alt+["
}]
}
大功告成。我们用F5来启动调试,就会启动一个新的vscode界面。
我们在新开的vscode界面,打开命令窗口(F1或shift-cmd-p),输入move-beginning-of-buffer就可以看到这个命令了:
我们可以移到文件中间的位置,按alt+[就会回到文件头。
目前完整的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';
import * as move from './move';
// 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 "littleemacs" 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_begin_buffer = vscode.commands.registerCommand('extension.littleemacs.moveBeginningOfBuffer',
move.moveBeginningOfBuffer);
context.subscriptions.push(disposable_begin_buffer);
}
// this method is called when your extension is deactivated
export function deactivate() {
console.log('Plugin deactivated');
}
对应的完整package.json为:
{
"name": "littleemacs",
"displayName": "littleemacs",
"description": "Some operations just like emacs",
"version": "0.0.1",
"engines": {
"vscode": "^1.33.0"
},
"categories": [
"Other"
],
"activationEvents": [
"onCommand:extension.littleemacs.moveBeginningOfBuffer"
],
"main": "./out/extension.js",
"contributes": {
"commands": [{
"command": "extension.littleemacs.moveBeginningOfBuffer",
"title": "move-beginning-of-buffer"
}],
"keybindings": [{
"command": "extension.littleemacs.moveBeginningOfBuffer",
"key": "alt+["
}]
},
"scripts": {
"vscode:prepublish": "yarn run compile",
"compile": "tsc -p ./",
"watch": "tsc -watch -p ./",
"postinstall": "node ./node_modules/vscode/bin/install",
"test": "yarn run compile && node ./node_modules/vscode/bin/test"
},
"devDependencies": {
"typescript": "^3.3.1",
"vscode": "^1.1.28",
"tslint": "^5.12.1",
"@types/node": "^10.12.21",
"@types/mocha": "^2.2.42"
}
}
一个插件实现多条命令
一个不够,我们再写一个:
activate函数:
let disposable_begin_buffer = vscode.commands.registerCommand('extension.littleemacs.beginningOfBuffer',
move.beginningOfBuffer);
let disposable_end_buffer = vscode.commands.registerCommand('extension.littleemacs.endOfBuffer',
move.endOfBuffer);
context.subscriptions.push(disposable_begin_buffer);
context.subscriptions.push(disposable_end_buffer);
功能实现函数:
import * as vscode from 'vscode';
export function beginningOfBuffer(): void {
vscode.commands.executeCommand('cursorTop');
}
export function endOfBuffer() {
vscode.commands.executeCommand('cursorBottom');
}
package.json:
"activationEvents": [
"onCommand:extension.littleemacs.beginningOfBuffer",
"onCommand:extension.littleemacs.endOfBuffer"
],
"main": "./out/extension.js",
"contributes": {
"commands": [{
"command": "extension.littleemacs.beginningOfBuffer",
"title": "beginning-of-buffer"
},
{
"command": "extension.littleemacs.endOfBuffer",
"title": "end-of-buffer"
}
],
"keybindings": [{
"command": "extension.littleemacs.beginningOfBuffer",
"key": "alt+["
},
{
"command": "extension.littleemacs.endOfBuffer",
"key": "alt+]"
}
]
},