-
-
Notifications
You must be signed in to change notification settings - Fork 215
New issue
Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? # to your account
Feature Request: Breakpoint persistence #198
Comments
You could write some custom functions that let you export and import the active breakpoints: local breakpoints = require('dap.breakpoints')
function M.store()
local bps = {}
local breakpoints_by_buf = breakpoints.get()
for buf, buf_bps in pairs(breakpoints_by_buf) do
bps[tostring(buf)] = buf_bps
end
local fp = io.open('/tmp/breakpoints.json', 'w')
fp:write(vim.fn.json_encode(bps))
fp:close()
end
function M.load()
local fp = io.open('/tmp/breakpoints.json', 'r')
local content = fp:read('*a')
local bps = vim.fn.json_decode(content)
for buf, buf_bps in pairs(bps) do
for _, bp in pairs(buf_bps) do
local line = bp.line
local opts = {
condition = bp.condition,
log_message = bp.logMessage,
hit_condition = bp.hitCondition
}
breakpoints.set(opts, tonumber(buf), line)
end
end
end Not sure if this is a common enough use-case to warrant including something like that out of the box. (And the |
Thanks for the pointer and implementation suggestion here! I'm fine having a local function and dealing with breakages. Nonetheless I do think normal IDEs persist by default (although it's been a while so might be wrong here) so my biased opinion is that this should likely be default behaviour :) In any event, this solves my issue so thanks a lot, and feel free to notfix or close this issue if you don't think you'll implement it! |
Just my two cents, I think persisting breakpoints would be great. At least for the life of the current open file. |
This is currently already the case, or maybe I misunderstand what you mean with persisting? |
I'm all for persistent breakpoints! I think it would make sense to make it an optional feature that is off by default but having the option built in would be great! |
If anyone is interested I've added to the functions that @mfussenegger left in a comment so that the breakpoints persist even when neovim is closed and the numbers of the buffers change. HOME = os.getenv("HOME")
local breakpoints = require('dap.breakpoints')
function _G.store_breakpoints(clear)
local load_bps_raw = io.open(HOME .. '/.cache/dap/breakpoints.json', 'r'):read("*a")
local bps = vim.fn.json_decode(load_bps_raw)
local breakpoints_by_buf = breakpoints.get()
if (clear) then
for _, bufrn in ipairs(vim.api.nvim_list_bufs()) do
local file_path = vim.api.nvim_buf_get_name(bufrn)
if (bps[file_path] ~= nil) then
bps[file_path] = {}
end
end
else
for buf, buf_bps in pairs(breakpoints_by_buf) do
bps[vim.api.nvim_buf_get_name(buf)] = buf_bps
end
end
local fp = io.open(HOME .. '/.cache/dap/breakpoints.json', 'w')
local final = vim.fn.json_encode(bps)
fp:write(final)
fp:close()
end
function _G.load_breakpoints()
local fp = io.open(HOME .. '/.cache/dap/breakpoints.json', 'r')
local content = fp:read('*a')
local bps = vim.fn.json_decode(content)
local loaded_buffers = {}
local found = false
for _, buf in ipairs(vim.api.nvim_list_bufs()) do
local file_name = vim.api.nvim_buf_get_name(buf)
if (bps[file_name] ~= nil and bps[file_name] ~= {}) then
found = true
end
loaded_buffers[file_name] = buf
end
if (found == false) then
return
end
for path, buf_bps in pairs(bps) do
for _, bp in pairs(buf_bps) do
local line = bp.line
local opts = {
condition = bp.condition,
log_message = bp.logMessage,
hit_condition = bp.hitCondition
}
breakpoints.set(opts, tonumber(loaded_buffers[path]), line)
end
end
end Then I trigger the storing at the same time as a breakpoint toggle or clear vim.keymap.set( {'n', 'i', 'v'}, '<F3>', '<cmd>lua require"dap".clear_breakpoints();store_breakpoints(true)<CR>' )
vim.keymap.set( {'n', 'i', 'v'}, '<F4>', '<cmd>lua require"dap".toggle_breakpoint();store_breakpoints(false)<CR>' ) and I load the breakpoints with an autocommand everytime a file opens autocmd BufRead * :lua load_breakpoints() This could probably be cleaned up because this is my first time writing lua but so far its been working pretty well for me |
Hey! Thanks for your solution! I faced some bugs with this implementation, so I decided to rewrite it in a more concise manner. Please, check it out in my repo if you are interested |
Haha I'll have to check it out because I've also had annoying bugs and have been too lazy to fix them. Thanks! |
I write a lua plugin for persistent checkpoints. https://github.com/Weissle/persistent-breakpoints.nvim |
Why not provide commands to export and import breakpoints? A better solution would be to record the actions in nvim-dap and let the user edit them. The ideal solution can transpile the simple things between gdb/lldb and nvim-dap (probably only in one direction is feasible). |
I'd like to suggest an alternative: let g:DAPBREAKPOINTS={
\ "filepath"= { line = "condition"}
\} That would save them to the |
This comment was marked as spam.
This comment was marked as spam.
@child404 Here is the linux version that creates the cache file if not exists: M.store_breakpoints = function(clear)
-- if doesn't exist create it:
if vim.fn.filereadable(HOME .. "/.cache/dap/breakpoints.json") == 0 then
-- Create file
os.execute("mkdir -p " .. HOME .. "/.cache/dap")
os.execute("touch " .. HOME .. "/.cache/dap/breakpoints.json")
end
local load_bps_raw = io.open(HOME .. "/.cache/dap/breakpoints.json", "r"):read "*a"
if load_bps_raw == "" then
load_bps_raw = "{}"
end
local bps = vim.fn.json_decode(load_bps_raw)
local breakpoints_by_buf = require("dap.breakpoints").get()
if clear then
for _, bufrn in ipairs(vim.api.nvim_list_bufs()) do
local file_path = vim.api.nvim_buf_get_name(bufrn)
if bps[file_path] ~= nil then
bps[file_path] = {}
end
end
else
for buf, buf_bps in pairs(breakpoints_by_buf) do
bps[vim.api.nvim_buf_get_name(buf)] = buf_bps
end
end
local fp = io.open(HOME .. "/.cache/dap/breakpoints.json", "w")
local final = vim.fn.json_encode(bps)
fp:write(final)
fp:close()
end
M.load_breakpoints = function()
local fp = io.open(HOME .. "/.cache/dap/breakpoints.json", "r")
if fp == nil then
print "No breakpoints found."
return
end
local content = fp:read "*a"
local bps = vim.fn.json_decode(content)
local loaded_buffers = {}
local found = false
for _, buf in ipairs(vim.api.nvim_list_bufs()) do
local file_name = vim.api.nvim_buf_get_name(buf)
if bps[file_name] ~= nil and bps[file_name] ~= {} then
found = true
end
loaded_buffers[file_name] = buf
end
if found == false then
return
end
for path, buf_bps in pairs(bps) do
for _, bp in pairs(buf_bps) do
local line = bp.line
local opts = {
condition = bp.condition,
log_message = bp.logMessage,
hit_condition = bp.hitCondition,
}
require("dap.breakpoints").set(opts, tonumber(loaded_buffers[path]), line)
end
end
end
|
There is a plugin with one of its features being exactly that, to save the breakpoints across sessions |
For people using resession.nvim, I wrote this little extension to persist it. You can save it as local M = {}
---Get the saved data for this extension
---@param _opts resession.Extension.OnSaveOpts Information about the session being saved
---@return any
M.on_save = function(_opts)
local breakpoints = {}
for bufnr, buf_breakpoints in pairs(require("dap.breakpoints").get()) do
breakpoints[vim.api.nvim_buf_get_name(bufnr)] = buf_breakpoints
end
return breakpoints
end
---Restore the extension state
---@param breakpoints The value returned from on_save
M.on_post_load = function(breakpoints)
local set = require("dap.breakpoints").set
-- Build a table of <filename, buffer number>
local loaded_buffers = {}
vim.iter(vim.api.nvim_list_bufs()):each(function(bufnr)
if vim.api.nvim_buf_is_loaded(bufnr) then
local fname = vim.api.nvim_buf_get_name(bufnr)
loaded_buffers[fname] = bufnr
end
end)
-- Iterate over the breakpoints and restore them
vim.iter(breakpoints):each(function(fname, buf_breakpoints)
local bufnr = loaded_buffers[fname]
if bufnr ~= nil then
vim.iter(buf_breakpoints):each(
function(bp)
set({
condition = bp.condition,
log_message = bp.logMessage,
hit_condition = bp.hitCondition,
}, tonumber(bufnr), bp.line)
end
)
end
end)
end
return M |
there is an issue with this approach I can't find how to fix. another issue in this approach with modules update. tldr; |
Hi there,
Would be great if I could persist the breakpoints over sessions - I often have to restart nvim (esp. because the dap UI is still a bit brittle over
.stop()
and.start()
rcarriga/nvim-dap-ui#18. Persisting this over sessions would be great! :)thanks a lot this awesome plugin.
The text was updated successfully, but these errors were encountered: