summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2020-11-07 16:58:59 +0100
committerBram Moolenaar <Bram@vim.org>2020-11-07 16:58:59 +0100
commitcbcd9cbd77acc8cc97c0d44683d96c01d3dd0fa7 (patch)
tree0327591c6c155fec6e557463815968f90bab3e0a
parent46f479c756c0255e3b6d473590c1857678eff5c6 (diff)
downloadvim-git-cbcd9cbd77acc8cc97c0d44683d96c01d3dd0fa7.tar.gz
patch 8.2.1966: popup becomes current window after closing a terminal windowv8.2.1966
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)
-rw-r--r--src/autocmd.c31
-rw-r--r--src/proto/window.pro1
-rw-r--r--src/structs.h14
-rw-r--r--src/testdir/test_popupwin.vim21
-rw-r--r--src/version.c2
-rw-r--r--src/window.c15
6 files changed, 62 insertions, 22 deletions
diff --git a/src/autocmd.c b/src/autocmd.c
index be35845c9..a82659f65 100644
--- 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
index 24ab0ec82..c10b61dba 100644
--- 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
index 330bb53fa..90e76203a 100644
--- 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
index 43dbeb5a1..fdfa305ba 100644
--- 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
index 786e05ea7..1fbae19e0 100644
--- 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
index 2cd06630f..501ea846a 100644
--- 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