patch 9.1.2001: cursor may end up in wrong window after :botright copen
Commit:
https://github.com/vim/vim/commit/b43f9ded7e98261e3e662a8e919f54e7399b0316
Author: glepnir <
gleph...@gmail.com>
Date: Sat Dec 20 17:26:39 2025 +0000
patch 9.1.2001: cursor may end up in wrong window after :botright copen
Problem: After :botright copen and closing the quikfix window, the
cursor ends up in the wrong window. The problem is fr_child
always points to the first (leftmost for FR_ROW, topmost for
FR_COL) child frame. When do :vsplit, the new window is
created on the left, and frame_insert() updates the parent's
fr_child to point to this new left window.
Solution: Create a snapshot before open the quickfix window and restore
it when close it (glepnir).
closes: #18961
Signed-off-by: glepnir <
gleph...@gmail.com>
Signed-off-by: Christian Brabandt <
c...@256bit.org>
diff --git a/src/quickfix.c b/src/quickfix.c
index cc4abcd00..c3c1ea84f 100644
--- a/src/quickfix.c
+++ b/src/quickfix.c
@@ -4612,6 +4612,12 @@ qf_open_new_cwindow(qf_info_T *qi, int height)
if (cmdmod.cmod_split == 0)
flags = WSP_BELOW;
flags |= WSP_NEWLOC;
+
+ // Create a snapshot for quickfix window (not for location list)
+ // so that when closing it, we can restore to the previous window
+ if (IS_QF_STACK(qi))
+ flags |= WSP_QUICKFIX;
+
if (win_split(height, flags) == FAIL)
return FAIL; // not enough room for window
RESET_BINDING(curwin);
diff --git a/src/structs.h b/src/structs.h
index d2043bbfb..bc2f49f7d 100644
--- a/src/structs.h
+++ b/src/structs.h
@@ -3693,9 +3693,10 @@ typedef void diffline_T;
typedef void diffline_change_T;
#endif
-#define SNAP_HELP_IDX 0
-#define SNAP_AUCMD_IDX 1
-#define SNAP_COUNT 2
+#define SNAP_HELP_IDX 0
+#define SNAP_AUCMD_IDX 1
+#define SNAP_QUICKFIX_IDX 2
+#define SNAP_COUNT 3
/*
* Tab pages point to the top frame of each tab page.
diff --git a/src/testdir/test_quickfix.vim b/src/testdir/test_quickfix.vim
index fed9dcf8d..6e939a653 100644
--- a/src/testdir/test_quickfix.vim
+++ b/src/testdir/test_quickfix.vim
@@ -6958,4 +6958,15 @@ func Test_vimgrep_dummy_buffer_keep()
%bw!
endfunc
+func Test_quickfix_restore_current_win()
+ let curwin = win_getid()
+ vsplit Xb
+ wincmd p
+ botright copen
+ cclose
+
+ call assert_equal(curwin, win_getid())
+ bw! Xb
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/version.c b/src/version.c
index f080339dc..a8602f71b 100644
--- a/src/version.c
+++ b/src/version.c
@@ -734,6 +734,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
+/**/
+ 2001,
/**/
2000,
/**/
diff --git a/src/vim.h b/src/vim.h
index fccb31b3d..4bd6c7001 100644
--- a/src/vim.h
+++ b/src/vim.h
@@ -1314,6 +1314,7 @@ extern int (*dyn_libintl_wputenv)(const wchar_t *envstring);
#define WSP_ABOVE 0x80 // put new window above/left
#define WSP_NEWLOC 0x100 // don't copy location list
#define WSP_FORCE_ROOM 0x200 // ignore "not enough room" errors
+#define WSP_QUICKFIX 0x400 // creating the quickfix window
/*
* arguments for gui_set_shellsize()
diff --git a/src/window.c b/src/window.c
index 28c68800c..3ceee02f6 100644
--- a/src/window.c
+++ b/src/window.c
@@ -959,6 +959,11 @@ win_split(int size, int flags)
else
clear_snapshot(curtab, SNAP_HELP_IDX);
+ if (flags & WSP_QUICKFIX)
+ make_snapshot(SNAP_QUICKFIX_IDX);
+ else
+ clear_snapshot(curtab, SNAP_QUICKFIX_IDX);
+
return win_split_ins(size, flags, NULL, 0, NULL);
}
@@ -2688,6 +2693,7 @@ win_close(win_T *win, int free_buf)
int close_curwin = FALSE;
int dir;
int help_window = FALSE;
+ int quickfix_window = FALSE;
tabpage_T *prev_curtab = curtab;
frame_T *win_frame = win->w_frame->fr_parent;
#ifdef FEAT_DIFF
@@ -2740,6 +2746,11 @@ win_close(win_T *win, int free_buf)
else
clear_snapshot(curtab, SNAP_HELP_IDX);
+ if (bt_quickfix(win->w_buffer))
+ quickfix_window = TRUE;
+ else
+ clear_snapshot(curtab, SNAP_QUICKFIX_IDX);
+
if (win == curwin)
{
#ifdef FEAT_JOB_CHANNEL
@@ -2845,11 +2856,11 @@ win_close(win_T *win, int free_buf)
// the screen space.
wp = win_free_mem(win, &dir, NULL);
- if (help_window)
+ if (help_window || quickfix_window)
{
// Closing the help window moves the cursor back to the current window
// of the snapshot.
- win_T *prev_win = get_snapshot_curwin(SNAP_HELP_IDX);
+ win_T *prev_win = get_snapshot_curwin(help_window ? SNAP_HELP_IDX : SNAP_QUICKFIX_IDX);
if (win_valid(prev_win))
wp = prev_win;
@@ -2939,10 +2950,11 @@ win_close(win_T *win, int free_buf)
--dont_parse_messages;
#endif
- // After closing the help window, try restoring the window layout from
- // before it was opened.
- if (help_window)
- restore_snapshot(SNAP_HELP_IDX, close_curwin);
+ // After closing the help or quickfix window, try restoring the window
+ // layout from before it was opened.
+ if (help_window || quickfix_window)
+ restore_snapshot(help_window ? SNAP_HELP_IDX : SNAP_QUICKFIX_IDX,
+ close_curwin);
#ifdef FEAT_DIFF
// If the window had 'diff' set and now there is only one window left in