天天看點

開發自己的vs code插件來改進你的工作

作者:一點鑫得

Visual Studio Code是微軟打造的一款開源、跨平台的開發工具,豐富的插件和優秀的使用體驗使得越來越多的開發者開始轉向VS Code,我也是其中的一員。VS Code的插件都是廣大的開發者貢獻的,我也想開發一款自己的插件來滿足我近期的一個小需求。

滿足自己的需求

我曾經斷斷續續地學了幾年的程式設計仍然停留在差不多hello world的水準,始終無法更進一步,直到我摸索着用python寫了一個小工具來解決工作中的重複任務才真正感覺到了進步,入了門。要想學會一樣技能,最快最有效的方法就是嘗試用它來解決身邊的問題,真正的把這個技術用起來。

工作上要經常調試pytest編寫的測試用例,我現在的方式是VS Code打開終端輸入“pytest -k 測試用例名稱”指令進行調測,要調試的用例比較多的話就要頻繁地輸入指令,我希望能編寫一個VS Code插件來自動從光标處讀取出測試用例名稱,拼接成pytest的調測指令發送到終端運作,這就是我的訴求。

說明:pytest是python語言編寫的單元測試架構,如果你不了解pytest也完全不影響,這裡直接把pytest認為是可以在cmd下運作的指令即可

生成插件腳手架

要編寫VS Code插件,首先要知道開發插件的約定規則,也就是建立插件需要哪些檔案、目錄如何組織、檔案包含什麼内容,我們沒有必要一一去手動建立,官方提供了互動式工具來自動生成插件的腳手架。

安裝腳手架生成工具

# 確定環境已經安裝了Node.js和Git
npm install -g yo generator-code           

執行yo code指令,根據提示輸入回答,插件類型選擇“New Extension (TypeScript)”,後續選項參考下面的記錄,選擇完成後将安裝相應的依賴并生成插件的目錄結構。

C:\xinRepo>yo code

     _-----_     ╭──────────────────────────╮
    |       |    │   Welcome to the Visual  │
    |--(o)--|    │   Studio Code Extension  │
   `---------´   │        generator!        │
    ( _´U`_ )    ╰──────────────────────────╯
    /___A___\   /
     |  ~  |
   __'.___.'__
 ´   `  |° ´ Y `

? What type of extension do you want to create? New Extension (TypeScript)
? What's the name of your extension? pytest-debug
? What's the identifier of your extension? pytest-debug
? What's the description of your extension? 快速調測pytest用例
? Initialize a git repository? Yes
? Bundle the source code with webpack? No
? Which package manager to use? npm

Writing in C:\xinRepo\pytest-debug...
   create pytest-debug\.vscode\extensions.json
   create pytest-debug\.vscode\launch.json
   create pytest-debug\.vscode\settings.json
   create pytest-debug\.vscode\tasks.json
   create pytest-debug\package.json
   create pytest-debug\tsconfig.json
   create pytest-debug\.vscodeignore
   create pytest-debug\vsc-extension-quickstart.md
   create pytest-debug\.gitignore
   create pytest-debug\README.md
   create pytest-debug\CHANGELOG.md
   create pytest-debug\src\extension.ts
   create pytest-debug\src\test\runTest.ts
   create pytest-debug\src\test\suite\extension.test.ts
   create pytest-debug\src\test\suite\index.ts
   create pytest-debug\.eslintrc.json

Changes to package.json were detected.

Running npm install for you to install the required dependencies.

added 211 packages in 10s

Your extension pytest-debug has been created!

To start editing with Visual Studio Code, use the following commands:

     code pytest-debug

Open vsc-extension-quickstart.md inside the new extension for further instructions
on how to modify, test and publish your extension.

For more information, also visit http://code.visualstudio.com and follow us @code.


? Do you want to open the new folder with Visual Studio Code? Open with `code`
           

檢視目錄結構,其中最重要的檔案是package.json和extension.ts,其他檔案暫不關注

開發自己的vs code插件來改進你的工作

package.json

  • activationEvents為contributes.commands注冊事件,也可以删除此激活事件,因為 VS Code 從 package.json 貢獻聲明中自動生成此類事件。
  • main為插件的運作入口檔案,因為插件使用TypeScript語言編寫,編譯後會自動生成out/extension.js檔案。
  • contributes.commands配置執行指令,其中command為需要注冊的方法,title為VS Code指令面闆顯示的指令名稱。
{
  "name": "pytest-debug",
  "displayName": "pytest-debug",
  "description": "快速調測pytest用例",
  "version": "0.0.1",
  "engines": {
    "vscode": "^1.75.0"
  },
  "categories": [
    "Other"
  ],
  "activationEvents": [
    "onCommand:pytest-debug.helloWorld"
  ],
  "main": "./out/extension.js",
  "contributes": {
    "commands": [
      {
        "command": "pytest-debug.helloWorld",
        "title": "Hello World"
      }
    ]
  },
  "scripts": {
    ...此處省略
  },
  "devDependencies": {
   ...此處省略
  }
}
           

extension.ts檔案主要包含activate和deactivate兩個方法,當注冊的事件被觸發後,active方法就會執行,deactivate方法用于清理操作,這裡沒有用到這個方法。

// 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 "pytest-debug" 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('pytest-debug.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 pytest-debug!');
	});

	context.subscriptions.push(disposable);
}

// This method is called when your extension is deactivated
export function deactivate() {}
           

調試插件

不改動任何代碼,先調試一下插件,左側導航欄進入運作與調測,點選運作會新打開一個新的VS Code視窗,Ctrl+Shift+P組合鍵打開指令面闆,輸入Hello World指令執行後,右下角會彈出一段消息框“Hello World from pytest-debug!”,這就是extension.ts中定義的回調方法中運作的代碼。

寫插件代碼

要寫自己的插件就需要會用VS Code的API,我是初次接觸,也不太可能短時間内全部了解它們,好在插件功能足夠簡單,适合入門,而且官方提供了大量插件的示例代碼(https://github.com/microsoft/vscode-extension-samples),再結合官方API文檔(https://code.visualstudio.com/api/references/vscode-api)就可以摸索着前進了。

插件計劃實作的功能就是指令面闆執行pytest debug指令,插件自動提取出下圖示例光标所在行的用例名稱及目前檔案的完整路徑,然後拼接成"pytest ${filepath} -k ${casename}"指令并在終端運作。

開發自己的vs code插件來改進你的工作

修改後的package.json檔案,改變了contributes.commands的command和title,相應地在extension.ts也需要改變注冊方法的名稱,另外增加了publisher項,這裡設定為自定義的釋出ID,釋出插件時需要用到

...之前部分無變化
"publisher": "pepperpapa",
...中間部分無變化
"activationEvents": [],
"main": "./out/extension.js",
"contributes": {
	"commands": [
	  {
		"command": "pytest-debug.run",
		"title": "pytest debug"
	  }
]
},
...後續部分無變化
           

修改後的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 "pytest-debug" 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('pytest-debug.run', () => {
		// The code you place here will be executed every time your command is executed
		// Display a message box to the user
		// 擷取目前打開的文本
		let current_editor = vscode.window.activeTextEditor;
		let testcase_name = "";
		let testcase_path = "";
		// 如果vs code有已經打開的文本
		if (current_editor) {
			// 得到光标所在的行
			let line = current_editor.selection.anchor.line;
			// 擷取目前行的文本
			testcase_name = current_editor.document.lineAt(line).text;
			// 正則方式取到測試用例名
			var reg = /\s*def test_(.+)\(/;
			let result = reg.exec(testcase_name);
			if (result) {
				testcase_name = result[1];
			} else {
                testcase_name = ""
            }
			// 取到目前打開檔案的完整路徑
			testcase_path = current_editor.document.uri.fsPath;
		}
		
		let terminal;
		// 如果vs code沒有打開的終端則建立終端,否則取第一個終端作為指令執行的終端
		if (vscode.window.terminals.length == 0) {
			terminal = vscode.window.createTerminal(`Terminal #pytest`);
		} else {
			terminal = vscode.window.terminals[0];
		}
		// 正常擷取到了測試用例名稱
		if (testcase_name.length > 0) {
			// 向終端發送拼接好的指令
			terminal.sendText(`pytest ${testcase_path} -k "${testcase_name}"`);
			// 顯示終端
			terminal.show(true);
		} else {
			vscode.window.showErrorMessage("請将光标放置到def test_xxx所在行,以便插件自動提取測試用例名稱!");
		}
	});

	context.subscriptions.push(disposable);
}

// This method is called when your extension is deactivated
export function deactivate() {}
           

釋出你的插件

調試代碼直到滿足了預期的需求之後,就可以打包和釋出你的插件了,官方提供vsce指令行工具簡化插件打包釋出流程。

安裝vsce工具

npm install -g @vscode/vsce           

打包插件

tip:打包前需要更新README.md,README.md是對插件的描述,如果沒有任何改變的話打包會出現錯誤提示

vsce package           

打包成功後,會在插件根目錄下生成pytest-debug-0.0.1.vsix檔案,如果你隻會在本地使用此插件,可以直接選擇.vsix安裝即可

開發自己的vs code插件來改進你的工作

釋出插件

将插件釋出到插件市場必須使用令牌方式釋出,需要根據官方指南(https://code.visualstudio.com/api/working-with-extensions/publishing-extension)先建立自己的組織,然後建立個人令牌并記住令牌。

執行vsce login publisher_name( publisher_name為package.json設定的publisher的值,即釋出者ID),這裡需要輸入建立的令牌進行認證

vsce login pepperpapa           
開發自己的vs code插件來改進你的工作

執行vsce publisher進行釋出

vsce publish           
開發自己的vs code插件來改進你的工作
開發自己的vs code插件來改進你的工作

稍等一會,稽核通過後就可以在VS Code搜尋到你的插件了!

開發自己的vs code插件來改進你的工作

參考文獻

  • VS Code API | Visual Studio Code Extension API
  • https://github.com/microsoft/vscode-extension-samples
  • Publishing Extensions | Visual Studio Code Extension API