ARTICLE DETAIL

资讯详情

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

Language Server Protocol 3.17 文本同步系列:深入解析 `textDocument/didSave` 保存通知的协议设计与实现

Language Server Protocol 3.17 文本同步系列:深入解析 `textDocument/didSave` 保存通知的协议设计与实现 开发工具【免费下载链接】language-server-protocolDefines a common protocol for language servers.项目地址https://gitcode.com/gh_mirrors/la/language-server-protocol点击查看免费下载textDocument/didSave是 LSPLanguage Server Protocol文本同步机制中保存环节的关键通知由客户端在文档被保存后发送给语言服务器配合textDocumentSync.save服务器能力与SaveOptions.includeText选项实现保存内容的按需回传。本文以本仓库 3.17 规范原文 为骨架结合同目录下的同步能力定义与元模型metaModel佐证完整讲解该通知的客户端/服务器能力声明、注册选项、参数结构以及与willSave、didChange等相邻通知的协同关系帮助语言服务器开发者正确实现保存感知与内容快照功能。一、通知概览保存事件从客户端到服务器的单向传递DidSaveTextDocument Notification是从客户端编辑器发送到服务器语言服务的通知:arrow_right:表示 Client → Server 方向触发时机为文档已在客户端完成保存。在协议生命周期中保存通知是文本同步text synchronization阶段的一部分。客户端在文档被保存后调用该方法通知服务器服务器可据此触发索引刷新、缓存失效、增量编译、格式化结果落盘等后处理逻辑。它的典型语义是事情已经发生因此与willSave保存前通知可在保存前做预处理形成时间轴上的先后呼应通知方向时机用途textDocument/willSaveClient → Server保存前预处理、拦截、记录状态textDocument/willSaveWaitUntilClient → Server请求保存前并等待结果返回编辑客户端应用后才保存textDocument/didSaveClient → Server保存后后处理、按需回传内容规范原文位于 didSave.md并作为子文档被 3.17 总规范 的文本同步章节通过include_relative引入与 didOpen、didChange、willSave、willSaveWaitUntil、didClose、didRename 共同构成完整的文本同步通知集合。二、客户端能力声明textDocument.synchronization.didSave要让服务器判断客户端是否会发送保存通知客户端必须在initialize请求的capabilities.textDocument.synchronization中声明能力属性名可选textDocument.synchronization.didSave属性类型boolean该能力表示客户端支持发送textDocument/didSave通知。在 总规范 中TextDocumentSyncClientCapabilities将这一字段与其他同步能力并列定义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; }一个声明了保存通知能力的客户端其initialize参数片段大致如下{ capabilities: { textDocument: { synchronization: { dynamicRegistration: true, willSave: true, willSaveWaitUntil: true, didSave: true } } } }服务器收到该能力后即可决定是否在initialize结果中开启自己的保存订阅。三、服务器能力声明textDocumentSync.save与SaveOptions.includeText服务器端对应的能力属性为属性名可选textDocumentSync.save属性类型boolean | SaveOptions该能力表示服务器对textDocument/didSave通知感兴趣即希望客户端在保存后通知它。SaveOptions的定义如下源自 didSave.mdexport interface SaveOptions { /** * The client is supposed to include the content on save. */ includeText?: boolean; }includeText是这里最值得关注的字段省略或为false客户端不在通知中携带文档内容仅通知文件已保存为true客户端应在didSave通知的参数text字段中携带保存时的完整文档内容。includeText的设计价值在于带宽与性能的权衡语言服务器多数场景只需要保存事件本身例如触发增量索引而某些场景如离线分析、文档内容校验、服务器端缓存缺失时的全量重建则需要保存瞬间的内容快照。协议把是否回传内容的决定权交给服务器避免每次保存都无谓地传输全文。在 3.17 总规范 中完整的TextDocumentSyncOptions将save字段与 openClose、change、willSave、willSaveWaitUntil 并列export interface TextDocumentSyncOptions { /** * Open and close notifications are sent to the server. If omitted open * close notification 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; /** * If present will save notifications are sent to the server. If omitted * the notification should not be sent. */ willSave?: boolean; /** * If present will save wait until requests are sent to the server. If * omitted the request should not be sent. */ willSaveWaitUntil?: boolean; /** * If present save notifications are sent to the server. If omitted the * notification should not be sent. */ save?: boolean | SaveOptions; }服务器在initialize结果中开启保存订阅的示例{ capabilities: { textDocumentSync: { openClose: true, change: 2, willSave: true, willSaveWaitUntil: true, save: { includeText: true } } } }若只需要保存事件本身可写save: true若还需要保存时的全文内容则写save: { includeText: true }。四、注册选项TextDocumentSaveRegistrationOptions当客户端支持动态注册dynamicRegistration时服务器可通过client/registerCapability请求动态订阅保存通知此时使用的注册选项为TextDocumentSaveRegistrationOptionsexport interface TextDocumentSaveRegistrationOptions extends TextDocumentRegistrationOptions { /** * The client is supposed to include the content on save. */ includeText?: boolean; }它同时继承了TextDocumentRegistrationOptions包含documentSelector用于限定订阅哪些文档与SaveOptions包含includeText。这一继承关系在 metaModel.json 的元模型中得到了印证TextDocumentSaveRegistrationOptions的extends数组同时引用了TextDocumentRegistrationOptions与SaveOptions。一个动态注册保存通知的client/registerCapability请求示例{ jsonrpc: 2.0, method: client/registerCapability, params: { registrations: [ { id: didSave-reg-1, method: textDocument/didSave, registerOptions: { documentSelector: [{ language: typescript }], includeText: false } } ] } }TextDocumentRegistrationOptions中的documentSelector用于约束哪些文档保存时通知本服务器是动态注册场景下精确控制事件流量的关键手段。五、通知本体方法与参数结构textDocument/didSave通知的核心定义如下方法名textDocument/didSave参数DidSaveTextDocumentParams参数结构源自 didSave.mdinterface DidSaveTextDocumentParams { /** * The document that was saved. */ textDocument: TextDocumentIdentifier; /** * Optional the content when saved. Depends on the includeText value * when the save notification was requested. */ text?: string; }两个字段的语义字段类型必填说明textDocumentTextDocumentIdentifier是被保存的文档标识URItextstring否保存时的文档内容仅当请求时includeText为true才出现TextDocumentIdentifier的定义见 textDocumentIdentifier.mdinterface TextDocumentIdentifier { /** * The text documents URI. */ uri: DocumentUri; }协议层面的 URI 以字符串形式传递。一个真实的textDocument/didSave通知报文示例includeText: true场景{ jsonrpc: 2.0, method: textDocument/didSave, params: { textDocument: { uri: file:///home/user/project/src/main.ts }, text: export function add(a: number, b: number): number {\n return a b;\n}\n } }而当includeText省略或为false时text字段应被省略报文仅携带 URI{ jsonrpc: 2.0, method: textDocument/didSave, params: { textDocument: { uri: file:///home/user/project/src/main.ts } } }六、与相邻同步通知的协同构建完整的保存语义理解didSave需要将它放在文本同步的完整时间轴中。从 3.17 总规范 的子文档引入顺序didOpen → didChange → willSave → willSaveWaitUntil → didSave → didClose → didRename可以看出协议设计的生命周期打开客户端通过textDocument/didOpen声明对文档内容的所有权参见 didOpen.md此后服务器不得再通过 URI 自行读取文档内容修改内容变化期间客户端按TextDocumentSyncKindNone/Full/Incremental见 specification.md通过textDocument/didChange增量同步参见 didChange.md保存前textDocument/willSave通知携带TextDocumentSaveReasonManual/AfterDelay/FocusOut见 willSave.md服务器可在保存发生前响应保存后textDocument/didSave通知事件发生服务器根据includeText决定是否收到内容快照关闭textDocument/didClose释放所有权。这里有一个关键实现考量didSave中的text是保存瞬间的内容与编辑过程中的最新缓冲区内容可能不同步。如果服务器依赖保存内容做全量分析应注意客户端在保存时可能尚未将所有didChange事件发送完毕因此更稳妥的做法是结合didChange的版本号VersionedTextDocumentIdentifier维护文档状态把didSave当作刷新时机而非内容来源。七、从元模型看协议的数据结构约束仓库中的 metaModel.json 是 3.17 协议的结构化元模型可作为实现层面的协议契约验证。与didSave相关的关键记录包括DidSaveTextDocumentParamsL4553-L4573明确textDocument引用TextDocumentIdentifiertext为可选的string类型其文档注释与规范原文一致——内容是否出现取决于请求保存通知时设置的includeText值TextDocumentSaveRegistrationOptionsL4576-L4589extends同时指向TextDocumentRegistrationOptions与SaveOptionsSaveOptionsL8795定义includeText?: boolean通知注册条目L2066-L2074textDocument/didSave关联DidSaveTextDocumentParams与TextDocumentSaveRegistrationOptions。对于使用代码生成方式开发 LSP 客户端的团队这套元模型正是自动生成DidSaveTextDocumentParams、SaveOptions等类型定义与消息分发代码的权威数据源确保生成的代码与规范文档严格一致。八、服务器端落地实践建议结合上述协议定义语言服务器实现didSave时建议遵循以下要点能力协商先行在initialize结果中按需声明textDocumentSync.save只在确实需要保存事件时开启避免无意义的事件流量按需选择includeText仅当服务器需要保存时刻的完整内容如离线索引、全文校验时设为true仅用于触发增量分析时应设为false或省略节省传输带宽区分willSave与didSave需要在保存前修改文档或拦截保存流程使用willSave/willSaveWaitUntil需要保存后的确定性回调使用didSave警惕内容时序didSave携带的text是保存时的内容与最新编辑缓冲区可能存在版本差异内容敏感的逻辑应以didChange的版本号为准动态注册按需订阅若客户端支持dynamicRegistration可通过client/registerCapability仅对目标语言/目录的文档订阅保存通知配合documentSelector精确控制。九、总结textDocument/didSave是 LSP 文本同步机制的收尾环节通过textDocument.synchronization.didSave客户端能力、textDocumentSync.save服务器能力boolean | SaveOptions与includeText选项的协商在保存事件与保存内容回传之间提供了灵活的选择粒度。本文完整覆盖了规范中该通知的能力声明、注册选项、参数结构并结合 总规范 与 metaModel.json 交叉验证了类型定义的一致性。对语言服务器开发者而言正确实现保存通知的协商与处理是构建可靠的保存触发式分析、索引与校验能力的基础一步。赞分享开发工具【免费下载链接】language-server-protocolDefines a common protocol for language servers.项目地址https://gitcode.com/gh_mirrors/la/language-server-protocol点击查看免费下载相关推荐Language Server Protocol 3.17 保存前通知 textDocument/willSave 全解析协议定义、参数结构与能力协商Language Server Protocol 3.17 保存前通知 textDocument/willSave 全解析协议定义、参数结构与能力协商 导读开发工具language-server-protocol 深度解析textDocument/didOpen 文档打开通知与文本同步机制language server protocol 深度解析textDocument/didOpen 文档打开通知与文本同步机制 textDocument/di开发工具Language Server Protocol 3.17 Find References 请求详解textDocument/references 协议规范与实现指南Language Server Protocol 3.17 Find References 请求详解textDocument/references 协议规范与开发工具创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表