From 129c349eeef302ab31dd73afdbaf2bc3fae9d6d0 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Sun, 24 Nov 2024 15:19:05 +1100 Subject: [PATCH] feat(#2948): add decorator registry and order --- doc/nvim-tree-lua.txt | 1 - lua/nvim-tree.lua | 1 - lua/nvim-tree/api.lua | 5 ++ lua/nvim-tree/renderer/builder.lua | 33 +++------ .../renderer/decorator/bookmarks.lua | 13 ++-- lua/nvim-tree/renderer/decorator/copied.lua | 13 ++-- lua/nvim-tree/renderer/decorator/cut.lua | 13 ++-- .../renderer/decorator/diagnostics.lua | 13 ++-- lua/nvim-tree/renderer/decorator/git.lua | 13 ++-- lua/nvim-tree/renderer/decorator/hidden.lua | 13 ++-- lua/nvim-tree/renderer/decorator/init.lua | 6 +- lua/nvim-tree/renderer/decorator/modified.lua | 13 ++-- lua/nvim-tree/renderer/decorator/opened.lua | 13 ++-- lua/nvim-tree/renderer/decorator/registry.lua | 71 +++++++++++++++++++ lua/nvim-tree/renderer/decorator/user.lua | 25 ++----- 15 files changed, 152 insertions(+), 94 deletions(-) create mode 100644 lua/nvim-tree/renderer/decorator/registry.lua diff --git a/doc/nvim-tree-lua.txt b/doc/nvim-tree-lua.txt index 2a670c59d31..060227f8220 100644 --- a/doc/nvim-tree-lua.txt +++ b/doc/nvim-tree-lua.txt @@ -417,7 +417,6 @@ Following is the default configuration. See |nvim-tree-opts| for details. >lua }, }, renderer = { - user_decorators = {}, add_trailing = false, group_empty = false, full_name = false, diff --git a/lua/nvim-tree.lua b/lua/nvim-tree.lua index 8c05be4fa47..212d4c14bab 100644 --- a/lua/nvim-tree.lua +++ b/lua/nvim-tree.lua @@ -276,7 +276,6 @@ local DEFAULT_OPTS = { -- BEGIN_DEFAULT_OPTS }, }, renderer = { - user_decorators = {}, add_trailing = false, group_empty = false, full_name = false, diff --git a/lua/nvim-tree/api.lua b/lua/nvim-tree/api.lua index 6a50a260b53..9e3fdc989c7 100644 --- a/lua/nvim-tree/api.lua +++ b/lua/nvim-tree/api.lua @@ -7,6 +7,7 @@ local events = require("nvim-tree.events") local help = require("nvim-tree.help") local keymap = require("nvim-tree.keymap") local notify = require("nvim-tree.notify") +local decorator_registry = require("nvim-tree.renderer.decorator.registry") local DirectoryNode = require("nvim-tree.node.directory") local FileLinkNode = require("nvim-tree.node.file-link") @@ -312,6 +313,10 @@ Api.commands.get = wrap(function() return require("nvim-tree.commands").get() end) +-- TODO provide a registration convenience to hide classic +-- TODO add doc Api.decorator.BaseDecorator = require("nvim-tree.renderer.decorator.user") --[[@as nvim_tree.api.decorator.BaseDecorator ]] +Api.decorator.register = decorator_registry.register +Api.decorator.unregister = decorator_registry.unregister return Api diff --git a/lua/nvim-tree/renderer/builder.lua b/lua/nvim-tree/renderer/builder.lua index 398d53d1825..e1da5314745 100644 --- a/lua/nvim-tree/renderer/builder.lua +++ b/lua/nvim-tree/renderer/builder.lua @@ -1,18 +1,11 @@ +local decorator_registry = require("nvim-tree.renderer.decorator.registry") local notify = require("nvim-tree.notify") local utils = require("nvim-tree.utils") local view = require("nvim-tree.view") local Class = require("nvim-tree.classic") local DirectoryNode = require("nvim-tree.node.directory") - -local DecoratorBookmarks = require("nvim-tree.renderer.decorator.bookmarks") -local DecoratorCopied = require("nvim-tree.renderer.decorator.copied") -local DecoratorCut = require("nvim-tree.renderer.decorator.cut") -local DecoratorDiagnostics = require("nvim-tree.renderer.decorator.diagnostics") -local DecoratorGit = require("nvim-tree.renderer.decorator.git") -local DecoratorModified = require("nvim-tree.renderer.decorator.modified") -local DecoratorHidden = require("nvim-tree.renderer.decorator.hidden") -local DecoratorOpened = require("nvim-tree.renderer.decorator.opened") +local DecoratorUser = require("nvim-tree.renderer.decorator.user") local pad = require("nvim-tree.renderer.components.padding") @@ -56,21 +49,17 @@ function Builder:new(args) self.signs = {} self.extmarks = {} self.virtual_lines = {} - self.decorators = { - -- priority order - DecoratorCut(self.explorer), - DecoratorCopied(self.explorer), - DecoratorDiagnostics(self.explorer), - DecoratorBookmarks(self.explorer), - DecoratorModified(self.explorer), - DecoratorHidden(self.explorer), - DecoratorOpened(self.explorer), - DecoratorGit(self.explorer), - } self.hidden_display = Builder:setup_hidden_display_function(self.explorer.opts) - for _, user_decorator in ipairs(args.explorer.opts.renderer.user_decorators) do - table.insert(self.decorators, user_decorator.class()) + -- lowest priority is registered first + self.decorators = {} + local decorator_args = { explorer = self.explorer } + for _, d in ipairs(decorator_registry.registered) do + if d:is(DecoratorUser) then + table.insert(self.decorators, 1, d()) + else + table.insert(self.decorators, 1, d(decorator_args)) + end end end diff --git a/lua/nvim-tree/renderer/decorator/bookmarks.lua b/lua/nvim-tree/renderer/decorator/bookmarks.lua index 4d074e55794..f963ddbf21a 100644 --- a/lua/nvim-tree/renderer/decorator/bookmarks.lua +++ b/lua/nvim-tree/renderer/decorator/bookmarks.lua @@ -4,23 +4,24 @@ local Decorator = require("nvim-tree.renderer.decorator") ---@field private explorer Explorer ---@field private icon HighlightedString? local DecoratorBookmarks = Decorator:extend() +DecoratorBookmarks.name = "Bookmarks" ---@class DecoratorBookmarks ---@overload fun(explorer: Explorer): DecoratorBookmarks ---@protected ----@param explorer Explorer -function DecoratorBookmarks:new(explorer) - self.explorer = explorer +---@param args DecoratorArgs +function DecoratorBookmarks:new(args) + self.explorer = args.explorer - ---@type DecoratorArgs - local args = { + ---@type AbstractDecoratorArgs + local a = { enabled = true, highlight_range = self.explorer.opts.renderer.highlight_bookmarks or "none", icon_placement = self.explorer.opts.renderer.icons.bookmarks_placement or "none", } - DecoratorBookmarks.super.new(self, args) + DecoratorBookmarks.super.new(self, a) if self.explorer.opts.renderer.icons.show.bookmarks then self.icon = { diff --git a/lua/nvim-tree/renderer/decorator/copied.lua b/lua/nvim-tree/renderer/decorator/copied.lua index 85ded7b7453..4f9210e8128 100644 --- a/lua/nvim-tree/renderer/decorator/copied.lua +++ b/lua/nvim-tree/renderer/decorator/copied.lua @@ -3,23 +3,24 @@ local Decorator = require("nvim-tree.renderer.decorator") ---@class (exact) DecoratorCopied: Decorator ---@field private explorer Explorer local DecoratorCopied = Decorator:extend() +DecoratorCopied.name = "Copied" ---@class DecoratorCopied ---@overload fun(explorer: Explorer): DecoratorCopied ---@protected ----@param explorer Explorer -function DecoratorCopied:new(explorer) - self.explorer = explorer +---@param args DecoratorArgs +function DecoratorCopied:new(args) + self.explorer = args.explorer - ---@type DecoratorArgs - local args = { + ---@type AbstractDecoratorArgs + local a = { enabled = true, highlight_range = self.explorer.opts.renderer.highlight_clipboard or "none", icon_placement = "none", } - DecoratorCopied.super.new(self, args) + DecoratorCopied.super.new(self, a) end ---Copied highlight: renderer.highlight_clipboard and node is copied diff --git a/lua/nvim-tree/renderer/decorator/cut.lua b/lua/nvim-tree/renderer/decorator/cut.lua index 4546a990a7d..3441b627359 100644 --- a/lua/nvim-tree/renderer/decorator/cut.lua +++ b/lua/nvim-tree/renderer/decorator/cut.lua @@ -3,23 +3,24 @@ local Decorator = require("nvim-tree.renderer.decorator") ---@class (exact) DecoratorCut: Decorator ---@field private explorer Explorer local DecoratorCut = Decorator:extend() +DecoratorCut.name = "Cut" ---@class DecoratorCut ---@overload fun(explorer: Explorer): DecoratorCut ---@protected ----@param explorer Explorer -function DecoratorCut:new(explorer) - self.explorer = explorer +---@param args DecoratorArgs +function DecoratorCut:new(args) + self.explorer = args.explorer - ---@type DecoratorArgs - local args = { + ---@type AbstractDecoratorArgs + local a = { enabled = true, highlight_range = self.explorer.opts.renderer.highlight_clipboard or "none", icon_placement = "none", } - DecoratorCut.super.new(self, args) + DecoratorCut.super.new(self, a) end ---Cut highlight: renderer.highlight_clipboard and node is cut diff --git a/lua/nvim-tree/renderer/decorator/diagnostics.lua b/lua/nvim-tree/renderer/decorator/diagnostics.lua index d61996bffef..ba3c3bf5f03 100644 --- a/lua/nvim-tree/renderer/decorator/diagnostics.lua +++ b/lua/nvim-tree/renderer/decorator/diagnostics.lua @@ -34,23 +34,24 @@ local ICON_KEYS = { ---@field private explorer Explorer ---@field private diag_icons HighlightedString[]? local DecoratorDiagnostics = Decorator:extend() +DecoratorDiagnostics.name = "Diagnostics" ---@class DecoratorDiagnostics ---@overload fun(explorer: Explorer): DecoratorDiagnostics ---@protected ----@param explorer Explorer -function DecoratorDiagnostics:new(explorer) - self.explorer = explorer +---@param args DecoratorArgs +function DecoratorDiagnostics:new(args) + self.explorer = args.explorer - ---@type DecoratorArgs - local args = { + ---@type AbstractDecoratorArgs + local a = { enabled = true, highlight_range = self.explorer.opts.renderer.highlight_diagnostics or "none", icon_placement = self.explorer.opts.renderer.icons.diagnostics_placement or "none", } - DecoratorDiagnostics.super.new(self, args) + DecoratorDiagnostics.super.new(self, a) if not self.enabled then return diff --git a/lua/nvim-tree/renderer/decorator/git.lua b/lua/nvim-tree/renderer/decorator/git.lua index a4e6cd7945c..6a24a1b68d0 100644 --- a/lua/nvim-tree/renderer/decorator/git.lua +++ b/lua/nvim-tree/renderer/decorator/git.lua @@ -19,23 +19,24 @@ local DirectoryNode = require("nvim-tree.node.directory") ---@field private icons_by_status GitIconsByStatus? ---@field private icons_by_xy GitIconsByXY? local DecoratorGit = Decorator:extend() +DecoratorGit.name = "Git" ---@class DecoratorGit ---@overload fun(explorer: Explorer): DecoratorGit ---@protected ----@param explorer Explorer -function DecoratorGit:new(explorer) - self.explorer = explorer +---@param args DecoratorArgs +function DecoratorGit:new(args) + self.explorer = args.explorer - ---@type DecoratorArgs - local args = { + ---@type AbstractDecoratorArgs + local a = { enabled = self.explorer.opts.git.enable, highlight_range = self.explorer.opts.renderer.highlight_git or "none", icon_placement = self.explorer.opts.renderer.icons.git_placement or "none", } - DecoratorGit.super.new(self, args) + DecoratorGit.super.new(self, a) if not self.enabled then return diff --git a/lua/nvim-tree/renderer/decorator/hidden.lua b/lua/nvim-tree/renderer/decorator/hidden.lua index 0c4c8fe1507..98d25c6d524 100644 --- a/lua/nvim-tree/renderer/decorator/hidden.lua +++ b/lua/nvim-tree/renderer/decorator/hidden.lua @@ -5,23 +5,24 @@ local DirectoryNode = require("nvim-tree.node.directory") ---@field private explorer Explorer ---@field private icon HighlightedString? local DecoratorHidden = Decorator:extend() +DecoratorHidden.name = "Hidden" ---@class DecoratorHidden ---@overload fun(explorer: Explorer): DecoratorHidden ---@protected ----@param explorer Explorer -function DecoratorHidden:new(explorer) - self.explorer = explorer +---@param args DecoratorArgs +function DecoratorHidden:new(args) + self.explorer = args.explorer - ---@type DecoratorArgs - local args = { + ---@type AbstractDecoratorArgs + local a = { enabled = true, highlight_range = self.explorer.opts.renderer.highlight_hidden or "none", icon_placement = self.explorer.opts.renderer.icons.hidden_placement or "none", } - DecoratorHidden.super.new(self, args) + DecoratorHidden.super.new(self, a) if self.explorer.opts.renderer.icons.show.hidden then self.icon = { diff --git a/lua/nvim-tree/renderer/decorator/init.lua b/lua/nvim-tree/renderer/decorator/init.lua index adfd01dc96d..70093017575 100644 --- a/lua/nvim-tree/renderer/decorator/init.lua +++ b/lua/nvim-tree/renderer/decorator/init.lua @@ -2,18 +2,22 @@ local Class = require("nvim-tree.classic") ---Abstract Decorator ---@class (exact) Decorator: Class +---@field name string for registry ---@field protected enabled boolean ---@field protected highlight_range DecoratorHighlightRange ---@field protected icon_placement DecoratorIconPlacement local Decorator = Class:extend() ---@class (exact) DecoratorArgs +---@field explorer Explorer +--- +---@class (exact) AbstractDecoratorArgs ---@field enabled boolean ---@field highlight_range DecoratorHighlightRange ---@field icon_placement DecoratorIconPlacement ---@protected ----@param args DecoratorArgs +---@param args AbstractDecoratorArgs function Decorator:new(args) if args then self.enabled = args.enabled diff --git a/lua/nvim-tree/renderer/decorator/modified.lua b/lua/nvim-tree/renderer/decorator/modified.lua index da55f19adf7..667cf45217d 100644 --- a/lua/nvim-tree/renderer/decorator/modified.lua +++ b/lua/nvim-tree/renderer/decorator/modified.lua @@ -7,23 +7,24 @@ local DirectoryNode = require("nvim-tree.node.directory") ---@field private explorer Explorer ---@field private icon HighlightedString? local DecoratorModified = Decorator:extend() +DecoratorModified.name = "Modified" ---@class DecoratorModified ---@overload fun(explorer: Explorer): DecoratorModified ---@protected ----@param explorer Explorer -function DecoratorModified:new(explorer) - self.explorer = explorer +---@param args DecoratorArgs +function DecoratorModified:new(args) + self.explorer = args.explorer - ---@type DecoratorArgs - local args = { + ---@type AbstractDecoratorArgs + local a = { enabled = true, highlight_range = self.explorer.opts.renderer.highlight_modified or "none", icon_placement = self.explorer.opts.renderer.icons.modified_placement or "none", } - DecoratorModified.super.new(self, args) + DecoratorModified.super.new(self, a) if not self.enabled then return diff --git a/lua/nvim-tree/renderer/decorator/opened.lua b/lua/nvim-tree/renderer/decorator/opened.lua index 7a02c6d4c99..04e2f989b28 100644 --- a/lua/nvim-tree/renderer/decorator/opened.lua +++ b/lua/nvim-tree/renderer/decorator/opened.lua @@ -6,23 +6,24 @@ local Decorator = require("nvim-tree.renderer.decorator") ---@field private explorer Explorer ---@field private icon HighlightedString|nil local DecoratorOpened = Decorator:extend() +DecoratorOpened.name = "Opened" ---@class DecoratorOpened ---@overload fun(explorer: Explorer): DecoratorOpened ---@protected ----@param explorer Explorer -function DecoratorOpened:new(explorer) - self.explorer = explorer +---@param args DecoratorArgs +function DecoratorOpened:new(args) + self.explorer = args.explorer - ---@type DecoratorArgs - local args = { + ---@type AbstractDecoratorArgs + local a = { enabled = true, highlight_range = self.explorer.opts.renderer.highlight_opened_files or "none", icon_placement = "none", } - DecoratorOpened.super.new(self, args) + DecoratorOpened.super.new(self, a) end ---Opened highlight: renderer.highlight_opened_files and node has an open buffer diff --git a/lua/nvim-tree/renderer/decorator/registry.lua b/lua/nvim-tree/renderer/decorator/registry.lua new file mode 100644 index 00000000000..5c94a31b4ac --- /dev/null +++ b/lua/nvim-tree/renderer/decorator/registry.lua @@ -0,0 +1,71 @@ +local notify = require("nvim-tree.notify") +local utils = require("nvim-tree.utils") + +local DecoratorBookmarks = require("nvim-tree.renderer.decorator.bookmarks") +local DecoratorCopied = require("nvim-tree.renderer.decorator.copied") +local DecoratorCut = require("nvim-tree.renderer.decorator.cut") +local DecoratorDiagnostics = require("nvim-tree.renderer.decorator.diagnostics") +local DecoratorGit = require("nvim-tree.renderer.decorator.git") +local DecoratorModified = require("nvim-tree.renderer.decorator.modified") +local DecoratorHidden = require("nvim-tree.renderer.decorator.hidden") +local DecoratorOpened = require("nvim-tree.renderer.decorator.opened") +local DecoratorUser = require("nvim-tree.renderer.decorator.user") + +-- Globally registered decorators including user +-- Lowest priority first + +---@alias DecoratorName nvim_tree.api.decorator.BaseDecorator | "Cut" | "Copied" | "Diagnostics" | "Bookmarks" | "Modified" | "Hidden" | "Opened" | "Git" + +local M = { + ---@type Decorator[] + registered = { + DecoratorGit, + DecoratorOpened, + DecoratorHidden, + DecoratorModified, + DecoratorBookmarks, + DecoratorDiagnostics, + DecoratorCopied, + DecoratorCut, + } +} + +---@class RegisterOpts +---@field decorator nvim_tree.api.decorator.BaseDecorator +---@field below DecoratorName? + +---@param opts RegisterOpts +function M.register(opts) + if not opts or not opts.decorator then + return + end + + if vim.tbl_contains(M.registered, opts.decorator) then + notify.error("decorator already registered") + return + end + + for i, d in ipairs(M.registered) do + if d:is(DecoratorUser) and d == opts.below or d.name == opts.below then + table.insert(M.registered, i, opts.decorator) + return + end + end + + -- default to highest at the top + table.insert(M.registered, opts.decorator) +end + +---@class UnRegisterOpts +---@field decorator nvim_tree.api.decorator.BaseDecorator + +---@param opts UnRegisterOpts +function M.unregister(opts) + if not opts or not opts.decorator then + return + end + + utils.array_remove(M.registered, opts.decorator) +end + +return M diff --git a/lua/nvim-tree/renderer/decorator/user.lua b/lua/nvim-tree/renderer/decorator/user.lua index 536725ed4b5..5dcbb7b82fc 100644 --- a/lua/nvim-tree/renderer/decorator/user.lua +++ b/lua/nvim-tree/renderer/decorator/user.lua @@ -1,24 +1,7 @@ local Decorator = require("nvim-tree.renderer.decorator") ----@class (exact) UserDecorator: Decorator -local UserDecorator = Decorator:extend() +---Exposed as nvim_tree.api.decorator.BaseDecorator +---@class (exact) DecoratorUser: Decorator +local DecoratorUser = Decorator:extend() ----@param node nvim_tree.api.Node ----@return HighlightedString? icon_node -function UserDecorator:icon_node(node) - return self:nop(node) -end - ----@param node nvim_tree.api.Node ----@return HighlightedString[]? icons -function UserDecorator:icons(node) - self:nop(node) -end - ----@param node nvim_tree.api.Node ----@return string? highlight_group -function UserDecorator:highlight_group(node) - self:nop(node) -end - -return UserDecorator +return DecoratorUser