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

通过任务与外部工具集成

存在许多工具可用于自动化任务,例如对软件系统进行代码检查、构建、打包、测试或部署。示例包括 TypeScript 编译器、ESLint 和 TSLint 等代码检查工具,以及 MakeAntGulpJakeRakeMSBuild 等构建系统。

VS Code can talk to a variety of external tools

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

扩展程序也可以使用 任务提供程序 贡献任务,并且这些贡献的任务可以添加在 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) 或从全局 Terminal 菜单运行 Run Build Task 会显示以下选择器

TypeScript Build Task

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

您还可以将 TypeScript 构建或监视任务定义为默认构建任务,以便在触发 Run Build Task⇧⌘B (Windows, Linux Ctrl+Shift+B))时直接执行它。为此,请从全局 Terminal 菜单中选择 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 启动程序假定没有分号的语句),然后再次执行 Run Tasks。这次选择 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

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

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

{
  "typescript.tsc.autoDetect": "off",
  "grunt.autoDetect": "off",
  "jake.autoDetect": "off",
  "gulp.autoDetect": "off",
  "npm.autoDetect": "off"
}

自定义任务

并非所有任务或脚本都能在您的工作区中自动检测到。有时有必要定义自己的自定义任务。假设您有一个运行测试的脚本,以正确设置某些环境。该脚本存储在工作区内的 scripts 文件夹中,对于 Linux 和 macOS 名为 test.sh,对于 Windows 名为 test.cmd。从全局 Terminal 菜单运行 Configure Tasks,然后选择 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 和 ⌃Space (Windows, Linux Ctrl+Space) 查看任务属性和值的完整集合。通过悬停或使用 Read More... ('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 默认也会对命令进行强引用。与参数一样,用户可以使用相同的字面量样式来控制命令的引用。

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

Tasks IntelliSense

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

Tasks in Command Palette

复合任务

您还可以使用 dependsOn 属性将任务组合成更简单的任务。例如,如果您有一个包含 client 和 server 文件夹的工作区,并且这两个文件夹都包含构建脚本,则可以创建一个任务,该任务在单独的终端中启动这两个构建脚本。如果 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 中列出的顺序执行任务依赖项。在 "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 - 包含文件夹打开时将运行任务。第一次打开包含 folderOpen 任务的文件夹时,系统会询问您是否要允许任务在该文件夹中自动运行。您可以使用 Manage Automatic Tasks 命令并选择 Allow Automatic TasksDisallow Automatic Tasks 稍后更改您的决定。
  • instanceLimit - 允许同时运行的任务实例数。默认值为 1

自定义自动检测的任务

如上所述,您可以在 tasks.json 文件中自定义自动检测的任务。通常,您这样做是为了修改表示属性或附加问题匹配器以扫描任务的输出以查找错误和警告。您可以按 Run Task 列表中的齿轮图标直接自定义任务,以在 tasks.json 文件中插入相应的任务引用。假设您有以下 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...
});

从全局 Terminal 菜单执行 Run Task 将显示以下选择器

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)或修改表示设置。

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

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 时,您可能会看到意外的空格和引号转义。意外的转义仅在 cmdlets 中发生,因为 VS Code 不知道您的命令是否包含 cmdlets。下面的示例 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 的命令添加到任务命令行中以更改编码。以下示例适用于使用代码页 437 作为默认值的 Windows。该任务显示一个包含西里尔字符的文件的输出,因此需要代码页 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 如何使用任务来集成外部工具,例如代码检查器和编译器。

将 TypeScript 转换为 JavaScript

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

将 Less 和 SCSS 转换为 CSS

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

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

定义问题匹配器

VS Code 预装了一些最常见的问题匹配器。然而,外面有大量的编译器和代码检查工具,它们都产生自己风格的错误和警告,所以您可能希望创建自己的问题匹配器。

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

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

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

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

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

{
  // 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
  }
}

请注意,文件、行和消息属性是必需的。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 - 问题代码的匹配组索引。如果编译器没有提供代码值,则可以省略。

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

注意: 如果将 kind 属性设置为 file,则有效的 pattern 至少必须提供 filemessage 的匹配组。如果未提供 kind 属性或将 kind 属性设置为 location,则有效的 pattern 也必须提供 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 属性使用一个问题模式数组。通过这种方式,您可以为想要匹配的每一行定义一个模式。

以下问题模式匹配 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

后台/监视任务

一些工具支持在后台运行,同时监视文件系统以查找更改,然后在文件在磁盘上更改时触发操作。对于 Gulpnpm 模块 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 架构 - 您可以查看完整的 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.