本站点文档内容均翻译自code.visualstudio.com,仅供个人学习,如有差异请以官网为准。

任务提供者

用户通常在Visual Studio Code中定义任务.json 文件。然而,在软件开发过程中有一些任务可以通过VS Code扩展(Task Provider)自动检测。当运行任务:运行任务命令时,VS Code会从所有活跃的任务提供者中贡献任务,用户可以运行这些任务。当任务.json文件允许用户为特定文件夹或工作区手动定义一个任务,任务提供程序可以检测有关工作区的详细信息,然后自动创建相应的 VS Code 任务。例如,任务提供程序可以检查是否有特定的构建文件,例如制作Rakefile,并创建一个构建任务。本主题描述了扩展如何自动检测并为最终用户提供任务。

本指南将教您如何构建一个任务提供程序,该提供程序可以自动检测在Rakefiles中定义的任务。完整的源代码位于:https://github.com/microsoft/vscode-extension-samples/tree/main/task-provider-sample

任务定义

为了在系统中唯一标识一个任务,一个扩展贡献一个任务需要定义标识任务的属性。在Rake示例中,任务定义如下:

"taskDefinitions": [
    {
        "type": "rake",
        "required": [
            "task"
        ],
        "properties": {
            "task": {
                "type": "string",
                "description": "The Rake task to customize"
            },
            "file": {
                "type": "string",
                "description": "The Rake file that provides the task. Can be omitted."
            }
        }
    }
]

这为……贡献了一个任务定义耙子任务。任务定义有两个属性任务文件任务是Rake任务的名称,并且文件指向Rakefile包含该任务。任务属性是必需的,文件属性是可选的。如果文件如果属性被省略,Rakefile在工作区文件夹的根目录中使用。

当子句

任务定义可以可选地有一个财产。属性指定了在这种类型的任务可用的条件。 属性在相同的方式下工作 和其他地方在 VS Code 中一样,那里有一个 属性。在创建任务定义时,应始终考虑以下上下文:

  • 外壳执行支持: 当 VS Code 可以运行时为真外壳执行任务,例如当 VS Code 作为桌面应用程序运行时或使用其中一个远程扩展(例如 Dev Containers)时。
  • 流程执行受支持: 当 VS Code 可以运行时为真进程执行任务,例如当 VS Code 作为桌面应用程序运行时或使用其中一个远程扩展(例如 Dev Containers)时。目前,它的值将始终与外壳执行支持输入:.
  • 自定义执行支持: 当 VS Code 可以运行时为真定制执行这是永远正确的。

任务提供者

类似于语言提供者允许扩展支持代码补全,一个扩展可以注册一个任务提供者来计算所有可用的任务。这是通过使用vscode.tasks命名空间如以下代码片段所示:

导入 * vscode 来自 'vscode';

let rakePromise: Thenable<vscode.Task[]> | undefined = undefined;
const taskProvider = vscode.tasks.registerTaskProvider('rake', {
  provideTasks: () => {
    if (!rakePromise) {
      rakePromise = getRakeTasks();
    }
    return rakePromise;
  },
  resolveTask(_task: vscode.Task): vscode.Task | undefined {
    const task = _task.definition.task;
    // A Rake task consists of a task and an optional file as specified in RakeTaskDefinition
    // Make sure that this looks like a Rake task by checking that there is a task.
    if (task) {
      // resolveTask requires that the same definition object be used.
      const definition: RakeTaskDefinition = <any>_task.定义;
      返回 vscode.任务(
        定义,
        _任务.作用域??vscode.任务作用域.工作区,
        定义.任务,
        'rake',
 vscode.壳执行('rake ${定义.任务}')
      );
    }
    返回 未定义;
  }
});

喜欢提供任务, ,解决任务方法被 VS Code 调用来获取扩展的任务。解决任务可以调用而不是提供任务,并且旨在为实现它的提供者提供可选的性能提升。例如,如果用户有一个运行扩展任务的键绑定,那么VS Code调用解决任务对于那个任务提供者,直接快速获取一个任务,而不是必须调用提供任务并等待扩展提供所有任务。允许用户关闭单独的任务提供者是一个良好的实践,因此这是常见的。用户可能会注意到来自特定提供者的任务获取速度较慢,并关闭该提供者。在这种情况下,用户可能仍然在其 中引用该提供者的一些任务。任务.json如果解决任务未实现,则会警告该任务在他们的任务.json未创建。使用解决任务一个扩展仍然可以为在中定义的任务提供一个任务任务.json输入:.

获取构建任务实现执行以下操作:

  • 列出在a中定义的所有rake任务Rakefile使用rake -AT -f Rakefile每个工作区文件夹的命令。
  • 解析stdio输出。
  • 对于每个列出的任务,创建一个vscode.任务实施。

由于一个Rake任务实例化需要一个如上所述的任务定义package.json文件,VS Code 也使用 TypeScript 接口来定义结构,如下所示:

接口 RakeTaskDefinition 扩展 vscode.TaskDefinition {
  /**
   * 任务名称
   */
  task: 字符串;

  /**
   * 包含任务的rake文件
   */
  文件?: 字符串;
}

假设输出来自一个名为的任务编译在第一个工作区文件夹中,相应的任务创建如下所示:

 任务 = 新的 vscode.任务(
  { 类型: 'rake', 任务: 'compile' },
  vscode.工作区.工作区文件夹[0],
  'compile',
  'rake',
  新的 vscode.Shell执行('rake compile')
);

对于输出中列出的每个任务,使用上述模式创建一个对应的 VS Code 任务,然后返回所有任务的数组获取构建任务呼叫。

外壳执行执行rake compile在特定操作系统下执行的 shell 命令(例如在 Windows 下命令会在 PowerShell 中执行,在 Ubuntu 下则会在 bash 中执行)。如果任务应该直接执行一个进程(而不是启动一个 shell),vscode.进程执行可以使用。进程执行具有优势,扩展对传递给进程的参数具有完全控制权。使用外壳执行使用了 shell 命令解释(如在 bash 下的通配符扩展)。如果外壳执行通过一个命令行创建,那么扩展需要确保在命令内部进行正确的引号和转义(例如处理空白字符)。

定制执行

通常情况下,最好使用一个外壳执行进程执行因为它们很简单。然而,如果您的任务需要在运行之间保存大量状态、无法很好地作为一个单独的脚本或进程运行,或者需要对输出进行大量处理,则不适用。定制执行可能是一个很好的匹配。现有用途定制执行通常用于复杂的构建系统。A定制执行只有一个回调函数,该函数在任务运行时执行。这使得任务可以执行更多的操作,但也意味着任务提供者需要负责任何需要进行的过程管理和输出解析。任务提供者还需要负责实现伪终端并将其返回定制执行回调。

return new vscode.Task(
  definition,
  vscode.TaskScope.Workspace,
  `${flavor} ${flags.join(' ')}`,
  CustomBuildTaskProvider.CustomBuildScriptType,
  new vscode.CustomExecution(
    async (): Promise<vscode.Pseudoterminal> => {
      // 当任务执行时,此回调将运行。在这里,我们设置运行任务。
      return new CustomBuildTaskTerminal(
        this.workspaceRoot,
        flavor,
        flags,
        () => this.sharedState,
        (state: string) => (this.sharedState = state)
      );
    }
  )
);

完整的示例,包括实现伪终端https://github.com/microsoft/vscode-extension-samples/tree/main/task-provider-sample/src/customTaskProvider.ts