Plugin Server Protocol Specification - 0.1
This document describes the 0.1.x version of the plugin server protocol. An implementation for Rust of the 0.1.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.
Please do note that while PSP is a superset of LSP, its specification will not be found here, but rather here
Plugin Server Protocol
Server lifecycle
The current protocol specification defines that the lifecycle of a server is managed by the client (e.g. a tool like Lapce, VS Code or Emacs). It is up to the client to decide when to start (process-wise) and when to shutdown a server.
Initialize Request ()
The initialize request follows the same rules as the initialize request from the LSP specification. Additions to this request are the new capabilities, and the subscribed events: A server (plugin) can choose to dynamically or at startup subscribe to PSP/LSP events. The client (editor) will only send the subscribed events to the server.
Request:
- method: ‘initialize’
- params:
InitializeParams
defined as follows:
/**
* LSP fields will not appear in this definition for the sake of clarity, unless they are needed to represent PSP fields.
* Bear in mind that these fields do exists, and are expected during the handshake.
*/
interface InitializeParams extends WorkDoneProgressParams {
capabilities: ClientCapabilities;
}
interface ClientCapabilities {
psp?: {
/**
* The client can start LSP servers on behalf of the server
* @since 0.1.0
*/
lsp?: boolean;
/**
* The client can start DAP servers on behalf of the server
* @since 0.1.0
*/
dap?: boolean;
/**
* The client can handle HttpRequest server methods
* @since 0.1.0
*/
httpRequests?: boolean;
/**
* The client can register commands.
* @since 0.1.0
*/
registerCommand?: boolean;
/**
* The client can handle PSP plugins
* This allows servers to dynamically know whether the client
* is an lsp client or a psp client.
* A use case would be:
* - server knows that PSP is being used and uses PSP methods
* - server knows that PSP is not being used and falls back to LSP methods only
* @since 0.1.0
*/
handlePsp?: boolean;
}
}
Response:
- result:
InitializeResult
defined as follows:
interface InitializeResult {
/**
* The capabilities the language server provides.
*/
capabilities: ServerCapabilities;
}
The server can signal the following capabilities:
interface ServerCapabilities {
psp?: {
/**
* The server is interested in starting LSP servers.
* @since 0.1.0
* default: false
*/
lsp?: boolean;
/**
* The server is interested in starting DAP servers.
* @since 0.1.0
* default: false
*/
dap?: boolean;
/**
* The server is interested in executing http requests.
* @since 0.1.0
* default: false
* true equals to every capabilities enabled
*/
httpRequests?: boolean | HTTPCapabilities;
/**
* The server is interested in registering commands.
* @since 0.1.0
*/
registerCommand?: boolean;
/**
* The methods the server would like to subscribe to
* Defaults to all if empty.
* Can also be a MethodGroup.
* @since 0.1.0
*/
subscribedMethods?: MethodGroup[] | string[];
}
}
- HttpCapabilities:
export interface HttpCapabilities: {
get?: boolean,
post?: boolean,
delete?: boolean,
put?: boolean,
redirect?: boolean,
}
- MethodGroup:
Groups can be used to represent a set of multiple methods:
/**
* @since 0.1.0
*/
export enum MethodGroup {
// All LSP methods
lsp = 'lsp',
// All PSP methods, excluding LSP
psp = 'psp',
// No methods
none = 'none',
}
Plugin Features
Plugin Features provide much of the behavior in the Plugin Sever Protocol. The main language feature categories are:
- LSP features (stemming from LSP), and some methods for LSP handling
- Settings features, like adding new settings or registering commands
- UI features, like drawing on the screen, or in a new window.
Server Protocol Features
Start LSP Server Request
Since version 0.1.0
The Start LSP Server request is sent from the server to the client when a standalone LSP server needs to be spawned.
Client Capability:
- property name (optional):
psp.lsp
Server Capability:
- property name (optional):
psp.lsp
Request:
- method:
psp/startLsp
- params:
StartLSPParams
defined as follows:
export interface StartLSPParams {
/**
* URI of the binary LSP server to run.
* The URI is a local file.
*/
serverUri: URI;
/**
* Selection of all file types that the lsp will receive events about
*/
documentSelector: DocumentSelector;
/**
* Args passed to the invoked LSP server
*/
serverArgs: string[];
/**
* Plugin options
*/
options: LSPAny;
}
Response:
- result:
null
- error: code and message set in case an exception happens during the declaration request.
Stop LSP Server Request
Since version 0.1.0
The Stop LSP Server request is sent from the server to the client when a standalone LSP server needs to be spawned.
Client Capability:
- property name (optional):
psp.lsp
Server Capability:
- property name (optional):
psp.lsp
Request:
- method:
psp/stopLsp
- params:
StopLSPParams
defined as follows:
export interface StopLSPParams {
/**
* URI of the binary LSP server as specified in the startLSP request.
*/
serverUri: URI;
}
Response:
- result:
null
- error: code and message set in case an exception happens during the declaration request.
Start DAP Server Request
Since version 0.1.0
The Start DAP Server request is sent from the server to the client when a standalone DAP server needs to be spawned.
Client Capability:
- property name (optional):
psp.dap
Server Capability:
- property name (optional):
psp.dap
Request:
- method:
psp/startDap
- params:
StartDAPParams
defined as follows:
export interface StartDAPParams {
/**
* URI of the binary LSP server to run.
* The URI is a local file.
*/
serverUri: URI;
/**
* Selection of all file types where the lsp will be in use.
*/
documentSelector: DocumentSelector;
/**
* Args passed to the invoked LSP server
*/
serverArgs: string[];
/**
* Plugin options
*/
options: LSPAny;
}
Response:
- result:
null
- error: code and message set in case an exception happens during the declaration request.
Stop DAP Server Request
Since version 0.1.0
The Stop DAP Server request is sent from the server to the client when a standalone DAP server needs to be spawned.
Client Capability:
- property name (optional):
psp.dap
Server Capability:
- property name (optional):
psp.dap
Request:
- method:
psp/stopDap
- params:
StopDAPParams
defined as follows:
export interface StopDAPParams {
/**
* URI of the binary DAP server as specified in the startDAP request.
*/
serverUri: URI;
}
Response:
- result:
null
- error: code and message set in case an exception happens during the declaration request.
Command Features
Make an Http Request
Since version 0.1.0
The HttpRequest
request is sent from the server to the client when it needs to access a resource over the network.
Client Capability:
- property name (optional):
psp.httpRequest
Server Capability:
- property name (optional):
psp.httpRequest
Request:
- method:
psp/httpRequest
- params:
HttpRequestParams
defined as follows:
export interface HttpRequestParams {
/**
* The HTTP method
*/
method: "GET" | "POST" | "PUT" | "DELETE";
/**
* The URL to send the request to.
*/
url: URI;
/**
* The output file where response data should be written.
* If "response", data is sent in the response of the request.
*/
output: URI | "response";
/**
* List of all headers of the response.
* Strings should be of format NAME: VALUE where NAME is the header name, and VALUE is the header value
* Headers disallowed: Content-Length
*/
headers: string[];
/**
* Follow redirects.
* Integer is the number of max hops.
* True allows unlimited hops up to the limit of the client's maximum.
* False allows no hops
* undefined means the http client gets to decide.
*/
redirects: boolean | integer;
/**
* Body contents.
*/
body: string | Uint8Array;
}
Response:
- result:
HttpRequestResponse
- error: code and message as
HttpRequestResponse
or string set in case an exception happens during the declaration request.
where HttpRequestResponse
defined as follows:
export interface HttpRequestResponse {
/**
* Status code of the response.
*/
statusCode: integer;
/**
* List of all headers of the response.
* Strings should be of format NAME: VALUE where NAME is the header name, and VALUE is the header value
*/
headers: string[];
/**
* Body of the response
*/
body: string | Uint8Array;
/**
* URI of the downloaded data.
*/
location: URI;
}
Interaction Features
Register new command Request
Since version 0.1.0
The Register Command request is sent from the server to the client when it wants to create a new integrated command. Such command can then be invoked by the user.
Client capability:
- property name (optional):
psp.registerCommand
Server capability:
- property name (optional):
psp.registerCommand
Request:
- method:
psp/registerCommand
- params:
RegisterCommandParams
defined as follows:
export interface RegisterCommandParams {
/**
* Commands to register.
*/
commands: RegisterCommand[];
}
where RegisterCommand
defined as follows:
export interface RegisterCommand {
/**
* Id of the command.
*/
label: string;
/**
* Description of the command.
*/
description: string;
}
Response:
- result
null
- error: code and message set in case an exception happens during the declaration request.
Trigger command Notification
When a user Executes a command, a notification is sent from the client to the server:
Client capability:
- property name (optional):
psp.registerCommand
Server capability:
- property name (optional):
psp.registerCommand
Notification:
- method:
psp/triggerCommand
- params:
TriggerCommandParams
defined as follows:
export interface TriggerCommandParams {
/**
* The name of the triggered command.
*/
command: string;
}
Unregister command Request
Since version 0.1.0
The Unregister Command request is sent from the server to the client when it wants to delete an previously created command.
Client capability:
- property name (optional):
psp.registerCommand
Server capability:
- property name (optional):
psp.registerCommand
Request:
- method:
psp/unregisterCommand
- params:
RegisterCommandParams
defined as follows:
export interface UnregisterCommandParams {
/**
* Commands to unregister.
*/
commands: RegisterCommand[];
}
Response:
- result
null
- error: code and message set in case an exception happens during the declaration request.
Ask for inputs / choices requests
a server can then ask for user inputs based on the command invoked. It can use two type of input request:
-
AskInput
: The user enters an arbitratry string -
AskChoice
: The user selects one or more choices from a list
Client capability:
- property name (optional):
psp.registerCommand
Server capability:
- property name (optional):
psp.registerCommand
Notification:
- method:
psp/askInput
- params:
askInput
defined as follows:
export interface AskInput {
/**
* Id of the command related to this input.
*/
id: integer;
/**
* Title of the input.
*/
title: string;
/**
* Placeholder to be shown inside the input field.
*/
placeholder?: string;
/**
* Hints about the way to fill this data.
*/
hint?: string | URI;
}
Response:
- result
AskInputResponse
- error: code and message set in case an exception happens during the declaration request.
where AskInputResponse
defined as follows:
export interface AskInputResponse {
/**
* Id of the command related to this input.
*/
id: integer;
/**
* Response of the user
*/
response: string[];
}
Client capability:
- property name (optional):
psp.registerCommand
Server capability:
- property name (optional):
psp.registerCommand
Request:
- method:
psp/askChoice
- params:
askInput
defined as follows:
export interface AskChoice {
/**
* Id of the command related to this input.
*/
id: integer;
/**
* Title of the input.
*/
title: string;
/**
* Choices the user can choose.
*/
choices: Choice[];
/**
* Minimum number of choices the user can choose
* Defaults to one
*/
minChoices?: integer;
/**
* Maximum number of choices the user can choose
* Defaults to one
* For unlimited number of choice, set to zero
*/
maxChoices?: integer;
/**
* Default selected choices indices.
*/
defaultChoices?: integer[]
/**
* Hints about the way to fill this data.
*/
hint?: string|URI;
}
where Choice
defined as follows:
export interface Choice {
/**
* The text that should be displayed for the choice
*/
text: string,
/**
* The icon that should be displayed for the choice
* The icon is a local only image.
*/
icon?: Uri,
/**
* Hint which gives a small amount of extra information about the choice
*/
hint?: string,
}
Response:
- result
AskChoiceResponse
- error: code and message set in case an exception happens during the declaration request.
where AskChoiceResponse
defined as follows:
export interface AskChoiceResponse {
/**
* Response of the user
* This is a list of indices of choice chosen
*/
response: integer[];
}