Completion
Completion 请求
完成请求从客户端发送到服务器,以计算给定光标位置的完成项。完成项显示在 IntelliSense 用户界面中。如果计算所以完成项的成本很高,服务器还可以为完成项解析请求提供处理程序(completionItem/resolve
)。在用户界面中选择完成项时,将发送此请求。例如,一个典型的用例是:textDocument/completion
请求不会填充返回的完成项的 documentation
属性,因为它的计算成本很高。在用户界面中选择项目时,将发送completionItem/resolve
请求,并将选定的完成项目作为参数。返回的完成项应填写 documentation
属性。默认情况下,请求只能延迟详细信息和文档属性的计算。从 3.16.0 开始,客户端可以发出信号,表明它可以延迟解析更多属性。这是使用 completionItem.resolveSupport
客户端能力完成的,该能力列出了在 completionItem/resolve
请求期间可以填写的所有属性。所有其他属性(通常为 sortText
、filterText
、insertText
和 textEdit
)必须在 textDocument/completion
响应中提供,并且在解析期间不得更改。
语言服务器协议围绕完成使用以下模型:
-
为了实现跨语言的一致性并尊重不同的客户端,通常客户端负责过滤和排序。这也有一个优点,即客户可以尝试不同的过滤和排序模型。但是,服务器可以通过设置
filterText
/sortText
来强制执行不同的行为 -
对于速度,如果用户继续键入,客户端应该能够过滤已收到的完成列表。服务器可以使用将
CompletionList
标记为isIncomplete
来选择退出此操作。
完成项提供了影响筛选和排序的其他方法。它们通过使用 insertText
或 textEdit
创建 CompletionItem
来表示。这两种模式的区别如下:
-
完成项提供插入
insertText
/label
,无需textEdit
: 在此模型中,客户端应使用语言的单词边界规则过滤用户已经输入的内容(例如,在光标位置下解析单词)。这种模式的原因是,它使服务器非常容易实现基本完成列表并在客户端上对其进行筛选。 -
带有
textEdit
的完成项目: 在这种模式下,服务器告诉客户端它实际上知道它在做什么。如果创建在当前光标位置进行文本编辑的完成项,则不会进行单词猜测,也不应进行筛选。此模式可以与排序文本和筛选文本结合使用,以自定义两件事:如果文本编辑是替换编辑,则范围表示用于过滤的单词;如果替换更改了文本,则指定要使用的筛选器文本很可能是有意义的。
客户端能力(Client capability):
- 属性路径:
textDocument.completion
- 属性类型:
CompletionClientCapabilities
, 定义如下:
export interface CompletionClientCapabilities {
/**
* Whether completion supports dynamic registration.
*/
dynamicRegistration?: boolean;
/**
* The client supports the following `CompletionItem` specific
* capabilities.
*/
completionItem?: {
/**
* Client supports snippets as insert text.
*
* A snippet can define tab stops and placeholders with `$1`, `$2`
* and `${3:foo}`. `$0` defines the final tab stop, it defaults to
* the end of the snippet. Placeholders with equal identifiers are
* linked, that is typing in one will update others too.
*/
snippetSupport?: boolean;
/**
* Client supports commit characters on a completion item.
*/
commitCharactersSupport?: boolean;
/**
* Client supports the follow content formats for the documentation
* property. The order describes the preferred format of the client.
*/
documentationFormat?: MarkupKind[];
/**
* Client supports the deprecated property on a completion item.
*/
deprecatedSupport?: boolean;
/**
* Client supports the preselect property on a completion item.
*/
preselectSupport?: boolean;
/**
* Client supports the tag property on a completion item. Clients
* supporting tags have to handle unknown tags gracefully. Clients
* especially need to preserve unknown tags when sending a completion
* item back to the server in a resolve call.
*
* @since 3.15.0
*/
tagSupport?: {
/**
* The tags supported by the client.
*/
valueSet: CompletionItemTag[];
};
/**
* Client supports insert replace edit to control different behavior if
* a completion item is inserted in the text or should replace text.
*
* @since 3.16.0
*/
insertReplaceSupport?: boolean;
/**
* Indicates which properties a client can resolve lazily on a
* completion item. Before version 3.16.0 only the predefined properties
* `documentation` and `detail` could be resolved lazily.
*
* @since 3.16.0
*/
resolveSupport?: {
/**
* The properties that a client can resolve lazily.
*/
properties: string[];
};
/**
* The client supports the `insertTextMode` property on
* a completion item to override the whitespace handling mode
* as defined by the client (see `insertTextMode`).
*
* @since 3.16.0
*/
insertTextModeSupport?: {
valueSet: InsertTextMode[];
};
/**
* The client has support for completion item label
* details (see also `CompletionItemLabelDetails`).
*
* @since 3.17.0
*/
labelDetailsSupport?: boolean;
};
completionItemKind?: {
/**
* The completion item kind values the client supports. When this
* property exists the client also guarantees that it will
* handle values outside its set gracefully and falls back
* to a default value when unknown.
*
* If this property is not present the client only supports
* the completion items kinds from `Text` to `Reference` as defined in
* the initial version of the protocol.
*/
valueSet?: CompletionItemKind[];
};
/**
* The client supports to send additional context information for a
* `textDocument/completion` request.
*/
contextSupport?: boolean;
/**
* The client's default when the completion item doesn't provide a
* `insertTextMode` property.
*
* @since 3.17.0
*/
insertTextMode?: InsertTextMode;
/**
* The client supports the following `CompletionList` specific
* capabilities.
*
* @since 3.17.0
*/
completionList?: {
/**
* The client supports the following itemDefaults on
* a completion list.
*
* The value lists the supported property names of the
* `CompletionList.itemDefaults` object. If omitted
* no properties are supported.
*
* @since 3.17.0
*/
itemDefaults?: string[];
}
}
服务端能力(Server capability):
- 属性路径:
completionProvider
- 属性类型:
CompletionOptions
, 定义如下:
/**
* Completion options.
*/
export interface CompletionOptions extends WorkDoneProgressOptions {
/**
* The additional characters, beyond the defaults provided by the client (typically
* [a-zA-Z]), that should automatically trigger a completion request. For example
* `.` in JavaScript represents the beginning of an object property or method and is
* thus a good candidate for triggering a completion request.
*
* Most tools trigger a completion request automatically without explicitly
* requesting it using a keyboard shortcut (e.g. Ctrl+Space). Typically they
* do so when the user starts to type an identifier. For example if the user
* types `c` in a JavaScript file code complete will automatically pop up
* present `console` besides others as a completion item. Characters that
* make up identifiers don't need to be listed here.
*/
triggerCharacters?: string[];
/**
* The list of all possible characters that commit a completion. This field
* can be used if clients don't support individual commit characters per
* completion item. See client capability
* `completion.completionItem.commitCharactersSupport`.
*
* If a server provides both `allCommitCharacters` and commit characters on
* an individual completion item the ones on the completion item win.
*
* @since 3.2.0
*/
allCommitCharacters?: string[];
/**
* The server provides support to resolve additional
* information for a completion item.
*/
resolveProvider?: boolean;
/**
* The server supports the following `CompletionItem` specific
* capabilities.
*
* @since 3.17.0
*/
completionItem?: {
/**
* The server has support for completion item label
* details (see also `CompletionItemLabelDetails`) when receiving
* a completion item in a resolve call.
*
* @since 3.17.0
*/
labelDetailsSupport?: boolean;
}
}
注册选项(Registration Options): CompletionRegistrationOptions
, 定义如下:
export interface CompletionRegistrationOptions
extends TextDocumentRegistrationOptions, CompletionOptions {
}
请求(Request):
- method: "textDocument/completion"
- params:
CompletionParams
, 定义如下:
export interface CompletionParams extends TextDocumentPositionParams,
WorkDoneProgressParams, PartialResultParams {
/**
* The completion context. This is only available if the client specifies
* to send this using the client capability
* `completion.contextSupport === true`
*/
context?: CompletionContext;
}
/**
* How a completion was triggered
*/
export namespace CompletionTriggerKind {
/**
* Completion was triggered by typing an identifier (24x7 code
* complete), manual invocation (e.g Ctrl+Space) or via API.
*/
export const Invoked: 1 = 1;
/**
* Completion was triggered by a trigger character specified by
* the `triggerCharacters` properties of the
* `CompletionRegistrationOptions`.
*/
export const TriggerCharacter: 2 = 2;
/**
* Completion was re-triggered as the current completion list is incomplete.
*/
export const TriggerForIncompleteCompletions: 3 = 3;
}
export type CompletionTriggerKind = 1 | 2 | 3;
/**
* Contains additional information about the context in which a completion
* request is triggered.
*/
export interface CompletionContext {
/**
* 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;
}
响应(Response):
- result:
CompletionItem[] | CompletionList | null
, 如果提供了CompletionItem[]
,则将其解释为完成。所以它和{ isIncomplete: false, items }
是一样的
/**
* Represents a collection of [completion items](#CompletionItem) to be
* presented in the editor.
*/
export interface CompletionList {
/**
* This list is not complete. Further typing should result in recomputing
* this list.
*
* Recomputed lists have all their items replaced (not appended) in the
* incomplete completion sessions.
*/
isIncomplete: boolean;
/**
* In many cases the items of an actual completion result share the same
* value for properties like `commitCharacters` or the range of a text
* edit. A completion list can therefore define item defaults which will
* be used if a completion item itself doesn't specify the value.
*
* If a completion list specifies a default value and a completion item
* also specifies a corresponding value the one from the item is used.
*
* Servers are only allowed to return default values if the client
* signals support for this via the `completionList.itemDefaults`
* capability.
*
* @since 3.17.0
*/
itemDefaults?: {
/**
* A default commit character set.
*
* @since 3.17.0
*/
commitCharacters?: string[];
/**
* A default edit range
*
* @since 3.17.0
*/
editRange?: Range | {
insert: Range;
replace: Range;
};
/**
* A default insert text format
*
* @since 3.17.0
*/
insertTextFormat?: InsertTextFormat;
/**
* A default insert text mode
*
* @since 3.17.0
*/
insertTextMode?: InsertTextMode;
/**
* A default data value.
*
* @since 3.17.0
*/
data?: LSPAny;
}
/**
* The completion items.
*/
items: CompletionItem[];
}
/**
* Defines whether the insert text in a completion item should be interpreted as
* plain text or a snippet.
*/
export namespace InsertTextFormat {
/**
* The primary text to be inserted is treated as a plain string.
*/
export const PlainText = 1;
/**
* The primary text to be inserted is treated as a snippet.
*
* A snippet can define tab stops and placeholders with `$1`, `$2`
* and `${3:foo}`. `$0` defines the final tab stop, it defaults to
* the end of the snippet. Placeholders with equal identifiers are linked,
* that is typing in one will update others too.
*/
export const Snippet = 2;
}
export type InsertTextFormat = 1 | 2;
/**
* Completion item tags are extra annotations that tweak the rendering of a
* completion item.
*
* @since 3.15.0
*/
export namespace CompletionItemTag {
/**
* Render a completion as obsolete, usually using a strike-out.
*/
export const Deprecated = 1;
}
export type CompletionItemTag = 1;
/**
* A special text edit to provide an insert and a replace operation.
*
* @since 3.16.0
*/
export interface InsertReplaceEdit {
/**
* The string to be inserted.
*/
newText: string;
/**
* The range if the insert is requested
*/
insert: Range;
/**
* The range if the replace is requested.
*/
replace: Range;
}
/**
* How whitespace and indentation is handled during completion
* item insertion.
*
* @since 3.16.0
*/
export namespace InsertTextMode {
/**
* The insertion or replace strings is taken as it is. If the
* value is multi line the lines below the cursor will be
* inserted using the indentation defined in the string value.
* The client will not apply any kind of adjustments to the
* string.
*/
export const asIs: 1 = 1;
/**
* The editor adjusts leading whitespace of new lines so that
* they match the indentation up to the cursor of the line for
* which the item is accepted.
*
* Consider a line like this: <2tabs><cursor><3tabs>foo. Accepting a
* multi line completion item is indented using 2 tabs and all
* following lines inserted will be indented using 2 tabs as well.
*/
export const adjustIndentation: 2 = 2;
}
export type InsertTextMode = 1 | 2;
/**
* Additional details for a completion item label.
*
* @since 3.17.0
*/
export interface CompletionItemLabelDetails {
/**
* An optional string which is rendered less prominently directly after
* {@link CompletionItem.label label}, without any spacing. Should be
* used for function signatures or type annotations.
*/
detail?: string;
/**
* An optional string which is rendered less prominently after
* {@link CompletionItemLabelDetails.detail}. Should be used for fully qualified
* names or file path.
*/
description?: string;
}
export interface CompletionItem {
/**
* The label of this completion item.
*
* The label property is also by default the text that
* is inserted when selecting this completion.
*
* If label details are provided the label itself should
* be an unqualified name of the completion item.
*/
label: string;
/**
* Additional details for the label
*
* @since 3.17.0
*/
labelDetails?: CompletionItemLabelDetails;
/**
* 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?: CompletionItemKind;
/**
* Tags for this completion item.
*
* @since 3.15.0
*/
tags?: CompletionItemTag[];
/**
* 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 Use `tags` instead if supported.
*/
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 omitted the label is used
* as the sort text for this item.
*/
sortText?: string;
/**
* A string that should be used when filtering a set of
* completion items. When omitted the label is used as the
* filter text for this item.
*/
filterText?: string;
/**
* A string that should be inserted into a document when selecting
* this completion. When omitted the label is used as the insert text
* for this item.
*
* 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 omitted defaults to `InsertTextFormat.PlainText`.
*
* Please note that the insertTextFormat doesn't apply to
* `additionalTextEdits`.
*/
insertTextFormat?: InsertTextFormat;
/**
* How whitespace and indentation is handled during completion
* item insertion. If not provided the client's default value depends on
* the `textDocument.completion.insertTextMode` client capability.
*
* @since 3.16.0
* @since 3.17.0 - support for `textDocument.completion.insertTextMode`
*/
insertTextMode?: InsertTextMode;
/**
* 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.
*
* Most editors support two different operations when accepting a completion
* item. One is to insert a completion text and the other is to replace an
* existing text with a completion text. Since this can usually not be
* predetermined by a server it can report both ranges. Clients need to
* signal support for `InsertReplaceEdit`s via the
* `textDocument.completion.completionItem.insertReplaceSupport` client
* capability property.
*
* *Note 1:* The text edit's range as well as both ranges from an insert
* replace edit must be a [single line] and they must contain the position
* at which completion has been requested.
* *Note 2:* If an `InsertReplaceEdit` is returned the edit's insert range
* must be a prefix of the edit's replace range, that means it must be
* contained and starting at the same position.
*
* @since 3.16.0 additional type `InsertReplaceEdit`
*/
textEdit?: TextEdit | InsertReplaceEdit;
/**
* The edit text used if the completion item is part of a CompletionList and
* CompletionList defines an item default for the text edit range.
*
* Clients will only honor this property if they opt into completion list
* item defaults using the capability `completionList.itemDefaults`.
*
* If not provided and a list's default range is provided the label
* property is used as a text.
*
* @since 3.17.0
*/
textEditText?: string;
/**
* 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?: LSPAny;
}
/**
* The kind of a completion entry.
*/
export namespace CompletionItemKind {
export const Text = 1;
export const Method = 2;
export const Function = 3;
export const Constructor = 4;
export const Field = 5;
export const Variable = 6;
export const Class = 7;
export const Interface = 8;
export const Module = 9;
export const Property = 10;
export const Unit = 11;
export const Value = 12;
export const Enum = 13;
export const Keyword = 14;
export const Snippet = 15;
export const Color = 16;
export const File = 17;
export const Reference = 18;
export const Folder = 19;
export const EnumMember = 20;
export const Constant = 21;
export const Struct = 22;
export const Event = 23;
export const Operator = 24;
export const TypeParameter = 25;
}
export type CompletionItemKind = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25;
- partial result: 部分结果:
CompletionItem[]
或CompletionList
后跟CompletionItem[]
。如果提供的第一个结果项的类型为CompletionList
,则CompletionItem[]
的后续部分结果将添加到CompletionList
的items
属性中。 - error:
code
和message
,以防在请求期间发生异常。
完成项支持代码段(请参阅 InsertTextFormat.Snippet
)。代码段格式如下:
Snippet Syntax(代码段语法)
代码段的 body
可以使用特殊构造来控制光标和插入的文本。以下是支持的功能及其语法:
Tab stops(制表位)
使用制表位,可以使编辑器光标在代码段内移动。使用 $1
、$2
指定光标位置。数字是访问制表位的顺序,而 $0
表示最终光标位置。多个制表位会同步链接和更新。
Placeholders(占位符)
占位符是带有值的制表位,例如 ${1:foo}
。将插入并选择占位符文本,以便可以轻松更改。占位符可以嵌套,例如 ${1:another ${2:placeholder}}
。
Choice(选项)
占位符可以将选项作为值。语法是以逗号分隔的值枚举,用竖线字符括起来,例如 ${1|one,two,three|}
。插入代码段并选择占位符后,选项将提示用户选择其中一个值。
Variables(变量)
使用 $name
或 ${name:default}
,您可以插入变量的值。如果未设置变量,则插入其默认值或空字符串。当变量未知(即未定义其名称)时,将插入变量的名称并将其转换为占位符。
可以使用以下变量:
TM_SELECTED_TEXT
当前选定的文本或空字符串TM_CURRENT_LINE
当前行的内容TM_CURRENT_WORD
光标串下的单词的内容或空字符TM_LINE_INDEX
基于零索引的行号TM_LINE_NUMBER
基于数字索引的行号TM_FILENAME
当前文档的文件名TM_FILENAME_BASE
当前文档的文件名(不带扩展名)TM_DIRECTORY
当前文档的目录TM_FILEPATH
当前文档的完整文件路径
Variable Transforms(变量转换)
转换允许您在插入变量之前修改变量的值。转换的定义由三个部分组成:
-
与变量的值匹配的正则表达式,或者在变量无法解析时与空字符串匹配。
-
一个“格式字符串”,允许从正则表达式引用匹配的组。格式字符串允许条件插入和简单修改。
-
传递给正则表达式的选项。
下面的示例插入当前文件的名称而不带其结尾,因此从 foo.txt
开始,它生成 foo
。
${TM_FILENAME/(.*)\..+$/$1/}
| | | |
| | | |-> no options
| | |
| | |-> references the contents of the first
| | capture group
| |
| |-> regex to capture everything before
| the final `.suffix`
|
|-> resolves to the filename
Grammar(语法)
以下是片段的 EBNF(extended Backus-Naur form)。使用 \
(反斜杠),可以转义 $
、}
和 \
。在选择元素中,反斜杠还转义了逗号和竖线字符。
any ::= tabstop | placeholder | choice | variable | text
tabstop ::= '$' int | '${' int '}'
placeholder ::= '${' int ':' any '}'
choice ::= '${' int '|' text (',' text)* '|}'
variable ::= '$' var | '${' var }'
| '${' var ':' any '}'
| '${' var '/' regex '/' (format | text)+ '/' options '}'
format ::= '$' int | '${' int '}'
| '${' int ':' '/upcase' | '/downcase' | '/capitalize' '}'
| '${' int ':+' if '}'
| '${' int ':?' if ':' else '}'
| '${' int ':-' else '}' | '${' int ':' else '}'
regex ::= Regular Expression value (ctor-string)
options ::= Regular Expression option (ctor-options)
var ::= [_a-zA-Z] [_a-zA-Z0-9]*
int ::= [0-9]+
text ::= .*
if ::= text
else ::= text
Completion Item Resolve 请求
请求从客户端发送到服务器,以解析给定完成项的其他信息。
请求(Request):
- method: "completionItem/resolve"
- params:
CompletionItem
响应(Response):
- result:
CompletionItem
- error:
code
和message
,以防在请求期间发生异常。