Выбор проектов в WezTerm
от aNNiMON
English version
Мне нравится WezTerm за то, что в нём используются lua-конфигурации, вместо скучных json/yaml/toml-файлов, а также в нём есть мощный и настраиваемый мультиплексор. В этой статье я покажу как создать переключатель проектов, который создаст именованное рабочее пространство, разделит окно и выполнит указанные команды.

Мультиплексор
Начнем с базовой конфигурации, чтобы понять возможности мультиплексирования. Представьте, что после запуска терминала мы хотим получить готовое рабочее пространство с узкой панелью для spotify-player справа, очень маленькой панелью внизу и основной рабочей панелью с погодой.
Мы используем событие gui-startup для настройки запуска WezTerm, в котором создаём новое окно с одной панелью pane_main, именем рабочего пространства main и некоторой директорией ~/dev. Затем мы разделяем pane_main вправо с размером 0.12 и другой директорией. Эта панель имеет название pane_spoti. То же самое для pane_bottom.
Дальше всё просто: разворачиваем окно WezTerm на весь экран, активируем главную панель и выполняем несколько команд в каждой панели.

Мы только что настроили лишь одно рабочее пространство, но вы можете создать сколько угодно, если укажете в новом окне workspace = 'something'.
Проекты
В этот раз мы используем аналогичный подход к мультиплексированию, но, вместо события gui-startup, запустим диалог выбора проекта с помощью комбинации клавиш:
Здесь я настроил одно и то же действие для двух разных привязок: комбинации клавиш и лидера. Используйте ту, которая вам больше нравится, или обе, как я.
В choose_project мы построим список проектов и будем использовать InputSelector с включенной опцией fuzzy:

В list_projects мы укажем объект с именами проектов и функциями их инициализации. Для одной панели это будет single_project, а для других, более сложных конфигураций проектов, будет отдельная функция:
Здесь я использую только одно- и двухпанельное рабочее пространство, но вы можете модифицировать этот пример и создать мощные проекты с динамическими проверками, установкой переменных окружения, использованием файлов .env, различных условий и т.д. Развлекайтесь!
Если проект нужно запускать часто, стоит подумать о том, чтобы запускать его напрямую по нажатию сочетания клавиш:
Полная конфигурация: github.com/annimon-tutorials/wezterm-projects
Стилизация
Этот серый диалог выбора выглядит так скучно, давайте добавим ему немного цвета и иконок. Вы можете использовать wezterm.format, чтобы применить стили к fuzzy_description:
Вместо определения собственных цветов можно использовать AnsiColor с 16 значениями: ■ Black, ■ Maroon, ■ Green, ■ Olive, ■ Navy, ■ Purple, ■ Teal, ■ Silver, ■ Grey, ■ Red, ■ Lime, ■ Yellow, ■ Blue, ■ Fuchsia, ■ Aqua или ■ White.
Для использования иконок смотрите страницу wezterm.nerdfonts.
Список проектов необходимо немного изменить:
И функцию выбора проекта тоже:
Вот что у меня получилось

Полный конфиг: github.com/annimon-tutorials/wezterm-projects
Мне нравится WezTerm за то, что в нём используются lua-конфигурации, вместо скучных json/yaml/toml-файлов, а также в нём есть мощный и настраиваемый мультиплексор. В этой статье я покажу как создать переключатель проектов, который создаст именованное рабочее пространство, разделит окно и выполнит указанные команды.

Мультиплексор
Начнем с базовой конфигурации, чтобы понять возможности мультиплексирования. Представьте, что после запуска терминала мы хотим получить готовое рабочее пространство с узкой панелью для spotify-player справа, очень маленькой панелью внизу и основной рабочей панелью с погодой.
- -- ~/.config/wezterm.lua
- local wezterm = require 'wezterm'
- wezterm.on('gui-startup', function()
- local _, pane_main, window = wezterm.mux.spawn_window{
- workspace = 'main',
- cwd = '~/dev'
- }
- local pane_spoti = pane_main:split {
- direction = "Right",
- size = 0.12,
- cwd = '/tmp',
- }
- local pane_bottom = pane_main:split {
- direction = "Bottom",
- size = 0.05,
- }
- window:gui_window():maximize()
- pane_main:activate()
- pane_main:send_text "curl wttr.in?2\ncd "
- pane_spoti:send_text 'spotify_player\n'
- pane_bottom:send_text "date\n"
- end)
Мы используем событие gui-startup для настройки запуска WezTerm, в котором создаём новое окно с одной панелью pane_main, именем рабочего пространства main и некоторой директорией ~/dev. Затем мы разделяем pane_main вправо с размером 0.12 и другой директорией. Эта панель имеет название pane_spoti. То же самое для pane_bottom.
Дальше всё просто: разворачиваем окно WezTerm на весь экран, активируем главную панель и выполняем несколько команд в каждой панели.

Мы только что настроили лишь одно рабочее пространство, но вы можете создать сколько угодно, если укажете в новом окне workspace = 'something'.
Проекты
В этот раз мы используем аналогичный подход к мультиплексированию, но, вместо события gui-startup, запустим диалог выбора проекта с помощью комбинации клавиш:
- -- ~/.config/wezterm.lua
- local wezterm = require 'wezterm'
- local projects = require 'projects'
- -- .. config ..
- -- leader = { mods="CTRL", key = '\\', timeout_milliseconds = 1200 },
- keys = {
- -- projects
- {mods="LEADER", key="p", action=projects.choose_project()},
- {mods="CTRL|SHIFT", key="k", action=projects.choose_project()},
- -- rest key bindings...
- }
Здесь я настроил одно и то же действие для двух разных привязок: комбинации клавиш и лидера. Используйте ту, которая вам больше нравится, или обе, как я.
В choose_project мы построим список проектов и будем использовать InputSelector с включенной опцией fuzzy:
- function list_projects()
- -- список проектов
- -- смотрите следующий блок кода
- end
- function module.choose_project()
- local choices = {}
- for key, _ in pairs(list_projects()) do
- table.insert(choices, { id = key, label = key })
- end
- table.sort(choices, function(a, b) return a.id < b.id end)
- return wezterm.action.InputSelector {
- title = 'Projects',
- choices = choices,
- fuzzy = true,
- fuzzy_description = 'Enter a project name: ',
- action = wezterm.action_callback(function(window, pane, id, label)
- if not id then return end
- local projects = list_projects()
- if not projects[id] then return end
- local project = projects[id]
- return project(window, pane)
- end)
- }
- end

В list_projects мы укажем объект с именами проектов и функциями их инициализации. Для одной панели это будет single_project, а для других, более сложных конфигураций проектов, будет отдельная функция:
- -- ~/.config/projects.lua
- local wezterm = require 'wezterm'
- local utils = require 'utils'
- local module = {}
- -- Creates a project with single workspace
- local function single_project(name, command)
- return function(window, pane)
- return utils.workspace_single_pane( window, pane, name, command)
- end
- end
- local function project_blog(window, pane)
- local cwd = '/m/blog'
- return utils.workspace_double_pane(
- window, pane, "Left", "blog",
- 'cd ' .. cwd .. '/content\nyazi\n',
- 'cd ' .. cwd .. '\nzola serve'
- )
- end
- local function list_projects()
- return {
- -- projects
- blog = project_blog,
- -- apps
- app_spoti = single_project('spotify', 'spoti\n'),
- app_notes = single_project('notes', 'cd ~/notes/main\nmoar "./$(fzf)"\n'),
- app_budget = single_project('budget', 'cd /opt/actual && docker-compose up'),
- -- ssh zellij
- ssh_anm = single_project('ssh anm', 'ssh anm -t "zellij a"\n'),
- ssh_gm = single_project('ssh gm', 'ssh gm -t "zellij a main"\n'),
- ssh_oracle = single_project('ssh oracle', 'ssh oracle -t "zellij a"\n'),
- }
- end
- -- function module.choose_project()
- -- смотрите предыдущий блок кода
- -- end
- return module
Здесь я использую только одно- и двухпанельное рабочее пространство, но вы можете модифицировать этот пример и создать мощные проекты с динамическими проверками, установкой переменных окружения, использованием файлов .env, различных условий и т.д. Развлекайтесь!

Если проект нужно запускать часто, стоит подумать о том, чтобы запускать его напрямую по нажатию сочетания клавиш:
- -- ~/.config/projects.lua
- function module.blog()
- return wezterm.action_callback(project_blog)
- end
- -- ~/.config/wezterm.lua
- keys = {
- {mods="LEADER", key="b", action=projects.blog()},
- -- остальные сочетания клавиш...
- }
Полная конфигурация: github.com/annimon-tutorials/wezterm-projects
Стилизация
Этот серый диалог выбора выглядит так скучно, давайте добавим ему немного цвета и иконок. Вы можете использовать wezterm.format, чтобы применить стили к fuzzy_description:
- function module.choose_project()
- -- ...
- fuzzy = true,
- fuzzy_description = wezterm.format {
- { Attribute = { Intensity = 'Bold' }},
- { Foreground = { Color = '#aaffaa' }},
- { Text = 'Enter a project name: '}
- },
- -- ...
- end
Вместо определения собственных цветов можно использовать AnsiColor с 16 значениями: ■ Black, ■ Maroon, ■ Green, ■ Olive, ■ Navy, ■ Purple, ■ Teal, ■ Silver, ■ Grey, ■ Red, ■ Lime, ■ Yellow, ■ Blue, ■ Fuchsia, ■ Aqua или ■ White.
- { Foreground = { AnsiColor = 'Lime' }},
Для использования иконок смотрите страницу wezterm.nerdfonts.
Список проектов необходимо немного изменить:
- local function list_projects()
- return {
- -- projects
- blog = {
- label = wezterm.format {
- { Foreground = { AnsiColor = 'Fuchsia' }},
- { Text = wezterm.nerdfonts.md_typewriter },
- { Foreground = { AnsiColor = 'White' }},
- { Text = ' Blog' },
- },
- action = project_blog
- },
- -- apps
- app_spoti = {
- label = wezterm.format {
- { Foreground = { AnsiColor = 'Green' }},
- { Text = wezterm.nerdfonts.md_spotify },
- { Foreground = { AnsiColor = 'White' }},
- { Text = ' Spoti' },
- },
- action = single_project('spotify', 'spoti\n')
- },
- -- other
- }
- end
И функцию выбора проекта тоже:
- function module.choose_project()
- local choices = {}
- for key, value in pairs(list_projects()) do
- table.insert(choices, { label = value.label, id = key })
- end
- table.sort(choices, function(a, b) return a.id < b.id end)
- -- ...
- action = wezterm.action_callback(function(window, pane, id, label)
- -- ...
- local project = projects[id].action
- return project(window, pane)
- end)
- end)
Вот что у меня получилось

Полный конфиг: github.com/annimon-tutorials/wezterm-projects