From f495542e5e71186c03a5ff879475c3522bd6bff2 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Sat, 28 Mar 2026 12:14:50 +1100 Subject: [PATCH 01/22] perf(#3257): remove devicons setup --- .../renderer/components/devicons.lua | 35 ++++++++++++------- lua/nvim-tree/renderer/components/init.lua | 2 -- 2 files changed, 22 insertions(+), 15 deletions(-) diff --git a/lua/nvim-tree/renderer/components/devicons.lua b/lua/nvim-tree/renderer/components/devicons.lua index ad91d058c15..d5fd307c2cd 100644 --- a/lua/nvim-tree/renderer/components/devicons.lua +++ b/lua/nvim-tree/renderer/components/devicons.lua @@ -1,3 +1,5 @@ +local config = require("nvim-tree.config") + ---@alias devicons_get_icon fun(name: string, ext: string?, opts: table?): string?, string? ---@alias devicons_setup fun(opts: table?) @@ -6,22 +8,14 @@ ---@field get_icon devicons_get_icon local devicons -local M = {} +--One shot lazy discovery and setup done +local initialized = false ----Wrapper around nvim-web-devicons, nils if devicons not available ----@type devicons_get_icon -function M.get_icon(name, ext, opts) - if devicons then - return devicons.get_icon(name, ext, opts) - else - return nil, nil - end -end +local M = {} ---Attempt to use nvim-web-devicons if present and enabled for file or folder ----@param opts table -function M.setup(opts) - if opts.renderer.icons.show.file or opts.renderer.icons.show.folder then +local function initialize() + if config.g.renderer.icons.show.file or config.g.renderer.icons.show.folder then local ok, di = pcall(require, "nvim-web-devicons") if ok then devicons = di --[[@as DevIcons]] @@ -30,6 +24,21 @@ function M.setup(opts) devicons.setup() end end + initialized = true +end + +---Wrapper around nvim-web-devicons, nils if devicons not available +---@type devicons_get_icon +function M.get_icon(name, ext, opts) + if not initialized then + initialize() + end + + if devicons then + return devicons.get_icon(name, ext, opts) + else + return nil, nil + end end return M diff --git a/lua/nvim-tree/renderer/components/init.lua b/lua/nvim-tree/renderer/components/init.lua index a06827422dd..5ef3bbd6d8e 100644 --- a/lua/nvim-tree/renderer/components/init.lua +++ b/lua/nvim-tree/renderer/components/init.lua @@ -1,10 +1,8 @@ local M = {} -M.devicons = require("nvim-tree.renderer.components.devicons") M.padding = require("nvim-tree.renderer.components.padding") function M.setup(opts) - M.devicons.setup(opts) M.padding.setup(opts) end From 0042f7d33c3fe466e5ac3036209c84a45abcc468 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Sat, 28 Mar 2026 12:49:51 +1100 Subject: [PATCH 02/22] perf(#3257): remove padding setup --- lua/nvim-tree.lua | 1 - lua/nvim-tree/config.lua | 15 +++++ lua/nvim-tree/renderer/components/init.lua | 9 --- lua/nvim-tree/renderer/components/padding.lua | 55 ++++++------------- 4 files changed, 33 insertions(+), 47 deletions(-) delete mode 100644 lua/nvim-tree/renderer/components/init.lua diff --git a/lua/nvim-tree.lua b/lua/nvim-tree.lua index 63cf5d1c154..a4ab3f2cd92 100644 --- a/lua/nvim-tree.lua +++ b/lua/nvim-tree.lua @@ -289,7 +289,6 @@ function M.setup(config_user) end require("nvim-tree.appearance").setup() - require("nvim-tree.renderer.components").setup(config.g) require("nvim-tree.view-state").initialize() diff --git a/lua/nvim-tree/config.lua b/lua/nvim-tree/config.lua index 8e819961a6d..5c3403d36d7 100644 --- a/lua/nvim-tree/config.lua +++ b/lua/nvim-tree/config.lua @@ -511,6 +511,21 @@ local function process_config(g) -- Open -- g.actions.open_file.window_picker.chars = tostring(g.actions.open_file.window_picker.chars):upper() + + -- + -- Padding + -- + if g.renderer.indent_width < 1 then + g.renderer.indent_width = 1 + end + for k, v in pairs(g.renderer.indent_markers.icons) do + if #v == 0 then + g.renderer.indent_markers.icons[k] = " " + else + -- return the first character from the UTF-8 encoded string; we may use utf8.codes from Lua 5.3 when available + g.renderer.indent_markers.icons[k] = v:match("[%z\1-\127\194-\244][\128-\191]*") + end + end end ---Validate user config and migrate legacy. diff --git a/lua/nvim-tree/renderer/components/init.lua b/lua/nvim-tree/renderer/components/init.lua deleted file mode 100644 index 5ef3bbd6d8e..00000000000 --- a/lua/nvim-tree/renderer/components/init.lua +++ /dev/null @@ -1,9 +0,0 @@ -local M = {} - -M.padding = require("nvim-tree.renderer.components.padding") - -function M.setup(opts) - M.padding.setup(opts) -end - -return M diff --git a/lua/nvim-tree/renderer/components/padding.lua b/lua/nvim-tree/renderer/components/padding.lua index be84ae0b9de..9e04addfdaf 100644 --- a/lua/nvim-tree/renderer/components/padding.lua +++ b/lua/nvim-tree/renderer/components/padding.lua @@ -1,3 +1,4 @@ +local config = require("nvim-tree.config") local DirectoryNode = require("nvim-tree.node.directory") local M = {} @@ -27,21 +28,21 @@ local function get_padding_indent_markers(depth, idx, nodes_number, markers, wit if depth > 0 then local has_folder_sibling = check_siblings_for_folder(node, with_arrows) - local indent = string.rep(" ", M.config.indent_width - 1) + local indent = string.rep(" ", config.g.renderer.indent_width - 1) markers[depth] = idx ~= nodes_number for i = 1, depth - early_stop do local glyph if idx == nodes_number and i == depth then - local bottom_width = M.config.indent_width - 2 + (with_arrows and not inline_arrows and has_folder_sibling and 2 or 0) - glyph = M.config.indent_markers.icons.corner - .. string.rep(M.config.indent_markers.icons.bottom, bottom_width) - .. (M.config.indent_width > 1 and " " or "") + local bottom_width = config.g.renderer.indent_width - 2 + (with_arrows and not inline_arrows and has_folder_sibling and 2 or 0) + glyph = config.g.renderer.indent_markers.icons.corner + .. string.rep(config.g.renderer.indent_markers.icons.bottom, bottom_width) + .. (config.g.renderer.indent_width > 1 and " " or "") elseif markers[i] and i == depth then - glyph = M.config.indent_markers.icons.item .. indent + glyph = config.g.renderer.indent_markers.icons.item .. indent elseif markers[i] then - glyph = M.config.indent_markers.icons.edge .. indent + glyph = config.g.renderer.indent_markers.icons.edge .. indent else - glyph = M.config.indent_markers.icons.none .. indent + glyph = config.g.renderer.indent_markers.icons.none .. indent end if not with_arrows or (inline_arrows and (depth ~= i or not node.nodes)) then @@ -68,10 +69,10 @@ end function M.get_indent_markers(depth, idx, nodes_number, node, markers, early_stop) local str = "" - local show_arrows = M.config.icons.show.folder_arrow - local show_markers = M.config.indent_markers.enable - local inline_arrows = M.config.indent_markers.inline_arrows - local indent_width = M.config.indent_width + local show_arrows = config.g.renderer.icons.show.folder_arrow + local show_markers = config.g.renderer.indent_markers.enable + local inline_arrows = config.g.renderer.indent_markers.inline_arrows + local indent_width = config.g.renderer.indent_width if show_markers then str = str .. get_padding_indent_markers(depth, idx, nodes_number, markers, show_arrows, inline_arrows, node, early_stop or 0) @@ -85,7 +86,7 @@ end ---@param node Node ---@return nvim_tree.api.highlighted_string[]? function M.get_arrows(node) - if not M.config.icons.show.folder_arrow then + if not config.g.renderer.icons.show.folder_arrow then return end @@ -95,38 +96,18 @@ function M.get_arrows(node) local dir = node:as(DirectoryNode) if dir then if dir.open then - str = M.config.icons.glyphs.folder["arrow_open"] .. M.config.icons.padding.folder_arrow + str = config.g.renderer.icons.glyphs.folder["arrow_open"] .. config.g.renderer.icons.padding.folder_arrow hl = "NvimTreeFolderArrowOpen" else - str = M.config.icons.glyphs.folder["arrow_closed"] .. M.config.icons.padding.folder_arrow + str = config.g.renderer.icons.glyphs.folder["arrow_closed"] .. config.g.renderer.icons.padding.folder_arrow end - elseif M.config.indent_markers.enable then + elseif config.g.renderer.indent_markers.enable then str = "" else - str = " " .. string.rep(" ", #M.config.icons.padding.folder_arrow) + str = " " .. string.rep(" ", #config.g.renderer.icons.padding.folder_arrow) end return { str = str, hl = { hl } } end -function M.setup(opts) - M.config = opts.renderer - - if M.config.indent_width < 1 then - M.config.indent_width = 1 - end - - local function check_marker(symbol) - if #symbol == 0 then - return " " - end - -- return the first character from the UTF-8 encoded string; we may use utf8.codes from Lua 5.3 when available - return symbol:match("[%z\1-\127\194-\244][\128-\191]*") - end - - for k, v in pairs(M.config.indent_markers.icons) do - M.config.indent_markers.icons[k] = check_marker(v) - end -end - return M From f917e9d50912cc251f2547df3c9d301e8686ba58 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Sat, 28 Mar 2026 13:24:43 +1100 Subject: [PATCH 03/22] perf(#3257): remove appearance and log setup --- lua/nvim-tree.lua | 4 ++-- lua/nvim-tree/appearance/init.lua | 3 ++- lua/nvim-tree/explorer/init.lua | 2 +- lua/nvim-tree/log.lua | 11 +++++++---- 4 files changed, 12 insertions(+), 8 deletions(-) diff --git a/lua/nvim-tree.lua b/lua/nvim-tree.lua index a4ab3f2cd92..0bf4fe91f30 100644 --- a/lua/nvim-tree.lua +++ b/lua/nvim-tree.lua @@ -281,14 +281,14 @@ function M.setup(config_user) manage_netrw() - require("nvim-tree.log").setup(config.g) + require("nvim-tree.log").start() if log.enabled("config") then log.line("config", "default config + user") log.raw("config", "%s\n", vim.inspect(config.g)) end - require("nvim-tree.appearance").setup() + require("nvim-tree.appearance").define_hi() require("nvim-tree.view-state").initialize() diff --git a/lua/nvim-tree/appearance/init.lua b/lua/nvim-tree/appearance/init.lua index 61714af644e..1b8d27cedc1 100644 --- a/lua/nvim-tree/appearance/init.lua +++ b/lua/nvim-tree/appearance/init.lua @@ -182,7 +182,8 @@ M.LEGACY_LINKS = { NvimTreeDiagnosticHintFolderHL = "NvimTreeLspDiagnosticsHintFolderText", } -function M.setup() +---Create all highlight groups and links. Idempotent. +function M.define_hi() -- non-linked for _, g in ipairs(M.HIGHLIGHT_GROUPS) do if g.def then diff --git a/lua/nvim-tree/explorer/init.lua b/lua/nvim-tree/explorer/init.lua index eb9b5f5d097..3559a74cf5c 100644 --- a/lua/nvim-tree/explorer/init.lua +++ b/lua/nvim-tree/explorer/init.lua @@ -88,7 +88,7 @@ function Explorer:create_autocmds() vim.api.nvim_create_autocmd("ColorScheme", { group = self.augroup_id, callback = function() - appearance.setup() + appearance.define_hi() view.reset_winhl() self.renderer:draw() end, diff --git a/lua/nvim-tree/log.lua b/lua/nvim-tree/log.lua index 9665c1335e6..ff5686061fd 100644 --- a/lua/nvim-tree/log.lua +++ b/lua/nvim-tree/log.lua @@ -1,3 +1,5 @@ +local config = require("nvim-tree.config") + ---@alias LogTypes "all" | "config" | "copy_paste" | "dev" | "diagnostics" | "git" | "profile" | "watcher" ---@type table @@ -110,11 +112,12 @@ function M.enabled(typ) return file_path ~= nil and (types[typ] or types.all) end -function M.setup(opts) - if opts.log and opts.log.enable and opts.log.types then - types = opts.log.types +--- Create the log file and enable logging, if globally configured +function M.start() + if config.g.log and config.g.log.enable and config.g.log.types then + types = config.g.log.types file_path = string.format("%s/nvim-tree.log", vim.fn.stdpath("log"), os.date("%H:%M:%S"), vim.env.USER) - if opts.log.truncate then + if config.g.log.truncate then os.remove(file_path) end require("nvim-tree.notify").debug("nvim-tree.lua logging to " .. file_path) From 2036eecc4b8e553843c71e343bf05a0b839b6473 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Sat, 28 Mar 2026 13:28:52 +1100 Subject: [PATCH 04/22] perf(#3257): remove appearance setup --- lua/nvim-tree.lua | 2 +- lua/nvim-tree/appearance/init.lua | 2 +- lua/nvim-tree/explorer/init.lua | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lua/nvim-tree.lua b/lua/nvim-tree.lua index 0bf4fe91f30..2fb77ed0a16 100644 --- a/lua/nvim-tree.lua +++ b/lua/nvim-tree.lua @@ -288,7 +288,7 @@ function M.setup(config_user) log.raw("config", "%s\n", vim.inspect(config.g)) end - require("nvim-tree.appearance").define_hi() + require("nvim-tree.appearance").set_hl() require("nvim-tree.view-state").initialize() diff --git a/lua/nvim-tree/appearance/init.lua b/lua/nvim-tree/appearance/init.lua index 1b8d27cedc1..9190ad07d49 100644 --- a/lua/nvim-tree/appearance/init.lua +++ b/lua/nvim-tree/appearance/init.lua @@ -183,7 +183,7 @@ M.LEGACY_LINKS = { } ---Create all highlight groups and links. Idempotent. -function M.define_hi() +function M.set_hl() -- non-linked for _, g in ipairs(M.HIGHLIGHT_GROUPS) do if g.def then diff --git a/lua/nvim-tree/explorer/init.lua b/lua/nvim-tree/explorer/init.lua index 3559a74cf5c..d33be5f10bf 100644 --- a/lua/nvim-tree/explorer/init.lua +++ b/lua/nvim-tree/explorer/init.lua @@ -88,7 +88,7 @@ function Explorer:create_autocmds() vim.api.nvim_create_autocmd("ColorScheme", { group = self.augroup_id, callback = function() - appearance.define_hi() + appearance.set_hl() view.reset_winhl() self.renderer:draw() end, From 68182509696d6847ab73c9e6ed2f277603e9f962 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Sat, 28 Mar 2026 13:31:14 +1100 Subject: [PATCH 05/22] perf(#3257): remove rename-file setup --- lua/nvim-tree/actions/fs/rename-file.lua | 4 ---- 1 file changed, 4 deletions(-) diff --git a/lua/nvim-tree/actions/fs/rename-file.lua b/lua/nvim-tree/actions/fs/rename-file.lua index 0b4f22ac1d7..0740b813841 100644 --- a/lua/nvim-tree/actions/fs/rename-file.lua +++ b/lua/nvim-tree/actions/fs/rename-file.lua @@ -192,8 +192,4 @@ function M.rename_full(node) prompt_to_rename(node, ":p") end -function M.setup(opts) - config.g.filesystem_watchers = opts.filesystem_watchers -end - return M From 77ed15f0457b4ab3bec6897d6575b5bfcb1332fb Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Mon, 30 Mar 2026 14:32:49 +1100 Subject: [PATCH 06/22] perf(#3257): remove devicons setup --- .../renderer/components/devicons.lua | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/lua/nvim-tree/renderer/components/devicons.lua b/lua/nvim-tree/renderer/components/devicons.lua index d5fd307c2cd..5d7bd275161 100644 --- a/lua/nvim-tree/renderer/components/devicons.lua +++ b/lua/nvim-tree/renderer/components/devicons.lua @@ -13,25 +13,11 @@ local initialized = false local M = {} ----Attempt to use nvim-web-devicons if present and enabled for file or folder -local function initialize() - if config.g.renderer.icons.show.file or config.g.renderer.icons.show.folder then - local ok, di = pcall(require, "nvim-web-devicons") - if ok then - devicons = di --[[@as DevIcons]] - - -- does nothing if already called i.e. doesn't clobber previous user setup - devicons.setup() - end - end - initialized = true -end - ---Wrapper around nvim-web-devicons, nils if devicons not available ---@type devicons_get_icon function M.get_icon(name, ext, opts) if not initialized then - initialize() + M.initialize() end if devicons then @@ -41,4 +27,18 @@ function M.get_icon(name, ext, opts) end end +---Attempt to use nvim-web-devicons if present and enabled for file or folder +function M.initialize() + if config.g.renderer.icons.show.file or config.g.renderer.icons.show.folder then + local ok, di = pcall(require, "nvim-web-devicons") + if ok then + devicons = di --[[@as DevIcons]] + + -- does nothing if already called i.e. doesn't clobber previous user setup + devicons.setup() + end + end + initialized = true +end + return M From 50e7e4c78e73df887b9431c23178ad31c4c97fed Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Mon, 30 Mar 2026 14:50:52 +1100 Subject: [PATCH 07/22] perf(#3257): remove appearance setup --- lua/nvim-tree.lua | 2 +- lua/nvim-tree/appearance/init.lua | 2 +- lua/nvim-tree/explorer/init.lua | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lua/nvim-tree.lua b/lua/nvim-tree.lua index 2fb77ed0a16..509a99bd1cb 100644 --- a/lua/nvim-tree.lua +++ b/lua/nvim-tree.lua @@ -288,7 +288,7 @@ function M.setup(config_user) log.raw("config", "%s\n", vim.inspect(config.g)) end - require("nvim-tree.appearance").set_hl() + require("nvim-tree.appearance").highlight() require("nvim-tree.view-state").initialize() diff --git a/lua/nvim-tree/appearance/init.lua b/lua/nvim-tree/appearance/init.lua index 9190ad07d49..9918ca4dd0b 100644 --- a/lua/nvim-tree/appearance/init.lua +++ b/lua/nvim-tree/appearance/init.lua @@ -183,7 +183,7 @@ M.LEGACY_LINKS = { } ---Create all highlight groups and links. Idempotent. -function M.set_hl() +function M.highlight() -- non-linked for _, g in ipairs(M.HIGHLIGHT_GROUPS) do if g.def then diff --git a/lua/nvim-tree/explorer/init.lua b/lua/nvim-tree/explorer/init.lua index d33be5f10bf..84af434edba 100644 --- a/lua/nvim-tree/explorer/init.lua +++ b/lua/nvim-tree/explorer/init.lua @@ -88,7 +88,7 @@ function Explorer:create_autocmds() vim.api.nvim_create_autocmd("ColorScheme", { group = self.augroup_id, callback = function() - appearance.set_hl() + appearance.highlight() view.reset_winhl() self.renderer:draw() end, From b7b1b980eeb6608022a6cc72f85741cbbc89304b Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Mon, 30 Mar 2026 14:59:01 +1100 Subject: [PATCH 08/22] perf(#3257): inline require legacy notify --- lua/nvim-tree/legacy.lua | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/lua/nvim-tree/legacy.lua b/lua/nvim-tree/legacy.lua index 7d42338abd5..ed432c51ed3 100644 --- a/lua/nvim-tree/legacy.lua +++ b/lua/nvim-tree/legacy.lua @@ -1,5 +1,3 @@ -local notify = require("nvim-tree.notify") - local M = {} --- Create empty sub-tables if not present @@ -120,25 +118,32 @@ end ---@param u nvim_tree.config user supplied subset of config local function deprecated_config(u) if type(u.view) == "table" and u.view.hide_root_folder then - notify.info("view.hide_root_folder is deprecated, please set renderer.root_folder_label = false") + require("nvim-tree.notify").info( + "view.hide_root_folder is deprecated, please set renderer.root_folder_label = false" + ) end end ---@param u nvim_tree.config user supplied subset of config local function removed_config(u) if u.auto_close then - notify.warn("auto close feature has been removed: https://github.com/nvim-tree/nvim-tree.lua/wiki/Auto-Close") + require("nvim-tree.notify").warn( + "auto close feature has been removed: https://github.com/nvim-tree/nvim-tree.lua/wiki/Auto-Close" + ) u["auto_close"] = nil end if u.focus_empty_on_setup then - notify.warn("focus_empty_on_setup has been removed: https://github.com/nvim-tree/nvim-tree.lua/wiki/Open-At-Startup") + require("nvim-tree.notify").warn( + "focus_empty_on_setup has been removed: https://github.com/nvim-tree/nvim-tree.lua/wiki/Open-At-Startup" + ) u["focus_empty_on_setup"] = nil end if u.create_in_closed_folder then - notify.warn( - "create_in_closed_folder has been removed and is now the default behaviour. You may use api.fs.create to add a file under your desired node.") + require("nvim-tree.notify").warn( + "create_in_closed_folder has been removed and is now the default behaviour. You may use api.fs.create to add a file under your desired node." + ) end u["create_in_closed_folder"] = nil end From bb845a651e7db47bd246318a3819867a5bb5688b Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Mon, 30 Mar 2026 15:02:51 +1100 Subject: [PATCH 09/22] perf(#3257): inline require events notify --- lua/nvim-tree/events.lua | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lua/nvim-tree/events.lua b/lua/nvim-tree/events.lua index 85e455ece52..ebabd2c4137 100644 --- a/lua/nvim-tree/events.lua +++ b/lua/nvim-tree/events.lua @@ -1,4 +1,3 @@ -local notify = require("nvim-tree.notify") local Event = require("nvim-tree._meta.api.events").Event local M = {} @@ -25,7 +24,7 @@ local function dispatch(event_name, payload) for _, handler in pairs(get_handlers(event_name)) do local success, error = pcall(handler, payload) if not success then - notify.error("Handler for event " .. event_name .. " errored. " .. vim.inspect(error)) + require("nvim-tree.notify").error("Handler for event " .. event_name .. " errored. " .. vim.inspect(error)) end end end From cc6bcda1686c9ad2268f075211422bec22ade7ab Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Mon, 30 Mar 2026 15:15:41 +1100 Subject: [PATCH 10/22] perf(#3257): inline require log notify --- lua/nvim-tree.lua | 2 +- lua/nvim-tree/log.lua | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/lua/nvim-tree.lua b/lua/nvim-tree.lua index 509a99bd1cb..c07c76cf7a4 100644 --- a/lua/nvim-tree.lua +++ b/lua/nvim-tree.lua @@ -281,7 +281,7 @@ function M.setup(config_user) manage_netrw() - require("nvim-tree.log").start() + log.start() if log.enabled("config") then log.line("config", "default config + user") diff --git a/lua/nvim-tree/log.lua b/lua/nvim-tree/log.lua index ff5686061fd..a564e3ca1bc 100644 --- a/lua/nvim-tree/log.lua +++ b/lua/nvim-tree/log.lua @@ -120,7 +120,9 @@ function M.start() if config.g.log.truncate then os.remove(file_path) end - require("nvim-tree.notify").debug("nvim-tree.lua logging to " .. file_path) + if config.g.notify.threshold <= vim.log.levels.DEBUG then + require("nvim-tree.notify").debug("nvim-tree.lua logging to " .. file_path) + end end end From 38916ac27f26296f3dd0fd695defc29653c92fb9 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Sat, 28 Mar 2026 15:12:25 +1100 Subject: [PATCH 11/22] perf(#3253): extract change-root --- lua/nvim-tree.lua | 68 +------------------- lua/nvim-tree/actions/tree/change-root.lua | 74 ++++++++++++++++++++++ lua/nvim-tree/actions/tree/find-file.lua | 3 +- lua/nvim-tree/actions/tree/open.lua | 3 +- lua/nvim-tree/actions/tree/toggle.lua | 3 +- lua/nvim-tree/config.lua | 9 ++- 6 files changed, 89 insertions(+), 71 deletions(-) create mode 100644 lua/nvim-tree/actions/tree/change-root.lua diff --git a/lua/nvim-tree.lua b/lua/nvim-tree.lua index c07c76cf7a4..110b624209f 100644 --- a/lua/nvim-tree.lua +++ b/lua/nvim-tree.lua @@ -9,9 +9,7 @@ local core = require("nvim-tree.core") local notify = require("nvim-tree.notify") local config = require("nvim-tree.config") -local M = { - init_root = "", -} +local M = {} --- Helper function to execute some explorer method safely ---@param fn string # key of explorer @@ -24,68 +22,6 @@ local function explorer_fn(fn, ...) end end ---- Update the tree root to a directory or the directory containing ----@param path string relative or absolute ----@param bufnr number|nil -function M.change_root(path, bufnr) - -- skip if current file is in ignore_list - if type(bufnr) == "number" then - local ft - - if vim.fn.has("nvim-0.10") == 1 then - ft = vim.api.nvim_get_option_value("filetype", { buf = bufnr }) or "" - else - ft = vim.api.nvim_buf_get_option(bufnr, "filetype") or "" ---@diagnostic disable-line: deprecated - end - - for _, value in pairs(config.g.update_focused_file.update_root.ignore_list) do - if utils.str_find(path, value) or utils.str_find(ft, value) then - return - end - end - end - - -- don't find inexistent - if vim.fn.filereadable(path) == 0 then - return - end - - local cwd = core.get_cwd() - if cwd == nil then - return - end - - local vim_cwd = vim.fn.getcwd() - - -- test if in vim_cwd - if utils.path_relative(path, vim_cwd) ~= path then - if vim_cwd ~= cwd then - explorer_fn("change_dir", vim_cwd) - end - return - end - -- test if in cwd - if utils.path_relative(path, cwd) ~= path then - return - end - - -- otherwise test M.init_root - if config.g.prefer_startup_root and utils.path_relative(path, M.init_root) ~= path then - explorer_fn("change_dir", M.init_root) - return - end - -- otherwise root_dirs - for _, dir in pairs(config.g.root_dirs) do - dir = vim.fn.fnamemodify(dir, ":p") - if utils.path_relative(path, dir) ~= path then - explorer_fn("change_dir", dir) - return - end - end - -- finally fall back to the folder containing the file - explorer_fn("change_dir", vim.fn.fnamemodify(path, ":p:h")) -end - function M.tab_enter() if view.is_visible({ any_tabpage = true }) then local bufname = vim.api.nvim_buf_get_name(0) @@ -275,8 +211,6 @@ function M.setup(config_user) return end - M.init_root = vim.fn.getcwd() - config.setup(config_user) manage_netrw() diff --git a/lua/nvim-tree/actions/tree/change-root.lua b/lua/nvim-tree/actions/tree/change-root.lua new file mode 100644 index 00000000000..81bdc39f353 --- /dev/null +++ b/lua/nvim-tree/actions/tree/change-root.lua @@ -0,0 +1,74 @@ +local utils = require("nvim-tree.utils") +local core = require("nvim-tree.core") +local config = require("nvim-tree.config") + +local M = {} + +--- Update the tree root to a directory or the directory containing +---@param path string relative or absolute +---@param bufnr number|nil +function M.fn(path, bufnr) + -- skip if current file is in ignore_list + if type(bufnr) == "number" then + local ft + + if vim.fn.has("nvim-0.10") == 1 then + ft = vim.api.nvim_get_option_value("filetype", { buf = bufnr }) or "" + else + ft = vim.api.nvim_buf_get_option(bufnr, "filetype") or "" ---@diagnostic disable-line: deprecated + end + + for _, value in pairs(config.g.update_focused_file.update_root.ignore_list) do + if utils.str_find(path, value) or utils.str_find(ft, value) then + return + end + end + end + + -- don't find inexistent + if vim.fn.filereadable(path) == 0 then + return + end + + local cwd = core.get_cwd() + if cwd == nil then + return + end + + local vim_cwd = vim.fn.getcwd() + + local explorer = core.get_explorer() + if not explorer then + return + end + + -- test if in vim_cwd + if utils.path_relative(path, vim_cwd) ~= path then + if vim_cwd ~= cwd then + explorer:change_dir(vim_cwd) + end + return + end + -- test if in cwd + if utils.path_relative(path, cwd) ~= path then + return + end + + -- otherwise test init_root + if config.g.prefer_startup_root and utils.path_relative(path, config.init_root) ~= path then + explorer:change_dir(config.init_root) + return + end + -- otherwise root_dirs + for _, dir in pairs(config.g.root_dirs) do + dir = vim.fn.fnamemodify(dir, ":p") + if utils.path_relative(path, dir) ~= path then + explorer:change_dir(dir) + return + end + end + -- finally fall back to the folder containing the file + explorer:change_dir(vim.fn.fnamemodify(path, ":p:h")) +end + +return M diff --git a/lua/nvim-tree/actions/tree/find-file.lua b/lua/nvim-tree/actions/tree/find-file.lua index d58c9cbfb51..deab9d1cdee 100644 --- a/lua/nvim-tree/actions/tree/find-file.lua +++ b/lua/nvim-tree/actions/tree/find-file.lua @@ -3,6 +3,7 @@ local lib = require("nvim-tree.lib") local view = require("nvim-tree.view") local config = require("nvim-tree.config") local finders_find_file = require("nvim-tree.actions.finders.find-file") +local change_root = require("nvim-tree.actions.tree.change-root") local M = {} @@ -58,7 +59,7 @@ function M.fn(opts) -- update root if opts.update_root or config.g.update_focused_file.update_root.enable then - require("nvim-tree").change_root(path, bufnr) + change_root.fn(path, bufnr) end -- find diff --git a/lua/nvim-tree/actions/tree/open.lua b/lua/nvim-tree/actions/tree/open.lua index 5244706a033..6e410521a6f 100644 --- a/lua/nvim-tree/actions/tree/open.lua +++ b/lua/nvim-tree/actions/tree/open.lua @@ -2,6 +2,7 @@ local lib = require("nvim-tree.lib") local view = require("nvim-tree.view") local config = require("nvim-tree.config") local finders_find_file = require("nvim-tree.actions.finders.find-file") +local change_root = require("nvim-tree.actions.tree.change-root") local M = {} @@ -41,7 +42,7 @@ function M.fn(opts) if config.g.update_focused_file.enable or opts.find_file then -- update root if opts.update_root then - require("nvim-tree").change_root(previous_path, previous_buf) + change_root.fn(previous_path, previous_buf) end -- find diff --git a/lua/nvim-tree/actions/tree/toggle.lua b/lua/nvim-tree/actions/tree/toggle.lua index f38b0999d90..8be5e7f3e4d 100644 --- a/lua/nvim-tree/actions/tree/toggle.lua +++ b/lua/nvim-tree/actions/tree/toggle.lua @@ -2,6 +2,7 @@ local lib = require("nvim-tree.lib") local view = require("nvim-tree.view") local config = require("nvim-tree.config") local finders_find_file = require("nvim-tree.actions.finders.find-file") +local change_root = require("nvim-tree.actions.tree.change-root") local M = {} @@ -56,7 +57,7 @@ function M.fn(opts, no_focus, cwd, bang) if config.g.update_focused_file.enable or opts.find_file then -- update root if opts.update_root then - require("nvim-tree").change_root(previous_path, previous_buf) + change_root.fn(previous_path, previous_buf) end -- find diff --git a/lua/nvim-tree/config.lua b/lua/nvim-tree/config.lua index 5c3403d36d7..63182fc8a62 100644 --- a/lua/nvim-tree/config.lua +++ b/lua/nvim-tree/config.lua @@ -17,7 +17,11 @@ local M = { ---Immutable OS, detected once on first require ---@type table<"unix"|"macos"|"wsl"|"windows", boolean> - os = nil + os = nil, + + ---Nvim cwd at setup time + ---@type string + init_root = "", } M.os = { @@ -554,6 +558,9 @@ function M.setup(u) -- process merged config process_config(M.g) + + -- store cwd + M.init_root = vim.fn.getcwd() end ---Deep clone defaults From b7b8e79871a446a574b11be9f07dfce62d245a2c Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Sat, 28 Mar 2026 15:21:39 +1100 Subject: [PATCH 12/22] perf(#3253): extract open_on_directory --- lua/nvim-tree.lua | 39 +++++------------------------ lua/nvim-tree/actions/tree/open.lua | 24 ++++++++++++++++++ lua/nvim-tree/explorer/init.lua | 1 - 3 files changed, 30 insertions(+), 34 deletions(-) diff --git a/lua/nvim-tree.lua b/lua/nvim-tree.lua index 110b624209f..327e06e79a7 100644 --- a/lua/nvim-tree.lua +++ b/lua/nvim-tree.lua @@ -11,17 +11,6 @@ local config = require("nvim-tree.config") local M = {} ---- Helper function to execute some explorer method safely ----@param fn string # key of explorer ----@param ... any|nil ----@return function|nil -local function explorer_fn(fn, ...) - local explorer = core.get_explorer() - if explorer then - return explorer[fn](explorer, ...) - end -end - function M.tab_enter() if view.is_visible({ any_tabpage = true }) then local bufname = vim.api.nvim_buf_get_name(0) @@ -47,27 +36,6 @@ function M.tab_enter() end end -function M.open_on_directory() - local should_proceed = config.g.hijack_directories.auto_open or view.is_visible() - if not should_proceed then - return - end - - local buf = vim.api.nvim_get_current_buf() - local bufname = vim.api.nvim_buf_get_name(buf) - if vim.fn.isdirectory(bufname) ~= 1 then - return - end - - - local explorer = core.get_explorer() - if not explorer then - core.init(bufname) - end - - explorer_fn("force_dirchange", bufname, true, false) -end - local function manage_netrw() if config.g.hijack_netrw then vim.cmd("silent! autocmd! FileExplorer *") @@ -126,7 +94,12 @@ local function setup_autocommands() end if config.g.hijack_directories.enable and (config.g.disable_netrw or config.g.hijack_netrw) then - create_nvim_tree_autocmd({ "BufEnter", "BufNewFile" }, { callback = M.open_on_directory, nested = true }) + create_nvim_tree_autocmd({ "BufEnter", "BufNewFile" }, { + callback = function() + require("nvim-tree.actions.tree.open").open_on_directory() + end, + nested = true + }) end if config.g.view.centralize_selection then diff --git a/lua/nvim-tree/actions/tree/open.lua b/lua/nvim-tree/actions/tree/open.lua index 6e410521a6f..aa3cfe23e4a 100644 --- a/lua/nvim-tree/actions/tree/open.lua +++ b/lua/nvim-tree/actions/tree/open.lua @@ -1,5 +1,6 @@ local lib = require("nvim-tree.lib") local view = require("nvim-tree.view") +local core = require("nvim-tree.core") local config = require("nvim-tree.config") local finders_find_file = require("nvim-tree.actions.finders.find-file") local change_root = require("nvim-tree.actions.tree.change-root") @@ -50,4 +51,27 @@ function M.fn(opts) end end +function M.open_on_directory() + local should_proceed = config.g.hijack_directories.auto_open or view.is_visible() + if not should_proceed then + return + end + + local buf = vim.api.nvim_get_current_buf() + local bufname = vim.api.nvim_buf_get_name(buf) + if vim.fn.isdirectory(bufname) ~= 1 then + return + end + + -- instantiate an explorer if there is not one + if not core.get_explorer() then + core.init(bufname) + end + + local explorer = core.get_explorer() + if explorer then + explorer:force_dirchange(bufname, true, false) + end +end + return M diff --git a/lua/nvim-tree/explorer/init.lua b/lua/nvim-tree/explorer/init.lua index 84af434edba..ff7fb4b2151 100644 --- a/lua/nvim-tree/explorer/init.lua +++ b/lua/nvim-tree/explorer/init.lua @@ -771,7 +771,6 @@ function Explorer:cd(global, path) vim.cmd((global and "cd " or "lcd ") .. vim.fn.fnameescape(path)) end ----@private ---@param foldername string ---@param should_open_view boolean|nil ---@param should_init boolean|nil From dc0fc5eaad772b57f4b995368606c44b6e372ce6 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Sat, 28 Mar 2026 15:25:37 +1100 Subject: [PATCH 13/22] perf(#3253): extract tab_enter --- lua/nvim-tree.lua | 29 +++-------------------------- lua/nvim-tree/actions/tree/open.lua | 25 +++++++++++++++++++++++++ 2 files changed, 28 insertions(+), 26 deletions(-) diff --git a/lua/nvim-tree.lua b/lua/nvim-tree.lua index 327e06e79a7..b2a6ce1a4a4 100644 --- a/lua/nvim-tree.lua +++ b/lua/nvim-tree.lua @@ -11,31 +11,6 @@ local config = require("nvim-tree.config") local M = {} -function M.tab_enter() - if view.is_visible({ any_tabpage = true }) then - local bufname = vim.api.nvim_buf_get_name(0) - - local ft - if vim.fn.has("nvim-0.10") == 1 then - ft = vim.api.nvim_get_option_value("filetype", { buf = 0 }) or "" - else - ft = vim.api.nvim_buf_get_option(0, "ft") ---@diagnostic disable-line: deprecated - end - - for _, filter in ipairs(config.g.tab.sync.ignore) do - if bufname:match(filter) ~= nil or ft:match(filter) ~= nil then - return - end - end - view.open({ focus_tree = false }) - - local explorer = core.get_explorer() - if explorer then - explorer.renderer:draw() - end - end -end - local function manage_netrw() if config.g.hijack_netrw then vim.cmd("silent! autocmd! FileExplorer *") @@ -70,7 +45,9 @@ local function setup_autocommands() }) if config.g.tab.sync.open then - create_nvim_tree_autocmd("TabEnter", { callback = vim.schedule_wrap(M.tab_enter) }) + create_nvim_tree_autocmd("TabEnter", { callback = vim.schedule_wrap(function() + require("nvim-tree.actions.tree.open").tab_enter() + end) }) end if config.g.sync_root_with_cwd then create_nvim_tree_autocmd("DirChanged", { diff --git a/lua/nvim-tree/actions/tree/open.lua b/lua/nvim-tree/actions/tree/open.lua index aa3cfe23e4a..7926edee382 100644 --- a/lua/nvim-tree/actions/tree/open.lua +++ b/lua/nvim-tree/actions/tree/open.lua @@ -74,4 +74,29 @@ function M.open_on_directory() end end +function M.tab_enter() + if view.is_visible({ any_tabpage = true }) then + local bufname = vim.api.nvim_buf_get_name(0) + + local ft + if vim.fn.has("nvim-0.10") == 1 then + ft = vim.api.nvim_get_option_value("filetype", { buf = 0 }) or "" + else + ft = vim.api.nvim_buf_get_option(0, "ft") ---@diagnostic disable-line: deprecated + end + + for _, filter in ipairs(config.g.tab.sync.ignore) do + if bufname:match(filter) ~= nil or ft:match(filter) ~= nil then + return + end + end + view.open({ focus_tree = false }) + + local explorer = core.get_explorer() + if explorer then + explorer.renderer:draw() + end + end +end + return M From 4c096cd2410b32c1fd6110819daf652a7961646a Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Sat, 28 Mar 2026 15:38:15 +1100 Subject: [PATCH 14/22] perf(#3253): move requires inline --- lua/nvim-tree.lua | 81 ++++++++++++++++++++++++----------------------- 1 file changed, 42 insertions(+), 39 deletions(-) diff --git a/lua/nvim-tree.lua b/lua/nvim-tree.lua index b2a6ce1a4a4..f5d8bfaff87 100644 --- a/lua/nvim-tree.lua +++ b/lua/nvim-tree.lua @@ -1,11 +1,5 @@ local api = require("nvim-tree.api") local log = require("nvim-tree.log") -local view = require("nvim-tree.view") -local utils = require("nvim-tree.utils") -local find_file = require("nvim-tree.actions.tree.find-file") -local change_dir = require("nvim-tree.actions.tree.change-dir") -local full_name = require("nvim-tree.renderer.components.full-name") -local core = require("nvim-tree.core") local notify = require("nvim-tree.notify") local config = require("nvim-tree.config") @@ -24,18 +18,16 @@ end local function setup_autocommands() local augroup_id = vim.api.nvim_create_augroup("NvimTree", { clear = true }) - local function create_nvim_tree_autocmd(name, custom_opts) - local default_opts = { group = augroup_id } - vim.api.nvim_create_autocmd(name, vim.tbl_extend("force", default_opts, custom_opts)) - end -- prevent new opened file from opening in the same window as nvim-tree - create_nvim_tree_autocmd("BufWipeout", { + vim.api.nvim_create_autocmd("BufWipeout", { + group = augroup_id, pattern = "NvimTree_*", callback = function() - if not utils.is_nvim_tree_buf(0) then + if not require("nvim-tree.utils").is_nvim_tree_buf(0) then return end + local view = require("nvim-tree.view") if config.g.actions.open_file.eject then view._prevent_buffer_override() else @@ -45,33 +37,39 @@ local function setup_autocommands() }) if config.g.tab.sync.open then - create_nvim_tree_autocmd("TabEnter", { callback = vim.schedule_wrap(function() - require("nvim-tree.actions.tree.open").tab_enter() - end) }) + vim.api.nvim_create_autocmd("TabEnter", { + group = augroup_id, + callback = vim.schedule_wrap(function() + require("nvim-tree.actions.tree.open").tab_enter() + end) + }) end if config.g.sync_root_with_cwd then - create_nvim_tree_autocmd("DirChanged", { + vim.api.nvim_create_autocmd("DirChanged", { + group = augroup_id, callback = function() - change_dir.fn(vim.loop.cwd()) + require("nvim-tree.actions.tree.change-dir").fn(vim.loop.cwd()) end, }) end if config.g.update_focused_file.enable then - create_nvim_tree_autocmd("BufEnter", { + vim.api.nvim_create_autocmd("BufEnter", { + group = augroup_id, callback = function(event) local exclude = config.g.update_focused_file.exclude if type(exclude) == "function" and exclude(event) then return end - utils.debounce("BufEnter:find_file", config.g.view.debounce_delay, function() - find_file.fn() + require("nvim-tree.utils").debounce("BufEnter:find_file", config.g.view.debounce_delay, function() + require("nvim-tree.actions.tree.find-file").fn() end) end, }) end if config.g.hijack_directories.enable and (config.g.disable_netrw or config.g.hijack_netrw) then - create_nvim_tree_autocmd({ "BufEnter", "BufNewFile" }, { + vim.api.nvim_create_autocmd({ "BufEnter", "BufNewFile" }, { + group = augroup_id, callback = function() require("nvim-tree.actions.tree.open").open_on_directory() end, @@ -80,30 +78,31 @@ local function setup_autocommands() end if config.g.view.centralize_selection then - create_nvim_tree_autocmd("BufEnter", { + vim.api.nvim_create_autocmd("BufEnter", { + group = augroup_id, pattern = "NvimTree_*", - callback = function() - vim.schedule(function() - vim.api.nvim_buf_call(0, function() - local is_term_mode = vim.api.nvim_get_mode().mode == "t" - if is_term_mode then - return - end - vim.cmd([[norm! zz]]) - end) + callback = vim.schedule_wrap(function() + vim.api.nvim_buf_call(0, function() + local is_term_mode = vim.api.nvim_get_mode().mode == "t" + if is_term_mode then + return + end + vim.cmd([[norm! zz]]) end) - end, + end) }) end if config.g.diagnostics.enable then - create_nvim_tree_autocmd("DiagnosticChanged", { + vim.api.nvim_create_autocmd("DiagnosticChanged", { + group = augroup_id, callback = function(ev) log.line("diagnostics", "DiagnosticChanged") require("nvim-tree.diagnostics").update_lsp(ev) end, }) - create_nvim_tree_autocmd("User", { + vim.api.nvim_create_autocmd("User", { + group = augroup_id, pattern = "CocDiagnosticChange", callback = function() log.line("diagnostics", "CocDiagnosticChange") @@ -113,18 +112,20 @@ local function setup_autocommands() end if config.g.view.float.enable and config.g.view.float.quit_on_focus_loss then - create_nvim_tree_autocmd("WinLeave", { + vim.api.nvim_create_autocmd("WinLeave", { + group = augroup_id, pattern = "NvimTree_*", callback = function() - if utils.is_nvim_tree_buf(0) then - view.close() + if require("nvim-tree.utils").is_nvim_tree_buf(0) then + require("nvim-tree.view").close() end end, }) end -- Handles event dispatch when tree is closed by `:q` - create_nvim_tree_autocmd("WinClosed", { + vim.api.nvim_create_autocmd("WinClosed", { + group = augroup_id, pattern = "*", ---@param ev vim.api.keyset.create_autocmd.callback_args callback = function(ev) @@ -138,10 +139,12 @@ local function setup_autocommands() }) -- renderer.full name - full_name.setup_autocommands() + require("nvim-tree.renderer.components.full-name").setup_autocommands() end function M.purge_all_state() + local view = require("nvim-tree.view") + local core = require("nvim-tree.core") view.close_all_tabs() view.abandon_all_windows() local explorer = core.get_explorer() From f9721946e5a85ee12b90f0dff1112d2b31423af8 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Sat, 28 Mar 2026 15:50:59 +1100 Subject: [PATCH 15/22] perf(#3253): extract au find-file, view --- lua/nvim-tree.lua | 34 +++++++----------------- lua/nvim-tree/actions/tree/find-file.lua | 12 +++++++++ lua/nvim-tree/diagnostics.lua | 2 ++ lua/nvim-tree/view.lua | 13 +++++++++ 4 files changed, 37 insertions(+), 24 deletions(-) diff --git a/lua/nvim-tree.lua b/lua/nvim-tree.lua index f5d8bfaff87..f9f58ec9723 100644 --- a/lua/nvim-tree.lua +++ b/lua/nvim-tree.lua @@ -1,6 +1,3 @@ -local api = require("nvim-tree.api") -local log = require("nvim-tree.log") -local notify = require("nvim-tree.notify") local config = require("nvim-tree.config") local M = {} @@ -19,20 +16,11 @@ end local function setup_autocommands() local augroup_id = vim.api.nvim_create_augroup("NvimTree", { clear = true }) - -- prevent new opened file from opening in the same window as nvim-tree vim.api.nvim_create_autocmd("BufWipeout", { group = augroup_id, pattern = "NvimTree_*", callback = function() - if not require("nvim-tree.utils").is_nvim_tree_buf(0) then - return - end - local view = require("nvim-tree.view") - if config.g.actions.open_file.eject then - view._prevent_buffer_override() - else - view.abandon_current_window() - end + require("nvim-tree.view").wipeout() end, }) @@ -44,6 +32,7 @@ local function setup_autocommands() end) }) end + if config.g.sync_root_with_cwd then vim.api.nvim_create_autocmd("DirChanged", { group = augroup_id, @@ -52,17 +41,12 @@ local function setup_autocommands() end, }) end + if config.g.update_focused_file.enable then vim.api.nvim_create_autocmd("BufEnter", { group = augroup_id, callback = function(event) - local exclude = config.g.update_focused_file.exclude - if type(exclude) == "function" and exclude(event) then - return - end - require("nvim-tree.utils").debounce("BufEnter:find_file", config.g.view.debounce_delay, function() - require("nvim-tree.actions.tree.find-file").fn() - end) + require("nvim-tree.actions.tree.find-file").buf_enter(event) end, }) end @@ -97,15 +81,14 @@ local function setup_autocommands() vim.api.nvim_create_autocmd("DiagnosticChanged", { group = augroup_id, callback = function(ev) - log.line("diagnostics", "DiagnosticChanged") require("nvim-tree.diagnostics").update_lsp(ev) end, }) + vim.api.nvim_create_autocmd("User", { group = augroup_id, pattern = "CocDiagnosticChange", callback = function() - log.line("diagnostics", "CocDiagnosticChange") require("nvim-tree.diagnostics").update_coc() end, }) @@ -145,6 +128,7 @@ end function M.purge_all_state() local view = require("nvim-tree.view") local core = require("nvim-tree.core") + view.close_all_tabs() view.abandon_all_windows() local explorer = core.get_explorer() @@ -159,8 +143,10 @@ end ---@param config_user? nvim_tree.config user supplied subset of config function M.setup(config_user) + local log = require("nvim-tree.log") + if vim.fn.has("nvim-0.9") == 0 then - notify.warn("nvim-tree.lua requires Neovim 0.9 or higher") + require("nvim-tree.notify").warn("nvim-tree.lua requires Neovim 0.9 or higher") return end @@ -189,7 +175,7 @@ function M.setup(config_user) vim.g.NvimTreeSetup = 1 vim.api.nvim_exec_autocmds("User", { pattern = "NvimTreeSetup" }) - require("nvim-tree.api.impl").hydrate_post_setup(api) + require("nvim-tree.api.impl").hydrate_post_setup(require("nvim-tree.api")) end vim.g.NvimTreeRequired = 1 diff --git a/lua/nvim-tree/actions/tree/find-file.lua b/lua/nvim-tree/actions/tree/find-file.lua index deab9d1cdee..99d771bdfaa 100644 --- a/lua/nvim-tree/actions/tree/find-file.lua +++ b/lua/nvim-tree/actions/tree/find-file.lua @@ -1,5 +1,6 @@ local core = require("nvim-tree.core") local lib = require("nvim-tree.lib") +local utils = require("nvim-tree.utils") local view = require("nvim-tree.view") local config = require("nvim-tree.config") local finders_find_file = require("nvim-tree.actions.finders.find-file") @@ -66,4 +67,15 @@ function M.fn(opts) finders_find_file.fn(path) end +---@param event vim.api.keyset.create_autocmd.callback_args +function M.buf_enter(event) + local exclude = config.g.update_focused_file.exclude + if type(exclude) == "function" and exclude(event) then + return + end + utils.debounce("BufEnter:find_file", config.g.view.debounce_delay, function() + M.fn() + end) +end + return M diff --git a/lua/nvim-tree/diagnostics.lua b/lua/nvim-tree/diagnostics.lua index 3c8c527e2b7..c4a6707026c 100644 --- a/lua/nvim-tree/diagnostics.lua +++ b/lua/nvim-tree/diagnostics.lua @@ -128,6 +128,7 @@ end ---On disabling LSP, a reset event will be sent for all buffers. ---@param ev table standard event with data.diagnostics populated function M.update_lsp(ev) + log.line("diagnostics", "DiagnosticChanged") if not config.g.diagnostics.enable or not ev or not ev.data or not ev.data.diagnostics then return end @@ -174,6 +175,7 @@ end ---Fired on CocDiagnosticChanged events: ---debounced retrieval, cache update, version increment and draw function M.update_coc() + log.line("diagnostics", "CocDiagnosticChange") if not config.g.diagnostics.enable then return end diff --git a/lua/nvim-tree/view.lua b/lua/nvim-tree/view.lua index 7cef8bff94d..dcb2fc1cfc6 100644 --- a/lua/nvim-tree/view.lua +++ b/lua/nvim-tree/view.lua @@ -521,4 +521,17 @@ function M.is_width_determined() return type(view_state.Active.width) ~= "function" end +---Called on BufWipeout +---Prevent new opened file from opening in the same window as nvim-tree +function M.wipeout() + if not utils.is_nvim_tree_buf(0) then + return + end + if config.g.actions.open_file.eject then + M._prevent_buffer_override() + else + M.abandon_current_window() + end +end + return M From d50a205e0956efc980a5115c6ca131a14b21cc76 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Sat, 28 Mar 2026 16:01:58 +1100 Subject: [PATCH 16/22] perf(#3253): extract manage_netrw --- lua/nvim-tree.lua | 13 ------------- lua/nvim-tree/config.lua | 16 ++++++++++++++++ 2 files changed, 16 insertions(+), 13 deletions(-) diff --git a/lua/nvim-tree.lua b/lua/nvim-tree.lua index f9f58ec9723..2e7d32bf49b 100644 --- a/lua/nvim-tree.lua +++ b/lua/nvim-tree.lua @@ -2,17 +2,6 @@ local config = require("nvim-tree.config") local M = {} -local function manage_netrw() - if config.g.hijack_netrw then - vim.cmd("silent! autocmd! FileExplorer *") - vim.cmd("autocmd VimEnter * ++once silent! autocmd! FileExplorer *") - end - if config.g.disable_netrw then - vim.g.loaded_netrw = 1 - vim.g.loaded_netrwPlugin = 1 - end -end - local function setup_autocommands() local augroup_id = vim.api.nvim_create_augroup("NvimTree", { clear = true }) @@ -152,8 +141,6 @@ function M.setup(config_user) config.setup(config_user) - manage_netrw() - log.start() if log.enabled("config") then diff --git a/lua/nvim-tree/config.lua b/lua/nvim-tree/config.lua index 63182fc8a62..56c02e9caef 100644 --- a/lua/nvim-tree/config.lua +++ b/lua/nvim-tree/config.lua @@ -532,6 +532,19 @@ local function process_config(g) end end +---Hijack and disable netrw if (globally) configured +---@param g nvim_tree.config +local function manage_netrw(g) + if g.hijack_netrw then + vim.cmd("silent! autocmd! FileExplorer *") + vim.cmd("autocmd VimEnter * ++once silent! autocmd! FileExplorer *") + end + if g.disable_netrw then + vim.g.loaded_netrw = 1 + vim.g.loaded_netrwPlugin = 1 + end +end + ---Validate user config and migrate legacy. ---Merge with M.d and persist as M.g ---When no user config M.g is set to M.d and M.u is set to nil @@ -559,6 +572,9 @@ function M.setup(u) -- process merged config process_config(M.g) + -- deal with netrw + manage_netrw(M.g) + -- store cwd M.init_root = vim.fn.getcwd() end From 9184bb469be0e75ea296b02af2f07c0b319ba128 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Sat, 28 Mar 2026 16:27:46 +1100 Subject: [PATCH 17/22] perf(#3253): extract purge_all_state and document --- lua/nvim-tree.lua | 40 +++++++++++++++++++-------------------- lua/nvim-tree/core.lua | 14 ++++++++++++++ lua/nvim-tree/watcher.lua | 2 +- 3 files changed, 34 insertions(+), 22 deletions(-) diff --git a/lua/nvim-tree.lua b/lua/nvim-tree.lua index 2e7d32bf49b..3b92d888460 100644 --- a/lua/nvim-tree.lua +++ b/lua/nvim-tree.lua @@ -114,55 +114,53 @@ local function setup_autocommands() require("nvim-tree.renderer.components.full-name").setup_autocommands() end -function M.purge_all_state() - local view = require("nvim-tree.view") - local core = require("nvim-tree.core") - - view.close_all_tabs() - view.abandon_all_windows() - local explorer = core.get_explorer() - if explorer then - require("nvim-tree.git").purge_state() - explorer:destroy() - core.reset_explorer() - end - -- purge orphaned that were not destroyed by their nodes - require("nvim-tree.watcher").purge_watchers() -end - ----@param config_user? nvim_tree.config user supplied subset of config +---`require("nvim-tree").setup` must be called once to initialise nvim-tree. +--- +---Call again to apply a change in configuration without restarting Nvim. +--- +---See :help nvim-tree-setup +--- +---@param config_user? nvim_tree.config subset, uses defaults when nil function M.setup(config_user) local log = require("nvim-tree.log") + -- Nvim version check if vim.fn.has("nvim-0.9") == 0 then require("nvim-tree.notify").warn("nvim-tree.lua requires Neovim 0.9 or higher") return end + -- validate and merge with defaults as config.g config.setup(config_user) + -- optionally create the log file log.start() + -- optionally log the configuration if log.enabled("config") then log.line("config", "default config + user") log.raw("config", "%s\n", vim.inspect(config.g)) end + -- idempotent highlight definition require("nvim-tree.appearance").highlight() + -- set the initial view state based on config require("nvim-tree.view-state").initialize() + -- idempotent au (re)definition setup_autocommands() + -- subsequent calls to setup clear all state if vim.g.NvimTreeSetup == 1 then - -- subsequent calls to setup - M.purge_all_state() + require("nvim-tree.core").purge_all_state() end + -- hydrate post setup API + require("nvim-tree.api.impl").hydrate_post_setup(require("nvim-tree.api")) + vim.g.NvimTreeSetup = 1 vim.api.nvim_exec_autocmds("User", { pattern = "NvimTreeSetup" }) - - require("nvim-tree.api.impl").hydrate_post_setup(require("nvim-tree.api")) end vim.g.NvimTreeRequired = 1 diff --git a/lua/nvim-tree/core.lua b/lua/nvim-tree/core.lua index 60d4a0a6f6a..6b4770ac215 100644 --- a/lua/nvim-tree/core.lua +++ b/lua/nvim-tree/core.lua @@ -2,6 +2,8 @@ local events = require("nvim-tree.events") local notify = require("nvim-tree.notify") local view = require("nvim-tree.view") local log = require("nvim-tree.log") +local git = require("nvim-tree.git") +local watcher = require("nvim-tree.watcher") local M = {} @@ -64,4 +66,16 @@ function M.get_nodes_starting_line() return offset end +function M.purge_all_state() + view.close_all_tabs() + view.abandon_all_windows() + if TreeExplorer then + git.purge_state() + TreeExplorer:destroy() + M.reset_explorer() + end + -- purge orphaned that were not destroyed by their nodes + watcher.purge_watchers() +end + return M diff --git a/lua/nvim-tree/watcher.lua b/lua/nvim-tree/watcher.lua index b29988538ab..d881af318cc 100644 --- a/lua/nvim-tree/watcher.lua +++ b/lua/nvim-tree/watcher.lua @@ -238,7 +238,7 @@ M.Watcher = Watcher function M.disable_watchers(msg) notify.warn(string.format("Disabling watchers: %s", msg)) config.g.filesystem_watchers.enable = false - require("nvim-tree").purge_all_state() + require("nvim-tree.core").purge_all_state() end function M.purge_watchers() From 430514f10fde7dac2141bff933f0884c95ffe999 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Mon, 30 Mar 2026 16:57:32 +1100 Subject: [PATCH 18/22] perf(#3253): move full-name setup_autocommands to main --- lua/nvim-tree.lua | 20 ++++++++- .../renderer/components/full-name.lua | 41 ++++--------------- 2 files changed, 27 insertions(+), 34 deletions(-) diff --git a/lua/nvim-tree.lua b/lua/nvim-tree.lua index 3b92d888460..a399b4bcbf4 100644 --- a/lua/nvim-tree.lua +++ b/lua/nvim-tree.lua @@ -110,8 +110,24 @@ local function setup_autocommands() end, }) - -- renderer.full name - require("nvim-tree.renderer.components.full-name").setup_autocommands() + if config.g.renderer.full_name then + local group = vim.api.nvim_create_augroup("nvim_tree_floating_node", { clear = true }) + vim.api.nvim_create_autocmd({ "BufLeave", "CursorMoved" }, { + group = group, + pattern = { "NvimTree_*" }, + callback = function() + require("nvim-tree.renderer.components.full-name").hide() + end, + }) + + vim.api.nvim_create_autocmd({ "CursorMoved" }, { + group = group, + pattern = { "NvimTree_*" }, + callback = function() + require("nvim-tree.renderer.components.full-name").show() + end, + }) + end end ---`require("nvim-tree").setup` must be called once to initialise nvim-tree. diff --git a/lua/nvim-tree/renderer/components/full-name.lua b/lua/nvim-tree/renderer/components/full-name.lua index 3b0a07a9925..e3674ee6d16 100644 --- a/lua/nvim-tree/renderer/components/full-name.lua +++ b/lua/nvim-tree/renderer/components/full-name.lua @@ -5,10 +5,10 @@ local M = {} local utils = require("nvim-tree.utils") -local function hide(win) - if win then - if vim.api.nvim_win_is_valid(win) then - vim.api.nvim_win_close(win, true) +function M.hide() + if M.popup_win and utils.is_nvim_tree_buf(0) then + if vim.api.nvim_win_is_valid(M.popup_win) then + vim.api.nvim_win_close(M.popup_win, true) end end end @@ -35,7 +35,11 @@ local function effective_win_width() return win_width - win_info[1].textoff end -local function show() +function M.show() + if not utils.is_nvim_tree_buf(0) then + return + end + local line_nr = vim.api.nvim_win_get_cursor(0)[1] if vim.wo.wrap then return @@ -104,31 +108,4 @@ local function show() end) end -function M.setup_autocommands() - if not config.g.renderer.full_name then - return - end - - local group = vim.api.nvim_create_augroup("nvim_tree_floating_node", { clear = true }) - vim.api.nvim_create_autocmd({ "BufLeave", "CursorMoved" }, { - group = group, - pattern = { "NvimTree_*" }, - callback = function() - if utils.is_nvim_tree_buf(0) then - hide(M.popup_win) - end - end, - }) - - vim.api.nvim_create_autocmd({ "CursorMoved" }, { - group = group, - pattern = { "NvimTree_*" }, - callback = function() - if utils.is_nvim_tree_buf(0) then - show() - end - end, - }) -end - return M From d38839dde9c17a51c40ae94f0aca9ac4c1001899 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Mon, 30 Mar 2026 17:15:04 +1100 Subject: [PATCH 19/22] perf(#3253): unextract au find-file for laziness --- lua/nvim-tree.lua | 26 +++++++++++++++--------- lua/nvim-tree/actions/tree/find-file.lua | 12 ----------- 2 files changed, 16 insertions(+), 22 deletions(-) diff --git a/lua/nvim-tree.lua b/lua/nvim-tree.lua index a399b4bcbf4..63f3ec59544 100644 --- a/lua/nvim-tree.lua +++ b/lua/nvim-tree.lua @@ -35,20 +35,26 @@ local function setup_autocommands() vim.api.nvim_create_autocmd("BufEnter", { group = augroup_id, callback = function(event) - require("nvim-tree.actions.tree.find-file").buf_enter(event) + if type(config.g.update_focused_file.exclude) == "function" and config.g.update_focused_file.exclude(event) then + return + end + require("nvim-tree.utils").debounce("BufEnter:find_file", config.g.view.debounce_delay, function() + require("nvim-tree.actions.tree.find-file").fn() + end) end, }) end - if config.g.hijack_directories.enable and (config.g.disable_netrw or config.g.hijack_netrw) then - vim.api.nvim_create_autocmd({ "BufEnter", "BufNewFile" }, { - group = augroup_id, - callback = function() - require("nvim-tree.actions.tree.open").open_on_directory() - end, - nested = true - }) - end + -- TODO this fires on setup + -- if config.g.hijack_directories.enable and (config.g.disable_netrw or config.g.hijack_netrw) then + -- vim.api.nvim_create_autocmd({ "BufEnter", "BufNewFile" }, { + -- group = augroup_id, + -- callback = function() + -- require("nvim-tree.actions.tree.open").open_on_directory() + -- end, + -- nested = true + -- }) + -- end if config.g.view.centralize_selection then vim.api.nvim_create_autocmd("BufEnter", { diff --git a/lua/nvim-tree/actions/tree/find-file.lua b/lua/nvim-tree/actions/tree/find-file.lua index 99d771bdfaa..deab9d1cdee 100644 --- a/lua/nvim-tree/actions/tree/find-file.lua +++ b/lua/nvim-tree/actions/tree/find-file.lua @@ -1,6 +1,5 @@ local core = require("nvim-tree.core") local lib = require("nvim-tree.lib") -local utils = require("nvim-tree.utils") local view = require("nvim-tree.view") local config = require("nvim-tree.config") local finders_find_file = require("nvim-tree.actions.finders.find-file") @@ -67,15 +66,4 @@ function M.fn(opts) finders_find_file.fn(path) end ----@param event vim.api.keyset.create_autocmd.callback_args -function M.buf_enter(event) - local exclude = config.g.update_focused_file.exclude - if type(exclude) == "function" and exclude(event) then - return - end - utils.debounce("BufEnter:find_file", config.g.view.debounce_delay, function() - M.fn() - end) -end - return M From c59fc312deb042288bbf58a6a3b06af1859476f7 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Tue, 31 Mar 2026 10:10:49 +1100 Subject: [PATCH 20/22] perf(#3253): short-circuit open_on_directory au --- lua/nvim-tree.lua | 22 ++++++++++++---------- lua/nvim-tree/actions/tree/open.lua | 13 ++++--------- 2 files changed, 16 insertions(+), 19 deletions(-) diff --git a/lua/nvim-tree.lua b/lua/nvim-tree.lua index 63f3ec59544..45bd8bc75a9 100644 --- a/lua/nvim-tree.lua +++ b/lua/nvim-tree.lua @@ -45,16 +45,18 @@ local function setup_autocommands() }) end - -- TODO this fires on setup - -- if config.g.hijack_directories.enable and (config.g.disable_netrw or config.g.hijack_netrw) then - -- vim.api.nvim_create_autocmd({ "BufEnter", "BufNewFile" }, { - -- group = augroup_id, - -- callback = function() - -- require("nvim-tree.actions.tree.open").open_on_directory() - -- end, - -- nested = true - -- }) - -- end + if config.g.hijack_directories.enable and (config.g.disable_netrw or config.g.hijack_netrw) then + vim.api.nvim_create_autocmd({ "BufEnter", "BufNewFile" }, { + group = augroup_id, + nested = true, + callback = function(data) + local bufname = vim.api.nvim_buf_get_name(data.buf) + if vim.fn.isdirectory(bufname) == 1 then + require("nvim-tree.actions.tree.open").open_on_directory(bufname) + end + end, + }) + end if config.g.view.centralize_selection then vim.api.nvim_create_autocmd("BufEnter", { diff --git a/lua/nvim-tree/actions/tree/open.lua b/lua/nvim-tree/actions/tree/open.lua index 7926edee382..698bd2c8c9a 100644 --- a/lua/nvim-tree/actions/tree/open.lua +++ b/lua/nvim-tree/actions/tree/open.lua @@ -51,26 +51,21 @@ function M.fn(opts) end end -function M.open_on_directory() +---@param dirname string absolute directory path +function M.open_on_directory(dirname) local should_proceed = config.g.hijack_directories.auto_open or view.is_visible() if not should_proceed then return end - local buf = vim.api.nvim_get_current_buf() - local bufname = vim.api.nvim_buf_get_name(buf) - if vim.fn.isdirectory(bufname) ~= 1 then - return - end - -- instantiate an explorer if there is not one if not core.get_explorer() then - core.init(bufname) + core.init(dirname) end local explorer = core.get_explorer() if explorer then - explorer:force_dirchange(bufname, true, false) + explorer:force_dirchange(dirname, true, false) end end From 400839b7e41a8e3c5b8fec64d735c427466e6b87 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Tue, 31 Mar 2026 10:26:48 +1100 Subject: [PATCH 21/22] perf(#3253): extract autocmd --- lua/nvim-tree.lua | 138 +----------------------------------- lua/nvim-tree/autocmd.lua | 145 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 146 insertions(+), 137 deletions(-) create mode 100644 lua/nvim-tree/autocmd.lua diff --git a/lua/nvim-tree.lua b/lua/nvim-tree.lua index 45bd8bc75a9..0f6c13e4f40 100644 --- a/lua/nvim-tree.lua +++ b/lua/nvim-tree.lua @@ -2,142 +2,6 @@ local config = require("nvim-tree.config") local M = {} -local function setup_autocommands() - local augroup_id = vim.api.nvim_create_augroup("NvimTree", { clear = true }) - - vim.api.nvim_create_autocmd("BufWipeout", { - group = augroup_id, - pattern = "NvimTree_*", - callback = function() - require("nvim-tree.view").wipeout() - end, - }) - - if config.g.tab.sync.open then - vim.api.nvim_create_autocmd("TabEnter", { - group = augroup_id, - callback = vim.schedule_wrap(function() - require("nvim-tree.actions.tree.open").tab_enter() - end) - }) - end - - if config.g.sync_root_with_cwd then - vim.api.nvim_create_autocmd("DirChanged", { - group = augroup_id, - callback = function() - require("nvim-tree.actions.tree.change-dir").fn(vim.loop.cwd()) - end, - }) - end - - if config.g.update_focused_file.enable then - vim.api.nvim_create_autocmd("BufEnter", { - group = augroup_id, - callback = function(event) - if type(config.g.update_focused_file.exclude) == "function" and config.g.update_focused_file.exclude(event) then - return - end - require("nvim-tree.utils").debounce("BufEnter:find_file", config.g.view.debounce_delay, function() - require("nvim-tree.actions.tree.find-file").fn() - end) - end, - }) - end - - if config.g.hijack_directories.enable and (config.g.disable_netrw or config.g.hijack_netrw) then - vim.api.nvim_create_autocmd({ "BufEnter", "BufNewFile" }, { - group = augroup_id, - nested = true, - callback = function(data) - local bufname = vim.api.nvim_buf_get_name(data.buf) - if vim.fn.isdirectory(bufname) == 1 then - require("nvim-tree.actions.tree.open").open_on_directory(bufname) - end - end, - }) - end - - if config.g.view.centralize_selection then - vim.api.nvim_create_autocmd("BufEnter", { - group = augroup_id, - pattern = "NvimTree_*", - callback = vim.schedule_wrap(function() - vim.api.nvim_buf_call(0, function() - local is_term_mode = vim.api.nvim_get_mode().mode == "t" - if is_term_mode then - return - end - vim.cmd([[norm! zz]]) - end) - end) - }) - end - - if config.g.diagnostics.enable then - vim.api.nvim_create_autocmd("DiagnosticChanged", { - group = augroup_id, - callback = function(ev) - require("nvim-tree.diagnostics").update_lsp(ev) - end, - }) - - vim.api.nvim_create_autocmd("User", { - group = augroup_id, - pattern = "CocDiagnosticChange", - callback = function() - require("nvim-tree.diagnostics").update_coc() - end, - }) - end - - if config.g.view.float.enable and config.g.view.float.quit_on_focus_loss then - vim.api.nvim_create_autocmd("WinLeave", { - group = augroup_id, - pattern = "NvimTree_*", - callback = function() - if require("nvim-tree.utils").is_nvim_tree_buf(0) then - require("nvim-tree.view").close() - end - end, - }) - end - - -- Handles event dispatch when tree is closed by `:q` - vim.api.nvim_create_autocmd("WinClosed", { - group = augroup_id, - pattern = "*", - ---@param ev vim.api.keyset.create_autocmd.callback_args - callback = function(ev) - if not vim.api.nvim_buf_is_valid(ev.buf) then - return - end - if vim.api.nvim_get_option_value("filetype", { buf = ev.buf }) == "NvimTree" then - require("nvim-tree.events")._dispatch_on_tree_close() - end - end, - }) - - if config.g.renderer.full_name then - local group = vim.api.nvim_create_augroup("nvim_tree_floating_node", { clear = true }) - vim.api.nvim_create_autocmd({ "BufLeave", "CursorMoved" }, { - group = group, - pattern = { "NvimTree_*" }, - callback = function() - require("nvim-tree.renderer.components.full-name").hide() - end, - }) - - vim.api.nvim_create_autocmd({ "CursorMoved" }, { - group = group, - pattern = { "NvimTree_*" }, - callback = function() - require("nvim-tree.renderer.components.full-name").show() - end, - }) - end -end - ---`require("nvim-tree").setup` must be called once to initialise nvim-tree. --- ---Call again to apply a change in configuration without restarting Nvim. @@ -173,7 +37,7 @@ function M.setup(config_user) require("nvim-tree.view-state").initialize() -- idempotent au (re)definition - setup_autocommands() + require("nvim-tree.autocmd").global() -- subsequent calls to setup clear all state if vim.g.NvimTreeSetup == 1 then diff --git a/lua/nvim-tree/autocmd.lua b/lua/nvim-tree/autocmd.lua new file mode 100644 index 00000000000..161f379e7c6 --- /dev/null +++ b/lua/nvim-tree/autocmd.lua @@ -0,0 +1,145 @@ +local config = require("nvim-tree.config") + +local M = {} + +---Create all global autocommands after setup. +---Idempotent: removes existing autocommands first. +---For startup performance reasons, all requires must be done inline during the callback. +---Some short circuiting logic is done directly inside the callback to prevent unnecessary requires. +function M.global() + local augroup_id = vim.api.nvim_create_augroup("NvimTree", { clear = true }) + + vim.api.nvim_create_autocmd("BufWipeout", { + group = augroup_id, + pattern = "NvimTree_*", + callback = function() + require("nvim-tree.view").wipeout() + end, + }) + + if config.g.tab.sync.open then + vim.api.nvim_create_autocmd("TabEnter", { + group = augroup_id, + callback = vim.schedule_wrap(function() + require("nvim-tree.actions.tree.open").tab_enter() + end) + }) + end + + if config.g.sync_root_with_cwd then + vim.api.nvim_create_autocmd("DirChanged", { + group = augroup_id, + callback = function() + require("nvim-tree.actions.tree.change-dir").fn(vim.loop.cwd()) + end, + }) + end + + if config.g.update_focused_file.enable then + vim.api.nvim_create_autocmd("BufEnter", { + group = augroup_id, + callback = function(event) + if type(config.g.update_focused_file.exclude) == "function" and config.g.update_focused_file.exclude(event) then + return + end + require("nvim-tree.utils").debounce("BufEnter:find_file", config.g.view.debounce_delay, function() + require("nvim-tree.actions.tree.find-file").fn() + end) + end, + }) + end + + if config.g.hijack_directories.enable and (config.g.disable_netrw or config.g.hijack_netrw) then + vim.api.nvim_create_autocmd({ "BufEnter", "BufNewFile" }, { + group = augroup_id, + nested = true, + callback = function(data) + local bufname = vim.api.nvim_buf_get_name(data.buf) + if vim.fn.isdirectory(bufname) == 1 then + require("nvim-tree.actions.tree.open").open_on_directory(bufname) + end + end, + }) + end + + if config.g.view.centralize_selection then + vim.api.nvim_create_autocmd("BufEnter", { + group = augroup_id, + pattern = "NvimTree_*", + callback = vim.schedule_wrap(function() + vim.api.nvim_buf_call(0, function() + local is_term_mode = vim.api.nvim_get_mode().mode == "t" + if is_term_mode then + return + end + vim.cmd([[norm! zz]]) + end) + end) + }) + end + + if config.g.diagnostics.enable then + vim.api.nvim_create_autocmd("DiagnosticChanged", { + group = augroup_id, + callback = function(ev) + require("nvim-tree.diagnostics").update_lsp(ev) + end, + }) + + vim.api.nvim_create_autocmd("User", { + group = augroup_id, + pattern = "CocDiagnosticChange", + callback = function() + require("nvim-tree.diagnostics").update_coc() + end, + }) + end + + if config.g.view.float.enable and config.g.view.float.quit_on_focus_loss then + vim.api.nvim_create_autocmd("WinLeave", { + group = augroup_id, + pattern = "NvimTree_*", + callback = function() + if require("nvim-tree.utils").is_nvim_tree_buf(0) then + require("nvim-tree.view").close() + end + end, + }) + end + + -- Handles event dispatch when tree is closed by `:q` + vim.api.nvim_create_autocmd("WinClosed", { + group = augroup_id, + pattern = "*", + ---@param ev vim.api.keyset.create_autocmd.callback_args + callback = function(ev) + if not vim.api.nvim_buf_is_valid(ev.buf) then + return + end + if vim.api.nvim_get_option_value("filetype", { buf = ev.buf }) == "NvimTree" then + require("nvim-tree.events")._dispatch_on_tree_close() + end + end, + }) + + if config.g.renderer.full_name then + local group = vim.api.nvim_create_augroup("nvim_tree_floating_node", { clear = true }) + vim.api.nvim_create_autocmd({ "BufLeave", "CursorMoved" }, { + group = group, + pattern = { "NvimTree_*" }, + callback = function() + require("nvim-tree.renderer.components.full-name").hide() + end, + }) + + vim.api.nvim_create_autocmd({ "CursorMoved" }, { + group = group, + pattern = { "NvimTree_*" }, + callback = function() + require("nvim-tree.renderer.components.full-name").show() + end, + }) + end +end + +return M From 181dab8ecddc90798295a9dae7905ba96f95eba7 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Tue, 31 Mar 2026 10:33:33 +1100 Subject: [PATCH 22/22] perf(#3253): move all setup requires inside the function --- lua/nvim-tree.lua | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/lua/nvim-tree.lua b/lua/nvim-tree.lua index 0f6c13e4f40..d55130df8a6 100644 --- a/lua/nvim-tree.lua +++ b/lua/nvim-tree.lua @@ -1,5 +1,3 @@ -local config = require("nvim-tree.config") - local M = {} ---`require("nvim-tree").setup` must be called once to initialise nvim-tree. @@ -10,7 +8,13 @@ local M = {} --- ---@param config_user? nvim_tree.config subset, uses defaults when nil function M.setup(config_user) + local api = require("nvim-tree.api") + local api_impl = require("nvim-tree.api.impl") + local appearance = require("nvim-tree.appearance") + local autocmd = require("nvim-tree.autocmd") + local config = require("nvim-tree.config") local log = require("nvim-tree.log") + local view_state = require("nvim-tree.view-state") -- Nvim version check if vim.fn.has("nvim-0.9") == 0 then @@ -31,13 +35,13 @@ function M.setup(config_user) end -- idempotent highlight definition - require("nvim-tree.appearance").highlight() + appearance.highlight() -- set the initial view state based on config - require("nvim-tree.view-state").initialize() + view_state.initialize() -- idempotent au (re)definition - require("nvim-tree.autocmd").global() + autocmd.global() -- subsequent calls to setup clear all state if vim.g.NvimTreeSetup == 1 then @@ -45,7 +49,7 @@ function M.setup(config_user) end -- hydrate post setup API - require("nvim-tree.api.impl").hydrate_post_setup(require("nvim-tree.api")) + api_impl.hydrate_post_setup(api) vim.g.NvimTreeSetup = 1 vim.api.nvim_exec_autocmds("User", { pattern = "NvimTreeSetup" })