You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session. You switched accounts on another tab or window. Reload to refresh your session.
This document describes the upcoming 3.18.x version of the language server protocol and is under development. An implementation for node of the 3.18.x version of the protocol can be found here.
Note: edits to this specification can be made via a pull request against this markdown document.
All new 3.18 features are tagged with a corresponding since version 3.18 text or in JSDoc using @since 3.18.0 annotation.
A detailed list of the changes can be found in the change log
The version of the specification is used to group features into a new specification release and to refer to their first appearance. Features in the spec are kept compatible using so called capability flags which are exchanged between the client and the server during initialization.
The base protocol consists of a header and a content part (comparable to HTTP). The header and content part are separated by a '\r\n'.
The header part consists of header fields. Each header field is comprised of a name and a value, separated by ': ' (a colon and a space). The structure of header fields conform to the HTTP semantic. Each header field is terminated by '\r\n'. Considering the last header field and the overall header itself are each terminated with '\r\n', and that at least one header is mandatory, this means that two '\r\n' sequences always immediately precede the content part of a message.
Currently the following header fields are supported:
Header Field Name | Value Type | Description |
---|---|---|
Content-Length | number | The length of the content part in bytes. This header is required. |
Content-Type | string | The mime type of the content part. Defaults to application/vscode-jsonrpc; charset=utf-8 |
The header part is encoded using the 'ascii' encoding. This includes the '\r\n' separating the header and content part.
Contains the actual content of the message. The content part of a message uses JSON-RPC 2.0 to describe requests, responses and notifications. The content part is encoded using the charset provided in the Content-Type field. It defaults to utf-8 , which is the only encoding supported right now. If a server or client receives a header with a different encoding than utf-8 it should respond with an error.
(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 .
Content-Length: . \r\n \r\n < "jsonrpc": "2.0", "id": 1, "method": "textDocument/completion", "params": < . >>
The protocol uses request, response, and notification objects as specified in the JSON-RPC protocol. The protocol currently does not support JSON-RPC batch messages; protocol clients and servers must not send JSON-RPC requests.
The following TypeScript definitions describe the base JSON-RPC protocol:
The protocol uses the following definitions for integers, unsigned integers, decimal numbers, objects and arrays:
/** * 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 */ 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[];
A general message as defined by JSON-RPC. The language server protocol always uses "2.0" as the jsonrpc version.
interface Message jsonrpc: string; >
A request message to describe a request between the client and the server. Every processed request must send a response back to the sender of the request.
interface RequestMessage extends Message /** * The request id. */ id: integer | string; /** * The method to be invoked. */ method: string; /** * The method's params. */ params?: array | object; >
A Response Message sent as a result of a request. If a request doesn't provide a result value the receiver of a request still needs to return a response message to conform to the JSON-RPC specification. The result property of the ResponseMessage should be set to null in this case to signal a successful request.
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?: LSPAny; /** * 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?: LSPAny; >
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 its 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 has 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; >
A notification message. A processed notification message must not send a response back. They work like events.
interface NotificationMessage extends Message /** * The method to be invoked. */ method: string; /** * The notification's params. */ params?: array | object; >
Notification and requests whose methods start with '$/' are messages which are protocol implementation dependent and might not be implementable in all clients or servers. For example if the server implementation uses a single threaded synchronous programming language then there is little a server can do to react to a $/cancelRequest notification. If a server or client receives notifications starting with '$/' it is free to ignore the notification. If a server or client receives a request starting with '$/' it must error the request with error code MethodNotFound (e.g. -32601 ).
The base protocol offers support for request cancellation. To cancel a request, a notification message with the following properties is sent:
interface CancelParams /** * The request id to cancel. */ id: integer | string; >
A request that got canceled still needs to return from the server and send a response back. It can not be left open / hanging. This is in line with the JSON-RPC protocol that requires that every request sends a response back. In addition, it allows for returning partial results on cancel. If the request returns an error response on cancellation it is advised to set the error code to ErrorCodes.RequestCancelled .
The base protocol also offers support to report progress in a generic fashion. This mechanism can be used to report any kind of progress including work done progress (usually used to report progress in the user interface using a progress bar) and partial result progress to support streaming of results.
A progress notification has the following properties:
type ProgressToken = integer | string;
interface ProgressParamsT> /** * The progress token provided by the client or server. */ token: ProgressToken; /** * The progress data. */ value: T; >
Progress is reported against a token. The token is different than the request ID which allows to report progress out of band and also for notification.
The language server protocol defines a set of JSON-RPC request, response and notification messages which are exchanged using the above base protocol. This section starts describing the basic JSON structures used in the protocol. The document uses TypeScript interfaces in strict mode to describe these. This means, for example, that a null value has to be explicitly listed and that a mandatory property must be listed even if a falsy value might exist. Based on the basic JSON structures, the actual requests with their responses and the notifications are described.
An example would be a request sent from the client to the server to request a hover value for a symbol at a certain position in a text document. The request's method would be textDocument/hover with a parameter like this:
interface HoverParams textDocument: string; /** The text document's URI in string form */ position: line: uinteger; character: uinteger; >; >
The result of the request would be the hover to be presented. In its simple form it can be a string. So the result looks like this:
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.
Not every language server can support all features defined by the protocol. LSP therefore provides ‘capabilities’. A capability groups a set of language features. A development tool and the language server announce their supported features using capabilities. As an example, a server announces that it can handle the textDocument/hover request, but it might not handle the workspace/symbol request. Similarly, a development tool announces its ability to provide about to save notifications before a document is saved, so that a server can compute textual edits to format the edited document before it is saved.
The set of capabilities is exchanged between the client and server during the initialize request.
Responses to requests should be sent in roughly the same order as the requests appear on the server or client side. So, for example, if a server receives a textDocument/completion request and then a textDocument/signatureHelp request it will usually first return the response for the textDocument/completion and then the response for textDocument/signatureHelp .
However, the server may decide to use a parallel execution strategy and may wish to return responses in a different order than the requests were received. The server may do so as long as this reordering doesn't affect the correctness of the responses. For example, reordering the result of textDocument/completion and textDocument/signatureHelp is allowed, as each of these requests usually won't affect the output of the other. On the other hand, the server most likely should not reorder textDocument/definition and textDocument/rename requests, since executing the latter may affect the result of the former.
As said, LSP defines a set of requests, responses and notifications. Each of those are documented using the following format:
There are quite some JSON structures that are shared between different requests and notifications. Their structure and capabilities are documented in this section.
The current protocol specification defines that the lifecycle of a server is managed by the client (e.g. a tool like VS Code or Emacs). It is up to the client to decide when to start (process-wise) and when to shutdown a server.
Client support for textDocument/didOpen , textDocument/didChange and textDocument/didClose notifications is mandatory in the protocol and clients can not opt out supporting them. This includes both full and incremental synchronization in the textDocument/didChange notification. In addition a server must either implement all three of them or none. Their capabilities are therefore controlled via a combined client and server capability. Opting out of text document synchronization makes only sense if the documents shown by the client are read only. Otherwise the server might receive request for documents, for which the content is managed in the client (e.g. they might have changed).
Controls whether text document synchronization supports dynamic registration.
/** * Defines how the host (editor) should sync document changes to the language * server. */ export namespace TextDocumentSyncKind /** * Documents should not be synced at all. */ export const None = 0; /** * Documents are synced by always sending the full content * of the document. */ export const Full = 1; /** * Documents are synced by sending the full content on open. * After that only incremental updates to the document are * sent. */ export const Incremental = 2; > export type TextDocumentSyncKind = 0 | 1 | 2;
export interface TextDocumentSyncOptions /** * Open and close notifications are sent to the server. If omitted open * close notifications 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; >
The final structure of the TextDocumentSyncClientCapabilities and the TextDocumentSyncOptions server options look like this
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; >
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; >
Language Features provide the actual smarts in the language server protocol. They are usually executed on a [text document, position] tuple. The main language feature categories are:
The language features should be computed on the synchronized state of the document.