Skip to content

Commit

Permalink
Add on_config hooks to dap.providers
Browse files Browse the repository at this point in the history
Should solve #720
  • Loading branch information
mfussenegger committed May 30, 2024
1 parent fdfb23c commit 11d96b7
Show file tree
Hide file tree
Showing 2 changed files with 75 additions and 32 deletions.
37 changes: 34 additions & 3 deletions doc/dap.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1289,9 +1289,40 @@ An example:
<

To support async operations, the config providers functions are called
within a coroutine and they can also return a `thread` which must be suspended
and which will be resumed at most once and must then yield the configurations
as list.
within a coroutine.

==============================================================================
ON_CONFIG EXTENSIONS API *dap-providers-on_config*

Plugins can pre-process the |dap-configuration| whenever a debug session
starts.

To do so, register a `on_config` hook in the `dap.providers.on_config` table.

The key for the table is a `plugin-id`. Plugins should use their plugin name.
Do _not_ use the `dap.` namespace. It is reserved for nvim-dap itself.

The value for the table is a function that takes a |dap-configuration| as
parameter and must return a |dap-configuration|.

Before making modifications to the config you should copy it, to ensure you
don't make permanent changes to a configuration stored within
`dap.configrations.<filetype>` via mutations.

Example:
>lua
local dap = require("dap")
dap.providers.on_config["dummy-noop"] = function(config)
return vim.deepcopy(config)
end
<
To support async operations, the on_config functions are called within a
coroutine.

This functionality should only be used by plugins that implement generic
functionality applicable for all or most configurations.
For configuration pre-processing that is specific to a individual adapter you
should instead use the `enrich_config` function available in |dap-adapter|.

==============================================================================
UTILS API *dap-utils*
Expand Down
70 changes: 41 additions & 29 deletions lua/dap.lua
Original file line number Diff line number Diff line change
Expand Up @@ -265,20 +265,24 @@ M.adapters = {}
---@type table<string, dap.Configuration[]>
M.configurations = {}

local providers_mt = {
__newindex = function()
error("Cannot add item to dap.providers")
end,
}
M.providers = setmetatable({

local providers = {
---@type table<string, fun(bufnr: integer): thread|dap.Configuration[]>
configs = {
},
}, providers_mt)
configs = {},

---@type table<string, fun(config: dap.Configuration):dap.Configuration>
on_config = {},
}
do
local providers_mt = {
__newindex = function()
error("Cannot add item to dap.providers")
end,
}
M.providers = setmetatable(providers, providers_mt)
end


M.providers.configs["dap.global"] = function(bufnr)
providers.configs["dap.global"] = function(bufnr)
local filetype = vim.bo[bufnr].filetype
local configurations = M.configurations[filetype] or {}
assert(
Expand All @@ -292,8 +296,7 @@ M.providers.configs["dap.global"] = function(bufnr)
return configurations
end


M.providers.configs["dap.launch.json"] = function()
providers.configs["dap.launch.json"] = function()
local ok, configs = pcall(require("dap.ext.vscode").getconfigs)
return ok and configs or {}
end
Expand Down Expand Up @@ -375,6 +378,7 @@ local var_placeholders = {
end,
}


local function expand_config_variables(option)
option = eval_option(option)
if option == M.ABORT then
Expand Down Expand Up @@ -404,6 +408,7 @@ local function expand_config_variables(option)
return ret
end


---@param lsession dap.Session
local function add_reset_session_hook(lsession)
lsession.on_close['dap.session'] = function(s)
Expand Down Expand Up @@ -470,10 +475,10 @@ local function select_config_and_run(opts)
lazy.async.run(function()
local all_configs = {}
local co = coroutine.running()
local providers = vim.tbl_keys(M.providers.configs)
table.sort(providers)
for _, provider in ipairs(providers) do
local config_provider = M.providers.configs[provider]
local provider_keys = vim.tbl_keys(providers.configs)
table.sort(provider_keys)
for _, provider in ipairs(provider_keys) do
local config_provider = providers.configs[provider]
local configs = config_provider(bufnr)
if type(configs) == "thread" then
assert(
Expand Down Expand Up @@ -537,6 +542,23 @@ local function first_stopped_session()
end


---@param config dap.Configuration
---@result dap.Configuration
local function prepare_config(config)
local co, is_main = coroutine.running()
assert(co and not is_main, "prepare_config must be running in coroutine")
local mt = getmetatable(config)
if mt and type(mt.__call) == "function" then
config = config()
assert(config and type(config) == "table", "config metatable __call must return a config table")
end
for _, on_config in pairs(providers.on_config) do
config = on_config(config)
end
return vim.tbl_map(expand_config_variables, config)
end


---@class dap.run.opts
---@field new? boolean force new session
---@field before? fun(config: dap.Configuration): dap.Configuration pre-process config
Expand Down Expand Up @@ -565,12 +587,7 @@ function M.run(config, opts)
config = opts.before(config)
end
local trigger_run = function()
local mt = getmetatable(config)
if mt and type(mt.__call) == "function" then
config = config()
assert(config and type(config) == "table", "config metatable __call must return a config table")
end
config = vim.tbl_map(expand_config_variables, config)
config = prepare_config(config)
for _, val in pairs(config) do
if val == M.ABORT then
notify("Run aborted", vim.log.levels.INFO)
Expand Down Expand Up @@ -832,12 +849,7 @@ function M.restart(config, opts)
config = config or lsession.config
if lsession.capabilities.supportsRestartRequest then
lazy.async.run(function()
local mt = getmetatable(config)
if mt and type(mt.__call) == "function" then
config = config()
assert(config and type(config) == "table", "config metatable __call must return a config table")
end
config = vim.tbl_map(expand_config_variables, config)
config = prepare_config(config)
lsession:request('restart', config, function(err0, _)
if err0 then
notify('Error restarting debug adapter: ' .. lazy.utils.fmt_error(err0), vim.log.levels.ERROR)
Expand Down

0 comments on commit 11d96b7

Please sign in to comment.