Skip to content

Commit 6305335

Browse files
committed
factories for all nodes, add RootNode
1 parent 0a8849f commit 6305335

File tree

8 files changed

+111
-75
lines changed

8 files changed

+111
-75
lines changed

lua/nvim-tree/core.lua

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ function M.init(foldername)
1515
if TreeExplorer then
1616
TreeExplorer:destroy()
1717
end
18-
TreeExplorer = require("nvim-tree.explorer"):new(foldername)
18+
TreeExplorer = require("nvim-tree.explorer"):create(foldername)
1919
if not first_init_done then
2020
events._dispatch_ready()
2121
first_init_done = true

lua/nvim-tree/explorer/init.lua

+18-21
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,7 @@ local utils = require "nvim-tree.utils"
55
local view = require "nvim-tree.view"
66
local node_factory = require "nvim-tree.node.factory"
77

8-
local BaseNode = require "nvim-tree.node"
9-
local DirectoryNode = require "nvim-tree.node.directory"
8+
local RootNode = require "nvim-tree.node.root"
109
local Watcher = require "nvim-tree.watcher"
1110

1211
local Iterator = require "nvim-tree.iterators.node-iterator"
@@ -23,19 +22,20 @@ local FILTER_REASON = require("nvim-tree.enum").FILTER_REASON
2322

2423
local config
2524

26-
---@class (exact) Explorer: DirectoryNode
25+
---@class (exact) Explorer: RootNode
2726
---@field opts table user options
2827
---@field renderer Renderer
2928
---@field filters Filters
3029
---@field live_filter LiveFilter
3130
---@field sorters Sorter
3231
---@field marks Marks
3332
---@field clipboard Clipboard
34-
local Explorer = BaseNode.new(DirectoryNode) -- TODO do not inherit, add a root node to separate Explorer and Node
33+
local Explorer = RootNode:new()
3534

36-
---@param path string|nil
37-
---@return Explorer|nil
38-
function Explorer:new(path)
35+
---Static factory method
36+
---@param path string?
37+
---@return Explorer?
38+
function Explorer:create(path)
3939
local err
4040

4141
if path then
@@ -45,19 +45,19 @@ function Explorer:new(path)
4545
end
4646
if not path then
4747
notify.error(err)
48-
return
48+
return nil
4949
end
5050

5151
---@type Explorer
52-
local placeholder = nil
52+
local explorer_placeholder
5353

54-
local o = DirectoryNode.new(self, placeholder, nil, path, "..", nil)
55-
---@cast o Explorer
54+
local o = RootNode.create(self, explorer_placeholder, path, "..", nil) --[[@as Explorer]]
5655

5756
o.explorer = o
58-
o.open = true
5957

58+
o.open = true
6059
o.opts = config
60+
6161
o.sorters = Sorters:new(config)
6262
o.renderer = Renderer:new(config, o)
6363
o.filters = Filters:new(config, o)
@@ -121,7 +121,7 @@ function Explorer:reload(node, git_status)
121121
})
122122

123123
while true do
124-
local name, _ = vim.loop.fs_scandir_next(handle)
124+
local name, t = vim.loop.fs_scandir_next(handle)
125125
if not name then
126126
break
127127
end
@@ -134,22 +134,19 @@ function Explorer:reload(node, git_status)
134134
if filter_reason == FILTER_REASON.none then
135135
remain_childs[abs] = true
136136

137-
-- Type must come from fs_stat and not fs_scandir_next to maintain sshfs compatibility
138-
local type = stat and stat.type or nil
139-
140137
-- Recreate node if type changes.
141138
if nodes_by_path[abs] then
142139
local n = nodes_by_path[abs]
143140

144-
if n.type ~= type then
141+
if n.type ~= t then
145142
utils.array_remove(node.nodes, n)
146143
n:destroy()
147144
nodes_by_path[abs] = nil
148145
end
149146
end
150147

151148
if not nodes_by_path[abs] then
152-
local new_child = node_factory.create_node(self, node, abs, stat, name)
149+
local new_child = node_factory.create_node(self, node, abs, t, stat, name)
153150
if new_child then
154151
table.insert(node.nodes, new_child)
155152
nodes_by_path[abs] = new_child
@@ -340,21 +337,21 @@ function Explorer:populate_children(handle, cwd, node, git_status, parent)
340337
})
341338

342339
while true do
343-
local name, _ = vim.loop.fs_scandir_next(handle)
340+
local name, t = vim.loop.fs_scandir_next(handle)
344341
if not name then
345342
break
346343
end
347344

348345
local abs = utils.path_join { cwd, name }
349346

350347
if Watcher.is_fs_event_capable(abs) then
351-
local profile = log.profile_start("populate_children %s", abs)
348+
local profile = log.profile_start("explore populate_children %s", abs)
352349

353350
---@type uv.fs_stat.result|nil
354351
local stat = vim.loop.fs_stat(abs)
355352
local filter_reason = parent.filters:should_filter_as_reason(abs, stat, filter_status)
356353
if filter_reason == FILTER_REASON.none and not nodes_by_path[abs] then
357-
local child = node_factory.create_node(self, node, abs, stat, name)
354+
local child = node_factory.create_node(self, node, abs, t, stat, name)
358355
if child then
359356
table.insert(node.nodes, child)
360357
nodes_by_path[child.absolute_path] = true

lua/nvim-tree/node/directory.lua

+15-9
Original file line numberDiff line numberDiff line change
@@ -3,40 +3,46 @@ local watch = require "nvim-tree.explorer.watch"
33
local BaseNode = require "nvim-tree.node"
44

55
---@class (exact) DirectoryNode: BaseNode
6-
---@field has_children boolean -- TODO remove this and just test nodes
7-
---@field group_next Node|nil -- If node is grouped, this points to the next child dir/link node
6+
---@field has_children boolean
7+
---@field group_next Node? -- If node is grouped, this points to the next child dir/link node
88
---@field nodes Node[]
99
---@field open boolean
10-
---@field hidden_stats table -- Each field of this table is a key for source and value for count
10+
---@field hidden_stats table? -- Each field of this table is a key for source and value for count
1111
local DirectoryNode = BaseNode:new()
1212

13+
---Static factory method
1314
---@param explorer Explorer
14-
-----@param parent DirectoryNode -- TODO #2871 #2886
15+
---@param parent Node?
1516
---@param absolute_path string
1617
---@param name string
1718
---@param fs_stat uv.fs_stat.result|nil
1819
---@return DirectoryNode
19-
function DirectoryNode:new(explorer, parent, absolute_path, name, fs_stat)
20+
function DirectoryNode:create(explorer, parent, absolute_path, name, fs_stat)
2021
local handle = vim.loop.fs_scandir(absolute_path)
21-
local has_children = handle and vim.loop.fs_scandir_next(handle) ~= nil
22+
local has_children = handle and vim.loop.fs_scandir_next(handle) ~= nil or false
2223

23-
local o = BaseNode.new(self, {
24+
---@type DirectoryNode
25+
local o = {
2426
type = "directory",
2527
explorer = explorer,
2628
absolute_path = absolute_path,
2729
executable = false,
2830
fs_stat = fs_stat,
31+
git_status = nil,
2932
hidden = false,
3033
is_dot = false,
3134
name = name,
3235
parent = parent,
36+
watcher = nil,
37+
diag_status = nil,
3338

3439
has_children = has_children,
3540
group_next = nil,
3641
nodes = {},
3742
open = false,
38-
})
39-
---@cast o DirectoryNode
43+
hidden_stats = nil,
44+
}
45+
o = self:new(o) --[[@as DirectoryNode]]
4046

4147
o.watcher = watch.create_watcher(o)
4248

lua/nvim-tree/node/factory.lua

+12-13
Original file line numberDiff line numberDiff line change
@@ -5,26 +5,25 @@ local Watcher = require "nvim-tree.watcher"
55

66
local M = {}
77

8+
---Factory function to create the appropriate Node
89
---@param explorer Explorer
9-
-----@param parent DirectoryNode -- TODO #2871 #2886
10+
---@param parent Node
1011
---@param abs string
11-
---@param stat uv.fs_stat.result|nil
12+
---@param t string? type from vim.loop.fs_scandir_next as stat.type is incorrectly reported as a file for links
13+
---@param stat uv.fs_stat.result?
1214
---@param name string
13-
---@return Node|nil
14-
function M.create_node(explorer, parent, abs, stat, name)
15+
---@return Node?
16+
function M.create_node(explorer, parent, abs, t, stat, name)
1517
if not stat then
1618
return nil
1719
end
1820

19-
if stat.type == "directory" and vim.loop.fs_access(abs, "R") and Watcher.is_fs_event_capable(abs) then
20-
return DirectoryNode:new(explorer, parent, abs, name, stat)
21-
elseif stat.type == "file" then
22-
return FileNode:new(explorer, parent, abs, name, stat)
23-
elseif stat.type == "link" then
24-
local link = LinkNode:new(explorer, parent, abs, name, stat)
25-
if link.link_to ~= nil then
26-
return link
27-
end
21+
if t == "directory" and vim.loop.fs_access(abs, "R") and Watcher.is_fs_event_capable(abs) then
22+
return DirectoryNode:create(explorer, parent, abs, name, stat)
23+
elseif t == "file" then
24+
return FileNode:create(explorer, parent, abs, name, stat)
25+
elseif t == "link" then
26+
return LinkNode:create(explorer, parent, abs, name, stat)
2827
end
2928

3029
return nil

lua/nvim-tree/node/file.lua

+13-8
Original file line numberDiff line numberDiff line change
@@ -6,27 +6,32 @@ local BaseNode = require "nvim-tree.node"
66
---@field extension string
77
local FileNode = BaseNode:new()
88

9+
---Static factory method
910
---@param explorer Explorer
10-
-----@param parent DirectoryNode -- TODO #2871 #2886
11+
---@param parent Node
1112
---@param absolute_path string
1213
---@param name string
13-
---@param fs_stat uv.fs_stat.result|nil
14+
---@param fs_stat uv.fs_stat.result?
1415
---@return FileNode
15-
function FileNode:new(explorer, parent, absolute_path, name, fs_stat)
16-
local o = BaseNode.new(self, {
16+
function FileNode:create(explorer, parent, absolute_path, name, fs_stat)
17+
---@type FileNode
18+
local o = {
1719
type = "file",
1820
explorer = explorer,
1921
absolute_path = absolute_path,
2022
executable = utils.is_executable(absolute_path),
2123
fs_stat = fs_stat,
22-
name = name,
23-
parent = parent,
24+
git_status = nil,
2425
hidden = false,
2526
is_dot = false,
27+
name = name,
28+
parent = parent,
29+
watcher = nil,
30+
diag_status = nil,
2631

2732
extension = string.match(name, ".?[^.]+%.(.*)") or "",
28-
})
29-
---@cast o FileNode
33+
}
34+
o = self:new(o) --[[@as FileNode]]
3035

3136
return o
3237
end

lua/nvim-tree/node/init.lua

+8-6
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,24 @@
11
local git = require "nvim-tree.git"
22

3+
---Abstract Node class.
4+
---Uses the abstract factory pattern to instantiate child instances.
35
---@class (exact) BaseNode
46
---@field private __index? table
57
---@field type NODE_TYPE
68
---@field explorer Explorer
79
---@field absolute_path string
810
---@field executable boolean
9-
---@field fs_stat uv.fs_stat.result|nil
10-
---@field git_status GitStatus|nil
11+
---@field fs_stat uv.fs_stat.result?
12+
---@field git_status GitStatus?
1113
---@field hidden boolean
1214
---@field is_dot boolean
1315
---@field name string
14-
---@field parent DirectoryNode|nil
15-
---@field watcher Watcher|nil
16-
---@field diag_status DiagStatus|nil
16+
---@field parent Node?
17+
---@field watcher Watcher?
18+
---@field diag_status DiagStatus?
1719
local BaseNode = {}
1820

19-
---@alias Node BaseNode|DirectoryNode|FileNode|LinkNode
21+
---@alias Node RootNode|BaseNode|DirectoryNode|FileNode|LinkNode
2022

2123
---@param o BaseNode|nil
2224
---@return BaseNode

lua/nvim-tree/node/link.lua

+24-17
Original file line numberDiff line numberDiff line change
@@ -3,36 +3,42 @@ local watch = require "nvim-tree.explorer.watch"
33
local BaseNode = require "nvim-tree.node"
44

55
---@class (exact) LinkNode: BaseNode
6-
---@field has_children boolean -- TODO remove this and just test nodes
7-
---@field group_next Node|nil -- If node is grouped, this points to the next child dir/link node
6+
---@field has_children boolean
7+
---@field group_next Node? -- If node is grouped, this points to the next child dir/link node
88
---@field link_to string absolute path
9+
---@field nodes Node[]
10+
---@field open boolean
911
local LinkNode = BaseNode:new()
1012

13+
---Static factory method
1114
---@param explorer Explorer
12-
-----@param parent DirectoryNode -- TODO #2871 #2886
15+
---@param parent Node
1316
---@param absolute_path string
1417
---@param name string
15-
---@param fs_stat uv.fs_stat.result|nil
16-
---@return LinkNode
17-
function LinkNode:new(explorer, parent, absolute_path, name, fs_stat)
18-
local link_to = vim.loop.fs_realpath(absolute_path)
19-
local open, nodes, has_children
20-
21-
-- TODO-INFO: sometimes fs_realpath returns nil
18+
---@param fs_stat uv.fs_stat.result?
19+
---@return LinkNode? nil on vim.loop.fs_realpath failure
20+
function LinkNode:create(explorer, parent, absolute_path, name, fs_stat)
21+
-- INFO: sometimes fs_realpath returns nil
2222
-- I expect this be a bug in glibc, because it fails to retrieve the path for some
2323
-- links (for instance libr2.so in /usr/lib) and thus even with a C program realpath fails
2424
-- when it has no real reason to. Maybe there is a reason, but errno is definitely wrong.
25-
-- So we need to check for link_to ~= nil when adding new links to the main tree
25+
local link_to = vim.loop.fs_realpath(absolute_path)
26+
if not link_to then
27+
return nil
28+
end
29+
30+
local open, nodes, has_children
2631
local is_dir_link = (link_to ~= nil) and vim.loop.fs_stat(link_to).type == "directory"
2732

2833
if is_dir_link and link_to then
2934
local handle = vim.loop.fs_scandir(link_to)
30-
has_children = handle and vim.loop.fs_scandir_next(handle) ~= nil
35+
has_children = handle and vim.loop.fs_scandir_next(handle) ~= nil or false
3136
open = false
3237
nodes = {}
3338
end
3439

35-
local o = BaseNode.new(self, {
40+
---@type LinkNode
41+
local o = {
3642
type = "link",
3743
explorer = explorer,
3844
absolute_path = absolute_path,
@@ -42,15 +48,16 @@ function LinkNode:new(explorer, parent, absolute_path, name, fs_stat)
4248
is_dot = false,
4349
name = name,
4450
parent = parent,
45-
46-
link_to = link_to,
51+
watcher = nil,
52+
diag_status = nil,
4753

4854
has_children = has_children,
4955
group_next = nil,
56+
link_to = link_to,
5057
nodes = nodes,
5158
open = open,
52-
})
53-
---@cast o LinkNode
59+
}
60+
o = self:new(o) --[[@as LinkNode]]
5461

5562
if is_dir_link then
5663
o.watcher = watch.create_watcher(o)

lua/nvim-tree/node/root.lua

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
local DirectoryNode = require "nvim-tree.node.directory"
2+
3+
---@class (exact) RootNode: DirectoryNode
4+
local RootNode = DirectoryNode:new()
5+
6+
---Static factory method
7+
---@param explorer Explorer
8+
---@param absolute_path string
9+
---@param name string
10+
---@param fs_stat uv.fs_stat.result|nil
11+
---@return RootNode
12+
function RootNode:create(explorer, absolute_path, name, fs_stat)
13+
local o = DirectoryNode:create(explorer, nil, absolute_path, name, fs_stat)
14+
15+
o = self:new(o) --[[@as RootNode]]
16+
17+
return o
18+
end
19+
20+
return RootNode

0 commit comments

Comments
 (0)