mirror of
https://github.com/folke/snacks.nvim
synced 2025-12-23 08:47:57 +00:00
fix(picker): fix race condition causing "Finder yielded after done" error. Closes #2327
The old code had a race condition where: 1. R:request() scheduled LSP request setup but immediately suspended 2. R:wait() checked #self.requests (still 0) and returned immediately 3. Finder completed and set running = false 4. Then scheduled function ran and LSP responses came back 5. Callbacks tried to yield items but finder was already done → error The fix uses a pending counter to track when the scheduled setup function is running, ensuring we wait for both the setup to complete AND all LSP responses before the finder completes. Also improved error handling by checking the err parameter in callbacks. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
142c620703
commit
c9ccbe5617
1 changed files with 8 additions and 7 deletions
|
|
@ -6,6 +6,7 @@ local Async = require("snacks.picker.util.async")
|
|||
local M = {}
|
||||
|
||||
---@alias lsp.Symbol lsp.SymbolInformation|lsp.DocumentSymbol
|
||||
---@alias lsp.Loc lsp.LocationLink|lsp.Location
|
||||
|
||||
---@class snacks.picker.lsp.Loc: lsp.Location
|
||||
---@field encoding string
|
||||
|
|
@ -99,6 +100,7 @@ end
|
|||
---@field async snacks.picker.Async
|
||||
---@field requests {client_id:number, request_id:number}[]
|
||||
---@field completed number
|
||||
---@field pending integer
|
||||
local R = {}
|
||||
R.__index = R
|
||||
|
||||
|
|
@ -106,6 +108,7 @@ function R.new()
|
|||
local self = setmetatable({}, R)
|
||||
self.async = Async.running()
|
||||
self.requests = {}
|
||||
self.pending = 0
|
||||
self.completed = 0
|
||||
self.async:on(
|
||||
"abort",
|
||||
|
|
@ -132,6 +135,7 @@ end
|
|||
---@param cb fun(client:vim.lsp.Client, result:table, params:table)
|
||||
---@async
|
||||
function R:request(buf, method, params, cb)
|
||||
self.pending = self.pending + 1
|
||||
vim.schedule(function()
|
||||
local clients = type(buf) == "number" and M.get_clients(buf, method)
|
||||
or {
|
||||
|
|
@ -139,11 +143,8 @@ function R:request(buf, method, params, cb)
|
|||
}
|
||||
for _, client in ipairs(clients) do
|
||||
local p = params(client)
|
||||
local status, request_id = client:request(method, p, function(_, result)
|
||||
if self.async._aborted then
|
||||
return
|
||||
end
|
||||
if result then
|
||||
local status, request_id = client:request(method, p, function(err, result)
|
||||
if not err and result and not self.async._aborted then
|
||||
cb(client, result, p)
|
||||
end
|
||||
self.completed = self.completed + 1
|
||||
|
|
@ -153,14 +154,14 @@ function R:request(buf, method, params, cb)
|
|||
table.insert(self.requests, { client_id = client.id, request_id = request_id })
|
||||
end
|
||||
end
|
||||
self.pending = self.pending - 1
|
||||
self.async:resume()
|
||||
end)
|
||||
self.async:suspend()
|
||||
return self
|
||||
end
|
||||
|
||||
function R:wait()
|
||||
while self.completed < #self.requests do
|
||||
while self.pending > 0 or self.completed < #self.requests do
|
||||
self.async:suspend()
|
||||
end
|
||||
end
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue