Skip to content

Commit b17358f

Browse files
authored
fix(#1731 #1723 #1716): handle all external file system changes (#1757)
* fix(#1731): watcher refreshes node rather than the first node matching absolute path, profile refresh * fix(#1731): reload explorer reloads closed folders * fix(#1731): do not fire folder created event on file create * fix(#1731): reload profile absolute path, not link to * fix(#1731): find-file locks/profiles on real path, reloads when watchers disabled * Revert "fix(#1731): reload explorer reloads closed folders" This reverts commit 5dfd8bd. * fix(#1731): tidy watch reload * fix(#1731): move refresh_node from watch to reload * fix(#1731): find-file reloads all nodes for the containing directory * fix(#1731): create-file refreshes synchronously * fix(#1731): remove unused watch node * fix(#1731): find-file refreshes root * fix(#1716): create-file invokes find-file * fix(#1731): refresh path walks down the tree to the targedt
1 parent 99d7136 commit b17358f

File tree

6 files changed

+128
-60
lines changed

6 files changed

+128
-60
lines changed

lua/nvim-tree/actions/finders/find-file.lua

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ local view = require "nvim-tree.view"
33
local utils = require "nvim-tree.utils"
44
local renderer = require "nvim-tree.renderer"
55
local core = require "nvim-tree.core"
6+
local reload = require "nvim-tree.explorer.reload"
67
local Iterator = require "nvim-tree.iterators.node-iterator"
78

89
local M = {}
@@ -12,18 +13,26 @@ local running = {}
1213
---Find a path in the tree, expand it and focus it
1314
---@param fname string full path
1415
function M.fn(fname)
15-
if running[fname] or not core.get_explorer() then
16+
if not core.get_explorer() then
1617
return
1718
end
18-
running[fname] = true
1919

20-
local ps = log.profile_start("find file %s", fname)
2120
-- always match against the real path
2221
local fname_real = vim.loop.fs_realpath(fname)
2322
if not fname_real then
2423
return
2524
end
2625

26+
if running[fname_real] then
27+
return
28+
end
29+
running[fname_real] = true
30+
31+
local ps = log.profile_start("find file %s", fname_real)
32+
33+
-- we cannot wait for watchers
34+
reload.refresh_nodes_for_path(vim.fn.fnamemodify(fname_real, ":h"))
35+
2736
local line = core.get_nodes_starting_line()
2837

2938
local absolute_paths_searched = {}
@@ -60,9 +69,9 @@ function M.fn(fname)
6069
view.set_cursor { line, 0 }
6170
end
6271

63-
running[fname] = false
72+
running[fname_real] = false
6473

65-
log.profile_end(ps, "find file %s", fname)
74+
log.profile_end(ps, "find file %s", fname_real)
6675
end
6776

6877
return M

lua/nvim-tree/actions/fs/create-file.lua

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,10 @@ local utils = require "nvim-tree.utils"
22
local events = require "nvim-tree.events"
33
local lib = require "nvim-tree.lib"
44
local core = require "nvim-tree.core"
5-
local watch = require "nvim-tree.explorer.watch"
65
local notify = require "nvim-tree.notify"
76

7+
local find_file = require("nvim-tree.actions.finders.find-file").fn
8+
89
local M = {}
910

1011
local function create_and_notify(file)
@@ -99,22 +100,15 @@ function M.fn(node)
99100
is_error = true
100101
break
101102
end
103+
events._dispatch_folder_created(new_file_path)
102104
end
103105
end
104106
if not is_error then
105107
notify.info(new_file_path .. " was properly created")
106108
end
107-
events._dispatch_folder_created(new_file_path)
108-
if M.enable_reload then
109-
require("nvim-tree.actions.reloaders.reloaders").reload_explorer()
110-
else
111-
-- synchronous call required so that we may focus the file now
112-
node = node.nodes ~= nil and node or node.parent
113-
if node then
114-
watch.refresh_path(node.absolute_path)
115-
end
116-
end
117-
utils.focus_file(utils.path_remove_trailing(new_file_path))
109+
110+
-- synchronously refreshes as we can't wait for the watchers
111+
find_file(utils.path_remove_trailing(new_file_path))
118112
end)
119113
end
120114

lua/nvim-tree/explorer/init.lua

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,9 @@ function Explorer.new(cwd)
1515
local explorer = setmetatable({
1616
absolute_path = cwd,
1717
nodes = {},
18-
watcher = watch.create_watcher(cwd),
1918
open = true,
2019
}, Explorer)
20+
explorer.watcher = watch.create_watcher(explorer)
2121
explorer:_load(explorer)
2222
return explorer
2323
end

lua/nvim-tree/explorer/node-builders.lua

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ function M.folder(parent, absolute_path, name)
1010
local handle = vim.loop.fs_scandir(absolute_path)
1111
local has_children = handle and vim.loop.fs_scandir_next(handle) ~= nil
1212

13-
return {
13+
local node = {
1414
type = "directory",
1515
absolute_path = absolute_path,
1616
fs_stat = vim.loop.fs_stat(absolute_path),
@@ -20,8 +20,11 @@ function M.folder(parent, absolute_path, name)
2020
nodes = {},
2121
open = false,
2222
parent = parent,
23-
watcher = watch.create_watcher(absolute_path),
2423
}
24+
25+
node.watcher = watch.create_watcher(node)
26+
27+
return node
2528
end
2629

2730
function M.is_executable(parent, absolute_path, ext)
@@ -63,16 +66,18 @@ end
6366
function M.link(parent, absolute_path, name)
6467
--- I dont know if this is needed, because in my understanding, there isn't hard links in windows, but just to be sure i changed it.
6568
local link_to = vim.loop.fs_realpath(absolute_path)
66-
local open, nodes, has_children, watcher
67-
if (link_to ~= nil) and vim.loop.fs_stat(link_to).type == "directory" then
69+
local open, nodes, has_children
70+
71+
local is_dir_link = (link_to ~= nil) and vim.loop.fs_stat(link_to).type == "directory"
72+
73+
if is_dir_link then
6874
local handle = vim.loop.fs_scandir(link_to)
6975
has_children = handle and vim.loop.fs_scandir_next(handle) ~= nil
7076
open = false
7177
nodes = {}
72-
watcher = watch.create_watcher(link_to)
7378
end
7479

75-
return {
80+
local node = {
7681
type = "link",
7782
absolute_path = absolute_path,
7883
fs_stat = vim.loop.fs_stat(absolute_path),
@@ -83,8 +88,13 @@ function M.link(parent, absolute_path, name)
8388
nodes = nodes,
8489
open = open,
8590
parent = parent,
86-
watcher = watcher,
8791
}
92+
93+
if is_dir_link then
94+
node.watcher = watch.create_watcher(node)
95+
end
96+
97+
return node
8898
end
8999

90100
return M

lua/nvim-tree/explorer/reload.lua

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@ local filters = require "nvim-tree.explorer.filters"
55
local sorters = require "nvim-tree.explorer.sorters"
66
local live_filter = require "nvim-tree.live-filter"
77
local notify = require "nvim-tree.notify"
8+
local git = require "nvim-tree.git"
9+
local log = require "nvim-tree.log"
10+
11+
local NodeIterator = require "nvim-tree.iterators.node-iterator"
812

913
local M = {}
1014

@@ -17,6 +21,19 @@ local function update_status(nodes_by_path, node_ignored, status)
1721
end
1822
end
1923

24+
local function reload_and_get_git_project(path)
25+
local project_root = git.get_project_root(path)
26+
git.reload_project(project_root, path)
27+
return project_root, git.get_project(project_root) or {}
28+
end
29+
30+
local function update_parent_statuses(node, project, root)
31+
while project and node and node.absolute_path ~= root do
32+
common.update_git_status(node, false, project)
33+
node = node.parent
34+
end
35+
end
36+
2037
function M.reload(node, status)
2138
local cwd = node.link_to or node.absolute_path
2239
local handle = vim.loop.fs_scandir(cwd)
@@ -25,6 +42,8 @@ function M.reload(node, status)
2542
return
2643
end
2744

45+
local ps = log.profile_start("reload %s", node.absolute_path)
46+
2847
if node.group_next then
2948
node.nodes = { node.group_next }
3049
node.group_next = nil
@@ -110,14 +129,65 @@ function M.reload(node, status)
110129
node.group_next = child_folder_only
111130
local ns = M.reload(child_folder_only, status)
112131
node.nodes = ns or {}
132+
log.profile_end(ps, "reload %s", node.absolute_path)
113133
return ns
114134
end
115135

116136
sorters.merge_sort(node.nodes, sorters.node_comparator)
117137
live_filter.apply_filter(node)
138+
log.profile_end(ps, "reload %s", node.absolute_path)
118139
return node.nodes
119140
end
120141

142+
---Refresh contents and git status for a single node
143+
---@param node table
144+
function M.refresh_node(node)
145+
if type(node) ~= "table" then
146+
return
147+
end
148+
149+
local parent_node = utils.get_parent_of_group(node)
150+
151+
local project_root, project = reload_and_get_git_project(node.absolute_path)
152+
153+
require("nvim-tree.explorer.reload").reload(parent_node, project)
154+
155+
update_parent_statuses(parent_node, project, project_root)
156+
end
157+
158+
---Refresh contents and git status for all nodes to a path: actual directory and links
159+
---@param path string absolute path
160+
function M.refresh_nodes_for_path(path)
161+
local explorer = require("nvim-tree.core").get_explorer()
162+
if not explorer then
163+
return
164+
end
165+
166+
local pn = string.format("refresh_nodes_for_path %s", path)
167+
local ps = log.profile_start(pn)
168+
169+
NodeIterator.builder({ explorer })
170+
:hidden()
171+
:recursor(function(node)
172+
if node.group_next then
173+
return { node.group_next }
174+
end
175+
if node.nodes then
176+
return node.nodes
177+
end
178+
end)
179+
:applier(function(node)
180+
local abs_contains = node.absolute_path and path:match("^" .. node.absolute_path)
181+
local link_contains = node.link_to and path:match("^" .. node.link_to)
182+
if abs_contains or link_contains then
183+
M.refresh_node(node)
184+
end
185+
end)
186+
:iterate()
187+
188+
log.profile_end(ps, pn)
189+
end
190+
121191
function M.setup(opts)
122192
M.config = opts.renderer
123193
end

lua/nvim-tree/explorer/watch.lua

Lines changed: 20 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,9 @@
11
local log = require "nvim-tree.log"
22
local utils = require "nvim-tree.utils"
3-
local git = require "nvim-tree.git"
43
local Watcher = require("nvim-tree.watcher").Watcher
54

65
local M = {}
76

8-
local function reload_and_get_git_project(path)
9-
local project_root = git.get_project_root(path)
10-
git.reload_project(project_root, path)
11-
return project_root, git.get_project(project_root) or {}
12-
end
13-
14-
local function update_parent_statuses(node, project, root)
15-
while project and node and node.absolute_path ~= root do
16-
require("nvim-tree.explorer.common").update_git_status(node, false, project)
17-
node = node.parent
18-
end
19-
end
20-
217
local function is_git(path)
228
return vim.fn.fnamemodify(path, ":t") == ".git"
239
end
@@ -46,39 +32,38 @@ local function is_folder_ignored(path)
4632
return false
4733
end
4834

49-
function M.refresh_path(path)
50-
log.line("watcher", "node event executing '%s'", path)
51-
local n = utils.get_node_from_path(path)
52-
if not n then
53-
return
35+
function M.create_watcher(node)
36+
if not M.enabled or type(node) ~= "table" then
37+
return nil
5438
end
5539

56-
local node = utils.get_parent_of_group(n)
57-
local project_root, project = reload_and_get_git_project(path)
58-
require("nvim-tree.explorer.reload").reload(node, project)
59-
update_parent_statuses(node, project, project_root)
60-
61-
require("nvim-tree.renderer").draw()
62-
end
63-
64-
function M.create_watcher(absolute_path)
65-
if not M.enabled then
66-
return nil
40+
local path
41+
if node.type == "link" then
42+
path = node.link_to
43+
else
44+
path = node.absolute_path
6745
end
68-
if is_git(absolute_path) or is_folder_ignored(absolute_path) then
46+
47+
if is_git(path) or is_folder_ignored(path) then
6948
return nil
7049
end
7150

7251
local function callback(watcher)
73-
log.line("watcher", "node event scheduled %s", watcher.context)
52+
log.line("watcher", "node event scheduled refresh %s", watcher.context)
7453
utils.debounce(watcher.context, M.debounce_delay, function()
75-
M.refresh_path(watcher._path)
54+
if node.link_to then
55+
log.line("watcher", "node event executing refresh '%s' -> '%s'", node.link_to, node.absolute_path)
56+
else
57+
log.line("watcher", "node event executing refresh '%s'", node.absolute_path)
58+
end
59+
require("nvim-tree.explorer.reload").refresh_node(node)
60+
require("nvim-tree.renderer").draw()
7661
end)
7762
end
7863

7964
M.uid = M.uid + 1
80-
return Watcher:new(absolute_path, nil, callback, {
81-
context = "explorer:watch:" .. absolute_path .. ":" .. M.uid,
65+
return Watcher:new(path, nil, callback, {
66+
context = "explorer:watch:" .. path .. ":" .. M.uid,
8267
})
8368
end
8469

0 commit comments

Comments
 (0)