VSCode插件开发全攻略之跳转到定义、自动补全、悬停提示功能

 更新时间:2020年05月07日 15:07:35   作者:我是小茗同学  
这篇文章主要介绍了VSCode插件开发全攻略之跳转到定义、自动补全、悬停提示,需要的朋友可以参考下

跳转到定义

跳转到定义其实很简单,通过vscode.languages.registerDefinitionProvider注册一个provider,这个provider如果返回了new vscode.Location()就表示当前光标所在单词支持跳转,并且跳转到对应location。

为了示例更加有意义,我在这里写了一个支持package.jsondependenciesdevDependencies跳转到对应依赖包的例子jump-to-definition.js(当然我们这里只是很简单的实现,没有考虑特殊情况,直接从node_modules文件夹下面去找):

代码如下:

/**
 * 跳转到定义示例,本示例支持package.json中dependencies、devDependencies跳转到对应依赖包。
 */
const vscode = require('vscode');
const path = require('path');
const fs = require('fs');
const util = require('./util');

/**
 * 查找文件定义的provider,匹配到了就return一个location,否则不做处理
 * 最终效果是,当按住Ctrl键时,如果return了一个location,字符串就会变成一个可以点击的链接,否则无任何效果
 * @param {*} document 
 * @param {*} position 
 * @param {*} token 
 */
function provideDefinition(document, position, token) {
 const fileName = document.fileName;
 const workDir = path.dirname(fileName);
 const word = document.getText(document.getWordRangeAtPosition(position));
 const line = document.lineAt(position);
 const projectPath = util.getProjectPath(document);

 console.log('====== 进入 provideDefinition 方法 ======');
 console.log('fileName: ' + fileName); // 当前文件完整路径
 console.log('workDir: ' + workDir); // 当前文件所在目录
 console.log('word: ' + word); // 当前光标所在单词
 console.log('line: ' + line.text); // 当前光标所在行
 console.log('projectPath: ' + projectPath); // 当前工程目录
 // 只处理package.json文件
 if (/\/package\.json$/.test(fileName)) {
 console.log(word, line.text);
 const json = document.getText();
 if (new RegExp(`"(dependencies|devDependencies)":\\s*?\\{[\\s\\S]*?${word.replace(/\//g, '\\/')}[\\s\\S]*?\\}`, 'gm').test(json)) {
  let destPath = `${workDir}/node_modules/${word.replace(/"/g, '')}/package.json`;
  if (fs.existsSync(destPath)) {
  // new vscode.Position(0, 0) 表示跳转到某个文件的第一行第一列
  return new vscode.Location(vscode.Uri.file(destPath), new vscode.Position(0, 0));
  }
 }
 }
}

module.exports = function(context) {
 // 注册如何实现跳转到定义,第一个参数表示仅对json文件生效
 context.subscriptions.push(vscode.languages.registerDefinitionProvider(['json'], {
 provideDefinition
 }));
};

注意不要忘了修改activationEvents

"activationEvents": [
 "onLanguage:json"
],

new vscode.Location接收2个参数,第一个是要跳转到文件的路径,第二个是跳转之后光标所在位置,接收Range或者Position对象,Position对象的初始化接收2个参数,行row和列col。

高亮显示范围

这里有一个问题我一直没找到解决方案,如下图所示:

当按住Ctrl跳转的时候,虽然可以控制跳转目标位置,但是却无法控制高亮显示的范围,下图我本应该让page/video/list.html全部变成蓝色的,但是默认却只能以单词为粒度变色,这个问题我找了很久官方文档就是没找到解决办法,如果大家有知道的欢迎评论指出。

自动补全

通过vscode.languages.registerCompletionItemProvider方法注册自动完成实现,接收3个参数:

  • 第一个是要关联的文件类型;
  • 第二个是一个对象,里面必须包含provideCompletionItems和resolveCompletionItem这2个方法;
  • 第三个是一个可选的触发提示的字符列表;

这里我们实现这样一个例子,当输入this.dependencies.xxx时自动把package.json中的依赖全部带出来,包括dependencies、devDependencies,就像这样:

实现代码如下:

const vscode = require('vscode');
const util = require('./util');

/**
 * 自动提示实现,这里模拟一个很简单的操作
 * 当输入 this.dependencies.xxx时自动把package.json中的依赖带出来
 * 当然这个例子没啥实际意义,仅仅是为了演示如何实现功能
 * @param {*} document 
 * @param {*} position 
 * @param {*} token 
 * @param {*} context 
 */
function provideCompletionItems(document, position, token, context) {
 const line = document.lineAt(position);
 const projectPath = util.getProjectPath(document);

 // 只截取到光标位置为止,防止一些特殊情况
 const lineText = line.text.substring(0, position.character);
 // 简单匹配,只要当前光标前的字符串为`this.dependencies.`都自动带出所有的依赖
 if(/(^|=| )\w+\.dependencies\.$/g.test(lineText)) {
 const json = require(`${projectPath}/package.json`);
 const dependencies = Object.keys(json.dependencies || {}).concat(Object.keys(json.devDependencies || {}));
 return dependencies.map(dep => {
  // vscode.CompletionItemKind 表示提示的类型
  return new vscode.CompletionItem(dep, vscode.CompletionItemKind.Field);
 })
 }
}

/**
 * 光标选中当前自动补全item时触发动作,一般情况下无需处理
 * @param {*} item 
 * @param {*} token 
 */
function resolveCompletionItem(item, token) {
 return null;
}

module.exports = function(context) {
 // 注册代码建议提示,只有当按下“.”时才触发
 context.subscriptions.push(vscode.languages.registerCompletionItemProvider('javascript', {
 provideCompletionItems,
 resolveCompletionItem
 }, '.'));
};

悬停提示

从上面的跳转到定义我们可以看到,虽然我们只是定义了如何调整,到按住Ctrl键但是不点击的时候,vscode默认就会帮我们预览一部分内容作为提示,除此之外,如果想获得更多的提示,我们还可以通过vscode.languages.registerHoverProvider命令来实现。

下面我们依然通过package.json中依赖跳转的例子来演示如何实现一个自定义hover,如下标红的内容是我们自己实现的,当鼠标停在package.json的dependencies或者devDependencies时,自动显示对应包的名称、版本号和许可协议:

如何实现的呢?也很简单,我们直接上代码:

const vscode = require('vscode');
const path = require('path');
const fs = require('fs');

/**
 * 鼠标悬停提示,当鼠标停在package.json的dependencies或者devDependencies时,
 * 自动显示对应包的名称、版本号和许可协议
 * @param {*} document 
 * @param {*} position 
 * @param {*} token 
 */
function provideHover(document, position, token) {
 const fileName = document.fileName;
 const workDir = path.dirname(fileName);
 const word = document.getText(document.getWordRangeAtPosition(position));

 if (/\/package\.json$/.test(fileName)) {
 console.log('进入provideHover方法');
 const json = document.getText();
 if (new RegExp(`"(dependencies|devDependencies)":\\s*?\\{[\\s\\S]*?${word.replace(/\//g, '\\/')}[\\s\\S]*?\\}`, 'gm').test(json)) {
  let destPath = `${workDir}/node_modules/${word.replace(/"/g, '')}/package.json`;
  if (fs.existsSync(destPath)) {
  const content = require(destPath);
  console.log('hover已生效');
  // hover内容支持markdown语法
  return new vscode.Hover(`* **名称**:${content.name}\n* **版本**:${content.version}\n* **许可协议**:${content.license}`);
  }
 }
 }
}

module.exports = function(context) {
 // 注册鼠标悬停提示
 context.subscriptions.push(vscode.languages.registerHoverProvider('json', {
 provideHover
 }));
};

有些时候某个字段可能本身已经有提示内容了,如果我们仍然给它注册了hover的实现的话,那么vscode会自动将多个hover内容合并一起显示。

总结

到此这篇关于VSCode插件开发全攻略之跳转到定义、自动补全、悬停提示功能的文章就介绍到这了,更多相关VSCode插件开发 跳转到定义、自动补全、悬停提示内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • C++实现公司人事管理系统

    C++实现公司人事管理系统

    这篇文章主要为大家详细介绍了C++实现公司人事管理系统,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-03-03
  • ​​C++11系列学习之Lambda表达式

    ​​C++11系列学习之Lambda表达式

    这篇文章主要介绍了​​C++11系列学习之Lambda表达式,C++11终于也引入了lambda表达式,lambda最早来源于函数式编程,现代语言慢慢都引入了这个语法,下文关于​​C++11Lambda表达式相关内容需要的小伙伴可以参考一下
    2022-04-04
  • VC判断进程是否具有administrator权限的方法

    VC判断进程是否具有administrator权限的方法

    这篇文章主要介绍了VC判断进程是否具有administrator权限的方法,在Windows应用程序设计中具有一定的实用价值,需要的朋友可以参考下
    2014-10-10
  • opencv实现角点检测

    opencv实现角点检测

    这篇文章主要为大家详细介绍了opencv实现角点检测,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-08-08
  • C语言中对数组赋值的三种形式

    C语言中对数组赋值的三种形式

    这篇文章主要给大家介绍了关于C语言中对数组赋值的3种形式,文中通过示例代码介绍的非常详细,对大家学习或者使用C语言具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧
    2019-09-09
  • 原码, 反码与补码基础知识详细介绍

    原码, 反码与补码基础知识详细介绍

    这篇文章讲解了计算机的原码, 反码和补码. 并且进行了深入探求了为何要使用反码和补码, 以及更进一步的论证了为何可以用反码, 补码的加法计算原码的减法,需要的朋友可以参考下
    2016-12-12
  • C语言连续生成随机数的实现方法

    C语言连续生成随机数的实现方法

    这篇文章主要介绍了C语言连续生成随机数的实现方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-01-01
  • C++排序算法之冒泡排序解析

    C++排序算法之冒泡排序解析

    这篇文章主要介绍了C++排序算法之冒泡排序解析,从左到右,相邻两数两两比较,若下标小的数大于下标大的数则交换,将最大的数放在数组的最后一位,,再次遍历数组,将第二大的数,放在数组倒数第二的位置,以此类推,直到数组有序需要的朋友可以参考下
    2023-10-10
  • 通过GDB学习C语言的讲解

    通过GDB学习C语言的讲解

    今天小编就为大家分享一篇关于通过GDB学习C语言的讲解,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧
    2019-01-01
  • 一文带你搞懂C语言动态内存管理

    一文带你搞懂C语言动态内存管理

    动态内存是指在堆上分配的内存,而静态内存是指在栈上分配的内存。本文将通过几个示例带大家深入了解一下C语言的动态内存管理,需要的可以参考一下
    2022-11-11

最新评论