diff --git a/lua/oil/init.lua b/lua/oil/init.lua index 68894b8..9f70d05 100644 --- a/lua/oil/init.lua +++ b/lua/oil/init.lua @@ -556,7 +556,11 @@ M.setup = function(opts) loading.set_loading(bufnr, true) local function finish(new_url) if new_url ~= params.file then - util.rename_buffer(bufnr, new_url) + if util.rename_buffer(bufnr, new_url) then + -- If the buffer was replaced then don't initialize it. It's dead. The replacement will + -- have BufReadCmd called for it + return + end end vim.cmd.doautocmd({ args = { "BufReadPre", params.file }, mods = { emsg_silent = true } }) view.initialize(bufnr) diff --git a/lua/oil/util.lua b/lua/oil/util.lua index 9192d91..ad03170 100644 --- a/lua/oil/util.lua +++ b/lua/oil/util.lua @@ -87,12 +87,13 @@ end ---@param src_bufnr integer|string Buffer number or name ---@param dest_buf_name string +---@return boolean True if the buffer was replaced instead of renamed M.rename_buffer = function(src_bufnr, dest_buf_name) if type(src_bufnr) == "string" then src_bufnr = vim.fn.bufadd(src_bufnr) if not vim.api.nvim_buf_is_loaded(src_bufnr) then vim.api.nvim_buf_delete(src_bufnr, {}) - return + return false end end @@ -107,7 +108,7 @@ M.rename_buffer = function(src_bufnr, dest_buf_name) if ok then -- Renaming the buffer creates a new buffer with the old name. Find it and delete it. vim.api.nvim_buf_delete(vim.fn.bufadd(bufname), {}) - return + return false end end @@ -116,20 +117,25 @@ M.rename_buffer = function(src_bufnr, dest_buf_name) if vim.bo[src_bufnr].buflisted then vim.bo[dest_bufnr].buflisted = true end - -- Find any windows with the old buffer and replace them - for _, winid in ipairs(vim.api.nvim_list_wins()) do - if vim.api.nvim_win_is_valid(winid) then - if vim.api.nvim_win_get_buf(winid) == src_bufnr then - vim.api.nvim_win_set_buf(winid, dest_bufnr) + -- If we're renaming a buffer that we're about to enter, this may be called before the buffer is + -- actually in the window. We need to wait to enter the buffer and _then_ replace it. + vim.schedule(function() + -- Find any windows with the old buffer and replace them + for _, winid in ipairs(vim.api.nvim_list_wins()) do + if vim.api.nvim_win_is_valid(winid) then + if vim.api.nvim_win_get_buf(winid) == src_bufnr then + vim.api.nvim_win_set_buf(winid, dest_bufnr) + end end end - end - if vim.bo[src_bufnr].modified then - local src_lines = vim.api.nvim_buf_get_lines(src_bufnr, 0, -1, true) - vim.api.nvim_buf_set_lines(dest_bufnr, 0, -1, true, src_lines) - end - -- Try to delete, but don't if the buffer has changes - pcall(vim.api.nvim_buf_delete, src_bufnr, {}) + if vim.bo[src_bufnr].modified then + local src_lines = vim.api.nvim_buf_get_lines(src_bufnr, 0, -1, true) + vim.api.nvim_buf_set_lines(dest_bufnr, 0, -1, true, src_lines) + end + -- Try to delete, but don't if the buffer has changes + pcall(vim.api.nvim_buf_delete, src_bufnr, {}) + end) + return true end ---@param count integer diff --git a/tests/regression_spec.lua b/tests/regression_spec.lua new file mode 100644 index 0000000..46eade8 --- /dev/null +++ b/tests/regression_spec.lua @@ -0,0 +1,20 @@ +require("plenary.async").tests.add_to_env() +local test_util = require("tests.test_util") + +a.describe("regression tests", function() + after_each(function() + test_util.reset_editor() + end) + -- see https://github.com/stevearc/oil.nvim/issues/25 + a.it("can edit dirs that will be renamed to an existing buffer", function() + vim.cmd.edit({ args = { "README.md" } }) + vim.cmd.vsplit() + vim.cmd.edit({ args = { "%:p:h" } }) + assert.equals("oil", vim.bo.filetype) + vim.cmd.wincmd({ args = { "p" } }) + assert.equals("markdown", vim.bo.filetype) + vim.cmd.edit({ args = { "%:p:h" } }) + a.util.sleep(10) + assert.equals("oil", vim.bo.filetype) + end) +end)