
开发工具【免费下载链接】language-server-protocolDefines a common protocol for language servers.项目地址https://gitcode.com/gh_mirrors/la/language-server-protocol点击查看免费下载导读本文聚焦语言服务器协议Language Server ProtocolLSP3.19 规范中的textDocument/didClose通知讲解客户端在关闭文本文档时如何向语言服务器同步状态包括通知的方向、参数结构、能力协商、注册选项以及它与didOpen、didChange之间的平衡与顺序约束。读完本文你将掌握 didClose 的完整协议语义能正确地在自己的语言服务器中注册并处理关闭事件也能依据本仓库的规范文档与 metaModel 定义校验你的实现是否符合 LSP 3.19。关闭通知在文本同步中的地位LSP 的文本文档同步由textDocument/didOpen、textDocument/didChange与textDocument/didClose三组通知共同组成。在 3.19 规范 的「Text Document Synchronization」一节中明确说明客户端对这三个通知的支持是强制性的mandatory客户端不能选择不支持而服务器要么三者全部实现要么全部不实现。同时退出文本同步opt out只在客户端展示只读文档时才有意义否则服务器收到的请求所针对的文档内容可能早已由客户端管理并发生变更。textDocument/didClose正是这条闭环上的最后一环它标志着一个由客户端托管内容的文档重新交还其「真源」master / truth。当文档被关闭后文档的真源重新存在于其 URI 所指向的位置——例如对于file协议 URI真源就是磁盘上的文件。在此之前文档内容一直由客户端内存托管服务器不得通过 URI 去读取文档内容。协议定义方法名、方向与参数结构didClose 是一条从客户端发往服务器的通知clientToServer规范中以:arrow_right:标识。其完整定义如下协议要素值methodtextDocument/didClosedirectionclient → server通知无响应paramsDidCloseTextDocumentParamsregistration optionsTextDocumentRegistrationOptionsclient capabilitytextDocument.synchronizationserver capabilitytextDocumentSync对应openClose选项参数的 TypeScript 定义来自 关联文档interface DidCloseTextDocumentParams { /** * The document that was closed. */ textDocument: TextDocumentIdentifier; }一条典型的 JSON-RPC 消息示例{ jsonrpc: 2.0, method: textDocument/didClose, params: { textDocument: { uri: file:///home/user/projects/example/src/main.ts } } }注意这是一条通知因此消息中没有id字段服务器也无需也不能返回任何响应。参数详解DidCloseTextDocumentParamsDidCloseTextDocumentParams仅包含一个字段textDocument其类型为TextDocumentIdentifier。与didOpen携带完整的TextDocumentItem包含uri、languageId、version、text四要素不同关闭时客户端不再需要也不可能再发送文档全文只用一个标识符即可。TextDocumentIdentifier的定义见 3.19 类型文档interface TextDocumentIdentifier { /** * The text documents URI. */ uri: DocumentUri; }在协议层面URI 一律以字符串形式传递DocumentUri。因此服务器可以通过params.textDocument.uri唯一确定被关闭的文档并据此清理缓存、释放内存或持久化相关状态。能力协商谁来决定 didClose 是否生效客户端能力Client CapabilitydidClose 的通知能力绑定在通用的同步能力上即 3.19 规范 中定义的textDocument.synchronization属性路径可选textDocument.synchronization.dynamicRegistration属性类型boolean该布尔值控制文本同步是否支持动态注册。完整的客户端能力结构如下export interface TextDocumentSyncClientCapabilities { /** * Whether text document synchronization supports dynamic registration. */ dynamicRegistration?: boolean; /** * The client supports sending will save notifications. */ willSave?: boolean; /** * The client supports sending a will save request and * waits for a response providing text edits which will * be applied to the document before it is saved. */ willSaveWaitUntil?: boolean; /** * The client supports did save notifications. */ didSave?: boolean; }服务器能力Server Capability服务器在initialize响应中通过textDocumentSync声明自己的同步能力其类型为TextDocumentSyncKind | TextDocumentSyncOptions。其中与 open/close 通知直接相关的选项是openClose。规范给出的核心定义如下export interface TextDocumentSyncOptions { /** * Open and close notifications are sent to the server. If omitted open * close notifications should not be sent. */ openClose?: boolean; /** * Change notifications are sent to the server. See * TextDocumentSyncKind.None, TextDocumentSyncKind.Full and * TextDocumentSyncKind.Incremental. If omitted it defaults to * TextDocumentSyncKind.None. */ change?: TextDocumentSyncKind; }要点openClose一旦省略客户端就不应再发送 open/close 通知change省略时默认值为TextDocumentSyncKind.None。TextDocumentSyncKind的三个取值如下export namespace TextDocumentSyncKind { /** * Documents should not be synced at all. */ export const None 0; /** * Documents are synced by always sending the full content * of the document. */ export const Full 1; /** * Documents are synced by sending the full content on open. * After that only incremental updates to the document are * sent. */ export const Incremental 2; } export type TextDocumentSyncKind 0 | 1 | 2;一个服务器在 initialize 响应中声明支持 open/close 与增量同步的示例{ jsonrpc: 2.0, id: 1, result: { capabilities: { textDocumentSync: { openClose: true, change: 2 } } } }从 metaModel 的机器可读定义看见 metaModel.jsonDidCloseTextDocumentNotification的serverCapability精确对应textDocumentSync.openClose——这印证了服务器只有显式开启openClose: truedidClose 通知才会被客户端发送。注册选项TextDocumentRegistrationOptions 与 documentSelectordidClose 的动态注册使用通用文本文档注册选项TextDocumentRegistrationOptions。该类型只有一个字段documentSelector用于界定注册的作用范围。根据 metaModel.json 中的定义export interface TextDocumentRegistrationOptions { /** * A document selector to identify the scope of the registration. * If set to null the document selector provided on the client * side will be used. */ documentSelector: DocumentSelector | null; }当服务器支持动态注册时可以通过client/registerCapability请求向客户端注册 didClose 处理注册选项中携带方法名textDocument/didClose与上述documentSelector例如限定只关注language: typescript或匹配*.ts模式的文档。若选择器为null则复用客户端侧提供的文档选择器。与 didOpen 的配对关系一条硬性约束关闭通知在语义上始终与打开通知配对规范文档给出了两条需要牢记的规则收到 close 通知不代表该文档之前在编辑器中打开过。打开open的本义是「由客户端托管内容」不一定意味着内容呈现在编辑器中同样关闭也不意味着它曾被展示。但协议要求一条 close 通知之前必须已经发送过对应的 open 通知。open 与 close 必须保持平衡对于同一个textDocument在没有对应 close 通知的情况下不得重复发送 open 通知——即单个文档的最大 open 计数为 1。从 3.19 didOpen 文档 可以读到更完整的表述open 和 close 通知必须成对出现某个特定 textDocument 的 open 计数上限为 1。这条约束带来的实际后果是服务器不应假设「收到 close 就一定意味着有编辑器标签页被关闭」更不能假设 close 之后文档就消失——它只是把内容托管权交还给 URI 指向的位置典型场景即磁盘文件。语言 id 变更时的 close → open 顺序didOpen的参数中携带文档关联的语言 idlanguageId。如果文档的语言 id 发生变化且服务器同样处理新语言 id则客户端必须先发送textDocument/didClose再发送携带新 language id 的textDocument/didOpen。这也是 close 通知在实际客户端中最重要的触发场景之一——它是语言切换language mode 切换时状态重置的标准通道。与 didChange 的衔接一次完整的状态流转结合 didChange 文档 可以梳理出文档内容在客户端与服务器之间的完整生命周期客户端打开文档 → textDocument/didOpen携带全文与语言 id 客户端编辑文档 → textDocument/didChange全量或增量内容变化 客户端关闭文档 → textDocument/didClose仅携带 uri在编辑过程中客户端必须保证发送请求如textDocument/completion、textDocument/signatureHelp之前文档状态已经与服务器同步否则请求结果可能基于过期内容。而关闭通知不携带版本号与内容它只负责终结这段托管关系。metaModel 证据机器可读定义与规范文本相互印证本仓库的 metaModel.json 是 LSP 3.19 的机器可读元模型其中对 didClose 的定义与规范文档完全一致可作为实现与校验的权威依据DidCloseTextDocumentNotificationmethod为textDocument/didClosemessageDirection为clientToServerclientCapability为textDocument.synchronizationserverCapability为textDocumentSync.openCloseregistrationOptions引用TextDocumentRegistrationOptionsparams引用DidCloseTextDocumentParams。DidCloseTextDocumentParams仅含textDocument属性类型引用TextDocumentIdentifier文档说明为「关闭文本文档通知所发送的参数」。如果你的语言服务器通过元模型生成类型或脚手架metaModel 同时提供metaModel.schema.json与 TypeScript 生成版本metaModel.ts见 _specifications/lsp/3.19/metaModel/didClose 的相关类型会被自动包含无需手工维护。此外3.19 元模型中还有同族的notebookDocument/didClose通知用于笔记本Notebook文档的关闭场景其语义与文本文档关闭类似但针对 Notebook 模型详见 notebook.md。服务器端处理实战建议以下是一个服务器端处理 didClose 的典型流程伪代码适用于基于任何语言实现的 LSP 服务器function onDidClose(params: DidCloseTextDocumentParams): void { const uri: string params.textDocument.uri; // 1. 从文档缓存中移除内容快照 documentStore.delete(uri); // 2. 清理与该文档关联的诊断信息若已发布可考虑 // 发送空诊断或在相关请求返回后自然失效 diagnostics.clear(uri); // 3. 释放该文档相关的语言特性缓存如符号列表、 // 语义令牌、折叠区间等派生数据 featureCache.invalidate(uri); // 4. 注意不应假设文档已删除文件可能仍然存在于磁盘 log(Document closed: ${uri}); }实现时需要把握规范强调的语义边界服务器满足请求的能力独立于文档是打开还是关闭。规范原文明确指出服务器完成请求的能力与文本文档的开关状态无关。因此在收到 didClose 后服务器不应把该文档视为「不可服务」——只是它不能再依赖客户端托管的内存内容如需内容应回到 URI 真源磁盘读取。不要为了响应 didClose 而主动向客户端索要内容也不需要发送任何确认它是单向通知。严格遵循 open/close 平衡如果客户端违反约束未 open 就 close从规范看这是客户端协议错误健壮的服务器可以记录告警并幂等地清理状态避免崩溃。小结与进一步阅读textDocument/didClose虽然参数只有一个 URI却是 LSP 文本同步闭环中不可或缺的一环它把文档内容的托管权从客户端交还给 URI 真源并与didOpen构成必须平衡的配对约束同时还是语言 id 切换时状态重置的标准手段。理解其方向性通知、无响应、能力协商textDocument.synchronization/textDocumentSync.openClose与注册方式TextDocumentRegistrationOptions是正确实现任何 LSP 服务器的基本功。如需深入推荐按以下路径在本仓库中继续阅读同步机制总览3.19 规范「Text Document Synchronization」章节与 close 配对的打开通知didOpen.md中间态的内容变更didChange.mdURI 标识符类型textDocumentIdentifier.md机器可读的完整定义metaModel.json赞分享开发工具【免费下载链接】language-server-protocolDefines a common protocol for language servers.项目地址https://gitcode.com/gh_mirrors/la/language-server-protocol点击查看免费下载相关推荐Language Server Protocol 的 textDocument/didClose 通知文档关闭同步机制全解析Language Server Protocol 的 textDocument/didClose 通知文档关闭同步机制全解析 导读 textDocument/开发工具language-server-protocol 文档精读textDocument/didChange 文档变更通知与客户端-服务端同步机制language server protocol 文档精读textDocument/didChange 文档变更通知与客户端 服务端同步机制 导读 textD开发工具Language Server Protocol 3.17 TextDocumentItem 详解客户端到服务器的文本文档传输载体Language Server Protocol 3.17 TextDocumentItem 详解客户端到服务器的文本文档传输载体 TextDocumentI开发工具上一篇web3.js 网络属性查询指南使用 web3-net 包获取节点网络 ID、Peer 数量与监听状态下一篇CANN ops-math 算子指南aclnnGeTensor / aclnnInplaceGeTensor 大于等于比较接口详解创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考