diff --git a/doc/nvim-tree-lua.txt b/doc/nvim-tree-lua.txt index 79ee7177150..d26d19d39e1 100644 --- a/doc/nvim-tree-lua.txt +++ b/doc/nvim-tree-lua.txt @@ -177,8 +177,6 @@ Subsequent calls to setup will replace the previous configuration. ignore_buffer_on_setup = false, open_on_setup = false, open_on_setup_file = false, - open_on_tab = false, - ignore_buf_on_tab_change = {}, sort_by = "name", root_dirs = {}, prefer_startup_root = false, @@ -360,6 +358,13 @@ Subsequent calls to setup will replace the previous configuration. prefix = "[FILTER]: ", always_show_folders = true, }, + tab = { + sync = { + open = false, + close = false, + ignore = {}, + }, + }, log = { enable = false, truncate = false, @@ -417,10 +422,6 @@ You can use this option if you don't want the tree to open in some scenarios (eg using vim startify). Type: {string}, Default: `{}` -*nvim-tree.ignore_buf_on_tab_change* -List of filetypes or buffer names that will prevent `open_on_tab` to open. - Type: {string}, Default: `{}` - *nvim-tree.auto_reload_on_write* Reloads the explorer every time a buffer is written to. Type: `boolean`, Default: `true` @@ -430,11 +431,6 @@ Creating a file when the cursor is on a closed folder will set the path to be inside the closed folder, otherwise the parent folder. Type: `boolean`, Default: `false` -*nvim-tree.open_on_tab* -Opens the tree automatically when switching tabpage or opening a new tabpage -if the tree was previously open. - Type: `boolean`, Default: `false` - *nvim-tree.sort_by* Changes how files within the same directory are sorted. Can be one of `name`, `case_sensitive`, `modification_time`, `extension` or a @@ -1002,6 +998,26 @@ The filter can be cleared with the `F` key by default. Whether to filter folders or not. Type: `boolean`, Default: `true` +*nvim-tree.tab* +Configuration for tab behaviour. + + *nvim-tree.tab.sync* + Configuration for syncing nvim-tree across tabs. + + *nvim-tree.tab.sync.open* (previously `nvim-tree.open_on_tab`) + Opens the tree automatically when switching tabpage or opening a new + tabpage if the tree was previously open. + Type: `boolean`, Default: `false` + + *nvim-tree.tab.sync.close* + Closes the tree across all tabpages when the tree is closed. + Type: `boolean`, Default: `false` + + *nvim-tree.tab.sync.ignore* (previously `nvim-tree.ignore_buf_on_tab_change`) + List of filetypes or buffer names on new tab that will prevent + |nvim-tree.tab.sync.open| and |nvim-tree.tab.sync.close| + Type: {string}, Default: `{}` + *nvim-tree.notify* Configuration for notification. @@ -1074,8 +1090,9 @@ You can easily implement a toggle using this too: > local function toggle_replace() local view = require"nvim-tree.view" + local api = require"nvim-tree.api" if view.is_visible() then - view.close() + api.tree.close() else require"nvim-tree".open_replacing_current_buffer() end diff --git a/lua/nvim-tree.lua b/lua/nvim-tree.lua index 46ddcbd5a2d..3cca4e940e4 100644 --- a/lua/nvim-tree.lua +++ b/lua/nvim-tree.lua @@ -116,11 +116,11 @@ function M.open_replacing_current_buffer(cwd) require("nvim-tree.actions.finders.find-file").fn(bufname) end -function M.tab_change() +function M.tab_enter() if view.is_visible { any_tabpage = true } then local bufname = vim.api.nvim_buf_get_name(0) local ft = vim.api.nvim_buf_get_option(0, "ft") - for _, filter in ipairs(M.config.ignore_buf_on_tab_change) do + for _, filter in ipairs(M.config.tab.sync.ignore) do if bufname:match(filter) ~= nil or ft:match(filter) ~= nil then return end @@ -360,8 +360,8 @@ local function setup_autocommands(opts) }) end - if opts.open_on_tab then - create_nvim_tree_autocmd("TabEnter", { callback = vim.schedule_wrap(M.tab_change) }) + if opts.tab.sync.open then + create_nvim_tree_autocmd("TabEnter", { callback = vim.schedule_wrap(M.tab_enter) }) end if opts.hijack_cursor then create_nvim_tree_autocmd("CursorMoved", { @@ -455,8 +455,6 @@ local DEFAULT_OPTS = { -- BEGIN_DEFAULT_OPTS ignore_buffer_on_setup = false, open_on_setup = false, open_on_setup_file = false, - open_on_tab = false, - ignore_buf_on_tab_change = {}, sort_by = "name", root_dirs = {}, prefer_startup_root = false, @@ -638,6 +636,13 @@ local DEFAULT_OPTS = { -- BEGIN_DEFAULT_OPTS prefix = "[FILTER]: ", always_show_folders = true, }, + tab = { + sync = { + open = false, + close = false, + ignore = {}, + }, + }, notify = { threshold = vim.log.levels.INFO, }, @@ -737,7 +742,6 @@ function M.setup(conf) _config.open_on_setup_file = opts.open_on_setup_file _config.ignore_buffer_on_setup = opts.ignore_buffer_on_setup _config.ignore_ft_on_setup = opts.ignore_ft_on_setup - _config.ignore_buf_on_tab_change = opts.ignore_buf_on_tab_change _config.hijack_directories = opts.hijack_directories _config.hijack_directories.enable = _config.hijack_directories.enable and netrw_disabled @@ -772,9 +776,9 @@ function M.setup(conf) setup_vim_commands() end - if M.setup_called and view.is_visible() then - view.close() - view.abandon_current_window() + if M.setup_called then + view.close_all_tabs() + view.abandon_all_windows() end if M.setup_called and core.get_explorer() ~= nil then diff --git a/lua/nvim-tree/api.lua b/lua/nvim-tree/api.lua index a2a3cc7cf8f..31d2081096e 100644 --- a/lua/nvim-tree/api.lua +++ b/lua/nvim-tree/api.lua @@ -18,6 +18,8 @@ end Api.tree.open = require("nvim-tree").open Api.tree.toggle = require("nvim-tree").toggle Api.tree.close = require("nvim-tree.view").close +Api.tree.close_in_this_tab = require("nvim-tree.view").close_this_tab_only +Api.tree.close_in_all_tabs = require("nvim-tree.view").close_all_tabs Api.tree.focus = require("nvim-tree").focus Api.tree.reload = require("nvim-tree.actions.reloaders.reloaders").reload_explorer Api.tree.change_root = require("nvim-tree").change_dir diff --git a/lua/nvim-tree/legacy.lua b/lua/nvim-tree/legacy.lua index 159bbe05432..5eeae40a0c8 100644 --- a/lua/nvim-tree/legacy.lua +++ b/lua/nvim-tree/legacy.lua @@ -289,6 +289,11 @@ local function refactored(opts) -- 2022/06/20 utils.move_missing_val(opts, "update_focused_file", "update_cwd", opts, "update_focused_file", "update_root") utils.move_missing_val(opts, "", "update_cwd", opts, "", "sync_root_with_cwd") + + -- 2022/11/07 + utils.move_missing_val(opts, "", "open_on_tab", opts, "tab.sync", "open", false) + utils.move_missing_val(opts, "", "open_on_tab", opts, "tab.sync", "close") + utils.move_missing_val(opts, "", "ignore_buf_on_tab_change", opts, "tab.sync", "ignore") end local function removed(opts) diff --git a/lua/nvim-tree/lib.lua b/lua/nvim-tree/lib.lua index bb66df44b38..02da79425a7 100644 --- a/lua/nvim-tree/lib.lua +++ b/lua/nvim-tree/lib.lua @@ -117,7 +117,7 @@ function M.open(cwd) core.init(cwd or vim.loop.cwd()) end if should_hijack_current_buf() then - view.close() + view.close_this_tab_only() view.open_in_current_win() renderer.draw() else diff --git a/lua/nvim-tree/utils.lua b/lua/nvim-tree/utils.lua index badfcb3b69c..3dda5fed41b 100644 --- a/lua/nvim-tree/utils.lua +++ b/lua/nvim-tree/utils.lua @@ -1,4 +1,5 @@ local Iterator = require "nvim-tree.iterators.node-iterator" +local notify = require "nvim-tree.notify" local M = { debouncers = {}, @@ -266,14 +267,20 @@ function M.table_create_missing(tbl, path) return t end --- Move a value from src to dst if value is nil on dst --- @param src to copy from --- @param src_path dot separated string of sub-tables --- @param src_pos value pos --- @param dst to copy to --- @param dst_path dot separated string of sub-tables, created when missing --- @param dst_pos value pos -function M.move_missing_val(src, src_path, src_pos, dst, dst_path, dst_pos) +--- Move a value from src to dst if value is nil on dst. +--- Remove value from src +--- @param src table to copy from +--- @param src_path string dot separated string of sub-tables +--- @param src_pos string value pos +--- @param dst table to copy to +--- @param dst_path string dot separated string of sub-tables, created when missing +--- @param dst_pos string value pos +--- @param remove boolean default true +function M.move_missing_val(src, src_path, src_pos, dst, dst_path, dst_pos, remove) + if remove == nil then + remove = true + end + local ok, err = pcall(vim.validate, { src = { src, "table" }, src_path = { src_path, "string" }, @@ -281,9 +288,11 @@ function M.move_missing_val(src, src_path, src_pos, dst, dst_path, dst_pos) dst = { dst, "table" }, dst_path = { dst_path, "string" }, dst_pos = { dst_pos, "string" }, + remove = { remove, "boolean" }, }) if not ok then - M.notify.warn("move_missing_val: " .. (err or "invalid arguments")) + notify.warn("move_missing_val: " .. (err or "invalid arguments")) + return end for pos in string.gmatch(src_path, "([^%.]+)%.*") do @@ -304,7 +313,9 @@ function M.move_missing_val(src, src_path, src_pos, dst, dst_path, dst_pos) dst[dst_pos] = src_val end - src[src_pos] = nil + if remove then + src[src_pos] = nil + end end function M.format_bytes(bytes) diff --git a/lua/nvim-tree/view.lua b/lua/nvim-tree/view.lua index 00e6f498c91..cf7aaa0db9c 100644 --- a/lua/nvim-tree/view.lua +++ b/lua/nvim-tree/view.lua @@ -179,21 +179,21 @@ local function switch_buf_if_last_buf() end -- save_tab_state saves any state that should be preserved across redraws. -local function save_tab_state() - local tabpage = vim.api.nvim_get_current_tabpage() - M.View.cursors[tabpage] = vim.api.nvim_win_get_cursor(M.get_winnr()) +local function save_tab_state(tabnr) + local tabpage = tabnr or vim.api.nvim_get_current_tabpage() + M.View.cursors[tabpage] = vim.api.nvim_win_get_cursor(M.get_winnr(tabpage)) end -function M.close() - if not M.is_visible() then +local function close(tabpage) + if not M.is_visible { tabpage = tabpage } then return end - save_tab_state() + save_tab_state(tabpage) switch_buf_if_last_buf() - local tree_win = M.get_winnr() + local tree_win = M.get_winnr(tabpage) local current_win = vim.api.nvim_get_current_win() - for _, win in pairs(vim.api.nvim_list_wins()) do - if tree_win ~= win and vim.api.nvim_win_get_config(win).relative == "" then + for _, win in pairs(vim.api.nvim_tabpage_list_wins(tabpage)) do + if vim.api.nvim_win_get_config(win).relative == "" then local prev_win = vim.fn.winnr "#" -- this tab only if tree_win == current_win and prev_win > 0 then vim.api.nvim_set_current_win(vim.fn.win_getid(prev_win)) @@ -207,6 +207,24 @@ function M.close() end end +function M.close_this_tab_only() + close(vim.api.nvim_get_current_tabpage()) +end + +function M.close_all_tabs() + for tabpage, _ in pairs(M.View.tabpages) do + close(tabpage) + end +end + +function M.close() + if M.View.tab.sync.close then + M.close_all_tabs() + else + M.close_this_tab_only() + end +end + function M.open(options) if M.is_visible() then return @@ -308,10 +326,29 @@ end function M.abandon_current_window() local tab = vim.api.nvim_get_current_tabpage() BUFNR_PER_TAB[tab] = nil - M.View.tabpages[tab].winnr = nil + if M.View.tabpages[tab] then + M.View.tabpages[tab].winnr = nil + end +end + +function M.abandon_all_windows() + for tab, _ in pairs(vim.api.nvim_list_tabpages()) do + BUFNR_PER_TAB[tab] = nil + if M.View.tabpages[tab] then + M.View.tabpages[tab].winnr = nil + end + end end function M.is_visible(opts) + if opts and opts.tabpage then + if M.View.tabpages[opts.tabpage] == nil then + return false + end + local winnr = M.View.tabpages[opts.tabpage].winnr + return winnr and vim.api.nvim_win_is_valid(winnr) + end + if opts and opts.any_tabpage then for _, v in pairs(M.View.tabpages) do if v.winnr and vim.api.nvim_win_is_valid(v.winnr) then @@ -450,6 +487,7 @@ function M.setup(opts) M.View.height = options.height M.View.initial_width = get_size() M.View.hide_root_folder = options.hide_root_folder + M.View.tab = opts.tab M.View.preserve_window_proportions = options.preserve_window_proportions M.View.winopts.number = options.number M.View.winopts.relativenumber = options.relativenumber