Skip to content

feat(watcher): fs_poll -> fs_event, destroy nodes/watchers #1431

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Jul 17, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion lua/nvim-tree/core.lua
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
10 changes: 10 additions & 0 deletions lua/nvim-tree/explorer/common.lua
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
17 changes: 6 additions & 11 deletions lua/nvim-tree/explorer/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {}

Expand Down Expand Up @@ -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)
Expand Down
7 changes: 6 additions & 1 deletion lua/nvim-tree/explorer/reload.lua
Original file line number Diff line number Diff line change
Expand Up @@ -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)
)

Expand Down
2 changes: 1 addition & 1 deletion lua/nvim-tree/explorer/watch.lua
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ function M.create_watcher(absolute_path)
end

log.line("watcher", "node start '%s'", absolute_path)
Watcher.new {
return Watcher.new {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

whoops

absolute_path = absolute_path,
interval = M.interval,
on_event = function(opts)
Expand Down
6 changes: 3 additions & 3 deletions lua/nvim-tree/git/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -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
Copy link
Member Author

@alex-courtis alex-courtis Jul 17, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was pattern matching the file name 🤦

Resolves #1373 (comment)

return
end

local git_status = Runner.run {
Expand All @@ -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
Expand Down
44 changes: 29 additions & 15 deletions lua/nvim-tree/watcher.lua
Original file line number Diff line number Diff line change
Expand Up @@ -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,
}
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Put this in for documentation purposes.


function Watcher.new(opts)
for _, existing in ipairs(M._watchers) do
if existing._opts.absolute_path == opts.absolute_path then
Expand All @@ -35,48 +42,55 @@ 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

M.Watcher = Watcher

function M.purge_watchers()
for _, watcher in pairs(M._watchers) do
watcher:stop()
watcher:destroy()
end
M._watchers = {}
end
Expand Down