开发一款专属的 VSCode 代码提示插件

简介: 作为前端开发者一定用过VsCode这款利器,而其强大的插件能力无疑更是让我们深深的爱上了它。据不完全统计,VsCode插件市场中的插件数量已经超过了3万,由此可见大家的热情有多高。其中涉及到各种各样功能的插件,有主题曲相关的,有代码开发相关的,比如代码片段、Git插件、tslint等等。作为开发者,肯定用过各种各样的代码提示的插件,代表性的有TabNine、Copilot等等。今天就让我们来自己动手,开发一款专属的代码提示插件。毕竟别人的再好也是别人的, 属于自己的才是最好的。


图片.png

作为前端开发者一定用过VsCode这款利器,而其强大的插件能力无疑更是让我们深深的爱上了它。据不完全统计,VsCode插件市场中的插件数量已经超过了3万,由此可见大家的热情有多高。其中涉及到各种各样功能的插件,有主题曲相关的,有代码开发相关的,比如代码片段、Git插件、tslint等等。作为开发者,肯定用过各种各样的代码提示的插件,代表性的有TabNine、Copilot等等。今天就让我们来自己动手,开发一款专属的代码提示插件。毕竟别人的再好也是别人的, 属于自己的才是最好的。


开发前准备


1、环境搭建

关于VsCode插件的开发环境搭建教程网上有很多,这里就不进行赘述了,具体可以参考这里的官方文档(https://code.visualstudio.com/api/get-started/your-first-extension)。


2、关于代码提示

这里的代码提示是指在编写代码过程中,VsCode基于当前的输入,会弹出一个面板,显示出你可能的一些输入。如果存在你预期的输入,直接按enter或者tab键(可以在设置中进行修改)即可将推荐的代码输入到编辑器中。这样可以极大的提升我们开发的效率,毕竟按一个键直接一行代码,远比我们一个一个字符敲出来高效。


image.gif图片.png


看到这里,大家可能会好奇,这里有这么多推荐的选项,那么这些代码是从哪里来的呢?为什么有的根本不是我想要的也会被推荐呢?这里据我研究(我也没看过源码),这里的选项来源有以下几个:

  1. LSP(语言服务协议)的具体实现,其实就是VsCode支持语言。比如选择了TypeScript,在编写代码时就会出现ts语法相关的提示。举个例子,比如输入了con,那么这里出现的constconsole以及continue都是ts语法中的关键字。
  2. 各种内置的代码片段(Code Snippet)。VsCode本身就有很多内置的代码片段,代码片段也可以帮助我们进行快速的输入,一般的代码片段都不止一行代码,可以帮我们省略很多输入。除了内置的代码片段,我们也可以配置自己的代码片段,这个也是我们定义专属插件的一部分。


image.gif图片.png

图片.png

  1. 对象路径、导出对象提示,比如我在另外的文件中定义了一个 APP的常量和一个Test的方法,然后在当前文件中,输入 AP,可以看到第一条就是之前定义的常量,这个时候按下tab之后,不仅会补全变量名,同时会在顶部加入 import语句

image.gif图片.png

image.gif

  1. 最后就是各种插件提供的选项了,这部分也是我们今天开发专属插件的主要内容。可以看出,繁多的插件带来了很多提示,但同时也加重了我们辨别、思考的负担,在一页页提示中找我们想要的代码,然而有这个时间可能早已经全部敲出来了。因此插件并不是万能的神器,也不是数量越多越好,仅仅安装一些常用、好用的插件即可。

image.gif

图片.png


插件开发


1、代码片段配置

代码片段配置方法有两种:

  1. 直接配置在VsCode中,方法为:
  • 呼出VsCode 命令面板,找到代码片段配置

image.gif图片.png

  • 选择要配置的语言,比如这里选择typescriptrect,就是我们常用的.tsx文件。(这个是tsx文件类型在vscode中的key)

图片.png

  • 选择之后会展示当前本地默认的代码片段配置,比如Python长这样。而我们要做的就是在这个json文件中加入我们自己的代码片段。

图片.png

  1. 开发代码片段的插件:

同时也可以开发一个代码片段相关的插件,这样不管在哪里,直接下载对应的插件就可以多个编辑器通用,比存在本地好很多。

代码片段插件的开发相对简单,就只需两步:

  • 在插件脚手架根目录中加入一份json格式的配置文件即可。
  • package.json中增加如下配置。作用是声明代码片段相关的信息,包含:对应的语言,即文件类型,代码片段对应的路径。下面展示的是同一份配置文件同时应用于 tstsxjsjsx文件。
"contributes": {
  "snippets": [
   {
    "language": "typescriptreact",
    "path": "./snippets.json"
   },
   {
    "language": "typescript",
    "path": "./snippets.json"
   },
   {
    "language": "javascript",
    "path": "./snippets.json"
   },
   {
    "language": "javascriptreact",
    "path": "./snippets.json"
   }
  ]
 },


2、代码片段的一些思路


代码片段相对简单,就是把一些固定的模式配置出来,通过快捷键直接输入。这里提供几个思路:

  • 组件开发代码片段,因为每次新组件的开发有很多固定的内容,因此很容易想到把这些代码记到代码片段里,这里提供一份参考:
"component": {
  "prefix": [
   "component"
  ],
  "body": [
   "import * as React from 'react';",
   "",
   "export interface IProps {",
   "\t${1}",
   "}",
   "",
   "const ${2}: React.FC<IProps> = (props) => {",
   "\tconst { } = props;",
   "",
   "\treturn (",
   "\t\t<div className=\"component-$3\">",
   "\t\t\t$4",
   "\t\t</div>",
   "\t);",
   "};",
   "",
   "export default ${2};",
   "",
  ],
  "description": "生成组件模版"
 },
  • import语句,import语句本身其实就有,但是默认是双引号,每次都需要autofix一下也很烦,就一句话简单定义一下
"import": {
        "prefix": "import",
        "body": [
            "import ${1} from '${2}';"
        ],
        "description": "导入"
    }
  • 我比较喜欢自定义一些代码区块,因此经常会用到region操作,因此把它也作为一个代码片段记下来
"region": {
        "prefix": "region",
        "body": [
            "// #region ${1}\n ${2}\n// #endregion"
        ],
        "description": "自定义代码块"
    },

Tips:可以看到上面有很多变量,比如${1}等等,具体的用法可以参考官方文档(https://code.visualstudio.com/docs/editor/userdefinedsnippets#_creating-your-own-snippets)。一些常用的、固定的模版记录下来还是很方便的。


代码推荐插件


这里才是我们的正题,自定义我们的专属插件。


1、了解下脚手架

首先,脚手架初始化好之后,我们看下代码目录,src目录下的extension.ts就是我们要写的插件代码了,可以看到初始化的文件长这个样子。里面包含了两个方法activatedeactivate,以及大量的注释。大概了解一下,就是每个插件都有自己的生命周期,而这两个生命周期方法就是对应插件激活和注销的生命周期。

而我们的主要推荐逻辑也是写在activate方法中。

image.gif图片.png

2、用到的API

我们用到的最基本的API就是registerCompletionItemProvider,位于vscode.languages的命名空间下。顾名思义,这个方法就是注册一个代码补全的provider。具体的API可以参考官方文档(https://code.visualstudio.com/api/references/vscode-api)。


3、基本代码

import * as vscode from 'vscode';
/** 支持的语言类型 */
const LANGUAGES = ['typescriptreact', 'typescript', 'javascript', 'javascriptreact'];
export function activate(context: vscode.ExtensionContext) {
 /** 触发推荐的字符列表 */
 const triggers = [' '];
 const completionProvider = vscode.languages.registerCompletionItemProvider(LANGUAGES, {
  async provideCompletionItems(document: vscode.TextDocument, position: vscode.Position, token: vscode.CancellationToken, context: vscode.CompletionContext) {
   const completionItem: vscode.CompletionItem = {
    label: 'Hello VsCode',
   };
   return [completionItem];
  }
 }, ...triggers);
 context.subscriptions.push(completionProvider);
}

上面是一份实现代码补全的最基本代码,注册一个completionProvider,返回vscode.CompletionItem的数组即可。上面的代码F5 Debug一下即可看到效果

图片.png

4、自定义逻辑

上面这个demo的效果肯定不是我们想要的,既然我们的目标是专属,那肯定得有些不一样的东西。

支持单词补全

作为一个英文渣,稍微长一点的单词就得查词典,那么这个操作为什么不通过插件来帮我们实现呢?思路其实也简单,就是找一个稍微完善的英文词库,下载到本地,然后根据当前的输入每次都去查一下词库返回最匹配的就好了。这里提供一份最简单的实现逻辑

import * as vscode from 'vscode';
/** 支持的语言类型 */
const LANGUAGES = ['typescriptreact', 'typescript', 'javascript', 'javascriptreact'];
const dictionary = ['hello', 'nihao', 'dajiahao', 'leihaoa'];
export function activate(context: vscode.ExtensionContext) {
 /** 触发推荐的字符列表 */
 const triggers = [' '];
 const completionProvider = vscode.languages.registerCompletionItemProvider(LANGUAGES, {
  async provideCompletionItems(document: vscode.TextDocument, position: vscode.Position, token: vscode.CancellationToken, context: vscode.CompletionContext) {
   const range = new vscode.Range(new vscode.Position(position.line, 0), position);
   const text = document.getText(range);
   const completionItemList: vscode.CompletionItem[] = dictionary.filter(item => item.startsWith(text)).map((item, idx) => ({
    label: item,
    preselect: idx === 0,
    documentation: '我的专属VsCode插件提供',
    sortText: `my_completion_${idx}`,
   }));
   return completionItemList;
  }
 }, ...triggers);
 context.subscriptions.push(completionProvider);
}

下面是效果:

01.gif


image.gif当然,上面的代码片段还有很多需要完善的地方,比如:

  • 推荐的匹配逻辑。现在是当前行的字符串匹配单词的开头,这样明显是有问题的,中间加个其他字符就无法匹配了,需要考虑分词,甚至是非连续匹配,比如输入lh,推荐出 leihaoa。还有一个办法就是 不加任何匹配逻辑,不管输入什么,全部一股脑的扔给Vscode,由vscode去自行匹配。这样当然也可以,但是当你的词库足够大的时候,就不太好了,还是自己先做一遍简单的筛选好一些。
  • 单词的信息量太少。目前就只有个单词,最好能加上些解释、用法会更好一些


5、个性化代码推荐

没有什么比个性化的代码推荐更适合自己了,毕竟没有人会更了解自己。我们的大致思路也简单,并不涉及到深度学习之类的。就是在编写代码过程中记录下自己的输入,对于这份数据进行处理,形成一份类似于词典的文档,方法和上面单词补全类似,根据输入查词典,获取最匹配的推荐即可。同时因为要做到个性化,那么这份词典必须要自动更新,才能满足我们个性化的需求。

说起来简单,这里有几件事情需要做:

  1. 初始文档如何获取?
  2. 词典自动更新逻辑如何实现?

简单的思路:

  1. 直接拿自己的代码库的代码进行抽取、处理,形成初始的词典。理论上代码库越丰富,词典越准确。那么同时带来了另外的问题,即:
  1. 如何从 代码 --> 词典 进行转换?同样简单处理的话,可以直接把代码根据空格进行分词,记录对应的词典
  2. 推荐的顺序如何确定?可以简单根据单词出现的次数决定推荐的顺序,次数越大,顺序越靠前
  1. 可以在每次接受推荐的时候,同时记录当前的文档内容,更新词典

这里的代码处理形成词典的过程 和 词典自动更新的代码就不放了,简单修改下上面的代码如下:

大致代码如下;

import * as vscode from 'vscode';
/** 注册选择推荐项时的触发的命令 */
function registerCommand(command: string) {
 vscode.commands.registerTextEditorCommand(
  command,
  (editor, edit, ...args) => {
   const [text] = args;
   // TODO 记录当前内容到词典中,并自动更新词典
  }
 );
}
/** 支持的语言类型 */
const LANGUAGES = ['typescriptreact', 'typescript', 'javascript', 'javascriptreact'];
const dictionary = ['hello', 'nihao', 'dajiahao', 'leihaoa'];
/** 用户选择之后触发的命令 */
const COMMAND_NAME = 'my_code_completion_choose_item';
export function activate(context: vscode.ExtensionContext) {
 /** 触发推荐的字符列表 */
 const triggers = [' '];
 registerCommand(COMMAND_NAME);
 const completionProvider = vscode.languages.registerCompletionItemProvider(LANGUAGES, {
  async provideCompletionItems(document: vscode.TextDocument, position: vscode.Position, token: vscode.CancellationToken, context: vscode.CompletionContext) {
   const range = new vscode.Range(new vscode.Position(position.line, 0), position);
   const text = document.getText(range);
   const completionItemList: vscode.CompletionItem[] = dictionary.filter(item => item.startsWith(text)).map((item, idx) => ({
    label: item,
    preselect: idx === 0,
    documentation: '我的专属VsCode插件提供',
    sortText: `my_completion_${idx}`,
    command: {
     arguments: [text],
     command: COMMAND_NAME,
     title: 'choose item'
    },
   }));
   return completionItemList;
  }
 }, ...triggers);
 context.subscriptions.push(completionProvider);
}

可以看到,相比单词补全,多了registerCommand方法,并且在每个推荐项都加了command参数,逻辑就是在每次选择推荐项的时候触发这个command,然后做词典的更新。

实现仅供参考,如果做的再好一点,可以尝试:

  1. 自动更新的逻辑需要完善,并且放到后台去
  2. 可以尝试句子的推荐,而不仅仅是单个单词
  3. 排序的逻辑可以再优化,根据出现的次数还是太原始


写在最后


上面通过一些简单的代码补全的例子,展示了VsCode插件辅助开发的能力。可以看出编写一个插件并不困难,欢迎大家自己动手,编写属于自己的个性化插件。同时,也想为大家提供一个思路,在开发中,有一些想法可以通过编写插件的方式去试试,也许就是提效的神器呢~


相关文章
|
1月前
|
自然语言处理 API C++
阿里通义推出SmartVscode插件,自然语言控制VS Code,轻松开发应用,核心技术开源!
SmartVscode插件深度解析:自然语言控制VS Code的革命性工具及其开源框架App-Controller
|
1月前
|
开发工具 C++ git
利用VS Code提升开发效率的五大插件推荐
本文推荐了五款能显著提升开发效率的VS Code插件:ESLint用于代码质量和风格检查;Prettier自动格式化代码;GitLens增强Git功能;Live Server提供前端实时预览;Docker支持容器管理。
|
2月前
|
自然语言处理 JavaScript 开发者
通义灵码插件:VSCode 的智能编程助手
通义灵码插件:VSCode 的智能编程助手
703 3
|
2月前
|
前端开发 JavaScript 编译器
2024最新VSCode实用插件推荐,开发效率遥遥领先!超全面,快收藏~
【10月更文挑战第11天】2024最新VSCode实用插件推荐,开发效率遥遥领先!超全面,快收藏~
369 0
2024最新VSCode实用插件推荐,开发效率遥遥领先!超全面,快收藏~
|
2月前
|
网络安全 Docker 容器
VScode远程服务器之远程 远程容器 进行开发(五)
VScode远程服务器之远程 远程容器 进行开发(五)
52 1
|
2月前
|
Kubernetes 网络安全 容器
VScode远程服务器进行开发(三)
VScode远程服务器进行开发(三)
52 0
|
2月前
|
Linux 网络安全 Windows
VScode远程开发之remote 远程开发(二)
VScode远程开发之remote 远程开发(二)
39 0
|
7月前
sublime和vscode 推荐安装的插件
sublime和vscode 推荐安装的插件
94 0
|
7月前
|
人工智能 自然语言处理 算法
国产新型AI编程助手—DevChat AI插件在VSCode中的应用
国产新型AI编程助手—DevChat AI插件在VSCode中的应用
262 0
|
7月前
|
敏捷开发 人工智能 前端开发
让你爽到飞起的【懒人插件AutoScssStruct4Vue】VSCode根据template的标签目录自动一键生成CSS/SCSS/LESS结构,敏捷开发必备插件!!!
让你爽到飞起的【懒人插件AutoScssStruct4Vue】VSCode根据template的标签目录自动一键生成CSS/SCSS/LESS结构,敏捷开发必备插件!!!