fix(git/repo): recurse subdirs in fs watcher
This commit is contained in:
+85
-28
@@ -32,7 +32,7 @@ local global = util.Emitter.new()
|
||||
---@field tabs table<integer, true>
|
||||
---@field status ow.Git.Status
|
||||
---@field private _events ow.Git.Util.Emitter<ow.Git.Repo.Event>
|
||||
---@field private _watcher? uv.uv_fs_event_t
|
||||
---@field private _watchers table<string, uv.uv_fs_event_t>
|
||||
---@field private _schedule_refresh fun(self: ow.Git.Repo)
|
||||
---@field private _refresh_handle ow.Git.Util.DebounceHandle
|
||||
---@field private _cache table<string, any>
|
||||
@@ -107,44 +107,101 @@ function Repo:get_cached(key, compute)
|
||||
return value
|
||||
end
|
||||
|
||||
function Repo:start_watcher()
|
||||
local watcher, err = vim.uv.new_fs_event()
|
||||
---@param path string
|
||||
---@param on_event fun(filename: string?)
|
||||
---@return uv.uv_fs_event_t?
|
||||
local function start_fs_event(path, on_event)
|
||||
local watcher = vim.uv.new_fs_event()
|
||||
if not watcher then
|
||||
util.error(
|
||||
"git: failed to create fs_event for %s: %s",
|
||||
self.gitdir,
|
||||
err
|
||||
)
|
||||
return
|
||||
return nil
|
||||
end
|
||||
local ok, start_err = watcher:start(
|
||||
self.gitdir,
|
||||
{ recursive = true },
|
||||
function(err_, filename)
|
||||
if
|
||||
err_
|
||||
or filename:match("^objects/")
|
||||
or filename:match("^logs/")
|
||||
then
|
||||
return
|
||||
end
|
||||
self:refresh()
|
||||
local ok = watcher:start(path, {}, function(err, filename)
|
||||
if err then
|
||||
return
|
||||
end
|
||||
)
|
||||
on_event(filename)
|
||||
end)
|
||||
if not ok then
|
||||
util.error("failed to watch %s: %s", self.gitdir, tostring(start_err))
|
||||
watcher:close()
|
||||
return nil
|
||||
end
|
||||
return watcher
|
||||
end
|
||||
|
||||
---@private
|
||||
---@param path string
|
||||
---@param on_change fun()
|
||||
function Repo:_watch_tree(path, on_change)
|
||||
if self._watchers[path] then
|
||||
return
|
||||
end
|
||||
self._watcher = watcher
|
||||
local stat = vim.uv.fs_stat(path)
|
||||
if not stat or stat.type ~= "directory" then
|
||||
return
|
||||
end
|
||||
local watcher = start_fs_event(path, function(filename)
|
||||
if not vim.uv.fs_stat(path) then
|
||||
local w = self._watchers[path] --[[@as uv.uv_fs_event_t?]]
|
||||
if w then
|
||||
w:stop()
|
||||
w:close()
|
||||
self._watchers[path] = nil
|
||||
end
|
||||
return
|
||||
end
|
||||
on_change()
|
||||
if filename then
|
||||
vim.schedule(function()
|
||||
self:_watch_tree(vim.fs.joinpath(path, filename), on_change)
|
||||
end)
|
||||
end
|
||||
end)
|
||||
if not watcher then
|
||||
return
|
||||
end
|
||||
self._watchers[path] = watcher
|
||||
local handle = vim.uv.fs_scandir(path)
|
||||
if not handle then
|
||||
return
|
||||
end
|
||||
while true do
|
||||
local name, typ = vim.uv.fs_scandir_next(handle)
|
||||
if not name then
|
||||
break
|
||||
end
|
||||
if typ == "directory" then
|
||||
self:_watch_tree(vim.fs.joinpath(path, name), on_change)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function Repo:start_watcher()
|
||||
self._watchers = {}
|
||||
local top = start_fs_event(self.gitdir, function(filename)
|
||||
if
|
||||
filename
|
||||
and (filename:match("^objects") or filename:match("^logs"))
|
||||
then
|
||||
return
|
||||
end
|
||||
self:refresh()
|
||||
end)
|
||||
if not top then
|
||||
util.error("git: failed to watch %s", self.gitdir)
|
||||
return
|
||||
end
|
||||
self._watchers[self.gitdir] = top
|
||||
self:_watch_tree(vim.fs.joinpath(self.gitdir, "refs"), function()
|
||||
self:refresh()
|
||||
end)
|
||||
end
|
||||
|
||||
function Repo:close()
|
||||
if self._watcher then
|
||||
self._watcher:stop()
|
||||
self._watcher:close()
|
||||
self._watcher = nil
|
||||
for _, watcher in pairs(self._watchers) do
|
||||
watcher:stop()
|
||||
watcher:close()
|
||||
end
|
||||
self._watchers = {}
|
||||
self._refresh_handle.close()
|
||||
end
|
||||
|
||||
|
||||
Reference in New Issue
Block a user