fix: remove winfixheight from dapui panes, let user resize freely

winfixheight was locking Breakpoints, Console, Scopes, etc. to their
configured heights, fighting any attempt to manually resize. That's
hostile to user agency — someone with many breakpoints wants a taller
Breakpoints pane; someone tailing log output wants a taller Console.

pin_dapui_sizes still runs ONCE per M.enter to set the initial
proportions (25% each sidebar pane, 8-or-20% Console). After that,
user is free to drag splits, :resize, etc. and those sticks.

Removed the WinResized handler entirely (it was the aggressive
re-pinner that made user resizes bounce back). The VimResized handler
stays but only recreates bars that got killed by shrink; it no longer
re-pins dapui sizes. Trade-off: tiny-equalizer-style `wincmd =`
plugins will now successfully equalize during debug mode, but since
we've already told the user to disable that plugin, it's acceptable.

Bar windows themselves (status + legend) KEEP winfixheight because
they're chrome, not data — users shouldn't be resizing a status bar,
and locking them down prevents accidental drift.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
swaitsandClaude Opus 4.6 committed 2026-04-12 15:03:08 -06:00
1 parent 1758fad8ca
commit c202038455
1 file changed
+15 -41
+15 -41
View File
@@ -522,12 +522,12 @@ local function open_bars()
render_bars() render_bars()
end end
-- Pin dapui pane heights. Console gets its configured size. Sidebar -- Set dapui pane heights to their initial proportions. Called ONCE
-- panes get explicit equal distribution with any rounding remainder -- per M.enter, after dapui.open(). No winfixheight — the user is free
-- going to the LAST pane (Breakpoints) so it's never smaller than its -- to manually resize panes (bigger Breakpoints list, taller Console to
-- neighbors. winfixheight locks each pane against future rearrangements. -- tail long output, etc.) and their resize sticks because we don't
-- fight subsequent WinResized events. Initial sizing only.
local function pin_dapui_sizes() local function pin_dapui_sizes()
-- gather one window per dapui pane filetype
local pane_wins = {} local pane_wins = {}
for _, buf in ipairs(vim.api.nvim_list_bufs()) do for _, buf in ipairs(vim.api.nvim_list_bufs()) do
if vim.api.nvim_buf_is_valid(buf) then if vim.api.nvim_buf_is_valid(buf) then
@@ -542,16 +542,14 @@ local function pin_dapui_sizes()
end end
end end
-- Console -- Console to configured height
if pane_wins.dapui_console then if pane_wins.dapui_console then
local target = config.opts.console_height local target = config.opts.console_height
or math.max(8, math.floor(vim.o.lines * 0.2)) or math.max(8, math.floor(vim.o.lines * 0.2))
pcall(vim.api.nvim_win_set_height, pane_wins.dapui_console, target) pcall(vim.api.nvim_win_set_height, pane_wins.dapui_console, target)
end end
-- Sidebar: explicit equal distribution. Compute total current height -- Sidebar panes distributed equally (residual to Breakpoints)
-- of the four sidebar panes and divide evenly, handing any remainder
-- to Breakpoints (last pane) so it's never smaller than the others.
local order = { "dapui_stacks", "dapui_scopes", "dapui_watches", "dapui_breakpoints" } local order = { "dapui_stacks", "dapui_scopes", "dapui_watches", "dapui_breakpoints" }
local present = {} local present = {}
local total = 0 local total = 0
@@ -570,11 +568,6 @@ local function pin_dapui_sizes()
pcall(vim.api.nvim_win_set_height, w, h) pcall(vim.api.nvim_win_set_height, w, h)
end end
end end
-- winfixheight on everything
for _, w in pairs(pane_wins) do
pcall(function() vim.wo[w].winfixheight = true end)
end
end end
local function close_bars() local function close_bars()
@@ -589,11 +582,11 @@ local function close_bars()
end end
local function reposition_bars() local function reposition_bars()
-- Splits auto-track VimResized via winfixheight; re-render the bar -- Just re-render bar content. We intentionally DON'T re-pin dapui
-- content and re-pin dapui sizes so plugins like focus.nvim that -- sizes here — the user may have manually resized panes, and
-- auto-resize on focus change can't permanently skew the layout. -- fighting their resize on every event is a worse UX than occasional
-- layout drift.
render_bars() render_bars()
pin_dapui_sizes()
end end
-- ─── dap-ui setup ──────────────────────────────────────────────────────────── -- ─── dap-ui setup ────────────────────────────────────────────────────────────
@@ -1085,44 +1078,25 @@ function M.enter()
if active then M._install_for_buf(args.buf) end if active then M._install_for_buf(args.buf) end
end, end,
}) })
-- On editor resize: -- On editor resize: if a bar got killed by shrink-below-minimum,
-- 1) if any bar got killed by a shrink-below-minimum, recreate it -- recreate it. Do NOT re-pin dapui sizes — whatever the user
-- 2) re-pin dapui pane sizes (defensive against any plugin — our -- (or nvim's shrink/expand redistribution) arrived at is respected.
-- own, another's, or nvim's own shrink-recovery — that might
-- have skewed the layout).
-- Deferred via vim.schedule so we run AFTER other plugins' handlers.
vim.api.nvim_create_autocmd("VimResized", { vim.api.nvim_create_autocmd("VimResized", {
group = group, group = group,
callback = function() callback = function()
vim.schedule(function() vim.schedule(function()
if not active then return end if not active then return end
-- recreate missing bars
if not (sbar_win and vim.api.nvim_win_is_valid(sbar_win)) then if not (sbar_win and vim.api.nvim_win_is_valid(sbar_win)) then
sbar_win, sbar_buf = nil, nil sbar_win, sbar_buf = nil, nil
end end
if not (cbar_win and vim.api.nvim_win_is_valid(cbar_win)) then if not (cbar_win and vim.api.nvim_win_is_valid(cbar_win)) then
cbar_win, cbar_buf = nil, nil cbar_win, cbar_buf = nil, nil
end end
open_bars() -- idempotent; only creates what's missing open_bars() -- idempotent; only creates what's missing
pin_dapui_sizes()
render_bars() render_bars()
end) end)
end, end,
}) })
-- WinResized catches mouse-drag resizes and plugin-driven wincmd=
-- that don't fire VimResized. Guarded against self-recursion.
vim.api.nvim_create_autocmd("WinResized", {
group = group,
callback = function()
if M._pinning then return end
vim.schedule(function()
if not active then return end
M._pinning = true
pin_dapui_sizes()
M._pinning = false
end)
end,
})
for _, buf in ipairs(vim.api.nvim_list_bufs()) do for _, buf in ipairs(vim.api.nvim_list_bufs()) do
if vim.api.nvim_buf_is_loaded(buf) then M._install_for_buf(buf) end if vim.api.nvim_buf_is_loaded(buf) then M._install_for_buf(buf) end
end end