vim-patch:8.2.0004: get E685 and E931 if buffer reload is interrupted

Problem:    Get E685 and E931 if buffer reload is interrupted.
Solution:   Do not abort deleting a dummy buffer. (closes vim/vim#5361)
a6e8f888e7
This commit is contained in:
zeertzjq 2022-04-07 21:46:07 +08:00
parent 8f3245dbfa
commit 44b59d1a69
9 changed files with 82 additions and 51 deletions

View File

@ -174,7 +174,7 @@ int open_buffer(int read_stdin, exarg_T *eap, int flags)
if (ml_open(curbuf) == FAIL) { if (ml_open(curbuf) == FAIL) {
// There MUST be a memfile, otherwise we can't do anything // There MUST be a memfile, otherwise we can't do anything
// If we can't create one for the current buffer, take another buffer // If we can't create one for the current buffer, take another buffer
close_buffer(NULL, curbuf, 0, false); close_buffer(NULL, curbuf, 0, false, false);
curbuf = NULL; curbuf = NULL;
FOR_ALL_BUFFERS(buf) { FOR_ALL_BUFFERS(buf) {
@ -402,8 +402,10 @@ bool buf_valid(buf_T *buf)
/// there to be only one window with this buffer. e.g. when /// there to be only one window with this buffer. e.g. when
/// ":quit" is supposed to close the window but autocommands /// ":quit" is supposed to close the window but autocommands
/// close all other windows. /// close all other windows.
/// @param ignore_abort
/// If true, don't abort even when aborting() returns true.
/// @return true when we got to the end and b_nwindows was decremented. /// @return true when we got to the end and b_nwindows was decremented.
bool close_buffer(win_T *win, buf_T *buf, int action, bool abort_if_last) bool close_buffer(win_T *win, buf_T *buf, int action, bool abort_if_last, bool ignore_abort)
{ {
bool unload_buf = (action != 0); bool unload_buf = (action != 0);
bool del_buf = (action == DOBUF_DEL || action == DOBUF_WIPE); bool del_buf = (action == DOBUF_DEL || action == DOBUF_WIPE);
@ -494,7 +496,8 @@ bool close_buffer(win_T *win, buf_T *buf, int action, bool abort_if_last)
return false; return false;
} }
} }
if (aborting()) { // autocmds may abort script processing // autocmds may abort script processing
if (!ignore_abort && aborting()) {
return false; return false;
} }
} }
@ -552,14 +555,16 @@ bool close_buffer(win_T *win, buf_T *buf, int action, bool abort_if_last)
buf->b_nwindows = nwindows; buf->b_nwindows = nwindows;
buf_freeall(buf, (del_buf ? BFA_DEL : 0) + (wipe_buf ? BFA_WIPE : 0)); buf_freeall(buf, ((del_buf ? BFA_DEL : 0)
+ (wipe_buf ? BFA_WIPE : 0)
+ (ignore_abort ? BFA_IGNORE_ABORT : 0)));
if (!bufref_valid(&bufref)) { if (!bufref_valid(&bufref)) {
// Autocommands may have deleted the buffer. // Autocommands may have deleted the buffer.
return false; return false;
} }
if (aborting()) { // autocmds may abort script processing.
// Autocmds may abort script processing. if (!ignore_abort && aborting()) {
return false; return false;
} }
@ -660,9 +665,10 @@ void buf_clear(void)
/// buf_freeall() - free all things allocated for a buffer that are related to /// buf_freeall() - free all things allocated for a buffer that are related to
/// the file. Careful: get here with "curwin" NULL when exiting. /// the file. Careful: get here with "curwin" NULL when exiting.
/// ///
/// @param flags BFA_DEL buffer is going to be deleted /// @param flags BFA_DEL buffer is going to be deleted
/// BFA_WIPE buffer is going to be wiped out /// BFA_WIPE buffer is going to be wiped out
/// BFA_KEEP_UNDO do not free undo information /// BFA_KEEP_UNDO do not free undo information
/// BFA_IGNORE_ABORT don't abort even when aborting() returns true
void buf_freeall(buf_T *buf, int flags) void buf_freeall(buf_T *buf, int flags)
{ {
bool is_curbuf = (buf == curbuf); bool is_curbuf = (buf == curbuf);
@ -706,7 +712,8 @@ void buf_freeall(buf_T *buf, int flags)
goto_tabpage_win(the_curtab, the_curwin); goto_tabpage_win(the_curtab, the_curwin);
unblock_autocmds(); unblock_autocmds();
} }
if (aborting()) { // autocmds may abort script processing // autocmds may abort script processing
if ((flags & BFA_IGNORE_ABORT) == 0 && aborting()) {
return; return;
} }
@ -877,7 +884,7 @@ void handle_swap_exists(bufref_T *old_curbuf)
// open a new, empty buffer. // open a new, empty buffer.
swap_exists_action = SEA_NONE; // don't want it again swap_exists_action = SEA_NONE; // don't want it again
swap_exists_did_quit = true; swap_exists_did_quit = true;
close_buffer(curwin, curbuf, DOBUF_UNLOAD, false); close_buffer(curwin, curbuf, DOBUF_UNLOAD, false, false);
if (old_curbuf == NULL if (old_curbuf == NULL
|| !bufref_valid(old_curbuf) || !bufref_valid(old_curbuf)
|| old_curbuf->br_buf == curbuf) { || old_curbuf->br_buf == curbuf) {
@ -1074,7 +1081,7 @@ static int empty_curbuf(int close_others, int forceit, int action)
// the old one. But do_ecmd() may have done that already, check // the old one. But do_ecmd() may have done that already, check
// if the buffer still exists. // if the buffer still exists.
if (buf != curbuf && bufref_valid(&bufref) && buf->b_nwindows == 0) { if (buf != curbuf && bufref_valid(&bufref) && buf->b_nwindows == 0) {
close_buffer(NULL, buf, action, false); close_buffer(NULL, buf, action, false, false);
} }
if (!close_others) { if (!close_others) {
@ -1259,7 +1266,7 @@ int do_buffer(int action, int start, int dir, int count, int forceit)
if (buf != curbuf) { if (buf != curbuf) {
close_windows(buf, false); close_windows(buf, false);
if (buf != curbuf && bufref_valid(&bufref) && buf->b_nwindows <= 0) { if (buf != curbuf && bufref_valid(&bufref) && buf->b_nwindows <= 0) {
close_buffer(NULL, buf, action, false); close_buffer(NULL, buf, action, false, false);
} }
return OK; return OK;
} }
@ -1485,7 +1492,7 @@ void set_curbuf(buf_T *buf, int action)
? action ? action
: (action == DOBUF_GOTO && !buf_hide(prevbuf) : (action == DOBUF_GOTO && !buf_hide(prevbuf)
&& !bufIsChanged(prevbuf)) ? DOBUF_UNLOAD : 0, && !bufIsChanged(prevbuf)) ? DOBUF_UNLOAD : 0,
false); false, false);
if (curwin != previouswin && win_valid(previouswin)) { if (curwin != previouswin && win_valid(previouswin)) {
// autocommands changed curwin, Grr! // autocommands changed curwin, Grr!
curwin = previouswin; curwin = previouswin;
@ -2805,7 +2812,7 @@ int setfname(buf_T *buf, char_u *ffname_arg, char_u *sfname_arg, bool message)
return FAIL; return FAIL;
} }
// delete from the list // delete from the list
close_buffer(NULL, obuf, DOBUF_WIPE, false); close_buffer(NULL, obuf, DOBUF_WIPE, false, false);
} }
sfname = vim_strsave(sfname); sfname = vim_strsave(sfname);
#ifdef USE_FNAME_CASE #ifdef USE_FNAME_CASE
@ -5650,7 +5657,7 @@ void wipe_buffer(buf_T *buf, bool aucmd)
// Don't trigger BufDelete autocommands here. // Don't trigger BufDelete autocommands here.
block_autocmds(); block_autocmds();
} }
close_buffer(NULL, buf, DOBUF_WIPE, false); close_buffer(NULL, buf, DOBUF_WIPE, false, true);
if (!aucmd) { if (!aucmd) {
unblock_autocmds(); unblock_autocmds();
} }

View File

@ -58,9 +58,10 @@ enum dobuf_start_values {
// flags for buf_freeall() // flags for buf_freeall()
enum bfa_values { enum bfa_values {
BFA_DEL = 1, // buffer is going to be deleted BFA_DEL = 1, // buffer is going to be deleted
BFA_WIPE = 2, // buffer is going to be wiped out BFA_WIPE = 2, // buffer is going to be wiped out
BFA_KEEP_UNDO = 4, // do not free undo information BFA_KEEP_UNDO = 4, // do not free undo information
BFA_IGNORE_ABORT = 8, // do not abort for aborting()
}; };
#ifdef INCLUDE_GENERATED_DECLARATIONS #ifdef INCLUDE_GENERATED_DECLARATIONS

View File

@ -2527,9 +2527,9 @@ int do_ecmd(int fnum, char_u *ffname, char_u *sfname, exarg_T *eap, linenr_T new
// Close the link to the current buffer. This will set // Close the link to the current buffer. This will set
// oldwin->w_buffer to NULL. // oldwin->w_buffer to NULL.
u_sync(false); u_sync(false);
const bool did_decrement = close_buffer(oldwin, curbuf, const bool did_decrement
(flags & ECMD_HIDE) || curbuf->terminal ? 0 : DOBUF_UNLOAD, = close_buffer(oldwin, curbuf, (flags & ECMD_HIDE) || curbuf->terminal ? 0 : DOBUF_UNLOAD,
false); false, false);
// Autocommands may have closed the window. // Autocommands may have closed the window.
if (win_valid(the_curwin)) { if (win_valid(the_curwin)) {

View File

@ -6544,7 +6544,7 @@ static int open_cmdwin(void)
// win_close() may have already wiped the buffer when 'bh' is // win_close() may have already wiped the buffer when 'bh' is
// set to 'wipe', autocommands may have closed other windows // set to 'wipe', autocommands may have closed other windows
if (bufref_valid(&bufref) && bufref.br_buf != curbuf) { if (bufref_valid(&bufref) && bufref.br_buf != curbuf) {
close_buffer(NULL, bufref.br_buf, DOBUF_WIPE, false); close_buffer(NULL, bufref.br_buf, DOBUF_WIPE, false, false);
} }
// Restore window sizes. // Restore window sizes.

View File

@ -691,7 +691,7 @@ void free_all_mem(void)
bufref_T bufref; bufref_T bufref;
set_bufref(&bufref, buf); set_bufref(&bufref, buf);
nextbuf = buf->b_next; nextbuf = buf->b_next;
close_buffer(NULL, buf, DOBUF_WIPE, false); close_buffer(NULL, buf, DOBUF_WIPE, false, false);
// Didn't work, try next one. // Didn't work, try next one.
buf = bufref_valid(&bufref) ? nextbuf : firstbuf; buf = bufref_valid(&bufref) ? nextbuf : firstbuf;
} }

View File

@ -1721,7 +1721,7 @@ static void wipe_qf_buffer(qf_info_T *qi)
if (qfbuf != NULL && qfbuf->b_nwindows == 0) { if (qfbuf != NULL && qfbuf->b_nwindows == 0) {
// If the quickfix buffer is not loaded in any window, then // If the quickfix buffer is not loaded in any window, then
// wipe the buffer. // wipe the buffer.
close_buffer(NULL, qfbuf, DOBUF_WIPE, false); close_buffer(NULL, qfbuf, DOBUF_WIPE, false, false);
qi->qf_bufnr = INVALID_QFBUFNR; qi->qf_bufnr = INVALID_QFBUFNR;
} }
} }
@ -5843,7 +5843,7 @@ static void wipe_dummy_buffer(buf_T *buf, char_u *dirname_start)
static void unload_dummy_buffer(buf_T *buf, char_u *dirname_start) static void unload_dummy_buffer(buf_T *buf, char_u *dirname_start)
{ {
if (curbuf != buf) { // safety check if (curbuf != buf) { // safety check
close_buffer(NULL, buf, DOBUF_UNLOAD, false); close_buffer(NULL, buf, DOBUF_UNLOAD, false, true);
// When autocommands/'autochdir' option changed directory: go back. // When autocommands/'autochdir' option changed directory: go back.
restore_start_dir(dirname_start); restore_start_dir(dirname_start);

View File

@ -1972,6 +1972,29 @@ func Test_builtin_func_error()
call assert_equal('jlmnpqrtueghivyzACD', g:Xpath) call assert_equal('jlmnpqrtueghivyzACD', g:Xpath)
endfunc endfunc
" Modelines {{{1 func Test_reload_in_try_catch()
call writefile(['x'], 'Xreload')
set autoread
edit Xreload
tabnew
call writefile(['xx'], 'Xreload')
augroup ReLoad
au FileReadPost Xreload let x = doesnotexist
au BufReadPost Xreload let x = doesnotexist
augroup END
try
edit Xreload
catch
endtry
tabnew
tabclose
tabclose
autocmd! ReLoad
set noautoread
bwipe! Xreload
call delete('Xreload')
endfunc
" Modeline {{{1
" vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker " vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker
"-------------------------------------------------------------------------------

View File

@ -2563,7 +2563,7 @@ static void win_close_buffer(win_T *win, bool free_buf, bool abort_if_last)
bufref_T bufref; bufref_T bufref;
set_bufref(&bufref, curbuf); set_bufref(&bufref, curbuf);
win->w_closing = true; win->w_closing = true;
close_buffer(win, win->w_buffer, free_buf ? DOBUF_UNLOAD : 0, abort_if_last); close_buffer(win, win->w_buffer, free_buf ? DOBUF_UNLOAD : 0, abort_if_last, false);
if (win_valid_any_tab(win)) { if (win_valid_any_tab(win)) {
win->w_closing = false; win->w_closing = false;
} }
@ -2885,7 +2885,7 @@ void win_close_othertab(win_T *win, int free_buf, tabpage_T *tp)
if (win->w_buffer != NULL) { if (win->w_buffer != NULL) {
// Close the link to the buffer. // Close the link to the buffer.
close_buffer(win, win->w_buffer, free_buf ? DOBUF_UNLOAD : 0, false); close_buffer(win, win->w_buffer, free_buf ? DOBUF_UNLOAD : 0, false, false);
} }
// Careful: Autocommands may have closed the tab page or made it the // Careful: Autocommands may have closed the tab page or made it the

View File

@ -17,8 +17,8 @@ describe('buffer functions', function()
return buffer.buflist_new(c_file, c_file, 1, flags) return buffer.buflist_new(c_file, c_file, 1, flags)
end end
local close_buffer = function(win, buf, action, abort_if_last) local close_buffer = function(win, buf, action, abort_if_last, ignore_abort)
return buffer.close_buffer(win, buf, action, abort_if_last) return buffer.close_buffer(win, buf, action, abort_if_last, ignore_abort)
end end
local path1 = 'test_file_path' local path1 = 'test_file_path'
@ -53,7 +53,7 @@ describe('buffer functions', function()
itp('should view a closed and hidden buffer as valid', function() itp('should view a closed and hidden buffer as valid', function()
local buf = buflist_new(path1, buffer.BLN_LISTED) local buf = buflist_new(path1, buffer.BLN_LISTED)
close_buffer(NULL, buf, 0, 0) close_buffer(NULL, buf, 0, 0, 0)
eq(true, buffer.buf_valid(buf)) eq(true, buffer.buf_valid(buf))
end) end)
@ -61,7 +61,7 @@ describe('buffer functions', function()
itp('should view a closed and unloaded buffer as valid', function() itp('should view a closed and unloaded buffer as valid', function()
local buf = buflist_new(path1, buffer.BLN_LISTED) local buf = buflist_new(path1, buffer.BLN_LISTED)
close_buffer(NULL, buf, buffer.DOBUF_UNLOAD, 0) close_buffer(NULL, buf, buffer.DOBUF_UNLOAD, 0, 0)
eq(true, buffer.buf_valid(buf)) eq(true, buffer.buf_valid(buf))
end) end)
@ -69,7 +69,7 @@ describe('buffer functions', function()
itp('should view a closed and wiped buffer as invalid', function() itp('should view a closed and wiped buffer as invalid', function()
local buf = buflist_new(path1, buffer.BLN_LISTED) local buf = buflist_new(path1, buffer.BLN_LISTED)
close_buffer(NULL, buf, buffer.DOBUF_WIPE, 0) close_buffer(NULL, buf, buffer.DOBUF_WIPE, 0, 0)
eq(false, buffer.buf_valid(buf)) eq(false, buffer.buf_valid(buf))
end) end)
@ -90,7 +90,7 @@ describe('buffer functions', function()
eq(buf.handle, buflist_findpat(path1, ONLY_LISTED)) eq(buf.handle, buflist_findpat(path1, ONLY_LISTED))
close_buffer(NULL, buf, buffer.DOBUF_WIPE, 0) close_buffer(NULL, buf, buffer.DOBUF_WIPE, 0, 0)
end) end)
itp('should prefer to match the start of a file path', function() itp('should prefer to match the start of a file path', function()
@ -102,9 +102,9 @@ describe('buffer functions', function()
eq(buf2.handle, buflist_findpat("file", ONLY_LISTED)) eq(buf2.handle, buflist_findpat("file", ONLY_LISTED))
eq(buf3.handle, buflist_findpat("path", ONLY_LISTED)) eq(buf3.handle, buflist_findpat("path", ONLY_LISTED))
close_buffer(NULL, buf1, buffer.DOBUF_WIPE, 0) close_buffer(NULL, buf1, buffer.DOBUF_WIPE, 0, 0)
close_buffer(NULL, buf2, buffer.DOBUF_WIPE, 0) close_buffer(NULL, buf2, buffer.DOBUF_WIPE, 0, 0)
close_buffer(NULL, buf3, buffer.DOBUF_WIPE, 0) close_buffer(NULL, buf3, buffer.DOBUF_WIPE, 0, 0)
end) end)
itp('should prefer to match the end of a file over the middle', function() itp('should prefer to match the end of a file over the middle', function()
@ -118,7 +118,7 @@ describe('buffer functions', function()
--} --}
--{ When: We close buf2 --{ When: We close buf2
close_buffer(NULL, buf2, buffer.DOBUF_WIPE, 0) close_buffer(NULL, buf2, buffer.DOBUF_WIPE, 0, 0)
-- And: Open buf1, which has 'file' in the middle of its name -- And: Open buf1, which has 'file' in the middle of its name
local buf1 = buflist_new(path1, buffer.BLN_LISTED) local buf1 = buflist_new(path1, buffer.BLN_LISTED)
@ -127,8 +127,8 @@ describe('buffer functions', function()
eq(buf3.handle, buflist_findpat("file", ONLY_LISTED)) eq(buf3.handle, buflist_findpat("file", ONLY_LISTED))
--} --}
close_buffer(NULL, buf1, buffer.DOBUF_WIPE, 0) close_buffer(NULL, buf1, buffer.DOBUF_WIPE, 0, 0)
close_buffer(NULL, buf3, buffer.DOBUF_WIPE, 0) close_buffer(NULL, buf3, buffer.DOBUF_WIPE, 0, 0)
end) end)
itp('should match a unique fragment of a file path', function() itp('should match a unique fragment of a file path', function()
@ -138,9 +138,9 @@ describe('buffer functions', function()
eq(buf3.handle, buflist_findpat("_test_", ONLY_LISTED)) eq(buf3.handle, buflist_findpat("_test_", ONLY_LISTED))
close_buffer(NULL, buf1, buffer.DOBUF_WIPE, 0) close_buffer(NULL, buf1, buffer.DOBUF_WIPE, 0, 0)
close_buffer(NULL, buf2, buffer.DOBUF_WIPE, 0) close_buffer(NULL, buf2, buffer.DOBUF_WIPE, 0, 0)
close_buffer(NULL, buf3, buffer.DOBUF_WIPE, 0) close_buffer(NULL, buf3, buffer.DOBUF_WIPE, 0, 0)
end) end)
itp('should include / ignore unlisted buffers based on the flag.', function() itp('should include / ignore unlisted buffers based on the flag.', function()
@ -152,7 +152,7 @@ describe('buffer functions', function()
--} --}
--{ When: We unlist the buffer --{ When: We unlist the buffer
close_buffer(NULL, buf3, buffer.DOBUF_DEL, 0) close_buffer(NULL, buf3, buffer.DOBUF_DEL, 0, 0)
-- Then: It should not find the buffer when searching only listed buffers -- Then: It should not find the buffer when searching only listed buffers
eq(-1, buflist_findpat("_test_", ONLY_LISTED)) eq(-1, buflist_findpat("_test_", ONLY_LISTED))
@ -162,7 +162,7 @@ describe('buffer functions', function()
--} --}
--{ When: We wipe the buffer --{ When: We wipe the buffer
close_buffer(NULL, buf3, buffer.DOBUF_WIPE, 0) close_buffer(NULL, buf3, buffer.DOBUF_WIPE, 0, 0)
-- Then: It should not find the buffer at all -- Then: It should not find the buffer at all
eq(-1, buflist_findpat("_test_", ONLY_LISTED)) eq(-1, buflist_findpat("_test_", ONLY_LISTED))
@ -180,7 +180,7 @@ describe('buffer functions', function()
--} --}
--{ When: The first buffer is unlisted --{ When: The first buffer is unlisted
close_buffer(NULL, buf1, buffer.DOBUF_DEL, 0) close_buffer(NULL, buf1, buffer.DOBUF_DEL, 0, 0)
-- Then: The second buffer is preferred because -- Then: The second buffer is preferred because
-- unlisted buffers are not allowed -- unlisted buffers are not allowed
@ -194,7 +194,7 @@ describe('buffer functions', function()
--} --}
--{ When: We unlist the second buffer --{ When: We unlist the second buffer
close_buffer(NULL, buf2, buffer.DOBUF_DEL, 0) close_buffer(NULL, buf2, buffer.DOBUF_DEL, 0, 0)
-- Then: The first buffer is preferred again -- Then: The first buffer is preferred again
-- because buf1 matches better which takes precedence -- because buf1 matches better which takes precedence
@ -205,8 +205,8 @@ describe('buffer functions', function()
eq(-1, buflist_findpat("test", ONLY_LISTED)) eq(-1, buflist_findpat("test", ONLY_LISTED))
--} --}
close_buffer(NULL, buf1, buffer.DOBUF_WIPE, 0) close_buffer(NULL, buf1, buffer.DOBUF_WIPE, 0, 0)
close_buffer(NULL, buf2, buffer.DOBUF_WIPE, 0) close_buffer(NULL, buf2, buffer.DOBUF_WIPE, 0, 0)
end) end)
end) end)