mirror of
https://github.com/neovim/neovim.git
synced 2026-04-19 22:10:45 +00:00
feat(lsp): add fswatch watchfunc backend
Problem:
vim._watch.watchdirs has terrible performance.
Solution:
- On linux use fswatch as a watcher backend if available.
- Add File watcher section to health:vim.lsp. Warn if watchfunc is
libuv-poll.
This commit is contained in:
@@ -222,5 +222,81 @@ function M.watchdirs(path, opts, callback)
|
||||
return cancel
|
||||
end
|
||||
|
||||
return M
|
||||
--- @param data string
|
||||
--- @param opts vim._watch.Opts?
|
||||
--- @param callback vim._watch.Callback
|
||||
local function fswatch_output_handler(data, opts, callback)
|
||||
local d = vim.split(data, '%s+')
|
||||
|
||||
-- only consider the last reported event
|
||||
local fullpath, event = d[1], d[#d]
|
||||
|
||||
if skip(fullpath, opts) then
|
||||
return
|
||||
end
|
||||
|
||||
--- @type integer
|
||||
local change_type
|
||||
|
||||
if event == 'Created' then
|
||||
change_type = M.FileChangeType.Created
|
||||
elseif event == 'Removed' then
|
||||
change_type = M.FileChangeType.Deleted
|
||||
elseif event == 'Updated' then
|
||||
change_type = M.FileChangeType.Changed
|
||||
elseif event == 'Renamed' then
|
||||
local _, staterr, staterrname = uv.fs_stat(fullpath)
|
||||
if staterrname == 'ENOENT' then
|
||||
change_type = M.FileChangeType.Deleted
|
||||
else
|
||||
assert(not staterr, staterr)
|
||||
change_type = M.FileChangeType.Created
|
||||
end
|
||||
end
|
||||
|
||||
if change_type then
|
||||
callback(fullpath, change_type)
|
||||
end
|
||||
end
|
||||
|
||||
--- @param path string The path to watch. Must refer to a directory.
|
||||
--- @param opts vim._watch.Opts?
|
||||
--- @param callback vim._watch.Callback Callback for new events
|
||||
--- @return fun() cancel Stops the watcher
|
||||
function M.fswatch(path, opts, callback)
|
||||
-- debounce isn't the same as latency but close enough
|
||||
local latency = 0.5 -- seconds
|
||||
if opts and opts.debounce then
|
||||
latency = opts.debounce / 1000
|
||||
end
|
||||
|
||||
local obj = vim.system({
|
||||
'fswatch',
|
||||
'--event=Created',
|
||||
'--event=Removed',
|
||||
'--event=Updated',
|
||||
'--event=Renamed',
|
||||
'--event-flags',
|
||||
'--recursive',
|
||||
'--latency=' .. tostring(latency),
|
||||
'--exclude',
|
||||
'/.git/',
|
||||
path,
|
||||
}, {
|
||||
stdout = function(err, data)
|
||||
if err then
|
||||
error(err)
|
||||
end
|
||||
|
||||
for line in vim.gsplit(data or '', '\n', { plain = true, trimempty = true }) do
|
||||
fswatch_output_handler(line, opts, callback)
|
||||
end
|
||||
end,
|
||||
})
|
||||
|
||||
return function()
|
||||
obj:kill(2)
|
||||
end
|
||||
end
|
||||
|
||||
return M
|
||||
|
||||
Reference in New Issue
Block a user