From c104076395fa4c5f3eb89e0f457ac94e71e61c0c Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Sat, 31 Jan 2026 17:36:20 +1100 Subject: [PATCH 01/27] docs(#3241): namespace decorator types --- lua/nvim-tree/_meta/api_decorator.lua | 18 +++++++++--------- lua/nvim-tree/_meta/config/renderer.lua | 1 + lua/nvim-tree/api.lua | 6 +++++- lua/nvim-tree/api/impl/post.lua | 2 ++ lua/nvim-tree/api/impl/pre.lua | 2 ++ lua/nvim-tree/renderer/builder.lua | 6 +++--- lua/nvim-tree/renderer/decorator/git.lua | 2 +- lua/nvim-tree/renderer/decorator/init.lua | 6 ++++-- 8 files changed, 27 insertions(+), 16 deletions(-) diff --git a/lua/nvim-tree/_meta/api_decorator.lua b/lua/nvim-tree/_meta/api_decorator.lua index 4acca3a9acf..71ca352270d 100644 --- a/lua/nvim-tree/_meta/api_decorator.lua +++ b/lua/nvim-tree/_meta/api_decorator.lua @@ -4,16 +4,16 @@ error("Cannot require a meta file") local nvim_tree = { api = { decorator = {} } } ---Highlight group range as per nvim-tree.renderer.highlight_* ----@alias nvim_tree.api.decorator.HighlightRange "none" | "icon" | "name" | "all" +---@alias nvim_tree.api.decorator.highlight_range nvim_tree.config.renderer.highlight ---Icon position as per renderer.icons.*_placement ----@alias nvim_tree.api.decorator.IconPlacement "none" | "before" | "after" | "signcolumn" | "right_align" +---@alias nvim_tree.api.decorator.icon_placement "none"|nvim_tree.config.renderer.icons.placement ---Names of builtin decorators or your decorator classes. Builtins are ordered lowest to highest priority. ----@alias nvim_tree.api.decorator.Name "Git" | "Opened" | "Hidden" | "Modified" | "Bookmarks" | "Diagnostics" | "Copied" | "Cut" | nvim_tree.api.decorator.UserDecorator +---@alias nvim_tree.api.decorator.types nvim_tree.api.decorator.UserDecorator|"Git"|"Opened"|"Hidden"|"Modified"|"Bookmarks"|"Diagnostics"|"Copied"|"Cut" ---A string for rendering, with optional highlight groups to apply to it ----@class (exact) nvim_tree.api.HighlightedString +---@class (exact) nvim_tree.api.decorator.highlighted_string ---@field str string ---@field hl string[] @@ -21,8 +21,8 @@ local nvim_tree = { api = { decorator = {} } } --- ---@class (exact) nvim_tree.api.decorator.UserDecorator ---@field protected enabled boolean ----@field protected highlight_range nvim_tree.api.decorator.HighlightRange ----@field protected icon_placement nvim_tree.api.decorator.IconPlacement +---@field protected highlight_range nvim_tree.api.decorator.highlight_range +---@field protected icon_placement nvim_tree.api.decorator.icon_placement nvim_tree.api.decorator.UserDecorator = {} ---Create your decorator class @@ -37,13 +37,13 @@ function nvim_tree.api.decorator.UserDecorator:new() end ---Abstract: optionally implement to set the node's icon --- ---@param node nvim_tree.api.Node ----@return nvim_tree.api.HighlightedString? icon_node +---@return nvim_tree.api.decorator.highlighted_string? icon_node function nvim_tree.api.decorator.UserDecorator:icon_node(node) end ---Abstract: optionally implement to provide icons and the highlight groups for your icon_placement. --- ---@param node nvim_tree.api.Node ----@return nvim_tree.api.HighlightedString[]? icons +---@return nvim_tree.api.decorator.highlighted_string[]? icons function nvim_tree.api.decorator.UserDecorator:icons(node) end ---Abstract: optionally implement to provide one highlight group to apply to your highlight_range. @@ -55,5 +55,5 @@ function nvim_tree.api.decorator.UserDecorator:highlight_group(node) end ---Define a sign. This should be called in the constructor. --- ---@protected ----@param icon nvim_tree.api.HighlightedString? +---@param icon nvim_tree.api.decorator.highlighted_string? function nvim_tree.api.decorator.UserDecorator:define_sign(icon) end diff --git a/lua/nvim-tree/_meta/config/renderer.lua b/lua/nvim-tree/_meta/config/renderer.lua index e1ba26cbb91..cf7826fe240 100644 --- a/lua/nvim-tree/_meta/config/renderer.lua +++ b/lua/nvim-tree/_meta/config/renderer.lua @@ -61,6 +61,7 @@ error("Cannot require a meta file") ---(default: `true`) ---@field symlink_destination? boolean --- +---TODO #3241 add an alias for builtins ---(default: `{ "Git", "Open", "Hidden", "Modified", "Bookmark", "Diagnostics", "Copied", "Cut", }`) ---@field decorators? (string|nvim_tree.api.decorator.UserDecorator)[] --- diff --git a/lua/nvim-tree/api.lua b/lua/nvim-tree/api.lua index e88b19d1f0a..be02d764994 100644 --- a/lua/nvim-tree/api.lua +++ b/lua/nvim-tree/api.lua @@ -96,10 +96,14 @@ local api = { -- --- Map before-setup implementations, most throw an error notification "nvim-tree setup not called". +-- Map before-setup function implementations, most throw an error notification "nvim-tree setup not called". -- require("nvim-tree.api.impl.pre")(api) +---#TODO 3241 +---Public API classes +-- api.decorator = require("nvim-tree.api.decorator") + return api diff --git a/lua/nvim-tree/api/impl/post.lua b/lua/nvim-tree/api/impl/post.lua index 2aa5a3caec3..5c2d15de3d3 100644 --- a/lua/nvim-tree/api/impl/post.lua +++ b/lua/nvim-tree/api/impl/post.lua @@ -254,6 +254,8 @@ local function hydrate_post(api) api.map.keymap.current = keymap.get_keymap end +---#TODO 3241 hydrate function, for clarity + ---Re-hydrate api ---@param api table not properly typed to prevent LSP from referencing implementations return function(api) diff --git a/lua/nvim-tree/api/impl/pre.lua b/lua/nvim-tree/api/impl/pre.lua index 7ad25ecb41f..4736d88da55 100644 --- a/lua/nvim-tree/api/impl/pre.lua +++ b/lua/nvim-tree/api/impl/pre.lua @@ -65,6 +65,8 @@ local function hydrate_pre(api) api.decorator.UserDecorator = UserDecorator --[[@as nvim_tree.api.decorator.UserDecorator]] end +---#TODO 3241 hydrate function, for clarity + ---Hydrate api ---@param api table not properly typed to prevent LSP from referencing implementations return function(api) diff --git a/lua/nvim-tree/renderer/builder.lua b/lua/nvim-tree/renderer/builder.lua index 819660e5306..d3d06f86c07 100644 --- a/lua/nvim-tree/renderer/builder.lua +++ b/lua/nvim-tree/renderer/builder.lua @@ -14,14 +14,14 @@ local GitDecorator = require("nvim-tree.renderer.decorator.git") local HiddenDecorator = require("nvim-tree.renderer.decorator.hidden") local ModifiedDecorator = require("nvim-tree.renderer.decorator.modified") local OpenDecorator = require("nvim-tree.renderer.decorator.opened") -local UserDecorator = require("nvim-tree.renderer.decorator.user") +local UserDecorator = require("nvim-tree.api").decorator.UserDecorator local pad = require("nvim-tree.renderer.components.padding") ----@alias HighlightedString nvim_tree.api.HighlightedString +---@alias HighlightedString nvim_tree.api.decorator.highlighted_string -- Builtin Decorators ----@type table +---@type table local BUILTIN_DECORATORS = { Git = GitDecorator, Open = OpenDecorator, diff --git a/lua/nvim-tree/renderer/decorator/git.lua b/lua/nvim-tree/renderer/decorator/git.lua index c117b16959d..37fac2dcbed 100644 --- a/lua/nvim-tree/renderer/decorator/git.lua +++ b/lua/nvim-tree/renderer/decorator/git.lua @@ -3,7 +3,7 @@ local notify = require("nvim-tree.notify") local Decorator = require("nvim-tree.renderer.decorator") local DirectoryNode = require("nvim-tree.node.directory") ----@class (exact) GitHighlightedString: nvim_tree.api.HighlightedString +---@class (exact) GitHighlightedString: nvim_tree.api.decorator.highlighted_string ---@field ord number decreasing priority ---@alias GitStatusStrings "deleted" | "ignored" | "renamed" | "staged" | "unmerged" | "unstaged" | "untracked" diff --git a/lua/nvim-tree/renderer/decorator/init.lua b/lua/nvim-tree/renderer/decorator/init.lua index cc7ab0ad305..82e2040de3e 100644 --- a/lua/nvim-tree/renderer/decorator/init.lua +++ b/lua/nvim-tree/renderer/decorator/init.lua @@ -1,10 +1,12 @@ local Class = require("nvim-tree.classic") +--- #TODO 3241 split this into abstract interface for API and concrete to return to user + ---Abstract Decorator ---@class (exact) Decorator: Class ---@field protected enabled boolean ----@field protected highlight_range nvim_tree.api.decorator.HighlightRange ----@field protected icon_placement nvim_tree.api.decorator.IconPlacement +---@field protected highlight_range nvim_tree.api.decorator.highlight_range +---@field protected icon_placement nvim_tree.api.decorator.icon_placement local Decorator = Class:extend() ---@class (exact) DecoratorArgs From 469f795cdf51957cf5c2ec70012955d62e48fc2c Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Sun, 1 Feb 2026 10:41:19 +1100 Subject: [PATCH 02/27] docs(#3241): namespace decorator types --- doc/nvim-tree-lua.txt | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/doc/nvim-tree-lua.txt b/doc/nvim-tree-lua.txt index fcf0ef1bf3e..3a0cfd3a95e 100644 --- a/doc/nvim-tree-lua.txt +++ b/doc/nvim-tree-lua.txt @@ -891,9 +891,9 @@ Require and register it during |nvim-tree-setup|: Contents of `my-decorator.lua`: >lua ---@class (exact) MyDecorator: nvim_tree.api.decorator.UserDecorator - ---@field private my_icon1 nvim_tree.api.HighlightedString - ---@field private my_icon2 nvim_tree.api.HighlightedString - ---@field private my_icon_node nvim_tree.api.HighlightedString + ---@field private my_icon1 nvim_tree.api.decorator.highlighted_string + ---@field private my_icon2 nvim_tree.api.decorator.highlighted_string + ---@field private my_icon_node nvim_tree.api.decorator.highlighted_string ---@field private my_highlight_group string local MyDecorator = require("nvim-tree.api").decorator.UserDecorator:extend() @@ -917,7 +917,7 @@ Contents of `my-decorator.lua`: ---Override node icon ---@param node nvim_tree.api.Node - ---@return nvim_tree.api.HighlightedString? icon_node + ---@return nvim_tree.api.decorator.highlighted_string? icon_node function MyDecorator:icon_node(node) if node.name == "example" then return self.my_icon_node @@ -928,7 +928,7 @@ Contents of `my-decorator.lua`: ---Return two icons for DecoratorIconPlacement "after" ---@param node nvim_tree.api.Node - ---@return nvim_tree.api.HighlightedString[]? icons + ---@return nvim_tree.api.decorator.highlighted_string[]? icons function MyDecorator:icons(node) if node.name == "example" then return { self.my_icon1, self.my_icon2, } From e81e6d5da751824c13ee2bf6cb2707793662414c Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Sun, 1 Feb 2026 11:04:29 +1100 Subject: [PATCH 03/27] docs(#3241): namespace decorator types --- lua/nvim-tree/_meta/config/renderer.lua | 1 - lua/nvim-tree/api.lua | 6 +++--- lua/nvim-tree/node/directory-link.lua | 4 ++-- lua/nvim-tree/node/directory.lua | 4 ++-- lua/nvim-tree/node/file-link.lua | 4 ++-- lua/nvim-tree/node/file.lua | 4 ++-- lua/nvim-tree/node/init.lua | 8 ++++---- lua/nvim-tree/renderer/builder.lua | 18 +++++++++--------- lua/nvim-tree/renderer/components/padding.lua | 4 ++-- lua/nvim-tree/renderer/decorator/bookmarks.lua | 4 ++-- .../renderer/decorator/diagnostics.lua | 4 ++-- lua/nvim-tree/renderer/decorator/git.lua | 2 +- lua/nvim-tree/renderer/decorator/hidden.lua | 4 ++-- lua/nvim-tree/renderer/decorator/init.lua | 12 ++++++------ lua/nvim-tree/renderer/decorator/modified.lua | 4 ++-- lua/nvim-tree/renderer/decorator/opened.lua | 2 +- 16 files changed, 42 insertions(+), 43 deletions(-) diff --git a/lua/nvim-tree/_meta/config/renderer.lua b/lua/nvim-tree/_meta/config/renderer.lua index cf7826fe240..e1ba26cbb91 100644 --- a/lua/nvim-tree/_meta/config/renderer.lua +++ b/lua/nvim-tree/_meta/config/renderer.lua @@ -61,7 +61,6 @@ error("Cannot require a meta file") ---(default: `true`) ---@field symlink_destination? boolean --- ----TODO #3241 add an alias for builtins ---(default: `{ "Git", "Open", "Hidden", "Modified", "Bookmark", "Diagnostics", "Copied", "Cut", }`) ---@field decorators? (string|nvim_tree.api.decorator.UserDecorator)[] --- diff --git a/lua/nvim-tree/api.lua b/lua/nvim-tree/api.lua index be02d764994..04182a1b745 100644 --- a/lua/nvim-tree/api.lua +++ b/lua/nvim-tree/api.lua @@ -101,9 +101,9 @@ local api = { require("nvim-tree.api.impl.pre")(api) ----#TODO 3241 ----Public API classes --- api.decorator = require("nvim-tree.api.decorator") +--#TODO 3241 +--Public API classes +--api.decorator = require("nvim-tree.api.decorator") return api diff --git a/lua/nvim-tree/node/directory-link.lua b/lua/nvim-tree/node/directory-link.lua index 6d503ad6d40..b1c19f54172 100644 --- a/lua/nvim-tree/node/directory-link.lua +++ b/lua/nvim-tree/node/directory-link.lua @@ -38,7 +38,7 @@ function DirectoryLinkNode:update_git_status(parent_ignored, project) self.git_status = git_utils.git_status_dir(parent_ignored, project, self.link_to, self.absolute_path) end ----@return HighlightedString name +---@return nvim_tree.api.decorator.highlighted_string name function DirectoryLinkNode:highlighted_icon() if not self.explorer.opts.renderer.icons.show.folder then return self:highlighted_icon_empty() @@ -58,7 +58,7 @@ function DirectoryLinkNode:highlighted_icon() end ---Maybe override name with arrow ----@return HighlightedString name +---@return nvim_tree.api.decorator.highlighted_string name function DirectoryLinkNode:highlighted_name() local name = DirectoryNode.highlighted_name(self) diff --git a/lua/nvim-tree/node/directory.lua b/lua/nvim-tree/node/directory.lua index d53718085f9..9b376e7b6f6 100644 --- a/lua/nvim-tree/node/directory.lua +++ b/lua/nvim-tree/node/directory.lua @@ -198,7 +198,7 @@ function DirectoryNode:expand_or_collapse(toggle_group) self.explorer.renderer:draw() end ----@return HighlightedString icon +---@return nvim_tree.api.decorator.highlighted_string icon function DirectoryNode:highlighted_icon() if not self.explorer.opts.renderer.icons.show.folder then return self:highlighted_icon_empty() @@ -243,7 +243,7 @@ function DirectoryNode:highlighted_icon() return { str = str, hl = { hl } } end ----@return HighlightedString icon +---@return nvim_tree.api.decorator.highlighted_string icon function DirectoryNode:highlighted_name() local str, hl diff --git a/lua/nvim-tree/node/file-link.lua b/lua/nvim-tree/node/file-link.lua index 6cb83e0343a..7130897ddec 100644 --- a/lua/nvim-tree/node/file-link.lua +++ b/lua/nvim-tree/node/file-link.lua @@ -31,7 +31,7 @@ function FileLinkNode:update_git_status(parent_ignored, project) self.git_status = git_utils.git_status_file(parent_ignored, project, self.link_to, self.absolute_path) end ----@return HighlightedString icon +---@return nvim_tree.api.decorator.highlighted_string icon function FileLinkNode:highlighted_icon() if not self.explorer.opts.renderer.icons.show.file then return self:highlighted_icon_empty() @@ -46,7 +46,7 @@ function FileLinkNode:highlighted_icon() return { str = str, hl = { hl } } end ----@return HighlightedString name +---@return nvim_tree.api.decorator.highlighted_string name function FileLinkNode:highlighted_name() local str = self.name if self.explorer.opts.renderer.symlink_destination then diff --git a/lua/nvim-tree/node/file.lua b/lua/nvim-tree/node/file.lua index bba1621e21b..2b0ea0362c9 100644 --- a/lua/nvim-tree/node/file.lua +++ b/lua/nvim-tree/node/file.lua @@ -50,7 +50,7 @@ function FileNode:get_git_xy() return self.git_status.file and { self.git_status.file } end ----@return HighlightedString icon +---@return nvim_tree.api.decorator.highlighted_string icon function FileNode:highlighted_icon() if not self.explorer.opts.renderer.icons.show.file then return self:highlighted_icon_empty() @@ -79,7 +79,7 @@ function FileNode:highlighted_icon() return { str = str, hl = { hl } } end ----@return HighlightedString name +---@return nvim_tree.api.decorator.highlighted_string name function FileNode:highlighted_name() local hl if vim.tbl_contains(self.explorer.opts.renderer.special_files, self.absolute_path) or vim.tbl_contains(self.explorer.opts.renderer.special_files, self.name) then diff --git a/lua/nvim-tree/node/init.lua b/lua/nvim-tree/node/init.lua index 5aaf4fb094a..4c8d5c81daa 100644 --- a/lua/nvim-tree/node/init.lua +++ b/lua/nvim-tree/node/init.lua @@ -93,28 +93,28 @@ end ---Empty highlighted icon ---@protected ----@return HighlightedString icon +---@return nvim_tree.api.decorator.highlighted_string icon function Node:highlighted_icon_empty() return { str = "", hl = {} } end ---Highlighted icon for the node ---Empty for base Node ----@return HighlightedString icon +---@return nvim_tree.api.decorator.highlighted_string icon function Node:highlighted_icon() return self:highlighted_icon_empty() end ---Empty highlighted name ---@protected ----@return HighlightedString name +---@return nvim_tree.api.decorator.highlighted_string name function Node:highlighted_name_empty() return { str = "", hl = {} } end ---Highlighted name for the node ---Empty for base Node ----@return HighlightedString name +---@return nvim_tree.api.decorator.highlighted_string name function Node:highlighted_name() return self:highlighted_name_empty() end diff --git a/lua/nvim-tree/renderer/builder.lua b/lua/nvim-tree/renderer/builder.lua index d3d06f86c07..d74ed2c7d64 100644 --- a/lua/nvim-tree/renderer/builder.lua +++ b/lua/nvim-tree/renderer/builder.lua @@ -18,7 +18,7 @@ local UserDecorator = require("nvim-tree.api").decorator.UserDecorator local pad = require("nvim-tree.renderer.components.padding") ----@alias HighlightedString nvim_tree.api.decorator.highlighted_string +---TODO #3241 add an alias for builtins or document the enum -- Builtin Decorators ---@type table @@ -106,7 +106,7 @@ function Builder:insert_highlight(groups, start, end_) end ---@private ----@param highlighted_strings HighlightedString[] +---@param highlighted_strings nvim_tree.api.decorator.highlighted_string[] ---@return string function Builder:unwrap_highlighted_strings(highlighted_strings) if not highlighted_strings then @@ -126,12 +126,12 @@ function Builder:unwrap_highlighted_strings(highlighted_strings) end ---@private ----@param indent_markers HighlightedString[] ----@param arrows HighlightedString[]|nil ----@param icon HighlightedString ----@param name HighlightedString +---@param indent_markers nvim_tree.api.decorator.highlighted_string[] +---@param arrows? nvim_tree.api.decorator.highlighted_string[] +---@param icon nvim_tree.api.decorator.highlighted_string +---@param name nvim_tree.api.decorator.highlighted_string ---@param node table ----@return HighlightedString[] +---@return nvim_tree.api.decorator.highlighted_string[] function Builder:format_line(indent_markers, arrows, icon, name, node) local added_len = 0 local function add_to_end(t1, t2) @@ -231,8 +231,8 @@ end ---A highlight group is always calculated and upserted for the case of highlights changing. ---@private ---@param node Node ----@return HighlightedString icon ----@return HighlightedString name +---@return nvim_tree.api.decorator.highlighted_string icon +---@return nvim_tree.api.decorator.highlighted_string name function Builder:icon_name_decorated(node) -- use the api node for user decorators local api_node = self.api_nodes and self.api_nodes[node.uid_node] --[[@as Node]] diff --git a/lua/nvim-tree/renderer/components/padding.lua b/lua/nvim-tree/renderer/components/padding.lua index a33525cc437..a8289b4d4e1 100644 --- a/lua/nvim-tree/renderer/components/padding.lua +++ b/lua/nvim-tree/renderer/components/padding.lua @@ -64,7 +64,7 @@ end ---@param node Node ---@param markers table ---@param early_stop integer? ----@return HighlightedString +---@return nvim_tree.api.decorator.highlighted_string function M.get_indent_markers(depth, idx, nodes_number, node, markers, early_stop) local str = "" @@ -83,7 +83,7 @@ function M.get_indent_markers(depth, idx, nodes_number, node, markers, early_sto end ---@param node Node ----@return HighlightedString[]|nil +---@return nvim_tree.api.decorator.highlighted_string[]? function M.get_arrows(node) if not M.config.icons.show.folder_arrow then return diff --git a/lua/nvim-tree/renderer/decorator/bookmarks.lua b/lua/nvim-tree/renderer/decorator/bookmarks.lua index c661748ef21..5c6bff438e2 100644 --- a/lua/nvim-tree/renderer/decorator/bookmarks.lua +++ b/lua/nvim-tree/renderer/decorator/bookmarks.lua @@ -2,7 +2,7 @@ local Decorator = require("nvim-tree.renderer.decorator") ---@class (exact) BookmarkDecorator: Decorator ---@field private explorer Explorer ----@field private icon HighlightedString? +---@field private icon nvim_tree.api.decorator.highlighted_string? local BookmarkDecorator = Decorator:extend() ---@class BookmarkDecorator @@ -28,7 +28,7 @@ end ---Bookmark icon: renderer.icons.show.bookmarks and node is marked ---@param node Node ----@return HighlightedString[]? icons +---@return nvim_tree.api.decorator.highlighted_string[]? icons function BookmarkDecorator:icons(node) if self.explorer.marks:get(node) then return { self.icon } diff --git a/lua/nvim-tree/renderer/decorator/diagnostics.lua b/lua/nvim-tree/renderer/decorator/diagnostics.lua index 56598ef9418..fd7ceba6446 100644 --- a/lua/nvim-tree/renderer/decorator/diagnostics.lua +++ b/lua/nvim-tree/renderer/decorator/diagnostics.lua @@ -32,7 +32,7 @@ local ICON_KEYS = { ---@class (exact) DiagnosticsDecorator: Decorator ---@field private explorer Explorer ----@field private diag_icons HighlightedString[]? +---@field private diag_icons nvim_tree.api.decorator.highlighted_string[]? local DiagnosticsDecorator = Decorator:extend() ---@class DiagnosticsDecorator @@ -73,7 +73,7 @@ end ---Diagnostic icon: diagnostics.enable, renderer.icons.show.diagnostics and node has status ---@param node Node ----@return HighlightedString[]? icons +---@return nvim_tree.api.decorator.highlighted_string[]? icons function DiagnosticsDecorator:icons(node) if node and self.diag_icons then local diag_status = diagnostics.get_diag_status(node) diff --git a/lua/nvim-tree/renderer/decorator/git.lua b/lua/nvim-tree/renderer/decorator/git.lua index 37fac2dcbed..bcd83df99a2 100644 --- a/lua/nvim-tree/renderer/decorator/git.lua +++ b/lua/nvim-tree/renderer/decorator/git.lua @@ -142,7 +142,7 @@ end ---Git icons: git.enable, renderer.icons.show.git and node has status ---@param node Node ----@return HighlightedString[]? icons +---@return nvim_tree.api.decorator.highlighted_string[]? icons function GitDecorator:icons(node) if not self.icons_by_xy then return nil diff --git a/lua/nvim-tree/renderer/decorator/hidden.lua b/lua/nvim-tree/renderer/decorator/hidden.lua index 87168ceb82b..bffd82c370b 100644 --- a/lua/nvim-tree/renderer/decorator/hidden.lua +++ b/lua/nvim-tree/renderer/decorator/hidden.lua @@ -3,7 +3,7 @@ local DirectoryNode = require("nvim-tree.node.directory") ---@class (exact) HiddenDecorator: Decorator ---@field private explorer Explorer ----@field private icon HighlightedString? +---@field private icon nvim_tree.api.decorator.highlighted_string? local HiddenDecorator = Decorator:extend() ---@class HiddenDecorator @@ -29,7 +29,7 @@ end ---Hidden icon: renderer.icons.show.hidden and node starts with `.` (dotfile). ---@param node Node ----@return HighlightedString[]? icons +---@return nvim_tree.api.decorator.highlighted_string[]? icons function HiddenDecorator:icons(node) if node:is_dotfile() then return { self.icon } diff --git a/lua/nvim-tree/renderer/decorator/init.lua b/lua/nvim-tree/renderer/decorator/init.lua index 82e2040de3e..013ab0cba28 100644 --- a/lua/nvim-tree/renderer/decorator/init.lua +++ b/lua/nvim-tree/renderer/decorator/init.lua @@ -14,7 +14,7 @@ local Decorator = Class:extend() ---Abstract icon override, optionally implemented ---@param node Node ----@return HighlightedString? icon_node +---@return nvim_tree.api.decorator.highlighted_string? icon_node function Decorator:icon_node(node) return self:nop(node) end @@ -22,7 +22,7 @@ end ---Abstract icons, optionally implemented ---@protected ---@param node Node ----@return HighlightedString[]? icons +---@return nvim_tree.api.decorator.highlighted_string[]? icons function Decorator:icons(node) self:nop(node) end @@ -72,7 +72,7 @@ end ---Icons when "before" ---@param node Node ----@return HighlightedString[]? icons +---@return nvim_tree.api.decorator.highlighted_string[]? icons function Decorator:icons_before(node) if not self.enabled or self.icon_placement ~= "before" then return @@ -83,7 +83,7 @@ end ---Icons when "after" ---@param node Node ----@return HighlightedString[]? icons +---@return nvim_tree.api.decorator.highlighted_string[]? icons function Decorator:icons_after(node) if not self.enabled or self.icon_placement ~= "after" then return @@ -94,7 +94,7 @@ end ---Icons when "right_align" ---@param node Node ----@return HighlightedString[]? icons +---@return nvim_tree.api.decorator.highlighted_string[]? icons function Decorator:icons_right_align(node) if not self.enabled or self.icon_placement ~= "right_align" then return @@ -105,7 +105,7 @@ end ---Define a sign ---@protected ----@param icon HighlightedString? +---@param icon nvim_tree.api.decorator.highlighted_string? function Decorator:define_sign(icon) if icon and #icon.hl > 0 then local name = icon.hl[1] diff --git a/lua/nvim-tree/renderer/decorator/modified.lua b/lua/nvim-tree/renderer/decorator/modified.lua index c182e300afc..ee41d7d90cd 100644 --- a/lua/nvim-tree/renderer/decorator/modified.lua +++ b/lua/nvim-tree/renderer/decorator/modified.lua @@ -5,7 +5,7 @@ local DirectoryNode = require("nvim-tree.node.directory") ---@class (exact) ModifiedDecorator: Decorator ---@field private explorer Explorer ----@field private icon HighlightedString? +---@field private icon nvim_tree.api.decorator.highlighted_string? local ModifiedDecorator = Decorator:extend() ---@class ModifiedDecorator @@ -31,7 +31,7 @@ end ---Modified icon: modified.enable, renderer.icons.show.modified and node is modified ---@param node Node ----@return HighlightedString[]? icons +---@return nvim_tree.api.decorator.highlighted_string[]? icons function ModifiedDecorator:icons(node) if buffers.is_modified(node) then return { self.icon } diff --git a/lua/nvim-tree/renderer/decorator/opened.lua b/lua/nvim-tree/renderer/decorator/opened.lua index 240dce4948a..094a893211c 100644 --- a/lua/nvim-tree/renderer/decorator/opened.lua +++ b/lua/nvim-tree/renderer/decorator/opened.lua @@ -4,7 +4,7 @@ local Decorator = require("nvim-tree.renderer.decorator") ---@class (exact) OpenDecorator: Decorator ---@field private explorer Explorer ----@field private icon HighlightedString|nil +---@field private icon? nvim_tree.api.decorator.highlighted_string local OpenDecorator = Decorator:extend() ---@class OpenDecorator From baa4b10536568c9969b7efe568b85b842eaf3f17 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Sun, 1 Feb 2026 13:23:05 +1100 Subject: [PATCH 04/27] docs(#3241): api exposes nvim_tree.api.decorator.Decorator interface, UserDecorator deprecated --- doc/nvim-tree-lua.txt | 20 +++---- lua/nvim-tree.lua | 2 +- lua/nvim-tree/_meta/api_decorator.lua | 38 ++++++------- lua/nvim-tree/_meta/config/renderer.lua | 2 +- lua/nvim-tree/api.lua | 26 +++------ lua/nvim-tree/api/impl/legacy.lua | 8 ++- lua/nvim-tree/api/impl/post.lua | 19 +++---- lua/nvim-tree/api/impl/pre.lua | 68 ++++++++--------------- lua/nvim-tree/renderer/builder.lua | 2 +- lua/nvim-tree/renderer/decorator/init.lua | 32 +---------- 10 files changed, 78 insertions(+), 139 deletions(-) diff --git a/doc/nvim-tree-lua.txt b/doc/nvim-tree-lua.txt index 3a0cfd3a95e..651de1096bd 100644 --- a/doc/nvim-tree-lua.txt +++ b/doc/nvim-tree-lua.txt @@ -890,31 +890,31 @@ Require and register it during |nvim-tree-setup|: < Contents of `my-decorator.lua`: >lua - ---@class (exact) MyDecorator: nvim_tree.api.decorator.UserDecorator + ---@class (exact) MyDecorator: nvim_tree.api.decorator.Decorator ---@field private my_icon1 nvim_tree.api.decorator.highlighted_string ---@field private my_icon2 nvim_tree.api.decorator.highlighted_string ---@field private my_icon_node nvim_tree.api.decorator.highlighted_string ---@field private my_highlight_group string - local MyDecorator = require("nvim-tree.api").decorator.UserDecorator:extend() - + local MyDecorator = require("nvim-tree.api").decorator.Decorator:extend() + ---Mandatory constructor :new() will be called once per tree render, with no arguments. function MyDecorator:new() self.enabled = true self.highlight_range = "name" self.icon_placement = "after" - + -- create your icons and highlights once, applied to every node self.my_icon1 = { str = "1", hl = { "DiffAdd" } } self.my_icon2 = { str = "2", hl = { "DiffText" } } self.my_icon_node = { str = "N", hl = { "Error" } } self.my_highlight_group = "IncSearch" - + -- Define the icon signs only once -- Only needed if you are using icon_placement = "signcolumn" -- self:define_sign(self.my_icon1) -- self:define_sign(self.my_icon2) end - + ---Override node icon ---@param node nvim_tree.api.Node ---@return nvim_tree.api.decorator.highlighted_string? icon_node @@ -925,7 +925,7 @@ Contents of `my-decorator.lua`: return nil end end - + ---Return two icons for DecoratorIconPlacement "after" ---@param node nvim_tree.api.Node ---@return nvim_tree.api.decorator.highlighted_string[]? icons @@ -936,7 +936,7 @@ Contents of `my-decorator.lua`: return nil end end - + ---Exactly one highlight group for DecoratorHighlightRange "name" ---@param node nvim_tree.api.Node ---@return string? highlight_group @@ -947,7 +947,7 @@ Contents of `my-decorator.lua`: return nil end end - + return MyDecorator < ============================================================================== @@ -1366,7 +1366,7 @@ Config: renderer *nvim-tree-config-renderer* • {symlink_destination}? (`boolean`, default: `true`) Appends an arrow followed by the target of the symlink. - • {decorators}? (`(string|nvim_tree.api.decorator.UserDecorator)[]`) + • {decorators}? (`(string|nvim_tree.api.decorator.Decorator)[]`) (default: `{ "Git", "Open", "Hidden", "Modified", "Bookmark", "Diagnostics", "Copied", "Cut", }`) • {highlight_git}? (`nvim_tree.config.renderer.highlight`) diff --git a/lua/nvim-tree.lua b/lua/nvim-tree.lua index 4d4dad7b1f3..7d3a79b46de 100644 --- a/lua/nvim-tree.lua +++ b/lua/nvim-tree.lua @@ -813,7 +813,7 @@ function M.setup(conf) vim.g.NvimTreeSetup = 1 vim.api.nvim_exec_autocmds("User", { pattern = "NvimTreeSetup" }) - require("nvim-tree.api.impl.post")(api) + require("nvim-tree.api.impl.post").hydrate(api) end vim.g.NvimTreeRequired = 1 diff --git a/lua/nvim-tree/_meta/api_decorator.lua b/lua/nvim-tree/_meta/api_decorator.lua index 71ca352270d..787c0e0f557 100644 --- a/lua/nvim-tree/_meta/api_decorator.lua +++ b/lua/nvim-tree/_meta/api_decorator.lua @@ -1,8 +1,9 @@ ---@meta -error("Cannot require a meta file") - +--- local nvim_tree = { api = { decorator = {} } } +local Class = require("nvim-tree.classic") + ---Highlight group range as per nvim-tree.renderer.highlight_* ---@alias nvim_tree.api.decorator.highlight_range nvim_tree.config.renderer.highlight @@ -10,50 +11,47 @@ local nvim_tree = { api = { decorator = {} } } ---@alias nvim_tree.api.decorator.icon_placement "none"|nvim_tree.config.renderer.icons.placement ---Names of builtin decorators or your decorator classes. Builtins are ordered lowest to highest priority. ----@alias nvim_tree.api.decorator.types nvim_tree.api.decorator.UserDecorator|"Git"|"Opened"|"Hidden"|"Modified"|"Bookmarks"|"Diagnostics"|"Copied"|"Cut" +---@alias nvim_tree.api.decorator.types nvim_tree.api.decorator.Decorator|"Git"|"Opened"|"Hidden"|"Modified"|"Bookmarks"|"Diagnostics"|"Copied"|"Cut" ---A string for rendering, with optional highlight groups to apply to it ---@class (exact) nvim_tree.api.decorator.highlighted_string ---@field str string ---@field hl string[] ----Custom decorator, see :help nvim-tree-decorators +---Abstract Decorator interface --- ----@class (exact) nvim_tree.api.decorator.UserDecorator +---@class (exact) nvim_tree.api.decorator.Decorator: Class ---@field protected enabled boolean ---@field protected highlight_range nvim_tree.api.decorator.highlight_range ---@field protected icon_placement nvim_tree.api.decorator.icon_placement -nvim_tree.api.decorator.UserDecorator = {} - ----Create your decorator class ---- -function nvim_tree.api.decorator.UserDecorator:extend() end - ----Abstract: no-args constructor must be implemented and will be called once per tree render. ----Must set all fields. ---- -function nvim_tree.api.decorator.UserDecorator:new() end +nvim_tree.api.decorator.Decorator = Class:extend() ---Abstract: optionally implement to set the node's icon --- ---@param node nvim_tree.api.Node ---@return nvim_tree.api.decorator.highlighted_string? icon_node -function nvim_tree.api.decorator.UserDecorator:icon_node(node) end +function nvim_tree.api.decorator.Decorator:icon_node(node) end ---Abstract: optionally implement to provide icons and the highlight groups for your icon_placement. --- ---@param node nvim_tree.api.Node ---@return nvim_tree.api.decorator.highlighted_string[]? icons -function nvim_tree.api.decorator.UserDecorator:icons(node) end +function nvim_tree.api.decorator.Decorator:icons(node) end ---Abstract: optionally implement to provide one highlight group to apply to your highlight_range. --- ---@param node nvim_tree.api.Node ---@return string? highlight_group -function nvim_tree.api.decorator.UserDecorator:highlight_group(node) end +function nvim_tree.api.decorator.Decorator:highlight_group(node) end ----Define a sign. This should be called in the constructor. +---Defines a sign. This should be called in the constructor. --- ---@protected ---@param icon nvim_tree.api.decorator.highlighted_string? -function nvim_tree.api.decorator.UserDecorator:define_sign(icon) end +function nvim_tree.api.decorator.Decorator:define_sign(icon) end + +---@deprecated use `nvim_tree.api.decorator.Decorator` +---@class nvim_tree.api.decorator.UserDecorator: nvim_tree.api.decorator.Decorator +nvim_tree.api.decorator.UserDecorator = nvim_tree.api.decorator.Decorator + +return nvim_tree.api.decorator diff --git a/lua/nvim-tree/_meta/config/renderer.lua b/lua/nvim-tree/_meta/config/renderer.lua index e1ba26cbb91..ab9d6c5505e 100644 --- a/lua/nvim-tree/_meta/config/renderer.lua +++ b/lua/nvim-tree/_meta/config/renderer.lua @@ -62,7 +62,7 @@ error("Cannot require a meta file") ---@field symlink_destination? boolean --- ---(default: `{ "Git", "Open", "Hidden", "Modified", "Bookmark", "Diagnostics", "Copied", "Cut", }`) ----@field decorators? (string|nvim_tree.api.decorator.UserDecorator)[] +---@field decorators? (string|nvim_tree.api.decorator.Decorator)[] --- ---(default: `"none"`) ---@field highlight_git? nvim_tree.config.renderer.highlight diff --git a/lua/nvim-tree/api.lua b/lua/nvim-tree/api.lua index 04182a1b745..6c0be191624 100644 --- a/lua/nvim-tree/api.lua +++ b/lua/nvim-tree/api.lua @@ -69,16 +69,14 @@ --- --- Load the (empty) meta definitions --- -local deprecated = require("nvim-tree._meta.api.deprecated") - +--- ---nvim-tree Public API +--- ---@class nvim_tree.api ---@nodoc local api = { commands = require("nvim-tree._meta.api.commands"), + decorator = require("nvim-tree._meta.api_decorator"), events = require("nvim-tree._meta.api.events"), filter = require("nvim-tree._meta.api.filter"), fs = require("nvim-tree._meta.api.fs"), @@ -89,21 +87,11 @@ local api = { node = require("nvim-tree._meta.api.node"), tree = require("nvim-tree._meta.api.tree"), - config = deprecated.config, ---@deprecated - diagnostics = deprecated.diagnostics, ---@deprecated - live_filter = deprecated.live_filter, ---@deprecated + config = require("nvim-tree._meta.api.deprecated").config, ---@deprecated + diagnostics = require("nvim-tree._meta.api.deprecated").diagnostics, ---@deprecated + live_filter = require("nvim-tree._meta.api.deprecated").live_filter, ---@deprecated } - --- --- Map before-setup function implementations, most throw an error notification "nvim-tree setup not called". --- -require("nvim-tree.api.impl.pre")(api) - - ---#TODO 3241 ---Public API classes ---api.decorator = require("nvim-tree.api.decorator") - +require("nvim-tree.api.impl.pre").hydrate(api) return api diff --git a/lua/nvim-tree/api/impl/legacy.lua b/lua/nvim-tree/api/impl/legacy.lua index 51924b4f365..bcab89322d2 100644 --- a/lua/nvim-tree/api/impl/legacy.lua +++ b/lua/nvim-tree/api/impl/legacy.lua @@ -1,6 +1,8 @@ +local M = {} + ---Silently create new api entries pointing legacy functions to current ---@param api table not properly typed to prevent LSP from referencing implementations -return function(api) +function M.hydrate(api) api.config = api.config or {} api.config.mappings = api.config.mappings or {} api.config.mappings.get_keymap = api.map.keymap.current @@ -22,4 +24,8 @@ return function(api) api.diagnostics = api.diagnostics or {} api.diagnostics.hi_test = api.health.hi_test + + api.decorator.UserDecorator = api.decorator.Decorator end + +return M diff --git a/lua/nvim-tree/api/impl/post.lua b/lua/nvim-tree/api/impl/post.lua index 5c2d15de3d3..5d772387e6a 100644 --- a/lua/nvim-tree/api/impl/post.lua +++ b/lua/nvim-tree/api/impl/post.lua @@ -16,6 +16,8 @@ local DirectoryNode = require("nvim-tree.node.directory") local FileLinkNode = require("nvim-tree.node.file-link") local RootNode = require("nvim-tree.node.root") +local M = {} + ---Invoke a method on the singleton explorer. ---Print error when setup not called. ---@param explorer_method string explorer method name @@ -133,9 +135,9 @@ local function open_or_expand_or_dir_up(mode, toggle_group) end end ----Hydrate all implementations barring those that were called during hydrate_pre +---Re-Hydrate api functions and classes post-setup ---@param api table not properly typed to prevent LSP from referencing implementations -local function hydrate_post(api) +function M.hydrate(api) api.tree.open = actions.tree.open.fn api.tree.focus = api.tree.open @@ -252,16 +254,9 @@ local function hydrate_post(api) api.marks.navigate.select = wrap_explorer_member("marks", "navigate_select") api.map.keymap.current = keymap.get_keymap -end - ----#TODO 3241 hydrate function, for clarity - ----Re-hydrate api ----@param api table not properly typed to prevent LSP from referencing implementations -return function(api) - -- All concrete implementations - hydrate_post(api) -- (Re)hydrate any legacy by mapping to function set above - require("nvim-tree.api.impl.legacy")(api) + require("nvim-tree.api.impl.legacy").hydrate(api) end + +return M diff --git a/lua/nvim-tree/api/impl/pre.lua b/lua/nvim-tree/api/impl/pre.lua index 4736d88da55..0eed8f6b884 100644 --- a/lua/nvim-tree/api/impl/pre.lua +++ b/lua/nvim-tree/api/impl/pre.lua @@ -1,6 +1,7 @@ ---Hydrates meta api empty definition functions with a new function: --- - Default: error notification "nvim-tree setup not called". --- - Exceptions: concrete implementation for API that can be called before setup. +--Hydrates meta api empty definitions pre-setup: +-- - Pre-setup functions will be hydrated with their concrete implementation. +-- - Post-setup functions will notify error: "nvim-tree setup not called" +-- - All classes will be hydrated with their implementations. -- --Call it once when api is first required -- @@ -15,67 +16,44 @@ local notify = require("nvim-tree.notify") -- already required by events and local UserDecorator = require("nvim-tree.renderer.decorator.user") ----Walk the api, hydrating all functions with the error notification ----@param t table api root or sub-module +local M = {} + +---Walk the api, hydrating all functions with the error notification. +---Do not hydrate classes: anything with a metatable. +---@param t table local function hydrate_error(t) for k, v in pairs(t) do if type(v) == "function" then t[k] = function() notify.error("nvim-tree setup not called") end - elseif type(v) == "table" then + elseif type(v) == "table" and not getmetatable(v) then hydrate_error(v) end end end ----Hydrate implementations that may be called pre setup +---Hydrate api functions and classes pre-setup ---@param api table not properly typed to prevent LSP from referencing implementations -local function hydrate_pre(api) - -- - -- Essential - -- +function M.hydrate(api) + -- default to the error message + hydrate_error(api) + + -- eager functions api.events.Event = events.Event api.events.subscribe = events.subscribe - api.map.on_attach.default = keymap.on_attach_default - - - -- - -- May be lazily requried on execution - -- - api.health.hi_test = function() require("nvim-tree.appearance.hi-test")() end - - - -- - -- Already required elsewhere - -- api.commands.get = commands.get - api.map.keymap.default = keymap.get_keymap_default + -- lazy functions + api.health.hi_test = function() require("nvim-tree.appearance.hi-test")() end - -- - -- TODO #3241 - -- - api.decorator = {} - ---Create a decorator class by calling :extend() - ---See :help nvim-tree-decorators - ---@type nvim_tree.api.decorator.UserDecorator - api.decorator.UserDecorator = UserDecorator --[[@as nvim_tree.api.decorator.UserDecorator]] -end - ----#TODO 3241 hydrate function, for clarity - ----Hydrate api ----@param api table not properly typed to prevent LSP from referencing implementations -return function(api) - -- Default: error - hydrate_error(api) - - -- Exceptions: may be called - hydrate_pre(api) + -- classes + api.decorator.Decorator = UserDecorator:extend() -- Hydrate any legacy by mapping to function set above - require("nvim-tree.api.impl.legacy")(api) + require("nvim-tree.api.impl.legacy").hydrate(api) end + +return M diff --git a/lua/nvim-tree/renderer/builder.lua b/lua/nvim-tree/renderer/builder.lua index d74ed2c7d64..d38d64c2873 100644 --- a/lua/nvim-tree/renderer/builder.lua +++ b/lua/nvim-tree/renderer/builder.lua @@ -14,7 +14,7 @@ local GitDecorator = require("nvim-tree.renderer.decorator.git") local HiddenDecorator = require("nvim-tree.renderer.decorator.hidden") local ModifiedDecorator = require("nvim-tree.renderer.decorator.modified") local OpenDecorator = require("nvim-tree.renderer.decorator.opened") -local UserDecorator = require("nvim-tree.api").decorator.UserDecorator +local UserDecorator = require("nvim-tree.renderer.decorator.user") local pad = require("nvim-tree.renderer.components.padding") diff --git a/lua/nvim-tree/renderer/decorator/init.lua b/lua/nvim-tree/renderer/decorator/init.lua index 013ab0cba28..7552ed4b3ab 100644 --- a/lua/nvim-tree/renderer/decorator/init.lua +++ b/lua/nvim-tree/renderer/decorator/init.lua @@ -1,40 +1,14 @@ -local Class = require("nvim-tree.classic") - ---- #TODO 3241 split this into abstract interface for API and concrete to return to user - ----Abstract Decorator +---Abstract Decorator implementation ---@class (exact) Decorator: Class ---@field protected enabled boolean ---@field protected highlight_range nvim_tree.api.decorator.highlight_range ---@field protected icon_placement nvim_tree.api.decorator.icon_placement -local Decorator = Class:extend() +local Decorator = require("nvim-tree._meta.api_decorator").Decorator:extend() +---TODO #3241 maybe create an internal decorator class and lose the UserDecorator ---@class (exact) DecoratorArgs ---@field explorer Explorer ----Abstract icon override, optionally implemented ----@param node Node ----@return nvim_tree.api.decorator.highlighted_string? icon_node -function Decorator:icon_node(node) - return self:nop(node) -end - ----Abstract icons, optionally implemented ----@protected ----@param node Node ----@return nvim_tree.api.decorator.highlighted_string[]? icons -function Decorator:icons(node) - self:nop(node) -end - ----Abstract highlight group, optionally implemented ----@protected ----@param node Node ----@return string? highlight_group -function Decorator:highlight_group(node) - self:nop(node) -end - ---Maybe highlight groups for icon and name ---@param node Node ---@return string? icon highlight group From 973a9d84cccddbfa250133018769a94b2155ae3b Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Sun, 1 Feb 2026 13:25:53 +1100 Subject: [PATCH 05/27] docs(#3241): move decorator meta into place --- lua/nvim-tree/_meta/{api_decorator.lua => api/decorator.lua} | 0 lua/nvim-tree/api.lua | 2 +- lua/nvim-tree/renderer/decorator/init.lua | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) rename lua/nvim-tree/_meta/{api_decorator.lua => api/decorator.lua} (100%) diff --git a/lua/nvim-tree/_meta/api_decorator.lua b/lua/nvim-tree/_meta/api/decorator.lua similarity index 100% rename from lua/nvim-tree/_meta/api_decorator.lua rename to lua/nvim-tree/_meta/api/decorator.lua diff --git a/lua/nvim-tree/api.lua b/lua/nvim-tree/api.lua index 6c0be191624..67d06e688b4 100644 --- a/lua/nvim-tree/api.lua +++ b/lua/nvim-tree/api.lua @@ -76,7 +76,7 @@ ---@nodoc local api = { commands = require("nvim-tree._meta.api.commands"), - decorator = require("nvim-tree._meta.api_decorator"), + decorator = require("nvim-tree._meta.api.decorator"), events = require("nvim-tree._meta.api.events"), filter = require("nvim-tree._meta.api.filter"), fs = require("nvim-tree._meta.api.fs"), diff --git a/lua/nvim-tree/renderer/decorator/init.lua b/lua/nvim-tree/renderer/decorator/init.lua index 7552ed4b3ab..feff51d10c8 100644 --- a/lua/nvim-tree/renderer/decorator/init.lua +++ b/lua/nvim-tree/renderer/decorator/init.lua @@ -3,7 +3,7 @@ ---@field protected enabled boolean ---@field protected highlight_range nvim_tree.api.decorator.highlight_range ---@field protected icon_placement nvim_tree.api.decorator.icon_placement -local Decorator = require("nvim-tree._meta.api_decorator").Decorator:extend() +local Decorator = require("nvim-tree._meta.api.decorator").Decorator:extend() ---TODO #3241 maybe create an internal decorator class and lose the UserDecorator ---@class (exact) DecoratorArgs From 32ac1e0a1edd0c96cfd4c9730463646b12fae5c1 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Sun, 1 Feb 2026 16:59:31 +1100 Subject: [PATCH 06/27] docs(#3241): generate decorator help --- doc/nvim-tree-lua.txt | 119 +++++++++++++++++++++- lua/nvim-tree/_meta/api/decorator.lua | 38 ++++--- lua/nvim-tree/_meta/config/default.lua | 1 + lua/nvim-tree/api/impl/post.lua | 2 +- lua/nvim-tree/api/impl/pre.lua | 2 +- lua/nvim-tree/classic.lua | 6 +- lua/nvim-tree/renderer/decorator/init.lua | 2 +- scripts/vimdoc_config.lua | 90 +++++++++++----- 8 files changed, 215 insertions(+), 45 deletions(-) diff --git a/doc/nvim-tree-lua.txt b/doc/nvim-tree-lua.txt index 651de1096bd..a9e40615426 100644 --- a/doc/nvim-tree-lua.txt +++ b/doc/nvim-tree-lua.txt @@ -2362,9 +2362,6 @@ Following is the default configuration, see |nvim_tree.config| for details. >lua }, } < - - - ============================================================================== API *nvim-tree-api* @@ -3200,4 +3197,120 @@ winid({opts}) *nvim_tree.api.tree.winid()* (`integer?`) |window-ID|, nil if tree is not visible. +============================================================================== +API: Decorator *nvim-tree-api-decorator* + +*nvim_tree.api.decorator.Decorator* + Extends: |nvim_tree.Class| + + Abstract Decorator interface + + Fields: ~ + • {enabled} (`boolean`) + • {highlight_range} (`nvim_tree.api.decorator.highlight_range`) + • {icon_placement} (`nvim_tree.api.decorator.icon_placement`) + • {icon_node} (`fun(self: nvim_tree.api.decorator.Decorator, node: nvim_tree.api.Node): nvim_tree.api.decorator.highlighted_string?`) + See + |nvim_tree.api.decorator.Decorator:icon_node()|. + • {icons} (`fun(self: nvim_tree.api.decorator.Decorator, node: nvim_tree.api.Node): nvim_tree.api.decorator.highlighted_string[]?`) + See |nvim_tree.api.decorator.Decorator:icons()|. + • {highlight_group} (`fun(self: nvim_tree.api.decorator.Decorator, node: nvim_tree.api.Node): string?`) + See + |nvim_tree.api.decorator.Decorator:highlight_group()|. + • {define_sign} (`fun(self: nvim_tree.api.decorator.Decorator, icon: nvim_tree.api.decorator.highlighted_string?)`) + See + |nvim_tree.api.decorator.Decorator:define_sign()|. + + + *nvim_tree.api.decorator.Decorator:define_sign()* +Decorator:define_sign({icon}) + Defines a sign. This should be called in the constructor. + + Parameters: ~ + • {icon} (`nvim_tree.api.decorator.highlighted_string?`) + + *nvim_tree.api.decorator.Decorator:highlight_group()* +Decorator:highlight_group({node}) + Abstract: optionally implement to provide one highlight group to apply to + your highlight_range. + + Parameters: ~ + • {node} (`nvim_tree.api.Node`) + + Return: ~ + (`string?`) highlight_group + + *nvim_tree.api.decorator.Decorator:icon_node()* +Decorator:icon_node({node}) + Abstract: optionally implement to set the node's icon + + Parameters: ~ + • {node} (`nvim_tree.api.Node`) + + Return: ~ + (`nvim_tree.api.decorator.highlighted_string?`) icon_node + +Decorator:icons({node}) *nvim_tree.api.decorator.Decorator:icons()* + Abstract: optionally implement to provide icons and the highlight groups + for your icon_placement. + + Parameters: ~ + • {node} (`nvim_tree.api.Node`) + + Return: ~ + (`nvim_tree.api.decorator.highlighted_string[]?`) icons + + +============================================================================== +API: Class *nvim-tree-api-class* + +*nvim_tree.Class* + + Fields: ~ + • {super} (`Class`) + • {extend} (`fun(self: nvim_tree.Class)`) See + |nvim_tree.Class:extend()|. + • {implement} (`fun(self: nvim_tree.Class, mixin: Class)`) See + |nvim_tree.Class:implement()|. + • {is} (`fun(self: nvim_tree.Class, class: T): boolean`) See + |nvim_tree.Class:is()|. + • {as} (`fun(self: nvim_tree.Class, class: T): T?`) See + |nvim_tree.Class:as()|. + • {nop} (`fun(self: nvim_tree.Class, ...: any)`) See + |nvim_tree.Class:nop()|. + + +Class:as({class}) *nvim_tree.Class:as()* + Return object if :is otherwise nil + + Parameters: ~ + • {class} (`any`) + + Return: ~ + (`T?`) + +Class:extend() *nvim_tree.Class:extend()* + Extend a class, setting .super + +Class:implement({mixin}) *nvim_tree.Class:implement()* + Implement the functions of a mixin Add the mixin to .implements + + Parameters: ~ + • {mixin} (`Class`) + +Class:is({class}) *nvim_tree.Class:is()* + Object is an instance of class or implements a mixin + + Parameters: ~ + • {class} (`any`) + + Return: ~ + (`boolean`) + +Class:nop({...}) *nvim_tree.Class:nop()* + + Parameters: ~ + • {...} (`any`) + + vim:tw=78:ts=8:sw=4:sts=4:et:ft=help:norl: diff --git a/lua/nvim-tree/_meta/api/decorator.lua b/lua/nvim-tree/_meta/api/decorator.lua index 787c0e0f557..de347c7a7f0 100644 --- a/lua/nvim-tree/_meta/api/decorator.lua +++ b/lua/nvim-tree/_meta/api/decorator.lua @@ -1,57 +1,71 @@ ---@meta ---- local nvim_tree = { api = { decorator = {} } } local Class = require("nvim-tree.classic") +--- ---Highlight group range as per nvim-tree.renderer.highlight_* +--- ---@alias nvim_tree.api.decorator.highlight_range nvim_tree.config.renderer.highlight ---Icon position as per renderer.icons.*_placement +--- ---@alias nvim_tree.api.decorator.icon_placement "none"|nvim_tree.config.renderer.icons.placement +--- ---Names of builtin decorators or your decorator classes. Builtins are ordered lowest to highest priority. +--- ---@alias nvim_tree.api.decorator.types nvim_tree.api.decorator.Decorator|"Git"|"Opened"|"Hidden"|"Modified"|"Bookmarks"|"Diagnostics"|"Copied"|"Cut" +--- ---A string for rendering, with optional highlight groups to apply to it +--- ---@class (exact) nvim_tree.api.decorator.highlighted_string ---@field str string ---@field hl string[] +--- ---Abstract Decorator interface --- ----@class (exact) nvim_tree.api.decorator.Decorator: Class ----@field protected enabled boolean ----@field protected highlight_range nvim_tree.api.decorator.highlight_range ----@field protected icon_placement nvim_tree.api.decorator.icon_placement -nvim_tree.api.decorator.Decorator = Class:extend() +---@class nvim_tree.api.decorator.Decorator: nvim_tree.Class +---@field enabled boolean +---@field highlight_range nvim_tree.api.decorator.highlight_range +---@field icon_placement nvim_tree.api.decorator.icon_placement +local Decorator = Class:extend() +nvim_tree.api.decorator.Decorator = Decorator +--- ---Abstract: optionally implement to set the node's icon --- ---@param node nvim_tree.api.Node ---@return nvim_tree.api.decorator.highlighted_string? icon_node -function nvim_tree.api.decorator.Decorator:icon_node(node) end +function Decorator:icon_node(node) end +--- ---Abstract: optionally implement to provide icons and the highlight groups for your icon_placement. --- ---@param node nvim_tree.api.Node ---@return nvim_tree.api.decorator.highlighted_string[]? icons -function nvim_tree.api.decorator.Decorator:icons(node) end +function Decorator:icons(node) end +--- ---Abstract: optionally implement to provide one highlight group to apply to your highlight_range. --- ---@param node nvim_tree.api.Node ---@return string? highlight_group -function nvim_tree.api.decorator.Decorator:highlight_group(node) end +function Decorator:highlight_group(node) end +--- ---Defines a sign. This should be called in the constructor. --- ----@protected ---@param icon nvim_tree.api.decorator.highlighted_string? -function nvim_tree.api.decorator.Decorator:define_sign(icon) end +function Decorator:define_sign(icon) end ----@deprecated use `nvim_tree.api.decorator.Decorator` +--- ---@class nvim_tree.api.decorator.UserDecorator: nvim_tree.api.decorator.Decorator +---@nodoc +---@deprecated use `nvim_tree.api.decorator.Decorator` +--- nvim_tree.api.decorator.UserDecorator = nvim_tree.api.decorator.Decorator return nvim_tree.api.decorator diff --git a/lua/nvim-tree/_meta/config/default.lua b/lua/nvim-tree/_meta/config/default.lua index 1f1252f7483..710c6cb3502 100644 --- a/lua/nvim-tree/_meta/config/default.lua +++ b/lua/nvim-tree/_meta/config/default.lua @@ -9,3 +9,4 @@ ---} ---``` --- +---placeholder for next section [nvim-tree-api]() diff --git a/lua/nvim-tree/api/impl/post.lua b/lua/nvim-tree/api/impl/post.lua index 5d772387e6a..181753a34ce 100644 --- a/lua/nvim-tree/api/impl/post.lua +++ b/lua/nvim-tree/api/impl/post.lua @@ -255,7 +255,7 @@ function M.hydrate(api) api.map.keymap.current = keymap.get_keymap - -- (Re)hydrate any legacy by mapping to function set above + -- (Re)hydrate any legacy by mapping to concrete set above require("nvim-tree.api.impl.legacy").hydrate(api) end diff --git a/lua/nvim-tree/api/impl/pre.lua b/lua/nvim-tree/api/impl/pre.lua index 0eed8f6b884..1bdf4dfaf0b 100644 --- a/lua/nvim-tree/api/impl/pre.lua +++ b/lua/nvim-tree/api/impl/pre.lua @@ -52,7 +52,7 @@ function M.hydrate(api) -- classes api.decorator.Decorator = UserDecorator:extend() - -- Hydrate any legacy by mapping to function set above + -- Hydrate any legacy by mapping to concrete set above require("nvim-tree.api.impl.legacy").hydrate(api) end diff --git a/lua/nvim-tree/classic.lua b/lua/nvim-tree/classic.lua index 6e856bc90c0..08a05c1ee44 100644 --- a/lua/nvim-tree/classic.lua +++ b/lua/nvim-tree/classic.lua @@ -9,7 +9,11 @@ -- https://github.com/rxi/classic -- ----@class (exact) Class +---TODO #3241 document and rename +---@class Class: nvim_tree.Class +---@nodoc + +---@class nvim_tree.Class ---@field super Class ---@field private implements table local Class = {} diff --git a/lua/nvim-tree/renderer/decorator/init.lua b/lua/nvim-tree/renderer/decorator/init.lua index feff51d10c8..e3cbe4b6666 100644 --- a/lua/nvim-tree/renderer/decorator/init.lua +++ b/lua/nvim-tree/renderer/decorator/init.lua @@ -5,7 +5,7 @@ ---@field protected icon_placement nvim_tree.api.decorator.icon_placement local Decorator = require("nvim-tree._meta.api.decorator").Decorator:extend() ----TODO #3241 maybe create an internal decorator class and lose the UserDecorator +---TODO #3241 create an internal decorator class with explorer member and lose the UserDecorator ---@class (exact) DecoratorArgs ---@field explorer Explorer diff --git a/scripts/vimdoc_config.lua b/scripts/vimdoc_config.lua index ec19468ad03..a18e769b939 100644 --- a/scripts/vimdoc_config.lua +++ b/scripts/vimdoc_config.lua @@ -10,6 +10,14 @@ ---@field section string arbitrary ---@field path string relative to root +---TODO #3241 do this for all classes, moving decorator up to nvim_tree.api.Decorator + +---Module overrides +---@type table +local module_overrides = { + ["nvim_tree.classic"] = "nvim_tree" +} + local pre = "runtime/lua/nvim_tree/" ---@type Src[] @@ -39,24 +47,24 @@ local srcs_config = { { helptag = "nvim-tree-config-log", section = "Config: log", path = pre .. "_meta/config/log.lua", }, { helptag = "nvim-tree-config-default", section = "Config: Default", path = pre .. "_meta/config/default.lua", }, - - { helptag = "nvim-tree-api", section = "placeholder for next Config", path = pre .. "api.lua", }, } ---@type Src[] local srcs_api = { - { helptag = "nvim-tree-api", section = "API", path = pre .. "api.lua", }, - - { helptag = "nvim-tree-api-commands", section = "API: commands", path = pre .. "_meta/api/commands.lua", }, - { helptag = "nvim-tree-api-events", section = "API: events", path = pre .. "_meta/api/events.lua", }, - { helptag = "nvim-tree-api-filter", section = "API: filter", path = pre .. "_meta/api/filter.lua", }, - { helptag = "nvim-tree-api-fs", section = "API: fs", path = pre .. "_meta/api/fs.lua", }, - { helptag = "nvim-tree-api-git", section = "API: git", path = pre .. "_meta/api/git.lua", }, - { helptag = "nvim-tree-api-health", section = "API: health", path = pre .. "_meta/api/health.lua", }, - { helptag = "nvim-tree-api-map", section = "API: map", path = pre .. "_meta/api/map.lua", }, - { helptag = "nvim-tree-api-marks", section = "API: marks", path = pre .. "_meta/api/marks.lua", }, - { helptag = "nvim-tree-api-node", section = "API: node", path = pre .. "_meta/api/node.lua", }, - { helptag = "nvim-tree-api-tree", section = "API: tree", path = pre .. "_meta/api/tree.lua", }, + { helptag = "nvim-tree-api", section = "API", path = pre .. "api.lua", }, + + { helptag = "nvim-tree-api-commands", section = "API: commands", path = pre .. "_meta/api/commands.lua", }, + { helptag = "nvim-tree-api-events", section = "API: events", path = pre .. "_meta/api/events.lua", }, + { helptag = "nvim-tree-api-filter", section = "API: filter", path = pre .. "_meta/api/filter.lua", }, + { helptag = "nvim-tree-api-fs", section = "API: fs", path = pre .. "_meta/api/fs.lua", }, + { helptag = "nvim-tree-api-git", section = "API: git", path = pre .. "_meta/api/git.lua", }, + { helptag = "nvim-tree-api-health", section = "API: health", path = pre .. "_meta/api/health.lua", }, + { helptag = "nvim-tree-api-map", section = "API: map", path = pre .. "_meta/api/map.lua", }, + { helptag = "nvim-tree-api-marks", section = "API: marks", path = pre .. "_meta/api/marks.lua", }, + { helptag = "nvim-tree-api-node", section = "API: node", path = pre .. "_meta/api/node.lua", }, + { helptag = "nvim-tree-api-tree", section = "API: tree", path = pre .. "_meta/api/tree.lua", }, + { helptag = "nvim-tree-api-decorator", section = "API: Decorator", path = pre .. "_meta/api/decorator.lua", }, + { helptag = "nvim-tree-api-class", section = "API: Class", path = pre .. "classic.lua", }, } ---Map paths to file names @@ -92,6 +100,17 @@ local function src_by_name(name, srcs) error(string.format("\n\nPath for lower, extension stripped file name='%s' not found in\nsrcs=%s\n", name, vim.inspect(srcs))) end +---HACK +---Problem: +--- Generator generates fields for a class' methods. +--- This is a problem as method fields don't have a module and aren't transformed. +--- Method field fun only contains: classvar, desc, name and (function) type +---Solution: +--- Collect a map of "class:method" to modules when the real method passes through fn_xform +--- This works as the real method function is processed before the field method. +---@type table +local modules_by_method = {} + -- @type nvim.gen_vimdoc.Config[] return { -- Config @@ -110,23 +129,42 @@ return { section_fmt = function(name) return src_by_name(name, srcs_api).section end, helptag_fmt = function(name) return src_by_name(name, srcs_api).helptag end, - -- optional, no default xform to override fn_xform = function(fun) - if (fun.module) then - -- generator doesn't strip meta - -- also cascades into fn_helptag_fmt - local module = fun.module:gsub("._meta", "", 1) - - -- remove the API prefix from the left aligned function name - -- this will cascade into fn_helptag_fmt, which will apply the module prefix anyway - local name, replaced = fun.name:gsub("^" .. module .. "%.", "", 1) + -- generator doesn't strip _meta; this propagates to fn_helptag_fmt + fun.module = fun.module:gsub("._meta", "", 1) + fun.module = module_overrides[fun.module] or fun.module + + if not fun.class then + -- functions require the module to be stripped from the name, classes do not + local name, replaced = fun.name:gsub("^" .. fun.module .. "%.", "", 1) if (replaced ~= 1) then - error(string.format("\n\nfun.name='%s' does not start with _meta stripped module='%s'\nfun=%s", fun.name, module, vim.inspect(fun))) + error(string.format("\n\nfn_xform: fun.name='%s' does not start with _meta stripped \nfun=%s", + fun.name, vim.inspect(fun))) end - - fun.module = module fun.name = name + elseif fun.class and fun.classvar and fun.name then + -- note the module for use by method fields + modules_by_method[fun.classvar .. ":" .. fun.name] = fun.module + end + end, + + -- fn_helptag_fmt_common modified: + -- module prepended to classes + -- module is fetched from modules_by_method when fun.module unavailable + fn_helptag_fmt = function(fun) + local fn_sfx = fun.table and "" or "()" + if fun.classvar then + local module = fun.module or modules_by_method[fun.classvar .. ":" .. fun.name] + if not module then + error(string.format("\n\nfn_helptag_fmt: no module:\nfun=%s\nmodules_by_method=%s", + vim.inspect(fun), vim.inspect(modules_by_method))) + end + return string.format("%s.%s:%s%s", module, fun.classvar, fun.name, fn_sfx) + end + if fun.module then + return string.format("%s.%s%s", fun.module, fun.name, fn_sfx) end + return fun.name .. fn_sfx end, } } From d61841e9e08c94b6064035f86b593b9d23592087 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Sun, 1 Feb 2026 17:53:15 +1100 Subject: [PATCH 07/27] docs(#3241): separate api and class generation configs, namespace classes without their filename, nicer generation placeholder --- doc/nvim-tree-lua.txt | 46 +++++----- lua/nvim-tree/_meta/api/decorator.lua | 17 ++-- lua/nvim-tree/_meta/api/deprecated.lua | 6 ++ lua/nvim-tree/_meta/config/default.lua | 2 - lua/nvim-tree/_meta/config/renderer.lua | 2 +- lua/nvim-tree/api.lua | 4 +- lua/nvim-tree/api/impl/legacy.lua | 2 +- lua/nvim-tree/api/impl/pre.lua | 2 +- lua/nvim-tree/classic.lua | 4 +- lua/nvim-tree/renderer/decorator/init.lua | 2 +- scripts/vimdoc_config.lua | 102 +++++++++++----------- 11 files changed, 94 insertions(+), 95 deletions(-) diff --git a/doc/nvim-tree-lua.txt b/doc/nvim-tree-lua.txt index a9e40615426..a5ebc95061a 100644 --- a/doc/nvim-tree-lua.txt +++ b/doc/nvim-tree-lua.txt @@ -890,12 +890,12 @@ Require and register it during |nvim-tree-setup|: < Contents of `my-decorator.lua`: >lua - ---@class (exact) MyDecorator: nvim_tree.api.decorator.Decorator + ---@class (exact) MyDecorator: nvim_tree.api.Decorator ---@field private my_icon1 nvim_tree.api.decorator.highlighted_string ---@field private my_icon2 nvim_tree.api.decorator.highlighted_string ---@field private my_icon_node nvim_tree.api.decorator.highlighted_string ---@field private my_highlight_group string - local MyDecorator = require("nvim-tree.api").decorator.Decorator:extend() + local MyDecorator = require("nvim-tree.api").Decorator:extend() ---Mandatory constructor :new() will be called once per tree render, with no arguments. function MyDecorator:new() @@ -1366,7 +1366,7 @@ Config: renderer *nvim-tree-config-renderer* • {symlink_destination}? (`boolean`, default: `true`) Appends an arrow followed by the target of the symlink. - • {decorators}? (`(string|nvim_tree.api.decorator.Decorator)[]`) + • {decorators}? (`(string|nvim_tree.api.Decorator)[]`) (default: `{ "Git", "Open", "Hidden", "Modified", "Bookmark", "Diagnostics", "Copied", "Cut", }`) • {highlight_git}? (`nvim_tree.config.renderer.highlight`) @@ -2362,6 +2362,9 @@ Following is the default configuration, see |nvim_tree.config| for details. >lua }, } < + + + ============================================================================== API *nvim-tree-api* @@ -3200,7 +3203,7 @@ winid({opts}) *nvim_tree.api.tree.winid()* ============================================================================== API: Decorator *nvim-tree-api-decorator* -*nvim_tree.api.decorator.Decorator* +*nvim_tree.api.Decorator* Extends: |nvim_tree.Class| Abstract Decorator interface @@ -3209,27 +3212,23 @@ API: Decorator *nvim-tree-api-decorator* • {enabled} (`boolean`) • {highlight_range} (`nvim_tree.api.decorator.highlight_range`) • {icon_placement} (`nvim_tree.api.decorator.icon_placement`) - • {icon_node} (`fun(self: nvim_tree.api.decorator.Decorator, node: nvim_tree.api.Node): nvim_tree.api.decorator.highlighted_string?`) - See - |nvim_tree.api.decorator.Decorator:icon_node()|. - • {icons} (`fun(self: nvim_tree.api.decorator.Decorator, node: nvim_tree.api.Node): nvim_tree.api.decorator.highlighted_string[]?`) - See |nvim_tree.api.decorator.Decorator:icons()|. - • {highlight_group} (`fun(self: nvim_tree.api.decorator.Decorator, node: nvim_tree.api.Node): string?`) - See - |nvim_tree.api.decorator.Decorator:highlight_group()|. - • {define_sign} (`fun(self: nvim_tree.api.decorator.Decorator, icon: nvim_tree.api.decorator.highlighted_string?)`) - See - |nvim_tree.api.decorator.Decorator:define_sign()|. - - - *nvim_tree.api.decorator.Decorator:define_sign()* -Decorator:define_sign({icon}) + • {icon_node} (`fun(self: nvim_tree.api.Decorator, node: nvim_tree.api.Node): nvim_tree.api.decorator.highlighted_string?`) + See |nvim_tree.api.Decorator:icon_node()|. + • {icons} (`fun(self: nvim_tree.api.Decorator, node: nvim_tree.api.Node): nvim_tree.api.decorator.highlighted_string[]?`) + See |nvim_tree.api.Decorator:icons()|. + • {highlight_group} (`fun(self: nvim_tree.api.Decorator, node: nvim_tree.api.Node): string?`) + See |nvim_tree.api.Decorator:highlight_group()|. + • {define_sign} (`fun(self: nvim_tree.api.Decorator, icon: nvim_tree.api.decorator.highlighted_string?)`) + See |nvim_tree.api.Decorator:define_sign()|. + + +Decorator:define_sign({icon}) *nvim_tree.api.Decorator:define_sign()* Defines a sign. This should be called in the constructor. Parameters: ~ • {icon} (`nvim_tree.api.decorator.highlighted_string?`) - *nvim_tree.api.decorator.Decorator:highlight_group()* + *nvim_tree.api.Decorator:highlight_group()* Decorator:highlight_group({node}) Abstract: optionally implement to provide one highlight group to apply to your highlight_range. @@ -3240,8 +3239,7 @@ Decorator:highlight_group({node}) Return: ~ (`string?`) highlight_group - *nvim_tree.api.decorator.Decorator:icon_node()* -Decorator:icon_node({node}) +Decorator:icon_node({node}) *nvim_tree.api.Decorator:icon_node()* Abstract: optionally implement to set the node's icon Parameters: ~ @@ -3250,7 +3248,7 @@ Decorator:icon_node({node}) Return: ~ (`nvim_tree.api.decorator.highlighted_string?`) icon_node -Decorator:icons({node}) *nvim_tree.api.decorator.Decorator:icons()* +Decorator:icons({node}) *nvim_tree.api.Decorator:icons()* Abstract: optionally implement to provide icons and the highlight groups for your icon_placement. @@ -3281,7 +3279,7 @@ API: Class *nvim-tree-api-class* Class:as({class}) *nvim_tree.Class:as()* - Return object if :is otherwise nil + Return object if |nvim_tree.Class:is()| otherwise nil Parameters: ~ • {class} (`any`) diff --git a/lua/nvim-tree/_meta/api/decorator.lua b/lua/nvim-tree/_meta/api/decorator.lua index de347c7a7f0..9ebb9954ab2 100644 --- a/lua/nvim-tree/_meta/api/decorator.lua +++ b/lua/nvim-tree/_meta/api/decorator.lua @@ -1,5 +1,5 @@ ---@meta -local nvim_tree = { api = { decorator = {} } } +local nvim_tree = { api = {} } local Class = require("nvim-tree.classic") @@ -15,7 +15,7 @@ local Class = require("nvim-tree.classic") --- ---Names of builtin decorators or your decorator classes. Builtins are ordered lowest to highest priority. --- ----@alias nvim_tree.api.decorator.types nvim_tree.api.decorator.Decorator|"Git"|"Opened"|"Hidden"|"Modified"|"Bookmarks"|"Diagnostics"|"Copied"|"Cut" +---@alias nvim_tree.api.decorator.types nvim_tree.api.Decorator|"Git"|"Opened"|"Hidden"|"Modified"|"Bookmarks"|"Diagnostics"|"Copied"|"Cut" --- ---A string for rendering, with optional highlight groups to apply to it @@ -27,12 +27,12 @@ local Class = require("nvim-tree.classic") --- ---Abstract Decorator interface --- ----@class nvim_tree.api.decorator.Decorator: nvim_tree.Class +---@class nvim_tree.api.Decorator: nvim_tree.Class ---@field enabled boolean ---@field highlight_range nvim_tree.api.decorator.highlight_range ---@field icon_placement nvim_tree.api.decorator.icon_placement local Decorator = Class:extend() -nvim_tree.api.decorator.Decorator = Decorator +nvim_tree.api.Decorator = Decorator --- ---Abstract: optionally implement to set the node's icon @@ -61,11 +61,4 @@ function Decorator:highlight_group(node) end ---@param icon nvim_tree.api.decorator.highlighted_string? function Decorator:define_sign(icon) end ---- ----@class nvim_tree.api.decorator.UserDecorator: nvim_tree.api.decorator.Decorator ----@nodoc ----@deprecated use `nvim_tree.api.decorator.Decorator` ---- -nvim_tree.api.decorator.UserDecorator = nvim_tree.api.decorator.Decorator - -return nvim_tree.api.decorator +return nvim_tree.api.Decorator diff --git a/lua/nvim-tree/_meta/api/deprecated.lua b/lua/nvim-tree/_meta/api/deprecated.lua index fdd4b88e85a..f9f37852225 100644 --- a/lua/nvim-tree/_meta/api/deprecated.lua +++ b/lua/nvim-tree/_meta/api/deprecated.lua @@ -30,4 +30,10 @@ nvim_tree.api.diagnostics = {} ---@deprecated use `nvim_tree.api.health.hi_test()` function nvim_tree.api.diagnostics.hi_test() end +nvim_tree.api.decorator = {} + +---@class nvim_tree.api.decorator.UserDecorator: nvim_tree.api.Decorator +---@deprecated use `nvim_tree.api.Decorator` +nvim_tree.api.decorator.UserDecorator = nvim_tree.api.Decorator + return nvim_tree.api diff --git a/lua/nvim-tree/_meta/config/default.lua b/lua/nvim-tree/_meta/config/default.lua index 710c6cb3502..6566a1ed4ab 100644 --- a/lua/nvim-tree/_meta/config/default.lua +++ b/lua/nvim-tree/_meta/config/default.lua @@ -8,5 +8,3 @@ ---default-config-injection-placeholder ---} ---``` ---- ----placeholder for next section [nvim-tree-api]() diff --git a/lua/nvim-tree/_meta/config/renderer.lua b/lua/nvim-tree/_meta/config/renderer.lua index ab9d6c5505e..8979eb8614e 100644 --- a/lua/nvim-tree/_meta/config/renderer.lua +++ b/lua/nvim-tree/_meta/config/renderer.lua @@ -62,7 +62,7 @@ error("Cannot require a meta file") ---@field symlink_destination? boolean --- ---(default: `{ "Git", "Open", "Hidden", "Modified", "Bookmark", "Diagnostics", "Copied", "Cut", }`) ----@field decorators? (string|nvim_tree.api.decorator.Decorator)[] +---@field decorators? (string|nvim_tree.api.Decorator)[] --- ---(default: `"none"`) ---@field highlight_git? nvim_tree.config.renderer.highlight diff --git a/lua/nvim-tree/api.lua b/lua/nvim-tree/api.lua index 67d06e688b4..81250fe5fca 100644 --- a/lua/nvim-tree/api.lua +++ b/lua/nvim-tree/api.lua @@ -76,7 +76,6 @@ ---@nodoc local api = { commands = require("nvim-tree._meta.api.commands"), - decorator = require("nvim-tree._meta.api.decorator"), events = require("nvim-tree._meta.api.events"), filter = require("nvim-tree._meta.api.filter"), fs = require("nvim-tree._meta.api.fs"), @@ -87,7 +86,10 @@ local api = { node = require("nvim-tree._meta.api.node"), tree = require("nvim-tree._meta.api.tree"), + Decorator = require("nvim-tree._meta.api.decorator"), + config = require("nvim-tree._meta.api.deprecated").config, ---@deprecated + decorator = require("nvim-tree._meta.api.deprecated").decorator, ---@deprecated diagnostics = require("nvim-tree._meta.api.deprecated").diagnostics, ---@deprecated live_filter = require("nvim-tree._meta.api.deprecated").live_filter, ---@deprecated } diff --git a/lua/nvim-tree/api/impl/legacy.lua b/lua/nvim-tree/api/impl/legacy.lua index bcab89322d2..66f817f6669 100644 --- a/lua/nvim-tree/api/impl/legacy.lua +++ b/lua/nvim-tree/api/impl/legacy.lua @@ -25,7 +25,7 @@ function M.hydrate(api) api.diagnostics = api.diagnostics or {} api.diagnostics.hi_test = api.health.hi_test - api.decorator.UserDecorator = api.decorator.Decorator + api.decorator.UserDecorator = api.Decorator end return M diff --git a/lua/nvim-tree/api/impl/pre.lua b/lua/nvim-tree/api/impl/pre.lua index 1bdf4dfaf0b..5ce5f67ac05 100644 --- a/lua/nvim-tree/api/impl/pre.lua +++ b/lua/nvim-tree/api/impl/pre.lua @@ -50,7 +50,7 @@ function M.hydrate(api) api.health.hi_test = function() require("nvim-tree.appearance.hi-test")() end -- classes - api.decorator.Decorator = UserDecorator:extend() + api.Decorator = UserDecorator:extend() -- Hydrate any legacy by mapping to concrete set above require("nvim-tree.api.impl.legacy").hydrate(api) diff --git a/lua/nvim-tree/classic.lua b/lua/nvim-tree/classic.lua index 08a05c1ee44..1431e5bb38c 100644 --- a/lua/nvim-tree/classic.lua +++ b/lua/nvim-tree/classic.lua @@ -72,7 +72,7 @@ function Class:is(class) return false end ----Return object if :is otherwise nil +---Return object if [nvim_tree.Class:is()] otherwise nil ---@generic T ---@param class T ---@return T|nil @@ -80,7 +80,7 @@ function Class:as(class) return self:is(class) and self or nil end ----Constructor to create instance, call :new and return +---Constructor to create instance, call [nvim_tree.Class:new()] and return function Class:__call(...) local obj = setmetatable({}, self) obj:new(...) diff --git a/lua/nvim-tree/renderer/decorator/init.lua b/lua/nvim-tree/renderer/decorator/init.lua index e3cbe4b6666..d5d2b1a7931 100644 --- a/lua/nvim-tree/renderer/decorator/init.lua +++ b/lua/nvim-tree/renderer/decorator/init.lua @@ -3,7 +3,7 @@ ---@field protected enabled boolean ---@field protected highlight_range nvim_tree.api.decorator.highlight_range ---@field protected icon_placement nvim_tree.api.decorator.icon_placement -local Decorator = require("nvim-tree._meta.api.decorator").Decorator:extend() +local Decorator = require("nvim-tree._meta.api.decorator"):extend() ---TODO #3241 create an internal decorator class with explorer member and lose the UserDecorator ---@class (exact) DecoratorArgs diff --git a/scripts/vimdoc_config.lua b/scripts/vimdoc_config.lua index a18e769b939..ef57e2ef15c 100644 --- a/scripts/vimdoc_config.lua +++ b/scripts/vimdoc_config.lua @@ -10,14 +10,6 @@ ---@field section string arbitrary ---@field path string relative to root ----TODO #3241 do this for all classes, moving decorator up to nvim_tree.api.Decorator - ----Module overrides ----@type table -local module_overrides = { - ["nvim_tree.classic"] = "nvim_tree" -} - local pre = "runtime/lua/nvim_tree/" ---@type Src[] @@ -47,22 +39,30 @@ local srcs_config = { { helptag = "nvim-tree-config-log", section = "Config: log", path = pre .. "_meta/config/log.lua", }, { helptag = "nvim-tree-config-default", section = "Config: Default", path = pre .. "_meta/config/default.lua", }, + + { helptag = "nvim-tree-api", section = "PLACEHOLDER", path = "runtime/lua/placeholder.lua", }, } ---@type Src[] local srcs_api = { - { helptag = "nvim-tree-api", section = "API", path = pre .. "api.lua", }, - - { helptag = "nvim-tree-api-commands", section = "API: commands", path = pre .. "_meta/api/commands.lua", }, - { helptag = "nvim-tree-api-events", section = "API: events", path = pre .. "_meta/api/events.lua", }, - { helptag = "nvim-tree-api-filter", section = "API: filter", path = pre .. "_meta/api/filter.lua", }, - { helptag = "nvim-tree-api-fs", section = "API: fs", path = pre .. "_meta/api/fs.lua", }, - { helptag = "nvim-tree-api-git", section = "API: git", path = pre .. "_meta/api/git.lua", }, - { helptag = "nvim-tree-api-health", section = "API: health", path = pre .. "_meta/api/health.lua", }, - { helptag = "nvim-tree-api-map", section = "API: map", path = pre .. "_meta/api/map.lua", }, - { helptag = "nvim-tree-api-marks", section = "API: marks", path = pre .. "_meta/api/marks.lua", }, - { helptag = "nvim-tree-api-node", section = "API: node", path = pre .. "_meta/api/node.lua", }, - { helptag = "nvim-tree-api-tree", section = "API: tree", path = pre .. "_meta/api/tree.lua", }, + { helptag = "nvim-tree-api", section = "API", path = pre .. "api.lua", }, + + { helptag = "nvim-tree-api-commands", section = "API: commands", path = pre .. "_meta/api/commands.lua", }, + { helptag = "nvim-tree-api-events", section = "API: events", path = pre .. "_meta/api/events.lua", }, + { helptag = "nvim-tree-api-filter", section = "API: filter", path = pre .. "_meta/api/filter.lua", }, + { helptag = "nvim-tree-api-fs", section = "API: fs", path = pre .. "_meta/api/fs.lua", }, + { helptag = "nvim-tree-api-git", section = "API: git", path = pre .. "_meta/api/git.lua", }, + { helptag = "nvim-tree-api-health", section = "API: health", path = pre .. "_meta/api/health.lua", }, + { helptag = "nvim-tree-api-map", section = "API: map", path = pre .. "_meta/api/map.lua", }, + { helptag = "nvim-tree-api-marks", section = "API: marks", path = pre .. "_meta/api/marks.lua", }, + { helptag = "nvim-tree-api-node", section = "API: node", path = pre .. "_meta/api/node.lua", }, + { helptag = "nvim-tree-api-tree", section = "API: tree", path = pre .. "_meta/api/tree.lua", }, + + { helptag = "nvim-tree-api-decorator", section = "PLACEHOLDER", path = "runtime/lua/placeholder.lua", }, +} + +---@type Src[] +local srcs_class = { { helptag = "nvim-tree-api-decorator", section = "API: Decorator", path = pre .. "_meta/api/decorator.lua", }, { helptag = "nvim-tree-api-class", section = "API: Class", path = pre .. "classic.lua", }, } @@ -100,6 +100,11 @@ local function src_by_name(name, srcs) error(string.format("\n\nPath for lower, extension stripped file name='%s' not found in\nsrcs=%s\n", name, vim.inspect(srcs))) end +-- generator doesn't strip _meta +local function normalise_module(fun) + fun.module = fun.module and fun.module:gsub("._meta", "", 1) or nil +end + ---HACK ---Problem: --- Generator generates fields for a class' methods. @@ -129,42 +134,39 @@ return { section_fmt = function(name) return src_by_name(name, srcs_api).section end, helptag_fmt = function(name) return src_by_name(name, srcs_api).helptag end, + -- strip module from the name fn_xform = function(fun) - -- generator doesn't strip _meta; this propagates to fn_helptag_fmt - fun.module = fun.module:gsub("._meta", "", 1) - fun.module = module_overrides[fun.module] or fun.module - - if not fun.class then - -- functions require the module to be stripped from the name, classes do not - local name, replaced = fun.name:gsub("^" .. fun.module .. "%.", "", 1) - if (replaced ~= 1) then - error(string.format("\n\nfn_xform: fun.name='%s' does not start with _meta stripped \nfun=%s", - fun.name, vim.inspect(fun))) - end - fun.name = name - elseif fun.class and fun.classvar and fun.name then - -- note the module for use by method fields - modules_by_method[fun.classvar .. ":" .. fun.name] = fun.module - end + normalise_module(fun) + fun.name = fun.name:gsub("^" .. fun.module .. "%.", "", 1) end, + }, + -- Classes + { + filename = "nvim-tree-lua.txt", + section_order = section_order(srcs_class), + files = files(srcs_class), + section_fmt = function(name) return src_by_name(name, srcs_class).section end, + helptag_fmt = function(name) return src_by_name(name, srcs_class).helptag end, + + fn_xform = function(fun) + -- strip module from name and record the module for the method + normalise_module(fun) - -- fn_helptag_fmt_common modified: + -- strip the class file from the module + fun.module = fun.module:gsub("%.[^%.]*$", "", 1) + + -- strip module from name and record the module for the method + modules_by_method[fun.classvar .. ":" .. fun.name] = fun.module + print(vim.inspect(modules_by_method)) + end, + + -- fn_helptag_fmt_common derived -- module prepended to classes -- module is fetched from modules_by_method when fun.module unavailable fn_helptag_fmt = function(fun) local fn_sfx = fun.table and "" or "()" - if fun.classvar then - local module = fun.module or modules_by_method[fun.classvar .. ":" .. fun.name] - if not module then - error(string.format("\n\nfn_helptag_fmt: no module:\nfun=%s\nmodules_by_method=%s", - vim.inspect(fun), vim.inspect(modules_by_method))) - end - return string.format("%s.%s:%s%s", module, fun.classvar, fun.name, fn_sfx) - end - if fun.module then - return string.format("%s.%s%s", fun.module, fun.name, fn_sfx) - end - return fun.name .. fn_sfx + local module = fun.module or modules_by_method[fun.classvar .. ":" .. fun.name] + return string.format("%s.%s:%s%s", module, fun.classvar, fun.name, fn_sfx) end, - } + }, } From 58d4b2a9925e90f63bfc6944f66a83d884393082 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Mon, 2 Feb 2026 16:13:19 +1100 Subject: [PATCH 08/27] docs(#3241): fix potential bug in builder: passing a nil node to a user decorator --- lua/nvim-tree/renderer/builder.lua | 47 ++++++++++++++++++++++++------ 1 file changed, 38 insertions(+), 9 deletions(-) diff --git a/lua/nvim-tree/renderer/builder.lua b/lua/nvim-tree/renderer/builder.lua index d38d64c2873..0c76ab515f5 100644 --- a/lua/nvim-tree/renderer/builder.lua +++ b/lua/nvim-tree/renderer/builder.lua @@ -155,23 +155,39 @@ function Builder:format_line(indent_markers, arrows, icon, name, node) -- use the api node for user decorators local api_node = self.api_nodes and self.api_nodes[node.uid_node] --[[@as Node]] + local u local line = { indent_markers, arrows } add_to_end(line, { icon }) for _, d in ipairs(self.decorators) do - add_to_end(line, d:icons_before(not d:is(UserDecorator) and node or api_node)) + u = d:as(UserDecorator) + if not u then + add_to_end(line, d:icons_before(node)) + elseif api_node then + add_to_end(line, u:icons_before(api_node)) + end end add_to_end(line, { name }) for _, d in ipairs(self.decorators) do - add_to_end(line, d:icons_after(not d:is(UserDecorator) and node or api_node)) + u = d:as(UserDecorator) + if not u then + add_to_end(line, d:icons_after(node)) + elseif api_node then + add_to_end(line, u:icons_after(api_node)) + end end local rights = {} for _, d in ipairs(self.decorators) do - add_to_end(rights, d:icons_right_align(not d:is(UserDecorator) and node or api_node)) + u = d:as(UserDecorator) + if not u then + add_to_end(line, d:icons_right_align(node)) + elseif api_node then + add_to_end(line, u:icons_right_align(api_node)) + end end if #rights > 0 then self.extmarks[self.index] = rights @@ -187,10 +203,17 @@ function Builder:build_signs(node) local api_node = self.api_nodes and self.api_nodes[node.uid_node] --[[@as Node]] -- first in priority order - local d, sign_name + local d, u, sign_name for i = #self.decorators, 1, -1 do d = self.decorators[i] - sign_name = d:sign_name(not d:is(UserDecorator) and node or api_node) + + u = d:as(UserDecorator) + if not u then + sign_name = d:sign_name(node) + elseif api_node then + sign_name = u:sign_name(api_node) + end + if sign_name then self.signs[self.index] = sign_name break @@ -245,11 +268,17 @@ function Builder:icon_name_decorated(node) local icon_groups = {} local name_groups = {} local hl_icon, hl_name + local u for _, d in ipairs(self.decorators) do - -- maybe overridde icon - icon = d:icon_node((not d:is(UserDecorator) and node or api_node)) or icon - - hl_icon, hl_name = d:highlight_group_icon_name((not d:is(UserDecorator) and node or api_node)) + -- maybe override icon + u = d:as(UserDecorator) + if not u then + icon = d:icon_node(node) or icon + hl_icon, hl_name = d:highlight_group_icon_name(node) + elseif api_node then + icon = u:icon_node(api_node) or icon + hl_icon, hl_name = u:highlight_group_icon_name(api_node) + end table.insert(icon_groups, hl_icon) table.insert(name_groups, hl_name) From 3e7b37650eada3f11eb3114fa17f8bf353be0f25 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Mon, 2 Feb 2026 16:43:51 +1100 Subject: [PATCH 09/27] docs(#3241): nvim-tree-api-decorator brief --- doc/nvim-tree-lua.txt | 46 ++++++++++++++++++++++--- lua/nvim-tree/_meta/api/decorator.lua | 29 ++++++++++++++++ lua/nvim-tree/_meta/config/renderer.lua | 1 + lua/nvim-tree/classic.lua | 1 - scripts/vimdoc_config.lua | 1 - 5 files changed, 72 insertions(+), 6 deletions(-) diff --git a/doc/nvim-tree-lua.txt b/doc/nvim-tree-lua.txt index a5ebc95061a..5e327ae72cf 100644 --- a/doc/nvim-tree-lua.txt +++ b/doc/nvim-tree-lua.txt @@ -487,7 +487,7 @@ for files and and directories. Highlighting is additive, with higher precedence overriding lower. |nvim_tree.config.renderer| {decorators} controls which highlighting is -applied and its precedence. See |nvim-tree-decorators| for information on +applied and its precedence. See |nvim-tree-api-decorator| for information on creating custom decorators. < `ICON` @@ -1366,9 +1366,10 @@ Config: renderer *nvim-tree-config-renderer* • {symlink_destination}? (`boolean`, default: `true`) Appends an arrow followed by the target of the symlink. - • {decorators}? (`(string|nvim_tree.api.Decorator)[]`) - (default: - `{ "Git", "Open", "Hidden", "Modified", "Bookmark", "Diagnostics", "Copied", "Cut", }`) + • {decorators}? (`(string|nvim_tree.api.Decorator)[]`, default: `{ "Git", "Open", "Hidden", "Modified", "Bookmark", "Diagnostics", "Copied", "Cut", }`) + Ordered list of builtin and user decorators + to enable, see |nvim-tree-api-decorator| + and |nvim-tree-icons-highlighting| • {highlight_git}? (`nvim_tree.config.renderer.highlight`) (default: `"none"`) • {highlight_opened_files}? (`nvim_tree.config.renderer.highlight`) @@ -3203,6 +3204,38 @@ winid({opts}) *nvim_tree.api.tree.winid()* ============================================================================== API: Decorator *nvim-tree-api-decorator* +Highlighting and icons for nodes are provided by Decorators, see +|nvim-tree-icons-highlighting|. You may provide your own in addition to the +builtin decorators. + +Decorators may: +• Add icons +• Set highlight group for the name or icons +• Override node icon + +To register your decorator: +• Create a class that extends |nvim_tree.api.Decorator| +• Register it by adding the class to |nvim_tree.config.renderer| {decorators} + +Your class must: +• |nvim_tree.Class:extend()| the interface |nvim_tree.api.Decorator| +• Provide a no-arguments constructor |nvim_tree.Class:new()| that sets the + mandatory fields: + • {enabled} + • {highlight_range} + • {icon_placement} + +Your class may: +• Implement methods to provide decorations: + • |nvim_tree.api.Decorator:highlight_group()| + • |nvim_tree.api.Decorator:icon_node()| + • |nvim_tree.api.Decorator:icons()| + +Your class must: +• Call |nvim_tree.api.Decorator:define_sign()| in your constructor if using + `"signcolumn"` {icon_placement} + + *nvim_tree.api.Decorator* Extends: |nvim_tree.Class| @@ -3266,6 +3299,8 @@ API: Class *nvim-tree-api-class* Fields: ~ • {super} (`Class`) + • {new} (`fun(self: nvim_tree.Class)`) See + |nvim_tree.Class:new()|. • {extend} (`fun(self: nvim_tree.Class)`) See |nvim_tree.Class:extend()|. • {implement} (`fun(self: nvim_tree.Class, mixin: Class)`) See @@ -3305,6 +3340,9 @@ Class:is({class}) *nvim_tree.Class:is()* Return: ~ (`boolean`) +Class:new() *nvim_tree.Class:new()* + Default constructor + Class:nop({...}) *nvim_tree.Class:nop()* Parameters: ~ diff --git a/lua/nvim-tree/_meta/api/decorator.lua b/lua/nvim-tree/_meta/api/decorator.lua index 9ebb9954ab2..c4643325572 100644 --- a/lua/nvim-tree/_meta/api/decorator.lua +++ b/lua/nvim-tree/_meta/api/decorator.lua @@ -1,4 +1,33 @@ ---@meta + +---@brief +---Highlighting and icons for nodes are provided by Decorators, see [nvim-tree-icons-highlighting]. You may provide your own in addition to the builtin decorators. +--- +---Decorators may: +---- Add icons +---- Set highlight group for the name or icons +---- Override node icon +--- +---To register your decorator: +---- Create a class that extends [nvim_tree.api.Decorator] +---- Register it by adding the class to [nvim_tree.config.renderer] {decorators} +--- +---Your class must: +---- [nvim_tree.Class:extend()] the interface [nvim_tree.api.Decorator] +---- Provide a no-arguments constructor [nvim_tree.Class:new()] that sets the mandatory fields: +--- - {enabled} +--- - {highlight_range} +--- - {icon_placement} +--- +---Your class may: +---- Implement methods to provide decorations: +--- - [nvim_tree.api.Decorator:highlight_group()] +--- - [nvim_tree.api.Decorator:icon_node()] +--- - [nvim_tree.api.Decorator:icons()] +--- +---Your class must: +---- Call [nvim_tree.api.Decorator:define_sign()] in your constructor if using `"signcolumn"` {icon_placement} + local nvim_tree = { api = {} } local Class = require("nvim-tree.classic") diff --git a/lua/nvim-tree/_meta/config/renderer.lua b/lua/nvim-tree/_meta/config/renderer.lua index 8979eb8614e..b18c0b0d319 100644 --- a/lua/nvim-tree/_meta/config/renderer.lua +++ b/lua/nvim-tree/_meta/config/renderer.lua @@ -61,6 +61,7 @@ error("Cannot require a meta file") ---(default: `true`) ---@field symlink_destination? boolean --- +---Ordered list of builtin and user decorators to enable, see [nvim-tree-api-decorator] and [nvim-tree-icons-highlighting] ---(default: `{ "Git", "Open", "Hidden", "Modified", "Bookmark", "Diagnostics", "Copied", "Cut", }`) ---@field decorators? (string|nvim_tree.api.Decorator)[] --- diff --git a/lua/nvim-tree/classic.lua b/lua/nvim-tree/classic.lua index 1431e5bb38c..d7a072c10da 100644 --- a/lua/nvim-tree/classic.lua +++ b/lua/nvim-tree/classic.lua @@ -20,7 +20,6 @@ local Class = {} Class.__index = Class ---@diagnostic disable-line: inject-field ---Default constructor ----@protected function Class:new(...) --luacheck: ignore 212 end diff --git a/scripts/vimdoc_config.lua b/scripts/vimdoc_config.lua index ef57e2ef15c..b52324288f3 100644 --- a/scripts/vimdoc_config.lua +++ b/scripts/vimdoc_config.lua @@ -157,7 +157,6 @@ return { -- strip module from name and record the module for the method modules_by_method[fun.classvar .. ":" .. fun.name] = fun.module - print(vim.inspect(modules_by_method)) end, -- fn_helptag_fmt_common derived From 8e84f544bb5e768dd514cf99bb07446478f00db8 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Tue, 3 Feb 2026 14:34:30 +1100 Subject: [PATCH 10/27] docs(#3241): Decorator class documentation --- doc/nvim-tree-lua.txt | 71 ++++++++++++++++------- lua/nvim-tree/_meta/api/decorator.lua | 70 +++++++++++++--------- lua/nvim-tree/renderer/decorator/init.lua | 4 +- 3 files changed, 95 insertions(+), 50 deletions(-) diff --git a/doc/nvim-tree-lua.txt b/doc/nvim-tree-lua.txt index 5e327ae72cf..8b0011a99cb 100644 --- a/doc/nvim-tree-lua.txt +++ b/doc/nvim-tree-lua.txt @@ -3205,18 +3205,24 @@ winid({opts}) *nvim_tree.api.tree.winid()* API: Decorator *nvim-tree-api-decorator* Highlighting and icons for nodes are provided by Decorators, see -|nvim-tree-icons-highlighting|. You may provide your own in addition to the -builtin decorators. +|nvim-tree-icons-highlighting| for an overview. You may provide your own in +addition to the builtin decorators. + +Decorators are rendered in |nvim_tree.config.renderer| {decorators} order of +precedence, with later decorators applying additively over earlier. Decorators may: • Add icons -• Set highlight group for the name or icons +• Set a highlight group name for the name or icons • Override node icon To register your decorator: • Create a class that extends |nvim_tree.api.Decorator| • Register it by adding the class to |nvim_tree.config.renderer| {decorators} +Your decorator will be constructed and executed each time the tree is +rendered. + Your class must: • |nvim_tree.Class:extend()| the interface |nvim_tree.api.Decorator| • Provide a no-arguments constructor |nvim_tree.Class:new()| that sets the @@ -3224,6 +3230,8 @@ Your class must: • {enabled} • {highlight_range} • {icon_placement} +• Call |nvim_tree.api.Decorator:define_sign()| in your constructor when + {icon_placement} is `"signcolumn"` Your class may: • Implement methods to provide decorations: @@ -3231,20 +3239,19 @@ Your class may: • |nvim_tree.api.Decorator:icon_node()| • |nvim_tree.api.Decorator:icons()| -Your class must: -• Call |nvim_tree.api.Decorator:define_sign()| in your constructor if using - `"signcolumn"` {icon_placement} - *nvim_tree.api.Decorator* Extends: |nvim_tree.Class| - Abstract Decorator interface + Decorator interface Fields: ~ - • {enabled} (`boolean`) - • {highlight_range} (`nvim_tree.api.decorator.highlight_range`) - • {icon_placement} (`nvim_tree.api.decorator.icon_placement`) + • {enabled} (`boolean`) Enable this decorator. + • {highlight_range} (`nvim_tree.config.renderer.highlight`) What to + highlight: |nvim_tree.config.renderer.highlight| + • {icon_placement} (`"none"|nvim_tree.config.renderer.icons.placement`) + Where to place the icons: + |nvim_tree.config.renderer.icons.placement| • {icon_node} (`fun(self: nvim_tree.api.Decorator, node: nvim_tree.api.Node): nvim_tree.api.decorator.highlighted_string?`) See |nvim_tree.api.Decorator:icon_node()|. • {icons} (`fun(self: nvim_tree.api.Decorator, node: nvim_tree.api.Node): nvim_tree.api.decorator.highlighted_string[]?`) @@ -3254,42 +3261,64 @@ Your class must: • {define_sign} (`fun(self: nvim_tree.api.Decorator, icon: nvim_tree.api.decorator.highlighted_string?)`) See |nvim_tree.api.Decorator:define_sign()|. +*nvim_tree.api.decorator.highlighted_string* + Text or glyphs with optional highlight group names to apply to it. + + Fields: ~ + • {str} (`string`) One or many glyphs/characters. + • {hl} (`string[]`) Highlight group names to apply in order. Empty + table for no highlighting. + Decorator:define_sign({icon}) *nvim_tree.api.Decorator:define_sign()* - Defines a sign. This should be called in the constructor. + Defines a sign for an icon. This is mandatory and necessary only when + {icon_placement} is `"signcolumn"` + + This must be called during your constructor for all icons that you will + return from |nvim_tree.api.Decorator:icons()| Parameters: ~ - • {icon} (`nvim_tree.api.decorator.highlighted_string?`) + • {icon} (`nvim_tree.api.decorator.highlighted_string?`) does nothing + if nil *nvim_tree.api.Decorator:highlight_group()* Decorator:highlight_group({node}) - Abstract: optionally implement to provide one highlight group to apply to - your highlight_range. + One highlight group that applies additively to the {node} name for + {highlight_range}. + + Abstract, optional to implement. Parameters: ~ • {node} (`nvim_tree.api.Node`) Return: ~ - (`string?`) highlight_group + (`string?`) highlight group name `nil` when no highlighting to apply + to the node Decorator:icon_node({node}) *nvim_tree.api.Decorator:icon_node()* - Abstract: optionally implement to set the node's icon + Icon to override for the node. + + Abstract, optional to implement. Parameters: ~ • {node} (`nvim_tree.api.Node`) Return: ~ - (`nvim_tree.api.decorator.highlighted_string?`) icon_node + (`nvim_tree.api.decorator.highlighted_string?`) icon `nil` for no + override Decorator:icons({node}) *nvim_tree.api.Decorator:icons()* - Abstract: optionally implement to provide icons and the highlight groups - for your icon_placement. + Icons to add to the node as per {icon_placement} + + Abstract, optional to implement. Parameters: ~ • {node} (`nvim_tree.api.Node`) Return: ~ - (`nvim_tree.api.decorator.highlighted_string[]?`) icons + (`nvim_tree.api.decorator.highlighted_string[]?`) icons `nil` or empty + table for no icons. Only the first glyph of {str} is used when + {icon_placement} is `"signcolumn"` ============================================================================== diff --git a/lua/nvim-tree/_meta/api/decorator.lua b/lua/nvim-tree/_meta/api/decorator.lua index c4643325572..307a7f30c24 100644 --- a/lua/nvim-tree/_meta/api/decorator.lua +++ b/lua/nvim-tree/_meta/api/decorator.lua @@ -1,93 +1,109 @@ ---@meta ---@brief ----Highlighting and icons for nodes are provided by Decorators, see [nvim-tree-icons-highlighting]. You may provide your own in addition to the builtin decorators. +---Highlighting and icons for nodes are provided by Decorators, see [nvim-tree-icons-highlighting] for an overview. You may provide your own in addition to the builtin decorators. +--- +---Decorators are rendered in [nvim_tree.config.renderer] {decorators} order of precedence, with later decorators applying additively over earlier. --- ---Decorators may: ---- Add icons ----- Set highlight group for the name or icons +---- Set a highlight group name for the name or icons ---- Override node icon --- ---To register your decorator: ---- Create a class that extends [nvim_tree.api.Decorator] ---- Register it by adding the class to [nvim_tree.config.renderer] {decorators} --- +---Your decorator will be constructed and executed each time the tree is rendered. +--- ---Your class must: ----- [nvim_tree.Class:extend()] the interface [nvim_tree.api.Decorator] +---- [nvim_tree.Class:extend()] the interface [nvim_tree.api.Decorator] ---- Provide a no-arguments constructor [nvim_tree.Class:new()] that sets the mandatory fields: --- - {enabled} --- - {highlight_range} --- - {icon_placement} +---- Call [nvim_tree.api.Decorator:define_sign()] in your constructor when {icon_placement} is `"signcolumn"` --- ---Your class may: ---- Implement methods to provide decorations: --- - [nvim_tree.api.Decorator:highlight_group()] --- - [nvim_tree.api.Decorator:icon_node()] --- - [nvim_tree.api.Decorator:icons()] ---- ----Your class must: ----- Call [nvim_tree.api.Decorator:define_sign()] in your constructor if using `"signcolumn"` {icon_placement} local nvim_tree = { api = {} } local Class = require("nvim-tree.classic") --- ----Highlight group range as per nvim-tree.renderer.highlight_* ---- ----@alias nvim_tree.api.decorator.highlight_range nvim_tree.config.renderer.highlight - ----Icon position as per renderer.icons.*_placement ---- ----@alias nvim_tree.api.decorator.icon_placement "none"|nvim_tree.config.renderer.icons.placement - +---TODO #3241 add this to config --- ---Names of builtin decorators or your decorator classes. Builtins are ordered lowest to highest priority. --- ---@alias nvim_tree.api.decorator.types nvim_tree.api.Decorator|"Git"|"Opened"|"Hidden"|"Modified"|"Bookmarks"|"Diagnostics"|"Copied"|"Cut" + +--- +---Text or glyphs with optional highlight group names to apply to it. --- ----A string for rendering, with optional highlight groups to apply to it +---@class nvim_tree.api.decorator.highlighted_string --- ----@class (exact) nvim_tree.api.decorator.highlighted_string +---One or many glyphs/characters. ---@field str string +--- +---Highlight group names to apply in order. Empty table for no highlighting. ---@field hl string[] + --- ----Abstract Decorator interface +---Decorator interface --- ---@class nvim_tree.api.Decorator: nvim_tree.Class +--- +---Enable this decorator. ---@field enabled boolean ----@field highlight_range nvim_tree.api.decorator.highlight_range ----@field icon_placement nvim_tree.api.decorator.icon_placement +--- +---What to highlight: [nvim_tree.config.renderer.highlight] +---@field highlight_range nvim_tree.config.renderer.highlight +--- +---Where to place the icons: [nvim_tree.config.renderer.icons.placement] +---@field icon_placement "none"|nvim_tree.config.renderer.icons.placement +--- local Decorator = Class:extend() nvim_tree.api.Decorator = Decorator --- ----Abstract: optionally implement to set the node's icon +---Icon to override for the node. +--- +---Abstract, optional to implement. --- ---@param node nvim_tree.api.Node ----@return nvim_tree.api.decorator.highlighted_string? icon_node +---@return nvim_tree.api.decorator.highlighted_string? icon `nil` for no override function Decorator:icon_node(node) end --- ----Abstract: optionally implement to provide icons and the highlight groups for your icon_placement. +---Icons to add to the node as per {icon_placement} +--- +---Abstract, optional to implement. --- ---@param node nvim_tree.api.Node ----@return nvim_tree.api.decorator.highlighted_string[]? icons +---@return nvim_tree.api.decorator.highlighted_string[]? icons `nil` or empty table for no icons. Only the first glyph of {str} is used when {icon_placement} is `"signcolumn"` function Decorator:icons(node) end --- ----Abstract: optionally implement to provide one highlight group to apply to your highlight_range. +---One highlight group that applies additively to the {node} name for {highlight_range}. +--- +---Abstract, optional to implement. --- ---@param node nvim_tree.api.Node ----@return string? highlight_group +---@return string? highlight group name `nil` when no highlighting to apply to the node function Decorator:highlight_group(node) end --- ----Defines a sign. This should be called in the constructor. +---Defines a sign for an icon. This is mandatory and necessary only when {icon_placement} is `"signcolumn"` +--- +---This must be called during your constructor for all icons that you will return from [nvim_tree.api.Decorator:icons()] --- ----@param icon nvim_tree.api.decorator.highlighted_string? +---@param icon nvim_tree.api.decorator.highlighted_string? does nothing if nil function Decorator:define_sign(icon) end return nvim_tree.api.Decorator diff --git a/lua/nvim-tree/renderer/decorator/init.lua b/lua/nvim-tree/renderer/decorator/init.lua index d5d2b1a7931..479e11f0805 100644 --- a/lua/nvim-tree/renderer/decorator/init.lua +++ b/lua/nvim-tree/renderer/decorator/init.lua @@ -1,8 +1,8 @@ ---Abstract Decorator implementation ---@class (exact) Decorator: Class ---@field protected enabled boolean ----@field protected highlight_range nvim_tree.api.decorator.highlight_range ----@field protected icon_placement nvim_tree.api.decorator.icon_placement +---@field protected highlight_range nvim_tree.config.renderer.highlight +---@field protected icon_placement "none"|nvim_tree.config.renderer.icons.placement local Decorator = require("nvim-tree._meta.api.decorator"):extend() ---TODO #3241 create an internal decorator class with explorer member and lose the UserDecorator From d06bccb7f1f4042a3b0382f57b68c165535081c6 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Tue, 3 Feb 2026 14:45:51 +1100 Subject: [PATCH 11/27] docs(#3241): add placholder to vimdoc.sh --- scripts/vimdoc.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/scripts/vimdoc.sh b/scripts/vimdoc.sh index 398cc57562d..e49987f8866 100755 --- a/scripts/vimdoc.sh +++ b/scripts/vimdoc.sh @@ -58,6 +58,7 @@ cleanup() { # remove our config rm -fv "${DIR_NVIM_SRC}/src/gen/vimdoc_config.lua" + rm -fv "${DIR_NVIM_SRC}/runtime/lua/placeholder.lua" # remove generated help rm -fv "${DIR_NVIM_SRC}/runtime/doc/nvim-tree-lua.txt" @@ -85,6 +86,9 @@ if [ "${1}" = "doc" ]; then cp "${DIR_NVIM_SRC}/src/gen/gen_vimdoc.lua" "${DIR_NVIM_SRC}/src/gen/gen_vimdoc.lua.org" sed -i -E 's/spairs\(config\)/spairs\(require("gen.vimdoc_config")\)/g' "${DIR_NVIM_SRC}/src/gen/gen_vimdoc.lua" + # leave a generic placeholder to bridge between nvim.gen_vimdoc.Config + echo "---@brief placeholder" > "${DIR_NVIM_SRC}/runtime/lua/placeholder.lua" + # copy our config cp -v "scripts/vimdoc_config.lua" "${DIR_NVIM_SRC}/src/gen" fi From 72756095f8463bef4c6f4bf1630aa198a6e53772 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Tue, 3 Feb 2026 15:37:16 +1100 Subject: [PATCH 12/27] docs(#3241): extract nvim_tree.config.renderer.decorator, add decorators to hl help section --- doc/nvim-tree-lua.txt | 61 +++++++++++++++---------- lua/nvim-tree/_meta/api/decorator.lua | 8 ---- lua/nvim-tree/_meta/config/renderer.lua | 6 ++- lua/nvim-tree/renderer/builder.lua | 2 +- 4 files changed, 41 insertions(+), 36 deletions(-) diff --git a/doc/nvim-tree-lua.txt b/doc/nvim-tree-lua.txt index 8b0011a99cb..cc6e4357c76 100644 --- a/doc/nvim-tree-lua.txt +++ b/doc/nvim-tree-lua.txt @@ -482,15 +482,25 @@ Icons And Highlighting *nvim-tree-icons-highlighting* Icons may be displayed before files and directories. Additional icons and highlighting may be displayed to indicate various states -for files and and directories. - -Highlighting is additive, with higher precedence overriding lower. - -|nvim_tree.config.renderer| {decorators} controls which highlighting is -applied and its precedence. See |nvim-tree-api-decorator| for information on -creating custom decorators. -< -`ICON` +for files and and directories. Highlighting is additive. + +Decorators are responsible for providing the icons and highlighting. +|nvim_tree.config.renderer| {decorators} configures the decorators used, +in ascending order of precedence. + +`DECORATOR` *nvim_tree.config.renderer.decorator* + A builtin decorator name or |nvim_tree.api.Decorator| class. + Builtin decorators in default order: + • `"Git"` + • `"Open"` + • `"Hidden"` + • `"Modified"` + • `"Bookmark"` + • `"Diagnostics"` + • `"Copied"` + • `"Cut"` + +`ICON?` Enable via |nvim_tree.config.renderer.icons.show `REQUIRES` @@ -510,7 +520,7 @@ creating custom decorators. • `name`: name only • `all`: icon and name -`DEVICONS` +`DEVICONS?` Glyphs and their colors will be overridden by optional plugin: `nvim-tree/nvim-web-devicons` |nvim_tree.config.renderer.icons.web_devicons| @@ -520,18 +530,19 @@ creating custom decorators. `GROUPS` Applicable highlight groups: |nvim-tree-highlight-groups| -Some defaults noted. In ascending order of default highlight precedence: +Some defaults noted. In ascending order of default decorator precedence: -`WHAT ICON REQUIRES PLACEMENT HIGHLIGHT GLYPHS DEVICONS GROUPS` -File Icon {file} Y - - - |nvim_tree.config.renderer.icons.glyphs| {default} Y `NvimTreeNormal`, `NvimTreeFileIcon` -Folder Icon {folder} Y - - - |nvim_tree.config.renderer.icons.glyphs.folder| Y `NvimTree*FolderName`, `NvimTree*FolderIcon` -Git Status {git} Y |nvim_tree.config.git| {git_placement} `"before"` {highlight_git} `"none"` |nvim_tree.config.renderer.icons.glyphs.git| N `NvimTreeGit*` -|bufloaded()| - - - {highlight_opened_files}`"none"` - N ` NvimTreeOpened*` -Dotfiles {hidden} N - {hidden_placement} `"after"` {highlight_hidden} `"none"` |nvim_tree.config.renderer.icons.glyphs| {hidden} N `NvimTreeHidden*` -|'modified'| {modified} Y |nvim_tree.config.modified| {modified_placement} `"after"` {highlight_modified} `"none"` |nvim_tree.config.renderer.icons.glyphs| {modified} N `NvimTreeModified*` -Bookmarked {bookmarks} Y - {bookmarks_placement} `"signcolumn"` {highlight_bookmarks} `"none"` |nvim_tree.config.renderer.icons.glyphs| {bookmark} N `NvimTreeBookmark*` -Diag Status {diagnostics}Y |nvim_tree.config.diagnostics| {diagnostics_placement}`"signcolumn"` {highlight_diagnostics} `"none" ` |nvim_tree.config.diagnostics.icons| N `NvimTreeDiagnostic*` -Cut/Copied - - - {highlight_clipboard} `"name"` - N `NvimTreeCutHL`, `NvimTreeCopiedHL` +`WHAT DECORATOR ICON? REQUIRES PLACEMENT HIGHLIGHT GLYPHS DEVICONS? GROUPS` +File Icon - {file} Y - - - |nvim_tree.config.renderer.icons.glyphs| {default} Y `NvimTreeNormal`, `NvimTreeFileIcon` +Folder Icon - {folder} Y - - - |nvim_tree.config.renderer.icons.glyphs.folder| Y `NvimTree*FolderName`, `NvimTree*FolderIcon` +Git Status `"Git"` {git} Y |nvim_tree.config.git| {git_placement} `"before"` {highlight_git} `"none"` |nvim_tree.config.renderer.icons.glyphs.git| N `NvimTreeGit*` +|bufloaded()| `"Open"` - - - {highlight_opened_files}`"none"` - N ` NvimTreeOpened*` +Dotfiles `"Hidden"` {hidden} N - {hidden_placement} `"after"` {highlight_hidden} `"none"` |nvim_tree.config.renderer.icons.glyphs| {hidden} N `NvimTreeHidden*` +|'modified'| `"Modified"` {modified} Y |nvim_tree.config.modified| {modified_placement} `"after"` {highlight_modified} `"none"` |nvim_tree.config.renderer.icons.glyphs| {modified} N `NvimTreeModified*` +Bookmarked `"Bookmark"` {bookmarks} Y - {bookmarks_placement} `"signcolumn"` {highlight_bookmarks} `"none"` |nvim_tree.config.renderer.icons.glyphs| {bookmark} N `NvimTreeBookmark*` +Diag Status ` "Diagnostics"` {diagnostics}Y |nvim_tree.config.diagnostics| {diagnostics_placement}`"signcolumn"` {highlight_diagnostics} `"none" ` |nvim_tree.config.diagnostics.icons| N `NvimTreeDiagnostic*` +Copied `"Copied"` - - - {highlight_clipboard} `"name"` - N `NvimTreeCopiedHL` +Cut `"Cut"` - - - {highlight_clipboard} `"name"` - N `NvimTreeCutHL` ============================================================================== @@ -1366,10 +1377,10 @@ Config: renderer *nvim-tree-config-renderer* • {symlink_destination}? (`boolean`, default: `true`) Appends an arrow followed by the target of the symlink. - • {decorators}? (`(string|nvim_tree.api.Decorator)[]`, default: `{ "Git", "Open", "Hidden", "Modified", "Bookmark", "Diagnostics", "Copied", "Cut", }`) - Ordered list of builtin and user decorators - to enable, see |nvim-tree-api-decorator| - and |nvim-tree-icons-highlighting| + • {decorators}? (`nvim_tree.config.renderer.decorator[]`, default: `{ "Git", "Open", "Hidden", "Modified", "Bookmark", "Diagnostics", "Copied", "Cut", }`) + Ordered list of builtin + |nvim_tree.config.renderer.decorator| names + and |nvim_tree.api.Decorator| classes. • {highlight_git}? (`nvim_tree.config.renderer.highlight`) (default: `"none"`) • {highlight_opened_files}? (`nvim_tree.config.renderer.highlight`) diff --git a/lua/nvim-tree/_meta/api/decorator.lua b/lua/nvim-tree/_meta/api/decorator.lua index 307a7f30c24..1dfccdd82f9 100644 --- a/lua/nvim-tree/_meta/api/decorator.lua +++ b/lua/nvim-tree/_meta/api/decorator.lua @@ -34,14 +34,6 @@ local nvim_tree = { api = {} } local Class = require("nvim-tree.classic") ---- ----TODO #3241 add this to config ---- ----Names of builtin decorators or your decorator classes. Builtins are ordered lowest to highest priority. ---- ----@alias nvim_tree.api.decorator.types nvim_tree.api.Decorator|"Git"|"Opened"|"Hidden"|"Modified"|"Bookmarks"|"Diagnostics"|"Copied"|"Cut" - - --- ---Text or glyphs with optional highlight group names to apply to it. --- diff --git a/lua/nvim-tree/_meta/config/renderer.lua b/lua/nvim-tree/_meta/config/renderer.lua index b18c0b0d319..4bda6dbfd51 100644 --- a/lua/nvim-tree/_meta/config/renderer.lua +++ b/lua/nvim-tree/_meta/config/renderer.lua @@ -32,6 +32,8 @@ error("Cannot require a meta file") --- ---@alias nvim_tree.config.renderer.highlight "none"|"icon"|"name"|"all" --- +---@alias nvim_tree.config.renderer.decorator nvim_tree.api.Decorator|"Git"|"Open"|"Hidden"|"Modified"|"Bookmark"|"Diagnostics"|"Copied"|"Cut" +--- ---@class nvim_tree.config.renderer --- ---Appends a trailing slash to folder and symlink folder target names. @@ -61,9 +63,9 @@ error("Cannot require a meta file") ---(default: `true`) ---@field symlink_destination? boolean --- ----Ordered list of builtin and user decorators to enable, see [nvim-tree-api-decorator] and [nvim-tree-icons-highlighting] +---Ordered list of builtin [nvim_tree.config.renderer.decorator] names and |nvim_tree.api.Decorator| classes. ---(default: `{ "Git", "Open", "Hidden", "Modified", "Bookmark", "Diagnostics", "Copied", "Cut", }`) ----@field decorators? (string|nvim_tree.api.Decorator)[] +---@field decorators? nvim_tree.config.renderer.decorator[] --- ---(default: `"none"`) ---@field highlight_git? nvim_tree.config.renderer.highlight diff --git a/lua/nvim-tree/renderer/builder.lua b/lua/nvim-tree/renderer/builder.lua index 0c76ab515f5..61e9f63ddca 100644 --- a/lua/nvim-tree/renderer/builder.lua +++ b/lua/nvim-tree/renderer/builder.lua @@ -21,7 +21,7 @@ local pad = require("nvim-tree.renderer.components.padding") ---TODO #3241 add an alias for builtins or document the enum -- Builtin Decorators ----@type table +---@type table local BUILTIN_DECORATORS = { Git = GitDecorator, Open = OpenDecorator, From 958feb08ff0ac520ea9dd51e4cacbca87331ac73 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Tue, 3 Feb 2026 15:57:21 +1100 Subject: [PATCH 13/27] docs(#3241): use general nvim_tree.api.highlighted_string --- doc/nvim-tree-lua.txt | 146 +++++++++--------- lua/nvim-tree/_meta/api/decorator.lua | 10 +- lua/nvim-tree/node/directory-link.lua | 4 +- lua/nvim-tree/node/directory.lua | 4 +- lua/nvim-tree/node/file-link.lua | 4 +- lua/nvim-tree/node/file.lua | 4 +- lua/nvim-tree/node/init.lua | 8 +- lua/nvim-tree/renderer/builder.lua | 16 +- lua/nvim-tree/renderer/components/padding.lua | 4 +- .../renderer/decorator/bookmarks.lua | 4 +- .../renderer/decorator/diagnostics.lua | 4 +- lua/nvim-tree/renderer/decorator/git.lua | 4 +- lua/nvim-tree/renderer/decorator/hidden.lua | 4 +- lua/nvim-tree/renderer/decorator/init.lua | 8 +- lua/nvim-tree/renderer/decorator/modified.lua | 4 +- lua/nvim-tree/renderer/decorator/opened.lua | 2 +- lua/nvim-tree/renderer/decorator/user.lua | 2 +- scripts/vimdoc_config.lua | 32 ++-- 18 files changed, 132 insertions(+), 132 deletions(-) diff --git a/doc/nvim-tree-lua.txt b/doc/nvim-tree-lua.txt index cc6e4357c76..5375f63f266 100644 --- a/doc/nvim-tree-lua.txt +++ b/doc/nvim-tree-lua.txt @@ -902,9 +902,9 @@ Require and register it during |nvim-tree-setup|: Contents of `my-decorator.lua`: >lua ---@class (exact) MyDecorator: nvim_tree.api.Decorator - ---@field private my_icon1 nvim_tree.api.decorator.highlighted_string - ---@field private my_icon2 nvim_tree.api.decorator.highlighted_string - ---@field private my_icon_node nvim_tree.api.decorator.highlighted_string + ---@field private my_icon1 nvim_tree.api.highlighted_string + ---@field private my_icon2 nvim_tree.api.highlighted_string + ---@field private my_icon_node nvim_tree.api.highlighted_string ---@field private my_highlight_group string local MyDecorator = require("nvim-tree.api").Decorator:extend() @@ -928,7 +928,7 @@ Contents of `my-decorator.lua`: ---Override node icon ---@param node nvim_tree.api.Node - ---@return nvim_tree.api.decorator.highlighted_string? icon_node + ---@return nvim_tree.api.highlighted_string? icon_node function MyDecorator:icon_node(node) if node.name == "example" then return self.my_icon_node @@ -939,7 +939,7 @@ Contents of `my-decorator.lua`: ---Return two icons for DecoratorIconPlacement "after" ---@param node nvim_tree.api.Node - ---@return nvim_tree.api.decorator.highlighted_string[]? icons + ---@return nvim_tree.api.highlighted_string[]? icons function MyDecorator:icons(node) if node.name == "example" then return { self.my_icon1, self.my_icon2, } @@ -3213,7 +3213,64 @@ winid({opts}) *nvim_tree.api.tree.winid()* ============================================================================== -API: Decorator *nvim-tree-api-decorator* +Class *nvim-tree-class* + +*nvim_tree.Class* + + Fields: ~ + • {super} (`Class`) + • {new} (`fun(self: nvim_tree.Class)`) See + |nvim_tree.Class:new()|. + • {extend} (`fun(self: nvim_tree.Class)`) See + |nvim_tree.Class:extend()|. + • {implement} (`fun(self: nvim_tree.Class, mixin: Class)`) See + |nvim_tree.Class:implement()|. + • {is} (`fun(self: nvim_tree.Class, class: T): boolean`) See + |nvim_tree.Class:is()|. + • {as} (`fun(self: nvim_tree.Class, class: T): T?`) See + |nvim_tree.Class:as()|. + • {nop} (`fun(self: nvim_tree.Class, ...: any)`) See + |nvim_tree.Class:nop()|. + + +Class:as({class}) *nvim_tree.Class:as()* + Return object if |nvim_tree.Class:is()| otherwise nil + + Parameters: ~ + • {class} (`any`) + + Return: ~ + (`T?`) + +Class:extend() *nvim_tree.Class:extend()* + Extend a class, setting .super + +Class:implement({mixin}) *nvim_tree.Class:implement()* + Implement the functions of a mixin Add the mixin to .implements + + Parameters: ~ + • {mixin} (`Class`) + +Class:is({class}) *nvim_tree.Class:is()* + Object is an instance of class or implements a mixin + + Parameters: ~ + • {class} (`any`) + + Return: ~ + (`boolean`) + +Class:new() *nvim_tree.Class:new()* + Default constructor + +Class:nop({...}) *nvim_tree.Class:nop()* + + Parameters: ~ + • {...} (`any`) + + +============================================================================== +Class: Decorator *nvim-tree-class-decorator* Highlighting and icons for nodes are provided by Decorators, see |nvim-tree-icons-highlighting| for an overview. You may provide your own in @@ -3263,16 +3320,16 @@ Your class may: • {icon_placement} (`"none"|nvim_tree.config.renderer.icons.placement`) Where to place the icons: |nvim_tree.config.renderer.icons.placement| - • {icon_node} (`fun(self: nvim_tree.api.Decorator, node: nvim_tree.api.Node): nvim_tree.api.decorator.highlighted_string?`) + • {icon_node} (`fun(self: nvim_tree.api.Decorator, node: nvim_tree.api.Node): nvim_tree.api.highlighted_string?`) See |nvim_tree.api.Decorator:icon_node()|. - • {icons} (`fun(self: nvim_tree.api.Decorator, node: nvim_tree.api.Node): nvim_tree.api.decorator.highlighted_string[]?`) + • {icons} (`fun(self: nvim_tree.api.Decorator, node: nvim_tree.api.Node): nvim_tree.api.highlighted_string[]?`) See |nvim_tree.api.Decorator:icons()|. • {highlight_group} (`fun(self: nvim_tree.api.Decorator, node: nvim_tree.api.Node): string?`) See |nvim_tree.api.Decorator:highlight_group()|. - • {define_sign} (`fun(self: nvim_tree.api.Decorator, icon: nvim_tree.api.decorator.highlighted_string?)`) + • {define_sign} (`fun(self: nvim_tree.api.Decorator, icon: nvim_tree.api.highlighted_string?)`) See |nvim_tree.api.Decorator:define_sign()|. -*nvim_tree.api.decorator.highlighted_string* +*nvim_tree.api.highlighted_string* Text or glyphs with optional highlight group names to apply to it. Fields: ~ @@ -3289,8 +3346,7 @@ Decorator:define_sign({icon}) *nvim_tree.api.Decorator:define_sign()* return from |nvim_tree.api.Decorator:icons()| Parameters: ~ - • {icon} (`nvim_tree.api.decorator.highlighted_string?`) does nothing - if nil + • {icon} (`nvim_tree.api.highlighted_string?`) does nothing if nil *nvim_tree.api.Decorator:highlight_group()* Decorator:highlight_group({node}) @@ -3315,8 +3371,7 @@ Decorator:icon_node({node}) *nvim_tree.api.Decorator:icon_node()* • {node} (`nvim_tree.api.Node`) Return: ~ - (`nvim_tree.api.decorator.highlighted_string?`) icon `nil` for no - override + (`nvim_tree.api.highlighted_string?`) icon `nil` for no override Decorator:icons({node}) *nvim_tree.api.Decorator:icons()* Icons to add to the node as per {icon_placement} @@ -3327,66 +3382,9 @@ Decorator:icons({node}) *nvim_tree.api.Decorator:icons()* • {node} (`nvim_tree.api.Node`) Return: ~ - (`nvim_tree.api.decorator.highlighted_string[]?`) icons `nil` or empty - table for no icons. Only the first glyph of {str} is used when - {icon_placement} is `"signcolumn"` - - -============================================================================== -API: Class *nvim-tree-api-class* - -*nvim_tree.Class* - - Fields: ~ - • {super} (`Class`) - • {new} (`fun(self: nvim_tree.Class)`) See - |nvim_tree.Class:new()|. - • {extend} (`fun(self: nvim_tree.Class)`) See - |nvim_tree.Class:extend()|. - • {implement} (`fun(self: nvim_tree.Class, mixin: Class)`) See - |nvim_tree.Class:implement()|. - • {is} (`fun(self: nvim_tree.Class, class: T): boolean`) See - |nvim_tree.Class:is()|. - • {as} (`fun(self: nvim_tree.Class, class: T): T?`) See - |nvim_tree.Class:as()|. - • {nop} (`fun(self: nvim_tree.Class, ...: any)`) See - |nvim_tree.Class:nop()|. - - -Class:as({class}) *nvim_tree.Class:as()* - Return object if |nvim_tree.Class:is()| otherwise nil - - Parameters: ~ - • {class} (`any`) - - Return: ~ - (`T?`) - -Class:extend() *nvim_tree.Class:extend()* - Extend a class, setting .super - -Class:implement({mixin}) *nvim_tree.Class:implement()* - Implement the functions of a mixin Add the mixin to .implements - - Parameters: ~ - • {mixin} (`Class`) - -Class:is({class}) *nvim_tree.Class:is()* - Object is an instance of class or implements a mixin - - Parameters: ~ - • {class} (`any`) - - Return: ~ - (`boolean`) - -Class:new() *nvim_tree.Class:new()* - Default constructor - -Class:nop({...}) *nvim_tree.Class:nop()* - - Parameters: ~ - • {...} (`any`) + (`nvim_tree.api.highlighted_string[]?`) icons `nil` or empty table for + no icons. Only the first glyph of {str} is used when {icon_placement} + is `"signcolumn"` vim:tw=78:ts=8:sw=4:sts=4:et:ft=help:norl: diff --git a/lua/nvim-tree/_meta/api/decorator.lua b/lua/nvim-tree/_meta/api/decorator.lua index 1dfccdd82f9..851c25e1c11 100644 --- a/lua/nvim-tree/_meta/api/decorator.lua +++ b/lua/nvim-tree/_meta/api/decorator.lua @@ -1,5 +1,7 @@ ---@meta +---#TODO 3241 maybe rename to UserDecorator + ---@brief ---Highlighting and icons for nodes are provided by Decorators, see [nvim-tree-icons-highlighting] for an overview. You may provide your own in addition to the builtin decorators. --- @@ -37,7 +39,7 @@ local Class = require("nvim-tree.classic") --- ---Text or glyphs with optional highlight group names to apply to it. --- ----@class nvim_tree.api.decorator.highlighted_string +---@class nvim_tree.api.highlighted_string --- ---One or many glyphs/characters. ---@field str string @@ -69,7 +71,7 @@ nvim_tree.api.Decorator = Decorator ---Abstract, optional to implement. --- ---@param node nvim_tree.api.Node ----@return nvim_tree.api.decorator.highlighted_string? icon `nil` for no override +---@return nvim_tree.api.highlighted_string? icon `nil` for no override function Decorator:icon_node(node) end --- @@ -78,7 +80,7 @@ function Decorator:icon_node(node) end ---Abstract, optional to implement. --- ---@param node nvim_tree.api.Node ----@return nvim_tree.api.decorator.highlighted_string[]? icons `nil` or empty table for no icons. Only the first glyph of {str} is used when {icon_placement} is `"signcolumn"` +---@return nvim_tree.api.highlighted_string[]? icons `nil` or empty table for no icons. Only the first glyph of {str} is used when {icon_placement} is `"signcolumn"` function Decorator:icons(node) end --- @@ -95,7 +97,7 @@ function Decorator:highlight_group(node) end --- ---This must be called during your constructor for all icons that you will return from [nvim_tree.api.Decorator:icons()] --- ----@param icon nvim_tree.api.decorator.highlighted_string? does nothing if nil +---@param icon nvim_tree.api.highlighted_string? does nothing if nil function Decorator:define_sign(icon) end return nvim_tree.api.Decorator diff --git a/lua/nvim-tree/node/directory-link.lua b/lua/nvim-tree/node/directory-link.lua index b1c19f54172..8ca9714bae7 100644 --- a/lua/nvim-tree/node/directory-link.lua +++ b/lua/nvim-tree/node/directory-link.lua @@ -38,7 +38,7 @@ function DirectoryLinkNode:update_git_status(parent_ignored, project) self.git_status = git_utils.git_status_dir(parent_ignored, project, self.link_to, self.absolute_path) end ----@return nvim_tree.api.decorator.highlighted_string name +---@return nvim_tree.api.highlighted_string name function DirectoryLinkNode:highlighted_icon() if not self.explorer.opts.renderer.icons.show.folder then return self:highlighted_icon_empty() @@ -58,7 +58,7 @@ function DirectoryLinkNode:highlighted_icon() end ---Maybe override name with arrow ----@return nvim_tree.api.decorator.highlighted_string name +---@return nvim_tree.api.highlighted_string name function DirectoryLinkNode:highlighted_name() local name = DirectoryNode.highlighted_name(self) diff --git a/lua/nvim-tree/node/directory.lua b/lua/nvim-tree/node/directory.lua index 9b376e7b6f6..8199da67e98 100644 --- a/lua/nvim-tree/node/directory.lua +++ b/lua/nvim-tree/node/directory.lua @@ -198,7 +198,7 @@ function DirectoryNode:expand_or_collapse(toggle_group) self.explorer.renderer:draw() end ----@return nvim_tree.api.decorator.highlighted_string icon +---@return nvim_tree.api.highlighted_string icon function DirectoryNode:highlighted_icon() if not self.explorer.opts.renderer.icons.show.folder then return self:highlighted_icon_empty() @@ -243,7 +243,7 @@ function DirectoryNode:highlighted_icon() return { str = str, hl = { hl } } end ----@return nvim_tree.api.decorator.highlighted_string icon +---@return nvim_tree.api.highlighted_string icon function DirectoryNode:highlighted_name() local str, hl diff --git a/lua/nvim-tree/node/file-link.lua b/lua/nvim-tree/node/file-link.lua index 7130897ddec..7bb2127b519 100644 --- a/lua/nvim-tree/node/file-link.lua +++ b/lua/nvim-tree/node/file-link.lua @@ -31,7 +31,7 @@ function FileLinkNode:update_git_status(parent_ignored, project) self.git_status = git_utils.git_status_file(parent_ignored, project, self.link_to, self.absolute_path) end ----@return nvim_tree.api.decorator.highlighted_string icon +---@return nvim_tree.api.highlighted_string icon function FileLinkNode:highlighted_icon() if not self.explorer.opts.renderer.icons.show.file then return self:highlighted_icon_empty() @@ -46,7 +46,7 @@ function FileLinkNode:highlighted_icon() return { str = str, hl = { hl } } end ----@return nvim_tree.api.decorator.highlighted_string name +---@return nvim_tree.api.highlighted_string name function FileLinkNode:highlighted_name() local str = self.name if self.explorer.opts.renderer.symlink_destination then diff --git a/lua/nvim-tree/node/file.lua b/lua/nvim-tree/node/file.lua index 2b0ea0362c9..a0b012cb048 100644 --- a/lua/nvim-tree/node/file.lua +++ b/lua/nvim-tree/node/file.lua @@ -50,7 +50,7 @@ function FileNode:get_git_xy() return self.git_status.file and { self.git_status.file } end ----@return nvim_tree.api.decorator.highlighted_string icon +---@return nvim_tree.api.highlighted_string icon function FileNode:highlighted_icon() if not self.explorer.opts.renderer.icons.show.file then return self:highlighted_icon_empty() @@ -79,7 +79,7 @@ function FileNode:highlighted_icon() return { str = str, hl = { hl } } end ----@return nvim_tree.api.decorator.highlighted_string name +---@return nvim_tree.api.highlighted_string name function FileNode:highlighted_name() local hl if vim.tbl_contains(self.explorer.opts.renderer.special_files, self.absolute_path) or vim.tbl_contains(self.explorer.opts.renderer.special_files, self.name) then diff --git a/lua/nvim-tree/node/init.lua b/lua/nvim-tree/node/init.lua index 4c8d5c81daa..8aae8adb72a 100644 --- a/lua/nvim-tree/node/init.lua +++ b/lua/nvim-tree/node/init.lua @@ -93,28 +93,28 @@ end ---Empty highlighted icon ---@protected ----@return nvim_tree.api.decorator.highlighted_string icon +---@return nvim_tree.api.highlighted_string icon function Node:highlighted_icon_empty() return { str = "", hl = {} } end ---Highlighted icon for the node ---Empty for base Node ----@return nvim_tree.api.decorator.highlighted_string icon +---@return nvim_tree.api.highlighted_string icon function Node:highlighted_icon() return self:highlighted_icon_empty() end ---Empty highlighted name ---@protected ----@return nvim_tree.api.decorator.highlighted_string name +---@return nvim_tree.api.highlighted_string name function Node:highlighted_name_empty() return { str = "", hl = {} } end ---Highlighted name for the node ---Empty for base Node ----@return nvim_tree.api.decorator.highlighted_string name +---@return nvim_tree.api.highlighted_string name function Node:highlighted_name() return self:highlighted_name_empty() end diff --git a/lua/nvim-tree/renderer/builder.lua b/lua/nvim-tree/renderer/builder.lua index 61e9f63ddca..25b2557a346 100644 --- a/lua/nvim-tree/renderer/builder.lua +++ b/lua/nvim-tree/renderer/builder.lua @@ -106,7 +106,7 @@ function Builder:insert_highlight(groups, start, end_) end ---@private ----@param highlighted_strings nvim_tree.api.decorator.highlighted_string[] +---@param highlighted_strings nvim_tree.api.highlighted_string[] ---@return string function Builder:unwrap_highlighted_strings(highlighted_strings) if not highlighted_strings then @@ -126,12 +126,12 @@ function Builder:unwrap_highlighted_strings(highlighted_strings) end ---@private ----@param indent_markers nvim_tree.api.decorator.highlighted_string[] ----@param arrows? nvim_tree.api.decorator.highlighted_string[] ----@param icon nvim_tree.api.decorator.highlighted_string ----@param name nvim_tree.api.decorator.highlighted_string +---@param indent_markers nvim_tree.api.highlighted_string[] +---@param arrows? nvim_tree.api.highlighted_string[] +---@param icon nvim_tree.api.highlighted_string +---@param name nvim_tree.api.highlighted_string ---@param node table ----@return nvim_tree.api.decorator.highlighted_string[] +---@return nvim_tree.api.highlighted_string[] function Builder:format_line(indent_markers, arrows, icon, name, node) local added_len = 0 local function add_to_end(t1, t2) @@ -254,8 +254,8 @@ end ---A highlight group is always calculated and upserted for the case of highlights changing. ---@private ---@param node Node ----@return nvim_tree.api.decorator.highlighted_string icon ----@return nvim_tree.api.decorator.highlighted_string name +---@return nvim_tree.api.highlighted_string icon +---@return nvim_tree.api.highlighted_string name function Builder:icon_name_decorated(node) -- use the api node for user decorators local api_node = self.api_nodes and self.api_nodes[node.uid_node] --[[@as Node]] diff --git a/lua/nvim-tree/renderer/components/padding.lua b/lua/nvim-tree/renderer/components/padding.lua index a8289b4d4e1..be84ae0b9de 100644 --- a/lua/nvim-tree/renderer/components/padding.lua +++ b/lua/nvim-tree/renderer/components/padding.lua @@ -64,7 +64,7 @@ end ---@param node Node ---@param markers table ---@param early_stop integer? ----@return nvim_tree.api.decorator.highlighted_string +---@return nvim_tree.api.highlighted_string function M.get_indent_markers(depth, idx, nodes_number, node, markers, early_stop) local str = "" @@ -83,7 +83,7 @@ function M.get_indent_markers(depth, idx, nodes_number, node, markers, early_sto end ---@param node Node ----@return nvim_tree.api.decorator.highlighted_string[]? +---@return nvim_tree.api.highlighted_string[]? function M.get_arrows(node) if not M.config.icons.show.folder_arrow then return diff --git a/lua/nvim-tree/renderer/decorator/bookmarks.lua b/lua/nvim-tree/renderer/decorator/bookmarks.lua index 5c6bff438e2..f61c44c7031 100644 --- a/lua/nvim-tree/renderer/decorator/bookmarks.lua +++ b/lua/nvim-tree/renderer/decorator/bookmarks.lua @@ -2,7 +2,7 @@ local Decorator = require("nvim-tree.renderer.decorator") ---@class (exact) BookmarkDecorator: Decorator ---@field private explorer Explorer ----@field private icon nvim_tree.api.decorator.highlighted_string? +---@field private icon nvim_tree.api.highlighted_string? local BookmarkDecorator = Decorator:extend() ---@class BookmarkDecorator @@ -28,7 +28,7 @@ end ---Bookmark icon: renderer.icons.show.bookmarks and node is marked ---@param node Node ----@return nvim_tree.api.decorator.highlighted_string[]? icons +---@return nvim_tree.api.highlighted_string[]? icons function BookmarkDecorator:icons(node) if self.explorer.marks:get(node) then return { self.icon } diff --git a/lua/nvim-tree/renderer/decorator/diagnostics.lua b/lua/nvim-tree/renderer/decorator/diagnostics.lua index fd7ceba6446..4e75346a89a 100644 --- a/lua/nvim-tree/renderer/decorator/diagnostics.lua +++ b/lua/nvim-tree/renderer/decorator/diagnostics.lua @@ -32,7 +32,7 @@ local ICON_KEYS = { ---@class (exact) DiagnosticsDecorator: Decorator ---@field private explorer Explorer ----@field private diag_icons nvim_tree.api.decorator.highlighted_string[]? +---@field private diag_icons nvim_tree.api.highlighted_string[]? local DiagnosticsDecorator = Decorator:extend() ---@class DiagnosticsDecorator @@ -73,7 +73,7 @@ end ---Diagnostic icon: diagnostics.enable, renderer.icons.show.diagnostics and node has status ---@param node Node ----@return nvim_tree.api.decorator.highlighted_string[]? icons +---@return nvim_tree.api.highlighted_string[]? icons function DiagnosticsDecorator:icons(node) if node and self.diag_icons then local diag_status = diagnostics.get_diag_status(node) diff --git a/lua/nvim-tree/renderer/decorator/git.lua b/lua/nvim-tree/renderer/decorator/git.lua index bcd83df99a2..268022644d6 100644 --- a/lua/nvim-tree/renderer/decorator/git.lua +++ b/lua/nvim-tree/renderer/decorator/git.lua @@ -3,7 +3,7 @@ local notify = require("nvim-tree.notify") local Decorator = require("nvim-tree.renderer.decorator") local DirectoryNode = require("nvim-tree.node.directory") ----@class (exact) GitHighlightedString: nvim_tree.api.decorator.highlighted_string +---@class (exact) GitHighlightedString: nvim_tree.api.highlighted_string ---@field ord number decreasing priority ---@alias GitStatusStrings "deleted" | "ignored" | "renamed" | "staged" | "unmerged" | "unstaged" | "untracked" @@ -142,7 +142,7 @@ end ---Git icons: git.enable, renderer.icons.show.git and node has status ---@param node Node ----@return nvim_tree.api.decorator.highlighted_string[]? icons +---@return nvim_tree.api.highlighted_string[]? icons function GitDecorator:icons(node) if not self.icons_by_xy then return nil diff --git a/lua/nvim-tree/renderer/decorator/hidden.lua b/lua/nvim-tree/renderer/decorator/hidden.lua index bffd82c370b..2d67d4e4cc2 100644 --- a/lua/nvim-tree/renderer/decorator/hidden.lua +++ b/lua/nvim-tree/renderer/decorator/hidden.lua @@ -3,7 +3,7 @@ local DirectoryNode = require("nvim-tree.node.directory") ---@class (exact) HiddenDecorator: Decorator ---@field private explorer Explorer ----@field private icon nvim_tree.api.decorator.highlighted_string? +---@field private icon nvim_tree.api.highlighted_string? local HiddenDecorator = Decorator:extend() ---@class HiddenDecorator @@ -29,7 +29,7 @@ end ---Hidden icon: renderer.icons.show.hidden and node starts with `.` (dotfile). ---@param node Node ----@return nvim_tree.api.decorator.highlighted_string[]? icons +---@return nvim_tree.api.highlighted_string[]? icons function HiddenDecorator:icons(node) if node:is_dotfile() then return { self.icon } diff --git a/lua/nvim-tree/renderer/decorator/init.lua b/lua/nvim-tree/renderer/decorator/init.lua index 479e11f0805..5a74785f30d 100644 --- a/lua/nvim-tree/renderer/decorator/init.lua +++ b/lua/nvim-tree/renderer/decorator/init.lua @@ -46,7 +46,7 @@ end ---Icons when "before" ---@param node Node ----@return nvim_tree.api.decorator.highlighted_string[]? icons +---@return nvim_tree.api.highlighted_string[]? icons function Decorator:icons_before(node) if not self.enabled or self.icon_placement ~= "before" then return @@ -57,7 +57,7 @@ end ---Icons when "after" ---@param node Node ----@return nvim_tree.api.decorator.highlighted_string[]? icons +---@return nvim_tree.api.highlighted_string[]? icons function Decorator:icons_after(node) if not self.enabled or self.icon_placement ~= "after" then return @@ -68,7 +68,7 @@ end ---Icons when "right_align" ---@param node Node ----@return nvim_tree.api.decorator.highlighted_string[]? icons +---@return nvim_tree.api.highlighted_string[]? icons function Decorator:icons_right_align(node) if not self.enabled or self.icon_placement ~= "right_align" then return @@ -79,7 +79,7 @@ end ---Define a sign ---@protected ----@param icon nvim_tree.api.decorator.highlighted_string? +---@param icon nvim_tree.api.highlighted_string? function Decorator:define_sign(icon) if icon and #icon.hl > 0 then local name = icon.hl[1] diff --git a/lua/nvim-tree/renderer/decorator/modified.lua b/lua/nvim-tree/renderer/decorator/modified.lua index ee41d7d90cd..a81a8411523 100644 --- a/lua/nvim-tree/renderer/decorator/modified.lua +++ b/lua/nvim-tree/renderer/decorator/modified.lua @@ -5,7 +5,7 @@ local DirectoryNode = require("nvim-tree.node.directory") ---@class (exact) ModifiedDecorator: Decorator ---@field private explorer Explorer ----@field private icon nvim_tree.api.decorator.highlighted_string? +---@field private icon nvim_tree.api.highlighted_string? local ModifiedDecorator = Decorator:extend() ---@class ModifiedDecorator @@ -31,7 +31,7 @@ end ---Modified icon: modified.enable, renderer.icons.show.modified and node is modified ---@param node Node ----@return nvim_tree.api.decorator.highlighted_string[]? icons +---@return nvim_tree.api.highlighted_string[]? icons function ModifiedDecorator:icons(node) if buffers.is_modified(node) then return { self.icon } diff --git a/lua/nvim-tree/renderer/decorator/opened.lua b/lua/nvim-tree/renderer/decorator/opened.lua index 094a893211c..125cb64787b 100644 --- a/lua/nvim-tree/renderer/decorator/opened.lua +++ b/lua/nvim-tree/renderer/decorator/opened.lua @@ -4,7 +4,7 @@ local Decorator = require("nvim-tree.renderer.decorator") ---@class (exact) OpenDecorator: Decorator ---@field private explorer Explorer ----@field private icon? nvim_tree.api.decorator.highlighted_string +---@field private icon? nvim_tree.api.highlighted_string local OpenDecorator = Decorator:extend() ---@class OpenDecorator diff --git a/lua/nvim-tree/renderer/decorator/user.lua b/lua/nvim-tree/renderer/decorator/user.lua index df55f543936..dda43fd7c90 100644 --- a/lua/nvim-tree/renderer/decorator/user.lua +++ b/lua/nvim-tree/renderer/decorator/user.lua @@ -1,6 +1,6 @@ local Decorator = require("nvim-tree.renderer.decorator") ----Exposed as nvim_tree.api.decorator.UserDecorator +---Exposed as nvim_tree.api.Decorator ---@class (exact) UserDecorator: Decorator local UserDecorator = Decorator:extend() diff --git a/scripts/vimdoc_config.lua b/scripts/vimdoc_config.lua index b52324288f3..5a2df20847d 100644 --- a/scripts/vimdoc_config.lua +++ b/scripts/vimdoc_config.lua @@ -45,26 +45,26 @@ local srcs_config = { ---@type Src[] local srcs_api = { - { helptag = "nvim-tree-api", section = "API", path = pre .. "api.lua", }, - - { helptag = "nvim-tree-api-commands", section = "API: commands", path = pre .. "_meta/api/commands.lua", }, - { helptag = "nvim-tree-api-events", section = "API: events", path = pre .. "_meta/api/events.lua", }, - { helptag = "nvim-tree-api-filter", section = "API: filter", path = pre .. "_meta/api/filter.lua", }, - { helptag = "nvim-tree-api-fs", section = "API: fs", path = pre .. "_meta/api/fs.lua", }, - { helptag = "nvim-tree-api-git", section = "API: git", path = pre .. "_meta/api/git.lua", }, - { helptag = "nvim-tree-api-health", section = "API: health", path = pre .. "_meta/api/health.lua", }, - { helptag = "nvim-tree-api-map", section = "API: map", path = pre .. "_meta/api/map.lua", }, - { helptag = "nvim-tree-api-marks", section = "API: marks", path = pre .. "_meta/api/marks.lua", }, - { helptag = "nvim-tree-api-node", section = "API: node", path = pre .. "_meta/api/node.lua", }, - { helptag = "nvim-tree-api-tree", section = "API: tree", path = pre .. "_meta/api/tree.lua", }, - - { helptag = "nvim-tree-api-decorator", section = "PLACEHOLDER", path = "runtime/lua/placeholder.lua", }, + { helptag = "nvim-tree-api", section = "API", path = pre .. "api.lua", }, + + { helptag = "nvim-tree-api-commands", section = "API: commands", path = pre .. "_meta/api/commands.lua", }, + { helptag = "nvim-tree-api-events", section = "API: events", path = pre .. "_meta/api/events.lua", }, + { helptag = "nvim-tree-api-filter", section = "API: filter", path = pre .. "_meta/api/filter.lua", }, + { helptag = "nvim-tree-api-fs", section = "API: fs", path = pre .. "_meta/api/fs.lua", }, + { helptag = "nvim-tree-api-git", section = "API: git", path = pre .. "_meta/api/git.lua", }, + { helptag = "nvim-tree-api-health", section = "API: health", path = pre .. "_meta/api/health.lua", }, + { helptag = "nvim-tree-api-map", section = "API: map", path = pre .. "_meta/api/map.lua", }, + { helptag = "nvim-tree-api-marks", section = "API: marks", path = pre .. "_meta/api/marks.lua", }, + { helptag = "nvim-tree-api-node", section = "API: node", path = pre .. "_meta/api/node.lua", }, + { helptag = "nvim-tree-api-tree", section = "API: tree", path = pre .. "_meta/api/tree.lua", }, + + { helptag = "nvim-tree-class", section = "PLACEHOLDER", path = "runtime/lua/placeholder.lua", }, } ---@type Src[] local srcs_class = { - { helptag = "nvim-tree-api-decorator", section = "API: Decorator", path = pre .. "_meta/api/decorator.lua", }, - { helptag = "nvim-tree-api-class", section = "API: Class", path = pre .. "classic.lua", }, + { helptag = "nvim-tree-class", section = "Class", path = pre .. "classic.lua", }, + { helptag = "nvim-tree-class-decorator", section = "Class: Decorator", path = pre .. "_meta/api/decorator.lua", }, } ---Map paths to file names From c2d266e17d62d92846d0e6a7a8d7c0d080c32341 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Tue, 3 Feb 2026 16:09:27 +1100 Subject: [PATCH 14/27] docs(#3241): add nvim-tree-class-decorator-example --- doc/nvim-tree-lua.txt | 215 +++++++++--------- lua/nvim-tree/_meta/api/decorator.lua | 4 +- lua/nvim-tree/_meta/api/decorator_example.lua | 96 ++++++++ scripts/vimdoc_config.lua | 5 +- 4 files changed, 204 insertions(+), 116 deletions(-) create mode 100644 lua/nvim-tree/_meta/api/decorator_example.lua diff --git a/doc/nvim-tree-lua.txt b/doc/nvim-tree-lua.txt index 5375f63f266..9396e88dd86 100644 --- a/doc/nvim-tree-lua.txt +++ b/doc/nvim-tree-lua.txt @@ -850,117 +850,6 @@ configurations for different types of prompts. - `nvimtree_bulk_trash` send all bookmarked to trash during |nvim_tree.api.marks.bulk.trash()| -============================================================================== -Decorators *nvim-tree-decorators* - -Highlighting and icons for nodes are provided by Decorators. You may provide -your own in addition to the builtin decorators. - -Decorators may: -- Add icons -- Set highlight group for the name or icons -- Override node icon - -Create a `nvim_tree.api.decorator.UserDecorator` class and register it with -precedence via |nvim_tree.config.renderer| {decorators} - -See |nvim-tree-decorator-example| - -============================================================================== -Decorators: Example *nvim-tree-decorator-example* - -A decorator class for nodes named "example", overridind all builtin decorators -except for Cut. - -- Highlights node name with `IncSearch` -- Creates two icons `"1"` and `"2"` placed after the node name, highlighted with - `DiffAdd` and `DiffText` -- Replaces the node icon with `"N"`, highlighted with `Error ` - -Create a class file `~/.config/nvim/lua/my-decorator.lua` - -Require and register it during |nvim-tree-setup|: ->lua - local MyDecorator = require("my-decorator") - - require("nvim-tree").setup({ - renderer = { - decorators = { - "Git", - "Open", - "Hidden", - "Modified", - "Bookmark", - "Diagnostics", - "Copied", - MyDecorator, - "Cut", - }, - }, - }) -< -Contents of `my-decorator.lua`: ->lua - ---@class (exact) MyDecorator: nvim_tree.api.Decorator - ---@field private my_icon1 nvim_tree.api.highlighted_string - ---@field private my_icon2 nvim_tree.api.highlighted_string - ---@field private my_icon_node nvim_tree.api.highlighted_string - ---@field private my_highlight_group string - local MyDecorator = require("nvim-tree.api").Decorator:extend() - - ---Mandatory constructor :new() will be called once per tree render, with no arguments. - function MyDecorator:new() - self.enabled = true - self.highlight_range = "name" - self.icon_placement = "after" - - -- create your icons and highlights once, applied to every node - self.my_icon1 = { str = "1", hl = { "DiffAdd" } } - self.my_icon2 = { str = "2", hl = { "DiffText" } } - self.my_icon_node = { str = "N", hl = { "Error" } } - self.my_highlight_group = "IncSearch" - - -- Define the icon signs only once - -- Only needed if you are using icon_placement = "signcolumn" - -- self:define_sign(self.my_icon1) - -- self:define_sign(self.my_icon2) - end - - ---Override node icon - ---@param node nvim_tree.api.Node - ---@return nvim_tree.api.highlighted_string? icon_node - function MyDecorator:icon_node(node) - if node.name == "example" then - return self.my_icon_node - else - return nil - end - end - - ---Return two icons for DecoratorIconPlacement "after" - ---@param node nvim_tree.api.Node - ---@return nvim_tree.api.highlighted_string[]? icons - function MyDecorator:icons(node) - if node.name == "example" then - return { self.my_icon1, self.my_icon2, } - else - return nil - end - end - - ---Exactly one highlight group for DecoratorHighlightRange "name" - ---@param node nvim_tree.api.Node - ---@return string? highlight_group - function MyDecorator:highlight_group(node) - if node.name == "example" then - return self.my_highlight_group - else - return nil - end - end - - return MyDecorator -< ============================================================================== OS Specific Restrictions *nvim-tree-os-specific* @@ -3273,12 +3162,14 @@ Class:nop({...}) *nvim_tree.Class:nop()* Class: Decorator *nvim-tree-class-decorator* Highlighting and icons for nodes are provided by Decorators, see -|nvim-tree-icons-highlighting| for an overview. You may provide your own in -addition to the builtin decorators. +|nvim-tree-icons-highlighting| for an overview. Decorators are rendered in |nvim_tree.config.renderer| {decorators} order of precedence, with later decorators applying additively over earlier. +You may provide your own in addition to the builtin decorators, see +|nvim-tree-class-decorator-example|. + Decorators may: • Add icons • Set a highlight group name for the name or icons @@ -3387,4 +3278,102 @@ Decorator:icons({node}) *nvim_tree.api.Decorator:icons()* is `"signcolumn"` +============================================================================== +Class: Decorator: example *nvim-tree-class-decorator-example* + +A decorator class for nodes named "example", overriding all builtin decorators +except for Cut. +• Highlights node name with `IncSearch` +• Creates two icons `"1"` and `"2"` placed after the node name, highlighted + with `DiffAdd` and `DiffText` +• Replaces the node icon with `"N"`, highlighted with `Error ` + +Create a class file `~/.config/nvim/lua/my-decorator.lua` + +Require and register it during |nvim-tree-setup|: >lua + + local MyDecorator = require("my-decorator") + + require("nvim-tree").setup({ + renderer = { + decorators = { + "Git", + "Open", + "Hidden", + "Modified", + "Bookmark", + "Diagnostics", + "Copied", + MyDecorator, + "Cut", + }, + }, + }) +< + +Contents of `my-decorator.lua`: >lua + + ---@class (exact) MyDecorator: nvim_tree.api.Decorator + ---@field private my_icon1 nvim_tree.api.highlighted_string + ---@field private my_icon2 nvim_tree.api.highlighted_string + ---@field private my_icon_node nvim_tree.api.highlighted_string + ---@field private my_highlight_group string + local MyDecorator = require("nvim-tree.api").Decorator:extend() + + ---Mandatory constructor :new() will be called once per tree render, with no arguments. + function MyDecorator:new() + self.enabled = true + self.highlight_range = "name" + self.icon_placement = "after" + + -- create your icons and highlights once, applied to every node + self.my_icon1 = { str = "1", hl = { "DiffAdd" } } + self.my_icon2 = { str = "2", hl = { "DiffText" } } + self.my_icon_node = { str = "N", hl = { "Error" } } + self.my_highlight_group = "IncSearch" + + -- Define the icon signs only once + -- Only needed if you are using icon_placement = "signcolumn" + -- self:define_sign(self.my_icon1) + -- self:define_sign(self.my_icon2) + end + + ---Override node icon + ---@param node nvim_tree.api.Node + ---@return nvim_tree.api.highlighted_string? icon_node + function MyDecorator:icon_node(node) + if node.name == "example" then + return self.my_icon_node + else + return nil + end + end + + ---Return two icons for DecoratorIconPlacement "after" + ---@param node nvim_tree.api.Node + ---@return nvim_tree.api.highlighted_string[]? icons + function MyDecorator:icons(node) + if node.name == "example" then + return { self.my_icon1, self.my_icon2, } + else + return nil + end + end + + ---Exactly one highlight group for DecoratorHighlightRange "name" + ---@param node nvim_tree.api.Node + ---@return string? highlight_group + function MyDecorator:highlight_group(node) + if node.name == "example" then + return self.my_highlight_group + else + return nil + end + end + + return MyDecorator +< + + + vim:tw=78:ts=8:sw=4:sts=4:et:ft=help:norl: diff --git a/lua/nvim-tree/_meta/api/decorator.lua b/lua/nvim-tree/_meta/api/decorator.lua index 851c25e1c11..583e4de5365 100644 --- a/lua/nvim-tree/_meta/api/decorator.lua +++ b/lua/nvim-tree/_meta/api/decorator.lua @@ -3,10 +3,12 @@ ---#TODO 3241 maybe rename to UserDecorator ---@brief ----Highlighting and icons for nodes are provided by Decorators, see [nvim-tree-icons-highlighting] for an overview. You may provide your own in addition to the builtin decorators. +---Highlighting and icons for nodes are provided by Decorators, see [nvim-tree-icons-highlighting] for an overview. --- ---Decorators are rendered in [nvim_tree.config.renderer] {decorators} order of precedence, with later decorators applying additively over earlier. --- +---You may provide your own in addition to the builtin decorators, see |nvim-tree-class-decorator-example|. +--- ---Decorators may: ---- Add icons ---- Set a highlight group name for the name or icons diff --git a/lua/nvim-tree/_meta/api/decorator_example.lua b/lua/nvim-tree/_meta/api/decorator_example.lua new file mode 100644 index 00000000000..0660d6d1ad9 --- /dev/null +++ b/lua/nvim-tree/_meta/api/decorator_example.lua @@ -0,0 +1,96 @@ +---@meta +error("Cannot require a meta file") + +---@brief +--- +---A decorator class for nodes named "example", overriding all builtin decorators except for Cut. +---- Highlights node name with `IncSearch` +---- Creates two icons `"1"` and `"2"` placed after the node name, highlighted with `DiffAdd` and `DiffText` +---- Replaces the node icon with `"N"`, highlighted with `Error ` +--- +---Create a class file `~/.config/nvim/lua/my-decorator.lua` +--- +---Require and register it during |nvim-tree-setup|: +---```lua +--- +---local MyDecorator = require("my-decorator") +--- +---require("nvim-tree").setup({ +--- renderer = { +--- decorators = { +--- "Git", +--- "Open", +--- "Hidden", +--- "Modified", +--- "Bookmark", +--- "Diagnostics", +--- "Copied", +--- MyDecorator, +--- "Cut", +--- }, +--- }, +---}) +---``` +---Contents of `my-decorator.lua`: +---```lua +--- +------@class (exact) MyDecorator: nvim_tree.api.Decorator +------@field private my_icon1 nvim_tree.api.highlighted_string +------@field private my_icon2 nvim_tree.api.highlighted_string +------@field private my_icon_node nvim_tree.api.highlighted_string +------@field private my_highlight_group string +---local MyDecorator = require("nvim-tree.api").Decorator:extend() +--- +------Mandatory constructor :new() will be called once per tree render, with no arguments. +---function MyDecorator:new() +--- self.enabled = true +--- self.highlight_range = "name" +--- self.icon_placement = "after" +--- +--- -- create your icons and highlights once, applied to every node +--- self.my_icon1 = { str = "1", hl = { "DiffAdd" } } +--- self.my_icon2 = { str = "2", hl = { "DiffText" } } +--- self.my_icon_node = { str = "N", hl = { "Error" } } +--- self.my_highlight_group = "IncSearch" +--- +--- -- Define the icon signs only once +--- -- Only needed if you are using icon_placement = "signcolumn" +--- -- self:define_sign(self.my_icon1) +--- -- self:define_sign(self.my_icon2) +---end +--- +------Override node icon +------@param node nvim_tree.api.Node +------@return nvim_tree.api.highlighted_string? icon_node +---function MyDecorator:icon_node(node) +--- if node.name == "example" then +--- return self.my_icon_node +--- else +--- return nil +--- end +---end +--- +------Return two icons for DecoratorIconPlacement "after" +------@param node nvim_tree.api.Node +------@return nvim_tree.api.highlighted_string[]? icons +---function MyDecorator:icons(node) +--- if node.name == "example" then +--- return { self.my_icon1, self.my_icon2, } +--- else +--- return nil +--- end +---end +--- +------Exactly one highlight group for DecoratorHighlightRange "name" +------@param node nvim_tree.api.Node +------@return string? highlight_group +---function MyDecorator:highlight_group(node) +--- if node.name == "example" then +--- return self.my_highlight_group +--- else +--- return nil +--- end +---end +--- +---return MyDecorator +---``` diff --git a/scripts/vimdoc_config.lua b/scripts/vimdoc_config.lua index 5a2df20847d..d66cbd1acd2 100644 --- a/scripts/vimdoc_config.lua +++ b/scripts/vimdoc_config.lua @@ -63,8 +63,9 @@ local srcs_api = { ---@type Src[] local srcs_class = { - { helptag = "nvim-tree-class", section = "Class", path = pre .. "classic.lua", }, - { helptag = "nvim-tree-class-decorator", section = "Class: Decorator", path = pre .. "_meta/api/decorator.lua", }, + { helptag = "nvim-tree-class", section = "Class", path = pre .. "classic.lua", }, + { helptag = "nvim-tree-class-decorator", section = "Class: Decorator", path = pre .. "_meta/api/decorator.lua", }, + { helptag = "nvim-tree-class-decorator-example", section = "Class: Decorator: example", path = pre .. "_meta/api/decorator_example.lua", }, } ---Map paths to file names From 88e0a93f0d7687fcfedc0b8edb060f3cdc30c553 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Tue, 3 Feb 2026 17:20:08 +1100 Subject: [PATCH 15/27] docs(#3241): move renderer alias doc to the class --- doc/nvim-tree-lua.txt | 91 ++++++++++++++----------- lua/nvim-tree/_meta/api/decorator.lua | 2 +- lua/nvim-tree/_meta/config/renderer.lua | 48 +++++++++++-- lua/nvim-tree/renderer/builder.lua | 2 - 4 files changed, 94 insertions(+), 49 deletions(-) diff --git a/doc/nvim-tree-lua.txt b/doc/nvim-tree-lua.txt index 9396e88dd86..9518e02d455 100644 --- a/doc/nvim-tree-lua.txt +++ b/doc/nvim-tree-lua.txt @@ -484,45 +484,29 @@ Icons may be displayed before files and directories. Additional icons and highlighting may be displayed to indicate various states for files and and directories. Highlighting is additive. -Decorators are responsible for providing the icons and highlighting. -|nvim_tree.config.renderer| {decorators} configures the decorators used, -in ascending order of precedence. - -`DECORATOR` *nvim_tree.config.renderer.decorator* - A builtin decorator name or |nvim_tree.api.Decorator| class. - Builtin decorators in default order: - • `"Git"` - • `"Open"` - • `"Hidden"` - • `"Modified"` - • `"Bookmark"` - • `"Diagnostics"` - • `"Copied"` - • `"Cut"` +Decorators are responsible for providing the icons and highlighting. They +apply additively in order of precedence. + +`DECORATOR` + See |nvim_tree.config.renderer.decorator| for available decorators and their + default precedence. `ICON?` Enable via |nvim_tree.config.renderer.icons.show `REQUIRES` - Feature must be enabled to show icons and highlighting. - -`PLACEMENT` *nvim_tree.config.renderer.icons.placement* - Where to place the icon: |nvim_tree.config.renderer.icons| {_placement} - • `before`: before file/folder, after the file/folders icons - • `after`: after file/folder - • `signcolumn`: far left, requires |nvim_tree.config.view| {signcolumn}. - • `right_align`: far right - -`HIGHLIGHT` *nvim_tree.config.renderer.highlight* - What should be highlighted: |nvim_tree.config.renderer| {highlight_} - • `none`: no highlighting - • `icon`: icon only - • `name`: name only - • `all`: icon and name + Features that must be enabled to show icons and highlighting. + +`PLACEMENT` + Where to place icons: |nvim_tree.config.renderer.icons.placement| + +`HIGHLIGHT` + What should be highlighted: |nvim_tree.config.renderer.highlight| `DEVICONS?` Glyphs and their colors will be overridden by optional plugin: - `nvim-tree/nvim-web-devicons` |nvim_tree.config.renderer.icons.web_devicons| + `nvim-tree/nvim-web-devicons` + See |nvim_tree.config.renderer.icons.web_devicons| `GLYPHS` Icon glyphs definitions. @@ -530,7 +514,8 @@ in ascending order of precedence. `GROUPS` Applicable highlight groups: |nvim-tree-highlight-groups| -Some defaults noted. In ascending order of default decorator precedence: +Some defaults noted. In ascending order of default decorator additive +precedence: `WHAT DECORATOR ICON? REQUIRES PLACEMENT HIGHLIGHT GLYPHS DEVICONS? GROUPS` File Icon - {file} Y - - - |nvim_tree.config.renderer.icons.glyphs| {default} Y `NvimTreeNormal`, `NvimTreeFileIcon` @@ -563,7 +548,8 @@ To view the nvim-tree highlight groups run |:NvimTreeHiTest| To view all active highlight groups run `:so $VIMRUNTIME/syntax/hitest.vim` as per |:highlight| -The `*HL` groups are additive as per |nvim_tree.config.renderer| precedence. +The `*HL` groups are additive according to per |nvim_tree.config.renderer| +precedence. Only present attributes will clobber each other. In this example a modified, opened file will have magenta text, with cyan undercurl: >vim @@ -1219,8 +1205,31 @@ Config: renderer *nvim-tree-config-renderer* *nvim_tree.config.renderer* Controls the appearance of the tree. - See |nvim-tree-icons-highlighting| for {highlight_} and {decorators} - fields. + {highlight_} *nvim_tree.config.renderer.highlight* + + See |nvim-tree-icons-highlighting| + • `"none"`: no highlighting + • `"icon"`: icon only + • `"name"`: name only + • `"all"`: icon and name + + {decorators} *nvim_tree.config.renderer.decorator* + + See |nvim-tree-icons-highlighting| + + A builtin decorator name `string` or |nvim_tree.api.Decorator| class. + + Builtin decorators in their default order: + • `"Git"` + • `"Open"` + • `"Hidden"` + • `"Modified"` + • `"Bookmark"` + • `"Diagnostics"` + • `"Copied"` + • `"Cut"` + + Specify {decorators} is a list e.g. `{ "Git", MyDecorator, "Cut" }` {root_folder_label} has 3 forms: • `string`: |filename-modifiers| format string, default `":~:s?$?/..?"` @@ -1267,9 +1276,7 @@ Config: renderer *nvim-tree-config-renderer* arrow followed by the target of the symlink. • {decorators}? (`nvim_tree.config.renderer.decorator[]`, default: `{ "Git", "Open", "Hidden", "Modified", "Bookmark", "Diagnostics", "Copied", "Cut", }`) - Ordered list of builtin - |nvim_tree.config.renderer.decorator| names - and |nvim_tree.api.Decorator| classes. + List in order of additive precedence. • {highlight_git}? (`nvim_tree.config.renderer.highlight`) (default: `"none"`) • {highlight_opened_files}? (`nvim_tree.config.renderer.highlight`) @@ -1324,7 +1331,11 @@ Config: renderer *nvim-tree-config-renderer* *nvim_tree.config.renderer.icons* Icons and separators - See |nvim-tree-icons-highlighting| for: {_placement} fields. + {_placement} *nvim_tree.config.renderer.icons.placement* + • `"before"`: before file/folder, after the file/folders icons + • `"after"`: after file/folder + • `"signcolumn"`: far left, requires |nvim_tree.config.view| {signcolumn}. + • `"right_align"`: far right Fields: ~ • {git_placement}? (`nvim_tree.config.renderer.icons.placement`) @@ -3165,7 +3176,7 @@ Highlighting and icons for nodes are provided by Decorators, see |nvim-tree-icons-highlighting| for an overview. Decorators are rendered in |nvim_tree.config.renderer| {decorators} order of -precedence, with later decorators applying additively over earlier. +additive precedence, with later decorators applying additively over earlier. You may provide your own in addition to the builtin decorators, see |nvim-tree-class-decorator-example|. diff --git a/lua/nvim-tree/_meta/api/decorator.lua b/lua/nvim-tree/_meta/api/decorator.lua index 583e4de5365..4da80d55cdc 100644 --- a/lua/nvim-tree/_meta/api/decorator.lua +++ b/lua/nvim-tree/_meta/api/decorator.lua @@ -5,7 +5,7 @@ ---@brief ---Highlighting and icons for nodes are provided by Decorators, see [nvim-tree-icons-highlighting] for an overview. --- ----Decorators are rendered in [nvim_tree.config.renderer] {decorators} order of precedence, with later decorators applying additively over earlier. +---Decorators are rendered in [nvim_tree.config.renderer] {decorators} order of additive precedence, with later decorators applying additively over earlier. --- ---You may provide your own in addition to the builtin decorators, see |nvim-tree-class-decorator-example|. --- diff --git a/lua/nvim-tree/_meta/config/renderer.lua b/lua/nvim-tree/_meta/config/renderer.lua index 4bda6dbfd51..3f7cef3a6b6 100644 --- a/lua/nvim-tree/_meta/config/renderer.lua +++ b/lua/nvim-tree/_meta/config/renderer.lua @@ -5,7 +5,39 @@ error("Cannot require a meta file") ---Controls the appearance of the tree. --- ----See [nvim-tree-icons-highlighting] for {highlight_} and {decorators} fields. +---{highlight_} [nvim_tree.config.renderer.highlight]() +--- +---See [nvim-tree-icons-highlighting] +--- +---- `"none"`: no highlighting +---- `"icon"`: icon only +---- `"name"`: name only +---- `"all"`: icon and name +---@alias nvim_tree.config.renderer.highlight "none"|"icon"|"name"|"all" +--- +--- +--- +---{decorators} [nvim_tree.config.renderer.decorator]() +--- +---See [nvim-tree-icons-highlighting] +--- +---A builtin decorator name `string` or |nvim_tree.api.Decorator| class. +--- +---Builtin decorators in their default order: +---- `"Git"` +---- `"Open"` +---- `"Hidden"` +---- `"Modified"` +---- `"Bookmark"` +---- `"Diagnostics"` +---- `"Copied"` +---- `"Cut"` +--- +---Specify {decorators} is a list e.g. `{ "Git", MyDecorator, "Cut" }` +--- +---@alias nvim_tree.config.renderer.decorator nvim_tree.api.Decorator|"Git"|"Open"|"Hidden"|"Modified"|"Bookmark"|"Diagnostics"|"Copied"|"Cut" +--- +--- --- ---{root_folder_label} has 3 forms: ---- `string`: [filename-modifiers] format string, default `":~:s?$?/..?"` @@ -17,6 +49,8 @@ error("Cannot require a meta file") ---end ---``` --- +--- +--- ---{hidden_display} [nvim_tree.config.renderer.hidden_display]() --- ---Summary of hidden nodes, below the last node in the directory, highlighted with `NvimTreeHiddenDisplay`. @@ -30,9 +64,7 @@ error("Cannot require a meta file") ---See [nvim_tree.config.renderer.hidden_stats] for details and example. ---@alias nvim_tree.config.renderer.hidden_display "none"|"simple"|"all"|(fun(hidden_stats: nvim_tree.config.renderer.hidden_stats): string?) --- ----@alias nvim_tree.config.renderer.highlight "none"|"icon"|"name"|"all" --- ----@alias nvim_tree.config.renderer.decorator nvim_tree.api.Decorator|"Git"|"Open"|"Hidden"|"Modified"|"Bookmark"|"Diagnostics"|"Copied"|"Cut" --- ---@class nvim_tree.config.renderer --- @@ -63,7 +95,7 @@ error("Cannot require a meta file") ---(default: `true`) ---@field symlink_destination? boolean --- ----Ordered list of builtin [nvim_tree.config.renderer.decorator] names and |nvim_tree.api.Decorator| classes. +---List in order of additive precedence. ---(default: `{ "Git", "Open", "Hidden", "Modified", "Bookmark", "Diagnostics", "Copied", "Cut", }`) ---@field decorators? nvim_tree.config.renderer.decorator[] --- @@ -134,10 +166,14 @@ error("Cannot require a meta file") ---Icons and separators --- ----See [nvim-tree-icons-highlighting] for: {_placement} fields. ---- +---{_placement} [nvim_tree.config.renderer.icons.placement]() +---- `"before"`: before file/folder, after the file/folders icons +---- `"after"`: after file/folder +---- `"signcolumn"`: far left, requires |nvim_tree.config.view| {signcolumn}. +---- `"right_align"`: far right ---@alias nvim_tree.config.renderer.icons.placement "before"|"after"|"signcolumn"|"right_align" --- +--- ---@class nvim_tree.config.renderer.icons --- ---(default: `before`) diff --git a/lua/nvim-tree/renderer/builder.lua b/lua/nvim-tree/renderer/builder.lua index 25b2557a346..903f31d904e 100644 --- a/lua/nvim-tree/renderer/builder.lua +++ b/lua/nvim-tree/renderer/builder.lua @@ -18,8 +18,6 @@ local UserDecorator = require("nvim-tree.renderer.decorator.user") local pad = require("nvim-tree.renderer.components.padding") ----TODO #3241 add an alias for builtins or document the enum - -- Builtin Decorators ---@type table local BUILTIN_DECORATORS = { From e60d7a29ece47e5918bb4f1ab55a416742b46db5 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Tue, 3 Feb 2026 17:24:53 +1100 Subject: [PATCH 16/27] docs(#3241): Class -> nvim_tree.Class --- lua/nvim-tree/actions/fs/clipboard.lua | 2 +- lua/nvim-tree/appearance/hi-test.lua | 3 ++- lua/nvim-tree/classic.lua | 10 ++++------ lua/nvim-tree/explorer/filters.lua | 2 +- lua/nvim-tree/explorer/live-filter.lua | 2 +- lua/nvim-tree/explorer/sorter.lua | 2 +- lua/nvim-tree/git/runner.lua | 2 +- lua/nvim-tree/marks/init.lua | 2 +- lua/nvim-tree/node/init.lua | 2 +- lua/nvim-tree/node/link.lua | 2 +- lua/nvim-tree/renderer/decorator/init.lua | 2 +- lua/nvim-tree/renderer/init.lua | 2 +- lua/nvim-tree/watcher.lua | 4 ++-- 13 files changed, 18 insertions(+), 19 deletions(-) diff --git a/lua/nvim-tree/actions/fs/clipboard.lua b/lua/nvim-tree/actions/fs/clipboard.lua index 3f3ed37c94d..494939d645b 100644 --- a/lua/nvim-tree/actions/fs/clipboard.lua +++ b/lua/nvim-tree/actions/fs/clipboard.lua @@ -15,7 +15,7 @@ local DirectoryNode = require("nvim-tree.node.directory") ---@alias ClipboardActionFn fun(source: string, dest: string): boolean, string? ----@class (exact) Clipboard: Class +---@class (exact) Clipboard: nvim_tree.Class ---@field private explorer Explorer ---@field private data ClipboardData ---@field private clipboard_name string diff --git a/lua/nvim-tree/appearance/hi-test.lua b/lua/nvim-tree/appearance/hi-test.lua index 5223b8336dd..8aa7567ec7b 100644 --- a/lua/nvim-tree/appearance/hi-test.lua +++ b/lua/nvim-tree/appearance/hi-test.lua @@ -7,7 +7,8 @@ local SHORT_LEN = 50 local namespace_hi_test_id = vim.api.nvim_create_namespace("NvimTreeHiTest") ----@class (exact) HighlightDisplay: Class for :NvimTreeHiTest +---For :NvimTreeHiTest +---@class (exact) HighlightDisplay: nvim_tree.Class ---@field group string nvim-tree highlight group name ---@field links string link chain to a concretely defined group ---@field def string :hi concrete definition after following any links diff --git a/lua/nvim-tree/classic.lua b/lua/nvim-tree/classic.lua index d7a072c10da..5efc64ae031 100644 --- a/lua/nvim-tree/classic.lua +++ b/lua/nvim-tree/classic.lua @@ -9,13 +9,11 @@ -- https://github.com/rxi/classic -- ----TODO #3241 document and rename ----@class Class: nvim_tree.Class ----@nodoc +---TODO #3241 document ---@class nvim_tree.Class ----@field super Class ----@field private implements table +---@field super nvim_tree.Class +---@field private implements table local Class = {} Class.__index = Class ---@diagnostic disable-line: inject-field @@ -39,7 +37,7 @@ end ---Implement the functions of a mixin ---Add the mixin to .implements ----@param mixin Class +---@param mixin nvim_tree.Class function Class:implement(mixin) if not rawget(self, "implements") then -- set on the class itself instead of parents diff --git a/lua/nvim-tree/explorer/filters.lua b/lua/nvim-tree/explorer/filters.lua index 43851954553..71be462e4c2 100644 --- a/lua/nvim-tree/explorer/filters.lua +++ b/lua/nvim-tree/explorer/filters.lua @@ -5,7 +5,7 @@ local Class = require("nvim-tree.classic") ---@alias FilterType "custom" | "dotfiles" | "git_ignored" | "git_clean" | "no_buffer" | "no_bookmark" ----@class (exact) Filters: Class +---@class (exact) Filters: nvim_tree.Class ---@field enabled boolean ---@field state table ---@field private explorer Explorer diff --git a/lua/nvim-tree/explorer/live-filter.lua b/lua/nvim-tree/explorer/live-filter.lua index c6d64e848d3..81e6da81657 100644 --- a/lua/nvim-tree/explorer/live-filter.lua +++ b/lua/nvim-tree/explorer/live-filter.lua @@ -5,7 +5,7 @@ local Class = require("nvim-tree.classic") local Iterator = require("nvim-tree.iterators.node-iterator") local DirectoryNode = require("nvim-tree.node.directory") ----@class (exact) LiveFilter: Class +---@class (exact) LiveFilter: nvim_tree.Class ---@field explorer Explorer ---@field prefix string ---@field always_show_folders boolean diff --git a/lua/nvim-tree/explorer/sorter.lua b/lua/nvim-tree/explorer/sorter.lua index 799cfa481b1..c0d5cb34cd4 100644 --- a/lua/nvim-tree/explorer/sorter.lua +++ b/lua/nvim-tree/explorer/sorter.lua @@ -6,7 +6,7 @@ local DirectoryNode = require("nvim-tree.node.directory") ---@alias SorterUser fun(nodes: Node[]): SorterType? ----@class (exact) Sorter: Class +---@class (exact) Sorter: nvim_tree.Class ---@field private explorer Explorer local Sorter = Class:extend() diff --git a/lua/nvim-tree/git/runner.lua b/lua/nvim-tree/git/runner.lua index 938d10fa0e0..3d41092631b 100644 --- a/lua/nvim-tree/git/runner.lua +++ b/lua/nvim-tree/git/runner.lua @@ -4,7 +4,7 @@ local notify = require("nvim-tree.notify") local Class = require("nvim-tree.classic") ----@class (exact) GitRunner: Class +---@class (exact) GitRunner: nvim_tree.Class ---@field private toplevel string absolute path ---@field private path string? absolute path ---@field private list_untracked boolean diff --git a/lua/nvim-tree/marks/init.lua b/lua/nvim-tree/marks/init.lua index 7394b3044e0..abe67448908 100644 --- a/lua/nvim-tree/marks/init.lua +++ b/lua/nvim-tree/marks/init.lua @@ -58,7 +58,7 @@ local function load_bookmarks(opts) return {} end ----@class (exact) Marks: Class +---@class (exact) Marks: nvim_tree.Class ---@field private explorer Explorer ---@field private marks table by absolute path local Marks = Class:extend() diff --git a/lua/nvim-tree/node/init.lua b/lua/nvim-tree/node/init.lua index 8aae8adb72a..61fe6178959 100644 --- a/lua/nvim-tree/node/init.lua +++ b/lua/nvim-tree/node/init.lua @@ -1,7 +1,7 @@ local Class = require("nvim-tree.classic") ---Abstract Node class. ----@class (exact) Node: Class +---@class (exact) Node: nvim_tree.Class ---@field uid_node number vim.loop.hrtime() at construction time ---@field type "file" | "directory" | "link" uv.fs_stat.result.type ---@field explorer Explorer diff --git a/lua/nvim-tree/node/link.lua b/lua/nvim-tree/node/link.lua index c3bc164b912..a59e978862b 100644 --- a/lua/nvim-tree/node/link.lua +++ b/lua/nvim-tree/node/link.lua @@ -1,6 +1,6 @@ local Class = require("nvim-tree.classic") ----@class (exact) LinkNode: Class +---@class (exact) LinkNode: nvim_tree.Class ---@field link_to string ---@field fs_stat_target uv.fs_stat.result local LinkNode = Class:extend() diff --git a/lua/nvim-tree/renderer/decorator/init.lua b/lua/nvim-tree/renderer/decorator/init.lua index 5a74785f30d..e60394f43df 100644 --- a/lua/nvim-tree/renderer/decorator/init.lua +++ b/lua/nvim-tree/renderer/decorator/init.lua @@ -1,5 +1,5 @@ ---Abstract Decorator implementation ----@class (exact) Decorator: Class +---@class (exact) Decorator: nvim_tree.Class ---@field protected enabled boolean ---@field protected highlight_range nvim_tree.config.renderer.highlight ---@field protected icon_placement "none"|nvim_tree.config.renderer.icons.placement diff --git a/lua/nvim-tree/renderer/init.lua b/lua/nvim-tree/renderer/init.lua index 30af27e81b9..e7b98e6cd6b 100644 --- a/lua/nvim-tree/renderer/init.lua +++ b/lua/nvim-tree/renderer/init.lua @@ -13,7 +13,7 @@ local namespace_virtual_lines_id = vim.api.nvim_create_namespace("NvimTreeVirtua ---@alias HighlightRangeArgs { higroup:string, start:integer[], finish:integer[] } named arguments for vim.hl.range ----@class (exact) Renderer: Class +---@class (exact) Renderer: nvim_tree.Class ---@field explorer Explorer local Renderer = Class:extend() diff --git a/lua/nvim-tree/watcher.lua b/lua/nvim-tree/watcher.lua index fbedc3b9e86..ecae249de4c 100644 --- a/lua/nvim-tree/watcher.lua +++ b/lua/nvim-tree/watcher.lua @@ -21,7 +21,7 @@ local M = { ---@type Event[] local events = {} ----@class (exact) Event: Class +---@class (exact) Event: nvim_tree.Class ---@field destroyed boolean ---@field private path string ---@field private fs_event uv.uv_fs_event_t? @@ -155,7 +155,7 @@ end ---@type Watcher[] local watchers = {} ----@class (exact) Watcher: Class +---@class (exact) Watcher: nvim_tree.Class ---@field data table user data ---@field destroyed boolean ---@field private path string From 4b2b5845cab18a8eb8fc3674b3b159a9cde60a3e Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Tue, 3 Feb 2026 17:25:35 +1100 Subject: [PATCH 17/27] docs(#3241): Class -> nvim_tree.Class --- doc/nvim-tree-lua.txt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/nvim-tree-lua.txt b/doc/nvim-tree-lua.txt index 9518e02d455..be61063850b 100644 --- a/doc/nvim-tree-lua.txt +++ b/doc/nvim-tree-lua.txt @@ -3118,13 +3118,13 @@ Class *nvim-tree-class* *nvim_tree.Class* Fields: ~ - • {super} (`Class`) + • {super} (`nvim_tree.Class`) • {new} (`fun(self: nvim_tree.Class)`) See |nvim_tree.Class:new()|. • {extend} (`fun(self: nvim_tree.Class)`) See |nvim_tree.Class:extend()|. - • {implement} (`fun(self: nvim_tree.Class, mixin: Class)`) See - |nvim_tree.Class:implement()|. + • {implement} (`fun(self: nvim_tree.Class, mixin: nvim_tree.Class)`) + See |nvim_tree.Class:implement()|. • {is} (`fun(self: nvim_tree.Class, class: T): boolean`) See |nvim_tree.Class:is()|. • {as} (`fun(self: nvim_tree.Class, class: T): T?`) See @@ -3149,7 +3149,7 @@ Class:implement({mixin}) *nvim_tree.Class:implement()* Implement the functions of a mixin Add the mixin to .implements Parameters: ~ - • {mixin} (`Class`) + • {mixin} (`nvim_tree.Class`) Class:is({class}) *nvim_tree.Class:is()* Object is an instance of class or implements a mixin From 67a74f38e2e930273d92ede65229c764f641dce9 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Wed, 4 Feb 2026 10:42:44 +1100 Subject: [PATCH 18/27] docs(#3241): document nvim_tree.Class --- doc/nvim-tree-lua.txt | 118 ++++++++++++++++++++++++++++++---- lua/nvim-tree/classic.lua | 129 ++++++++++++++++++++++++++++++++++---- 2 files changed, 223 insertions(+), 24 deletions(-) diff --git a/doc/nvim-tree-lua.txt b/doc/nvim-tree-lua.txt index be61063850b..b8123d5ade4 100644 --- a/doc/nvim-tree-lua.txt +++ b/doc/nvim-tree-lua.txt @@ -3115,13 +3115,82 @@ winid({opts}) *nvim_tree.api.tree.winid()* ============================================================================== Class *nvim-tree-class* +nvim-tree uses the https://github.com/rxi/classic class framework adding safe +casts, instanceof mixin and conventional destructors. + +The key differences between classic and ordinary Lua classes: +• The constructor |nvim_tree.Class:new()| is not responsible for allocation: + `self` is available when the constructor is called. +• Instances are constructed via the `__call` meta method: `SomeClass(args)` + +Classes are conventionally named using camel case e.g. `MyClass` + +Classes are created by extending another class: >lua + + local Class = require("nvim-tree.classic") + + ---@class (exact) Fruit: nvim_tree.Class + ---@field ... + local Fruit = Class:extend() + + ---@class (exact) Apple: Fruit + ---@field ... + local Apple = Fruit:extend() +< + +Implementing a constructor |nvim_tree.Class:new()| is optional, however it +must call the `super` constructor: >lua + + ---@protected + ---@param args AppleArgs + function Apple:new(args) + + ---@type FruitArgs + local fruit_args = ... + + Apple.super.new(self, fruit_args) + --- +< + +Create an instance of a class using the `__call` meta method that will invoke +the constructor: >lua + + ---@type AppleArgs + local args = ... + + local an_apple = Apple(args) + -- above will call `Apple:new(args)` +< + +In order to strongly type instantiation, the following pattern is used to type +the meta method `__call` with arguments and return: >lua + + ---@class (exact) Fruit: nvim_tree.Class + ---@field ... + local Fruit = Class:extend() + + ---@class (exact) FruitArgs + ---@field ... + + ---@class Fruit + ---@overload fun(args: FruitArgs): Fruit + + ---@protected + ---@param args FruitArgs + function Fruit:new(args) +< + + *nvim_tree.Class* Fields: ~ - • {super} (`nvim_tree.Class`) - • {new} (`fun(self: nvim_tree.Class)`) See + • {super} (`nvim_tree.Class`) Parent class, `Class` for base + classes. + • {new} (`fun(self: nvim_tree.Class, ...: any)`) See |nvim_tree.Class:new()|. - • {extend} (`fun(self: nvim_tree.Class)`) See + • {destroy} (`fun(self: nvim_tree.Class)`) See + |nvim_tree.Class:destroy()|. + • {extend} (`fun(self: nvim_tree.Class): [nvim_tree.Class]`) See |nvim_tree.Class:extend()|. • {implement} (`fun(self: nvim_tree.Class, mixin: nvim_tree.Class)`) See |nvim_tree.Class:implement()|. @@ -3134,36 +3203,61 @@ Class *nvim-tree-class* Class:as({class}) *nvim_tree.Class:as()* - Return object if |nvim_tree.Class:is()| otherwise nil + Type safe cast. + + If instance |nvim_tree.Class:is()|, cast to {class} and return it, + otherwise nil. Parameters: ~ - • {class} (`any`) + • {class} (`any`) `` Return: ~ - (`T?`) + (`any?`) `` + +Class:destroy() *nvim_tree.Class:destroy()* + Conventional destructor, optional, must be called by the owner. + + Parent destructor must be invoked using the form `Parent.destroy(self)` Class:extend() *nvim_tree.Class:extend()* - Extend a class, setting .super + Create a new class by extending another class. + + Base classes extend `Class` + + Return: ~ + (`[nvim_tree.Class]`) child class Class:implement({mixin}) *nvim_tree.Class:implement()* - Implement the functions of a mixin Add the mixin to .implements + Add the methods and fields of a mixin using the form + `SomeClass:implement(MixinClass)` + + If the mixin has fields, it must implement a constructor. Parameters: ~ • {mixin} (`nvim_tree.Class`) Class:is({class}) *nvim_tree.Class:is()* - Object is an instance of class or implements a mixin + Instance of. + + Test whether an object inherits {class} or implements a mixin {class}. Parameters: ~ - • {class} (`any`) + • {class} (`any`) `` Return: ~ (`boolean`) -Class:new() *nvim_tree.Class:new()* - Default constructor +Class:new({...}) *nvim_tree.Class:new()* + Constructor: `self` has been allocated and is available. + + Super constructor must be called using the form + `Child.super.new(self, parent_args)` + + Parameters: ~ + • {...} (`any`) constructor arguments Class:nop({...}) *nvim_tree.Class:nop()* + Utility method to bypass unused param warnings in abstract methods. Parameters: ~ • {...} (`any`) diff --git a/lua/nvim-tree/classic.lua b/lua/nvim-tree/classic.lua index 5efc64ae031..7135eb64550 100644 --- a/lua/nvim-tree/classic.lua +++ b/lua/nvim-tree/classic.lua @@ -9,19 +9,107 @@ -- https://github.com/rxi/classic -- ----TODO #3241 document +---@brief +--- +---nvim-tree uses the https://github.com/rxi/classic class framework adding safe casts, instanceof mixin and conventional destructors. +--- +---The key differences between classic and ordinary Lua classes: +---- The constructor [nvim_tree.Class:new()] is not responsible for allocation: `self` is available when the constructor is called. +---- Instances are constructed via the `__call` meta method: `SomeClass(args)` +--- +---Classes are conventionally named using camel case e.g. `MyClass` +--- +---Classes are created by extending another class: +---```lua +--- +--- local Class = require("nvim-tree.classic") +--- +--- ---@class (exact) Fruit: nvim_tree.Class +--- ---@field ... +--- local Fruit = Class:extend() +--- +--- ---@class (exact) Apple: Fruit +--- ---@field ... +--- local Apple = Fruit:extend() +---``` +--- +---Implementing a constructor [nvim_tree.Class:new()] is optional, however it must call the `super` constructor: +---```lua +--- +--- ---@protected +--- ---@param args AppleArgs +--- function Apple:new(args) +--- +--- ---@type FruitArgs +--- local fruit_args = ... +--- +--- Apple.super.new(self, fruit_args) +--- --- +---``` +--- +---Create an instance of a class using the `__call` meta method that will invoke the constructor: +---```lua +--- +--- ---@type AppleArgs +--- local args = ... +--- +--- local an_apple = Apple(args) +--- -- above will call `Apple:new(args)` +---``` +--- +---In order to strongly type instantiation, the following pattern is used to type the meta method `__call` with arguments and return: +---```lua +--- +--- ---@class (exact) Fruit: nvim_tree.Class +--- ---@field ... +--- local Fruit = Class:extend() +--- +--- ---@class (exact) FruitArgs +--- ---@field ... +--- +--- ---@class Fruit +--- ---@overload fun(args: FruitArgs): Fruit +--- +--- ---@protected +--- ---@param args FruitArgs +--- function Fruit:new(args) +---``` + +--- ---@class nvim_tree.Class +--- +---Parent class, `Class` for base classes. ---@field super nvim_tree.Class +--- +---mixin classes that are implemented. ---@field private implements table local Class = {} Class.__index = Class ---@diagnostic disable-line: inject-field ----Default constructor +--- +---Constructor: `self` has been allocated and is available. +--- +---Super constructor must be called using the form `Child.super.new(self, parent_args)` +--- +---@param ... any constructor arguments function Class:new(...) --luacheck: ignore 212 end ----Extend a class, setting .super +--- +---Conventional destructor, optional, must be called by the owner. +--- +---Parent destructor must be invoked using the form `Parent.destroy(self)` +--- +function Class:destroy() +end + +--- +---Create a new class by extending another class. +--- +---Base classes extend `Class` +--- +---@return [nvim_tree.Class] child class function Class:extend() local cls = {} for k, v in pairs(self) do @@ -35,8 +123,11 @@ function Class:extend() return cls end ----Implement the functions of a mixin ----Add the mixin to .implements +--- +---Add the methods and fields of a mixin using the form `SomeClass:implement(MixinClass)` +--- +---If the mixin has fields, it must implement a constructor. +--- ---@param mixin nvim_tree.Class function Class:implement(mixin) if not rawget(self, "implements") then @@ -51,9 +142,13 @@ function Class:implement(mixin) end end ----Object is an instance of class or implements a mixin +--- +---Instance of. +--- +---Test whether an object inherits {class} or implements a mixin {class}. +--- ---@generic T ----@param class T +---@param class T `` ---@return boolean function Class:is(class) local mt = getmetatable(self) @@ -69,22 +164,32 @@ function Class:is(class) return false end ----Return object if [nvim_tree.Class:is()] otherwise nil +--- +---Type safe cast. +--- +---If instance [nvim_tree.Class:is()], cast to {class} and return it, otherwise nil. +--- ---@generic T ----@param class T ----@return T|nil +---@param class T `` +---@return T? `` function Class:as(class) return self:is(class) and self or nil end ----Constructor to create instance, call [nvim_tree.Class:new()] and return +--- +---Constructs an instance: calls [nvim_tree.Class:new()] and returns the new instance. +--- +---@param ... any constructor args +---@return nvim_tree.Class function Class:__call(...) local obj = setmetatable({}, self) obj:new(...) return obj end --- avoid unused param warnings in abstract methods +--- +---Utility method to bypass unused param warnings in abstract methods. +--- ---@param ... any function Class:nop(...) --luacheck: ignore 212 end From e7803aa1fec6a45ca5e6bd09ef463094851eb047 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Wed, 4 Feb 2026 10:48:11 +1100 Subject: [PATCH 19/27] docs(#3241): fix help lua indentation --- doc/nvim-tree-lua.txt | 135 ++++++++-------- lua/nvim-tree/_meta/api/decorator_example.lua | 152 +++++++++--------- lua/nvim-tree/_meta/config/actions.lua | 14 +- lua/nvim-tree/_meta/config/default.lua | 8 +- lua/nvim-tree/_meta/config/renderer.lua | 32 ++-- lua/nvim-tree/_meta/config/sort.lua | 16 +- lua/nvim-tree/_meta/config/view.lua | 16 +- lua/nvim-tree/classic.lua | 2 +- 8 files changed, 188 insertions(+), 187 deletions(-) diff --git a/doc/nvim-tree-lua.txt b/doc/nvim-tree-lua.txt index b8123d5ade4..77c7ec7766e 100644 --- a/doc/nvim-tree-lua.txt +++ b/doc/nvim-tree-lua.txt @@ -1094,9 +1094,9 @@ Config: sort *nvim-tree-config-sort* ---@param nodes nvim_tree.api.Node[] ---@return nvim_tree.config.sort.Sorter? local sorter = function(nodes) - table.sort(nodes, function(a, b) - return #a.name < #b.name - end) + table.sort(nodes, function(a, b) + return #a.name < #b.name + end) end < @@ -1167,12 +1167,12 @@ Config: view *nvim-tree-config-view* {open_win_config} is passed to |nvim_open_win()|, default: >lua { - relative = "editor", - border = "rounded", - width = 30, - height = 30, - row = 1, - col = 1, + relative = "editor", + border = "rounded", + width = 30, + height = 30, + row = 1, + col = 1, } < @@ -1237,7 +1237,7 @@ Config: renderer *nvim-tree-config-renderer* • `fun(root_cwd: string): string`: return a literal string from root's absolute path e.g. >lua my_root_folder_label = function(path) - return ".../" .. vim.fn.fnamemodify(path, ":t") + return ".../" .. vim.fn.fnamemodify(path, ":t") end < @@ -1308,15 +1308,15 @@ Config: renderer *nvim-tree-config-renderer* ---@param hidden_stats nvim_tree.config.renderer.hidden_stats ---@return string? summary local my_hidden_display = function(hidden_stats) - local total_count = 0 - for reason, count in pairs(hidden_stats) do - total_count = total_count + count - end - - if total_count > 0 then - return "(" .. tostring(total_count) .. " hidden)" - end - return nil + local total_count = 0 + for reason, count in pairs(hidden_stats) do + total_count = total_count + count + end + + if total_count > 0 then + return "(" .. tostring(total_count) .. " hidden)" + end + return nil end < @@ -1766,11 +1766,11 @@ Config: actions *nvim-tree-config-actions* {open_win_config} is passed to |nvim_open_win()|, default: >lua { - col = 1, - row = 1, - relative = "cursor", - border = "shadow", - style = "minimal", + col = 1, + row = 1, + relative = "cursor", + border = "shadow", + style = "minimal", } < @@ -3239,7 +3239,8 @@ Class:implement({mixin}) *nvim_tree.Class:implement()* Class:is({class}) *nvim_tree.Class:is()* Instance of. - Test whether an object inherits {class} or implements a mixin {class}. + Test whether an object is {class}, inherits {class} or implements mixin + {class}. Parameters: ~ • {class} (`any`) `` @@ -3400,19 +3401,19 @@ Require and register it during |nvim-tree-setup|: >lua local MyDecorator = require("my-decorator") require("nvim-tree").setup({ - renderer = { - decorators = { - "Git", - "Open", - "Hidden", - "Modified", - "Bookmark", - "Diagnostics", - "Copied", - MyDecorator, - "Cut", - }, - }, + renderer = { + decorators = { + "Git", + "Open", + "Hidden", + "Modified", + "Bookmark", + "Diagnostics", + "Copied", + MyDecorator, + "Cut", + }, + }, }) < @@ -3427,53 +3428,53 @@ Contents of `my-decorator.lua`: >lua ---Mandatory constructor :new() will be called once per tree render, with no arguments. function MyDecorator:new() - self.enabled = true - self.highlight_range = "name" - self.icon_placement = "after" - - -- create your icons and highlights once, applied to every node - self.my_icon1 = { str = "1", hl = { "DiffAdd" } } - self.my_icon2 = { str = "2", hl = { "DiffText" } } - self.my_icon_node = { str = "N", hl = { "Error" } } - self.my_highlight_group = "IncSearch" - - -- Define the icon signs only once - -- Only needed if you are using icon_placement = "signcolumn" - -- self:define_sign(self.my_icon1) - -- self:define_sign(self.my_icon2) + self.enabled = true + self.highlight_range = "name" + self.icon_placement = "after" + + -- create your icons and highlights once, applied to every node + self.my_icon1 = { str = "1", hl = { "DiffAdd" } } + self.my_icon2 = { str = "2", hl = { "DiffText" } } + self.my_icon_node = { str = "N", hl = { "Error" } } + self.my_highlight_group = "IncSearch" + + -- Define the icon signs only once + -- Only needed if you are using icon_placement = "signcolumn" + -- self:define_sign(self.my_icon1) + -- self:define_sign(self.my_icon2) end ---Override node icon ---@param node nvim_tree.api.Node ---@return nvim_tree.api.highlighted_string? icon_node function MyDecorator:icon_node(node) - if node.name == "example" then - return self.my_icon_node - else - return nil - end + if node.name == "example" then + return self.my_icon_node + else + return nil + end end ---Return two icons for DecoratorIconPlacement "after" ---@param node nvim_tree.api.Node ---@return nvim_tree.api.highlighted_string[]? icons function MyDecorator:icons(node) - if node.name == "example" then - return { self.my_icon1, self.my_icon2, } - else - return nil - end + if node.name == "example" then + return { self.my_icon1, self.my_icon2, } + else + return nil + end end ---Exactly one highlight group for DecoratorHighlightRange "name" ---@param node nvim_tree.api.Node ---@return string? highlight_group function MyDecorator:highlight_group(node) - if node.name == "example" then - return self.my_highlight_group - else - return nil - end + if node.name == "example" then + return self.my_highlight_group + else + return nil + end end return MyDecorator diff --git a/lua/nvim-tree/_meta/api/decorator_example.lua b/lua/nvim-tree/_meta/api/decorator_example.lua index 0660d6d1ad9..32ccc4fd991 100644 --- a/lua/nvim-tree/_meta/api/decorator_example.lua +++ b/lua/nvim-tree/_meta/api/decorator_example.lua @@ -13,84 +13,84 @@ error("Cannot require a meta file") ---Require and register it during |nvim-tree-setup|: ---```lua --- ----local MyDecorator = require("my-decorator") ---- ----require("nvim-tree").setup({ ---- renderer = { ---- decorators = { ---- "Git", ---- "Open", ---- "Hidden", ---- "Modified", ---- "Bookmark", ---- "Diagnostics", ---- "Copied", ---- MyDecorator, ---- "Cut", ---- }, ---- }, ----}) +--- local MyDecorator = require("my-decorator") +--- +--- require("nvim-tree").setup({ +--- renderer = { +--- decorators = { +--- "Git", +--- "Open", +--- "Hidden", +--- "Modified", +--- "Bookmark", +--- "Diagnostics", +--- "Copied", +--- MyDecorator, +--- "Cut", +--- }, +--- }, +--- }) ---``` ---Contents of `my-decorator.lua`: ---```lua --- -------@class (exact) MyDecorator: nvim_tree.api.Decorator -------@field private my_icon1 nvim_tree.api.highlighted_string -------@field private my_icon2 nvim_tree.api.highlighted_string -------@field private my_icon_node nvim_tree.api.highlighted_string -------@field private my_highlight_group string ----local MyDecorator = require("nvim-tree.api").Decorator:extend() ---- -------Mandatory constructor :new() will be called once per tree render, with no arguments. ----function MyDecorator:new() ---- self.enabled = true ---- self.highlight_range = "name" ---- self.icon_placement = "after" ---- ---- -- create your icons and highlights once, applied to every node ---- self.my_icon1 = { str = "1", hl = { "DiffAdd" } } ---- self.my_icon2 = { str = "2", hl = { "DiffText" } } ---- self.my_icon_node = { str = "N", hl = { "Error" } } ---- self.my_highlight_group = "IncSearch" ---- ---- -- Define the icon signs only once ---- -- Only needed if you are using icon_placement = "signcolumn" ---- -- self:define_sign(self.my_icon1) ---- -- self:define_sign(self.my_icon2) ----end ---- -------Override node icon -------@param node nvim_tree.api.Node -------@return nvim_tree.api.highlighted_string? icon_node ----function MyDecorator:icon_node(node) ---- if node.name == "example" then ---- return self.my_icon_node ---- else ---- return nil ---- end ----end ---- -------Return two icons for DecoratorIconPlacement "after" -------@param node nvim_tree.api.Node -------@return nvim_tree.api.highlighted_string[]? icons ----function MyDecorator:icons(node) ---- if node.name == "example" then ---- return { self.my_icon1, self.my_icon2, } ---- else ---- return nil ---- end ----end ---- -------Exactly one highlight group for DecoratorHighlightRange "name" -------@param node nvim_tree.api.Node -------@return string? highlight_group ----function MyDecorator:highlight_group(node) ---- if node.name == "example" then ---- return self.my_highlight_group ---- else ---- return nil ---- end ----end ---- ----return MyDecorator +--- ---@class (exact) MyDecorator: nvim_tree.api.Decorator +--- ---@field private my_icon1 nvim_tree.api.highlighted_string +--- ---@field private my_icon2 nvim_tree.api.highlighted_string +--- ---@field private my_icon_node nvim_tree.api.highlighted_string +--- ---@field private my_highlight_group string +--- local MyDecorator = require("nvim-tree.api").Decorator:extend() +--- +--- ---Mandatory constructor :new() will be called once per tree render, with no arguments. +--- function MyDecorator:new() +--- self.enabled = true +--- self.highlight_range = "name" +--- self.icon_placement = "after" +--- +--- -- create your icons and highlights once, applied to every node +--- self.my_icon1 = { str = "1", hl = { "DiffAdd" } } +--- self.my_icon2 = { str = "2", hl = { "DiffText" } } +--- self.my_icon_node = { str = "N", hl = { "Error" } } +--- self.my_highlight_group = "IncSearch" +--- +--- -- Define the icon signs only once +--- -- Only needed if you are using icon_placement = "signcolumn" +--- -- self:define_sign(self.my_icon1) +--- -- self:define_sign(self.my_icon2) +--- end +--- +--- ---Override node icon +--- ---@param node nvim_tree.api.Node +--- ---@return nvim_tree.api.highlighted_string? icon_node +--- function MyDecorator:icon_node(node) +--- if node.name == "example" then +--- return self.my_icon_node +--- else +--- return nil +--- end +--- end +--- +--- ---Return two icons for DecoratorIconPlacement "after" +--- ---@param node nvim_tree.api.Node +--- ---@return nvim_tree.api.highlighted_string[]? icons +--- function MyDecorator:icons(node) +--- if node.name == "example" then +--- return { self.my_icon1, self.my_icon2, } +--- else +--- return nil +--- end +--- end +--- +--- ---Exactly one highlight group for DecoratorHighlightRange "name" +--- ---@param node nvim_tree.api.Node +--- ---@return string? highlight_group +--- function MyDecorator:highlight_group(node) +--- if node.name == "example" then +--- return self.my_highlight_group +--- else +--- return nil +--- end +--- end +--- +--- return MyDecorator ---``` diff --git a/lua/nvim-tree/_meta/config/actions.lua b/lua/nvim-tree/_meta/config/actions.lua index 316ec3a47b1..012f4c364d9 100644 --- a/lua/nvim-tree/_meta/config/actions.lua +++ b/lua/nvim-tree/_meta/config/actions.lua @@ -60,13 +60,13 @@ error("Cannot require a meta file") --- ---{open_win_config} is passed to [nvim_open_win()], default: ---```lua ----{ ---- col = 1, ---- row = 1, ---- relative = "cursor", ---- border = "shadow", ---- style = "minimal", ----} +--- { +--- col = 1, +--- row = 1, +--- relative = "cursor", +--- border = "shadow", +--- style = "minimal", +--- } ---``` ---You shouldn't define {width} and {height} values here. They will be overridden to fit the file_popup content. ---@class nvim_tree.config.actions.file_popup diff --git a/lua/nvim-tree/_meta/config/default.lua b/lua/nvim-tree/_meta/config/default.lua index 6566a1ed4ab..4db71c02437 100644 --- a/lua/nvim-tree/_meta/config/default.lua +++ b/lua/nvim-tree/_meta/config/default.lua @@ -3,8 +3,8 @@ --- ---```lua --- -------@type nvim_tree.config ----local config = { ----default-config-injection-placeholder ----} +--- ---@type nvim_tree.config +--- local config = { +--- default-config-injection-placeholder +--- } ---``` diff --git a/lua/nvim-tree/_meta/config/renderer.lua b/lua/nvim-tree/_meta/config/renderer.lua index 3f7cef3a6b6..4e7d419f101 100644 --- a/lua/nvim-tree/_meta/config/renderer.lua +++ b/lua/nvim-tree/_meta/config/renderer.lua @@ -44,9 +44,9 @@ error("Cannot require a meta file") ---- `boolean`: `true` to disable ---- `fun(root_cwd: string): string`: return a literal string from root's absolute path e.g. ---```lua ----my_root_folder_label = function(path) ---- return ".../" .. vim.fn.fnamemodify(path, ":t") ----end +--- my_root_folder_label = function(path) +--- return ".../" .. vim.fn.fnamemodify(path, ":t") +--- end ---``` --- --- @@ -357,19 +357,19 @@ error("Cannot require a meta file") ---Passed to your [nvim_tree.config.renderer.hidden_display] function e.g. ---```lua --- -------@param hidden_stats nvim_tree.config.renderer.hidden_stats -------@return string? summary ----local my_hidden_display = function(hidden_stats) ---- local total_count = 0 ---- for reason, count in pairs(hidden_stats) do ---- total_count = total_count + count ---- end ---- ---- if total_count > 0 then ---- return "(" .. tostring(total_count) .. " hidden)" ---- end ---- return nil ----end +--- ---@param hidden_stats nvim_tree.config.renderer.hidden_stats +--- ---@return string? summary +--- local my_hidden_display = function(hidden_stats) +--- local total_count = 0 +--- for reason, count in pairs(hidden_stats) do +--- total_count = total_count + count +--- end +--- +--- if total_count > 0 then +--- return "(" .. tostring(total_count) .. " hidden)" +--- end +--- return nil +--- end ---``` --- ---@class nvim_tree.config.renderer.hidden_stats diff --git a/lua/nvim-tree/_meta/config/sort.lua b/lua/nvim-tree/_meta/config/sort.lua index 569fe56ba78..6c692dee73c 100644 --- a/lua/nvim-tree/_meta/config/sort.lua +++ b/lua/nvim-tree/_meta/config/sort.lua @@ -17,14 +17,14 @@ error("Cannot require a meta file") ---{sorter} may be a function that is passed a list of `nvim_tree.api.Node` to be sorted in place e.g. ---```lua --- -------Sort by name length -------@param nodes nvim_tree.api.Node[] -------@return nvim_tree.config.sort.Sorter? ----local sorter = function(nodes) ---- table.sort(nodes, function(a, b) ---- return #a.name < #b.name ---- end) ----end +--- ---Sort by name length +--- ---@param nodes nvim_tree.api.Node[] +--- ---@return nvim_tree.config.sort.Sorter? +--- local sorter = function(nodes) +--- table.sort(nodes, function(a, b) +--- return #a.name < #b.name +--- end) +--- end ---``` ---{sorter} may be a function that returns a [nvim_tree.config.sort.Sorter] --- diff --git a/lua/nvim-tree/_meta/config/view.lua b/lua/nvim-tree/_meta/config/view.lua index bc599885593..3d3a0404b9b 100644 --- a/lua/nvim-tree/_meta/config/view.lua +++ b/lua/nvim-tree/_meta/config/view.lua @@ -85,14 +85,14 @@ error("Cannot require a meta file") --- ---{open_win_config} is passed to [nvim_open_win()], default: ---```lua ----{ ---- relative = "editor", ---- border = "rounded", ---- width = 30, ---- height = 30, ---- row = 1, ---- col = 1, ----} +--- { +--- relative = "editor", +--- border = "rounded", +--- width = 30, +--- height = 30, +--- row = 1, +--- col = 1, +--- } ---``` ---@class nvim_tree.config.view.float --- diff --git a/lua/nvim-tree/classic.lua b/lua/nvim-tree/classic.lua index 7135eb64550..f22d31f4172 100644 --- a/lua/nvim-tree/classic.lua +++ b/lua/nvim-tree/classic.lua @@ -145,7 +145,7 @@ end --- ---Instance of. --- ----Test whether an object inherits {class} or implements a mixin {class}. +---Test whether an object is {class}, inherits {class} or implements mixin {class}. --- ---@generic T ---@param class T `` From 7c51988fc1a25e6bc85bbe449ead21a2d6490f8f Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Wed, 4 Feb 2026 12:10:53 +1100 Subject: [PATCH 20/27] docs(#3241): extract builtin decorator interface, partially complete --- lua/nvim-tree/renderer/builder.lua | 6 +- lua/nvim-tree/renderer/decorator/init.lua | 116 ++++------------------ lua/nvim-tree/renderer/decorator/user.lua | 105 +++++++++++++++++++- 3 files changed, 121 insertions(+), 106 deletions(-) diff --git a/lua/nvim-tree/renderer/builder.lua b/lua/nvim-tree/renderer/builder.lua index 903f31d904e..0bb651e63fe 100644 --- a/lua/nvim-tree/renderer/builder.lua +++ b/lua/nvim-tree/renderer/builder.lua @@ -128,7 +128,7 @@ end ---@param arrows? nvim_tree.api.highlighted_string[] ---@param icon nvim_tree.api.highlighted_string ---@param name nvim_tree.api.highlighted_string ----@param node table +---@param node Node ---@return nvim_tree.api.highlighted_string[] function Builder:format_line(indent_markers, arrows, icon, name, node) local added_len = 0 @@ -152,7 +152,7 @@ function Builder:format_line(indent_markers, arrows, icon, name, node) end -- use the api node for user decorators - local api_node = self.api_nodes and self.api_nodes[node.uid_node] --[[@as Node]] + local api_node = self.api_nodes and self.api_nodes[node.uid_node] local u local line = { indent_markers, arrows } @@ -198,7 +198,7 @@ end ---@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]] + local api_node = self.api_nodes and self.api_nodes[node.uid_node] -- first in priority order local d, u, sign_name diff --git a/lua/nvim-tree/renderer/decorator/init.lua b/lua/nvim-tree/renderer/decorator/init.lua index e60394f43df..8654b7ef9dd 100644 --- a/lua/nvim-tree/renderer/decorator/init.lua +++ b/lua/nvim-tree/renderer/decorator/init.lua @@ -1,108 +1,26 @@ ----Abstract Decorator implementation ----@class (exact) Decorator: nvim_tree.Class +local UserDecorator = require("nvim-tree.renderer.decorator.user") + +---Builtin decorator interface. +---Overrides all methods to use a Node instead of nvim_tree.api.Node as we don't have generics. +--- +---@class (exact) Decorator: UserDecorator +--- ---@field protected enabled boolean ---@field protected highlight_range nvim_tree.config.renderer.highlight ---@field protected icon_placement "none"|nvim_tree.config.renderer.icons.placement -local Decorator = require("nvim-tree._meta.api.decorator"):extend() +--- +---@field icon_node fun(self: Decorator, node: Node): nvim_tree.api.highlighted_string? +---@field icons fun(self: Decorator, node: Node): nvim_tree.api.highlighted_string? +---@field highlight_group fun(self: Decorator, node: Node): string? +---@field highlight_group_icon_name fun(self: Decorator, node: Node): string?, string? +---@field sign_name fun(self: Decorator, node: Node): string? +---@field icons_before fun(self: Decorator, node: Node): nvim_tree.api.highlighted_string[]? +---@field icons_after fun(self: Decorator, node: Node): nvim_tree.api.highlighted_string[]? +---@field icons_right_align fun(self: Decorator, node: Node): nvim_tree.api.highlighted_string[]? +local Decorator = UserDecorator:extend() ---TODO #3241 create an internal decorator class with explorer member and lose the UserDecorator ---@class (exact) DecoratorArgs ---@field explorer Explorer ----Maybe highlight groups for icon and name ----@param node Node ----@return string? icon highlight group ----@return string? name highlight group -function Decorator:highlight_group_icon_name(node) - local icon_hl, name_hl - - if self.enabled and self.highlight_range ~= "none" then - local hl = self:highlight_group(node) - - if self.highlight_range == "all" or self.highlight_range == "icon" then - icon_hl = hl - end - if self.highlight_range == "all" or self.highlight_range == "name" then - name_hl = hl - end - end - - return icon_hl, name_hl -end - ----Maybe icon sign ----@param node Node ----@return string? name -function Decorator:sign_name(node) - if not self.enabled or self.icon_placement ~= "signcolumn" then - return - end - - local icons = self:icons(node) - if icons and #icons > 0 then - return icons[1].hl[1] - end -end - ----Icons when "before" ----@param node Node ----@return nvim_tree.api.highlighted_string[]? icons -function Decorator:icons_before(node) - if not self.enabled or self.icon_placement ~= "before" then - return - end - - return self:icons(node) -end - ----Icons when "after" ----@param node Node ----@return nvim_tree.api.highlighted_string[]? icons -function Decorator:icons_after(node) - if not self.enabled or self.icon_placement ~= "after" then - return - end - - return self:icons(node) -end - ----Icons when "right_align" ----@param node Node ----@return nvim_tree.api.highlighted_string[]? icons -function Decorator:icons_right_align(node) - if not self.enabled or self.icon_placement ~= "right_align" then - return - end - - return self:icons(node) -end - ----Define a sign ----@protected ----@param icon nvim_tree.api.highlighted_string? -function Decorator:define_sign(icon) - if icon and #icon.hl > 0 then - local name = icon.hl[1] - - if not vim.tbl_isempty(vim.fn.sign_getdefined(name)) then - vim.fn.sign_undefine(name) - end - - -- don't render sign if empty - if #icon.str < 1 then - return - end - - -- byte index of the next character, allowing for wide - local bi = vim.fn.byteidx(icon.str, 1) - - -- first (wide) character, falls back to empty string - local text = string.sub(icon.str, 1, bi) - vim.fn.sign_define(name, { - text = text, - texthl = name, - }) - end -end - return Decorator diff --git a/lua/nvim-tree/renderer/decorator/user.lua b/lua/nvim-tree/renderer/decorator/user.lua index dda43fd7c90..bf03cfc15c9 100644 --- a/lua/nvim-tree/renderer/decorator/user.lua +++ b/lua/nvim-tree/renderer/decorator/user.lua @@ -1,7 +1,104 @@ -local Decorator = require("nvim-tree.renderer.decorator") +--- +---Abstract decorator implementation +--- +---@class (exact) UserDecorator: nvim_tree.api.Decorator +local UserDecorator = require("nvim-tree._meta.api.decorator"):extend() ----Exposed as nvim_tree.api.Decorator ----@class (exact) UserDecorator: Decorator -local UserDecorator = Decorator:extend() +---Maybe highlight groups for icon and name +---@param node nvim_tree.api.Node +---@return string? icon highlight group +---@return string? name highlight group +function UserDecorator:highlight_group_icon_name(node) + local icon_hl, name_hl + if self.enabled and self.highlight_range ~= "none" then + local hl = self:highlight_group(node) + + if self.highlight_range == "all" or self.highlight_range == "icon" then + icon_hl = hl + end + if self.highlight_range == "all" or self.highlight_range == "name" then + name_hl = hl + end + end + + return icon_hl, name_hl +end + +---Maybe icon sign +---@param node nvim_tree.api.Node +---@return string? name +function UserDecorator:sign_name(node) + if not self.enabled or self.icon_placement ~= "signcolumn" then + return + end + + local icons = self:icons(node) + if icons and #icons > 0 then + return icons[1].hl[1] + end +end + +---Icons when "before" +---@param node nvim_tree.api.Node +---@return nvim_tree.api.highlighted_string[]? icons +function UserDecorator:icons_before(node) + if not self.enabled or self.icon_placement ~= "before" then + return + end + + return self:icons(node) +end + +---Icons when "after" +---@param node nvim_tree.api.Node +---@return nvim_tree.api.highlighted_string[]? icons +function UserDecorator:icons_after(node) + if not self.enabled or self.icon_placement ~= "after" then + return + end + + return self:icons(node) +end + +---Icons when "right_align" +---@param node nvim_tree.api.Node +---@return nvim_tree.api.highlighted_string[]? icons +function UserDecorator:icons_right_align(node) + if not self.enabled or self.icon_placement ~= "right_align" then + return + end + + return self:icons(node) +end + +---Define a sign +---@protected +---@param icon nvim_tree.api.highlighted_string? +function UserDecorator:define_sign(icon) + if icon and #icon.hl > 0 then + local name = icon.hl[1] + + if not vim.tbl_isempty(vim.fn.sign_getdefined(name)) then + vim.fn.sign_undefine(name) + end + + -- don't render sign if empty + if #icon.str < 1 then + return + end + + -- byte index of the next character, allowing for wide + local bi = vim.fn.byteidx(icon.str, 1) + + -- first (wide) character, falls back to empty string + local text = string.sub(icon.str, 1, bi) + vim.fn.sign_define(name, { + text = text, + texthl = name, + }) + end +end + +---@type UserDecorator return UserDecorator From 268a798b6f14b5019886fe3f33c0090f1997e387 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Wed, 4 Feb 2026 12:36:46 +1100 Subject: [PATCH 21/27] docs(#3241): extracted BuiltinDecorator --- lua/nvim-tree/_meta/api/decorator.lua | 2 - lua/nvim-tree/_meta/classes.lua | 2 +- lua/nvim-tree/api/impl/pre.lua | 4 +- lua/nvim-tree/renderer/builder.lua | 66 +++++----- .../renderer/decorator/bookmarks.lua | 10 +- lua/nvim-tree/renderer/decorator/builtin.lua | 26 ++++ lua/nvim-tree/renderer/decorator/copied.lua | 10 +- lua/nvim-tree/renderer/decorator/cut.lua | 10 +- .../renderer/decorator/diagnostics.lua | 10 +- lua/nvim-tree/renderer/decorator/git.lua | 10 +- lua/nvim-tree/renderer/decorator/hidden.lua | 10 +- lua/nvim-tree/renderer/decorator/init.lua | 122 ++++++++++++++---- lua/nvim-tree/renderer/decorator/modified.lua | 10 +- lua/nvim-tree/renderer/decorator/opened.lua | 10 +- lua/nvim-tree/renderer/decorator/user.lua | 104 --------------- 15 files changed, 201 insertions(+), 205 deletions(-) create mode 100644 lua/nvim-tree/renderer/decorator/builtin.lua delete mode 100644 lua/nvim-tree/renderer/decorator/user.lua diff --git a/lua/nvim-tree/_meta/api/decorator.lua b/lua/nvim-tree/_meta/api/decorator.lua index 4da80d55cdc..c4ef939765b 100644 --- a/lua/nvim-tree/_meta/api/decorator.lua +++ b/lua/nvim-tree/_meta/api/decorator.lua @@ -1,7 +1,5 @@ ---@meta ----#TODO 3241 maybe rename to UserDecorator - ---@brief ---Highlighting and icons for nodes are provided by Decorators, see [nvim-tree-icons-highlighting] for an overview. --- diff --git a/lua/nvim-tree/_meta/classes.lua b/lua/nvim-tree/_meta/classes.lua index 7de002916c6..f8c66153362 100644 --- a/lua/nvim-tree/_meta/classes.lua +++ b/lua/nvim-tree/_meta/classes.lua @@ -5,7 +5,7 @@ error("Cannot require a meta file") -- TODO #2688 -- These node subclasses are not ready for public exposure as they are: -- - not classic classes --- - only used in a few locations: api.tree.get_nodes and UserDecorator +-- - only used in a few locations: api.tree.get_nodes and Decorator --- ---File diff --git a/lua/nvim-tree/api/impl/pre.lua b/lua/nvim-tree/api/impl/pre.lua index 5ce5f67ac05..73d5c5e148c 100644 --- a/lua/nvim-tree/api/impl/pre.lua +++ b/lua/nvim-tree/api/impl/pre.lua @@ -14,7 +14,7 @@ local events = require("nvim-tree.events") -- needed for event registration local keymap = require("nvim-tree.keymap") -- needed for default on attach local notify = require("nvim-tree.notify") -- already required by events and others -local UserDecorator = require("nvim-tree.renderer.decorator.user") +local Decorator = require("nvim-tree.renderer.decorator") local M = {} @@ -50,7 +50,7 @@ function M.hydrate(api) api.health.hi_test = function() require("nvim-tree.appearance.hi-test")() end -- classes - api.Decorator = UserDecorator:extend() + api.Decorator = Decorator:extend() -- Hydrate any legacy by mapping to concrete set above require("nvim-tree.api.impl.legacy").hydrate(api) diff --git a/lua/nvim-tree/renderer/builder.lua b/lua/nvim-tree/renderer/builder.lua index 0bb651e63fe..be924ce5870 100644 --- a/lua/nvim-tree/renderer/builder.lua +++ b/lua/nvim-tree/renderer/builder.lua @@ -14,12 +14,13 @@ local GitDecorator = require("nvim-tree.renderer.decorator.git") local HiddenDecorator = require("nvim-tree.renderer.decorator.hidden") local ModifiedDecorator = require("nvim-tree.renderer.decorator.modified") local OpenDecorator = require("nvim-tree.renderer.decorator.opened") -local UserDecorator = require("nvim-tree.renderer.decorator.user") +local Decorator = require("nvim-tree.renderer.decorator") +local BuiltinDecorator = require("nvim-tree.renderer.decorator.builtin") local pad = require("nvim-tree.renderer.components.padding") -- Builtin Decorators ----@type table +---@type table local BUILTIN_DECORATORS = { Git = GitDecorator, Open = OpenDecorator, @@ -72,11 +73,11 @@ function Builder:new(args) -- instantiate all the builtin and user decorator instances local builtin, user for _, d in ipairs(self.explorer.opts.renderer.decorators) do - ---@type Decorator + ---@type BuiltinDecorator builtin = BUILTIN_DECORATORS[d] - ---@type UserDecorator - user = type(d) == "table" and type(d.as) == "function" and d:as(UserDecorator) + ---@type Decorator + user = type(d) == "table" and type(d.as) == "function" and d:as(Decorator) if builtin then table.insert(self.decorators, builtin({ explorer = self.explorer })) @@ -151,40 +152,39 @@ 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] - local u + local b local line = { indent_markers, arrows } add_to_end(line, { icon }) for _, d in ipairs(self.decorators) do - u = d:as(UserDecorator) - if not u then - add_to_end(line, d:icons_before(node)) + b = d:as(BuiltinDecorator) + if b then + add_to_end(line, b:icons_before(node)) elseif api_node then - add_to_end(line, u:icons_before(api_node)) + add_to_end(line, d:icons_before(api_node)) end end add_to_end(line, { name }) for _, d in ipairs(self.decorators) do - u = d:as(UserDecorator) - if not u then - add_to_end(line, d:icons_after(node)) + b = d:as(BuiltinDecorator) + if b then + add_to_end(line, b:icons_after(node)) elseif api_node then - add_to_end(line, u:icons_after(api_node)) + add_to_end(line, d:icons_after(api_node)) end end local rights = {} for _, d in ipairs(self.decorators) do - u = d:as(UserDecorator) - if not u then - add_to_end(line, d:icons_right_align(node)) + b = d:as(BuiltinDecorator) + if b then + add_to_end(line, b:icons_right_align(node)) elseif api_node then - add_to_end(line, u:icons_right_align(api_node)) + add_to_end(line, d:icons_right_align(api_node)) end end if #rights > 0 then @@ -197,19 +197,18 @@ 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] -- first in priority order - local d, u, sign_name + local d, b, sign_name for i = #self.decorators, 1, -1 do d = self.decorators[i] - u = d:as(UserDecorator) - if not u then - sign_name = d:sign_name(node) + b = d:as(BuiltinDecorator) + if b then + sign_name = b:sign_name(node) elseif api_node then - sign_name = u:sign_name(api_node) + sign_name = d:sign_name(api_node) end if sign_name then @@ -255,8 +254,7 @@ end ---@return nvim_tree.api.highlighted_string icon ---@return nvim_tree.api.highlighted_string name function Builder:icon_name_decorated(node) - -- use the api node for user decorators - local api_node = self.api_nodes and self.api_nodes[node.uid_node] --[[@as Node]] + local api_node = self.api_nodes and self.api_nodes[node.uid_node] -- base case local icon = node:highlighted_icon() @@ -266,16 +264,16 @@ function Builder:icon_name_decorated(node) local icon_groups = {} local name_groups = {} local hl_icon, hl_name - local u + local b for _, d in ipairs(self.decorators) do -- maybe override icon - u = d:as(UserDecorator) - if not u then - icon = d:icon_node(node) or icon - hl_icon, hl_name = d:highlight_group_icon_name(node) + b = d:as(BuiltinDecorator) + if b then + icon = b:icon_node(node) or icon + hl_icon, hl_name = b:highlight_group_icon_name(node) elseif api_node then - icon = u:icon_node(api_node) or icon - hl_icon, hl_name = u:highlight_group_icon_name(api_node) + icon = d:icon_node(api_node) or icon + hl_icon, hl_name = d:highlight_group_icon_name(api_node) end table.insert(icon_groups, hl_icon) diff --git a/lua/nvim-tree/renderer/decorator/bookmarks.lua b/lua/nvim-tree/renderer/decorator/bookmarks.lua index f61c44c7031..fead683a4ce 100644 --- a/lua/nvim-tree/renderer/decorator/bookmarks.lua +++ b/lua/nvim-tree/renderer/decorator/bookmarks.lua @@ -1,15 +1,15 @@ -local Decorator = require("nvim-tree.renderer.decorator") +local BuiltinDecorator = require("nvim-tree.renderer.decorator.builtin") ----@class (exact) BookmarkDecorator: Decorator +---@class (exact) BookmarkDecorator: BuiltinDecorator ---@field private explorer Explorer ---@field private icon nvim_tree.api.highlighted_string? -local BookmarkDecorator = Decorator:extend() +local BookmarkDecorator = BuiltinDecorator:extend() ---@class BookmarkDecorator ----@overload fun(args: DecoratorArgs): BookmarkDecorator +---@overload fun(args: BuiltinDecoratorArgs): BookmarkDecorator ---@protected ----@param args DecoratorArgs +---@param args BuiltinDecoratorArgs function BookmarkDecorator:new(args) self.explorer = args.explorer diff --git a/lua/nvim-tree/renderer/decorator/builtin.lua b/lua/nvim-tree/renderer/decorator/builtin.lua new file mode 100644 index 00000000000..f495fe485e9 --- /dev/null +++ b/lua/nvim-tree/renderer/decorator/builtin.lua @@ -0,0 +1,26 @@ +local Decorator = require("nvim-tree.renderer.decorator") + +---Builtin decorator interface. +---Overrides all methods to use a Node instead of nvim_tree.api.Node as we don't have generics. +--- +---@class (exact) BuiltinDecorator: Decorator +--- +---@field protected enabled boolean +---@field protected highlight_range nvim_tree.config.renderer.highlight +---@field protected icon_placement "none"|nvim_tree.config.renderer.icons.placement +--- +---@field icon_node fun(self: BuiltinDecorator, node: Node): nvim_tree.api.highlighted_string? +---@field icons fun(self: BuiltinDecorator, node: Node): nvim_tree.api.highlighted_string? +---@field highlight_group fun(self: BuiltinDecorator, node: Node): string? +---@field highlight_group_icon_name fun(self: BuiltinDecorator, node: Node): string?, string? +---@field sign_name fun(self: BuiltinDecorator, node: Node): string? +---@field icons_before fun(self: BuiltinDecorator, node: Node): nvim_tree.api.highlighted_string[]? +---@field icons_after fun(self: BuiltinDecorator, node: Node): nvim_tree.api.highlighted_string[]? +---@field icons_right_align fun(self: BuiltinDecorator, node: Node): nvim_tree.api.highlighted_string[]? +local BuiltinDecorator = Decorator:extend() + +---TODO #3241 create a common constructor +---@class (exact) BuiltinDecoratorArgs +---@field explorer Explorer + +return BuiltinDecorator diff --git a/lua/nvim-tree/renderer/decorator/copied.lua b/lua/nvim-tree/renderer/decorator/copied.lua index e930f14ee7f..b2a773bf65b 100644 --- a/lua/nvim-tree/renderer/decorator/copied.lua +++ b/lua/nvim-tree/renderer/decorator/copied.lua @@ -1,14 +1,14 @@ -local Decorator = require("nvim-tree.renderer.decorator") +local BuiltinDecorator = require("nvim-tree.renderer.decorator.builtin") ----@class (exact) CopiedDecorator: Decorator +---@class (exact) CopiedDecorator: BuiltinDecorator ---@field private explorer Explorer -local CopiedDecorator = Decorator:extend() +local CopiedDecorator = BuiltinDecorator:extend() ---@class CopiedDecorator ----@overload fun(args: DecoratorArgs): CopiedDecorator +---@overload fun(args: BuiltinDecoratorArgs): CopiedDecorator ---@protected ----@param args DecoratorArgs +---@param args BuiltinDecoratorArgs function CopiedDecorator:new(args) self.explorer = args.explorer diff --git a/lua/nvim-tree/renderer/decorator/cut.lua b/lua/nvim-tree/renderer/decorator/cut.lua index 8a212da5d68..f721572d752 100644 --- a/lua/nvim-tree/renderer/decorator/cut.lua +++ b/lua/nvim-tree/renderer/decorator/cut.lua @@ -1,14 +1,14 @@ -local Decorator = require("nvim-tree.renderer.decorator") +local BuiltinDecorator = require("nvim-tree.renderer.decorator.builtin") ----@class (exact) CutDecorator: Decorator +---@class (exact) CutDecorator: BuiltinDecorator ---@field private explorer Explorer -local CutDecorator = Decorator:extend() +local CutDecorator = BuiltinDecorator:extend() ---@class CutDecorator ----@overload fun(args: DecoratorArgs): CutDecorator +---@overload fun(args: BuiltinDecoratorArgs): CutDecorator ---@protected ----@param args DecoratorArgs +---@param args BuiltinDecoratorArgs function CutDecorator:new(args) self.explorer = args.explorer diff --git a/lua/nvim-tree/renderer/decorator/diagnostics.lua b/lua/nvim-tree/renderer/decorator/diagnostics.lua index 4e75346a89a..e0741222238 100644 --- a/lua/nvim-tree/renderer/decorator/diagnostics.lua +++ b/lua/nvim-tree/renderer/decorator/diagnostics.lua @@ -1,6 +1,6 @@ local diagnostics = require("nvim-tree.diagnostics") -local Decorator = require("nvim-tree.renderer.decorator") +local BuiltinDecorator = require("nvim-tree.renderer.decorator.builtin") local DirectoryNode = require("nvim-tree.node.directory") -- highlight groups by severity @@ -30,16 +30,16 @@ local ICON_KEYS = { ["hint"] = vim.diagnostic.severity.HINT, } ----@class (exact) DiagnosticsDecorator: Decorator +---@class (exact) DiagnosticsDecorator: BuiltinDecorator ---@field private explorer Explorer ---@field private diag_icons nvim_tree.api.highlighted_string[]? -local DiagnosticsDecorator = Decorator:extend() +local DiagnosticsDecorator = BuiltinDecorator:extend() ---@class DiagnosticsDecorator ----@overload fun(args: DecoratorArgs): DiagnosticsDecorator +---@overload fun(args: BuiltinDecoratorArgs): DiagnosticsDecorator ---@protected ----@param args DecoratorArgs +---@param args BuiltinDecoratorArgs function DiagnosticsDecorator:new(args) self.explorer = args.explorer diff --git a/lua/nvim-tree/renderer/decorator/git.lua b/lua/nvim-tree/renderer/decorator/git.lua index 268022644d6..07446752eb3 100644 --- a/lua/nvim-tree/renderer/decorator/git.lua +++ b/lua/nvim-tree/renderer/decorator/git.lua @@ -1,6 +1,6 @@ local notify = require("nvim-tree.notify") -local Decorator = require("nvim-tree.renderer.decorator") +local BuiltinDecorator = require("nvim-tree.renderer.decorator.builtin") local DirectoryNode = require("nvim-tree.node.directory") ---@class (exact) GitHighlightedString: nvim_tree.api.highlighted_string @@ -12,19 +12,19 @@ local DirectoryNode = require("nvim-tree.node.directory") ---@alias GitIconsByXY table porcelain status ---@alias GitGlyphsByStatus table from opts ----@class (exact) GitDecorator: Decorator +---@class (exact) GitDecorator: BuiltinDecorator ---@field private explorer Explorer ---@field private file_hl_by_xy table? ---@field private folder_hl_by_xy table? ---@field private icons_by_status GitIconsByStatus? ---@field private icons_by_xy GitIconsByXY? -local GitDecorator = Decorator:extend() +local GitDecorator = BuiltinDecorator:extend() ---@class GitDecorator ----@overload fun(args: DecoratorArgs): GitDecorator +---@overload fun(args: BuiltinDecoratorArgs): GitDecorator ---@protected ----@param args DecoratorArgs +---@param args BuiltinDecoratorArgs function GitDecorator:new(args) self.explorer = args.explorer diff --git a/lua/nvim-tree/renderer/decorator/hidden.lua b/lua/nvim-tree/renderer/decorator/hidden.lua index 2d67d4e4cc2..07a02d6dd17 100644 --- a/lua/nvim-tree/renderer/decorator/hidden.lua +++ b/lua/nvim-tree/renderer/decorator/hidden.lua @@ -1,16 +1,16 @@ -local Decorator = require("nvim-tree.renderer.decorator") +local BuiltinDecorator = require("nvim-tree.renderer.decorator.builtin") local DirectoryNode = require("nvim-tree.node.directory") ----@class (exact) HiddenDecorator: Decorator +---@class (exact) HiddenDecorator: BuiltinDecorator ---@field private explorer Explorer ---@field private icon nvim_tree.api.highlighted_string? -local HiddenDecorator = Decorator:extend() +local HiddenDecorator = BuiltinDecorator:extend() ---@class HiddenDecorator ----@overload fun(args: DecoratorArgs): HiddenDecorator +---@overload fun(args: BuiltinDecoratorArgs): HiddenDecorator ---@protected ----@param args DecoratorArgs +---@param args BuiltinDecoratorArgs function HiddenDecorator:new(args) self.explorer = args.explorer diff --git a/lua/nvim-tree/renderer/decorator/init.lua b/lua/nvim-tree/renderer/decorator/init.lua index 8654b7ef9dd..27fc57a3b4e 100644 --- a/lua/nvim-tree/renderer/decorator/init.lua +++ b/lua/nvim-tree/renderer/decorator/init.lua @@ -1,26 +1,104 @@ -local UserDecorator = require("nvim-tree.renderer.decorator.user") - ----Builtin decorator interface. ----Overrides all methods to use a Node instead of nvim_tree.api.Node as we don't have generics. ---- ----@class (exact) Decorator: UserDecorator --- ----@field protected enabled boolean ----@field protected highlight_range nvim_tree.config.renderer.highlight ----@field protected icon_placement "none"|nvim_tree.config.renderer.icons.placement +---Abstract decorator implementation --- ----@field icon_node fun(self: Decorator, node: Node): nvim_tree.api.highlighted_string? ----@field icons fun(self: Decorator, node: Node): nvim_tree.api.highlighted_string? ----@field highlight_group fun(self: Decorator, node: Node): string? ----@field highlight_group_icon_name fun(self: Decorator, node: Node): string?, string? ----@field sign_name fun(self: Decorator, node: Node): string? ----@field icons_before fun(self: Decorator, node: Node): nvim_tree.api.highlighted_string[]? ----@field icons_after fun(self: Decorator, node: Node): nvim_tree.api.highlighted_string[]? ----@field icons_right_align fun(self: Decorator, node: Node): nvim_tree.api.highlighted_string[]? -local Decorator = UserDecorator:extend() - ----TODO #3241 create an internal decorator class with explorer member and lose the UserDecorator ----@class (exact) DecoratorArgs ----@field explorer Explorer +---@class (exact) Decorator: nvim_tree.api.Decorator +local Decorator = require("nvim-tree._meta.api.decorator"):extend() + +---Maybe highlight groups for icon and name +---@param node nvim_tree.api.Node +---@return string? icon highlight group +---@return string? name highlight group +function Decorator:highlight_group_icon_name(node) + local icon_hl, name_hl + + if self.enabled and self.highlight_range ~= "none" then + local hl = self:highlight_group(node) + + if self.highlight_range == "all" or self.highlight_range == "icon" then + icon_hl = hl + end + if self.highlight_range == "all" or self.highlight_range == "name" then + name_hl = hl + end + end + + return icon_hl, name_hl +end + +---Maybe icon sign +---@param node nvim_tree.api.Node +---@return string? name +function Decorator:sign_name(node) + if not self.enabled or self.icon_placement ~= "signcolumn" then + return + end + + local icons = self:icons(node) + if icons and #icons > 0 then + return icons[1].hl[1] + end +end + +---Icons when "before" +---@param node nvim_tree.api.Node +---@return nvim_tree.api.highlighted_string[]? icons +function Decorator:icons_before(node) + if not self.enabled or self.icon_placement ~= "before" then + return + end + + return self:icons(node) +end + +---Icons when "after" +---@param node nvim_tree.api.Node +---@return nvim_tree.api.highlighted_string[]? icons +function Decorator:icons_after(node) + if not self.enabled or self.icon_placement ~= "after" then + return + end + + return self:icons(node) +end + +---Icons when "right_align" +---@param node nvim_tree.api.Node +---@return nvim_tree.api.highlighted_string[]? icons +function Decorator:icons_right_align(node) + if not self.enabled or self.icon_placement ~= "right_align" then + return + end + + return self:icons(node) +end + +---Define a sign +---@protected +---@param icon nvim_tree.api.highlighted_string? +function Decorator:define_sign(icon) + if icon and #icon.hl > 0 then + local name = icon.hl[1] + + if not vim.tbl_isempty(vim.fn.sign_getdefined(name)) then + vim.fn.sign_undefine(name) + end + + -- don't render sign if empty + if #icon.str < 1 then + return + end + + -- byte index of the next character, allowing for wide + local bi = vim.fn.byteidx(icon.str, 1) + + -- first (wide) character, falls back to empty string + local text = string.sub(icon.str, 1, bi) + vim.fn.sign_define(name, { + text = text, + texthl = name, + }) + end +end +---@type Decorator return Decorator diff --git a/lua/nvim-tree/renderer/decorator/modified.lua b/lua/nvim-tree/renderer/decorator/modified.lua index a81a8411523..3edb811f9c7 100644 --- a/lua/nvim-tree/renderer/decorator/modified.lua +++ b/lua/nvim-tree/renderer/decorator/modified.lua @@ -1,18 +1,18 @@ local buffers = require("nvim-tree.buffers") -local Decorator = require("nvim-tree.renderer.decorator") +local BuiltinDecorator = require("nvim-tree.renderer.decorator.builtin") local DirectoryNode = require("nvim-tree.node.directory") ----@class (exact) ModifiedDecorator: Decorator +---@class (exact) ModifiedDecorator: BuiltinDecorator ---@field private explorer Explorer ---@field private icon nvim_tree.api.highlighted_string? -local ModifiedDecorator = Decorator:extend() +local ModifiedDecorator = BuiltinDecorator:extend() ---@class ModifiedDecorator ----@overload fun(args: DecoratorArgs): ModifiedDecorator +---@overload fun(args: BuiltinDecoratorArgs): ModifiedDecorator ---@protected ----@param args DecoratorArgs +---@param args BuiltinDecoratorArgs function ModifiedDecorator:new(args) self.explorer = args.explorer diff --git a/lua/nvim-tree/renderer/decorator/opened.lua b/lua/nvim-tree/renderer/decorator/opened.lua index 125cb64787b..4bf88527e72 100644 --- a/lua/nvim-tree/renderer/decorator/opened.lua +++ b/lua/nvim-tree/renderer/decorator/opened.lua @@ -1,17 +1,17 @@ local buffers = require("nvim-tree.buffers") -local Decorator = require("nvim-tree.renderer.decorator") +local BuiltinDecorator = require("nvim-tree.renderer.decorator.builtin") ----@class (exact) OpenDecorator: Decorator +---@class (exact) OpenDecorator: BuiltinDecorator ---@field private explorer Explorer ---@field private icon? nvim_tree.api.highlighted_string -local OpenDecorator = Decorator:extend() +local OpenDecorator = BuiltinDecorator:extend() ---@class OpenDecorator ----@overload fun(args: DecoratorArgs): OpenDecorator +---@overload fun(args: BuiltinDecoratorArgs): OpenDecorator ---@protected ----@param args DecoratorArgs +---@param args BuiltinDecoratorArgs function OpenDecorator:new(args) self.explorer = args.explorer diff --git a/lua/nvim-tree/renderer/decorator/user.lua b/lua/nvim-tree/renderer/decorator/user.lua deleted file mode 100644 index bf03cfc15c9..00000000000 --- a/lua/nvim-tree/renderer/decorator/user.lua +++ /dev/null @@ -1,104 +0,0 @@ ---- ----Abstract decorator implementation ---- ----@class (exact) UserDecorator: nvim_tree.api.Decorator -local UserDecorator = require("nvim-tree._meta.api.decorator"):extend() - ----Maybe highlight groups for icon and name ----@param node nvim_tree.api.Node ----@return string? icon highlight group ----@return string? name highlight group -function UserDecorator:highlight_group_icon_name(node) - local icon_hl, name_hl - - if self.enabled and self.highlight_range ~= "none" then - local hl = self:highlight_group(node) - - if self.highlight_range == "all" or self.highlight_range == "icon" then - icon_hl = hl - end - if self.highlight_range == "all" or self.highlight_range == "name" then - name_hl = hl - end - end - - return icon_hl, name_hl -end - ----Maybe icon sign ----@param node nvim_tree.api.Node ----@return string? name -function UserDecorator:sign_name(node) - if not self.enabled or self.icon_placement ~= "signcolumn" then - return - end - - local icons = self:icons(node) - if icons and #icons > 0 then - return icons[1].hl[1] - end -end - ----Icons when "before" ----@param node nvim_tree.api.Node ----@return nvim_tree.api.highlighted_string[]? icons -function UserDecorator:icons_before(node) - if not self.enabled or self.icon_placement ~= "before" then - return - end - - return self:icons(node) -end - ----Icons when "after" ----@param node nvim_tree.api.Node ----@return nvim_tree.api.highlighted_string[]? icons -function UserDecorator:icons_after(node) - if not self.enabled or self.icon_placement ~= "after" then - return - end - - return self:icons(node) -end - ----Icons when "right_align" ----@param node nvim_tree.api.Node ----@return nvim_tree.api.highlighted_string[]? icons -function UserDecorator:icons_right_align(node) - if not self.enabled or self.icon_placement ~= "right_align" then - return - end - - return self:icons(node) -end - ----Define a sign ----@protected ----@param icon nvim_tree.api.highlighted_string? -function UserDecorator:define_sign(icon) - if icon and #icon.hl > 0 then - local name = icon.hl[1] - - if not vim.tbl_isempty(vim.fn.sign_getdefined(name)) then - vim.fn.sign_undefine(name) - end - - -- don't render sign if empty - if #icon.str < 1 then - return - end - - -- byte index of the next character, allowing for wide - local bi = vim.fn.byteidx(icon.str, 1) - - -- first (wide) character, falls back to empty string - local text = string.sub(icon.str, 1, bi) - vim.fn.sign_define(name, { - text = text, - texthl = name, - }) - end -end - ----@type UserDecorator -return UserDecorator From efc9fa1af224aba53d7408a1a7ad13670550afe4 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Wed, 4 Feb 2026 12:47:40 +1100 Subject: [PATCH 22/27] docs(#3241): add BuiltinDecorator constructor --- lua/nvim-tree/renderer/decorator/bookmarks.lua | 3 +-- lua/nvim-tree/renderer/decorator/builtin.lua | 11 +++++++---- lua/nvim-tree/renderer/decorator/copied.lua | 3 +-- lua/nvim-tree/renderer/decorator/cut.lua | 3 +-- lua/nvim-tree/renderer/decorator/diagnostics.lua | 3 +-- lua/nvim-tree/renderer/decorator/git.lua | 3 +-- lua/nvim-tree/renderer/decorator/hidden.lua | 3 +-- lua/nvim-tree/renderer/decorator/modified.lua | 3 +-- lua/nvim-tree/renderer/decorator/opened.lua | 3 +-- 9 files changed, 15 insertions(+), 20 deletions(-) diff --git a/lua/nvim-tree/renderer/decorator/bookmarks.lua b/lua/nvim-tree/renderer/decorator/bookmarks.lua index fead683a4ce..cc9da51e27b 100644 --- a/lua/nvim-tree/renderer/decorator/bookmarks.lua +++ b/lua/nvim-tree/renderer/decorator/bookmarks.lua @@ -1,7 +1,6 @@ local BuiltinDecorator = require("nvim-tree.renderer.decorator.builtin") ---@class (exact) BookmarkDecorator: BuiltinDecorator ----@field private explorer Explorer ---@field private icon nvim_tree.api.highlighted_string? local BookmarkDecorator = BuiltinDecorator:extend() @@ -11,7 +10,7 @@ local BookmarkDecorator = BuiltinDecorator:extend() ---@protected ---@param args BuiltinDecoratorArgs function BookmarkDecorator:new(args) - self.explorer = args.explorer + BookmarkDecorator.super.new(self, args) self.enabled = true self.highlight_range = self.explorer.opts.renderer.highlight_bookmarks or "none" diff --git a/lua/nvim-tree/renderer/decorator/builtin.lua b/lua/nvim-tree/renderer/decorator/builtin.lua index f495fe485e9..a1f3ec8d826 100644 --- a/lua/nvim-tree/renderer/decorator/builtin.lua +++ b/lua/nvim-tree/renderer/decorator/builtin.lua @@ -5,9 +5,7 @@ local Decorator = require("nvim-tree.renderer.decorator") --- ---@class (exact) BuiltinDecorator: Decorator --- ----@field protected enabled boolean ----@field protected highlight_range nvim_tree.config.renderer.highlight ----@field protected icon_placement "none"|nvim_tree.config.renderer.icons.placement +---@field protected explorer Explorer --- ---@field icon_node fun(self: BuiltinDecorator, node: Node): nvim_tree.api.highlighted_string? ---@field icons fun(self: BuiltinDecorator, node: Node): nvim_tree.api.highlighted_string? @@ -19,8 +17,13 @@ local Decorator = require("nvim-tree.renderer.decorator") ---@field icons_right_align fun(self: BuiltinDecorator, node: Node): nvim_tree.api.highlighted_string[]? local BuiltinDecorator = Decorator:extend() ----TODO #3241 create a common constructor ---@class (exact) BuiltinDecoratorArgs ---@field explorer Explorer +---@protected +---@param args BuiltinDecoratorArgs +function BuiltinDecorator:new(args) + self.explorer = args.explorer +end + return BuiltinDecorator diff --git a/lua/nvim-tree/renderer/decorator/copied.lua b/lua/nvim-tree/renderer/decorator/copied.lua index b2a773bf65b..581ce753dfc 100644 --- a/lua/nvim-tree/renderer/decorator/copied.lua +++ b/lua/nvim-tree/renderer/decorator/copied.lua @@ -1,7 +1,6 @@ local BuiltinDecorator = require("nvim-tree.renderer.decorator.builtin") ---@class (exact) CopiedDecorator: BuiltinDecorator ----@field private explorer Explorer local CopiedDecorator = BuiltinDecorator:extend() ---@class CopiedDecorator @@ -10,7 +9,7 @@ local CopiedDecorator = BuiltinDecorator:extend() ---@protected ---@param args BuiltinDecoratorArgs function CopiedDecorator:new(args) - self.explorer = args.explorer + CopiedDecorator.super.new(self, args) self.enabled = true self.highlight_range = self.explorer.opts.renderer.highlight_clipboard or "none" diff --git a/lua/nvim-tree/renderer/decorator/cut.lua b/lua/nvim-tree/renderer/decorator/cut.lua index f721572d752..565e043165c 100644 --- a/lua/nvim-tree/renderer/decorator/cut.lua +++ b/lua/nvim-tree/renderer/decorator/cut.lua @@ -1,7 +1,6 @@ local BuiltinDecorator = require("nvim-tree.renderer.decorator.builtin") ---@class (exact) CutDecorator: BuiltinDecorator ----@field private explorer Explorer local CutDecorator = BuiltinDecorator:extend() ---@class CutDecorator @@ -10,7 +9,7 @@ local CutDecorator = BuiltinDecorator:extend() ---@protected ---@param args BuiltinDecoratorArgs function CutDecorator:new(args) - self.explorer = args.explorer + CutDecorator.super.new(self, args) self.enabled = true self.highlight_range = self.explorer.opts.renderer.highlight_clipboard or "none" diff --git a/lua/nvim-tree/renderer/decorator/diagnostics.lua b/lua/nvim-tree/renderer/decorator/diagnostics.lua index e0741222238..c859e767820 100644 --- a/lua/nvim-tree/renderer/decorator/diagnostics.lua +++ b/lua/nvim-tree/renderer/decorator/diagnostics.lua @@ -31,7 +31,6 @@ local ICON_KEYS = { } ---@class (exact) DiagnosticsDecorator: BuiltinDecorator ----@field private explorer Explorer ---@field private diag_icons nvim_tree.api.highlighted_string[]? local DiagnosticsDecorator = BuiltinDecorator:extend() @@ -41,7 +40,7 @@ local DiagnosticsDecorator = BuiltinDecorator:extend() ---@protected ---@param args BuiltinDecoratorArgs function DiagnosticsDecorator:new(args) - self.explorer = args.explorer + DiagnosticsDecorator.super.new(self, args) self.enabled = true self.highlight_range = self.explorer.opts.renderer.highlight_diagnostics or "none" diff --git a/lua/nvim-tree/renderer/decorator/git.lua b/lua/nvim-tree/renderer/decorator/git.lua index 07446752eb3..8b473150500 100644 --- a/lua/nvim-tree/renderer/decorator/git.lua +++ b/lua/nvim-tree/renderer/decorator/git.lua @@ -13,7 +13,6 @@ local DirectoryNode = require("nvim-tree.node.directory") ---@alias GitGlyphsByStatus table from opts ---@class (exact) GitDecorator: BuiltinDecorator ----@field private explorer Explorer ---@field private file_hl_by_xy table? ---@field private folder_hl_by_xy table? ---@field private icons_by_status GitIconsByStatus? @@ -26,7 +25,7 @@ local GitDecorator = BuiltinDecorator:extend() ---@protected ---@param args BuiltinDecoratorArgs function GitDecorator:new(args) - self.explorer = args.explorer + GitDecorator.super.new(self, args) self.enabled = self.explorer.opts.git.enable self.highlight_range = self.explorer.opts.renderer.highlight_git or "none" diff --git a/lua/nvim-tree/renderer/decorator/hidden.lua b/lua/nvim-tree/renderer/decorator/hidden.lua index 07a02d6dd17..f25a7f35f8f 100644 --- a/lua/nvim-tree/renderer/decorator/hidden.lua +++ b/lua/nvim-tree/renderer/decorator/hidden.lua @@ -2,7 +2,6 @@ local BuiltinDecorator = require("nvim-tree.renderer.decorator.builtin") local DirectoryNode = require("nvim-tree.node.directory") ---@class (exact) HiddenDecorator: BuiltinDecorator ----@field private explorer Explorer ---@field private icon nvim_tree.api.highlighted_string? local HiddenDecorator = BuiltinDecorator:extend() @@ -12,7 +11,7 @@ local HiddenDecorator = BuiltinDecorator:extend() ---@protected ---@param args BuiltinDecoratorArgs function HiddenDecorator:new(args) - self.explorer = args.explorer + HiddenDecorator.super.new(self, args) self.enabled = true self.highlight_range = self.explorer.opts.renderer.highlight_hidden or "none" diff --git a/lua/nvim-tree/renderer/decorator/modified.lua b/lua/nvim-tree/renderer/decorator/modified.lua index 3edb811f9c7..5715a7c76f5 100644 --- a/lua/nvim-tree/renderer/decorator/modified.lua +++ b/lua/nvim-tree/renderer/decorator/modified.lua @@ -4,7 +4,6 @@ local BuiltinDecorator = require("nvim-tree.renderer.decorator.builtin") local DirectoryNode = require("nvim-tree.node.directory") ---@class (exact) ModifiedDecorator: BuiltinDecorator ----@field private explorer Explorer ---@field private icon nvim_tree.api.highlighted_string? local ModifiedDecorator = BuiltinDecorator:extend() @@ -14,7 +13,7 @@ local ModifiedDecorator = BuiltinDecorator:extend() ---@protected ---@param args BuiltinDecoratorArgs function ModifiedDecorator:new(args) - self.explorer = args.explorer + ModifiedDecorator.super.new(self, args) self.enabled = true self.highlight_range = self.explorer.opts.renderer.highlight_modified or "none" diff --git a/lua/nvim-tree/renderer/decorator/opened.lua b/lua/nvim-tree/renderer/decorator/opened.lua index 4bf88527e72..d9722c20013 100644 --- a/lua/nvim-tree/renderer/decorator/opened.lua +++ b/lua/nvim-tree/renderer/decorator/opened.lua @@ -3,7 +3,6 @@ local buffers = require("nvim-tree.buffers") local BuiltinDecorator = require("nvim-tree.renderer.decorator.builtin") ---@class (exact) OpenDecorator: BuiltinDecorator ----@field private explorer Explorer ---@field private icon? nvim_tree.api.highlighted_string local OpenDecorator = BuiltinDecorator:extend() @@ -13,7 +12,7 @@ local OpenDecorator = BuiltinDecorator:extend() ---@protected ---@param args BuiltinDecoratorArgs function OpenDecorator:new(args) - self.explorer = args.explorer + OpenDecorator.super.new(self, args) self.enabled = true self.highlight_range = self.explorer.opts.renderer.highlight_opened_files or "none" From c74dc201932570e3752ac3bdc936d48114c53fbe Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Wed, 4 Feb 2026 13:19:48 +1100 Subject: [PATCH 23/27] docs(#3241): revert api function changes --- scripts/vimdoc_config.lua | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/scripts/vimdoc_config.lua b/scripts/vimdoc_config.lua index d66cbd1acd2..708a44ccae8 100644 --- a/scripts/vimdoc_config.lua +++ b/scripts/vimdoc_config.lua @@ -137,8 +137,18 @@ return { -- strip module from the name fn_xform = function(fun) - normalise_module(fun) - fun.name = fun.name:gsub("^" .. fun.module .. "%.", "", 1) + if (fun.module) then + normalise_module(fun) + + -- remove the API prefix from the left aligned function name + -- this will cascade into fn_helptag_fmt, which will apply the module prefix anyway + local name, replaced = fun.name:gsub("^" .. fun.module .. "%.", "", 1) + if (replaced ~= 2) then + error(string.format("\n\nfun.name='%s' does not start with module\nfun=%s", fun.name, vim.inspect(fun))) + end + + fun.name = name + end end, }, -- Classes @@ -150,14 +160,15 @@ return { helptag_fmt = function(name) return src_by_name(name, srcs_class).helptag end, fn_xform = function(fun) - -- strip module from name and record the module for the method - normalise_module(fun) + if (fun.module) then + normalise_module(fun) - -- strip the class file from the module - fun.module = fun.module:gsub("%.[^%.]*$", "", 1) + -- strip the class file from the module + fun.module = fun.module:gsub("%.[^%.]*$", "", 1) - -- strip module from name and record the module for the method - modules_by_method[fun.classvar .. ":" .. fun.name] = fun.module + -- record the module for the method + modules_by_method[fun.classvar .. ":" .. fun.name] = fun.module + end end, -- fn_helptag_fmt_common derived From cebf53cfb52abfb31acd206e61dfc4c898d5b6c7 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Wed, 4 Feb 2026 13:20:46 +1100 Subject: [PATCH 24/27] docs(#3241): revert api function changes --- scripts/vimdoc_config.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/vimdoc_config.lua b/scripts/vimdoc_config.lua index 708a44ccae8..92ef9186838 100644 --- a/scripts/vimdoc_config.lua +++ b/scripts/vimdoc_config.lua @@ -143,7 +143,7 @@ return { -- remove the API prefix from the left aligned function name -- this will cascade into fn_helptag_fmt, which will apply the module prefix anyway local name, replaced = fun.name:gsub("^" .. fun.module .. "%.", "", 1) - if (replaced ~= 2) then + if (replaced ~= 1) then error(string.format("\n\nfun.name='%s' does not start with module\nfun=%s", fun.name, vim.inspect(fun))) end From 3d1a172d17033e622bf976ce69cf6c8c55f8894f Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Wed, 4 Feb 2026 13:28:08 +1100 Subject: [PATCH 25/27] docs(#3241): vimdoc polish --- doc/nvim-tree-lua.txt | 2 +- scripts/vimdoc_config.lua | 103 +++++++++++++++++++------------------- 2 files changed, 52 insertions(+), 53 deletions(-) diff --git a/doc/nvim-tree-lua.txt b/doc/nvim-tree-lua.txt index 77c7ec7766e..16a6654a3a3 100644 --- a/doc/nvim-tree-lua.txt +++ b/doc/nvim-tree-lua.txt @@ -3113,7 +3113,7 @@ winid({opts}) *nvim_tree.api.tree.winid()* ============================================================================== -Class *nvim-tree-class* +Class: Class *nvim-tree-class* nvim-tree uses the https://github.com/rxi/classic class framework adding safe casts, instanceof mixin and conventional destructors. diff --git a/scripts/vimdoc_config.lua b/scripts/vimdoc_config.lua index 92ef9186838..4a00d9141ed 100644 --- a/scripts/vimdoc_config.lua +++ b/scripts/vimdoc_config.lua @@ -8,64 +8,65 @@ ---@class (exact) Src ---@field helptag string must be globally unique ---@field section string arbitrary ----@field path string relative to root +---@field path string relative to cwd -local pre = "runtime/lua/nvim_tree/" +local base = "runtime/lua/nvim_tree/" +local placeholder = "runtime/lua/placeholder.lua" ---@type Src[] local srcs_config = { - { helptag = "nvim-tree-config", section = "Config", path = pre .. "_meta/config.lua", }, - - { helptag = "nvim-tree-config-sort", section = "Config: sort", path = pre .. "_meta/config/sort.lua", }, - { helptag = "nvim-tree-config-view", section = "Config: view", path = pre .. "_meta/config/view.lua", }, - { helptag = "nvim-tree-config-renderer", section = "Config: renderer", path = pre .. "_meta/config/renderer.lua", }, - { helptag = "nvim-tree-config-hijack-directories", section = "Config: hijack_directories", path = pre .. "_meta/config/hijack_directories.lua", }, - { helptag = "nvim-tree-config-update-focused-file", section = "Config: update_focused_file", path = pre .. "_meta/config/update_focused_file.lua", }, - { helptag = "nvim-tree-config-system-open", section = "Config: system_open", path = pre .. "_meta/config/system_open.lua", }, - { helptag = "nvim-tree-config-git", section = "Config: git", path = pre .. "_meta/config/git.lua", }, - { helptag = "nvim-tree-config-diagnostics", section = "Config: diagnostics", path = pre .. "_meta/config/diagnostics.lua", }, - { helptag = "nvim-tree-config-modified", section = "Config: modified", path = pre .. "_meta/config/modified.lua", }, - { helptag = "nvim-tree-config-filters", section = "Config: filters", path = pre .. "_meta/config/filters.lua", }, - { helptag = "nvim-tree-config-live-filter", section = "Config: live_filter", path = pre .. "_meta/config/live_filter.lua", }, - { helptag = "nvim-tree-config-filesystem-watchers", section = "Config: filesystem_watchers", path = pre .. "_meta/config/filesystem_watchers.lua", }, - { helptag = "nvim-tree-config-actions", section = "Config: actions", path = pre .. "_meta/config/actions.lua", }, - { helptag = "nvim-tree-config-trash", section = "Config: trash", path = pre .. "_meta/config/trash.lua", }, - { helptag = "nvim-tree-config-tab", section = "Config: tab", path = pre .. "_meta/config/tab.lua", }, - { helptag = "nvim-tree-config-notify", section = "Config: notify", path = pre .. "_meta/config/notify.lua", }, - { helptag = "nvim-tree-config-bookmarks", section = "Config: bookmarks", path = pre .. "_meta/config/bookmarks.lua", }, - { helptag = "nvim-tree-config-help", section = "Config: help", path = pre .. "_meta/config/help.lua", }, - { helptag = "nvim-tree-config-ui", section = "Config: ui", path = pre .. "_meta/config/ui.lua", }, - { helptag = "nvim-tree-config-experimental", section = "Config: experimental", path = pre .. "_meta/config/experimental.lua", }, - { helptag = "nvim-tree-config-log", section = "Config: log", path = pre .. "_meta/config/log.lua", }, - - { helptag = "nvim-tree-config-default", section = "Config: Default", path = pre .. "_meta/config/default.lua", }, - - { helptag = "nvim-tree-api", section = "PLACEHOLDER", path = "runtime/lua/placeholder.lua", }, + { helptag = "nvim-tree-config", section = "Config", path = base .. "_meta/config.lua", }, + + { helptag = "nvim-tree-config-sort", section = "Config: sort", path = base .. "_meta/config/sort.lua", }, + { helptag = "nvim-tree-config-view", section = "Config: view", path = base .. "_meta/config/view.lua", }, + { helptag = "nvim-tree-config-renderer", section = "Config: renderer", path = base .. "_meta/config/renderer.lua", }, + { helptag = "nvim-tree-config-hijack-directories", section = "Config: hijack_directories", path = base .. "_meta/config/hijack_directories.lua", }, + { helptag = "nvim-tree-config-update-focused-file", section = "Config: update_focused_file", path = base .. "_meta/config/update_focused_file.lua", }, + { helptag = "nvim-tree-config-system-open", section = "Config: system_open", path = base .. "_meta/config/system_open.lua", }, + { helptag = "nvim-tree-config-git", section = "Config: git", path = base .. "_meta/config/git.lua", }, + { helptag = "nvim-tree-config-diagnostics", section = "Config: diagnostics", path = base .. "_meta/config/diagnostics.lua", }, + { helptag = "nvim-tree-config-modified", section = "Config: modified", path = base .. "_meta/config/modified.lua", }, + { helptag = "nvim-tree-config-filters", section = "Config: filters", path = base .. "_meta/config/filters.lua", }, + { helptag = "nvim-tree-config-live-filter", section = "Config: live_filter", path = base .. "_meta/config/live_filter.lua", }, + { helptag = "nvim-tree-config-filesystem-watchers", section = "Config: filesystem_watchers", path = base .. "_meta/config/filesystem_watchers.lua", }, + { helptag = "nvim-tree-config-actions", section = "Config: actions", path = base .. "_meta/config/actions.lua", }, + { helptag = "nvim-tree-config-trash", section = "Config: trash", path = base .. "_meta/config/trash.lua", }, + { helptag = "nvim-tree-config-tab", section = "Config: tab", path = base .. "_meta/config/tab.lua", }, + { helptag = "nvim-tree-config-notify", section = "Config: notify", path = base .. "_meta/config/notify.lua", }, + { helptag = "nvim-tree-config-bookmarks", section = "Config: bookmarks", path = base .. "_meta/config/bookmarks.lua", }, + { helptag = "nvim-tree-config-help", section = "Config: help", path = base .. "_meta/config/help.lua", }, + { helptag = "nvim-tree-config-ui", section = "Config: ui", path = base .. "_meta/config/ui.lua", }, + { helptag = "nvim-tree-config-experimental", section = "Config: experimental", path = base .. "_meta/config/experimental.lua", }, + { helptag = "nvim-tree-config-log", section = "Config: log", path = base .. "_meta/config/log.lua", }, + + { helptag = "nvim-tree-config-default", section = "Config: Default", path = base .. "_meta/config/default.lua", }, + + { helptag = "nvim-tree-api", section = "PLACEHOLDER", path = placeholder, }, } ---@type Src[] local srcs_api = { - { helptag = "nvim-tree-api", section = "API", path = pre .. "api.lua", }, - - { helptag = "nvim-tree-api-commands", section = "API: commands", path = pre .. "_meta/api/commands.lua", }, - { helptag = "nvim-tree-api-events", section = "API: events", path = pre .. "_meta/api/events.lua", }, - { helptag = "nvim-tree-api-filter", section = "API: filter", path = pre .. "_meta/api/filter.lua", }, - { helptag = "nvim-tree-api-fs", section = "API: fs", path = pre .. "_meta/api/fs.lua", }, - { helptag = "nvim-tree-api-git", section = "API: git", path = pre .. "_meta/api/git.lua", }, - { helptag = "nvim-tree-api-health", section = "API: health", path = pre .. "_meta/api/health.lua", }, - { helptag = "nvim-tree-api-map", section = "API: map", path = pre .. "_meta/api/map.lua", }, - { helptag = "nvim-tree-api-marks", section = "API: marks", path = pre .. "_meta/api/marks.lua", }, - { helptag = "nvim-tree-api-node", section = "API: node", path = pre .. "_meta/api/node.lua", }, - { helptag = "nvim-tree-api-tree", section = "API: tree", path = pre .. "_meta/api/tree.lua", }, - - { helptag = "nvim-tree-class", section = "PLACEHOLDER", path = "runtime/lua/placeholder.lua", }, + { helptag = "nvim-tree-api", section = "API", path = base .. "api.lua", }, + + { helptag = "nvim-tree-api-commands", section = "API: commands", path = base .. "_meta/api/commands.lua", }, + { helptag = "nvim-tree-api-events", section = "API: events", path = base .. "_meta/api/events.lua", }, + { helptag = "nvim-tree-api-filter", section = "API: filter", path = base .. "_meta/api/filter.lua", }, + { helptag = "nvim-tree-api-fs", section = "API: fs", path = base .. "_meta/api/fs.lua", }, + { helptag = "nvim-tree-api-git", section = "API: git", path = base .. "_meta/api/git.lua", }, + { helptag = "nvim-tree-api-health", section = "API: health", path = base .. "_meta/api/health.lua", }, + { helptag = "nvim-tree-api-map", section = "API: map", path = base .. "_meta/api/map.lua", }, + { helptag = "nvim-tree-api-marks", section = "API: marks", path = base .. "_meta/api/marks.lua", }, + { helptag = "nvim-tree-api-node", section = "API: node", path = base .. "_meta/api/node.lua", }, + { helptag = "nvim-tree-api-tree", section = "API: tree", path = base .. "_meta/api/tree.lua", }, + + { helptag = "nvim-tree-class", section = "PLACEHOLDER", path = placeholder, }, } ---@type Src[] local srcs_class = { - { helptag = "nvim-tree-class", section = "Class", path = pre .. "classic.lua", }, - { helptag = "nvim-tree-class-decorator", section = "Class: Decorator", path = pre .. "_meta/api/decorator.lua", }, - { helptag = "nvim-tree-class-decorator-example", section = "Class: Decorator: example", path = pre .. "_meta/api/decorator_example.lua", }, + { helptag = "nvim-tree-class", section = "Class: Class", path = base .. "classic.lua", }, + { helptag = "nvim-tree-class-decorator", section = "Class: Decorator", path = base .. "_meta/api/decorator.lua", }, + { helptag = "nvim-tree-class-decorator-example", section = "Class: Decorator: example", path = base .. "_meta/api/decorator_example.lua", }, } ---Map paths to file names @@ -135,19 +136,17 @@ return { section_fmt = function(name) return src_by_name(name, srcs_api).section end, helptag_fmt = function(name) return src_by_name(name, srcs_api).helptag end, - -- strip module from the name fn_xform = function(fun) if (fun.module) then normalise_module(fun) - -- remove the API prefix from the left aligned function name - -- this will cascade into fn_helptag_fmt, which will apply the module prefix anyway - local name, replaced = fun.name:gsub("^" .. fun.module .. "%.", "", 1) + -- remove the module prefix from the left aligned function name + -- default fn_helptag_fmt adds it back to the help tag + local replaced + fun.name, replaced = fun.name:gsub("^" .. fun.module .. "%.", "", 1) if (replaced ~= 1) then error(string.format("\n\nfun.name='%s' does not start with module\nfun=%s", fun.name, vim.inspect(fun))) end - - fun.name = name end end, }, From 8785496aed8330fda9dfddfda64e22142acb7fe4 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Wed, 4 Feb 2026 13:50:05 +1100 Subject: [PATCH 26/27] docs(#3241): tidy --- lua/nvim-tree/api/impl/legacy.lua | 31 -------------------- lua/nvim-tree/api/impl/post.lua | 4 ++- lua/nvim-tree/api/impl/pre.lua | 6 ++-- lua/nvim-tree/legacy.lua | 28 ++++++++++++++++++ lua/nvim-tree/renderer/decorator/builtin.lua | 2 +- lua/nvim-tree/renderer/decorator/init.lua | 6 ++-- 6 files changed, 40 insertions(+), 37 deletions(-) delete mode 100644 lua/nvim-tree/api/impl/legacy.lua diff --git a/lua/nvim-tree/api/impl/legacy.lua b/lua/nvim-tree/api/impl/legacy.lua deleted file mode 100644 index 66f817f6669..00000000000 --- a/lua/nvim-tree/api/impl/legacy.lua +++ /dev/null @@ -1,31 +0,0 @@ -local M = {} - ----Silently create new api entries pointing legacy functions to current ----@param api table not properly typed to prevent LSP from referencing implementations -function M.hydrate(api) - api.config = api.config or {} - api.config.mappings = api.config.mappings or {} - api.config.mappings.get_keymap = api.map.keymap.current - api.config.mappings.get_keymap_default = api.map.keymap.default - api.config.mappings.default_on_attach = api.map.on_attach.default - - api.live_filter = api.live_filter or {} - api.live_filter.start = api.filter.live.start - api.live_filter.clear = api.filter.live.clear - - api.tree = api.tree or {} - api.tree.toggle_enable_filters = api.filter.toggle - api.tree.toggle_gitignore_filter = api.filter.git.ignored.toggle - api.tree.toggle_git_clean_filter = api.filter.git.clean.toggle - api.tree.toggle_no_buffer_filter = api.filter.no_buffer.toggle - api.tree.toggle_custom_filter = api.filter.custom.toggle - api.tree.toggle_hidden_filter = api.filter.dotfiles.toggle - api.tree.toggle_no_bookmark_filter = api.filter.no_bookmark.toggle - - api.diagnostics = api.diagnostics or {} - api.diagnostics.hi_test = api.health.hi_test - - api.decorator.UserDecorator = api.Decorator -end - -return M diff --git a/lua/nvim-tree/api/impl/post.lua b/lua/nvim-tree/api/impl/post.lua index 181753a34ce..11c4b5ede14 100644 --- a/lua/nvim-tree/api/impl/post.lua +++ b/lua/nvim-tree/api/impl/post.lua @@ -6,6 +6,8 @@ ---This is expensive as there are many cascading requires and is avoided ---until after setup has been called, so that the user may require API cheaply. +local legacy = require("nvim-tree.legacy") + local actions = require("nvim-tree.actions") local help = require("nvim-tree.help") local keymap = require("nvim-tree.keymap") @@ -256,7 +258,7 @@ function M.hydrate(api) api.map.keymap.current = keymap.get_keymap -- (Re)hydrate any legacy by mapping to concrete set above - require("nvim-tree.api.impl.legacy").hydrate(api) + legacy.map_api(api) end return M diff --git a/lua/nvim-tree/api/impl/pre.lua b/lua/nvim-tree/api/impl/pre.lua index 73d5c5e148c..489fb05649c 100644 --- a/lua/nvim-tree/api/impl/pre.lua +++ b/lua/nvim-tree/api/impl/pre.lua @@ -9,6 +9,8 @@ -- --Everything must be as lazily loaded as possible: the user must be able to require api cheaply. +local legacy = require("nvim-tree.legacy") + local commands = require("nvim-tree.commands") -- already required by plugin.lua local events = require("nvim-tree.events") -- needed for event registration pre-setup local keymap = require("nvim-tree.keymap") -- needed for default on attach @@ -40,7 +42,6 @@ function M.hydrate(api) hydrate_error(api) -- eager functions - api.events.Event = events.Event api.events.subscribe = events.subscribe api.map.on_attach.default = keymap.on_attach_default api.commands.get = commands.get @@ -51,9 +52,10 @@ function M.hydrate(api) -- classes api.Decorator = Decorator:extend() + api.events.Event = events.Event -- Hydrate any legacy by mapping to concrete set above - require("nvim-tree.api.impl.legacy").hydrate(api) + legacy.map_api(api) end return M diff --git a/lua/nvim-tree/legacy.lua b/lua/nvim-tree/legacy.lua index 842700ba36b..47495e0e609 100644 --- a/lua/nvim-tree/legacy.lua +++ b/lua/nvim-tree/legacy.lua @@ -151,4 +151,32 @@ function M.migrate_legacy_options(opts) removed(opts) end +---Silently create new api entries pointing legacy functions to current +---@param api table not properly typed to prevent LSP from referencing implementations +function M.map_api(api) + api.config = api.config or {} + api.config.mappings = api.config.mappings or {} + api.config.mappings.get_keymap = api.map.keymap.current + api.config.mappings.get_keymap_default = api.map.keymap.default + api.config.mappings.default_on_attach = api.map.on_attach.default + + api.live_filter = api.live_filter or {} + api.live_filter.start = api.filter.live.start + api.live_filter.clear = api.filter.live.clear + + api.tree = api.tree or {} + api.tree.toggle_enable_filters = api.filter.toggle + api.tree.toggle_gitignore_filter = api.filter.git.ignored.toggle + api.tree.toggle_git_clean_filter = api.filter.git.clean.toggle + api.tree.toggle_no_buffer_filter = api.filter.no_buffer.toggle + api.tree.toggle_custom_filter = api.filter.custom.toggle + api.tree.toggle_hidden_filter = api.filter.dotfiles.toggle + api.tree.toggle_no_bookmark_filter = api.filter.no_bookmark.toggle + + api.diagnostics = api.diagnostics or {} + api.diagnostics.hi_test = api.health.hi_test + + api.decorator.UserDecorator = api.Decorator +end + return M diff --git a/lua/nvim-tree/renderer/decorator/builtin.lua b/lua/nvim-tree/renderer/decorator/builtin.lua index a1f3ec8d826..e1ff61300b7 100644 --- a/lua/nvim-tree/renderer/decorator/builtin.lua +++ b/lua/nvim-tree/renderer/decorator/builtin.lua @@ -1,6 +1,6 @@ local Decorator = require("nvim-tree.renderer.decorator") ----Builtin decorator interface. +---Abstract builtin decorator ---Overrides all methods to use a Node instead of nvim_tree.api.Node as we don't have generics. --- ---@class (exact) BuiltinDecorator: Decorator diff --git a/lua/nvim-tree/renderer/decorator/init.lua b/lua/nvim-tree/renderer/decorator/init.lua index 27fc57a3b4e..075156772ee 100644 --- a/lua/nvim-tree/renderer/decorator/init.lua +++ b/lua/nvim-tree/renderer/decorator/init.lua @@ -1,8 +1,10 @@ +local DecoratorInterface = require("nvim-tree._meta.api.decorator") + --- ----Abstract decorator implementation +---Abstract decorator --- ---@class (exact) Decorator: nvim_tree.api.Decorator -local Decorator = require("nvim-tree._meta.api.decorator"):extend() +local Decorator = DecoratorInterface:extend() ---Maybe highlight groups for icon and name ---@param node nvim_tree.api.Node From 5585bfd18e508979f42fdd01ec2c2205c906c3cb Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Wed, 4 Feb 2026 14:20:48 +1100 Subject: [PATCH 27/27] docs(#3241): tidy --- doc/nvim-tree-lua.txt | 4 ++-- lua/nvim-tree/_meta/classes.lua | 6 ------ scripts/vimdoc_config.lua | 6 +++--- 3 files changed, 5 insertions(+), 11 deletions(-) diff --git a/doc/nvim-tree-lua.txt b/doc/nvim-tree-lua.txt index 16a6654a3a3..05df7e4e762 100644 --- a/doc/nvim-tree-lua.txt +++ b/doc/nvim-tree-lua.txt @@ -548,7 +548,7 @@ To view the nvim-tree highlight groups run |:NvimTreeHiTest| To view all active highlight groups run `:so $VIMRUNTIME/syntax/hitest.vim` as per |:highlight| -The `*HL` groups are additive according to per |nvim_tree.config.renderer| +The `*HL` groups are additive, following |nvim_tree.config.renderer.decorator| precedence. Only present attributes will clobber each other. In this example a modified, opened file will have magenta text, with cyan @@ -3385,7 +3385,7 @@ Decorator:icons({node}) *nvim_tree.api.Decorator:icons()* ============================================================================== -Class: Decorator: example *nvim-tree-class-decorator-example* +Class: Decorator example *nvim-tree-class-decorator-example* A decorator class for nodes named "example", overriding all builtin decorators except for Cut. diff --git a/lua/nvim-tree/_meta/classes.lua b/lua/nvim-tree/_meta/classes.lua index f8c66153362..fc2c5021462 100644 --- a/lua/nvim-tree/_meta/classes.lua +++ b/lua/nvim-tree/_meta/classes.lua @@ -1,12 +1,6 @@ ---@meta error("Cannot require a meta file") - --- TODO #2688 --- These node subclasses are not ready for public exposure as they are: --- - not classic classes --- - only used in a few locations: api.tree.get_nodes and Decorator - --- ---File --- diff --git a/scripts/vimdoc_config.lua b/scripts/vimdoc_config.lua index 4a00d9141ed..07d47eec2b8 100644 --- a/scripts/vimdoc_config.lua +++ b/scripts/vimdoc_config.lua @@ -64,9 +64,9 @@ local srcs_api = { ---@type Src[] local srcs_class = { - { helptag = "nvim-tree-class", section = "Class: Class", path = base .. "classic.lua", }, - { helptag = "nvim-tree-class-decorator", section = "Class: Decorator", path = base .. "_meta/api/decorator.lua", }, - { helptag = "nvim-tree-class-decorator-example", section = "Class: Decorator: example", path = base .. "_meta/api/decorator_example.lua", }, + { helptag = "nvim-tree-class", section = "Class: Class", path = base .. "classic.lua", }, + { helptag = "nvim-tree-class-decorator", section = "Class: Decorator", path = base .. "_meta/api/decorator.lua", }, + { helptag = "nvim-tree-class-decorator-example", section = "Class: Decorator example", path = base .. "_meta/api/decorator_example.lua", }, } ---Map paths to file names