mirror of
https://codeberg.org/muon/home.git
synced 2026-03-09 20:03: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 = {
|
modes = {
|
||||||
locked = {
|
locked = {
|
||||||
fg = color.base03;
|
fg = color.base03;
|
||||||
hint = "⌥: ⌥hl: ⌥1-9: ⌥n: ⌥w: ^ud:";
|
hint = "⌥: ⌥hl: ^ud: ⌥1-9: ⌥n: ⌥s: ⌥w: ⌥t: ⌥p:";
|
||||||
};
|
};
|
||||||
normal = {
|
normal = {
|
||||||
fg = color.base0D;
|
fg = color.base0D;
|
||||||
|
|
@ -207,6 +207,39 @@ in {
|
||||||
end)
|
end)
|
||||||
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 ────────────────────────────────────────────────────────────
|
-- ─── Status bar ────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
-- Per-mode accent colour and hint text, generated from Nix/stylix palette
|
-- Per-mode accent colour and hint text, generated from Nix/stylix palette
|
||||||
|
|
@ -251,6 +284,51 @@ in {
|
||||||
return tab.active_pane.title
|
return tab.active_pane.title
|
||||||
end)
|
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)
|
wezterm.on("update-status", function(window, _pane)
|
||||||
local kt = window:active_key_table()
|
local kt = window:active_key_table()
|
||||||
local mode = kt or "locked"
|
local mode = kt or "locked"
|
||||||
|
|
@ -290,6 +368,7 @@ in {
|
||||||
config.default_cursor_style = "BlinkingBar"
|
config.default_cursor_style = "BlinkingBar"
|
||||||
config.hide_tab_bar_if_only_one_tab = false
|
config.hide_tab_bar_if_only_one_tab = false
|
||||||
config.use_fancy_tab_bar = false
|
config.use_fancy_tab_bar = false
|
||||||
|
config.tab_max_width = 24
|
||||||
|
|
||||||
config.colors = {
|
config.colors = {
|
||||||
tab_bar = {
|
tab_bar = {
|
||||||
|
|
@ -313,6 +392,11 @@ in {
|
||||||
|
|
||||||
config.scrollback_lines = 10000
|
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 ──────────────────────────────────────────────────────────
|
-- ─── Key bindings ──────────────────────────────────────────────────────────
|
||||||
--
|
--
|
||||||
-- Default mode = "locked" (all keys pass through to the shell).
|
-- Default mode = "locked" (all keys pass through to the shell).
|
||||||
|
|
@ -324,7 +408,7 @@ in {
|
||||||
|
|
||||||
config.keys = {
|
config.keys = {
|
||||||
-- Alt+h/l: move focus or switch tab at edge (Zellij MoveFocusOrTab)
|
-- 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 {
|
${viDirKeys {
|
||||||
mods = "ALT";
|
mods = "ALT";
|
||||||
indent = " ";
|
indent = " ";
|
||||||
|
|
@ -340,6 +424,21 @@ in {
|
||||||
}}
|
}}
|
||||||
-- Alt+n: new pane (split right)
|
-- Alt+n: new pane (split right)
|
||||||
{ key = "n", mods = "ALT", action = act.SplitHorizontal({ domain = "CurrentPaneDomain" }) },
|
{ 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
|
-- Alt+f: toggle zoom
|
||||||
{ key = "f", mods = "ALT", action = act.TogglePaneZoomState },
|
{ key = "f", mods = "ALT", action = act.TogglePaneZoomState },
|
||||||
-- Alt+[/]: rotate panes
|
-- Alt+[/]: rotate panes
|
||||||
|
|
@ -352,8 +451,24 @@ in {
|
||||||
-- Alt+i/o: reorder tabs
|
-- Alt+i/o: reorder tabs
|
||||||
{ key = "i", mods = "ALT", action = act.MoveTabRelative(-1) },
|
{ key = "i", mods = "ALT", action = act.MoveTabRelative(-1) },
|
||||||
{ key = "o", mods = "ALT", action = act.MoveTabRelative(1) },
|
{ key = "o", mods = "ALT", action = act.MoveTabRelative(1) },
|
||||||
-- Alt+w: close current pane
|
-- Alt+w: close current pane; if tab was in stacked (zoom) mode, re-zoom
|
||||||
{ key = "w", mods = "ALT", action = act.CloseCurrentPane({ confirm = true }) },
|
-- 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
|
-- Alt+q: quit
|
||||||
{ key = "q", mods = "ALT", action = act.QuitApplication },
|
{ key = "q", mods = "ALT", action = act.QuitApplication },
|
||||||
-- Ctrl+U/D: scroll half page (matches Alacritty)
|
-- Ctrl+U/D: scroll half page (matches Alacritty)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue