WIP: aesthetics!
This commit is contained in:
6 files changed
+690
-243
No files matched your search
@@ -12,19 +12,61 @@ function M.setup()
|
||||
load_breakpoints_event = { "BufReadPost" },
|
||||
})
|
||||
|
||||
-- sign highlights (default = true so colorschemes can override)
|
||||
vim.api.nvim_set_hl(0, "DapBreakpoint", { default = true, fg = "#e06c75" })
|
||||
vim.api.nvim_set_hl(0, "DapBreakpointCondition", { default = true, fg = "#e5c07b" })
|
||||
vim.api.nvim_set_hl(0, "DapBreakpointRejected", { default = true, fg = "#5c6370" })
|
||||
vim.api.nvim_set_hl(0, "DapStopped", { default = true, fg = "#98c379" })
|
||||
vim.api.nvim_set_hl(0, "DapStoppedLine", { default = true, bg = "#2e3b2e" })
|
||||
vim.api.nvim_set_hl(0, "DapLogPoint", { default = true, fg = "#61afef" })
|
||||
-- link sign highlights to standard diagnostic groups so they pick up the
|
||||
-- user's colorscheme instead of hardcoding hex colors.
|
||||
vim.api.nvim_set_hl(0, "DapBreakpoint", { default = true, link = "DiagnosticError" })
|
||||
vim.api.nvim_set_hl(0, "DapBreakpointCondition", { default = true, link = "DiagnosticWarn" })
|
||||
vim.api.nvim_set_hl(0, "DapBreakpointRejected", { default = true, link = "DiagnosticHint" })
|
||||
vim.api.nvim_set_hl(0, "DapStopped", { default = true, link = "DiagnosticOk" })
|
||||
vim.api.nvim_set_hl(0, "DapStoppedLine", { default = true, link = "Search" })
|
||||
vim.api.nvim_set_hl(0, "DapLogPoint", { default = true, link = "DiagnosticInfo" })
|
||||
|
||||
vim.fn.sign_define("DapBreakpoint", { text = "🔴", texthl = "DapBreakpoint" })
|
||||
vim.fn.sign_define("DapBreakpointCondition", { text = "🟡", texthl = "DapBreakpointCondition" })
|
||||
vim.fn.sign_define("DapBreakpointRejected", { text = "⭕", texthl = "DapBreakpointRejected" })
|
||||
vim.fn.sign_define("DapStopped", { text = "➤", texthl = "DapStopped", linehl = "DapStoppedLine" })
|
||||
vim.fn.sign_define("DapLogPoint", { text = "📝", texthl = "DapLogPoint" })
|
||||
-- gutter signs: Unicode geometric symbols via byte escapes so they survive
|
||||
-- any tool-pipeline that strips PUA/Nerd-Font codepoints. They render in
|
||||
-- any monospace font, Nerd Font required.
|
||||
-- ● U+25CF (solid circle) = breakpoint
|
||||
-- ◆ U+25C6 (solid diamond) = conditional breakpoint
|
||||
-- ○ U+25CB (hollow circle) = rejected breakpoint
|
||||
-- ▶ U+25B6 (right triangle) = current execution line (IP)
|
||||
-- ✎ U+270E (pencil) = log breakpoint
|
||||
vim.fn.sign_define("DapBreakpoint", { text = "\xe2\x97\x8f", texthl = "DapBreakpoint", numhl = "DapBreakpoint" })
|
||||
vim.fn.sign_define("DapBreakpointCondition", { text = "\xe2\x97\x86", texthl = "DapBreakpointCondition", numhl = "DapBreakpointCondition" })
|
||||
vim.fn.sign_define("DapBreakpointRejected", { text = "\xe2\x97\x8b", texthl = "DapBreakpointRejected", numhl = "DapBreakpointRejected" })
|
||||
vim.fn.sign_define("DapStopped", { text = "\xe2\x96\xb6", texthl = "DapStopped", linehl = "DapStoppedLine", numhl = "DapStopped" })
|
||||
vim.fn.sign_define("DapLogPoint", { text = "\xe2\x9c\x8e", texthl = "DapLogPoint", numhl = "DapLogPoint" })
|
||||
|
||||
-- unobtrusive inline virtual text: italic, comment-colored
|
||||
vim.api.nvim_set_hl(0, "NvimDapVirtualText", { default = true, link = "Comment", italic = true })
|
||||
vim.api.nvim_set_hl(0, "NvimDapVirtualTextChanged", { default = true, link = "DiagnosticWarn", italic = true })
|
||||
vim.api.nvim_set_hl(0, "NvimDapVirtualTextError", { default = true, link = "DiagnosticError", italic = true })
|
||||
vim.api.nvim_set_hl(0, "NvimDapVirtualTextInfo", { default = true, link = "DiagnosticInfo", italic = true })
|
||||
|
||||
-- turbo-debug's own UI groups (help float, active-pane borders, winbar badge)
|
||||
vim.api.nvim_set_hl(0, "TurboDebugHelpBrand", { default = true, link = "Title" })
|
||||
vim.api.nvim_set_hl(0, "TurboDebugHelpTagline", { default = true, link = "Comment", italic = true })
|
||||
vim.api.nvim_set_hl(0, "TurboDebugHelpSection", { default = true, link = "Function" })
|
||||
vim.api.nvim_set_hl(0, "TurboDebugHelpSectionIcon", { default = true, link = "Constant" })
|
||||
vim.api.nvim_set_hl(0, "TurboDebugHelpKey", { default = true, link = "Special" })
|
||||
vim.api.nvim_set_hl(0, "TurboDebugHelpParen", { default = true, link = "Comment" })
|
||||
vim.api.nvim_set_hl(0, "TurboDebugCtrlButton", { default = true, link = "Function" })
|
||||
vim.api.nvim_set_hl(0, "TurboDebugCtrlMuted", { default = true, link = "Comment" })
|
||||
|
||||
-- derived highlight: the IP "reason" vtext (STEP / BREAKPOINT / EXCEPTION /
|
||||
-- PAUSE / etc.) — bold + the WarningMsg color so it jumps off the screen.
|
||||
-- nvim_set_hl can't combine link + bold, so copy attrs explicitly and
|
||||
-- re-apply on ColorScheme so theme switches don't blank it out.
|
||||
local function apply_ip_reason_hl()
|
||||
local ok, src = pcall(vim.api.nvim_get_hl, 0, { name = "WarningMsg", link = false })
|
||||
if not ok or not src or not src.fg then return end
|
||||
vim.api.nvim_set_hl(0, "TurboDebugIPReason", {
|
||||
fg = src.fg, bg = src.bg, bold = true, default = true,
|
||||
})
|
||||
end
|
||||
apply_ip_reason_hl()
|
||||
vim.api.nvim_create_autocmd("ColorScheme", {
|
||||
group = vim.api.nvim_create_augroup("TurboDebugColors", { clear = true }),
|
||||
callback = apply_ip_reason_hl,
|
||||
})
|
||||
|
||||
-- global mappings (work outside debug mode)
|
||||
local gk = config.opts.global_keys
|
||||
|
||||
+44
-21
@@ -4,6 +4,11 @@ M.defaults = {
|
||||
help_on_enter = true,
|
||||
builtin_adapters = true,
|
||||
quit_exits_mode = true, -- q terminates AND exits debug mode (false = terminate only)
|
||||
-- When `c` is pressed with no breakpoints set, launch the first adapter
|
||||
-- configuration for the filetype with stopOnEntry so the debugger pauses
|
||||
-- at the program's entry point. Matches the Turbo Pascal "press key to
|
||||
-- start debugging" model. Set false to always run until a breakpoint.
|
||||
stop_on_entry_when_no_breakpoints = true,
|
||||
|
||||
-- modal keys (active only during debug mode, single-key)
|
||||
keys = {
|
||||
@@ -31,40 +36,58 @@ M.defaults = {
|
||||
clear_breakpoints = "<leader>dD",
|
||||
},
|
||||
|
||||
-- sidebar position: "left" (default) or "right"
|
||||
sidebar = "left",
|
||||
|
||||
-- highlight the active dapui pane's border/separator vs. dim inactive panes
|
||||
active_window_highlight = true,
|
||||
|
||||
dapui = {
|
||||
icons = { expanded = "▼", collapsed = "▶", current_frame = "➤" },
|
||||
-- Unicode icons via byte escapes so they survive tool round-trips.
|
||||
-- ▾ U+25BE down-triangle (expanded), ▸ U+25B8 right-triangle (collapsed),
|
||||
-- ▶ U+25B6 right-pointing triangle (current frame / play-head)
|
||||
icons = {
|
||||
expanded = "\xe2\x96\xbe",
|
||||
collapsed = "\xe2\x96\xb8",
|
||||
current_frame = "\xe2\x96\xb6",
|
||||
},
|
||||
controls = {
|
||||
enabled = true,
|
||||
element = "repl",
|
||||
-- ▶ play, ⏸ pause, ⤓ step-into, ⇒ step-over, ⤒ step-out, ↶ step-back,
|
||||
-- ↻ run-last, ■ terminate, ⊗ disconnect
|
||||
icons = {
|
||||
play = "\xe2\x96\xb6",
|
||||
pause = "\xe2\x8f\xb8",
|
||||
step_into = "\xe2\xa4\x93",
|
||||
step_over = "\xe2\x87\x92",
|
||||
step_out = "\xe2\xa4\x92",
|
||||
step_back = "\xe2\x86\xb6",
|
||||
run_last = "\xe2\x86\xbb",
|
||||
terminate = "\xe2\x96\xa0",
|
||||
disconnect = "\xe2\x8a\x97",
|
||||
},
|
||||
},
|
||||
floating = { border = "rounded" },
|
||||
floating = { border = "rounded", mappings = { close = { "q", "<Esc>" } } },
|
||||
render = { indent = 2, max_type_length = 20 },
|
||||
layouts = {
|
||||
{
|
||||
position = "right",
|
||||
size = 40,
|
||||
elements = {
|
||||
{ id = "scopes", size = 0.50 },
|
||||
{ id = "watches", size = 0.25 },
|
||||
{ id = "stacks", size = 0.25 },
|
||||
},
|
||||
},
|
||||
{
|
||||
position = "bottom",
|
||||
size = 12,
|
||||
elements = {
|
||||
{ id = "repl", size = 0.50 },
|
||||
{ id = "console", size = 0.50 },
|
||||
},
|
||||
},
|
||||
},
|
||||
-- layouts are built dynamically from `sidebar` in mode.lua; override
|
||||
-- `layouts` here to fully customize.
|
||||
layouts = nil,
|
||||
},
|
||||
|
||||
virtual_text = {
|
||||
enabled = true,
|
||||
commented = true,
|
||||
virt_text_pos = "eol",
|
||||
show_stop_reason = true,
|
||||
highlight_changed_variables = true,
|
||||
highlight_new_as_changed = false,
|
||||
only_first_definition = false,
|
||||
all_frames = false,
|
||||
display_callback = function(variable)
|
||||
if #variable.value > 80 then return " = " .. variable.value:sub(1, 77) .. "…" end
|
||||
return " = " .. variable.value
|
||||
end,
|
||||
},
|
||||
|
||||
adapters = {},
|
||||
|
||||
+155
-65
@@ -4,69 +4,168 @@ local M = {}
|
||||
|
||||
local win_id = nil
|
||||
local buf_id = nil
|
||||
local timer = nil
|
||||
|
||||
local modal_info = {
|
||||
{ "continue", "Continue" },
|
||||
{ "step_over", "Step over" },
|
||||
{ "step_into", "Step into" },
|
||||
{ "step_out", "Step out" },
|
||||
{ "run_to_cursor", "Run to cursor" },
|
||||
{ "breakpoint", "Toggle breakpoint" },
|
||||
{ "cond_breakpoint", "Conditional breakpoint" },
|
||||
{ "clear_breakpoints", "Clear all breakpoints" },
|
||||
{ "watch", "Watch expression" },
|
||||
{ "hover", "Hover / inspect" },
|
||||
{ "eval", "Eval in REPL" },
|
||||
{ "terminate", "Quit debugging" },
|
||||
{ "restart", "Restart session" },
|
||||
-- Each entry:
|
||||
-- { action, key_letter, pre, post }
|
||||
-- The formatted line is: " <pre>(<key>)<post>" with <key> taken from the
|
||||
-- config.opts.keys[action] lookup. Highlight spans are computed against
|
||||
-- the actual key letter in the final line.
|
||||
local flow = {
|
||||
{ "continue", "c", "(", ")ontinue" },
|
||||
{ "step_over", "s", "(", ")tep over" },
|
||||
{ "step_into", "d", "(", ")escend into" },
|
||||
{ "step_out", "r", "(", ")eturn out" },
|
||||
{ "run_to_cursor", "C", "run to (", ") cursor" },
|
||||
{ "restart", "R", "(", ")estart session" },
|
||||
{ "terminate", "q", "(", ")uit debugging" },
|
||||
}
|
||||
|
||||
local global_info = {
|
||||
{ "toggle", "Toggle debug mode" },
|
||||
{ "breakpoint", "Toggle breakpoint" },
|
||||
{ "cond_breakpoint", "Conditional breakpoint" },
|
||||
{ "clear_breakpoints", "Clear all breakpoints" },
|
||||
local breakpoints = {
|
||||
{ "breakpoint", "x", "(", ") toggle breakpoint" },
|
||||
{ "cond_breakpoint", "X", "(", ") conditional breakpoint" },
|
||||
{ "clear_breakpoints", "D", "(", ")elete all breakpoints" },
|
||||
}
|
||||
|
||||
local function build_content()
|
||||
local lines = { " turbo-debug", "" }
|
||||
local width = #lines[1]
|
||||
local inspect = {
|
||||
{ "watch", "W", "(", ")atch expression" },
|
||||
{ "hover", "K", "(", ") hover / inspect" },
|
||||
{ "eval", "E", "(", ")val in REPL" },
|
||||
}
|
||||
|
||||
local function add(key, label)
|
||||
local line = string.format(" %-12s %s", key, label)
|
||||
local meta = {
|
||||
{ "help", "?", "(", ") this popup" },
|
||||
}
|
||||
|
||||
local globals = {
|
||||
{ "breakpoint", "toggle breakpoint" },
|
||||
{ "cond_breakpoint", "conditional breakpoint" },
|
||||
{ "clear_breakpoints", "delete all breakpoints" },
|
||||
}
|
||||
|
||||
local dapui_panes = {
|
||||
{ "<CR>", "expand / jump to target" },
|
||||
{ "o", "open target (jump to frame / breakpoint)" },
|
||||
{ "e", "edit (watches)" },
|
||||
{ "d", "remove (watches)" },
|
||||
{ "r", "send to REPL" },
|
||||
{ "t", "toggle subtle frames (call stack)" },
|
||||
}
|
||||
|
||||
-- ▶ U+25B6, ● U+25CF, ◉ U+25C9, ◆ U+25C6, ❯ U+276F, ≡ U+2261
|
||||
local ICON_FLOW = "\xe2\x96\xb6"
|
||||
local ICON_BRK = "\xe2\x97\x8f"
|
||||
local ICON_INSPECT = "\xe2\x97\x89"
|
||||
local ICON_META = "\xe2\x97\x86"
|
||||
local ICON_CHEVRON = "\xe2\x9d\xaf"
|
||||
local ICON_STACK = "\xe2\x89\xa1"
|
||||
|
||||
-- a brand header and tagline
|
||||
local BRAND_TITLE = " " .. ICON_FLOW .. " TURBO DEBUG"
|
||||
local BRAND_TAGLINE = " modal text + GUI debugger · left hand keys, right hand mouse"
|
||||
|
||||
local function build()
|
||||
local lines = { "", BRAND_TITLE, BRAND_TAGLINE, "" }
|
||||
local hl = {} -- list of { line_idx, col_start, col_end, hl_group }
|
||||
|
||||
-- title + tagline highlights
|
||||
hl[#hl + 1] = { 1, 0, #BRAND_TITLE, "TurboDebugHelpBrand" }
|
||||
hl[#hl + 1] = { 2, 0, #BRAND_TAGLINE, "TurboDebugHelpTagline" }
|
||||
|
||||
local function section(icon, title)
|
||||
lines[#lines + 1] = " " .. icon .. " " .. title
|
||||
local idx = #lines - 1
|
||||
hl[#hl + 1] = { idx, 2, 2 + #icon, "TurboDebugHelpSectionIcon" }
|
||||
hl[#hl + 1] = { idx, 2 + #icon + 2, 2 + #icon + 2 + #title, "TurboDebugHelpSection" }
|
||||
end
|
||||
|
||||
local function entry(pre, keyletter, post)
|
||||
-- format: " <pre>(<keyletter>)<tail>"
|
||||
-- e.g., " (s)tep over" or " run to (C) cursor"
|
||||
-- the key letter is inside the parens pair
|
||||
local indent = " "
|
||||
-- pre already ends at "("; post already starts with ")"
|
||||
local line = indent .. pre .. keyletter .. post
|
||||
local idx = #lines
|
||||
lines[#lines + 1] = line
|
||||
if #line > width then width = #line end
|
||||
-- highlight: the key letter itself
|
||||
local col = #indent + #pre
|
||||
hl[#hl + 1] = { idx, col, col + #keyletter, "TurboDebugHelpKey" }
|
||||
-- highlight the surrounding parens dimmer
|
||||
hl[#hl + 1] = { idx, col - 1, col, "TurboDebugHelpParen" }
|
||||
hl[#hl + 1] = { idx, col + #keyletter, col + #keyletter + 1, "TurboDebugHelpParen" }
|
||||
end
|
||||
|
||||
lines[#lines + 1] = " Debug mode:"
|
||||
for _, pair in ipairs(modal_info) do
|
||||
local key = config.opts.keys[pair[1]]
|
||||
if key then add(key, pair[2]) end
|
||||
local function add_modal(list)
|
||||
for _, row in ipairs(list) do
|
||||
local action, letter, pre, post = row[1], row[2], row[3], row[4]
|
||||
local configured = config.opts.keys[action]
|
||||
if configured then
|
||||
-- if the user remapped, show their actual key (preserves surprise-free behavior)
|
||||
local lk = configured
|
||||
entry(pre, lk, post)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function add_global(list)
|
||||
for _, row in ipairs(list) do
|
||||
local action, label = row[1], row[2]
|
||||
local key = config.opts.global_keys[action]
|
||||
if key then
|
||||
local indent = " "
|
||||
local line = indent .. string.format("%-13s ", key) .. label
|
||||
local idx = #lines
|
||||
lines[#lines + 1] = line
|
||||
hl[#hl + 1] = { idx, #indent, #indent + #key, "TurboDebugHelpKey" }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function add_pane(list)
|
||||
for _, row in ipairs(list) do
|
||||
local key, label = row[1], row[2]
|
||||
local indent = " "
|
||||
local line = indent .. string.format("%-6s ", key) .. label
|
||||
local idx = #lines
|
||||
lines[#lines + 1] = line
|
||||
hl[#hl + 1] = { idx, #indent, #indent + #key, "TurboDebugHelpKey" }
|
||||
end
|
||||
end
|
||||
|
||||
section(ICON_FLOW, "Flow")
|
||||
add_modal(flow)
|
||||
lines[#lines + 1] = ""
|
||||
|
||||
section(ICON_BRK, "Breakpoints")
|
||||
add_modal(breakpoints)
|
||||
lines[#lines + 1] = ""
|
||||
|
||||
section(ICON_INSPECT, "Inspect")
|
||||
add_modal(inspect)
|
||||
lines[#lines + 1] = ""
|
||||
|
||||
section(ICON_META, "Help")
|
||||
add_modal(meta)
|
||||
lines[#lines + 1] = ""
|
||||
|
||||
section(ICON_CHEVRON, "Always available")
|
||||
add_global(globals)
|
||||
lines[#lines + 1] = ""
|
||||
|
||||
section(ICON_STACK, "In dap-ui panes")
|
||||
add_pane(dapui_panes)
|
||||
lines[#lines + 1] = ""
|
||||
lines[#lines + 1] = " Always available:"
|
||||
for _, pair in ipairs(global_info) do
|
||||
local key = config.opts.global_keys[pair[1]]
|
||||
if key then add(key, pair[2]) end
|
||||
end
|
||||
|
||||
-- highlight line at the bottom
|
||||
local help_key = config.opts.keys.help or "?"
|
||||
lines[#lines + 1] = ""
|
||||
lines[#lines + 1] = " Press " .. help_key .. " for help"
|
||||
lines[#lines + 1] = " press " .. help_key .. " anytime to reopen"
|
||||
lines[#lines + 1] = ""
|
||||
|
||||
return lines, width + 2
|
||||
local width = 0
|
||||
for _, l in ipairs(lines) do if vim.fn.strdisplaywidth(l) > width then width = vim.fn.strdisplaywidth(l) end end
|
||||
return lines, width + 2, hl
|
||||
end
|
||||
|
||||
function M.close()
|
||||
if timer then
|
||||
timer:stop()
|
||||
timer:close()
|
||||
timer = nil
|
||||
end
|
||||
if win_id and vim.api.nvim_win_is_valid(win_id) then
|
||||
vim.api.nvim_win_close(win_id, true)
|
||||
end
|
||||
@@ -77,17 +176,21 @@ function M.close()
|
||||
buf_id = nil
|
||||
end
|
||||
|
||||
local function show(auto_dismiss)
|
||||
function M.open()
|
||||
M.close()
|
||||
|
||||
local lines, width = build_content()
|
||||
local lines, width, hl = build()
|
||||
local height = #lines
|
||||
|
||||
buf_id = vim.api.nvim_create_buf(false, true)
|
||||
vim.api.nvim_buf_set_lines(buf_id, 0, -1, false, lines)
|
||||
|
||||
local hl_line = height - 2
|
||||
vim.api.nvim_buf_add_highlight(buf_id, -1, "Bold", hl_line, 0, -1)
|
||||
local ns = vim.api.nvim_create_namespace("turbo-debug.help")
|
||||
for _, span in ipairs(hl) do
|
||||
pcall(vim.api.nvim_buf_set_extmark, buf_id, ns, span[1], span[2], {
|
||||
end_row = span[1], end_col = span[3], hl_group = span[4],
|
||||
})
|
||||
end
|
||||
|
||||
vim.bo[buf_id].modifiable = false
|
||||
vim.bo[buf_id].bufhidden = "wipe"
|
||||
@@ -107,23 +210,10 @@ local function show(auto_dismiss)
|
||||
noautocmd = true,
|
||||
})
|
||||
|
||||
if auto_dismiss then
|
||||
timer = vim.uv.new_timer()
|
||||
timer:start(3000, 0, vim.schedule_wrap(function() M.close() end))
|
||||
else
|
||||
vim.api.nvim_create_autocmd({ "CursorMoved", "InsertEnter", "CmdlineEnter" }, {
|
||||
once = true,
|
||||
callback = function() M.close() end,
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
function M.open()
|
||||
show(false)
|
||||
end
|
||||
|
||||
function M.splash()
|
||||
show(true)
|
||||
vim.api.nvim_create_autocmd({ "CursorMoved", "InsertEnter", "CmdlineEnter" }, {
|
||||
once = true,
|
||||
callback = function() M.close() end,
|
||||
})
|
||||
end
|
||||
|
||||
function M.is_open()
|
||||
|
||||
+381
-134
@@ -4,49 +4,234 @@ local help = require("turbo-debug.help")
|
||||
local M = {}
|
||||
|
||||
local active = false
|
||||
local active_buf = nil
|
||||
local active_win = nil
|
||||
local stashed_maps = {}
|
||||
local saved_winbar = nil
|
||||
local mapped_keys = {} -- track exactly which keys we set, for reliable cleanup
|
||||
local saved_statusline = nil
|
||||
local saved_laststatus = nil
|
||||
|
||||
-- installed[buf][name] = { key = lhs, prev_n = <prev n-mode map>, prev_v = <prev v-mode map> }
|
||||
local installed = {}
|
||||
|
||||
-- one-time dap-ui and virtual-text initialization
|
||||
local dapui_initialized = false
|
||||
local vt_initialized = false
|
||||
|
||||
-- ─── layout ──────────────────────────────────────────────────────────────────
|
||||
|
||||
local function build_default_layouts()
|
||||
local pos = config.opts.sidebar == "right" and "right" or "left"
|
||||
return {
|
||||
{
|
||||
position = pos,
|
||||
size = 40,
|
||||
elements = {
|
||||
{ id = "scopes", size = 0.40 },
|
||||
{ id = "watches", size = 0.20 },
|
||||
{ id = "stacks", size = 0.25 },
|
||||
{ id = "breakpoints", size = 0.15 },
|
||||
},
|
||||
},
|
||||
{
|
||||
position = "bottom",
|
||||
size = 12,
|
||||
elements = {
|
||||
{ id = "repl", size = 0.50 },
|
||||
{ id = "console", size = 0.50 },
|
||||
},
|
||||
},
|
||||
}
|
||||
end
|
||||
|
||||
-- ─── highlights ──────────────────────────────────────────────────────────────
|
||||
|
||||
local function define_highlights()
|
||||
local hl = vim.api.nvim_set_hl
|
||||
hl(0, "TurboDebugBorderActive", { default = true, link = "Function" })
|
||||
hl(0, "TurboDebugBorderInactive", { default = true, link = "Comment" })
|
||||
hl(0, "TurboDebugWinbar", { default = true, link = "DiagnosticError" })
|
||||
hl(0, "TurboDebugSLState", { default = true, link = "DiagnosticError" })
|
||||
hl(0, "TurboDebugSLCtrl", { default = true, link = "Function" })
|
||||
hl(0, "TurboDebugSLStatus", { default = true, link = "Comment" })
|
||||
end
|
||||
|
||||
local function setup_active_win_highlights()
|
||||
local active_hl = "WinSeparator:TurboDebugBorderActive,FloatBorder:TurboDebugBorderActive"
|
||||
local inactive_hl = "WinSeparator:TurboDebugBorderInactive,FloatBorder:TurboDebugBorderInactive"
|
||||
|
||||
local group = vim.api.nvim_create_augroup("TurboDebugActiveWin", { clear = true })
|
||||
local function apply(win, hl)
|
||||
if vim.api.nvim_win_is_valid(win) and vim.api.nvim_win_get_config(win).relative == "" then
|
||||
local ft = vim.bo[vim.api.nvim_win_get_buf(win)].filetype or ""
|
||||
if ft:match("^dapui_") or ft == "dap-repl" then
|
||||
vim.wo[win].winhighlight = hl
|
||||
end
|
||||
end
|
||||
end
|
||||
vim.api.nvim_create_autocmd("WinEnter", {
|
||||
group = group,
|
||||
callback = function() apply(vim.api.nvim_get_current_win(), active_hl) end,
|
||||
})
|
||||
vim.api.nvim_create_autocmd("WinLeave", {
|
||||
group = group,
|
||||
callback = function() apply(vim.api.nvim_get_current_win(), inactive_hl) end,
|
||||
})
|
||||
end
|
||||
|
||||
-- ─── global control buttons (used by the statusline) ────────────────────────
|
||||
|
||||
_G.turbo_debug_continue = function() M.actions().continue() end
|
||||
_G.turbo_debug_step_over = function() require("dap").step_over() end
|
||||
_G.turbo_debug_step_into = function() require("dap").step_into() end
|
||||
_G.turbo_debug_step_out = function() require("dap").step_out() end
|
||||
_G.turbo_debug_restart = function() require("dap").restart() end
|
||||
_G.turbo_debug_terminate = function() require("dap").terminate() end
|
||||
_G.turbo_debug_toggle = function() M.toggle() end
|
||||
|
||||
function _G.turbo_debug_statusline()
|
||||
local dap_ok, dap = pcall(require, "dap")
|
||||
local state, state_hl
|
||||
if not dap_ok then
|
||||
state, state_hl = "READY", "TurboDebugSLStatus"
|
||||
else
|
||||
local s = dap.session()
|
||||
if not s then
|
||||
state, state_hl = "READY", "TurboDebugSLStatus"
|
||||
elseif s.stopped_thread_id then
|
||||
state, state_hl = "PAUSED", "TurboDebugSLState"
|
||||
else
|
||||
state, state_hl = "RUNNING", "TurboDebugSLCtrl"
|
||||
end
|
||||
end
|
||||
|
||||
-- ● state, then 6 clickable controls, then dap progress text (right-aligned)
|
||||
local parts = {
|
||||
"%#" .. state_hl .. "# \xe2\x97\x8f " .. state .. " %*",
|
||||
" ",
|
||||
"%#TurboDebugSLCtrl#",
|
||||
"%@v:lua.turbo_debug_continue@ \xe2\x96\xb6 %X", -- ▶ continue
|
||||
"%@v:lua.turbo_debug_step_over@ \xe2\x87\x92 %X", -- ⇒ step over
|
||||
"%@v:lua.turbo_debug_step_into@ \xe2\xa4\x93 %X", -- ⤓ step into
|
||||
"%@v:lua.turbo_debug_step_out@ \xe2\xa4\x92 %X", -- ⤒ step out
|
||||
"%@v:lua.turbo_debug_restart@ \xe2\x86\xbb %X", -- ↻ restart
|
||||
"%@v:lua.turbo_debug_terminate@ \xe2\x96\xa0 %X", -- ■ terminate
|
||||
"%@v:lua.turbo_debug_toggle@ \xe2\x8a\x97 %X", -- ⊗ exit debug mode
|
||||
"%*",
|
||||
" %=",
|
||||
"%#TurboDebugSLStatus#%{v:lua.require'dap'.status()}%*",
|
||||
" %l:%c ",
|
||||
}
|
||||
return table.concat(parts, "")
|
||||
end
|
||||
|
||||
-- ─── dap-ui setup ────────────────────────────────────────────────────────────
|
||||
|
||||
local function set_dapui_window_opts(win)
|
||||
-- dapui elements render long single-line values (e.g. register dumps) that
|
||||
-- bleed into adjacent windows when wrap is on. Force-disable wrap and
|
||||
-- horizontal-scroll padding so values stay inside the pane.
|
||||
if vim.api.nvim_win_is_valid(win) then
|
||||
vim.wo[win].wrap = false
|
||||
vim.wo[win].sidescrolloff = 0
|
||||
vim.wo[win].linebreak = false
|
||||
vim.wo[win].cursorline = true
|
||||
end
|
||||
end
|
||||
|
||||
local function ensure_dapui()
|
||||
if dapui_initialized then return end
|
||||
dapui_initialized = true
|
||||
require("dapui").setup(config.opts.dapui)
|
||||
local dapui_opts = vim.deepcopy(config.opts.dapui)
|
||||
if not dapui_opts.layouts then dapui_opts.layouts = build_default_layouts() end
|
||||
require("dapui").setup(dapui_opts)
|
||||
|
||||
local dap = require("dap")
|
||||
dap.listeners.after.event_terminated["turbo-debug"] = function()
|
||||
if active then M.exit() end
|
||||
end
|
||||
dap.listeners.after.event_exited["turbo-debug"] = function()
|
||||
if active then M.exit() end
|
||||
dap.listeners.after.event_initialized["turbo-debug"] = function()
|
||||
require("dapui").open()
|
||||
end
|
||||
|
||||
-- set winbar titles on dapui panels (REPL gets controls toolbar from dapui)
|
||||
-- K = hover during a live dap session (works globally, not just modally)
|
||||
dap.listeners.after.event_initialized["turbo-debug-hover"] = function()
|
||||
vim.keymap.set("n", "K", function()
|
||||
require("dap.ui.widgets").hover(nil, { border = "rounded" })
|
||||
end, { silent = true, desc = "DAP hover" })
|
||||
end
|
||||
dap.listeners.after.event_terminated["turbo-debug-hover"] = function()
|
||||
pcall(vim.keymap.del, "n", "K")
|
||||
end
|
||||
|
||||
-- Console redraws: dapui's console buffer updates on event_output but
|
||||
-- nvim doesn't always repaint the window until focus changes. Force a
|
||||
-- schedule-wrapped redraw so output appears live.
|
||||
dap.listeners.after.event_output["turbo-debug-redraw"] = vim.schedule_wrap(function()
|
||||
pcall(vim.cmd.redraw)
|
||||
end)
|
||||
|
||||
-- IP marker: paired-arrow design.
|
||||
-- gutter: ▶ (points RIGHT at the line from the sign column)
|
||||
-- eol: ◀ (points LEFT at the line from the end of content)
|
||||
-- The uppercase reason (STEP / BREAKPOINT / EXCEPTION / PAUSE / ENTRY)
|
||||
-- renders in bold TurboDebugIPReason so it jumps off the screen.
|
||||
local ip_ns = vim.api.nvim_create_namespace("turbo-debug.ip")
|
||||
local function clear_ip()
|
||||
for _, buf in ipairs(vim.api.nvim_list_bufs()) do
|
||||
if vim.api.nvim_buf_is_valid(buf) then
|
||||
vim.api.nvim_buf_clear_namespace(buf, ip_ns, 0, -1)
|
||||
end
|
||||
end
|
||||
end
|
||||
dap.listeners.after.event_stopped["turbo-debug-ip"] = function(session, body)
|
||||
vim.defer_fn(function()
|
||||
clear_ip()
|
||||
local frame = session and session.current_frame
|
||||
if not (frame and frame.source and frame.source.path) then return end
|
||||
local buf = vim.fn.bufnr(frame.source.path)
|
||||
if buf == -1 or not vim.api.nvim_buf_is_valid(buf) then return end
|
||||
local line = math.max(0, (frame.line or 1) - 1)
|
||||
local reason = ((body and body.reason) or "stopped"):upper()
|
||||
pcall(vim.api.nvim_buf_set_extmark, buf, ip_ns, line, 0, {
|
||||
virt_text = {
|
||||
{ " \xe2\x97\x80 ", "DapStopped" }, -- ◀
|
||||
{ reason, "TurboDebugIPReason" },
|
||||
},
|
||||
virt_text_pos = "eol",
|
||||
hl_mode = "combine",
|
||||
priority = 200,
|
||||
})
|
||||
end, 50)
|
||||
end
|
||||
dap.listeners.after.event_continued["turbo-debug-ip"] = function() clear_ip() end
|
||||
dap.listeners.before.event_terminated["turbo-debug-ip"] = function() clear_ip() end
|
||||
dap.listeners.before.event_exited["turbo-debug-ip"] = function() clear_ip() end
|
||||
|
||||
-- dapui winbar titles + window options (wrap=false to stop the register
|
||||
-- overflow bug). Apply on FileType so we catch every pane dapui creates.
|
||||
local titles = {
|
||||
dapui_scopes = " Scopes",
|
||||
dapui_watches = " Watches",
|
||||
dapui_stacks = " Call Stack",
|
||||
dapui_console = " Console",
|
||||
dapui_breakpoints = " Breakpoints",
|
||||
dapui_scopes = " \xe2\x97\x86 Scopes",
|
||||
dapui_watches = " \xe2\x97\x89 Watches",
|
||||
dapui_stacks = " \xe2\x89\xa1 Call Stack",
|
||||
dapui_breakpoints = " \xe2\x97\x8f Breakpoints",
|
||||
dapui_console = " \xe2\x9d\xaf Console",
|
||||
["dap-repl"] = " \xe2\x9d\xaf_ REPL",
|
||||
}
|
||||
vim.api.nvim_create_autocmd("FileType", {
|
||||
pattern = "dapui_*",
|
||||
pattern = { "dapui_*", "dap-repl" },
|
||||
callback = function(args)
|
||||
local title = titles[vim.bo[args.buf].filetype]
|
||||
if title then
|
||||
vim.schedule(function()
|
||||
local win = vim.fn.bufwinid(args.buf)
|
||||
if win ~= -1 then vim.wo[win].winbar = title end
|
||||
end)
|
||||
end
|
||||
local ft = vim.bo[args.buf].filetype
|
||||
local title = titles[ft]
|
||||
vim.schedule(function()
|
||||
local win = vim.fn.bufwinid(args.buf)
|
||||
if win ~= -1 then
|
||||
if title then vim.wo[win].winbar = title end
|
||||
set_dapui_window_opts(win)
|
||||
end
|
||||
-- also (re-)install modal keys on this dapui buffer — BufEnter may
|
||||
-- not fire at create time and we want the keys ready the moment
|
||||
-- the user clicks in.
|
||||
if active then M._install_for_buf(args.buf) end
|
||||
end)
|
||||
end,
|
||||
})
|
||||
|
||||
if config.opts.active_window_highlight then setup_active_win_highlights() end
|
||||
end
|
||||
|
||||
local function ensure_vt()
|
||||
@@ -55,123 +240,165 @@ local function ensure_vt()
|
||||
require("nvim-dap-virtual-text").setup(config.opts.virtual_text)
|
||||
end
|
||||
|
||||
-- keymap stash/restore
|
||||
-- ─── actions ────────────────────────────────────────────────────────────────
|
||||
|
||||
local function stash_mapping(buf, lhs)
|
||||
for _, map in ipairs(vim.api.nvim_buf_get_keymap(buf, "n")) do
|
||||
if map.lhs == lhs then
|
||||
stashed_maps[lhs] = map
|
||||
return
|
||||
end
|
||||
end
|
||||
stashed_maps[lhs] = nil
|
||||
end
|
||||
|
||||
local function restore_mapping(buf, lhs)
|
||||
local map = stashed_maps[lhs]
|
||||
if map then
|
||||
local rhs = map.rhs or map.callback
|
||||
if rhs then
|
||||
pcall(vim.keymap.set, "n", lhs, rhs, {
|
||||
buffer = buf,
|
||||
silent = map.silent == 1,
|
||||
noremap = map.noremap == 1,
|
||||
expr = map.expr == 1,
|
||||
desc = map.desc,
|
||||
})
|
||||
end
|
||||
else
|
||||
pcall(vim.keymap.del, "n", lhs, { buffer = buf })
|
||||
end
|
||||
end
|
||||
|
||||
-- actions (set up once)
|
||||
|
||||
local actions = {}
|
||||
local actions_cache
|
||||
local visual_actions = { watch = true, hover = true }
|
||||
|
||||
local function has_any_breakpoint()
|
||||
local ok, bps = pcall(require, "dap.breakpoints")
|
||||
if not ok then return false end
|
||||
local all = bps.get()
|
||||
for _, lines in pairs(all or {}) do
|
||||
if #lines > 0 then return true end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
local function launch_with_stop_on_entry()
|
||||
local dap = require("dap")
|
||||
local ft = vim.bo.filetype or ""
|
||||
local cfgs = dap.configurations[ft]
|
||||
if not (cfgs and cfgs[1]) then
|
||||
-- no config → fall back to normal continue (which will prompt / error)
|
||||
dap.continue()
|
||||
return
|
||||
end
|
||||
local cfg = vim.deepcopy(cfgs[1])
|
||||
cfg.stopOnEntry = true
|
||||
cfg.name = (cfg.name or "debug") .. " (stop on entry)"
|
||||
dap.run(cfg)
|
||||
end
|
||||
|
||||
local function smart_continue()
|
||||
local dap = require("dap")
|
||||
if dap.session() then dap.continue(); return end
|
||||
if config.opts.stop_on_entry_when_no_breakpoints ~= false and not has_any_breakpoint() then
|
||||
launch_with_stop_on_entry()
|
||||
else
|
||||
dap.continue()
|
||||
end
|
||||
end
|
||||
|
||||
local function step_or_launch(step_fn)
|
||||
-- if no session yet, a step key starts the session with stop-on-entry —
|
||||
-- matches the Turbo Pascal "just press a key to start stepping" vibe.
|
||||
if require("dap").session() then
|
||||
step_fn()
|
||||
else
|
||||
smart_continue()
|
||||
end
|
||||
end
|
||||
|
||||
local function setup_actions()
|
||||
if next(actions) then return end
|
||||
if actions_cache then return actions_cache end
|
||||
local dap = require("dap")
|
||||
local pb = require("persistent-breakpoints.api")
|
||||
|
||||
actions.continue = function() dap.continue() end
|
||||
actions.step_over = function() dap.step_over() end
|
||||
actions.step_into = function() dap.step_into() end
|
||||
actions.step_out = function() dap.step_out() end
|
||||
actions.run_to_cursor = function() dap.run_to_cursor() end
|
||||
actions.restart = function() dap.restart() end
|
||||
actions.help = function()
|
||||
if help.is_open() then help.close() else help.open() end
|
||||
end
|
||||
actions.terminate = function()
|
||||
dap.terminate()
|
||||
if config.opts.quit_exits_mode then M.exit() end
|
||||
end
|
||||
|
||||
-- breakpoint actions (modal shortcuts for the <leader>d* globals)
|
||||
actions.breakpoint = function() pb.toggle_breakpoint() end
|
||||
actions.cond_breakpoint = function() pb.set_conditional_breakpoint() end
|
||||
actions.clear_breakpoints = function() pb.clear_all_breakpoints() end
|
||||
|
||||
actions.watch = function()
|
||||
local expr
|
||||
if vim.fn.mode() == "v" or vim.fn.mode() == "V" then
|
||||
vim.cmd('noautocmd normal! "vy')
|
||||
expr = vim.fn.getreg("v")
|
||||
else
|
||||
expr = vim.fn.expand("<cexpr>")
|
||||
end
|
||||
if expr and expr ~= "" then
|
||||
require("dapui").elements.watches.add(expr)
|
||||
end
|
||||
end
|
||||
actions.hover = function() require("dapui").eval() end
|
||||
actions.eval = function() require("dapui").float_element("repl") end
|
||||
end
|
||||
|
||||
-- keymap lifecycle
|
||||
-- track every key we set so cleanup is exact — never miss one, never clear the wrong one
|
||||
|
||||
local function set_keymaps(buf)
|
||||
mapped_keys = {}
|
||||
local keys = config.opts.keys
|
||||
for name, key in pairs(keys) do
|
||||
if key and actions[name] then
|
||||
stash_mapping(buf, key)
|
||||
vim.keymap.set("n", key, actions[name], { buffer = buf, silent = true, desc = "turbo-debug: " .. name })
|
||||
if visual_actions[name] then
|
||||
vim.keymap.set("v", key, actions[name], { buffer = buf, silent = true, desc = "turbo-debug: " .. name })
|
||||
actions_cache = {
|
||||
continue = smart_continue,
|
||||
step_over = function() step_or_launch(dap.step_over) end,
|
||||
step_into = function() step_or_launch(dap.step_into) end,
|
||||
step_out = function() step_or_launch(dap.step_out) end,
|
||||
run_to_cursor = function() dap.run_to_cursor() end,
|
||||
restart = function() dap.restart() end,
|
||||
terminate = function()
|
||||
dap.terminate()
|
||||
if config.opts.quit_exits_mode then M.exit() end
|
||||
end,
|
||||
help = function()
|
||||
if help.is_open() then help.close() else help.open() end
|
||||
end,
|
||||
breakpoint = function() pb.toggle_breakpoint() end,
|
||||
cond_breakpoint = function() pb.set_conditional_breakpoint() end,
|
||||
clear_breakpoints = function() pb.clear_all_breakpoints() end,
|
||||
watch = function()
|
||||
local expr
|
||||
if vim.fn.mode() == "v" or vim.fn.mode() == "V" then
|
||||
vim.cmd('noautocmd normal! "vy')
|
||||
expr = vim.fn.getreg("v")
|
||||
else
|
||||
expr = vim.fn.expand("<cexpr>")
|
||||
end
|
||||
mapped_keys[#mapped_keys + 1] = { name = name, key = key }
|
||||
if expr and expr ~= "" then
|
||||
require("dapui").elements.watches.add(expr)
|
||||
end
|
||||
end,
|
||||
hover = function() require("dapui").eval() end,
|
||||
eval = function() require("dapui").float_element("repl") end,
|
||||
}
|
||||
return actions_cache
|
||||
end
|
||||
|
||||
function M.actions() return actions_cache or setup_actions() end
|
||||
|
||||
-- ─── keymap install / clear ─────────────────────────────────────────────────
|
||||
|
||||
local function find_buf_mapping(buf, lhs, mode)
|
||||
for _, m in ipairs(vim.api.nvim_buf_get_keymap(buf, mode)) do
|
||||
if m.lhs == lhs then return m end
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
local function restore_mapping(buf, mode, map)
|
||||
local rhs = map.rhs or map.callback
|
||||
if not rhs then return end
|
||||
pcall(vim.keymap.set, mode, map.lhs, rhs, {
|
||||
buffer = buf,
|
||||
silent = map.silent == 1,
|
||||
noremap = map.noremap == 1,
|
||||
expr = map.expr == 1,
|
||||
desc = map.desc,
|
||||
})
|
||||
end
|
||||
|
||||
function M._install_for_buf(buf)
|
||||
if not vim.api.nvim_buf_is_valid(buf) then return end
|
||||
local acts = setup_actions()
|
||||
installed[buf] = installed[buf] or {}
|
||||
for name, key in pairs(config.opts.keys) do
|
||||
if key and acts[name] and not installed[buf][name] then
|
||||
local prev_n = find_buf_mapping(buf, key, "n")
|
||||
local prev_v = visual_actions[name] and find_buf_mapping(buf, key, "v") or nil
|
||||
local opts = { buffer = buf, silent = true, desc = "turbo-debug: " .. name }
|
||||
if name == "continue" then opts.nowait = true end
|
||||
pcall(vim.keymap.set, "n", key, acts[name], opts)
|
||||
if visual_actions[name] then
|
||||
pcall(vim.keymap.set, "v", key, acts[name], opts)
|
||||
end
|
||||
installed[buf][name] = { key = key, prev_n = prev_n, prev_v = prev_v }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function clear_keymaps(buf)
|
||||
if not vim.api.nvim_buf_is_valid(buf) then
|
||||
mapped_keys = {}
|
||||
stashed_maps = {}
|
||||
return
|
||||
end
|
||||
for _, mk in ipairs(mapped_keys) do
|
||||
pcall(vim.keymap.del, "n", mk.key, { buffer = buf })
|
||||
if visual_actions[mk.name] then
|
||||
pcall(vim.keymap.del, "v", mk.key, { buffer = buf })
|
||||
local function clear_all_modal_keys()
|
||||
for buf, entries in pairs(installed) do
|
||||
if vim.api.nvim_buf_is_valid(buf) then
|
||||
for name, entry in pairs(entries) do
|
||||
pcall(vim.keymap.del, "n", entry.key, { buffer = buf })
|
||||
if visual_actions[name] then
|
||||
pcall(vim.keymap.del, "v", entry.key, { buffer = buf })
|
||||
end
|
||||
if entry.prev_n then restore_mapping(buf, "n", entry.prev_n) end
|
||||
if entry.prev_v then restore_mapping(buf, "v", entry.prev_v) end
|
||||
end
|
||||
end
|
||||
restore_mapping(buf, mk.key)
|
||||
end
|
||||
mapped_keys = {}
|
||||
stashed_maps = {}
|
||||
installed = {}
|
||||
end
|
||||
|
||||
-- debug mode chrome
|
||||
-- ─── chrome: per-source-window winbar badge + global statusline controls ──
|
||||
|
||||
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 = "%#DiagnosticError# 🐛 DEBUG %* %f"
|
||||
vim.api.nvim_set_hl(0, "Cursor", { bg = "#ff6600", fg = "#000000" })
|
||||
vim.wo[active_win].winbar = "%#TurboDebugWinbar# \xe2\x97\x8f DEBUG %* %f"
|
||||
|
||||
saved_statusline = vim.o.statusline
|
||||
saved_laststatus = vim.o.laststatus
|
||||
vim.o.laststatus = 3 -- one global statusline
|
||||
vim.o.statusline = "%!v:lua.turbo_debug_statusline()"
|
||||
end
|
||||
|
||||
local function clear_debug_chrome()
|
||||
@@ -180,37 +407,59 @@ local function clear_debug_chrome()
|
||||
end
|
||||
active_win = nil
|
||||
saved_winbar = nil
|
||||
vim.api.nvim_set_hl(0, "Cursor", {})
|
||||
|
||||
if saved_statusline ~= nil then vim.o.statusline = saved_statusline end
|
||||
if saved_laststatus ~= nil then vim.o.laststatus = saved_laststatus end
|
||||
saved_statusline = nil
|
||||
saved_laststatus = nil
|
||||
end
|
||||
|
||||
-- public API
|
||||
-- ─── public API ─────────────────────────────────────────────────────────────
|
||||
|
||||
function M.enter()
|
||||
if active then return end
|
||||
active = true
|
||||
define_highlights()
|
||||
setup_actions()
|
||||
|
||||
active_buf = vim.api.nvim_get_current_buf()
|
||||
set_keymaps(active_buf)
|
||||
set_debug_chrome()
|
||||
vim.api.nvim_create_augroup("TurboDebugModalKeys", { clear = true })
|
||||
vim.api.nvim_create_autocmd("BufEnter", {
|
||||
group = "TurboDebugModalKeys",
|
||||
callback = function(args)
|
||||
if active then M._install_for_buf(args.buf) 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
|
||||
|
||||
set_debug_chrome()
|
||||
ensure_dapui()
|
||||
require("dapui").open()
|
||||
|
||||
-- second install pass after dapui has created its buffers, since BufEnter
|
||||
-- doesn't always fire for windows that were opened without focus-change.
|
||||
vim.schedule(function()
|
||||
if not active then return 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
|
||||
end)
|
||||
|
||||
ensure_vt()
|
||||
require("nvim-dap-virtual-text").enable()
|
||||
|
||||
if config.opts.help_on_enter then
|
||||
help.splash()
|
||||
end
|
||||
if config.opts.help_on_enter then help.open() end
|
||||
end
|
||||
|
||||
function M.exit()
|
||||
if not active then return end
|
||||
active = false
|
||||
|
||||
clear_keymaps(active_buf or vim.api.nvim_get_current_buf())
|
||||
active_buf = nil
|
||||
if require("dap").session() then pcall(require("dap").terminate) end
|
||||
|
||||
pcall(vim.api.nvim_del_augroup_by_name, "TurboDebugModalKeys")
|
||||
clear_all_modal_keys()
|
||||
clear_debug_chrome()
|
||||
help.close()
|
||||
|
||||
@@ -222,8 +471,6 @@ function M.toggle()
|
||||
if active then M.exit() else M.enter() end
|
||||
end
|
||||
|
||||
function M.is_active()
|
||||
return active
|
||||
end
|
||||
function M.is_active() return active end
|
||||
|
||||
return M
|
||||
Reference in new issue
Block a user