diff --git a/lua/nvim-tree.lua b/lua/nvim-tree.lua index 708f10c5..5855f62c 100644 --- a/lua/nvim-tree.lua +++ b/lua/nvim-tree.lua @@ -13,6 +13,7 @@ local core = require "nvim-tree.core" local reloaders = require "nvim-tree.actions.reloaders" local copy_paste = require "nvim-tree.actions.copy-paste" local collapse_all = require "nvim-tree.actions.collapse-all" +local git = require "nvim-tree.git" local _config = {} @@ -323,7 +324,7 @@ function M.change_dir(name) end local function setup_autocommands(opts) - local augroup_id = api.nvim_create_augroup("NvimTree", {}) + local augroup_id = api.nvim_create_augroup("NvimTree", { clear = true }) local function create_nvim_tree_autocmd(name, custom_opts) local default_opts = { group = augroup_id } api.nvim_create_autocmd(name, vim.tbl_extend("force", default_opts, custom_opts)) @@ -391,6 +392,16 @@ local function setup_autocommands(opts) end, }) end + + if opts.diagnostics.enable then + create_nvim_tree_autocmd("DiagnosticChanged", { + callback = require("nvim-tree.diagnostics").update, + }) + create_nvim_tree_autocmd("User", { + pattern = "CocDiagnosticChange", + callback = require("nvim-tree.diagnostics").update, + }) + end end local DEFAULT_OPTS = { -- BEGIN_DEFAULT_OPTS @@ -623,11 +634,6 @@ function M.setup(conf) return end - if M.setup_called then - utils.warn "nvim-tree.lua setup called multiple times" - return - end - M.setup_called = true M.init_root = vim.fn.getcwd() legacy.migrate_legacy_options(conf or {}) @@ -668,8 +674,24 @@ function M.setup(conf) require("nvim-web-devicons").setup() end - setup_vim_commands() setup_autocommands(opts) + require("nvim-tree.watcher").purge_watchers() + + if not M.setup_called then + setup_vim_commands() + end + + if M.setup_called and view.is_visible() then + view.close() + view.abandon_current_window() + end + + if M.setup_called and core.get_explorer() ~= nil then + git.purge_state() + TreeExplorer = nil + end + + M.setup_called = true vim.schedule(function() M.on_enter(netrw_disabled) diff --git a/lua/nvim-tree/actions/init.lua b/lua/nvim-tree/actions/init.lua index ceb2aea2..40da651d 100644 --- a/lua/nvim-tree/actions/init.lua +++ b/lua/nvim-tree/actions/init.lua @@ -7,223 +7,225 @@ local util = require "nvim-tree.utils" local nvim_tree_callback = require("nvim-tree.config").nvim_tree_callback -- BEGIN_DEFAULT_MAPPINGS -local M = { - mappings = { - { - key = { "", "o", "<2-LeftMouse>" }, - action = "edit", - desc = "open a file or folder; root will cd to the above directory", - }, - { - key = "", - action = "edit_in_place", - desc = "edit the file in place, effectively replacing the tree explorer", - }, - { - key = "O", - action = "edit_no_picker", - desc = "same as (edit) with no window picker", - }, - { - key = { "", "<2-RightMouse>" }, - action = "cd", - desc = "cd in the directory under the cursor", - }, - { - key = "", - action = "vsplit", - desc = "open the file in a vertical split", - }, - { - key = "", - action = "split", - desc = "open the file in a horizontal split", - }, - { - key = "", - action = "tabnew", - desc = "open the file in a new tab", - }, - { - key = "<", - action = "prev_sibling", - desc = "navigate to the previous sibling of current file/directory", - }, - { - key = ">", - action = "next_sibling", - desc = "navigate to the next sibling of current file/directory", - }, - { - key = "P", - action = "parent_node", - desc = "move cursor to the parent directory", - }, - { - key = "", - action = "close_node", - desc = "close current opened directory or parent", - }, - { - key = "", - action = "preview", - desc = "open the file as a preview (keeps the cursor in the tree)", - }, - { - key = "K", - action = "first_sibling", - desc = "navigate to the first sibling of current file/directory", - }, - { - key = "J", - action = "last_sibling", - desc = "navigate to the last sibling of current file/directory", - }, - { - key = "I", - action = "toggle_git_ignored", - desc = "toggle visibility of files/folders hidden via |git.ignore| option", - }, - { - key = "H", - action = "toggle_dotfiles", - desc = "toggle visibility of dotfiles via |filters.dotfiles| option", - }, - { - key = "U", - action = "toggle_custom", - desc = "toggle visibility of files/folders hidden via |filters.custom| option", - }, - { - key = "R", - action = "refresh", - desc = "refresh the tree", - }, - { - key = "a", - action = "create", - desc = "add a file; leaving a trailing `/` will add a directory", - }, - { - key = "d", - action = "remove", - desc = "delete a file (will prompt for confirmation)", - }, - { - key = "D", - action = "trash", - desc = "trash a file via |trash| option", - }, - { - key = "r", - action = "rename", - desc = "rename a file", - }, - { - key = "", - action = "full_rename", - desc = "rename a file and omit the filename on input", - }, - { - key = "x", - action = "cut", - desc = "add/remove file/directory to cut clipboard", - }, - { - key = "c", - action = "copy", - desc = "add/remove file/directory to copy clipboard", - }, - { - key = "p", - action = "paste", - desc = "paste from clipboard; cut clipboard has precedence over copy; will prompt for confirmation", - }, - { - key = "y", - action = "copy_name", - desc = "copy name to system clipboard", - }, - { - key = "Y", - action = "copy_path", - desc = "copy relative path to system clipboard", - }, - { - key = "gy", - action = "copy_absolute_path", - desc = "copy absolute path to system clipboard", - }, - { - key = "[c", - action = "prev_git_item", - desc = "go to next git item", - }, - { - key = "]c", - action = "next_git_item", - desc = "go to prev git item", - }, - { - key = "-", - action = "dir_up", - desc = "navigate up to the parent directory of the current file/directory", - }, - { - key = "s", - action = "system_open", - desc = "open a file with default system application or a folder with default file manager, using |system_open| option", - }, - { - key = "f", - action = "live_filter", - desc = "live filter nodes dynamically based on regex matching.", - }, - { - key = "F", - action = "clear_live_filter", - desc = "clear live filter", - }, - { - key = "q", - action = "close", - desc = "close tree window", - }, - { - key = "W", - action = "collapse_all", - desc = "collapse the whole tree", - }, - { - key = "E", - action = "expand_all", - desc = "expand the whole tree, stopping after expanding |actions.expand_all.max_folder_discovery| folders; this might hang neovim for a while if running on a big folder", - }, - { - key = "S", - action = "search_node", - desc = "prompt the user to enter a path and then expands the tree to match the path", - }, - { - key = ".", - action = "run_file_command", - desc = "enter vim command mode with the file the cursor is on", - }, - { - key = "", - action = "toggle_file_info", - desc = "toggle a popup with file infos about the file under the cursor", - }, - { - key = "g?", - action = "toggle_help", - desc = "toggle help", - }, +local DEFAULT_MAPPINGS = { + { + key = { "", "o", "<2-LeftMouse>" }, + action = "edit", + desc = "open a file or folder; root will cd to the above directory", + }, + { + key = "", + action = "edit_in_place", + desc = "edit the file in place, effectively replacing the tree explorer", + }, + { + key = "O", + action = "edit_no_picker", + desc = "same as (edit) with no window picker", + }, + { + key = { "", "<2-RightMouse>" }, + action = "cd", + desc = "cd in the directory under the cursor", + }, + { + key = "", + action = "vsplit", + desc = "open the file in a vertical split", + }, + { + key = "", + action = "split", + desc = "open the file in a horizontal split", + }, + { + key = "", + action = "tabnew", + desc = "open the file in a new tab", + }, + { + key = "<", + action = "prev_sibling", + desc = "navigate to the previous sibling of current file/directory", + }, + { + key = ">", + action = "next_sibling", + desc = "navigate to the next sibling of current file/directory", + }, + { + key = "P", + action = "parent_node", + desc = "move cursor to the parent directory", + }, + { + key = "", + action = "close_node", + desc = "close current opened directory or parent", + }, + { + key = "", + action = "preview", + desc = "open the file as a preview (keeps the cursor in the tree)", + }, + { + key = "K", + action = "first_sibling", + desc = "navigate to the first sibling of current file/directory", + }, + { + key = "J", + action = "last_sibling", + desc = "navigate to the last sibling of current file/directory", + }, + { + key = "I", + action = "toggle_git_ignored", + desc = "toggle visibility of files/folders hidden via |git.ignore| option", + }, + { + key = "H", + action = "toggle_dotfiles", + desc = "toggle visibility of dotfiles via |filters.dotfiles| option", + }, + { + key = "U", + action = "toggle_custom", + desc = "toggle visibility of files/folders hidden via |filters.custom| option", + }, + { + key = "R", + action = "refresh", + desc = "refresh the tree", + }, + { + key = "a", + action = "create", + desc = "add a file; leaving a trailing `/` will add a directory", + }, + { + key = "d", + action = "remove", + desc = "delete a file (will prompt for confirmation)", + }, + { + key = "D", + action = "trash", + desc = "trash a file via |trash| option", + }, + { + key = "r", + action = "rename", + desc = "rename a file", + }, + { + key = "", + action = "full_rename", + desc = "rename a file and omit the filename on input", + }, + { + key = "x", + action = "cut", + desc = "add/remove file/directory to cut clipboard", + }, + { + key = "c", + action = "copy", + desc = "add/remove file/directory to copy clipboard", + }, + { + key = "p", + action = "paste", + desc = "paste from clipboard; cut clipboard has precedence over copy; will prompt for confirmation", + }, + { + key = "y", + action = "copy_name", + desc = "copy name to system clipboard", + }, + { + key = "Y", + action = "copy_path", + desc = "copy relative path to system clipboard", + }, + { + key = "gy", + action = "copy_absolute_path", + desc = "copy absolute path to system clipboard", + }, + { + key = "[c", + action = "prev_git_item", + desc = "go to next git item", + }, + { + key = "]c", + action = "next_git_item", + desc = "go to prev git item", + }, + { + key = "-", + action = "dir_up", + desc = "navigate up to the parent directory of the current file/directory", + }, + { + key = "s", + action = "system_open", + desc = "open a file with default system application or a folder with default file manager, using |system_open| option", + }, + { + key = "f", + action = "live_filter", + desc = "live filter nodes dynamically based on regex matching.", + }, + { + key = "F", + action = "clear_live_filter", + desc = "clear live filter", + }, + { + key = "q", + action = "close", + desc = "close tree window", + }, + { + key = "W", + action = "collapse_all", + desc = "collapse the whole tree", + }, + { + key = "E", + action = "expand_all", + desc = "expand the whole tree, stopping after expanding |actions.expand_all.max_folder_discovery| folders; this might hang neovim for a while if running on a big folder", + }, + { + key = "S", + action = "search_node", + desc = "prompt the user to enter a path and then expands the tree to match the path", + }, + { + key = ".", + action = "run_file_command", + desc = "enter vim command mode with the file the cursor is on", + }, + { + key = "", + action = "toggle_file_info", + desc = "toggle a popup with file infos about the file under the cursor", + }, + { + key = "g?", + action = "toggle_help", + desc = "toggle help", }, - custom_keypress_funcs = {}, } -- END_DEFAULT_MAPPINGS +local M = { + mappings = {}, + custom_keypress_funcs = {}, +} + local keypress_funcs = { close = view.close, close_node = require("nvim-tree.actions.movements").parent_node(true), @@ -397,6 +399,22 @@ local function copy_mappings(user_mappings) return user_mappings end +local function cleanup_existing_mappings() + local bufnr = view.get_bufnr() + if bufnr == nil or not a.nvim_buf_is_valid(bufnr) then + return + end + for _, b in pairs(M.mappings) do + if type(b.key) == "table" then + for _, key in pairs(b.key) do + a.nvim_buf_del_keymap(bufnr, b.mode or "n", key) + end + else + a.nvim_buf_del_keymap(bufnr, b.mode or "n", b.key) + end + end +end + local DEFAULT_MAPPING_CONFIG = { custom_only = false, list = {}, @@ -413,6 +431,9 @@ function M.setup(opts) require("nvim-tree.actions.copy-paste").setup(opts) require("nvim-tree.actions.expand-all").setup(opts) + cleanup_existing_mappings() + M.mappings = vim.deepcopy(DEFAULT_MAPPINGS) + local user_map_config = (opts.view or {}).mappings or {} local options = vim.tbl_deep_extend("force", DEFAULT_MAPPING_CONFIG, user_map_config) if options.custom_only then diff --git a/lua/nvim-tree/diagnostics.lua b/lua/nvim-tree/diagnostics.lua index 685a1c85..ecaed103 100644 --- a/lua/nvim-tree/diagnostics.lua +++ b/lua/nvim-tree/diagnostics.lua @@ -8,16 +8,6 @@ local M = {} local GROUP = "NvimTreeDiagnosticSigns" -local function get_lowest_severity(diagnostics) - local severity = math.huge - for _, v in ipairs(diagnostics) do - if v.severity < severity then - severity = v.severity - end - end - return severity -end - local severity_levels = { Error = 1, Warning = 2, Information = 3, Hint = 4 } local sign_names = { { "NvimTreeSignError", "NvimTreeLspDiagnosticsError" }, @@ -38,29 +28,13 @@ end local function from_nvim_lsp() local buffer_severity = {} - -- vim.lsp.diagnostic.get_all was deprecated in nvim 0.7 and replaced with vim.diagnostic.get - -- This conditional can be removed when the minimum required version of nvim is changed to 0.7. - if vim.diagnostic then - -- nvim version >= 0.7 - for _, diagnostic in ipairs(vim.diagnostic.get()) do - local buf = diagnostic.bufnr - if a.nvim_buf_is_valid(buf) then - local bufname = a.nvim_buf_get_name(buf) - local lowest_severity = buffer_severity[bufname] - if not lowest_severity or diagnostic.severity < lowest_severity then - buffer_severity[bufname] = diagnostic.severity - end - end - end - else - -- nvim version < 0.7 - for buf, diagnostics in pairs(vim.lsp.diagnostic.get_all()) do - if a.nvim_buf_is_valid(buf) then - local bufname = a.nvim_buf_get_name(buf) - if not buffer_severity[bufname] then - local severity = get_lowest_severity(diagnostics) - buffer_severity[bufname] = severity - end + for _, diagnostic in ipairs(vim.diagnostic.get()) do + local buf = diagnostic.bufnr + if a.nvim_buf_is_valid(buf) then + local bufname = a.nvim_buf_get_name(buf) + local lowest_severity = buffer_severity[bufname] + if not lowest_severity or diagnostic.severity < lowest_severity then + buffer_severity[bufname] = diagnostic.severity end end end @@ -157,6 +131,11 @@ local links = { function M.setup(opts) M.enable = opts.diagnostics.enable + + if M.enable then + log.line("diagnostics", "setup") + end + M.show_on_dirs = opts.diagnostics.show_on_dirs vim.fn.sign_define(sign_names[1][1], { text = opts.diagnostics.icons.error, texthl = sign_names[1][2] }) vim.fn.sign_define(sign_names[2][1], { text = opts.diagnostics.icons.warning, texthl = sign_names[2][2] }) @@ -166,17 +145,6 @@ function M.setup(opts) for lhs, rhs in pairs(links) do vim.cmd("hi def link " .. lhs .. " " .. rhs) end - - if M.enable then - log.line("diagnostics", "setup") - a.nvim_create_autocmd("DiagnosticChanged", { - callback = M.update, - }) - a.nvim_create_autocmd("User", { - pattern = "CocDiagnosticChange", - callback = M.update, - }) - end end return M diff --git a/lua/nvim-tree/explorer/filters.lua b/lua/nvim-tree/explorer/filters.lua index 8ec661e2..e26095f2 100644 --- a/lua/nvim-tree/explorer/filters.lua +++ b/lua/nvim-tree/explorer/filters.lua @@ -64,6 +64,7 @@ function M.setup(opts) filter_git_ignored = opts.git.ignore, } + M.ignore_list = {} M.exclude_list = opts.filters.exclude local custom_filter = opts.filters.custom diff --git a/lua/nvim-tree/git/init.lua b/lua/nvim-tree/git/init.lua index 41d6f62a..6b754002 100644 --- a/lua/nvim-tree/git/init.lua +++ b/lua/nvim-tree/git/init.lua @@ -134,6 +134,11 @@ function M.load_project_status(cwd) return M.projects[project_root] end +function M.purge_state() + M.projects = {} + M.cwd_to_project_root = {} +end + function M.setup(opts) M.config = opts.git M.config.watcher = opts.filesystem_watchers diff --git a/lua/nvim-tree/watcher.lua b/lua/nvim-tree/watcher.lua index 78021451..6baf21c3 100644 --- a/lua/nvim-tree/watcher.lua +++ b/lua/nvim-tree/watcher.lua @@ -3,14 +3,14 @@ local uv = vim.loop local log = require "nvim-tree.log" local utils = require "nvim-tree.utils" -local M = {} -local Watcher = { +local M = { _watchers = {}, } +local Watcher = {} Watcher.__index = Watcher function Watcher.new(opts) - for _, existing in ipairs(Watcher._watchers) do + for _, existing in ipairs(M._watchers) do if existing._opts.absolute_path == opts.absolute_path then log.line("watcher", "Watcher:new using existing '%s'", opts.absolute_path) return existing @@ -25,7 +25,7 @@ function Watcher.new(opts) watcher = watcher:start() - table.insert(Watcher._watchers, watcher) + table.insert(M._watchers, watcher) return watcher end @@ -74,4 +74,11 @@ end M.Watcher = Watcher +function M.purge_watchers() + for _, watcher in pairs(M._watchers) do + watcher:stop() + end + M._watchers = {} +end + return M diff --git a/scripts/generate_default_mappings.lua b/scripts/generate_default_mappings.lua index 476698b8..986278b4 100644 --- a/scripts/generate_default_mappings.lua +++ b/scripts/generate_default_mappings.lua @@ -9,7 +9,7 @@ local max_action_help = 0 local outs_help = {} local outs_lua = {} -for _, m in pairs(M.mappings) do +for _, m in pairs(DEFAULT_MAPPINGS) do local out if type(m.key) == "table" then local first = true