feat(watcher): debounce FS watchers
This commit is contained in:
@@ -273,6 +273,7 @@ Setup may only be run once; subsequent calls will result in a warning.
|
|||||||
filesystem_watchers = {
|
filesystem_watchers = {
|
||||||
enable = false,
|
enable = false,
|
||||||
interval = 100,
|
interval = 100,
|
||||||
|
debounce_delay = 50,
|
||||||
},
|
},
|
||||||
git = {
|
git = {
|
||||||
enable = true,
|
enable = true,
|
||||||
@@ -524,6 +525,10 @@ This will be experimental for a few weeks and will become the default.
|
|||||||
https://github.com/luvit/luv/blob/master/docs.md#uvfs_poll_startfs_poll-path-interval-callback
|
https://github.com/luvit/luv/blob/master/docs.md#uvfs_poll_startfs_poll-path-interval-callback
|
||||||
Type: `number`, Default: `100` (ms)
|
Type: `number`, Default: `100` (ms)
|
||||||
|
|
||||||
|
*nvim-tree.filesystem_watchers.debounce_delay*
|
||||||
|
Idle milliseconds between filesystem change and action.
|
||||||
|
Type: `number`, Default: `50` (ms)
|
||||||
|
|
||||||
*nvim-tree.view*
|
*nvim-tree.view*
|
||||||
Window / buffer setup.
|
Window / buffer setup.
|
||||||
|
|
||||||
|
|||||||
@@ -524,6 +524,7 @@ local DEFAULT_OPTS = { -- BEGIN_DEFAULT_OPTS
|
|||||||
filesystem_watchers = {
|
filesystem_watchers = {
|
||||||
enable = false,
|
enable = false,
|
||||||
interval = 100,
|
interval = 100,
|
||||||
|
debounce_delay = 50,
|
||||||
},
|
},
|
||||||
git = {
|
git = {
|
||||||
enable = true,
|
enable = true,
|
||||||
|
|||||||
@@ -22,6 +22,21 @@ local function is_git(path)
|
|||||||
return path:match "%.git$" ~= nil or path:match(utils.path_add_trailing ".git") ~= nil
|
return path:match "%.git$" ~= nil or path:match(utils.path_add_trailing ".git") ~= nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local function refresh_path(path)
|
||||||
|
log.line("watcher", "node event executing '%s'", path)
|
||||||
|
local n = utils.get_node_from_path(path)
|
||||||
|
if not n then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local node = utils.get_parent_of_group(n)
|
||||||
|
local project_root, project = reload_and_get_git_project(path)
|
||||||
|
require("nvim-tree.explorer.reload").reload(node, project)
|
||||||
|
update_parent_statuses(node, project, project_root)
|
||||||
|
|
||||||
|
require("nvim-tree.renderer").draw()
|
||||||
|
end
|
||||||
|
|
||||||
function M.create_watcher(absolute_path)
|
function M.create_watcher(absolute_path)
|
||||||
if not M.enabled then
|
if not M.enabled then
|
||||||
return nil
|
return nil
|
||||||
@@ -34,19 +49,11 @@ function M.create_watcher(absolute_path)
|
|||||||
Watcher.new {
|
Watcher.new {
|
||||||
absolute_path = absolute_path,
|
absolute_path = absolute_path,
|
||||||
interval = M.interval,
|
interval = M.interval,
|
||||||
on_event = function(path)
|
on_event = function(opts)
|
||||||
local n = utils.get_node_from_path(absolute_path)
|
log.line("watcher", "node event scheduled '%s'", opts.absolute_path)
|
||||||
if not n then
|
utils.debounce("explorer:watch:" .. opts.absolute_path, M.debounce_delay, function()
|
||||||
return
|
refresh_path(opts.absolute_path)
|
||||||
end
|
end)
|
||||||
log.line("watcher", "node event '%s'", path)
|
|
||||||
|
|
||||||
local node = utils.get_parent_of_group(n)
|
|
||||||
local project_root, project = reload_and_get_git_project(path)
|
|
||||||
require("nvim-tree.explorer.reload").reload(node, project)
|
|
||||||
update_parent_statuses(node, project, project_root)
|
|
||||||
|
|
||||||
require("nvim-tree.renderer").draw()
|
|
||||||
end,
|
end,
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
@@ -54,6 +61,7 @@ end
|
|||||||
function M.setup(opts)
|
function M.setup(opts)
|
||||||
M.enabled = opts.filesystem_watchers.enable
|
M.enabled = opts.filesystem_watchers.enable
|
||||||
M.interval = opts.filesystem_watchers.interval
|
M.interval = opts.filesystem_watchers.interval
|
||||||
|
M.debounce_delay = opts.filesystem_watchers.debounce_delay
|
||||||
end
|
end
|
||||||
|
|
||||||
return M
|
return M
|
||||||
|
|||||||
@@ -5,13 +5,13 @@ local Runner = require "nvim-tree.git.runner"
|
|||||||
local Watcher = require("nvim-tree.watcher").Watcher
|
local Watcher = require("nvim-tree.watcher").Watcher
|
||||||
|
|
||||||
local M = {
|
local M = {
|
||||||
config = nil,
|
config = {},
|
||||||
projects = {},
|
projects = {},
|
||||||
cwd_to_project_root = {},
|
cwd_to_project_root = {},
|
||||||
}
|
}
|
||||||
|
|
||||||
function M.reload()
|
function M.reload()
|
||||||
if not M.config.enable then
|
if not M.config.git.enable then
|
||||||
return {}
|
return {}
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -24,7 +24,7 @@ end
|
|||||||
|
|
||||||
function M.reload_project(project_root, path)
|
function M.reload_project(project_root, path)
|
||||||
local project = M.projects[project_root]
|
local project = M.projects[project_root]
|
||||||
if not project or not M.config.enable then
|
if not project or not M.config.git.enable then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -37,7 +37,7 @@ function M.reload_project(project_root, path)
|
|||||||
path = path,
|
path = path,
|
||||||
list_untracked = git_utils.should_show_untracked(project_root),
|
list_untracked = git_utils.should_show_untracked(project_root),
|
||||||
list_ignored = true,
|
list_ignored = true,
|
||||||
timeout = M.config.timeout,
|
timeout = M.config.git.timeout,
|
||||||
}
|
}
|
||||||
|
|
||||||
if path then
|
if path then
|
||||||
@@ -71,7 +71,8 @@ function M.get_project_root(cwd)
|
|||||||
return project_root
|
return project_root
|
||||||
end
|
end
|
||||||
|
|
||||||
function M.reload_tree_at(project_root)
|
local function reload_tree_at(project_root)
|
||||||
|
log.line("watcher", "git event executing '%s'", project_root)
|
||||||
local root_node = utils.get_node_from_path(project_root)
|
local root_node = utils.get_node_from_path(project_root)
|
||||||
if not root_node then
|
if not root_node then
|
||||||
return
|
return
|
||||||
@@ -98,10 +99,12 @@ function M.reload_tree_at(project_root)
|
|||||||
end
|
end
|
||||||
|
|
||||||
iterate(root_node)
|
iterate(root_node)
|
||||||
|
|
||||||
|
require("nvim-tree.renderer").draw()
|
||||||
end
|
end
|
||||||
|
|
||||||
function M.load_project_status(cwd)
|
function M.load_project_status(cwd)
|
||||||
if not M.config.enable then
|
if not M.config.git.enable then
|
||||||
return {}
|
return {}
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -120,19 +123,25 @@ function M.load_project_status(cwd)
|
|||||||
project_root = project_root,
|
project_root = project_root,
|
||||||
list_untracked = git_utils.should_show_untracked(project_root),
|
list_untracked = git_utils.should_show_untracked(project_root),
|
||||||
list_ignored = true,
|
list_ignored = true,
|
||||||
timeout = M.config.timeout,
|
timeout = M.config.git.timeout,
|
||||||
}
|
}
|
||||||
|
|
||||||
local watcher = nil
|
local watcher = nil
|
||||||
if M.config.watcher.enable then
|
if M.config.filesystem_watchers.enable then
|
||||||
log.line("watcher", "git start")
|
log.line("watcher", "git start")
|
||||||
watcher = Watcher.new {
|
watcher = Watcher.new {
|
||||||
absolute_path = utils.path_join { project_root, ".git" },
|
absolute_path = utils.path_join { project_root, ".git" },
|
||||||
interval = M.config.watcher.interval,
|
project_root = project_root,
|
||||||
on_event = function()
|
interval = M.config.filesystem_watchers.interval,
|
||||||
|
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)
|
||||||
|
end)
|
||||||
|
end,
|
||||||
|
on_event0 = function()
|
||||||
log.line("watcher", "git event")
|
log.line("watcher", "git event")
|
||||||
M.reload_tree_at(project_root)
|
M.reload_tree_at(project_root)
|
||||||
require("nvim-tree.renderer").draw()
|
|
||||||
end,
|
end,
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
@@ -151,8 +160,8 @@ function M.purge_state()
|
|||||||
end
|
end
|
||||||
|
|
||||||
function M.setup(opts)
|
function M.setup(opts)
|
||||||
M.config = opts.git
|
M.config.git = opts.git
|
||||||
M.config.watcher = opts.filesystem_watchers
|
M.config.filesystem_watchers = opts.filesystem_watchers
|
||||||
end
|
end
|
||||||
|
|
||||||
return M
|
return M
|
||||||
|
|||||||
@@ -3,7 +3,9 @@ local has_notify, notify = pcall(require, "notify")
|
|||||||
local a = vim.api
|
local a = vim.api
|
||||||
local uv = vim.loop
|
local uv = vim.loop
|
||||||
|
|
||||||
local M = {}
|
local M = {
|
||||||
|
debouncers = {},
|
||||||
|
}
|
||||||
|
|
||||||
M.is_windows = vim.fn.has "win32" == 1 or vim.fn.has "win32unix" == 1
|
M.is_windows = vim.fn.has "win32" == 1 or vim.fn.has "win32unix" == 1
|
||||||
|
|
||||||
@@ -328,4 +330,25 @@ function M.key_by(tbl, key)
|
|||||||
return keyed
|
return keyed
|
||||||
end
|
end
|
||||||
|
|
||||||
|
---Execute callback timeout ms after the lastest invocation with context. Waiting invocations for that context will be discarded. Caller should this ensure that callback performs the same or functionally equivalent actions.
|
||||||
|
---@param context string identifies the callback to debounce
|
||||||
|
---@param timeout number ms to wait
|
||||||
|
---@param callback function to execute on completion
|
||||||
|
function M.debounce(context, timeout, callback)
|
||||||
|
if M.debouncers[context] then
|
||||||
|
pcall(uv.close, M.debouncers[context])
|
||||||
|
end
|
||||||
|
|
||||||
|
M.debouncers[context] = uv.new_timer()
|
||||||
|
M.debouncers[context]:start(
|
||||||
|
timeout,
|
||||||
|
0,
|
||||||
|
vim.schedule_wrap(function()
|
||||||
|
M.debouncers[context]:close()
|
||||||
|
M.debouncers[context] = nil
|
||||||
|
callback()
|
||||||
|
end)
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
return M
|
return M
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ function Watcher:start()
|
|||||||
if err then
|
if err then
|
||||||
log.line("watcher", "poll_cb for %s fail : %s", self._opts.absolute_path, err)
|
log.line("watcher", "poll_cb for %s fail : %s", self._opts.absolute_path, err)
|
||||||
else
|
else
|
||||||
self._opts.on_event(self._opts.absolute_path)
|
self._opts.on_event(self._opts)
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user