Skip to content

Commit ecdfbac

Browse files
committed
fix: use listener hooks for nvim-dap instead of monkey patching
1 parent 31f3096 commit ecdfbac

File tree

3 files changed

+106
-114
lines changed

3 files changed

+106
-114
lines changed

doc/third_party.md

Lines changed: 32 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -30,22 +30,24 @@ Or with options:
3030
```lua
3131
require("lualine").setup({
3232
sections = {
33-
lualine_x = { {
34-
"overseer",
35-
label = '', -- Prefix for task counts
36-
colored = true, -- Color the task icons and counts
37-
symbols = {
38-
[overseer.STATUS.FAILURE] = "F:",
39-
[overseer.STATUS.CANCELED] = "C:",
40-
[overseer.STATUS.SUCCESS] = "S:",
41-
[overseer.STATUS.RUNNING] = "R:",
33+
lualine_x = {
34+
{
35+
"overseer",
36+
label = "", -- Prefix for task counts
37+
colored = true, -- Color the task icons and counts
38+
symbols = {
39+
[overseer.STATUS.FAILURE] = "F:",
40+
[overseer.STATUS.CANCELED] = "C:",
41+
[overseer.STATUS.SUCCESS] = "S:",
42+
[overseer.STATUS.RUNNING] = "R:",
43+
},
44+
unique = false, -- Unique-ify non-running task count by name
45+
name = nil, -- List of task names to search for
46+
name_not = false, -- When true, invert the name search
47+
status = nil, -- List of task statuses to display
48+
status_not = false, -- When true, invert the status search
4249
},
43-
unique = false, -- Unique-ify non-running task count by name
44-
name = nil, -- List of task names to search for
45-
name_not = false, -- When true, invert the name search
46-
status = nil, -- List of task statuses to display
47-
status_not = false, -- When true, invert the status search
48-
} },
50+
},
4951
},
5052
})
5153
```
@@ -109,7 +111,7 @@ local Overseer = {
109111
To run all neotest processes using overseer, add it as a custom consumer:
110112

111113
```lua
112-
require('neotest').setup({
114+
require("neotest").setup({
113115
consumers = {
114116
overseer = require("neotest.consumers.overseer"),
115117
},
@@ -119,7 +121,7 @@ require('neotest').setup({
119121
This will automatically hook `neotest.run` and force it to use overseer to run tests wherever possible. If you would instead like to only use the overseer consumer explicitly, you can disable the monkey patching:
120122

121123
```lua
122-
require('neotest').setup({
124+
require("neotest").setup({
123125
consumers = {
124126
overseer = require("neotest.consumers.overseer"),
125127
},
@@ -137,15 +139,15 @@ neotest.overseer.run({})
137139
You can customize the default components of neotest tasks by setting the `default_neotest` component alias (when unset it maps to `default`).
138140

139141
```lua
140-
require('overseer').setup({
142+
require("overseer").setup({
141143
component_aliases = {
142144
default_neotest = {
143145
"on_output_summarize",
144146
"on_exit_set_status",
145147
"on_complete_notify",
146148
"on_complete_dispose",
147149
},
148-
}
150+
},
149151
})
150152
```
151153

@@ -170,43 +172,36 @@ require("neotest").setup({
170172

171173
## DAP
172174

173-
If you have both overseer and [nvim-dap](https://github.com/mfussenegger/nvim-dap) installed, overseer will automatically run the `preLaunchTask` and `postDebugTask` when present in a debug configuration.
174-
175-
I also recommend that you configure nvim-dap to use overseer's json decoder, since it supports JSON5 (comments and trailing commas)
176-
177-
```lua
178-
require("dap.ext.vscode").json_decode = require("overseer.json").decode
179-
```
175+
If you have both overseer and [nvim-dap](https://github.com/mfussenegger/nvim-dap) installed, overseer will automatically run the `preLaunchTask` and `postDebugTask` when present in a debug configuration. No special configuration or action is needed.
180176

181-
A note about lazy loading: make sure you load nvim-dap before overseer because overseer will attempt
182-
to patch nvim-dap inside `overseer.setup()`. Alternatively, you can disable the automatic support
177+
For lazy-loading, you may wish to avoid loading `nvim-dap` when overseer is loaded. If so, you can disable DAP support initially:
183178

184179
```lua
185180
require("overseer").setup({
186181
dap = false,
187182
})
188183
```
189184

190-
And enable the integration manually later, such as when nvim-dap is loaded
185+
And enable the integration manually later, such as when `nvim-dap` is loaded:
191186

192187
```lua
193-
require("overseer").patch_dap(true)
188+
require("overseer").enable_dap()
194189
```
195190

196191
## ToggleTerm
197192

198193
If you use [toggleterm](https://github.com/akinsho/toggleterm.nvim), you can use the built-in "toggleterm" strategy to allow your tasks to be in a terminal buffer owned by toggleterm. You can use your existing toggleterm keybinds to pull up long-running tasks started with overseer. You can set it up with defaults using:
199194

200195
```lua
201-
require('overseer').setup({
196+
require("overseer").setup({
202197
strategy = "toggleterm",
203198
})
204199
```
205200

206201
You can also configure the behavior a bit more:
207202

208203
```lua
209-
require('overseer').setup({
204+
require("overseer").setup({
210205
strategy = {
211206
"toggleterm",
212207
-- load your default shell before starting the task
@@ -233,7 +228,7 @@ require('overseer').setup({
233228
-- command to run when the terminal is created. Combine with `use_shell`
234229
-- to run a terminal command before starting the task
235230
on_create = nil,
236-
}
231+
},
237232
})
238233
```
239234

@@ -246,12 +241,12 @@ More documentation on this strategy can be found [here](strategies.md#toggleterm
246241
Overseer has built-in support for [resession.nvim](https://github.com/stevearc/resession.nvim).
247242

248243
```lua
249-
require('resession').setup({
244+
require("resession").setup({
250245
extensions = {
251246
overseer = {
252247
-- customize here
253-
}
254-
}
248+
},
249+
},
255250
})
256251
```
257252

@@ -288,7 +283,7 @@ require("auto-session").setup({
288283
for _, task in ipairs(overseer.list_tasks({})) do
289284
task:dispose(true)
290285
end
291-
end
286+
end,
292287
},
293288
post_restore_cmds = {
294289
function()

lua/overseer/dap.lua

Lines changed: 52 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -20,74 +20,68 @@ local function get_task(name, config, cb)
2020
require("overseer").run_template(args, cb)
2121
end
2222

23-
M.wrap_run = function(daprun)
24-
return function(config, opts)
25-
dap.listeners.after.event_terminated["overseer"] = function()
26-
if config.postDebugTask then
27-
log:trace("Running DAP postDebugTask %s", config.postDebugTask)
28-
get_task(config.postDebugTask, config, function(task, err)
29-
if err then
30-
log:error("Could not run postDebugTask %s", config.postDebugTask)
31-
elseif task then
32-
task:start()
33-
end
34-
end)
35-
end
36-
end
23+
M.listener = function(config)
24+
dap.listeners.after.event_terminated.overseer = nil
25+
if not config.preLaunchTask and not config.postDebugTask then
26+
return config
27+
end
3728

38-
if config.preLaunchTask then
39-
log:trace("Running DAP preLaunchTask %s", config.preLaunchTask)
40-
get_task(config.preLaunchTask, config, function(task, err)
41-
if not task then
42-
log:error("Could not run preLaunchTask %s: %s", config.preLaunchTask, err)
43-
return
29+
if config.postDebugTask then
30+
dap.listeners.after.event_terminated.overseer = function()
31+
log:debug("Running DAP postDebugTask %s", config.postDebugTask)
32+
get_task(config.postDebugTask, config, function(task, err)
33+
if err then
34+
log:error("Could not run postDebugTask %s", config.postDebugTask)
35+
elseif task then
36+
task:start()
4437
end
38+
end)
39+
end
40+
end
4541

46-
-- Non-background task with problemMatcher will trigger both on_result and on_complete so use the first one
47-
local done = false
48-
local cleanup
42+
if config.preLaunchTask then
43+
log:debug("Running DAP preLaunchTask %s", config.preLaunchTask)
44+
local co = coroutine.running()
45+
get_task(config.preLaunchTask, config, function(task, err)
46+
if not task then
47+
log:error("Could not run preLaunchTask %s: %s", config.preLaunchTask, err)
48+
return
49+
end
4950

50-
local function on_done(ok)
51-
if done then
52-
return
53-
end
54-
done = true
51+
-- Non-background task with problemMatcher will trigger both on_result and on_complete so use the first one
52+
local on_done
53+
on_done = function(ok)
54+
on_done = function() end
5555

56-
if ok then
57-
daprun(config, opts)
58-
else
59-
vim.notify(
60-
string.format(
61-
"Failed to launch debugger; preLaunchTask '%s' failed",
62-
config.preLaunchTask
63-
),
64-
vim.log.levels.ERROR
65-
)
66-
end
67-
vim.schedule(cleanup)
56+
if not ok then
57+
vim.notify(
58+
string.format("DAP preLaunchTask '%s' failed", config.preLaunchTask),
59+
vim.log.levels.ERROR
60+
)
6861
end
62+
coroutine.resume(co)
63+
end
6964

70-
local function on_complete(_, status)
71-
on_done(status == STATUS.SUCCESS)
72-
end
65+
local function on_complete(_, status)
66+
on_done(status == STATUS.SUCCESS)
67+
return false
68+
end
7369

74-
local function on_result()
75-
-- We get the on_result callback from background tasks once they hit their end pattern
76-
on_done(task.status ~= STATUS.FAILURE)
77-
end
70+
local function on_result()
71+
-- We get the on_result callback from background tasks once they hit their end pattern
72+
on_done(task.status ~= STATUS.FAILURE)
73+
return false
74+
end
7875

79-
task:subscribe("on_complete", on_complete)
80-
task:subscribe("on_result", on_result)
81-
cleanup = function()
82-
task:unsubscribe("on_complete", on_complete)
83-
task:unsubscribe("on_result", on_result)
84-
end
85-
task:start()
86-
end)
87-
else
88-
daprun(config, opts)
89-
end
76+
task:subscribe("on_complete", on_complete)
77+
task:subscribe("on_result", on_result)
78+
task:start()
79+
end)
80+
81+
coroutine.yield()
9082
end
83+
84+
return config
9185
end
9286

9387
return M

lua/overseer/init.lua

Lines changed: 22 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -254,35 +254,38 @@ end
254254

255255
---Add support for preLaunchTask/postDebugTask to nvim-dap
256256
---@private
257+
---@deprecated
257258
---@param enabled boolean
258259
M.patch_dap = function(enabled)
260+
M.enable_dap(enabled)
261+
end
262+
263+
---Add support for preLaunchTask/postDebugTask to nvim-dap
264+
---This is enabled by default when you call overseer.setup() unless you set `dap = false`
265+
---@param enabled boolean
266+
M.enable_dap = function(enabled)
267+
if enabled == nil then
268+
enabled = true
269+
end
259270
if not enabled and not package.loaded.dap then
260271
return
261272
end
262273
local ok, dap = pcall(require, "dap")
263274
if not ok then
264275
return
265276
end
266-
if type(dap.run) == "table" then
267-
if not enabled then
268-
dap.run = dap.run.original
277+
if enabled then
278+
dap.listeners.on_config.overseer = require("overseer.dap").listener
279+
280+
-- If the user has not overridden the DAP json decoder, use ours since it supports JSON5
281+
local vscode = require("dap.ext.vscode")
282+
if vscode.json_decode == vim.json.decode then
283+
vscode.json_decode = require("overseer.json").decode
269284
end
270-
return
271-
elseif not enabled then
272-
return
285+
else
286+
dap.listeners.on_config.overseer = nil
287+
dap.listeners.after.event_terminated.overseer = nil
273288
end
274-
local daprun = dap.run
275-
dap.run = setmetatable({
276-
wrapper = nil,
277-
original = daprun,
278-
}, {
279-
__call = function(self, config, opts)
280-
if not self.wrapper then
281-
self.wrapper = require("overseer.dap").wrap_run(daprun)
282-
end
283-
self.wrapper(config, opts)
284-
end,
285-
})
286289
end
287290

288291
---Initialize overseer
@@ -297,7 +300,7 @@ M.setup = function(opts)
297300
end
298301
opts = opts or {}
299302
create_commands()
300-
M.patch_dap(opts.dap ~= false)
303+
M.enable_dap(opts.dap)
301304
pending_opts = opts
302305
if initialized then
303306
do_setup()

0 commit comments

Comments
 (0)