Привет, Хабр! Если вы читаете мои дайджесты, то знаете, что обычно я пишу о развитии проекта far2l — порта Far Manager под Linux, macOS и BSD. Но сегодня случай особый. На прошлых выходных я обещал вам рассказать про f4 — написанный с нуля клон far2l на языке Go.

Сегодня состоялся релиз первой публичной альфа-версии 0.1.1-alpha. В этой статье я расскажу, как я пришел к идее переписать легендарный файловый менеджер, почему выбрал Go, как в этом помогли нейросети и почему современному консольному приложению не обязательно страдать от «наследия предков».

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

Сразу спойлер: что под капотом f4?

Прежде чем углубляться в историю, давайте сразу обозначим, ради чего всё это затевалось. Чем f4 принципиально отличается от своего прародителя?

  1. Тотальная асинхронность. Пользовательский интерфейс больше не «фризится» при чтении директории по медленному SFTP. Вы можете запустить тяжелую операцию и продолжать работу в панелях. Есть и выстраивание операций в очередь с управленим числом потоков на ресурс для максимальной эффективности IO, как в менеджерах загрузок.

  2. Out-of-process плагины (RPC). Никакой боли с бинарной совместимостью и C++ ABI. Плагины общаются с ядром через stdin/stdout по протоколу MessagePack. Пишите плагины на Python, Rust, Node.js или Lua — если язык умеет писать в консоль, он может расширять f4. Экосистема превыше всего!

  3. FISH+ (WIP). Эволюция удаленного управления файлами. Вместо скачивания файла для поиска по нему, f4 будет слать команду на сервер, чтобы он нашёл сам. Это не только спасает на медленных линках, но и решает проблему WSL: можно запустить f4 в Linux-контейнере и управлять файлами хостовой Windows с нативной скоростью!

  4. Собственный UI-фреймворк (vtui). Написанная с нуля библиотека компонентов в духе классического Turbo Vision, но изначально асинхронная, с поддержкой современных протоколов ввода (kitty keyboard, win32-input-mode) и Zero-allocation рендерингом.

Демонстрационное приложение фреймворка vtui, написанного специально для f4.
Демонстрационное приложение фреймворка vtui, написанного специально для f4.

Как я пришёл к переписыванию Far'а

Работая над far2l, я часто ловил себя на мысли, что узкое место консольных файловых менеджеров — не процессорные такты, а ввод и вывод. И поэтому ручное управление памятью в C/C++ скорее отнимает ресурсы разработчика, которые могли бы уйти на оптимизацию I/O, чем приносит пользу за счёт собственной эффективности. И, конечно, очень сильно ограничивала развитие синхронная природа старого кода: фоновое копирование в far2l на самом деле есть, но из-за синхронного ядра оно реализовано так, что вы скорее всего даже не знаете, что оно там есть, и как его найти.

Когда-то давно, только начав изучать программирование, я после BASIC'а и Turbo Pascal'я сразу прыгнул в Ассемблер. Долго не мог понять: зачем вообще нужен промежуточный язык между Паскалем и ассемблером, который даёт бинарник той же эффективности что и Паскаль, но при этом предоставляет куда больше способов прострелить себе ногу, включая самые изощрённые. Со временем, конечно, я в той или иной степени смирился (думаю, как многие из нас), но интуитивное чувство, что интерфейс должен писаться проще, меня не покидало. И в особенности потому что я избалован высокоуровневыми языками как php, и мне не очень интересно тратить время на отслеживание утечек памяти в коде отрисовки выпадающего меню.

Кстати, оригинальный Far 2 поддерживал плагины и на Pascal/Delphi, и это было круто (и у меня как-то даже получилось завести это и в far2l). Но Pascal сейчас не в моде, а разработчиков, знакомых с ним — мало (к слову, на мой взгляд, причина провала — то, что дефолтные строки не в UTF8, и только это).

Были и другие проблемы, фундаментально неразрешимые на базе существующего кода:

Зависимости и дистрибуция. Ещё одна боль. Мы слишком долго ждали, пока far2l возьмут в Debian, и так и не дождались пакета в официальной Fedora. Зависимость от версий libc, wxWidgets, glib — всё это делало дистрибуцию сложной. Я хотел, чтобы файловый менеджер в Linux работал как Telegram, Tor Browser или оригинальный Far в Windows: скачал один бинарник, положил куда угодно, и он просто работает, независимо от того, Ubuntu у тебя, Arch, старый CentOS или вообще Gentoo. А ведь ещё есть плагины! Сейчас пользователю плагина надо самому подсовывать его исходники в дерево far2l, куда такое годится?

Плагины, включенные в состав far2l. О существовании других никто не знает, потому что нет организованной системы дистрибьюции.
Плагины, включенные в состав far2l. О существовании других никто не знает, потому что нет организованной системы дистрибьюции.

Плагины и экосистема. Сам я особо не пользовался плагинами Far не «из коробки» на Винде — всего хватало и так, но всегда понимал их важность. При этом заставлять людей учить отдельный язык, Lua, только ради написания плагина — на мой взгляд, утопия. И тут я вспомнил гениальную мысль создателя OpenStreetMap (OSM): «Дайте людям простой инструмент здесь и сейчас, и занимайтесь сообществом» (они там годами шлифовали идеальную модель данных при нуле контрибьютеров, а он дал людям точку, линию и полигон, с возможностью привязывать к ним пары ключ-значение, и всё поехало). Хотелось дать людям универсальный штепсель, куда можно будет цепляться хоть из Питона, хоть из бинарного кода. Таким штепселем стал бинарный RPC интерфейс через stdin/stdout.

Обратное портирование и ИИ. Наконец, у меня была давняя мечта — портировать far2l обратно на Windows (звучит как шутка, но, вообще-то, получить единую базу кода для всех платформ было бы очень неплохо, и это не что-то неосуществимое, в cygwin мы даже когда-то работали). Проблема в том, что внутри far2l есть прослойка WinPort, которая эмулирует (частично подмножество, а частично надмножество) Windows API под Linux. Когда я пробовал натравливать на этот код нейросети для обратного портирования, они сходили с ума, путаясь между WinPort и реальным WinAPI, куда я пытался WinPort транслировать. С человеком, скорее всего, случилось бы то же самое.

Одновременно с этим главный мейнтейнер far2l как-то обмолвился о зашкаливающей цикломатической сложности некоторых старых участков кода. Прекрасно помню, чего стоило добавить в редактор поддержку переноса по словам. Сказать, что этот код запутан, значит, ничего не сказать! И я подумал: а не проще ли уже начать понемногу параллельно переписывать это всё с нуля, сразу правильно? С асинхронностью, отдельным удобным UI-фреймворком и на современном языке.

Почему именно Go?

Итак, было принято решение разделить проект на две части: мощную UI-библиотеку (по смыслу — асинхронного наследника Turbo Vision) и сам файловый менеджер на её основе. Перебрал несколько вариантов:

  • Rust: Да, он быстрый. Но цена владения (borrow checker) при написании UI-деревьев с перекрестными ссылками (фокус, паренты, линки) слишком высока. Нейросети в нём тоже иногда откровенно плывут. Код UI не должен быть сложным в разработке и генерации.

  • Node.js / Python: Была безумная мысль написать или взять готовый плюсовый UI движок (как современный форк того же Turbo Vision) и сделать к нему биндинги из JS или Python. Но биндинги — это всегда хрупко. А ещё Python отпал из-за GIL (прощай, нормальная асинхронность) и кошмара с дистрибуцией (pip, например, на современных Ubuntu ругается на externally managed среду, и это не даёт установить хоть что-нибудь сложнее тривиального). Тащить с каждым плагином свой VirtualEnv? Нет, спасибо. К тому же, для тулзы, которая открывается по 100 раз на дню, время старта скриптовых виртуальных машин слишком велико.

Go подошел идеально. Он компилируется в статически слинкованный бинарник, решая проблему дистрибуции. У него есть сборщик мусора, так что мне не придётся тратить время на отлов сегфолтов в UI. У Go мощнейшая встроенная поддержка многопоточности, горутины и каналы. За ним стоит огромная корпорация и развитая экосистема, так что мне не пришлось писать с нуля алгоритмы ZIP, TAR или крипотграфию для SFTP. И современные нейросети пишут на Go на очень приличном уровне!

Архитектура и магия скорости

Бытует заблуждение, что Go — медленный язык из-за сборщика мусора. Это просто не так: ограничение не в языке, а в стиле разработки. Уже сейчас, в состоянии альфы, f4 субъективно ощущается отзывчивее, чем far2l на C++.

В чём магия? Я исходил всё из той же идеи, что узкое место консольного файлового менеджера — это ввод-вывод, а не отрисовка кнопок. Поэтому как раз ввод-вывод в f4 оптимизирован маниакально. Например,

  • Zero-allocation рендеринг: Фреймворк vtui использует систему двойной буферизации. При вызове Flush() он побитово сравнивает логический экран с теневым буфером терминала и генерирует минимальные ANSI-последовательности для отрисовки только изменений, без единой аллокации памяти в куче. Сборщик мусора просто отдыхает, пока вы быстро скроллите список файлов.

  • PieceTable в Редакторе: Вместо загрузки файла в память целиком, редактор f4 использует структуру данных Piece Table, натравленную на асинхронный VFS-буфер. В результате f4 открывает гигабайтные логи по SSH мгновенно, не выедая ОЗУ, и позволяет мгновенно прыгать в конец файла.

  • Event Draining: Обработка ввода (например, вставку больших кусков текста в терминал в режиме Bracketed Paste) собирается в пакеты, и экран перерисовывается только один раз в конце.

Редактор прекрсно справляется со случайным 80-мегабайтным бинарником.
Редактор прекрсно справляется со случайным 80-мегабайтным бинарником.

В скомпилированном виде без отладочной информации f4 весит около 15 Мб и жмется UPX'ом до 4-5. По меркам 2025 года это ничто, субъективно запускается он мгновенно.

Минусы

15 Мб отлично для десктопа или виртуалки, но даже 5 многовато для копеечного роутера с 16 Мб флеша, там far2l или mc чувствуют себя лучше. Эту проблему можно обойти тремя способами:

  1. Выкинуть зависимости. Большую часть веса в f4 дают библиотеки криптографии (SSH/SFTP) и архивации. Если сделать для слабого железа альтернативные плагины, где вместо библиотек Go будут использоваться обёртки над внешними утилитами (ziptarssh и т.д. — так же, как делал MultiArc в Far2), бинарник похудеет до 5-6 Мб, что уже будет сопоставимо с весом конкурентов.

  2. Использовать FISH+. Зачем вообще тащить тяжелый комбайн на роутер? Запускаем f4 на рабочей машине, а к роутеру цепляемся по SSH. Согласно протоколу FISH+ на роутер закидывается крошечный шелл-скрипт (или микробинарник), который берет на себя рекурсивный подсчет размеров, поиск файлов сервером, парсинг директорий и т.д. — всё то, что удаленно делать долго, будет делаться на стороне SSH сервера. Это же решает и проблему WSL — работая в f4 внутри виртуалки, вы сможете мгновенно и без тормозов управлять файлами хостовой Windows, если там есть OpenSSH сервер, который давно ставится одним кликом.

  3. А почему бы не допилить mc? Можно сделать (и я подумываю как-нибудь заняться этим) форк Midnight Commander, добавив туда привычные фаровские шорткаты (хотя бы по галке, но вообще-то, пользователей Far на Windows в мире всё же несоизмеримо больше) и поддержку современных терминальных протоколов (kitty, win32im, osc52, bracketed paste). Это закроет нишу embedded окончательно.

mc, работающий во встроенном терминале f4. Добавить передачу всех сочетаний клавиш и буфера обмена между ними — и станет хорошо!
mc, работающий во встроенном терминале f4. Добавить передачу всех сочетаний клавиш и буфера обмена между ними — и станет хорошо!

f4 и far2l

Сразу отвечу на уже интересовавших многих вопрос: я не отказываюсь от разработки far2l полностью в пользу f4. Буквально недавно занимался для far2l тестами переноса по словам в редакторе.

f4 — это экспериментальный полигон. Здесь можно пробовать то, что долго тащить в legacy C++ код или когда страшно что-нибудь сломать. У f4 параноидальное покрытие тестами — экспериментируйте на здоровье, что-то здесь сломать будет очень непросто! А если фича приживётся, её можно будет перенести и в far2l. Например, реализованную в f4 идею навигации по элементам диалога только с помощью обычных стрелок (а не только Tab) уже просили перенести в старшего брата.

И, конечно, f4 полностью понимает far2l terminal extensions. Он идеально работает внутри встроенного терминала far2l (с общим буфером обмена и всеми хоткеями), и наоборот — far2l прекрасно работает в терминале f4.

Более того, архитектура f4 вовсю заимствует самые удачные идеи своего предка. Например, как и в far2l, в f4 реализован нативный графический бэкенд для X11. Да, консольный файловый менеджер на Go может рисовать себя напрямую в иксовое окно, минуя эмуляторы терминала. Зачем? Потому что терминалы обожают перехватывать нужные нам сочетания клавиш.

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

Приглашаю к тестированию!

Проект находится в стадии alpha. Базовый функционал уже работает стабильно: панели, архивы (через встроенный плагин), SFTP/FTP (тоже встроенный плагин NetFox), редактор, вьюер, встроенный терминал с поддержкой PTY.

Если вы любите консоль, соскучились по Фару или просто хотите посмотреть, на что способны современные TUI на Go — добро пожаловать!

Скачать готовые бинарники для Windows, macOS и Linux (включая ARM) можно прямо на главной странице репозитория:
https://github.com/unxed/f4

Буду рад вашим звездочкам, баг-репортам и идеям в Issues. А если вы знаете Go или хотите написать свой RPC-плагин — в репозитории есть готовый SDK и пример dummy_rpc. И, пожалуйста, поделитесь опытом знакомства в f4 в комментариях!

Есть и пасхалочка :)

Комментарии (58)


  1. titbit
    01.05.2026 13:50

    Идея выглядит прикольно, но почему бы не пойти дальше и полностью перейти на клиент-серверную архитектуру? Т.е. изначально разделить продукт на части: 1. клиент - интерфейс оболочка для взаимодействия с пользователем (GUI/TUI, поддeржка всяких расширений терминалов, X11/wayland и т.д.), 2. основная серверная часть-планировщик, которая рулит всеми асинхронными параллельными операциями и взаимодействует с клиентом(ами), включая возможность делать это по сети, и с плагинами/скриптами, если надо работает с повышенными правами, 3. выносная микросерверная часть для сценариев embedded/slow link/etc. т.е. без планировщика и поддержки плагинов, но тоже с возможностью взаимодействия по сети с основным сервисом по ssh/telnet/serial port (эта часть опциональна).


    1. unxed Автор
      01.05.2026 13:50

      Возможно, ага. Тоже думал о подобном.


      1. rPman
        01.05.2026 13:50

        разве FISH+ не то же самое? это буквально то что хочется, тяжелый интерфейс работает на клиенте, а удаленно по ssh шлются команды, которые 99% linux поддерживаются


        1. unxed Автор
          01.05.2026 13:50

          Может, я неправильно понял комментарий. FISH+ будет работать точно как вы описали. Странно, но ни в одном сетевом протоколе ничего подобного пока нет. Максимум это server side copy, и тот поддерживается чаще в теории чем на практике.


          1. rPman
            01.05.2026 13:50

            может это я неправильно понял комментарий titbit, что значит разделить far на клиента и сервера, я подумал что то что уже у вас сделано и есть FISH+


            1. unxed Автор
              01.05.2026 13:50

              FISH+ ещё не сделан, это пока только концепт. Но принципиальных каких-то причин не работать у этого нет, просто ещё руки не дошли.


    1. achekalin
      01.05.2026 13:50

      Т.е. у меня на дохлой VPS-ке будут не только серверы nginx, php-fpm, mysql, но и сервер far-server? Хотя, если он еще и будет консольные команды исполнять, и сможет хранить сессии - цены ж ему не будет!


      1. unxed Автор
        01.05.2026 13:50

        Так это уже есть же. Можно через меню уйти в фон. Можно при следующем запуске подцепиться к одной из фоновых сессий или стартануть новую. Можно даже закрыть терминал, переключиться на другую сеть, подключиться по ssh снова и подхватить сессию.

        И консольные команды встроенный терминал f4, конечно же, чудесно исполняет!

        Но это не решает проблему работы на слабом железе. Для этого придуман FISH+: это когда на сервер заливается крохотный скрипт, делающий на его стороне тяжёлые операции вроде поиска по файлам. Чтоб не было смысла гонять там f4 локально, производительность и возможности удаленной работы через FISH+ будут те же.


        1. unxed Автор
          01.05.2026 13:50

          Более того, в каждом инстансе f4 у вас может быть анлим панелей с отдельными логами терминалов под каждой парой. Форк текущих по Ctrl+N, закрытие по Ctrl+W, переключение по Ctrl+Tab и Ctrl+Shift+Tab.


  1. Flux82
    01.05.2026 13:50

    Спасибо за интересный рассказ и проект!

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

    Немного прокомментирую про pip. Странное заблуждение, что нельзя установить хоть что-нибудь сложнее тривиального. Вы можете поставить почти всё, что угодно и без venv c --break-system-packages в ~/.local. Только от sudo не запускайте pip.

    Так как python активно используется в системе, как правило большой частью популярных пакетов рулит системный менеджер пакетов. Что будет, к примеру, если вы через sudo pip поставите глобально numpy 2.x, в то время как через apt установлен какой-нибудь python3-numpy? Уверяю - что-нибудь обязательно сломается. Ну и так очень-очень много с чем. Об этом вас pip и предупреждает.

    Ну и наконец последний совет - рассмотрите современные альтернативы pip. Обычный pip очень медленный. uv вас приятно удивит)


    1. unxed Автор
      01.05.2026 13:50

      Спасибо! Да, тут пригодился опыт надёжной разработки нейронками. Поэтому в том числе такое тщательное покрытие тестами.


  1. rrran7
    01.05.2026 13:50

    Я вот сейчас пытаюсь перейти на far2l с MC. Все хорошо, кроме терминала. Жуть как непривычно.

    Особенно paste много строчных команд. В МЦ ls\ncat file проходит на ура, а вот в far2l только первая строка


    1. kruphi
      01.05.2026 13:50

      В far2l

      • между 2.6.5 и 2.7.0 введена поддержка вставки из буфера обмена многосторочных команд - выдает предупреждение и спрашивает выполнять или отклонить.

      • между 2.7.0 и 2.8.0 это улучшили - после вставки сразу поле ввода, где можно не только посмотреть, но и отредактировать вставленное до его запуска.


  1. rrran7
    01.05.2026 13:50

    Так что с терминалом в F4?


    1. unxed Автор
      01.05.2026 13:50

      Нормальный такой себе терминал, mc и far2l работают комфортно!


  1. MagisterAlexandr
    01.05.2026 13:50

    Есть неограниченная история посещённых путей?


    1. unxed Автор
      01.05.2026 13:50

      Пока история есть только у выполненных команд. Сделаем и для путей!


      1. unxed Автор
        01.05.2026 13:50

        Сделал, пробуйте! Alt+F12