From 537c45fe455de592d9689a51e2b10b860cc703f0 Mon Sep 17 00:00:00 2001 From: Brian Lehrer <661570+blehrer@users.noreply.github.com> Date: Tue, 13 May 2025 14:25:10 -0700 Subject: [PATCH] feat(dap): enhance breakpoint editing The key-mapping `dB` (in `lazyvim.plugins.extras.dap.core`) is now configured to guide users through the process of adding a `condition`, `hitCondition`, and `logMessage` to a breakpoint. This also allows attributes that have already been set to be edited, instead of having to start from scratch each time you want to update one of these fields. These breakpoints will persist for the duration of the session. Tested with Neovim v0.11.1, and LazyVim/starter (803bc18) --- lua/lazyvim/plugins/extras/dap/core.lua | 104 +++++++++++++++++++----- 1 file changed, 84 insertions(+), 20 deletions(-) diff --git a/lua/lazyvim/plugins/extras/dap/core.lua b/lua/lazyvim/plugins/extras/dap/core.lua index d84b71bf..982f10b9 100644 --- a/lua/lazyvim/plugins/extras/dap/core.lua +++ b/lua/lazyvim/plugins/extras/dap/core.lua @@ -31,26 +31,90 @@ return { }, }, - -- stylua: ignore - keys = { - { "dB", function() require("dap").set_breakpoint(vim.fn.input('Breakpoint condition: ')) end, desc = "Breakpoint Condition" }, - { "db", function() require("dap").toggle_breakpoint() end, desc = "Toggle Breakpoint" }, - { "dc", function() require("dap").continue() end, desc = "Run/Continue" }, - { "da", function() require("dap").continue({ before = get_args }) end, desc = "Run with Args" }, - { "dC", function() require("dap").run_to_cursor() end, desc = "Run to Cursor" }, - { "dg", function() require("dap").goto_() end, desc = "Go to Line (No Execute)" }, - { "di", function() require("dap").step_into() end, desc = "Step Into" }, - { "dj", function() require("dap").down() end, desc = "Down" }, - { "dk", function() require("dap").up() end, desc = "Up" }, - { "dl", function() require("dap").run_last() end, desc = "Run Last" }, - { "do", function() require("dap").step_out() end, desc = "Step Out" }, - { "dO", function() require("dap").step_over() end, desc = "Step Over" }, - { "dP", function() require("dap").pause() end, desc = "Pause" }, - { "dr", function() require("dap").repl.toggle() end, desc = "Toggle REPL" }, - { "ds", function() require("dap").session() end, desc = "Session" }, - { "dt", function() require("dap").terminate() end, desc = "Terminate" }, - { "dw", function() require("dap.ui.widgets").hover() end, desc = "Widgets" }, - }, + keys = function(_, keys) + local dap = require("dap") + + local function edit_breakpoint() + -- Search for an existing breakpoint on this line in this buffer + ---@return dap.SourceBreakpoint bp that was either found, or an empty placeholder + local function find_bp() + local buf_bps = require("dap.breakpoints").get(vim.fn.bufnr())[vim.fn.bufnr()] + ---@type dap.SourceBreakpoint + local bp = { condition = "", logMessage = "", hitCondition = "", line = vim.fn.line(".") } + for _, candidate in ipairs(buf_bps) do + if candidate.line and candidate.line == vim.fn.line(".") then + bp = candidate + break + end + end + return bp + end + + -- Elicit customization via a UI prompt + ---@param bp dap.SourceBreakpoint a breakpoint + local function customize_bp(bp) + local props = { + ["Condition"] = { + value = bp.condition, + setter = function(v) + bp.condition = v + end, + }, + ["Hit Condition"] = { + value = bp.hitCondition, + setter = function(v) + bp.hitCondition = v + end, + }, + ["Log Message"] = { + value = bp.logMessage, + setter = function(v) + bp.logMessage = v + end, + }, + } + local menu_options = {} + for k, v in pairs(props) do + table.insert(menu_options, ("%s: %s"):format(k, v.value)) + end + vim.ui.select(menu_options, { + prompt = "Edit Breakpoint", + }, function(choice) + local prompt = (tostring(choice)):gsub(":.*", "") + props[prompt].setter(vim.fn.input({ + prompt = prompt, + default = props[prompt].value, + })) + + -- Set breakpoint for current line, with customizations (see h:dap.set_breakpoint()) + dap.set_breakpoint(bp.condition, bp.hitCondition, bp.logMessage) + end) + end + + customize_bp(find_bp()) + end + -- stylua: ignore + local default_keys = { + { "dB", edit_breakpoint, desc = "Breakpoint Condition" }, + { "db", function() dap.toggle_breakpoint() end, desc = "Toggle Breakpoint" }, + { "dc", function() dap.continue() end, desc = "Run/Continue" }, + { "da", function() dap.continue({ before = get_args }) end, desc = "Run with Args" }, + { "dC", function() dap.run_to_cursor() end, desc = "Run to Cursor" }, + { "dg", function() dap.goto_() end, desc = "Go to Line (No Execute)" }, + { "di", function() dap.step_into() end, desc = "Step Into" }, + { "dj", function() dap.down() end, desc = "Down" }, + { "dk", function() dap.up() end, desc = "Up" }, + { "dl", function() dap.run_last() end, desc = "Run Last" }, + { "do", function() dap.step_out() end, desc = "Step Out" }, + { "dO", function() dap.step_over() end, desc = "Step Over" }, + { "dP", function() dap.pause() end, desc = "Pause" }, + { "dr", function() dap.repl.toggle() end, desc = "Toggle REPL" }, + { "ds", function() dap.session() end, desc = "Session" }, + { "dt", function() dap.terminate() end, desc = "Terminate" }, + { "dw", function() require("dap.ui.widgets").hover() end, desc = "Widgets" }, + } + return vim.tbl_deep_extend("force", default_keys, keys) + end, config = function() -- load mason-nvim-dap here, after all adapters have been setup