-
-
Notifications
You must be signed in to change notification settings - Fork 217
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in 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; |
@dennypenta I wrote a functionality to persist breakpoints using AutoSession that loads the buffer, if necessary: rmagatti/auto-session#402 So, my solution was:
|
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: