ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Language Server Protocol Selection Range 请求全解析:基于 syntax tree 的嵌套选区能力(3.15+)

Language Server Protocol Selection Range 请求全解析:基于 syntax tree 的嵌套选区能力(3.15+) 开发工具【免费下载链接】language-server-protocolDefines a common protocol for language servers.项目地址https://gitcode.com/gh_mirrors/la/language-server-protocol点击查看免费下载导读textDocument/selectionRange是 Language Server ProtocolLSP中用于实现「智能展开选区」能力的核心请求客户端在编辑器里按下快捷键例如 VS Code 的 ShiftAlt→时会向语言服务器请求某个光标位置附近一系列「用户可能感兴趣的嵌套选区」服务器按语法树从最小单元逐层向外返回。本文以本仓库_specifications/lsp/3.19/language/selectionRange.md为骨架结合 3.19 版本的 metaModel.json 与 initialize.md 中的能力声明完整讲解该请求的消息结构、能力协商、返回语义、协议约束与典型实现思路帮助你写出符合规范的语言服务器选区提供器。一、Selection Range 请求是什么1.1 协议定位与引入版本textDocument/selectionRange请求自LSP 3.15.0起引入属于「客户端 → 服务器」方向clientToServer的标准请求。在 3.19 的 specification.md 变更日志中可以看到3.15 版本明确「Added support fortextDocument/selectionRange」。它的作用一句话概括客户端向服务器发送一组位置positions服务器为每个位置返回一组由内向外逐层嵌套的选区selection ranges用户可以通过编辑器快捷键在相邻层级之间来回切换选区。典型使用场景包括光标放在函数调用foo(bar, baz)中先选中bar再展开到foo(bar, baz)整体光标放在字符串字面量中先选中字符串内容再展开到带引号的完整字面量在嵌套括号、中缀表达式、模板字符串等结构中逐层扩大选择范围。规范原文指出通常但不是必须选区对应语法树的节点Typically, but not necessary, selection ranges correspond to the nodes of the syntax tree。也就是说选区并不强制要求与语法树一一对应语言服务器完全可以根据分词结果、注释块或其他语义单元自定义选区层次。1.2 请求整体流程在 LSP 中textDocument/selectionRange的请求method为textDocument/selectionRange其元数据在 3.19 的 metaModel.json 中登记为SelectionRangeRequest要点如下messageDirection:clientToServerclientCapability:textDocument.selectionRangeserverCapability:selectionRangeProviderparams:SelectionRangeParamsresult:SelectionRange[] | nullpartialResult:SelectionRange[]支持部分结果流式返回registrationOptions:SelectionRangeRegistrationOptions1.3 核心语义数组按索引一一对应请求的positions是一个位置数组返回的SelectionRange[]与之按下标一一对应。规范对此有两条硬性约束positions[i]必须包含在result[i].range中即返回的选区必须覆盖请求的位置为了允许「某些位置有选区、某些位置没有选区」的情况result[i].range允许退化为positions[i]处的空选区empty range。这两条约束保证了协议在边界情况下的健壮性即使服务器对某个位置无法给出有意义的选区也必须返回一个与请求位置对应的占位项而不是缩短返回数组、破坏索引对齐关系。二、客户端能力声明SelectionRangeClientCapabilities客户端需要在initialize请求中通过能力声明告知服务器自己是否支持选区提供器。3.19 的 initialize.md 中ClientCapabilities包含selectionRange?: SelectionRangeClientCapabilities字段。规范定义如下selectionRange.md原文export interface SelectionRangeClientCapabilities { /** * Whether the implementation supports dynamic registration for selection range * providers. If this is set to true, the client supports the new * SelectionRangeRegistrationOptions return value for the corresponding * server capability as well. */ dynamicRegistration?: boolean; }该接口在 metaModel.json 中同样以SelectionRangeClientCapabilities类型登记文档注释与规范一致。关键点属性名为textDocument.selectionRange类型为SelectionRangeClientCapabilities可选客户端可以不声明表示不支持该功能dynamicRegistration表示客户端是否支持对选区提供器的动态注册。若为true服务器在serverCapabilities中即可返回完整的SelectionRangeRegistrationOptions而不只是布尔值或SelectionRangeOptions从而允许服务器在运行期通过client/registerCapability动态注册/注销该能力详见 registerCapability.md。三、服务器能力声明与注册选项3.1 serverCapabilities 声明服务器在initialize响应中通过serverCapabilities.selectionRangeProvider声明自己支持该请求。3.19 的 initialize.md 中ServerCapabilities对应声明为selectionRangeProvider?: boolean | SelectionRangeOptions | SelectionRangeRegistrationOptions;即三种声明方式声明值含义true服务器静态支持选区请求最简单的声明方式SelectionRangeOptions带工作进度work done progress支持的静态声明SelectionRangeRegistrationOptions完整注册选项支持动态注册需客户端dynamicRegistration: true3.2 SelectionRangeOptionsexport interface SelectionRangeOptions extends WorkDoneProgressOptions { }SelectionRangeOptions本身是一个空接口仅继承WorkDoneProgressOptionsworkDoneProgress?: boolean表示服务器是否支持在请求处理期间报告工作进度配合window/workDoneProgress/create使用。从源码结构看它作为一个独立类型存在是为了给后续版本扩展选项预留位置同时在类型系统上保证SelectionRangeRegistrationOptions可以安全地继承它。3.3 SelectionRangeRegistrationOptionsexport interface SelectionRangeRegistrationOptions extends SelectionRangeOptions, TextDocumentRegistrationOptions, StaticRegistrationOptions { }它组合了三类既有选项SelectionRangeOptions工作进度支持TextDocumentRegistrationOptionsdocumentSelector?: DocumentFilter[]限定该提供器只作用于匹配的文档语言标识、URI scheme、pattern 等参考 documentFilter.mdStaticRegistrationOptionsid?: string当该能力不是通过 initialize 静态注册、而是后续动态注册时用于标识注册 id。在 metaModel.json 中SelectionRangeRegistrationOptions的登记结构与上述一致extendsSelectionRangeOptions、TextDocumentRegistrationOptionsmixinsStaticRegistrationOptions。四、请求参数SelectionRangeParams请求方法为textDocument/selectionRange参数类型为SelectionRangeParamsexport interface SelectionRangeParams extends WorkDoneProgressParams, PartialResultParams { /** * The text document. */ textDocument: TextDocumentIdentifier; /** * The positions inside the text document. */ positions: Position[]; }字段说明textDocumentTextDocumentIdentifier即目标文档的uri文档唯一资源标识参考 textDocumentIdentifier.mdpositions位置数组一次请求可以批量查询多个位置例如编辑器对多光标选择、或对整屏做选区预处理时会一次传入多个光标位置继承自WorkDoneProgressParams的可选workDoneToken用于报告处理进度继承自PartialResultParams的可选partialResultToken用于以部分结果SelectionRange[]分片流式返回避免大文档结果一次性全量传输相关机制见 partialResultParams.md 与 partialResults.md。其中Position是零基的{ line, character }结构character的字节含义由初始化时协商的PositionEncodingKind决定默认utf-16详见 position.md。五、返回结构SelectionRange 与父节点链5.1 SelectionRange 类型export interface SelectionRange { /** * The [range](#Range) of this selection range. */ range: Range; /** * The parent selection range containing this range. * Therefore, parent.range must contain this.range. */ parent?: SelectionRange; }SelectionRange是一个自引用链表节点由两个字段构成range必填本次选区的 Range零基的start/end位置end为开区间parent可选指向包含当前选区的外层选区。约束parent.range必须包含this.range。在 metaModel.json 中该类型被登记为 A selection range represents a part of a selection hierarchy. A selection range may have a parent selection range that contains it.——即整个返回值本质上描述的是一个选区层级selection hierarchy。5.2 层级链的读取方式客户端拿到SelectionRange[]后通过循环读取parent指针即可从最内层一路遍历到最外层形成「由小到大」的选区序列。典型结果形态如下示意[ { range: { start: { line: 2, character: 6 }, end: { line: 2, character: 9 } }, // bar parent: { range: { start: { line: 2, character: 4 }, end: { line: 2, character: 14 } }, // foo(bar) parent: { range: { start: { line: 2, character: 0 }, end: { line: 2, character: 17 } }, // 整条语句 parent: undefined // 最外层没有父节点 } } } ]编辑器依据这条链实现「Expand Selection展开选区」第一次按快捷键选中bar再按一次切换到foo(bar)第三次切换到整条语句。展开方向一定是由内向外因为协议强制parent.range包含this.range。5.3 返回结果的整体约束result类型为SelectionRange[] | nullnull表示无法提供任何选区例如文档不支持数组则与positions按下标对齐允许部分位置返回空选区range为positions[i]处零长度 range以维持索引对齐支持部分结果partial result以SelectionRange[]分片流式返回出错时返回错误码与错误消息error: code and message例如文档未打开、位置越界等异常场景。六、服务器实现要点与协议约束6.1 实现步骤在语言服务器中实现textDocument/selectionRange推荐按以下步骤能力声明在initialize响应中设置capabilities.selectionRangeProvider true或返回SelectionRangeOptions/SelectionRangeRegistrationOptions视是否支持动态注册而定处理请求收到textDocument/selectionRange请求后按textDocument.uri找到文档内容解析语法树对positions中的每个位置定位其在语法树中命中的最内层节点构造层级链从最内层节点开始沿语法树父节点向上逐层生成SelectionRange节点每个节点的range对应语法树节点或词法单元的范围parent指向外层节点直到没有父节点为止按索引对齐返回保证result[i]与positions[i]一一对应某个位置无法解析时返回positions[i]处的空选区作为占位可选进度与部分结果耗时场景使用workDoneToken上报进度、partialResultToken分片返回结果。6.2 需要注意的协议细节空选区占位宁可返回空 range 也不要在数组中对齐错位这是规范明确允许的兜底行为层级包含性parent.range必须包含this.range否则编辑器展开选区的行为会混乱选区不一定是语法节点规范明确说明选区「通常但非必须」对应语法树节点服务器可以自由定义更有用的层级例如包含注释、宏展开区域等批量位置positions支持数组一次请求处理多个光标位置实现时应注意对每个位置独立解析、互不影响与 Symbol 的 selectionRange 区别注意区分本请求与 documentSymbol.md、callHierarchy.md、typeHierarchy.md 中符号条目上携带的selectionRange字段——后者是「符号被选中时应该高亮/选中的范围」如函数名而本文的请求是按光标位置动态计算整套嵌套选区二者语义不同但可以共享同一套语法树与范围计算逻辑。七、版本与规范演变小结3.15.0textDocument/selectionRange首次引入并同时引入服务器/客户端信息等能力见 specification.md 的 3.15 变更日志3.16 ~ 3.19请求类型定义保持稳定SelectionRangeParams一直继承WorkDoneProgressParams与PartialResultParamsSelectionRangeRegistrationOptions的组合方式也保持兼容同一请求在 3.17、3.18、3.19 各版本的 language/selectionRange.md3.17 版与 3.19 版之间仅有文案微调接口结构完全一致说明该能力自 3.15 引入后接口层相当稳定。如果你正在开发 LSP 语言服务器可以让编辑器的「Expand Selection」体验与主流 IDE 保持一致核心就是把语法树节点的嵌套关系翻译成SelectionRange.parent链并按规范守住「索引对齐」与「父包含子」两条底线即可。赞分享开发工具【免费下载链接】language-server-protocolDefines a common protocol for language servers.项目地址https://gitcode.com/gh_mirrors/la/language-server-protocol点击查看免费下载相关推荐Language Server Protocol 3.18 Selection Range 请求详解从语法树节点到智能选区Language Server Protocol 3.18 Selection Range 请求详解从语法树节点到智能选区 导读 textDocument/s开发工具LSP 动态能力注销全解析language-server-protocol 的 client/unregisterCapability 请求实践LSP 动态能力注销全解析language server protocol 的 client/unregisterCapability 请求实践 本文以 la开发工具Language Server Protocol 动态能力注销深入解析 client/unregisterCapability 请求Language Server Protocol 动态能力注销深入解析 client/unregisterCapability 请求 导读 client/un开发工具上一篇Audacity音频编辑神器3个真实场景教你从零到专业创作下一篇Captura多显示器录制快捷键终极指南自定义与预设方案完整教程创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表