
开发工具【免费下载链接】language-server-protocolDefines a common protocol for language servers.项目地址https://gitcode.com/gh_mirrors/la/language-server-protocol点击查看免费下载导读本文基于开源仓库 language-server-protocol 中 _specifications/lsp/3.19/language/publishDiagnostics.md 的协议定义系统讲解 LSP 中诊断Diagnostics从服务器到客户端的推送机制包括消息方向与格式、诊断的所有权与清除规则、客户端能力声明PublishDiagnosticsClientCapabilities、通知参数PublishDiagnosticsParams以及底层Diagnostic数据结构。读完本文你将掌握如何实现一个符合 LSP 3.19 规范的语言服务器诊断发布逻辑并能结合仓库中的元模型metaModel与规范正文验证实现细节。1. 通知概览服务器单向推送诊断textDocument/publishDiagnostics是一个由**服务器发送到客户端serverToClient**的 Notification通知用于把校验validation运行的结果推送给客户端。在 LSP 消息体系中通知不需要客户端应答服务器可以随时主动推送。该消息在仓库的元模型 metaModel.json 中被正式登记为methodtextDocument/publishDiagnosticstypeNamePublishDiagnosticsNotificationmessageDirectionserverToClientclientCapabilitytextDocument.publishDiagnosticsparamsPublishDiagnosticsParams同时它也被登记在TextDocumentClientCapabilities的可选属性列表中metaModel.json说明客户端需要在初始化握手时声明对该通知的接收能力。规范正文在 _specifications/lsp/3.19/specification.md 中通过{% include_relative language/publishDiagnostics.md %}引入本文档与pullDiagnostics诊断拉取等章节并列构成 LSP 的诊断能力全景。2. 诊断的所有权模型清除是服务器的责任规范明确规定诊断Diagnostics由服务器拥有owned因此如果需要清除诊断必须由服务器自己负责。客户端不会自作主张地删除服务器推送的诊断。规范以 VS Code 生态中两类典型语言服务器为例给出了两种截然不同的清除策略单文件语言例如 HTML当文件关闭时服务器清除该文件的诊断。但请注意打开/关闭事件并不完全等同于用户在界面上看到的内容——这些事件本质上是所有权转移事件ownership events。因此在当前版本规范下可能出现文件已在界面中不可见但客户端尚未关闭该文件导致问题诊断仍然保留的情况。具备项目系统的语言例如 C#文件关闭时不清除诊断。当项目被打开时所有文件的诊断会被重新计算或从缓存中读取。这两条规则背后折射出的设计思想是服务器对一份诊断的生命周期拥有最终决定权客户端只负责展示。从源码结构看这与 LSP 中textDocument/didOpen、textDocument/didChange、textDocument/didClose等通知见 _specifications/lsp/3.19/textDocument 目录下的对应文档共同构成文档所有权管理闭环——正是这些所有权事件驱动服务器决定何时重算、何时清除诊断。3. 重算与覆盖语义空数组即清除、新推即替换规范对文件变更后的诊断更新给出了三条必须遵守的硬性规则当文件发生变化时服务器有责任重新计算诊断并推送给客户端。如果计算出的集合为空服务器必须推送空数组[]以清除先前的诊断。新推送的诊断总是完全替换先前推送的诊断客户端不做任何合并no merging。也就是说textDocument/publishDiagnostics每次推送的都是该文档当前时刻的完整诊断快照而不是增量补丁。这一语义极大简化了客户端的实现客户端只需无条件地以最新一次推送覆盖该 URI 对应的诊断集合即可无需考虑合并冲突或历史增量。这也是该通知在协议层面反复强调服务器拥有诊断、服务器负责清除的根本原因。4. 客户端能力声明PublishDiagnosticsClientCapabilities在初始化阶段客户端可通过initialize请求的capabilities.textDocument.publishDiagnostics属性可选声明其对该通知的支持程度。规范原文定义如下export interface PublishDiagnosticsClientCapabilities { /** * Whether the clients accepts diagnostics with related information. */ relatedInformation?: boolean; /** * Client supports the tag property to provide meta data about a diagnostic. * Clients supporting tags have to handle unknown tags gracefully. * * since 3.15.0 */ tagSupport?: ClientDiagnosticsTagOptions; /** * Whether the client interprets the version property of the * textDocument/publishDiagnostics notifications parameter. * * since 3.15.0 */ versionSupport?: boolean; /** * Client supports a codeDescription property. * * since 3.16.0 */ codeDescriptionSupport?: boolean; /** * Whether code action supports the data property which is * preserved between a textDocument/publishDiagnostics and * textDocument/codeAction request. * * since 3.16.0 */ dataSupport?: boolean; }各字段含义与使用建议如下表字段类型引入版本含义服务器侧注意事项relatedInformationboolean?基础客户端是否接受带关联信息related information的诊断为false或缺失时服务器不应发送Diagnostic.relatedInformationtagSupportClientDiagnosticsTagOptions?3.15.0客户端支持的诊断标签tag集合客户端必须对未知标签优雅降级gracefully handle unknown tags服务器仍应尽量只发声明过的标签versionSupportboolean?3.15.0客户端是否解析通知参数中的version字段为true时服务器应正确维护并推送文档版本号codeDescriptionSupportboolean?3.16.0客户端是否支持codeDescription属性决定服务器能否为错误码附带可点击的说明链接dataSupportboolean?3.16.0客户端是否支持data属性在诊断通知与 codeAction 请求之间往返传递见第 8 节data 往返说明其中tagSupport的类型ClientDiagnosticsTagOptions定义如下export type ClientDiagnosticsTagOptions { /** * The tags supported by the client. */ valueSet: DiagnosticTag[]; };从仓库元模型可以印证这些字段在协议描述中的位置metaModel.json 记录了versionSupport的文档注释metaModel.json 记录了dataSupport的文档注释二者均与规范正文一一对应可作为实现方对拍校验的机器可读依据。5. 通知参数PublishDiagnosticsParamstextDocument/publishDiagnostics通知的参数结构定义如下interface PublishDiagnosticsParams { /** * The URI for which diagnostic information is reported. */ uri: DocumentUri; /** * Optionally, the version number of the document the diagnostics are * published for. * * since 3.15.0 */ version?: integer; /** * An array of diagnostic information items. */ diagnostics: Diagnostic[]; }字段说明uri: DocumentUri必填本次诊断所针对的文档 URI。客户端将依据该 URI 把诊断挂载到对应的编辑器文档上。version?: integer可选自 3.15.0 起该文档的版本号。服务器在客户端声明versionSupport后才应发送此字段其作用是把某一版本文档的诊断与文档内容变化精确关联帮助客户端判断诊断是否过期。diagnostics: Diagnostic[]必填诊断信息条目数组。注意即使没有任何问题也应按第 3 节规则推送空数组以完成清除。一个完整的推送载荷示例JSON-RPC 2.0 消息{ jsonrpc: 2.0, method: textDocument/publishDiagnostics, params: { uri: file:///workspace/src/app.ts, version: 7, diagnostics: [ { range: { start: { line: 3, character: 5 }, end: { line: 3, character: 21 } }, severity: 1, code: TS2304, source: ts, message: Cannot find name foo. } ] } }6. Diagnostic 数据结构深度扩展PublishDiagnosticsParams.diagnostics中的每个条目都是Diagnostic。该类型的完整定义位于 _specifications/lsp/3.19/types/diagnostic.md是理解推送内容的必读配套文档export interface Diagnostic { range: Range; severity?: DiagnosticSeverity; code?: integer | string; codeDescription?: CodeDescription; // since 3.16.0 source?: string; message: string | MarkupContent; // since 3.18.0 支持 MarkupContent tags?: DiagnosticTag[]; // since 3.15.0 relatedInformation?: DiagnosticRelatedInformation[]; data?: LSPAny; // since 3.16.0 }要点解析range: Range必填诊断作用的文本区间是客户端绘制波浪线squiggle的依据。severity?: DiagnosticSeverity严重级别。为避免同一服务器对接不同客户端时产生解释偏差规范强烈建议服务器始终提供 severity若省略客户端通常将其解释为Error错误。code?: integer | string诊断码可能显示在用户界面中例如 TypeScript 的TS2304。codeDescription?: CodeDescription3.16.0对错误码的可选描述链接结构为{ href: URI }。source?: string可读的诊断来源描述例如typescript或super lint。message必填诊断消息。自 3.18.0 起支持MarkupContent富文本但该能力由客户端能力textDocument.diagnostic.markupMessageSupport门控——客户端未声明该能力时服务器不应发送MarkupContent形式的诊断消息。这是 3.19 规范下诊断推送最重要的扩展点之一。tags?: DiagnosticTag[]3.15.0附加元数据用于标记无必要代码或已废弃代码。relatedInformation?: DiagnosticRelatedInformation[]关联诊断信息数组例如作用域内符号名冲突时可通过该属性把所有定义位置一并标记出来。data?: LSPAny3.16.0任意类型数据在textDocument/publishDiagnostics通知与textDocument/codeAction请求之间原样保留见第 8 节。6.1 严重级别枚举DiagnosticSeverityexport namespace DiagnosticSeverity { export const Error: 1 1; // 错误 export const Warning: 2 2; // 警告 export const Information: 3 3; // 信息 export const Hint: 4 4; // 提示 } export type DiagnosticSeverity 1 | 2 | 3 | 4;数值越小表示问题越严重1为 Error、2为 Warning、3为 Information、4为 Hint。6.2 诊断标签枚举DiagnosticTag/** * The diagnostic tags. * * since 3.15.0 */ export namespace DiagnosticTag { export const Unnecessary: 1 1; // 无用/多余代码客户端可淡化渲染 export const Deprecated: 2 2; // 已废弃代码客户端可加删除线渲染 } export type DiagnosticTag 1 | 2;Unnecessary1无用或不必要的代码。客户端被允许将带有该标签的诊断**淡化faded out**渲染而不是显示错误波浪线。Deprecated2已废弃或过时的代码。客户端被允许将其**加删除线strike through**渲染。注意标签能否使用取决于客户端在PublishDiagnosticsClientCapabilities.tagSupport.valueSet中声明的标签集合且客户端被要求对未知标签优雅处理。6.3 关联信息与错误码说明DiagnosticRelatedInformation用于指向导致或与某诊断相关的代码位置例如作用域内重复定义符号的所有定义处export interface DiagnosticRelatedInformation { location: Location; // 关联信息的位置 message: string; // 关联信息的消息 }CodeDescription用于为错误码提供可点击的说明链接export interface CodeDescription { href: URI; // 打开以获取更多错误信息的 URI }这两个类型的使用均受客户端能力门控分别为relatedInformation与codeDescriptionSupport。7. 与 pullDiagnostics 的对比推送 vs 拉取为帮助读者准确定位 publishDiagnostics 在 LSP 诊断体系中的角色这里对照同版本规范的 _specifications/lsp/3.19/language/pullDiagnostics.md 做简要辨析publishDiagnostics推送服务器在自选时机计算并推送诊断。优势是适合工作区级诊断服务器可自由选择计算时点劣势是服务器无法感知用户正在编辑哪个文件难以按需优先计算从didOpen/didChange推断客户端 UI 状态还可能产生误判因为它们是所有权转移通知。pullDiagnostics拉取自 3.17.0引入诊断拉取请求让客户端对哪些文档需要计算诊断、在什么时间点计算拥有更多控制权。两者互补并存pullDiagnostics的引入并非取代推送模型而是为需要精细控制诊断计算时机的场景提供替代路径。本文档所属的publishDiagnostics依然是绝大多数语言服务器的基础实现方式。8. data 字段的跨请求往返自 3.16.0 起Diagnostic.data字段被设计为在textDocument/publishDiagnostics通知与textDocument/codeAction请求之间原样保留的数据通道。其典型用法是服务器推送诊断时在data中放入内部编码的诊断标识如 lint 规则 ID、检查器内部状态用户对某个诊断发起代码修复时客户端把该诊断连同data原样带回textDocument/codeAction请求服务器据此准确还原上下文生成对应的修复 Edit。该设计在元模型中有多处佐证例如 metaModel.json 中data字段的注释即写明在textDocument/publishDiagnostics通知与textDocument/codeAction请求之间保留与 codeAction 文档 中的Diagnostic引用形成闭环。服务器在实现诊断 → 快速修复链路时应优先利用data而非在message中编码私有状态。9. 基于 metaModel 的协议实现骨架本仓库提供了机器可读的协议元模型可作为实现语言服务器的权威对拍依据metaModel.json完整的协议元数据PublishDiagnosticsNotification、PublishDiagnosticsClientCapabilities、PublishDiagnosticsParams均在其中登记metaModel.schema.json元模型自身的 JSON Schema可用于校验自定义元数据生成器metaModel.ts元模型对应的 TypeScript 类型定义如MessageDirection clientToServer | serverToClient | bothpublishDiagnostics 的serverToClient方向正对应此枚举。从实现角度看一个最小可用的诊断推送逻辑需要同时满足在客户端能力未声明对应字段时避免发送相关数据文件变更后总是推送完整快照结果为空时推送[]。这三条正是本文第 2、3 节反复强调的所有权与覆盖语义。10. 参考文档索引本文涉及的核心仓库文档建议按需深读本文档_specifications/lsp/3.19/language/publishDiagnostics.md3.17/3.18 版本位于 _specifications/lsp/3.17 与 _specifications/lsp/3.18 对应目录内容一致Diagnostic 类型_specifications/lsp/3.19/types/diagnostic.md诊断拉取机制对照阅读_specifications/lsp/3.19/language/pullDiagnostics.md完整 3.19 规范正文_specifications/lsp/3.19/specification.md机器可读元模型_specifications/lsp/3.19/metaModel/metaModel.json相关文档生命周期通知textDocument/didOpen.md、textDocument/didChange.md、textDocument/didClose.md通过本文档与上述源码级资料的结合你可以完整落地一个符合 LSP 3.19 规范的诊断推送实现正确声明/读取客户端能力、按所有权规则维护诊断生命周期、推送携带version与data的完整诊断快照并在需要精细控制时评估是否引入pullDiagnostics拉取模型。赞分享开发工具【免费下载链接】language-server-protocolDefines a common protocol for language servers.项目地址https://gitcode.com/gh_mirrors/la/language-server-protocol点击查看免费下载相关推荐Language Server Protocol 3.19 工作进度取消机制window/workDoneProgress/cancel 通知深度解析Language Server Protocol 3.19 工作进度取消机制window/workDoneProgress/cancel 通知深度解析 win开发工具Language Server Protocol 3.19 文档变更同步机制textDocument/didChange 通知详解Language Server Protocol 3.19 文档变更同步机制textDocument/didChange 通知详解 textDocument/开发工具LSP 3.17 诊断推送机制深度解析textDocument/publishDiagnostics 从协议定义到实现细节LSP 3.17 诊断推送机制深度解析textDocument/publishDiagnostics 从协议定义到实现细节 本指南围绕 language se开发工具上一篇openeuler/security-baseline5大核心功能让你的系统安全防护能力飙升下一篇CPDS-analyzer开发者入门指南如何为容器故障检测系统贡献代码创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考