VS Code插件命令篇

849 阅读3分钟

Commands

命令触发VS Code中的操作。插件可以使用命令向用户公开功能,绑定到VS Code UI中的操作,并实现内部逻辑。

VS Code包含大量内置命令,可用于与编辑器交互、控制用户界面或执行后台操作。许多插件还将其核心功能公开为用户和其他插件可利用的命令。

以编程方式执行命令

vscode.commands.executeCommandAPI以编程方式执行命令。这可以让你使用VS Code的内置功能,并构建在VS Code的内置Git和Markdown插件等插件之上。

例如,下面命令在当前活动文本编辑器中注释当前选定的行:

import * as vscode from 'vscode';

function commentLine() {
  vscode.commands.executeCommand('editor.action.addCommentLine');
}

此外,一些命令采用参数来控制其行为。命令也可以返回一个结果。例如,类似API的命令查询文档中给定位置的定义。它以文档URI和位置作为参数,并返回带有定义列表的Promise。

import * as vscode from 'vscode';

async function printDefinitionsForActiveEditor() {
  const activeEditor = vscode.window.activeTextEditor;
  if (!activeEditor) {
    return;
  }

  const definitions = await vscode.commands.executeCommand<vscode.Location[]>(
    'vscode.executeDefinitionProvider',
    activeEditor.document.uri,
    activeEditor.selection.active
  );

  for (const definition of definitions) {
    console.log(definition);
  }
}

内置命令

  • editor.action.addCommentLine 在当前活动文本编辑器中注释当前选定的行

code.visualstudio.com/api/referen…

命令Functions

code.visualstudio.com/api/referen…

  • executeCommand<T>(command: string, ...rest: any[]): Thenable<T> 执行一个命令

  • getCommands(filterInternal?: boolean): Thenable<string[]> 获取命令

  • registerCommand(command: string, callback: (args: any[]) => any, thisArg?: any): Disposable 注册一个命令,可以通过键盘快捷键、菜单项、操作或直接调用

  • registerTextEditorCommand(command: string, callback: (textEditor: TextEditor, edit: TextEditorEdit, args: any[]) => void, thisArg?: any): Disposable 注册一个文本编辑器命令,可以通过键盘快捷键、菜单项、操作或直接调用

命令URI

命令URI是执行给定命令的链接。它们可以用作悬停文本、完成项详细信息或网络式图内部的可点击链接。

命令URI使用后跟命令名称的方案。例如,这是一个悬停提供程序,它在活动文本编辑器中的当前行的注释中显示一个链接,点击这个链接会执行相应的命令URI。

import * as vscode from 'vscode';

export function activate(context: vscode.ExtensionContext) {
  vscode.languages.registerHoverProvider(
    'javascript',
    new (class implements vscode.HoverProvider {
      provideHover(
        _document: vscode.TextDocument,
        _position: vscode.Position,
        _token: vscode.CancellationToken
      ): vscode.ProviderResult<vscode.Hover> {
        // 命令URI
        const commentCommandUri = vscode.Uri.parse(`command:editor.action.addCommentLine`);
        const contents = new vscode.MarkdownString(`[Add comment](${commentCommandUri})`);
     
        // 要在Markdown内容中启用命令URI,必须设置isTrusted标志,
        //当创建可信的Markdown字符串时,确保正确清理所有输入内容,以便只执行预期的命令URI
        contents.isTrusted = true;

        return new vscode.Hover(contents);
      }
    })()
  );
}

Snipaste_2022-12-07_15-32-23.png

命令的参数列表作为已正确进行URI编码的JSON数组传递,例如,使用命令创建一个悬停链接来暂存当前文件:

import * as vscode from 'vscode';

export function activate(context: vscode.ExtensionContext) {
  vscode.languages.registerHoverProvider(
    'javascript',
    new (class implements vscode.HoverProvider {
      provideHover(
        document: vscode.TextDocument,
        _position: vscode.Position,
        _token: vscode.CancellationToken
      ): vscode.ProviderResult<vscode.Hover> {
        //命令参数列表,需结合JSON.stringify以及encodeURIComponent使用
        const args = [{ resourceUri: document.uri }];
        const stageCommandUri = vscode.Uri.parse(
          `command:git.stage?${encodeURIComponent(JSON.stringify(args))}`
        );
        const contents = new vscode.MarkdownString(`[Stage file](${stageCommandUri})`);
        contents.isTrusted = true;
        return new vscode.Hover(contents);
      }
    })()
  );
}

Snipaste_2022-12-07_16-21-26.png

创建新命令

注册命令

vscode.commands.registerCommand将命令ID绑定到插件中的处理函数:


import * as vscode from 'vscode';

export function activate(context: vscode.ExtensionContext) {

    // The command has been defined in the package.json file
    // Now provide the implementation of the command with registerCommand
    // The commandId parameter must match the command field in package.json
    vscode.commands.registerCommand('extension.helloWorld', () => {
        // The code you place here will be executed every time your command is executed
        // Display a message box to the user                                   
        vscode.window.showInformationMessage('Hello World!');
    });
}

创建面向用户的命令

vscode.commands.registerCommand仅将命令ID绑定到处理函数。要在命令面板中公开此命令以便用户可以发现它,您还需要在插件程序的package.json中添加相应的命令。

此时,如果用户从命令面板选择命令,但我们的插件尚未激活,则VS Code不会发生任何操作。为了防止这种情况,插件必须为所有面向用户注册命令registerCommand extension.helloWorld onCommand activationEvent

注意,调用命令时(从键绑定、命令面板、任何其他菜单或以编程方式),VS Code将发出activationEvent onCommand:${command}

{
  "activationEvents": [
    "onCommand:extension.helloWorld"
  ],
  "contributes": {
    "commands": [
      {
        "command": "extension.helloWorld",
        "title": "Hello World"        
        "category": "Hello",
        "icon": {
           "light": "path/to/light/icon.svg",
           "dark": "path/to/dark/icon.svg"
        }
      }
    ],
  }
}

demo.gif

此外,可以为命令提供UI,包含title、可选图标icon、类别category、启用状态enabled。命令的显示取决于包含的菜单。

命令面板为命令加上它们的类别作为前缀,便于分组。但是,命令面板不显示图标,也不显示禁用的命令。另外,编辑器上下文菜单显示禁用的命令,但不显示类别标签

注意,使用产品图标中的图标时,设置lightdark会禁用图标,正确的语法是"icon": "$(book)"

命令icon规格包括:

  • Size 推荐16*16像素大小,留1像素padding,即图像14*14
  • Color 推荐使用单种颜色
  • Format 推荐使用svg格式

image.png

控制命令何时出现在命令面板中

默认情况下,所有面向用户的命令都是通过显示在命令面板中的部分提供的。但是,许多命令仅在某些情况下才相关,例如,当存在给定语言的活动文本编辑器时或当用户具有特定配置选项时。

contributes中的menus.commandPalette可以让你限制命令何时应显示在命令面板中。它使用目标命令的ID和控制何时显示命令的when子句,例如,下面代码只有在编辑javascript文件时才会出现helloWorld菜单:

{
  "contributes": {
    "menus": {
      "commandPalette": [
         {
           "command": "extension.helloWorld",
           "when": "editorLangId == javascript"
         }
      ],
    }
  }
}

使用自定义when子句上下文

如果你正在编写自己的VS Code插件,并且需要使用子句上下文来启用/禁用命令、菜单或视图,而现有的键都不适合你的需要,那么你可以添加自己的上下文。

vscode.commands.executeCommand('setContext', 'myExtension.showMyCommand', true);

vscode.commands.executeCommand('setContext', 'myExtension.numberOfCoolOpenThings', 4);

更多when子句上下文,参考code.visualstudio.com/api/referen…