Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 9 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ The plugin provides 6 "views" that share the same window (so there's clutter)
- Shows a list of user defined expressions, that are evaluated by the debug adapter
- Add, edit and delete expressions from the watch list
- Add variable under the cursor using a command
- Expand and collapse expressions and variables
- Set the value of an expression or variable (if supported by debug adapter)
- Copy the value of an expression or variable

Expand Down Expand Up @@ -208,14 +209,13 @@ Start a regular debugging session. When desired, you can use `:DapViewOpen` to
start the plugin. You can switch to a view (section) using the letter outlined
in the `'winbar'` (e.g., `B` for the breakpoints view).

The breakpoints view, the exceptions view and the scopes view only have 1
mapping: `<CR>`. It jumps to a breakpoint, toggles an exception filter, and
expands a variable, respectively. The watches view comes with 5 mappings:
The breakpoints view and the exceptions view only have 1 mapping: `<CR>`. It jumps to a breakpoint and toggles an exception filter, respectively. The watches view comes with 6 mappings:

- `<CR>` to expand or collapse a variable
- `i` to insert a new expression
- `e` to edit an expression
- `c` to copy an expression or variable
- `s` to change the value of an expression or variable
- `s` to set (change) the value of an expression or variable
- `d` to delete an expression

Though, the preferred way of adding a new expression is using the
Expand All @@ -225,6 +225,11 @@ to the watch list. The threads view has 2 mappings:
- `<CR>` jumps to a location in the call stack
- `t` toggles subtle frames

Similarly, the scopes view comes with 2 mappings:

- `<CR>` to expand or collapse a variable
- `o` to open a menu with further actions

When you finish your session, you can use `:DapViewClose` to close the
`nvim-dap-view` window.

Expand Down
15 changes: 5 additions & 10 deletions lua/dap-view/events.lua
Original file line number Diff line number Diff line change
Expand Up @@ -53,17 +53,16 @@ dap.listeners.after.setBreakpoints[SUBSCRIPTION_ID] = function()
end
end

dap.listeners.after.evaluate[SUBSCRIPTION_ID] = function()
if state.current_section == "watches" then
watches.show()
end
end

dap.listeners.after.scopes[SUBSCRIPTION_ID] = function()
-- nvim-dap needs a buffer to operate
if state.current_section == "scopes" and state.bufnr then
scopes.refresh()
end

-- Avoid race conditions by not using `event_stopped`
for expr, _ in pairs(state.watched_expressions) do
eval.eval_expr(expr)
end
end

dap.listeners.after.variables[SUBSCRIPTION_ID] = function()
Expand All @@ -81,10 +80,6 @@ end
dap.listeners.after.event_stopped[SUBSCRIPTION_ID] = function()
require("dap-view.threads").get_threads()

for expr, _ in pairs(state.watched_expressions) do
eval.eval_expr(expr)
end

winbar.redraw_controls()
end

Expand Down
25 changes: 20 additions & 5 deletions lua/dap-view/state.lua
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,23 @@
---@class ThreadWithErr: dap.Thread
---@field err? string

---@class ExpressionPack
---@field response? dap.EvaluateResponse | string
---@field children? VariablePack[] | string
---@field expanded boolean
---@field updated boolean

---@class VariablePack
---@field variable dap.Variable
---@field updated boolean
---@field reference number
---@field expanded boolean
---@field children string|VariablePack[]

-- Necessary for some type assertions
---@class VariablePackNested : VariablePack
---@field children VariablePack[]

---@class State
---@field bufnr? integer
---@field winnr? integer
Expand All @@ -16,17 +33,15 @@
---@field exceptions_options ExceptionsOption[]
---@field threads ThreadWithErr[]
---@field threads_err? string
---@field frames_by_line {[number]: dap.StackFrame[]}
---@field expressions_by_line {[integer]: {name: string, response: dap.EvaluateResponse | string}}
---@field variables_by_reference table<integer, {variable: dap.Variable, updated: boolean}[] | string>
---@field frames_by_line table<integer, dap.StackFrame[]>
---@field expressions_by_line table<integer, {name: string, expression: ExpressionPack}>
---@field variables_by_line table<integer, {response: dap.Variable, reference: number}>
---@field watched_expressions table<string,{response?: dap.EvaluateResponse | string, updated?: boolean}>
---@field watched_expressions table<string, ExpressionPack>
local M = {
exceptions_options = {},
threads = {},
frames_by_line = {},
expressions_by_line = {},
variables_by_reference = {},
variables_by_line = {},
subtle_frames = false,
watched_expressions = {},
Expand Down
37 changes: 37 additions & 0 deletions lua/dap-view/tree/traversal.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
local state = require("dap-view.state")

local M = {}

---@param children VariablePack[]
---@param reference number
---@return VariablePack?
local function dfs(children, reference)
for _, v in pairs(children) do
if v.variable.variablesReference == reference then
return v
end
if v.children and type(v.children) ~= "string" then
---@cast v VariablePackNested
local ref = dfs(v.children, reference)
if ref then
return ref
end
end
end
end

---@param reference number
---@return VariablePack?
M.find_node = function(reference)
for _, v in pairs(state.watched_expressions) do
local children = v.children
if children and type(children) ~= "string" then
local ref = dfs(children, reference)
if ref then
return ref
end
end
end
end

return M
7 changes: 5 additions & 2 deletions lua/dap-view/views/keymaps.lua
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ M.set_keymaps = function()
require("dap-view.exceptions.actions").toggle_exception_filter()
elseif state.current_section == "scopes" then
require("dap.ui").trigger_actions({ mode = "first" })
elseif state.current_section == "watches" then
local cursor_line = vim.api.nvim_win_get_cursor(state.winnr)[1]
watches_actions.expand_or_collapse(cursor_line)
end
end, { buffer = state.bufnr })

Expand Down Expand Up @@ -73,8 +76,8 @@ M.set_keymaps = function()

local get_default = function()
local expr = state.expressions_by_line[cursor_line]
if expr and type(expr.response) ~= "string" then
return expr.response.result
if expr and expr.expression and type(expr.expression.response) ~= "string" then
return expr.expression.response.result
end

local var = state.variables_by_line[cursor_line]
Expand Down
2 changes: 1 addition & 1 deletion lua/dap-view/views/options.lua
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ local M = {}

M.set_options = function()
local win = vim.wo[state.winnr][0]
win.scrolloff = 0
win.scrolloff = 99
win.wrap = false
win.number = false
win.relativenumber = false
Expand Down
59 changes: 46 additions & 13 deletions lua/dap-view/watches/actions.lua
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ local state = require("dap-view.state")
local guard = require("dap-view.guard")
local eval = require("dap-view.watches.eval")
local set = require("dap-view.watches.set")
local traversal = require("dap-view.tree.traversal")
local watches_view = require("dap-view.watches.view")

local M = {}

Expand All @@ -12,7 +14,9 @@ M.add_watch_expr = function(expr)
return false
end

eval.eval_expr(expr)
eval.eval_expr(expr, function()
watches_view.show()
end)

return true
end
Expand All @@ -21,18 +25,7 @@ end
M.remove_watch_expr = function(line)
local expr = state.expressions_by_line[line]
if expr then
local eval_result = state.watched_expressions[expr.name].response

state.watched_expressions[expr.name] = nil
state.expressions_by_line[line] = nil

-- If the result is a string, it's the error
if type(eval_result) ~= "string" then
local ref = eval_result and eval_result.variablesReference
if ref then
state.variables_by_reference[ref] = nil
end
end
else
vim.notify("No expression under the under cursor")
end
Expand Down Expand Up @@ -116,7 +109,47 @@ M.edit_watch_expr = function(expr, line)
-- The easiest way to edit is to delete and insert again
M.remove_watch_expr(line)

eval.eval_expr(expr)
eval.eval_expr(expr, function()
watches_view.show()
end)
end

---@param line number
M.expand_or_collapse = function(line)
if not guard.expect_session() then
return
end

local var = state.variables_by_line[line]

local expr = state.expressions_by_line[line]
if expr then
local e = state.watched_expressions[expr.name]
if e then
e.expanded = not e.expanded

eval.eval_expr(expr.name, function()
watches_view.show()
end)
end
else
if var then
local reference = var.response.variablesReference
if reference > 0 then
local v = traversal.find_node(reference)
if v then
v.expanded = not v.expanded
eval.expand_var(reference, v.children, function(result)
v.children = result
end)
end
else
vim.notify("Nothing to expand")
end
else
vim.notify("No expression or variable under the under cursor")
end
end
end

return M
Loading