通过任务集成外部工具

存在许多用于自动化任务(如代码检查、构建、打包、测试或部署软件系统)的工具。例如 TypeScript 编译器,像 ESLintTSLint 这样的代码检查工具,以及像 MakeAntGulpJakeRakeMSBuild 这样的构建系统。

VS Code can talk to a variety of external tools

这些工具大多从命令行运行,并自动化软件开发循环(编辑、编译、测试和调试)内外的作业。鉴于它们在开发生命周期中的重要性,能够在 VS Code 中运行工具并分析其结果是非常有帮助的。VS Code 中的任务可以配置为运行脚本和启动进程,这样许多现有的工具就可以在 VS Code 内部使用,而无需输入命令行或编写新代码。工作区或文件夹特定的任务在工作区 .vscode 文件夹中的 tasks.json 文件中进行配置。

扩展程序还可以使用 任务提供程序 (Task Provider) 提供任务,这些提供的任务可以添加在 tasks.json 文件中定义的工作区特定配置。

注意: 任务支持仅在使用工作区文件夹时可用。在编辑单个文件时不可用。

TypeScript Hello World

让我们从一个简单的“Hello World” TypeScript 程序开始,我们希望将其编译为 JavaScript。

创建一个空文件夹 "mytask",生成一个 tsconfig.json 文件,并从该文件夹启动 VS Code。

mkdir mytask
cd mytask
tsc --init
code .

现在创建一个内容如下的 HelloWorld.ts 文件

function sayHello(name: string): void {
  console.log(`Hello ${name}!`);
}

sayHello('Dave');

按下 ⇧⌘B (Windows, Linux Ctrl+Shift+B) 或从全局 终端 菜单运行 运行构建任务 (Run Build Task),将显示以下选择器

TypeScript Build Task

第一个条目执行 TypeScript 编译器并将 TypeScript 文件转换为 JavaScript 文件。当编译器完成后,应该会有一个 HelloWorld.js 文件。第二个条目以监视模式启动 TypeScript 编译器。每次保存 HelloWorld.ts 文件时,都会重新生成 HelloWorld.js 文件。

您还可以将 TypeScript 构建或监视任务定义为默认构建任务,以便在触发 运行构建任务 (⇧⌘B (Windows, Linux Ctrl+Shift+B)) 时直接执行它。为此,请从全局 终端 菜单中选择 配置默认构建任务 (Configure Default Build Task)。这将向您显示一个包含可用构建任务的选择器。选择 tsc: buildtsc: watch,VS Code 将生成一个 tasks.json 文件。如下所示,它将 tsc: build 任务设为默认构建任务

{
  // See https://go.microsoft.com/fwlink/?LinkId=733558
  // for the documentation about the tasks.json format
  "version": "2.0.0",
  "tasks": [
    {
      "type": "typescript",
      "tsconfig": "tsconfig.json",
      "problemMatcher": ["$tsc"],
      "group": {
        "kind": "build",
        "isDefault": true
      }
    }
  ]
}

上面的 tasks.json 示例没有定义新任务。它将 VS Code 的 TypeScript 扩展提供的 tsc: build 任务标记为默认构建任务。现在,您可以通过按下 ⇧⌘B (Windows, Linux Ctrl+Shift+B) 来执行 TypeScript 编译器。

任务自动检测

VS Code 目前会自动检测以下系统的任务:Gulp、Grunt、Jake 和 npm。我们正在与相应的扩展作者合作,增加对 Maven 和 C# dotnet 命令的支持。如果您使用 Node.js 作为运行时开发 JavaScript 应用程序,通常会有一个 package.json 文件,其中描述了您的依赖项和要运行的脚本。如果您克隆了 eslint-starter 示例,那么从全局菜单执行 运行任务 (Run Tasks) 将显示以下列表

Tasks ESLint starter

如果尚未执行此操作,请通过运行 npm install 安装必要的 npm 模块。现在打开 server.js 文件,并在语句末尾添加一个分号(注意 ESLint starter 假定语句末尾没有分号),然后再次执行 运行任务。这次选择 npm: lint 任务。当提示选择要使用的问题匹配器时,选择 ESLint stylish

Tasks ESLint Problem Matcher Selection

执行该任务会产生一个错误,显示在 问题 (Problems) 视图中

Tasks ESLint Problem

此外,VS Code 创建了一个内容如下的 tasks.json 文件

{
  // See https://go.microsoft.com/fwlink/?LinkId=733558
  // for the documentation about the tasks.json format
  "version": "2.0.0",
  "tasks": [
    {
      "type": "npm",
      "script": "lint",
      "problemMatcher": ["$eslint-stylish"]
    }
  ]
}

这指示 VS Code 使用 ESLint stylish 格式扫描 npm lint 脚本的输出以查找问题。

对于 Gulp、Grunt 和 Jake,任务自动检测的工作方式相同。以下是为 vscode-node-debug 扩展检测到的任务示例。

Gulp task auto-detection

提示: 您可以通过 快速打开 (Quick Open) (⌘P (Windows, Linux Ctrl+P)) 输入 'task'、空格 和命令名称来运行任务。在这种情况下,输入 'task lint'。

可以使用以下设置禁用任务自动检测

{
  "js/ts.tsc.autoDetect": "off",
  "grunt.autoDetect": "off",
  "jake.autoDetect": "off",
  "gulp.autoDetect": "off",
  "npm.autoDetect": "off"
}

自定义任务

工作区中并非所有任务或脚本都能自动检测到。有时需要定义自己的自定义任务。假设您有一个脚本来运行测试,以便正确设置某些环境。该脚本存储在工作区内的脚本文件夹中,在 Linux 和 macOS 上命名为 test.sh,在 Windows 上命名为 test.cmd。从全局 终端 菜单运行 配置任务 (Configure Tasks),并选择 从模板创建 tasks.json 文件 (Create tasks.json file from template) 条目。这将打开以下选择器

Configure Task Runner

注意: 如果您没有看到任务运行器模板列表,说明您的文件夹中可能已经有一个 tasks.json 文件,且其内容已在编辑器中打开。请关闭该文件,并为本示例删除或重命名它。

我们正在开发更多的自动检测支持,因此将来此列表会越来越小。由于我们要编写自己的自定义任务,请从列表中选择 Others。这将打开一个带有任务骨架的 tasks.json 文件。将其内容替换为以下内容

{
  // See https://go.microsoft.com/fwlink/?LinkId=733558
  // for the documentation about the tasks.json format
  "version": "2.0.0",
  "tasks": [
    {
      "label": "Run tests",
      "type": "shell",
      "command": "./scripts/test.sh",
      "windows": {
        "command": ".\\scripts\\test.cmd"
      },
      "group": "test",
      "presentation": {
        "reveal": "always",
        "panel": "new"
      }
    }
  ]
}

任务的属性具有以下语义

  • label:用户界面中使用的任务标签。
  • type:任务类型。对于自定义任务,可以是 shellprocess。如果指定了 shell,命令将被解释为 shell 命令(例如:bash、cmd 或 PowerShell)。如果指定了 process,命令将被解释为要执行的进程。
  • command:要执行的实际命令。
  • windows:任何 Windows 特定的属性。当命令在 Windows 操作系统上执行时,将代替默认属性使用。
  • group:定义任务所属的组。在示例中,它属于 test 组。属于测试组的任务可以通过运行 命令面板 (Command Palette) 中的 运行测试任务 (Run Test Task) 来执行。
  • presentation:定义在用户界面中如何处理任务输出。在此示例中,显示输出的集成终端总是被 always 显示,并且每次运行任务时都会创建一个 new 终端。
  • options:覆盖 cwd(当前工作目录)、env(环境变量)或 shell(默认 shell)的默认设置。选项可以按任务设置,也可以全局或按平台设置。此处配置的环境变量只能在您的任务脚本或进程中引用,如果它们是 args、command 或其他任务属性的一部分,则不会被解析。
  • runOptions:定义任务何时以及如何运行。
  • hide:在“运行任务”快速选择列表中隐藏该任务,这对复合任务中不可独立运行的元素非常有用。

您可以在 tasks.json 文件中使用 IntelliSense 查看完整的任务属性和值集。通过 触发建议 (Trigger Suggest) (⌃Space (Windows, Linux Ctrl+Space)) 调出建议,并悬停查看描述,或通过 阅读更多... ('i') 浮窗查看。

tasks.json IntelliSense

您还可以查阅 tasks.json 模式

当涉及包含空格或其他特殊字符(如 $)的命令和参数时,Shell 命令需要特殊处理。默认情况下,任务系统支持以下行为

  • 如果提供单个命令,任务系统将按原样将该命令传递给底层 shell。如果命令需要引号或转义才能正常工作,则命令需要包含正确的引号或转义字符。例如,要列出名称中包含空格的文件夹目录,在 bash 中执行的命令应如下所示:ls 'folder with spaces'
{
  "label": "dir",
  "type": "shell",
  "command": "dir 'folder with spaces'"
}
  • 如果提供了命令和参数,当命令或参数包含空格时,任务系统将使用单引号。对于 cmd.exe,使用双引号。如下所示的 shell 命令将在 PowerShell 中作为 dir 'folder with spaces' 执行。
{
  "label": "dir",
  "type": "shell",
  "command": "dir",
  "args": ["folder with spaces"]
}
  • 如果您想控制参数的引用方式,参数可以是一个指定值和引用样式的字面量。下面的示例对带有空格的参数使用了转义而不是引用。
{
  "label": "dir",
  "type": "shell",
  "command": "dir",
  "args": [
    {
      "value": "folder with spaces",
      "quoting": "escape"
    }
  ]
}

除了转义,还支持以下值

  • strong:使用 shell 的强引用机制,抑制字符串内的所有计算。在 PowerShell 以及 Linux 和 macOS 的 shell 下,使用单引号 (')。对于 cmd.exe,使用 "
  • weak:使用 shell 的弱引用机制,仍然计算字符串内的表达式(例如环境变量)。在 PowerShell 以及 Linux 和 macOS 的 shell 下,使用双引号 (")。cmd.exe 不支持弱引用,因此 VS Code 也使用 "

如果命令本身包含空格,VS Code 默认也会强引用该命令。与参数一样,用户可以使用相同的字面量样式控制命令的引用。

还有更多的任务属性可以配置您的工作流。您可以使用带有 ⌃Space (Windows, Linux Ctrl+Space) 的 IntelliSense 来获取有效属性的概述。

Tasks IntelliSense

除了全局菜单栏,还可以使用 命令面板 (Command Palette) (⇧⌘P (Windows, Linux Ctrl+Shift+P)) 访问任务命令。您可以筛选 'task' 并查看各种与任务相关的命令。

Tasks in Command Palette

复合任务

您还可以使用 dependsOn 属性从简单的任务中组合任务。例如,如果您有一个包含客户端和服务器文件夹的工作区,并且两者都包含构建脚本,则可以创建一个在单独的终端中启动两个构建脚本的任务。如果您在 dependsOn 属性中列出多个任务,它们默认会并行执行。

tasks.json 文件如下所示

{
  "version": "2.0.0",
  "tasks": [
    {
      "label": "Client Build",
      "command": "gulp",
      "args": ["build"],
      "options": {
        "cwd": "${workspaceFolder}/client"
      }
    },
    {
      "label": "Server Build",
      "command": "gulp",
      "args": ["build"],
      "options": {
        "cwd": "${workspaceFolder}/server"
      }
    },
    {
      "label": "Build",
      "dependsOn": ["Client Build", "Server Build"]
    }
  ]
}

如果指定了 "dependsOrder": "sequence",则您的任务依赖项将按照它们在 dependsOn 中列出的顺序执行。在 dependsOn 中使用 "dependsOrder": "sequence" 的任何后台/监视任务都必须有一个问题匹配器,用于跟踪它们何时“完成”。以下任务依次运行任务 Two、任务 Three,然后是任务 One。

{
  "label": "One",
  "type": "shell",
  "command": "echo Hello ",
  "dependsOrder": "sequence",
  "dependsOn": ["Two", "Three"]
}

用户级任务

您可以使用 任务: 打开用户任务 (Tasks: Open User Tasks) 命令创建不绑定到特定工作区或文件夹的用户级任务。由于其他任务类型需要工作区信息,因此此处只能使用 shellprocess 任务。

输出行为

有时您希望控制运行任务时集成终端面板的行为。例如,您可能希望最大化编辑器空间,仅在认为有问题时查看任务输出。终端的行为可以使用任务的 presentation 属性进行控制。它提供以下属性

  • reveal:控制集成终端面板是否被带到前台。有效值为
    • always - 面板总是被带到前台。这是默认值。
    • never - 用户必须使用 视图 (View) > 终端 (Terminal) 命令 (⌃` (Windows, Linux Ctrl+`)) 显式地将终端面板带到前台。
    • silent - 仅当输出未扫描错误和警告时,终端面板才会被带到前台。
  • revealProblems:控制运行此任务时是否显示“问题”面板。优先级高于 reveal 选项。默认为 never
    • always - 执行此任务时始终显示“问题”面板。
    • onProblem - 仅当发现问题时才显示“问题”面板。
    • never - 执行此任务时从不显示“问题”面板。
  • focus:控制终端是否获取输入焦点。默认为 false
  • echo:控制执行的命令是否在终端中回显。默认为 true
  • showReuseMessage:控制是否显示“终端将被任务重用,按任意键关闭它”的消息。
  • panel:控制终端实例是否在任务运行之间共享。可能的值为
    • shared - 终端被共享,其他任务运行的输出被添加到同一个终端中。
    • dedicated - 终端专用于特定任务。如果再次执行该任务,将重用终端。但是,不同任务的输出会显示在不同的终端中。
    • new - 该任务的每次执行都使用一个新的干净终端。
  • clear:控制运行此任务前是否清除终端。默认为 false
  • close:控制任务退出时,任务运行的终端是否关闭。默认为 false
  • group:控制任务是否使用拆分窗格在特定终端组中执行。同一组(由字符串值指定)中的任务将使用拆分终端来呈现,而不是使用新的终端面板。

您也可以修改自动检测到的任务的终端面板行为。例如,如果您想更改上述 ESLint 示例中 npm: run lint 的输出行为,请为其添加 presentation 属性

{
  // See https://go.microsoft.com/fwlink/?LinkId=733558
  // for the documentation about the tasks.json format
  "version": "2.0.0",
  "tasks": [
    {
      "type": "npm",
      "script": "lint",
      "problemMatcher": ["$eslint-stylish"],
      "presentation": {
        "reveal": "never"
      }
    }
  ]
}

您也可以将自定义任务与检测到的任务的配置混合使用。配置 npm: run lint 任务并添加自定义 Run Test 任务的 tasks.json 如下所示

{
  // See https://go.microsoft.com/fwlink/?LinkId=733558
  // for the documentation about the tasks.json format
  "version": "2.0.0",
  "tasks": [
    {
      "type": "npm",
      "script": "lint",
      "problemMatcher": ["$eslint-stylish"],
      "presentation": {
        "reveal": "never"
      }
    },
    {
      "label": "Run tests",
      "type": "shell",
      "command": "./scripts/test.sh",
      "windows": {
        "command": ".\\scripts\\test.cmd"
      },
      "group": "test",
      "presentation": {
        "reveal": "always",
        "panel": "new"
      }
    }
  ]
}

运行行为

您可以使用 runOptions 属性指定任务的运行行为

  • reevaluateOnRerun:控制通过 重新运行上次任务 (Rerun Last Task) 命令执行任务时如何评估变量。默认值为 true,意味着重新运行任务时将重新评估变量。设置为 false 时,将使用任务上一次运行中解析的变量值。

  • runOn:指定任务何时运行。

    • default - 任务仅在通过 运行任务 (Run Task) 命令执行时才会运行。
    • folderOpen:打开包含的文件夹时将运行任务。另请参阅如何 控制自动任务执行
  • instanceLimit:允许同时运行的任务实例数。默认值为 1

  • instancePolicy:确定当任务达到其 instanceLimit 时会发生什么。可以设置为

    • prompt - 提示用户终止哪个实例(默认)。
    • silent - 不启动新实例(静默)。
    • terminateNewest - 终止最新的运行实例。
    • terminateOldest - 终止最旧的运行实例。
    • warn - 不启动新实例(显示警告)。

控制自动任务执行

task.allowAutomaticTasks 在 VS Code 中打开 在 VS Code Insiders 中打开 设置控制在打开工作区时,是否允许 "runOn": "folderOpen" 的任务自动运行。无论此设置如何,自动任务都不会在 不受信任的工作区 中运行。

该设置接受两个值

  • off(默认):不运行自动任务。如果您尚未为当前工作区做出选择,系统会提示您一次 允许 (Allow)禁止 (Disallow) 自动任务。如果您选择 禁止(或显式将值设置为 off),任务将不会运行,也不会再次提示您。
  • on:打开受信任的工作区时始终运行自动任务,无需提示。

要配置该设置,请将其添加到您的用户或工作区设置中

{
  "task.allowAutomaticTasks": "off"
}

您还可以随时使用命令面板中的 任务: 管理自动任务 (Tasks: Manage Automatic Tasks) 命令来更改您的选择,并在当前工作区的 允许自动任务禁止自动任务 之间进行选择。

自定义自动检测到的任务

如上所述,您可以在 tasks.json 文件中自定义自动检测到的任务。您通常这样做是为了修改 presentation 属性或附加一个问题匹配器来扫描任务输出中的错误和警告。您可以通过按右侧的齿轮图标,将相应的任务引用插入到 tasks.json 文件中,直接从 运行任务 (Run Task) 列表中自定义任务。假设您有以下 Gulp 文件来使用 ESLint 检查 JavaScript 文件(文件取自 https://github.com/adametry/gulp-eslint

const gulp = require('gulp');
const eslint = require('gulp-eslint');

gulp.task('lint', () => {
  // ESLint ignores files with "node_modules" paths.
  // So, it's best to have gulp ignore the directory as well.
  // Also, Be sure to return the stream from the task;
  // Otherwise, the task may end before the stream has finished.
  return (
    gulp
      .src(['**/*.js', '!node_modules/**'])
      // eslint() attaches the lint output to the "eslint" property
      // of the file object so it can be used by other modules.
      .pipe(eslint())
      // eslint.format() outputs the lint results to the console.
      // Alternatively use eslint.formatEach() (see Docs).
      .pipe(eslint.format())
      // To have the process exit with an error code (1) on
      // lint error, return the stream and pipe to failAfterError last.
      .pipe(eslint.failAfterError())
  );
});

gulp.task('default', ['lint'], function() {
  // This will only run if the lint task is successful...
});

从全局 终端 菜单执行 运行任务 将显示以下选择器

Configure Task

按下齿轮图标。这将创建以下 tasks.json 文件

{
  // See https://go.microsoft.com/fwlink/?LinkId=733558
  // for the documentation about the tasks.json format
  "version": "2.0.0",
  "tasks": [
    {
      "type": "gulp",
      "task": "default",
      "problemMatcher": []
    }
  ]
}

通常,您现在会添加一个问题匹配器(本例中为 $eslint-stylish)或修改 presentation 设置。

使用问题匹配器处理任务输出

VS Code 可以使用问题匹配器处理来自任务的输出。问题匹配器会扫描任务输出文本中已知的警告或错误字符串,并将其内联报告在编辑器和“问题”面板中。VS Code 附带了几个“开箱即用”的问题匹配器

  • TypeScript: $tsc 假定输出中的文件名相对于打开的文件夹。
  • TypeScript Watch: $tsc-watch 匹配 tsc 编译器在监视模式下执行时报告的问题。
  • JSHint: $jshint 假定文件名以绝对路径报告。
  • JSHint Stylish: $jshint-stylish 假定文件名以绝对路径报告。
  • ESLint Compact: $eslint-compact 假定输出中的文件名相对于打开的文件夹。
  • ESLint Stylish: $eslint-stylish 假定输出中的文件名相对于打开的文件夹。
  • Go: $go 匹配 go 编译器报告的问题。假定文件名相对于打开的文件夹。
  • CSharp and VB Compiler: $mscompile 假定文件名以绝对路径报告。
  • Lessc compiler: $lessc 假定文件名以绝对路径报告。
  • Node Sass compiler: $node-sass 假定文件名以绝对路径报告。

您还可以创建自己的问题匹配器,我们将在 后续章节 中讨论。

为任务绑定键盘快捷键

如果您需要频繁运行某个任务,可以为该任务定义键盘快捷键。

例如,要将 Ctrl+H 绑定到上述 运行测试 (Run tests) 任务,请将以下内容添加到您的 keybindings.json 文件中

{
  "key": "ctrl+h",
  "command": "workbench.action.tasks.runTask",
  "args": "Run tests"
}

变量替换

编写任务配置时,拥有一组预定义的通用变量非常有用,例如活动文件 (${file}) 或工作区根文件夹 (${workspaceFolder})。VS Code 支持在 tasks.json 文件的字符串中进行变量替换,您可以在 变量参考 中看到预定义变量的完整列表。

注意: 并非所有属性都接受变量替换。具体来说,只有 commandargsoptions 支持变量替换。

以下是一个自定义任务配置示例,该配置将当前打开的文件传递给 TypeScript 编译器。

{
  "label": "TypeScript compile",
  "type": "shell",
  "command": "tsc ${file}",
  "problemMatcher": ["$tsc"]
}

同样,您可以通过在名称前加上 ${config: 来引用项目的配置设置。例如,${config:python.formatting.autopep8Path} 返回 Python 扩展设置 formatting.autopep8Path

以下是一个自定义任务配置示例,它使用 python.formatting.autopep8Path 设置定义的 autopep8 可执行文件在当前文件上执行 autopep8

{
  "label": "autopep8 current file",
  "type": "process",
  "command": "${config:python.formatting.autopep8Path}",
  "args": ["--in-place", "${file}"]
}

如果您想为 tasks.jsonlaunch.json 指定 Python 扩展使用的选定 Python 解释器,可以使用 ${command:python.interpreterPath} 命令。

如果简单的变量替换不够用,您还可以通过在 tasks.json 文件中添加 inputs 部分来获取任务用户的输入。

Inputs Example

有关 inputs 的更多信息,请参阅 变量参考

特定于操作系统的属性

任务系统支持为特定操作系统定义值(例如要执行的命令)。为此,请在 tasks.json 文件中放入一个特定于操作系统的字面量,并在该字面量内指定相应的属性。

以下是一个将 Node.js 可执行文件用作命令,并在 Windows 和 Linux 上进行不同处理的示例

{
  "label": "Run Node",
  "type": "process",
  "windows": {
    "command": "C:\\Program Files\\nodejs\\node.exe"
  },
  "linux": {
    "command": "/usr/bin/node"
  }
}

有效的操作系统属性是用于 Windows 的 windows、用于 Linux 的 linux 以及用于 macOS 的 osx。在特定于操作系统的范围内定义的属性会覆盖在任务或全局范围内定义的属性。

全局任务

任务属性也可以在全局范围内定义。如果存在,它们将用于特定任务,除非这些任务定义了具有不同值的相同属性。在下例中,有一个全局 presentation 属性,它定义了所有任务都应在新面板中执行

{
  // See https://go.microsoft.com/fwlink/?LinkId=733558
  // for the documentation about the tasks.json format
  "version": "2.0.0",
  "presentation": {
    "panel": "new"
  },
  "tasks": [
    {
      "label": "TS - Compile current file",
      "type": "shell",
      "command": "tsc ${file}",
      "problemMatcher": ["$tsc"]
    }
  ]
}

提示: 要访问全局范围的 tasks.json 文件,请打开命令面板 (⇧⌘P (Windows, Linux Ctrl+Shift+P)) 并运行 任务: 打开用户任务 (Tasks: Open User Tasks) 命令。

PowerShell 中的字符转义

当默认 shell 是 PowerShell 或任务配置为使用 PowerShell 时,您可能会看到意外的空格和引号转义。意外转义仅在使用 cmdlet 时发生,因为 VS Code 不知道您的命令是否包含 cmdlet。下面的示例 1 显示了在 PowerShell 中无法正常工作的转义情况。示例 2 显示了获得良好转义的最佳跨平台方式。在某些情况下,您可能无法遵循示例 2,此时需要执行示例 3 中所示的手动转义。

"tasks": [
    {
        "label": "PowerShell example 1 (unexpected escaping)",
        "type": "shell",
        "command": "Get-ChildItem \"Folder With Spaces\""
    },
    {
        "label": "PowerShell example 2 (expected escaping)",
        "type": "shell",
        "command": "Get-ChildItem",
        "args": ["Folder With Spaces"]
    },
    {
        "label": "PowerShell example 3 (manual escaping)",
        "type": "shell",
        "command": "& Get-ChildItem \\\"Folder With Spaces\\\""
    }
]

更改任务输出的编码

任务经常与磁盘上的文件交互。如果这些文件存储在磁盘上的编码与系统编码不同,您需要让作为任务执行的命令知道使用哪种编码。由于这取决于操作系统和所使用的 shell,因此没有通用的解决方案来控制这一点。下面是关于如何使其工作的建议和示例。

如果您需要调整编码,应该检查更改操作系统使用的默认编码是否有意义,或者至少通过调整 shell 的配置文件来更改所使用的 shell 的编码。

如果您只需要为特定任务调整它,请将更改编码所需的 OS 特定命令添加到任务命令行中。以下示例适用于 Windows,其默认使用代码页 437。该任务显示包含西里尔字母的文件内容,因此需要代码页 866。假设默认 shell 设置为 cmd.exe,列出该文件的任务如下所示

{
  // See https://go.microsoft.com/fwlink/?LinkId=733558
  // for the documentation about the tasks.json format
  "version": "2.0.0",
  "tasks": [
    {
      "label": "more",
      "type": "shell",
      "command": "chcp 866 && more russian.txt",
      "problemMatcher": []
    }
  ]
}

如果任务在 PowerShell 中执行,命令需要读取为 chcp 866; more russian.txt。在 Linux 和 macOS 上,可以使用 locale 命令来检查区域设置并调整必要的环境变量。

任务应用示例

为了突出任务的强大功能,以下是一些 VS Code 如何使用任务集成 lint 工具和编译器等外部工具的示例。

将 TypeScript 转译为 JavaScript

TypeScript 主题 包含一个示例,该示例创建了一个任务,用于将 TypeScript 转译为 JavaScript 并从 VS Code 内部观察任何相关错误。

将 Less 和 SCSS 转译为 CSS

CSS 主题提供了如何使用任务生成 CSS 文件的示例。

  1. 使用构建任务手动转译
  2. 使用文件监视器实现编译步骤的自动化

定义问题匹配器

VS Code 附带了一些最常见的问题匹配器。但是,市面上有许多编译器和 lint 工具,它们都会产生自己风格的错误和警告,因此您可能需要创建自己的问题匹配器。

我们有一个 helloWorld.c 程序,开发人员错误地将 printf 输入为 prinft。使用 gcc 编译它将产生以下警告

helloWorld.c:5:3: warning: implicit declaration of function ‘prinft’

我们想要生成一个问题匹配器,它可以捕获输出中的消息并在 VS Code 中显示相应的问题。问题匹配器在很大程度上依赖于 正则表达式。以下部分假设您熟悉正则表达式。

提示: 我们发现具有 ECMAScript (JavaScript) 风格的 RegEx101 playground 是开发和测试正则表达式的好方法。

捕获上述警告(和错误)的匹配器如下所示

{
  // The problem is owned by the cpp language service.
  "owner": "cpp",
  // The file name for reported problems is relative to the opened folder.
  "fileLocation": ["relative", "${workspaceFolder}"],
  // The name that will be shown as the source of the problem.
  "source": "gcc",
  // The actual pattern to match problems in the output.
  "pattern": {
    // The regular expression. Example to match: helloWorld.c:5:3: warning: implicit declaration of function ‘printf’ [-Wimplicit-function-declaration]
    "regexp": "^(.*):(\\d+):(\\d+):\\s+(warning|error):\\s+(.*)$",
    // The first match group matches the file name which is relative.
    "file": 1,
    // The second match group matches the line on which the problem occurred.
    "line": 2,
    // The third match group matches the column at which the problem occurred.
    "column": 3,
    // The fourth match group matches the problem's severity. Can be ignored. Then all problems are captured as errors.
    "severity": 4,
    // The fifth match group matches the message.
    "message": 5
  }
}

请注意,file、line 和 message 属性是强制性的。fileLocation 指定任务输出产生并匹配在问题中的文件路径是 absolute(绝对)还是 relative(相对)。如果任务同时产生绝对路径和相对路径,则可以使用 autoDetect 文件位置。使用 autoDetect 时,首先将路径作为绝对路径进行测试,如果文件不存在,则假定路径是相对的。

severity 指定如果模式不包含严重性,则使用哪种问题严重性。severity 的可能值为 errorwarninginfo

这是一个包含上述代码(已删除注释)并包装了实际任务详细信息的完整 tasks.json 文件

{
  "version": "2.0.0",
  "tasks": [
    {
      "label": "build",
      "command": "gcc",
      "args": ["-Wall", "helloWorld.c", "-o", "helloWorld"],
      "problemMatcher": {
        "owner": "cpp",
        "fileLocation": ["relative", "${workspaceFolder}"],
        "source": "gcc",
        "pattern": {
          "regexp": "^(.*):(\\d+):(\\d+):\\s+(warning|error):\\s+(.*)$",
          "file": 1,
          "line": 2,
          "column": 3,
          "severity": 4,
          "message": 5
        }
      }
    }
  ]
}

在 VS Code 中运行它并按下 ⇧⌘M (Windows, Linux Ctrl+Shift+M) 获取问题列表,将得到以下输出

GCC Problem Matcher

注意: C/C++ 扩展 包含了 GCC 的问题匹配器,因此无需定义我们自己的。

还有一些属性可以在模式内部使用。它们是

  • location - 如果问题位置是 line 或 line,column 或 startLine,startColumn,endLine,endColumn,则可以使用我们的通用位置匹配组。
  • endLine - 问题结束行的匹配组索引。如果编译器未提供结束行值,则可以省略。
  • endColumn - 问题结束列的匹配组索引。如果编译器未提供结束列值,则可以省略。
  • code - 问题代码的匹配组索引。如果编译器未提供代码值,则可以省略。

您还可以定义仅捕获文件的“问题匹配器”。为此,请定义一个 pattern,并将可选的 kind 属性设置为 file。在这种情况下,无需提供 linelocation 属性。

注意: 如果 kind 属性设置为 file,功能模式必须至少为 filemessage 提供一个匹配组。如果未提供 kind 属性或 kind 属性设置为 location,则函数模式必须同时提供 linelocation 属性。

注意: 问题匹配器仅解析来自给定命令的输出。如果您想解析写入单独文件(例如日志文件)的输出,请让您运行的命令在执行完成前打印出单独文件中的行。

定义多行问题匹配器

一些工具将源文件中发现的问题分散在多行上,特别是在使用时尚报告器时。例如 ESLint;在时尚模式下,它产生如下输出

test.js
  1:0   error  Missing "use strict" statement                 strict
 1 problems (1 errors, 0 warnings)

我们的问题匹配器是基于行的,因此我们需要用与实际问题位置和消息(1:0 error Missing "use strict" statement)不同的正则表达式来捕获文件名(test.js)。

为此,请对 pattern 属性使用问题模式数组。这样,您可以为要匹配的每一行定义一个模式。

注意: 在多行问题匹配器中,模式数组必须匹配输出的每一连续行,从第一个模式开始。即使中间行不包含有用信息,也不能跳过它们。

如果您的工具输出三行,而您只需要第一行和第三行的数据,您的模式数组仍然需要三个条目。对您不需要数据的行使用 {"regexp": "^.*$"},且不分配捕获组。

"pattern": [
    { "regexp": "^Error:\\s+(.*)$", "message": 1 },
    { "regexp": "^.*$" },
    { "regexp": "^\\s+at\\s+(.*):(\\d+)$", "file": 1, "line": 2 }
]

以下问题模式匹配 ESLint 在时尚模式下的输出 - 但仍有一个小问题需要我们接下来解决。下面的代码有一个第一个正则表达式来捕获文件名,第二个来捕获行、列、严重性、消息和错误代码

{
  "owner": "javascript",
  "fileLocation": ["relative", "${workspaceFolder}"],
  "pattern": [
    {
      "regexp": "^([^\\s].*)$",
      "file": 1
    },
    {
      "regexp": "^\\s+(\\d+):(\\d+)\\s+(error|warning|info)\\s+(.*)\\s\\s+(.*)$",
      "line": 1,
      "column": 2,
      "severity": 3,
      "message": 4,
      "code": 5
    }
  ]
}

但是,如果资源上有多个问题,此模式将无法工作。例如,想象 ESLint 的以下输出

test.js
  1:0   error  Missing "use strict" statement                 strict
  1:9   error  foo is defined but never used                  no-unused-vars
  2:5   error  x is defined but never used                    no-unused-vars
  2:11  error  Missing semicolon                              semi
  3:1   error  "bar" is not defined                           no-undef
  4:1   error  Newline required at end of file but not found  eol-last
 6 problems (6 errors, 0 warnings)

模式的第一个正则表达式将匹配 "test.js",第二个匹配 "1:0 error ..."。下一行 "1:9 error ..." 被处理但未被第一个正则表达式匹配,因此没有捕获到问题。

为了使其工作,多行模式的最后一个正则表达式可以指定 loop 属性。如果设置为 true,它会指示任务系统只要正则表达式匹配,就将多行匹配器的最后一个模式应用于输出中的行。

第一个模式捕获的信息(本例中匹配 test.js)将与匹配 loop 模式的每个后续行组合,以创建多个问题。在此示例中,将创建六个问题。

这是一个用于完全捕获 ESLint 时尚问题的“问题匹配器”

{
  "owner": "javascript",
  "fileLocation": ["relative", "${workspaceFolder}"],
  "pattern": [
    {
      "regexp": "^([^\\s].*)$",
      "file": 1
    },
    {
      "regexp": "^\\s+(\\d+):(\\d+)\\s+(error|warning|info)\\s+(.*)\\s\\s+(.*)$",
      "line": 1,
      "column": 2,
      "severity": 3,
      "message": 4,
      "code": 5,
      "loop": true
    }
  ]
}

注意:如果同一资源上发生了多个完全相同的行和列的问题,则只会显示一个问题。这适用于所有问题匹配器,而不止是多行问题匹配器。

修改现有的问题匹配器

如果现有的问题匹配器接近您所需的内容,您可以在 tasks.json 任务中对其进行修改。例如,$tsc-watch 问题匹配器仅适用于已关闭的文档。如果您希望它适用于所有文档,可以对其进行修改

{
  "type": "npm",
  "script": "watch",
  "problemMatcher": {
    "base": "$tsc-watch",
    "applyTo": "allDocuments"
  },
  "isBackground": true
}

其他可修改的问题匹配器属性包括 backgroundfileLocationownerpatternseveritysource

后台/监视任务

一些工具支持在后台运行,同时监视文件系统以检测更改,然后在磁盘上的文件更改时触发操作。通过 Gulp,这种功能通过 npm 模块 gulp-watch 提供。TypeScript 编译器 tsc 通过 --watch 命令行选项内置了对此的支持。

为了提供后台任务在 VS Code 中处于活动状态并产生问题结果的反馈,问题匹配器必须使用额外信息来检测输出中的这些 state 更改。让我们以 tsc 编译器为例。当编译器在监视模式下启动时,它会将以下额外信息打印到控制台

> tsc --watch
12:30:36 PM - Compilation complete. Watching for file changes.

当包含问题的磁盘文件发生更改时,会出现以下输出

12:32:35 PM - File change detected. Starting incremental compilation...
src/messages.ts(276,9): error TS2304: Cannot find name 'candidate'.
12:32:35 PM - Compilation complete. Watching for file changes.

查看输出显示了以下模式

  • 当控制台打印 File change detected. Starting incremental compilation... 时,编译器运行。
  • 当控制台打印 Compilation complete. Watching for file changes. 时,编译器停止。
  • 在这两个字符串之间报告了问题。
  • 编译器也在初始启动后运行一次(无需向控制台打印 File change detected. Starting incremental compilation...)。

要捕获此信息,问题匹配器可以提供 background 属性。

对于 tsc 编译器,适当的 background 属性如下所示

"background": {
    "activeOnStart": true,
    "beginsPattern": "^\\s*\\d{1,2}:\\d{1,2}:\\d{1,2}(?: AM| PM)? - File change detected\\. Starting incremental compilation\\.\\.\\.",
    "endsPattern": "^\\s*\\d{1,2}:\\d{1,2}:\\d{1,2}(?: AM| PM)? - Compilation complete\\. Watching for file changes\\."
}

除了问题匹配器上的 background 属性外,任务本身还必须标记为 isBackground,以便任务继续在后台运行。

一个用于在监视模式下运行 tsc 任务的手写完整 tasks.json 如下所示

{
  "version": "2.0.0",
  "tasks": [
    {
      "label": "watch",
      "command": "tsc",
      "args": ["--watch"],
      "isBackground": true,
      "problemMatcher": {
        "owner": "typescript",
        "fileLocation": "relative",
        "pattern": {
          "regexp": "^([^\\s].*)\\((\\d+|\\d+,\\d+|\\d+,\\d+,\\d+,\\d+)\\):\\s+(error|warning|info)\\s+(TS\\d+)\\s*:\\s*(.*)$",
          "file": 1,
          "location": 2,
          "severity": 3,
          "code": 4,
          "message": 5
        },
        "background": {
          "activeOnStart": true,
          "beginsPattern": "^\\s*\\d{1,2}:\\d{1,2}:\\d{1,2}(?: AM| PM)? - File change detected\\. Starting incremental compilation\\.\\.\\.",
          "endsPattern": "^\\s*\\d{1,2}:\\d{1,2}:\\d{1,2}(?: AM| PM)? - Compilation complete\\. Watching for file changes\\."
        }
      }
    }
  ]
}

后续步骤

这就是任务 - 让我们继续...

  • tasks.json Schema - 您可以查阅完整的 tasks.json 模式和描述。
  • 基本编辑 - 了解功能强大的 VS Code 编辑器。
  • 代码导航 - 快速浏览您的源代码。
  • 语言支持 - 了解我们支持的编程语言,包括随 VS Code 提供的语言以及通过社区扩展提供的语言。
  • 调试 - 直接在 VS Code 编辑器中调试您的源代码。

常见问题

任务可以使用与集成终端指定的 shell 不同的 shell 吗?

可以。您可以使用 "terminal.integrated.automationProfile.*" 设置来设置将用于 VS Code 中所有自动化的 shell,这包括任务。

    "terminal.integrated.automationProfile.windows": {
        "path": "cmd.exe"
    }

或者,您可以使用 options.shell 属性覆盖任务的 shell。您可以按任务、全局或按平台进行设置。例如,要在 Windows 上使用 cmd.exe,您的 tasks.json 将包含

{
    "version": "2.0.0",
    "windows": {
        "options": {
            "shell": {
                "executable": "cmd.exe",
                "args": [
                    "/d", "/c"
                ]
            }
        }
    },
    ...

可以将后台任务用作 launch.json 中的 prelaunchTask 吗?

可以。由于后台任务会一直运行直到被终止,因此后台任务本身没有它已“完成”的信号。要将后台任务用作 prelaunchTask,您必须为后台任务添加适当的后台 problemMatcher,以便任务系统和调试系统有一种方式知道该任务已“完成”。

您的任务可以是

{
  "type": "npm",
  "script": "watch",
  "problemMatcher": "$tsc-watch",
  "isBackground": true
}

注意: $tsc-watch 是后台任务所需的后台问题匹配器。

然后,您可以在 launch.json 文件中将该任务用作 prelaunchTask

{
  "name": "Launch Extension",
  "type": "extensionHost",
  "request": "launch",
  "runtimeExecutable": "${execPath}",
  "args": ["--extensionDevelopmentPath=${workspaceRoot}"],
  "stopOnEntry": false,
  "sourceMaps": true,
  "outFiles": ["${workspaceRoot}/out/src/**/*.js"],
  "preLaunchTask": "npm: watch"
}

有关后台任务的更多信息,请访问 后台/监视任务

为什么我在运行任务时得到“command not found”?

“command not found”消息是在您尝试运行的任务命令未被您的终端识别为可运行内容时出现的。最常见的情况是,这是因为命令被配置为您 shell 启动脚本的一部分。任务作为非登录和非交互式运行,这意味着不会运行 shell 的启动脚本。特别是 nvm 以在配置过程中使用启动脚本而闻名。

有几种方法可以解决此问题

  1. 确保您的命令在路径中,并且不需要启动脚本即可添加到路径中。这是解决问题的最彻底方法,也是推荐的解决方案。
  2. 您可以为您的任务进行一次性修复,使其以登录或交互式方式运行。这不建议使用,因为它可能会产生其他后果。但是,对于单个任务来说,这也可能是一个简单快捷的修复方法。下面是一个使用 bash 作为 shell 执行此操作的任务示例
{
  "type": "npm",
  "script": "watch",
  "options": {
    "shell": {
      "args": ["-c", "-l"]
    }
  }
}

上述 npm 任务将像任务系统默认执行的那样,带着一个命令 (-c) 运行 bash。但是,此任务还将 bash 作为登录 shell (-l) 运行。

© . This site is unofficial and not affiliated with Microsoft.