Skip to content

Commit 98ca98c

Browse files
committed
refactor(#2886): multi instance: node class refactoring: extract links, *_git_status (#2944)
* extract DirectoryLinkNode and FileLinkNode, move Node methods to children * temporarily move DirectoryNode methods into BaseNode for easier reviewing * move mostly unchanged DirectoryNode methods back to BaseNode * tidy * git.git_status_file takes an array * update git status of links * luacheck hack
1 parent 8859bbb commit 98ca98c

File tree

9 files changed

+256
-184
lines changed

9 files changed

+256
-184
lines changed

lua/nvim-tree/git/init.lua

+22-9
Original file line numberDiff line numberDiff line change
@@ -283,33 +283,46 @@ function M.load_project_status(path)
283283
end
284284
end
285285

286+
---Git file and directory status for an absolute path with optional file fallback
286287
---@param parent_ignored boolean
287288
---@param status table|nil
288-
---@param absolute_path string
289+
---@param path string
290+
---@param path_file string? alternative file path when no other file status
289291
---@return GitStatus|nil
290-
function M.git_status_dir(parent_ignored, status, absolute_path)
292+
function M.git_status_dir(parent_ignored, status, path, path_file)
291293
if parent_ignored then
292294
return { file = "!!" }
293295
end
294296

295297
if status then
296298
return {
297-
file = status.files and status.files[absolute_path],
299+
file = status.files and status.files[path] or path_file and status.files[path_file],
298300
dir = status.dirs and {
299-
direct = status.dirs.direct[absolute_path],
300-
indirect = status.dirs.indirect[absolute_path],
301+
direct = status.dirs.direct[path],
302+
indirect = status.dirs.indirect[path],
301303
},
302304
}
303305
end
304306
end
305307

308+
---Git file status for an absolute path with optional fallback
306309
---@param parent_ignored boolean
307310
---@param status table|nil
308-
---@param absolute_path string
311+
---@param path string
312+
---@param path_fallback string?
309313
---@return GitStatus
310-
function M.git_status_file(parent_ignored, status, absolute_path)
311-
local file_status = parent_ignored and "!!" or (status and status.files and status.files[absolute_path])
312-
return { file = file_status }
314+
function M.git_status_file(parent_ignored, status, path, path_fallback)
315+
if parent_ignored then
316+
return { file = "!!" }
317+
end
318+
319+
if not status or not status.files then
320+
return {}
321+
end
322+
323+
return {
324+
file = status.files[path] or status.files[path_fallback]
325+
}
313326
end
314327

315328
function M.purge_state()

lua/nvim-tree/log.lua

+19
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,25 @@ function M.raw(typ, fmt, ...)
2121
end
2222
end
2323

24+
--- Write to a new file
25+
---@param typ string as per log.types config
26+
---@param path string absolute path
27+
---@param fmt string for string.format
28+
---@param ... any arguments for string.format
29+
function M.file(typ, path, fmt, ...)
30+
if not M.enabled(typ) then
31+
return
32+
end
33+
34+
local line = string.format(fmt, ...)
35+
local file = io.open(path, "w")
36+
if file then
37+
io.output(file)
38+
io.write(line)
39+
io.close(file)
40+
end
41+
end
42+
2443
---@class Profile
2544
---@field start number nanos
2645
---@field tag string

lua/nvim-tree/node/directory-link.lua

+54
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
local git = require("nvim-tree.git")
2+
3+
local DirectoryNode = require("nvim-tree.node.directory")
4+
5+
---@class (exact) DirectoryLinkNode: DirectoryNode
6+
---@field link_to string absolute path
7+
---@field fs_stat_target uv.fs_stat.result
8+
local DirectoryLinkNode = DirectoryNode:new()
9+
10+
---Static factory method
11+
---@param explorer Explorer
12+
---@param parent Node
13+
---@param absolute_path string
14+
---@param link_to string
15+
---@param name string
16+
---@param fs_stat uv.fs_stat.result?
17+
---@param fs_stat_target uv.fs_stat.result
18+
---@return DirectoryLinkNode? nil on vim.loop.fs_realpath failure
19+
function DirectoryLinkNode:create(explorer, parent, absolute_path, link_to, name, fs_stat, fs_stat_target)
20+
-- create DirectoryNode with the target path for the watcher
21+
local o = DirectoryNode:create(explorer, parent, link_to, name, fs_stat)
22+
23+
o = self:new(o) --[[@as DirectoryLinkNode]]
24+
25+
-- reset absolute path to the link itself
26+
o.absolute_path = absolute_path
27+
28+
o.type = "link"
29+
o.link_to = link_to
30+
o.fs_stat_target = fs_stat_target
31+
32+
return o
33+
end
34+
35+
-----Update the directory GitStatus of link target and the file status of the link itself
36+
-----@param parent_ignored boolean
37+
-----@param status table|nil
38+
function DirectoryLinkNode:update_git_status(parent_ignored, status)
39+
self.git_status = git.git_status_dir(parent_ignored, status, self.link_to, self.absolute_path)
40+
end
41+
42+
---Create a sanitized partial copy of a node, populating children recursively.
43+
---@return DirectoryLinkNode cloned
44+
function DirectoryLinkNode:clone()
45+
local clone = DirectoryNode.clone(self) --[[@as DirectoryLinkNode]]
46+
47+
clone.type = self.type
48+
clone.link_to = self.link_to
49+
clone.fs_stat_target = self.fs_stat_target
50+
51+
return clone
52+
end
53+
54+
return DirectoryLinkNode

lua/nvim-tree/node/directory.lua

+58
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
local git = require("nvim-tree.git")
12
local watch = require("nvim-tree.explorer.watch")
23

34
local BaseNode = require("nvim-tree.node")
@@ -58,6 +59,63 @@ function DirectoryNode:destroy()
5859
end
5960
end
6061

62+
---Update the GitStatus of the directory
63+
---@param parent_ignored boolean
64+
---@param status table|nil
65+
function DirectoryNode:update_git_status(parent_ignored, status)
66+
self.git_status = git.git_status_dir(parent_ignored, status, self.absolute_path, nil)
67+
end
68+
69+
---@return GitStatus|nil
70+
function DirectoryNode:get_git_status()
71+
if not self.git_status or not self.explorer.opts.git.show_on_dirs then
72+
return nil
73+
end
74+
75+
local status = {}
76+
if not self:last_group_node().open or self.explorer.opts.git.show_on_open_dirs then
77+
-- dir is closed or we should show on open_dirs
78+
if self.git_status.file ~= nil then
79+
table.insert(status, self.git_status.file)
80+
end
81+
if self.git_status.dir ~= nil then
82+
if self.git_status.dir.direct ~= nil then
83+
for _, s in pairs(self.git_status.dir.direct) do
84+
table.insert(status, s)
85+
end
86+
end
87+
if self.git_status.dir.indirect ~= nil then
88+
for _, s in pairs(self.git_status.dir.indirect) do
89+
table.insert(status, s)
90+
end
91+
end
92+
end
93+
else
94+
-- dir is open and we shouldn't show on open_dirs
95+
if self.git_status.file ~= nil then
96+
table.insert(status, self.git_status.file)
97+
end
98+
if self.git_status.dir ~= nil and self.git_status.dir.direct ~= nil then
99+
local deleted = {
100+
[" D"] = true,
101+
["D "] = true,
102+
["RD"] = true,
103+
["DD"] = true,
104+
}
105+
for _, s in pairs(self.git_status.dir.direct) do
106+
if deleted[s] then
107+
table.insert(status, s)
108+
end
109+
end
110+
end
111+
end
112+
if #status == 0 then
113+
return nil
114+
else
115+
return status
116+
end
117+
end
118+
61119
---Create a sanitized partial copy of a node, populating children recursively.
62120
---@return DirectoryNode cloned
63121
function DirectoryNode:clone()

lua/nvim-tree/node/factory.lua

+24-7
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1+
local DirectoryLinkNode = require("nvim-tree.node.directory-link")
12
local DirectoryNode = require("nvim-tree.node.directory")
2-
local LinkNode = require("nvim-tree.node.link")
3+
local FileLinkNode = require("nvim-tree.node.file-link")
34
local FileNode = require("nvim-tree.node.file")
45
local Watcher = require("nvim-tree.watcher")
56

@@ -8,21 +9,37 @@ local M = {}
89
---Factory function to create the appropriate Node
910
---@param explorer Explorer
1011
---@param parent Node
11-
---@param abs string
12+
---@param absolute_path string
1213
---@param stat uv.fs_stat.result? -- on nil stat return nil Node
1314
---@param name string
1415
---@return Node?
15-
function M.create_node(explorer, parent, abs, stat, name)
16+
function M.create_node(explorer, parent, absolute_path, stat, name)
1617
if not stat then
1718
return nil
1819
end
1920

20-
if stat.type == "directory" and vim.loop.fs_access(abs, "R") and Watcher.is_fs_event_capable(abs) then
21-
return DirectoryNode:create(explorer, parent, abs, name, stat)
21+
if stat.type == "directory" then
22+
-- directory must be readable and enumerable
23+
if vim.loop.fs_access(absolute_path, "R") and Watcher.is_fs_event_capable(absolute_path) then
24+
return DirectoryNode:create(explorer, parent, absolute_path, name, stat)
25+
end
2226
elseif stat.type == "file" then
23-
return FileNode:create(explorer, parent, abs, name, stat)
27+
-- any file
28+
return FileNode:create(explorer, parent, absolute_path, name, stat)
2429
elseif stat.type == "link" then
25-
return LinkNode:create(explorer, parent, abs, name, stat)
30+
-- link target path and stat must resolve
31+
local link_to = vim.loop.fs_realpath(absolute_path)
32+
local link_to_stat = link_to and vim.loop.fs_stat(link_to)
33+
if not link_to or not link_to_stat then
34+
return
35+
end
36+
37+
-- choose directory or file
38+
if link_to_stat.type == "directory" then
39+
return DirectoryLinkNode:create(explorer, parent, absolute_path, link_to, name, stat, link_to_stat)
40+
else
41+
return FileLinkNode:create(explorer, parent, absolute_path, link_to, name, stat, link_to_stat)
42+
end
2643
end
2744

2845
return nil

lua/nvim-tree/node/file-link.lua

+50
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
local git = require("nvim-tree.git")
2+
3+
local FileNode = require("nvim-tree.node.file")
4+
5+
---@class (exact) FileLinkNode: FileNode
6+
---@field link_to string absolute path
7+
---@field fs_stat_target uv.fs_stat.result
8+
local FileLinkNode = FileNode:new()
9+
10+
---Static factory method
11+
---@param explorer Explorer
12+
---@param parent Node
13+
---@param absolute_path string
14+
---@param link_to string
15+
---@param name string
16+
---@param fs_stat uv.fs_stat.result?
17+
---@param fs_stat_target uv.fs_stat.result
18+
---@return FileLinkNode? nil on vim.loop.fs_realpath failure
19+
function FileLinkNode:create(explorer, parent, absolute_path, link_to, name, fs_stat, fs_stat_target)
20+
local o = FileNode:create(explorer, parent, absolute_path, name, fs_stat)
21+
22+
o = self:new(o) --[[@as FileLinkNode]]
23+
24+
o.type = "link"
25+
o.link_to = link_to
26+
o.fs_stat_target = fs_stat_target
27+
28+
return o
29+
end
30+
31+
-----Update the GitStatus of the target otherwise the link itself
32+
-----@param parent_ignored boolean
33+
-----@param status table|nil
34+
function FileLinkNode:update_git_status(parent_ignored, status)
35+
self.git_status = git.git_status_file(parent_ignored, status, self.link_to, self.absolute_path)
36+
end
37+
38+
---Create a sanitized partial copy of a node
39+
---@return FileLinkNode cloned
40+
function FileLinkNode:clone()
41+
local clone = FileNode.clone(self) --[[@as FileLinkNode]]
42+
43+
clone.type = self.type
44+
clone.link_to = self.link_to
45+
clone.fs_stat_target = self.fs_stat_target
46+
47+
return clone
48+
end
49+
50+
return FileLinkNode

lua/nvim-tree/node/file.lua

+18-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
local git = require("nvim-tree.git")
12
local utils = require("nvim-tree.utils")
23

34
local BaseNode = require("nvim-tree.node")
@@ -36,7 +37,23 @@ function FileNode:create(explorer, parent, absolute_path, name, fs_stat)
3637
return o
3738
end
3839

39-
---Create a sanitized partial copy of a node, populating children recursively.
40+
---Update the GitStatus of the file
41+
---@param parent_ignored boolean
42+
---@param status table|nil
43+
function FileNode:update_git_status(parent_ignored, status)
44+
self.git_status = git.git_status_file(parent_ignored, status, self.absolute_path, nil)
45+
end
46+
47+
---@return GitStatus|nil
48+
function FileNode:get_git_status()
49+
if not self.git_status then
50+
return nil
51+
end
52+
53+
return self.git_status.file and { self.git_status.file }
54+
end
55+
56+
---Create a sanitized partial copy of a node
4057
---@return FileNode cloned
4158
function FileNode:clone()
4259
local clone = BaseNode.clone(self) --[[@as FileNode]]

0 commit comments

Comments
 (0)