brave-rofi-rust: переключение вкладок браузера из любого окна
Меню на Rust + rofi, которое переключает вкладки, закладки и историю браузера из любого окна в i3 — а не только когда браузер в фокусе. Оно управляет Brave по Chrome DevTools Protocol, а поднятие окна отдаёт хуку, так что один хоткей работает везде.
На macOS есть воркфлоу Alfred для переключения вкладок браузера: жмёшь хоткей откуда угодно, фаззи-поиском находишь нужную вкладку, прыгаешь прямо в неё. В i3 с rofi ничего подобного у меня не было. Единственный специально сделанный инструмент, который я нашёл — brotab, управляющий вкладками из CLI через расширение браузера, — у меня так и не заработал, по причинам, которые я уже забыл. А сами по себе расширения браузера и скрипты на Puppeteer страдают другой проблемой: они помогают в основном только когда браузер уже в фокусе. А весь смысл в том, чтобы попасть в него, когда он не в фокусе.
Так появился brave-rofi-rust — небольшая программа на Rust, которая складывает открытые вкладки (плюс закладки и историю) в меню rofi, вызываемое из любого окна. Выбираешь вкладку из редактора, терминала, откуда угодно — и браузер выходит на передний план на нужной странице.
Что он делает
Привяжи brave-rofi к клавише в i3 — и получишь глобальный переключатель:
- Вкладки — все открытые вкладки в фаззи-меню; выбираешь — активируется.
- Закладки — открыть закладку откуда угодно, обычную или в инкогнито.
- История — открыть запись истории откуда угодно.
- Плюс поиск (обычный/инкогнито), новая вкладка и закрытие с мультивыбором.
Поддерживается семейство Chromium — Brave Beta (по умолчанию), Brave и
Chromium — выбирается переменной окружения $BROWSER.
Почему нужны два протокола
Самое интересное: «переключиться на вкладку» — это на самом деле две разные задачи, и ни один инструмент не делает обе.
Chrome DevTools Protocol (CDP) умеет переключать активную вкладку внутри
браузера. brave-rofi запрашивает у браузера список вкладок по
http://localhost:9222/json (браузер нужно запустить с
--remote-debugging-port=9222), показывает их в rofi, а по выбору шлёт
Target.activateTarget через WebSocket. Это фокусирует нужную вкладку — но CDP
понятия не имеет о твоём оконном менеджере, так что если окно браузера
завалено под редактором, визуально ничего не происходит.
Поднять окно ОС — задача i3, а не CDP. Поэтому после переключения вкладки
brave-rofi выполняет то, что ты положишь в $BROWSER_POST_SWITCH_HOOK:
export BROWSER_POST_SWITCH_HOOK='i3-msg [class="Brave-browser"] focus'Разделение этих двух обязанностей — CDP для вкладки, пользовательский хук для
окна — и есть то, что заставляет инструмент работать из любого активного
приложения и не привязывает его к i3. Замени хук на swaymsg или wmctrl — и
он заработает на sway или в чистом X11.
любое активное окно ──хоткей──▶ brave-rofi ──curl──▶ /json (список вкладок, CDP) │ меню rofi ──┤── вкладка → CDP Target.activateTarget ├── закладка → запуск $BROWSER <url> └── история → запуск $BROWSER <url> │ ▼ $BROWSER_POST_SWITCH_HOOK → поднять окно браузераЗакладки и история — тем же способом
Как только переключение вкладок заработало отовсюду, стало обидно, что закладки и история — нет. Так что я провёл их через тот же путь «rofi из любого окна».
История — прямой потомок fzf-сниппета, который я писал раньше:
Просмотр истории браузера Brave. Тот же приём:
браузер держит History заблокированной SQLite-базой, пока запущен, поэтому
сначала копируешь её в /tmp, а затем запрашиваешь urls с сортировкой по
last_visit_time. В той статье результат уходил в fzf в терминале; здесь тот
же самый запрос кормит полноэкранное меню rofi, которое можно открыть, вообще не
трогая браузер.
Закладки читаются из моего файла закладок surfraw
(~/.config/surfraw/bookmarks) — простой текстовый файл имя url, который я и
так веду, так что добавить закладку — это дописать одну строку. Выбираешь в rofi
— открывается в браузере (или в окне инкогнито), а тот же хук поднимает окно.
В каком это состоянии
Честно: это черновик. Он закрывает мою личную боль, и по репозиторию это видно.
- Только семейство Chromium. Zen и другие браузеры на базе Firefox говорят
на другом протоколе удалённого управления и хранят историю в другой схеме
(
moz_placesвplaces.sqlite). Переключение вкладок для Zen я начал и не доделал — это одна из нескольких недостроенных идей внутри. - Мёртвый код. Остались обрывки и наполовину смигрированные пути от прежних подходов (логика фокуса окна раньше была жёстко зашита под i3, до появления общего хука), которые я не вычистил.
- Название может измениться.
brave-rofi-rustописывает, откуда всё началось, а не где оно сейчас — он уже работает с Chromium и не так уж привязан к Brave. Если вырастет во что-то более цельное и функциональное, скорее всего переименую. - CDP, возможно, неправильная основа. Требование запускать браузер с
--remote-debugging-port=9222— реальная заноза. Расширение браузера, общающееся через native messaging — примерно как устроен brotab, — вероятно, было бы более чистой основой, чем управление по CDP снаружи, даже ценой отказа от простоты одного статического бинарника. В сторону этого я бы и копал при переосмыслении.
Воспринимай это как рабочий прототип идеи, которая мне нравится, а не как законченный инструмент.
Попробовать
cargo install --git https://github.com/antlis/brave-rofi-rust.gitЗапусти браузер с --remote-debugging-port=9222, задай $BROWSER и
$BROWSER_POST_SWITCH_HOOK, затем привяжи в i3:
bindsym $mod+b exec --no-startup-id brave-rofiВ README — полная настройка и актуальный список шероховатостей. Issues и PR приветствуются — особенно если заведёшь переключение для Firefox/Zen, потому что у меня не вышло.