一个简单 VS Code 插件编写教程

902 阅读5分钟

前言

在写代码时, 我们经常会用到枚举值, 比如这样:

enum TEST{
    TEST_WORD_1 = 'testWord1',
    TEST_WORD_2 = 'testWord2',
}
const TEST_WORD = 'testWord';

TEST_WORD 为例, 虽然字母相同, 但无论是先输入 TEST_WORD, 还是 testWord, 你都需要自己手动输入另一个对应的大写+下划线或是小驼峰式。

再输入一遍虽然也花不了多少时间,但秉着能懒则懒的精神,我们可以通过一个 VS Code 插件来帮我们自动添加需要的字符。

接下来,我们就一起来看一下这个 VS Code 插件如何编写。

本文的目录结构如下:

脚手架初始化项目

需求已经明确,那我们就动手开干吧。

在这里,我选用了官方的脚手架来初始化项目。

yarn global add yo generator-code

yo code

之后就是输入项目的一些配置信息了, 如使用 TS , 设置插件名字等。

项目结构

打开脚手架初始化好的项目, 可以看到如下的结构了:

├── CHANGELOG.md
├── README.md
├── node_modules
   └── ...
├── build
   └── node-extension.webpack.config.js
├── dist
   ├── extension.js
   └── extension.js.map
├── package.json
├── src
   ├── extension.ts
   └── test
       ├── runTest.ts
       └── suite
           ├── extension.test.ts
           └── index.ts
├── tsconfig.json
├── vsc-extension-quickstart.md
└── yarn.lock

目前我们只需要知道两个文件就可以了。一个是 src/extension.ts,这个是插件的入口; 另一个是 package.json, 保存着插件的一些配置信息, 这个之后会再提到。

项目入口

我们先来看 src/extension.ts

以下是脚手架帮我们生成的代码(删除了注释):

import * as vscode from 'vscode';

export function activate(context: vscode.ExtensionContext) {
    console.log('Congratulations, your extension "faster-enum" is now active!');
    let disposable = vscode.commands.registerCommand('faster-enum.helloWorld', () => {
        vscode.window.showInformationMessage('Hello World from faster-enum!');
    });

    context.subscriptions.push(disposable);
}
export function deactivate() {}

先来简单的介绍一下:

  • 首先是函数 activate,就是插件被激活时会触发的代码;
  • vscode.commands.registerCommand 方法注册了一个名字叫 faster-enum.helloWorld 的命令, 作用是弹出一个 **Hello World from faster-enum! **的信息框;
  • 函数 deactivate 是插件被释放时会触发的代码;

配置清单

虽然在项目入口中定义了命令, 但是 vscode 此时并不知道要在什么时候去执行, 比如说是在右键菜单中点击, 还是再命令菜单中选择, 这些都是要在配置清单 package.json 中配置的。

配置如下:

{
    "activationEvents": [
        "onCommand:faster-enum.helloWorld"
    ]
}

其中 activationEvents 表示的是激活事件, 当激活事件触发时, 插件就会被激活。 onCommand:faster-enum.helloWorld 表示的就是调用命令时激活 faster-enum.helloWorld 这个之前注册的命令。

另外,我们还需要配置 contributescontributes 表示的是发布内容配置, 可以在其中注册各种配置项扩展 VS Code 的能力。

{
    "contributes": {
        "commands": [
            {
                "command": "faster-enum.helloWorld",
                "title": "Hello World"
            }
        ]
    }
}

commands 配置项配置了 vscode 命令面板中可以使用的命令, 比如脚手架中的这个我们可以先 f5 运行项目后, 在命令面板(cmd + P)中输入 >hello 点击下方出现的命令后就可以在右下角看到弹出框了。

contributes 具体的配置还是比较复杂的, 建议还是再官网上熟悉下比较好, Contribution Points | Visual Studio Code Extension API

插件开发

项目配置好以后,接下来我们就开始插件开发了。

功能1:大写转小驼峰

首先我们先来注册我们的这个命令:

export function activate(context: vscode.ExtensionContext) {
    context.subscriptions.push(
        vscode.commands.registerTextEditorCommand('faster-enum.toLowerCamelCase', (textEditor, edit) => {

        })
    )
}

可以注意到我这里没有使用 vscode.commands.registerCommand 而是使用了vscode.commands.registerTextEditorCommand, 这两者的区别就是, 后者只会在文本编辑器被激活时调用才生效, 而且其能直接访问到当前的活动编辑器(通过参数传入)。

我们要实现的效果是, 选中文本后, 右键菜单执行相关命令, 所以我们要对选中状态进行一个判断,

vscode.commands.registerTextEditorCommand('faster-enum.toLowerCamelCase', (textEditor, edit) => {
    if (textEditor.selection.isEmpty) { // 未选中文本直接返回
	return;
    }

    // TODO
})

接着, 我们考虑如何得到选中的文本。

首先要明确一点, 在活动编辑器 textEditor中, 并没有直接的属性让我们获取到选中的文本, 我们必须要得到选中的文本在编辑器中的位置信息, 才能通过调用 textEditor.document.getText 来得到文本, 代码如下:

vscode.commands.registerTextEditorCommand('faster-enum.toLowerCamelCase', (textEditor, edit) => {
    if (textEditor.selection.isEmpty) { // 未选中文本直接返回
	return;
    }
    const textRange = new vscode.Range(textEditor.selection.start, textEditor.selection.end);
    const text = textEditor.document.getText(textRange);
})

textEditor的属性和方法可以看这里VS Code API | Visual Studio Code Extension API

获得了选中的文本后就简单了, 写个函数进行处理下, 之后通过 edit.replace 方法去替换文本就好了。

export const toLowerCamelCase = (str: string) => {
    if (str.length < 2) {
        return str.toLowerCase();
    }
    const [firstWords, …otherWords] = str.split('_');
    return firstWords.toLowerCase() + otherWords.filter(word => !!word).map(word => word[0].toUpperCase() + word.slice(1, word.length).toLowerCase()).join('');
}
vscode.commands.registerTextEditorCommand('faster-enum.toLowerCamelCase', (textEditor, edit) => {
    if (textEditor.selection.isEmpty) { // 未选中文本直接返回
	return;
    }
    const textRange = new vscode.Range(textEditor.selection.start, textEditor.selection.end);
    const text = textEditor.document.getText(textRange);
    edit.replace(textRange, toLowerCamelCase(text));
})

在右键菜单中添加命令

逻辑代码写好后别忘记在配置清单 package.json 中配置一下:

{
    "activationEvents": [
        "onCommand:faster-enum.toLowerCamelCase"
    ],
    "contributes": {
        "menus": {
            "editor/context": [
                {
                    "when": "editorFocus",
                    "command": "faster-enum.toLowerCamelCase"
                }
            ]
        },
        "commands": [
            {
                "command": "faster-enum.toLowerCamelCase",
                "title": "toLowerCamelCase",
                "category": "faster-enum"
            }
        ]
    }
}

可以看到 contributes 中多了好多之前没提到的属性, 别急, 我来简单解释下

  • menus 表示的是对菜单的配置, 可以是文本编辑器中的右键菜单, 可以是右上角标题栏处的菜单, 这些都可以配置;
  • editor/context 表示的就是文本编辑器中的右键菜单, 它是一个数组, 数组的每一项就是菜单中的一个选项;
  • when 表示的是此菜单项会在什么时机出现;

注意在菜单中编写的命令都要在 commands 中同样配置一遍。

运行插件

到这里,一个简单的 VS Code 插件就开发完成了,我们可以通过按 f5 来测试一下。

参考文献

参考资料如下: