feat: split bar into top status + bottom controls, drop REPL pane

Layout overhaul per UX feedback — the 4-row bottom bar was too much and
mixing status info with action controls in one block felt crammed.

New chrome:
  ┌── row 0 ──────────────────────────────────────────────┐
  │  turbo-debug       dap.status msg     DEBUG · STATE   │  ← top bar
  ├───────────────────────────────────────────────────────┤
  │  source code…                                         │
  │  (filename winbar now shows just %f, no DEBUG prefix) │
  ├── bottom tray (Console, 10 rows, full width) ─────────┤
  ├───────────────────────────────────────────────────────┤
  │  (c)ontinue (s)tep (d)escend (r)eturn …      ❓ help  │  ← control bar
  │  statusline (user's lualine untouched)                │
  │  cmdline                                              │
  └───────────────────────────────────────────────────────┘

- Top bar (2 rows, sbar_win): brand on left, dap.status() in middle,
  colored state chip (DEBUG · READY/RUNNING/PAUSED) on right.
- Bottom bar (2 rows, cbar_win): controls centered, help right-anchored.
  Down from 4 rows to 2 — no more crammed single-row layout.
- REPL pane removed from the bottom tray. Duplicates Console for most
  workflows and the horizontal space is better spent on program output.
  Users who want a REPL can hit E in debug mode to open it as a float.
- Console (bottom tray) now gets the full width and size 10 (was 8 in a
  split).
- Source file winbar simplified to just " %f" — the DEBUG · STATE chip
  has moved to the top bar where it belongs.

Total chrome cost: 2 (top) + 10 (tray) + 2 (bottom) + 1 (statusline) +
1 (cmdline) = 16 rows. Previous: 4 (bar) + 8 (tray) + 1 + 1 = 14.
Trade 2 extra chrome rows for vastly better layout clarity.

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 13:43:55 -06:00
1 parent 5477df4578
commit 869a4a36d9
1 file changed
+248 -166
+248 -166
View File
@@ -7,8 +7,15 @@ local active = false
local active_win = nil
local saved_winbar = nil
-- floating control-bar window (independent of lualine)
local bar_win, bar_buf = nil, nil
-- two floating chrome bars (both independent of lualine):
-- sbar = status bar pinned at the TOP of the editor.
-- Row 0: turbo-debug · {dap status} · DEBUG · STATE
-- Row 1: ─── separator
-- cbar = control bar pinned just above the statusline.
-- Row 0: ─── separator
-- Row 1: {controls} ❓ help
local sbar_win, sbar_buf = nil, nil
local cbar_win, cbar_buf = nil, nil
-- installed[buf][name] = { key = lhs, prev_n = <prev n-mode map>, prev_v = <prev v-mode map> }
local installed = {}
@@ -91,13 +98,14 @@ local function build_default_layouts()
},
},
{
-- 8 rows — the control bar below takes 4 rows (sep + state + controls
-- + sep). 8 + 4 = 12, matching the dapui default tray size.
-- Console only; REPL removed because it duplicates Console for most
-- workflows and the horizontal space is better spent on program
-- output. Users who want a REPL can hit `E` in debug mode to open
-- it as a floating widget.
position = "bottom",
size = 8,
size = 10,
elements = {
{ id = "repl", size = 0.50 },
{ id = "console", size = 0.50 },
{ id = "console", size = 1.0 },
},
},
}
@@ -114,6 +122,7 @@ local function define_highlights()
hl(0, "TurboDebugBarSeparator", { default = true, link = "FloatBorder" })
hl(0, "TurboDebugBarCtrl", { default = true, link = "StatusLine" })
hl(0, "TurboDebugBarStatus", { default = true, link = "Comment" })
hl(0, "TurboDebugBarBrand", { default = true, link = "Title" })
hl(0, "TurboDebugBarReady", { default = true, link = "DiagnosticHint" })
hl(0, "TurboDebugBarRunning", { default = true, link = "DiagnosticInfo" })
hl(0, "TurboDebugBarPaused", { default = true, link = "DiagnosticError" })
@@ -163,20 +172,18 @@ local function setup_active_win_highlights()
})
end
-- ─── control bar (buffer-rendered, not winbar — survives floating windows) ──
-- Layout: a 2-row floating window pinned above the statusline.
-- Row 0: a full-width ─ separator line (distinguishes bar from REPL/Console).
-- Row 1: state chip + clickable control buttons + dap status + cursor pos.
-- Content is written to the buffer directly (winbar doesn't render reliably
-- in minimal-style floats). Highlights via extmarks. Clicks via a buffer-local
-- <LeftMouse> keymap that inspects cursor column and dispatches.
-- ─── chrome bars (top = status, bottom = controls) ─────────────────────────
--
-- Both bars are floating windows with buffer-rendered content (winbar
-- doesn't render reliably in minimal-style floats). Highlights via
-- extmarks; mouse click dispatch via buffer-local <LeftMouse> keymap +
-- per-zone display-column lookup.
local bar_ns = vim.api.nvim_create_namespace("turbo-debug.bar")
-- `click_zones` is populated by render_bar: each entry is { col_start, col_end, fn }.
-- On <LeftMouse> in the bar, we look up the cursor column and fire the matching fn.
local click_zones = {}
-- click zones, one table per bar. Each entry: { line_1based, dcol_start, dcol_end, fn }
local sbar_zones = {}
local cbar_zones = {}
local function dap_state()
local ok, dap = pcall(require, "dap")
@@ -215,55 +222,87 @@ local function build_control_text(icon, key, tail)
return table.concat(parts), key_col, key_end_col
end
-- 4-row bar layout:
-- row 0 (line 1): ─ top separator
-- row 1 (line 2): state chip + dap.status() ❓ help
-- row 2 (line 3): controls (centered)
-- row 3 (line 4): ─ bottom separator
-- Help is on its own anchored right-of-row-1 so it can NEVER be pushed
-- off by long status text or wide control labels.
local function render_bar()
if not (bar_buf and vim.api.nvim_buf_is_valid(bar_buf)) then return end
if not (bar_win and vim.api.nvim_win_is_valid(bar_win)) then return end
local function render_sbar()
if not (sbar_buf and vim.api.nvim_buf_is_valid(sbar_buf)) then return end
if not (sbar_win and vim.api.nvim_win_is_valid(sbar_win)) then return end
local width = vim.api.nvim_win_get_width(bar_win)
local width = vim.api.nvim_win_get_width(sbar_win)
if width < 1 then width = vim.o.columns end
local sep = string.rep(ICON.hline, width)
local state, state_hl = dap_state()
-- ─── ROW 1: state info + help ───────────────────────────
local chip_text = " " .. ICON.bug .. " DEBUG " .. ICON.divider .. " " .. state .. " "
-- layout: [brand] [status msg] [state chip]
local brand_text = " turbo-debug "
local status_ok, status_msg = pcall(function() return require("dap").status() end)
if not status_ok then status_msg = "" end
local status_text = status_msg ~= "" and (" " .. status_msg) or ""
local help_text = ICON.help .. " help "
local state_chip = " DEBUG " .. ICON.divider .. " " .. state .. " "
-- fit-check: if status is too long, truncate it so help stays anchored
local chip_dw = vim.fn.strdisplaywidth(chip_text)
local help_dw = vim.fn.strdisplaywidth(help_text)
local status_dw = vim.fn.strdisplaywidth(status_text)
local needed = chip_dw + status_dw + help_dw + 2 -- at least 2 cells of spacer
if needed > width and status_dw > 0 then
local max_status = width - chip_dw - help_dw - 5
if max_status > 5 then
status_text = " " .. status_msg:sub(1, max_status - 3) .. ICON.ellipsis
status_dw = vim.fn.strdisplaywidth(status_text)
else
status_text = ""
status_dw = 0
end
local brand_dw = vim.fn.strdisplaywidth(brand_text)
local chip_dw = vim.fn.strdisplaywidth(state_chip)
-- fit status msg if too long
local status_dw = vim.fn.strdisplaywidth(status_msg)
local available = width - brand_dw - chip_dw - 4
if status_dw > available and available > 5 then
status_msg = status_msg:sub(1, available - 1) .. ICON.ellipsis
status_dw = vim.fn.strdisplaywidth(status_msg)
elseif available <= 5 then
status_msg = ""
status_dw = 0
end
local left_state = chip_text .. status_text
local left_state_dw = chip_dw + status_dw
local state_pad = width - left_state_dw - help_dw
if state_pad < 1 then state_pad = 1 end
local state_line = left_state .. string.rep(" ", state_pad) .. help_text
local remain = width - brand_dw - status_dw - chip_dw
if remain < 2 then remain = 2 end
-- split evenly on either side of the status msg
local pad_left = math.floor(remain / 2)
local pad_right = remain - pad_left
local top_line = brand_text .. string.rep(" ", pad_left) .. status_msg .. string.rep(" ", pad_right) .. state_chip
-- ─── ROW 2: controls (centered) ─────────────────────────
-- Modal variants so the text reflects what the key will ACTUALLY do:
vim.bo[sbar_buf].modifiable = true
vim.api.nvim_buf_set_lines(sbar_buf, 0, -1, false, { top_line, sep })
vim.bo[sbar_buf].modifiable = false
vim.api.nvim_buf_clear_namespace(sbar_buf, bar_ns, 0, -1)
-- brand
pcall(vim.api.nvim_buf_set_extmark, sbar_buf, bar_ns, 0, 0, {
end_row = 0, end_col = #brand_text, hl_group = "TurboDebugBarBrand",
})
-- status (middle)
if status_dw > 0 then
local status_byte_start = #brand_text + pad_left
pcall(vim.api.nvim_buf_set_extmark, sbar_buf, bar_ns, 0, status_byte_start, {
end_row = 0, end_col = status_byte_start + #status_msg, hl_group = "TurboDebugBarStatus",
})
end
-- state chip (right)
local chip_byte_start = #top_line - #state_chip
pcall(vim.api.nvim_buf_set_extmark, sbar_buf, bar_ns, 0, chip_byte_start, {
end_row = 0, end_col = #top_line, hl_group = state_hl,
})
-- separator
pcall(vim.api.nvim_buf_set_extmark, sbar_buf, bar_ns, 1, 0, {
end_row = 1, end_col = #sep, hl_group = "TurboDebugBarSeparator",
})
sbar_zones = {}
end
local function render_cbar()
if not (cbar_buf and vim.api.nvim_buf_is_valid(cbar_buf)) then return end
if not (cbar_win and vim.api.nvim_win_is_valid(cbar_win)) then return end
local width = vim.api.nvim_win_get_width(cbar_win)
if width < 1 then width = vim.o.columns end
local sep = string.rep(ICON.hline, width)
local state, _ = dap_state()
local help_text = ICON.help .. " help "
local help_dw = vim.fn.strdisplaywidth(help_text)
-- Modal control labels. State-dependent text so the label shows what
-- the key will ACTUALLY do right now:
-- no session: (c) start (q)uit
-- active: (c)ontinue (q) terminate
local has_session = state ~= "READY"
@@ -299,86 +338,72 @@ local function render_bar()
end
local controls_text = table.concat(ctrl_parts)
local controls_dw = vim.fn.strdisplaywidth(controls_text)
local ctrl_pad_left = math.floor((width - controls_dw) / 2)
if ctrl_pad_left < 0 then ctrl_pad_left = 0 end
local ctrl_pad_right = width - controls_dw - ctrl_pad_left
if ctrl_pad_right < 0 then ctrl_pad_right = 0 end
local controls_line = string.rep(" ", ctrl_pad_left) .. controls_text .. string.rep(" ", ctrl_pad_right)
-- ─── commit buffer + extmarks ──────────────────────────
vim.bo[bar_buf].modifiable = true
vim.api.nvim_buf_set_lines(bar_buf, 0, -1, false, { sep, state_line, controls_line, sep })
vim.bo[bar_buf].modifiable = false
-- controls centered between left edge and help (right anchor)
local ctrl_zone_width = width - help_dw
local ctrl_pad_left = math.floor((ctrl_zone_width - controls_dw) / 2)
if ctrl_pad_left < 1 then ctrl_pad_left = 1 end
local ctrl_pad_right = ctrl_zone_width - controls_dw - ctrl_pad_left
if ctrl_pad_right < 1 then ctrl_pad_right = 1 end
local bottom_line = string.rep(" ", ctrl_pad_left) .. controls_text .. string.rep(" ", ctrl_pad_right) .. help_text
vim.api.nvim_buf_clear_namespace(bar_buf, bar_ns, 0, -1)
vim.bo[cbar_buf].modifiable = true
vim.api.nvim_buf_set_lines(cbar_buf, 0, -1, false, { sep, bottom_line })
vim.bo[cbar_buf].modifiable = false
-- top + bottom separator highlights
pcall(vim.api.nvim_buf_set_extmark, bar_buf, bar_ns, 0, 0, {
vim.api.nvim_buf_clear_namespace(cbar_buf, bar_ns, 0, -1)
pcall(vim.api.nvim_buf_set_extmark, cbar_buf, bar_ns, 0, 0, {
end_row = 0, end_col = #sep, hl_group = "TurboDebugBarSeparator",
})
pcall(vim.api.nvim_buf_set_extmark, bar_buf, bar_ns, 3, 0, {
end_row = 3, end_col = #sep, hl_group = "TurboDebugBarSeparator",
})
-- row 1: state chip color + status + help
pcall(vim.api.nvim_buf_set_extmark, bar_buf, bar_ns, 1, 0, {
end_row = 1, end_col = #chip_text, hl_group = state_hl,
})
if #status_text > 0 then
pcall(vim.api.nvim_buf_set_extmark, bar_buf, bar_ns, 1, #chip_text, {
end_row = 1, end_col = #chip_text + #status_text, hl_group = "TurboDebugBarStatus",
})
end
local help_byte_start = #state_line - #help_text
pcall(vim.api.nvim_buf_set_extmark, bar_buf, bar_ns, 1, help_byte_start, {
end_row = 1, end_col = #state_line, hl_group = "TurboDebugBarCtrl",
})
-- row 2: controls (offset by ctrl_pad_left bytes, which is all ASCII spaces)
-- control labels
local ctrl_byte_offset = ctrl_pad_left -- spaces are 1 byte each
click_zones = {}
for _, span in ipairs(ctrl_spans) do
pcall(vim.api.nvim_buf_set_extmark, bar_buf, bar_ns, 2, ctrl_byte_offset + span[1], {
end_row = 2, end_col = ctrl_byte_offset + span[2], hl_group = span[3],
pcall(vim.api.nvim_buf_set_extmark, cbar_buf, bar_ns, 1, ctrl_byte_offset + span[1], {
end_row = 1, end_col = ctrl_byte_offset + span[2], hl_group = span[3],
})
end
for _, span in ipairs(ctrl_key_spans) do
pcall(vim.api.nvim_buf_set_extmark, bar_buf, bar_ns, 2, ctrl_byte_offset + span[1], {
end_row = 2, end_col = ctrl_byte_offset + span[2], hl_group = "TurboDebugBarKey",
pcall(vim.api.nvim_buf_set_extmark, cbar_buf, bar_ns, 1, ctrl_byte_offset + span[1], {
end_row = 1, end_col = ctrl_byte_offset + span[2], hl_group = "TurboDebugBarKey",
})
end
-- click zones — stored as { line_number_1_based, dcol_start, dcol_end, fn }
-- help click lives on row 1 (line 2)
local help_dcol_start = vim.fn.strdisplaywidth(state_line:sub(1, help_byte_start))
local help_dcol_end = vim.fn.strdisplaywidth(state_line)
click_zones[#click_zones + 1] = { 2, help_dcol_start, help_dcol_end,
function() require("turbo-debug.help").open() end }
-- control clicks live on row 2 (line 3)
-- help (right-anchored)
local help_byte_start = #bottom_line - #help_text
pcall(vim.api.nvim_buf_set_extmark, cbar_buf, bar_ns, 1, help_byte_start, {
end_row = 1, end_col = #bottom_line, hl_group = "TurboDebugBarCtrl",
})
cbar_zones = {}
for _, z in ipairs(ctrl_zones_bytes) do
local byte_start = ctrl_byte_offset + z[1]
local byte_end = ctrl_byte_offset + z[2]
local dcol_start = vim.fn.strdisplaywidth(controls_line:sub(1, byte_start))
local dcol_end = vim.fn.strdisplaywidth(controls_line:sub(1, byte_end))
click_zones[#click_zones + 1] = { 3, dcol_start, dcol_end, z[3] }
local dcol_start = vim.fn.strdisplaywidth(bottom_line:sub(1, byte_start))
local dcol_end = vim.fn.strdisplaywidth(bottom_line:sub(1, byte_end))
cbar_zones[#cbar_zones + 1] = { 2, dcol_start, dcol_end, z[3] }
end
-- help click zone
local help_dcol_start = vim.fn.strdisplaywidth(bottom_line:sub(1, help_byte_start))
local help_dcol_end = vim.fn.strdisplaywidth(bottom_line)
cbar_zones[#cbar_zones + 1] = { 2, help_dcol_start, help_dcol_end,
function() require("turbo-debug.help").open() end }
end
local function bar_position()
-- 4 rows: ─ top sep / state+help / controls / ─ bottom sep
local row
if vim.o.laststatus > 0 then
row = vim.o.lines - vim.o.cmdheight - 5 -- 4 (bar) + 1 (statusline)
else
row = vim.o.lines - vim.o.cmdheight - 4 -- 4 (bar)
end
if row < 0 then row = 0 end
local function render_bars()
render_sbar()
render_cbar()
end
local function sbar_position()
-- 2 rows at the top of the editor, row 0 (below any tabline if present).
local top_row = vim.o.showtabline >= 2 and 1 or 0
return {
relative = "editor",
row = row,
row = top_row,
col = 0,
width = vim.o.columns,
height = 4,
height = 2,
style = "minimal",
border = "none",
focusable = false,
@@ -387,75 +412,129 @@ local function bar_position()
}
end
local function handle_bar_click()
local function cbar_position()
-- 2 rows just above the statusline.
local row
if vim.o.laststatus > 0 then
row = vim.o.lines - vim.o.cmdheight - 3 -- 2 (bar) + 1 (statusline)
else
row = vim.o.lines - vim.o.cmdheight - 2 -- 2 (bar)
end
if row < 0 then row = 0 end
return {
relative = "editor",
row = row,
col = 0,
width = vim.o.columns,
height = 2,
style = "minimal",
border = "none",
focusable = false,
noautocmd = true,
zindex = 50,
}
end
local function handle_sbar_click()
local pos = vim.fn.getmousepos()
if not pos or pos.winid ~= bar_win then return end
local col = pos.wincol - 1
for _, zone in ipairs(click_zones) do
if zone[1] == pos.line and col >= zone[2] and col < zone[3] then
if not pos or pos.winid ~= sbar_win then return end
for _, zone in ipairs(sbar_zones) do
if zone[1] == pos.line and pos.wincol - 1 >= zone[2] and pos.wincol - 1 < zone[3] then
zone[4]()
return
end
end
end
local function open_bar()
if bar_win and vim.api.nvim_win_is_valid(bar_win) then
render_bar()
return
local function handle_cbar_click()
local pos = vim.fn.getmousepos()
if not pos or pos.winid ~= cbar_win then return end
for _, zone in ipairs(cbar_zones) do
if zone[1] == pos.line and pos.wincol - 1 >= zone[2] and pos.wincol - 1 < zone[3] then
zone[4]()
return
end
end
bar_buf = vim.api.nvim_create_buf(false, true)
vim.bo[bar_buf].bufhidden = "wipe"
vim.bo[bar_buf].buftype = "nofile"
vim.bo[bar_buf].swapfile = false
vim.bo[bar_buf].buflisted = false
vim.bo[bar_buf].filetype = "TurboDebugBar"
bar_win = vim.api.nvim_open_win(bar_buf, false, bar_position())
vim.wo[bar_win].winhighlight = "Normal:TurboDebugBar,EndOfBuffer:TurboDebugBar"
vim.wo[bar_win].winfixheight = true
vim.wo[bar_win].list = false
vim.wo[bar_win].cursorline = false
vim.wo[bar_win].number = false
vim.wo[bar_win].relativenumber = false
vim.wo[bar_win].signcolumn = "no"
vim.wo[bar_win].statuscolumn = ""
vim.wo[bar_win].wrap = false
end
-- click dispatch
vim.keymap.set("n", "<LeftMouse>", handle_bar_click, { buffer = bar_buf, silent = true, nowait = true })
vim.keymap.set("n", "<LeftRelease>", "<Nop>", { buffer = bar_buf, silent = true, nowait = true })
local function setup_bar_buf(buf)
vim.bo[buf].bufhidden = "wipe"
vim.bo[buf].buftype = "nofile"
vim.bo[buf].swapfile = false
vim.bo[buf].buflisted = false
vim.bo[buf].filetype = "TurboDebugBar"
end
-- Safety net: if the user somehow lands in the bar buffer (mouse drag into
-- it, or some focus accident), bounce them back out immediately. Stops
-- them from hitting E21 "Cannot make changes, 'modifiable' is off" when
-- they try to type in a non-modifiable buffer.
local function setup_bar_win(win)
vim.wo[win].winhighlight = "Normal:TurboDebugBar,EndOfBuffer:TurboDebugBar"
vim.wo[win].winfixheight = true
vim.wo[win].list = false
vim.wo[win].cursorline = false
vim.wo[win].number = false
vim.wo[win].relativenumber = false
vim.wo[win].signcolumn = "no"
vim.wo[win].statuscolumn = ""
vim.wo[win].wrap = false
end
local function bounce_out(buf)
-- if focus lands in a bar buffer (e.g. mouse drag), kick it back out
-- so the user can't accidentally type into a non-modifiable buffer.
vim.api.nvim_create_autocmd("BufEnter", {
buffer = bar_buf,
buffer = buf,
callback = function()
vim.schedule(function()
if vim.api.nvim_get_current_buf() == bar_buf then
if vim.api.nvim_get_current_buf() == buf then
pcall(vim.cmd, "wincmd p")
end
end)
end,
})
render_bar()
end
local function close_bar()
if bar_win and vim.api.nvim_win_is_valid(bar_win) then
pcall(vim.api.nvim_win_close, bar_win, true)
local function open_bars()
-- status bar (top)
if not (sbar_win and vim.api.nvim_win_is_valid(sbar_win)) then
sbar_buf = vim.api.nvim_create_buf(false, true)
setup_bar_buf(sbar_buf)
sbar_win = vim.api.nvim_open_win(sbar_buf, false, sbar_position())
setup_bar_win(sbar_win)
vim.keymap.set("n", "<LeftMouse>", handle_sbar_click, { buffer = sbar_buf, silent = true, nowait = true })
vim.keymap.set("n", "<LeftRelease>", "<Nop>", { buffer = sbar_buf, silent = true, nowait = true })
bounce_out(sbar_buf)
end
bar_win, bar_buf = nil, nil
click_zones = {}
-- control bar (bottom)
if not (cbar_win and vim.api.nvim_win_is_valid(cbar_win)) then
cbar_buf = vim.api.nvim_create_buf(false, true)
setup_bar_buf(cbar_buf)
cbar_win = vim.api.nvim_open_win(cbar_buf, false, cbar_position())
setup_bar_win(cbar_win)
vim.keymap.set("n", "<LeftMouse>", handle_cbar_click, { buffer = cbar_buf, silent = true, nowait = true })
vim.keymap.set("n", "<LeftRelease>", "<Nop>", { buffer = cbar_buf, silent = true, nowait = true })
bounce_out(cbar_buf)
end
render_bars()
end
local function reposition_bar()
if bar_win and vim.api.nvim_win_is_valid(bar_win) then
pcall(vim.api.nvim_win_set_config, bar_win, bar_position())
render_bar()
local function close_bars()
if sbar_win and vim.api.nvim_win_is_valid(sbar_win) then
pcall(vim.api.nvim_win_close, sbar_win, true)
end
if cbar_win and vim.api.nvim_win_is_valid(cbar_win) then
pcall(vim.api.nvim_win_close, cbar_win, true)
end
sbar_win, sbar_buf, cbar_win, cbar_buf = nil, nil, nil, nil
sbar_zones, cbar_zones = {}, {}
end
local function reposition_bars()
if sbar_win and vim.api.nvim_win_is_valid(sbar_win) then
pcall(vim.api.nvim_win_set_config, sbar_win, sbar_position())
end
if cbar_win and vim.api.nvim_win_is_valid(cbar_win) then
pcall(vim.api.nvim_win_set_config, cbar_win, cbar_position())
end
render_bars()
end
-- ─── dap-ui setup ────────────────────────────────────────────────────────────
@@ -569,12 +648,12 @@ local function ensure_dapui()
-- re-render the control bar on any dap state change so the READY/RUNNING/
-- PAUSED chip and dap.status() text stay live.
local function refresh_bar() vim.schedule(render_bar) end
dap.listeners.after.event_initialized["turbo-debug-bar"] = refresh_bar
dap.listeners.after.event_stopped["turbo-debug-bar"] = refresh_bar
dap.listeners.after.event_continued["turbo-debug-bar"] = refresh_bar
dap.listeners.after.event_terminated["turbo-debug-bar"] = refresh_bar
dap.listeners.after.event_exited["turbo-debug-bar"] = refresh_bar
local function refresh_bars() vim.schedule(render_bars) end
dap.listeners.after.event_initialized["turbo-debug-bar"] = refresh_bars
dap.listeners.after.event_stopped["turbo-debug-bar"] = refresh_bars
dap.listeners.after.event_continued["turbo-debug-bar"] = refresh_bars
dap.listeners.after.event_terminated["turbo-debug-bar"] = refresh_bars
dap.listeners.after.event_exited["turbo-debug-bar"] = refresh_bars
dap.listeners.after.event_stopped["turbo-debug-ip"] = function(session, body)
vim.defer_fn(function()
@@ -852,7 +931,10 @@ end
local function set_debug_chrome()
active_win = vim.api.nvim_get_current_win()
saved_winbar = vim.wo[active_win].winbar
vim.wo[active_win].winbar = "%#TurboDebugWinbar# " .. ICON.bug .. " DEBUG %* " .. ICON.divider .. " %f"
-- Source file's winbar is just the filename now — the "DEBUG · STATE"
-- chip lives in the top status bar (sbar). Keeps the source context
-- minimal and leaves more room for filename paths.
vim.wo[active_win].winbar = " %f"
end
local function clear_debug_chrome()
@@ -880,7 +962,7 @@ function M.enter()
})
vim.api.nvim_create_autocmd("VimResized", {
group = group,
callback = reposition_bar,
callback = reposition_bars,
})
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
@@ -889,7 +971,7 @@ function M.enter()
set_debug_chrome()
ensure_dapui()
require("dapui").open()
open_bar()
open_bars()
-- second install pass after dapui has created its buffers
vim.schedule(function()
@@ -897,7 +979,7 @@ function M.enter()
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
reposition_bar()
reposition_bars()
end)
ensure_vt()
@@ -915,7 +997,7 @@ function M.exit()
pcall(vim.api.nvim_del_augroup_by_name, "TurboDebugModalKeys")
clear_all_modal_keys()
clear_debug_chrome()
close_bar()
close_bars()
help.close()
if dapui_initialized then require("dapui").close() end