fix: stable sidebar + console sizing across toggle cycles
The "console fills the whole column" + "sidebar panes all fucked up on re-entry" bug traces to three interacting problems: 1. I was creating bars BEFORE dapui.open, then using `wincmd K/J` to force them to full width. That cascade recomputed every window height. dapui windows without winfixheight absorbed freed space unpredictably, and the drift accumulated on every toggle. 2. M.exit was closing our bars BEFORE dapui. When our bars closed, their 4 rows were freed; dapui grabbed those rows into Console and remembered the new size. Next open → Console ballooned. 3. Console height was coming out right on first entry but dapui's internal size tracker was letting it grow back on re-open. Fixes: - Open bars AFTER dapui.open. `:topleft split` and `:botright split` natively produce full-width horizontal splits above/below whatever layout already exists — no wincmd K/J rearrangement needed. - Close dapui BEFORE close_bars in M.exit so dapui doesn't see our bars disappearing and grow to fill the void. - New pin_dapui_sizes(): after dapui.open, iterate dapui panes and set winfixheight = true on all of them. Console gets an explicit set_height to config.opts.console_height (default 5) first. Panes are now locked — wincmd/resize can't mess with them. - Console height: fixed 5 rows (config.opts.console_height), no more dynamic min(5, 15% of avail) which was producing unstable values on re-entry. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 file changed
+49
-40
+49
-40
@@ -81,18 +81,12 @@ local ICON = {
|
|||||||
local function build_default_layouts()
|
local function build_default_layouts()
|
||||||
local pos = config.opts.sidebar == "right" and "right" or "left"
|
local pos = config.opts.sidebar == "right" and "right" or "left"
|
||||||
|
|
||||||
-- Console height: min(5 rows, 15% of available vertical space). Caps
|
-- Console height: fixed 5 rows. Dynamic sizing via min(5, 15%) was
|
||||||
-- at 5 rows — Console is ancillary; the sidebar panes and source area
|
-- producing the right number on first enter but dapui's internal
|
||||||
-- deserve most of the vertical space. On very tall terminals the 15%
|
-- layout tracker was letting Console grow back up on re-enter,
|
||||||
-- calc would dominate, so the min() clamp keeps Console compact.
|
-- eventually filling the column. A hard-coded size plus a post-open
|
||||||
local top_bar_rows = 2
|
-- `winfixheight = true` pin (see pin_dapui_sizes) stops the drift.
|
||||||
local bottom_bar_rows = 2
|
local console_size = config.opts.console_height or 5
|
||||||
local statusline_rows = vim.o.laststatus > 0 and 1 or 0
|
|
||||||
local cmdline_rows = math.max(1, vim.o.cmdheight)
|
|
||||||
local avail = vim.o.lines - top_bar_rows - bottom_bar_rows - statusline_rows - cmdline_rows
|
|
||||||
if avail < 10 then avail = 10 end
|
|
||||||
local console_size = math.min(5, math.floor(avail * 0.15))
|
|
||||||
if console_size < 3 then console_size = 3 end -- absolute floor so it's usable
|
|
||||||
|
|
||||||
-- Sidebar width: ideal 40 cols, never less than 25, never more than 1/3
|
-- Sidebar width: ideal 40 cols, never less than 25, never more than 1/3
|
||||||
-- of tty width. Scales down gracefully on narrow terminals, stops at 40
|
-- of tty width. Scales down gracefully on narrow terminals, stops at 40
|
||||||
@@ -137,7 +131,11 @@ local function define_highlights()
|
|||||||
-- seam between the bar and the surrounding panes.
|
-- seam between the bar and the surrounding panes.
|
||||||
hl(0, "TurboDebugBar", { default = true, link = "Normal" })
|
hl(0, "TurboDebugBar", { default = true, link = "Normal" })
|
||||||
hl(0, "TurboDebugBarSeparator", { default = true, link = "FloatBorder" })
|
hl(0, "TurboDebugBarSeparator", { default = true, link = "FloatBorder" })
|
||||||
hl(0, "TurboDebugBarCtrl", { default = true, link = "StatusLine" })
|
-- Control labels: link to Normal so the text blends with the bar's
|
||||||
|
-- Normal-bg surface. StatusLine bg was creating a visible color patch
|
||||||
|
-- behind each label. The key letter still pops via TurboDebugBarKey
|
||||||
|
-- (Special fg, bold), and icons carry their own emoji color.
|
||||||
|
hl(0, "TurboDebugBarCtrl", { default = true, link = "Normal" })
|
||||||
hl(0, "TurboDebugBarStatus", { default = true, link = "Comment" })
|
hl(0, "TurboDebugBarStatus", { default = true, link = "Comment" })
|
||||||
hl(0, "TurboDebugBarBrand", { default = true, link = "Title" })
|
hl(0, "TurboDebugBarBrand", { default = true, link = "Title" })
|
||||||
hl(0, "TurboDebugBarReady", { default = true, link = "DiagnosticHint" })
|
hl(0, "TurboDebugBarReady", { default = true, link = "DiagnosticHint" })
|
||||||
@@ -525,27 +523,30 @@ local function open_bars()
|
|||||||
render_bars()
|
render_bars()
|
||||||
end
|
end
|
||||||
|
|
||||||
-- After dapui has created its vertical splits (sidebar etc.), the bars
|
-- Pin every dapui pane's height so layout drift from subsequent wincmd
|
||||||
-- may be constrained to the non-sidebar column. `wincmd K` / `wincmd J`
|
-- rearrangements (or from our own bar manipulations) can't mess with
|
||||||
-- re-layout the window tree with the bar window spanning full editor
|
-- the sizing. Console is the main offender — without winfixheight it
|
||||||
-- width at the top / bottom respectively, pushing everything else into
|
-- absorbs freed rows on re-entry and eventually fills the column.
|
||||||
-- the middle rows.
|
local function pin_dapui_sizes()
|
||||||
local function force_bars_full_width()
|
local pane_fts = {
|
||||||
local caller_win = vim.api.nvim_get_current_win()
|
dapui_stacks = true, dapui_scopes = true, dapui_watches = true,
|
||||||
if sbar_win and vim.api.nvim_win_is_valid(sbar_win) then
|
dapui_breakpoints = true, dapui_console = true, ["dap-repl"] = true,
|
||||||
pcall(vim.api.nvim_set_current_win, sbar_win)
|
}
|
||||||
pcall(vim.cmd, "wincmd K")
|
for _, buf in ipairs(vim.api.nvim_list_bufs()) do
|
||||||
pcall(vim.api.nvim_win_set_height, sbar_win, 2)
|
if vim.api.nvim_buf_is_valid(buf) then
|
||||||
|
local ft = vim.bo[buf].filetype
|
||||||
|
if pane_fts[ft] then
|
||||||
|
for _, win in ipairs(vim.fn.win_findbuf(buf)) do
|
||||||
|
if vim.api.nvim_win_is_valid(win) then
|
||||||
|
if ft == "dapui_console" then
|
||||||
|
pcall(vim.api.nvim_win_set_height, win, config.opts.console_height or 5)
|
||||||
|
end
|
||||||
|
pcall(function() vim.wo[win].winfixheight = true end)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
if cbar_win and vim.api.nvim_win_is_valid(cbar_win) then
|
|
||||||
pcall(vim.api.nvim_set_current_win, cbar_win)
|
|
||||||
pcall(vim.cmd, "wincmd J")
|
|
||||||
pcall(vim.api.nvim_win_set_height, cbar_win, 2)
|
|
||||||
end
|
|
||||||
if vim.api.nvim_win_is_valid(caller_win) then
|
|
||||||
pcall(vim.api.nvim_set_current_win, caller_win)
|
|
||||||
end
|
|
||||||
render_bars()
|
|
||||||
end
|
end
|
||||||
|
|
||||||
local function close_bars()
|
local function close_bars()
|
||||||
@@ -1064,12 +1065,15 @@ function M.enter()
|
|||||||
set_debug_chrome()
|
set_debug_chrome()
|
||||||
ensure_dapui()
|
ensure_dapui()
|
||||||
require("dapui").open()
|
require("dapui").open()
|
||||||
|
-- Create bars AFTER dapui.open so :topleft split / :botright split
|
||||||
|
-- create full-width splits above/below whatever dapui built. Doing it
|
||||||
|
-- before dapui meant dapui's sidebar-vsplit could extend through the
|
||||||
|
-- bar rows, and my old `wincmd K/J` compensation caused layout drift
|
||||||
|
-- on re-entry (Console ballooning). Opening after dapui avoids both.
|
||||||
open_bars()
|
open_bars()
|
||||||
-- dapui creates full-height vertical splits for the sidebar. Without
|
-- Pin dapui pane heights so re-entry / resize doesn't let Console
|
||||||
-- this step the bars end up constrained to the non-sidebar column.
|
-- absorb freed rows.
|
||||||
-- `wincmd K`/`J` rearranges the window tree so each bar spans full
|
pin_dapui_sizes()
|
||||||
-- editor width at the top/bottom, pushing everything else in-between.
|
|
||||||
force_bars_full_width()
|
|
||||||
|
|
||||||
-- second install pass after dapui has created its buffers
|
-- second install pass after dapui has created its buffers
|
||||||
vim.schedule(function()
|
vim.schedule(function()
|
||||||
@@ -1077,7 +1081,8 @@ function M.enter()
|
|||||||
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
|
||||||
reposition_bars()
|
pin_dapui_sizes()
|
||||||
|
render_bars()
|
||||||
end)
|
end)
|
||||||
|
|
||||||
ensure_vt()
|
ensure_vt()
|
||||||
@@ -1095,10 +1100,14 @@ function M.exit()
|
|||||||
pcall(vim.api.nvim_del_augroup_by_name, "TurboDebugModalKeys")
|
pcall(vim.api.nvim_del_augroup_by_name, "TurboDebugModalKeys")
|
||||||
clear_all_modal_keys()
|
clear_all_modal_keys()
|
||||||
clear_debug_chrome()
|
clear_debug_chrome()
|
||||||
close_bars()
|
|
||||||
help.close()
|
help.close()
|
||||||
|
|
||||||
|
-- Close dapui FIRST so dapui's windows tear down into a state we
|
||||||
|
-- control. Closing our bars first would let dapui's remaining panes
|
||||||
|
-- expand into the freed rows, which dapui then "remembers" and
|
||||||
|
-- breaks the next open's layout.
|
||||||
if dapui_initialized then require("dapui").close() end
|
if dapui_initialized then require("dapui").close() end
|
||||||
|
close_bars()
|
||||||
if vt_initialized then require("nvim-dap-virtual-text").disable() end
|
if vt_initialized then require("nvim-dap-virtual-text").disable() end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user