前端知识体系
GitHub (opens new window)

GuoLiBin6

程序员永不下班
GitHub (opens new window)
  • 介绍
  • 前端基础

  • 浏览器基础

  • 软件开发

  • 数据结构

  • 性能优化

  • Node.js

  • 收录

  • 搞事啦

    • python

      • 爬虫
    • vscode插件开发
      • 一、环境准备及项目初始化
        • 1. 准备环境
        • 2. 初始化插件项目
        • 3. 插件运行及调试
        • 4. 开发初试
        • a. 修改Hello World命令行为
        • b. 定义命令弹出警告框
      • 二、了解插件能力及项目架构
        • 1. 插件能干什么
        • a. 插件通用功能
        • b. 主题化
        • c. 声明性语言特性
        • d. 程序语言特性
        • e. 扩展工作台
        • f. 调试
        • 2. 项目结构
        • a. package.json
        • 1)main
        • 2)activationEvents
        • 3)contributes
      • 三、开发实战
        • 1. 插件目标
        • 2. 目标实现
        • a. 增加右键菜单
        • b. 程序获取用户选择文本
        • c. 用户选择文本后自动弹出提示
        • d. 实现翻译
      • 四、发布
        • 1. 发布方式
        • a. 本地文件
        • b. 打包成 vsix 插件
        • c. 发布到官网应用市场
        • 2. 打包成 vsix 插件
        • 3. 发布到官网
  • 前端知识体系
  • 搞事啦
GuoLiBin6
2023-05-09
目录

vscode插件开发

简单的中英翻译的vscode插件实现全过程介绍

# 一、环境准备及项目初始化

# 1. 准备环境

先使用的是 centsos 开发环境,但是会一直有权限问题,所以切换到了 mac 开发环境

确保安装了 Node.js 和 Git,安装以下工具:

npm install -g yo generator-code
1

# 2. 初始化插件项目

生成器搭建一个准备开发的 TypeScript 或 JavaScript 项目。运行生成器并为 TypeScript 项目填写几个字段:

> 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? WordTranslate
? What's the identifier of your extension? wordtranslate
? What's the description of your extension? 
? Initialize a git repository? Yes
? Bundle the source code with webpack? Yes
? Which package manager to use? npm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

# 3. 插件运行及调试

项目生成完后,在编辑器中,按 F5 ,会弹出配置提示,选择【配置任务】,随后选择 【npm:compile】即可

完成后编辑器会开启一个新的窗口,标题为 [扩展开发宿主机], 在这个窗口中已经加载了我们的插件,就可以使用了

打出组合键 ⇧⌘P,输入 >Hello World 随后回车,在编辑器右下角,就可以看到我们的插件的通知了

# 4. 开发初试

# a. 修改Hello World命令行为

修改 src/extension.ts 中 Hello World from WordTranslate!为 Hello vscode !,随后调出命令preload,选择 【开发人员:重新加载窗口】,重新加载插件,随后 执行Hello Wold命令,查看变化

以上是以 Hello World 命令做出一个普通提示框。也可以自定义其他命令做出其他操作

# b. 定义命令弹出警告框

package.json

"commands": [
  {
    "command": "wordtranslate.helloWorld",
    "title": "Hello World"
  },
  // 新增 DoNotSupport 命令
  {
    "command": "wordtranslate.doNotSupport",
    "title": "DoNotSupport"
  }
]
1
2
3
4
5
6
7
8
9
10
11

src/extension.ts

  // 增加 doNotSupport 命令的注册
  let doNotSupport = vscode.commands.registerCommand('wordtranslate.doNotSupport', () => {
    vscode.window.showWarningMessage('您当前编辑器不支持此版本插件!');
  });

  context.subscriptions.push(doNotSupport);
1
2
3
4
5
6

重新加载窗口,执行命令 doNotSupport,可看到警告框

注: 以下为 package.json 中命令的配置参数示例,更多详细信息可参考 Contribution Points | Visual Studio Code Extension API (opens new window)

{
  "contributes": {
    "commands": [
      {
        "command": "extension.sayHello",
        "title": "Hello World",
        "category": "Hello",
        "icon": {
          "light": "path/to/light/icon.svg",
          "dark": "path/to/dark/icon.svg"
        }
      }
    ]
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

至此,项目就跑起来了

# 二、了解插件能力及项目架构

插件就是利用 vscode 给我们开放的一些API的基础上进行扩展功能的开发,从而解决开发中的一些问题,提高生产效率。这种插件化思想一方面使该代码编辑器更轻量化;另一方面能够充分利用社区的力量,为其提供更加多元化的插件。

# 1. 插件能干什么

# a. 插件通用功能

可以在任何扩展中使用的核心功能,主要包括以下几点:

  • 能够添加命令、配置项、快捷键、菜单项、右键菜单;

  • 存储工作区或全局数据;

  • 展示通知信息;

  • 使用快速选择收集用户的输入;

  • 打开文件选择器让用户去选择文件或文件夹;

  • 使用Progress API去阐述长时间运行的操作;

# b. 主题化

控制vscode的外观,包括编辑器中源代码的颜色和vscode ui的颜色,其主要包含三种类型的主题:

  • 颜色主题:其允许将颜色应用于VS Code UI组件和编辑器中的文本;

  • 文件图标主题:文件图标显示在VS Code UI中的位置,例如文件资源管理器、快速打开列表和编辑器选项卡;

  • 产品图标主题:在整个UI中使用的一组图标

# c. 声明性语言特性

声明性语言功能为编程语言添加了基本的文本编辑支持,例如括号匹配、自动缩进和语法突出显示。

# d. 程序语言特性

编程语言功能添加了丰富的编程语言支持,例如悬停、转到定义、诊断错误、IntelliSense 和 CodeLens。

# e. 扩展工作台

工作台是指包含标题栏、活动栏、侧边栏、控制板、编辑组、状态栏等UI组件的整体Visual Studio Code UI。VS Code提供了各种API,允许将自己的组件添加到工作台。

# f. 调试

可以通过编写将 VS Code 的调试 UI 连接到特定调试器或运行时的调试器扩展来利用 VS Code 的调试功能。

# 2. 项目结构

以下是初始化项目完成后的目录结构,其中重要的就是 extension.ts 和 package.json 两个文件

# a. package.json

{
  "name": "wordtranslate", // 插件名称
  "displayName": "WordTranslate", // 显示在应用市场的名字
  "description": "", // 插件描述
  "version": "0.0.1", // 插件版本号
  "engines": {
    "vscode": "^1.77.0" // 最低支持的vscode版本
  },
  "categories": [
    "Other" // 扩展类别
  ],
  "activationEvents": [], // 激活事件组,在哪些事件下会被激活
  "main": "./dist/extension.js", // 插件的主入口文件
  "contributes": { // 贡献点
    "commands": [ // 命令
      {
        "command": "wordtranslate.helloWorld",
        "title": "Hello World"
      },
      {
        "command": "wordtranslate.doNotSupport",
        "title": "DoNotSupport"
      }
    ]
  },
  "scripts": {
    "vscode:prepublish": "npm run package",
    "compile": "webpack",
    "watch": "webpack --watch",
    "package": "webpack --mode production --devtool hidden-source-map",
    "compile-tests": "tsc -p . --outDir out",
    "watch-tests": "tsc -p . -w --outDir out",
    "pretest": "npm run compile-tests && npm run compile && npm run lint",
    "lint": "eslint src --ext ts",
    "test": "node ./out/test/runTest.js"
  },
  "devDependencies": { // 开发依赖项
    "@types/vscode": "^1.77.0",
    "@types/glob": "^8.1.0",
    "@types/mocha": "^10.0.1",
    "@types/node": "16.x",
    "@typescript-eslint/eslint-plugin": "^5.56.0",
    "@typescript-eslint/parser": "^5.56.0",
    "eslint": "^8.36.0",
    "glob": "^8.1.0",
    "mocha": "^10.2.0",
    "typescript": "^4.9.5",
    "ts-loader": "^9.4.2",
    "webpack": "^5.76.3",
    "webpack-cli": "^5.0.1",
    "@vscode/test-electron": "^2.3.0"
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53

文件中 activationEvents、main、contributes 这三个配置项需要格外关注

# 1)main

标明了插件的入口在哪,只有找对了入口,项目才能正确运行

# 2)activationEvents

标明该插件在何种情况下会被激活,只有激活后插件才能正常使用,官网已经指明了激活的时机,我们只需要设置对应的时机去激活插件就可以了。

  • onLanguage: 打开解析为特定的语言文件时被激活,如:onLanguage: python
  • onCommand: 在调用命令时激活
  • onDebug: 在启动调试之前被激活
  • onDebugInitialConfigurations
  • onDebugResolve
  • workspaceContains: 每当打开文件夹并且该文件夹包含至少一个与glob模式匹配的文件时
  • onFileSystem: 每当读取来自特定方案的文件和文件夹时
  • onView: 当 vscode 侧栏中展开指定 id 的视图
  • onUri: 当打开该扩展的系统范围的 Uri 时
    • onWebviewPanel
    • onCustomEditor
    • onAuthenticationRequest
  • *:只要一启动 vscode,该插件就被激活
  • onStartupFinished
# 3)contributes
  • breakpoints:断点,可列出将启用断点的语言文件类型
  • colors:颜色,提供新的主题颜色
  • commands:命令,可设置由标题、类别、图标和启用状态组成的命令ui
  • configuration:配置,提供将向用户开放的配置键
  • configurationDefaults:为其他已注册的配置提供默认值并覆盖其默认值
  • customEditors:标识自定义编辑器的信息
  • debuggers:调试器
  • grammars:语法
  • icons:按插件id设置新图标和一个默认图标
  • iconThemes:文件图标主题
  • jsonValidation:为特定类型的文件提供验证框架
  • keybindings:键绑定规则
  • languages:编程语言的定义
  • menus:菜单
  • problemMatchers:问题匹配器
  • problemPatterns:问题匹配器中使用的命名问题模式
  • productIconThemes:产品图标主题
  • resourceLabelFormatters:语义标记修饰符
  • semanticTokenModifiers:语义标记类型和修饰符与范围之间的映射,作为回退或支持特定语言的主题
  • semanticTokenScopes
  • semanticTokenTypes
  • snippets
  • submenus
  • taskDefinitions
  • terminal
  • themes
  • typescriptServerPlugins
  • views
  • viewsContainers
  • viewsWelcome
  • walkthroughs

# 三、开发实战

# 1. 插件目标

看名释意: WordTranslate 词汇翻译

预期实现:选择一段文字后,右键可以增加一个翻译的菜单,进行中英翻译

# 2. 目标实现

# a. 增加右键菜单

官方文档:(Contribution Points | Visual Studio Code Extension API)[https://code.visualstudio.com/api/references/contribution-points#contributes.menus]

package.json 文件修改

  "contributes": {
    "commands": [
      {
        "command": "wordtranslate.helloWorld",
        "title": "Hello World"
      },
      {
        "command": "wordtranslate.doNotSupport",
        "title": "DoNotSupport"
      }
    ],
    // 增加按钮配置内容
    "menus": {
      "editor/context": [
        {
          "command": "wordtranslate.helloWorld",
          "group": "navigation"
        }
      ]
    }
  },
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

运行插件,右键 可看到增加的 Hello Wold 菜单,点击可看到右下角弹框提示

# b. 程序获取用户选择文本

src/extension.ts 修改

let disposable = vscode.commands.registerCommand('wordtranslate.helloWorld', () => {
    // vscode.window.showInformationMessage('Hello vscode !');
    // 获取当前激活的文本编辑器实例
    const editor = vscode.window.activeTextEditor;
    if (editor) {
      // 获取当前用户选中的文本
      const selection = editor.selection;
      const selectedText = editor.document.getText(selection);

      vscode.window.showInformationMessage(`选中的文本是:${selectedText}`);
    } else {
      vscode.window.showInformationMessage(`当前没有打开的文本编辑器。`);
    }
  });
1
2
3
4
5
6
7
8
9
10
11
12
13
14

以上代码实例将原本的 Hello vscode提示,修改为根据用户选择文本进行提示。效果如下:

# c. 用户选择文本后自动弹出提示

失败方案,通过右键菜单点击后提示弹框,展示不方便,所以换成以下方案

思路:利用鼠标移上hover弹出provider,包含选择的文本

src/extension.ts 修改

// 定义一个HoverProvider
const hoverProvider = {
  provideHover(document: any, position: any) {
    const editor = vscode.window.activeTextEditor;
    if (editor) {
      // 获取当前用户选中的文本
      const selection = editor.selection;
      const selectedText = editor.document.getText(selection);
      if (selectedText) {
        return new vscode.Hover('选择文本:' + selectedText);
      }
    }
  },
};
// 注册HoverProvider
const languageSelector = [ // 匹配到对应的文件才激活HoverProvider
  { language: 'javascript', scheme: 'file' },
];
const showTranslate = vscode.languages.registerHoverProvider(languageSelector, hoverProvider);
context.subscriptions.push(showTranslate);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

但是上述文件在 activate 中,即插件激活后才会被启动,打开调试后右键菜单点击Hello World之后,插件激活后可以查看效果,若需要编辑器启动即启动插件,则需要增加相应的配置

package.json 修改

  "activationEvents": [
    "onLanguage:javascript" // 检测到打开js文件时启动插件
  ],
1
2
3

这样当编辑器打开js文件时,插件就会启动,效果如下:

# d. 实现翻译

使用第三方翻译API,这里使用百度翻译API

首先注册成为开发者,地址:百度翻译开放平台 (baidu.com) (opens new window)

接入百度翻译API

  const hoverProvider = {
    async provideHover(document: any, position: any) {
      const editor = vscode.window.activeTextEditor;
      if (editor) {
        // 获取当前用户选中的文本
        const selection = editor.selection;
        const selectedText = editor.document.getText(selection);
        if (selectedText) {
          const translation = await translate(selectedText);
          if (translation) {
            return new vscode.Hover("翻译文本:" + translation);
          } else {
            return new vscode.Hover("选择文本:" + selectedText);
          }
        }
      }
    },
  };
  // 注册HoverProvider
  const languageSelector = [{ language: "javascript", scheme: "file" }];
  const showTranslate = vscode.languages.registerHoverProvider(
    languageSelector,
    hoverProvider
  );

  async function translate(text: string) {
    // 百度翻译的 API 地址和 APP ID 与密钥
    const apiEndpoint = "https://fanyi-api.baidu.com/api/trans/vip/translate";
    const appid = "your_own_appid"; // 此处替换为你自己的开发者appid
    const key = "your_own_key"; // 此处替换为你自己的额开发者key

    // 设置 API 请求参数
    const sourceLang = "auto";
    const targetLang = "zh";
    const query = text;
    const salt = Math.round(Math.random() * 100000); // 随机数,用于签名
    const sign = baiduSign(query, appid, salt, key);
    const params = `?q=${encodeURIComponent(
      query
    )}&from=${sourceLang}&to=${targetLang}&appid=${appid}&salt=${salt}&sign=${sign}`;

    // 发送 HTTP 请求获取翻译结果
    return new Promise<string | undefined>((resolve, reject) => {
      const req = https.get(apiEndpoint + params, (res) => {
        let data = "";
        res.on("data", (chunk) => {
          data += chunk;
        });
        res.on("end", () => {
          const result = JSON.parse(data);
          if (result?.trans_result?.length > 0) {
            resolve(result.trans_result[0].dst);
          } else {
            reject("Translation failed!");
          }
        });
      });
      req.on("error", (error) => {
        console.error('error', error);
        reject(error);
      });
    });
  }

  function baiduSign(query: string, appid: string, salt: number, key: string) {
    // 计算百度翻译 API 的签名,用于 API 认证
    const signString = `${appid}${query}${salt}${key}`;
    const md5 = require("md5");
    return md5(signString);
  }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70

效果如下:

基于以上内容,我们可以获取用户选择的文本,并且接入百度翻译API翻译成指定语言的文本,并在鼠标hover时展示,目标功能基本完成

# 四、发布

# 1. 发布方式

# a. 本地文件

直接把文件夹发给别人,让别人找到 vscode 插件存放目录放进去,然后重启 vscode,一般不推荐

# b. 打包成 vsix 插件

打包成vsix插件,发给别人安装,如果插件涉及到机密不方便发送到应用市场,可以尝试使用这种方式

# c. 发布到官网应用市场

注册开发者账号,发布到官网应用市场,这个发布和npm一样是不需要审核的。

# 2. 打包成 vsix 插件

打包需要用到 vsce

npm install vsce -g
1

打包,打包前需修改 README.md , 并且在 package.json 文件中增加 repository 配置

vsce package
1

安装时需 从插件右上角,从 VSIX 安装

安装完成后就可以正常使用了,从已安装的插件中也可以找到

# 3. 发布到官网

发布过程未经过实操,可参考 VSCode插件开发全攻略(十)打包、发布、升级 - 我是小茗同学 - 博客园 (cnblogs.com) (opens new window)

上次更新: 2023-05-10 14:57:44
爬虫

← 爬虫

最近更新
01
蛤蟆先生去看心理医生
04-12
02
梁永安:阅读、游历和爱情
03-20
03
阿甘正传
02-07
更多文章>
Theme by Vdoing | Copyright © 2022-2024 GuoLiBin6
冀ICP备2022013865号-1
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式