本來連接:https://hellogithub2014.github.io/2019/06/09/vscode-plugin-development/javascript
以前一直覺得開發VS code插件是一件很難的事情,後來工做上須要搞一個效率小工具,就試着找了些資料來入門,發現其實就入門和開發一些簡單功能的插件來講難度仍是很低的。由於vscode自己是基於electron開發的,因此整體來講開發插件就是在寫node代碼,額外再加一些編輯器api,插件發佈的過程和npm包的發佈很相似。html
vscode官方提供的腳手架還幫忙加上了調試配置,調試很是方便。下面就來講下具體步驟,在學習的過程當中參考了一些博客,放在了最後面。前端
環境準備
這個很簡單,我就直接拷貝過來了。vue
-
nodejs: 建議使用 LTS 版本 -
npm: 建議最新版本 -
yeoman : npm install -g yo -
generator-code : npm install -g generator-code
另外小TIPS
,咱們平時直接安裝的插件所在目錄是~/.vscode/extensions
,有興趣的能夠看看這些插件是怎麼實現的。java
腳手架
安裝的yo能夠直接生成一個Hello World版本的插件目錄。執行node
yo code
即會提示一些問題,按照我的喜愛填寫便可,最後會生成樣板代碼:git
.
├── CHANGELOG.md 插件變動記錄
├── README.md
├── extension.js 插件入口main文件
├── jsconfig.json 編輯器關於js的配置
├── package.json 全局配置
├── test 測試代碼文件夾
│ ├── extension.test.js
│ └── index.js
├── vsc-extension-quickstart.md 新手介紹
└── yarn.lock
其中的quickstart.md
是新手引導,裏面包含了對文件的做用解析、如何運行插件、測試插等等,推薦去看一看,咱們在下面也會介紹一些。除此以外在package.json裏也包含了不少很是重要的信息:github
{
"name": "hello-world", // 插件名
"displayName": "hello-world",
"description": "hello world", // 插件描述
"version": "0.0.1",
"engines": {
"vscode": "^1.35.0" // 運行插件須要vscode最低版本
},
"categories": ["Other"],
"activationEvents": ["onCommand:extension.helloWorld"], // 如何激活插件:在命令面板(Command+Shift+P吊起)輸入helloWorld. 注意command名須要在contributes.commands中有配置
"main": "./extension.js", // 插件入口
"contributes": {
"commands": [
// 此數組表示插件支持的全部命令
{
"command": "extension.helloWorld", // 命令對應的Command,須要和代碼裏保持一致
"title": "Hello World" // 命令的顯示名稱
}
]
},
"scripts": {
// 正常的npm script
"postinstall": "node ./node_modules/vscode/bin/install",
"test": "node ./node_modules/vscode/bin/test"
},
"devDependencies": {
// 依賴包
"typescript": "^3.3.1",
"vscode": "^1.1.28",
"eslint": "^5.13.0",
"@types/node": "^10.12.21",
"@types/mocha": "^2.2.42"
}
}
啓動、調試插件
啓動運行
腳手架生成的其實就是一個node應用,直接按F5便可運行。對配置感興趣的也能夠查看根目錄下的.vscode/launch.json
。web
跑起來之後默認會新開一個vscode窗口,而後會發現什麼都沒有發生,這是由插件的啓動方式決定的,配置於package.json
裏的activationEvents
項。經常使用的有:算法
-
onLanguage
在打開特定語言類型的文件後激活 -
onCommand
在執行特定命令後激活
因爲咱們的插件是配置的onCommand
啓動,而且指定的命令名是Hello World
,因此咱們在新開的vscode
窗口中按下快捷鍵Command+Shift+P
後再找到Hello World
,選中並執行便可。
最後順利的話,編輯器右下角會彈出Hello World!。
若是細心的話,還會在源窗口的控制檯的調試控制檯tab 中看到以下輸出:
Congratulations, your extension "hello-world" is now active!
這個就是由插件的真正代碼部分輸出的了。咱們接下來看看extension.js的內容:
// vscode編輯器api入口
const vscode = require('vscode');
/**
* 今生命週期方法在插件激活時執行
* @param {vscode.ExtensionContext} context
*/
function activate(context) {
// console的各類方法都是輸出在`調試控制檯`tab下
console.log('Congratulations, your extension "hello-world" is now active!');
// registerCommand用於註冊命令並提供具體邏輯,命令名須要和package.json裏寫的一致。
// 回調函數在命令被觸發時執行。
let disposable = vscode.commands.registerCommand('extension.helloWorld', function() {
// 在編輯器右下角展現一個message box
vscode.window.showInformationMessage('Hello World!');
});
// 將registerCommand的返回值放入subscriptions能夠自動執行內存回收邏輯。
context.subscriptions.push(disposable);
}
exports.activate = activate;
// 當插件被設置爲無效時執行今生命週期鉤子
function deactivate() {}
module.exports = {
activate,
deactivate,
};
以上就是此插件的完整邏輯了,配置註釋是很簡單的。能夠看到主要就是兩個生命週期函數,另外搭配一些編輯器api就完成了。
調試
腳手架已經貼心的幫咱們加了調試配置,咱們只用添加斷點便可:
Command 配置
上面提到了生成一個command只須要 2 步,先是利用vscode.commands.registerCommand註冊一個,而後再到package.json裏的contributes.commands中配置便可。圍繞command還能夠作一些其餘事情,最多見的就是配置右鍵菜單和快捷鍵。
右鍵菜單
表示右鍵的菜單裏出現指定command,配置方法:
"contributes":{
"menus": {
"editor/context": [
{
"when": "editorHasSelection && resourceFilename =~ /.js|.vue|.ts/", // 出現時機,當編輯器中有選中文本同時文件名後綴是js/vue/ts
"command": "extension.starling_textSearch", // 須要在`contributes.commands`存在此命令
"group": "6_Starling" // 命令所在的組,右鍵菜單能夠分組,組與組之間存在分隔線
},
]
}
}
快捷鍵
有了快捷鍵後,就不用每次在命令面板裏查找並運行命令了,一樣是在package.json中配置:
"contributes": {
"keybindings": [
{
"command": "extension.starling_textSearch",
"key": "ctrl+f11", // 在Windows上的快捷鍵
"mac": "cmd+f11", // 在mac上的快捷鍵
"when": "editorTextFocus" // 出現時機, 當編輯器焦點在某個文本中
}
],
}
發佈
主要參考的是官方文檔
首先須要安裝vsce工具:
npm install -g vsce
本地打包將插件打包成.vsix文件。
vsce package
會在項目根目錄生成hello-world-0.0.1.vsix,而後在編輯器的插件面板選擇從VSIX安裝便可:
發佈到插件市場
-
須要獲取一個token,參考官方文檔 -
利用token建立一個publisher,這是在插件市場的用戶
vsce create-publisher (publisher name)
-
本地登陸此用戶
vsce login (publisher name)
-
發佈插件
vsce publish
順利的話在控制檯會提示發佈成功,而後過幾分鐘就能夠在插件市場搜到本身的插件啦!😄
版本升級
當插件內容發生變動時,從新發布時最好更新版本號,vsce能夠遵循語義化版本指定升級大(major)/小(minor)/補丁(patch)版本,也能夠直接指定版本號。例如只升級小版本:
vsce publish minor
若是插件代碼在gitlab上,由於倉庫在內網,須要事先將README裏的圖片替換爲公網cdn上的路徑。
snippets
snippets是代碼片斷,能夠理解爲代碼快捷鍵,在輸入不多量觸發代碼後便可聯想出一大坨關聯代碼,很是方便。對於js、ts、vue均可以在插件市場找到很是多的snippets插件。
開發snippets只用兩步:
-
編寫snippets映射文件,它是一個json,例如javascript.json:
{
"this$t": {
"prefix": "tt'", // 觸發代碼
"body": [
// 聯想出來的關聯代碼
"this.\\$t('${1:key}')" // ${1: key} 是佔位符,聯想出來後會自動聚焦在這裏
],
"description": "this.$t" // snippets描述,當有多個匹配的代碼片斷時,能夠用來識別
}
}
-
在package.json中配置
"contributes": {
"snippets": [
{
"language": "javascript", // 代碼片斷起做用的語言類型
"path": "./src/snippets/javascript.json" // 對應的映射文件
}
]
}
最後就能夠在編輯器看到效果了:
-
更多細節參考snippets-syntax
插件默認配置
不少插件是須要一些額外配置才能工做的,設置默認配置一樣在package.json裏:
"contributes": {
"configuration": { // 默認配置
"type": "object",
"title": "",
"required": [
"sid"
],
"properties": {
"includes": {
"type": "Array",
"default": [
"json"
],
"description": "文件類型過濾器"
}
}
},
}
默認配置是json schema格式,在覆蓋默認配置時若是校驗出錯會有提示。
插件中使用getConfiguration來讀取配置:
function getConfig() {
const config = vscode.workspace.getConfiguration();
const includes: string[] | undefined = config.get('includes'); // 獲取指定配置項
return {
includes: includes || [],
};
}
監聽配置項修改
在用戶安裝了插件後,可能會修改配置,如何實時監聽配置項的修改呢?vscode提供了onDidChangeConfiguration事件監聽。
vscode.workspace.onDidChangeConfiguration(function(event) {
const configList = ['includes'];
// affectsConfiguration: 判斷是否變動了指定配置項
const affected = configList.some(item => event.affectsConfiguration(item));
if (affected) {
// do some thing ...
}
});
常見編輯器 api
全部vscode相關api均可以在官網文檔查找,vscode內部也集成了.d.ts文件,編輯器內直接跳轉定義便可。這裏只列舉一些常見的api.
-
messgae
用於展現提示性消息,出如今編輯器右下角,而不是頂部或右上角。
和console相似,提供了普通消息、警告消息、錯誤消息。
vscode.window.showInformationMessage('普通消息');
vscode.window.showWarningMessage('警告消息');
vscode.window.showErrorMessage('錯誤消息');
消息也支持交互按鈕,當選中按鈕時返回的是按鈕自己:
vscode.window.showErrorMessage(`與starling的遠程交互依賴vscode-starling.sid配置項`, '打開配置項').then(selection => {
if (selection === '打開配置項') {
vscode.commands.executeCommand('workbench.action.openSettings');
}
});
input box
在編輯器頂部展現一個input輸入框,使用vscode.window.showInputBox,會返回一個Promise:
const text: string | undefined = await vscode.window.showInputBox({
'最後一步,輸入文案'
})
quick pick
用於從一組選項中選擇一個,相似於select組件。使用vscode.window.showQuickPick,一樣返回一個Promise,resolve時獲得被選中的選項或undefined:
const lang: string | undefined = await vscode.window.showQuickPick(['en', 'zh', 'ja'], {
placeHolder: '第一步:選擇語言',
});
每一個選項也能夠是對象類型:
const option: Object | undefined = await vscode.window.showQuickPick([{ id: 1, name: 'a' }, { id: 2, name: 'b' }, { id: 3, name: 'c' }], {
placeHolder: 'select an option',
});
output channel
在利用Control + ~打開控制檯後,會出現 4 個tab,從左到右依次是問題、輸出、調試控制檯、終端。output channel就是用於控制輸出 tab的內容,能夠往其中追加文本、追加行、清空,能夠將其當作一個簡單的文件。output channel適用於一次展現大量信息.
使用vscode.window.createOutputChannel建立output channel實例,而後就能夠操做各類api了。
const opc = vscode.window.createOutputChannel('textSearch'); // 能夠有多個OutputChannel共存,使用參數名區分
opc.clear(); // 清空
opc.appendLine('水電費'); // 追加一行
opc.show(); // 打開控制檯並切換到OutputChannel tab
一個例子:
file selector
有些時候須要操做本地文件系統,例如選擇某個文件、將文件保存到指定位置等。
-
保存文件到指定位置使用showSaveDialog,它會打開文件選擇器彈窗,選擇了保存路徑後點擊肯定會返回選中的路徑,若是點擊取消會返回undefined。
// 讓用戶手動選擇文件的的存儲路徑
const uri = await vscode.window.showSaveDialog({
filters: {
zip: ['zip'], // 文件類型過濾
},
});
if (!uri) {
return false;
}
writeFile(uri.fsPath); // 寫入文件
-
文件選擇showOpenDialog一樣會打開文件選擇器彈窗,不過此次是用於選擇文件,若是有選擇文件會返回選中的文件路徑,反之返回undefined。
// showOpenDialog返回的是文件路徑數組
const uris = await window.showOpenDialog({
canSelectFolders: false, // 是否能夠選擇文件夾
canSelectMany: false, // 是否能夠選擇多個文件
filters: {
json: ['json'], // 文件類型過濾
},
});
if (!uris || !uris.length) {
return;
}
handleFiles(uris);
hover
有時候須要在hover到文本上時展現一些提示信息,例如eslint插件在hover到不合規的代碼上時會展現具體違反了哪些規則:
處理hover須要註冊一個hover處理器,vscode會在hover到文本上時自動調用處理器,同時傳遞hover相關的信息。例如一個展現光標所在的單詞hover處理器:
/**
* document: 打開的文本
* position:hover的位置
* token: 用於取消hover處理器做用
*/
async function hover(document: vscode.TextDocument, position: vscode.Position, token: vscode.CancellationToken) {
const line = document.lineAt(position).text; // 光標所在的行
// getWordRangeAtPosition獲取光標所在單詞的行列號範圍;getText獲取指定範圍的文本
const positionWord = document.getText(document.getWordRangeAtPosition(position));
console.log('光標所在位置的單詞是:', positionWord);
}
// registerHoverProvider的第一個參數數組代表此處理器的做用範圍
const hoverDisposable = vscode.languages.registerHoverProvider(['javascript', 'vue'], {
provideHover: hover,
});
context.subscriptions.push(hoverDisposable);
selection
與hover相似,有時候須要處理選中的文本,獲取它是經過vscode.TextEditor實例上的屬性,有兩個相關屬性
-
selections:全部被選中的文本信息 -
selection:第一個被選中的文本信息, 等同於selections[0]
獲取TextEditor的一個方法是經過註冊textEditorCommand,會在回調函數裏提供TextEditor實例,例如展現選中文本:
let command = vscode.commands.registerTextEditorCommand('extension.selection', function(textEditor, edit) {
const text = textEditor.document.getText(textEditor.selection);
console.log('選中的文本是:', text);
});
context.subscriptions.push(command);
FileSystemWatcher
用於監聽文件是否發生了變化,能夠監聽到新建、更新、刪除這 3 種事件,也能夠選擇忽略其中某個類型事件。建立watcher是利用vscode.workspace.createFileSystemWatcher:
function createFileSystemWatcher(globPattern: GlobPattern, ignoreCreateEvents?: boolean, ignoreChangeEvents?: boolean, ignoreDeleteEvents?: boolean): FileSystemWatcher;
例如監聽全部js文件的變更:
const watcher = vscode.workspace.createFileSystemWatcher('*.js', false, false, false);
watcher.onDidChange(e => { // 文件發生更新
console.log('js changed,' e.fsPath);
});
watcher.onDidCreate(e => { // 新建了js文件
console.log('js created,' e.fsPath);
});
watcher.onDidDelete(e => { // 刪除了js文件
console.log('js deleted,' e.fsPath);
});
參考文章
-
https://code.visualstudio.com/api -
VSCode插件開發全攻略:https://www.cnblogs.com/liuxianan/p/vscode-plugin-overview.html -
VSCode插件開發急速入門:https://juejin.im/entry/6844903640826642440
回覆「加羣」與大佬們一塊兒交流學習~
點擊「閱讀原文」查看 80+ 篇原創文章
本文分享自微信公衆號 - 前端自習課(FE-study)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。