Skip to content

Commit 40b3432

Browse files
committed
refactor(#2875): multi instance renderer
1 parent cd9c6db commit 40b3432

File tree

2 files changed

+105
-105
lines changed

2 files changed

+105
-105
lines changed

lua/nvim-tree/renderer/builder.lua

+100-100
Original file line numberDiff line numberDiff line change
@@ -15,45 +15,90 @@ local DecoratorOpened = require "nvim-tree.renderer.decorator.opened"
1515
local pad = require "nvim-tree.renderer.components.padding"
1616
local icons = require "nvim-tree.renderer.components.icons"
1717

18-
local M = {
19-
opts = {},
20-
decorators = {},
21-
picture_map = {
22-
jpg = true,
23-
jpeg = true,
24-
png = true,
25-
gif = true,
26-
webp = true,
27-
jxl = true,
28-
},
18+
local PICTURE_MAP = {
19+
jpg = true,
20+
jpeg = true,
21+
png = true,
22+
gif = true,
23+
webp = true,
24+
jxl = true,
2925
}
3026

31-
---@class HighlightedString
27+
---@class (exact) HighlightedString
3228
---@field str string
3329
---@field hl string[]
3430

35-
---@class AddHighlightArgs
31+
---@class (exact) AddHighlightArgs
3632
---@field group string[]
3733
---@field line number
3834
---@field col_start number
3935
---@field col_end number
4036

41-
---@class Builder
37+
---@class (exact) Builder
4238
---@field lines string[] includes icons etc.
4339
---@field hl_args AddHighlightArgs[] line highlights
4440
---@field signs string[] line signs
4541
---@field extmarks table[] extra marks for right icon placement
4642
---@field virtual_lines table[] virtual lines for hidden count display
47-
---@field private root_cwd string absolute path
43+
---@field private explorer Explorer
44+
---@field private root_cwd string|nil absolute path
4845
---@field private index number
4946
---@field private depth number
5047
---@field private combined_groups table<string, boolean> combined group names
5148
---@field private markers boolean[] indent markers
49+
---@field private decorators Decorator[]
50+
---@field private hidden_display fun(node: Node): string|nil
5251
local Builder = {}
5352

53+
---@param opts table
54+
---@return fun(node: Node): string|nil
55+
local setup_hidden_display_function = function(opts)
56+
local hidden_display = opts.renderer.hidden_display
57+
-- options are already validated, so ´hidden_display´ can ONLY be `string` or `function` if type(hidden_display) == "string" then
58+
if type(hidden_display) == "string" then
59+
if hidden_display == "none" then
60+
return function()
61+
return nil
62+
end
63+
elseif hidden_display == "simple" then
64+
return function(hidden_stats)
65+
return utils.default_format_hidden_count(hidden_stats, true)
66+
end
67+
else -- "all"
68+
return function(hidden_stats)
69+
return utils.default_format_hidden_count(hidden_stats, false)
70+
end
71+
end
72+
else -- "function
73+
return function(hidden_stats)
74+
-- In case of missing field such as live_filter we zero it, otherwise keep field as is
75+
hidden_stats = vim.tbl_deep_extend("force", {
76+
live_filter = 0,
77+
git = 0,
78+
buf = 0,
79+
dotfile = 0,
80+
custom = 0,
81+
bookmark = 0,
82+
}, hidden_stats or {})
83+
84+
local ok, result = pcall(hidden_display, hidden_stats)
85+
if not ok then
86+
notify.warn "Problem occurred in the function ``opts.renderer.hidden_display`` see nvim-tree.renderer.hidden_display on :h nvim-tree"
87+
return nil
88+
end
89+
return result
90+
end
91+
end
92+
end
93+
94+
---@param opts table user options
95+
---@param explorer Explorer
5496
---@return Builder
55-
function Builder:new()
97+
function Builder:new(opts, explorer)
98+
---@type Builder
5699
local o = {
100+
opts = opts,
101+
explorer = explorer,
57102
root_cwd = core.get_cwd(),
58103
index = 0,
59104
depth = 0,
@@ -64,9 +109,21 @@ function Builder:new()
64109
signs = {},
65110
extmarks = {},
66111
virtual_lines = {},
112+
decorators = {
113+
-- priority order
114+
DecoratorCut:new(opts),
115+
DecoratorCopied:new(opts),
116+
DecoratorDiagnostics:new(opts),
117+
DecoratorBookmarks:new(opts),
118+
DecoratorModified:new(opts),
119+
DecoratorHidden:new(opts),
120+
DecoratorOpened:new(opts),
121+
DecoratorGit:new(opts),
122+
},
123+
hidden_display = setup_hidden_display_function(opts),
67124
}
68-
setmetatable(o, self)
69-
self.__index = self
125+
126+
setmetatable(o, { __index = self })
70127

71128
return o
72129
end
@@ -89,16 +146,16 @@ function Builder:get_folder_name(node)
89146
next = next.group_next
90147
end
91148

92-
if node.group_next and type(M.opts.renderer.group_empty) == "function" then
93-
local new_name = M.opts.renderer.group_empty(name)
149+
if node.group_next and type(self.opts.renderer.group_empty) == "function" then
150+
local new_name = self.opts.renderer.group_empty(name)
94151
if type(new_name) == "string" then
95152
name = new_name
96153
else
97154
notify.warn(string.format("Invalid return type for field renderer.group_empty. Expected string, got %s", type(new_name)))
98155
end
99156
end
100157

101-
return string.format("%s%s", name, M.opts.renderer.add_trailing and "/" or "")
158+
return string.format("%s%s", name, self.opts.renderer.add_trailing and "/" or "")
102159
end
103160

104161
---@private
@@ -139,13 +196,13 @@ function Builder:build_folder(node)
139196
end
140197

141198
local foldername_hl = "NvimTreeFolderName"
142-
if node.link_to and M.opts.renderer.symlink_destination then
199+
if node.link_to and self.opts.renderer.symlink_destination then
143200
local arrow = icons.i.symlink_arrow
144201
local link_to = utils.path_relative(node.link_to, self.root_cwd)
145202
foldername = string.format("%s%s%s", foldername, arrow, link_to)
146203
foldername_hl = "NvimTreeSymlinkFolderName"
147204
elseif
148-
vim.tbl_contains(M.opts.renderer.special_files, node.absolute_path) or vim.tbl_contains(M.opts.renderer.special_files, node.name)
205+
vim.tbl_contains(self.opts.renderer.special_files, node.absolute_path) or vim.tbl_contains(self.opts.renderer.special_files, node.name)
149206
then
150207
foldername_hl = "NvimTreeSpecialFolderName"
151208
elseif node.open then
@@ -165,7 +222,7 @@ function Builder:build_symlink(node)
165222
local icon = icons.i.symlink
166223
local arrow = icons.i.symlink_arrow
167224
local symlink_formatted = node.name
168-
if M.opts.renderer.symlink_destination then
225+
if self.opts.renderer.symlink_destination then
169226
local link_to = utils.path_relative(node.link_to, self.root_cwd)
170227
symlink_formatted = string.format("%s%s%s", symlink_formatted, arrow, link_to)
171228
end
@@ -179,11 +236,13 @@ end
179236
---@return HighlightedString name
180237
function Builder:build_file(node)
181238
local hl
182-
if vim.tbl_contains(M.opts.renderer.special_files, node.absolute_path) or vim.tbl_contains(M.opts.renderer.special_files, node.name) then
239+
if
240+
vim.tbl_contains(self.opts.renderer.special_files, node.absolute_path) or vim.tbl_contains(self.opts.renderer.special_files, node.name)
241+
then
183242
hl = "NvimTreeSpecialFile"
184243
elseif node.executable then
185244
hl = "NvimTreeExecFile"
186-
elseif M.picture_map[node.extension] then
245+
elseif PICTURE_MAP[node.extension] then
187246
hl = "NvimTreeImageFile"
188247
end
189248

@@ -206,7 +265,7 @@ function Builder:format_line(indent_markers, arrows, icon, name, node)
206265
end
207266
for _, v in ipairs(t2) do
208267
if added_len > 0 then
209-
table.insert(t1, { str = M.opts.renderer.icons.padding })
268+
table.insert(t1, { str = self.opts.renderer.icons.padding })
210269
end
211270
table.insert(t1, v)
212271
end
@@ -222,19 +281,19 @@ function Builder:format_line(indent_markers, arrows, icon, name, node)
222281
local line = { indent_markers, arrows }
223282
add_to_end(line, { icon })
224283

225-
for i = #M.decorators, 1, -1 do
226-
add_to_end(line, M.decorators[i]:icons_before(node))
284+
for i = #self.decorators, 1, -1 do
285+
add_to_end(line, self.decorators[i]:icons_before(node))
227286
end
228287

229288
add_to_end(line, { name })
230289

231-
for i = #M.decorators, 1, -1 do
232-
add_to_end(line, M.decorators[i]:icons_after(node))
290+
for i = #self.decorators, 1, -1 do
291+
add_to_end(line, self.decorators[i]:icons_after(node))
233292
end
234293

235294
local rights = {}
236-
for i = #M.decorators, 1, -1 do
237-
add_to_end(rights, M.decorators[i]:icons_right_align(node))
295+
for i = #self.decorators, 1, -1 do
296+
add_to_end(rights, self.decorators[i]:icons_right_align(node))
238297
end
239298
if #rights > 0 then
240299
self.extmarks[self.index] = rights
@@ -248,7 +307,7 @@ end
248307
function Builder:build_signs(node)
249308
-- first in priority order
250309
local sign_name
251-
for _, d in ipairs(M.decorators) do
310+
for _, d in ipairs(self.decorators) do
252311
sign_name = d:sign_name(node)
253312
if sign_name then
254313
self.signs[self.index] = sign_name
@@ -300,8 +359,8 @@ function Builder:add_highlights(node)
300359
local icon_groups = {}
301360
local name_groups = {}
302361
local d, icon, name
303-
for i = #M.decorators, 1, -1 do
304-
d = M.decorators[i]
362+
for i = #self.decorators, 1, -1 do
363+
d = self.decorators[i]
305364
icon, name = d:groups_icon_name(node)
306365
table.insert(icon_groups, icon)
307366
table.insert(name_groups, name)
@@ -366,10 +425,10 @@ function Builder:add_hidden_count_string(node, idx, num_children)
366425
if not node.open then
367426
return
368427
end
369-
local hidden_count_string = M.opts.renderer.hidden_display(node.hidden_stats)
428+
local hidden_count_string = self.hidden_display(node.hidden_stats)
370429
if hidden_count_string and hidden_count_string ~= "" then
371430
local indent_markers = pad.get_indent_markers(self.depth, idx or 0, num_children or 0, node, self.markers, 1)
372-
local indent_width = M.opts.renderer.indent_width
431+
local indent_width = self.opts.renderer.indent_width
373432

374433
local indent_padding = string.rep(" ", indent_width)
375434
local indent_string = indent_padding .. indent_markers.str
@@ -438,16 +497,16 @@ end
438497
function Builder:build_header()
439498
local explorer = core.get_explorer()
440499
if view.is_root_folder_visible(core.get_cwd()) then
441-
local root_name = self:format_root_name(M.opts.renderer.root_folder_label)
500+
local root_name = self:format_root_name(self.opts.renderer.root_folder_label)
442501
table.insert(self.lines, root_name)
443502
self:insert_highlight({ "NvimTreeRootFolder" }, 0, string.len(root_name))
444503
self.index = 1
445504
end
446505

447506
if explorer and explorer.live_filter.filter then
448-
local filter_line = string.format("%s/%s/", M.opts.live_filter.prefix, explorer.live_filter.filter)
507+
local filter_line = string.format("%s/%s/", self.opts.live_filter.prefix, explorer.live_filter.filter)
449508
table.insert(self.lines, filter_line)
450-
local prefix_length = string.len(M.opts.live_filter.prefix)
509+
local prefix_length = string.len(self.opts.live_filter.prefix)
451510
self:insert_highlight({ "NvimTreeLiveFilterPrefix" }, 0, prefix_length)
452511
self:insert_highlight({ "NvimTreeLiveFilterValue" }, prefix_length, string.len(filter_line))
453512
self.index = self.index + 1
@@ -472,63 +531,4 @@ function Builder:build()
472531
return self
473532
end
474533

475-
---@param opts table
476-
local setup_hidden_display_function = function(opts)
477-
local hidden_display = opts.renderer.hidden_display
478-
-- options are already validated, so ´hidden_display´ can ONLY be `string` or `function` if type(hidden_display) == "string" then
479-
if type(hidden_display) == "string" then
480-
if hidden_display == "none" then
481-
opts.renderer.hidden_display = function()
482-
return nil
483-
end
484-
elseif hidden_display == "simple" then
485-
opts.renderer.hidden_display = function(hidden_stats)
486-
return utils.default_format_hidden_count(hidden_stats, true)
487-
end
488-
elseif hidden_display == "all" then
489-
opts.renderer.hidden_display = function(hidden_stats)
490-
return utils.default_format_hidden_count(hidden_stats, false)
491-
end
492-
end
493-
elseif type(hidden_display) == "function" then
494-
local safe_render = function(hidden_stats)
495-
-- In case of missing field such as live_filter we zero it, otherwise keep field as is
496-
hidden_stats = vim.tbl_deep_extend("force", {
497-
live_filter = 0,
498-
git = 0,
499-
buf = 0,
500-
dotfile = 0,
501-
custom = 0,
502-
bookmark = 0,
503-
}, hidden_stats or {})
504-
505-
local ok, result = pcall(hidden_display, hidden_stats)
506-
if not ok then
507-
notify.warn "Problem occurred in the function ``opts.renderer.hidden_display`` see nvim-tree.renderer.hidden_display on :h nvim-tree"
508-
return nil
509-
end
510-
return result
511-
end
512-
513-
opts.renderer.hidden_display = safe_render
514-
end
515-
end
516-
517-
function Builder.setup(opts)
518-
setup_hidden_display_function(opts)
519-
M.opts = opts
520-
521-
-- priority order
522-
M.decorators = {
523-
DecoratorCut:new(opts),
524-
DecoratorCopied:new(opts),
525-
DecoratorDiagnostics:new(opts),
526-
DecoratorBookmarks:new(opts),
527-
DecoratorModified:new(opts),
528-
DecoratorHidden:new(opts),
529-
DecoratorOpened:new(opts),
530-
DecoratorGit:new(opts),
531-
}
532-
end
533-
534534
return Builder

lua/nvim-tree/renderer/init.lua

+5-5
Original file line numberDiff line numberDiff line change
@@ -77,8 +77,10 @@ function M.render_hl(bufnr, hl)
7777
end
7878

7979
function M.draw()
80+
local explorer = core.get_explorer()
81+
8082
local bufnr = view.get_bufnr()
81-
if not core.get_explorer() or not bufnr or not vim.api.nvim_buf_is_loaded(bufnr) then
83+
if not explorer or not bufnr or not vim.api.nvim_buf_is_loaded(bufnr) then
8284
return
8385
end
8486

@@ -87,7 +89,7 @@ function M.draw()
8789
local cursor = vim.api.nvim_win_get_cursor(view.get_winnr() or 0)
8890
icon_component.reset_config()
8991

90-
local builder = Builder:new():build()
92+
local builder = Builder:new(M.opts, explorer):build()
9193

9294
_draw(bufnr, builder.lines, builder.hl_args, builder.signs, builder.extmarks, builder.virtual_lines)
9395

@@ -103,13 +105,11 @@ function M.draw()
103105
end
104106

105107
function M.setup(opts)
106-
M.config = opts.renderer
108+
M.opts = opts
107109

108110
_padding.setup(opts)
109111
full_name.setup(opts)
110112
icon_component.setup(opts)
111-
112-
Builder.setup(opts)
113113
end
114114

115115
return M

0 commit comments

Comments
 (0)