现已发布!阅读关于 11 月份的新功能和修复。

程序化语言特性

程序化语言特性是一组由 vscode.languages.* API 提供支持的智能编辑功能。在 Visual Studio Code 中提供动态语言功能有两种常见方法。让我们以悬停为例

vscode.languages.registerHoverProvider('javascript', {
  provideHover(document, position, token) {
    return {
      contents: ['Hover Content']
    };
  }
});

如上所示,vscode.languages.registerHoverProvider API 提供了一种向 JavaScript 文件提供悬停内容的简单方法。在此扩展被激活后,每当您将鼠标悬停在某些 JavaScript 代码上时,VS Code 都会查询所有 JavaScript 的HoverProvider,并将结果显示在悬停小部件中。语言特性列表和下面的 GIF 图为您提供了一种简单的方法来定位您的扩展需要哪个 VS Code API/LSP 方法。

另一种方法是实现一个遵循语言服务器协议的语言服务器。它的工作方式如下

  • 一个扩展为 JavaScript 提供了一个语言客户端和一个语言服务器。
  • 语言客户端类似于任何其他 VS Code 扩展,在 Node.js 扩展主机上下文中运行。当它被激活时,它会在另一个进程中生成语言服务器,并通过 语言服务器协议与其通信。
  • 您在 VS Code 中将鼠标悬停在 JavaScript 代码上
  • VS Code 将悬停信息告知语言客户端
  • 语言客户端向语言服务器查询悬停结果,并将其发送回 VS Code
  • VS Code 在悬停小部件中显示悬停结果

该过程看起来更复杂,但它提供了两个主要好处

  • 语言服务器可以用任何语言编写
  • 语言服务器可以重用,为多个编辑器提供智能编辑功能

有关更深入的指南,请转到语言服务器扩展指南


语言特性列表

此列表包括每个语言特性的以下项

  • VS Code 中语言特性的说明
  • 相关的 VS Code API
  • 相关的 LSP 方法
VS Code API LSP 方法
createDiagnosticCollection PublishDiagnostics
registerCompletionItemProvider Completion & Completion Resolve
registerHoverProvider 悬停
registerSignatureHelpProvider SignatureHelp
registerDefinitionProvider 定义
registerTypeDefinitionProvider TypeDefinition
registerImplementationProvider 实现
registerReferenceProvider 参考
registerDocumentHighlightProvider DocumentHighlight
registerDocumentSymbolProvider DocumentSymbol
registerCodeActionsProvider CodeAction
registerCodeLensProvider CodeLens & CodeLens Resolve
registerDocumentLinkProvider DocumentLink & DocumentLink Resolve
registerColorProvider DocumentColor & Color Presentation
registerDocumentFormattingEditProvider 格式化
registerDocumentRangeFormattingEditProvider 范围格式化
registerOnTypeFormattingEditProvider OnTypeFormatting
registerRenameProvider 重命名 & 准备重命名
registerFoldingRangeProvider FoldingRange

提供诊断

诊断是一种指示代码问题的方法。

Diagnostics indicating a misspelled method name

语言服务器协议

您的语言服务器向语言客户端发送 textDocument/publishDiagnostics 消息。该消息携带一个资源 URI 的诊断项数组。

注意:客户端不会向服务器请求诊断。服务器将诊断信息推送给客户端。

直接实现

let diagnosticCollection: vscode.DiagnosticCollection;

export function activate(ctx: vscode.ExtensionContext): void {
  ...
  ctx.subscriptions.push(getDisposable());
  diagnosticCollection = vscode.languages.createDiagnosticCollection('go');
  ctx.subscriptions.push(diagnosticCollection);
  ...
}

function onChange() {
  let uri = document.uri;
  check(uri.fsPath, goConfig).then(errors => {
    diagnosticCollection.clear();
    let diagnosticMap: Map<string, vscode.Diagnostic[]> = new Map();
    errors.forEach(error => {
      let canonicalFile = vscode.Uri.file(error.file).toString();
      let range = new vscode.Range(error.line-1, error.startColumn, error.line-1, error.endColumn);
      let diagnostics = diagnosticMap.get(canonicalFile);
      if (!diagnostics) { diagnostics = []; }
      diagnostics.push(new vscode.Diagnostic(range, error.msg, error.severity));
      diagnosticMap.set(canonicalFile, diagnostics);
    });
    diagnosticMap.forEach((diags, file) => {
      diagnosticCollection.set(vscode.Uri.parse(file), diags);
    });
  })
}

基本

报告打开的编辑器的诊断信息。至少,这需要在每次保存时发生。更好的是,应基于编辑器的未保存内容计算诊断信息。

高级

不仅报告打开的编辑器的诊断信息,还报告打开的文件夹中的所有资源的诊断信息,无论它们是否在编辑器中打开过。

显示代码补全建议

代码补全为用户提供上下文相关的建议。

Code Completion prompting variable, method, and parameter names while writing code

语言服务器协议

在对 initialize 方法的响应中,您的语言服务器需要声明它提供补全,以及它是否支持 completionItem\resolve 方法,以便为计算的补全项提供其他信息。

{
    ...
    "capabilities" : {
        "completionProvider" : {
            "resolveProvider": "true",
            "triggerCharacters": [ '.' ]
        }
        ...
    }
}

直接实现

class GoCompletionItemProvider implements vscode.CompletionItemProvider {
    public provideCompletionItems(
        document: vscode.TextDocument, position: vscode.Position, token: vscode.CancellationToken):
        Thenable<vscode.CompletionItem[]> {
    ...
    }
}

export function activate(ctx: vscode.ExtensionContext): void {
    ...
    ctx.subscriptions.push(getDisposable());
    ctx.subscriptions.push(
        vscode.languages.registerCompletionItemProvider(
            GO_MODE, new GoCompletionItemProvider(), '.', '\"'));
    ...
}

基本

您不支持解析提供程序。

高级

您支持解析提供程序,这些提供程序会计算用户选择的补全建议的其他信息。此信息会与所选项目一起显示。

显示悬停

悬停显示鼠标光标下方符号/对象的相关信息。这通常是符号的类型和描述。

Showing details about a workspace and a method when hovering over them

语言服务器协议

在对 initialize 方法的响应中,您的语言服务器需要声明它提供悬停。

{
    ...
    "capabilities" : {
        "hoverProvider" : "true",
        ...
    }
}

此外,您的语言服务器需要响应 textDocument/hover 请求。

直接实现

class GoHoverProvider implements HoverProvider {
    public provideHover(
        document: TextDocument, position: Position, token: CancellationToken):
        Thenable<Hover> {
    ...
    }
}

export function activate(ctx: vscode.ExtensionContext): void {
    ...
    ctx.subscriptions.push(
        vscode.languages.registerHoverProvider(
            GO_MODE, new GoHoverProvider()));
    ...
}

基本

显示类型信息,并在可用时包括文档。

高级

以与您对代码进行着色相同的样式对方法签名进行着色。

帮助处理函数和方法签名

当用户输入函数或方法时,显示有关正在调用的函数/方法的信息。

Showing information about the getPackageInfo method including the necessary parameters

语言服务器协议

在对 initialize 方法的响应中,您的语言服务器需要声明它提供签名帮助。

{
    ...
    "capabilities" : {
        "signatureHelpProvider" : {
            "triggerCharacters": [ '(' ]
        }
        ...
    }
}

此外,您的语言服务器需要响应 textDocument/signatureHelp 请求。

直接实现

class GoSignatureHelpProvider implements SignatureHelpProvider {
    public provideSignatureHelp(
        document: TextDocument, position: Position, token: CancellationToken):
        Promise<SignatureHelp> {
    ...
    }
}

export function activate(ctx: vscode.ExtensionContext): void {
    ...
    ctx.subscriptions.push(
        vscode.languages.registerSignatureHelpProvider(
            GO_MODE, new GoSignatureHelpProvider(), '(', ','));
    ...
}

基本

确保签名帮助包含函数或方法的参数的文档。

高级

没有其他内容。

显示符号的定义

允许用户查看正在使用的变量/函数/方法的定义。

Right click a variable, function, or method and select "Go to Definition" to jump to the definition

语言服务器协议

在对 initialize 方法的响应中,您的语言服务器需要声明它提供转到定义位置。

{
    ...
    "capabilities" : {
        "definitionProvider" : "true"
        ...
    }
}

此外,您的语言服务器需要响应 textDocument/definition 请求。

直接实现

class GoDefinitionProvider implements vscode.DefinitionProvider {
    public provideDefinition(
        document: vscode.TextDocument, position: vscode.Position, token: vscode.CancellationToken):
        Thenable<vscode.Location> {
    ...
    }
}

export function activate(ctx: vscode.ExtensionContext): void {
    ...
    ctx.subscriptions.push(
        vscode.languages.registerDefinitionProvider(
            GO_MODE, new GoDefinitionProvider()));
    ...
}

基本

如果一个符号是模棱两可的,您可以显示多个定义。

高级

没有其他内容。

查找符号的所有引用

允许用户查看正在使用某个变量/函数/方法/符号的所有源代码位置。

Right clicking and selecting "Find All References" to highlight all the locations where that symbol is used

语言服务器协议

在对 initialize 方法的响应中,您的语言服务器需要声明它提供符号引用位置。

{
    ...
    "capabilities" : {
        "referencesProvider" : "true"
        ...
    }
}

此外,您的语言服务器需要响应 textDocument/references 请求。

直接实现

class GoReferenceProvider implements vscode.ReferenceProvider {
    public provideReferences(
        document: vscode.TextDocument, position: vscode.Position,
        options: { includeDeclaration: boolean }, token: vscode.CancellationToken):
        Thenable<vscode.Location[]> {
    ...
    }
}

export function activate(ctx: vscode.ExtensionContext): void {
    ...
    ctx.subscriptions.push(
        vscode.languages.registerReferenceProvider(
            GO_MODE, new GoReferenceProvider()));
    ...
}

基本

返回所有引用的位置(资源 URI 和范围)。

高级

没有其他内容。

高亮显示文档中符号的所有出现

允许用户查看打开的编辑器中符号的所有出现。

Select a symbol to highlight all occurrences

语言服务器协议

在对 initialize 方法的响应中,您的语言服务器需要声明它提供符号文档位置。

{
    ...
    "capabilities" : {
        "documentHighlightProvider" : "true"
        ...
    }
}

此外,您的语言服务器需要响应 textDocument/documentHighlight 请求。

直接实现

class GoDocumentHighlightProvider implements vscode.DocumentHighlightProvider {
    public provideDocumentHighlights(
        document: vscode.TextDocument, position: vscode.Position, token: vscode.CancellationToken):
        vscode.DocumentHighlight[] | Thenable<vscode.DocumentHighlight[]>;
    ...
    }
}

export function activate(ctx: vscode.ExtensionContext): void {
    ...
    ctx.subscriptions.push(
        vscode.languages.registerDocumentHighlightProvider(
            GO_MODE, new GoDocumentHighlightProvider()));
    ...
}

基本

您返回编辑器文档中找到引用的范围。

高级

没有其他内容。

显示文档中所有符号定义

允许用户快速导航到打开的编辑器中的任何符号定义。

Navigate to a symbol definition in the open editor using @

语言服务器协议

在对 initialize 方法的响应中,您的语言服务器需要声明它提供符号文档位置。

{
    ...
    "capabilities" : {
        "documentSymbolProvider" : "true"
        ...
    }
}

此外,您的语言服务器需要响应 textDocument/documentSymbol 请求。

直接实现

class GoDocumentSymbolProvider implements vscode.DocumentSymbolProvider {
    public provideDocumentSymbols(
        document: vscode.TextDocument, token: vscode.CancellationToken):
        Thenable<vscode.SymbolInformation[]> {
    ...
    }
}

export function activate(ctx: vscode.ExtensionContext): void {
    ...
    ctx.subscriptions.push(
        vscode.languages.registerDocumentSymbolProvider(
            GO_MODE, new GoDocumentSymbolProvider()));
    ...
}

基本

返回文档中的所有符号。定义符号的种类,如变量、函数、类、方法等。

高级

没有其他内容。

显示文件夹中的所有符号定义

允许用户快速导航到 VS Code 中打开的文件夹(工作区)中任何位置的符号定义。

Navigate to symbol definitions in the workspace using #

语言服务器协议

在对 initialize 方法的响应中,您的语言服务器需要声明它提供全局符号位置。

{
    ...
    "capabilities" : {
        "workspaceSymbolProvider" : "true"
        ...
    }
}

此外,您的语言服务器需要响应 workspace/symbol 请求。

直接实现

class GoWorkspaceSymbolProvider implements vscode.WorkspaceSymbolProvider {
    public provideWorkspaceSymbols(
        query: string, token: vscode.CancellationToken):
        Thenable<vscode.SymbolInformation[]> {
    ...
    }
}

export function activate(ctx: vscode.ExtensionContext): void {
    ...
    ctx.subscriptions.push(
        vscode.languages.registerWorkspaceSymbolProvider(
            new GoWorkspaceSymbolProvider()));
    ...
}

基本

返回打开的文件夹中源代码定义的所有符号。定义符号的种类,如变量、函数、类、方法等。

高级

没有其他内容。

错误或警告的可能操作

在错误或警告旁边为用户提供可能的纠正操作。如果存在可用的操作,则错误或警告旁边会显示一个灯泡。当用户单击灯泡时,会显示可用代码操作的列表。

Selecting a light bulb to view a list of available Code Actions

语言服务器协议

在对 initialize 方法的响应中,您的语言服务器需要声明它提供代码操作。

{
    ...
    "capabilities" : {
        "codeActionProvider" : "true"
        ...
    }
}

此外,您的语言服务器需要响应 textDocument/codeAction 请求。

直接实现

class GoCodeActionProvider implements vscode.CodeActionProvider<vscode.CodeAction> {
    public provideCodeActions(
        document: vscode.TextDocument, range: vscode.Range | vscode.Selection,
        context: vscode.CodeActionContext, token: vscode.CancellationToken):
        Thenable<vscode.CodeAction[]> {
    ...
    }
}

export function activate(ctx: vscode.ExtensionContext): void {
    ...
    ctx.subscriptions.push(
        vscode.languages.registerCodeActionsProvider(
            GO_MODE, new GoCodeActionProvider()));
    ...
}

基本

提供用于纠正错误/警告操作的代码操作。

高级

此外,还提供源代码操作(如重构)。例如,“提取方法”。

CodeLens - 在源代码中显示可操作的上下文信息

为用户提供可操作的、与上下文相关的信息,这些信息会穿插在源代码中显示。

CodeLens providing context

语言服务器协议

在对 initialize 方法的响应中,你的语言服务器需要声明它提供 CodeLens 结果,以及是否支持 codeLens\resolve 方法将 CodeLens 绑定到其命令。

{
    ...
    "capabilities" : {
        "codeLensProvider" : {
            "resolveProvider": "true"
        }
        ...
    }
}

此外,你的语言服务器需要响应 textDocument/codeLens 请求。

直接实现

class GoCodeLensProvider implements vscode.CodeLensProvider {
    public provideCodeLenses(document: TextDocument, token: CancellationToken):
        CodeLens[] | Thenable<CodeLens[]> {
    ...
    }

    public resolveCodeLens?(codeLens: CodeLens, token: CancellationToken):
         CodeLens | Thenable<CodeLens> {
    ...
    }
}

export function activate(ctx: vscode.ExtensionContext): void {
    ...
    ctx.subscriptions.push(
        vscode.languages.registerCodeLensProvider(
            GO_MODE, new GoCodeLensProvider()));
    ...
}

基本

定义可用于文档的 CodeLens 结果。

高级

通过响应 codeLens/resolve 将 CodeLens 结果绑定到命令。

显示颜色装饰器

允许用户预览和修改文档中的颜色。

Showing the color picker

语言服务器协议

在对 initialize 方法的响应中,你的语言服务器需要声明它提供颜色信息。

{
    ...
    "capabilities" : {
        "colorProvider" : "true"
        ...
    }
}

此外,你的语言服务器需要响应 textDocument/documentColortextDocument/colorPresentation 请求。

直接实现

class GoColorProvider implements vscode.DocumentColorProvider {
    public provideDocumentColors(
        document: vscode.TextDocument, token: vscode.CancellationToken):
        Thenable<vscode.ColorInformation[]> {
    ...
    }
    public provideColorPresentations(
        color: Color, context: { document: TextDocument, range: Range }, token: vscode.CancellationToken):
        Thenable<vscode.ColorPresentation[]> {
    ...
    }
}

export function activate(ctx: vscode.ExtensionContext): void {
    ...
    ctx.subscriptions.push(
        vscode.languages.registerColorProvider(
            GO_MODE, new GoColorProvider()));
    ...
}

基本

返回文档中的所有颜色引用。为支持的颜色格式(例如 rgb(...), hsl(...))提供颜色表示。

高级

没有其他内容。

在编辑器中格式化源代码

为用户提供格式化整个文档的支持。

Right click and select format code

语言服务器协议

在对 initialize 方法的响应中,你的语言服务器需要声明它提供文档格式化。

{
    ...
    "capabilities" : {
        "documentFormattingProvider" : "true"
        ...
    }
}

此外,你的语言服务器需要响应 textDocument/formatting 请求。

直接实现

class GoDocumentFormatter implements vscode.DocumentFormattingEditProvider {
    provideDocumentFormattingEdits(
        document: vscode.TextDocument, options: vscode.FormattingOptions, token: vscode.CancellationToken)
        : vscode.ProviderResult<vscode.TextEdit[]> {
    ...
    }
}

export function activate(ctx: vscode.ExtensionContext): void {
    ...
    ctx.subscriptions.push(
        vscode.languages.registerDocumentFormattingEditProvider(
            GO_MODE, new GoDocumentFormatter()));
    ...
}

基本

不提供格式化支持。

高级

你应该始终返回导致源代码被格式化的最小文本编辑。这对于确保诸如诊断结果之类的标记被正确调整并且不会丢失至关重要。

格式化编辑器中选定的行

为用户提供格式化文档中选定行范围的支持。

Select lines, right click, and select format code

语言服务器协议

在对 initialize 方法的响应中,你的语言服务器需要声明它提供对行范围的格式化支持。

{
    ...
    "capabilities" : {
        "documentRangeFormattingProvider" : "true"
        ...
    }
}

此外,你的语言服务器需要响应 textDocument/rangeFormatting 请求。

直接实现

class GoDocumentRangeFormatter implements vscode.DocumentRangeFormattingEditProvider{
    public provideDocumentRangeFormattingEdits(
        document: vscode.TextDocument, range: vscode.Range,
        options: vscode.FormattingOptions, token: vscode.CancellationToken):
        vscode.ProviderResult<vscode.TextEdit[]> {
    ...
    }
}

export function activate(ctx: vscode.ExtensionContext): void {
    ...
    ctx.subscriptions.push(
        vscode.languages.registerDocumentRangeFormattingEditProvider(
            GO_MODE, new GoDocumentRangeFormatter()));
    ...
}

基本

不提供格式化支持。

高级

你应该始终返回导致源代码被格式化的最小文本编辑。这对于确保诸如诊断结果之类的标记被正确调整并且不会丢失至关重要。

在用户键入时增量格式化代码

为用户提供在键入时格式化文本的支持。

注意:用户设置 editor.formatOnType 控制在用户键入时是否格式化源代码。

Visual indicators for formatting as code is typed

语言服务器协议

在对 initialize 方法的响应中,你的语言服务器需要声明它提供在用户键入时进行格式化的功能。它还需要告知客户端应在哪些字符上触发格式化。 moreTriggerCharacters 是可选的。

{
    ...
    "capabilities" : {
        "documentOnTypeFormattingProvider" : {
            "firstTriggerCharacter": "}",
            "moreTriggerCharacter": [";", ","]
        }
        ...
    }
}

此外,你的语言服务器需要响应 textDocument/onTypeFormatting 请求。

直接实现

class GoOnTypingFormatter implements vscode.OnTypeFormattingEditProvider{
    public provideOnTypeFormattingEdits(
        document: vscode.TextDocument, position: vscode.Position,
        ch: string, options: vscode.FormattingOptions, token: vscode.CancellationToken):
        vscode.ProviderResult<vscode.TextEdit[]> {
    ...
    }
}

export function activate(ctx: vscode.ExtensionContext): void {
    ...
    ctx.subscriptions.push(
        vscode.languages.registerOnTypeFormattingEditProvider(
            GO_MODE, new GoOnTypingFormatter()));
    ...
}

基本

不提供格式化支持。

高级

你应该始终返回导致源代码被格式化的最小文本编辑。这对于确保诸如诊断结果之类的标记被正确调整并且不会丢失至关重要。

重命名符号

允许用户重命名符号并更新对该符号的所有引用。

Rename a symbol and update all references to the new name

语言服务器协议

在对 initialize 方法的响应中,你的语言服务器需要声明它提供重命名功能。

{
    ...
    "capabilities" : {
        "renameProvider" : "true"
        ...
    }
}

此外,你的语言服务器需要响应 textDocument/rename 请求。

直接实现

class GoRenameProvider implements vscode.RenameProvider {
    public provideRenameEdits(
        document: vscode.TextDocument, position: vscode.Position,
        newName: string, token: vscode.CancellationToken):
        Thenable<vscode.WorkspaceEdit> {
    ...
    }
}

export function activate(ctx: vscode.ExtensionContext): void {
    ...
    ctx.subscriptions.push(
        vscode.languages.registerRenameProvider(
            GO_MODE, new GoRenameProvider()));
    ...
}

基本

不提供重命名支持。

高级

返回需要执行的所有工作区编辑的列表,例如所有文件中包含对该符号的引用的所有编辑。