vim-patch:partial:9.0.0907: restoring window after WinScrolled may fail

Problem:    Restoring window after WinScrolled may fail.
Solution:   Lock the window layout when triggering WinScrolled.

d63a85592c

Only check close_disallowed in window_layout_locked() for now.
Also don't check window_layout_locked() when closing a floating window,
as it's not checked when creating a floating window.

Co-authored-by: Bram Moolenaar <Bram@vim.org>
This commit is contained in:
zeertzjq
2026-01-14 09:21:35 +08:00
parent dddc359213
commit 92596a37e7
3 changed files with 66 additions and 9 deletions

View File

@@ -195,6 +195,8 @@ EXTERN const char e_stray_closing_curly_str[]
INIT(= N_("E1278: Stray '}' without a matching '{': %s"));
EXTERN const char e_missing_close_curly_str[]
INIT(= N_("E1279: Missing '}': %s"));
EXTERN const char e_not_allowed_to_change_window_layout_in_this_autocmd[]
INIT(= N_("E1312: Not allowed to change the window layout in this autocmd"));
EXTERN const char e_val_too_large[] INIT(= N_("E1510: Value too large: %s"));

View File

@@ -5033,6 +5033,9 @@ void ex_win_close(int forceit, win_T *win, tabpage_T *tp)
emsg(_(e_autocmd_close));
return;
}
if (!win->w_floating && window_layout_locked()) {
return;
}
buf_T *buf = win->w_buffer;
@@ -5074,6 +5077,10 @@ static void ex_tabclose(exarg_T *eap)
return;
}
if (window_layout_locked()) {
return;
}
int tab_number = get_tabpage_arg(eap);
if (eap->errmsg != NULL) {
return;
@@ -5105,6 +5112,10 @@ static void ex_tabonly(exarg_T *eap)
return;
}
if (window_layout_locked()) {
return;
}
int tab_number = get_tabpage_arg(eap);
if (eap->errmsg != NULL) {
return;
@@ -5175,9 +5186,12 @@ void tabpage_close_other(tabpage_T *tp, int forceit)
/// ":only".
static void ex_only(exarg_T *eap)
{
win_T *wp;
if (window_layout_locked()) {
return;
}
if (eap->addr_count > 0) {
win_T *wp;
linenr_T wnr = eap->line2;
for (wp = firstwin; --wnr > 0;) {
if (wp->w_next == NULL) {
@@ -5185,11 +5199,9 @@ static void ex_only(exarg_T *eap)
}
wp = wp->w_next;
}
} else {
wp = curwin;
}
if (wp != curwin) {
win_goto(wp);
if (wp != curwin) {
win_goto(wp);
}
}
close_others(true, eap->forceit);
}
@@ -5201,11 +5213,11 @@ static void ex_hide(exarg_T *eap)
return;
}
win_T *win = NULL;
if (eap->addr_count == 0) {
win_close(curwin, false, eap->forceit); // don't free buffer
win = curwin;
} else {
int winnr = 0;
win_T *win = NULL;
FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
winnr++;
@@ -5217,8 +5229,13 @@ static void ex_hide(exarg_T *eap)
if (win == NULL) {
win = lastwin;
}
win_close(win, false, eap->forceit);
}
if (!win->w_floating && window_layout_locked()) {
return;
}
win_close(win, false, eap->forceit); // don't free buffer
}
/// ":stop" and ":suspend": Suspend Vim.

View File

@@ -108,6 +108,38 @@ static char *m_onlyone = N_("Already only one window");
/// autocommands mess up the window structure.
static int split_disallowed = 0;
/// When non-zero closing a window is forbidden. Used to avoid that nasty
/// autocommands mess up the window structure.
static int close_disallowed = 0;
/// Disallow changing the window layout (split window, close window, move
/// window). Resizing is still allowed.
/// Used for autocommands that temporarily use another window and need to
/// make sure the previously selected window is still there.
/// Must be matched with exactly one call to window_layout_unlock()!
static void window_layout_lock(void)
{
split_disallowed++;
close_disallowed++;
}
static void window_layout_unlock(void)
{
split_disallowed--;
close_disallowed--;
}
/// When the window layout cannot be changed give an error and return true.
bool window_layout_locked(void)
{
// if (split_disallowed > 0 || close_disallowed > 0) {
if (close_disallowed > 0) {
emsg(_(e_not_allowed_to_change_window_layout_in_this_autocmd));
return true;
}
return false;
}
// #define WIN_DEBUG
#ifdef WIN_DEBUG
/// Call this method to log the current window layout.
@@ -2739,6 +2771,9 @@ int win_close(win_T *win, bool free_buf, bool force)
emsg(_(e_cannot_close_last_window));
return FAIL;
}
if (!win->w_floating && window_layout_locked()) {
return FAIL;
}
if (win_locked(win)
|| (win->w_buffer != NULL && win->w_buffer->b_locked > 0)) {
@@ -4315,6 +4350,9 @@ int win_new_tabpage(int after, char *filename)
emsg(_(e_cmdwin));
return FAIL;
}
if (window_layout_locked()) {
return FAIL;
}
tabpage_T *newtp = alloc_tabpage();