From 8e2c3d81bdc72ac55ad40f5b60da7f66a844c48b Mon Sep 17 00:00:00 2001 From: pynappo Date: Mon, 7 Apr 2025 00:00:55 -0700 Subject: [PATCH 1/2] preserve layout when non-neotree splits all close --- Dockerfile | 4 +- lua/neo-tree/setup/init.lua | 88 +++++++++++++++++++++++++++++ lua/neo-tree/utils/init.lua | 110 ++++++++++++++++++------------------ 3 files changed, 146 insertions(+), 56 deletions(-) diff --git a/Dockerfile b/Dockerfile index b7f91f9e3..abd8006fd 100644 --- a/Dockerfile +++ b/Dockerfile @@ -10,8 +10,8 @@ RUN apk update && apk add --no-cache \ gettext-tiny-dev \ git -# Install neovim -RUN git clone --depth=1 https://github.com/neovim/neovim --branch release-0.10 +# install neovim +RUN git clone https://github.com/neovim/neovim RUN cd neovim && make CMAKE_BUILD_TYPE=RelWithDebInfo && make install # --- Final Stage --- diff --git a/lua/neo-tree/setup/init.lua b/lua/neo-tree/setup/init.lua index c7325b467..31ebe0a8b 100644 --- a/lua/neo-tree/setup/init.lua +++ b/lua/neo-tree/setup/init.lua @@ -671,6 +671,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, diff --git a/lua/neo-tree/utils/init.lua b/lua/neo-tree/utils/init.lua index 00049be83..4d896cc08 100644 --- a/lua/neo-tree/utils/init.lua +++ b/lua/neo-tree/utils/init.lua @@ -765,7 +765,7 @@ end ---@param state neotree.State ---@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. @@ -783,65 +783,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) From c726b9e3bea046295ea0cef51a1560d7f5faa3ac Mon Sep 17 00:00:00 2001 From: pynappo Date: Wed, 8 Oct 2025 03:24:34 -0700 Subject: [PATCH 2/2] simplify --- lua/neo-tree/setup/init.lua | 27 +++++++++------------------ 1 file changed, 9 insertions(+), 18 deletions(-) diff --git a/lua/neo-tree/setup/init.lua b/lua/neo-tree/setup/init.lua index 31ebe0a8b..264e2b7d0 100644 --- a/lua/neo-tree/setup/init.lua +++ b/lua/neo-tree/setup/init.lua @@ -685,11 +685,6 @@ M.merge_config = function(user_config) 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 @@ -699,7 +694,6 @@ M.merge_config = function(user_config) 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 @@ -713,7 +707,7 @@ M.merge_config = function(user_config) end end - -- skip buffers shown in floating windows and edgy windows + -- skip buffers shown in floating windows and neotree windows local skip = {} for _, win in pairs(floating_wins) do local buf = vim.api.nvim_win_get_buf(win) @@ -736,18 +730,15 @@ M.merge_config = function(user_config) 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" + local altbuf = nil + for _, buf in ipairs(bufs) do + if args.buf ~= buf then + altbuf = buf + break + end end - local edit_cmd = bufs[1] and "sb " .. bufs[1] or "new" - vim.cmd(([[%s %s]]):format(direction, edit_cmd)) + + vim.cmd(altbuf and "sb " .. altbuf or "new") end, })