chore(watchers): Watcher shares single fs_event from Event, node watchers use unique path prefixed debounce context (#1453)
This commit is contained in:
committed by
GitHub
parent
e5222970d9
commit
eff1db341c
@@ -3,10 +3,16 @@ local uv = vim.loop
|
||||
local log = require "nvim-tree.log"
|
||||
local utils = require "nvim-tree.utils"
|
||||
|
||||
local M = {
|
||||
local M = {}
|
||||
|
||||
local Event = {
|
||||
_events = {},
|
||||
}
|
||||
Event.__index = Event
|
||||
|
||||
local Watcher = {
|
||||
_watchers = {},
|
||||
}
|
||||
local Watcher = {}
|
||||
Watcher.__index = Watcher
|
||||
|
||||
local FS_EVENT_FLAGS = {
|
||||
@@ -16,87 +22,129 @@ local FS_EVENT_FLAGS = {
|
||||
recursive = false,
|
||||
}
|
||||
|
||||
function Watcher.new(opts)
|
||||
for _, existing in ipairs(M._watchers) do
|
||||
if existing._opts.absolute_path == opts.absolute_path then
|
||||
log.line("watcher", "Watcher:new using existing '%s'", opts.absolute_path)
|
||||
return existing
|
||||
end
|
||||
function Event:new(path)
|
||||
log.line("watcher", "Event:new '%s'", path)
|
||||
|
||||
local e = setmetatable({
|
||||
_path = path,
|
||||
_fs_event = nil,
|
||||
_listeners = {},
|
||||
}, Event)
|
||||
|
||||
if e:start() then
|
||||
Event._events[path] = e
|
||||
return e
|
||||
else
|
||||
return nil
|
||||
end
|
||||
|
||||
log.line("watcher", "Watcher:new '%s'", opts.absolute_path)
|
||||
|
||||
local watcher = setmetatable({
|
||||
_opts = opts,
|
||||
}, Watcher)
|
||||
|
||||
watcher = watcher:start()
|
||||
|
||||
table.insert(M._watchers, watcher)
|
||||
|
||||
return watcher
|
||||
end
|
||||
|
||||
function Watcher:start()
|
||||
log.line("watcher", "Watcher:start '%s'", self._opts.absolute_path)
|
||||
function Event:start()
|
||||
log.line("watcher", "Event:start '%s'", self._path)
|
||||
|
||||
local rc, _, name
|
||||
|
||||
self._e, _, name = uv.new_fs_event()
|
||||
if not self._e then
|
||||
self._e = nil
|
||||
utils.notify.warn(
|
||||
string.format("Could not initialize an fs_event watcher for path %s : %s", self._opts.absolute_path, name)
|
||||
)
|
||||
return nil
|
||||
self._fs_event, _, name = uv.new_fs_event()
|
||||
if not self._fs_event then
|
||||
self._fs_event = nil
|
||||
utils.notify.warn(string.format("Could not initialize an fs_event watcher for path %s : %s", self._path, name))
|
||||
return false
|
||||
end
|
||||
|
||||
local event_cb = vim.schedule_wrap(function(err, filename, events)
|
||||
local event_cb = vim.schedule_wrap(function(err, filename)
|
||||
if err then
|
||||
log.line("watcher", "event_cb for %s fail : %s", self._opts.absolute_path, err)
|
||||
log.line("watcher", "event_cb for %s fail : %s", self._path, err)
|
||||
else
|
||||
log.line("watcher", "event_cb '%s' '%s' %s", self._opts.absolute_path, filename, vim.inspect(events))
|
||||
self._opts.on_event(self._opts)
|
||||
log.line("watcher", "event_cb '%s' '%s'", self._path, filename)
|
||||
for _, listener in ipairs(self._listeners) do
|
||||
listener()
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
rc, _, name = self._e:start(self._opts.absolute_path, FS_EVENT_FLAGS, event_cb)
|
||||
rc, _, name = self._fs_event:start(self._path, FS_EVENT_FLAGS, event_cb)
|
||||
if rc ~= 0 then
|
||||
utils.notify.warn(
|
||||
string.format("Could not start the fs_event watcher for path %s : %s", self._opts.absolute_path, name)
|
||||
)
|
||||
utils.notify.warn(string.format("Could not start the fs_event watcher for path %s : %s", self._path, name))
|
||||
return false
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
function Event:add(listener)
|
||||
table.insert(self._listeners, listener)
|
||||
end
|
||||
|
||||
function Event:remove(listener)
|
||||
utils.array_remove(self._listeners, listener)
|
||||
if #self._listeners == 0 then
|
||||
self:destroy()
|
||||
end
|
||||
end
|
||||
|
||||
function Event:destroy()
|
||||
log.line("watcher", "Event:destroy '%s'", self._path)
|
||||
|
||||
if self._fs_event then
|
||||
local rc, _, name = self._fs_event:stop()
|
||||
if rc ~= 0 then
|
||||
utils.notify.warn(string.format("Could not stop the fs_event watcher for path %s : %s", self._path, name))
|
||||
end
|
||||
self._fs_event = nil
|
||||
end
|
||||
|
||||
Event._events[self._path] = nil
|
||||
end
|
||||
|
||||
function Watcher:new(path, callback, data)
|
||||
log.line("watcher", "Watcher:new '%s'", path)
|
||||
|
||||
local w = setmetatable(data, Watcher)
|
||||
|
||||
w._event = Event._events[path] or Event:new(path)
|
||||
w._listener = nil
|
||||
w._path = path
|
||||
w._callback = callback
|
||||
|
||||
if not w._event then
|
||||
return nil
|
||||
end
|
||||
|
||||
return self
|
||||
w:start()
|
||||
|
||||
table.insert(Watcher._watchers, w)
|
||||
|
||||
return w
|
||||
end
|
||||
|
||||
function Watcher:start()
|
||||
self._listener = function()
|
||||
self._callback(self)
|
||||
end
|
||||
|
||||
self._event:add(self._listener)
|
||||
end
|
||||
|
||||
function Watcher:destroy()
|
||||
log.line("watcher", "Watcher:destroy '%s'", self._opts.absolute_path)
|
||||
if self._e then
|
||||
local rc, _, name = self._e:stop()
|
||||
if rc ~= 0 then
|
||||
utils.notify.warn(
|
||||
string.format("Could not stop the fs_event watcher for path %s : %s", self._opts.absolute_path, name)
|
||||
)
|
||||
end
|
||||
self._e = nil
|
||||
end
|
||||
for i, w in ipairs(M._watchers) do
|
||||
if w == self then
|
||||
table.remove(M._watchers, i)
|
||||
break
|
||||
end
|
||||
end
|
||||
log.line("watcher", "Watcher:destroy '%s'", self._path)
|
||||
|
||||
self._event:remove(self._listener)
|
||||
|
||||
utils.array_remove(Watcher._watchers, self)
|
||||
end
|
||||
|
||||
M.Watcher = Watcher
|
||||
|
||||
function M.purge_watchers()
|
||||
for _, watcher in pairs(M._watchers) do
|
||||
watcher:destroy()
|
||||
log.line("watcher", "purge_watchers")
|
||||
|
||||
for _, w in ipairs(utils.array_shallow_clone(Watcher._watchers)) do
|
||||
w:destroy()
|
||||
end
|
||||
|
||||
for _, e in pairs(Event._events) do
|
||||
e:destroy()
|
||||
end
|
||||
M._watchers = {}
|
||||
end
|
||||
|
||||
return M
|
||||
|
||||
Reference in New Issue
Block a user