如何为VSCode设置一个自定义的代码透镜(CodeLens)提供程序?

答案:自定义CodeLens提供程序需实现接口并注册,通过正则匹配或AST解析在代码上方显示可操作标签,适用于展示版本控制、测试状态等上下文信息。

如何为VSCode设置一个自定义的代码透镜(CodeLens)提供程序?

要在VSCode里搞定一个自定义的代码透镜(CodeLens)提供程序,说白了,就是得写一个VSCode扩展。核心在于实现

CodeLensProvider

这个接口,然后把它注册到VSCode的语言服务里。这玩意儿能让你在代码行上方,像小标签一样显示一些上下文信息或者可执行的命令,挺有意思的。

解决方案

搞一个自定义的CodeLens提供程序,其实没想象中那么玄乎,但确实需要一点点耐心去理解VSCode扩展的套路。

  1. 初始化项目: 首先,你需要一个VSCode扩展的脚手架。如果你还没装

    yo code

    ,先

    npm install -g yo generator-code

    。然后跑

    yo code

    ,选“New Extension (TypeScript)”,一路回车,给你的扩展起个名字,比如

    my-custom-codelens

  2. package.json

    配置: 打开生成的

    package.json

    文件。这里有几个关键点:

    • activationEvents

      :告诉VSCode你的扩展什么时候被激活。对于CodeLens,通常是当某个语言文件被打开时。比如,如果你想在TypeScript文件里显示CodeLens,可以写

      "onLanguage:typescript"

    • contributes.commands

      :如果你的CodeLens需要执行一个命令(比如点击后跳转、运行测试),你得在这里声明这个命令。

    • contributes.languages

      :虽然不是直接为CodeLens配置,但它定义了你的扩展支持哪些语言,间接影响CodeLens的显示。

    // package.json 示例 {   "name": "my-custom-codelens",   "displayName": "My Custom CodeLens",   "version": "0.0.1",   "engines": {     "vscode": "^1.80.0"   },   "categories": [     "Other"   ],   "activationEvents": [     "onLanguage:typescript", // 当TypeScript文件打开时激活     "onCommand:myCustomCodelens.doSomething" // 当特定命令被执行时激活   ],   "main": "./out/extension.js",   "contributes": {     "commands": [       {         "command": "myCustomCodelens.doSomething",         "title": "执行我的自定义操作"       }     ]   },   "scripts": {     "vscode:prepublish": "npm run compile",     "compile": "tsc -p ./",     "watch": "tsc -watch -p ./",     "pretest": "npm run compile && npm run lint",     "lint": "eslint src --ext ts",     "test": "node ./out/test/runTest.js"   },   "devDependencies": {     "@types/vscode": "^1.80.0",     "@types/node": "^18.17.1",     "@typescript-eslint/eslint-plugin": "^6.4.1",     "@typescript-eslint/parser": "^6.4.1",     "eslint": "^8.47.0",     "typescript": "^5.1.6"   } }
  3. 实现

    CodeLensProvider

    这是核心逻辑所在。在

    src/extension.ts

    里,你需要创建一个类来实现

    vscode.CodeLensProvider

    接口。这个接口有两个主要方法:

    provideCodeLenses

    resolveCodeLens

    • provideCodeLenses(document: vscode.TextDocument, token: vscode.CancellationToken)

      : 这个方法是VSCode用来“扫描”文档,找出哪些地方应该显示CodeLens的。你需要遍历文档内容,根据你的逻辑(比如正则匹配、AST解析等)来创建

      vscode.CodeLens

      对象。每个

      CodeLens

      对象至少需要一个

      range

      (它将显示在哪一行代码的上方)。 为了性能考虑,你可以在这里只返回带有

      range

      CodeLens

      ,而将实际的

      command

      (标题和要执行的动作)留到

      resolveCodeLens

      里处理。

    • resolveCodeLens?(codeLens: vscode.CodeLens, token: vscode.CancellationToken)

      : 这个方法是可选的,但非常推荐实现。当VSCode需要显示CodeLens时,它会按需调用这个方法来“解析”CodeLens,填充它的

      command

      属性。这样做的好处是,当文档很大或者CodeLens很多时,可以避免一次性计算所有CodeLens的完整信息,从而提高性能和响应速度。

    // src/extension.ts 示例 import * as vscode from 'vscode';  // 定义一个正则表达式,用于匹配我们想要添加CodeLens的特定模式 // 比如,我们想在所有包含 "TODO:" 的行上方显示一个CodeLens const TODO_REGEX = /(TODO:)s*(.*)/g;  class MyCodeLensProvider implements vscode.CodeLensProvider {     // 当文档内容变化或CodeLens需要刷新时,VSCode会调用这个方法     public provideCodeLenses(document: vscode.TextDocument, token: vscode.CancellationToken): vscode.ProviderResult<vscode.CodeLens[]> {         const codeLenses: vscode.CodeLens[] = [];         const text = document.getText();         let match;          // 遍历文档,查找所有匹配我们正则表达式的行         while ((match = TODO_REGEX.exec(text)) !== null) {             // 获取匹配到的行的位置             const line = document.lineAt(document.positionAt(match.index).line);             const range = new vscode.Range(line.range.start, line.range.end);              // 创建一个CodeLens对象。注意,这里我们暂时不设置command,留给resolveCodeLens处理             if (range) {                 codeLenses.push(new vscode.CodeLens(range));             }         }         return codeLenses;     }      // VSCode会按需调用这个方法来填充CodeLens的command     public resolveCodeLens(codeLens: vscode.CodeLens, token: vscode.CancellationToken): vscode.ProviderResult<vscode.CodeLens> {         // 在这里,我们可以根据CodeLens的range,获取对应行的文本         // 然后根据文本内容,决定CodeLens要显示什么标题和执行什么命令         const lineText = vscode.window.activeTextEditor?.document.getText(codeLens.range);          if (lineText?.includes("TODO:")) {             codeLens.command = {                 title: `找到一个待办事项: ${lineText.trim().substring(5)}`, // 显示CodeLens的标题                 command: 'myCustomCodelens.doSomething', // 点击CodeLens时执行的命令                 arguments: [lineText] // 命令的参数             };         }         return codeLens;     } }  // 激活扩展的入口点 export function activate(context: vscode.ExtensionContext) {     console.log('Congratulations, your extension "my-custom-codelens" is now active!');      // 注册CodeLens提供程序     // 'typescript' 是语言ID,确保和 package.json 中的 activationEvents 匹配     context.subscriptions.push(vscode.languages.registerCodeLensProvider(         { language: 'typescript', scheme: 'file' }, // 也可以是 ['typescript', 'javascript'] 等数组         new MyCodeLensProvider()     ));      // 注册一个命令,供CodeLens点击时调用     context.subscriptions.push(vscode.commands.registerCommand(         'myCustomCodelens.doSomething',         (todoText: string) => {             vscode.window.showInformationMessage(`你点击了待办事项: ${todoText}`);             // 在这里可以实现更复杂的逻辑,比如打开一个新的文件、跳转到某个位置等         }     )); }  // 当你的扩展被禁用时,会调用这个方法 export function deactivate() {}
  4. 调试和测试: 按下F5,VSCode会打开一个新的“扩展开发主机”窗口。在这个新窗口里打开一个TypeScript文件,随便写几行带

    TODO:

    的注释,你就能看到CodeLens在行上方出现了。点击它,看看命令是否正确执行。

这套流程走下来,一个基本的自定义CodeLens就搭起来了。实际应用中,你可能需要更复杂的逻辑来解析代码,但核心思路就是这样。

自定义CodeLens有哪些实际应用场景?

说实话,CodeLens这东西,用好了简直是提升开发体验的神器。它把一些原本需要你手动查找或切换上下文才能获取的信息,直接“钉”在代码旁边,减少了认知负担。

在我看来,最实用的场景包括:

  • 版本控制信息: 比如显示当前行代码的Git提交者、提交时间和提交信息。想象一下,你不用再开Git Blame视图,直接在代码行上方就能看到是谁在什么时候改了这行,多方便。很多IDE都有类似功能,VSCode通过扩展也能实现。
  • 测试状态和运行: 对于单元测试,CodeLens可以直接显示某个测试用例的通过/失败状态,甚至提供一个点击就能运行该测试的按钮。这对于TDD或者快速验证代码改动非常有帮助。
  • 引用计数与实现: 显示一个函数、类或接口被引用了多少次,或者一个接口有多少个实现。点击CodeLens可以直接跳转到所有引用或实现的地方。这在大型代码库中,快速理解代码影响范围时特别有用。
  • 性能指标: 在某些特定代码块(比如数据库查询、API调用)上方显示其平均执行时间。这需要一些运行时数据收集,但一旦集成,就能直观地看到代码的性能瓶颈。
  • 文档链接与外部资源: 如果你的代码中使用了某个库的特定API,CodeLens可以提供一个链接,直接跳转到该API的官方文档。这比在浏览器里搜索快多了。
  • TODO/FIXME管理: 就像我们示例里做的,把代码里的
    TODO

    FIXME

    等标记变成可点击的CodeLens,点击后可以快速打开一个任务管理工具,或者标记为已完成。

  • 代码覆盖率: 在测试报告中,CodeLens可以显示每行代码是否被测试覆盖,或者覆盖率百分比。

总的来说,CodeLens的价值在于它提供了一种“即时上下文”的信息展示方式,让开发者能更专注于代码本身,同时又不会错过重要的辅助信息。

如何避免CodeLens导致VSCode卡顿?

性能问题,尤其是在VSCode这种高频使用的工具里,是绝对不能忽视的。CodeLens如果写得不好,确实可能让VSCode变得迟钝。这方面,有几个关键点我觉得特别重要:

  1. 善用

    resolveCodeLens

    这几乎是CodeLens性能优化的黄金法则。

    provideCodeLenses

    应该尽可能快地返回CodeLens的

    range

    信息,而把计算CodeLens的

    command

    (标题、参数等)的耗时操作放到

    resolveCodeLens

    里。VSCode会按需、异步地调用

    resolveCodeLens

    ,这样可以避免在文档加载时一次性计算所有CodeLens的完整信息,大大减少首次加载和滚动时的卡顿。

  2. 高效地扫描文档:

    • 避免全文档正则匹配: 如果你的逻辑是基于正则匹配的,尽量限制匹配的范围,或者使用更高效的正则表达式。对于超大文件,全文档正则匹配是性能杀手。
    • 增量更新: 如果可能,只处理文档中发生变化的部分。虽然
      provideCodeLenses

      每次都会收到整个文档,但你可以内部维护一个状态,只对修改过的行进行重新计算。

    • AST解析: 对于复杂的语言结构,使用抽象语法树(AST)解析器通常比正则表达式更准确也更高效,因为它理解代码的结构,而不是简单的文本模式。但引入AST解析器也会增加扩展的复杂性和依赖。
  3. 异步操作: 确保你的CodeLens提供程序中的任何潜在耗时操作都是异步的(例如,网络请求、文件I/O)。使用

    async/await

    ,并确保不会阻塞主线程。

    vscode.CancellationToken

    也很有用,可以在用户快速滚动或切换文件时取消正在进行的计算。

  4. 限制CodeLens数量: 如果一个文件中有成百上千个CodeLens,即使每个CodeLens的计算量很小,累积起来也会造成性能问题。考虑对CodeLens的数量进行限制,或者只在用户关注的特定区域显示。

    如何为VSCode设置一个自定义的代码透镜(CodeLens)提供程序?

    阿里·犸良

    一站式动效制作平台

    如何为VSCode设置一个自定义的代码透镜(CodeLens)提供程序?52

    查看详情 如何为VSCode设置一个自定义的代码透镜(CodeLens)提供程序?

  5. 内存管理: 避免在

    provideCodeLenses

    resolveCodeLens

    中创建大量临时对象,尤其是在循环内部。注意内存泄漏,确保不再需要的资源被正确释放。

  6. Debounce和Throttle: 如果你的CodeLens逻辑需要在用户输入时频繁更新,考虑使用

    debounce

    throttle

    技术来限制更新频率。例如,当用户键入时,不是每次按键都重新计算CodeLens,而是在用户停止输入一段时间后再计算。

总之,CodeLens的性能优化,很大程度上就是权衡“即时性”和“资源消耗”。优先保证用户界面的流畅性,然后才是信息的丰富度。

CodeLens与Hover、Diagnostic有什么区别?

在VSCode里,有多种方式可以给开发者提供上下文信息,CodeLens、Hover和Diagnostic就是其中最常用的三种。它们各自有其特点和最佳使用场景,了解它们的区别能帮助你选择最合适的扩展点。

  1. CodeLens (代码透镜)

    • 展示位置: 直接显示在代码行的上方,像一个小标签或提示。
    • 交互性: 通常是可点击的,点击后可以执行一个命令(比如跳转、运行测试、显示更多信息)。
    • 特点:
      • 主动性: 信息是“推”给用户的,无需用户主动触发。
      • 上下文关联: 紧密关联到它所在的特定代码行。
      • 动作导向: 往往提供一个快速操作的入口。
    • 最佳用途: 适用于提供即时、可操作的上下文信息,比如 Git blame 信息、测试运行/状态、引用计数、快速导航链接。
  2. Hover (悬停提示)

    • 展示位置: 当鼠标悬停在代码元素(变量、函数、类等)上时,弹出一个小窗口显示信息。
    • 交互性: 通常是只读的,但可以包含链接,点击后跳转到其他地方。
    • 特点:
      • 被动性: 需要用户主动将鼠标悬停才能触发。
      • 详细信息: 适合展示较多的、详细的、解释性的信息。
      • 按需获取: 信息是“拉”给用户的,只在需要时才显示。
    • 最佳用途: 适用于显示类型定义、函数签名、文档注释、错误详情、变量值等,这些信息通常比较丰富,不适合直接显示在代码行上方。
  3. Diagnostic (诊断信息)

    • 展示位置: 在代码编辑器中以波浪线、下划线等形式标记出来,同时在“问题”面板(Problems panel)中列出所有诊断信息。
    • 交互性: 通常不可点击,但点击问题面板中的条目可以跳转到代码位置。某些诊断可以通过“快速修复”(Quick Fix)功能提供建议操作。
    • 特点:
      • 问题导向: 主要用于报告代码中的错误、警告、信息或提示。
      • 持久性: 诊断信息会一直显示,直到问题解决。
      • 全局视图: “问题”面板提供了一个所有问题的集中视图。
    • 最佳用途: 适用于静态代码分析、Linting、编译器错误、语法错误、潜在的运行时问题等,这些信息需要被开发者关注并修复。

如何选择?

  • 如果你想在代码行上方主动展示一些可操作的、概括性的信息,选 CodeLens
  • 如果你想在用户按需查看时提供详细的、解释性的信息,选 Hover
  • 如果你想报告代码中的问题(错误、警告等),并希望它们持续显示且有全局视图,选 Diagnostic

它们不是互斥的,很多时候,一个功能可能需要结合使用这些扩展点。比如,CodeLens可以显示一个函数有多少个引用,而Hover可以显示这个函数的完整文档。诊断信息则可以指出这个函数有没有潜在的bug。合理搭配,才能提供最棒的开发体验。

vscode javascript java js git json node go 正则表达式 typescript typescript json 正则表达式 npm Token 循环 接口 线程 主线程 对象 异步 git ide vscode 数据库 性能优化 tdd bug

上一篇
下一篇
text=ZqhQzanResources