Sublime Text 3中的Cargo版本的file_regex

时间:2018-11-13 17:21:29

标签: regex sublimetext3 rust-cargo

问题

在Sublime Text 3构建系统中捕获Cargo / Rustc的错误消息的权利file_regex是什么?我要特别询问的是相对较新的cargo / rustc版本(似乎较旧的版本使用了更容易解析的单行错误输出格式)。

示例

在中断的hello-world项目上输出cargo build的示例(cargo new --bin broken自动生成的默认代码,其中删除了双引号以创建错误消息):

error: unterminated double quote string
 --> src/main.rs:2:14
  |
2 |       println!("Hello, world!);
  |  ______________^
3 | | }
  | |__^

error: aborting due to previous error

error: Could not compile `broken`.

相对文件路径为src/main.rs,行列为2:14,我个人更希望直接在行之间看到的错误消息是

unterminated double quote string

第一次解决方案尝试

这种方法有效,但不能正确捕获错误消息,因为它们位于之前带有文件路径和行号的行:

    {
        "name": "cargo build",
        "shell_cmd": "cargo build",
        "working_dir": 
          "/home/you/path/to/cargo/project/with/the/toml",
        "file_regex": 
          "^ *--> *([a-zA-Z0-9_/.]+):([0-9]+):([0-9]+)()$"
    },

第二次尝试解决方案

使用funny regex herethis awesome lookahead-with-matching-groups-trick

error(?:\[E\d+\])?: (?=.+\n +--> +([a-zA-Z0-9_\/.-]+):([\d]+):([\d]+))(.+)

本可以解决问题,但是Sublime doesn't seem to work with multiline regexes


2 个答案:

答案 0 :(得分:2)

不幸的是,答案的TL; DR版本是,我认为让Sublime识别问题中的错误输出的唯一方法是使工具生成不同格式的输出(直接或通过某种方式生成)。过滤器应用(位于中间)或通过为您的构建创建自己的自定义构建目标来识别此错误输出(但仅适用于内联错误,请参见下文)。

背景

Sublime Text中的构建系统具有两个可用于尝试和匹配错误输出/构建结果的正则表达式file_regexline_regex。两者都将应用于输出面板中的构建结果,以获得构建结果列表。

file_regex是用于匹配构建结果的“通用”正则表达式,并且应包含2到4个捕获适当数据的捕获组中的任意一个。捕获组(按顺序使用)是filenamelinecolumnmessage

line_regex用于有关错误位置的信息与错误消息/位置不在同一行的情况。在这里,捕获按照linecolumnmessage的顺序进行,您可以使用其中任意1到3个。

在两种情况下,捕获都按照上面给定的顺序使用,这可能需要有空的捕获组来确保一切按预期进行。

在正常使用情况下,您仅使用file_regex而不使用其他任何内容,即可为您捕获结果。如果您还使用line_regex,则在内部line_regex上进行Sublime匹配,然后,如果找到匹配项,它将在结果输出中向后查找与file_regex匹配的第一行,并将捕获的结果结合在一起。

从本质上讲,这意味着Sublime可以捕获的结果类型受到一些限制;该文件名必须出现在有关该错误的其他信息之前,以便被捕获。

按摩输出

在上面的示例中,首先显示错误,然后显示错误的位置,因此,固有地,没有办法将两个正则表达式匹配正确地关联在一起。

最常见的解决方法是修改工具的输出,以便将其重新加工为Sublime可以使用上述正则表达式检测到的格式。

例如,您可能会更改构建,以使其执行命令并将结果通过管道传输到另一个Shell脚本或程序,这些脚本或程序可以在运行过程中即时更改信息。另一个示例是更改构建,以使其调用执行该工具的脚本/批处理文件,并在内部进行输出更改,以使最终输出与Sublime期望的结果匹配。

自定义构建目标

尽管无法使用regex系统完全匹配您的构建输出,但是如果您主要对显示的内联构建错误感兴趣,那么如果您想通过一点Sublime插件开发来使自己的手变得肮脏,则可以采取一些措施。在这种情况下,您需要了解一些Python。有custom build targetsSublime API上的文档。

在内部,当您运行构建时,Sublime从sublime-build文件中收集信息,展开其中的所有变量,然后调用exec内部命令来实际执行构建,并提供密钥sublime-build作为参数(由于Sublime会为您处理,因此未提供诸如selector之类的参数),并且exec命令设置了file_regex和{{ 1}}设置进​​入输出缓冲区。

从此处开始,Sublime核心将直接使用应用的设置对构建结果进行导航,例如,通过单击结果以打开文件,或使用导航命令来查找下一个和上一个错误。

但是,line_regex命令负责使用相同的结果向您显示内联构建错误,因此尽管结果导航只能将您带到该位置,但仍可能使内联错误消息正常工作在文件中。

可以在exec文件中提供的键之一是sublime-build,它指定应执行构建的命令;如果未提供,则默认为target

通过创建自己的模仿exec的自定义命令并在exec的{​​{1}}指令中使用它,您可以进入构建过程以捕获适当的数据。

target命令存储在sublime-build中,您可以使用命令面板中的exec命令进行查看。

作为一个最小的示例,以下插件定义了一个名为Default/exec.py的新命令,该命令准确地模仿了View Package File命令的作用。对cargo_exec的调用是使Sublime核心从构建输出视图返回所有错误信息的API调用,该视图用于设置用于内联构建错误的模型。

通过修改该代码以检查缓冲区的内容并使用您对错误的外观的自定义知识,核心exec命令中的其余代码将为您显示内联错误。

self.output_view.find_all_results_with_text()

要将其用作自定义构建目标,您需要在exec文件中添加几个额外的键:

import sublime
import sublime_plugin

from Default.exec import ExecCommand

# Subclass the exec command to hook into the output processing.
class CargoExecCommand(ExecCommand):
    def run(self, **kwargs):
        # If we are being told to kill a running build, kill it right away
        # and leave.
        if kwargs.get("kill", False):
            return super().run(kill=True)

        # Use our super class to execute the build from this point.
        super().run(**kwargs)

    # override the super class method so we can handle output as it
    # arrives in the output panel.
    def service_text_queue(self):
        is_empty = False
        with self.text_queue_lock:
            if len(self.text_queue) == 0:
                # this can happen if a new build was started, which will clear
                # the text_queue
                return

            characters = self.text_queue.popleft()
            is_empty = (len(self.text_queue) == 0)

        self.output_view.run_command(
            'append',
            {'characters': characters, 'force': True, 'scroll_to_end': True})

        if self.show_errors_inline and characters.find('\n') >= 0:
            errs = self.output_view.find_all_results_with_text()
            errs_by_file = {}
            for file, line, column, text in errs:
                if file not in errs_by_file:
                    errs_by_file[file] = []
                errs_by_file[file].append((line, column, text))
            self.errs_by_file = errs_by_file

            self.update_phantoms()

        if not is_empty:
            sublime.set_timeout(self.service_text_queue, 1)


# Use the latest build results to add inline errors to newly opened files.
class CargoExecEventListener(sublime_plugin.EventListener):
    def on_load(self, view):
        w = view.window()
        if w is not None:
            w.run_command('cargo_exec', {'update_phantoms_only': True})

答案 1 :(得分:1)

此AWK脚本将错误消息与行号结合在一起,并将其带入Sublime所需的顺序:

awk 'BEGIN { errmsg="" } /error(\[E[0-9]+\])?:.*/ {errmsg=$0; next} /\ *-->\ *.*/ { printf "%s::::%s\n", $0, errmsg; next} {print $0}'

输出与following regex轻松匹配:

error(?:\[E\d+\])?: (?=.+\n +--> +([a-zA-Z0-9_\/.-]+):([\d]+):([\d]+))(.+)

您可以在|内使用shell_cmd和AWK脚本,因此此构建配置将捕获所有错误消息并以正确的行号显示它们:

{
    "name": "cargo build",
    "working_dir": "/wherever/your/project",
    "shell_cmd": "cargo build 2>&1 | awk 'BEGIN { errmsg=\"\" } /error(\\[E[0-9]+\\])?:.*/ {errmsg=\\$0; next} /\\ *-->\\ *.*/ { printf \"%s::::%s\\n\", \\$0, errmsg; next} {print \\$0}'",
    "file_regex": " +--> +([a-zA-Z_\\/.-]+):(\\d+):(\\d+)::::(.*)"
}

这也以相同的方式对待warning

"shell_cmd": "cargo build 2>&1 | awk 'BEGIN { errmsg=\"\" } /(error|warning)(\\[E[0-9]+\\])?:.*/ {errmsg=\\$0; next} /\\ *-->\\ *.*/ { printf \"%s::::%s\\n\", \\$0, errmsg; next} {print \\$0}'",