Skip to content

Commit

Permalink
Add support for data breakpoints
Browse files Browse the repository at this point in the history
  • Loading branch information
theHamsta committed Mar 31, 2021
1 parent 492849b commit 4b42ba5
Show file tree
Hide file tree
Showing 3 changed files with 181 additions and 21 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ that's not listed.
- [x] breakpoints with conditions
- [x] logpoints
- [x] set exception breakpoints
- [x] set data breakpoints
- [x] step over, step into, step out
- [x] step back, reverse continue
- [x] Goto
Expand Down
131 changes: 131 additions & 0 deletions lua/dap.lua
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ local ns_pos = 'dap_pos'
local Session = {}
local session = nil
local bp_info = {}
local data_bp_info = {}
local last_run = nil
local terminal_buf
local deprecation_warning = {}
Expand Down Expand Up @@ -50,6 +51,22 @@ M.listeners = {
}


function M.listeners.after.event_initialized.databreakpoints()
if session and session.capabilities and session.capabilities.supportsDataBreakpoints then
session:_set_data_breakpoints()
end
end


function M.listeners.after.event_terminated.databreakpoints()
for key, bp in pairs(data_bp_info) do
if not bp.canPersist then
data_bp_info[key] = nil
end
end
end


local function from_fallback(_, key)
return M.defaults.fallback[key]
end
Expand Down Expand Up @@ -560,6 +577,11 @@ function Session:event_stopped(stopped)
self:_show_exception_info()
end

if stopped.reason == 'data breakpoint' then
require'dap.repl'.append("Stopped due to data breakpoint"
..(stopped.description and (': '..stopped.description) or '.'))
end

self:request('stackTrace', { threadId = stopped.threadId; }, function(err1, frames_resp)
if err1 then
print('Error retrieving stack traces: ' .. err1.message)
Expand Down Expand Up @@ -790,6 +812,85 @@ function Session:set_breakpoints(bufexpr, on_done)
end
end


function Session:_set_data_breakpoint(expression, condition, hit_condition, variables_reference, toggle)
if not session.capabilities.supportsDataBreakpoints then
vim.notify("Debug adapter does not support data breakpoints", vim.log.levels.ERROR, {})
return
end

session:request('dataBreakpointInfo', { name = expression, variablesReference = variables_reference },
function(err, response)
if err then
vim.notify(err.message, vim.log.levels.ERROR, {})
else
if not response or not response.dataId then
vim.notify('Cannot set data breakpoint for "'..expression..'": '
..((response and response.description) or 'reason unknown'), vim.log.levels.ERROR, {})
else

if toggle and data_bp_info[response.dataId] then
data_bp_info[response.dataId] = nil
vim.notify('Deleting data breakpoint "'..expression..'" ('..response.dataId..')', vim.log.levels.INFO, {})
session:_set_data_breakpoints()
else
local access_type
if response.accessTypes then
ui.pick_one(
response.accessTypes,
'Which access type for "'..expression..'"?: ',
function(t) return t end,
function(t)
if not t then
access_type = 'abort'
else
access_type = t
end
end
)
end
if access_type ~= 'abort' then
data_bp_info[response.dataId] = {
dataId = response.dataId,
accessType = access_type,
condition = condition,
hitCondition = hit_condition,
canPersist = response.canPersist,
}
vim.notify('Setting data breakpoint for "'..expression..'" ('..response.dataId..')',
vim.log.levels.INFO,
{})
end
session:_set_data_breakpoints()
end
end
end
end)
end


function Session:_set_data_breakpoints(on_done)
if not session.capabilities.supportsDataBreakpoints then
vim.notify("Debug adapter does not support data breakpoints", vim.log.levels.ERROR, {})
return
end
local breakpoints = {}
for _, bp in pairs(data_bp_info) do
table.insert(breakpoints, bp)
end

if #breakpoints > 0 then
session:request('setDataBreakpoints', { breakpoints = breakpoints },
function(err, _)
if err then
vim.notify("Failed to set data breakpoints: "..err.message, vim.log.levels.ERROR, {})
end
if on_done then on_done() end
end)
end
end


function Session:set_exception_breakpoints(filters, exceptionOptions, on_done)
if not self.capabilities.exceptionBreakpointFilters then
print("Debug adapter doesn't support exception breakpoints")
Expand Down Expand Up @@ -974,6 +1075,12 @@ function Session:connect(host, port, opts)
setmetatable(o, self)
self.__index = self

for expression, bp in pairs(data_bp_info) do
if not bp.canPersist then
data_bp_info[expression] = nil
end
end

local client = uv.new_tcp()
o.client = {
write = function(line) client:write(line) end;
Expand Down Expand Up @@ -1357,6 +1464,30 @@ function M.set_exception_breakpoints(filters, exceptionOptions)
end


function M.clear_data_breakpoints()
data_bp_info = {}
if not session then return end
session:_set_data_breakpoints()
end


function M.toggle_data_breakpoint(resolve_expression_fn, condition, hit_condition)
if not session then return end

if 'function' == type(resolve_expression_fn) then
resolve_expression_fn = resolve_expression_fn()
end

local expression = resolve_expression_fn or vim.fn.expand("<cexpr>")
session:_set_data_breakpoint(expression, condition, hit_condition, nil, true)
end


function M.toggle_data_breakpoint_visual_selection(condition, hit_condition)
M.set_data_breakpoint(utils.get_visual_selection_text, condition, hit_condition)
end


function M.continue()
if not session then
select_config_and_run()
Expand Down
70 changes: 49 additions & 21 deletions lua/dap/ui/variables.lua
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
local api = vim.api
local dap = require'dap'
local utils = require("dap.utils")
local non_empty = utils.non_empty

Expand All @@ -8,6 +9,13 @@ M.multiline_variable_display = false
M.max_win_width = 100
M.variable_value_separator = " = "
M.show_types = true
M.keymaps = {
['<CR>'] = 'toggle_variable_expanded()',
['<2-LeftMouse>'] = 'toggle_variable_expanded()',
['g?'] = 'toggle_multiline_display()',
['b'] = 'toggle_data_breakpoint()',
['<f1>'] = 'show_help()',
}

local floating_buf = nil
local floating_win = nil
Expand Down Expand Up @@ -99,6 +107,34 @@ local function update_variable_buffer(buf, win)
end


function M.toggle_data_breakpoint(condition, hit_condition)
local buf = api.nvim_get_current_buf()
local state = variable_buffers[buf]
local pos = api.nvim_win_get_cursor(0)
if not state then return end

local variable = state.line_to_variable[pos[1] - 1]

if variable then
local parent
for _, p in pairs(state.line_to_variable) do
for _, v in pairs(p.variables or {}) do
if v == variable then
parent = p
end
end
end
state.session:_set_data_breakpoint(
variable.name,
condition,
hit_condition,
parent and parent.variablesReference,
true
)
end
end


function M.toggle_variable_expanded()
local buf = api.nvim_get_current_buf()
local state = variable_buffers[buf]
Expand Down Expand Up @@ -184,27 +220,11 @@ local function popup()
api.nvim_buf_set_option(buf, 'buftype', 'nofile')
api.nvim_buf_set_option(buf, 'filetype', 'dap-variables')
api.nvim_buf_set_option(buf, 'syntax', 'dap-variables')
api.nvim_buf_set_keymap(
buf,
"n",
"<CR>",
"<Cmd>lua require('dap.ui.variables').toggle_variable_expanded()<CR>",
{}
)
api.nvim_buf_set_keymap(
buf,
"n",
"<2-LeftMouse>",
"<Cmd>lua require('dap.ui.variables').toggle_variable_expanded()<CR>",
{}
)
api.nvim_buf_set_keymap(
buf,
"n",
"g?",
"<Cmd>lua require('dap.ui.variables').toggle_multiline_display()<CR>",
{}
)

for key, mapping in pairs(M.keymaps) do
api.nvim_buf_set_keymap(buf, "n", key, "<Cmd>lua require('dap.ui.variables')."..mapping.."<CR>", {})
end

-- width and height are increased later once variables are written to the buffer
local opts = vim.lsp.util.make_floating_popup_options(1, 1, {})
local win = api.nvim_open_win(buf, true, opts)
Expand All @@ -216,6 +236,14 @@ function M.resolve_expression()
return vim.fn.expand("<cexpr>")
end

function M.show_help()
local function filter(item, path)
if path[#path] == vim.inspect.METATABLE then return end
return item
end
print("Current keybindings:")
print(vim.inspect(M.keymaps, {process=filter}))
end

local function is_stopped_at_frame()
local session = require('dap').session()
Expand Down

0 comments on commit 4b42ba5

Please sign in to comment.