lsp 3.17协议规范文档 - 1 - 基础协议

发布时间 2023-07-04 13:39:40作者: theiaide

文档翻译自:Language Server Protocol Specification - 3.17  https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/ 

本文档描述了 3.17.x 版本的语言服务器协议。 可以在此处找到协议 3.17.x 版本的node实现:https://github.com/Microsoft/vscode-languageserver-node。

注意:可以通过针对此文档https://github.com/Microsoft/language-server-protocol/blob/gh-pages/_specifications/lsp/3.17/specification.md提交pull request来编辑本文档。

What’s new in 3.17

所有新的 3.17 功能都使用相应的“自版本 3.17”或在 JSDoc 中使用 @since 3.17.0 注释进行标记。 主要的新功能是:类型层次结构、内联值、嵌入提示、笔记本文档支持和描述 3.17 LSP 版本的元模型。

可以在change log中找到更改的详细列表

版本号是用于将新特性归类到新的版本中,比如可以标记某个特性是从哪个版本开始出现的。 规范中的功能使用“capability”标志保持兼容,这些兼容性标志会在客户端和服务器初始化期间进行数据交换。

基础协议

基本协议由标头和内容部分组成(类似于 HTTP)。 标题和内容部分由“\r\n”分隔。

标头部分

标头部分由标头字段组成。 每个标头字段由一个名称和一个值组成,由“: ”(一个冒号和一个空格)分隔。 标头字段的结构符合 HTTP 语义。 每个字段都以‘\r\n’结束。 考虑到最后一个标头字段和整个标头本身都以 '\r\n' 结尾,这意味着在整个标头和消息内容部分由两个/r/n分割。

目前支持以下字段:

字段名称Value Type说明
Content-Length 数字 内容部分的长度(以字节为单位)。 此标头必填。
Content-Type 字符 内容部分的 MIME 类型。 默认为 application/vscode-jsonrpc; charset=utf-8

标头部分和分隔标题和内容部分的“\r\n”都使用“ascii”编码进行编码。

内容部分

包含消息的实际内容。 消息的内容部分使用 JSON-RPC(http://www.jsonrpc.org/) 来描述请求、响应和通知。 内容部分使用标头字段Content-Type中指定的字符集进行编码。 它默认为 utf-8,这是目前唯一支持的编码。 如果服务器或客户端收到一个编码不同于 utf-8 的标头,会返回一个错误。

(Prior versions of the protocol used the string constant utf8 which is not a correct encoding constant according to specification.) For backwards compatibility it is highly recommended that a client and a server treats the string utf8 as utf-8.

(协议的早期版本使用字符串常量 utf8,根据规范(http://www.iana.org/assignments/character-sets/character-sets.xhtml),它不是正确的编码常量,少了“-”横线,应该是utf-8。)为了向后兼容,强烈建议客户端和服务器将字符串 utf8 视为 utf-8

示例:

Content-Length: ...\r\n
\r\n
{
	"jsonrpc": "2.0",
	"id": 1,
	"method": "textDocument/didOpen",
	"params": {
		...
	}
}

 

基本协议 JSON 结构

以下 TypeScript 定义描述了基本的 JSON-RPC 协议(http://www.jsonrpc.org/specification)

基础数据类型

该协议对整数、无符号整数、十进制数、对象和数组使用以下定义::

/**
 * Defines an integer number in the range of -2^31 to 2^31 - 1.
 */
export type integer = number;
/**
 * Defines an unsigned integer number in the range of 0 to 2^31 - 1.
 */
export type uinteger = number;
/**
 * Defines a decimal number. Since decimal numbers are very
 * rare in the language server specification we denote the
 * exact range with every decimal using the mathematics
 * interval notation (e.g. [0, 1] denotes all decimals d with
 * 0 <= d <= 1.
 */
export type decimal = number;
/**
 * The LSP any type
 *
 * @since 3.17.0
 */
export type LSPAny = LSPObject | LSPArray | string | integer | uinteger |
	decimal | boolean | null;
/**
 * LSP object definition.
 *
 * @since 3.17.0
 */
export type LSPObject = { [key: string]: LSPAny };
/**
 * LSP arrays.
 *
 * @since 3.17.0
 */
export type LSPArray = LSPAny[];

  

抽象消息

JSON-RPC 定义的普通消息结构如下。 lsp使用“2.0”作为 jsonrpc 版本。

interface Message {
	jsonrpc: string;
}

  

请求消息

请求消息描述客户端和服务器之间的请求。 每个请求处理完成后都必须回复响应消息给请求发起方。

interface RequestMessage extends Message {

	/**
	 * The request id.
	 */
	id: integer | string;

	/**
	 * The method to be invoked.
	 */
	method: string;

	/**
	 * The method's params.
	 */
	params?: array | object;
}

  

响应消息

响应消息表示请求处理的结果。 如果响应没有result值,请求消息的处理方仍然需要返回响应消息以符合 JSON-RPC 规范。 在这种情况下,应将 ResponseMessage 的结果属性设置为 null 以表示请求成功。

interface ResponseMessage extends Message {
	/**
	 * The request id.
	 */
	id: integer | string | null;

	/**
	 * The result of a request. This member is REQUIRED on success.
	 * This member MUST NOT exist if there was an error invoking the method.
	 */
	result?: string | number | boolean | object | null;

	/**
	 * The error object in case a request fails.
	 */
	error?: ResponseError;
}

 

interface ResponseError {
	/**
	 * A number indicating the error type that occurred.
	 */
	code: integer;

	/**
	 * A string providing a short description of the error.
	 */
	message: string;

	/**
	 * A primitive or structured value that contains additional
	 * information about the error. Can be omitted.
	 */
	data?: string | number | boolean | array | object | null;
}

 

export namespace ErrorCodes {
	// Defined by JSON-RPC
	export const ParseError: integer = -32700;
	export const InvalidRequest: integer = -32600;
	export const MethodNotFound: integer = -32601;
	export const InvalidParams: integer = -32602;
	export const InternalError: integer = -32603;

	/**
	 * This is the start range of JSON-RPC reserved error codes.
	 * It doesn't denote a real error code. No LSP error codes should
	 * be defined between the start and end range. For backwards
	 * compatibility the `ServerNotInitialized` and the `UnknownErrorCode`
	 * are left in the range.
	 *
	 * @since 3.16.0
	 */
	export const jsonrpcReservedErrorRangeStart: integer = -32099;
	/** @deprecated use jsonrpcReservedErrorRangeStart */
	export const serverErrorStart: integer = jsonrpcReservedErrorRangeStart;

	/**
	 * Error code indicating that a server received a notification or
	 * request before the server has received the `initialize` request.
	 */
	export const ServerNotInitialized: integer = -32002;
	export const UnknownErrorCode: integer = -32001;

	/**
	 * This is the end range of JSON-RPC reserved error codes.
	 * It doesn't denote a real error code.
	 *
	 * @since 3.16.0
	 */
	export const jsonrpcReservedErrorRangeEnd = -32000;
	/** @deprecated use jsonrpcReservedErrorRangeEnd */
	export const serverErrorEnd: integer = jsonrpcReservedErrorRangeEnd;

	/**
	 * This is the start range of LSP reserved error codes.
	 * It doesn't denote a real error code.
	 *
	 * @since 3.16.0
	 */
	export const lspReservedErrorRangeStart: integer = -32899;

	/**
	 * A request failed but it was syntactically correct, e.g the
	 * method name was known and the parameters were valid. The error
	 * message should contain human readable information about why
	 * the request failed.
	 *
	 * @since 3.17.0
	 */
	export const RequestFailed: integer = -32803;

	/**
	 * The server cancelled the request. This error code should
	 * only be used for requests that explicitly support being
	 * server cancellable.
	 *
	 * @since 3.17.0
	 */
	export const ServerCancelled: integer = -32802;

	/**
	 * The server detected that the content of a document got
	 * modified outside normal conditions. A server should
	 * NOT send this error code if it detects a content change
	 * in it unprocessed messages. The result even computed
	 * on an older state might still be useful for the client.
	 *
	 * If a client decides that a result is not of any use anymore
	 * the client should cancel the request.
	 */
	export const ContentModified: integer = -32801;

	/**
	 * The client has canceled a request and a server as detected
	 * the cancel.
	 */
	export const RequestCancelled: integer = -32800;

	/**
	 * This is the end range of LSP reserved error codes.
	 * It doesn't denote a real error code.
	 *
	 * @since 3.16.0
	 */
	export const lspReservedErrorRangeEnd: integer = -32800;
}

  

通知消息

通知消息处理完成后不用回复响应,类似于一个事件通知的机制

interface NotificationMessage extends Message {
	/**
	 * The method to be invoked.
	 */
	method: string;

	/**
	 * The notification's params.
	 */
	params?: array | object;
}

  

$通知与请求

“$/”开头的通知和请求是依赖于协议实现的,可能无法在所有客户端或服务器中实现。 例如,如果服务器实现使用单线程同步编程语言,那么服务器几乎无法对 $/cancelRequest 通知做出反应。 如果服务器或客户端收到以“$/”开头的通知,则可以忽略该通知。 如果服务器或客户端收到以“$/”开头的请求,则它必须使用错误代码 MethodNotFound(例如 -32601)对请求进行错误处理。

取消请求

基本协议支持取消请求。 要取消请求,将发送具有以下属性的通知消息:

Notification:

  • method: ‘$/cancelRequest’
  • params: CancelParams 定义如下
interface CancelParams {
	/**
	 * 要取消的请求id.
	 */
	id: integer | string;
}

被取消的请求仍然需要从服务器返回并发回响应。 它不能被挂起。 这符合每个请求都要发回响应的 JSON-RPC 协议规范。 此外,它允许在取消时返回部分结果。 如果要在该请求被取消时返回错误响应,建议将错误代码设置为 ErrorCodes.RequestCancelled。

进度支持(自3.15.0之后

基本协议还支持以通用方式报告进度。 此机制可用于报告任何类型的进度,包括工作完成进度(通常用于使用进度条在用户界面中报告进度)和结果流形式的部分结果进度。

进度通知包含以下属性

Notification:

type ProgressToken = integer | string;
interface ProgressParams<T> {
	/**
	 * The progress token provided by the client or server.
	 */
	token: ProgressToken;

	/**
	 * The progress data.
	 */
	value: T;
}

根据token报告进度。 token不同于request ID,token允许报告非请求类的进度,如通知等 。