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