更多文章请戳 VSCode 插件开发全攻略系列目录导航.
跳转到定义
跳转到定义其实很简单, 通过 vscode.languages.registerDefinitionProvider 注册一个 provider, 这个 provider 如果返回了 new vscode.Location() 就表示当前光标所在单词支持跳转, 并且跳转到对应 location.
为了示例更加有意义, 我在这里写了一个支持 package.JSON 中 dependencies,devDependencies 跳转到对应依赖包的例子 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 内容合并一起显示.
来源: https://www.cnblogs.com/liuxianan/p/vscode-plugin-jump-completion-hover.html