Skip to content

Commit dd10409

Browse files
committed
fix(libuv): race condition in spawn/vim.schedule
1 parent 01ef2bb commit dd10409

2 files changed

Lines changed: 18 additions & 7 deletions

File tree

lua/fzf-lua/devicons.lua

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -515,6 +515,9 @@ M.get_devicon = function(filepath, extensionOverride)
515515
-- `vim.{api|fn}` calls so we still have to make sure we schedule the call on the
516516
-- main thread but not on headless as it will fail due to uv callbacks (#1831/#1841)
517517
local ft_match = _G._fzf_lua_is_headless and path.ft_match or path.ft_match_fast_event
518+
-- NOTE: no longer required since we `vim.schedule` uv.spawn's read callback
519+
-- TODO: failing the CI
520+
-- local ft_match = vim.filetype.match
518521
local ft = ft_match({ filename = filename })
519522
local by_ft = ft and #ft > 0 and STATE.icons.by_filetype[ft]
520523

lua/fzf-lua/libuv.lua

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ M.spawn = function(opts, fn_transform, fn_done)
5656
local EOL = opts.EOL or "\n"
5757
local output_pipe = uv.new_pipe(false)
5858
local error_pipe = uv.new_pipe(false)
59-
local write_cb_count, on_exit_called = 0, nil
59+
local write_cb_count, read_cb_count, on_exit_called = 0, 0, nil
6060
local prev_line_content = nil
6161

6262
if opts.fn_transform then fn_transform = opts.fn_transform end
@@ -91,8 +91,9 @@ M.spawn = function(opts, fn_transform, fn_done)
9191
table.insert(args, tostring(opts.cmd))
9292
end
9393

94+
local handle, pid
9495
---@diagnostic disable-next-line: missing-fields
95-
local handle, pid = uv.spawn(shell, {
96+
handle, pid = uv.spawn(shell, {
9697
args = args,
9798
stdio = { nil, output_pipe, error_pipe },
9899
cwd = opts.cwd,
@@ -113,12 +114,15 @@ M.spawn = function(opts, fn_transform, fn_done)
113114
verbatim = _is_win,
114115
}, function(code, signal)
115116
on_exit_called = true
116-
if write_cb_count == 0 and not output_pipe:is_active() then
117+
if write_cb_count == 0
118+
and read_cb_count == 0
119+
and not output_pipe:is_active()
120+
then
117121
-- Do not call `:read_stop` or `:close` here as we may have data
118122
-- reads outstanding on slower Windows machines (#1521), only call
119123
-- `finish` if all our `uv.write` calls are completed and the pipe
120124
-- is no longer active (i.e. no more read cb's expected)
121-
finish(code, signal, 1)
125+
finish(code, signal, 1, pid)
122126
end
123127
end)
124128

@@ -211,10 +215,14 @@ M.spawn = function(opts, fn_transform, fn_done)
211215
end
212216

213217
local read_cb = function(err, data)
214-
local read = function() _read_cb(err, data) end
218+
read_cb_count = read_cb_count + 1
219+
local read = function()
220+
_read_cb(err, data)
221+
read_cb_count = read_cb_count - 1
222+
end
215223
-- Avoid "attempt to yield across C-call boundary"
216-
-- if vim.in_fast_event() then vim.schedule(read) else read() end
217-
read()
224+
if vim.in_fast_event() then vim.schedule(read) else read() end
225+
-- read()
218226
end
219227

220228
local err_cb = function(err, data)

0 commit comments

Comments
 (0)