Skip to content

Sync closing of nvim-tree across tabs #1698

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 17 commits into from
Nov 19, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 29 additions & 12 deletions doc/nvim-tree-lua.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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`
Expand All @@ -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
Expand Down Expand Up @@ -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.

Expand Down Expand Up @@ -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
Expand Down
24 changes: 14 additions & 10 deletions lua/nvim-tree.lua
Original file line number Diff line number Diff line change
Expand Up @@ -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
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn't work very well, however that is for another day.

if bufname:match(filter) ~= nil or ft:match(filter) ~= nil then
return
end
Expand Down Expand Up @@ -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", {
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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,
},
Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -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
Expand Down
2 changes: 2 additions & 0 deletions lua/nvim-tree/api.lua
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
5 changes: 5 additions & 0 deletions lua/nvim-tree/legacy.lua
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion lua/nvim-tree/lib.lua
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
31 changes: 21 additions & 10 deletions lua/nvim-tree/utils.lua
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
local Iterator = require "nvim-tree.iterators.node-iterator"
local notify = require "nvim-tree.notify"

local M = {
debouncers = {},
Expand Down Expand Up @@ -266,24 +267,32 @@ 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" },
src_pos = { src_pos, "string" },
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
Expand All @@ -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)
Expand Down
58 changes: 48 additions & 10 deletions lua/nvim-tree/view.lua
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand All @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down