# HG changeset patch # User Bram Moolenaar # Date 1604764805 -3600 # Node ID 80bd5de5dcab2ffc49a6c99864955435b3c01516 # Parent a1e5d99414e8c728b8b82fe97e252b2d75b52a63 patch 8.2.1966: popup becomes current window after closing a terminal window Commit: https://github.com/vim/vim/commit/cbcd9cbd77acc8cc97c0d44683d96c01d3dd0fa7 Author: Bram Moolenaar Date: Sat Nov 7 16:58:59 2020 +0100 patch 8.2.1966: popup becomes current window after closing a terminal window Problem: Popup becomes current window after closing a terminal window. Solution: When restoring the window after executing autocommands, check that the window ID is still the same. (Naruhiko Nishino, closes #7272) diff --git a/src/autocmd.c b/src/autocmd.c --- a/src/autocmd.c +++ b/src/autocmd.c @@ -1433,9 +1433,9 @@ aucmd_prepbuf( // window. Expect a few side effects... win = curwin; - aco->save_curwin = curwin; + aco->save_curwin_id = curwin->w_id; aco->save_curbuf = curbuf; - aco->save_prevwin = prevwin; + aco->save_prevwin_id = prevwin == NULL ? 0 : prevwin->w_id; if (win != NULL) { // There is a window for "buf" in the current tab page, make it the @@ -1481,7 +1481,7 @@ aucmd_prepbuf( curwin = aucmd_win; } curbuf = buf; - aco->new_curwin = curwin; + aco->new_curwin_id = curwin->w_id; set_bufref(&aco->new_curbuf, curbuf); } @@ -1493,7 +1493,8 @@ aucmd_prepbuf( aucmd_restbuf( aco_save_T *aco) // structure holding saved values { - int dummy; + int dummy; + win_T *save_curwin; if (aco->use_aucmd_win) { @@ -1533,8 +1534,9 @@ win_found: (void)win_comp_pos(); // recompute window positions unblock_autocmds(); - if (win_valid(aco->save_curwin)) - curwin = aco->save_curwin; + save_curwin = win_find_by_id(aco->save_curwin_id); + if (save_curwin != NULL) + curwin = save_curwin; else // Hmm, original window disappeared. Just use the first one. curwin = firstwin; @@ -1543,9 +1545,7 @@ win_found: // May need to restore insert mode for a prompt buffer. entering_window(curwin); #endif - - if (win_valid(aco->save_prevwin)) - prevwin = aco->save_prevwin; + prevwin = win_find_by_id(aco->save_prevwin_id); #ifdef FEAT_EVAL vars_clear(&aucmd_win->w_vars->dv_hashtab); // free all w: variables hash_init(&aucmd_win->w_vars->dv_hashtab); // re-use the hashtab @@ -1571,13 +1571,15 @@ win_found: } else { - // restore curwin - if (win_valid(aco->save_curwin)) + // Restore curwin. Use the window ID, a window may have been closed + // and the memory re-used for another one. + save_curwin = win_find_by_id(aco->save_curwin_id); + if (save_curwin != NULL) { // Restore the buffer which was previously edited by curwin, if // it was changed, we are still the same window and the buffer is // valid. - if (curwin == aco->new_curwin + if (curwin->w_id == aco->new_curwin_id && curbuf != aco->new_curbuf.br_buf && bufref_valid(&aco->new_curbuf) && aco->new_curbuf.br_buf->b_ml.ml_mfp != NULL) @@ -1592,10 +1594,9 @@ win_found: ++curbuf->b_nwindows; } - curwin = aco->save_curwin; + curwin = save_curwin; curbuf = curwin->w_buffer; - if (win_valid(aco->save_prevwin)) - prevwin = aco->save_prevwin; + prevwin = win_find_by_id(aco->save_prevwin_id); // In case the autocommand moves the cursor to a position that // does not exist in curbuf. check_cursor(); diff --git a/src/proto/window.pro b/src/proto/window.pro --- a/src/proto/window.pro +++ b/src/proto/window.pro @@ -5,6 +5,7 @@ int win_split(int size, int flags); int win_split_ins(int size, int flags, win_T *new_wp, int dir); int win_valid_popup(win_T *win); int win_valid(win_T *win); +win_T *win_find_by_id(int id); int win_valid_any_tab(win_T *win); int win_count(void); int make_windows(int count, int vertical); diff --git a/src/structs.h b/src/structs.h --- a/src/structs.h +++ b/src/structs.h @@ -3889,13 +3889,13 @@ typedef int vimmenu_T; */ typedef struct { - buf_T *save_curbuf; // saved curbuf - int use_aucmd_win; // using aucmd_win - win_T *save_curwin; // saved curwin - win_T *new_curwin; // new curwin - win_T *save_prevwin; // saved prevwin - bufref_T new_curbuf; // new curbuf - char_u *globaldir; // saved value of globaldir + buf_T *save_curbuf; // saved curbuf + int use_aucmd_win; // using aucmd_win + int save_curwin_id; // ID of saved curwin + int new_curwin_id; // ID of new curwin + int save_prevwin_id; // ID of saved prevwin + bufref_T new_curbuf; // new curbuf + char_u *globaldir; // saved value of globaldir } aco_save_T; /* diff --git a/src/testdir/test_popupwin.vim b/src/testdir/test_popupwin.vim --- a/src/testdir/test_popupwin.vim +++ b/src/testdir/test_popupwin.vim @@ -3737,5 +3737,26 @@ func Test_popupwin_splitmove() bwipe endfunc +func Test_popupwin_exiting_terminal() + CheckFeature terminal + + " Tests that when creating a popup right after closing a terminal window does + " not make the popup the current window. + let winid = win_getid() + try + augroup Test_popupwin_exiting_terminal + autocmd! + autocmd WinEnter * :call popup_create('test', {}) + augroup END + let bnr = term_start(&shell, #{term_finish: 'close'}) + call term_sendkeys(bnr, "exit\r\n") + call WaitForAssert({-> assert_equal(winid, win_getid())}) + finally + call popup_clear(1) + augroup Test_popupwin_exiting_terminal + autocmd! + augroup END + endtry +endfunc " vim: shiftwidth=2 sts=2 diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -751,6 +751,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 1966, +/**/ 1965, /**/ 1964, diff --git a/src/window.c b/src/window.c --- a/src/window.c +++ b/src/window.c @@ -1461,6 +1461,21 @@ win_valid(win_T *win) } /* + * Find window "id" in the current tab page. + * Return NULL if not found. + */ + win_T * +win_find_by_id(int id) +{ + win_T *wp; + + FOR_ALL_WINDOWS(wp) + if (wp->w_id == id) + return wp; + return NULL; +} + +/* * Check if "win" is a pointer to an existing window in any tab page. */ int