文本文档同步
客户端对 textDocument/didOpen
、textDocument/didChange
和 textDocument/didClose
通知的支持在协议中是强制性的,客户端无法选择不支持它们。这包括 textDocument/didChange
通知中的完全同步和增量同步。此外,服务器必须实现所有这三个,或者不实现。因此,它们是通过客户端能力和服务端能力来联合控制的。仅当客户端显示的文档是只读的时,选择退出文本文档同步才有意义。否则,服务器可能会收到文档请求,这些文档的内容在客户端中进行管理(例如,它们可能已更改)。
客户端能力(Client capability):
- 属性路径:
textDocument.synchronization.dynamicRegistration
- 属性类型:
boolean
控制文本文档同步是否支持动态注册。
服务端能力(Server capability):
- 属性路径:
textDocumentSync
- 属性类型:
TextDocumentSyncKind | TextDocumentSyncOptions
。下面的TextDocumentSyncOptions
定义仅涵盖特定于打开、更改和关闭通知的属性:
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;
}
/**
* 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;
DidOpenTextDocument 通知
文档打开通知从客户端发送到服务器,以发出新打开的文本文档的信号。文档的内容现在由客户端管理,服务器不得尝试使用文档的 Uri 读取文档的内容。从这个意义上说,Open 意味着它由客户端管理。这并不一定意味着它的内容在编辑器中呈现。如果没有相应的关闭通知,则不得多次发送打开通知。这意味着打开和关闭通知必须平衡,并且特定 textDocument
的最大打开计数为 1。请注意,服务器满足请求的能力与文本文档是打开还是关闭无关。
DidOpenTextDocumentParams
包含与文档关联的语言 ID。如果文档的语言 ID 发生更改,则客户端需要向服务器发送 textDocument/didClose
,如果服务器也处理新的语言 ID,则需要发送具有新语言 ID 的 textDocument/didOpen
。
客户端能力(Client capability): 请参阅通用文本文档同步的 客户端能力。
服务端能力(Server Capability): 请参阅通用文本文档同步的 服务端能力
注册选项(Registration Options): TextDocumentRegistrationOptions
通知(Notification):
- method: "textDocument/didOpen"
- params:
DidOpenTextDocumentParams
定义如下:
interface DidOpenTextDocumentParams {
/**
* The document that was opened.
*/
textDocument: TextDocumentItem;
}
DidChangeTextDocument 通知
文档更改通知从客户端发送到服务器,以发出对文本文档的更改信号。在客户端可以更改文本文档之前,它必须使用 textDocument/didOpen
通知声明其内容的所有权。在 2.0 中,参数的形状已更改为包含正确的版本号。
客户端能力(Client capability): 请参阅通用文本文档同步的 客户端能力。
服务端能力(Server Capability): 请参阅通用文本文档同步的 服务端能力
注册选项(Registration Options): TextDocumentChangeRegistrationOptions
定义如下:
/**
* Describe options to be used when registering for text document change events.
*/
export interface TextDocumentChangeRegistrationOptions
extends TextDocumentRegistrationOptions {
/**
* How documents are synced to the server. See TextDocumentSyncKind.Full
* and TextDocumentSyncKind.Incremental.
*/
syncKind: TextDocumentSyncKind;
}
通知(Notification):
- method: "textDocument/didChange"
- params:
DidChangeTextDocumentParams
定义如下:
interface DidChangeTextDocumentParams {
/**
* The document that did change. The version number points
* to the version after all provided content changes have
* been applied.
*/
textDocument: VersionedTextDocumentIdentifier;
/**
* The actual content changes. The content changes describe single state
* changes to the document. So if there are two content changes c1 (at
* array index 0) and c2 (at array index 1) for a document in state S then
* c1 moves the document from S to S' and c2 from S' to S''. So c1 is
* computed on the state S and c2 is computed on the state S'.
*
* To mirror the content of a document using change events use the following
* approach:
* - start with the same initial content
* - apply the 'textDocument/didChange' notifications in the order you
* receive them.
* - apply the `TextDocumentContentChangeEvent`s in a single notification
* in the order you receive them.
*/
contentChanges: TextDocumentContentChangeEvent[];
}
/**
* An event describing a change to a text document. If only a text is provided
* it is considered to be the full content of the document.
*/
export type TextDocumentContentChangeEvent = {
/**
* The range of the document that changed.
*/
range: Range;
/**
* The optional length of the range that got replaced.
*
* @deprecated use range instead.
*/
rangeLength?: uinteger;
/**
* The new text for the provided range.
*/
text: string;
} | {
/**
* The new text of the whole document.
*/
text: string;
};
WillSaveTextDocument 通知
在实际保存文档之前,文档将保存通知从客户端发送到服务器。如果服务器已注册打开/关闭事件,则客户端应确保在发送 willSave
通知之前打开文档,因为客户端无法在不转移所有权的情况下更改文件的内容。
客户端能力(Client capability):
- 属性路径:
textDocument.synchronization.willSave
- 属性类型:
boolean
服务端能力(Server capability):
- 属性路径:
textDocumentSync.willSave
- 属性类型:
boolean
注册选项(Registration Options): TextDocumentRegistrationOptions
通知(Notification):
- method: "textDocument/willSave"
- params:
WillSaveTextDocumentParams
定义如下:
/**
* The parameters send in a will save text document notification.
*/
export interface WillSaveTextDocumentParams {
/**
* The document that will be saved.
*/
textDocument: TextDocumentIdentifier;
/**
* The 'TextDocumentSaveReason'.
*/
reason: TextDocumentSaveReason;
}
/**
* Represents reasons why a text document is saved.
*/
export namespace TextDocumentSaveReason {
/**
* Manually triggered, e.g. by the user pressing save, by starting
* debugging, or by an API call.
*/
export const Manual = 1;
/**
* Automatic after a delay.
*/
export const AfterDelay = 2;
/**
* When the editor lost focus.
*/
export const FocusOut = 3;
}
export type TextDocumentSaveReason = 1 | 2 | 3;
WillSaveWaitUntilTextDocument 请求
在文档实际保存之前,文档将保存请求从客户端发送到服务器。该请求可以返回一个 TextEdits
数组,该数组将在保存文本文档之前应用于文本文档。请注意,如果计算文本编辑花费的时间过长,或者服务器在此请求上不断失败,则客户端可能会丢弃结果。这样做是为了保持保存的快速和可靠。如果服务器已注册打开/关闭事件,则客户端应确保在发送 willSaveWaitUntil
通知之前打开文档,因为客户端无法在不转移所有权的情况下更改文件的内容。
客户端能力(Client capability):
- 属性路径:
textDocument.synchronization.willSaveWaitUntil
- 属性类型:
boolean
服务端能力(Server capability):
- 属性路径:
textDocumentSync.willSaveWaitUntil
- 属性类型:
boolean
注册选项(Registration Options): TextDocumentRegistrationOptions
请求(Request):
- method: "textDocument/willSaveWaitUntil"
- params:
WillSaveTextDocumentParams
响应(Response):
- result:
TextEdit[] | null
- error:
code
和message
,以防在请求期间发生异常。
DidSaveTextDocument 通知
当文档在客户端中被保存时,文档保存通知将从客户端发送到服务器。
客户端能力(Client capability):
- 属性路径:
textDocument.synchronization.didSave
- 属性类型:
boolean
服务端能力(Server capability):
- 属性路径:
textDocumentSync.save
- 属性类型:
boolean | SaveOptions
,SaveOptions
定义如下:
export interface SaveOptions {
/**
* The client is supposed to include the content on save.
*/
includeText?: boolean;
}
注册选项(Registration Options): TextDocumentSaveRegistrationOptions
, 定义如下:
export interface TextDocumentSaveRegistrationOptions extends TextDocumentRegistrationOptions {
/**
* The client is supposed to include the content on save.
*/
includeText?: boolean;
}
通知(Notification):
- method: "textDocument/didSave"
- params:
DidSaveTextDocumentParams
, 定义如下:
interface DidSaveTextDocumentParams {
/**
* The document that was saved.
*/
textDocument: TextDocumentIdentifier;
/**
* Optional the content when saved. Depends on the includeText value
* when the save notification was requested.
*/
text?: string;
}
DidCloseTextDocument 通知
当文档在客户端中关闭时,文档关闭通知将从客户端发送到服务器。文档的 Uri
现在存在于文档的 Uri
指向的位置(例如,如果文档的 Uri
是文件 Uri
,则主文件现在存在于磁盘上)。与打开通知一样,发送关闭通知意味着它不再由客户端管理,收到关闭通知并不意味着文档之前已在编辑器中打开。只有打开通知发送后,才能发送关闭通知。请注意,服务器满足请求的能力与文本文档是打开还是关闭无关。
客户端能力(Client capability): 请参阅通用文本文档同步的 客户端能力。
服务端能力(Server Capability): 请参阅通用文本文档同步的 服务端能力
注册选项(Registration Options): TextDocumentRegistrationOptions
通知(Notification):
- method: "textDocument/didClose"
- params:
DidCloseTextDocumentParams
, 定义如下:
interface DidCloseTextDocumentParams {
/**
* The document that was closed.
*/
textDocument: TextDocumentIdentifier;
}
重命名文档
文档重命名应向服务器发出信号,使用文档的旧名称发送文档关闭通知,然后使用文档的新名称发送打开通知。这样做的主要原因是除了名称之外,其他属性也可以更改,例如与文档关联的语言。此外,服务器可能不再对新文档感兴趣。
服务器可以通过订阅 workspace/didRenameFiles
通知或 workspace/willRenameFiles
请求来参与文档重命名。
TextDocumentSyncClientCapabilities
和 TextDocumentSyncOptions
服务器选项的最终结构如下所示:
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;
}