在日常使用vscode开发中,总会碰到自己想使用的插件功能但是苦苦找不到合适的插件,这时我们不妨自己开发一个插件来使用
1.生成插件脚手架
要开发VSCode插件,首先要知道开发需要哪些文件、目录如何组织、文件都包含什么内容,官方提供了交互式工具来自动生成插件的脚手架,一键命令生成即可
npm install -g yo generator-code
yo code
_-----_ ╭──────────────────────────╮
| | │ Welcome to the Visual │
|--(o)--| │ Studio Code Extension │
`---------´ │ generator! │
( _´U`_ ) ╰──────────────────────────╯
/___A___\ /
| ~ |
__'.___.'__
´ ` |° ´ Y `
生成后,我们只需要关注 extension.js和package.json即可,了解这两个文件基本上就可以入门开发一个vscode插件了
2.extension.js
该文件是其入口文件,即package.json中main字段对应的文件(不一定叫extension.js这个名字),该文件中将导出两个方法:activate和deactivate,两个方法的执行时机如下所示:
activate
这是插件被激活时执行的函数
deactivate
这是插件被销毁时调用的方法,比如释放内存等
3.package.json
该文件是vscode扩展的清单文件,里面有很多字段,官方对每个字段都进行了详细阐述,本次我们重点阐述以下初始化后期清单文件
{
"publisher": "CC",// 开发插件人
"name": "clear-git", // 插件名
"displayName": "clear-git", // 显示在插件市场的名称
"description": "一键清理git本地分支插件", // 插件描述
"version": "0.0.1", // 版本号
"engines": {
"vscode": "^1.83.0" // 最低支持的vscode版本
},
"repository": { // 仓库链接
"type": "git",
"url": "https://gitee.com/cc-2018_admin/clean-git.git"
},
"categories": [
"Other" // 扩展类别
],
"activationEvents": [], // 激活事件组,在那些事件情况下被激活
"main": "./extension.js", // 入口文件
"icon": "icon.png", // 插件icon
// 命令列表
"contributes": {
"commands": [
{
// 命令名称,与extension.js里名称对应
"command": "cleanLocalBranch",
// 显示在标题的名称
"title": "一键清理本地git"
}
],
// 右键菜单列表
"menus": {
"editor/context": [
{
// 命令名称,与extension.js里名称对应
"command": "cleanLocalBranch",
// 分组
"group": "group1"
}
],
// 上下文列表
"explorer/context": [
{
// 命令名称,与extension.js里名称对应
"command": "cleanLocalBranch",
// 分组
"group": "group1"
}
]
}
},
"scripts": {
"lint": "eslint .",
"pretest": "pnpm run lint",
"test": "node ./test/runTest.js"
},
"devDependencies": {
"@types/vscode": "^1.83.0",
"@types/mocha": "^10.0.2",
"@types/node": "18.x",
"eslint": "^8.50.0",
"glob": "^10.3.3",
"mocha": "^10.2.0",
"typescript": "^5.2.2",
"@vscode/test-electron": "^2.3.4"
}
}
重点关注的主要有三部分内容:activationEvents、main以及contributes,其是整个文件中的核心模块
main
指明了该插件的主入口在哪,只有找到主入口整个项目才能正常的运转
activationEvents
指明该插件在何种情况下才会被激活,因为只有激活后插件才能被正常使用,官网已经指明了激活的时机,这样我们就可以按需设置对应时机。(具体每个时机用的时候详细查看即可)
-
onLanguage 打开解析为特定语言文件时被激活,例如"onLanguage:JavaScript"
-
onCommand 在调用命令时被激活
-
onDebug 在启动调试话之前被激活
-
workspaceContains 每当打开文件夹并且该文件夹包含至少一个与 glob 模式匹配的文件时
-
onFileSystem 每当读取来自特定方案的文件或文件夹时
-
onView 每当在 VS Code 侧栏中展开指定 id 的视图
-
onUri 每当打开该扩展的系统范围的 Uri 时
-
onWebviewPanel
-
onCustomEditor
-
onAuthenticationRequest
-
- 只要一启动vscode,插件就会被激活
-
onStartupFinished
contributes
通过扩展注册contributes用来扩展Visual Studio Code中的各项技能,其有多个配置,如下所示:
- breakpoints 断点
- colors 主题颜色
- commands 命令
- configuration 配置
- configurationDefaults 默认的特定于语言的编辑器配置
- customEditors 自定义编辑器
- debuggers
- grammars
- iconThemes
- jsonValidation
- keybindings 快捷键绑定
- languages
- menus
- problemMatchers
- problemPatterns
- productIconThemes
- resourceLabelFormatters
- snippets 特定语言的片段
- submenus
- taskDefinitions
- themes 颜色主题
- typescriptServerPlugins
- views
- viewsContainers
- viewsWelcome
- walkthroughs
4.实战开发
这是一个帮你一键管理本地git分支的vscode插件,当你在开发时,可能会有需要迭代更新,迭代更新完毕后,有许多不需要的本地分支,不需要执行复杂的git branch -D 命令清除,只需点击一键即可清除
插件开发官方示例库:github.com/microsoft/v…
-
extension.js
-
const vscode = require("vscode"); const { checkGitFile } = require("./fs-service/operaFile.js"); /** * @param {vscode.ExtensionContext} context */ function activate(context) { const cleanGit = vscode.commands.registerCommand( "cleanLocalBranch", async () => { const isDefaultBranch = await vscode.window.showInformationMessage( "当前分支是否为默认分支?", "是", "否" ); if (isDefaultBranch === "否") { vscode.window.showErrorMessage("请先切换到默认分支,例如master"); } else { const projectRoot = vscode.workspace.workspaceFolders[0].uri.fsPath || ""; checkGitFile(projectRoot, vscode); } } ); context.subscriptions.push(cleanGit); } function deactivate() {} module.exports = { activate, deactivate, };
-
fs-service/operaFile.js
-
const fs = require("fs"); const path = require("path"); /** * @param {string} url * @param {{window:any}} vscode */ function checkGitFile(url, vscode) { let files = fs.readdirSync(url); //返回文件和子目录的数组 if (!files.includes(".git")) { vscode.window.showErrorMessage("您还未初始化git,请先初始化"); return; } else { const gitFolderPath = path.join(url, ".git"); readRefsGitFile(gitFolderPath, vscode); } } /** * @param {string} url * @param {{window: any}} vscode */ function readRefsGitFile(url, vscode) { fs.readdir(url, (err, files) => { if (err) { vscode.window.showErrorMessage(err); return; } if (files.includes("refs")) { for (const file of files) { if (file === "refs") { const filePath = path.join(url, file); fs.stat(filePath, (err, stats) => { if (err) { vscode.window.showErrorMessage(err); return; } if (stats.isDirectory()) { // 递归调用 readGitFile 函数,继续读取子目录 readGitFile(filePath, vscode); } }); } } } else { vscode.window.showErrorMessage("git文件夹配置出错,请重新初始化"); return; } }); } /** * @param {string} url * @param {{window: any}} vscode */ function readGitFile(url, vscode) { fs.readdir(url, (err, files) => { if (err) { vscode.window.showErrorMessage(err); return; } for (const file of files) { const filePath = path.join(url, file); fs.stat(filePath, (err, stats) => { if (err) { vscode.window.showErrorMessage(err); return; } if (stats.isDirectory()) { // 递归调用 readGitFile 函数,继续读取子目录 readGitFile(filePath, vscode); } else { deleteGitFile(filePath, vscode); } }); } }); } /** * @param {string} filePath * @param {{ window: any; commands?: any; }} vscode */ function deleteGitFile(filePath, vscode) { if (!["master", "HEAD"].some((item) => filePath.endsWith(item))) { fs.unlink(filePath, (err) => { if (err) { vscode.window.showErrorMessage(err); return; } }); // 在 checkGitFile 完成后执行 git pull 命令 vscode.commands.executeCommand("git.pull"); } } module.exports = { checkGitFile, };