在 VSCode 中显示校对工具提示 - problem matcher 解析
Back to Top
为了覆盖更广泛的受众,这篇文章已从日语翻译而来。
您可以在这里找到原始版本。
引言
#我是来自商务解决方案事业部的山下。这次,我将讲解在 Visual Studio Code (VSCode) 的任务功能中可以设定的 Problem Matcher。
在日常开发中,由于代码检查功能通常由编辑器或其扩展提供,所以你可能不会过于在意。
然而,也会出现你想要在编辑器中查看自己从零开始开发的 CLI 工具输出的情况。
这次在 VSCode 开发过程中,通过同时使用 Task 和 problem matcher,介绍一种轻松显示自制工具输出结果提示的步骤。
关于本文的示例代码,已发布在下面的仓库中。
背景
#在 isデベロッパーサイト上发布文章之前,规定必须针对文章中的 Markdown 使用 lint 工具。[1]
Lint 工具已注册为 deno 的任务,可以通过以下命令执行。
deno task lint ${mdファイルのパス}
运行此命令后,会在标准输出中检测到校对结果。
/.../mamezou-tech-site/src/posts/blogs/2025/0117_cycle-postgres.md
10:19 error "で" が連続して2回使われています。 ja-no-successive-word
// (略)
12:11 error 【dict2】 "することのできること"は冗長な表現です。"することの"を省き簡潔な表現にすると文章が明瞭になります。 解説: https://github.com/textlint-ja/textlint-rule-ja-no-redundant-expression#dict2 ja-no-redundant-expression
128:3 error 文末が"。"で終わっていません。 ja-no-mixed-period
✖ 7 problems (7 errors, 0 warnings)
基本上是从控制台输出中确定修正部分,但当修正量较多时,检查工作也会相当辛苦。
因此经过研究,我最终采用了 Task 和 problem matcher 的联合使用这一方法。
如下面的画面所示,修正部分能一目了然地作为提示显示。
VSCode 的 Task 与 problem matcher
#关于 Task
#Task 是 VSCode 提供的标准功能之一,简单来说,它是 VSCode 的标准功能,可以指定命令操作的别名等。
通过在 tasks.json 文件中做适当的定义,可以为各种命令或脚本指定别名。
指定了别名的命令不仅可以在 GUI 界面上执行,还可以分配快捷键[2]。
在 tasks.json 中,不仅可以对命令本身或执行方式进行配置,还可以设置如后续所述基于命令触发的附加操作。
problem matcher
#problem matcher 是 tasks.json 中的设置项之一,用于捕获由指定别名的命令输出,并在编辑器上显示为提示。
本章中介绍了官方发布的示例[3]。
{
"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
}
}
}
]
}
关注 problem matcher 后,你应该能看到以下四个属性:
- owner
- fileLocation
- source
- pattern
首先,除 pattern 之外的三个属性做个概述说明。
- owner: 描述违反了什么[4]。(例如:语言名称或标准等)
- fileLocation: 问题被检测到的文件位置的解释方式。(例如:绝对路径、相对路径)
- source: 输出问题的工具(例如:linter 名称、工具名称、编译器等)
接下来,将深入探讨主要的设置项 pattern。为了解释,仅关注 pattern 的配置,以下展示内容。
{
"version": "2.0.0",
"tasks": [
{
// (略)
"problemMatcher": {
// (略)
"pattern": {
"regexp": "^(.*):(\\d+):(\\d+):\\s+(warning|error):\\s+(.*)$",
"file": 1, // 第一个捕获组表示文件
"line": 2, // 同上
"column": 3, //
"severity": 4, //
"message": 5 //
}
}
}
]
}
关于 pattern,为了说明,接下来将其分为 regexp 和其他部分进行展示。
首先,在 regexp 中,指定包含必要信息的模式的正则表达式。
在此过程中,请指定合适的捕获组,以便从正则表达式中以适当的粒度提取所需信息。
例如,考虑这样一个从输出中提取信息的例子。
helloWorld.c:5:3: warning: implicit declaration of function ‘prinft’
可以确认这一行包含了以下信息:
- ファイル名
- 行番号
- 列番号
- 重要度
- エラー内容
在刚才的例子中,似乎可以通过下面这样的正则表达式来捕获输出[5].
"^(.*):(\\d+):(\\d+):\\s+(warning|error):\\s+(.*)$"
接下来,只要指定每个捕获组对应的内容,就可以将作为提示所需的信息传递给编辑器了。
因此,除了 regexp 以外,还需要进行设置。配置了适当项的 problemMatcher 如下所示。
{
"version": "2.0.0",
"tasks": [
{
//(略)
"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 //
}
}
}
]
}
另一方面,根据工具的不同,输出可能跨越多行。
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
即使是这样的输出,只要按下面设置 problemMatcher,就可以解析错误。
{
"version": "2.0.0",
"tasks": [
{
//(略)
"problemMatcher": {
"owner": "cpp",
"fileLocation": ["relative", "${workspaceFolder}"],
"source": "gcc",
"pattern": [
{
"regexp": "^([^\\s]+\\.\\w+)$",
"file": 1
},
{
"regexp": "^\\s*(\\d+):(\\d+)\\s*\\S?\\s*(error|warning)\\s+(.*)\\s+(.*)$",
"line": 1,
"column": 2,
"severity": 3,
"message": 4,
"code": 5,
"loop": true
}
]
}
}
]
}
具体来说,首先准备了两种模式,①用于检测文件名,②用于检测其它部分。
在后者中添加了 “loop”: true,通过这种方式解析输出,即 [文件名] → [其他部分(重复)].
实现结果
#在 isデベロッパーサイト中使用的 Lint 工具的输出结果形式为“基本为文件的绝对路径 → 修正部分重复出现”。
/.../mamezou-tech-site/src/posts/blogs/2025/0117_cycle-postgres.md
10:19 error "で" が連続して2回使われています。 ja-no-successive-word
11:4 error ✔︎ 漢字が7つ以上連続しています: 漢字七文字以上 max-kanji-continuous-len
12:11 error 【dict2】 "することのできること"は冗長な表現です。"することの"を省き簡潔な表現にすると文章が明瞭になります。 解説: https://github.com/textlint-ja/textlint-rule-ja-no-redundant-expression#dict2 ja-no-redundant-expression
128:3 error 文末が"。"で終わっていません。 ja-no-mixed-period
若以通用记法描述,大致如下。
${ファイルの絶対パス}
(複数の空白)${行番号}:${列番号}(複数の空白)$(0or1文字)(複数の空白)${重要度}(複数の空白)${エラーメッセージ}(複数の空白)${エラーの識別子}
以下繰り返し
因此,预期只要按照如下指定 problemMatcher,就可以捕获相关信息。
{
"label": "deno lint Manual",
// (略)
"problemMatcher": {
"owner": "md",
"fileLocation": [
"absolute",
],
"pattern": [
{
"regexp": "^([^\\s]+\\.\\w+)$",
"file": 1
},
{
"regexp": "^\\s*(\\d+):(\\d+)\\s*\\S?\\s*(error|warning)\\s+(.*)\\s+(.*)$",
"line": 1,
"column": 2,
"severity": 3,
"message": 4,
"code": 5,
"loop": true
}
]
},
}
在这里,我们来看看示例。再次附上仓库的链接。
在示例仓库上运行校对处理后,会在编辑文件的界面中显示提示,如下所示。
然而,这并不意味着万事皆遂,还发现了以下需要改进之处。
- 项目特有的语法,例如“:::”,也被纳入了校对范围
- 无法充分解析错误
这些问题的解决超出了 problem matcher 的范畴,请在其他文章中补充说明。
总结
#这次通过控制 VSCode 的 Task 中的 problem matcher 属性,实现了从 CLI 工具反馈结果的功能。
只要准备好相应工具,只需编辑 tasks.json,即可在编辑器上将工具的结果可视化。
https://code.visualstudio.com/docs/editor/tasks#_binding-keyboard-shortcuts-to-tasks ↩︎
https://code.visualstudio.com/docs/editor/tasks#_defining-a-problem-matcher ↩︎
在官方页面中有 "The problem is owned by … ." 这样的描述。因为这种表达不太常见,所以加入了自己的理解。 ↩︎
正则表达式的检查可以尝试使用 Regex Playground 等工具。 ↩︎