feat: 4-row bar (state+help row above controls row), ❓ help, no underlines
Layout restructure per UX feedback — the single-row-crammed layout couldn't fit state + status + controls + help on narrow windows, and byte-based truncation was clipping emoji at the right edge. New shape: ┌────────────────── width ──────────────────┐ ├ ─ ─ ─ ─ top separator ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┤ │ 🐛 DEBUG · PAUSED · status… ❓ help │ │ 🟢 (c)ontinue … 🛑 (q) terminate│ ├ ─ ─ ─ ─ bottom separator ─ ─ ─ ─ ─ ─ ─ ─ ─┤ └────────────────────────────────────────────┘ - Help has its own right-anchored slot on row 1 — it can never be squeezed off by long status messages or wide control labels. Solves the "no help visible on READY state" regression where dap's "All threads stopped" message was pushing it past the byte-truncation. - Controls get the full width of row 2 without fighting status text, centered horizontally. - If status message is too long for row 1, we truncate status first with an ellipsis — help stays put. Other fixes: - TurboDebugBarKey no longer applies underline. The descender of lowercase q crossed the underline and read as a lowercase g. Kept bold; dropped underline. - Help emoji switched back to ❓ (U+2753). It's BMP but has Emoji_Presentation=Yes by default, so Ghostty renders it as color. The previous "❓ invisible" symptom was caused by the broken-extmark underline leak; fixed in the prior commit. - Bottom tray shrunk 9 → 8 rows to preserve the 12-row total footprint of the original dapui default (8 tray + 4 bar = 12). Click zones now include a line number so we can dispatch correctly between the state row (help click) and the controls row (control clicks). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 file changed
+120
-148
+120
-148
@@ -50,7 +50,14 @@ local ICON = {
|
|||||||
|
|
||||||
-- brand / state emoji
|
-- brand / state emoji
|
||||||
bug = "\xf0\x9f\x90\x9b", -- 🐛 bug (U+1F41B)
|
bug = "\xf0\x9f\x90\x9b", -- 🐛 bug (U+1F41B)
|
||||||
help = "\xf0\x9f\x92\xa1", -- 💡 lightbulb (U+1F4A1) — insight/help
|
help = "\xe2\x9d\x93", -- ❓ black question mark ornament
|
||||||
|
-- (U+2753). It's BMP but is
|
||||||
|
-- Emoji_Presentation by default,
|
||||||
|
-- so modern terminals render it
|
||||||
|
-- as color. The previous attempt
|
||||||
|
-- appeared broken only because
|
||||||
|
-- of a misaligned extmark; with
|
||||||
|
-- that gone, ❓ renders fine.
|
||||||
|
|
||||||
-- IP arrows
|
-- IP arrows
|
||||||
ip_left = "\xf0\x9f\x91\x88", -- 👈 backhand pointing left (U+1F448)
|
ip_left = "\xf0\x9f\x91\x88", -- 👈 backhand pointing left (U+1F448)
|
||||||
@@ -84,9 +91,10 @@ local function build_default_layouts()
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
-- 9 rows (was 12) to leave room for the 3-row control bar below
|
-- 8 rows — the control bar below takes 4 rows (sep + state + controls
|
||||||
|
-- + sep). 8 + 4 = 12, matching the dapui default tray size.
|
||||||
position = "bottom",
|
position = "bottom",
|
||||||
size = 9,
|
size = 8,
|
||||||
elements = {
|
elements = {
|
||||||
{ id = "repl", size = 0.50 },
|
{ id = "repl", size = 0.50 },
|
||||||
{ id = "console", size = 0.50 },
|
{ id = "console", size = 0.50 },
|
||||||
@@ -110,19 +118,19 @@ local function define_highlights()
|
|||||||
hl(0, "TurboDebugBarRunning", { default = true, link = "DiagnosticInfo" })
|
hl(0, "TurboDebugBarRunning", { default = true, link = "DiagnosticInfo" })
|
||||||
hl(0, "TurboDebugBarPaused", { default = true, link = "DiagnosticError" })
|
hl(0, "TurboDebugBarPaused", { default = true, link = "DiagnosticError" })
|
||||||
|
|
||||||
-- The key letter inside (c)ontinue etc. gets bold + underline + Special's
|
-- The key letter inside (c)ontinue etc. gets bold + Special's fg.
|
||||||
-- fg. nvim_set_hl can't combine link + bold, so we copy Special's fg
|
-- No underline — the descender on lowercase q/g/p/y overlaps the
|
||||||
-- explicitly and add bold/underline. Re-applied on ColorScheme so theme
|
-- underline and makes the glyph unreadable (q reads as g, etc.).
|
||||||
-- swaps don't blank it out.
|
-- nvim_set_hl can't combine link + bold, so copy Special's fg explicitly.
|
||||||
|
-- Re-applied on ColorScheme so theme swaps don't blank it out.
|
||||||
local function apply_key_hl()
|
local function apply_key_hl()
|
||||||
local ok, src = pcall(vim.api.nvim_get_hl, 0, { name = "Special", link = false })
|
local ok, src = pcall(vim.api.nvim_get_hl, 0, { name = "Special", link = false })
|
||||||
if not ok or not src or not src.fg then
|
if not ok or not src or not src.fg then
|
||||||
-- fallback: at least make it bold via linking to something bold-ish
|
|
||||||
vim.api.nvim_set_hl(0, "TurboDebugBarKey", { default = true, link = "Special" })
|
vim.api.nvim_set_hl(0, "TurboDebugBarKey", { default = true, link = "Special" })
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
vim.api.nvim_set_hl(0, "TurboDebugBarKey", {
|
vim.api.nvim_set_hl(0, "TurboDebugBarKey", {
|
||||||
fg = src.fg, bg = src.bg, bold = true, underline = true, default = true,
|
fg = src.fg, bg = src.bg, bold = true, default = true,
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
apply_key_hl()
|
apply_key_hl()
|
||||||
@@ -207,6 +215,13 @@ local function build_control_text(icon, key, tail)
|
|||||||
return table.concat(parts), key_col, key_end_col
|
return table.concat(parts), key_col, key_end_col
|
||||||
end
|
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()
|
local function render_bar()
|
||||||
if not (bar_buf and vim.api.nvim_buf_is_valid(bar_buf)) then return end
|
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
|
if not (bar_win and vim.api.nvim_win_is_valid(bar_win)) then return end
|
||||||
@@ -217,28 +232,43 @@ local function render_bar()
|
|||||||
|
|
||||||
local state, state_hl = dap_state()
|
local state, state_hl = dap_state()
|
||||||
|
|
||||||
-- ─── LEFT ZONE ─── state chip (always shown) + dap.status() (optional)
|
-- ─── ROW 1: state info + help ───────────────────────────
|
||||||
local chip_text = " " .. ICON.bug .. " DEBUG " .. ICON.divider .. " " .. state .. " "
|
local chip_text = " " .. ICON.bug .. " DEBUG " .. ICON.divider .. " " .. state .. " "
|
||||||
local status_ok, status_msg = pcall(function() return require("dap").status() end)
|
local status_ok, status_msg = pcall(function() return require("dap").status() end)
|
||||||
if not status_ok then status_msg = "" end
|
if not status_ok then status_msg = "" end
|
||||||
local status_text = (status_msg ~= "" and (" " .. status_msg) or "")
|
local status_text = status_msg ~= "" and (" " .. status_msg) or ""
|
||||||
|
|
||||||
-- ─── CENTER ZONE ─── control labels, each clickable. Two labels have
|
local help_text = ICON.help .. " help "
|
||||||
-- modal variants that track the dap state so the text reflects what the
|
|
||||||
-- key will ACTUALLY do right now:
|
-- fit-check: if status is too long, truncate it so help stays anchored
|
||||||
-- (c) start when no session is running
|
local chip_dw = vim.fn.strdisplaywidth(chip_text)
|
||||||
-- (c)ontinue when a session is paused or running
|
local help_dw = vim.fn.strdisplaywidth(help_text)
|
||||||
-- (q)uit when no session is running (exits debug mode)
|
local status_dw = vim.fn.strdisplaywidth(status_text)
|
||||||
-- (q) terminate when a session is running (kills the process)
|
local needed = chip_dw + status_dw + help_dw + 2 -- at least 2 cells of spacer
|
||||||
local has_session = state ~= "READY"
|
if needed > width and status_dw > 0 then
|
||||||
local continue_icon, continue_tail
|
local max_status = width - chip_dw - help_dw - 5
|
||||||
if has_session then
|
if max_status > 5 then
|
||||||
continue_icon = ICON.go
|
status_text = " " .. status_msg:sub(1, max_status - 3) .. ICON.ellipsis
|
||||||
continue_tail = "ontinue"
|
status_dw = vim.fn.strdisplaywidth(status_text)
|
||||||
else
|
else
|
||||||
continue_icon = ICON.start_rkt
|
status_text = ""
|
||||||
continue_tail = " start"
|
status_dw = 0
|
||||||
|
end
|
||||||
end
|
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
|
||||||
|
|
||||||
|
-- ─── ROW 2: controls (centered) ─────────────────────────
|
||||||
|
-- Modal variants so the text reflects what the key will ACTUALLY do:
|
||||||
|
-- no session: (c) start (q)uit
|
||||||
|
-- active: (c)ontinue (q) terminate
|
||||||
|
local has_session = state ~= "READY"
|
||||||
|
local continue_icon = has_session and ICON.go or ICON.start_rkt
|
||||||
|
local continue_tail = has_session and "ontinue" or " start"
|
||||||
local quit_tail = has_session and " terminate" or "uit"
|
local quit_tail = has_session and " terminate" or "uit"
|
||||||
|
|
||||||
local controls = {
|
local controls = {
|
||||||
@@ -250,153 +280,97 @@ local function render_bar()
|
|||||||
{ icon = ICON.stop, key = keyof("terminate", "q"), tail = quit_tail, fn = action("terminate") },
|
{ icon = ICON.stop, key = keyof("terminate", "q"), tail = quit_tail, fn = action("terminate") },
|
||||||
}
|
}
|
||||||
|
|
||||||
-- ─── RIGHT ZONE ─── help (no "(?)" — the ❓ emoji is self-documenting)
|
local ctrl_parts = {}
|
||||||
local help_icon = ICON.help
|
local ctrl_spans = {}
|
||||||
local help_label_text = help_icon .. " help "
|
local ctrl_key_spans = {}
|
||||||
local help_fn = function() require("turbo-debug.help").open() end
|
local ctrl_zones_bytes = {}
|
||||||
|
|
||||||
-- compose the center text first so we can measure it
|
|
||||||
local center_parts = {}
|
|
||||||
local center_spans = {} -- { byte_start, byte_end, hl }
|
|
||||||
local center_key_spans = {} -- { byte_start, byte_end } for TurboDebugBarKey
|
|
||||||
local center_zones = {} -- { byte_start, byte_end, fn } pre-display-column
|
|
||||||
local gap = " "
|
local gap = " "
|
||||||
for i, c in ipairs(controls) do
|
for i, c in ipairs(controls) do
|
||||||
local prefix_len = #table.concat(center_parts)
|
local prefix_len = #table.concat(ctrl_parts)
|
||||||
if i > 1 then
|
if i > 1 then
|
||||||
center_parts[#center_parts + 1] = gap
|
ctrl_parts[#ctrl_parts + 1] = gap
|
||||||
prefix_len = prefix_len + #gap
|
prefix_len = prefix_len + #gap
|
||||||
end
|
end
|
||||||
local txt, kcol, kend = build_control_text(c.icon, c.key, c.tail)
|
local txt, kcol, kend = build_control_text(c.icon, c.key, c.tail)
|
||||||
local label_start = prefix_len
|
ctrl_parts[#ctrl_parts + 1] = txt
|
||||||
local label_end = prefix_len + #txt
|
ctrl_spans[#ctrl_spans + 1] = { prefix_len, prefix_len + #txt, "TurboDebugBarCtrl" }
|
||||||
center_parts[#center_parts + 1] = txt
|
ctrl_key_spans[#ctrl_key_spans + 1] = { prefix_len + kcol, prefix_len + kend }
|
||||||
center_spans[#center_spans + 1] = { label_start, label_end, "TurboDebugBarCtrl" }
|
ctrl_zones_bytes[#ctrl_zones_bytes + 1] = { prefix_len, prefix_len + #txt, c.fn }
|
||||||
center_key_spans[#center_key_spans + 1] = { label_start + kcol, label_start + kend }
|
|
||||||
center_zones[#center_zones + 1] = { label_start, label_end, c.fn }
|
|
||||||
end
|
|
||||||
local center_text = table.concat(center_parts)
|
|
||||||
|
|
||||||
-- widths in display columns (not bytes — emoji are multi-byte and multi-cell)
|
|
||||||
local left_dw = vim.fn.strdisplaywidth(chip_text) + vim.fn.strdisplaywidth(status_text)
|
|
||||||
local center_dw = vim.fn.strdisplaywidth(center_text)
|
|
||||||
local right_dw = vim.fn.strdisplaywidth(help_label_text)
|
|
||||||
|
|
||||||
-- Graceful degradation when the window narrows. Priority (most important last):
|
|
||||||
-- 1. dap.status() — drop first
|
|
||||||
-- 2. center controls — truncate from the right
|
|
||||||
-- 3. state chip — collapse to just "🐛"
|
|
||||||
-- 4. help — NEVER drop
|
|
||||||
local show_status = true
|
|
||||||
local show_controls = true
|
|
||||||
local show_chip = true
|
|
||||||
|
|
||||||
if left_dw + center_dw + right_dw + 4 > width then
|
|
||||||
show_status = false -- drop status first
|
|
||||||
left_dw = vim.fn.strdisplaywidth(chip_text)
|
|
||||||
end
|
|
||||||
if left_dw + center_dw + right_dw + 4 > width then
|
|
||||||
show_controls = false -- drop center next
|
|
||||||
center_dw = 0
|
|
||||||
end
|
|
||||||
if left_dw + right_dw + 2 > width then
|
|
||||||
show_chip = false -- collapse chip to just the bug icon
|
|
||||||
chip_text = " " .. ICON.bug .. " "
|
|
||||||
left_dw = vim.fn.strdisplaywidth(chip_text)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- compose: [left][pad1][center][pad2][right]
|
|
||||||
local left_text = chip_text .. (show_status and status_text or "")
|
|
||||||
local right_text = help_label_text
|
|
||||||
local center_to_use = show_controls and center_text or ""
|
|
||||||
local center_dw_used = show_controls and center_dw or 0
|
|
||||||
|
|
||||||
local remain = width - left_dw - center_dw_used - right_dw
|
|
||||||
if remain < 0 then remain = 0 end
|
|
||||||
-- split remaining space symmetrically on either side of the center
|
|
||||||
local pad1 = math.floor(remain / 2)
|
|
||||||
local pad2 = remain - pad1
|
|
||||||
local line = left_text .. string.rep(" ", pad1) .. center_to_use .. string.rep(" ", pad2) .. right_text
|
|
||||||
|
|
||||||
-- safety truncate
|
|
||||||
if vim.fn.strdisplaywidth(line) > width then
|
|
||||||
-- keep right-anchored help visible by truncating from the middle if possible
|
|
||||||
line = line:sub(1, width)
|
|
||||||
end
|
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.bo[bar_buf].modifiable = true
|
||||||
vim.api.nvim_buf_set_lines(bar_buf, 0, -1, false, { sep, line, sep })
|
vim.api.nvim_buf_set_lines(bar_buf, 0, -1, false, { sep, state_line, controls_line, sep })
|
||||||
vim.bo[bar_buf].modifiable = false
|
vim.bo[bar_buf].modifiable = false
|
||||||
|
|
||||||
vim.api.nvim_buf_clear_namespace(bar_buf, bar_ns, 0, -1)
|
vim.api.nvim_buf_clear_namespace(bar_buf, bar_ns, 0, -1)
|
||||||
|
|
||||||
-- top + bottom separator highlights
|
-- top + bottom separator highlights
|
||||||
vim.api.nvim_buf_set_extmark(bar_buf, bar_ns, 0, 0, {
|
pcall(vim.api.nvim_buf_set_extmark, bar_buf, bar_ns, 0, 0, {
|
||||||
end_row = 0, end_col = #sep, hl_group = "TurboDebugBarSeparator",
|
end_row = 0, end_col = #sep, hl_group = "TurboDebugBarSeparator",
|
||||||
})
|
})
|
||||||
vim.api.nvim_buf_set_extmark(bar_buf, bar_ns, 2, 0, {
|
pcall(vim.api.nvim_buf_set_extmark, bar_buf, bar_ns, 3, 0, {
|
||||||
end_row = 2, end_col = #sep, hl_group = "TurboDebugBarSeparator",
|
end_row = 3, end_col = #sep, hl_group = "TurboDebugBarSeparator",
|
||||||
})
|
})
|
||||||
|
|
||||||
-- state chip highlight (at the start of the line)
|
-- row 1: state chip color + status + help
|
||||||
local chip_end = #chip_text
|
|
||||||
pcall(vim.api.nvim_buf_set_extmark, bar_buf, bar_ns, 1, 0, {
|
pcall(vim.api.nvim_buf_set_extmark, bar_buf, bar_ns, 1, 0, {
|
||||||
end_row = 1, end_col = chip_end, hl_group = state_hl,
|
end_row = 1, end_col = #chip_text, hl_group = state_hl,
|
||||||
})
|
})
|
||||||
if show_status and #status_text > 0 then
|
if #status_text > 0 then
|
||||||
local s = chip_end
|
pcall(vim.api.nvim_buf_set_extmark, bar_buf, bar_ns, 1, #chip_text, {
|
||||||
local e = chip_end + #status_text
|
end_row = 1, end_col = #chip_text + #status_text, hl_group = "TurboDebugBarStatus",
|
||||||
pcall(vim.api.nvim_buf_set_extmark, bar_buf, bar_ns, 1, s, {
|
})
|
||||||
end_row = 1, end_col = e, 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)
|
||||||
|
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],
|
||||||
|
})
|
||||||
|
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",
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
|
|
||||||
-- center highlights (offset by left_text + pad1 bytes)
|
-- click zones — stored as { line_number_1_based, dcol_start, dcol_end, fn }
|
||||||
local center_byte_offset = #left_text + pad1
|
-- help click lives on row 1 (line 2)
|
||||||
click_zones = {}
|
local help_dcol_start = vim.fn.strdisplaywidth(state_line:sub(1, help_byte_start))
|
||||||
if show_controls then
|
local help_dcol_end = vim.fn.strdisplaywidth(state_line)
|
||||||
for _, span in ipairs(center_spans) do
|
click_zones[#click_zones + 1] = { 2, help_dcol_start, help_dcol_end,
|
||||||
pcall(vim.api.nvim_buf_set_extmark, bar_buf, bar_ns, 1, center_byte_offset + span[1], {
|
function() require("turbo-debug.help").open() end }
|
||||||
end_row = 1, end_col = center_byte_offset + span[2], hl_group = span[3],
|
-- control clicks live on row 2 (line 3)
|
||||||
})
|
for _, z in ipairs(ctrl_zones_bytes) do
|
||||||
end
|
local byte_start = ctrl_byte_offset + z[1]
|
||||||
for _, span in ipairs(center_key_spans) do
|
local byte_end = ctrl_byte_offset + z[2]
|
||||||
pcall(vim.api.nvim_buf_set_extmark, bar_buf, bar_ns, 1, center_byte_offset + span[1], {
|
local dcol_start = vim.fn.strdisplaywidth(controls_line:sub(1, byte_start))
|
||||||
end_row = 1, end_col = center_byte_offset + span[2], hl_group = "TurboDebugBarKey",
|
local dcol_end = vim.fn.strdisplaywidth(controls_line:sub(1, byte_end))
|
||||||
})
|
click_zones[#click_zones + 1] = { 3, dcol_start, dcol_end, z[3] }
|
||||||
end
|
|
||||||
for _, zone in ipairs(center_zones) do
|
|
||||||
local byte_start = center_byte_offset + zone[1]
|
|
||||||
local byte_end = center_byte_offset + zone[2]
|
|
||||||
local dcol_start = vim.fn.strdisplaywidth(line:sub(1, byte_start))
|
|
||||||
local dcol_end = vim.fn.strdisplaywidth(line:sub(1, byte_end))
|
|
||||||
click_zones[#click_zones + 1] = { dcol_start, dcol_end, zone[3] }
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
-- right zone (help) — single-group highlight across the whole label.
|
|
||||||
-- No special key-hint styling here: the earlier attempt put a misaligned
|
|
||||||
-- TurboDebugBarKey (bold+underline) extmark starting 1 byte INTO the
|
|
||||||
-- emoji's 4 UTF-8 bytes, so when the emoji didn't render at all the
|
|
||||||
-- underline showed up as "_____" after "terminate". Just use the
|
|
||||||
-- standard control highlight on the whole help region — emoji speaks
|
|
||||||
-- for itself.
|
|
||||||
local right_byte_start = #line - #right_text
|
|
||||||
pcall(vim.api.nvim_buf_set_extmark, bar_buf, bar_ns, 1, right_byte_start, {
|
|
||||||
end_row = 1, end_col = #line, hl_group = "TurboDebugBarCtrl",
|
|
||||||
})
|
|
||||||
local help_dcol_start = vim.fn.strdisplaywidth(line:sub(1, right_byte_start))
|
|
||||||
local help_dcol_end = vim.fn.strdisplaywidth(line)
|
|
||||||
click_zones[#click_zones + 1] = { help_dcol_start, help_dcol_end, help_fn }
|
|
||||||
end
|
end
|
||||||
|
|
||||||
local function bar_position()
|
local function bar_position()
|
||||||
-- 3 rows (─ top, content, ─ bottom). Sits above the statusline.
|
-- 4 rows: ─ top sep / state+help / controls / ─ bottom sep
|
||||||
local row
|
local row
|
||||||
if vim.o.laststatus > 0 then
|
if vim.o.laststatus > 0 then
|
||||||
row = vim.o.lines - vim.o.cmdheight - 4 -- 3 (bar) + 1 (statusline)
|
row = vim.o.lines - vim.o.cmdheight - 5 -- 4 (bar) + 1 (statusline)
|
||||||
else
|
else
|
||||||
row = vim.o.lines - vim.o.cmdheight - 3 -- 3 (bar)
|
row = vim.o.lines - vim.o.cmdheight - 4 -- 4 (bar)
|
||||||
end
|
end
|
||||||
if row < 0 then row = 0 end
|
if row < 0 then row = 0 end
|
||||||
return {
|
return {
|
||||||
@@ -404,7 +378,7 @@ local function bar_position()
|
|||||||
row = row,
|
row = row,
|
||||||
col = 0,
|
col = 0,
|
||||||
width = vim.o.columns,
|
width = vim.o.columns,
|
||||||
height = 3,
|
height = 4,
|
||||||
style = "minimal",
|
style = "minimal",
|
||||||
border = "none",
|
border = "none",
|
||||||
focusable = false,
|
focusable = false,
|
||||||
@@ -416,12 +390,10 @@ end
|
|||||||
local function handle_bar_click()
|
local function handle_bar_click()
|
||||||
local pos = vim.fn.getmousepos()
|
local pos = vim.fn.getmousepos()
|
||||||
if not pos or pos.winid ~= bar_win then return end
|
if not pos or pos.winid ~= bar_win then return end
|
||||||
-- only the middle (content) row is clickable; top/bottom are separators
|
|
||||||
if pos.line ~= 2 then return end
|
|
||||||
local col = pos.wincol - 1
|
local col = pos.wincol - 1
|
||||||
for _, zone in ipairs(click_zones) do
|
for _, zone in ipairs(click_zones) do
|
||||||
if col >= zone[1] and col < zone[2] then
|
if zone[1] == pos.line and col >= zone[2] and col < zone[3] then
|
||||||
zone[3]()
|
zone[4]()
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
Reference in new issue
Block a user