Language Server Protocol (LSP) defines how the development tools and language servers communicate. The development tool performs as a client while all computation is done in backend language server. In LSP, the communication uses JSON-RPC format.
How LSP Works?
The following image shows how LSP works:
As you can see, the communication between the development tool and the language server can be classified into three types: Notification, Request and Response.
A request requires a response, while the notification does not.
A response is sent only after the server or the development tool receives a request.
If there is no result for a request, a response is still needed, with the result property set to null
Base Protocol
The base protocol contains a header and a content part. The header and content are seperated by \r\n
Content part uses JSON-RPC to describe requests, responses and notifications. The charset used is specified in Content-type field in header. By default it's utf-8.
The following is the format of messages in TypeScript
Abstract message
First, notification, request and response extend an abstract message format:
1
2
3
interfaceMessage{jsonrpc: string;}
where the LSP uses "2.0" as the value of jsonrpc, which is the used JSON-RPC version.
Request message
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
interfaceRequestMessageextendsMessage{/**
* The request id.
*/id: number|string;/**
* The method to be invoked.
*/method: string;/**
* The method's params.
*/params?: Array<any>|object;}
Response message
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
interfaceResponseMessageextendsMessage{/**
* The request id.
*/id: number|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<any>;}
There is an optional error field, the response error is defined as the following:
// ResponseError definition
interfaceResponseError<D>{/**
* A number indicating the error type that occurred.
*/code: number;/**
* 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?: D;}// Error codes
exportnamespaceErrorCodes{// Defined by JSON RPC
exportconstParseError: number=-32700;exportconstInvalidRequest: number=-32600;exportconstMethodNotFound: number=-32601;exportconstInvalidParams: number=-32602;exportconstInternalError: number=-32603;exportconstserverErrorStart: number=-32099;exportconstserverErrorEnd: number=-32000;exportconstServerNotInitialized: number=-32002;exportconstUnknownErrorCode: number=-32001;// Defined by the protocol.
exportconstRequestCancelled: number=-32800;exportconstContentModified: number=-32801;}
Notification message
1
2
3
4
5
6
7
8
9
10
11
interfaceNotificationMessageextendsMessage{/**
* The method to be invoked.
*/method: string;/**
* The notification's params.
*/params?: Array<any>|object;}
Beware that a processed notification message must not send a response back.
$ Notifications and Requests
Notifications and requests which start with $/ are protocol implementation dependent, which means this type of notifications and requests might not be implementated in some LSPs. A server or client would ignore the $ notification or send an error message with error code MethodNotFound as the response of $ request.
Actual Protocol
There are some examples for the actual protocol used in LSP
Server Lifetime
The lifetime of a server is managed by the client, that is, the client decides when to start and shutdown the server.
This should be the first request sent from client, and before the client receives InitializeResult response from server, no more request and notification should be sent.
The initialized notification is sent from client to server after the client receives the result of initialize request. This notification is used by server to dynamically register capabilities.
The initialized notification may only be sent once as well.
The server uses this request to request the server to shutdown(but to not exit). After this request, the client must not send any notifications or request other than exit notification.
Request:
method: 'shutdown'
params: void
Response:
result: null
error: code and message set in case an exception happens during shutdown request
exportinterfaceCompletionParamsextendsTextDocumentPositionParams{/**
* The completion context. This is only available if the client specifies
* to send this using `ClientCapabilities.textDocument.completion.contextSupport === true`
*/context?: CompletionContext;}exportinterfaceCompletionContext{/**
* How the completion was triggered.
*/triggerKind: CompletionTriggerKind;/**
* The trigger character (a single character) that has trigger code complete.
* Is undefined if `triggerKind !== CompletionTriggerKind.TriggerCharacter`
*/triggerCharacter?: string;}/**
* How a completion was triggered
*/exportnamespaceCompletionTriggerKind{/**
* Completion was triggered by typing an identifier (24x7 code
* complete), manual invocation (e.g Ctrl+Space) or via API.
*/exportconstInvoked: 1=1;/**
* Completion was triggered by a trigger character specified by
* the `triggerCharacters` properties of the `CompletionRegistrationOptions`.
*/exportconstTriggerCharacter: 2=2;/**
* Completion was re-triggered as the current completion list is incomplete.
*/exportconstTriggerForIncompleteCompletions: 3=3;}exporttypeCompletionTriggerKind=1|2|3;
interfaceCompletionItem{/**
* The label of this completion item. By default
* also the text that is inserted when selecting
* this completion.
*/label: string;/**
* The kind of this completion item. Based of the kind
* an icon is chosen by the editor. The standardized set
* of available values is defined in `CompletionItemKind`.
*/kind?: number;/**
* A human-readable string with additional information
* about this item, like type or symbol information.
*/detail?: string;/**
* A human-readable string that represents a doc-comment.
*/documentation?: string|MarkupContent;/**
* Indicates if this item is deprecated.
*/deprecated?: boolean;/**
* Select this item when showing.
*
* *Note* that only one completion item can be selected and that the
* tool / client decides which item that is. The rule is that the *first*
* item of those that match best is selected.
*/preselect?: boolean;/**
* A string that should be used when comparing this item
* with other items. When `falsy` the label is used.
*/sortText?: string;/**
* A string that should be used when filtering a set of
* completion items. When `falsy` the label is used.
*/filterText?: string;/**
* A string that should be inserted into a document when selecting
* this completion. When `falsy` the label is used.
*
* The `insertText` is subject to interpretation by the client side.
* Some tools might not take the string literally. For example
* VS Code when code complete is requested in this example `con<cursor position>`
* and a completion item with an `insertText` of `console` is provided it
* will only insert `sole`. Therefore it is recommended to use `textEdit` instead
* since it avoids additional client side interpretation.
*/insertText?: string;/**
* The format of the insert text. The format applies to both the `insertText` property
* and the `newText` property of a provided `textEdit`. If ommitted defaults to
* `InsertTextFormat.PlainText`.
*/insertTextFormat?: InsertTextFormat;/**
* An edit which is applied to a document when selecting this completion. When an edit is provided the value of
* `insertText` is ignored.
*
* *Note:* The range of the edit must be a single line range and it must contain the position at which completion
* has been requested.
*/textEdit?: TextEdit;/**
* An optional array of additional text edits that are applied when
* selecting this completion. Edits must not overlap (including the same insert position)
* with the main edit nor with themselves.
*
* Additional text edits should be used to change text unrelated to the current cursor position
* (for example adding an import statement at the top of the file if the completion item will
* insert an unqualified type).
*/additionalTextEdits?: TextEdit[];/**
* An optional set of characters that when pressed while this completion is active will accept it first and
* then type that character. *Note* that all commit characters should have `length=1` and that superfluous
* characters will be ignored.
*/commitCharacters?: string[];/**
* An optional command that is executed *after* inserting this completion. *Note* that
* additional modifications to the current document should be described with the
* additionalTextEdits-property.
*/command?: Command;/**
* A data entry field that is preserved on a completion item between
* a completion and a completion resolve request.
*/data?: any}/**
* The kind of a completion entry.
*/namespaceCompletionItemKind{exportconstText=1;exportconstMethod=2;exportconstFunction=3;exportconstConstructor=4;exportconstField=5;exportconstVariable=6;exportconstClass=7;exportconstInterface=8;exportconstModule=9;exportconstProperty=10;exportconstUnit=11;exportconstValue=12;exportconstEnum=13;exportconstKeyword=14;exportconstSnippet=15;exportconstColor=16;exportconstFile=17;exportconstReference=18;exportconstFolder=19;exportconstEnumMember=20;exportconstConstant=21;exportconstStruct=22;exportconstEvent=23;exportconstOperator=24;exportconstTypeParameter=25;}