Skip to content

Commit 0406598

Browse files
committed
Update threads at most once on stopped events
1 parent 3b4bdea commit 0406598

File tree

3 files changed

+52
-48
lines changed

3 files changed

+52
-48
lines changed

lua/dap/protocol.lua

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,9 @@
4646
---@field stopped nil|boolean not part of the spec; added by nvim-dap
4747

4848

49+
---@class dap.ThreadResponse
50+
---@field threads dap.Thread[]
51+
4952
---@class dap.StackFrame
5053
---@field id number
5154
---@field name string

lua/dap/session.lua

Lines changed: 48 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -618,8 +618,9 @@ function Session:update_threads(cb)
618618
for _, thread in pairs(response.threads) do
619619
threads[thread.id] = thread
620620
local old_thread = self.threads[thread.id]
621-
if old_thread and old_thread.stopped then
622-
thread.stopped = true
621+
if old_thread then
622+
thread.stopped = old_thread.stopped
623+
thread.frames = old_thread.frames
623624
end
624625
end
625626
self.threads = threads
@@ -646,61 +647,61 @@ end
646647

647648
---@param stopped dap.StoppedEvent
648649
function Session:event_stopped(stopped)
649-
if self.dirty.threads or (stopped.threadId and self.threads[stopped.threadId] == nil) then
650-
self:update_threads(function(err)
650+
coroutine.wrap(function()
651+
local co = coroutine.running()
652+
653+
if self.dirty.threads or (stopped.threadId and self.threads[stopped.threadId] == nil) then
654+
self:update_threads(co_resume(co))
655+
local err = coroutine.yield()
651656
if err then
652657
utils.notify('Error retrieving threads: ' .. utils.fmt_error(err), vim.log.levels.ERROR)
653658
return
654659
end
655-
self:event_stopped(stopped)
656-
end)
657-
return
658-
end
660+
end
659661

660-
local should_jump = stopped.reason ~= 'pause' or stopped.allThreadsStopped
661-
662-
-- Some debug adapters allow to continue/step via custom REPL commands (via evaluate)
663-
-- That by-passes `clear_running`, resulting in self.stopped_thread_id still being set
664-
-- Dont auto-continue if`threadId == self.stopped_thread_id`, but stop & jump
665-
if self.stopped_thread_id and self.stopped_thread_id ~= stopped.threadId and should_jump then
666-
if defaults(self).auto_continue_if_many_stopped then
667-
local thread = self.threads[self.stopped_thread_id]
668-
local thread_name = thread and thread.name or self.stopped_thread_id
669-
log.debug(
670-
'Received stopped event, but ' .. thread_name .. ' is already stopped. ' ..
671-
'Resuming newly stopped thread. ' ..
672-
'To disable this set the `auto_continue_if_many_stopped` option to false.')
673-
self:request('continue', { threadId = stopped.threadId })
674-
return
675-
else
676-
-- Allow thread to stop, but don't jump to it because stepping
677-
-- interleaved between threads is confusing
678-
should_jump = false
662+
local should_jump = stopped.reason ~= 'pause' or stopped.allThreadsStopped
663+
664+
-- Some debug adapters allow to continue/step via custom REPL commands (via evaluate)
665+
-- That by-passes `clear_running`, resulting in self.stopped_thread_id still being set
666+
-- Dont auto-continue if`threadId == self.stopped_thread_id`, but stop & jump
667+
if self.stopped_thread_id and self.stopped_thread_id ~= stopped.threadId and should_jump then
668+
if defaults(self).auto_continue_if_many_stopped then
669+
local thread = self.threads[self.stopped_thread_id]
670+
local thread_name = thread and thread.name or self.stopped_thread_id
671+
log.debug(
672+
'Received stopped event, but ' .. thread_name .. ' is already stopped. ' ..
673+
'Resuming newly stopped thread. ' ..
674+
'To disable this set the `auto_continue_if_many_stopped` option to false.')
675+
self:request('continue', { threadId = stopped.threadId }, function() end)
676+
return
677+
else
678+
-- Allow thread to stop, but don't jump to it because stepping
679+
-- interleaved between threads is confusing
680+
should_jump = false
681+
end
682+
end
683+
if should_jump then
684+
self.stopped_thread_id = stopped.threadId
679685
end
680-
end
681-
if should_jump then
682-
self.stopped_thread_id = stopped.threadId
683-
end
684686

685-
if stopped.allThreadsStopped then
686-
progress.report('All threads stopped')
687-
for _, thread in pairs(self.threads) do
688-
thread.stopped = true
687+
if stopped.allThreadsStopped then
688+
progress.report('All threads stopped')
689+
for _, thread in pairs(self.threads) do
690+
thread.stopped = true
691+
end
692+
elseif stopped.threadId then
693+
progress.report('Thread stopped: ' .. stopped.threadId)
694+
self.threads[stopped.threadId].stopped = true
695+
else
696+
utils.notify('Stopped event received, but no threadId or allThreadsStopped', vim.log.levels.WARN)
689697
end
690-
elseif stopped.threadId then
691-
progress.report('Thread stopped: ' .. stopped.threadId)
692-
self.threads[stopped.threadId].stopped = true
693-
else
694-
utils.notify('Stopped event received, but no threadId or allThreadsStopped', vim.log.levels.WARN)
695-
end
696698

697-
if not stopped.threadId then
698-
return
699-
end
700-
local thread = self.threads[stopped.threadId]
701-
assert(thread, 'Thread not found: ' .. stopped.threadId)
699+
if not stopped.threadId then
700+
return
701+
end
702+
local thread = self.threads[stopped.threadId]
703+
assert(thread, 'Thread not found: ' .. stopped.threadId)
702704

703-
coroutine.wrap(function()
704705
local err, response = self:request('stackTrace', { threadId = stopped.threadId; })
705706
if err then
706707
utils.notify('Error retrieving stack traces: ' .. utils.fmt_error(err), vim.log.levels.ERROR)

lua/dap/utils.lua

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ local M = {}
22

33

44
---@param err dap.ErrorResponse
5-
---@return string?
5+
---@return string
66
function M.fmt_error(err)
77
local body = err.body or {}
88
if body.error and body.error.showUser then

0 commit comments

Comments
 (0)