file_regex для сборок Cargo в Sublime Text 3 - PullRequest
0 голосов
/ 13 ноября 2018

Вопрос

Что будет правильным file_regex для записи сообщений об ошибках Cargo / Rustc в системе сборки Sublime Text 3?Я спрашиваю конкретно об относительно недавних версиях cargo / rustc (кажется, что более старые версии использовали несколько более легко разбираемый формат вывода однострочных ошибок).

Пример

Пример вывода cargo build в сломанном проекте hello-world (код по умолчанию, автоматически сгенерированный 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

1-я попытка решения

Этот вид работает, но оннеправильно фиксирует сообщения об ошибках, потому что они находятся в отдельной строке, которая предшествует строке с путем к файлу и номерами строк:

    {
        "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]+)()$"
    },

2nd Solution Attempt

Это смешное регулярное выражение здесь , которое использует этот удивительный трюк с подходящим сопоставлением групп :

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

решило бы проблему, но Возвышенное не видитem для работы с многострочными регулярными выражениями .


Ответы [ 2 ]

0 голосов
/ 14 ноября 2018

Этот скрипт AWK объединяет сообщение об ошибке с номерами строк и приводит его в порядок, который хочет Sublime:

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

Вывод тривиально сопоставляется с следующим регулярным выражением :

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

Вы можете использовать | и сценарии AWK внутри shell_cmd, поэтому эта конфигурация сборки собирает все сообщения об ошибках и отображает их в правильных номерах строк:

{
    "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}'",
0 голосов
/ 13 ноября 2018

Версия ответа TL; DR заключается в том, что, к сожалению, я думаю, что единственный способ заставить Sublime распознать вывод ошибки в вашем вопросе - заставить инструмент генерировать вывод в другом формате (либо напрямую, либо с помощью некоторогоотфильтруйте приложение, расположенное посередине) или создав собственную цель сборки для вашей сборки, которая может распознавать этот вывод ошибок (но он будет работать только для встроенных ошибок, см. ниже).

Фон

Системы сборки в Sublime Text имеют два регулярных выражения, которые можно применять для сопоставления результатов вывода / сборки ошибок, file_regex и line_regex.Оба применяются к результатам компоновки в панели вывода для получения списка результатов компоновки.

file_regex - это регулярное выражение общего назначения для сопоставления результатов компоновки, которое должно содержать от 24 группы захвата, которые захватывают соответствующие данные.Группы захвата (используются по порядку): filename, line, column, message.

line_regex используется в тех случаях, когда информация о местонахождении ошибки находится в другой строке, чем сообщение об ошибке / местонахождение.Здесь захваты находятся в порядке line, column, message, и вы можете использовать от 1 до 3 из них.

В обоих случаях захваты используются в указанном выше порядке, которыйможет потребоваться наличие пустых групп захвата, чтобы убедиться, что все выстраивается в соответствии с ожиданиями.

При обычном использовании вы просто используете file_regex и ничего больше, и это фиксирует результаты для вас.Если вы также используете line_regex, то вместо этого внутренне Sublime совпадает с line_regex, а затем, если находит совпадение, он просматривает выходные данные результата для первой строки, которая соответствует file_regex, и объединяет результаты из захватов.вместе.

По своей сути это означает, что существуют некоторые ограничения, налагаемые на результаты, которые может захватить Sublime;имя файла должно отображаться перед другой информацией об ошибке, чтобы ее можно было зафиксировать.

Массаж выходных данных

В приведенном выше примере сначала отображается ошибка, а также местоположениеошибка отображается второй, поэтому по сути нет способа правильно связать два совпадения регулярных выражений.

Наиболее распространенный способ - изменить выходные данные инструмента, чтобы преобразовать его в форматSublime может обнаружить с помощью приведенных выше регулярных выражений.

Например, вы можете изменить свою сборку так, чтобы она выполняла вашу команду и передавала результат в другой сценарий оболочки или программу, которая может на ходу изменять информацию на ходу.через.Другим примером может быть изменение вашей сборки так, чтобы он вызывал скрипт / пакетный файл, который запускает инструмент и выполняет внутреннее изменение вывода, так, чтобы окончательный вывод соответствовал тому, что ожидает Sublime.

Пользовательские цели сборки

Хотя нет никакого способа использовать систему регулярных выражений, чтобы полностью соответствовать выводу вашей сборки, если вы в первую очередь заинтересованы в отображении встроенных ошибок сборки, есть некоторые способы, если вы хотите испачкать руки с помощью небольшой разработки плагинов Sublime.,В этом случае вам нужно немного знать Python.Имеется документация по пользовательским целям сборки , а также по Sublime API .

Внутренне, когда вы запускаете сборку, Sublime собирает информацию из sublime-buildфайл, раскрывает в нем все переменные и затем вызывает внутреннюю команду exec, чтобы фактически выполнить сборку, предоставляя ключи в sublime-build в качестве аргументов (некоторые, такие как selector, не предоставляются, потому что Sublime обрабатывает это для вас), и это команда exec, которая устанавливает параметры file_regex и line_regex в выходной буфер.

Отсюда, примененные настройки используются ядром Sublime непосредственно для выполнения навигации по результатам сборки.например, нажав на результаты, чтобы открыть файл, или используя команды навигации, чтобы перейти к следующей и предыдущей ошибкам.

Однако именно команда exec отвечает за использование тех же результатов, чтобы показать вам встроенные ошибки сборки, поэтому можно по-прежнему работать с встроенными сообщениями об ошибках, хотя навигация по результатам может привести вас только к местоположению в файл.

Один из ключей, который вы можете предоставить в файле sublime-build, - target, который указывает команду, которая должна выполнить сборку; по умолчанию exec, если не указано.

Создавая собственную пользовательскую команду, которая имитирует действия exec и используя ее в директиве target вашего sublime-build, вы можете подключиться к процессу сборки, чтобы получить соответствующие данные.

Команда exec хранится в Default/exec.py, которую можно просмотреть с помощью команды View Package File из палитры команд.

В качестве минимального примера следующий плагин определяет новую команду с именем cargo_exec, которая точно имитирует то, что делает команда exec. Вызов self.output_view.find_all_results_with_text() - это вызов API, который заставляет ядро ​​Sublime возвращать всю информацию об ошибках из представления вывода сборки, которое используется для установки фантомов, используемых для встроенных ошибок сборки.

Изменяя этот код, чтобы проверить содержимое буфера и использовать ваши собственные знания о том, как выглядят ошибки, оставшаяся часть кода в основной команде 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})

Чтобы использовать это в качестве пользовательской цели сборки, вам нужно добавить пару дополнительных ключей в ваш файл sublime-build:

// Specify a custom build target to execute this build, and specify what
// argument to the command will cause it to cancel a build that is currently
// running.
"target": "cargo_exec",
"cancel": {"kill": true},
...