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
@@ -45,21 +45,23 @@ function M.create_watcher(absolute_path)
|
||||
return nil
|
||||
end
|
||||
|
||||
log.line("watcher", "node start '%s'", absolute_path)
|
||||
return Watcher.new {
|
||||
absolute_path = absolute_path,
|
||||
on_event = function(opts)
|
||||
log.line("watcher", "node event scheduled '%s'", opts.absolute_path)
|
||||
utils.debounce("explorer:watch:" .. opts.absolute_path, M.debounce_delay, function()
|
||||
refresh_path(opts.absolute_path)
|
||||
local function callback(watcher)
|
||||
log.line("watcher", "node event scheduled %s", watcher.context)
|
||||
utils.debounce(watcher.context, M.debounce_delay, function()
|
||||
refresh_path(watcher._path)
|
||||
end)
|
||||
end,
|
||||
}
|
||||
end
|
||||
|
||||
M.uid = M.uid + 1
|
||||
return Watcher:new(absolute_path, callback, {
|
||||
context = "explorer:watch:" .. absolute_path .. ":" .. M.uid,
|
||||
})
|
||||
end
|
||||
|
||||
function M.setup(opts)
|
||||
M.enabled = opts.filesystem_watchers.enable
|
||||
M.debounce_delay = opts.filesystem_watchers.debounce_delay
|
||||
M.uid = 0
|
||||
end
|
||||
|
||||
return M
|
||||
|
||||
@@ -143,16 +143,17 @@ function M.load_project_status(cwd)
|
||||
local watcher = nil
|
||||
if M.config.filesystem_watchers.enable then
|
||||
log.line("watcher", "git start")
|
||||
watcher = Watcher.new {
|
||||
absolute_path = utils.path_join { project_root, ".git" },
|
||||
project_root = project_root,
|
||||
on_event = function(opts)
|
||||
log.line("watcher", "git event scheduled '%s'", opts.project_root)
|
||||
utils.debounce("git:watcher:" .. opts.project_root, M.config.filesystem_watchers.debounce_delay, function()
|
||||
reload_tree_at(opts.project_root)
|
||||
|
||||
local callback = function(w)
|
||||
log.line("watcher", "git event scheduled '%s'", w.project_root)
|
||||
utils.debounce("git:watcher:" .. w.project_root, M.config.filesystem_watchers.debounce_delay, function()
|
||||
reload_tree_at(w.project_root)
|
||||
end)
|
||||
end,
|
||||
}
|
||||
end
|
||||
|
||||
watcher = Watcher:new(utils.path_join { project_root, ".git" }, callback, {
|
||||
project_root = project_root,
|
||||
})
|
||||
end
|
||||
|
||||
M.projects[project_root] = {
|
||||
|
||||
@@ -169,15 +169,17 @@ end
|
||||
---Matching executable files in Windows.
|
||||
---@param ext string
|
||||
---@return boolean
|
||||
local PATHEXT = vim.env.PATHEXT or ""
|
||||
local wexe = vim.split(PATHEXT:gsub("%.", ""), ";")
|
||||
local pathexts = {}
|
||||
for _, v in pairs(wexe) do
|
||||
pathexts[v] = true
|
||||
end
|
||||
|
||||
function M.is_windows_exe(ext)
|
||||
return pathexts[ext:upper()]
|
||||
if not M.pathexts then
|
||||
local PATHEXT = vim.env.PATHEXT or ""
|
||||
local wexe = vim.split(PATHEXT:gsub("%.", ""), ";")
|
||||
M.pathexts = {}
|
||||
for _, v in pairs(wexe) do
|
||||
M.pathexts[v] = true
|
||||
end
|
||||
end
|
||||
|
||||
return M.pathexts[ext:upper()]
|
||||
end
|
||||
|
||||
function M.rename_loaded_buffers(old_path, new_path)
|
||||
@@ -379,4 +381,23 @@ function M.clear_prompt()
|
||||
end
|
||||
end
|
||||
|
||||
-- return a new table with values from array
|
||||
function M.array_shallow_clone(array)
|
||||
local to = {}
|
||||
for _, v in ipairs(array) do
|
||||
table.insert(to, v)
|
||||
end
|
||||
return to
|
||||
end
|
||||
|
||||
-- remove item from array if it exists
|
||||
function M.array_remove(array, item)
|
||||
for i, v in ipairs(array) do
|
||||
if v == item then
|
||||
table.remove(array, i)
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return M
|
||||
|
||||
@@ -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
|
||||
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
|
||||
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