Skip to content

feat: preserve layout when all non-neotree splits are closed #1751

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

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
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
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ RUN apt install -y git ninja-build gettext libtool libtool-bin autoconf \

# install neovim
RUN git clone https://github.com/neovim/neovim
RUN cd neovim && make CMAKE_BUILD_TYPE=RelWithDebInfo && make install
RUN cd neovim && git checkout release-0.11 && make CMAKE_BUILD_TYPE=RelWithDebInfo && make install

# install required plugins
ARG PLUG_DIR="root/.local/share/nvim/site/pack/packer/start"
Expand Down
89 changes: 88 additions & 1 deletion lua/neo-tree/setup/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -268,7 +268,6 @@ M.win_enter_event = function()

-- if the new win is not a floating window, make sure all neo-tree floats are closed
manager.close_all("float")

if M.config.close_if_last_window then
local tabid = vim.api.nvim_get_current_tabpage()
local wins = utils.get_value(M, "config.prior_windows", {})[tabid]
Expand Down Expand Up @@ -740,6 +739,94 @@ M.merge_config = function(user_config)
id = "neo-tree-win-enter",
})

vim.api.nvim_create_autocmd("WinClosed", {
callback = function(args)
local closing_win = tonumber(args.match)
if utils.is_floating(closing_win) then
return
end

local neotree_sidebar_exists = false
for _, win in ipairs(vim.api.nvim_tabpage_list_wins(0)) do
if win ~= closing_win then
local buf = vim.api.nvim_win_get_buf(win)
local neotree_pos = vim.b[buf].neo_tree_position
if not utils.is_floating(win) and neotree_pos then
neotree_sidebar_exists = true
if neotree_pos == "left" then
left_neotree = win
elseif neotree_pos == "right" then
right_neotree = win
end
end
end
end

if not neotree_sidebar_exists then
return
end

-- When we have an open sidebar and the other non-floating windows are all closed, prevent neo-tree from expanding.
local left_neotree, right_neotree, bottom_neotree, top_neotree
local floating_wins = {}
local neotree_wins = {}
for _, win in ipairs(vim.api.nvim_list_wins()) do
local buf = vim.api.nvim_win_get_buf(win)
local neotree_pos = vim.b[buf].neo_tree_position
if utils.is_floating(win) then
table.insert(floating_wins, win)
end
if neotree_pos then
table.insert(neotree_wins, win)
end
end

-- skip buffers shown in floating windows and edgy windows
local skip = {}
for _, win in pairs(floating_wins) do
local buf = vim.api.nvim_win_get_buf(win)
skip[buf] = buf
end
for _, win in pairs(neotree_wins) do
local buf = vim.api.nvim_win_get_buf(win)
skip[buf] = buf
end

local bufs = {}
for _, buf in ipairs(vim.api.nvim_list_bufs()) do
if not skip[buf] then
table.insert(bufs, buf)
end
end

-- sort by last enter time
table.sort(bufs, function(a, b)
return (vim.b[a].neotree_enter or 0) > (vim.b[b].neotree_enter or 0)
end)

local direction
if left_neotree then
direction = "vertical rightbelow"
elseif right_neotree then
direction = "vertical leftabove"
elseif bottom_neotree then
direction = "topleft"
elseif top_neotree then
direction = "botright"
end
local edit_cmd = bufs[1] and "sb " .. bufs[1] or "new"
vim.cmd(([[%s %s]]):format(direction, edit_cmd))
end,
})

local enter_tick = 1
vim.api.nvim_create_autocmd("WinEnter", {
callback = function(args)
vim.b[args.buf].neotree_enter = enter_tick
enter_tick = enter_tick + 1
end,
})

--Dispose ourselves if the tab closes
events.subscribe({
event = events.VIM_TAB_CLOSED,
Expand Down
112 changes: 57 additions & 55 deletions lua/neo-tree/utils/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -754,9 +754,9 @@ end

---Open file in the appropriate window.
---@param state table The state of the source
---@param path string The file to open
---@param path string? The file to open
---@param open_cmd string? The vimcommand to use to open the file
---@param bufnr number|nil The buffer number to open
---@param bufnr integer? The buffer number to open
M.open_file = function(state, path, open_cmd, bufnr)
open_cmd = open_cmd or "edit"
-- If the file is already open, switch to it.
Expand All @@ -774,65 +774,67 @@ M.open_file = function(state, path, open_cmd, bufnr)
end
end

if M.truthy(path) then
local relative = require("neo-tree").config.open_files_using_relative_paths
local escaped_path = M.escape_path_for_cmd(relative and vim.fn.fnamemodify(path, ":.") or path)
local bufnr_or_path = bufnr or escaped_path
local events = require("neo-tree.events")
local result = true
local err = nil
local event_result = events.fire_event(events.FILE_OPEN_REQUESTED, {
state = state,
path = path,
open_cmd = open_cmd,
bufnr = bufnr,
}) or {}
if event_result.handled then
events.fire_event(events.FILE_OPENED, path)
return
end
if state.current_position == "current" then
if not path or not M.truthy(path) then
return
end

local relative = require("neo-tree").config.open_files_using_relative_paths
local escaped_path = M.escape_path_for_cmd(relative and vim.fn.fnamemodify(path, ":.") or path)
local bufnr_or_path = bufnr or escaped_path
local events = require("neo-tree.events")
local result = true
local err = nil
local event_result = events.fire_event(events.FILE_OPEN_REQUESTED, {
state = state,
path = path,
open_cmd = open_cmd,
bufnr = bufnr,
}) or {}
if event_result.handled then
events.fire_event(events.FILE_OPENED, path)
return
end
if state.current_position == "current" then
---@diagnostic disable-next-line: param-type-mismatch
result, err = pcall(vim.cmd, open_cmd .. " " .. bufnr_or_path)
else
local winid, is_neo_tree_window = M.get_appropriate_window(state)
vim.api.nvim_set_current_win(winid)
-- TODO: make this configurable, see issue #43
if is_neo_tree_window then
local width = vim.api.nvim_win_get_width(0)
if width == vim.o.columns then
-- Neo-tree must be the only window, restore it's status as a sidebar
width = M.get_value(state, "window.width", 40, false)
width = M.resolve_width(width)
end
result, err = M.force_new_split(state.current_position, escaped_path)
vim.api.nvim_win_set_width(winid, width)
else
---@diagnostic disable-next-line: param-type-mismatch
result, err = pcall(vim.cmd, open_cmd .. " " .. bufnr_or_path)
else
local winid, is_neo_tree_window = M.get_appropriate_window(state)
vim.api.nvim_set_current_win(winid)
-- TODO: make this configurable, see issue #43
if is_neo_tree_window then
local width = vim.api.nvim_win_get_width(0)
if width == vim.o.columns then
-- Neo-tree must be the only window, restore it's status as a sidebar
width = M.get_value(state, "window.width", 40, false)
width = M.resolve_width(width)
end
result, err = M.force_new_split(state.current_position, escaped_path)
vim.api.nvim_win_set_width(winid, width)
else
---@diagnostic disable-next-line: param-type-mismatch
result, err = pcall(vim.cmd, open_cmd .. " " .. bufnr_or_path)
end
end
if not result and string.find(err or "", "winfixbuf") and M.is_winfixbuf() then
local winid, is_neo_tree_window = M.get_appropriate_window(state, true)
-- Rescan window list to find a window that is not winfixbuf.
-- If found, retry executing command in that window,
-- otherwise, all windows are either neo-tree or winfixbuf so we make a new split.
if not is_neo_tree_window and not M.is_winfixbuf(winid) then
vim.api.nvim_set_current_win(winid)
---@diagnostic disable-next-line: param-type-mismatch
result, err = pcall(vim.cmd, open_cmd .. " " .. bufnr_or_path)
else
result, err = M.force_new_split(state.current_position, escaped_path)
end
end
if result or err == "Vim(edit):E325: ATTENTION" then
-- fixes #321
vim.bo[0].buflisted = true
events.fire_event(events.FILE_OPENED, path)
end
if not result and string.find(err or "", "winfixbuf") and M.is_winfixbuf() then
local winid, is_neo_tree_window = M.get_appropriate_window(state, true)
-- Rescan window list to find a window that is not winfixbuf.
-- If found, retry executing command in that window,
-- otherwise, all windows are either neo-tree or winfixbuf so we make a new split.
if not is_neo_tree_window and not M.is_winfixbuf(winid) then
vim.api.nvim_set_current_win(winid)
---@diagnostic disable-next-line: param-type-mismatch
result, err = pcall(vim.cmd, open_cmd .. " " .. bufnr_or_path)
else
log.error("Error opening file:", err)
result, err = M.force_new_split(state.current_position, escaped_path)
end
end
if result or err == "Vim(edit):E325: ATTENTION" then
-- fixes #321
vim.bo[0].buflisted = true
events.fire_event(events.FILE_OPENED, path)
else
log.error("Error opening file:", err)
end
end

M.reduce = function(list, memo, func)
Expand Down
Loading