语言服务器协议
语言服务器协议定义了一组使用上述基本协议交换的 JSON-RPC 请求、响应和通知消息。 本节开始描述协议中使用的基本 JSON 结构。 该文档使用严格模式下的 TypeScript 接口来描述这些。 这意味着,例如,必须显式列出空值,并且即使可能存在伪造值,也必须列出强制属性。 基于基本的 JSON 结构,描述了实际的请求及其响应和通知。
一个例子是从客户端发送到服务器的请求,以请求文本文档中鼠标悬浮在特定位置时,展示一个字符串。 请求的方法将是带有如下参数的 textDocument/hover:
interface HoverParams { textDocument: string; /** The text document's URI in string form */ position: { line: uinteger; character: uinteger; }; }
请求的结果将在悬浮层的形式展示出来。 在其简单形式中,它可以是一个字符串。 所以结果看起来像这样:
interface HoverResult { value: string; }
Please also note that a response return value of null
indicates no result. It doesn’t tell the client to resend the request.
In general, the language server protocol supports JSON-RPC messages, however the base protocol defined here uses a convention such that the parameters passed to request/notification messages should be of object
type (if passed at all). However, this does not disallow using Array
parameter types in custom messages.
The protocol currently assumes that one server serves one tool. There is currently no support in the protocol to share one server between different tools. Such a sharing would require additional protocol e.g. to lock a document to support concurrent editing.
另请注意,响应返回值为 null 表示没有结果。 而不是告诉客户端要重新发送请求。
通常,"语言服务器协议"支持 JSON-RPC 消息,但是此处定义的基本协议使用约定,即传递给请求/通知消息的参数应该是对象类型(如果传递的话)。 但是,这并不禁止在自定义消息中使用数组参数类型。
该协议目前假定一台语言服务器服务于一种前端开发工具。 目前协议中不支持在不同开发工具之间共享一台语言服务器。 这样的共享将需要额外的协议,例如 锁定文档以支持并发编辑。
能力
并非每个语言服务器都可以支持协议定义的所有功能。 因此,LSP 提供了“能力”。 能力将一组语言特性组合在一起。 开发工具和语言服务器使用 capabilities 宣布它们支持的特性。 例如,服务器宣布它可以处理 textDocument/hover 请求,但它可能无法处理 workspace/symbol 请求。 类似地,开发工具宣布它能够在保存文档之前提供即将保存通知,以便服务器可以计算文本编辑情况,从而可以在保存文档之前做格式化。
功能集在初始化请求期间在客户端和服务器之间交换。即开发工具和语言服务器在初始化时会互相交换自己支持的功能特性。
请求、通知和响应排序
一个请求的响应的发送顺序应与请求出现在服务器端或客户端的顺序相同。 因此,例如,如果服务器收到 textDocument/completion 请求,然后收到 textDocument/signatureHelp 请求,它通常会首先返回 textDocument/completion 的响应,然后返回 textDocument/signatureHelp 的响应。
但是,服务器可能会使用并行执行策略,并且可能希望可以与收到请求不同的顺序返回响应。 只要响应重新排序不影响响应的正确性,服务器就可以这样做。 例如,允许重新排序 textDocument/completion 和 textDocument/signatureHelp 的结果,因为这些请求中的每一个通常不会影响另一个的输出。 另一方面,服务器不应该重新排序 textDocument/definition 和 textDocument/rename 请求,因为用户先做了查看某个变量的定义,然后又对这个变量做了重命名。和先重命名再查看定义,产生的结果可能是不一样的。响应顺序乱了就会出bug。
消息文档
如前所述,LSP 定义了一组请求、响应和通知。 每一个都使用以下格式记录:
- 一个消息头描述请求
- 可选的客户端capability部分,描述请求的客户端功能。 这包括客户端功能属性路径和 JSON 结构。
-
一个可选的服务器capability部分,描述请求的服务器能力。 这包括服务器功能属性路径和 JSON 结构。 客户端应该忽略他们不支持的服务器功能(例如,初始化请求在这种情况下不应该失败)。
- 一个可选的注册选项部分,用于描述注册选项。如果请求或通知支持动态capability注册, 有关其工作原理的详细信息,请参阅下文的注册和注销请求。
-
Request部分描述请求的格式。 该方法是一个标识请求的字符串,参数是使用 TypeScript 接口记录的。 还记录了请求是否支持工作完成进度和部分结果进度。
- 描述响应格式的Response部分。 result项描述成功时返回的数据。 可选的partial result项描述了部分结果通知的返回数据。 error.data 描述了发生错误时返回的数据。 请记住,在失败的情况下,响应已经包含一个 error.code 和一个 error.message 字段。 仅当协议强制使用某些错误代码或消息时才指定这些字段。 在服务器可以自由决定这些值的情况下,它们不会在此处列出(译注:没懂,原文这么说的: In cases where the server can decide on these values freely they aren’t listed here.)。