Loading [MathJax]/jax/output/CommonHTML/config.js
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >插件机制详述_VSCode插件开发笔记1

插件机制详述_VSCode插件开发笔记1

作者头像
ayqy贾杰
发布于 2019-06-12 06:32:20
发布于 2019-06-12 06:32:20
3K00
代码可运行
举报
文章被收录于专栏:黯羽轻扬黯羽轻扬
运行总次数:0
代码可运行

一.扩展能力

VS Code插件不适合做UI定制,比如Atom的tool-bar 在VS Code很难实现:

提供了丰富的扩展能力模型,但不允许插件直接访问底层UI DOM(也就是说插件难以改变IDE外观,UI定制受限),这是出于方便底层持续优化考虑:

With VS Code, we’re continually trying to optimize use of the underlying web technologies to deliver an always available, highly responsive editor and we will continue to tune our use of the DOM as these technologies and our product evolve.

UI DOM这一层可能会随着优化频繁变动,VS Code不希望这些优化项受限于插件依赖,所以干脆把UI定制能力限制起来

除UI定制之外的,IDE相关的功能型特性都是支持扩展的,如基础的语法高亮/API提示、引用跳转(转到定义)/文件搜索、主题定制,高级的debug协议等等

P.S.实际上,非要扩展UI,也是有办法的(逃出插件运行环境,但要费不少力气),具体见access electron API from vscode extension,后续笔记会详细介绍

二.运行环境

为了性能与兼容性,插件在独立的进程(称为extension host process)中运行,并且不允许直接访问DOM,所以提供了一套内置的UI组件,比如智能提示(IntelliSense)

所以插件崩溃或无响应不影响IDE正常运行,例如:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// ref: my-extension/src/extension.ts
export function activate(context: vscode.ExtensionContext) {
 // hang up
 while (true);
}

一个插件的死循环并不影响IDE的正常使用和其它插件的加载/激活,但在进程列表能够看到Code Helper的CPU占用接近100%,进程级沙箱保证了插件机制的稳定性

三.核心理念

稳定性:插件隔离

插件可能会影响启动性能和IDE自身的稳定性,所以通过进程隔离来解决这个问题,插件运行在独立的进程中,不影响IDE及其启动时间

这样做是从用户角度考虑的,希望用户对IDE拥有完全的控制力,无论插件在做什么,都不影响IDE基本功能的正常使用

P.S.extension host process是个特殊的Node进程,能够访问VS Code扩展API,VS Code也对这种进程提供了debug支持

性能:插件激活

插件都是懒加载的(as late as possible),只在特定场景才加载/激活,所有在此之前也不耗费内存等资源

实现上是插件注册特定激活事件(activation events),由IDE来触发执行,比如markdown插件只在用户代开md文件时才需要激活

激活方式

插件有6种激活方式:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
onLanguage:${language} 打开特定语言的文档
onCommand:${command} 通过Command Palette执行特定命令
onDebug 进入调试模式
workspaceContains:${toplevelfilename} 打开的文件夹里含有特定文件
onView:${viewId} 展开指定view
* 打开IDE就激活

"activationEvents": ["*"]外都是条件激活,只在特定场景或满足特定条件时才加载/激活插件

插件清单文件

清单文件用来描述插件的meta信息,直接把package.json作为清单文件,并增加了一些特有字段,比如触发插件加载的激活事件(activation events)、插件想要增强的扩展点(contribution points

IDE在启动过程中扫一遍插件清单文件,UI相关的就扩展UI,UI无关的就把扩展点与插件功能关联起来

另外,由于插件的执行环境是Node进程,所以npm package都是可用的,依赖模块同样声明在package.json里。注意,用户安装插件时不会自动npm install,所以需要在发布插件前把依赖模块打包进去,具体见Installation and Packaging

P.S.扩展点类似于AOP里的Join point(连接点),即“允许在这里扩展/增强”,比如新增一个自定义命令,就是对commands扩展点的增强

manifest
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// package.json
{
 // 插件名称
 "name": "my-extension",
 // 显示名称
 "displayName": "MyExtension",
 // 描述信息
 "description": "An awesome vscode  extension",
 // 版本号 semver格式
 "version": "0.0.1",
 // 在插件市场展示的图标
 "icon": "img/icon.png",
 // 发布者名字
 "publisher": "ayqy",
 // vscode版本要求
 "engines": {
   "vscode": "^1.19.0"
 },
 // 所属分类,可选Languages, Snippets, Linters, Themes等等
 "categories": ["Other"],
 // 加载/激活方式
 "activationEvents": ["onLanguage:javascript"],
 // 入口文件路径
 "main": "./out/extension",
 // 注册扩展点关联
 "contributes": {
   "languages": [
     {
       "id": "javascript",
       "aliases": ["JavaScript", "javascript"],
       "extensions": [".js"]
     }
   ]
 }
}

P.S.完整的见Extension Manifest File – package.json

extension.ts/activate只触发一次,根据package.json声明的activationEvents来触发,触发条件可以是打开特定语言的文件,或者执行特定命令。激活之后,直到IDE被关闭/崩溃才会触发extension.ts/deactivate,所以一般用法是:

  • activate: 插件被激活,初始化功能模块单例(只执行一次)
  • deactivate: IDE即将关闭,清理现场,但不宜做太耗时的操作,因为据说最多只等待10s
扩展点

即支持的扩展类型,都声明在package.json/contributes下,包括:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
configuration 插件配置项,用户可以通过Settings设置
configurationDefaults 插件配置项默认值
commands  添加命令,用户可以通过Command Palette输入特定命令激活插件功能
menus     添加与命令关联的菜单项,用户点击菜单项时执行对应命令
keybindings 添加与命令关联的快捷键,用户按下特定快捷键时执行对应命令
languages 与文件类型建立关联或扩展新语言,用户打开(满足某些要求的)特定文件类型时执行对应命令
debuggers 添加debugger,通过VS Code debug协议与IDE通信
breakpoints 配合debuggers,声明对debugger支持的(编程)语言类型
grammars 新增TextMate语法描述,语法高亮
themes 添加定制主题
snippets 添加代码片段
jsonValidation 添加json格式校验
views 新增左侧文件查看器视图和调试视图分栏
problemMatchers 添加错误匹配,从lint结果解析出error,warning等
problemPatterns 配合problemMatchers,定义匹配模式

menus唯一的UI扩展官方途径,支持扩展的菜单具体如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Command Palette搜索框下方菜单 commandPalette
文件查看器右键菜单 explorer/context
编辑器
 右键菜单 editor/context
 标题栏菜单 editor/title
 标题栏右键菜单 editor/title/context
调试视图
 调用栈右键菜单 debug/callstack/context
SCM(源码管理)视图
 标题栏菜单 scm/title
 文件分组菜单 scm/resourceGroup/context
 文件状态菜单 scm/resource/context
 文件变动菜单 scm/change/title
左侧视图
 文件查看器分栏 view/title
 调试视图分栏 view/item/context

P.S.都是些不起眼的位置,大刀阔斧的UI定制是不支持的,比如想在左端侧边栏(Activity Bar)加个Icon都是做不到的

标题栏上的菜单扩展支持自定义icon,但定义方式比较奇怪,例如:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
"commands": [{
 "command": "markdown.showPreviewToSide",
 "title": "%markdown.previewSide.title%",
 "category": "Markdown",
 "icon": {
   "light": "./media/PreviewOnRightPane_16x.svg",
   "dark": "./media/PreviewOnRightPane_16x_dark.svg"
 }
}],
"menus": {
       "editor/title": [
           {
               "command": "markdown.showPreviewToSide",
               "when": "editorLangId == markdown",
               "alt": "markdown.showPreview",
               "group": "navigation"
           }
 ]
}

command定义iconmenu关联到command,然后menu展示对应的icon

扩展API

环境隔离让严格限制插件可用API变得容易很多,插件只能访问IDE提供的扩展性API,不能胡乱搞事情(比如修改UI DOM和样式,官方支持的主题定制项除外)

API设计原则

插件API遵循一些原则:

  • 基于Promise:异步操作都用Promise来描述
  • 取消token:传入CancellationToken作为额外参数来检查取消状态,以及接收取消通知
  • 可释放式资源管理:持有的资源都需要手动释放,例如事件监听,命令,UI交互等
  • 事件API:调用订阅方法(on[Will|Did]VerbNoun)传入listener(接收event参数)返回Disposable
  • 严格空检查:通过TypeScript严格区分undefinednull

P.S.关于“可释放式”(Disposable)的更多信息,请查看Dispose pattern

API概览

API按命名空间组织,全局命名空间如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
commands 执行/注册命令,IDE自身的和其它插件注册的命令都可以,如executeCommand
debug 调试相关API,比如startDebugging
env IDE相关的环境信息,比如machineId, sessionId
extensions 跨插件API调用,extensionDependency声明插件依赖
languages 编程语言相关API,如createDiagnosticCollection, registerDocumentFormattingEditProvider
scm 源码版本控制API,如createSourceControl
window 编辑器窗体相关API,如onDidChangeTextEditorSelection, createTerminal, showTextDocument
workspace 工作空间级API(打开了文件夹才有工作空间),如findFiles, openTextDocument, saveAll

比如可以通过workspace.findFiles + languages.registerDefinitionProvider实现Haste的全局模块引用跳转支持

另外,一些API以命令形式提供(即上面提到的“IDE自身的”命令),例如vscode.previewHtmlvscode.openFoldereditorScroll等等

基于协议的扩展

插件进程与IDE之间通过特定协议来通信,实现上是以JSON形式的stdin/stdout来通信

这种模式更强大的一点是:插件可以用任意语言来实现,只要遵守这套约定的通信协议即可

四.语言相关扩展

通过配置文件来支持语法高亮、代码片段和智能括号匹配,更复杂的通过扩展API或language server来做

配置型扩展

  • 语法高亮:基础支持区分字符串、注释、关键字等语法角色,高级支持变量、函数引用等语义区分
  • 代码片段:snippets快捷输入,基础支持简单占位符,高级支持嵌套占位符
  • 智能括号匹配:高级支持自动补充成对出现的东西,比如括号、引号、跨行注释等

注意,语言扩展VS Code支持标准Text Mate Grammar(tmLanguage格式),比如Monaco Editor的非主流Monarch-style友好很多,具体见Colorization Clarification

编程型扩展

简单配置搞不定的,都通过扩展API(写插件)来实现,有2种方式:

  • 实现language server protocol与IDE通信,完全独立
  • 注册Provider提供自定义能力,类似于hook的方式

使用上,第一种麻烦但更强大灵活,第二种方便直接但没那么灵活。支持的扩展能力如下:

  • hover提示:基础支持类型、文档等信息,高级支持方法签名语法高亮
  • 补全提示:高级支持在补全提示项旁边展示额外信息
  • 检查报错:基础支持保存时对打开的文件内容检查报错,高级支持对打开的文件目录里的任意资源检查报错
  • 方法签名:基础支持在方法签名中包含参数说明文档
  • 跳转到定义:基础支持存在多处定义时都展示出来
  • 引用查找:基础支持返回所有引用处的具体位置
  • 选中查找高亮:基础支持返回当前文档的所有相同引用
  • 方法/变量声明目录:基础支持返回文档中声明的所有标识符,及其定义位置
  • 快速修复:对Warning和Error给出建议做法,快捷修复。基础支持纠错动作,高级支持修改源码,比如重复代码提出函数
  • 上下文操作选项:允许根据用户处代码上下文,提供额外的信息与可操作选项。基础支持展示,高级可以添加自定义命令
  • 重命名:基础不支持按引用重命名,高级支持工作空间下跨文件重命名
  • 代码格式化:基础不支持代码格式化,高级支持全文/选中/输入中格式化

五.开发步骤

环境要求

  • VS Code
  • Yeoman与Yo Code – Extension Generator:npm install -g yo generator-code一步搞定

步骤

通过脚手架生成项目模版:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
yo code

命令交互选择插件类型:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
New Extension (TypeScript)
New Extension (JavaScript)
New Color Theme
New Language Support
New Code Snippets
New Extension Pack

建议TypeScript,其它都是字面意思,其中Extension Pack(插件包)比较有意思,即插件组装成的插件,类似于React Native的Nuclide

输入插件名称等meta信息,就得到一个插件项目,然后用VS Code单独打开该项目(工作空间不能有其它项目目录),F5启动debug进入插件调试

插件入口文件是my-extension/src/extension.ts,项目结构规范可以参照VS Code内置插件:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// ref: https://github.com/Microsoft/vscode/tree/master/extensions/markdown
markdown/
 media/
   *.svg
   *.css
 snippets/
   markdown.json
 syntaxes/
   *.tmLanguage
 src/
   features/
     *Provider.ts
   typings/
     *.d.ts
   commandManager.ts
   commands.ts
   logger.ts
   markdownEngine.ts
   security.ts
   telemetryReporter.ts

六.打包发布

提供了CLI工具,vsce:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
npm install -g vsce

打包

进入插件目录,打包成.vsix文件:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
cd my-extension
vsce package

会得到一个my-extesion.vsix本地包(包括node_modules依赖),然后不想公开的话,自己想办法传播安装,因为不像npm registry,可以手动部署一份,在内网环境放私有插件,Visual Studio Marketplace(VS Code插件市场)没有这么开放的心态:

If you want to share your extension with others privately, you can send them your packaged extension .vsix file.

(见Sharing Privately with Others)

没有办法部署一套Visual Studio Marketplace,所以只能想办法手动解决插件更新问题,比如自动下载/提示安装

发布

要发布到插件市场的话,需要做几件事情:

  1. 注册Visual Studio Team Services账号
  2. 进入Security页面创建个Personal Access Token
  3. vsce create-publisher (publisher name)命令新增publisher
  4. vsce login (publisher name)命令登录
  5. vsce publish -p <token>命令发布

具体见Publishing Extensions

参考资料

  • Extending Visual Studio Code
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2018-02-03,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 前端向后 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
VS Code插件开发介绍(一)
前段时间做了一个基于命令行的效率工具,可以自动生成组件的模板代码。自己用起来还觉得挺好,但在组内案例几次后大家都不愿意用,究其原因还是命令行工具使用起来门槛有点高,不方便。由于组内已经统一使用VS Code进行开发了,于是决定研究下VS Code的插件开发,让效率工具更方便的用起来。
Dickensl
2022/06/14
8500
VS Code插件开发介绍(一)
vscode插件开发入门
在我们日常使用中,会安装很多插件,如: 主题、Prettier、code snippets、Eslint、Jest Runner、Git等等。每种插件都能解决我们实际开发中的某一块诉求。我把所有的插件大致归为三类:UX/UI类、语言类、工具类
gary12138
2022/10/05
6.5K0
vscode插件开发入门
【VSCode】插件开发——基础的基础
Activation Events is a set of JSON declarations that you make in the activationEvents field of package.json Extension Manifest. Your extension becomes activated when the Activation Event happens.
WEBJ2EE
2020/11/05
8700
【VSCode】插件开发——基础的基础
【Web技术】746- VSCode 插件开发入门教程
之前一直以为开发VS code插件是一件很难的事情,后来工作上需要搞一个效率小工具,就试着找了些资料来入门,发现其实就入门和开发一些简单功能的插件来说难度还是很低的。因为vscode本身是基于electron开发的,所以总体来说开发插件就是在写node代码,额外再加一些编辑器api,插件发布的过程和npm包的发布很类似。
pingan8787
2020/10/23
2.6K0
【Web技术】746- VSCode 插件开发入门教程
从零开发一款基于 webview 的 vscode 扩展
在团队降本提效的基建中,洛竹开发了一款 vscode 插件,第一版我使用的是 vscode 内置 UI,虽说也能用,但是用户体验欠佳。由于 vscode 内置 UI 不够灵活,一番调研后我决定使用 webview 重构。
用户1250838
2021/09/18
5.3K0
从零开发一款基于 webview 的 vscode 扩展
写一个VSCode扩展
自从使用过 VSCode 后就再也离不开 VSCode,其轻量的代码编辑器与诸多插件让多数开发者爱不释手。同样我也不例外,一年前的我甚至还特意买本《Visual Studio Code 权威指南》的书籍,来更进一步了解与使用。
愧怍
2022/12/27
3.2K0
写一个VSCode扩展
VS Code 折腾记 - (10) 你想发布自己捣鼓的snippets到VSCode插件市场!
em..自认为英文不错和自学能力灰常好的大佬,到这里可以停止阅读了,省的浪费时间!
CRPER
2018/08/28
1.1K0
VS Code 折腾记 - (10) 你想发布自己捣鼓的snippets到VSCode插件市场!
VSCode跳转到定义内部实现_VSCode插件开发笔记4
从源码来看,VSCode主体只是个Editor(核心部分可在Web环境独立运行,叫Monaco),并不提供任何语言特性相关的功能,比如:
ayqy贾杰
2019/06/12
5.1K0
VSCode跳转到定义内部实现_VSCode插件开发笔记4
DIY VSCode 插件,让你的开发效率突飞猛进
Visual Studio Code(简称 VSCode)凭借其占用内存小、文件加载快、稳定性好、插件丰富等等特点,从众多 IDE 中脱颖而出,受到了广大开发人员的青睐。工欲善其事,必先利其器。选择适合自己的 VSCode 插件,能够让你的开发效率突飞猛进。VSCode 插件市场 上面插件百花齐放,但实际开发过程中问题复杂且多变,有时候并不能找到完全满足你实际开发需求的插件,那就自己动手 DIY 一个吧。VSCode 提供以下扩展能力:代码自动补全、自定义命令/菜单/快捷键、悬浮提示、自定义跳转、主题定制、自定义 WebView 等等。你可以根据自己的需要随意组合使用。
政采云前端团队
2019/12/19
2.2K0
一起来写 VS Code 插件:实现一个翻译插件
上一篇介绍了用 code snippets 的方式开发一个插件,本文将通过实现一个翻译插件实例的方式来熟悉 VS Code 插件开发的常见功能和方法。当然大家可以前往 VS Code 官网API 和官方 GitHub 示例 查看和学习。
狂奔滴小马
2021/11/22
1.6K0
一起来写 VS Code 插件:实现一个翻译插件
Webview 为 VSCode 开启了一扇门,安全限制却又把它关上了
关注「前端向后」微信公众号,你将收获一系列「用心原创」的高质量技术文章,主题包括但不限于前端、Node.js以及服务端技术
ayqy贾杰
2019/12/25
5.8K0
Webview 为 VSCode 开启了一扇门,安全限制却又把它关上了
VSCode变量命名转换插件(Var-Conv)
有一个良好的变量命名方式对于一个程序员是相当的重要的,但是入门的编程语言不同或者各自的习惯不同导致实际工作中的变量命名依然是层次不齐的,在不同的平台间,服务间的变量命名更是什么样的都有,为了应对不同的变量命令我一开始使用的是uTools中的插件,也推荐更多朋友使用,在IED中选中变量后alt+空格呼起uTools会自动匹配到变量替换的插件,但是最后升级后发现还需要搜索到插件后才能再转换,所以就想不脱离VSCode就可以直接转换变量的命名方式,通过一顿的搜索参考,终于把这个插件做了出来。
前端小鑫同学
2022/12/26
1.3K0
VSCode变量命名转换插件(Var-Conv)
教你动手写VScode插件 - 初探
摘要 在我之前的文章中,我使用了不同编程语言开发了如下许多上位机。 序号内容语言1《如何定制自己的HID调试助手》C#2《C# 串口上位机开发》C#3《Qt 串口上位机开发》QT4《教你动手写UDP协议栈 - OTA上位机》python5《基于RT-THREAD nano的平衡车--上位机软件》QT6《R-Plan上位机》QT7《BearPi TCP》QT 你会发现很零散,集成度,而且久而久之就没有维护了。今天我又来解锁一种开发工具的神器--VScode插件。 其实vscode现在已经很多大厂先后开发出他们
Rice加饭
2022/05/10
2.1K0
教你动手写VScode插件 - 初探
API注入机制及插件启动流程_VSCode插件开发笔记2
在插件进程环境,可以引入vscode模块访问插件可用的API,好奇一点的话,能够发现node_modules下并没有vscode模块,而且vscode模块也名没被define()过,看起来我们require了一个不存在的模块,那么,这个东西是哪里来的?
ayqy贾杰
2019/06/12
1.2K0
Vue3+NodeJS 接入文心一言, 发布一个 VSCode 大模型问答插件
随着大模型能力越来越卷,在垂直领域的落地也在加快,对于大模型代码生成能力而言,最简洁高效的方式就是集成为常用IDE的插件,在vscode的插件战场中,比较知名的就有 GitHub Copilot, 智谱清言的codegeex, 讯飞星火的iFlyCode。
五月君
2023/11/14
2.6K0
Vue3+NodeJS 接入文心一言, 发布一个 VSCode 大模型问答插件
你不知道的 VSCode 代码高亮原理
Vscode 的代码高亮、代码补齐、错误诊断、跳转定义等语言功能由两种扩展方案协同实现,包括:
winty
2021/07/01
3.1K1
你不知道的 VSCode 代码高亮原理
VSCode拓展推荐(前端开发)
Text-to-speech function is limited to 200 characters
botkenni
2019/09/03
2.6K0
萌新看过来,你还学不懂VScode插件吗?
VSCode是微软家一个非常轻量化的编辑器,体量虽轻,但是却有异常强大的功能。原因在于VSCode许多强大功能都是基于插件实现的,IDE只提供一个最基本的框架和基本功能,我们需要使用插件来丰富和扩展它的功能。
葡萄城控件
2022/05/09
9810
萌新看过来,你还学不懂VScode插件吗?
实例解析:如何开发 VSCode LSP 服务
上图应该大家经常使用的「错误诊断」 功能,它能够在你编写代码的过程中提示,那一块代码存在什么类型的问题。
桃翁
2021/08/13
1.8K0
实例解析:如何开发 VSCode LSP 服务
从小白到大白 — 如何开发 VSCode 插件
由于之前的国际化的项目中总是要统计老项目中待翻译的内容,然后再交由业务进行翻译,如果总是人为统计不仅相当耗费精力和时间,而且还不能保证是否有遗漏,因此想通过编写一个 i18n-helper 插件来实现这个功能。
winty
2023/11/12
2.3K0
从小白到大白 — 如何开发 VSCode 插件
推荐阅读
相关推荐
VS Code插件开发介绍(一)
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档