Skip to content
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

fix(winfixbuf): avoid windows that have winfixbuf when opening buffers #1390

Merged
merged 4 commits into from
Mar 13, 2024
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 2 additions & 2 deletions lua/neo-tree.lua
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ M.ensure_config = function()
end
end

M.get_prior_window = function(ignore_filetypes)
M.get_prior_window = function(ignore_filetypes, ignore_winfixbuf)
ignore_filetypes = ignore_filetypes or {}
local ignore = utils.list_to_dict(ignore_filetypes)
ignore["neo-tree"] = true
Expand All @@ -32,7 +32,7 @@ M.get_prior_window = function(ignore_filetypes)
local last_win = wins[win_index]
if type(last_win) == "number" then
local success, is_valid = pcall(vim.api.nvim_win_is_valid, last_win)
if success and is_valid then
if success and is_valid and not (ignore_winfixbuf and utils.is_winfixbuf(last_win)) then
local buf = vim.api.nvim_win_get_buf(last_win)
local ft = vim.api.nvim_buf_get_option(buf, "filetype")
local bt = vim.api.nvim_buf_get_option(buf, "buftype") or "normal"
Expand Down
19 changes: 10 additions & 9 deletions lua/neo-tree/setup/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -197,8 +197,17 @@ M.buffer_enter_event = function()
end
last_buffer_enter_filetype = vim.bo.filetype

-- For all others, make sure another buffer is not hijacking our window
-- ..but not if the position is "current"
local prior_buf = vim.fn.bufnr("#")
if prior_buf < 1 then
return
end
local prior_type = vim.api.nvim_buf_get_option(prior_buf, "filetype")

-- there is nothing more we want to do with floating windows
if utils.is_floating() then
-- but when prior_type is neo-tree we might need to redirect buffer somewhere else.
if utils.is_floating() and prior_type ~= "neo-tree" then
return
end

Expand All @@ -207,14 +216,6 @@ M.buffer_enter_event = function()
return
end

-- For all others, make sure another buffer is not hijacking our window
-- ..but not if the position is "current"
local prior_buf = vim.fn.bufnr("#")
if prior_buf < 1 then
return
end
local winid = vim.api.nvim_get_current_win()
local prior_type = vim.api.nvim_buf_get_option(prior_buf, "filetype")
if prior_type == "neo-tree" then
local success, position = pcall(vim.api.nvim_buf_get_var, prior_buf, "neo_tree_position")
if not success then
Expand Down
17 changes: 8 additions & 9 deletions lua/neo-tree/ui/renderer.lua
Original file line number Diff line number Diff line change
Expand Up @@ -164,15 +164,12 @@ M.close = function(state, focus_prior_window)
state.winid = nil
end
local bufnr = utils.get_value(state, "bufnr", 0, true)
if bufnr > 0 and vim.api.nvim_buf_is_valid(bufnr) then
state.bufnr = nil
local success, err = pcall(vim.api.nvim_buf_delete, bufnr, { force = true })
if not success and err:match("E523") then
vim.schedule_wrap(function()
vim.api.nvim_buf_delete(bufnr, { force = true })
end)()
state.bufnr = nil
vim.schedule(function()
if bufnr > 0 and vim.api.nvim_buf_is_valid(bufnr) then
vim.api.nvim_buf_delete(bufnr, { force = true })
end
end
end)
return window_existed
end

Expand Down Expand Up @@ -1040,7 +1037,9 @@ M.acquire_window = function(state)
M.position.save(state)
end)
win:on({ "BufDelete" }, function()
win:unmount()
vim.schedule(function ()
win:unmount()
end)
end, { once = true })
end

Expand Down
70 changes: 50 additions & 20 deletions lua/neo-tree/utils/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -508,6 +508,14 @@ M.is_floating = function(win_id)
return false
end

M.is_winfixbuf = function(win_id)
if vim.fn.exists("&winfixbuf") == 1 then
win_id = win_id or vim.api.nvim_get_current_win()
return vim.api.nvim_get_option_value("winfixbuf", { win = win_id })
end
return false
end

---Evaluates the value of <afile>, which comes from an autocmd event, and determines if it
---is a valid file or some sort of utility buffer like quickfix or neo-tree itself.
---@param afile string The path or relative path to the file.
Expand Down Expand Up @@ -565,7 +573,7 @@ M.map = function(tbl, fn)
return t
end

M.get_appropriate_window = function(state)
M.get_appropriate_window = function(state, ignore_winfixbuf)
-- Avoid triggering autocommands when switching windows
local eventignore = vim.o.eventignore
vim.o.eventignore = "all"
Expand All @@ -579,7 +587,7 @@ M.get_appropriate_window = function(state)
local ignore = M.list_to_dict(ignore_ft)
ignore["neo-tree"] = true
if nt.config.open_files_in_last_window then
local prior_window = nt.get_prior_window(ignore)
local prior_window = nt.get_prior_window(ignore, ignore_winfixbuf)
if prior_window > 0 then
local success = pcall(vim.api.nvim_set_current_win, prior_window)
if success then
Expand All @@ -601,6 +609,9 @@ M.get_appropriate_window = function(state)
if ignore[vim.bo.filetype] or ignore[bt] or M.is_floating() then
attempts = attempts + 1
vim.cmd("wincmd w")
elseif ignore_winfixbuf and M.is_winfixbuf() then
attempts = attempts + 1
vim.cmd("wincmd w")
else
suitable_window_found = true
end
Expand Down Expand Up @@ -642,6 +653,28 @@ M.resolve_width = function(width)
return math.floor(width)
end

M.force_new_split = function(current_position, escaped_path)
local result, err
local split_command = "vsplit"
-- respect window position in user config when Neo-tree is the only window
if current_position == "left" then
split_command = "rightbelow vs"
elseif current_position == "right" then
split_command = "leftabove vs"
end
if escaped_path == M.escape_path_for_cmd("[No Name]") then
-- vim's default behavior is to overwrite [No Name] buffers.
-- We need to split first and then open the path to workaround this behavior.
result, err = pcall(vim.cmd, split_command)
if result then
vim.cmd.edit(escaped_path)
end
else
result, err = pcall(vim.cmd, split_command .. " " .. escaped_path)
end
return result, err
end

---Open file in the appropriate window.
---@param state table The state of the source
---@param path string The file to open
Expand All @@ -654,7 +687,8 @@ M.open_file = function(state, path, open_cmd, bufnr)
if bufnr <= 0 then
bufnr = nil
else
local buf_cmd_lookup = { edit = "b", e = "b", split = "sb", sp = "sb", vsplit = "vert sb", vs = "vert sb" }
local buf_cmd_lookup =
{ edit = "b", e = "b", split = "sb", sp = "sb", vsplit = "vert sb", vs = "vert sb" }
local cmd_for_buf = buf_cmd_lookup[open_cmd]
if cmd_for_buf then
open_cmd = cmd_for_buf
Expand Down Expand Up @@ -692,28 +726,24 @@ M.open_file = function(state, path, open_cmd, bufnr)
width = M.get_value(state, "window.width", 40, false)
width = M.resolve_width(width)
end

local split_command = "vsplit"
-- respect window position in user config when Neo-tree is the only window
if state.current_position == "left" then
split_command = "rightbelow vs"
elseif state.current_position == "right" then
split_command = "leftabove vs"
end
if path == "[No Name]" then
result, err = pcall(vim.cmd, split_command)
if result then
vim.cmd("b" .. bufnr)
end
else
result, err = pcall(vim.cmd, split_command .. " " .. escaped_path)
end

result, err = M.force_new_split(state.current_position, escaped_path)
vim.api.nvim_win_set_width(winid, width)
else
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)
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.api.nvim_buf_set_option(0, "buflisted", true)
Expand Down
7 changes: 6 additions & 1 deletion tests/neo-tree/command/command_current_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,11 @@ local run_in_current_command = function(command, expected_tree_node)
end
end

local run_close_command = function(command)
vim.cmd(command)
u.wait_for(function() end, { interval = 200, timeout = 200 })
end

describe("Command", function()
local test = u.fs.init_test({
items = {
Expand Down Expand Up @@ -71,7 +76,7 @@ describe("Command", function()
run_in_current_command(cmd, testfile)

-- toggle CLOSE
vim.cmd(cmd)
run_close_command(cmd)
verify.window_handle_is(tree_winid)
verify.buf_name_is(testfile)
end)
Expand Down
13 changes: 9 additions & 4 deletions tests/neo-tree/command/command_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,11 @@ local run_show_command = function(command, expected_tree_node)
end, "Expected to see a new window without focusing it.")
end

local run_close_command = function(command)
vim.cmd(command)
u.wait_for(function() end, { interval = 200, timeout = 200 })
end

describe("Command", function()
local test = u.fs.init_test({
items = {
Expand Down Expand Up @@ -87,7 +92,7 @@ describe("Command", function()
local tree_winid = vim.api.nvim_get_current_win()

-- toggle CLOSE
vim.cmd(cmd)
run_close_command(cmd)
verify.window_handle_is_not(tree_winid)
verify.buf_name_is(testfile)

Expand All @@ -109,7 +114,7 @@ describe("Command", function()
local tree_winid = vim.api.nvim_get_current_win()

-- toggle CLOSE
vim.cmd("Neotree float reveal toggle")
run_close_command("Neotree float reveal toggle")
verify.window_handle_is_not(tree_winid)
verify.buf_name_is(testfile)

Expand Down Expand Up @@ -158,7 +163,7 @@ describe("Command", function()

verify.after(500, function()
-- toggle CLOSE
vim.cmd(cmd)
run_close_command(cmd)

-- toggle OPEN
u.editfile(topfile)
Expand Down Expand Up @@ -189,7 +194,7 @@ describe("Command", function()
run_focus_command("Neotree reveal", baz)
local expected_tree_node = baz
-- toggle CLOSE
vim.cmd(cmd)
run_close_command(cmd)

verify.after(500, function()
-- toggle OPEN
Expand Down