Public Access
137 lines
6.1 KiB
Lua
137 lines
6.1 KiB
Lua
local dap, dapui = require("dap"), require("dapui")
|
|
|
|
-- Install debug adapters via Mason (same pattern as the LSP tool loop in
|
|
-- plugins.lua). codelldb -> c/cpp/rust, debugpy -> python,
|
|
-- js-debug-adapter -> node/ts, haskell-debug-adapter -> haskell.
|
|
-- java-debug-adapter is installed by the LSP ensure loop and wired through
|
|
-- jdtls (see lua/lsp.lua).
|
|
-- Note: haskell-debug-adapter builds from source via cabal on first install
|
|
-- (needs ghc/cabal on PATH) so it can take a few minutes to appear.
|
|
local registry = require("mason-registry")
|
|
registry.refresh(function()
|
|
for _, tool in ipairs({ "debugpy", "codelldb", "js-debug-adapter", "haskell-debug-adapter" }) do
|
|
local ok, pkg = pcall(registry.get_package, tool)
|
|
if ok and not pkg:is_installed() then pkg:install() end
|
|
end
|
|
end)
|
|
|
|
dapui.setup()
|
|
require("nvim-dap-virtual-text").setup()
|
|
|
|
-- Auto-wire adapters + default launch configs for every mason-installed
|
|
-- adapter. Empty handlers = use mason-nvim-dap's default handler for all.
|
|
-- To add a language later: install its adapter in the loop above; it is
|
|
-- configured here automatically. Override by defining dap.configurations.<ft>
|
|
-- below this call.
|
|
require("mason-nvim-dap").setup({
|
|
ensure_installed = {},
|
|
automatic_installation = false,
|
|
handlers = {},
|
|
})
|
|
|
|
-- JS/TS (node): mason-nvim-dap ships no default handler for js-debug-adapter,
|
|
-- so wire the pwa-node adapter and launch/attach configs manually.
|
|
dap.adapters["pwa-node"] = {
|
|
type = "server",
|
|
host = "localhost",
|
|
port = "${port}",
|
|
executable = {
|
|
command = "node",
|
|
args = {
|
|
vim.fs.joinpath(vim.fn.stdpath("data"), "mason", "packages",
|
|
"js-debug-adapter", "js-debug", "src", "dapDebugServer.js"),
|
|
"${port}",
|
|
},
|
|
},
|
|
}
|
|
for _, ft in ipairs({ "javascript", "typescript" }) do
|
|
dap.configurations[ft] = {
|
|
{
|
|
type = "pwa-node",
|
|
request = "launch",
|
|
name = "Launch file",
|
|
program = "${file}",
|
|
cwd = "${workspaceFolder}",
|
|
},
|
|
{
|
|
type = "pwa-node",
|
|
request = "attach",
|
|
name = "Attach to process",
|
|
processId = require("dap.utils").pick_process,
|
|
cwd = "${workspaceFolder}",
|
|
},
|
|
}
|
|
end
|
|
|
|
-- Haskell (plain ghc): mason-nvim-dap's default handler auto-wires the
|
|
-- haskell-debug-adapter, but its default launch config assumes `stack ghci`
|
|
-- (with a literal "TARGET" placeholder). Override it to drive ghci-dap
|
|
-- directly so a bare `.hs` file debugs with <F5> — no cabal/stack project
|
|
-- required. ghci-dap resolves via PATH (mason bin). Switch ghciCmd to
|
|
-- `cabal exec -- ghci-dap ...` or `stack ghci --with-ghc=ghci-dap ...` if you
|
|
-- later move to a build tool. Verified end-to-end: loads ${file}, stops at
|
|
-- entry, hits breakpoints.
|
|
dap.configurations.haskell = {
|
|
{
|
|
type = "haskell",
|
|
request = "launch",
|
|
name = "Debug (ghc)",
|
|
workspace = "${workspaceFolder}",
|
|
startup = "${file}",
|
|
stopOnEntry = true,
|
|
logFile = vim.fs.joinpath(vim.fn.stdpath("data"), "haskell-dap.log"),
|
|
logLevel = "WARNING",
|
|
ghciEnv = vim.empty_dict(),
|
|
ghciPrompt = "H>>= ",
|
|
ghciInitialPrompt = "ghci> ",
|
|
ghciCmd = "ghci-dap --interactive -i${workspaceFolder} ${startup}",
|
|
},
|
|
}
|
|
|
|
-- Run debuggees in dap-ui's Console terminal so programs that read user input
|
|
-- work. Without this, nvim-dap uses an output-only internal console with no
|
|
-- stdin (the program just hangs on input()/getLine/scanf). dap-ui registers its
|
|
-- Console as dap.defaults.fallback.terminal_win_cmd, so any adapter that runs
|
|
-- the program in an integrated terminal is routed there. Adapters disagree on
|
|
-- the key -- debugpy/pwa-node use `console`, codelldb uses `terminal` -- and
|
|
-- each ignores the other, so set both on every launch config. Applies to the
|
|
-- mason-auto-generated configs (python/cpp/rust) too, since it runs after their
|
|
-- setup. To type: focus the Console window and press `i` (terminal insert).
|
|
for _, configs in pairs(dap.configurations) do
|
|
for _, cfg in ipairs(configs) do
|
|
if cfg.request == "launch" then
|
|
if cfg.console == nil then cfg.console = "integratedTerminal" end
|
|
if cfg.terminal == nil then cfg.terminal = "integrated" end
|
|
end
|
|
end
|
|
end
|
|
|
|
-- Open/close the dap-ui panels automatically with the session.
|
|
dap.listeners.before.attach.dapui_config = function() dapui.open() end
|
|
dap.listeners.before.launch.dapui_config = function() dapui.open() end
|
|
dap.listeners.before.event_terminated.dapui_config = function() dapui.close() end
|
|
dap.listeners.before.event_exited.dapui_config = function() dapui.close() end
|
|
|
|
-- VS Code standard F-keys
|
|
local map = vim.keymap.set
|
|
map("n", "<F5>", dap.continue, { desc = "Debug: continue / start" })
|
|
map("n", "<S-F5>", dap.terminate, { desc = "Debug: stop" })
|
|
map("n", "<C-S-F5>", dap.restart, { desc = "Debug: restart" })
|
|
map("n", "<F6>", dap.pause, { desc = "Debug: pause" })
|
|
map("n", "<F9>", dap.toggle_breakpoint, { desc = "Debug: toggle breakpoint" })
|
|
map("n", "<F10>", dap.step_over, { desc = "Debug: step over" })
|
|
map("n", "<F11>", dap.step_into, { desc = "Debug: step into" })
|
|
map("n", "<S-F11>", dap.step_out, { desc = "Debug: step out" })
|
|
|
|
-- Leader maps (preserve the previous <leader>d* bindings + a few niceties;
|
|
-- discoverable via <C-k> Pick keymaps thanks to desc).
|
|
map("n", "<leader>duo", dapui.open, { desc = "Debug: open UI" })
|
|
map("n", "<leader>duc", dapui.close, { desc = "Debug: close UI" })
|
|
map("n", "<leader>dbp", dap.toggle_breakpoint, { desc = "Debug: toggle breakpoint" })
|
|
map("n", "<leader>drc", dap.run_to_cursor, { desc = "Debug: run to cursor" })
|
|
map("n", "<leader>dr", dap.repl.toggle, { desc = "Debug: toggle REPL" })
|
|
map("n", "<leader>de", function() dapui.eval() end, { desc = "Debug: eval under cursor" })
|
|
map("n", "<leader>dB", function()
|
|
dap.set_breakpoint(vim.fn.input("Breakpoint condition: "))
|
|
end, { desc = "Debug: conditional breakpoint" })
|