vim-patch:8.2.4868: when closing help window autocmds triggered for wrong window (#18420)

Problem:    When closing help window autocmds triggered for the wrong window.
Solution:   Figure out the new current window earlier. (closes vim/vim#10348)
2a2707d033
This commit is contained in:
zeertzjq 2022-05-05 07:26:42 +08:00 committed by GitHub
parent beb8f48489
commit 82c7a82c35
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 58 additions and 26 deletions

View File

@ -9,6 +9,30 @@ func Test_help_restore_snapshot()
helpclose helpclose
endfunc endfunc
func Test_help_restore_snapshot_split()
" Squeeze the unnamed buffer, Xfoo and the help one side-by-side and focus
" the first one before calling :help.
let bnr = bufnr()
botright vsp Xfoo
wincmd h
help
wincmd L
let g:did_bufenter = v:false
augroup T
au!
au BufEnter Xfoo let g:did_bufenter = v:true
augroup END
helpclose
augroup! T
" We're back to the unnamed buffer.
call assert_equal(bnr, bufnr())
" No BufEnter was triggered for Xfoo.
call assert_equal(v:false, g:did_bufenter)
close!
bwipe!
endfunc
func Test_help_errors() func Test_help_errors()
call assert_fails('help doesnotexist', 'E149:') call assert_fails('help doesnotexist', 'E149:')
call assert_fails('help!', 'E478:') call assert_fails('help!', 'E478:')

View File

@ -2813,10 +2813,11 @@ int win_close(win_T *win, bool free_buf, bool force)
wp = win_free_mem(win, &dir, NULL); wp = win_free_mem(win, &dir, NULL);
if (help_window) { if (help_window) {
// Closing the help window moves the cursor back to the original window. // Closing the help window moves the cursor back to the current window
win_T *tmpwp = get_snapshot_focus(SNAP_HELP_IDX); // of the snapshot.
if (tmpwp != NULL) { win_T *prev_win = get_snapshot_curwin(SNAP_HELP_IDX);
wp = tmpwp; if (win_valid(prev_win)) {
wp = prev_win;
} }
} }
@ -6827,6 +6828,35 @@ static void clear_snapshot_rec(frame_T *fr)
} }
} }
/// Traverse a snapshot to find the previous curwin.
static win_T *get_snapshot_curwin_rec(frame_T *ft)
{
win_T *wp;
if (ft->fr_next != NULL) {
if ((wp = get_snapshot_curwin_rec(ft->fr_next)) != NULL) {
return wp;
}
}
if (ft->fr_child != NULL) {
if ((wp = get_snapshot_curwin_rec(ft->fr_child)) != NULL) {
return wp;
}
}
return ft->fr_win;
}
/// @return the current window stored in the snapshot or NULL.
static win_T *get_snapshot_curwin(int idx)
{
if (curtab->tp_snapshot[idx] == NULL) {
return NULL;
}
return get_snapshot_curwin_rec(curtab->tp_snapshot[idx]);
}
/// Restore a previously created snapshot, if there is any. /// Restore a previously created snapshot, if there is any.
/// This is only done if the screen size didn't change and the window layout is /// This is only done if the screen size didn't change and the window layout is
/// still the same. /// still the same.
@ -6899,28 +6929,6 @@ static win_T *restore_snapshot_rec(frame_T *sn, frame_T *fr)
return wp; return wp;
} }
/// Gets the focused window (the one holding the cursor) of the snapshot.
static win_T *get_snapshot_focus(int idx)
{
if (curtab->tp_snapshot[idx] == NULL) {
return NULL;
}
frame_T *sn = curtab->tp_snapshot[idx];
// This should be equivalent to the recursive algorithm found in
// restore_snapshot as far as traveling nodes go.
while (sn->fr_child != NULL || sn->fr_next != NULL) {
while (sn->fr_child != NULL) {
sn = sn->fr_child;
}
if (sn->fr_next != NULL) {
sn = sn->fr_next;
}
}
return win_valid(sn->fr_win) ? sn->fr_win : NULL;
}
/// Set "win" to be the curwin and "tp" to be the current tab page. /// Set "win" to be the curwin and "tp" to be the current tab page.
/// restore_win() MUST be called to undo, also when FAIL is returned. /// restore_win() MUST be called to undo, also when FAIL is returned.
/// No autocommands will be executed until restore_win() is called. /// No autocommands will be executed until restore_win() is called.