aboutsummaryrefslogtreecommitdiff
path: root/runtime/lua/vim/_watch.lua
diff options
context:
space:
mode:
authorLewis Russell <lewis6991@gmail.com>2024-02-07 11:28:35 +0000
committerLewis Russell <lewis6991@gmail.com>2024-03-01 23:00:20 +0000
commit4ff3217bbd8747d2d44680a825ac29097faf9c4b (patch)
tree22b024bfa5738a0556a88f9a35fca8cbe619841a /runtime/lua/vim/_watch.lua
parent816b56f878f0291c00a9018d5057b7b2b00f1891 (diff)
downloadrneovim-4ff3217bbd8747d2d44680a825ac29097faf9c4b.tar.gz
rneovim-4ff3217bbd8747d2d44680a825ac29097faf9c4b.tar.bz2
rneovim-4ff3217bbd8747d2d44680a825ac29097faf9c4b.zip
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.
Diffstat (limited to 'runtime/lua/vim/_watch.lua')
-rw-r--r--runtime/lua/vim/_watch.lua78
1 files changed, 77 insertions, 1 deletions
diff --git a/runtime/lua/vim/_watch.lua b/runtime/lua/vim/_watch.lua
index 03b632b53c..d199cf8e29 100644
--- a/runtime/lua/vim/_watch.lua
+++ b/runtime/lua/vim/_watch.lua
@@ -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