Skip to content

Commit cb351ae

Browse files
committed
feat(#2948): use renderer.decorators to define order and register
1 parent ba296e6 commit cb351ae

File tree

16 files changed

+97
-145
lines changed

16 files changed

+97
-145
lines changed

doc/nvim-tree-lua.txt

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -425,6 +425,7 @@ Following is the default configuration. See |nvim-tree-opts| for details. >lua
425425
special_files = { "Cargo.toml", "Makefile", "README.md", "readme.md" },
426426
hidden_display = "none",
427427
symlink_destination = true,
428+
decorators = { "Git", "Opened", "Hidden", "Modified", "Bookmarks", "Diagnostics", "Copied", "Cut", },
428429
highlight_git = "none",
429430
highlight_diagnostics = "none",
430431
highlight_opened_files = "none",
@@ -842,7 +843,7 @@ Use nvim-tree in a floating window.
842843
==============================================================================
843844
5.3 OPTS: RENDERER *nvim-tree-opts-renderer*
844845

845-
Highlight precedence, additive:
846+
Highlight precedence, additive, change via |nvim-tree.renderer.decorators|
846847
git < opened < modified < bookmarked < diagnostics < copied < cut
847848

848849
*nvim-tree.renderer.add_trailing*
@@ -927,6 +928,22 @@ Show a summary of hidden files below the tree using `NvimTreeHiddenDisplay
927928
Whether to show the destination of the symlink.
928929
Type: `boolean`, Default: `true`
929930

931+
*nvim-tree.renderer.decorators*
932+
Highlighting and icons for the nodes, in increasing order of precedence.
933+
Uses strings to specify builtin decorators otherwise specify your
934+
`nvim_tree.api.decorator.DecoratorUser` class.
935+
Type: `nvim_tree.api.decorator.Name[]`, Default: >lua
936+
{
937+
"Git",
938+
"Opened",
939+
"Hidden",
940+
"Modified",
941+
"Bookmarks",
942+
"Diagnostics",
943+
"Copied",
944+
"Cut",
945+
}
946+
<
930947
*nvim-tree.renderer.highlight_git*
931948
Enable highlight for git attributes using `NvimTreeGit*HL` highlight groups.
932949
Requires |nvim-tree.git.enable|
@@ -996,7 +1013,7 @@ Configuration options for tree indent markers.
9961013
*nvim-tree.renderer.icons*
9971014
Configuration options for icons.
9981015

999-
Icon order and sign column precedence:
1016+
Icon order and sign column precedence, change via |nvim-tree.renderer.decorators|
10001017
git < hidden < modified < bookmarked < diagnostics
10011018

10021019
`renderer.icons.*_placement` options may be:
@@ -2943,6 +2960,7 @@ highlight group is not, hard linking as follows: >
29432960
|nvim-tree.prefer_startup_root|
29442961
|nvim-tree.reload_on_bufenter|
29452962
|nvim-tree.renderer.add_trailing|
2963+
|nvim-tree.renderer.decorators|
29462964
|nvim-tree.renderer.full_name|
29472965
|nvim-tree.renderer.group_empty|
29482966
|nvim-tree.renderer.hidden_display|

lua/nvim-tree.lua

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -284,6 +284,7 @@ local DEFAULT_OPTS = { -- BEGIN_DEFAULT_OPTS
284284
special_files = { "Cargo.toml", "Makefile", "README.md", "readme.md" },
285285
hidden_display = "none",
286286
symlink_destination = true,
287+
decorators = { "Git", "Opened", "Hidden", "Modified", "Bookmarks", "Diagnostics", "Copied", "Cut", },
287288
highlight_git = "none",
288289
highlight_diagnostics = "none",
289290
highlight_opened_files = "none",

lua/nvim-tree/_meta/api_decorator.lua

Lines changed: 18 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,87 +1,87 @@
11
---@meta
22
error("Cannot require a meta file")
33

4-
local nvim_tree = { api = { decorator = { AbstractDecorator = {} } } }
4+
local nvim_tree = { api = { decorator = { DecoratorUser = {} } } }
55

66
---Custom decorator
77
---It may:
88
--- Add icons
99
--- Set highlight group for the name or icons
1010
--- Override node icon
11-
---Class must be created via nvim_tree.api.decorator.create()
11+
---Register it via :help nvim-tree.renderer.decorators
12+
---Create class via require("nvim-tree.api").decorator.DecoratorUser:extend()
1213
---Mandatory constructor :new() will be called once per tree render, with no arguments.
1314
---Constructor must call:
1415
--- :init
1516
--- :define_sign when using "signcolumn" range
16-
---Decorator must be registered via api.decorator.register
1717

1818
---Highlight group range as per nvim-tree.renderer.highlight_*
1919
---@alias nvim_tree.api.decorator.HighlightRange "none" | "icon" | "name" | "all"
2020

2121
---Icon position as per renderer.icons.*_placement
2222
---@alias nvim_tree.api.decorator.IconPlacement "none" | "before" | "after" | "signcolumn" | "right_align"
2323

24-
---Names of predefined decorators or your decorator classes
25-
---@alias nvim_tree.api.decorator.Name "Cut" | "Copied" | "Diagnostics" | "Bookmarks" | "Modified" | "Hidden" | "Opened" | "Git" | nvim_tree.api.decorator.AbstractDecorator
24+
---Names of builtin decorators or your decorator classes. Builtins are ordered lowest to highest priority.
25+
---@alias nvim_tree.api.decorator.Name "Git" | "Opened" | "Hidden" | "Modified" | "Bookmarks" | "Diagnostics" | "Copied" | "Cut" | nvim_tree.api.decorator.DecoratorUser
2626

27-
---Abstract decorator class, your decorator will extend this.
27+
---Your decorator will extend this class via require("nvim-tree.api").decorator.DecoratorUser:extend()
2828
---
29-
---@class (exact) nvim_tree.api.decorator.AbstractDecorator
29+
---@class (exact) nvim_tree.api.decorator.DecoratorUser
3030
---@field protected enabled boolean
3131
---@field protected highlight_range nvim_tree.api.decorator.HighlightRange
3232
---@field protected icon_placement nvim_tree.api.decorator.IconPlacement
3333

3434
---Abstract: no-args constructor must be implemented.
3535
---
36-
function nvim_tree.api.decorator.AbstractDecorator:new() end
36+
function nvim_tree.api.decorator.DecoratorUser:new() end
3737

3838
---Abstract: optionally implement to set the node's icon
3939
---
4040
---@param node nvim_tree.api.Node
4141
---@return HighlightedString? icon_node
42-
function nvim_tree.api.decorator.AbstractDecorator:icon_node(node) end
42+
function nvim_tree.api.decorator.DecoratorUser:icon_node(node) end
4343

4444
---Abstract: optionally implement to provide icons and the highlight groups for your icon_placement.
4545
---
4646
---@param node nvim_tree.api.Node
4747
---@return HighlightedString[]? icons
48-
function nvim_tree.api.decorator.AbstractDecorator:icons(node) end
48+
function nvim_tree.api.decorator.DecoratorUser:icons(node) end
4949

5050
---Abstract: optionally implement to provide one highlight group to apply to your highlight_range.
5151
---
5252
---@param node nvim_tree.api.Node
5353
---@return string? highlight_group
54-
function nvim_tree.api.decorator.AbstractDecorator:highlight_group(node) end
54+
function nvim_tree.api.decorator.DecoratorUser:highlight_group(node) end
5555

5656
---Must be called from your constructor.
5757
---
58-
---@class (exact) nvim_tree.api.decorator.AbstractDecoratorInitArgs
58+
---@class (exact) nvim_tree.api.decorator.InitArgs
5959
---@field enabled boolean
6060
---@field highlight_range nvim_tree.api.decorator.HighlightRange
6161
---@field icon_placement nvim_tree.api.decorator.IconPlacement
6262
---
6363
---@protected
64-
---@param args nvim_tree.api.decorator.AbstractDecoratorInitArgs
65-
function nvim_tree.api.decorator.AbstractDecorator:init(args) end
64+
---@param args nvim_tree.api.decorator.InitArgs
65+
function nvim_tree.api.decorator.DecoratorUser:init(args) end
6666

6767
---Define a sign. This should be called in the constructor.
6868
---
6969
---@protected
7070
---@param icon HighlightedString?
71-
function nvim_tree.api.decorator.AbstractDecorator:define_sign(icon) end
71+
function nvim_tree.api.decorator.DecoratorUser:define_sign(icon) end
7272

7373

7474
--
7575
-- Example Decorator
7676
--
7777

78-
---@class (exact) MyDecorator: nvim_tree.api.decorator.AbstractDecorator
78+
---@class (exact) MyDecorator: nvim_tree.api.decorator.DecoratorUser
7979
---@field private my_icon nvim_tree.api.HighlightedString
80-
local MyDecorator = require("nvim-tree.api").decorator.create()
80+
local MyDecorator = require("nvim-tree.api").decorator.DecoratorUser:extend()
8181

8282
---Mandatory constructor :new() will be called once per tree render, with no arguments.
8383
function MyDecorator:new()
84-
---@type nvim_tree.api.decorator.AbstractDecoratorInitArgs
84+
---@type nvim_tree.api.decorator.InitArgs
8585
local args = {
8686
enabled = true,
8787
highlight_range = "all",
@@ -131,6 +131,3 @@ function MyDecorator:highlight_group(node)
131131
return nil
132132
end
133133
end
134-
135-
---Register the decorator, below Cut in priority
136-
require("nvim-tree.api").decorator.register({ decorator = MyDecorator, below = "Cut" })

lua/nvim-tree/api.lua

Lines changed: 3 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ local events = require("nvim-tree.events")
77
local help = require("nvim-tree.help")
88
local keymap = require("nvim-tree.keymap")
99
local notify = require("nvim-tree.notify")
10-
local decorator_registry = require("nvim-tree.renderer.decorator.registry")
1110

1211
local DirectoryNode = require("nvim-tree.node.directory")
1312
local FileLinkNode = require("nvim-tree.node.file-link")
@@ -314,26 +313,8 @@ Api.commands.get = wrap(function()
314313
return require("nvim-tree.commands").get()
315314
end)
316315

317-
---Create a new decorator class
318-
---
319-
---@return nvim_tree.api.decorator.AbstractDecorator
320-
Api.decorator.create = function() return DecoratorUser:extend() end
321-
322-
---Register a decorator class
323-
---
324-
---@class RegisterOpts
325-
---@field decorator nvim_tree.api.decorator.AbstractDecorator
326-
---@field below nvim_tree.api.decorator.Name?
327-
---
328-
---@param opts RegisterOpts
329-
Api.decorator.register = function(opts) decorator_registry.register(opts) end
330-
331-
---Unregister a decorator class
332-
---
333-
---@class UnRegisterOpts
334-
---@field decorator nvim_tree.api.decorator.AbstractDecorator
335-
---
336-
---@param opts UnRegisterOpts
337-
Api.decorator.unregister = function(opts) decorator_registry.unregister(opts) end
316+
---User provided decorator. Extend this class via :extend()
317+
---@type nvim_tree.api.decorator.DecoratorUser
318+
Api.decorator.DecoratorUser = DecoratorUser --[[@as nvim_tree.api.decorator.DecoratorUser]]
338319

339320
return Api

lua/nvim-tree/renderer/builder.lua

Lines changed: 53 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,36 @@
1-
local decorator_registry = require("nvim-tree.renderer.decorator.registry")
21
local notify = require("nvim-tree.notify")
32
local utils = require("nvim-tree.utils")
43
local view = require("nvim-tree.view")
54

65
local Class = require("nvim-tree.classic")
6+
77
local DirectoryNode = require("nvim-tree.node.directory")
8+
9+
local DecoratorBookmarks = require("nvim-tree.renderer.decorator.bookmarks")
10+
local DecoratorCopied = require("nvim-tree.renderer.decorator.copied")
11+
local DecoratorCut = require("nvim-tree.renderer.decorator.cut")
12+
local DecoratorDiagnostics = require("nvim-tree.renderer.decorator.diagnostics")
13+
local DecoratorGit = require("nvim-tree.renderer.decorator.git")
14+
local DecoratorHidden = require("nvim-tree.renderer.decorator.hidden")
15+
local DecoratorModified = require("nvim-tree.renderer.decorator.modified")
16+
local DecoratorOpened = require("nvim-tree.renderer.decorator.opened")
817
local DecoratorUser = require("nvim-tree.renderer.decorator.user")
918

1019
local pad = require("nvim-tree.renderer.components.padding")
1120

21+
-- Builtin Decorators
22+
---@type table<nvim_tree.api.decorator.Name, Decorator>
23+
local BUILTIN_DECORATORS = {
24+
Git = DecoratorGit,
25+
Opened = DecoratorOpened,
26+
Hidden = DecoratorHidden,
27+
Modified = DecoratorModified,
28+
Bookmarks = DecoratorBookmarks,
29+
Diagnostics = DecoratorDiagnostics,
30+
Copied = DecoratorCopied,
31+
Cut = DecoratorCut,
32+
}
33+
1234
---@class (exact) AddHighlightArgs
1335
---@field group string[]
1436
---@field line number
@@ -52,31 +74,28 @@ function Builder:new(args)
5274
self.virtual_lines = {}
5375
self.decorators = {}
5476
self.hidden_display = Builder:setup_hidden_display_function(self.explorer.opts)
55-
self.api_nodes = nil
56-
57-
---@type DecoratorArgs
58-
local decorator_args = { explorer = self.explorer }
59-
60-
-- instantiate all the decorators
61-
for _, d in ipairs(decorator_registry.registered) do
62-
if d:is(DecoratorUser) then
63-
self:build_api_nodes()
64-
table.insert(self.decorators, d())
65-
else
66-
table.insert(self.decorators, d(decorator_args))
67-
end
68-
end
69-
end
7077

71-
---Create and populate api_nodes if not present
72-
---@private
73-
function Builder:build_api_nodes()
74-
if self.api_nodes then
75-
return
76-
end
78+
-- instantiate all the builtin and user decorator instances
79+
local builtin, user
80+
for _, d in ipairs(self.explorer.opts.renderer.decorators) do
81+
---@type Decorator
82+
builtin = BUILTIN_DECORATORS[d]
7783

78-
self.api_nodes = {}
79-
self.explorer:clone(self.api_nodes)
84+
---@type DecoratorUser
85+
user = d.as and d:as(DecoratorUser)
86+
87+
if builtin then
88+
table.insert(self.decorators, builtin({ explorer = self.explorer }))
89+
elseif user then
90+
table.insert(self.decorators, user())
91+
92+
-- clone user nodes once
93+
if not self.api_nodes then
94+
self.api_nodes = {}
95+
self.explorer:clone(self.api_nodes)
96+
end
97+
end
98+
end
8099
end
81100

82101
---Insert ranged highlight groups into self.highlights
@@ -143,18 +162,18 @@ function Builder:format_line(indent_markers, arrows, icon, name, node)
143162
add_to_end(line, { icon })
144163

145164
for _, d in ipairs(self.decorators) do
146-
add_to_end(line, d:icons_before(d:is(DecoratorUser) and api_node or node))
165+
add_to_end(line, d:icons_before(not d:is(DecoratorUser) and node or api_node))
147166
end
148167

149168
add_to_end(line, { name })
150169

151170
for _, d in ipairs(self.decorators) do
152-
add_to_end(line, d:icons_after(d:is(DecoratorUser) and api_node or node))
171+
add_to_end(line, d:icons_after(not d:is(DecoratorUser) and node or api_node))
153172
end
154173

155174
local rights = {}
156175
for _, d in ipairs(self.decorators) do
157-
add_to_end(rights, d:icons_right_align(d:is(DecoratorUser) and api_node or node))
176+
add_to_end(rights, d:icons_right_align(not d:is(DecoratorUser) and node or api_node))
158177
end
159178
if #rights > 0 then
160179
self.extmarks[self.index] = rights
@@ -173,7 +192,7 @@ function Builder:build_signs(node)
173192
local d, sign_name
174193
for i = #self.decorators, 1, -1 do
175194
d = self.decorators[i]
176-
sign_name = d:sign_name(d:is(DecoratorUser) and api_node or node)
195+
sign_name = d:sign_name(not d:is(DecoratorUser) and node or api_node)
177196
if sign_name then
178197
self.signs[self.index] = sign_name
179198
break
@@ -217,6 +236,9 @@ end
217236
---@return HighlightedString icon
218237
---@return HighlightedString name
219238
function Builder:icon_name_decorated(node)
239+
-- use the api node for user decorators
240+
local api_node = self.api_nodes and self.api_nodes[node.uid_node] --[[@as Node]]
241+
220242
-- base case
221243
local icon = node:highlighted_icon()
222244
local name = node:highlighted_name()
@@ -225,11 +247,11 @@ function Builder:icon_name_decorated(node)
225247
local icon_groups = {}
226248
local name_groups = {}
227249
local hl_icon, hl_name
228-
for _, decorator in ipairs(self.decorators) do
250+
for _, d in ipairs(self.decorators) do
229251
-- maybe overridde icon
230-
icon = decorator:icon_node(node) or icon
252+
icon = d:icon_node((not d:is(DecoratorUser) and node or api_node)) or icon
231253

232-
hl_icon, hl_name = decorator:highlight_group_icon_name(node)
254+
hl_icon, hl_name = d:highlight_group_icon_name((not d:is(DecoratorUser) and node or api_node))
233255

234256
table.insert(icon_groups, hl_icon)
235257
table.insert(name_groups, hl_name)

lua/nvim-tree/renderer/decorator/bookmarks.lua

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ local Decorator = require("nvim-tree.renderer.decorator")
44
---@field private explorer Explorer
55
---@field private icon HighlightedString?
66
local DecoratorBookmarks = Decorator:extend()
7-
DecoratorBookmarks.name = "Bookmarks"
87

98
---@class DecoratorBookmarks
109
---@overload fun(args: DecoratorArgs): DecoratorBookmarks

lua/nvim-tree/renderer/decorator/copied.lua

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ local Decorator = require("nvim-tree.renderer.decorator")
33
---@class (exact) DecoratorCopied: Decorator
44
---@field private explorer Explorer
55
local DecoratorCopied = Decorator:extend()
6-
DecoratorCopied.name = "Copied"
76

87
---@class DecoratorCopied
98
---@overload fun(args: DecoratorArgs): DecoratorCopied

lua/nvim-tree/renderer/decorator/cut.lua

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ local Decorator = require("nvim-tree.renderer.decorator")
33
---@class (exact) DecoratorCut: Decorator
44
---@field private explorer Explorer
55
local DecoratorCut = Decorator:extend()
6-
DecoratorCut.name = "Cut"
76

87
---@class DecoratorCut
98
---@overload fun(args: DecoratorArgs): DecoratorCut

lua/nvim-tree/renderer/decorator/diagnostics.lua

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@ local ICON_KEYS = {
3434
---@field private explorer Explorer
3535
---@field private diag_icons HighlightedString[]?
3636
local DecoratorDiagnostics = Decorator:extend()
37-
DecoratorDiagnostics.name = "Diagnostics"
3837

3938
---@class DecoratorDiagnostics
4039
---@overload fun(args: DecoratorArgs): DecoratorDiagnostics

0 commit comments

Comments
 (0)