Debugger in Neovim
Introduction
There has been some discussion on using debugger more actively as one of the primary tools when programming. Debugger is particularly useful to help us navigate the complexity of the program, especially if the program we are building is a complex one.
Debugger in Neovim
One of the key inspiration for me to write this is due to the image of complexity associated with establishing config in Neovim. I can assure you if you are not interested in doing custom Neovim, you can set up your own debugging IDE in 10-15 minutes.
Install Neovim
I'm using LazyVim. Just follow the installation process which is fairly easy:
Install DAP (Debugger Adapter Protocol)
You install DAP via Mason:
I mainly writes C, Zig and Rust so codelldb here is perfect for my use case. You can choose whatever DAP you need: elixir, python, go, haskell, etc.
Config - Plugins
Now we are going to do some neovim configuration that is famous to be hard to do..well it is hard if you want to custom everything, but relatively easy if you are okay with the defaults.
Go to your neovim config, mine is at ~/.config/nvim
.
Below is the tree view of my neovim config directory:
Next let's install the two plugins (mason-nvim-dap and nvim-dap-ui).
mason-nvim-dap.lua
return {
"jay-babu/mason-nvim-dap.nvim",
event = "VeryLazy",
dependencies = {
"williamboman/mason.nvim",
"mfussenegger/nvim-dap",
},
opts = {
handlers = {},
ensure_installed = {
"codelldb",
},
},
}
nvim-dap-ui.lua
return {
{
"rcarriga/nvim-dap-ui",
dependencies = {
"mfussenegger/nvim-dap",
"nvim-neotest/nvim-nio",
},
event = "VeryLazy",
config = function()
local dap, dapui = require("dap"), require("dapui")
dapui.setup()
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
vim.keymap.set("n", "<F1>", dap.close, { desc = "DAP: Close" })
vim.keymap.set("n", "<F4>", dap.continue, { desc = "DAP: Continue" })
vim.keymap.set("n", "<F5>", dap.clear_breakpoints, { desc = "DAP: Clear Breakpoint" })
vim.keymap.set("n", "<F8>", dap.toggle_breakpoint, { desc = "DAP: Toggle Breakpoint" })
vim.keymap.set("n", "<F10>", dap.step_over, { desc = "DAP: Step Over" })
vim.keymap.set("n", "<F11>", dap.step_into, { desc = "DAP: Step Into" })
vim.keymap.set("n", "<F12>", dap.step_out, { desc = "DAP: Step Out" })
vim.keymap.set("n", "<Leader>dt", dapui.toggle, { desc = "Toggle DAP-UI" })
vim.keymap.set(
"n",
"<Leader>dr",
":lua require('dapui').open({reset = true})<CR>",
{ noremap = true, desc = "Reset DAP-UI layout" }
)
vim.fn.sign_define(
"DapBreakpoint",
{ text = "🔴", texthl = "DapBreakpoint", linehl = "DapBreakpoint", numhl = "DapBreakpoint" }
)
vim.fn.sign_define(
"DapStopped",
-- the text symbol below looks empty but it's actually there (orange play button)
{ text = "▶️", texthl = "DapStopped", linehl = "DapStopped", numhl = "DapStopped" }
)
end,
},
}
And that's it...you've successfully set up a debugger in your Neovim! How long did it took? 20-30 mins at most assuming you encountered roadblocks?
What it looks like
Mine looks like this:
Additional references
Check these youtube vids:
Enjoy your new Neovim debugger, cheers!