首页 / 资讯中心 / 文章详情

Language Server Protocol 文本文档标识符(TextDocumentIdentifier)全解析:URI 定位与 3.18 协议实现

Language Server Protocol 文本文档标识符(TextDocumentIdentifier)全解析:URI 定位与 3.18 协议实现 ★ FEATURED ARTICLE
开发工具【免费下载链接】language-server-protocolDefines a common protocol for language servers.项目地址https://gitcode.com/gh_mirrors/la/language-server-protocol点击查看免费下载TextDocumentIdentifier是 LSPLanguage Server Protocol中最基础、最常被复用的数据结构之一它用一个 URI 字符串唯一定位客户端中的某个文本文档是几乎所有文本同步、诊断、符号检索与编辑类请求的入参起点。本文以仓库中的 3.18 规范文档为主体结合协议类型定义、metaModel 机器可读模型与具体请求/通知的使用场景讲清楚它的结构、派生类型、URI 编码约定以及在实际 LSP 通信中的典型用法帮助读者在实现语言服务器或客户端时准确构造与解析该类型。一、什么是 TextDocumentIdentifier协议层的最小文档句柄在 LSP 中文本文档通过 URI 来标识。在协议传输层即 JSON-RPC 消息的 payload中URI 一律以字符串形式传递而不是对象或二进制句柄。TextDocumentIdentifier就是封装这一约定的最小数据结构定义于 3.18 规范的类型章节 textDocumentIdentifier.mdinterface TextDocumentIdentifier { /** * The text documents URI. */ uri: DocumentUri; }该类型仅包含一个字段uri其类型为DocumentUri本质上是带约束的string。从仓库的机器可读元模型 metaModel.json 中可以看到完全一致的正式化描述{ name: TextDocumentIdentifier, properties: [ { name: uri, type: { kind: base, name: DocumentUri }, documentation: The text documents uri. } ], documentation: A literal to identify a text document in the client. }metaModel 中将其定性为 A literal to identify a text document in the client即用于在客户端一侧标识文本文档的字面量。这也说明TextDocumentIdentifier本身不携带文档内容、语言或版本信息它只是一个句柄——由客户端发往服务器时用来告诉服务器我说的是哪个文件。在类型系统层面DocumentUri是元模型声明的 9 种基础类型BaseTypes之一。在 metaModel.ts 中可以看到完整的基类型枚举export type BaseTypes URI | DocumentUri | integer | uinteger | decimal | RegExp | string | boolean | null;也就是说DocumentUri与string、integer一样属于协议内置的原子类型它专门用于承载文档 URI语义上区别于普通字符串。二、URI 的协议约定字符串化与文件 URI协议要求uri必须是完整的、带有 scheme 的 URI 字符串例如{ uri: file:///home/user/projects/demo/src/main.py }几个在实践中容易踩坑的约定必须是绝对 URIfile:///...或untitled:...等不能是相对路径或裸文件路径否则服务器端无法稳定地将其映射到文件系统。大小写与规范化不同平台对路径大小写、URL 编码如空格%20、非 ASCII 字符的百分号编码的敏感度不同客户端与服务器应就 URI 规范化策略保持一致否则同一文档可能出现两个不同的 URI 键值导致诊断、符号等结果错位。未保存/新文档编辑器内尚未落盘的新文件通常使用untitled:scheme 的 URI协议对文档打开的定义是由客户端托管内容并不要求其内容一定呈现在编辑器中详见下文 didOpen 一节。此外uri在 JSON 传输层是字符串但协议同时在 types/uri.md3.18 目录下的 URI 类型说明中约定其编码规则。实现时建议在服务器端统一维护一个DocumentUri解析/序列化工具将协议字符串与内部文件路径互相转换避免散落各处的临时字符串拼接引发不一致。三、三个直接派生的近亲类型版本、可选版本与文档项TextDocumentIdentifier是多个扩展类型的基座理解它们之间的关系对读懂 LSP 各种请求参数至关重要。3.1 VersionedTextDocumentIdentifier带版本号的标识定义于 versionedTextDocumentIdentifier.mdinterface VersionedTextDocumentIdentifier extends TextDocumentIdentifier { /** * The version number of this document. * * The version number of a document will increase after each change, * including undo/redo. The number doesnt need to be consecutive. */ version: integer; }它继承TextDocumentIdentifier追加一个version字段。版本号在每次变更包括撤销/重做后递增且不要求连续——也就是说客户端完全可以发 1、2、3、5、9 这样的版本序列。该类型的信息流通常是从客户端流向服务器典型用途是textDocument/didChange等增量同步通知以及服务器校验编辑是否基于最新版本。3.2 OptionalVersionedTextDocumentIdentifier版本可空的可选版本标识同一个文档中还定义了它的可选版本变体interface OptionalVersionedTextDocumentIdentifier extends TextDocumentIdentifier { /** * The version number of this document. If an optional versioned text document * identifier is sent from the server to the client and the file is not * open in the editor (the server has not received an open notification * before) the server can send null to indicate that the version is * known and the content on disk is the master (as specified with document * content ownership). */ version: integer | null; }该类型的信息流通常是从服务器流向客户端。关键语义在注释中写明当服务器向客户端发送该类型而目标文件并未在编辑器中打开服务器此前未收到过对应的 open 通知时服务器可发送version: null表示版本已知且磁盘上的内容是权威即文档内容所有权的约定。TextDocumentEdit见下文正是使用该类型来让客户端在应用编辑前做版本一致性检查。3.3 TextDocumentItem携带全文内容的文档传输载体定义于 textDocumentItem.mdinterface TextDocumentItem { uri: DocumentUri; languageId: string; version: integer; text: string; }TextDocumentItem与TextDocumentIdentifier的区别在于它用于从客户端向服务器传输整个文档因此除了uri外还携带languageId语言标识符、version版本号和text完整内容。它是textDocument/didOpen通知的参数主体见第五节。需要特别指出的是languageId的作用服务器可能同时处理多种语言通过语言标识符而非文件扩展名来区分避免重新解析扩展名带来的歧义。3.18 规范在该文档中给出了推荐的语言标识符清单节选语言标识符CcCcppC#csharpGogoJavajavaJavaScriptjavascriptPythonpythonRustrustTypeScripttypescriptTypeScript ReacttypescriptreactYAMLyaml完整清单约 60 项ABAP、BibTeX、Clojure、CSS、D、Diff、Dockerfile、Elixir、Erlang、F#、Haskell、HTML、JSON、LaTeX、Less、Lua、Markdown、PHP、Powershell、Ruby、Scala、Shell、SQL、Swift、XML 等其中d、pascal是 3.18 新增标注since 3.18.0。客户端在打开文档时应尽量使用推荐标识符以便服务器正确路由到对应语言处理器。四、组合型参数TextDocumentPositionParams 与 TextDocumentEditTextDocumentIdentifier极少单独作为请求参数出现更多时候是作为组合参数的一员被嵌入。两个最具代表性的例子4.1 TextDocumentPositionParams文档 位置定义于 textDocumentPositionParams.mdinterface TextDocumentPositionParams { /** * The text document. */ textDocument: TextDocumentIdentifier; /** * The position inside the text document. */ position: Position; }这是在文档中定位这一族请求hover、definition、references、completion 等的通用基座。文档还特别说明由客户端决定如何将选区selection转换为 position——客户端可以尊重或忽略选区方向以使 LSP 请求与编辑器内置功能的行为保持一致。换言之服务器不应假设 position 一定来自选区起始点。Position的语义细节在 textDocuments.md 中进一步明确位置由从 0 开始的行号line与字符偏移character表达协议当前只支持文本型文档不支持二进制文档3.17 起客户端与服务器可通过general.positionEncodings/capabilities.positionEncoding协商 UTF-8、UTF-16 等编码但 UTF-16utf-16是唯一强制兼容的编码若未协商则默认 UTF-16行尾序列仅承认\n、\r\n、\r三种position 是行尾字符无关的不能表示位于\r|\n或\n|之间的偏移。4.2 TextDocumentEdit引用可选版本标识的编辑单元定义于 textDocumentEdit.mdexport interface TextDocumentEdit { textDocument: OptionalVersionedTextDocumentIdentifier; edits: (TextEdit | AnnotatedTextEdit | SnippetTextEdit)[]; }TextDocumentEdit描述对单个文本文档的文本变更其中文档引用正是OptionalVersionedTextDocumentIdentifier而非无版本标识目的是让客户端在应用编辑前校验文档版本。文档规定一次TextDocumentEdit描述从版本 Si 到版本 Si1 的全部变化因此创建者无需对 edits 排序但 edits 之间不得重叠。此外3.16 起支持AnnotatedTextEdit受workspace.workspaceEdit.changeAnnotationSupport能力门控3.18 起新增SnippetTextEdit受workspace.workspaceEdit.snippetEditSupport能力门控——若客户端未声明相应能力服务器不应发送对应字面量。五、真实调用场景从 didOpen 到 publishDiagnosticsTextDocumentIdentifier/DocumentUri贯穿了 LSP 的文本同步与诊断链路以下是仓库 3.18 规范中几个可以直接对照源码文档验证的典型场景。5.1 打开文档textDocument/didOpen见 didOpen.md。didOpen通知由客户端发往服务器告知新打开的文本文档其内容此后由客户端托管服务器不得再通过 URI 读取文档内容interface DidOpenTextDocumentParams { textDocument: TextDocumentItem; }几个关键约束打开意味着由客户端管理不一定代表内容呈现在编辑器中open 与 close 通知必须配对同一文档的最大 open 计数为 1若文档的语言标识符发生变化客户端需先发textDocument/didClose再用新languageId发textDocument/didOpen服务器能否完成请求与文档是否处于打开状态无关。5.2 推送诊断textDocument/publishDiagnostics见 publishDiagnostics.md。诊断结果从服务器发回客户端时同样以DocumentUri标识目标文档interface PublishDiagnosticsParams { uri: DocumentUri; version?: integer; // since 3.15.0 diagnostics: Diagnostic[]; }version为可选字段用于关联诊断所对应的文档版本帮助客户端在文档版本已变化时决定是否丢弃过期诊断。URI 作为该通知的键客户端通常用uri - diagnostics的映射维护诊断面板。5.3 符号检索textDocument/documentSymbol见 documentSymbol.md。其请求参数正是TextDocumentIdentifier返回DocumentSymbol[]/SymbolInformation[]。该请求的服务器能力声明为documentSymbolProviderboolean | DocumentSymbolOptions注册选项DocumentSymbolRegistrationOptions由TextDocumentRegistrationOptions与DocumentSymbolOptions组合而成——后者自 3.16支持label字段用于在同一文档显示多个大纲树时提供人类可读标签。5.4 更广泛的使用面TextDocumentIdentifier/DocumentUri还广泛出现在 callHierarchy、typeHierarchy、pullDiagnostics 等 3.17/3.18 特性中。例如 callHierarchy 的CallHierarchyItemcallHierarchy.md同样含uri: DocumentUri字段pullDiagnostics 的文档范围参数中也以DocumentUri为键组织文档集合。可以说凡是针对某个文档的请求几乎都以它或其派生类型作为参数的组成部分。六、实现要点与自检清单综合以上规范与源码证据实现TextDocumentIdentifier相关逻辑时建议核对以下清单构造只传uri一个字段类型为字符串不要混入version、languageId、text这些属于VersionedTextDocumentIdentifier/TextDocumentItem的职责。URI 规范化统一使用绝对 URI 与一致的大小写/编码规则文件路径与file://URI 互转要有唯一映射。版本语义需要版本校验时用VersionedTextDocumentIdentifier客户端→服务器服务器回发引用时用OptionalVersionedTextDocumentIdentifier未打开文档可发version: null。能力门控涉及AnnotatedTextEdit/SnippetTextEdit时先检查对应 client capability未声明则不发送。位置编码处理Position前先确认协商后的编码默认 UTF-16并只认可\n、\r\n、\r三种行尾。配对约束didOpen/didClose严格配对同文档 open 计数不超过 1语言切换先 close 再 open。元模型校验若基于元模型生成代码见 metaModel.json 与 metaModel.ts注意TextDocumentIdentifier仅含uri其派生类型的继承关系在 JSON 中以mixins/extends表达生成器应正确处理。从 3.14 到 3.18TextDocumentIdentifier的定义保持稳定——这正说明它是 LSP 中经受住多年演进检验的基石类型。掌握了它的结构与衍生关系再阅读仓库中 initialize.md 的rootUri、各类语言特性请求乃至 workspace 编辑workspaceEdit.md时都能立刻识别出文档标识的脉络从而更准确地在客户端与服务器两侧实现 URI 的解析、缓存与一致性维护。赞分享开发工具【免费下载链接】language-server-protocolDefines a common protocol for language servers.项目地址https://gitcode.com/gh_mirrors/la/language-server-protocol点击查看免费下载相关推荐language-server-protocol 3.17 规范精读TextDocumentIdentifier 与文本文档 URI 标识机制language server protocol 3.17 规范精读TextDocumentIdentifier 与文本文档 URI 标识机制 导读 Text开发工具Minimal Mistakes 主题文章图片实战带链接图片Linked Image的 Markdown 写法与底层机制Minimal Mistakes 主题文章图片实战带链接图片Linked Image的 Markdown 写法与底层机制 本文聚焦 Minimal Mis开发工具深入解析 LSP 的 documentHighlight 请求Language Server Protocol 3.18 文档高亮协议全解深入解析 LSP 的 documentHighlight 请求Language Server Protocol 3.18 文档高亮协议全解 textDocum开发工具上一篇NVIDIA Profile Inspector完全指南解锁200隐藏设置彻底优化显卡性能下一篇Chromatic深度解析打破Chromium/V8应用限制的三大核心技术引擎创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
阅读完成 · 觉得有帮助?
咨询建站