LL
llawn/save-my-breakpoints.nvim
Neovim nvim-dap extension for persistent breakpoints
Save My Breakpoints
save-my-breakpoints is a memory-efficient Lua plugin for Neovim that saves
nvim-dap breakpoints to a file and
automatically restores them based on your current working directory.
Inspired by persistent-breakpoints.nvim
This version uses Base64URL encoding to create unique, reversible save
files for every project and uses an in-memory cache to ensure high
performance without constant disk I/O.
It comes with an optional Telescope menu for viewing and managing breakpoints:
Install
lazy.nvim
{
"llawn/save-my-breakpoints",
dependencies = {
"mfussenegger/nvim-dap",
"nvim-telescope/telescope.nvim" -- Optional for telescope integration
"nvim-tree/nvim-web-devicons" -- Optional for filetype icons in telescope_menu
},
}
Using vim.pack (Neovim 0.12+)
-- In your init.lua
vim.pack.add({
"mfussenegger/nvim-dap",
})
vim.pack.add({
"nvim-telescope/telescope.nvim", -- Optional for telescope integration
})
vim.pack.add({
"nvim-tree/nvim-web-devicons", -- Optional for filetype icons
})
vim.pack.add({
"llawn/save-my-breakpoints.nvim",
config = function()
require('save-my-breakpoints').setup({
telescope_menu = true,
load_on_buffer_open = true,
save_on_exit = true,
})
end,
})
Dependencies
- Optional: jq to format JSON files in
save_dir
Setup
Basic Setup
{
"llawn/save-my-breakpoints",
dependencies = {
"mfussenegger/nvim-dap",
"nvim-telescope/telescope.nvim" -- Optional for telescope integration
"nvim-tree/nvim-web-devicons" -- Optional for filetype icons in telescope_menu
},
config = function()
require('save-my-breakpoints').setup({
save_dir = vim.fn.stdpath('data') .. '/save_my_breakpoints',
load_on_start = true,
load_on_buffer_open = true,
save_on_exit = true,
telescope_menu = true, -- Enable telescope integration
})
end
}
Complete DAP Setup Example
This example shows how to integrate save-my-breakpoints with a full nvim-dap configuration (Lazy):
return {
{
"mfussenegger/nvim-dap",
dependencies = {
"rcarriga/nvim-dap-ui",
"theHamsta/nvim-dap-virtual-text",
"nvim-neotest/nvim-nio",
"jay-babu/mason-nvim-dap.nvim",
"williamboman/mason.nvim",
"llawn/save-my-breakpoints.nvim",
},
config = function()
local dap = require("dap")
local dapui = require("dapui")
-- Mason DAP Setup
require("mason-nvim-dap").setup({
automatic_installation = false,
ensure_installed = {},
handlers = {
function(config)
require('mason-nvim-dap').default_setup(config)
end,
},
})
-- UI & Virtual Text Setup
dapui.setup()
require("nvim-dap-virtual-text").setup({
commented = true,
})
-- Breakpoint Signs
local signs = {
DapBreakpoint = { text = "●", texthl = "DapBreakpoint", linehl = "", numhl = "" },
DapBreakpointCondition = { text = "●", texthl = "DapBreakpointCondition", linehl = "", numhl = "" },
DapLogPoint = { text = "", texthl = "DapLogPoint", linehl = "", numhl = "" },
DapStopped = { text = "", texthl = "DapStopped", linehl = "DapStopped", numhl = "DapStopped" },
}
vim.api.nvim_set_hl(0, 'DapBreakpoint', { fg = '#ff0800', bg = 'NONE' })
vim.api.nvim_set_hl(0, 'DapBreakpointCondition', { fg = '#da9100', bg = 'NONE' })
vim.api.nvim_set_hl(0, 'DapLogPoint', { fg = '#6cb4ee', bg = 'NONE' })
vim.api.nvim_set_hl(0, 'DapStopped', { fg = '#93c572', bg = '#353839', bold = true })
for name, sign in pairs(signs) do
vim.fn.sign_define(name, sign)
end
-- DAP Listeners
dap.listeners.after.event_initialized["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
-- Keymaps
local set = vim.keymap.set
set("n", "<F5>", dap.continue, { desc = "Debug: Start/Continue" })
set("n", "<F6>", dap.step_over, { desc = "Debug: Step Over" })
set("n", "<F7>", dap.step_into, { desc = "Debug: Step Into" })
set("n", "<F8>", dap.step_out, { desc = "Debug: Step Out" })
set("n", "<Leader>b", require('save-my-breakpoints').toggle_breakpoint, { desc = "Toggle Breakpoint" })
-- Save My Breakpoints Setup
require('save-my-breakpoints').setup({
save_dir = vim.fn.stdpath('data') .. '/breakpoints',
load_on_buffer_open = true,
save_on_exit = true,
telescope_menu = true,
})
end,
},
}
Default Configuration
| Option | Default | Description |
|---|---|---|
save_dir |
vim.fn.stdpath('data') .. /save_my_breakpoints |
Path to store the encoded JSON files. |
load_on_start |
true |
Load project breakpoints on startup. |
load_on_buffer_open |
true |
Load breakpoints for a file as soon as its buffer is opened. |
save_on_exit |
true |
Flush the memory cache to disk when Neovim closes. |
telescope_menu |
false |
Enable telescope integration for breakpoint management. |
Usage
User Commands
| Command | Description |
|---|---|
:SMBToggleBreakpoint |
Toggles a breakpoint and syncs memory (Delete Line Breakpoint / Add default Breakpoint) |
:SMBSetConditionalBreakpoint |
Prompts for a condition and sets a breakpoint |
:SMBSetLogPoint |
Prompts for a log message and sets a breakpoint |
:SMBClearAllBreakpoints |
Clears all breakpoints and deletes the project save file |
:SMBLoadBufferBreakpoints |
Load all breakpoints from current buffer |
:SMBLoadAllBreakpoints |
Load all breakpoints from current project |
:TelescopeBreakpoints |
Opens a telescope picker to view and delete breakpoints (requires telescope_menu = true) |
Recommended Keymaps
local smb = require('save-my-breakpoints')
vim.keymap.set("n", "<leader>bb", smb.toggle_breakpoint, { desc = "DAP Toggle Breakpoint" })
vim.keymap.set("n", "<leader>bc", smb.set_conditional_breakpoint, { desc = "DAP Conditional Breakpoint" })
vim.keymap.set("n", "<leader>bp", smb.set_log_point, { desc = "DAP Log Breakpoint" })
vim.keymap.set("n", "<leader>bX", smb.clear_all_breakpoints, { desc = "DAP Clear All Breakpoints" })
vim.keymap.set("n", "<leader>bl", smb.load_bps_for_buf, { desc = "DAP Load Buffer Breakpoints" })
vim.keymap.set("n", "<leader>bL", smb.load_all_breakpoints, { desc = "DAP Load All Breakpoints" })
vim.keymap.set("n", "<leader>bt", smb.show_breakpoints, { desc = "DAP Show Breakpoints (Telescope)" })
How it Works
- Efficiency: Breakpoints are stored in an in-memory session cache. Disk writes only happen when you call
flush_to_disk(automatically on exit). - Path Encoding: The plugin uses Base64URL to convert your current working directory into a safe filename. This allows you to have different breakpoints for the same file in different projects.
- Automatic Cleanup: If you clear all breakpoints in a project, the corresponding JSON file is automatically deleted from your disk.
- Telescope Integration: When enabled, provides a convenient telescope picker for viewing and managing breakpoints with delete functionality using
<C-d>.
License
MIT License - see LICENSE
On this page
Languages
Lua93.0%Makefile7.0%
Contributors
MIT License
Created January 27, 2026
Updated February 4, 2026
