diff --git a/lua/nvim-tree.lua b/lua/nvim-tree.lua index aa48597d2c2..06f8ab74afc 100644 --- a/lua/nvim-tree.lua +++ b/lua/nvim-tree.lua @@ -1,15 +1,10 @@ local lib = require "nvim-tree.lib" local log = require "nvim-tree.log" local appearance = require "nvim-tree.appearance" -local renderer = require "nvim-tree.renderer" local view = require "nvim-tree.view" -local commands = require "nvim-tree.commands" local utils = require "nvim-tree.utils" local actions = require "nvim-tree.actions" -local legacy = require "nvim-tree.legacy" local core = require "nvim-tree.core" -local git = require "nvim-tree.git" -local buffers = require "nvim-tree.buffers" local notify = require "nvim-tree.notify" local _config = {} @@ -97,7 +92,11 @@ function M.tab_enter() end end view.open { focus_tree = false } - renderer.draw() + + local explorer = core.get_explorer() + if explorer then + explorer.renderer:draw() + end end end @@ -179,7 +178,11 @@ local function setup_autocommands(opts) callback = function() appearance.setup() view.reset_winhl() - renderer.draw() + + local explorer = core.get_explorer() + if explorer then + explorer.renderer:draw() + end end, }) @@ -217,7 +220,7 @@ local function setup_autocommands(opts) return end if - (explorer.filters.config.filter_no_buffer or renderer.config.highlight_opened_files ~= "none") and vim.bo[data.buf].buftype == "" + (explorer.filters.config.filter_no_buffer or explorer.opts.highlight_opened_files ~= "none") and vim.bo[data.buf].buftype == "" then utils.debounce("Buf:filter_buffer", opts.view.debounce_delay, function() explorer:reload_explorer() @@ -234,7 +237,7 @@ local function setup_autocommands(opts) return end if - (explorer.filters.config.filter_no_buffer or renderer.config.highlight_opened_files ~= "none") and vim.bo[data.buf].buftype == "" + (explorer.filters.config.filter_no_buffer or explorer.opts.highlight_opened_files ~= "none") and vim.bo[data.buf].buftype == "" then utils.debounce("Buf:filter_buffer", opts.view.debounce_delay, function() explorer:reload_explorer() @@ -351,7 +354,7 @@ local function setup_autocommands(opts) create_nvim_tree_autocmd({ "BufModifiedSet", "BufWritePost" }, { callback = function() utils.debounce("Buf:modified", opts.view.debounce_delay, function() - buffers.reload_modified() + require("nvim-tree.buffers").reload_modified() local explorer = core.get_explorer() if explorer then explorer:reload_explorer() @@ -801,7 +804,7 @@ function M.purge_all_state() view.close_all_tabs() view.abandon_all_windows() if core.get_explorer() ~= nil then - git.purge_state() + require("nvim-tree.git").purge_state() core.reset_explorer() end end @@ -817,7 +820,7 @@ function M.setup(conf) localise_default_opts() - legacy.migrate_legacy_options(conf or {}) + require("nvim-tree.legacy").migrate_legacy_options(conf or {}) validate_options(conf) @@ -851,7 +854,7 @@ function M.setup(conf) require("nvim-tree.git.utils").setup(opts) require("nvim-tree.view").setup(opts) require("nvim-tree.lib").setup(opts) - require("nvim-tree.renderer").setup(opts) + require("nvim-tree.renderer.components").setup(opts) require("nvim-tree.buffers").setup(opts) require("nvim-tree.help").setup(opts) require("nvim-tree.watcher").setup(opts) @@ -863,7 +866,7 @@ function M.setup(conf) if vim.g.NvimTreeSetup ~= 1 then -- first call to setup - commands.setup() + require("nvim-tree.commands").setup() else -- subsequent calls to setup M.purge_all_state() diff --git a/lua/nvim-tree/actions/finders/find-file.lua b/lua/nvim-tree/actions/finders/find-file.lua index fcfd24941ff..7798de4b05b 100644 --- a/lua/nvim-tree/actions/finders/find-file.lua +++ b/lua/nvim-tree/actions/finders/find-file.lua @@ -1,7 +1,6 @@ local log = require "nvim-tree.log" local view = require "nvim-tree.view" local utils = require "nvim-tree.utils" -local renderer = require "nvim-tree.renderer" local core = require "nvim-tree.core" local Iterator = require "nvim-tree.iterators.node-iterator" @@ -76,7 +75,7 @@ function M.fn(path) :iterate() if found and view.is_visible() then - renderer.draw() + explorer.renderer:draw() view.set_cursor { line, 0 } end diff --git a/lua/nvim-tree/actions/fs/clipboard.lua b/lua/nvim-tree/actions/fs/clipboard.lua index fccb7c1159c..8ee7554a3f2 100644 --- a/lua/nvim-tree/actions/fs/clipboard.lua +++ b/lua/nvim-tree/actions/fs/clipboard.lua @@ -4,7 +4,6 @@ local utils = require "nvim-tree.utils" local core = require "nvim-tree.core" local events = require "nvim-tree.events" local notify = require "nvim-tree.notify" -local renderer = require "nvim-tree.renderer" local find_file = require("nvim-tree.actions.finders.find-file").fn @@ -193,7 +192,7 @@ function Clipboard:clear_clipboard() self.data[ACTION.copy] = {} self.data[ACTION.cut] = {} notify.info "Clipboard has been emptied." - renderer.draw() + self.explorer.renderer:draw() end ---Copy one node @@ -201,7 +200,7 @@ end function Clipboard:copy(node) utils.array_remove(self.data[ACTION.cut], node) toggle(node, self.data[ACTION.copy]) - renderer.draw() + self.explorer.renderer:draw() end ---Cut one node @@ -209,7 +208,7 @@ end function Clipboard:cut(node) utils.array_remove(self.data[ACTION.copy], node) toggle(node, self.data[ACTION.cut]) - renderer.draw() + self.explorer.renderer:draw() end ---Paste cut or cop diff --git a/lua/nvim-tree/actions/moves/parent.lua b/lua/nvim-tree/actions/moves/parent.lua index 598483eb120..c9367763dfe 100644 --- a/lua/nvim-tree/actions/moves/parent.lua +++ b/lua/nvim-tree/actions/moves/parent.lua @@ -1,4 +1,3 @@ -local renderer = require "nvim-tree.renderer" local view = require "nvim-tree.view" local utils = require "nvim-tree.utils" local core = require "nvim-tree.core" @@ -11,11 +10,16 @@ local M = {} function M.fn(should_close) should_close = should_close or false + local explorer = core.get_explorer() + return function(node) node = lib.get_last_group_node(node) if should_close and node.open then node.open = false - return renderer.draw() + if explorer then + explorer.renderer:draw() + end + return end local parent = utils.get_parent_of_group(node).parent @@ -31,7 +35,9 @@ function M.fn(should_close) view.set_cursor { line + 1, 0 } if should_close then parent.open = false - renderer.draw() + if explorer then + explorer.renderer:draw() + end end end end diff --git a/lua/nvim-tree/actions/root/change-dir.lua b/lua/nvim-tree/actions/root/change-dir.lua index 954b2081ccf..8ba5763d151 100644 --- a/lua/nvim-tree/actions/root/change-dir.lua +++ b/lua/nvim-tree/actions/root/change-dir.lua @@ -91,7 +91,10 @@ M.force_dirchange = add_profiling_to(function(foldername, should_open_view) if should_open_view then require("nvim-tree.lib").open() else - require("nvim-tree.renderer").draw() + local explorer = core.get_explorer() + if explorer then + explorer.renderer:draw() + end end end) diff --git a/lua/nvim-tree/actions/tree/modifiers/collapse-all.lua b/lua/nvim-tree/actions/tree/modifiers/collapse-all.lua index c6add436f1e..e15f185ab69 100644 --- a/lua/nvim-tree/actions/tree/modifiers/collapse-all.lua +++ b/lua/nvim-tree/actions/tree/modifiers/collapse-all.lua @@ -1,4 +1,3 @@ -local renderer = require "nvim-tree.renderer" local utils = require "nvim-tree.utils" local core = require "nvim-tree.core" local lib = require "nvim-tree.lib" @@ -46,7 +45,7 @@ function M.fn(keep_buffers) end) :iterate() - renderer.draw() + explorer.renderer:draw() utils.focus_node_or_parent(node) end diff --git a/lua/nvim-tree/actions/tree/modifiers/expand-all.lua b/lua/nvim-tree/actions/tree/modifiers/expand-all.lua index 6af62e6ae49..22fe97cea97 100644 --- a/lua/nvim-tree/actions/tree/modifiers/expand-all.lua +++ b/lua/nvim-tree/actions/tree/modifiers/expand-all.lua @@ -1,5 +1,4 @@ local core = require "nvim-tree.core" -local renderer = require "nvim-tree.renderer" local Iterator = require "nvim-tree.iterators.node-iterator" local notify = require "nvim-tree.notify" local lib = require "nvim-tree.lib" @@ -65,11 +64,14 @@ end ---@param base_node table function M.fn(base_node) - local node = base_node.nodes and base_node or core.get_explorer() + local explorer = core.get_explorer() + local node = base_node.nodes and base_node or explorer if gen_iterator()(node) then notify.warn("expansion iteration was halted after " .. M.MAX_FOLDER_DISCOVERY .. " discovered folders") end - renderer.draw() + if explorer then + explorer.renderer:draw() + end end function M.setup(opts) diff --git a/lua/nvim-tree/core.lua b/lua/nvim-tree/core.lua index a255233dab3..186a8b17d77 100644 --- a/lua/nvim-tree/core.lua +++ b/lua/nvim-tree/core.lua @@ -1,5 +1,4 @@ local events = require "nvim-tree.events" -local explorer = require "nvim-tree.explorer" local view = require "nvim-tree.view" local log = require "nvim-tree.log" @@ -16,7 +15,7 @@ function M.init(foldername) if TreeExplorer then TreeExplorer:destroy() end - TreeExplorer = explorer:new(foldername) + TreeExplorer = require("nvim-tree.explorer"):new(foldername) if not first_init_done then events._dispatch_ready() first_init_done = true diff --git a/lua/nvim-tree/diagnostics.lua b/lua/nvim-tree/diagnostics.lua index 7cfc585122c..4fa314d67ac 100644 --- a/lua/nvim-tree/diagnostics.lua +++ b/lua/nvim-tree/diagnostics.lua @@ -1,3 +1,4 @@ +local core = require "nvim-tree.core" local utils = require "nvim-tree.utils" local view = require "nvim-tree.view" local log = require "nvim-tree.log" @@ -165,7 +166,10 @@ function M.update() end log.profile_end(profile) if view.is_buf_valid(view.get_bufnr()) then - require("nvim-tree.renderer").draw() + local explorer = core.get_explorer() + if explorer then + explorer.renderer:draw() + end end end) end diff --git a/lua/nvim-tree/explorer/init.lua b/lua/nvim-tree/explorer/init.lua index 1b6b6d12b3a..0d44217b11e 100644 --- a/lua/nvim-tree/explorer/init.lua +++ b/lua/nvim-tree/explorer/init.lua @@ -2,7 +2,6 @@ local builders = require "nvim-tree.explorer.node-builders" local git = require "nvim-tree.git" local log = require "nvim-tree.log" local notify = require "nvim-tree.notify" -local renderer = {} -- circular dependency, will become a member local utils = require "nvim-tree.utils" local view = require "nvim-tree.view" local watch = require "nvim-tree.explorer.watch" @@ -13,19 +12,23 @@ local NodeIterator = require "nvim-tree.iterators.node-iterator" local Watcher = require "nvim-tree.watcher" local Filters = require "nvim-tree.explorer.filters" -local Marks = {} -- circular dependencies +local Marks = require "nvim-tree.marks" local LiveFilter = require "nvim-tree.explorer.live-filter" local Sorters = require "nvim-tree.explorer.sorters" -local Clipboard = {} -- circular dependencies +local Clipboard = require "nvim-tree.actions.fs.clipboard" +local Renderer = require "nvim-tree.renderer" local FILTER_REASON = require("nvim-tree.enum").FILTER_REASON local config ---@class Explorer +---@field opts table user options ---@field absolute_path string ---@field nodes Node[] ---@field open boolean +---@field watcher Watcher|nil +---@field renderer Renderer ---@field filters Filters ---@field live_filter LiveFilter ---@field sorters Sorter @@ -48,17 +51,19 @@ function Explorer:new(path) return end - ---@class Explorer - local o = setmetatable({ + local o = { + opts = config, absolute_path = path, nodes = {}, open = true, sorters = Sorters:new(config), - }, Explorer) + } + setmetatable(o, self) self.__index = self o.watcher = watch.create_watcher(o) + o.renderer = Renderer:new(config, o) o.filters = Filters:new(config, o) o.live_filter = LiveFilter:new(config, o) o.marks = Marks:new(config, o) @@ -454,7 +459,7 @@ function Explorer:reload_explorer() local projects = git.reload() self:refresh_nodes(projects) if view.is_visible() then - renderer.draw() + self.renderer:draw() end event_running = false end @@ -467,7 +472,7 @@ function Explorer:reload_git() local projects = git.reload() explorer_node.reload_node_status(self, projects) - renderer.draw() + self.renderer:draw() event_running = false end @@ -475,11 +480,6 @@ function Explorer.setup(opts) config = opts require("nvim-tree.explorer.node").setup(opts) require("nvim-tree.explorer.watch").setup(opts) - - renderer = require "nvim-tree.renderer" - - Marks = require "nvim-tree.marks" - Clipboard = require "nvim-tree.actions.fs.clipboard" end return Explorer diff --git a/lua/nvim-tree/explorer/live-filter.lua b/lua/nvim-tree/explorer/live-filter.lua index ed9dd6c44ce..be2848969cc 100644 --- a/lua/nvim-tree/explorer/live-filter.lua +++ b/lua/nvim-tree/explorer/live-filter.lua @@ -23,10 +23,6 @@ function LiveFilter:new(opts, explorer) return o end -local function redraw() - require("nvim-tree.renderer").draw() -end - ---@param node_ Node|nil local function reset_filter(self, node_) node_ = node_ or self.explorer @@ -129,7 +125,7 @@ local function record_char(self) vim.schedule(function() self.filter = vim.api.nvim_buf_get_lines(overlay_bufnr, 0, -1, false)[1] self:apply_filter() - redraw() + self.explorer.renderer:draw() end) end @@ -199,7 +195,7 @@ function LiveFilter:start_filtering() view.View.live_filter.prev_focused_node = require("nvim-tree.lib").get_node_at_cursor() self.filter = self.filter or "" - redraw() + self.explorer.renderer:draw() local row = require("nvim-tree.core").get_nodes_starting_line() - 1 local col = #self.prefix > 0 and #self.prefix - 1 or 1 view.set_cursor { row, col } @@ -215,7 +211,7 @@ function LiveFilter:clear_filter() self.filter = nil reset_filter(self) - redraw() + self.explorer.renderer:draw() if node then utils.focus_file(node.absolute_path) diff --git a/lua/nvim-tree/explorer/watch.lua b/lua/nvim-tree/explorer/watch.lua index 90ccedb20de..ad7b9254f73 100644 --- a/lua/nvim-tree/explorer/watch.lua +++ b/lua/nvim-tree/explorer/watch.lua @@ -79,7 +79,7 @@ function M.create_watcher(node) local explorer = require("nvim-tree.core").get_explorer() if explorer then explorer:refresh_node(node, function() - require("nvim-tree.renderer").draw() + explorer.renderer:draw() end) end end) diff --git a/lua/nvim-tree/git/init.lua b/lua/nvim-tree/git/init.lua index 6c1dbc1b3a5..4889c12766f 100644 --- a/lua/nvim-tree/git/init.lua +++ b/lua/nvim-tree/git/init.lua @@ -216,7 +216,10 @@ local function reload_tree_at(toplevel) end) :iterate() - require("nvim-tree.renderer").draw() + local explorer = require("nvim-tree.core").get_explorer() + if explorer then + explorer.renderer:draw() + end end) end diff --git a/lua/nvim-tree/lib.lua b/lua/nvim-tree/lib.lua index 6efb42e4156..83c0b61268e 100644 --- a/lua/nvim-tree/lib.lua +++ b/lua/nvim-tree/lib.lua @@ -1,4 +1,3 @@ -local renderer = require "nvim-tree.renderer" local view = require "nvim-tree.view" local core = require "nvim-tree.core" local utils = require "nvim-tree.utils" @@ -150,13 +149,15 @@ end ---@param node Node function M.expand_or_collapse(node, toggle_group) + local explorer = core.get_explorer() + toggle_group = toggle_group or false if node.has_children then node.has_children = false end - if #node.nodes == 0 then - core.get_explorer():expand(node) + if #node.nodes == 0 and explorer then + explorer:expand(node) end local head_node = utils.get_parent_of_group(node) @@ -175,7 +176,9 @@ function M.expand_or_collapse(node, toggle_group) n.open = next_open end - renderer.draw() + if explorer then + explorer.renderer:draw() + end end function M.set_target_win() @@ -200,7 +203,11 @@ local function open_view_and_draw() local cwd = vim.fn.getcwd() view.open() handle_buf_cwd(cwd) - renderer.draw() + + local explorer = core.get_explorer() + if explorer then + explorer.renderer:draw() + end end local function should_hijack_current_buf() @@ -256,6 +263,8 @@ end function M.open(opts) opts = opts or {} + local explorer = core.get_explorer() + M.set_target_win() if not core.get_explorer() or opts.path then if opts.path then @@ -272,13 +281,19 @@ function M.open(opts) if should_hijack_current_buf() then view.close_this_tab_only() view.open_in_win() - renderer.draw() + if explorer then + explorer.renderer:draw() + end elseif opts.winid then view.open_in_win { hijack_current_buf = false, resize = false, winid = opts.winid } - renderer.draw() + if explorer then + explorer.renderer:draw() + end elseif opts.current_window then view.open_in_win { hijack_current_buf = false, resize = false } - renderer.draw() + if explorer then + explorer.renderer:draw() + end else open_view_and_draw() end diff --git a/lua/nvim-tree/marks/init.lua b/lua/nvim-tree/marks/init.lua index 85d87fdc2b2..32670e162f8 100644 --- a/lua/nvim-tree/marks/init.lua +++ b/lua/nvim-tree/marks/init.lua @@ -5,7 +5,6 @@ local notify = require "nvim-tree.notify" local open_file = require "nvim-tree.actions.node.open-file" local remove_file = require "nvim-tree.actions.fs.remove-file" local rename_file = require "nvim-tree.actions.fs.rename-file" -local renderer = require "nvim-tree.renderer" local trash = require "nvim-tree.actions.fs.trash" local utils = require "nvim-tree.utils" @@ -46,7 +45,7 @@ end ---@public function Marks:clear() self.marks = {} - renderer.draw() + self.explorer.renderer:draw() end ---@public @@ -62,7 +61,7 @@ function Marks:toggle(node) self.marks[node.absolute_path] = node end - renderer.draw() + self.explorer.renderer:draw() end ---Return node if marked diff --git a/lua/nvim-tree/renderer/builder.lua b/lua/nvim-tree/renderer/builder.lua index 23bef62ac8f..2cccec8d033 100644 --- a/lua/nvim-tree/renderer/builder.lua +++ b/lua/nvim-tree/renderer/builder.lua @@ -1,4 +1,3 @@ -local core = require "nvim-tree.core" local notify = require "nvim-tree.notify" local utils = require "nvim-tree.utils" local view = require "nvim-tree.view" @@ -15,46 +14,49 @@ local DecoratorOpened = require "nvim-tree.renderer.decorator.opened" local pad = require "nvim-tree.renderer.components.padding" local icons = require "nvim-tree.renderer.components.icons" -local M = { - opts = {}, - decorators = {}, - picture_map = { - jpg = true, - jpeg = true, - png = true, - gif = true, - webp = true, - jxl = true, - }, +local PICTURE_MAP = { + jpg = true, + jpeg = true, + png = true, + gif = true, + webp = true, + jxl = true, } ----@class HighlightedString +---@class (exact) HighlightedString ---@field str string ---@field hl string[] ----@class AddHighlightArgs +---@class (exact) AddHighlightArgs ---@field group string[] ---@field line number ---@field col_start number ---@field col_end number ----@class Builder +---@class (exact) Builder +---@field private __index? table ---@field lines string[] includes icons etc. ---@field hl_args AddHighlightArgs[] line highlights ---@field signs string[] line signs ---@field extmarks table[] extra marks for right icon placement ---@field virtual_lines table[] virtual lines for hidden count display ----@field private root_cwd string absolute path +---@field private explorer Explorer ---@field private index number ---@field private depth number ---@field private combined_groups table combined group names ---@field private markers boolean[] indent markers +---@field private decorators Decorator[] +---@field private hidden_display fun(node: Node): string|nil local Builder = {} +---@param opts table user options +---@param explorer Explorer ---@return Builder -function Builder:new() +function Builder:new(opts, explorer) + ---@type Builder local o = { - root_cwd = core.get_cwd(), + opts = opts, + explorer = explorer, index = 0, depth = 0, hl_args = {}, @@ -64,7 +66,20 @@ function Builder:new() signs = {}, extmarks = {}, virtual_lines = {}, + decorators = { + -- priority order + DecoratorCut:new(opts, explorer), + DecoratorCopied:new(opts, explorer), + DecoratorDiagnostics:new(opts, explorer), + DecoratorBookmarks:new(opts, explorer), + DecoratorModified:new(opts, explorer), + DecoratorHidden:new(opts, explorer), + DecoratorOpened:new(opts, explorer), + DecoratorGit:new(opts, explorer), + }, + hidden_display = Builder:setup_hidden_display_function(opts), } + setmetatable(o, self) self.__index = self @@ -89,8 +104,8 @@ function Builder:get_folder_name(node) next = next.group_next end - if node.group_next and type(M.opts.renderer.group_empty) == "function" then - local new_name = M.opts.renderer.group_empty(name) + if node.group_next and type(self.opts.renderer.group_empty) == "function" then + local new_name = self.opts.renderer.group_empty(name) if type(new_name) == "string" then name = new_name else @@ -98,7 +113,7 @@ function Builder:get_folder_name(node) end end - return string.format("%s%s", name, M.opts.renderer.add_trailing and "/" or "") + return string.format("%s%s", name, self.opts.renderer.add_trailing and "/" or "") end ---@private @@ -139,13 +154,13 @@ function Builder:build_folder(node) end local foldername_hl = "NvimTreeFolderName" - if node.link_to and M.opts.renderer.symlink_destination then + if node.link_to and self.opts.renderer.symlink_destination then local arrow = icons.i.symlink_arrow - local link_to = utils.path_relative(node.link_to, self.root_cwd) + local link_to = utils.path_relative(node.link_to, self.explorer.absolute_path) foldername = string.format("%s%s%s", foldername, arrow, link_to) foldername_hl = "NvimTreeSymlinkFolderName" elseif - vim.tbl_contains(M.opts.renderer.special_files, node.absolute_path) or vim.tbl_contains(M.opts.renderer.special_files, node.name) + vim.tbl_contains(self.opts.renderer.special_files, node.absolute_path) or vim.tbl_contains(self.opts.renderer.special_files, node.name) then foldername_hl = "NvimTreeSpecialFolderName" elseif node.open then @@ -165,8 +180,8 @@ function Builder:build_symlink(node) local icon = icons.i.symlink local arrow = icons.i.symlink_arrow local symlink_formatted = node.name - if M.opts.renderer.symlink_destination then - local link_to = utils.path_relative(node.link_to, self.root_cwd) + if self.opts.renderer.symlink_destination then + local link_to = utils.path_relative(node.link_to, self.explorer.absolute_path) symlink_formatted = string.format("%s%s%s", symlink_formatted, arrow, link_to) end @@ -179,11 +194,13 @@ end ---@return HighlightedString name function Builder:build_file(node) local hl - if vim.tbl_contains(M.opts.renderer.special_files, node.absolute_path) or vim.tbl_contains(M.opts.renderer.special_files, node.name) then + if + vim.tbl_contains(self.opts.renderer.special_files, node.absolute_path) or vim.tbl_contains(self.opts.renderer.special_files, node.name) + then hl = "NvimTreeSpecialFile" elseif node.executable then hl = "NvimTreeExecFile" - elseif M.picture_map[node.extension] then + elseif PICTURE_MAP[node.extension] then hl = "NvimTreeImageFile" end @@ -206,7 +223,7 @@ function Builder:format_line(indent_markers, arrows, icon, name, node) end for _, v in ipairs(t2) do if added_len > 0 then - table.insert(t1, { str = M.opts.renderer.icons.padding }) + table.insert(t1, { str = self.opts.renderer.icons.padding }) end table.insert(t1, v) end @@ -222,19 +239,19 @@ function Builder:format_line(indent_markers, arrows, icon, name, node) local line = { indent_markers, arrows } add_to_end(line, { icon }) - for i = #M.decorators, 1, -1 do - add_to_end(line, M.decorators[i]:icons_before(node)) + for i = #self.decorators, 1, -1 do + add_to_end(line, self.decorators[i]:icons_before(node)) end add_to_end(line, { name }) - for i = #M.decorators, 1, -1 do - add_to_end(line, M.decorators[i]:icons_after(node)) + for i = #self.decorators, 1, -1 do + add_to_end(line, self.decorators[i]:icons_after(node)) end local rights = {} - for i = #M.decorators, 1, -1 do - add_to_end(rights, M.decorators[i]:icons_right_align(node)) + for i = #self.decorators, 1, -1 do + add_to_end(rights, self.decorators[i]:icons_right_align(node)) end if #rights > 0 then self.extmarks[self.index] = rights @@ -248,7 +265,7 @@ end function Builder:build_signs(node) -- first in priority order local sign_name - for _, d in ipairs(M.decorators) do + for _, d in ipairs(self.decorators) do sign_name = d:sign_name(node) if sign_name then self.signs[self.index] = sign_name @@ -300,8 +317,8 @@ function Builder:add_highlights(node) local icon_groups = {} local name_groups = {} local d, icon, name - for i = #M.decorators, 1, -1 do - d = M.decorators[i] + for i = #self.decorators, 1, -1 do + d = self.decorators[i] icon, name = d:groups_icon_name(node) table.insert(icon_groups, icon) table.insert(name_groups, name) @@ -366,10 +383,10 @@ function Builder:add_hidden_count_string(node, idx, num_children) if not node.open then return end - local hidden_count_string = M.opts.renderer.hidden_display(node.hidden_stats) + local hidden_count_string = self.hidden_display(node.hidden_stats) if hidden_count_string and hidden_count_string ~= "" then local indent_markers = pad.get_indent_markers(self.depth, idx or 0, num_children or 0, node, self.markers, 1) - local indent_width = M.opts.renderer.indent_width + local indent_width = self.opts.renderer.indent_width local indent_padding = string.rep(" ", indent_width) local indent_string = indent_padding .. indent_markers.str @@ -388,8 +405,7 @@ end ---@private function Builder:get_nodes_number(nodes) - local explorer = core.get_explorer() - if not explorer or not explorer.live_filter.filter then + if not self.explorer.live_filter.filter then return #nodes end @@ -405,7 +421,7 @@ end ---@private function Builder:build_lines(node) if not node then - node = core.get_explorer() + node = self.explorer end local num_children = self:get_nodes_number(node.nodes) local idx = 1 @@ -424,30 +440,29 @@ end ---@return string function Builder:format_root_name(root_label) if type(root_label) == "function" then - local label = root_label(self.root_cwd) + local label = root_label(self.explorer.absolute_path) if type(label) == "string" then return label end elseif type(root_label) == "string" then - return utils.path_remove_trailing(vim.fn.fnamemodify(self.root_cwd, root_label)) + return utils.path_remove_trailing(vim.fn.fnamemodify(self.explorer.absolute_path, root_label)) end return "???" end ---@private function Builder:build_header() - local explorer = core.get_explorer() - if view.is_root_folder_visible(core.get_cwd()) then - local root_name = self:format_root_name(M.opts.renderer.root_folder_label) + if view.is_root_folder_visible(self.explorer.absolute_path) then + local root_name = self:format_root_name(self.opts.renderer.root_folder_label) table.insert(self.lines, root_name) self:insert_highlight({ "NvimTreeRootFolder" }, 0, string.len(root_name)) self.index = 1 end - if explorer and explorer.live_filter.filter then - local filter_line = string.format("%s/%s/", M.opts.live_filter.prefix, explorer.live_filter.filter) + if self.explorer.live_filter.filter then + local filter_line = string.format("%s/%s/", self.opts.live_filter.prefix, self.explorer.live_filter.filter) table.insert(self.lines, filter_line) - local prefix_length = string.len(M.opts.live_filter.prefix) + local prefix_length = string.len(self.opts.live_filter.prefix) self:insert_highlight({ "NvimTreeLiveFilterPrefix" }, 0, prefix_length) self:insert_highlight({ "NvimTreeLiveFilterValue" }, prefix_length, string.len(filter_line)) self.index = self.index + 1 @@ -472,26 +487,28 @@ function Builder:build() return self end +---TODO refactor back to function; this was left here to reduce PR noise ---@param opts table -local setup_hidden_display_function = function(opts) +---@return fun(node: Node): string|nil +function Builder:setup_hidden_display_function(opts) local hidden_display = opts.renderer.hidden_display -- options are already validated, so ´hidden_display´ can ONLY be `string` or `function` if type(hidden_display) == "string" then if type(hidden_display) == "string" then if hidden_display == "none" then - opts.renderer.hidden_display = function() + return function() return nil end elseif hidden_display == "simple" then - opts.renderer.hidden_display = function(hidden_stats) + return function(hidden_stats) return utils.default_format_hidden_count(hidden_stats, true) end - elseif hidden_display == "all" then - opts.renderer.hidden_display = function(hidden_stats) + else -- "all" + return function(hidden_stats) return utils.default_format_hidden_count(hidden_stats, false) end end - elseif type(hidden_display) == "function" then - local safe_render = function(hidden_stats) + else -- "function + return function(hidden_stats) -- In case of missing field such as live_filter we zero it, otherwise keep field as is hidden_stats = vim.tbl_deep_extend("force", { live_filter = 0, @@ -509,26 +526,7 @@ local setup_hidden_display_function = function(opts) end return result end - - opts.renderer.hidden_display = safe_render end end -function Builder.setup(opts) - setup_hidden_display_function(opts) - M.opts = opts - - -- priority order - M.decorators = { - DecoratorCut:new(opts), - DecoratorCopied:new(opts), - DecoratorDiagnostics:new(opts), - DecoratorBookmarks:new(opts), - DecoratorModified:new(opts), - DecoratorHidden:new(opts), - DecoratorOpened:new(opts), - DecoratorGit:new(opts), - } -end - return Builder diff --git a/lua/nvim-tree/renderer/components/init.lua b/lua/nvim-tree/renderer/components/init.lua new file mode 100644 index 00000000000..5cdf6b22a84 --- /dev/null +++ b/lua/nvim-tree/renderer/components/init.lua @@ -0,0 +1,15 @@ +local M = {} + +M.diagnostics = require "nvim-tree.renderer.components.diagnostics" +M.full_name = require "nvim-tree.renderer.components.full-name" +M.icons = require "nvim-tree.renderer.components.icons" +M.padding = require "nvim-tree.renderer.components.padding" + +function M.setup(opts) + M.diagnostics.setup(opts) + M.full_name.setup(opts) + M.icons.setup(opts) + M.padding.setup(opts) +end + +return M diff --git a/lua/nvim-tree/renderer/decorator/bookmarks.lua b/lua/nvim-tree/renderer/decorator/bookmarks.lua index 56065fd7895..29f0f649743 100644 --- a/lua/nvim-tree/renderer/decorator/bookmarks.lua +++ b/lua/nvim-tree/renderer/decorator/bookmarks.lua @@ -1,18 +1,18 @@ -local core = require "nvim-tree.core" - local HL_POSITION = require("nvim-tree.enum").HL_POSITION local ICON_PLACEMENT = require("nvim-tree.enum").ICON_PLACEMENT local Decorator = require "nvim-tree.renderer.decorator" ----@class DecoratorBookmarks: Decorator +---@class (exact) DecoratorBookmarks: Decorator ---@field icon HighlightedString local DecoratorBookmarks = Decorator:new() ---@param opts table +---@param explorer Explorer ---@return DecoratorBookmarks -function DecoratorBookmarks:new(opts) +function DecoratorBookmarks:new(opts, explorer) local o = Decorator.new(self, { + explorer = explorer, enabled = true, hl_pos = HL_POSITION[opts.renderer.highlight_bookmarks] or HL_POSITION.none, icon_placement = ICON_PLACEMENT[opts.renderer.icons.bookmarks_placement] or ICON_PLACEMENT.none, @@ -34,7 +34,7 @@ end ---@param node Node ---@return HighlightedString[]|nil icons function DecoratorBookmarks:calculate_icons(node) - if core.get_explorer() and core.get_explorer().marks:get(node) then + if self.explorer.marks:get(node) then return { self.icon } end end @@ -43,7 +43,7 @@ end ---@param node Node ---@return string|nil group function DecoratorBookmarks:calculate_highlight(node) - if self.hl_pos ~= HL_POSITION.none and core.get_explorer() and core.get_explorer().marks:get(node) then + if self.hl_pos ~= HL_POSITION.none and self.explorer.marks:get(node) then return "NvimTreeBookmarkHL" end end diff --git a/lua/nvim-tree/renderer/decorator/copied.lua b/lua/nvim-tree/renderer/decorator/copied.lua index ba187e7d5be..3d7e131fc7e 100644 --- a/lua/nvim-tree/renderer/decorator/copied.lua +++ b/lua/nvim-tree/renderer/decorator/copied.lua @@ -1,19 +1,19 @@ -local core = require "nvim-tree.core" - local HL_POSITION = require("nvim-tree.enum").HL_POSITION local ICON_PLACEMENT = require("nvim-tree.enum").ICON_PLACEMENT local Decorator = require "nvim-tree.renderer.decorator" ----@class DecoratorCopied: Decorator +---@class (exact) DecoratorCopied: Decorator ---@field enabled boolean ---@field icon HighlightedString|nil local DecoratorCopied = Decorator:new() ---@param opts table +---@param explorer Explorer ---@return DecoratorCopied -function DecoratorCopied:new(opts) +function DecoratorCopied:new(opts, explorer) local o = Decorator.new(self, { + explorer = explorer, enabled = true, hl_pos = HL_POSITION[opts.renderer.highlight_clipboard] or HL_POSITION.none, icon_placement = ICON_PLACEMENT.none, @@ -27,7 +27,7 @@ end ---@param node Node ---@return string|nil group function DecoratorCopied:calculate_highlight(node) - if self.hl_pos ~= HL_POSITION.none and core.get_explorer() and core.get_explorer().clipboard:is_copied(node) then + if self.hl_pos ~= HL_POSITION.none and self.explorer.clipboard:is_copied(node) then return "NvimTreeCopiedHL" end end diff --git a/lua/nvim-tree/renderer/decorator/cut.lua b/lua/nvim-tree/renderer/decorator/cut.lua index 615168f8907..8710e36f9a1 100644 --- a/lua/nvim-tree/renderer/decorator/cut.lua +++ b/lua/nvim-tree/renderer/decorator/cut.lua @@ -1,19 +1,19 @@ -local core = require "nvim-tree.core" - local HL_POSITION = require("nvim-tree.enum").HL_POSITION local ICON_PLACEMENT = require("nvim-tree.enum").ICON_PLACEMENT local Decorator = require "nvim-tree.renderer.decorator" ----@class DecoratorCut: Decorator +---@class (exact) DecoratorCut: Decorator ---@field enabled boolean ---@field icon HighlightedString|nil local DecoratorCut = Decorator:new() ---@param opts table +---@param explorer Explorer ---@return DecoratorCut -function DecoratorCut:new(opts) +function DecoratorCut:new(opts, explorer) local o = Decorator.new(self, { + explorer = explorer, enabled = true, hl_pos = HL_POSITION[opts.renderer.highlight_clipboard] or HL_POSITION.none, icon_placement = ICON_PLACEMENT.none, @@ -27,7 +27,7 @@ end ---@param node Node ---@return string|nil group function DecoratorCut:calculate_highlight(node) - if self.hl_pos ~= HL_POSITION.none and core.get_explorer() and core.get_explorer().clipboard:is_cut(node) then + if self.hl_pos ~= HL_POSITION.none and self.explorer.clipboard:is_cut(node) then return "NvimTreeCutHL" end end diff --git a/lua/nvim-tree/renderer/decorator/diagnostics.lua b/lua/nvim-tree/renderer/decorator/diagnostics.lua index d18ff4d43d2..770fe07473e 100644 --- a/lua/nvim-tree/renderer/decorator/diagnostics.lua +++ b/lua/nvim-tree/renderer/decorator/diagnostics.lua @@ -32,14 +32,16 @@ local ICON_KEYS = { ["hint"] = vim.diagnostic.severity.HINT, } ----@class DecoratorDiagnostics: Decorator +---@class (exact) DecoratorDiagnostics: Decorator ---@field icons HighlightedString[] local DecoratorDiagnostics = Decorator:new() ---@param opts table +---@param explorer Explorer ---@return DecoratorDiagnostics -function DecoratorDiagnostics:new(opts) +function DecoratorDiagnostics:new(opts, explorer) local o = Decorator.new(self, { + explorer = explorer, enabled = opts.diagnostics.enable, hl_pos = HL_POSITION[opts.renderer.highlight_diagnostics] or HL_POSITION.none, icon_placement = ICON_PLACEMENT[opts.renderer.icons.diagnostics_placement] or ICON_PLACEMENT.none, diff --git a/lua/nvim-tree/renderer/decorator/git.lua b/lua/nvim-tree/renderer/decorator/git.lua index de2477880bd..412d3361bc8 100644 --- a/lua/nvim-tree/renderer/decorator/git.lua +++ b/lua/nvim-tree/renderer/decorator/git.lua @@ -9,7 +9,7 @@ local Decorator = require "nvim-tree.renderer.decorator" ---@class HighlightedStringGit: HighlightedString ---@field ord number decreasing priority ----@class DecoratorGit: Decorator +---@class (exact) DecoratorGit: Decorator ---@field file_hl table by porcelain status e.g. "AM" ---@field folder_hl table by porcelain status ---@field icons_by_status HighlightedStringGit[] by human status @@ -17,9 +17,11 @@ local Decorator = require "nvim-tree.renderer.decorator" local DecoratorGit = Decorator:new() ---@param opts table +---@param explorer Explorer ---@return DecoratorGit -function DecoratorGit:new(opts) +function DecoratorGit:new(opts, explorer) local o = Decorator.new(self, { + explorer = explorer, enabled = opts.git.enable, hl_pos = HL_POSITION[opts.renderer.highlight_git] or HL_POSITION.none, icon_placement = ICON_PLACEMENT[opts.renderer.icons.git_placement] or ICON_PLACEMENT.none, diff --git a/lua/nvim-tree/renderer/decorator/hidden.lua b/lua/nvim-tree/renderer/decorator/hidden.lua index bf21c2d25cc..f7aa58b57e4 100644 --- a/lua/nvim-tree/renderer/decorator/hidden.lua +++ b/lua/nvim-tree/renderer/decorator/hidden.lua @@ -3,14 +3,16 @@ local ICON_PLACEMENT = require("nvim-tree.enum").ICON_PLACEMENT local explorer_node = require "nvim-tree.explorer.node" local Decorator = require "nvim-tree.renderer.decorator" ----@class DecoratorHidden: Decorator +---@class (exact) DecoratorHidden: Decorator ---@field icon HighlightedString|nil local DecoratorHidden = Decorator:new() ---@param opts table +---@param explorer Explorer ---@return DecoratorHidden -function DecoratorHidden:new(opts) +function DecoratorHidden:new(opts, explorer) local o = Decorator.new(self, { + explorer = explorer, enabled = true, hl_pos = HL_POSITION[opts.renderer.highlight_hidden] or HL_POSITION.none, icon_placement = ICON_PLACEMENT[opts.renderer.icons.hidden_placement] or ICON_PLACEMENT.none, diff --git a/lua/nvim-tree/renderer/decorator/init.lua b/lua/nvim-tree/renderer/decorator/init.lua index f2d047767b5..92fcc579b38 100644 --- a/lua/nvim-tree/renderer/decorator/init.lua +++ b/lua/nvim-tree/renderer/decorator/init.lua @@ -1,7 +1,9 @@ local HL_POSITION = require("nvim-tree.enum").HL_POSITION local ICON_PLACEMENT = require("nvim-tree.enum").ICON_PLACEMENT ----@class Decorator +---@class (exact) Decorator +---@field private __index? table +---@field protected explorer Explorer ---@field protected enabled boolean ---@field protected hl_pos HL_POSITION ---@field protected icon_placement ICON_PLACEMENT @@ -11,6 +13,7 @@ local Decorator = {} ---@return Decorator function Decorator:new(o) o = o or {} + setmetatable(o, self) self.__index = self diff --git a/lua/nvim-tree/renderer/decorator/modified.lua b/lua/nvim-tree/renderer/decorator/modified.lua index 1ec546d1d65..e20433d75aa 100644 --- a/lua/nvim-tree/renderer/decorator/modified.lua +++ b/lua/nvim-tree/renderer/decorator/modified.lua @@ -5,14 +5,16 @@ local ICON_PLACEMENT = require("nvim-tree.enum").ICON_PLACEMENT local Decorator = require "nvim-tree.renderer.decorator" ----@class DecoratorModified: Decorator +---@class (exact) DecoratorModified: Decorator ---@field icon HighlightedString|nil local DecoratorModified = Decorator:new() ---@param opts table +---@param explorer Explorer ---@return DecoratorModified -function DecoratorModified:new(opts) +function DecoratorModified:new(opts, explorer) local o = Decorator.new(self, { + explorer = explorer, enabled = opts.modified.enable, hl_pos = HL_POSITION[opts.renderer.highlight_modified] or HL_POSITION.none, icon_placement = ICON_PLACEMENT[opts.renderer.icons.modified_placement] or ICON_PLACEMENT.none, diff --git a/lua/nvim-tree/renderer/decorator/opened.lua b/lua/nvim-tree/renderer/decorator/opened.lua index 848faae42e6..9b3f2de87de 100644 --- a/lua/nvim-tree/renderer/decorator/opened.lua +++ b/lua/nvim-tree/renderer/decorator/opened.lua @@ -5,15 +5,17 @@ local ICON_PLACEMENT = require("nvim-tree.enum").ICON_PLACEMENT local Decorator = require "nvim-tree.renderer.decorator" ----@class DecoratorOpened: Decorator +---@class (exact) DecoratorOpened: Decorator ---@field enabled boolean ---@field icon HighlightedString|nil local DecoratorOpened = Decorator:new() ---@param opts table +---@param explorer Explorer ---@return DecoratorOpened -function DecoratorOpened:new(opts) +function DecoratorOpened:new(opts, explorer) local o = Decorator.new(self, { + explorer = explorer, enabled = true, hl_pos = HL_POSITION[opts.renderer.highlight_opened_files] or HL_POSITION.none, icon_placement = ICON_PLACEMENT.none, diff --git a/lua/nvim-tree/renderer/init.lua b/lua/nvim-tree/renderer/init.lua index 729164aea5b..46e73186bc8 100644 --- a/lua/nvim-tree/renderer/init.lua +++ b/lua/nvim-tree/renderer/init.lua @@ -1,14 +1,10 @@ -local core = require "nvim-tree.core" local log = require "nvim-tree.log" local view = require "nvim-tree.view" local events = require "nvim-tree.events" -local _padding = require "nvim-tree.renderer.components.padding" local icon_component = require "nvim-tree.renderer.components.icons" -local full_name = require "nvim-tree.renderer.components.full-name" -local Builder = require "nvim-tree.renderer.builder" -local M = {} +local Builder = require "nvim-tree.renderer.builder" local SIGN_GROUP = "NvimTreeRendererSigns" @@ -16,11 +12,36 @@ local namespace_highlights_id = vim.api.nvim_create_namespace "NvimTreeHighlight local namespace_extmarks_id = vim.api.nvim_create_namespace "NvimTreeExtmarks" local namespace_virtual_lines_id = vim.api.nvim_create_namespace "NvimTreeVirtualLines" +---@class (exact) Renderer +---@field private __index? table +---@field private opts table user options +---@field private explorer Explorer +---@field private builder Builder +local Renderer = {} + +---@param opts table user options +---@param explorer Explorer +---@return Renderer +function Renderer:new(opts, explorer) + ---@type Renderer + local o = { + opts = opts, + explorer = explorer, + builder = Builder:new(opts, explorer), + } + + setmetatable(o, self) + self.__index = self + + return o +end + +---@private ---@param bufnr number ---@param lines string[] ---@param hl_args AddHighlightArgs[] ---@param signs string[] -local function _draw(bufnr, lines, hl_args, signs, extmarks, virtual_lines) +function Renderer:_draw(bufnr, lines, hl_args, signs, extmarks, virtual_lines) if vim.fn.has "nvim-0.10" == 1 then vim.api.nvim_set_option_value("modifiable", true, { buf = bufnr }) else @@ -28,7 +49,7 @@ local function _draw(bufnr, lines, hl_args, signs, extmarks, virtual_lines) end vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, lines) - M.render_hl(bufnr, hl_args) + self:render_hl(bufnr, hl_args) if vim.fn.has "nvim-0.10" == 1 then vim.api.nvim_set_option_value("modifiable", false, { buf = bufnr }) @@ -62,7 +83,8 @@ local function _draw(bufnr, lines, hl_args, signs, extmarks, virtual_lines) end end -function M.render_hl(bufnr, hl) +---@private +function Renderer:render_hl(bufnr, hl) if not bufnr or not vim.api.nvim_buf_is_loaded(bufnr) then return end @@ -76,9 +98,9 @@ function M.render_hl(bufnr, hl) end end -function M.draw() +function Renderer:draw() local bufnr = view.get_bufnr() - if not core.get_explorer() or not bufnr or not vim.api.nvim_buf_is_loaded(bufnr) then + if not bufnr or not vim.api.nvim_buf_is_loaded(bufnr) then return end @@ -87,9 +109,9 @@ function M.draw() local cursor = vim.api.nvim_win_get_cursor(view.get_winnr() or 0) icon_component.reset_config() - local builder = Builder:new():build() + local builder = Builder:new(self.opts, self.explorer):build() - _draw(bufnr, builder.lines, builder.hl_args, builder.signs, builder.extmarks, builder.virtual_lines) + self:_draw(bufnr, builder.lines, builder.hl_args, builder.signs, builder.extmarks, builder.virtual_lines) if cursor and #builder.lines >= cursor[1] then vim.api.nvim_win_set_cursor(view.get_winnr() or 0, cursor) @@ -102,14 +124,4 @@ function M.draw() events._dispatch_on_tree_rendered(bufnr, view.get_winnr()) end -function M.setup(opts) - M.config = opts.renderer - - _padding.setup(opts) - full_name.setup(opts) - icon_component.setup(opts) - - Builder.setup(opts) -end - -return M +return Renderer diff --git a/lua/nvim-tree/view.lua b/lua/nvim-tree/view.lua index 315da3d0d19..5e28cfb66f9 100644 --- a/lua/nvim-tree/view.lua +++ b/lua/nvim-tree/view.lua @@ -531,7 +531,12 @@ function M._prevent_buffer_override() vim.cmd "setlocal nowinfixwidth" vim.cmd "setlocal nowinfixheight" M.open { focus_tree = false } - require("nvim-tree.renderer").draw() + + local explorer = require("nvim-tree.core").get_explorer() + if explorer then + explorer.renderer:draw() + end + pcall(vim.api.nvim_win_close, curwin, { force = true }) -- to handle opening a file using :e when nvim-tree is on floating mode