diff --git a/lua/nvim-tree/core.lua b/lua/nvim-tree/core.lua index 83f3db92877..a61fea72743 100644 --- a/lua/nvim-tree/core.lua +++ b/lua/nvim-tree/core.lua @@ -10,7 +10,7 @@ local first_init_done = false function M.init(foldername) if TreeExplorer then - TreeExplorer:_clear_watchers() + TreeExplorer:destroy() end TreeExplorer = explorer.Explorer.new(foldername) if not first_init_done then diff --git a/lua/nvim-tree/explorer/common.lua b/lua/nvim-tree/explorer/common.lua index 14cef92b92a..e3c3e76d32a 100644 --- a/lua/nvim-tree/explorer/common.lua +++ b/lua/nvim-tree/explorer/common.lua @@ -43,6 +43,16 @@ function M.update_git_status(node, parent_ignored, status) end end +function M.node_destroy(node) + if not node then + return + end + + if node.watcher then + node.watcher:destroy() + end +end + function M.setup(opts) M.config = { git = opts.git, diff --git a/lua/nvim-tree/explorer/init.lua b/lua/nvim-tree/explorer/init.lua index 5578331f67c..6b9a8c9e5cc 100644 --- a/lua/nvim-tree/explorer/init.lua +++ b/lua/nvim-tree/explorer/init.lua @@ -2,6 +2,7 @@ local uv = vim.loop local git = require "nvim-tree.git" local watch = require "nvim-tree.explorer.watch" +local common = require "nvim-tree.explorer.common" local M = {} @@ -33,22 +34,16 @@ function Explorer:expand(node) self:_load(node) end -function Explorer.clear_watchers_for(root_node) +function Explorer:destroy() local function iterate(node) - if node.watcher then - node.watcher:stop() + common.node_destroy(node) + if node.nodes then for _, child in pairs(node.nodes) do - if child.watcher then - iterate(child) - end + iterate(child) end end end - iterate(root_node) -end - -function Explorer:_clear_watchers() - Explorer.clear_watchers_for(self) + iterate(self) end function M.setup(opts) diff --git a/lua/nvim-tree/explorer/reload.lua b/lua/nvim-tree/explorer/reload.lua index e26a68b0a92..5d9299b7830 100644 --- a/lua/nvim-tree/explorer/reload.lua +++ b/lua/nvim-tree/explorer/reload.lua @@ -69,7 +69,12 @@ function M.reload(node, status) node.nodes = vim.tbl_map( update_status(nodes_by_path, node_ignored, status), vim.tbl_filter(function(n) - return child_names[n.absolute_path] + if child_names[n.absolute_path] then + return child_names[n.absolute_path] + else + common.node_destroy(n) + return nil + end end, node.nodes) ) diff --git a/lua/nvim-tree/explorer/watch.lua b/lua/nvim-tree/explorer/watch.lua index 2243df2ada8..79b50fc57c0 100644 --- a/lua/nvim-tree/explorer/watch.lua +++ b/lua/nvim-tree/explorer/watch.lua @@ -46,7 +46,7 @@ function M.create_watcher(absolute_path) end log.line("watcher", "node start '%s'", absolute_path) - Watcher.new { + return Watcher.new { absolute_path = absolute_path, interval = M.interval, on_event = function(opts) diff --git a/lua/nvim-tree/git/init.lua b/lua/nvim-tree/git/init.lua index c1eb094835e..761677d042e 100644 --- a/lua/nvim-tree/git/init.lua +++ b/lua/nvim-tree/git/init.lua @@ -29,8 +29,8 @@ function M.reload_project(project_root, path) return end - if path and not path:match("^" .. project_root) then - path = nil + if path and path:find(project_root, 1, true) ~= 1 then + return end local git_status = Runner.run { @@ -43,7 +43,7 @@ function M.reload_project(project_root, path) if path then for p in pairs(project.files) do - if p:match("^" .. path) then + if p:find(path, 1, true) == 1 then project.files[p] = nil end end diff --git a/lua/nvim-tree/watcher.lua b/lua/nvim-tree/watcher.lua index 15ebeb90296..3ab7a42d8b2 100644 --- a/lua/nvim-tree/watcher.lua +++ b/lua/nvim-tree/watcher.lua @@ -9,6 +9,13 @@ local M = { local Watcher = {} Watcher.__index = Watcher +local FS_EVENT_FLAGS = { + -- inotify or equivalent will be used; fallback to stat has not yet been implemented + stat = false, + -- recursive is not functional in neovim's libuv implementation + recursive = false, +} + function Watcher.new(opts) for _, existing in ipairs(M._watchers) do if existing._opts.absolute_path == opts.absolute_path then @@ -35,40 +42,47 @@ function Watcher:start() local rc, _, name - self._p, _, name = uv.new_fs_poll() - if not self._p then - self._p = nil + self._e, _, name = uv.new_fs_event() + if not self._e then + self._e = nil utils.warn( - string.format("Could not initialize an fs_poll watcher for path %s : %s", self._opts.absolute_path, name) + string.format("Could not initialize an fs_event watcher for path %s : %s", self._opts.absolute_path, name) ) return nil end - local poll_cb = vim.schedule_wrap(function(err) + local event_cb = vim.schedule_wrap(function(err, filename, events) if err then - log.line("watcher", "poll_cb for %s fail : %s", self._opts.absolute_path, err) + log.line("watcher", "event_cb for %s fail : %s", self._opts.absolute_path, err) else + log.line("watcher", "event_cb '%s' '%s' %s", self._opts.absolute_path, filename, vim.inspect(events)) self._opts.on_event(self._opts) end end) - rc, _, name = uv.fs_poll_start(self._p, self._opts.absolute_path, self._opts.interval, poll_cb) + rc, _, name = self._e:start(self._opts.absolute_path, FS_EVENT_FLAGS, event_cb) if rc ~= 0 then - utils.warn(string.format("Could not start the fs_poll watcher for path %s : %s", self._opts.absolute_path, name)) + utils.warn(string.format("Could not start the fs_event watcher for path %s : %s", self._opts.absolute_path, name)) return nil end return self end -function Watcher:stop() - log.line("watcher", "Watcher:stop '%s'", self._opts.absolute_path) - if self._p then - local rc, _, name = uv.fs_poll_stop(self._p) +function Watcher:destroy() + log.line("watcher", "Watcher:destroy '%s'", self._opts.absolute_path) + if self._e then + local rc, _, name = self._e:stop() if rc ~= 0 then - utils.warn(string.format("Could not stop the fs_poll watcher for path %s : %s", self._opts.absolute_path, name)) + utils.warn(string.format("Could not stop the fs_event watcher for path %s : %s", self._opts.absolute_path, name)) + end + self._e = nil + end + for i, w in ipairs(M._watchers) do + if w == self then + table.remove(M._watchers, i) + break end - self._p = nil end end @@ -76,7 +90,7 @@ M.Watcher = Watcher function M.purge_watchers() for _, watcher in pairs(M._watchers) do - watcher:stop() + watcher:destroy() end M._watchers = {} end