fix(cwd): E812 when a message opens a window during a file read #41458

Problem:
When ui2 is enabled, opening an already-open file in another Neovim
instance results in the error `E812: Autocommands changed buffer…`.

Analysis:
On E812 the file is not loaded.  The default SwapExists handler notifies
`W325: Ignoring swapfile…`, and ui2 shows that message by opening
a window, which is a temp context switch.  `ctx_dirs_restore()`
re-shortens every buffer name on the way out, and `shorten_buf_fname()`
always frees and reallocates `b_sfname`.  `readfile()` aliases `b_fname`
across `check_need_swap()` and compares the pointer to detect a rename.

Regression by b296666e41, which replaced the `cs_save_sfname` restore
(that kept curbuf's pointer) with `shorten_fnames(true)`.

Solution:
Keep the allocation in `shorten_buf_fname()` when the short name is
unchanged.  Pointer stability is what the E200/E201/E812 guards actually
assert.
This commit is contained in:
Justin M. Keyes
2026-08-23 19:32:07 -04:00
committed by GitHub
parent 716835c232
commit eeefe7ca65
2 changed files with 62 additions and 16 deletions

View File

@@ -436,6 +436,46 @@ describe('swapfile detection', function()
nvim1:close()
end)
-- ui2 opens windows to show a message, which chdirs in and out of the target window's context.
-- readfile() aliases the buffer name across that.
it('ui2 message from the SwapExists handler does not abort the read #41454', function()
exec(init)
write_file('Xfile1', 'some text...\n')
command('edit Xfile1')
command('preserve') -- Make sure the swap file exists.
local initfile = 'Xtest_swapdialog_init.lua'
write_file(
initfile,
('vim.opt.directory:prepend(%q)\nrequire("vim._core.ui2").enable()\n'):format(swapdir .. '//')
)
finally(function()
os.remove(initfile)
os.remove('Xfile1')
end)
local nvim1 = n.new_session(true)
set_session(nvim1)
local screen = Screen.new(75, 10)
-- ui2 needs a UI attached while the file argument is read, i.e. a real TTY.
fn.jobstart({ nvim_prog, '-i', 'NONE', '--noplugin', '-u', initfile, 'Xfile1' }, {
term = true,
env = { VIMRUNTIME = os.getenv('VIMRUNTIME') },
})
screen:expect({
grid = [[
^some text... |
~ |*6
Xfile1 1,1 All|
{MATCH:W325: Ignoring swapfile from Nvim process %d+ *}|
|
]],
attr_ids = {},
})
nvim1:close()
end)
it('attention message kind', function()
exec(init)
command('edit Xfile1')