From 58387dd7ea5fd05f15c345b47eecfc8cd3fd6afb Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Thu, 12 Feb 2026 15:31:51 +1100 Subject: [PATCH 1/9] refactor(#3253): move setup/config related functionality to new module config.lua --- CONTRIBUTING.md | 2 +- lua/nvim-tree.lua | 579 ++----------------------- lua/nvim-tree/_meta/config/default.lua | 2 +- lua/nvim-tree/buffers.lua | 2 +- lua/nvim-tree/config.lua | 510 ++++++++++++++++++++++ lua/nvim-tree/legacy.lua | 3 + scripts/help-defaults.sh | 14 +- 7 files changed, 568 insertions(+), 544 deletions(-) create mode 100644 lua/nvim-tree/config.lua diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 086f807557f..7ff73020ac6 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -142,7 +142,7 @@ Please add or update documentation when you make changes, see `:help dev-lua-doc Help is updated for: - Default keymap at `keymap.on_attach_default` -- Default config at `--- default-config-start` +- Default config at `--- config-default-start` ## Updating And Generating diff --git a/lua/nvim-tree.lua b/lua/nvim-tree.lua index e8c301b9a94..837ededd587 100644 --- a/lua/nvim-tree.lua +++ b/lua/nvim-tree.lua @@ -5,8 +5,7 @@ local utils = require("nvim-tree.utils") local actions = require("nvim-tree.actions") local core = require("nvim-tree.core") local notify = require("nvim-tree.notify") - -local _config = {} +local config = require("nvim-tree.config") local M = { init_root = "", @@ -37,7 +36,7 @@ function M.change_root(path, bufnr) ft = vim.api.nvim_buf_get_option(bufnr, "filetype") or "" ---@diagnostic disable-line: deprecated end - for _, value in pairs(_config.update_focused_file.update_root.ignore_list) do + for _, value in pairs(config.current().update_focused_file.update_root.ignore_list) do if utils.str_find(path, value) or utils.str_find(ft, value) then return end @@ -69,12 +68,12 @@ function M.change_root(path, bufnr) end -- otherwise test M.init_root - if _config.prefer_startup_root and utils.path_relative(path, M.init_root) ~= path then + if config.current().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.root_dirs) do + for _, dir in pairs(config.current().root_dirs) do dir = vim.fn.fnamemodify(dir, ":p") if utils.path_relative(path, dir) ~= path then explorer_fn("change_dir", dir) @@ -96,7 +95,7 @@ function M.tab_enter() ft = vim.api.nvim_buf_get_option(0, "ft") ---@diagnostic disable-line: deprecated end - for _, filter in ipairs(M.config.tab.sync.ignore) do + for _, filter in ipairs(config.current().tab.sync.ignore) do if bufname:match(filter) ~= nil or ft:match(filter) ~= nil then return end @@ -111,7 +110,7 @@ function M.tab_enter() end function M.open_on_directory() - local should_proceed = _config.hijack_directories.auto_open or view.is_visible() + local should_proceed = config.current().hijack_directories.auto_open or view.is_visible() if not should_proceed then return end @@ -131,19 +130,12 @@ function M.open_on_directory() explorer_fn("force_dirchange", bufname, true, false) end ----@return table -function M.get_config() - return M.config -end - ----@param disable_netrw boolean ----@param hijack_netrw boolean -local function manage_netrw(disable_netrw, hijack_netrw) - if hijack_netrw then +local function manage_netrw() + if config.current().hijack_netrw then vim.cmd("silent! autocmd! FileExplorer *") vim.cmd("autocmd VimEnter * ++once silent! autocmd! FileExplorer *") end - if disable_netrw then + if config.current().disable_netrw then vim.g.loaded_netrw = 1 vim.g.loaded_netrwPlugin = 1 end @@ -155,13 +147,12 @@ function M.change_dir(name) explorer_fn("change_dir", name) end - if _config.update_focused_file.update_root.enable then + if config.current().update_focused_file.update_root.enable then actions.tree.find_file.fn() end end ----@param opts table -local function setup_autocommands(opts) +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 } @@ -175,7 +166,7 @@ local function setup_autocommands(opts) if not utils.is_nvim_tree_buf(0) then return end - if opts.actions.open_file.eject then + if config.current().actions.open_file.eject then view._prevent_buffer_override() else view.abandon_current_window() @@ -183,35 +174,35 @@ local function setup_autocommands(opts) end, }) - if opts.tab.sync.open then + if config.current().tab.sync.open then create_nvim_tree_autocmd("TabEnter", { callback = vim.schedule_wrap(M.tab_enter) }) end - if opts.sync_root_with_cwd then + if config.current().sync_root_with_cwd then create_nvim_tree_autocmd("DirChanged", { callback = function() M.change_dir(vim.loop.cwd()) end, }) end - if opts.update_focused_file.enable then + if config.current().update_focused_file.enable then create_nvim_tree_autocmd("BufEnter", { callback = function(event) - local exclude = opts.update_focused_file.exclude + local exclude = config.current().update_focused_file.exclude if type(exclude) == "function" and exclude(event) then return end - utils.debounce("BufEnter:find_file", opts.view.debounce_delay, function() + utils.debounce("BufEnter:find_file", config.current().view.debounce_delay, function() actions.tree.find_file.fn() end) end, }) end - if opts.hijack_directories.enable then + if config.current().hijack_directories.enable and (config.current().disable_netrw or config.current().hijack_netrw) then create_nvim_tree_autocmd({ "BufEnter", "BufNewFile" }, { callback = M.open_on_directory, nested = true }) end - if opts.view.centralize_selection then + if config.current().view.centralize_selection then create_nvim_tree_autocmd("BufEnter", { pattern = "NvimTree_*", callback = function() @@ -228,7 +219,7 @@ local function setup_autocommands(opts) }) end - if opts.diagnostics.enable then + if config.current().diagnostics.enable then create_nvim_tree_autocmd("DiagnosticChanged", { callback = function(ev) log.line("diagnostics", "DiagnosticChanged") @@ -244,7 +235,7 @@ local function setup_autocommands(opts) }) end - if opts.view.float.enable and opts.view.float.quit_on_focus_loss then + if config.current().view.float.enable and config.current().view.float.quit_on_focus_loss then create_nvim_tree_autocmd("WinLeave", { pattern = "NvimTree_*", callback = function() @@ -270,475 +261,6 @@ local function setup_autocommands(opts) }) end ----@type nvim_tree.config -local DEFAULT_OPTS = { -- default-config-start - on_attach = "default", - hijack_cursor = false, - auto_reload_on_write = true, - disable_netrw = false, - hijack_netrw = true, - hijack_unnamed_buffer_when_opening = false, - root_dirs = {}, - prefer_startup_root = false, - sync_root_with_cwd = false, - reload_on_bufenter = false, - respect_buf_cwd = false, - select_prompts = false, - sort = { - sorter = "name", - folders_first = true, - files_first = false, - }, - view = { - centralize_selection = false, - cursorline = true, - cursorlineopt = "both", - debounce_delay = 15, - side = "left", - preserve_window_proportions = false, - number = false, - relativenumber = false, - signcolumn = "yes", - width = 30, - float = { - enable = false, - quit_on_focus_loss = true, - open_win_config = { - relative = "editor", - border = "rounded", - width = 30, - height = 30, - row = 1, - col = 1, - }, - }, - }, - renderer = { - add_trailing = false, - group_empty = false, - full_name = false, - root_folder_label = ":~:s?$?/..?", - indent_width = 2, - special_files = { "Cargo.toml", "Makefile", "README.md", "readme.md" }, - hidden_display = "none", - symlink_destination = true, - decorators = { "Git", "Open", "Hidden", "Modified", "Bookmark", "Diagnostics", "Copied", "Cut", }, - highlight_git = "none", - highlight_diagnostics = "none", - highlight_opened_files = "none", - highlight_modified = "none", - highlight_hidden = "none", - highlight_bookmarks = "none", - highlight_clipboard = "name", - indent_markers = { - enable = false, - inline_arrows = true, - icons = { - corner = "└", - edge = "│", - item = "│", - bottom = "─", - none = " ", - }, - }, - icons = { - web_devicons = { - file = { - enable = true, - color = true, - }, - folder = { - enable = false, - color = true, - }, - }, - git_placement = "before", - modified_placement = "after", - hidden_placement = "after", - diagnostics_placement = "signcolumn", - bookmarks_placement = "signcolumn", - padding = { - icon = " ", - folder_arrow = " ", - }, - symlink_arrow = " ➛ ", - show = { - file = true, - folder = true, - folder_arrow = true, - git = true, - modified = true, - hidden = false, - diagnostics = true, - bookmarks = true, - }, - glyphs = { - default = "", - symlink = "", - bookmark = "󰆤", - modified = "●", - hidden = "󰜌", - folder = { - arrow_closed = "", - arrow_open = "", - default = "", - open = "", - empty = "", - empty_open = "", - symlink = "", - symlink_open = "", - }, - git = { - unstaged = "✗", - staged = "✓", - unmerged = "", - renamed = "➜", - untracked = "★", - deleted = "", - ignored = "◌", - }, - }, - }, - }, - hijack_directories = { - enable = true, - auto_open = true, - }, - update_focused_file = { - enable = false, - update_root = { - enable = false, - ignore_list = {}, - }, - exclude = false, - }, - system_open = { - cmd = "", - args = {}, - }, - git = { - enable = true, - show_on_dirs = true, - show_on_open_dirs = true, - disable_for_dirs = {}, - timeout = 400, - cygwin_support = false, - }, - diagnostics = { - enable = false, - show_on_dirs = false, - show_on_open_dirs = true, - debounce_delay = 500, - severity = { - min = vim.diagnostic.severity.HINT, - max = vim.diagnostic.severity.ERROR, - }, - icons = { - hint = "", - info = "", - warning = "", - error = "", - }, - diagnostic_opts = false, - }, - modified = { - enable = false, - show_on_dirs = true, - show_on_open_dirs = true, - }, - filters = { - enable = true, - git_ignored = true, - dotfiles = false, - git_clean = false, - no_buffer = false, - no_bookmark = false, - custom = {}, - exclude = {}, - }, - live_filter = { - prefix = "[FILTER]: ", - always_show_folders = true, - }, - filesystem_watchers = { - enable = true, - debounce_delay = 50, - max_events = 1000, - ignore_dirs = { - "/.ccls-cache", - "/build", - "/node_modules", - "/target", - }, - }, - actions = { - use_system_clipboard = true, - change_dir = { - enable = true, - global = false, - restrict_above_cwd = false, - }, - expand_all = { - max_folder_discovery = 300, - exclude = {}, - }, - file_popup = { - open_win_config = { - col = 1, - row = 1, - relative = "cursor", - border = "shadow", - style = "minimal", - }, - }, - open_file = { - quit_on_open = false, - eject = true, - resize_window = true, - relative_path = true, - window_picker = { - enable = true, - picker = "default", - chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890", - exclude = { - filetype = { "notify", "packer", "qf", "diff", "fugitive", "fugitiveblame" }, - buftype = { "nofile", "terminal", "help" }, - }, - }, - }, - remove_file = { - close_window = true, - }, - }, - trash = { - cmd = "gio trash", - }, - tab = { - sync = { - open = false, - close = false, - ignore = {}, - }, - }, - notify = { - threshold = vim.log.levels.INFO, - absolute_path = true, - }, - help = { - sort_by = "key", - }, - ui = { - confirm = { - remove = true, - trash = true, - default_yes = false, - }, - }, - bookmarks = { - persist = false, - }, - experimental = { - }, - log = { - enable = false, - truncate = false, - types = { - all = false, - config = false, - copy_paste = false, - dev = false, - diagnostics = false, - git = false, - profile = false, - watcher = false, - }, - }, -} -- default-config-end - -local function merge_options(conf) - return vim.tbl_deep_extend("force", DEFAULT_OPTS, conf or {}) -end - -local FIELD_SKIP_VALIDATE = { - open_win_config = true, -} - -local ACCEPTED_TYPES = { - on_attach = { "function", "string" }, - sort = { - sorter = { "function", "string" }, - }, - view = { - width = { - "string", - "function", - "number", - "table", - min = { "string", "function", "number" }, - max = { "string", "function", "number" }, - lines_excluded = { "table" }, - padding = { "function", "number" }, - }, - }, - renderer = { - hidden_display = { "function", "string" }, - group_empty = { "boolean", "function" }, - root_folder_label = { "function", "string", "boolean" }, - }, - update_focused_file = { - exclude = { "function" }, - }, - git = { - disable_for_dirs = { "function" }, - }, - filters = { - custom = { "function" }, - }, - filesystem_watchers = { - ignore_dirs = { "function" }, - }, - actions = { - open_file = { - window_picker = { - picker = { "function", "string" }, - }, - }, - }, - bookmarks = { - persist = { "boolean", "string" }, - }, -} - -local ACCEPTED_STRINGS = { - sort = { - sorter = { "name", "case_sensitive", "modification_time", "extension", "suffix", "filetype" }, - }, - view = { - side = { "left", "right" }, - signcolumn = { "yes", "no", "auto" }, - }, - renderer = { - hidden_display = { "none", "simple", "all" }, - highlight_git = { "none", "icon", "name", "all" }, - highlight_opened_files = { "none", "icon", "name", "all" }, - highlight_modified = { "none", "icon", "name", "all" }, - highlight_hidden = { "none", "icon", "name", "all" }, - highlight_bookmarks = { "none", "icon", "name", "all" }, - highlight_diagnostics = { "none", "icon", "name", "all" }, - highlight_clipboard = { "none", "icon", "name", "all" }, - icons = { - git_placement = { "before", "after", "signcolumn", "right_align" }, - modified_placement = { "before", "after", "signcolumn", "right_align" }, - hidden_placement = { "before", "after", "signcolumn", "right_align" }, - diagnostics_placement = { "before", "after", "signcolumn", "right_align" }, - bookmarks_placement = { "before", "after", "signcolumn", "right_align" }, - }, - }, - help = { - sort_by = { "key", "desc" }, - }, -} - -local ACCEPTED_ENUMS = { - view = { - width = { - lines_excluded = { "root", }, - }, - }, -} - ----@param conf? nvim_tree.config -local function validate_options(conf) - local msg - - ---@param user any - ---@param def any - ---@param strs table - ---@param types table - ---@param enums table - ---@param prefix string - local function validate(user, def, strs, types, enums, prefix) - -- if user's option is not a table there is nothing to do - if type(user) ~= "table" then - return - end - - -- we have hit a leaf enum to validate against - it's an integer indexed table - local enum_value = type(enums) == "table" and next(enums) and type(next(enums)) == "number" - - -- only compare tables with contents that are not integer indexed nor enums - if not enum_value and (type(def) ~= "table" or not next(def) or type(next(def)) == "number") then - -- unless the field can be a table (and is not a table in default config) - if vim.tbl_contains(types, "table") then - -- use a dummy default to allow all checks - def = {} - else - return - end - end - - for k, v in pairs(user) do - if not FIELD_SKIP_VALIDATE[k] then - local invalid - - if enum_value then - if not vim.tbl_contains(enums, v) then - invalid = string.format("Invalid value for field %s%s: Expected one of enum '%s', got '%s'", prefix, k, - table.concat(enums, "'|'"), tostring(v)) - end - else - if def[k] == nil and types[k] == nil then - -- option does not exist - invalid = string.format("Unknown option: %s%s", prefix, k) - elseif type(v) ~= type(def[k]) then - local expected - - if types[k] and #types[k] > 0 then - if not vim.tbl_contains(types[k], type(v)) then - expected = table.concat(types[k], "|") - end - else - expected = type(def[k]) - end - - if expected then - -- option is of the wrong type - invalid = string.format("Invalid option: %s%s. Expected %s, got %s", prefix, k, expected, type(v)) - end - elseif type(v) == "string" and strs[k] and not vim.tbl_contains(strs[k], v) then - -- option has type `string` but value is not accepted - invalid = string.format("Invalid value for field %s%s: '%s'", prefix, k, v) - end - end - - if invalid then - if msg then - msg = string.format("%s\n%s", msg, invalid) - else - msg = invalid - end - user[k] = nil - elseif not enum_value then - validate(v, def[k], strs[k] or {}, types[k] or {}, enums[k] or {}, prefix .. k .. ".") - end - end - end - end - - validate(conf, DEFAULT_OPTS, ACCEPTED_STRINGS, ACCEPTED_TYPES, ACCEPTED_ENUMS, "") - - if msg then - notify.warn(msg .. "\n\nsee :help nvim-tree-opts for available configuration options") - end -end - ---- Apply OS specific localisations to DEFAULT_OPTS -local function localise_default_opts() - if utils.is_macos or utils.is_windows then - DEFAULT_OPTS.trash.cmd = "trash" - end -end - function M.purge_all_state() view.close_all_tabs() view.abandon_all_windows() @@ -752,6 +274,10 @@ function M.purge_all_state() require("nvim-tree.watcher").purge_watchers() end + +-- TODO #3253 ensure that we can call setup twice + + ---@param conf? nvim_tree.config function M.setup(conf) if vim.fn.has("nvim-0.9") == 0 then @@ -761,49 +287,34 @@ function M.setup(conf) M.init_root = vim.fn.getcwd() - localise_default_opts() - - require("nvim-tree.legacy").migrate_legacy_options(conf or {}) - - validate_options(conf) - - local opts = merge_options(conf) - - local netrw_disabled = opts.disable_netrw or opts.hijack_netrw - - _config.root_dirs = opts.root_dirs - _config.prefer_startup_root = opts.prefer_startup_root - _config.update_focused_file = opts.update_focused_file - _config.hijack_directories = opts.hijack_directories - _config.hijack_directories.enable = _config.hijack_directories.enable and netrw_disabled + config.setup(conf) - manage_netrw(opts.disable_netrw, opts.hijack_netrw) + manage_netrw() - M.config = opts - require("nvim-tree.notify").setup(opts) - require("nvim-tree.log").setup(opts) + require("nvim-tree.notify").setup(config.current()) + require("nvim-tree.log").setup(config.current()) if log.enabled("config") then log.line("config", "default config + user") - log.raw("config", "%s\n", vim.inspect(opts)) + log.raw("config", "%s\n", vim.inspect(config.current())) end - require("nvim-tree.actions").setup(opts) - require("nvim-tree.keymap").setup(opts) + require("nvim-tree.actions").setup(config.current()) + require("nvim-tree.keymap").setup(config.current()) require("nvim-tree.appearance").setup() - require("nvim-tree.diagnostics").setup(opts) - require("nvim-tree.explorer"):setup(opts) - require("nvim-tree.explorer.watch").setup(opts) - require("nvim-tree.git").setup(opts) - require("nvim-tree.git.utils").setup(opts) - require("nvim-tree.view").setup(opts) - require("nvim-tree.lib").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) - - setup_autocommands(opts) + require("nvim-tree.diagnostics").setup(config.current()) + require("nvim-tree.explorer"):setup(config.current()) + require("nvim-tree.explorer.watch").setup(config.current()) + require("nvim-tree.git").setup(config.current()) + require("nvim-tree.git.utils").setup(config.current()) + require("nvim-tree.view").setup(config.current()) + require("nvim-tree.lib").setup(config.current()) + require("nvim-tree.renderer.components").setup(config.current()) + require("nvim-tree.buffers").setup(config.current()) + require("nvim-tree.help").setup(config.current()) + require("nvim-tree.watcher").setup(config.current()) + + setup_autocommands() if vim.g.NvimTreeSetup == 1 then -- subsequent calls to setup diff --git a/lua/nvim-tree/_meta/config/default.lua b/lua/nvim-tree/_meta/config/default.lua index 4db71c02437..f248a259138 100644 --- a/lua/nvim-tree/_meta/config/default.lua +++ b/lua/nvim-tree/_meta/config/default.lua @@ -5,6 +5,6 @@ --- --- ---@type nvim_tree.config --- local config = { ---- default-config-injection-placeholder +--- config-default-injection-placeholder --- } ---``` diff --git a/lua/nvim-tree/buffers.lua b/lua/nvim-tree/buffers.lua index d53c1570df7..4ccbe78adbc 100644 --- a/lua/nvim-tree/buffers.lua +++ b/lua/nvim-tree/buffers.lua @@ -55,7 +55,7 @@ function M.is_opened(node) return node and vim.fn.bufloaded(node.absolute_path) > 0 end ----@param opts table +---@param opts nvim_tree.config function M.setup(opts) M.config = { modified = opts.modified, diff --git a/lua/nvim-tree/config.lua b/lua/nvim-tree/config.lua new file mode 100644 index 00000000000..d49a6b4a0b6 --- /dev/null +++ b/lua/nvim-tree/config.lua @@ -0,0 +1,510 @@ +local notify = require("nvim-tree.notify") +local legacy = require("nvim-tree.legacy") +local utils = require("nvim-tree.utils") + +local M = {} + +-- nil until after setup +---@type nvim_tree.config +local current + +---@type nvim_tree.config +local DEFAULT = { -- config-default-start + on_attach = "default", + hijack_cursor = false, + auto_reload_on_write = true, + disable_netrw = false, + hijack_netrw = true, + hijack_unnamed_buffer_when_opening = false, + root_dirs = {}, + prefer_startup_root = false, + sync_root_with_cwd = false, + reload_on_bufenter = false, + respect_buf_cwd = false, + select_prompts = false, + sort = { + sorter = "name", + folders_first = true, + files_first = false, + }, + view = { + centralize_selection = false, + cursorline = true, + cursorlineopt = "both", + debounce_delay = 15, + side = "left", + preserve_window_proportions = false, + number = false, + relativenumber = false, + signcolumn = "yes", + width = 30, + float = { + enable = false, + quit_on_focus_loss = true, + open_win_config = { + relative = "editor", + border = "rounded", + width = 30, + height = 30, + row = 1, + col = 1, + }, + }, + }, + renderer = { + add_trailing = false, + group_empty = false, + full_name = false, + root_folder_label = ":~:s?$?/..?", + indent_width = 2, + special_files = { "Cargo.toml", "Makefile", "README.md", "readme.md" }, + hidden_display = "none", + symlink_destination = true, + decorators = { "Git", "Open", "Hidden", "Modified", "Bookmark", "Diagnostics", "Copied", "Cut", }, + highlight_git = "none", + highlight_diagnostics = "none", + highlight_opened_files = "none", + highlight_modified = "none", + highlight_hidden = "none", + highlight_bookmarks = "none", + highlight_clipboard = "name", + indent_markers = { + enable = false, + inline_arrows = true, + icons = { + corner = "└", + edge = "│", + item = "│", + bottom = "─", + none = " ", + }, + }, + icons = { + web_devicons = { + file = { + enable = true, + color = true, + }, + folder = { + enable = false, + color = true, + }, + }, + git_placement = "before", + modified_placement = "after", + hidden_placement = "after", + diagnostics_placement = "signcolumn", + bookmarks_placement = "signcolumn", + padding = { + icon = " ", + folder_arrow = " ", + }, + symlink_arrow = " ➛ ", + show = { + file = true, + folder = true, + folder_arrow = true, + git = true, + modified = true, + hidden = false, + diagnostics = true, + bookmarks = true, + }, + glyphs = { + default = "", + symlink = "", + bookmark = "󰆤", + modified = "●", + hidden = "󰜌", + folder = { + arrow_closed = "", + arrow_open = "", + default = "", + open = "", + empty = "", + empty_open = "", + symlink = "", + symlink_open = "", + }, + git = { + unstaged = "✗", + staged = "✓", + unmerged = "", + renamed = "➜", + untracked = "★", + deleted = "", + ignored = "◌", + }, + }, + }, + }, + hijack_directories = { + enable = true, + auto_open = true, + }, + update_focused_file = { + enable = false, + update_root = { + enable = false, + ignore_list = {}, + }, + exclude = false, + }, + system_open = { + cmd = "", + args = {}, + }, + git = { + enable = true, + show_on_dirs = true, + show_on_open_dirs = true, + disable_for_dirs = {}, + timeout = 400, + cygwin_support = false, + }, + diagnostics = { + enable = false, + show_on_dirs = false, + show_on_open_dirs = true, + debounce_delay = 500, + severity = { + min = vim.diagnostic.severity.HINT, + max = vim.diagnostic.severity.ERROR, + }, + icons = { + hint = "", + info = "", + warning = "", + error = "", + }, + diagnostic_opts = false, + }, + modified = { + enable = false, + show_on_dirs = true, + show_on_open_dirs = true, + }, + filters = { + enable = true, + git_ignored = true, + dotfiles = false, + git_clean = false, + no_buffer = false, + no_bookmark = false, + custom = {}, + exclude = {}, + }, + live_filter = { + prefix = "[FILTER]: ", + always_show_folders = true, + }, + filesystem_watchers = { + enable = true, + debounce_delay = 50, + max_events = 1000, + ignore_dirs = { + "/.ccls-cache", + "/build", + "/node_modules", + "/target", + }, + }, + actions = { + use_system_clipboard = true, + change_dir = { + enable = true, + global = false, + restrict_above_cwd = false, + }, + expand_all = { + max_folder_discovery = 300, + exclude = {}, + }, + file_popup = { + open_win_config = { + col = 1, + row = 1, + relative = "cursor", + border = "shadow", + style = "minimal", + }, + }, + open_file = { + quit_on_open = false, + eject = true, + resize_window = true, + relative_path = true, + window_picker = { + enable = true, + picker = "default", + chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890", + exclude = { + filetype = { "notify", "packer", "qf", "diff", "fugitive", "fugitiveblame" }, + buftype = { "nofile", "terminal", "help" }, + }, + }, + }, + remove_file = { + close_window = true, + }, + }, + trash = { + cmd = "gio trash", + }, + tab = { + sync = { + open = false, + close = false, + ignore = {}, + }, + }, + notify = { + threshold = vim.log.levels.INFO, + absolute_path = true, + }, + help = { + sort_by = "key", + }, + ui = { + confirm = { + remove = true, + trash = true, + default_yes = false, + }, + }, + bookmarks = { + persist = false, + }, + experimental = { + }, + log = { + enable = false, + truncate = false, + types = { + all = false, + config = false, + copy_paste = false, + dev = false, + diagnostics = false, + git = false, + profile = false, + watcher = false, + }, + }, +} -- config-default-end + +-- Immediately apply OS specific localisations to defaults +if utils.is_macos or utils.is_windows then + DEFAULT.trash.cmd = "trash" +end + +local FIELD_SKIP_VALIDATE = { + open_win_config = true, +} + +local ACCEPTED_TYPES = { + on_attach = { "function", "string" }, + sort = { + sorter = { "function", "string" }, + }, + view = { + width = { + "string", + "function", + "number", + "table", + min = { "string", "function", "number" }, + max = { "string", "function", "number" }, + lines_excluded = { "table" }, + padding = { "function", "number" }, + }, + }, + renderer = { + hidden_display = { "function", "string" }, + group_empty = { "boolean", "function" }, + root_folder_label = { "function", "string", "boolean" }, + }, + update_focused_file = { + exclude = { "function" }, + }, + git = { + disable_for_dirs = { "function" }, + }, + filters = { + custom = { "function" }, + }, + filesystem_watchers = { + ignore_dirs = { "function" }, + }, + actions = { + open_file = { + window_picker = { + picker = { "function", "string" }, + }, + }, + }, + bookmarks = { + persist = { "boolean", "string" }, + }, +} + +local ACCEPTED_STRINGS = { + sort = { + sorter = { "name", "case_sensitive", "modification_time", "extension", "suffix", "filetype" }, + }, + view = { + side = { "left", "right" }, + signcolumn = { "yes", "no", "auto" }, + }, + renderer = { + hidden_display = { "none", "simple", "all" }, + highlight_git = { "none", "icon", "name", "all" }, + highlight_opened_files = { "none", "icon", "name", "all" }, + highlight_modified = { "none", "icon", "name", "all" }, + highlight_hidden = { "none", "icon", "name", "all" }, + highlight_bookmarks = { "none", "icon", "name", "all" }, + highlight_diagnostics = { "none", "icon", "name", "all" }, + highlight_clipboard = { "none", "icon", "name", "all" }, + icons = { + git_placement = { "before", "after", "signcolumn", "right_align" }, + modified_placement = { "before", "after", "signcolumn", "right_align" }, + hidden_placement = { "before", "after", "signcolumn", "right_align" }, + diagnostics_placement = { "before", "after", "signcolumn", "right_align" }, + bookmarks_placement = { "before", "after", "signcolumn", "right_align" }, + }, + }, + help = { + sort_by = { "key", "desc" }, + }, +} + +local ACCEPTED_ENUMS = { + view = { + width = { + lines_excluded = { "root", }, + }, + }, +} + +---Validate types and values of the user supplied config. +---Warns and removes invalid in place. +---@param config_user nvim_tree.config +local function validate_config(config_user) + local msg + + ---@param user any + ---@param def any + ---@param strs table + ---@param types table + ---@param enums table + ---@param prefix string + local function validate(user, def, strs, types, enums, prefix) + -- if user's option is not a table there is nothing to do + if type(user) ~= "table" then + return + end + + -- we have hit a leaf enum to validate against - it's an integer indexed table + local enum_value = type(enums) == "table" and next(enums) and type(next(enums)) == "number" + + -- only compare tables with contents that are not integer indexed nor enums + if not enum_value and (type(def) ~= "table" or not next(def) or type(next(def)) == "number") then + -- unless the field can be a table (and is not a table in default config) + if vim.tbl_contains(types, "table") then + -- use a dummy default to allow all checks + def = {} + else + return + end + end + + for k, v in pairs(user) do + if not FIELD_SKIP_VALIDATE[k] then + local invalid + + if enum_value then + if not vim.tbl_contains(enums, v) then + invalid = string.format("Invalid value for field %s%s: Expected one of enum '%s', got '%s'", prefix, k, + table.concat(enums, "'|'"), tostring(v)) + end + else + if def[k] == nil and types[k] == nil then + -- option does not exist + invalid = string.format("Unknown option: %s%s", prefix, k) + elseif type(v) ~= type(def[k]) then + local expected + + if types[k] and #types[k] > 0 then + if not vim.tbl_contains(types[k], type(v)) then + expected = table.concat(types[k], "|") + end + else + expected = type(def[k]) + end + + if expected then + -- option is of the wrong type + invalid = string.format("Invalid option: %s%s. Expected %s, got %s", prefix, k, expected, type(v)) + end + elseif type(v) == "string" and strs[k] and not vim.tbl_contains(strs[k], v) then + -- option has type `string` but value is not accepted + invalid = string.format("Invalid value for field %s%s: '%s'", prefix, k, v) + end + end + + if invalid then + if msg then + msg = string.format("%s\n%s", msg, invalid) + else + msg = invalid + end + user[k] = nil + elseif not enum_value then + validate(v, def[k], strs[k] or {}, types[k] or {}, enums[k] or {}, prefix .. k .. ".") + end + end + end + end + + validate(config_user, DEFAULT, ACCEPTED_STRINGS, ACCEPTED_TYPES, ACCEPTED_ENUMS, "") + + if msg then + notify.warn(msg .. "\n\nsee :help nvim-tree-opts for available configuration options") + end +end + +---Validate user config, migrate legacy and merge with defaults. +---Persists as M.current +---If no config passed, M.current will be set to defaults. +---@param config_user? nvim_tree.config user supplied subset of config +function M.setup(config_user) + if not config_user or type(config_user) ~= "table" then + current = vim.deepcopy(DEFAULT) + return + end + + legacy.migrate_legacy_options(config_user) + + validate_config(config_user) + + -- set current to the validated and populated user config + current = vim.tbl_deep_extend("force", DEFAULT, config_user) +end + + +-- TODO #3253 consider returning M.config to avoid the function call overhead + + +---Return the current config +---@return nvim_tree.config returns defaults until after setup +function M.current() + return current or DEFAULT +end + +---Return the default config +---@return nvim_tree.config +function M.default() + return DEFAULT +end + +return M diff --git a/lua/nvim-tree/legacy.lua b/lua/nvim-tree/legacy.lua index 81bb10217e1..13ad0dfe15c 100644 --- a/lua/nvim-tree/legacy.lua +++ b/lua/nvim-tree/legacy.lua @@ -140,6 +140,9 @@ local function removed(opts) opts.create_in_closed_folder = nil end +---Migrate legacy config in place. +---Refactored are silently migrated. Deprecated and removed result in a warning. +---@param opts nvim_tree.config user supplied subset of config function M.migrate_legacy_options(opts) -- silently move refactored(opts) diff --git a/scripts/help-defaults.sh b/scripts/help-defaults.sh index 11ffefe4cc0..6f358705244 100755 --- a/scripts/help-defaults.sh +++ b/scripts/help-defaults.sh @@ -16,18 +16,18 @@ cp "doc/nvim-tree-lua.txt" "${WIP}" # # Inject default config # -begin="default-config-start" -end="default-config-end" -inject="default-config-injection-placeholder" +begin="config-default-start" +end="config-default-end" +inject="config-default-injection-placeholder" -# scrape DEFAULT_OPTS, indented at 2 -sed -n -e "/${begin}/,/${end}/{ /${begin}/d; /${end}/d; p; }" lua/nvim-tree.lua > /tmp/DEFAULT_OPTS.2.lua +# scrape config.default, indented at 2 +sed -n -e "/${begin}/,/${end}/{ /${begin}/d; /${end}/d; p; }" lua/nvim-tree/config.lua > /tmp/config.default.2.lua # indent to match help -sed -e "s/^ / /" /tmp/DEFAULT_OPTS.2.lua > /tmp/DEFAULT_OPTS.6.lua +sed -e "s/^ / /" /tmp/config.default.2.lua > /tmp/config.default.6.lua # inject then remove the placeholder -sed -i -e "/${inject}/r /tmp/DEFAULT_OPTS.6.lua" -e "/${inject}/d" "${WIP}" +sed -i -e "/${inject}/r /tmp/config.default.6.lua" -e "/${inject}/d" "${WIP}" # # Inject default mappings From d8a82bdb18cd95728027227bb3f299626aeb901f Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Fri, 13 Feb 2026 12:32:57 +1100 Subject: [PATCH 2/9] refactor(#3253): add api.config, tidy new config module --- doc/nvim-tree-lua.txt | 22 +++++++ lua/nvim-tree.lua | 74 +++++++++++------------ lua/nvim-tree/_meta/api/config.lua | 33 +++++++++++ lua/nvim-tree/_meta/api/deprecated.lua | 13 ----- lua/nvim-tree/api.lua | 2 +- lua/nvim-tree/api/impl/post.lua | 4 ++ lua/nvim-tree/api/impl/pre.lua | 1 + lua/nvim-tree/config.lua | 81 +++++++++++++++----------- scripts/vimdoc_config.lua | 14 ++++- 9 files changed, 159 insertions(+), 85 deletions(-) create mode 100644 lua/nvim-tree/_meta/api/config.lua diff --git a/doc/nvim-tree-lua.txt b/doc/nvim-tree-lua.txt index 084d429169d..be92d7d37ab 100644 --- a/doc/nvim-tree-lua.txt +++ b/doc/nvim-tree-lua.txt @@ -2382,6 +2382,28 @@ get() *nvim_tree.api.commands.get()* • {opts} (`vim.api.keyset.user_command`) |command-attributes| +============================================================================== +API: config *nvim-tree-api-config* + +default() *nvim_tree.api.config.default()* + Default nvim-tree config. + + Return: ~ + (`nvim_tree.config`) immutable deep clone + +global() *nvim_tree.api.config.global()* + Global current nvim-tree config. + + Return: ~ + (`nvim_tree.config`) immutable deep clone + +user() *nvim_tree.api.config.user()* + Reference to config passed to |nvim-tree-setup| + + Return: ~ + (`nvim_tree.config?`) nil when no config passed to setup + + ============================================================================== API: events *nvim-tree-api-events* diff --git a/lua/nvim-tree.lua b/lua/nvim-tree.lua index 837ededd587..a8a349ec879 100644 --- a/lua/nvim-tree.lua +++ b/lua/nvim-tree.lua @@ -36,7 +36,7 @@ function M.change_root(path, bufnr) ft = vim.api.nvim_buf_get_option(bufnr, "filetype") or "" ---@diagnostic disable-line: deprecated end - for _, value in pairs(config.current().update_focused_file.update_root.ignore_list) do + 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 @@ -68,12 +68,12 @@ function M.change_root(path, bufnr) end -- otherwise test M.init_root - if config.current().prefer_startup_root and utils.path_relative(path, M.init_root) ~= path then + 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.current().root_dirs) do + 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) @@ -95,7 +95,7 @@ function M.tab_enter() ft = vim.api.nvim_buf_get_option(0, "ft") ---@diagnostic disable-line: deprecated end - for _, filter in ipairs(config.current().tab.sync.ignore) do + for _, filter in ipairs(config.g.tab.sync.ignore) do if bufname:match(filter) ~= nil or ft:match(filter) ~= nil then return end @@ -110,7 +110,7 @@ function M.tab_enter() end function M.open_on_directory() - local should_proceed = config.current().hijack_directories.auto_open or view.is_visible() + local should_proceed = config.g.hijack_directories.auto_open or view.is_visible() if not should_proceed then return end @@ -131,11 +131,11 @@ function M.open_on_directory() end local function manage_netrw() - if config.current().hijack_netrw then + if config.g.hijack_netrw then vim.cmd("silent! autocmd! FileExplorer *") vim.cmd("autocmd VimEnter * ++once silent! autocmd! FileExplorer *") end - if config.current().disable_netrw then + if config.g.disable_netrw then vim.g.loaded_netrw = 1 vim.g.loaded_netrwPlugin = 1 end @@ -147,7 +147,7 @@ function M.change_dir(name) explorer_fn("change_dir", name) end - if config.current().update_focused_file.update_root.enable then + if config.g.update_focused_file.update_root.enable then actions.tree.find_file.fn() end end @@ -166,7 +166,7 @@ local function setup_autocommands() if not utils.is_nvim_tree_buf(0) then return end - if config.current().actions.open_file.eject then + if config.g.actions.open_file.eject then view._prevent_buffer_override() else view.abandon_current_window() @@ -174,35 +174,35 @@ local function setup_autocommands() end, }) - if config.current().tab.sync.open then + if config.g.tab.sync.open then create_nvim_tree_autocmd("TabEnter", { callback = vim.schedule_wrap(M.tab_enter) }) end - if config.current().sync_root_with_cwd then + if config.g.sync_root_with_cwd then create_nvim_tree_autocmd("DirChanged", { callback = function() M.change_dir(vim.loop.cwd()) end, }) end - if config.current().update_focused_file.enable then + if config.g.update_focused_file.enable then create_nvim_tree_autocmd("BufEnter", { callback = function(event) - local exclude = config.current().update_focused_file.exclude + local exclude = config.g.update_focused_file.exclude if type(exclude) == "function" and exclude(event) then return end - utils.debounce("BufEnter:find_file", config.current().view.debounce_delay, function() + utils.debounce("BufEnter:find_file", config.g.view.debounce_delay, function() actions.tree.find_file.fn() end) end, }) end - if config.current().hijack_directories.enable and (config.current().disable_netrw or config.current().hijack_netrw) then + 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 }) end - if config.current().view.centralize_selection then + if config.g.view.centralize_selection then create_nvim_tree_autocmd("BufEnter", { pattern = "NvimTree_*", callback = function() @@ -219,7 +219,7 @@ local function setup_autocommands() }) end - if config.current().diagnostics.enable then + if config.g.diagnostics.enable then create_nvim_tree_autocmd("DiagnosticChanged", { callback = function(ev) log.line("diagnostics", "DiagnosticChanged") @@ -235,7 +235,7 @@ local function setup_autocommands() }) end - if config.current().view.float.enable and config.current().view.float.quit_on_focus_loss then + if config.g.view.float.enable and config.g.view.float.quit_on_focus_loss then create_nvim_tree_autocmd("WinLeave", { pattern = "NvimTree_*", callback = function() @@ -278,8 +278,8 @@ end -- TODO #3253 ensure that we can call setup twice ----@param conf? nvim_tree.config -function M.setup(conf) +---@param config_user? nvim_tree.config user supplied subset of config +function M.setup(config_user) if vim.fn.has("nvim-0.9") == 0 then notify.warn("nvim-tree.lua requires Neovim 0.9 or higher") return @@ -287,32 +287,32 @@ function M.setup(conf) M.init_root = vim.fn.getcwd() - config.setup(conf) + config.setup(config_user) manage_netrw() - require("nvim-tree.notify").setup(config.current()) - require("nvim-tree.log").setup(config.current()) + require("nvim-tree.notify").setup(config.g) + require("nvim-tree.log").setup(config.g) if log.enabled("config") then log.line("config", "default config + user") - log.raw("config", "%s\n", vim.inspect(config.current())) + log.raw("config", "%s\n", vim.inspect(config.g)) end - require("nvim-tree.actions").setup(config.current()) - require("nvim-tree.keymap").setup(config.current()) + require("nvim-tree.actions").setup(config.g) + require("nvim-tree.keymap").setup(config.g) require("nvim-tree.appearance").setup() - require("nvim-tree.diagnostics").setup(config.current()) - require("nvim-tree.explorer"):setup(config.current()) - require("nvim-tree.explorer.watch").setup(config.current()) - require("nvim-tree.git").setup(config.current()) - require("nvim-tree.git.utils").setup(config.current()) - require("nvim-tree.view").setup(config.current()) - require("nvim-tree.lib").setup(config.current()) - require("nvim-tree.renderer.components").setup(config.current()) - require("nvim-tree.buffers").setup(config.current()) - require("nvim-tree.help").setup(config.current()) - require("nvim-tree.watcher").setup(config.current()) + require("nvim-tree.diagnostics").setup(config.g) + require("nvim-tree.explorer"):setup(config.g) + require("nvim-tree.explorer.watch").setup(config.g) + require("nvim-tree.git").setup(config.g) + require("nvim-tree.git.utils").setup(config.g) + require("nvim-tree.view").setup(config.g) + require("nvim-tree.lib").setup(config.g) + require("nvim-tree.renderer.components").setup(config.g) + require("nvim-tree.buffers").setup(config.g) + require("nvim-tree.help").setup(config.g) + require("nvim-tree.watcher").setup(config.g) setup_autocommands() diff --git a/lua/nvim-tree/_meta/api/config.lua b/lua/nvim-tree/_meta/api/config.lua new file mode 100644 index 00000000000..1db99f3d64f --- /dev/null +++ b/lua/nvim-tree/_meta/api/config.lua @@ -0,0 +1,33 @@ +---@meta +local nvim_tree = { api = { config = {} } } + +--- +---Default nvim-tree config. +--- +---@return nvim_tree.config immutable deep clone +function nvim_tree.api.config.default() end + +--- +---Global current nvim-tree config. +--- +---@return nvim_tree.config immutable deep clone +function nvim_tree.api.config.global() end + +--- +---Reference to config passed to [nvim-tree-setup] +--- +---@return nvim_tree.config? nil when no config passed to setup +function nvim_tree.api.config.user() end + +nvim_tree.api.config.mappings = {} + +---@deprecated use `nvim_tree.api.map.keymap.current()` +function nvim_tree.api.config.mappings.get_keymap() end + +---@deprecated use `nvim_tree.api.map.keymap.default()` +function nvim_tree.api.config.mappings.get_keymap_default() end + +---@deprecated use `nvim_tree.api.map.on_attach.default()` +function nvim_tree.api.config.mappings.default_on_attach(bufnr) end + +return nvim_tree.api.config diff --git a/lua/nvim-tree/_meta/api/deprecated.lua b/lua/nvim-tree/_meta/api/deprecated.lua index 3bfe136162a..cdb5b40a95a 100644 --- a/lua/nvim-tree/_meta/api/deprecated.lua +++ b/lua/nvim-tree/_meta/api/deprecated.lua @@ -4,19 +4,6 @@ local nvim_tree = { api = {} } -nvim_tree.api.config = {} - -nvim_tree.api.config.mappings = {} - ----@deprecated use `nvim_tree.api.map.keymap.current()` -function nvim_tree.api.config.mappings.get_keymap() end - ----@deprecated use `nvim_tree.api.map.keymap.default()` -function nvim_tree.api.config.mappings.get_keymap_default() end - ----@deprecated use `nvim_tree.api.map.on_attach.default()` -function nvim_tree.api.config.mappings.default_on_attach(bufnr) end - nvim_tree.api.live_filter = {} ---@deprecated use `nvim_tree.api.filter.live.start()` diff --git a/lua/nvim-tree/api.lua b/lua/nvim-tree/api.lua index b90a9e1a1e9..0e9d6d45c5c 100644 --- a/lua/nvim-tree/api.lua +++ b/lua/nvim-tree/api.lua @@ -77,6 +77,7 @@ local api = { appearance = require("nvim-tree._meta.api.appearance"), commands = require("nvim-tree._meta.api.commands"), + config = require("nvim-tree._meta.api.config"), events = require("nvim-tree._meta.api.events"), filter = require("nvim-tree._meta.api.filter"), fs = require("nvim-tree._meta.api.fs"), @@ -88,7 +89,6 @@ local api = { Decorator = require("nvim-tree._meta.api.decorator"), - config = require("nvim-tree._meta.api.deprecated").config, ---@deprecated decorator = require("nvim-tree._meta.api.deprecated").decorator, ---@deprecated diagnostics = require("nvim-tree._meta.api.deprecated").diagnostics, ---@deprecated live_filter = require("nvim-tree._meta.api.deprecated").live_filter, ---@deprecated diff --git a/lua/nvim-tree/api/impl/post.lua b/lua/nvim-tree/api/impl/post.lua index 11c4b5ede14..b3937467904 100644 --- a/lua/nvim-tree/api/impl/post.lua +++ b/lua/nvim-tree/api/impl/post.lua @@ -9,6 +9,7 @@ local legacy = require("nvim-tree.legacy") local actions = require("nvim-tree.actions") +local config = require("nvim-tree.config") local help = require("nvim-tree.help") local keymap = require("nvim-tree.keymap") local utils = require("nvim-tree.utils") @@ -257,6 +258,9 @@ function M.hydrate(api) api.map.keymap.current = keymap.get_keymap + api.config.global = config.g_clone + api.config.user = config.u_clone + -- (Re)hydrate any legacy by mapping to concrete set above legacy.map_api(api) end diff --git a/lua/nvim-tree/api/impl/pre.lua b/lua/nvim-tree/api/impl/pre.lua index 1191b906734..93c5849b62a 100644 --- a/lua/nvim-tree/api/impl/pre.lua +++ b/lua/nvim-tree/api/impl/pre.lua @@ -49,6 +49,7 @@ function M.hydrate(api) -- lazy functions api.appearance.hi_test = function() require("nvim-tree.appearance.hi-test")() end + api.config.default = function() return require("nvim-tree.config").d_clone() end -- classes api.Decorator = Decorator:extend() diff --git a/lua/nvim-tree/config.lua b/lua/nvim-tree/config.lua index d49a6b4a0b6..2074169b587 100644 --- a/lua/nvim-tree/config.lua +++ b/lua/nvim-tree/config.lua @@ -2,14 +2,20 @@ local notify = require("nvim-tree.notify") local legacy = require("nvim-tree.legacy") local utils = require("nvim-tree.utils") -local M = {} +-- short names like g are used to keep code brief --- nil until after setup ----@type nvim_tree.config -local current +local M = { + ---@type nvim_tree.config immutable default config + d = {}, ----@type nvim_tree.config -local DEFAULT = { -- config-default-start + ---@type nvim_tree.config? global current config, nil until after setup + g = nil, + + ---@type nvim_tree.config? raw user config, nil when no user config supplied + u = nil, +} + +M.d = { -- config-default-start on_attach = "default", hijack_cursor = false, auto_reload_on_write = true, @@ -295,7 +301,7 @@ local DEFAULT = { -- config-default-start -- Immediately apply OS specific localisations to defaults if utils.is_macos or utils.is_windows then - DEFAULT.trash.cmd = "trash" + M.d.trash.cmd = "trash" end local FIELD_SKIP_VALIDATE = { @@ -388,8 +394,8 @@ local ACCEPTED_ENUMS = { ---Validate types and values of the user supplied config. ---Warns and removes invalid in place. ----@param config_user nvim_tree.config -local function validate_config(config_user) +---@param u nvim_tree.config +local function validate_config(u) local msg ---@param user any @@ -466,45 +472,54 @@ local function validate_config(config_user) end end - validate(config_user, DEFAULT, ACCEPTED_STRINGS, ACCEPTED_TYPES, ACCEPTED_ENUMS, "") + validate(u, M.d, ACCEPTED_STRINGS, ACCEPTED_TYPES, ACCEPTED_ENUMS, "") if msg then - notify.warn(msg .. "\n\nsee :help nvim-tree-opts for available configuration options") + notify.warn(msg .. "\n\nsee :help nvim-tree-config for available configuration options") end end ----Validate user config, migrate legacy and merge with defaults. ----Persists as M.current ----If no config passed, M.current will be set to defaults. ----@param config_user? nvim_tree.config user supplied subset of config -function M.setup(config_user) - if not config_user or type(config_user) ~= "table" then - current = vim.deepcopy(DEFAULT) +---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 +---@param u? nvim_tree.config user supplied subset of config +function M.setup(u) + if not u or type(u) ~= "table" then + if u then + notify.warn(string.format("invalid config type \"%s\" passed to setup, using defaults", type(u))) + end + M.g = vim.deepcopy(M.d) + M.u = nil return end - legacy.migrate_legacy_options(config_user) - - validate_config(config_user) + -- retain user for reference + M.u = vim.deepcopy(u) - -- set current to the validated and populated user config - current = vim.tbl_deep_extend("force", DEFAULT, config_user) -end + legacy.migrate_legacy_options(u) + validate_config(u) --- TODO #3253 consider returning M.config to avoid the function call overhead + -- set global to the validated and populated user config + M.g = vim.tbl_deep_extend("force", M.d, u) +end +---Deep clone defaults +---@return nvim_tree.config +function M.d_clone() + return vim.deepcopy(M.d) +end ----Return the current config ----@return nvim_tree.config returns defaults until after setup -function M.current() - return current or DEFAULT +---Deep clone user +---@return nvim_tree.config? nil when no config passed to setup +function M.u_clone() + return vim.deepcopy(M.u) end ----Return the default config ----@return nvim_tree.config -function M.default() - return DEFAULT +---Deep clone global +---@return nvim_tree.config? nil when setup not called +function M.g_clone() + return vim.deepcopy(M.g) end return M diff --git a/scripts/vimdoc_config.lua b/scripts/vimdoc_config.lua index 56b63e93844..7d19e895baa 100644 --- a/scripts/vimdoc_config.lua +++ b/scripts/vimdoc_config.lua @@ -58,7 +58,19 @@ local srcs_api = { { helptag = "nvim-tree-api-node", section = "API: node", path = base .. "_meta/api/node.lua", }, { helptag = "nvim-tree-api-tree", section = "API: tree", path = base .. "_meta/api/tree.lua", }, - { helptag = "nvim-tree-class", section = "PLACEHOLDER", path = placeholder, }, + { helptag = "nvim-tree-api-commands", section = "API: commands", path = base .. "_meta/api/commands.lua", }, + { helptag = "nvim-tree-api-config", section = "API: config", path = base .. "_meta/api/config.lua", }, + { helptag = "nvim-tree-api-events", section = "API: events", path = base .. "_meta/api/events.lua", }, + { helptag = "nvim-tree-api-filter", section = "API: filter", path = base .. "_meta/api/filter.lua", }, + { helptag = "nvim-tree-api-fs", section = "API: fs", path = base .. "_meta/api/fs.lua", }, + { helptag = "nvim-tree-api-git", section = "API: git", path = base .. "_meta/api/git.lua", }, + { helptag = "nvim-tree-api-health", section = "API: health", path = base .. "_meta/api/health.lua", }, + { helptag = "nvim-tree-api-map", section = "API: map", path = base .. "_meta/api/map.lua", }, + { helptag = "nvim-tree-api-marks", section = "API: marks", path = base .. "_meta/api/marks.lua", }, + { helptag = "nvim-tree-api-node", section = "API: node", path = base .. "_meta/api/node.lua", }, + { helptag = "nvim-tree-api-tree", section = "API: tree", path = base .. "_meta/api/tree.lua", }, + + { helptag = "nvim-tree-class", section = "PLACEHOLDER", path = placeholder, }, } ---@type Src[] From 7c5893ba01e0c643b649ae040b6a33d7fdc91d15 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Fri, 13 Feb 2026 12:49:51 +1100 Subject: [PATCH 3/9] refactor(#3253): add api.config, tidy new config module --- lua/nvim-tree/config.lua | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/lua/nvim-tree/config.lua b/lua/nvim-tree/config.lua index 2074169b587..0b656b5ffea 100644 --- a/lua/nvim-tree/config.lua +++ b/lua/nvim-tree/config.lua @@ -1,17 +1,20 @@ +--This will be required after api, before setup. +--This file should have minimal requires that are cheap and have no dependencies or are already required. + local notify = require("nvim-tree.notify") local legacy = require("nvim-tree.legacy") local utils = require("nvim-tree.utils") --- short names like g are used to keep code brief +-- short names like g are used rather than getters to keep code brief local M = { ---@type nvim_tree.config immutable default config d = {}, - ---@type nvim_tree.config? global current config, nil until after setup + ---@type nvim_tree.config? global current config, nil until setup called g = nil, - ---@type nvim_tree.config? raw user config, nil when no user config supplied + ---@type nvim_tree.config? raw user config, nil when no user config passed to setup u = nil, } From 9bc98d9860c8430a7645f6b1eac39fc98164da35 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Fri, 13 Feb 2026 13:22:47 +1100 Subject: [PATCH 4/9] refactor(#3253): add api.config, tidy new config module --- lua/nvim-tree.lua | 3 --- 1 file changed, 3 deletions(-) diff --git a/lua/nvim-tree.lua b/lua/nvim-tree.lua index a8a349ec879..b2acbb27142 100644 --- a/lua/nvim-tree.lua +++ b/lua/nvim-tree.lua @@ -275,9 +275,6 @@ function M.purge_all_state() end --- TODO #3253 ensure that we can call setup twice - - ---@param config_user? nvim_tree.config user supplied subset of config function M.setup(config_user) if vim.fn.has("nvim-0.9") == 0 then From 3ba80994dfbe484cf5a91cd9009b1aec62130638 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Sat, 14 Feb 2026 11:25:26 +1100 Subject: [PATCH 5/9] refactor(#3253): format --- scripts/vimdoc_config.lua | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/scripts/vimdoc_config.lua b/scripts/vimdoc_config.lua index 7d19e895baa..7173e380364 100644 --- a/scripts/vimdoc_config.lua +++ b/scripts/vimdoc_config.lua @@ -58,19 +58,19 @@ local srcs_api = { { helptag = "nvim-tree-api-node", section = "API: node", path = base .. "_meta/api/node.lua", }, { helptag = "nvim-tree-api-tree", section = "API: tree", path = base .. "_meta/api/tree.lua", }, - { helptag = "nvim-tree-api-commands", section = "API: commands", path = base .. "_meta/api/commands.lua", }, - { helptag = "nvim-tree-api-config", section = "API: config", path = base .. "_meta/api/config.lua", }, - { helptag = "nvim-tree-api-events", section = "API: events", path = base .. "_meta/api/events.lua", }, - { helptag = "nvim-tree-api-filter", section = "API: filter", path = base .. "_meta/api/filter.lua", }, - { helptag = "nvim-tree-api-fs", section = "API: fs", path = base .. "_meta/api/fs.lua", }, - { helptag = "nvim-tree-api-git", section = "API: git", path = base .. "_meta/api/git.lua", }, - { helptag = "nvim-tree-api-health", section = "API: health", path = base .. "_meta/api/health.lua", }, - { helptag = "nvim-tree-api-map", section = "API: map", path = base .. "_meta/api/map.lua", }, - { helptag = "nvim-tree-api-marks", section = "API: marks", path = base .. "_meta/api/marks.lua", }, - { helptag = "nvim-tree-api-node", section = "API: node", path = base .. "_meta/api/node.lua", }, - { helptag = "nvim-tree-api-tree", section = "API: tree", path = base .. "_meta/api/tree.lua", }, - - { helptag = "nvim-tree-class", section = "PLACEHOLDER", path = placeholder, }, + { helptag = "nvim-tree-api-commands", section = "API: commands", path = base .. "_meta/api/commands.lua", }, + { helptag = "nvim-tree-api-config", section = "API: config", path = base .. "_meta/api/config.lua", }, + { helptag = "nvim-tree-api-events", section = "API: events", path = base .. "_meta/api/events.lua", }, + { helptag = "nvim-tree-api-filter", section = "API: filter", path = base .. "_meta/api/filter.lua", }, + { helptag = "nvim-tree-api-fs", section = "API: fs", path = base .. "_meta/api/fs.lua", }, + { helptag = "nvim-tree-api-git", section = "API: git", path = base .. "_meta/api/git.lua", }, + { helptag = "nvim-tree-api-health", section = "API: health", path = base .. "_meta/api/health.lua", }, + { helptag = "nvim-tree-api-map", section = "API: map", path = base .. "_meta/api/map.lua", }, + { helptag = "nvim-tree-api-marks", section = "API: marks", path = base .. "_meta/api/marks.lua", }, + { helptag = "nvim-tree-api-node", section = "API: node", path = base .. "_meta/api/node.lua", }, + { helptag = "nvim-tree-api-tree", section = "API: tree", path = base .. "_meta/api/tree.lua", }, + + { helptag = "nvim-tree-class", section = "PLACEHOLDER", path = placeholder, }, } ---@type Src[] From f59f986b63b56540f9d8bacc8f48353ab0eb14da Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Sat, 14 Feb 2026 11:36:35 +1100 Subject: [PATCH 6/9] refactor(#3256): fix doc generator --- scripts/vimdoc_config.lua | 1 - 1 file changed, 1 deletion(-) diff --git a/scripts/vimdoc_config.lua b/scripts/vimdoc_config.lua index 7173e380364..9e8e0063250 100644 --- a/scripts/vimdoc_config.lua +++ b/scripts/vimdoc_config.lua @@ -64,7 +64,6 @@ local srcs_api = { { helptag = "nvim-tree-api-filter", section = "API: filter", path = base .. "_meta/api/filter.lua", }, { helptag = "nvim-tree-api-fs", section = "API: fs", path = base .. "_meta/api/fs.lua", }, { helptag = "nvim-tree-api-git", section = "API: git", path = base .. "_meta/api/git.lua", }, - { helptag = "nvim-tree-api-health", section = "API: health", path = base .. "_meta/api/health.lua", }, { helptag = "nvim-tree-api-map", section = "API: map", path = base .. "_meta/api/map.lua", }, { helptag = "nvim-tree-api-marks", section = "API: marks", path = base .. "_meta/api/marks.lua", }, { helptag = "nvim-tree-api-node", section = "API: node", path = base .. "_meta/api/node.lua", }, From ac82ad4d553ab5bfda6e2710c4a22d8a14cf44c0 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Sat, 14 Feb 2026 11:41:39 +1100 Subject: [PATCH 7/9] refactor(#3256): fix doc generator --- scripts/vimdoc_config.lua | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/scripts/vimdoc_config.lua b/scripts/vimdoc_config.lua index 9e8e0063250..3eecfabb9a3 100644 --- a/scripts/vimdoc_config.lua +++ b/scripts/vimdoc_config.lua @@ -48,16 +48,6 @@ local srcs_config = { local srcs_api = { { helptag = "nvim-tree-api", section = "API", path = base .. "api.lua", }, { helptag = "nvim-tree-api-appearance", section = "API: appearance", path = base .. "_meta/api/appearance.lua", }, - { helptag = "nvim-tree-api-commands", section = "API: commands", path = base .. "_meta/api/commands.lua", }, - { helptag = "nvim-tree-api-events", section = "API: events", path = base .. "_meta/api/events.lua", }, - { helptag = "nvim-tree-api-filter", section = "API: filter", path = base .. "_meta/api/filter.lua", }, - { helptag = "nvim-tree-api-fs", section = "API: fs", path = base .. "_meta/api/fs.lua", }, - { helptag = "nvim-tree-api-git", section = "API: git", path = base .. "_meta/api/git.lua", }, - { helptag = "nvim-tree-api-map", section = "API: map", path = base .. "_meta/api/map.lua", }, - { helptag = "nvim-tree-api-marks", section = "API: marks", path = base .. "_meta/api/marks.lua", }, - { helptag = "nvim-tree-api-node", section = "API: node", path = base .. "_meta/api/node.lua", }, - { helptag = "nvim-tree-api-tree", section = "API: tree", path = base .. "_meta/api/tree.lua", }, - { helptag = "nvim-tree-api-commands", section = "API: commands", path = base .. "_meta/api/commands.lua", }, { helptag = "nvim-tree-api-config", section = "API: config", path = base .. "_meta/api/config.lua", }, { helptag = "nvim-tree-api-events", section = "API: events", path = base .. "_meta/api/events.lua", }, From d3a71f215bae89c5d482dd99ac11e76a952bd01e Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Tue, 17 Feb 2026 11:50:00 +1100 Subject: [PATCH 8/9] refactor(#3256): strongly type legacy config --- lua/nvim-tree.lua | 1 - lua/nvim-tree/config.lua | 2 +- lua/nvim-tree/legacy.lua | 33 ++++++++++++++++++--------------- 3 files changed, 19 insertions(+), 17 deletions(-) diff --git a/lua/nvim-tree.lua b/lua/nvim-tree.lua index b2acbb27142..d4192539d30 100644 --- a/lua/nvim-tree.lua +++ b/lua/nvim-tree.lua @@ -274,7 +274,6 @@ function M.purge_all_state() require("nvim-tree.watcher").purge_watchers() end - ---@param config_user? nvim_tree.config user supplied subset of config function M.setup(config_user) if vim.fn.has("nvim-0.9") == 0 then diff --git a/lua/nvim-tree/config.lua b/lua/nvim-tree/config.lua index 0b656b5ffea..0129f9e13e2 100644 --- a/lua/nvim-tree/config.lua +++ b/lua/nvim-tree/config.lua @@ -499,7 +499,7 @@ function M.setup(u) -- retain user for reference M.u = vim.deepcopy(u) - legacy.migrate_legacy_options(u) + legacy.migrate_config(u) validate_config(u) diff --git a/lua/nvim-tree/legacy.lua b/lua/nvim-tree/legacy.lua index 13ad0dfe15c..cfb3a9028e2 100644 --- a/lua/nvim-tree/legacy.lua +++ b/lua/nvim-tree/legacy.lua @@ -50,8 +50,9 @@ local function move(src, src_path, src_pos, dst, dst_path, dst_pos, remove) end end --- silently move, please add to help nvim-tree-legacy-opts -local function refactored(opts) +-- silently move, please add to help nvim-tree-legacy-config +---@param opts nvim_tree.config user supplied subset of config +local function refactored_config(opts) -- 2022/06/20 move(opts, "update_focused_file", "update_cwd", opts, "update_focused_file", "update_root", true) move(opts, "", "update_cwd", opts, "", "sync_root_with_cwd", true) @@ -73,12 +74,12 @@ local function refactored(opts) -- 2023/01/15 if type(opts.view) == "table" and opts.view.adaptive_size ~= nil then if opts.view.adaptive_size and type(opts.view.width) ~= "table" then - local width = opts.view.width + local width = opts.view.width --[[@as nvim_tree.config.view.width.spec]] opts.view.width = { min = width, } end - opts.view.adaptive_size = nil + opts.view["adaptive_size"] = nil end -- 2023/07/15 @@ -103,55 +104,57 @@ local function refactored(opts) -- 2024/02/15 if type(opts.update_focused_file) == "table" then if type(opts.update_focused_file.update_root) ~= "table" then - opts.update_focused_file.update_root = { enable = opts.update_focused_file.update_root } + opts.update_focused_file.update_root = { enable = opts.update_focused_file.update_root == true } end end move(opts, "update_focused_file", "ignore_list", opts, "update_focused_file.update_root", "ignore_list", true) -- 2025/04/30 if opts.renderer and opts.renderer.icons and type(opts.renderer.icons.padding) == "string" then - local icons_padding = opts.renderer.icons.padding + local icons_padding = opts.renderer.icons.padding --[[@as string]] opts.renderer.icons.padding = {} opts.renderer.icons.padding.icon = icons_padding end end -local function deprecated(opts) +---@param opts nvim_tree.config user supplied subset of config +local function deprecated_config(opts) if type(opts.view) == "table" and opts.view.hide_root_folder then notify.info("view.hide_root_folder is deprecated, please set renderer.root_folder_label = false") end end -local function removed(opts) +---@param opts nvim_tree.config user supplied subset of config +local function removed_config(opts) if opts.auto_close then notify.warn("auto close feature has been removed: https://github.com/nvim-tree/nvim-tree.lua/wiki/Auto-Close") - opts.auto_close = nil + opts["auto_close"] = nil end if opts.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") - opts.focus_empty_on_setup = nil + opts["focus_empty_on_setup"] = nil end if opts.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.") end - opts.create_in_closed_folder = nil + opts["create_in_closed_folder"] = nil end ---Migrate legacy config in place. ---Refactored are silently migrated. Deprecated and removed result in a warning. ---@param opts nvim_tree.config user supplied subset of config -function M.migrate_legacy_options(opts) +function M.migrate_config(opts) -- silently move - refactored(opts) + refactored_config(opts) -- warn - deprecated(opts) + deprecated_config(opts) -- warn and delete - removed(opts) + removed_config(opts) end ---Silently create new api entries pointing legacy functions to current From bec7fcf0399eafdabfabba5a9534c831b4a2d2c5 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Tue, 17 Feb 2026 11:51:45 +1100 Subject: [PATCH 9/9] refactor(#3256): legacy config consistent parameter naming --- lua/nvim-tree/legacy.lua | 92 ++++++++++++++++++++-------------------- 1 file changed, 46 insertions(+), 46 deletions(-) diff --git a/lua/nvim-tree/legacy.lua b/lua/nvim-tree/legacy.lua index cfb3a9028e2..7d42338abd5 100644 --- a/lua/nvim-tree/legacy.lua +++ b/lua/nvim-tree/legacy.lua @@ -51,110 +51,110 @@ local function move(src, src_path, src_pos, dst, dst_path, dst_pos, remove) end -- silently move, please add to help nvim-tree-legacy-config ----@param opts nvim_tree.config user supplied subset of config -local function refactored_config(opts) +---@param u nvim_tree.config user supplied subset of config +local function refactored_config(u) -- 2022/06/20 - move(opts, "update_focused_file", "update_cwd", opts, "update_focused_file", "update_root", true) - move(opts, "", "update_cwd", opts, "", "sync_root_with_cwd", true) + move(u, "update_focused_file", "update_cwd", u, "update_focused_file", "update_root", true) + move(u, "", "update_cwd", u, "", "sync_root_with_cwd", true) -- 2022/11/07 - move(opts, "", "open_on_tab", opts, "tab.sync", "open", false) - move(opts, "", "open_on_tab", opts, "tab.sync", "close", true) - move(opts, "", "ignore_buf_on_tab_change", opts, "tab.sync", "ignore", true) + move(u, "", "open_on_tab", u, "tab.sync", "open", false) + move(u, "", "open_on_tab", u, "tab.sync", "close", true) + move(u, "", "ignore_buf_on_tab_change", u, "tab.sync", "ignore", true) -- 2022/11/22 - move(opts, "renderer", "root_folder_modifier", opts, "renderer", "root_folder_label", true) + move(u, "renderer", "root_folder_modifier", u, "renderer", "root_folder_label", true) -- 2023/01/01 - move(opts, "update_focused_file", "debounce_delay", opts, "view", "debounce_delay", true) + move(u, "update_focused_file", "debounce_delay", u, "view", "debounce_delay", true) -- 2023/01/08 - move(opts, "trash", "require_confirm", opts, "ui.confirm", "trash", true) + move(u, "trash", "require_confirm", u, "ui.confirm", "trash", true) -- 2023/01/15 - if type(opts.view) == "table" and opts.view.adaptive_size ~= nil then - if opts.view.adaptive_size and type(opts.view.width) ~= "table" then - local width = opts.view.width --[[@as nvim_tree.config.view.width.spec]] - opts.view.width = { + if type(u.view) == "table" and u.view.adaptive_size ~= nil then + if u.view.adaptive_size and type(u.view.width) ~= "table" then + local width = u.view.width --[[@as nvim_tree.config.view.width.spec]] + u.view.width = { min = width, } end - opts.view["adaptive_size"] = nil + u.view["adaptive_size"] = nil end -- 2023/07/15 - move(opts, "", "sort_by", opts, "sort", "sorter", true) + move(u, "", "sort_by", u, "sort", "sorter", true) -- 2023/07/16 - move(opts, "git", "ignore", opts, "filters", "git_ignored", true) + move(u, "git", "ignore", u, "filters", "git_ignored", true) -- 2023/08/26 - move(opts, "renderer.icons", "webdev_colors", opts, "renderer.icons.web_devicons.file", "color", true) + move(u, "renderer.icons", "webdev_colors", u, "renderer.icons.web_devicons.file", "color", true) -- 2023/10/08 - if type(opts.renderer) == "table" and type(opts.renderer.highlight_diagnostics) == "boolean" then - opts.renderer.highlight_diagnostics = opts.renderer.highlight_diagnostics and "name" or "none" + if type(u.renderer) == "table" and type(u.renderer.highlight_diagnostics) == "boolean" then + u.renderer.highlight_diagnostics = u.renderer.highlight_diagnostics and "name" or "none" end -- 2023/10/21 - if type(opts.renderer) == "table" and type(opts.renderer.highlight_git) == "boolean" then - opts.renderer.highlight_git = opts.renderer.highlight_git and "name" or "none" + if type(u.renderer) == "table" and type(u.renderer.highlight_git) == "boolean" then + u.renderer.highlight_git = u.renderer.highlight_git and "name" or "none" end -- 2024/02/15 - if type(opts.update_focused_file) == "table" then - if type(opts.update_focused_file.update_root) ~= "table" then - opts.update_focused_file.update_root = { enable = opts.update_focused_file.update_root == true } + if type(u.update_focused_file) == "table" then + if type(u.update_focused_file.update_root) ~= "table" then + u.update_focused_file.update_root = { enable = u.update_focused_file.update_root == true } end end - move(opts, "update_focused_file", "ignore_list", opts, "update_focused_file.update_root", "ignore_list", true) + move(u, "update_focused_file", "ignore_list", u, "update_focused_file.update_root", "ignore_list", true) -- 2025/04/30 - if opts.renderer and opts.renderer.icons and type(opts.renderer.icons.padding) == "string" then - local icons_padding = opts.renderer.icons.padding --[[@as string]] - opts.renderer.icons.padding = {} - opts.renderer.icons.padding.icon = icons_padding + if u.renderer and u.renderer.icons and type(u.renderer.icons.padding) == "string" then + local icons_padding = u.renderer.icons.padding --[[@as string]] + u.renderer.icons.padding = {} + u.renderer.icons.padding.icon = icons_padding end end ----@param opts nvim_tree.config user supplied subset of config -local function deprecated_config(opts) - if type(opts.view) == "table" and opts.view.hide_root_folder then +---@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") end end ----@param opts nvim_tree.config user supplied subset of config -local function removed_config(opts) - if opts.auto_close then +---@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") - opts["auto_close"] = nil + u["auto_close"] = nil end - if opts.focus_empty_on_setup then + 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") - opts["focus_empty_on_setup"] = nil + u["focus_empty_on_setup"] = nil end - if opts.create_in_closed_folder then + 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.") end - opts["create_in_closed_folder"] = nil + u["create_in_closed_folder"] = nil end ---Migrate legacy config in place. ---Refactored are silently migrated. Deprecated and removed result in a warning. ----@param opts nvim_tree.config user supplied subset of config -function M.migrate_config(opts) +---@param u nvim_tree.config user supplied subset of config +function M.migrate_config(u) -- silently move - refactored_config(opts) + refactored_config(u) -- warn - deprecated_config(opts) + deprecated_config(u) -- warn and delete - removed_config(opts) + removed_config(u) end ---Silently create new api entries pointing legacy functions to current