原文链接: 编写一个VSCode插件 - 愧怍的小站

自从使用过 VSCode 后就再也离不开 VSCode,其轻量的代码编辑器与诸多插件让多数开发者爱不释手。同样我也不例外,一年前的我甚至还特意买本《Visual Studio Code 权威指南》的书籍,来更进一步了解与使用。

在购买这本书时就想写一个 vscode 插件(扩展),奈何当时事务繁忙加之不知做何功能,就迟迟未能动手。如今有时间了,就顺带体验下 vscode 插件开发,并记录整个开发过程。

插件地址:VSCode-extension

开源地址:kuizuo/vscode-extension (github.com)

Vscode 相关

vscode 应用商店

vscode 插件官方文档

vscode 官方插件例子

关于 Vscode 及其插件就不过多介绍,相信这篇文章 VSCode 插件开发全攻略(一)概览 - 我是小茗同学 - 博客园 能告诉你 Vscode 插件的作用。

工具准备

:::tip

在开发前,建议关闭所有功能性扩展,以防止部分日志输出与调试效率

:::

vscode 插件脚手架

vscode 提供插件开发的脚手架 vscode-generator-code 来生成项目结构,选择要生成的类型

? ==========================================================================
We're constantly looking for ways to make yo better!
May we anonymously report usage statistics to improve the tool over time?
More info: https://github.com/yeoman/insight & http://yeoman.io
========================================================================== Yes_-----_     ╭──────────────────────────╮|       |    │   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 ThemeNew Language SupportNew Code SnippetsNew KeymapNew Extension PackNew Language Pack (Localization)New Web Extension (TypeScript)New Notebook Renderer (TypeScript)

根据指示一步步选择,这里省略勾选过程,最终生成的项目结果如下

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-J0Rl9Hqr-1657543591405)(https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/f2930db8192c4854996baf4da13d223b~tplv-k3u1fbpfcp-zoom-1.image)]

运行 vscode 插件

既然创建好了工程,那必然是要运行的。由于我这里选择的 ts + webpack 进行开发,所以是需要打包,同时脚手架已经生成好了对应.vscode 的设置。只需要按下 F5 即可开始调试,这时会打开一个新的 vscode 窗口,Ctrl+Shift+P打开命令行,输入Hello World,右下角弹出提示框Hello World from kuizuo-plugin!

:::danger

注意: 由于是 webpack 开发,在调用堆栈中可以看到有两个进程,一个是 webpack,另一个是新开的插件窗口的,同时在该调试窗口也能查看调试输出信息。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-poZm1hJQ-1657543591415)(https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/e9554510d419439eb29c15b4e8f18a34~tplv-k3u1fbpfcp-zoom-1.image)]

切记一定要等到第二个调试进程加载完毕(时间根据电脑性能而定),再打开命令行输入 Hello World 才会有命令,否则会提示 没有匹配命令。

:::

至此,一个 vscode 的开发环境就已经搭建完毕,接下来就是了解项目结构,以及 vscode 插件的 api 了。

代码解读

import * as vscode from 'vscode'export function activate(context: vscode.ExtensionContext) {let disposable = vscode.commands.registerCommand('kuizuo-plugin.helloWorld', () => {vscode.window.showInformationMessage('Hello World from kuizuo-plugin!')})context.subscriptions.push(disposable)
}export function deactivate() {}

vscode.commands.registerCommand用于注册命令,kuizuo-plugin.helloWorld 为命令 ID,在后续package.json中要与之匹配。第二个参数为一个回调函数,当触发该命令时,弹出提示框。

在 package.json 中关注 activationEvents 与 contributes

{"activationEvents": ["onCommand:kuizuo-plugin.helloWorld"],"contributes": {"commands": [{"command": "kuizuo-plugin.helloWorld","title": "Hello World"}]}
}

activationEvents 激活事件,onCommand:kuizuo-plugin.helloWorldkuizuo-plugin是插件 ID 要与 extension.ts 中的注册命令匹配,helloWorld则是命令标识,而 onCommand 则是监听的类型,此外还有onViewonUrionLanguage等等。

contributes 则是配置那些地方来显示命令,像官方的例子中,就是在 Ctrl + Shift + P 命令行中输入 Hello World 来调用kuizuo-plugin.helloWorld 命令。此外还可以设置按键与菜单

"keybindings": [{"command": "kuizuo-plugin.helloWorld","key": "ctrl+f10","mac": "cmd+f10","when": "editorTextFocus"}],"menus": {"editor/context": [{"when": "editorFocus","command": "kuizuo-plugin.helloWorld","group": "navigation"}]}

设置完毕后,可以按 Ctrl + Alt + O 或者命令行中键入 reload 来重启 vscode

:::danger

这里也要注意,如果重启后并无生效,请查看 package.json 是否配置正确(多一个逗号都不行),或者尝试重新调试。如果还不行,那么很有可能就是代码报错,但日志输出并没有,那么在弹出的新窗口中打开开发人员工具(Ctrl+Alt+I 或帮助 → 切换开发人员工具),这里有报错相关的提示信息。

建议查看VSCode 插件开发全攻略(六)开发调试技巧

:::

功能

首次启动弹窗与配置项

先说首次启动弹窗的实现,要实现该功能,肯定要保证插件在 VSCode 一打开就运行,而这取决于 vscode 触发插件的时机,也就是 activationEvents,所以activationEvents需要设置成onStartupFinished。想要更高的优先级,可以选择 * (但官方不建议,除非其他事件无法实现的前提下),这里为了演示就使用*

其实现代码主要调用 vscode.window.showInformationMessage 函数如下

import * as vscode from 'vscode'
import { exec } from 'child_process'export function activate(context: vscode.ExtensionContext) {vscode.window.showInformationMessage('是否要打开愧怍的小站?', '是', '否', '不再提示').then((result) => {if (result === '是') {exec(`start 'https://kuizuo.cn'`)} else if (result === '不再提示') {// 其他操作 后文会说}})
}

此时重启窗口,就会有如下弹窗显示

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2q7PGGjj-1657543591416)(https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/85b2741822ea4af28f90984529baac94~tplv-k3u1fbpfcp-zoom-1.image)]

但如果你是 mac 用户的话,你会发现无法打开,其原因是 window 下打开链接的指令是 start,而 mac 则是 open,所以需要区分不同的系统。要区分系统就可以使用 node 中的 os 模块的 platform 方法获取系统,如下(省略部分代码)

import * as os from 'os'const commandLine = os.platform() === 'win32' ? `start https://kuizuo.cn` : `open https://kuizuo.cn`
exec(commandLine)

当然了,当用户选择不再提示的时候,下次再打开 vscode 就别提示了,不然大概率就是卸载插件了。这里就需要设置全局参数了,在 package.json 中 contributes 设置 configuration,具体如下,注意kuizuoPlugin.showTip 为全局参数之一

"contributes": {"configuration": {"title": "kuizuo-plugin","properties": {"kuizuoPlugin.showTip": {"type": "boolean","default": true,"description": "是否在每次启动时显示欢迎提示!"}}}
}

该参数可以在设置 → 扩展中找到kuizuo-plugin插件来手动选择,也可以是通过 api 来修改

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dIGEurZk-1657543591416)(https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/813669faa6b546eda203abe9fdd214ec~tplv-k3u1fbpfcp-zoom-1.image)]

然后读取vscode.workspace.getConfiguration().get(key)和设置该参数vscode.workspace.getConfiguration().update(key, value)

export async function activate(context: vscode.ExtensionContext) {const key = 'kuizuoPlugin.showTip'const showTip = vscode.workspace.getConfiguration().get(key)if (showTip) {const result = await vscode.window.showInformationMessage('是否要打开愧怍的小站?', '是', '否', '不再提示')if (result === '是') {const commandLine = os.platform() === 'win32' ? `start https://kuizuo.cn` : `open https://kuizuo.cn`exec(commandLine)} else if (result === '不再提示') {//最后一个参数,为true时表示写入全局配置,为false或不传时则只写入工作区配置await vscode.workspace.getConfiguration().update(key, false, true)}}
}

即便是调试状态下,重启也不会影响全局参数。最终封装完整代码查看源码,这里不再做展示了。

右键资源管理器(快捷键)新建测试文件

我日常开发中写的最多的文件就是 js/ts 了,有时候就会在目录下创建 demo.js 来简单测试编写 js 代码,那么我就要点击资源管理器,然后右键新建文件,输入 demo.js。于是我想的是将该功能封装成快捷键的方式,当然右键也有新建测试文件这一选项。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-stgz2HOa-1657543591417)(https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/eded811fae67413783b0a63572c4ccab~tplv-k3u1fbpfcp-zoom-1.image)]

功能其实挺鸡肋的,也挺高不了多少效率,这里可以说为了演示和测试这个功能而实现

总之前面这么多废话相当于铺垫了,具体还是看功能实现吧。

首先就是注册命令,具体就不解读代码了,其逻辑就是获取调用vscode.window.showQuickPick弹出选择框选择 js 还是 ts 文件(自定义),接着获取到其目录,判断文件是否存在,创建文件等操作。

import * as vscode from 'vscode'
import * as fs from 'fs'export async function activate(context: vscode.ExtensionContext) {let disposable = vscode.commands.registerCommand('kuizuo-plugin.newFile', (uri: vscode.Uri) => {vscode.window.showQuickPick(['js', 'ts'], {}).then(async (item) => {if (!uri?.fsPath) {return}const filename = `${uri.fsPath}/demo.${item}`if (fs.existsSync(filename)) {vscode.window.showErrorMessage(`文件${filename}已存在`)return}fs.writeFile(filename, '', () => {vscode.window.showInformationMessage(`demo.${item}已创建`)vscode.window.showTextDocument(vscode.Uri.file(filename), {viewColumn: vscode.ViewColumn.Two, // 显示在第二个编辑器窗口})})})})context.subscriptions.push(disposable)
}export function deactivate() {}

然后再 keybindins 中添加一条

"keybindings": [{"command": "kuizuo-plugin.newFile","key": "shift+alt+n",}
],

然后就当我实现完功能的时候,我在想自带的新建文件是不是就是个 command?只是没有绑定快捷键? 于是我到键盘快捷方式中找到答案

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GQrkfThb-1657543591417)(https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/416e33d36f34427d8731eb525dfe0aa8~tplv-k3u1fbpfcp-zoom-1.image)]

图中的explorer.newFile就是资源管理器右键新建文件的命令,只是没有键绑定。所以我只需要简单的加上shift + alt + n即可实现我一开始想要的快捷键功能,此时再次右键资源管理器新建文件右侧就有对应的快捷键。

此时的我不知该哭该笑,折腾半天的功能其实只是设置个快捷键的事情。

:::note

这些命令在 vscode 中作为内置命令Built-in Commands。要查看 vscode 所有命令的话,也可以通过vscode.commands.getCommands 来获取所有命令 ID,要在插件中执行也只需要调用vscode.commands.executeCommand(id)

:::

键盘快捷键(光标移动)

接着我就在想,既然很多 vscode 功能都是命令的形式,那是不是在插件级别就能做键盘映射,而不用让用户在 vscode 设置,很显然是可以的。只需要在 package.json 中 contributes 的 keybindings 中设置,就可以实现组合键来进行光标的移动。下面是我给出的答案

"keybindings": [{"command": "cursorUp","key": "shift+alt+i","when": "textInputFocus"},{"command": "cursorDown","key": "shift+alt+k","when": "textInputFocus"},{"command": "cursorLeft","key": "shift+alt+j","when": "textInputFocus"},{"command": "cursorRight","key": "shift+alt+l","when": "textInputFocus"},{"command": "cursorHome","key": "shift+alt+h","when": "textInputFocus"},{"command": "cursorEnd","key": "shift+alt+;","when": "textInputFocus"}]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HX2l2HfA-1657543591418)(https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/6674f9018ec94ecdadf2fd11326768eb~tplv-k3u1fbpfcp-zoom-1.image)]

仔细看右侧来源就可以知道是没问题的,第一个为我之前设置的,而扩展则是通过上面的方法。

自定义扩展工作台

在 vscode 中有几个地方可以用于扩展,具体可看Extending Workbench | Visual Studio Code Extension API

  • 左侧图标(活动栏):主要有资源管理器、搜索、调试、源代码管理、插件

  • 编辑器右上角:代码分栏、code runner 的运行图标

  • 底部(状态栏):git、消息、编码等等

在 contributes 添加 viewsContainers 与 views,注意,views 的属性要与 viewsContainers 的 id 对应。

"viewsContainers": {"activitybar": [{"id": "demo","title": "愧怍","icon": "public/lollipop.svg"}]
},
"views": {"demo": [{"id": "view1","name": "视图1"},{"id": "view2","name": "视图2"}]
}

编辑器右上角是在 menus 中设置 editor/title,图标则是对应命令下设置,不然就是显示文字

"commands": [{"command": "kuizuo-plugin.helloWorld","title": "Hello World","icon": {"light": "public/lollipop.svg","dark": "public/lollipop.svg"}}
],
"menus": {"editor/title": [{"when": "resourceLangId == javascript","command": "kuizuo-plugin.helloWorld","group": "navigation"}],
}

至于底部状态栏,这里借用官方例子vscode-extension-samples/statusbar-sample at main · microsoft/vscode-extension-samples (github.com),最终效果如下

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3LyOO7r1-1657543591419)(https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/9655a221920742009e4a7a082a4edab5~tplv-k3u1fbpfcp-zoom-1.image)]

那个

编写一个VSCode插件相关推荐

  1. 从零开始编写一个vue插件

    title: 从零开始编写一个vue插件 toc: true date: 2018-12-17 10:54:29 categories: Web tags: vue mathjax 写毕设的时候需要一 ...

  2. 如何编写一个Jquery插件

    首先我们来搞清楚一些关于Jquery插件的知识: 一.插件的种类: 封装对象方法的插件 这种插件是将对象方法封装起来,用于对通过选择器获取的jQuery对象进行操作,是最常见的一种插件 封装全局函数的 ...

  3. java插件开发_编写一个IDEA插件之:自动生成Java代码

    我很喜欢IDEA的一键自动生成代码功能,例如自动生成构造方法.字段的Get/Set方法.ToString方法等等,除此之外,也有一些插件提供自动生成代码的功能,例如我们所熟悉的GsonFormat插件 ...

  4. 怎么编写一个chrome插件

    怎么编写一个chrome插件 总觉得chrome插件这种东西很高端,很遥不可及.当然复杂的chrome插件开发起来确实比较困难,但是我们可以从一个简单的chrome插件demo慢慢入手,了解一下chr ...

  5. 编写一个IDEA插件之:事件监听

    事件监听,我们最熟悉不过的就是开发APP时,监听按钮点击事件.手指触摸及移动事件.网络状态事件等等.事件监听大多通过观察者模式实现,首先API调用者不需要知道后台是如何检测出网络状态不可用的,而只需要 ...

  6. 如何用vbs编写一个游戏_如何编写一个 SkyWalking 插件

    点击上方"开源社"关注我们 | 作者:vcjmhg| 编辑:李明康| 责编:袁睿斌 | 设计:叶修缘丶 1 概述 之前几篇文章,我们着重介绍了在对 SkyWalking 进行二次开 ...

  7. 如何编写一个抢购bot_如何编写一个SkyWalking插件

    概述 之前几篇文章,我们着重介绍了在对SkyWalking进行二次开发之前的环境搭建问题,因此本篇文章将基于SkyWalking-8.1.0版本,以开发webflux-webclent插件为例,分享一 ...

  8. 软妹音程序员鼓励师24小时在线,只需一个VSCode插件,还能帮忙吐槽产品经理...

    Python实战社群 Java实战社群 长按识别下方二维码,按需求添加 扫码关注添加客服 进Python社群▲ 扫码关注添加客服 进Java社群▲ 鱼羊 郭一璞 发自 凹非寺 量子位 报道 | 公众号 ...

  9. 编写一个GStreamer插件

    前面章节对GStreamer做了概述,不过我们最终用到主要是插件,下面我们对插件做一个简单介绍,大部分内容都是copy的,并非原创,主要用于学习记录,英文好的可以看官方文档,我和官方校对过,翻译的大体 ...

最新文章

  1. Python-Django配置阿里大于的短信验证码接口
  2. java webservice接口开发_php开发webservice服务端接口(wsdl)
  3. 图像分类再思考DNN似乎遵循一种令人困惑的简单策略来对图像分类
  4. 通用算法-sql相似度模糊匹配
  5. 基于STM32,无人船岸基信息处理代码--python实现
  6. android 限制edittext 最大输入字符数
  7. 【Java】 剑指offer(67) 把字符串转换成整数
  8. python数据可视化是什么_Python数据分析:可视化
  9. C与PHP的联系与区别
  10. 黑苹果无法登录Appstore
  11. SQL SERVER2008 打开脚本总是报“未能完成操作,存储空间不足”
  12. centos离线安装谷歌浏览器flash-player
  13. 柔性电流传感器(柔性电流探头)的工作原理和特点是什么?
  14. 面部皮肤200种问题_面部皮肤问题
  15. 前端三件套之css笔记
  16. SmartUpload综合
  17. 分享一个react 图片上传组件 支持OSS 七牛云
  18. 【LeedCode每周总结】还在犹豫怎么刷LeedCode有没有用?快来加入每日刷题卷进大厂吧,冲冲冲
  19. 【车牌识别】模板匹配新能源车牌识别【含Matlab源码 865期】
  20. iTunes C盘占用空间太大 解决方案

热门文章

  1. mysql 快照_Mysql可重复读(2) —— 快照真的就是快照吗
  2. activiti使用详解
  3. 人脸验证与二分类(Face verification and binary classification)
  4. 推荐一位 10w+ 粉丝的 Python 工程师
  5. python 对角阵_python-Numpy分区对角矩阵
  6. 小区综合业务系统/小区管理系统
  7. [普及练习场] 生活大爆炸版石头剪刀布
  8. 8.Python函数
  9. python3结果窗口打开_python3+PyQt5 使用三种不同的简便项窗口部件显示数据的方法...
  10. Why c++ coroutine?Why libgo?