Basisprotokoll-Spezifikation - 0.9
Basisprotokoll
Der Zweck des Basisprotokolls besteht darin, eine Abstraktion gängiger Muster zur Erweiterbarkeit von Editoren in einer eigenen Spezifikation zu schaffen, unabhängig von der Anwesenheit eines Language Servers, der eine solche Erweiterung antreibt. Insbesondere Konzepte wie Server- und Client-Fähigkeiten, die Initialisierungs- und Shutdown-Anfrage sowie die Struktur von Anfragen und Benachrichtigungen waren ursprünglich Teil des Language Server Protocol, aber es gibt nichts daran, das ausschließlich für Language Service-Erweiterungen bestimmt sein sollte.
Ein motivierendes Beispiel ist das Build Server Protocol. Wie in seiner Spezifikation beschrieben, werden alle Benachrichtigungen und Anfragen unter Verwendung der Basisdefinitionen des LSP definiert, und Nachrichten wie InitializeBuild, OnBuildInitialized und OnBuildExit entsprechen fast exakt ihren LSP-Pendants. Durch die Implementierung des Basisprotokolls kann ein Server mehrere Protokollspezifikationen unterstützen, ohne den „gemeinsamen Boilerplate“-Code neu implementieren zu müssen, den sie alle gemeinsam haben.
Beachten Sie, dass das Basisprotokoll derzeit experimentell entwickelt wird und Änderungen unterliegt. Seine zukünftige Entwicklung hängt vom Feedback der Community und der anfänglichen Implementierer des Protokolls ab.
Header-Teil
Das Basisprotokoll besteht aus einem Header- und einem Inhaltsteil (vergleichbar mit HTTP). Der Header- und Inhaltsteil werden durch ein „\r\n“ getrennt.
Der Header-Teil besteht aus Header-Feldern. Jedes Header-Feld besteht aus einem Namen und einem Wert, getrennt durch „: “ (ein Doppelpunkt und ein Leerzeichen). Die Struktur der Header-Felder entspricht dem HTTP-Standard. Jedes Header-Feld wird mit „\r\n“ abgeschlossen. Da das letzte Header-Feld und die gesamte Header-Sektion jeweils mit „\r\n“ abgeschlossen werden und mindestens ein Header obligatorisch ist, bedeutet dies, dass zwei „\r\n“-Sequenzen immer unmittelbar vor dem Inhaltsteil einer Nachricht stehen.
Aktuell werden folgende Header-Felder unterstützt
| Name des Header-Feldes | Wert-Typ | Beschreibung |
|---|---|---|
| Content-Length | number | Die Länge des Inhaltsteils in Bytes. Dieser Header ist erforderlich. |
| Content-Type | string | Der MIME-Typ des Inhaltsteils. Standardmäßig `application/vscode-jsonrpc; charset=utf-8` |
Der Header-Teil wird mit der ‚ascii‘-Kodierung codiert. Dies schließt die ‚\r\n‘, die den Header- und den Inhaltsteil trennen, mit ein.
Inhaltsteil
Enthält den eigentlichen Inhalt der Nachricht. Der Inhaltsteil einer Nachricht verwendet JSON-RPC, um Anfragen, Antworten und Benachrichtigungen zu beschreiben. Der Inhaltsteil wird mit dem im Feld `Content-Type` angegebenen Zeichensatz codiert. Er standardmäßig auf utf-8, was derzeit die einzige unterstützte Codierung ist. Wenn ein Server oder Client einen Header mit einer anderen Codierung als utf-8 empfängt, sollte er mit einem Fehler antworten.
Beispiel
Content-Length: ...\r\n
\r\n
{
"jsonrpc": "2.0",
"id": 1,
"method": "initialize",
"params": {
...
}
}
Fähigkeiten
Nicht jeder Server kann alle vom Protokoll definierten Funktionen unterstützen. Das Basisprotokoll bietet daher „Fähigkeiten“. Eine Fähigkeit gruppiert eine Reihe von Funktionen. Ein Entwicklungswerkzeug und der Server kündigen ihre unterstützten Funktionen anhand von Fähigkeiten an. Beispielsweise könnte ein Entwicklungswerkzeug die Unterstützung für Benachrichtigungen zur Dokumentenerstellung ankündigen, damit Server ihre entsprechenden Dokumentensynchronisierungsaufgaben ausführen können.
Der Satz von Capabilities wird zwischen Client und Server während der initialisieren-Anfrage ausgetauscht.
Beachten Sie, dass die folgende Liste von Fähigkeitsbezeichnern bereits vom Language Server Protocol verwendet wird und daher nicht in anderen Protokollen verwendet werden kann
callHierarchyProvidercodeActionProvidercodeLensProvidercolorProvidercompletionProviderdeclarationProviderdefinitionProviderdiagnosticProviderdocumentFormattingProviderdocumentHighlightProviderdocumentLinkProviderdocumentOnTypeFormattingProviderdocumentRangeFormattingProviderdocumentSymbolProviderexecuteCommandProviderexperimentalfoldingRangeProvidergeneralhoverProviderimplementationProviderinlayHintProviderinlineValueProviderlinkedEditingRangeProvidermonikerProvidernotebookDocumentnotebookDocumentSyncpositionEncodingreferencesProviderrenameProviderselectionRangeProvidersemanticTokensProvidersignatureHelpProvidertextDocumenttextDocumentSynctypeDefinitionProvidertypeHierarchyProviderwindowworkspaceworkspaceSymbolProvider
Reihenfolge von Anfragen, Benachrichtigungen und Antworten
Antworten auf Anfragen sollten ungefähr in der gleichen Reihenfolge gesendet werden, wie die Anfragen auf der Server- oder Clientseite erscheinen. Wenn ein Server, der Unit-Testing-Funktionen bereitstellt, beispielsweise eine testing/configureFramework-Anfrage und dann eine testing/configureProject-Anfrage erhält, wird er normalerweise zuerst die Antwort für testing/configureFramework und dann die Antwort für testing/configureProject zurückgeben.
Der Server kann jedoch entscheiden, eine parallele Ausführungsstrategie zu verwenden und Antworten in einer anderen Reihenfolge als die empfangenen Anfragen zurückzugeben. Dies kann der Server tun, solange diese Neuordnung die Korrektheit der Antworten nicht beeinträchtigt. Beispielsweise ist die Neuordnung des Ergebnisses von testing/configureFramework und testing/configureProject zulässig, da jede dieser Anfragen normalerweise keinen Einfluss auf die Ausgabe der anderen hat. Andererseits sollte der Server wahrscheinlich die Anfragen testing/testCreated und testing/executeTest nicht neu ordnen, da die Test-Erstellung vor ihrer Ausführung erfolgen sollte.
Nachrichtendokumentation
Wie bereits erwähnt, definiert das Basisprotokoll eine Reihe von Anfragen, Antworten und Benachrichtigungen. Jede davon wird im folgenden Format dokumentiert
- Eine Kopfzeile, die die Anfrage beschreibt
- Ein optionaler Abschnitt *Client-Fähigkeit*, der die Client-Fähigkeit der Anfrage beschreibt. Dies beinhaltet den Pfad der Client-Fähigkeitseigenschaft und die JSON-Struktur.
- Ein optionaler Abschnitt *Server-Fähigkeit*, der die Server-Fähigkeit der Anfrage beschreibt. Dies beinhaltet den Pfad der Server-Fähigkeitseigenschaft und die JSON-Struktur. Clients sollten Server-Fähigkeiten ignorieren, die sie nicht verstehen (z. B. sollte die initialize-Anfrage in diesem Fall nicht fehlschlagen).
- Ein optionaler Abschnitt *Registrierungsoptionen*, der die Registrierungsoptionen beschreibt, falls die Anfrage oder Benachrichtigung dynamische Fähigkeitsregistrierung unterstützt. Siehe die register- und unregister-Anfragen für Details, wie dies funktioniert.
- ein Abschnitt „Request“, der das Format der gesendeten Anfrage beschreibt. Die Methode ist eine Zeichenkette, die die Anfrage identifiziert, die Parameter werden mithilfe einer TypeScript-Schnittstelle dokumentiert. Es wird auch dokumentiert, ob die Anfrage Fortschritt bei der Arbeit und Teilergebnisfortschritt unterstützt.
- ein Abschnitt „Response“, der das Format der Antwort beschreibt. Das Ergebniselement beschreibt die zurückgegebenen Daten im Erfolgsfall. Das optionale Teilergebnis-Element beschreibt die zurückgegebenen Daten einer Teilergebnis-Benachrichtigung. Die
error.databeschreibt die zurückgegebenen Daten im Fehlerfall. Bitte denken Sie daran, dass die Antwort im Fehlerfall bereits ein Felderror.codeunderror.messageenthält. Diese Felder sind nur dann angegeben, wenn das Protokoll die Verwendung bestimmter Fehlercodes oder -nachrichten erzwingt. In Fällen, in denen der Server frei über diese Werte entscheiden kann, werden sie hier nicht aufgeführt.
JSON-Strukturen
Das Basisprotokoll verwendet Anfrage-, Antwort- und Benachrichtigungsobjekte gemäß dem JSON-RPC-Protokoll. Es unterstützt derzeit keine JSON-RPC-Batch-Nachrichten; Protokollclients und -server dürfen keine JSON-RPC-Anfragen senden.
Basistypen
Das Basisprotokoll verwendet die folgenden Definitionen für Ganzzahlen, vorzeichenlose Ganzzahlen, Dezimalzahlen, Objekte und 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 base protocol 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;
/**
* Base Protocol any type.
*/
export type BaseAny = BaseObject | BaseArray | string | integer | uinteger |
decimal | boolean | null;
/**
* Base Protocol object definition.
*/
export type BaseObject = { [key: string]: BaseAny };
/**
* Base Protocol arrays.
*/
export type BaseArray = BaseAny[];
URI
URIs werden als Zeichenketten übertragen. Das Format der URIs ist in https://tools.ietf.org/html/rfc3986 definiert.
foo://example.com:8042/over/there?name=ferret#nose
\_/ \______________/\_________/ \_________/ \__/
| | | | |
scheme authority path query fragment
| _____________________|__
/ \ / \
urn:example:animal:ferret:nose
Wir pflegen auch ein Node-Modul, um eine Zeichenkette in scheme, authority, path, query und fragment URI-Komponenten zu parsen. Das GitHub-Repository ist https://github.com/Microsoft/vscode-uri, und das npm-Modul ist https://www.npmjs.com/package/vscode-uri.
Viele der Interfaces enthalten Felder, die der URI eines Dokuments entsprechen. Zur Verdeutlichung wird der Typ eines solchen Feldes als DocumentUri deklariert. Über das Netzwerk wird es weiterhin als Zeichenkette übertragen, aber dies garantiert, dass der Inhalt dieser Zeichenkette als gültige URI geparst werden kann.
Es ist Vorsicht geboten, die Kodierung in URIs zu behandeln. Einige Clients (wie VS Code) kodieren beispielsweise Doppelpunkte in Laufwerksbuchstaben, während andere dies nicht tun. Die folgenden URIs sind beide gültig, aber Clients und Server sollten konsistent mit der Form sein, die sie selbst verwenden, um sicherzustellen, dass die andere Partei sie nicht als unterschiedliche URIs interpretiert. Clients und Server sollten nicht davon ausgehen, dass die andere Partei auf die gleiche Weise kodiert (z. B. kann ein Client, der Doppelpunkte in Laufwerksbuchstaben kodiert, nicht davon ausgehen, dass Serverantworten kodierte Doppelpunkte enthalten). Dasselbe gilt für die Groß-/Kleinschreibung von Laufwerksbuchstaben – eine Partei sollte nicht davon ausgehen, dass die andere Partei Pfade mit Laufwerksbuchstaben zurückgibt, die die gleiche Groß-/Kleinschreibung haben wie sie selbst.
file:///c:/project/readme.md
file:///C%3A/project/readme.md
type DocumentUri = string;
Es gibt auch ein Tagging-Interface für normale, nicht-dokumentbezogene URIs. Es wird ebenfalls auf eine string abgebildet.
type URI = string;
Reguläre Ausdrücke
Reguläre Ausdrücke sind ein mächtiges Werkzeug und es gibt tatsächliche Anwendungsfälle dafür in Protokollen wie LSP. Der Nachteil ist jedoch, dass fast jede Programmiersprache ihre eigene Menge an regulären Ausdrucksfunktionen hat, so dass die Basisspezifikation sich nicht einfach auf sie als regulären Ausdruck beziehen kann.
Beispielsweise verwendet LSP einen zweistufigen Ansatz zur Unterstützung regulärer Ausdrücke
- Der Client kündigt an, welche reguläre Ausdrucksmaschine er verwenden wird. Dies ermöglicht es Servern, die für einen sehr spezifischen Client geschrieben sind, die volle Leistungsfähigkeit der regulären Ausdrücke des Clients zu nutzen.
- Die Spezifikation definiert eine Reihe von Funktionen für reguläre Ausdrücke, die von einem Client unterstützt werden sollten. Anstatt eine neue Spezifikation zu schreiben, verweist LSP auf die ECMAScript Regular Expression Specification und entfernt daraus Funktionen, die im Kontext von LSP nicht notwendig oder für andere Clients schwer zu implementieren sind.
Die folgende Client-Capability wird verwendet, um die Regex-Engine eines Clients anzukündigen
- Eigenschaftspfad (optional):
general.regularExpressions - Eigenschaftstyp:
RegularExpressionsClientCapabilities, wie folgt definiert
/**
* Client capabilities specific to regular expressions.
*/
export interface RegularExpressionsClientCapabilities {
/**
* The engine's name.
*/
engine: string;
/**
* The engine's version.
*/
version?: string;
}
Aufzählungen
Das Basisprotokoll unterstützt zwei Arten von Aufzählungen: (a) ganzzahlbasierte Aufzählungen und (b) stringbasierte Aufzählungen. Ganzzahlbasierte Aufzählungen beginnen normalerweise mit 1. Gegebenenfalls wird der Werteumfang einer Aufzählung von der definierenden Seite (z. B. Client oder Server) angekündigt und während des Initialisierungs-Handshakes an die andere Seite übertragen. Betrachten Sie beispielsweise eine Anfrage printSymbol, die eine Aufzählung PrintFormat verwendet. Der Client könnte seine unterstützten Druckformate über die Eigenschaft printing.format ankündigen
/**
* Capabilities specific to the `printSymbol` request.
*/
print: {
format: [ "json", "compact", "checkstyle" ]
...
}
Um die Entwicklung von Aufzählungen zu unterstützen, sollte die verwendende Seite einer Aufzählung bei einem unbekannten Aufzählungswert nicht fehlschlagen. Sie sollte ihn einfach als nicht nutzbaren Wert ignorieren und versuchen, ihn bei Rundreisen zu erhalten. Betrachten wir die PrintFormat-Aufzählung noch einmal: Wenn in einer zukünftigen Version des Protokolls ein zusätzliches Format "html" hinzugefügt wird und nun von einem Client angekündigt wird, sollte ein (älterer) Server, der den Wert nicht kennt, nicht fehlschlagen, sondern den Wert einfach als nutzbares Druckformat ignorieren.
Abstrakte Nachricht
Eine allgemeine Nachricht gemäß JSON-RPC. Das Language Server Protocol verwendet immer „2.0“ als jsonrpc-Version.
interface Message {
jsonrpc: string;
}
Anfrage-Nachricht
Eine Anfrage-Nachricht zur Beschreibung einer Anfrage zwischen Client und Server. Jede verarbeitete Anfrage muss eine Antwort an den Absender der Anfrage zurücksenden.
interface RequestMessage extends Message {
/**
* The request id.
*/
id: integer | string;
/**
* The method to be invoked.
*/
method: string;
/**
* The method's params.
*/
params?: array | object;
}
Antwort-Nachricht
Eine Antwortnachricht, die als Ergebnis einer Anfrage gesendet wird. Wenn eine Anfrage keinen Ergebniswert liefert, muss der Empfänger einer Anfrage dennoch eine Antwortnachricht zurückgeben, um der JSON-RPC-Spezifikation zu entsprechen. Die Ergebnis-Eigenschaft der Antwortnachricht sollte in diesem Fall auf null gesetzt werden, um eine erfolgreiche Anfrage zu signalisieren.
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 | array | 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 error codes of the
* base protocol should be defined between the start and end
* range. For backwards compatibility the `ServerNotInitialized`
* and the `UnknownErrorCode` are left in the range.
*/
export const jsonrpcReservedErrorRangeStart: integer = -32099;
/**
* 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.
*/
export const jsonrpcReservedErrorRangeEnd = -32000;
/**
* This is the start range of LSP reserved error codes.
* It doesn't denote a real error code.
*/
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.
*/
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.
*/
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 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.
*/
export const lspReservedErrorRangeEnd: integer = -32800;
}
Um Konflikte mit den Fehlercodes des Language Service Protocol zu vermeiden, müssen andere Implementierer des Basisprotokolls Fehlercodes außerhalb des Bereichs verwenden, der von lspReservedErrorRangeStart und lspReservedErrorRangeEnd definiert wird.
Benachrichtigungs-Nachricht
Eine Benachrichtigungs-Nachricht. Eine verarbeitete Benachrichtigungs-Nachricht darf keine Antwort zurücksenden. Sie funktionieren wie Ereignisse.
interface NotificationMessage extends Message {
/**
* The method to be invoked.
*/
method: string;
/**
* The notification's params.
*/
params?: array | object;
}
$ Benachrichtigungen und Anfragen
Benachrichtigungen und Anfragen, deren Methoden mit „$/“ beginnen, sind Nachrichten, die von der Protokollimplementierung abhängen und möglicherweise nicht in allen Clients oder Servern implementierbar sind. Wenn beispielsweise die Serverimplementierung eine Single-Threaded-synchrone Programmiersprache verwendet, kann ein Server wenig tun, um auf eine $/cancelRequest-Benachrichtigung zu reagieren. Wenn ein Server oder Client Benachrichtigungen empfängt, die mit „$/“ beginnen, kann er die Benachrichtigung frei ignorieren. Wenn ein Server oder Client eine Anfrage empfängt, die mit „$/“ beginnt, muss er die Anfrage mit dem Fehlercode MethodNotFound (z. B. -32601) ablehnen.
Unterstützung für Abbruch (
)
Das Basisprotokoll bietet Unterstützung für den Abbruch von Anfragen. Um eine Anfrage abzubrechen, wird eine Benachrichtigungsnachricht mit den folgenden Eigenschaften gesendet
Benachrichtigung:
- Methode: ‚$/cancelRequest‘
- params:
CancelParams, wie folgt definiert
interface CancelParams {
/**
* The request id to cancel.
*/
id: integer | string;
}
Eine abgebrochene Anfrage muss immer noch vom Server zurückgegeben und eine Antwort gesendet werden. Sie kann nicht offen / hängen gelassen werden. Dies entspricht dem JSON-RPC-Protokoll, das verlangt, dass jede Anfrage eine Antwort sendet. Darüber hinaus ermöglicht es die Rückgabe von Teilergebnissen bei Abbruch. Wenn die Anfrage eine Fehlerantwort bei Abbruch zurückgibt, wird empfohlen, den Fehlercode auf ErrorCodes.RequestCancelled zu setzen.
Fortschrittsunterstützung (
)
Das Basisprotokoll bietet auch Unterstützung für die allgemeine Berichterstattung von Fortschritt. Dieser Mechanismus kann verwendet werden, um jegliche Art von Fortschritt zu melden, einschließlich Arbeitsfortschritt (typischerweise zur Berichterstattung von Fortschritt in der Benutzeroberfläche mit einer Fortschrittsleiste) und Teilergebnisfortschritt zur Unterstützung des Streamings von Ergebnissen.
Eine Fortschrittsbenachrichtigung hat die folgenden Eigenschaften
Benachrichtigung:
- Methode: ‚$/progress‘
- params:
ProgressParams, wie folgt definiert
type ProgressToken = integer | string;
interface ProgressParams<T> {
/**
* The progress token provided by the client or server.
*/
token: ProgressToken;
/**
* The progress data.
*/
value: T;
}
Der Fortschritt wird gegen ein Token gemeldet. Das Token unterscheidet sich von der Anfragedatenbank-ID, was es ermöglicht, Fortschritte "out of band" zu melden und auch für Benachrichtigungen.
Work Done Progress
Work Done Progress wird über die generische Benachrichtigung $/progress gemeldet. Der Wert-Payload einer Work Done Progress-Benachrichtigung kann drei verschiedene Formen haben.
Work Done Progress Begin
Um die Fortschrittsmeldung zu starten, muss eine $/progress-Benachrichtigung mit dem folgenden Payload gesendet werden
export interface WorkDoneProgressBegin {
kind: 'begin';
/**
* Mandatory title of the progress operation. Used to briefly inform about
* the kind of operation being performed.
*
* Examples: "Indexing" or "Linking dependencies".
*/
title: string;
/**
* Controls if a cancel button should show to allow the user to cancel the
* long running operation. Clients that don't support cancellation are
* allowed to ignore the setting.
*/
cancellable?: boolean;
/**
* Optional, more detailed associated progress message. Contains
* complementary information to the `title`.
*
* Examples: "3/25 files", "project/src/module2", "node_modules/some_dep".
* If unset, the previous progress message (if any) is still valid.
*/
message?: string;
/**
* Optional progress percentage to display (value 100 is considered 100%).
* If not provided infinite progress is assumed and clients are allowed
* to ignore the `percentage` value in subsequent report notifications.
*
* The value should be steadily rising. Clients are free to ignore values
* that are not following this rule. The value range is [0, 100].
*/
percentage?: uinteger;
}
Work Done Progress Report
Die Fortschrittsmeldung erfolgt über den folgenden Payload
export interface WorkDoneProgressReport {
kind: 'report';
/**
* Controls enablement state of a cancel button. This property is only valid
* if a cancel button got requested in the `WorkDoneProgressBegin` payload.
*
* Clients that don't support cancellation or don't support control the
* button's enablement state are allowed to ignore the setting.
*/
cancellable?: boolean;
/**
* Optional, more detailed associated progress message. Contains
* complementary information to the `title`.
*
* Examples: "3/25 files", "project/src/module2", "node_modules/some_dep".
* If unset, the previous progress message (if any) is still valid.
*/
message?: string;
/**
* Optional progress percentage to display (value 100 is considered 100%).
* If not provided infinite progress is assumed and clients are allowed
* to ignore the `percentage` value in subsequent report notifications.
*
* The value should be steadily rising. Clients are free to ignore values
* that are not following this rule. The value range is [0, 100].
*/
percentage?: uinteger;
}
Work Done Progress End
Das Ende der Fortschrittsmeldung wird über den folgenden Payload signalisiert
export interface WorkDoneProgressEnd {
kind: 'end';
/**
* Optional, a final message indicating to, for example, indicate the outcome
* of the operation.
*/
message?: string;
}
Initiierung von Work Done Progress
Work Done Progress kann auf zwei verschiedene Arten initiiert werden
- durch den Absender einer Anfrage (meist Clients) über die vordefinierte
workDoneToken-Eigenschaft im Parameter-Literal der Anfrage. Das Dokument wird diese Art von Fortschritt als vom Client initiierte Fortschrittsmeldung bezeichnen. - durch einen Server über die Anfrage
window/workDoneProgress/create. Das Dokument wird diese Art von Fortschritt als vom Server initiierte Fortschrittsmeldung bezeichnen.
Vom Client initiierter Fortschritt
Betrachten Sie einen Client, der eine build/deploy-Anfrage an einen Server sendet, der Anwendungen kompilieren und erstellen kann, und der Client die Berichterstattung über Arbeitsfortschritt für diese Anfrage akzeptiert. Um dies dem Server zu signalisieren, würde der Client eine workDoneToken-Eigenschaft zu den Referenzanfrageparametern hinzufügen
{
"project": {
"guid": "A083-41A9-A0E8"
},
"context": {
"destinationDirectory": "/prod"
},
// The token used to report work done progress.
"workDoneToken": "1d546990-40a3-4b77-b134-46622995f6ae"
}
Die entsprechende Typdefinition für die Parameter-Eigenschaft sieht wie folgt aus
export interface WorkDoneProgressParams {
/**
* An optional token that a server can use to report work done progress.
*/
workDoneToken?: ProgressToken;
}
Ein Server verwendet das workDoneToken, um den Fortschritt für das spezifische build/deploy zu melden. Für die obige Anfrage sehen die Parameter der $/progress-Benachrichtigung wie folgt aus
{
"token": "1d546990-40a3-4b77-b134-46622995f6ae",
"value": {
"kind": "begin",
"title": "Deploying project#A083-41A9-A0E8",
"cancellable": false,
"message": "Processing projectConfig.json",
"percentage": 0
}
}
Das über die workDoneToken-Eigenschaft im Parameterobjekt einer Anfrage empfangene Token ist nur gültig, solange die Anfrage noch keine Antwort gesendet hat. Das Abbrechen des Arbeitsfortschritts erfolgt durch einfaches Abbrechen der entsprechenden Anfrage.
Es gibt keine spezifische Client-Capability, die signalisiert, ob ein Client ein Fortschrittstoken pro Anfrage sendet. Der Grund dafür ist, dass dies bei vielen Clients kein statischer Aspekt ist und sich sogar für jede Anfrageinstanz desselben Anfragetyps ändern kann. Daher wird die Capability bei jeder Anfrageinstanz durch das Vorhandensein einer workDoneToken-Eigenschaft signalisiert.
Um zu vermeiden, dass Clients eine Fortschrittsüberwachungs-Benutzeroberfläche einrichten, bevor sie eine Anfrage senden, aber der Server keinen Fortschritt meldet, muss ein Server die allgemeine Unterstützung für die Berichterstattung über Arbeitsfortschritt in der entsprechenden Serverfähigkeit signalisieren. Für das obige Beispiel würde ein Server eine solche Unterstützung signalisieren, indem er die deployProvider-Eigenschaft in den Serverfähigkeiten wie folgt setzt
{
"build.deployProvider": {
"workDoneProgress": true
}
}
Die entsprechende Typdefinition für die Serverfähigkeit sieht wie folgt aus
export interface WorkDoneProgressOptions {
workDoneProgress?: boolean;
}
Vom Server initiierter Fortschritt
Server können auch die Fortschrittsberichterstattung über die window/workDoneProgress/create-Anfrage initiieren. Dies ist nützlich, wenn der Server den Fortschritt außerhalb einer Anfrage melden muss (z. B. muss der Server eine Datenbank neu indexieren). Das Token kann dann verwendet werden, um den Fortschritt über die gleichen Benachrichtigungen zu melden, die auch für clientinitiierte Fortschrittsberichte verwendet werden. Das im Create-Request bereitgestellte Token sollte nur einmal verwendet werden (d. h. nur ein Beginn, viele Berichte und eine Endbenachrichtigung sollten an es gesendet werden).
Um das Protokoll abwärtskompatibel zu halten, dürfen Server die window/workDoneProgress/create-Anfrage nur verwenden, wenn der Client die entsprechende Unterstützung über die Clientfähigkeit window.workDoneProgress signalisiert, die wie folgt definiert ist
/**
* Window specific client capabilities.
*/
window?: {
/**
* Whether client supports server initiated progress using the
* `window/workDoneProgress/create` request.
*/
workDoneProgress?: boolean;
};
TraceValue
Ein TraceValue repräsentiert die Ausführlichkeitsstufe, mit der der Server systematisch seine Ausführungstraces über $/logTrace-Benachrichtigungen meldet. Der anfängliche Trace-Wert wird vom Client bei der Initialisierung gesetzt und kann später über die $/setTrace-Benachrichtigung geändert werden.
export type TraceValue = 'off' | 'messages' | 'verbose';
Lebenszyklusnachrichten
Die aktuelle Protokollspezifikation besagt, dass der Lebenszyklus eines Servers vom Client verwaltet wird (z. B. ein Tool wie VS Code oder Emacs). Es liegt am Client zu entscheiden, wann ein Server gestartet (prozessual) und wann er heruntergefahren wird.
Initialize-Anfrage (
)
Die initialize-Anfrage wird als erste Anfrage vom Client an den Server gesendet. Wenn der Server vor der initialize-Anfrage eine Anfrage oder Benachrichtigung empfängt, sollte er wie folgt vorgehen
- Bei einer Anfrage sollte die Antwort ein Fehler mit
code: -32002sein. Die Nachricht kann vom Server gewählt werden. - Benachrichtigungen sollten verworfen werden, mit Ausnahme der exit-Benachrichtigung. Dies ermöglicht das Beenden eines Servers ohne eine initialize-Anfrage.
Bis der Server mit einem InitializeResult auf die initialize-Anfrage geantwortet hat, darf der Client keine zusätzlichen Anfragen oder Benachrichtigungen an den Server senden. Darüber hinaus darf der Server keine Anfragen oder Benachrichtigungen an den Client senden, bis er mit einem InitializeResult geantwortet hat, mit der Ausnahme, dass während der initialize-Anfrage der Server die Benachrichtigungen window/showMessage, window/logMessage und telemetry/event sowie die window/showMessageRequest-Anfrage an den Client senden darf. Falls der Client ein Fortschritts-Token in den Initialisierungsparametern setzt (z. B. die Eigenschaft workDoneToken), darf der Server dieses Token (und nur dieses Token) auch über die $/progress-Benachrichtigung vom Server an den Client verwenden.
Die initialize-Anfrage darf nur einmal gesendet werden.
Anfrage:
- method: ‘initialize’
- params:
InitializeParams, wie folgt definiert
interface InitializeParams extends WorkDoneProgressParams {
/**
* The process Id of the parent process that started the server. Is null if
* the process has not been started by another process. If the parent
* process is not alive then the server should exit (see exit notification)
* its process.
*/
processId: integer | null;
/**
* Information about the client
*/
clientInfo?: {
/**
* The name of the client as defined by the client.
*/
name: string;
/**
* The client's version as defined by the client.
*/
version?: string;
};
/**
* The locale the client is currently showing the user interface
* in. This must not necessarily be the locale of the operating
* system.
*
* Uses IETF language tags as the value's syntax
* (See https://en.wikipedia.org/wiki/IETF_language_tag)
*/
locale?: string;
/**
* User provided initialization options.
*/
initializationOptions?: BaseAny;
/**
* The capabilities provided by the client (editor or tool)
*/
capabilities: {};
/**
* The initial trace setting. If omitted trace is disabled ('off').
*/
trace?: TraceValue;
}
Antwort:
- result:
InitializeResult, wie folgt definiert
interface InitializeResult {
/**
* The capabilities the server provides.
*/
capabilities: {};
/**
* Information about the server.
*/
serverInfo?: {
/**
* The name of the server as defined by the server.
*/
name: string;
/**
* The server's version as defined by the server.
*/
version?: string;
};
}
- error.data
interface InitializeError {
/**
* Indicates whether the client execute the following retry logic:
* (1) show the message provided by the ResponseError to the user
* (2) user selects retry or cancel
* (3) if user selected retry the initialize method is sent again.
*/
retry: boolean;
}
Beachten Sie, dass capabilities sowohl in InitializeParams als auch in InitializeResult als leeres Objekt spezifiziert ist und jeder Implementierung des Basisprotokolls überlassen bleibt, diese entsprechend zu definieren. Um Konflikte mit von LSP verwendeten Eigenschaften zu vermeiden, dürfen diese jedoch keine der im obigen Capabilities-Abschnitt aufgeführten Eigenschaftsnamen enthalten.
Initialized-Benachrichtigung (
)
Die initialized-Benachrichtigung wird vom Client an den Server gesendet, nachdem der Client das Ergebnis der initialize-Anfrage erhalten hat, aber bevor der Client andere Anfragen oder Benachrichtigungen an den Server sendet. Der Server kann die initialized-Benachrichtigung beispielsweise zur dynamischen Registrierung von Fähigkeiten verwenden. Die initialized-Benachrichtigung darf nur einmal gesendet werden.
Benachrichtigung:
- method: ‘initialized’
- params:
InitializedParams, wie folgt definiert
interface InitializedParams {
}
Capability registrieren (
)
Die client/registerCapability-Anfrage wird vom Server an den Client gesendet, um eine neue Fähigkeit auf Clientseite zu registrieren. Nicht alle Clients müssen eine dynamische Fähigkeitsregistrierung unterstützen. Ein Client wählt sich über die Eigenschaft dynamicRegistration bei den spezifischen Client-Fähigkeiten ein. Ein Client kann sogar eine dynamische Registrierung für Fähigkeit A, aber nicht für Fähigkeit B anbieten.
Der Server darf dieselbe Fähigkeit nicht sowohl statisch über das Initialisierungsergebnis als auch dynamisch für denselben Dokumentselektor registrieren. Wenn ein Server sowohl statische als auch dynamische Registrierung unterstützen möchte, muss er die Client-Fähigkeit in der Initialisierungsanfrage prüfen und die Fähigkeit nur statisch registrieren, wenn der Client keine dynamische Registrierung für diese Fähigkeit unterstützt.
Anfrage:
- method: ‘client/registerCapability’
- params:
RegistrationParams
Dabei ist RegistrationParams wie folgt definiert
/**
* General parameters to register for a capability.
*/
export interface Registration {
/**
* The id used to register the request. The id can be used to deregister
* the request again.
*/
id: string;
/**
* The method / capability to register for.
*/
method: string;
/**
* Options necessary for the registration.
*/
registerOptions?: BaseAny;
}
export interface RegistrationParams {
registrations: Registration[];
}
Antwort:
- result: void.
- error: code und message werden gesetzt, wenn während der Anfrage ein Fehler auftritt.
StaticRegistrationOptions können verwendet werden, um eine Funktion im initialize-Ergebnis mit einer gegebenen Server-Steuerungs-ID zu registrieren, um die Funktion später deregistrieren zu können.
/**
* Static registration options to be returned in the initialize request.
*/
export interface StaticRegistrationOptions {
/**
* The id used to register the request. The id can be used to deregister
* the request again. See also Registration#id.
*/
id?: string;
}
Capability abmelden (
)
Die client/unregisterCapability-Anfrage wird vom Server an den Client gesendet, um eine zuvor registrierte Fähigkeit abzumelden.
Anfrage:
- method: ‘client/unregisterCapability’
- params:
UnregistrationParams
Dabei ist UnregistrationParams wie folgt definiert
/**
* General parameters to unregister a capability.
*/
export interface Unregistration {
/**
* The id used to unregister the request or notification. Usually an id
* provided during the register request.
*/
id: string;
/**
* The method / capability to unregister for.
*/
method: string;
}
export interface UnregistrationParams {
unregistrations: Unregistration[];
}
Antwort:
- result: void.
- error: code und message werden gesetzt, wenn während der Anfrage ein Fehler auftritt.
SetTrace-Benachrichtigung (
)
Eine Benachrichtigung, die vom Client verwendet werden sollte, um die Trace-Einstellung des Servers zu ändern.
Benachrichtigung:
- method: ‘$/setTrace’
- params:
SetTraceParams, wie folgt definiert
interface SetTraceParams {
/**
* The new value that should be assigned to the trace setting.
*/
value: TraceValue;
}
LogTrace-Benachrichtigung (
)
Eine Benachrichtigung, um den Trace der Serverausführung zu protokollieren. Der Umfang und Inhalt dieser Benachrichtigungen hängen von der aktuellen trace-Konfiguration ab. Wenn trace auf 'off' gesetzt ist, sollte der Server keine logTrace-Benachrichtigung senden. Wenn trace auf 'messages' gesetzt ist, sollte der Server das Feld 'verbose' in LogTraceParams nicht hinzufügen.
$/logTrace sollte für die systematische Trace-Berichterstattung verwendet werden. Für einzelne Debugging-Nachrichten sollte der Server window/logMessage-Benachrichtigungen senden.
Benachrichtigung:
- method: ‘$/logTrace’
- params:
LogTraceParams, wie folgt definiert
interface LogTraceParams {
/**
* The message to be logged.
*/
message: string;
/**
* Additional information that can be computed if the `trace` configuration
* is set to `'verbose'`
*/
verbose?: string;
}
Shutdown-Anfrage (
)
Die shutdown-Anfrage wird vom Client an den Server gesendet. Sie fordert den Server auf, sich herunterzufahren, aber nicht zu beenden (andernfalls könnte die Antwort möglicherweise nicht korrekt an den Client geliefert werden). Es gibt eine separate exit-Benachrichtigung, die den Server zum Beenden auffordert. Clients dürfen nach dem Senden einer shutdown-Anfrage keine anderen Benachrichtigungen als exit oder Anfragen an einen Server senden. Clients sollten auch mit dem Senden der exit-Benachrichtigung warten, bis sie eine Antwort auf die shutdown-Anfrage erhalten haben.
Wenn ein Server nach einer shutdown-Anfrage Anfragen erhält, sollten diese mit InvalidRequest fehlschlagen.
Anfrage:
- method: ‘shutdown’
- params: none
Antwort:
- result: null
- error: code und message werden gesetzt, wenn während der shutdown-Anfrage ein Fehler auftritt.
Exit-Benachrichtigung (
)
Eine Benachrichtigung, die den Server auffordert, seinen Prozess zu beenden. Der Server sollte mit dem Erfolgs-Code 0 beenden, wenn die shutdown-Anfrage zuvor empfangen wurde; andernfalls mit dem Fehler-Code 1.
Benachrichtigung:
- method: ‘exit’
- params: none
Fensterfunktionen
ShowMessage-Benachrichtigung (
)
Die show message-Benachrichtigung wird von einem Server an einen Client gesendet, um den Client aufzufordern, eine bestimmte Nachricht in der Benutzeroberfläche anzuzeigen.
Benachrichtigung:
- method: ‘window/showMessage’
- params:
ShowMessageParams, wie folgt definiert
interface ShowMessageParams {
/**
* The message type. See {@link MessageType}.
*/
type: MessageType;
/**
* The actual message.
*/
message: string;
}
Dabei ist der Typ wie folgt definiert
export namespace MessageType {
/**
* An error message.
*/
export const Error = 1;
/**
* A warning message.
*/
export const Warning = 2;
/**
* An information message.
*/
export const Info = 3;
/**
* A log message.
*/
export const Log = 4;
/**
* A debug message.
*
* @since 3.18.0
* @proposed
*/
export const Debug = 5;
}
export type MessageType = 1 | 2 | 3 | 4 | 5;
ShowMessage-Anfrage (
)
Die show message request-Anfrage wird von einem Server an einen Client gesendet, um den Client aufzufordern, eine bestimmte Nachricht in der Benutzeroberfläche anzuzeigen. Neben der show message-Benachrichtigung ermöglicht die Anfrage, Aktionen zu übergeben und auf eine Antwort vom Client zu warten.
Client Capability:
- property path (optional):
window.showMessage - property type:
ShowMessageRequestClientCapabilities, wie folgt definiert
/**
* Show message request client capabilities
*/
export interface ShowMessageRequestClientCapabilities {
/**
* Capabilities specific to the `MessageActionItem` type.
*/
messageActionItem?: {
/**
* Whether the client supports additional attributes which
* are preserved and sent back to the server in the
* request's response.
*/
additionalPropertiesSupport?: boolean;
};
}
Anfrage:
- method: ‘window/showMessageRequest’
- params:
ShowMessageRequestParams, wie folgt definiert
interface ShowMessageRequestParams {
/**
* The message type. See {@link MessageType}
*/
type: MessageType;
/**
* The actual message
*/
message: string;
/**
* The message action items to present.
*/
actions?: MessageActionItem[];
}
Dabei ist das MessageActionItem wie folgt definiert
interface MessageActionItem {
/**
* A short title like 'Retry', 'Open Log' etc.
*/
title: string;
}
Antwort:
- result: das ausgewählte
MessageActionItem|null, wenn keines ausgewählt wurde. - error: code und message werden gesetzt, wenn während der Anzeige einer Nachricht ein Fehler auftritt.
LogMessage-Benachrichtigung (
)
Die log message-Benachrichtigung wird vom Server an den Client gesendet, um den Client aufzufordern, eine bestimmte Nachricht zu protokollieren.
Benachrichtigung:
- method: ‘window/logMessage’
- params:
LogMessageParams, wie folgt definiert
interface LogMessageParams {
/**
* The message type. See {@link MessageType}
*/
type: MessageType;
/**
* The actual message
*/
message: string;
}
Telemetry-Benachrichtigung (
)
Die telemetry-Benachrichtigung wird vom Server an den Client gesendet, um den Client aufzufordern, ein Telemetrieereignis zu protokollieren. Das Protokoll spezifiziert die Nutzlast nicht, da keine Interpretation der Daten im Protokoll stattfindet. Die meisten Clients verarbeiten das Ereignis nicht direkt, sondern leiten es an die Erweiterungen weiter, denen der entsprechende Server gehört, der das Ereignis auslöst.
Benachrichtigung:
- method: ‘telemetry/event’
- Parameter:
object | array;