Редакторы кода и интегрированные среды разработки постоянно стремятся улучшить пользовательский опыт, предоставляя все более гибкие и мощные инструменты для форматирования исходного кода. Zed, новый современный редактор, выделяется среди конкурентов благодаря поддержке внешних форматтеров, которые позволяют интегрировать сторонние утилиты форматирования прямо в рабочий процесс. Однако, несмотря на очевидные преимущества, использование внешних форматтеров в Zed таит в себе ряд особенностей и сложностей, с которыми сталкиваются многие разработчики в процессе настройки и эксплуатации. В этой статье мы подробно исследуем возможности, ограничивающие факторы и нестандартные решения, позволяющие извлечь максимальную пользу из функционала внешних форматтеров в Zed. Основным атрибутом форматтера в Zed выступает исполняемый файл, который принимает данные текущего файла из стандартного потока ввода и возвращает отформатированный результат в стандартный поток вывода.
Такая архитектура обеспечивает гибкость, так как любой скрипт или бинарный файл, способный работать с stdin и stdout, потенциально может стать форматтером. Этим обуславливается возможность простого подключения популярных средств форматирования, например Prettier, посредством указания команды и аргументов в конфигурационном файле. Простая стандартная конфигурация выглядит следующим образом: задается команда prettier с аргументом --stdin-filepath, который позволяет форматтеру определить тип файла и применить соответствующие правила форматирования. Помимо индивидуального форматтера, Zed поддерживает массив форматтеров, где для одного файла можно последовательно применять несколько инструментов. Это открывает дополнительный простор для сложных схем форматирования, когда, например, сначала вызывается rust-analyzer для форматирования Rust-кода, а затем вывод подвергается постобработке с помощью команд вроде sed для удаления лишних пробелов или других мелких косметических изменений.
В документации Zed подчеркивается, что каждый последующий форматтер запускается вне зависимости от успешности предыдущего, и в итоге результат последнего форматтера будет итоговым содержимым файла. Такой подход стимулирует создавать цепочки обработки, когда один инструмент меняет код, а другой исправляет или дополняет изменения. Однако на практике возникают ситуации, когда требуется более тонкий контроль над последовательностью и логикой применения форматтеров. Например, бывают случаи, когда хочется не просто последовательно применять инструменты, а реализовать логику с использованием форматов с запасными вариантами или fallback-механизмами: использовать один форматтер по умолчанию, и при его неудаче автоматически задействовать альтернативный инструмент без наслаивания изменений друг над другом. В стандартной реализации Zed это сделать сложно, потому что все форматтеры применяются подряд и последний всегда побеждает.
Для обхода этих ограничений разработчики часто прибегают к написанию собственных оберток или скриптов, которые становятся единым форматтером с внутренней логикой вызова нескольких внешних инструментов. Такая кастомная обертка получает код из stdin, последовательно запускает несколько форматтеров, проверяя их статус выхода из процесса, и возвращает первый успешный результат либо объединяет их каким-либо осмысленным образом. Это обеспечивает возможность реализации условного поведения, гибко меняющегося в зависимости от наличия конфигураций или типа используемых файлов. Примером эффективного подхода служит оболочка на bash, где логика заключается в использовании сначала форматтера Biome, известного как инструмент для форматирования и проверки TypeScript-кода, а если он недоступен или завершился с ошибкой, подключается Prettier. Для последнего предусмотрена возможность выбора между проектной конфигурацией, найденной автоматически в текущей директории, и глобальной конфигурацией пользователя, хранящейся в домашней папке.
Скрипт аккуратно собирает сообщения об ошибках каждого этапа и при полном провале сообщает пользователю в логе Zed о всех неудачах, что очень удобно при диагностике. Такой подход позволяет решать сразу несколько задач одновременно: расширяет совместимость формата исходного кода, оптимизирует настройки форматирования без жесткой привязки к одному инструменту и обеспечивает прозрачность в работе. При этом важно помнить, что форматтер не имеет прямого доступа к файлу, а только к передаваемому через stdin содержимому, поэтому любые решения должны строиться, исходя из этой архитектурной особенности. Хотя bash-скрипты удобны для простых сценариев, их сложность быстро возрастает с увеличением количества условий и необходимости обработки ошибок. Поэтому многие разработчики осваивают более развитые языки программирования, например TypeScript с использованием среды выполнения Bun.
Благодаря современному API и возможности асинхронного запуска процессов, такое решение становится более масштабируемым, читаемым и поддерживаемым. Новый тип форматтера, реализованный на TypeScript, может оперировать группами форматтеров, обрабатывая выход каждого предыдущего как вход для следующего в цепочке. Это позволяет объединять преимущества нескольких инструментов при сохранении строгого контроля над последовательностью и успешностью выполнения. В дополнение к функционалу fallback, TypeScript-обертка дает возможность дифференцировать форматирование по расширению файла, направляя .astro-файлы сначала в Prettier проектной конфигурации и затем в Biome, а все остальные файлы форматировать в обратном порядке.
Такие настройки значительно повышают гибкость и дают возможность оптимизировать качество форматирования под особенности конкретных технологий и стеков. При создании собственной логики обработки форматтеров важно учитывать тонкости работы каждого инструмента, их требования к входным данным и реакцию на отсутствие конфигураций. Вышеприведенный пример TypeScript-кода иллюстрирует, что успешное форматирование возможно только при наличии подходящей конфигурации и бинарника в проекте. Отсутствие любого из этих условий не означает сбоя, а вызывает переключение на следующий вариант. В целом, использование внешних форматтеров в Zed предоставляет широчайшие возможности для кастомизации и автоматизации форматирования, но требует определенного времени на разработку и отладку собственных решений для более сложных сценариев.
Свобода выбора инструмента и возможность комбинирования их потенциалов — это ключевой фактор успеха. В то же время, нужно внимательно подходить к обработке ошибок и четко контролировать поток данных между форматтерами, чтобы избежать неожиданных эффектов и повысить производительность. Кроме того, рекомендуются периодические проверки актуальности и доступности используемых бинарников в node_modules, настройка правильных путей и настройка исключений для языков, которые лучше обрабатывать встроенными средствами или language servers. Такая практика позволяет сохранить быстрый отклик редактора и чистоту кода. Подводя итоги, можно отметить, что грамотное использование внешних форматтеров в Zed открывает новые горизонты работы с исходным кодом, позволяет строить сложные многоступенчатые схемы форматирования с условным переключением и снижает зависимость от одного единственного средства.
Рекомендуется создавать собственные обертки – скрипты или небольшие приложения на более мощных языках программирования, что позволит реализовать необходимую бизнес-логику и добиться высокого качества кода с минимальными усилиями и временными затратами. Такой подход будет полезен всем, кто стремится к максимальной автоматизации и эффективной интеграции современных инструментов в рабочий процесс редактора Zed.