diff --git a/lua/nvim-tree/_meta/api_decorator.lua b/lua/nvim-tree/_meta/api_decorator.lua index b111999e072..b14dfd256c8 100644 --- a/lua/nvim-tree/_meta/api_decorator.lua +++ b/lua/nvim-tree/_meta/api_decorator.lua @@ -13,6 +13,7 @@ local nvim_tree = { api = { decorator = { AbstractDecorator = {} } } } ---Constructor must call: --- :init --- :define_sign when using "signcolumn" range +---Decorator must be registered via api.decorator.register ---Highlight group range as per nvim-tree.renderer.highlight_* ---@alias nvim_tree.api.decorator.HighlightRange "none" | "icon" | "name" | "all" @@ -125,4 +126,5 @@ function MyDecorator:highlight_group(node) end end -return MyDecorator +---Register the decorator, below Cut in priority +require("nvim-tree.api").decorator.register({ decorator = MyDecorator, below = "Cut" }) diff --git a/lua/nvim-tree/node/directory-link.lua b/lua/nvim-tree/node/directory-link.lua index 81f5dc9a998..9666ca4d7c2 100644 --- a/lua/nvim-tree/node/directory-link.lua +++ b/lua/nvim-tree/node/directory-link.lua @@ -73,9 +73,10 @@ function DirectoryLinkNode:highlighted_name() end ---Create a sanitized partial copy of a node, populating children recursively. +---@param api_nodes table? optional map of uids to api node to populate ---@return nvim_tree.api.DirectoryLinkNode cloned -function DirectoryLinkNode:clone() - local clone = DirectoryNode.clone(self) --[[@as nvim_tree.api.DirectoryLinkNode]] +function DirectoryLinkNode:clone(api_nodes) + local clone = DirectoryNode.clone(self, api_nodes) --[[@as nvim_tree.api.DirectoryLinkNode]] clone.link_to = self.link_to clone.fs_stat_target = self.fs_stat_target diff --git a/lua/nvim-tree/node/directory.lua b/lua/nvim-tree/node/directory.lua index 866792d7788..0965e4ab9fc 100644 --- a/lua/nvim-tree/node/directory.lua +++ b/lua/nvim-tree/node/directory.lua @@ -271,9 +271,10 @@ function DirectoryNode:highlighted_name() end ---Create a sanitized partial copy of a node, populating children recursively. +---@param api_nodes table? optional map of uids to api node to populate ---@return nvim_tree.api.DirectoryNode cloned -function DirectoryNode:clone() - local clone = Node.clone(self) --[[@as nvim_tree.api.DirectoryNode]] +function DirectoryNode:clone(api_nodes) + local clone = Node.clone(self, api_nodes) --[[@as nvim_tree.api.DirectoryNode]] clone.has_children = self.has_children clone.nodes = {} @@ -281,7 +282,7 @@ function DirectoryNode:clone() local clone_child for _, child in ipairs(self.nodes) do - clone_child = child:clone() + clone_child = child:clone(api_nodes) clone_child.parent = clone table.insert(clone.nodes, clone_child) end diff --git a/lua/nvim-tree/node/file-link.lua b/lua/nvim-tree/node/file-link.lua index 9b68d5e9d3d..b13c88f0d6b 100644 --- a/lua/nvim-tree/node/file-link.lua +++ b/lua/nvim-tree/node/file-link.lua @@ -58,9 +58,10 @@ function FileLinkNode:highlighted_name() end ---Create a sanitized partial copy of a node +---@param api_nodes table? optional map of uids to api node to populate ---@return nvim_tree.api.FileLinkNode cloned -function FileLinkNode:clone() - local clone = FileNode.clone(self) --[[@as nvim_tree.api.FileLinkNode]] +function FileLinkNode:clone(api_nodes) + local clone = FileNode.clone(self, api_nodes) --[[@as nvim_tree.api.FileLinkNode]] clone.link_to = self.link_to clone.fs_stat_target = self.fs_stat_target diff --git a/lua/nvim-tree/node/file.lua b/lua/nvim-tree/node/file.lua index 6c3567f7cbc..6e160409c29 100644 --- a/lua/nvim-tree/node/file.lua +++ b/lua/nvim-tree/node/file.lua @@ -94,9 +94,10 @@ function FileNode:highlighted_name() end ---Create a sanitized partial copy of a node +---@param api_nodes table? optional map of uids to api node to populate ---@return nvim_tree.api.FileNode cloned -function FileNode:clone() - local clone = Node.clone(self) --[[@as nvim_tree.api.FileNode]] +function FileNode:clone(api_nodes) + local clone = Node.clone(self, api_nodes) --[[@as nvim_tree.api.FileNode]] clone.extension = self.extension diff --git a/lua/nvim-tree/node/init.lua b/lua/nvim-tree/node/init.lua index 2a9eda56896..f8898d12691 100644 --- a/lua/nvim-tree/node/init.lua +++ b/lua/nvim-tree/node/init.lua @@ -121,8 +121,9 @@ function Node:highlighted_name() end ---Create a sanitized partial copy of a node, populating children recursively. +---@param api_nodes table? optional map of uids to api node to populate ---@return nvim_tree.api.Node cloned -function Node:clone() +function Node:clone(api_nodes) ---@type nvim_tree.api.Node local clone = { uid_node = self.uid_node, @@ -137,6 +138,10 @@ function Node:clone() diag_severity = self.diag_status and self.diag_status.value or nil, } + if api_nodes then + api_nodes[self.uid_node] = clone + end + return clone end diff --git a/lua/nvim-tree/node/root.lua b/lua/nvim-tree/node/root.lua index 683c08b8ef8..f991dec847d 100644 --- a/lua/nvim-tree/node/root.lua +++ b/lua/nvim-tree/node/root.lua @@ -23,9 +23,10 @@ function RootNode:destroy() end ---Create a sanitized partial copy of a node, populating children recursively. +---@param api_nodes table? optional map of uids to api node to populate ---@return nvim_tree.api.RootNode cloned -function RootNode:clone() - local clone = DirectoryNode.clone(self) --[[@as nvim_tree.api.RootNode]] +function RootNode:clone(api_nodes) + local clone = DirectoryNode.clone(self, api_nodes) --[[@as nvim_tree.api.RootNode]] return clone end diff --git a/lua/nvim-tree/renderer/builder.lua b/lua/nvim-tree/renderer/builder.lua index 306c2ebfb46..1b0a3bc0d63 100644 --- a/lua/nvim-tree/renderer/builder.lua +++ b/lua/nvim-tree/renderer/builder.lua @@ -28,6 +28,7 @@ local pad = require("nvim-tree.renderer.components.padding") ---@field private markers boolean[] indent markers ---@field private decorators Decorator[] ---@field private hidden_display fun(node: Node): string|nil +---@field private api_nodes table? optional map of uids to api node for user decorators local Builder = Class:extend() ---@class Builder @@ -51,20 +52,33 @@ function Builder:new(args) self.virtual_lines = {} self.decorators = {} self.hidden_display = Builder:setup_hidden_display_function(self.explorer.opts) + self.api_nodes = nil ---@type DecoratorArgs local decorator_args = { explorer = self.explorer } - -- lowest priority is registered first + -- instantiate all the decorators for _, d in ipairs(decorator_registry.registered) do if d:is(DecoratorUser) then - table.insert(self.decorators, 1, d()) + self:build_api_nodes() + table.insert(self.decorators, d()) else - table.insert(self.decorators, 1, d(decorator_args)) + table.insert(self.decorators, d(decorator_args)) end end end +---Create and populate api_nodes if not present +---@private +function Builder:build_api_nodes() + if self.api_nodes then + return + end + + self.api_nodes = {} + self.explorer:clone(self.api_nodes) +end + ---Insert ranged highlight groups into self.highlights ---@private ---@param groups string[] @@ -122,22 +136,25 @@ function Builder:format_line(indent_markers, arrows, icon, name, node) end end + -- use the api node for user decorators + local api_node = self.api_nodes and self.api_nodes[node.uid_node] --[[@as Node]] + local line = { indent_markers, arrows } add_to_end(line, { icon }) - for i = #self.decorators, 1, -1 do - add_to_end(line, self.decorators[i]:icons_before(node)) + for _, d in ipairs(self.decorators) do + add_to_end(line, d:icons_before(d:is(DecoratorUser) and api_node or node)) end add_to_end(line, { name }) - for i = #self.decorators, 1, -1 do - add_to_end(line, self.decorators[i]:icons_after(node)) + for _, d in ipairs(self.decorators) do + add_to_end(line, d:icons_after(d:is(DecoratorUser) and api_node or node)) end local rights = {} - for i = #self.decorators, 1, -1 do - add_to_end(rights, self.decorators[i]:icons_right_align(node)) + for _, d in ipairs(self.decorators) do + add_to_end(rights, d:icons_right_align(d:is(DecoratorUser) and api_node or node)) end if #rights > 0 then self.extmarks[self.index] = rights @@ -149,10 +166,14 @@ end ---@private ---@param node Node function Builder:build_signs(node) + -- use the api node for user decorators + local api_node = self.api_nodes and self.api_nodes[node.uid_node] --[[@as Node]] + -- first in priority order - local sign_name - for _, d in ipairs(self.decorators) do - sign_name = d:sign_name(node) + local d, sign_name + for i = #self.decorators, 1, -1 do + d = self.decorators[i] + sign_name = d:sign_name(d:is(DecoratorUser) and api_node or node) if sign_name then self.signs[self.index] = sign_name break @@ -203,10 +224,8 @@ function Builder:icon_name_decorated(node) -- calculate node icon and all decorated highlight groups local icon_groups = {} local name_groups = {} - local decorator, hl_icon, hl_name - for i = #self.decorators, 1, -1 do - decorator = self.decorators[i] - + local hl_icon, hl_name + for _, decorator in ipairs(self.decorators) do -- maybe overridde icon icon = decorator:icon_node(node) or icon