From 0ee55d0077c972da1678829fed3468539dd2878d Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Mon, 12 Jun 2023 16:50:24 +1000 Subject: [PATCH 1/2] fix(#2240): disable watchers following EMFILE --- lua/nvim-tree.lua | 60 ++++++++++++++---------- lua/nvim-tree/actions/fs/copy-paste.lua | 12 +++-- lua/nvim-tree/actions/fs/create-file.lua | 4 -- lua/nvim-tree/actions/fs/remove-file.lua | 15 +++--- lua/nvim-tree/actions/fs/rename-file.lua | 8 ++-- lua/nvim-tree/actions/fs/trash.lua | 15 +++--- lua/nvim-tree/actions/init.lua | 1 - lua/nvim-tree/explorer/watch.lua | 15 +++--- lua/nvim-tree/marks/bulk-move.lua | 8 ++-- lua/nvim-tree/watcher.lua | 25 ++++++++-- 10 files changed, 98 insertions(+), 65 deletions(-) diff --git a/lua/nvim-tree.lua b/lua/nvim-tree.lua index ae02eba0a44..78827835762 100644 --- a/lua/nvim-tree.lua +++ b/lua/nvim-tree.lua @@ -201,11 +201,14 @@ local function setup_autocommands(opts) end, }) - local has_watchers = opts.filesystem_watchers.enable - - if opts.auto_reload_on_write and not has_watchers then - create_nvim_tree_autocmd("BufWritePost", { callback = reloaders.reload_explorer }) - end + create_nvim_tree_autocmd("BufWritePost", { + callback = function() + if opts.auto_reload_on_write and not opts.filesystem_watchers.enable then + log.line("dev", "BufWritePost reloading") + reloaders.reload_explorer() + end + end, + }) create_nvim_tree_autocmd("BufReadPost", { callback = function(data) @@ -235,12 +238,14 @@ local function setup_autocommands(opts) end, }) - if not has_watchers and opts.git.enable then - create_nvim_tree_autocmd("User", { - pattern = { "FugitiveChanged", "NeogitStatusRefreshed" }, - callback = reloaders.reload_git, - }) - end + create_nvim_tree_autocmd("User", { + pattern = { "FugitiveChanged", "NeogitStatusRefreshed" }, + callback = function() + if not opts.filesystem_watchers.enable and opts.git.enable then + reloaders.reload_git() + end + end, + }) if opts.tab.sync.open then create_nvim_tree_autocmd("TabEnter", { callback = vim.schedule_wrap(M.tab_enter) }) @@ -276,16 +281,16 @@ local function setup_autocommands(opts) create_nvim_tree_autocmd({ "BufEnter", "BufNewFile" }, { callback = M.open_on_directory }) end - if opts.reload_on_bufenter and not has_watchers then - create_nvim_tree_autocmd("BufEnter", { - pattern = "NvimTree_*", - callback = function() + create_nvim_tree_autocmd("BufEnter", { + pattern = "NvimTree_*", + callback = function() + if opts.reload_on_bufenter and not opts.filesystem_watchers.enable then if utils.is_nvim_tree_buf(0) then reloaders.reload_explorer() end - end, - }) - end + end + end, + }) if opts.view.centralize_selection then create_nvim_tree_autocmd("BufEnter", { @@ -639,6 +644,16 @@ local function validate_options(conf) end end +function M.purge_all_state() + require("nvim-tree.watcher").purge_watchers() + view.close_all_tabs() + view.abandon_all_windows() + if core.get_explorer() ~= nil then + git.purge_state() + TreeExplorer = nil + end +end + function M.setup(conf) if vim.fn.has "nvim-0.8" == 0 then vim.notify_once("nvim-tree.lua requires Neovim 0.8 or higher", vim.log.levels.WARN) @@ -687,6 +702,7 @@ function M.setup(conf) require("nvim-tree.marks").setup(opts) require("nvim-tree.modified").setup(opts) require("nvim-tree.help").setup(opts) + require("nvim-tree.watcher").setup(opts) if M.config.renderer.icons.show.file and pcall(require, "nvim-web-devicons") then require("nvim-web-devicons").setup() end @@ -698,13 +714,7 @@ function M.setup(conf) commands.setup() else -- subsequent calls to setup - require("nvim-tree.watcher").purge_watchers() - view.close_all_tabs() - view.abandon_all_windows() - if core.get_explorer() ~= nil then - git.purge_state() - TreeExplorer = nil - end + M.purge_all_state() end vim.g.NvimTreeSetup = 1 diff --git a/lua/nvim-tree/actions/fs/copy-paste.lua b/lua/nvim-tree/actions/fs/copy-paste.lua index 79a8f7fa4a9..c59114f80a1 100644 --- a/lua/nvim-tree/actions/fs/copy-paste.lua +++ b/lua/nvim-tree/actions/fs/copy-paste.lua @@ -7,7 +7,9 @@ local notify = require "nvim-tree.notify" local find_file = require("nvim-tree.actions.finders.find-file").fn -local M = {} +local M = { + config = {} +} local clipboard = { move = {}, @@ -175,7 +177,7 @@ local function do_paste(node, action_type, action_fn) end clipboard[action_type] = {} - if M.enable_reload then + if not M.config.filesystem_watchers.enable then return require("nvim-tree.actions.reloaders.reloaders").reload_explorer() end end @@ -226,7 +228,7 @@ function M.print_clipboard() end local function copy_to_clipboard(content) - if M.use_system_clipboard == true then + if M.config.actions.use_system_clipboard == true then vim.fn.setreg("+", content) vim.fn.setreg('"', content) return notify.info(string.format("Copied %s to system clipboard!", content)) @@ -255,8 +257,8 @@ function M.copy_absolute_path(node) end function M.setup(opts) - M.use_system_clipboard = opts.actions.use_system_clipboard - M.enable_reload = not opts.filesystem_watchers.enable + M.config.filesystem_watchers = opts.filesystem_watchers + M.config.actions = opts.actions end return M diff --git a/lua/nvim-tree/actions/fs/create-file.lua b/lua/nvim-tree/actions/fs/create-file.lua index cd0a83800f1..74f4ff37565 100644 --- a/lua/nvim-tree/actions/fs/create-file.lua +++ b/lua/nvim-tree/actions/fs/create-file.lua @@ -96,8 +96,4 @@ function M.fn(node) end) end -function M.setup(opts) - M.enable_reload = not opts.filesystem_watchers.enable -end - return M diff --git a/lua/nvim-tree/actions/fs/remove-file.lua b/lua/nvim-tree/actions/fs/remove-file.lua index 9acf6c516b0..5cf8d1c447e 100644 --- a/lua/nvim-tree/actions/fs/remove-file.lua +++ b/lua/nvim-tree/actions/fs/remove-file.lua @@ -4,7 +4,9 @@ local view = require "nvim-tree.view" local lib = require "nvim-tree.lib" local notify = require "nvim-tree.notify" -local M = {} +local M = { + config = {} +} local function close_windows(windows) if view.View.float.enable and #vim.api.nvim_list_wins() == 1 then @@ -31,7 +33,7 @@ local function clear_buffer(absolute_path) end end vim.api.nvim_buf_delete(buf.bufnr, { force = true }) - if M.close_window then + if M.config.actions.remove_file.close_window then close_windows(buf.windows) end return @@ -90,7 +92,7 @@ function M.fn(node) clear_buffer(node.absolute_path) end notify.info(node.absolute_path .. " was properly removed.") - if M.enable_reload then + if not M.config.filesystem_watchers.enable then require("nvim-tree.actions.reloaders.reloaders").reload_explorer() end end @@ -110,10 +112,9 @@ function M.fn(node) end function M.setup(opts) - M.config = {} - M.config.ui = opts.ui or {} - M.enable_reload = not opts.filesystem_watchers.enable - M.close_window = opts.actions.remove_file.close_window + M.config.ui = opts.ui + M.config.actions = opts.actions + M.config.filesystem_watchers = opts.filesystem_watchers end return M diff --git a/lua/nvim-tree/actions/fs/rename-file.lua b/lua/nvim-tree/actions/fs/rename-file.lua index fd6ad85b13a..11fbe2ce50b 100644 --- a/lua/nvim-tree/actions/fs/rename-file.lua +++ b/lua/nvim-tree/actions/fs/rename-file.lua @@ -5,7 +5,9 @@ local notify = require "nvim-tree.notify" local find_file = require("nvim-tree.actions.finders.find-file").fn -local M = {} +local M = { + config = {} +} local ALLOWED_MODIFIERS = { [":p:h"] = true, @@ -83,7 +85,7 @@ function M.fn(default_modifier) end M.rename(node, prepend .. new_file_path .. append) - if M.enable_reload then + if not M.config.filesystem_watchers.enable then require("nvim-tree.actions.reloaders.reloaders").reload_explorer() end @@ -93,7 +95,7 @@ function M.fn(default_modifier) end function M.setup(opts) - M.enable_reload = not opts.filesystem_watchers.enable + M.config.filesystem_watchers = opts.filesystem_watchers end return M diff --git a/lua/nvim-tree/actions/fs/trash.lua b/lua/nvim-tree/actions/fs/trash.lua index ea38511a843..b208e2d7aab 100644 --- a/lua/nvim-tree/actions/fs/trash.lua +++ b/lua/nvim-tree/actions/fs/trash.lua @@ -1,7 +1,9 @@ local lib = require "nvim-tree.lib" local notify = require "nvim-tree.notify" -local M = {} +local M = { + config = {} +} local utils = require "nvim-tree.utils" local events = require "nvim-tree.events" @@ -68,7 +70,7 @@ function M.fn(node) return end events._dispatch_folder_removed(node.absolute_path) - if M.enable_reload then + if not M.config.filesystem_watchers.enable then require("nvim-tree.actions.reloaders.reloaders").reload_explorer() end end) @@ -80,7 +82,7 @@ function M.fn(node) end events._dispatch_file_removed(node.absolute_path) clear_buffer(node.absolute_path) - if M.enable_reload then + if not M.config.filesystem_watchers.enable then require("nvim-tree.actions.reloaders.reloaders").reload_explorer() end end) @@ -102,10 +104,9 @@ function M.fn(node) end function M.setup(opts) - M.config = {} - M.config.ui = opts.ui or {} - M.config.trash = opts.trash or {} - M.enable_reload = not opts.filesystem_watchers.enable + M.config.ui = opts.ui + M.config.trash = opts.trash + M.config.filesystem_watchers = opts.filesystem_watchers end return M diff --git a/lua/nvim-tree/actions/init.lua b/lua/nvim-tree/actions/init.lua index a2798b5aec3..d845296a9d4 100644 --- a/lua/nvim-tree/actions/init.lua +++ b/lua/nvim-tree/actions/init.lua @@ -6,7 +6,6 @@ function M.setup(opts) require("nvim-tree.actions.node.file-popup").setup(opts) require("nvim-tree.actions.node.open-file").setup(opts) require("nvim-tree.actions.root.change-dir").setup(opts) - require("nvim-tree.actions.fs.create-file").setup(opts) require("nvim-tree.actions.fs.rename-file").setup(opts) require("nvim-tree.actions.fs.remove-file").setup(opts) require("nvim-tree.actions.fs.copy-paste").setup(opts) diff --git a/lua/nvim-tree/explorer/watch.lua b/lua/nvim-tree/explorer/watch.lua index 50afb5a3da8..dad1738c4f5 100644 --- a/lua/nvim-tree/explorer/watch.lua +++ b/lua/nvim-tree/explorer/watch.lua @@ -2,7 +2,10 @@ local log = require "nvim-tree.log" local utils = require "nvim-tree.utils" local Watcher = require("nvim-tree.watcher").Watcher -local M = {} +local M = { + config = {}, + uid = 0, +} local function is_git(path) return vim.fn.fnamemodify(path, ":t") == ".git" @@ -23,7 +26,7 @@ local function is_folder_ignored(path) end end - for _, ignore_dir in ipairs(M.ignore_dirs) do + for _, ignore_dir in ipairs(M.config.filesystem_watchers.ignore_dirs) do if vim.fn.match(path, ignore_dir) ~= -1 then return true end @@ -33,7 +36,7 @@ local function is_folder_ignored(path) end function M.create_watcher(node) - if not M.enabled or type(node) ~= "table" then + if not M.config.filesystem_watchers.enable or type(node) ~= "table" then return nil end @@ -50,7 +53,7 @@ function M.create_watcher(node) local function callback(watcher) log.line("watcher", "node event scheduled refresh %s", watcher.context) - utils.debounce(watcher.context, M.debounce_delay, function() + utils.debounce(watcher.context, M.config.filesystem_watchers.debounce_delay, function() if watcher.destroyed then return end @@ -72,9 +75,7 @@ function M.create_watcher(node) end function M.setup(opts) - M.enabled = opts.filesystem_watchers.enable - M.debounce_delay = opts.filesystem_watchers.debounce_delay - M.ignore_dirs = opts.filesystem_watchers.ignore_dirs + M.config.filesystem_watchers = opts.filesystem_watchers M.uid = 0 end diff --git a/lua/nvim-tree/marks/bulk-move.lua b/lua/nvim-tree/marks/bulk-move.lua index ee0e2e8b2ac..9384c21f7f6 100644 --- a/lua/nvim-tree/marks/bulk-move.lua +++ b/lua/nvim-tree/marks/bulk-move.lua @@ -4,7 +4,9 @@ local utils = require "nvim-tree.utils" local FsRename = require "nvim-tree.actions.fs.rename-file" local notify = require "nvim-tree.notify" -local M = {} +local M = { + config = {}, +} function M.bulk_move() if #Marks.get_marks() == 0 then @@ -29,14 +31,14 @@ function M.bulk_move() FsRename.rename(node, to) end - if M.enable_reload then + if not M.config.filesystem_watchers.enable then require("nvim-tree.actions.reloaders.reloaders").reload_explorer() end end) end function M.setup(opts) - M.enable_reload = not opts.filesystem_watchers.enable + M.config.filesystem_watchers = opts.filesystem_watchers end return M diff --git a/lua/nvim-tree/watcher.lua b/lua/nvim-tree/watcher.lua index 26f463eb955..7dd00529aac 100644 --- a/lua/nvim-tree/watcher.lua +++ b/lua/nvim-tree/watcher.lua @@ -1,9 +1,10 @@ local notify = require "nvim-tree.notify" - local log = require "nvim-tree.log" local utils = require "nvim-tree.utils" -local M = {} +local M = { + config = {} +} local Event = { _events = {}, @@ -72,7 +73,12 @@ function Event:start() rc, _, name = self._fs_event:start(self._path, FS_EVENT_FLAGS, event_cb) if rc ~= 0 then - notify.warn(string.format("Could not start the fs_event watcher for path %s : %s", self._path, name)) + local warning = string.format("Could not start the fs_event watcher for path %s : %s", self._path, name) + if name == "EMFILE" then + M.disable_watchers(warning, "Please see https://github.com/nvim-tree/nvim-tree.lua/wiki/Troubleshooting#could-not-start-fs_event-for-path--emfile") + else + notify.warn(warning) + end return false end @@ -154,6 +160,15 @@ end M.Watcher = Watcher +--- Permanently disable watchers and purge all state following a catastrophic error. +--- @param warning string +--- @param detail string +function M.disable_watchers(warning, detail) + notify.warn(string.format("%s Disabling watchers: %s", warning, detail)) + M.config.filesystem_watchers.enable = false + require("nvim-tree").purge_all_state() +end + function M.purge_watchers() log.line("watcher", "purge_watchers") @@ -191,4 +206,8 @@ function M.is_fs_event_capable(path) return true end +function M.setup(opts) + M.config.filesystem_watchers = opts.filesystem_watchers +end + return M From 03d5c01956a2d9e12d50d73a2de5fc85da7c79cc Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Mon, 12 Jun 2023 16:53:51 +1000 Subject: [PATCH 2/2] fix(#2240): disable watchers following EMFILE --- lua/nvim-tree/actions/fs/copy-paste.lua | 2 +- lua/nvim-tree/actions/fs/remove-file.lua | 2 +- lua/nvim-tree/actions/fs/rename-file.lua | 2 +- lua/nvim-tree/actions/fs/trash.lua | 2 +- lua/nvim-tree/watcher.lua | 7 +++++-- 5 files changed, 9 insertions(+), 6 deletions(-) diff --git a/lua/nvim-tree/actions/fs/copy-paste.lua b/lua/nvim-tree/actions/fs/copy-paste.lua index c59114f80a1..406272913d9 100644 --- a/lua/nvim-tree/actions/fs/copy-paste.lua +++ b/lua/nvim-tree/actions/fs/copy-paste.lua @@ -8,7 +8,7 @@ local notify = require "nvim-tree.notify" local find_file = require("nvim-tree.actions.finders.find-file").fn local M = { - config = {} + config = {}, } local clipboard = { diff --git a/lua/nvim-tree/actions/fs/remove-file.lua b/lua/nvim-tree/actions/fs/remove-file.lua index 5cf8d1c447e..6b91b1df0a2 100644 --- a/lua/nvim-tree/actions/fs/remove-file.lua +++ b/lua/nvim-tree/actions/fs/remove-file.lua @@ -5,7 +5,7 @@ local lib = require "nvim-tree.lib" local notify = require "nvim-tree.notify" local M = { - config = {} + config = {}, } local function close_windows(windows) diff --git a/lua/nvim-tree/actions/fs/rename-file.lua b/lua/nvim-tree/actions/fs/rename-file.lua index 11fbe2ce50b..9e686e41dab 100644 --- a/lua/nvim-tree/actions/fs/rename-file.lua +++ b/lua/nvim-tree/actions/fs/rename-file.lua @@ -6,7 +6,7 @@ local notify = require "nvim-tree.notify" local find_file = require("nvim-tree.actions.finders.find-file").fn local M = { - config = {} + config = {}, } local ALLOWED_MODIFIERS = { diff --git a/lua/nvim-tree/actions/fs/trash.lua b/lua/nvim-tree/actions/fs/trash.lua index b208e2d7aab..137468ce8e7 100644 --- a/lua/nvim-tree/actions/fs/trash.lua +++ b/lua/nvim-tree/actions/fs/trash.lua @@ -2,7 +2,7 @@ local lib = require "nvim-tree.lib" local notify = require "nvim-tree.notify" local M = { - config = {} + config = {}, } local utils = require "nvim-tree.utils" diff --git a/lua/nvim-tree/watcher.lua b/lua/nvim-tree/watcher.lua index 7dd00529aac..efa5246963e 100644 --- a/lua/nvim-tree/watcher.lua +++ b/lua/nvim-tree/watcher.lua @@ -3,7 +3,7 @@ local log = require "nvim-tree.log" local utils = require "nvim-tree.utils" local M = { - config = {} + config = {}, } local Event = { @@ -75,7 +75,10 @@ function Event:start() if rc ~= 0 then local warning = string.format("Could not start the fs_event watcher for path %s : %s", self._path, name) if name == "EMFILE" then - M.disable_watchers(warning, "Please see https://github.com/nvim-tree/nvim-tree.lua/wiki/Troubleshooting#could-not-start-fs_event-for-path--emfile") + M.disable_watchers( + warning, + "Please see https://github.com/nvim-tree/nvim-tree.lua/wiki/Troubleshooting#could-not-start-fs_event-for-path--emfile" + ) else notify.warn(warning) end