chore(setup): make setup idempotent (#1340)

Co-authored-by: Alexander Courtis <alex@courtis.org>
This commit is contained in:
Kiyan 2022-06-26 12:14:03 +02:00 committed by GitHub
parent 0c13bd76a8
commit e6c1b4cd5b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 293 additions and 269 deletions

View File

@ -13,6 +13,7 @@ local core = require "nvim-tree.core"
local reloaders = require "nvim-tree.actions.reloaders" local reloaders = require "nvim-tree.actions.reloaders"
local copy_paste = require "nvim-tree.actions.copy-paste" local copy_paste = require "nvim-tree.actions.copy-paste"
local collapse_all = require "nvim-tree.actions.collapse-all" local collapse_all = require "nvim-tree.actions.collapse-all"
local git = require "nvim-tree.git"
local _config = {} local _config = {}
@ -323,7 +324,7 @@ function M.change_dir(name)
end end
local function setup_autocommands(opts) 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 function create_nvim_tree_autocmd(name, custom_opts)
local default_opts = { group = augroup_id } local default_opts = { group = augroup_id }
api.nvim_create_autocmd(name, vim.tbl_extend("force", default_opts, custom_opts)) api.nvim_create_autocmd(name, vim.tbl_extend("force", default_opts, custom_opts))
@ -391,6 +392,16 @@ local function setup_autocommands(opts)
end, end,
}) })
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 end
local DEFAULT_OPTS = { -- BEGIN_DEFAULT_OPTS local DEFAULT_OPTS = { -- BEGIN_DEFAULT_OPTS
@ -623,11 +634,6 @@ function M.setup(conf)
return return
end 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() M.init_root = vim.fn.getcwd()
legacy.migrate_legacy_options(conf or {}) legacy.migrate_legacy_options(conf or {})
@ -668,8 +674,24 @@ function M.setup(conf)
require("nvim-web-devicons").setup() require("nvim-web-devicons").setup()
end end
setup_vim_commands()
setup_autocommands(opts) 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() vim.schedule(function()
M.on_enter(netrw_disabled) M.on_enter(netrw_disabled)

View File

@ -7,223 +7,225 @@ local util = require "nvim-tree.utils"
local nvim_tree_callback = require("nvim-tree.config").nvim_tree_callback local nvim_tree_callback = require("nvim-tree.config").nvim_tree_callback
-- BEGIN_DEFAULT_MAPPINGS -- BEGIN_DEFAULT_MAPPINGS
local M = { local DEFAULT_MAPPINGS = {
mappings = { {
{ key = { "<CR>", "o", "<2-LeftMouse>" },
key = { "<CR>", "o", "<2-LeftMouse>" }, action = "edit",
action = "edit", desc = "open a file or folder; root will cd to the above directory",
desc = "open a file or folder; root will cd to the above directory", },
}, {
{ key = "<C-e>",
key = "<C-e>", action = "edit_in_place",
action = "edit_in_place", desc = "edit the file in place, effectively replacing the tree explorer",
desc = "edit the file in place, effectively replacing the tree explorer", },
}, {
{ key = "O",
key = "O", action = "edit_no_picker",
action = "edit_no_picker", desc = "same as (edit) with no window picker",
desc = "same as (edit) with no window picker", },
}, {
{ key = { "<C-]>", "<2-RightMouse>" },
key = { "<C-]>", "<2-RightMouse>" }, action = "cd",
action = "cd", desc = "cd in the directory under the cursor",
desc = "cd in the directory under the cursor", },
}, {
{ key = "<C-v>",
key = "<C-v>", action = "vsplit",
action = "vsplit", desc = "open the file in a vertical split",
desc = "open the file in a vertical split", },
}, {
{ key = "<C-x>",
key = "<C-x>", action = "split",
action = "split", desc = "open the file in a horizontal split",
desc = "open the file in a horizontal split", },
}, {
{ key = "<C-t>",
key = "<C-t>", action = "tabnew",
action = "tabnew", desc = "open the file in a new tab",
desc = "open the file in a new tab", },
}, {
{ key = "<",
key = "<", action = "prev_sibling",
action = "prev_sibling", desc = "navigate to the previous sibling of current file/directory",
desc = "navigate to the previous sibling of current file/directory", },
}, {
{ key = ">",
key = ">", action = "next_sibling",
action = "next_sibling", desc = "navigate to the next sibling of current file/directory",
desc = "navigate to the next sibling of current file/directory", },
}, {
{ key = "P",
key = "P", action = "parent_node",
action = "parent_node", desc = "move cursor to the parent directory",
desc = "move cursor to the parent directory", },
}, {
{ key = "<BS>",
key = "<BS>", action = "close_node",
action = "close_node", desc = "close current opened directory or parent",
desc = "close current opened directory or parent", },
}, {
{ key = "<Tab>",
key = "<Tab>", action = "preview",
action = "preview", desc = "open the file as a preview (keeps the cursor in the tree)",
desc = "open the file as a preview (keeps the cursor in the tree)", },
}, {
{ key = "K",
key = "K", action = "first_sibling",
action = "first_sibling", desc = "navigate to the first sibling of current file/directory",
desc = "navigate to the first sibling of current file/directory", },
}, {
{ key = "J",
key = "J", action = "last_sibling",
action = "last_sibling", desc = "navigate to the last sibling of current file/directory",
desc = "navigate to the last sibling of current file/directory", },
}, {
{ key = "I",
key = "I", action = "toggle_git_ignored",
action = "toggle_git_ignored", desc = "toggle visibility of files/folders hidden via |git.ignore| option",
desc = "toggle visibility of files/folders hidden via |git.ignore| option", },
}, {
{ key = "H",
key = "H", action = "toggle_dotfiles",
action = "toggle_dotfiles", desc = "toggle visibility of dotfiles via |filters.dotfiles| option",
desc = "toggle visibility of dotfiles via |filters.dotfiles| option", },
}, {
{ key = "U",
key = "U", action = "toggle_custom",
action = "toggle_custom", desc = "toggle visibility of files/folders hidden via |filters.custom| option",
desc = "toggle visibility of files/folders hidden via |filters.custom| option", },
}, {
{ key = "R",
key = "R", action = "refresh",
action = "refresh", desc = "refresh the tree",
desc = "refresh the tree", },
}, {
{ key = "a",
key = "a", action = "create",
action = "create", desc = "add a file; leaving a trailing `/` will add a directory",
desc = "add a file; leaving a trailing `/` will add a directory", },
}, {
{ key = "d",
key = "d", action = "remove",
action = "remove", desc = "delete a file (will prompt for confirmation)",
desc = "delete a file (will prompt for confirmation)", },
}, {
{ key = "D",
key = "D", action = "trash",
action = "trash", desc = "trash a file via |trash| option",
desc = "trash a file via |trash| option", },
}, {
{ key = "r",
key = "r", action = "rename",
action = "rename", desc = "rename a file",
desc = "rename a file", },
}, {
{ key = "<C-r>",
key = "<C-r>", action = "full_rename",
action = "full_rename", desc = "rename a file and omit the filename on input",
desc = "rename a file and omit the filename on input", },
}, {
{ key = "x",
key = "x", action = "cut",
action = "cut", desc = "add/remove file/directory to cut clipboard",
desc = "add/remove file/directory to cut clipboard", },
}, {
{ key = "c",
key = "c", action = "copy",
action = "copy", desc = "add/remove file/directory to copy clipboard",
desc = "add/remove file/directory to copy clipboard", },
}, {
{ key = "p",
key = "p", action = "paste",
action = "paste", desc = "paste from clipboard; cut clipboard has precedence over copy; will prompt for confirmation",
desc = "paste from clipboard; cut clipboard has precedence over copy; will prompt for confirmation", },
}, {
{ key = "y",
key = "y", action = "copy_name",
action = "copy_name", desc = "copy name to system clipboard",
desc = "copy name to system clipboard", },
}, {
{ key = "Y",
key = "Y", action = "copy_path",
action = "copy_path", desc = "copy relative path to system clipboard",
desc = "copy relative path to system clipboard", },
}, {
{ key = "gy",
key = "gy", action = "copy_absolute_path",
action = "copy_absolute_path", desc = "copy absolute path to system clipboard",
desc = "copy absolute path to system clipboard", },
}, {
{ key = "[c",
key = "[c", action = "prev_git_item",
action = "prev_git_item", desc = "go to next git item",
desc = "go to next git item", },
}, {
{ key = "]c",
key = "]c", action = "next_git_item",
action = "next_git_item", desc = "go to prev git item",
desc = "go to prev git item", },
}, {
{ key = "-",
key = "-", action = "dir_up",
action = "dir_up", desc = "navigate up to the parent directory of the current file/directory",
desc = "navigate up to the parent directory of the current file/directory", },
}, {
{ key = "s",
key = "s", action = "system_open",
action = "system_open", desc = "open a file with default system application or a folder with default file manager, using |system_open| option",
desc = "open a file with default system application or a folder with default file manager, using |system_open| option", },
}, {
{ key = "f",
key = "f", action = "live_filter",
action = "live_filter", desc = "live filter nodes dynamically based on regex matching.",
desc = "live filter nodes dynamically based on regex matching.", },
}, {
{ key = "F",
key = "F", action = "clear_live_filter",
action = "clear_live_filter", desc = "clear live filter",
desc = "clear live filter", },
}, {
{ key = "q",
key = "q", action = "close",
action = "close", desc = "close tree window",
desc = "close tree window", },
}, {
{ key = "W",
key = "W", action = "collapse_all",
action = "collapse_all", desc = "collapse the whole tree",
desc = "collapse the whole tree", },
}, {
{ key = "E",
key = "E", action = "expand_all",
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",
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",
key = "S", action = "search_node",
action = "search_node", desc = "prompt the user to enter a path and then expands the tree to match the path",
desc = "prompt the user to enter a path and then expands the tree to match the path", },
}, {
{ key = ".",
key = ".", action = "run_file_command",
action = "run_file_command", desc = "enter vim command mode with the file the cursor is on",
desc = "enter vim command mode with the file the cursor is on", },
}, {
{ key = "<C-k>",
key = "<C-k>", action = "toggle_file_info",
action = "toggle_file_info", desc = "toggle a popup with file infos about the file under the cursor",
desc = "toggle a popup with file infos about the file under the cursor", },
}, {
{ key = "g?",
key = "g?", action = "toggle_help",
action = "toggle_help", desc = "toggle help",
desc = "toggle help",
},
}, },
custom_keypress_funcs = {},
} }
-- END_DEFAULT_MAPPINGS -- END_DEFAULT_MAPPINGS
local M = {
mappings = {},
custom_keypress_funcs = {},
}
local keypress_funcs = { local keypress_funcs = {
close = view.close, close = view.close,
close_node = require("nvim-tree.actions.movements").parent_node(true), close_node = require("nvim-tree.actions.movements").parent_node(true),
@ -397,6 +399,22 @@ local function copy_mappings(user_mappings)
return user_mappings return user_mappings
end 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 = { local DEFAULT_MAPPING_CONFIG = {
custom_only = false, custom_only = false,
list = {}, list = {},
@ -413,6 +431,9 @@ function M.setup(opts)
require("nvim-tree.actions.copy-paste").setup(opts) require("nvim-tree.actions.copy-paste").setup(opts)
require("nvim-tree.actions.expand-all").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 user_map_config = (opts.view or {}).mappings or {}
local options = vim.tbl_deep_extend("force", DEFAULT_MAPPING_CONFIG, user_map_config) local options = vim.tbl_deep_extend("force", DEFAULT_MAPPING_CONFIG, user_map_config)
if options.custom_only then if options.custom_only then

View File

@ -8,16 +8,6 @@ local M = {}
local GROUP = "NvimTreeDiagnosticSigns" 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 severity_levels = { Error = 1, Warning = 2, Information = 3, Hint = 4 }
local sign_names = { local sign_names = {
{ "NvimTreeSignError", "NvimTreeLspDiagnosticsError" }, { "NvimTreeSignError", "NvimTreeLspDiagnosticsError" },
@ -38,29 +28,13 @@ end
local function from_nvim_lsp() local function from_nvim_lsp()
local buffer_severity = {} local buffer_severity = {}
-- vim.lsp.diagnostic.get_all was deprecated in nvim 0.7 and replaced with vim.diagnostic.get for _, diagnostic in ipairs(vim.diagnostic.get()) do
-- This conditional can be removed when the minimum required version of nvim is changed to 0.7. local buf = diagnostic.bufnr
if vim.diagnostic then if a.nvim_buf_is_valid(buf) then
-- nvim version >= 0.7 local bufname = a.nvim_buf_get_name(buf)
for _, diagnostic in ipairs(vim.diagnostic.get()) do local lowest_severity = buffer_severity[bufname]
local buf = diagnostic.bufnr if not lowest_severity or diagnostic.severity < lowest_severity then
if a.nvim_buf_is_valid(buf) then buffer_severity[bufname] = diagnostic.severity
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
end end
end end
end end
@ -157,6 +131,11 @@ local links = {
function M.setup(opts) function M.setup(opts)
M.enable = opts.diagnostics.enable M.enable = opts.diagnostics.enable
if M.enable then
log.line("diagnostics", "setup")
end
M.show_on_dirs = opts.diagnostics.show_on_dirs 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[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] }) 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 for lhs, rhs in pairs(links) do
vim.cmd("hi def link " .. lhs .. " " .. rhs) vim.cmd("hi def link " .. lhs .. " " .. rhs)
end 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 end
return M return M

View File

@ -64,6 +64,7 @@ function M.setup(opts)
filter_git_ignored = opts.git.ignore, filter_git_ignored = opts.git.ignore,
} }
M.ignore_list = {}
M.exclude_list = opts.filters.exclude M.exclude_list = opts.filters.exclude
local custom_filter = opts.filters.custom local custom_filter = opts.filters.custom

View File

@ -134,6 +134,11 @@ function M.load_project_status(cwd)
return M.projects[project_root] return M.projects[project_root]
end end
function M.purge_state()
M.projects = {}
M.cwd_to_project_root = {}
end
function M.setup(opts) function M.setup(opts)
M.config = opts.git M.config = opts.git
M.config.watcher = opts.filesystem_watchers M.config.watcher = opts.filesystem_watchers

View File

@ -3,14 +3,14 @@ local uv = vim.loop
local log = require "nvim-tree.log" local log = require "nvim-tree.log"
local utils = require "nvim-tree.utils" local utils = require "nvim-tree.utils"
local M = {} local M = {
local Watcher = {
_watchers = {}, _watchers = {},
} }
local Watcher = {}
Watcher.__index = Watcher Watcher.__index = Watcher
function Watcher.new(opts) 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 if existing._opts.absolute_path == opts.absolute_path then
log.line("watcher", "Watcher:new using existing '%s'", opts.absolute_path) log.line("watcher", "Watcher:new using existing '%s'", opts.absolute_path)
return existing return existing
@ -25,7 +25,7 @@ function Watcher.new(opts)
watcher = watcher:start() watcher = watcher:start()
table.insert(Watcher._watchers, watcher) table.insert(M._watchers, watcher)
return watcher return watcher
end end
@ -74,4 +74,11 @@ end
M.Watcher = Watcher M.Watcher = Watcher
function M.purge_watchers()
for _, watcher in pairs(M._watchers) do
watcher:stop()
end
M._watchers = {}
end
return M return M

View File

@ -9,7 +9,7 @@ local max_action_help = 0
local outs_help = {} local outs_help = {}
local outs_lua = {} local outs_lua = {}
for _, m in pairs(M.mappings) do for _, m in pairs(DEFAULT_MAPPINGS) do
local out local out
if type(m.key) == "table" then if type(m.key) == "table" then
local first = true local first = true