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

通过任务与外部工具集成

许多工具可以自动化诸如代码检查、构建、打包、测试或部署软件系统等任务。示例包括 TypeScript 编译器、代码检查工具如 ESLint TSLint以及构建系统如 Make Ant Gulp Jake Rake MSBuild

VS Code 可以与各种外部工具进行通信

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

扩展程序还可以通过 任务提供程序 贡献任务,这些贡献的任务可以添加在 任务.json文件。

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

TypeScript Hello World

让我们从一个简单的 "Hello World" TypeScript 程序开始,我们将编译成 JavaScript。

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

创建目录 mytask
进入目录 mytask
类型检查 --初始化
代码 .

现在创建一个HelloWorld.ts文件包含以下内容

函数 sayHello(name: 字符串): 无返回值 {
  console.log(`Hello ${name}!`);
}

说你好('戴夫');

⇧⌘B(Windows, LinuxCtrl+Shift+B或从全局Run Build Task菜单运行Terminal显示以下选择器:

TypeScript 构建任务

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

您还可以将 TypeScript 构建或监视任务定义为默认构建任务,以便在触发时直接执行运行构建任务 (⇧⌘B (Windows, Linux Ctrl+Shift+B))。要这样做,请从全局配置默认构建任务菜单中选择终端。这将显示一个带有可用构建任务的选择器。选择tsc: 构建tsc: 监视,VS Code 将生成一个任务.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
      }
    }
  ]
}

任务.json 上面的例子没有定义一个新的任务。它注释了 tsc: build 任务,这些任务由 VS Code 的 TypeScript 扩展贡献,成为默认的构建任务。现在你可以通过按 ⇧⌘B (Windows, Linux Ctrl+Shift+B 来执行 TypeScript 编译器。

任务自动检测

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

任务 ESLint 启动器

如果你还没有这样做,请通过运行安装所需的npm模块npm 安装现在打开服务器.js 文件并在语句末尾添加分号(注意,ESLint 起点假设没有分号的语句)然后再次执行 运行任务。这次选择 npm: lint 任务。当被要求选择问题匹配器时,选择 ESLint stylish

任务 ESLint 问题匹配器选择

执行任务产生一个错误,显示在问题视图中:

任务 ESLint 问题

此外,VS Code 创建了一个任务.json文件包含以下内容:

{
  // 参见 https://go.microsoft.com/fwlink/?LinkId=733558
  // 了解 tasks.json 格式的文档
  "version": "2.0.0",
  "tasks": [
    {
      "type": "npm",
      "script": "lint",
      "problemMatcher": ["$eslint-stylish"]
    }
  ]
}

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

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

Gulp 任务自动检测

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

任务自动检测可以通过以下设置禁用:

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

定制任务

并非所有任务或脚本都能在你的工作区中自动检测到。有时需要定义自己的自定义任务。假设你有一个脚本,用于运行测试以正确设置某些环境。该脚本存储在工作区内的脚本文件夹中,名为test.sh适用于 Linux 和 macOStest.cmd 适用于 Windows。运行 配置任务 从全局 终端 菜单并选择 从模板创建 tasks.json 文件 选项。这将打开以下选择器:

配置任务运行器

注意: 如果您没有看到任务运行器模板列表,您可能已经有一个任务.json将文件放入文件夹中,其内容将在编辑器中打开。关闭文件,然后删除或重命名此示例中的文件。

我们正在增加更多的自动检测支持,因此未来这个列表会越来越小。由于我们想编写自己的自定义任务,请从列表中选择其他。这将打开任务.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": {
        "显示""总是"
        "面板""新"
      }
    }
  ]
}

任务的属性具有以下语义:

  • Tab:用户界面中使用的任务标签。
  • 类型:任务的类型。对于自定义任务,这可以是 处理如果如果指定了,该命令将被解释为一个 shell 命令(例如:bash、cmd 或 PowerShell)。如果处理如果指定了命令,则将其解释为一个要执行的过程。
  • 命令:要执行的实际命令。
  • windows:任何 Windows 特定的属性。当在 Windows 操作系统上执行命令时,将使用这些属性而不是默认属性。
  • :定义该任务属于哪个组。在示例中,它属于 测试 组。属于测试组的任务可以通过在 运行测试任务 中运行 命令面板 来执行。
  • 展示:定义了任务输出在用户界面中的处理方式。在这个示例中,显示输出的集成终端是总是揭示和一个新的每个任务运行时都会创建终端。
  • 选项:覆盖默认设置当前工作目录(当前工作目录)环境(环境变量),或(默认 shell)。选项可以按任务设置,也可以全局设置或按平台设置。在此配置的环境变量只能在您的任务脚本或过程中引用,如果它们是您参数、命令或其他任务属性的一部分,则不会解析。
  • runOptions:定义任务何时以及如何运行。
  • 隐藏:隐藏该任务,使其不再出现在运行任务快速选择中,这对于复合任务中无法单独运行的元素很有用。

您可以在您的代码中看到任务属性和值的完整集合和IntelliSense。任务.json 文件。使用 Trigger Suggest (⌃Space (Windows, Linux Ctrl+Space)) 提出建议,并在悬停或使用 Read More... ("i") 弹出框阅读描述。

tasks.json 智能感知

您还可以查看tasks.json 模式

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

  • 如果只提供一个命令,任务系统会原封不动地将该命令传递给底层 shell。如果命令需要引用或转义才能正常工作,那么命令需要包含适当的引用或转义字符。例如,要列出一个文件夹名中包含空格的文件夹的目录,执行的 bash 命令应如下所示:ls '文件夹有空格'输入:.
{
  "标签": "目录",
  "类型": "shell",
  "命令": "目录 '包含空格的文件夹'"
}
  • 如果提供了命令和参数,任务系统将在命令或参数包含空格时使用单引号。命令提示符双引号被使用。像下面这样的 shell 命令将在 PowerShell 中执行目录 'folder with spaces'输入:.
{
  "标签": "目录",
  "类型": "shell",
  "命令": "目录",
  "参数": ["带空格的文件夹"]
}
  • 如果您想控制参数的引用方式,参数可以是指定值和引用风格的字面值。下面的示例使用转义而不是引用包含空格的参数。
{
  "标签": "目录",
  "类型": "shell",
  "命令": "目录",
  "参数": [
    {
      "值": "带空格的文件夹",
      "引号处理": "转义"
    }
  ]
}

除了转义,还支持以下值:

  • :使用 shell 的强引用机制,该机制会抑制字符串内部的所有评估。在 PowerShell 以及 Linux 和 macOS 下的 shell 中,使用单引号 ('). 对于 cmd.exe,输入:"被使用。
  • 弱引用:使用 shell 的弱引用机制,这仍然会评估字符串内部的表达式(例如,环境变量)。在 PowerShell 和 Linux 和 macOS 的 shell 中,使用双引号 (输入:"). cmd.exe 不支持弱引用,因此 VS Code 使用输入:"也一样。

如果命令本身包含空格,VS Code 将默认为命令加强引号。与参数一样,用户可以使用相同的文字样式控制命令的引号。

还有更多的任务属性可以配置您的工作流。您可以使用IntelliSense与⌃Space(Windows, LinuxCtrl+Space来查看有效的属性。

任务智能感知

除了全局菜单栏,任务命令还可以通过命令面板 (⇧⌘P (Windows, Linux Ctrl+Shift+P))访问。您可以通过“任务”进行筛选,并可以查看各种与任务相关的命令。

命令面板中的任务

复合任务

您还可以将更简单的任务组合成更复杂的任务依赖于属性。例如,如果您有一个包含客户端和服务器文件夹的工作区,并且两个文件夹都包含一个构建脚本,您可以创建一个任务,以在不同的终端中启动两个构建脚本。如果在依赖于属性,它们默认是并行执行的。

任务.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": {
        "当前工作目录": "${workspaceFolder}/server"
      }
    },
    {
      "标签": "构建",
      "依赖于": ["客户端构建", "服务器构建"]
    }
  ]
}

如果你指定"依赖顺序": "顺序",则您的任务依赖将按照它们在列表中出现的顺序执行依赖于任何在 中使用的背景/观看任务依赖于"依赖顺序": "顺序"必须有一个问题匹配器来跟踪何时完成。以下任务运行任务 Two,任务 Three,然后任务 One。

{
  "标签": "One",
  "类型": "外壳",
  "命令": "echo Hello ",
  "依赖顺序": "序列",
  "依赖项": ["Two", "Three"]
}

用户级别任务

您可以使用 任务:打开用户任务 命令创建不与特定工作区或文件夹绑定的用户级别任务。只有 处理任务可以在这里使用,因为其他任务类型需要工作区信息。

输出行为

有时您可能希望控制集成终端面板在运行任务时的行为。例如,您可能希望最大化编辑器空间,并且只有在认为有问题时才查看任务输出。终端的行为可以通过使用来控制展示任务的属性。它提供了以下属性:

  • 显示:控制是否将集成终端面板带到前台。有效值为:
    • 总是- 该面板始终会被移至最前面。这是默认设置。
    • 从不 - 用户必须使用命令将终端面板移至最前面 视图 > 终端 (⌃` (Windows, Linux Ctrl+`)).
    • 沉默终端面板仅在输出不进行错误和警告扫描时才会显示在前面。
  • 显示问题:控制在运行此任务时问题面板是否显示。优先于选项揭示默认是从不
    • 总是- 在执行此任务时始终显示问题面板。
    • 遇到问题- 仅在找到问题时显示问题面板。
    • 从不- 在执行此任务时从不显示问题面板。
  • 焦点:控制终端是否接受输入焦点。默认是输入:.
  • echo:控制是否在终端中显示执行的命令。默认是输入:.
  • showReuseMessage:控制是否显示“终端将被任务复用,请按任意键关闭”消息。
  • 面板:控制终端实例是否在任务运行之间共享。可能的值是:
    • 共享- 终端是共享的,其他任务运行的输出会添加到同一个终端。
    • 专注- 终端用于特定任务。如果该任务再次执行,终端将被再次使用。但是,不同任务的输出将显示在不同的终端中。
    • 新的- 每次执行该任务时都会使用一个新的干净终端。
  • 清除:控制在运行此任务之前是否清除终端。默认是输入:.
  • 关闭:控制任务退出时终端是否关闭。默认是输入:.
  • :控制任务是否在特定终端组中使用分屏执行。属于同一组(由字符串值指定)的任务将使用分屏终端而不是新的终端面板。

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

{
  // 参见 https://go.microsoft.com/fwlink/?LinkId=733558
  // 有关 tasks.json 格式的文档
  "version": "2.0.0",
  "tasks": [
    {
      "type": "npm",
      "script": "lint",
      "problemMatcher": ["$eslint-stylish"],
      "presentation": {
        "reveal": "never"
      }
    }
  ]
}

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

{
  // 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",
      "命令""./scripts/test.sh"
      "Windows":{
        "命令""."\\scripts\\test.cmd"
      },
      "组""test"
      "展示":{
        "显示""总是"
        "面板""新"
      }
    }
  ]
}

运行行为

您可以使用运行选项属性:

  • reevaluateOnRerun:控制在通过Rerun Last Task命令执行任务时变量的评估方式。默认值是,这意味着当任务重新运行时,变量将被重新评估。当设置为将使用任务上一次运行的已解析变量值。
  • runOn:指定任务何时运行。
    • 默认 - 该任务仅在通过 运行任务 命令执行时才会运行。
    • 文件夹打开- 当打开包含任务的文件夹时,该任务将运行。第一次打开包含任务的文件夹时文件夹打开,您将被询问是否允许在该文件夹中自动运行任务。您可以稍后使用管理自动任务命令并在允许自动任务不允许自动任务之间进行选择。
  • instanceLimit - 允许同时运行的任务实例数量。默认值是1输入:.

自定义自动检测的任务

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

常量 gulp = 需要('gulp');
常量 eslint = 需要('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...
});

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

配置任务

按齿轮图标。这将创建以下内容任务.json文件:

{
  // 参考 https://go.microsoft.com/fwlink/?LinkId=733558
  // 获取 tasks.json 格式的文档
  "version": "2.0.0",
  "tasks": [
    {
      "type": "gulp",
      "task": "default",
      "problemMatcher": []
    }
  ]
}

通常情况下,您现在会添加一个问题匹配器(在这种情况下$eslint-stylish) 或修改演示设置。

处理任务输出与问题匹配器

VS Code 可以处理任务的输出,并使用问题匹配器。问题匹配器扫描任务输出文本,查找已知的警告或错误字符串,并在编辑器和问题面板中内联报告这些信息。VS Code 预装了一些“开箱即用”的问题匹配器:

  • TypeScript$时间戳假定输出中的文件名相对于打开的文件夹。
  • TypeScript 监控$tsc-watch与报告的问题匹配翻译结果:tsc编译器在watch模式下执行时。
  • JSHint$jshint假设文件名以绝对路径报告。
  • JSHint Stylish$jshint-stylish假设文件名以绝对路径报告。
  • ESLint 紧凑$eslint-紧凑假定输出中的文件名相对于打开的文件夹。
  • ESLint 样式$eslint-stylish假定输出中的文件名相对于打开的文件夹。
  • GO$去与报告的问题匹配GO编译器。假定文件名是相对于打开的文件夹。
  • CSharp和VB编译器$编译假设文件名以绝对路径报告。
  • Lessc 编译器$lessc假设文件名以绝对路径报告。
  • Node Sass 编译器$node-sass假设文件名以绝对路径报告。

你也可以创建自己的问题匹配器,我们将在稍后的章节讨论。

将键盘快捷键绑定到任务

如果您需要经常运行一个任务,您可以为该任务定义一个键盘快捷键。

例如,绑定Ctrl+H运行测试 上面的任务,将以下内容添加到你的 keybindings.json文件:

{
  "键": "ctrl+h",
  "命令": "workbench.action.tasks.runTask",
  "参数": "运行测试"
}

变量替换

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

注意: 并非所有属性都接受变量替换。具体来说,只有 命令参数,和选项支持变量替换。

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

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

同样地,您可以通过在名称前加上${config:来引用项目配置设置。例如,${config:python.formatting.autopep8Path}返回Python扩展设置格式化自动 pep8 路径输入:.

以下是自定义任务配置的一个示例,该示例使用通过定义的autopep8可执行文件对当前文件执行autopep8。python.格式化自动pep8路径设置:

{
  "标签": "autopep8当前文件",
  "类型": "进程",
  "命令": "${config:python.formatting.autopep8Path}",
  "参数": ["--in-place", "${file}"]
}

如果你想要指定Python扩展使用的选定Python解释器任务.jsonlaunch.json,你可以使用${命令:python.解释器路径}命令。

如果简单的变量替换不够,你还可以通过添加一个来从你的任务用户那里获取输入输入部分到你的任务.json文件。

输入示例

欲了解更多关于输入,请参阅变量参考

操作系统特定属性

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

以下是一个示例,它使用Node.js可执行文件作为命令,并且在Windows和Linux上处理方式不同:

{
  "label": "运行节点",
  "type": "过程",
  "windows": {
    "命令": "C:\\Program Files\\nodejs\\node.exe"
  },
  "linux": {
    "命令": "/usr/bin/node"
  }
}

有效的操作属性是Windows适用于 Windows,Linux对于 Linux,并且osx适用于 macOS。操作系统特定范围中定义的属性会覆盖在任务或全局范围中定义的属性。

全球任务

任务属性也可以在全局作用域中定义。如果存在,它们将用于特定任务,除非它们定义了具有不同值的相同属性。在下面的示例中,有一个全局展示属性,定义所有任务应在新面板中执行:

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

提示: 要访问全局作用域 任务.json 文件,打开命令面板 (⇧⌘P (Windows, Linux Ctrl+Shift+P)) 并运行 任务:打开用户任务 命令。

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 示例 3(手动转义)",
        "type": "shell",
        "command": "& Get-ChildItem \\\"带空格的文件夹\\\""
    }
]

更改任务输出的编码

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

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

如果你只需要为特定任务调整它,那么将更改编码所需的OS特定命令添加到任务命令行中。以下示例是针对Windows使用437代码页作为默认值。该任务显示包含西里尔字符的文件,因此需要866代码页。列出文件的任务如下所示,假设默认的shell设置为命令提示符输入:

{
  // 参考 https://go.microsoft.com/fwlink/?LinkId=733558
  // 了解 tasks.json 格式的文档
  "version": "2.0.0",
  "tasks": [
    {
      "label": "more",
      "type": "shell",
      "command": "chcp 866 && more russian.txt",
      "problemMatcher": []
    }
  ]
}

如果任务执行在PowerShell命令需要像这样读取chcp 866; 更多俄语.txt在 Linux 和 macOS 上,区域设置命令可以用来检查区域设置并调整必要的环境变量。

行动任务示例

为了突显任务的力量,这里有一些 VS Code 如何使用任务来集成外部工具(如 linters 和 compilers)的例子。

将 TypeScript 转译为 JavaScript

TypeScript 主题 包括一个示例,该示例创建一个任务将 TypeScript 转译为 JavaScript,并在 VS Code 内观察任何相关的错误。

将 Less 和 SCSS 转译成 CSS

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

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

定义问题匹配器

VS Code 附带了一些最常用的 проблем匹配器。然而,有很多编译器和静态代码分析工具,它们都会产生自己的错误和警告样式,因此您可能需要创建自己的问题匹配器。

我们有一个你好世界.c 程序中开发人员误输入 printfprinft。用 gcc 编译它将产生以下警告:

helloWorld.c:5:3: 警告: 隐式 声明 函数 ‘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,
    // 第五组匹配消息。
    "message": 5
  }
}

请注意,文件、行和消息属性是必需的。文件位置指定任务输出和问题中匹配的文件路径是否绝对相对的如果任务生成了绝对和相对路径,您可以使用自动检测文件位置。随着自动检测首先测试路径是否为绝对路径,如果文件不存在,那么该路径被认为相对。

严重性指定如果模式不包括问题严重性,则使用哪个问题严重性。可能的值为严重性错误警告,或信息输入:.

这是一个完成的任务.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 问题匹配器

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

在模式中可以使用的几个更多属性。这些是:

  • 位置 - 如果问题位置是行或行,列或起始行,起始列,结束行,结束列,那么我们可以使用通用的位置匹配组。
  • endLine - 问题结束行的匹配组索引。如果编译器没有提供结束行值,则可以省略。
  • endColumn - 问题结束列的匹配组索引。如果编译器没有提供结束列值,则可以省略。
  • 代码 - 问题代码的匹配组索引。如果编译器没有提供代码值,则可以省略。

您还可以定义一个仅捕获文件的问题匹配器。要这样做,请定义一个图案带有可选的孩子属性设置为文件在这种情况下,无需提供位置财产。

注意: 功能模式至少必须提供一个匹配组 文件消息如果孩子属性设置为文件如果不行孩子属性已提供或孩子属性设置为位置,函数模式必须提供一个位置属性也是如此。

注意: 问题匹配器只会解析给定命令的输出。如果你希望解析写入到单独文件的输出(例如日志文件),请在命令执行完毕前打印出单独文件中的行。

定义一个多行问题匹配器

一些工具会将源文件中发现的问题分散到多行,特别是如果使用了 stylish 格式化工具。一个例子是ESLint;在 stylish 模式下,它会生成如下输出:

测试.js
  1:0   错误  缺失 "use strict" 语句                 严格
 1 问题 (1 错误, 0 警告)

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

要这样做,请使用问题模式数组图案属性。这样你就可以为每一条想要匹配的规则定义一个模式。

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

{
  "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   错误  新行 被要求 结束 文件 但是 没有 找到  eol-last
 6 问题 (6 错误, 0 警告)

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

为了实现这一点,多行模式的最后一个普通表达式可以指定循环属性。如果设置为 true,它会指示任务系统将多行匹配器的最后一个模式应用于输出中的行,只要正则表达式匹配。

第一个模式捕获的信息,在这种情况下匹配测试.js将与后续匹配的每一行组合循环模式创建多个问题。在这个例子中,将创建六个问题。

这里是一个问题匹配器,可以完全捕获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
    }
  ]
}

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

修改现有的问题匹配器

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

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

其他可修改的问题匹配器属性包括背景文件位置所有者图案严重性,和输入:.

背景 / 观看任务

一些工具支持在后台运行,同时监控文件系统的变化,当文件在磁盘上更改时触发操作。吞咽 这种功能是通过npm模块 gulp-watch 提供的。TypeScript编译器 翻译结果:tsc通过 ,已经内置了对此的支持。--观察命令行选项。

为了提供反馈,表明 VS Code 中有一个背景任务正在活动并产生问题结果,问题匹配器必须使用附加信息来检测这些输出的变化。让我们以翻译结果:tsc编译器作为一个例子。当编译器以监视模式启动时,它会向控制台打印以下附加信息:

> tsc --watch
12:30:36 下午 - 编译 完成。 监控 文件 变化。

当磁盘上的文件更改时,包含问题的文件将出现以下输出:

12:32:35 下午 - 文件 变更 被检测到。 开始 增量 编译...
src/messages.ts(276,9): 错误 TS2304: 无法找到名称 'candidate'
12:32:35 下午 - 编译 完成。 监控 文件 变更。

查看输出显示以下模式:

  • 编译器在运行时检测到文件更改。开始增量编译...打印到控制台。
  • 编译器在...时停止编译完成。正在监控文件变化。打印到控制台。
  • 在那两个字符串之间报告了问题。
  • 编译器在初始启动时也会运行一次(不打印)检测到文件更改。开始增量编译...到控制台。

为了获取这些信息,问题匹配器可以提供一个背景财产。

对于翻译结果:tsc编译器,一个适当的背景属性看起来像这样:

"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\\."
}

除了背景在问题匹配器上,任务本身必须被标记为是否为背景这样任务就会在后台继续运行。

全手工制作任务.json为一个翻译结果:tsc在 watch 模式下运行的任务如下所示:

{
  "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 模式 - 您可以查看完整的 任务.json模式和描述。
  • 基本编辑 - 了解强大的 VS Code 编辑器。
  • 代码导航 - 快速浏览您的源代码。
  • 语言支持 - 了解我们支持的编程语言,这些语言既包含与 VS Code 一同提供的,也包含通过社区扩展提供的。
  • 调试 - 在 VS Code 编辑器中直接调试您的源代码。

常见问题

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

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

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

或者,您可以覆盖任务的 shell选项. shell属性。您可以按任务、全局或按平台设置此属性。例如,要使用Windows上的cmd.exe,您的任务.json将包括:

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

一个后台任务可以被用作预发布任务在 launch.json 中?

是的。由于后台任务会在被终止之前一直运行,因此单个后台任务没有“完成”的信号。要将后台任务用作预发布任务, 你必须添加一个合适的背景问题匹配器将任务放到后台,以便任务系统和调试系统能够知道该任务“完成”。

您的任务可能是:

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

注意: $tsc-watch 是一个 后台 问题匹配器,符合后台任务的要求。

然后你可以将此任务用作预发布任务在你的launch.json文件:

{
  "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”发生时,您尝试运行的任务命令未被终端识别为可运行的。最常见的情况是,因为该命令是作为 shell 启动脚本的一部分配置的。任务以非登录和非交互式方式运行,这意味着您的 shell 启动脚本将不会被运行。没关系特别的是,已知它将启动脚本用作其配置的一部分。

有几种方法可以解决这个问题:

  1. 确保你的命令在你的路径上,并且不需要启动脚本将其添加到路径中。这是解决该问题的最彻底的方法,也是推荐的解决方案。
  2. 您可以为您的任务一次性设置为以登录或交互模式运行。这不推荐,因为它可能会有其他后果。然而,对于单个任务来说,这也可能是一个快速简便的解决方案。下面是一个执行此操作的任务示例巴什作为外壳:
{
  "type": "npm",
  "script": "watch",
  "options": {
    "shell": {
      "args": ["-c", "-l"]
    }
  }
}

以上npm任务将运行巴什使用命令 (- c),就像任务系统默认所做的那样。然而,这个任务也运行巴什作为登录 shell-列表)。