Language Server Protocol 3.17 Code Lens 完整指南:请求、解析与刷新机制详解

发布时间:2026/10/6 18:34:35

Language Server Protocol 3.17 Code Lens 完整指南:请求、解析与刷新机制详解 开发工具【免费下载链接】language-server-protocolDefines a common protocol for language servers.项目地址https://gitcode.com/gh_mirrors/la/language-server-protocol点击查看免费下载Code Lens代码透镜是 LSPLanguage Server Protocol中一类特殊的界面增强能力它允许语言服务器在编辑器中的源码文本行上方渲染一个可点击的交互提示例如“N 处引用”“运行测试”“查看实现”等。本文以当前仓库 codeLens.md 为骨架结合仓库内的 metaModel.json 元模型定义系统讲解 3.17 规范中 Code Lens 的完整消息链路textDocument/codeLens、codeLens/resolve、workspace/codeLens/refresh、全部类型定义、能力协商与动态注册方式并给出可直接落地的实战示例。读完本文你将能够为自己的语言服务器实现 Code Lens 的计算、惰性解析与项目级刷新同时理解客户端应如何声明能力并消费这些请求。一、Code Lens 在 LSP 中的定位Code Lens 与普通 hover、补全等请求的最大区别在于两点它附着在源码文本上每个 Code Lens 都通过range与文档中的某个通常是单行的区域绑定它的核心价值是命令化——每个 Code Lens 本质上是一个可执行的Command如运行测试、查看引用数用户点击透镜文本即可触发对应操作。协议为 Code Lens 设计了两阶段模型先批量计算未解析unresolved的透镜只有 range没有 command再按需逐条解析出真正的命令。这样做的目的在规范中写得很明确——性能计算 code lens 和解析 command 是两个阶段避免一次性为所有透镜生成完整命令带来不必要的开销见 codeLens.md 中CodeLens接口注释。二、能力协商Client Capability 与 Server Capability与所有 LSP 功能一样Code Lens 在使用前需要经过initialize阶段的能力协商。相关定义位于 initialize.md 描述的初始化握手流程中。2.1 客户端能力textDocument.codeLens客户端在initialize请求的capabilities.textDocument中声明export interface CodeLensClientCapabilities { /** * Whether code lens supports dynamic registration. */ dynamicRegistration?: boolean; }dynamicRegistration可选客户端是否支持对 code lens 进行动态注册。如果为true服务器可以在运行时通过client/registerCapability动态注册/注销 code lens 提供者否则服务器只能在初始化时静态声明。对应能力属性名为textDocument.codeLens见 codeLens.md 中的 Client Capability 一节。2.2 服务端能力codeLensProvider服务器在initialize响应的capabilities.codeLensProvider中声明export interface CodeLensOptions extends WorkDoneProgressOptions { /** * Code lens has a resolve provider as well. */ resolveProvider?: boolean; }resolveProvider可选服务器是否额外实现了codeLens/resolve解析处理器。这是两阶段模型的关键开关为false时服务器在textDocument/codeLens返回的每个透镜都必须自带完整的command为true时服务器可以先返回只有range和data的未解析透镜客户端在需要时如用户点击透镜再发送codeLens/resolve请求。CodeLensOptions还继承了WorkDoneProgressOptions意味着服务器可以在 code lens 请求处理期间通过$/progress上报工作进度工作进度相关定义见 workDoneProgress.md。2.3 注册选项CodeLensRegistrationOptions无论是静态注册初始化响应还是动态注册client/registerCapabilitycode lens 提供者的注册选项统一为export interface CodeLensRegistrationOptions extends TextDocumentRegistrationOptions, CodeLensOptions { }它同时继承了TextDocumentRegistrationOptions声明该提供者适用于哪些文档通过documentSelector指定语言/模式过滤条件相关定义见 textDocumentRegistrationOptions 相关类型页CodeLensOptions即上述服务端能力含resolveProvider与工作进度选项。在 metaModel.json 中CodeLensRegistrationOptions被建模为同时extends这两个接口的结构对应条目中extends数组包含TextDocumentRegistrationOptions与CodeLensOptions。三、主请求textDocument/codeLens3.1 请求定义当客户端需要为一个文本文档计算 code lens 时发送请求项目值methodtextDocument/codeLensparamsCodeLensParamsresultCodeLens[]|nullpartial resultCodeLens[]errorcode 与 message请求处理期间发生异常时设置参数类型interface CodeLensParams extends WorkDoneProgressParams, PartialResultParams { /** * The document to request code lens for. */ textDocument: TextDocumentIdentifier; }textDocument要计算 code lens 的目标文档标识TextDocumentIdentifier见 textDocumentIdentifier.md继承WorkDoneProgressParams可附带工作进度令牌继承PartialResultParams可附带部分结果令牌客户端支持时服务器可通过$/partialResult分块返回透镜列表相关基础见 partialResultParams.md 与 partialResults.md。在元模型中该请求被正式记录为clientToServer方向的消息textDocument/codeLens其result为CodeLens[] | nullpartialResult为CodeLens[]registrationOptions为CodeLensRegistrationOptions见 metaModel.json 中 method 为textDocument/codeLens的 request 条目。3.2 结果类型CodeLens/** * A code lens represents a command that should be shown along with * source text, like the number of references, a way to run tests, etc. * * A code lens is _unresolved_ when no command is associated to it. For * performance reasons the creation of a code lens and resolving should be done * in two stages. */ interface CodeLens { /** * The range in which this code lens is valid. Should only span a single * line. */ range: Range; /** * The command this code lens represents. */ command?: Command; /** * A data entry field that is preserved on a code lens item between * a code lens and a code lens resolve request. */ data?: LSPAny; }三个字段的含义range必填该透镜在文档中生效的区间。规范明确要求应当只跨越单行Should only span a single line这样客户端才能把透镜渲染在该行上方。范围类型Range的定义见 range.md。command可选透镜代表的可执行命令。未解析unresolved状态下不携带该字段。命令结构Command由titleUI 显示的标题、command命令处理器标识符和可选的arguments参数数组组成完整定义见 command.md。data可选一个LSPAny任意 JSON 值字段会在textDocument/codeLens与codeLens/resolve两个请求之间原样保留。服务器通常用它存放定位上下文如符号 ID、文件路径、行号等供解析阶段快速还原命令而不必重新扫描整个文档。元模型对这三个字段的建模与规范一致range为必填的Range引用command与data均为可选见 metaModel.json 中CodeLens结构条目的properties。3.3 结果返回约定若服务器无法/不需要为该文档提供任何透镜应返回null或空数组若设置了resolveProvider返回的透镜可全部为未解析状态仅rangedata响应中的错误字段用于在异常如文档不存在、内部错误时返回code与message。四、惰性解析codeLens/resolve4.1 请求定义method: codeLens/resolve params: CodeLens result: CodeLens error: code and message解析期间发生异常时设置客户端把某个未解析的CodeLens对象原样回传给服务器包含其range与data服务器据此返回补全了command的同一透镜项目值methodcodeLens/resolveparamsCodeLensresultCodeLenserrorcode 与 message异常时设置元模型中该请求同样被记录为clientToServer方向params与result均为CodeLens引用见 metaModel.json 中 method 为codeLens/resolve的 request 条目。4.2 为什么需要两阶段主请求轻量化大文件可能有几十上百个透镜若全部立即生成命令包括计算参数响应会显著变大、变慢按需计算只有用户真正查看/点击某个透镜时才触发该透镜的命令解析data是桥梁服务器把解析所需的最小上下文放进dataresolve 时只需反序列化data即可定位到具体符号无需重新分析全文。一个典型实现模式textDocument/codeLens阶段为每个候选位置创建{ range, data: { uri, symbolId } }不填commandcodeLens/resolve阶段读取params.data从索引/符号表中查出命令返回{ ...params, command: { title: 运行测试, command: extension.runTest, arguments: [...] } }。五、服务端主动刷新workspace/codeLens/refresh5.1 背景与用途自版本 3.16.0 起引入。workspace/codeLens/refresh是由服务器发给客户端的请求方向serverToClient见 metaModel.json 中 method 为workspace/codeLens/refresh的条目标注since 3.16.0。典型触发场景服务器检测到配置或项目范围的变化导致所有已展示的 code lens 需要重新计算例如切换了测试框架、启用了新的 linter 规则。规范特别提醒客户端收到刷新请求后应当请求服务器重新计算当前编辑器中展示的透镜但客户端仍有权延迟刷新——例如某个编辑器当前不可见时可以推迟到其重新可见后再计算。5.2 客户端能力声明客户端若支持该请求需要在initialize的capabilities.workspace.codeLens中声明export interface CodeLensWorkspaceClientCapabilities { /** * Whether the client implementation supports a refresh request sent from the * server to the client. * * Note that this event is global and will force the client to refresh all * code lenses currently shown. It should be used with absolute care and is * useful for situation where a server for example detect a project wide * change that requires such a calculation. */ refreshSupport?: boolean; }refreshSupport可选自 3.16.0 起为true表示客户端支持服务器发来的刷新请求。规范用词是绝对小心地使用should be used with absolute care——因为该事件是全局性的会强制客户端刷新当前显示的所有 code lens只应在确实需要全局重算如项目级变更时使用。5.3 请求与响应项目值methodworkspace/codeLens/refreshparamsnone无参数resultvoiderrorcode 与 message请求处理期间发生异常时设置调用链路服务器 → 客户端 → 客户端据此再次发送textDocument/codeLens→ 服务器重新计算 → 新透镜渲染。整个过程形成一个服务器驱动的刷新闭环。六、三个请求全链路对比请求方向methodparamsresult触发时机Code Lens Request客户端 → 服务器textDocument/codeLensCodeLensParamsCodeLens[] \| null可部分结果文档打开/内容变化/收到刷新请求Code Lens Resolve Request客户端 → 服务器codeLens/resolveCodeLensCodeLens客户端需要某个透镜的命令时Code Lens Refresh Request服务器 → 客户端workspace/codeLens/refresh无void服务器检测到项目级配置变化自 3.16.0七、实战示例服务端与客户端实现要点以下给出可直接参考的实现骨架TypeScript 风格帮助理解三个请求如何协同。7.1 服务器端静态注册与主请求在initialize响应中声明能力result.capabilities.codeLensProvider { resolveProvider: true // 声明支持 codeLens/resolve };实现主请求connection.onRequest(textDocument/codeLens, (params: CodeLensParams): CodeLens[] | null { const doc documents.get(params.textDocument.uri); if (!doc) return null; const lenses: CodeLens[] []; for (const sym of findCandidateSymbols(doc)) { lenses.push({ range: { start: { line: sym.line, character: 0 }, end: { line: sym.line, character: sym.endColumn } }, data: { uri: params.textDocument.uri, symbolId: sym.id } // 桥梁数据 }); } return lenses; });7.2 服务器端resolve 处理器connection.onRequest(codeLens/resolve, (lens: CodeLens): CodeLens { const { uri, symbolId } lens.data as ResolveData; const sym symbolTable.get(uri, symbolId); lens.command { title: 运行 ${sym.name} 的测试, command: extension.runTest, arguments: [uri, sym.id] }; return lens; });7.3 服务器端触发全局刷新// 检测到项目配置变化时 if (capabilities.workspace?.codeLens?.refreshSupport) { await connection.sendRequest(workspace/codeLens/refresh); }发送前应检查客户端CodeLensWorkspaceClientCapabilities.refreshSupport是否为true避免向不支持该请求的客户端发送老版本客户端没有该能力。7.4 客户端端要点initialize中声明capabilities.textDocument.codeLens { dynamicRegistration: true }capabilities.workspace.codeLens { refreshSupport: true }支持动态注册时可在运行时用CodeLensRegistrationOptions含documentSelector注册/注销提供者收到workspace/codeLens/refresh后对可见编辑器重新发起textDocument/codeLens并允许延迟到编辑器可见时再算把CodeLens[] | null渲染为对应range所在行上方的可点击文本未解析的透镜在用户点击/需要时再发codeLens/resolve。八、配套类型与资源索引Code Lens 功能依赖的配套类型散落在规范各页便于深入学习Command透镜携带的可执行命令结构title / command / argumentsRange透镜的生效区间规范要求单行TextDocumentIdentifierCodeLensParams.textDocument的类型workDoneProgress.mdWorkDoneProgressOptions/Params的说明partialResultParams.md 与 partialResults.md部分结果机制metaModel.json机器可读的元模型包含全部 Code Lens 相关类型与请求条目适合代码生成与校验specification.md3.17 规范全文档含各语言特性的总览。结语Code Lens 是 LSP 中轻计算 惰性解析 全局刷新设计思想的典型代表textDocument/codeLens保证主请求足够轻量codeLens/resolve把昂贵的命令构造推迟到真正需要的时刻workspace/codeLens/refresh则让服务器在项目级变化时主动驱动客户端重算。理解并正确实现这三个请求含各自的能力协商字段dynamicRegistration、resolveProvider、refreshSupport是让编辑器内的引用计数、测试运行等交互提示既流畅又省电的关键。赞分享开发工具【免费下载链接】language-server-protocolDefines a common protocol for language servers.项目地址https://gitcode.com/gh_mirrors/la/language-server-protocol点击查看免费下载相关推荐BSC 客户端 Debian/Ubuntu 打包指南基于 build/ci-notes.md 的 PPA 发布与本地构建全流程BSC 客户端 Debian/Ubuntu 打包指南基于 build/ci notes.md 的 PPA 发布与本地构建全流程 本文以仓库 build/ci开发工具Security-101 之 SecOps 零信任架构集中日志收集体系设计与现代安全运营最佳实践Security 101 之 SecOps 零信任架构集中日志收集体系设计与现代安全运营最佳实践 零信任Zero Trust不是单一产品而是一套以永不开发工具slime LLM 后训练框架完整指南用 Megatron 与 SGLang 打通强化学习扩展的闭环slime LLM 后训练框架完整指南用 Megatron 与 SGLang 打通强化学习扩展的闭环 slime 是一个面向大语言模型LLM后训练的框架开发工具上一篇用 Forge 的 :fixme 自定义命令自动扫描并修复代码中的 FIXME 注释下一篇effect/platform-node v4 变更解读Node.js 平台层的能力演进与迁移指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
延伸阅读

更多相关文章

2026/10/6 18:29:35

MOS管栅极电阻优化:抑制米勒效应与开关损耗

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/6 18:29:35

高速PCB差分阻抗设计:从SI9000到HFSS的完整流程

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/6 19:44:39

多用户多仓库进销存系统源码解析:基于uniapp的跨端库存管理方案

跑进销存这条路的人都知道,真正的痛点从来不是“做一张入库单”或者“打一张出库单”,而是当公司有多个门店、多个仓,甚至多人同时操作时,数据到底怎么算得清。前阵子我拿到一套基于uniapp的多用户多仓库进销存管理系统源码&#…

2026/10/6 19:44:39

用OpenSSH与dotfiles打造标准化Shell环境:登录配置安全一键搞定

把一套散落在不同机器上的 Shell 环境,收拢成可复用、可迁移、可安全交付的标准化方案,这件事我琢磨了很久。OpenShell 这个名字听起来像是一个开源项目,其实它更像是我给自己定的一套“终端环境建设规则”:把 SSH 登录、dotfiles…

2026/10/6 19:44:39

C++自定义字面量高级用法:编译期单位换算与字符串解析

一提到C里的自定义字面量,很多人的第一反应是“哦,不就是operator""嘛,给数值加个后缀,看着挺酷,实际上用不上”。说实话,我早几年也是这个态度。直到有一次在系统里接测量模块,满屏的…

2026/10/6 19:44:39

华为云码道代码智能体实战:从零上手到代码检视与修复

1. 从零上手华为云码道代码智能体:一个后端老兵的真实踩坑记录 第一次听说华为云码道(CodeArts)代码智能体的时候,我正被一个祖传项目折磨得够呛。那是一个跑了快六年的老系统,代码里到处是复制粘贴留下的痕迹&#xf…

2026/10/6 19:39:38

Agent-Reach 实战:用 CLI 让 AI Agent 稳定触达外部世界

Agent-Reach 这个名字第一次看到的时候,我下意识以为是某个网络代理工具,后来翻了翻社区讨论和相关的技术标签,才反应过来它指向的是另一件事:让 AI Agent 真正"够得着"外部世界的那一层能力。CLI、Python、AI Agent 这…

2026/10/5 6:32:56

Jev+Agent接管浏览器:browser-use实战与jev-ultrafast性能优化

1. 从“Jev”说起:为什么我要把Agent接进浏览器“Jev”这个词最近在圈子里出现的频率越来越高,很多人第一次听到会以为是某个新模型的名字,其实它更像是一种思路——把Jev模型的能力当作底座,通过Agent的方式去接管浏览器&#xf…

2026/10/6 4:01:51

多智能体集群实战:DeepAgents编排、MCP与A2A协议及Skills体系

1. 从"单兵作战"到"集群协同":多智能体编排到底在解决什么问题如果你最近在折腾 Agent 相关的东西,大概率会有一种感觉:单个 Agent 能做的事情,其实很快就摸到天花板了。你给它一个提示词,挂几个工…

2026/10/6 17:46:51

无源低通滤波器设计实战:从RC到LC,手把手教你避开那些坑

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/6 0:03:23

MR25H40CDF+STM32F031C6工业级高可靠数据存储方案

1. 项目概述:为什么在工业现场非得用 MR25H40CDF 配 STM32F031C6 做数据存储?在工厂产线的 PLC 控制柜里、在风电变流器的散热片背面、在矿井监测终端的金属外壳下,你经常能看到一块指甲盖大小的黑色芯片——它既不是 Flash,也不是…

2026/10/6 0:03:23

MRAM+STM32工业断电数据保全实战指南

1. 项目概述:为什么在工业现场非得用 MR25H40CDF 配 STM32F031C6 做数据存储?在工厂产线的PLC柜里、在野外无人值守的环境监测终端里、在高速运转的包装机控制板上,你经常能看到一块指甲盖大小的黑色芯片,旁边贴着“MR25H40CDF”丝…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑