Skip to content

Commit 31503ad

Browse files
authored
perf(#3231): decrease setup time: optimise setup and defer requires until tree open (#3308)
* perf(#3257): remove devicons setup * perf(#3257): remove padding setup * perf(#3257): remove appearance and log setup * perf(#3257): remove appearance setup * perf(#3257): remove rename-file setup * perf(#3257): remove devicons setup * perf(#3257): remove appearance setup * perf(#3257): inline require legacy notify * perf(#3257): inline require events notify * perf(#3257): inline require log notify * perf(#3253): extract change-root * perf(#3253): extract open_on_directory * perf(#3253): extract tab_enter * perf(#3253): move requires inline * perf(#3253): extract au find-file, view * perf(#3253): extract manage_netrw * perf(#3253): extract purge_all_state and document * perf(#3253): move full-name setup_autocommands to main * perf(#3253): unextract au find-file for laziness * perf(#3253): short-circuit open_on_directory au * perf(#3253): extract autocmd * perf(#3253): move all setup requires inside the function
1 parent 02ccbcd commit 31503ad

File tree

13 files changed

+365
-321
lines changed

13 files changed

+365
-321
lines changed

lua/nvim-tree.lua

Lines changed: 33 additions & 283 deletions
Original file line numberDiff line numberDiff line change
@@ -1,308 +1,58 @@
1-
local api = require("nvim-tree.api")
2-
local log = require("nvim-tree.log")
3-
local view = require("nvim-tree.view")
4-
local utils = require("nvim-tree.utils")
5-
local find_file = require("nvim-tree.actions.tree.find-file")
6-
local change_dir = require("nvim-tree.actions.tree.change-dir")
7-
local full_name = require("nvim-tree.renderer.components.full-name")
8-
local core = require("nvim-tree.core")
9-
local notify = require("nvim-tree.notify")
10-
local config = require("nvim-tree.config")
11-
12-
local M = {
13-
init_root = "",
14-
}
15-
16-
--- Helper function to execute some explorer method safely
17-
---@param fn string # key of explorer
18-
---@param ... any|nil
19-
---@return function|nil
20-
local function explorer_fn(fn, ...)
21-
local explorer = core.get_explorer()
22-
if explorer then
23-
return explorer[fn](explorer, ...)
24-
end
25-
end
26-
27-
--- Update the tree root to a directory or the directory containing
28-
---@param path string relative or absolute
29-
---@param bufnr number|nil
30-
function M.change_root(path, bufnr)
31-
-- skip if current file is in ignore_list
32-
if type(bufnr) == "number" then
33-
local ft
34-
35-
if vim.fn.has("nvim-0.10") == 1 then
36-
ft = vim.api.nvim_get_option_value("filetype", { buf = bufnr }) or ""
37-
else
38-
ft = vim.api.nvim_buf_get_option(bufnr, "filetype") or "" ---@diagnostic disable-line: deprecated
39-
end
40-
41-
for _, value in pairs(config.g.update_focused_file.update_root.ignore_list) do
42-
if utils.str_find(path, value) or utils.str_find(ft, value) then
43-
return
44-
end
45-
end
46-
end
47-
48-
-- don't find inexistent
49-
if vim.fn.filereadable(path) == 0 then
50-
return
51-
end
52-
53-
local cwd = core.get_cwd()
54-
if cwd == nil then
55-
return
56-
end
57-
58-
local vim_cwd = vim.fn.getcwd()
59-
60-
-- test if in vim_cwd
61-
if utils.path_relative(path, vim_cwd) ~= path then
62-
if vim_cwd ~= cwd then
63-
explorer_fn("change_dir", vim_cwd)
64-
end
65-
return
66-
end
67-
-- test if in cwd
68-
if utils.path_relative(path, cwd) ~= path then
69-
return
70-
end
71-
72-
-- otherwise test M.init_root
73-
if config.g.prefer_startup_root and utils.path_relative(path, M.init_root) ~= path then
74-
explorer_fn("change_dir", M.init_root)
75-
return
76-
end
77-
-- otherwise root_dirs
78-
for _, dir in pairs(config.g.root_dirs) do
79-
dir = vim.fn.fnamemodify(dir, ":p")
80-
if utils.path_relative(path, dir) ~= path then
81-
explorer_fn("change_dir", dir)
82-
return
83-
end
84-
end
85-
-- finally fall back to the folder containing the file
86-
explorer_fn("change_dir", vim.fn.fnamemodify(path, ":p:h"))
87-
end
88-
89-
function M.tab_enter()
90-
if view.is_visible({ any_tabpage = true }) then
91-
local bufname = vim.api.nvim_buf_get_name(0)
92-
93-
local ft
94-
if vim.fn.has("nvim-0.10") == 1 then
95-
ft = vim.api.nvim_get_option_value("filetype", { buf = 0 }) or ""
96-
else
97-
ft = vim.api.nvim_buf_get_option(0, "ft") ---@diagnostic disable-line: deprecated
98-
end
99-
100-
for _, filter in ipairs(config.g.tab.sync.ignore) do
101-
if bufname:match(filter) ~= nil or ft:match(filter) ~= nil then
102-
return
103-
end
104-
end
105-
view.open({ focus_tree = false })
106-
107-
local explorer = core.get_explorer()
108-
if explorer then
109-
explorer.renderer:draw()
110-
end
111-
end
112-
end
113-
114-
function M.open_on_directory()
115-
local should_proceed = config.g.hijack_directories.auto_open or view.is_visible()
116-
if not should_proceed then
117-
return
118-
end
119-
120-
local buf = vim.api.nvim_get_current_buf()
121-
local bufname = vim.api.nvim_buf_get_name(buf)
122-
if vim.fn.isdirectory(bufname) ~= 1 then
123-
return
124-
end
125-
126-
127-
local explorer = core.get_explorer()
128-
if not explorer then
129-
core.init(bufname)
130-
end
131-
132-
explorer_fn("force_dirchange", bufname, true, false)
133-
end
134-
135-
local function manage_netrw()
136-
if config.g.hijack_netrw then
137-
vim.cmd("silent! autocmd! FileExplorer *")
138-
vim.cmd("autocmd VimEnter * ++once silent! autocmd! FileExplorer *")
139-
end
140-
if config.g.disable_netrw then
141-
vim.g.loaded_netrw = 1
142-
vim.g.loaded_netrwPlugin = 1
143-
end
144-
end
145-
146-
local function setup_autocommands()
147-
local augroup_id = vim.api.nvim_create_augroup("NvimTree", { clear = true })
148-
local function create_nvim_tree_autocmd(name, custom_opts)
149-
local default_opts = { group = augroup_id }
150-
vim.api.nvim_create_autocmd(name, vim.tbl_extend("force", default_opts, custom_opts))
151-
end
152-
153-
-- prevent new opened file from opening in the same window as nvim-tree
154-
create_nvim_tree_autocmd("BufWipeout", {
155-
pattern = "NvimTree_*",
156-
callback = function()
157-
if not utils.is_nvim_tree_buf(0) then
158-
return
159-
end
160-
if config.g.actions.open_file.eject then
161-
view._prevent_buffer_override()
162-
else
163-
view.abandon_current_window()
164-
end
165-
end,
166-
})
167-
168-
if config.g.tab.sync.open then
169-
create_nvim_tree_autocmd("TabEnter", { callback = vim.schedule_wrap(M.tab_enter) })
170-
end
171-
if config.g.sync_root_with_cwd then
172-
create_nvim_tree_autocmd("DirChanged", {
173-
callback = function()
174-
change_dir.fn(vim.loop.cwd())
175-
end,
176-
})
177-
end
178-
if config.g.update_focused_file.enable then
179-
create_nvim_tree_autocmd("BufEnter", {
180-
callback = function(event)
181-
local exclude = config.g.update_focused_file.exclude
182-
if type(exclude) == "function" and exclude(event) then
183-
return
184-
end
185-
utils.debounce("BufEnter:find_file", config.g.view.debounce_delay, function()
186-
find_file.fn()
187-
end)
188-
end,
189-
})
190-
end
191-
192-
if config.g.hijack_directories.enable and (config.g.disable_netrw or config.g.hijack_netrw) then
193-
create_nvim_tree_autocmd({ "BufEnter", "BufNewFile" }, { callback = M.open_on_directory, nested = true })
194-
end
195-
196-
if config.g.view.centralize_selection then
197-
create_nvim_tree_autocmd("BufEnter", {
198-
pattern = "NvimTree_*",
199-
callback = function()
200-
vim.schedule(function()
201-
vim.api.nvim_buf_call(0, function()
202-
local is_term_mode = vim.api.nvim_get_mode().mode == "t"
203-
if is_term_mode then
204-
return
205-
end
206-
vim.cmd([[norm! zz]])
207-
end)
208-
end)
209-
end,
210-
})
211-
end
212-
213-
if config.g.diagnostics.enable then
214-
create_nvim_tree_autocmd("DiagnosticChanged", {
215-
callback = function(ev)
216-
log.line("diagnostics", "DiagnosticChanged")
217-
require("nvim-tree.diagnostics").update_lsp(ev)
218-
end,
219-
})
220-
create_nvim_tree_autocmd("User", {
221-
pattern = "CocDiagnosticChange",
222-
callback = function()
223-
log.line("diagnostics", "CocDiagnosticChange")
224-
require("nvim-tree.diagnostics").update_coc()
225-
end,
226-
})
227-
end
228-
229-
if config.g.view.float.enable and config.g.view.float.quit_on_focus_loss then
230-
create_nvim_tree_autocmd("WinLeave", {
231-
pattern = "NvimTree_*",
232-
callback = function()
233-
if utils.is_nvim_tree_buf(0) then
234-
view.close()
235-
end
236-
end,
237-
})
238-
end
239-
240-
-- Handles event dispatch when tree is closed by `:q`
241-
create_nvim_tree_autocmd("WinClosed", {
242-
pattern = "*",
243-
---@param ev vim.api.keyset.create_autocmd.callback_args
244-
callback = function(ev)
245-
if not vim.api.nvim_buf_is_valid(ev.buf) then
246-
return
247-
end
248-
if vim.api.nvim_get_option_value("filetype", { buf = ev.buf }) == "NvimTree" then
249-
require("nvim-tree.events")._dispatch_on_tree_close()
250-
end
251-
end,
252-
})
253-
254-
-- renderer.full name
255-
full_name.setup_autocommands()
256-
end
257-
258-
function M.purge_all_state()
259-
view.close_all_tabs()
260-
view.abandon_all_windows()
261-
local explorer = core.get_explorer()
262-
if explorer then
263-
require("nvim-tree.git").purge_state()
264-
explorer:destroy()
265-
core.reset_explorer()
266-
end
267-
-- purge orphaned that were not destroyed by their nodes
268-
require("nvim-tree.watcher").purge_watchers()
269-
end
270-
271-
---@param config_user? nvim_tree.config user supplied subset of config
1+
local M = {}
2+
3+
---`require("nvim-tree").setup` must be called once to initialise nvim-tree.
4+
---
5+
---Call again to apply a change in configuration without restarting Nvim.
6+
---
7+
---See :help nvim-tree-setup
8+
---
9+
---@param config_user? nvim_tree.config subset, uses defaults when nil
27210
function M.setup(config_user)
11+
local api = require("nvim-tree.api")
12+
local api_impl = require("nvim-tree.api.impl")
13+
local appearance = require("nvim-tree.appearance")
14+
local autocmd = require("nvim-tree.autocmd")
15+
local config = require("nvim-tree.config")
16+
local log = require("nvim-tree.log")
17+
local view_state = require("nvim-tree.view-state")
18+
19+
-- Nvim version check
27320
if vim.fn.has("nvim-0.9") == 0 then
274-
notify.warn("nvim-tree.lua requires Neovim 0.9 or higher")
21+
require("nvim-tree.notify").warn("nvim-tree.lua requires Neovim 0.9 or higher")
27522
return
27623
end
27724

278-
M.init_root = vim.fn.getcwd()
279-
25+
-- validate and merge with defaults as config.g
28026
config.setup(config_user)
28127

282-
manage_netrw()
283-
28+
-- optionally create the log file
28429
log.start()
28530

31+
-- optionally log the configuration
28632
if log.enabled("config") then
28733
log.line("config", "default config + user")
28834
log.raw("config", "%s\n", vim.inspect(config.g))
28935
end
29036

291-
require("nvim-tree.appearance").highlight()
37+
-- idempotent highlight definition
38+
appearance.highlight()
29239

293-
require("nvim-tree.view-state").initialize()
40+
-- set the initial view state based on config
41+
view_state.initialize()
29442

295-
setup_autocommands()
43+
-- idempotent au (re)definition
44+
autocmd.global()
29645

46+
-- subsequent calls to setup clear all state
29747
if vim.g.NvimTreeSetup == 1 then
298-
-- subsequent calls to setup
299-
M.purge_all_state()
48+
require("nvim-tree.core").purge_all_state()
30049
end
30150

51+
-- hydrate post setup API
52+
api_impl.hydrate_post_setup(api)
53+
30254
vim.g.NvimTreeSetup = 1
30355
vim.api.nvim_exec_autocmds("User", { pattern = "NvimTreeSetup" })
304-
305-
require("nvim-tree.api.impl").hydrate_post_setup(api)
30656
end
30757

30858
vim.g.NvimTreeRequired = 1

0 commit comments

Comments
 (0)