mirror of
https://codeberg.org/muon/home.git
synced 2026-03-09 11:53:12 +00:00
Add stacked panes
This commit is contained in:
parent
9433fc31ea
commit
5e84e6aba8
1 changed files with 119 additions and 4 deletions
|
|
@ -152,7 +152,7 @@
|
|||
modes = {
|
||||
locked = {
|
||||
fg = color.base03;
|
||||
hint = "⌥: ⌥hl: ⌥1-9: ⌥n: ⌥w: ^ud:";
|
||||
hint = "⌥: ⌥hl: ^ud: ⌥1-9: ⌥n: ⌥s: ⌥w: ⌥t: ⌥p:";
|
||||
};
|
||||
normal = {
|
||||
fg = color.base0D;
|
||||
|
|
@ -207,6 +207,39 @@ in {
|
|||
end)
|
||||
end
|
||||
|
||||
-- tab_is_zoomed: true if any pane in the current tab is zoomed.
|
||||
-- Used by move_vertical to decide whether to carry zoom forward.
|
||||
local function tab_is_zoomed(pane)
|
||||
for _, info in ipairs(pane:tab():panes_with_info()) do
|
||||
if info.is_zoomed then return true end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
-- move_vertical: move focus Up/Down.
|
||||
-- If any pane in the tab is currently zoomed (zoom-mode is "on" for this
|
||||
-- tab), zoom the destination pane too — stacked-panel behaviour.
|
||||
-- Otherwise just move focus plainly.
|
||||
local function move_vertical(direction)
|
||||
return wezterm.action_callback(function(window, pane)
|
||||
local neighbour = pane:tab():get_pane_direction(direction)
|
||||
if neighbour == nil then return end
|
||||
if tab_is_zoomed(pane) then
|
||||
-- unzoom_on_switch_pane unzooms the current pane when we move;
|
||||
-- then SetPaneZoomState(true) zooms the newly active pane.
|
||||
window:perform_action(
|
||||
act.Multiple({
|
||||
act.ActivatePaneDirection(direction),
|
||||
act.SetPaneZoomState(true),
|
||||
}),
|
||||
pane
|
||||
)
|
||||
else
|
||||
window:perform_action(act.ActivatePaneDirection(direction), pane)
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
-- ─── Status bar ────────────────────────────────────────────────────────────
|
||||
|
||||
-- Per-mode accent colour and hint text, generated from Nix/stylix palette
|
||||
|
|
@ -251,6 +284,51 @@ in {
|
|||
return tab.active_pane.title
|
||||
end)
|
||||
|
||||
-- format-tab-title: show "rank/total title" when the active tab is in
|
||||
-- stacked (zoom) mode; otherwise show plain " title ".
|
||||
-- Returning a cell table gives us explicit padding and colours;
|
||||
-- returning a plain string loses the retro tab bar's built-in spacing.
|
||||
local tab_bg_active = "${color.base0D}"
|
||||
local tab_fg_active = "${color.base00}"
|
||||
local tab_bg_inactive = "${color.base01}"
|
||||
local tab_fg_inactive = "${color.base03}"
|
||||
|
||||
wezterm.on("format-tab-title", function(tab, _tabs, panes, _config, _hover, _max_width)
|
||||
local title = (tab.tab_title and tab.tab_title ~= "") and tab.tab_title or tab.active_pane.title
|
||||
local bg = tab.is_active and tab_bg_active or tab_bg_inactive
|
||||
local fg = tab.is_active and tab_fg_active or tab_fg_inactive
|
||||
|
||||
-- Only compute stack position for the active tab.
|
||||
-- The `panes` event parameter only contains the active pane snapshot
|
||||
-- and lacks `top`, so we use wezterm.mux.get_tab():panes_with_info()
|
||||
-- which returns full PaneInformation including top/is_zoomed/is_active.
|
||||
if tab.is_active then
|
||||
local mux_tab = wezterm.mux.get_tab(tab.tab_id)
|
||||
if mux_tab then
|
||||
local infos = mux_tab:panes_with_info()
|
||||
table.sort(infos, function(a, b) return a.top < b.top end)
|
||||
|
||||
local any_zoomed = false
|
||||
local active_rank, total = 0, 0
|
||||
for _, p in ipairs(infos) do
|
||||
total = total + 1
|
||||
if p.is_active then active_rank = total end
|
||||
if p.is_zoomed then any_zoomed = true end
|
||||
end
|
||||
|
||||
if any_zoomed and total > 1 and active_rank > 0 then
|
||||
title = active_rank .. "/" .. total .. " " .. title
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return {
|
||||
{ Background = { Color = bg } },
|
||||
{ Foreground = { Color = fg } },
|
||||
{ Text = " " .. title .. " " },
|
||||
}
|
||||
end)
|
||||
|
||||
wezterm.on("update-status", function(window, _pane)
|
||||
local kt = window:active_key_table()
|
||||
local mode = kt or "locked"
|
||||
|
|
@ -290,6 +368,7 @@ in {
|
|||
config.default_cursor_style = "BlinkingBar"
|
||||
config.hide_tab_bar_if_only_one_tab = false
|
||||
config.use_fancy_tab_bar = false
|
||||
config.tab_max_width = 24
|
||||
|
||||
config.colors = {
|
||||
tab_bar = {
|
||||
|
|
@ -313,6 +392,11 @@ in {
|
|||
|
||||
config.scrollback_lines = 10000
|
||||
|
||||
-- ─── Stacked panes ─────────────────────────────────────────────────────────
|
||||
-- When switching away from a zoomed pane, unzoom it automatically.
|
||||
-- Paired with stack_focus (Alt+j/k) this gives Zellij-style stacked panels.
|
||||
config.unzoom_on_switch_pane = true
|
||||
|
||||
-- ─── Key bindings ──────────────────────────────────────────────────────────
|
||||
--
|
||||
-- Default mode = "locked" (all keys pass through to the shell).
|
||||
|
|
@ -324,7 +408,7 @@ in {
|
|||
|
||||
config.keys = {
|
||||
-- Alt+h/l: move focus or switch tab at edge (Zellij MoveFocusOrTab)
|
||||
-- Alt+j/k: move focus between panes
|
||||
-- Alt+j/k: initial bindings (overridden below by stacked-focus variants)
|
||||
${viDirKeys {
|
||||
mods = "ALT";
|
||||
indent = " ";
|
||||
|
|
@ -340,6 +424,21 @@ in {
|
|||
}}
|
||||
-- Alt+n: new pane (split right)
|
||||
{ key = "n", mods = "ALT", action = act.SplitHorizontal({ domain = "CurrentPaneDomain" }) },
|
||||
-- Alt+s: split below, then zoom the new pane so stacked mode starts.
|
||||
-- Two separate perform_action calls: the split runs first and focuses
|
||||
-- the new pane, then the second call zooms window:active_pane() which
|
||||
-- is now the new pane (not the original `pane` argument).
|
||||
{ key = "s", mods = "ALT", action = wezterm.action_callback(function(window, pane)
|
||||
window:perform_action(act.SplitVertical({ domain = "CurrentPaneDomain" }), pane)
|
||||
window:perform_action(act.SetPaneZoomState(true), window:active_pane())
|
||||
end)
|
||||
},
|
||||
-- Alt+j/k: move_vertical — plain focus move normally, stacked zoom
|
||||
-- when any pane in the tab is already zoomed (mirrors Alt+f state).
|
||||
{ key = "j", mods = "ALT", action = move_vertical("Down") },
|
||||
{ key = "k", mods = "ALT", action = move_vertical("Up") },
|
||||
{ key = "DownArrow", mods = "ALT", action = move_vertical("Down") },
|
||||
{ key = "UpArrow", mods = "ALT", action = move_vertical("Up") },
|
||||
-- Alt+f: toggle zoom
|
||||
{ key = "f", mods = "ALT", action = act.TogglePaneZoomState },
|
||||
-- Alt+[/]: rotate panes
|
||||
|
|
@ -352,8 +451,24 @@ in {
|
|||
-- Alt+i/o: reorder tabs
|
||||
{ key = "i", mods = "ALT", action = act.MoveTabRelative(-1) },
|
||||
{ key = "o", mods = "ALT", action = act.MoveTabRelative(1) },
|
||||
-- Alt+w: close current pane
|
||||
{ key = "w", mods = "ALT", action = act.CloseCurrentPane({ confirm = true }) },
|
||||
-- Alt+w: close current pane; if tab was in stacked (zoom) mode, re-zoom
|
||||
-- the new active pane so zoom mode persists across close.
|
||||
-- confirm=false because the callback must run synchronously after close;
|
||||
-- a confirm dialog would make the zoom fire before the user answers.
|
||||
-- Guard: only re-zoom when there will still be panes left after close.
|
||||
{ key = "w", mods = "ALT", action = wezterm.action_callback(function(window, pane)
|
||||
local panes = pane:tab():panes()
|
||||
local was_zoomed = tab_is_zoomed(pane)
|
||||
window:perform_action(act.CloseCurrentPane({ confirm = false }), pane)
|
||||
if was_zoomed and #panes > 1 then
|
||||
window:perform_action(act.SetPaneZoomState(true), window:active_pane())
|
||||
end
|
||||
end)
|
||||
},
|
||||
-- Alt+p: command palette
|
||||
{ key = "p", mods = "ALT", action = act.ActivateCommandPalette },
|
||||
-- Alt+t: tab navigator (searchable tab list)
|
||||
{ key = "t", mods = "ALT", action = act.ShowTabNavigator },
|
||||
-- Alt+q: quit
|
||||
{ key = "q", mods = "ALT", action = act.QuitApplication },
|
||||
-- Ctrl+U/D: scroll half page (matches Alacritty)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue