revert: "fix(window): :close crash with autocmd, floats and tabpage" (#27796)

This reverts PR #27793.

On second thought, this solution may still crash, because it can leave a
window with a NULL buffer if there are autocommand windows or if closing
a floating window fails. It also makes close_last_window_tabpage() more
complicated, so revert it.
This commit is contained in:
zeertzjq
2024-03-10 10:33:10 +08:00
committed by GitHub
parent 9bd4a28079
commit 6052b346f1
2 changed files with 30 additions and 35 deletions

View File

@@ -2539,47 +2539,21 @@ bool can_close_in_cmdwin(win_T *win, Error *err)
return true; return true;
} }
/// Close the possibly last non-floating window in a tab page. /// Close the possibly last window in a tab page.
/// ///
/// @param win window to close /// @param win window to close
/// @param free_buf whether to free the window's current buffer /// @param free_buf whether to free the window's current buffer
/// @param force close floating windows even if they are modified
/// @param prev_curtab previous tabpage that will be closed if "win" is the /// @param prev_curtab previous tabpage that will be closed if "win" is the
/// last window in the tabpage /// last window in the tabpage
/// ///
/// @return false if there are other non-floating windows and nothing is done, true otherwise. /// @return false if there are other windows and nothing is done, true otherwise.
static bool close_last_window_tabpage(win_T *win, bool free_buf, bool force, tabpage_T *prev_curtab) static bool close_last_window_tabpage(win_T *win, bool free_buf, tabpage_T *prev_curtab)
FUNC_ATTR_NONNULL_ARG(1) FUNC_ATTR_NONNULL_ARG(1)
{ {
if (!one_window(win)) { if (!ONE_WINDOW) {
return false; return false;
} }
if (lastwin->w_floating && one_window(win)) {
if (is_aucmd_win(lastwin)) {
emsg(_("E814: Cannot close window, only autocmd window would remain"));
return true;
}
if (force || can_close_floating_windows()) {
// close the last window until the there are no floating windows
while (lastwin->w_floating) {
// `force` flag isn't actually used when closing a floating window.
if (win_close(lastwin, free_buf, true) == FAIL) {
// If closing the window fails give up, to avoid looping forever.
return true;
}
}
} else {
emsg(e_floatonly);
return true;
}
if (!win_valid_any_tab(win)) {
return true; // window already closed by autocommands
}
}
buf_T *old_curbuf = curbuf; buf_T *old_curbuf = curbuf;
Terminal *term = win->w_buffer ? win->w_buffer->terminal : NULL; Terminal *term = win->w_buffer ? win->w_buffer->terminal : NULL;
@@ -2675,11 +2649,33 @@ int win_close(win_T *win, bool free_buf, bool force)
emsg(_(e_autocmd_close)); emsg(_(e_autocmd_close));
return FAIL; return FAIL;
} }
if (lastwin->w_floating && one_window(win)) {
if (is_aucmd_win(lastwin)) {
emsg(_("E814: Cannot close window, only autocmd window would remain"));
return FAIL;
}
if (force || can_close_floating_windows()) {
// close the last window until the there are no floating windows
while (lastwin->w_floating) {
// `force` flag isn't actually used when closing a floating window.
if (win_close(lastwin, free_buf, true) == FAIL) {
// If closing the window fails give up, to avoid looping forever.
return FAIL;
}
}
if (!win_valid_any_tab(win)) {
return FAIL; // window already closed by autocommands
}
} else {
emsg(e_floatonly);
return FAIL;
}
}
// When closing the last window in a tab page first go to another tab page // When closing the last window in a tab page first go to another tab page
// and then close the window and the tab page to avoid that curwin and // and then close the window and the tab page to avoid that curwin and
// curtab are invalid while we are freeing memory. // curtab are invalid while we are freeing memory.
if (close_last_window_tabpage(win, free_buf, force, prev_curtab)) { if (close_last_window_tabpage(win, free_buf, prev_curtab)) {
return FAIL; return FAIL;
} }
@@ -2774,7 +2770,7 @@ int win_close(win_T *win, bool free_buf, bool force)
// Autocommands may have closed the window already, or closed the only // Autocommands may have closed the window already, or closed the only
// other window or moved to another tab page. // other window or moved to another tab page.
if (!win_valid(win) || (!win->w_floating && last_window(win)) if (!win_valid(win) || (!win->w_floating && last_window(win))
|| close_last_window_tabpage(win, free_buf, force, prev_curtab)) { || close_last_window_tabpage(win, free_buf, prev_curtab)) {
return FAIL; return FAIL;
} }

View File

@@ -893,7 +893,7 @@ describe('float window', function()
assert_alive() assert_alive()
end) end)
it('does not crash if BufUnload makes it the only non-float in tabpage', function() pending('does not crash if BufUnload makes it the only non-float in tabpage', function()
exec([[ exec([[
tabnew tabnew
let g:buf = bufnr() let g:buf = bufnr()
@@ -909,10 +909,9 @@ describe('float window', function()
assert_alive() assert_alive()
end) end)
it('does not crash if WinClosed from floating windows closes it', function() it('does not crash if WinClosed from floating window closes it', function()
exec([[ exec([[
tabnew tabnew
let g:buf = bufnr()
new new
let s:win = win_getid() let s:win = win_getid()
call nvim_win_set_config(s:win, call nvim_win_set_config(s:win,