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 tabs table<integer, true>
|
||||||
---@field status ow.Git.Status
|
---@field status ow.Git.Status
|
||||||
---@field private _events ow.Git.Util.Emitter<ow.Git.Repo.Event>
|
---@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 _schedule_refresh fun(self: ow.Git.Repo)
|
||||||
---@field private _refresh_handle ow.Git.Util.DebounceHandle
|
---@field private _refresh_handle ow.Git.Util.DebounceHandle
|
||||||
---@field private _cache table<string, any>
|
---@field private _cache table<string, any>
|
||||||
@@ -107,44 +107,101 @@ function Repo:get_cached(key, compute)
|
|||||||
return value
|
return value
|
||||||
end
|
end
|
||||||
|
|
||||||
function Repo:start_watcher()
|
---@param path string
|
||||||
local watcher, err = vim.uv.new_fs_event()
|
---@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
|
if not watcher then
|
||||||
util.error(
|
return nil
|
||||||
"git: failed to create fs_event for %s: %s",
|
|
||||||
self.gitdir,
|
|
||||||
err
|
|
||||||
)
|
|
||||||
return
|
|
||||||
end
|
end
|
||||||
local ok, start_err = watcher:start(
|
local ok = watcher:start(path, {}, function(err, filename)
|
||||||
self.gitdir,
|
if err then
|
||||||
{ recursive = true },
|
return
|
||||||
function(err_, filename)
|
|
||||||
if
|
|
||||||
err_
|
|
||||||
or filename:match("^objects/")
|
|
||||||
or filename:match("^logs/")
|
|
||||||
then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
self:refresh()
|
|
||||||
end
|
end
|
||||||
)
|
on_event(filename)
|
||||||
|
end)
|
||||||
if not ok then
|
if not ok then
|
||||||
util.error("failed to watch %s: %s", self.gitdir, tostring(start_err))
|
|
||||||
watcher:close()
|
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
|
return
|
||||||
end
|
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
|
end
|
||||||
|
|
||||||
function Repo:close()
|
function Repo:close()
|
||||||
if self._watcher then
|
for _, watcher in pairs(self._watchers) do
|
||||||
self._watcher:stop()
|
watcher:stop()
|
||||||
self._watcher:close()
|
watcher:close()
|
||||||
self._watcher = nil
|
|
||||||
end
|
end
|
||||||
|
self._watchers = {}
|
||||||
self._refresh_handle.close()
|
self._refresh_handle.close()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user