Skip to content

Commit 8f2b018

Browse files
committed
fix(#3198): add filesystem_watchers.max_outstanding_events which disables filesystem watchers on a directory when runaway events are received
1 parent b8b44b6 commit 8f2b018

File tree

4 files changed

+44
-5
lines changed

4 files changed

+44
-5
lines changed

doc/nvim-tree-lua.txt

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -569,6 +569,7 @@ Following is the default configuration. See |nvim-tree-opts| for details. >lua
569569
filesystem_watchers = {
570570
enable = true,
571571
debounce_delay = 50,
572+
max_outstanding_events = 100,
572573
ignore_dirs = {
573574
"/.ccls-cache",
574575
"/build",
@@ -1450,6 +1451,15 @@ Enable / disable the feature.
14501451
Idle milliseconds between filesystem change and action.
14511452
Type: `number`, Default: `50` (ms)
14521453

1454+
*nvim-tree.filesystem_watchers.max_outstanding_events*
1455+
Maximum number of consecutive file system events for a single directory with
1456+
an interval < |nvim-tree.filesystem_watchers.debounce_delay|
1457+
When this is exceeded a warning notification will be shown and the file system
1458+
watcher disabled for the directory.
1459+
This has been observed when running on Windows PowerShell.
1460+
Consider adding this directory to |filesystem_watchers.ignore_dirs|
1461+
Type: `number`, Default: `100`
1462+
14531463
*nvim-tree.filesystem_watchers.ignore_dirs*
14541464
List of vim regex for absolute directory paths that will not be watched or
14551465
function returning whether a path should be ignored.
@@ -3203,6 +3213,7 @@ highlight group is not, hard linking as follows: >
32033213
|nvim-tree.filesystem_watchers.debounce_delay|
32043214
|nvim-tree.filesystem_watchers.enable|
32053215
|nvim-tree.filesystem_watchers.ignore_dirs|
3216+
|nvim-tree.filesystem_watchers.max_outstanding_events|
32063217
|nvim-tree.filters.custom|
32073218
|nvim-tree.filters.dotfiles|
32083219
|nvim-tree.filters.enable|

lua/nvim-tree.lua

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -444,6 +444,7 @@ local DEFAULT_OPTS = { -- BEGIN_DEFAULT_OPTS
444444
filesystem_watchers = {
445445
enable = true,
446446
debounce_delay = 50,
447+
max_outstanding_events = 100,
447448
ignore_dirs = {
448449
"/.ccls-cache",
449450
"/build",

lua/nvim-tree/explorer/watch.lua

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
local log = require("nvim-tree.log")
22
local git = require("nvim-tree.git")
33
local utils = require("nvim-tree.utils")
4+
local notify = require("nvim-tree.notify")
45
local Watcher = require("nvim-tree.watcher").Watcher
56

67
local M = {
@@ -69,10 +70,30 @@ function M.create_watcher(node)
6970
---@param watcher Watcher
7071
local function callback(watcher)
7172
log.line("watcher", "node event scheduled refresh %s", watcher.data.context)
73+
74+
-- event is awaiting debouncing and handling
75+
watcher.data.outstanding_events = watcher.data.outstanding_events + 1
76+
77+
-- disable watcher when outstanding exceeds max
78+
if watcher.data.outstanding_events > M.config.filesystem_watchers.max_outstanding_events then
79+
notify.error(string.format(
80+
"Observed %d consecutive file system events with interval < %dms, exceeding filesystem_watchers.max_events=%s. Disabling watcher for directory '%s'. Consider adding this directory to filesystem_watchers.ignore_dirs",
81+
watcher.data.outstanding_events,
82+
M.config.filesystem_watchers.max_outstanding_events,
83+
M.config.filesystem_watchers.debounce_delay,
84+
node.absolute_path
85+
))
86+
node:destroy_watcher()
87+
end
88+
7289
utils.debounce(watcher.data.context, M.config.filesystem_watchers.debounce_delay, function()
7390
if watcher.destroyed then
7491
return
7592
end
93+
94+
-- event has been handled
95+
watcher.data.outstanding_events = 0
96+
7697
if node.link_to then
7798
log.line("watcher", "node event executing refresh '%s' -> '%s'", node.link_to, node.absolute_path)
7899
else
@@ -87,7 +108,8 @@ function M.create_watcher(node)
87108
path = path,
88109
callback = callback,
89110
data = {
90-
context = "explorer:watch:" .. path .. ":" .. M.uid
111+
context = "explorer:watch:" .. path .. ":" .. M.uid,
112+
outstanding_events = 0, -- unprocessed events that have not been debounced
91113
}
92114
})
93115
end

lua/nvim-tree/node/directory.lua

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,7 @@ function DirectoryNode:new(args)
3636
end
3737

3838
function DirectoryNode:destroy()
39-
if self.watcher then
40-
self.watcher:destroy()
41-
self.watcher = nil
42-
end
39+
self:destroy_watcher()
4340

4441
if self.nodes then
4542
for _, node in pairs(self.nodes) do
@@ -50,6 +47,14 @@ function DirectoryNode:destroy()
5047
Node.destroy(self)
5148
end
5249

50+
---Halt and remove the watcher for this node
51+
function DirectoryNode:destroy_watcher()
52+
if self.watcher then
53+
self.watcher:destroy()
54+
self.watcher = nil
55+
end
56+
end
57+
5358
---Update the git_status of the directory
5459
---@param parent_ignored boolean
5560
---@param project GitProject?

0 commit comments

Comments
 (0)