zoukankan      html  css  js  c++  java
  • 【插件开发】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

    1.1. 高亮显示范围

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

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

    自动补全

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

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

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

    实现代码如下:

    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}
    * **版本**:${content.version}
    * **许可协议**:${content.license}`);
                }
            }
        }
    }
    
    module.exports = function(context) {
        // 注册鼠标悬停提示
        context.subscriptions.push(vscode.languages.registerHoverProvider('json', {
            provideHover
        }));
    };

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

  • 相关阅读:
    机器学习(深度学习)
    机器学习(六)
    机器学习一-三
    Leetcode 90. 子集 II dfs
    Leetcode 83. 删除排序链表中的重复元素 链表操作
    《算法竞赛进阶指南》 第二章 Acwing 139. 回文子串的最大长度
    LeetCode 80. 删除有序数组中的重复项 II 双指针
    LeetCode 86 分割链表
    《算法竞赛进阶指南》 第二章 Acwing 138. 兔子与兔子 哈希
    《算法竞赛进阶指南》 第二章 Acwing 137. 雪花雪花雪花 哈希
  • 原文地址:https://www.cnblogs.com/mailyuan/p/13404288.html
Copyright © 2011-2022 走看看