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
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
log.line("watcher", "node start '%s'", absolute_path)
|
local function callback(watcher)
|
||||||
return Watcher.new {
|
log.line("watcher", "node event scheduled %s", watcher.context)
|
||||||
absolute_path = absolute_path,
|
utils.debounce(watcher.context, M.debounce_delay, function()
|
||||||
on_event = function(opts)
|
refresh_path(watcher._path)
|
||||||
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)
|
|
||||||
end)
|
end)
|
||||||
end,
|
end
|
||||||
}
|
|
||||||
|
M.uid = M.uid + 1
|
||||||
|
return Watcher:new(absolute_path, callback, {
|
||||||
|
context = "explorer:watch:" .. absolute_path .. ":" .. M.uid,
|
||||||
|
})
|
||||||
end
|
end
|
||||||
|
|
||||||
function M.setup(opts)
|
function M.setup(opts)
|
||||||
M.enabled = opts.filesystem_watchers.enable
|
M.enabled = opts.filesystem_watchers.enable
|
||||||
M.debounce_delay = opts.filesystem_watchers.debounce_delay
|
M.debounce_delay = opts.filesystem_watchers.debounce_delay
|
||||||
|
M.uid = 0
|
||||||
end
|
end
|
||||||
|
|
||||||
return M
|
return M
|
||||||
|
|||||||
@@ -143,16 +143,17 @@ function M.load_project_status(cwd)
|
|||||||
local watcher = nil
|
local watcher = nil
|
||||||
if M.config.filesystem_watchers.enable then
|
if M.config.filesystem_watchers.enable then
|
||||||
log.line("watcher", "git start")
|
log.line("watcher", "git start")
|
||||||
watcher = Watcher.new {
|
|
||||||
absolute_path = utils.path_join { project_root, ".git" },
|
local callback = function(w)
|
||||||
project_root = project_root,
|
log.line("watcher", "git event scheduled '%s'", w.project_root)
|
||||||
on_event = function(opts)
|
utils.debounce("git:watcher:" .. w.project_root, M.config.filesystem_watchers.debounce_delay, function()
|
||||||
log.line("watcher", "git event scheduled '%s'", opts.project_root)
|
reload_tree_at(w.project_root)
|
||||||
utils.debounce("git:watcher:" .. opts.project_root, M.config.filesystem_watchers.debounce_delay, function()
|
|
||||||
reload_tree_at(opts.project_root)
|
|
||||||
end)
|
end)
|
||||||
end,
|
end
|
||||||
}
|
|
||||||
|
watcher = Watcher:new(utils.path_join { project_root, ".git" }, callback, {
|
||||||
|
project_root = project_root,
|
||||||
|
})
|
||||||
end
|
end
|
||||||
|
|
||||||
M.projects[project_root] = {
|
M.projects[project_root] = {
|
||||||
|
|||||||
@@ -169,15 +169,17 @@ end
|
|||||||
---Matching executable files in Windows.
|
---Matching executable files in Windows.
|
||||||
---@param ext string
|
---@param ext string
|
||||||
---@return boolean
|
---@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)
|
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
|
end
|
||||||
|
|
||||||
function M.rename_loaded_buffers(old_path, new_path)
|
function M.rename_loaded_buffers(old_path, new_path)
|
||||||
@@ -379,4 +381,23 @@ function M.clear_prompt()
|
|||||||
end
|
end
|
||||||
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
|
return M
|
||||||
|
|||||||
@@ -3,10 +3,16 @@ local uv = vim.loop
|
|||||||
local log = require "nvim-tree.log"
|
local log = require "nvim-tree.log"
|
||||||
local utils = require "nvim-tree.utils"
|
local utils = require "nvim-tree.utils"
|
||||||
|
|
||||||
local M = {
|
local M = {}
|
||||||
|
|
||||||
|
local Event = {
|
||||||
|
_events = {},
|
||||||
|
}
|
||||||
|
Event.__index = Event
|
||||||
|
|
||||||
|
local Watcher = {
|
||||||
_watchers = {},
|
_watchers = {},
|
||||||
}
|
}
|
||||||
local Watcher = {}
|
|
||||||
Watcher.__index = Watcher
|
Watcher.__index = Watcher
|
||||||
|
|
||||||
local FS_EVENT_FLAGS = {
|
local FS_EVENT_FLAGS = {
|
||||||
@@ -16,87 +22,129 @@ local FS_EVENT_FLAGS = {
|
|||||||
recursive = false,
|
recursive = false,
|
||||||
}
|
}
|
||||||
|
|
||||||
function Watcher.new(opts)
|
function Event:new(path)
|
||||||
for _, existing in ipairs(M._watchers) do
|
log.line("watcher", "Event:new '%s'", path)
|
||||||
if existing._opts.absolute_path == opts.absolute_path then
|
|
||||||
log.line("watcher", "Watcher:new using existing '%s'", opts.absolute_path)
|
local e = setmetatable({
|
||||||
return existing
|
_path = path,
|
||||||
|
_fs_event = nil,
|
||||||
|
_listeners = {},
|
||||||
|
}, Event)
|
||||||
|
|
||||||
|
if e:start() then
|
||||||
|
Event._events[path] = e
|
||||||
|
return e
|
||||||
|
else
|
||||||
|
return nil
|
||||||
end
|
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
|
end
|
||||||
|
|
||||||
function Watcher:start()
|
function Event:start()
|
||||||
log.line("watcher", "Watcher:start '%s'", self._opts.absolute_path)
|
log.line("watcher", "Event:start '%s'", self._path)
|
||||||
|
|
||||||
local rc, _, name
|
local rc, _, name
|
||||||
|
|
||||||
self._e, _, name = uv.new_fs_event()
|
self._fs_event, _, name = uv.new_fs_event()
|
||||||
if not self._e then
|
if not self._fs_event then
|
||||||
self._e = nil
|
self._fs_event = nil
|
||||||
utils.notify.warn(
|
utils.notify.warn(string.format("Could not initialize an fs_event watcher for path %s : %s", self._path, name))
|
||||||
string.format("Could not initialize an fs_event watcher for path %s : %s", self._opts.absolute_path, name)
|
return false
|
||||||
)
|
|
||||||
return nil
|
|
||||||
end
|
end
|
||||||
|
|
||||||
local event_cb = vim.schedule_wrap(function(err, filename, events)
|
local event_cb = vim.schedule_wrap(function(err, filename)
|
||||||
if err then
|
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
|
else
|
||||||
log.line("watcher", "event_cb '%s' '%s' %s", self._opts.absolute_path, filename, vim.inspect(events))
|
log.line("watcher", "event_cb '%s' '%s'", self._path, filename)
|
||||||
self._opts.on_event(self._opts)
|
for _, listener in ipairs(self._listeners) do
|
||||||
|
listener()
|
||||||
|
end
|
||||||
end
|
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
|
if rc ~= 0 then
|
||||||
utils.notify.warn(
|
utils.notify.warn(string.format("Could not start the fs_event watcher for path %s : %s", self._path, name))
|
||||||
string.format("Could not start the fs_event watcher for path %s : %s", self._opts.absolute_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
|
return nil
|
||||||
end
|
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
|
end
|
||||||
|
|
||||||
function Watcher:destroy()
|
function Watcher:destroy()
|
||||||
log.line("watcher", "Watcher:destroy '%s'", self._opts.absolute_path)
|
log.line("watcher", "Watcher:destroy '%s'", self._path)
|
||||||
if self._e then
|
|
||||||
local rc, _, name = self._e:stop()
|
self._event:remove(self._listener)
|
||||||
if rc ~= 0 then
|
|
||||||
utils.notify.warn(
|
utils.array_remove(Watcher._watchers, self)
|
||||||
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
|
|
||||||
end
|
end
|
||||||
|
|
||||||
M.Watcher = Watcher
|
M.Watcher = Watcher
|
||||||
|
|
||||||
function M.purge_watchers()
|
function M.purge_watchers()
|
||||||
for _, watcher in pairs(M._watchers) do
|
log.line("watcher", "purge_watchers")
|
||||||
watcher:destroy()
|
|
||||||
|
for _, w in ipairs(utils.array_shallow_clone(Watcher._watchers)) do
|
||||||
|
w:destroy()
|
||||||
|
end
|
||||||
|
|
||||||
|
for _, e in pairs(Event._events) do
|
||||||
|
e:destroy()
|
||||||
end
|
end
|
||||||
M._watchers = {}
|
|
||||||
end
|
end
|
||||||
|
|
||||||
return M
|
return M
|
||||||
|
|||||||
Reference in New Issue
Block a user