commit f89558848b119048a2656fbf127f4cd85129330b
parent 69167006a4d3e5cfe77b9bc6e58be5dc4030fa39
Author: zeertzjq <zeertzjq@outlook.com>
Date: Sun, 21 Dec 2025 10:41:53 +0800
vim-patch:9.1.2001: cursor may end up in wrong window after :botright copen (#37056)
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: vim/vim#18961
https://github.com/vim/vim/commit/b43f9ded7e98261e3e662a8e919f54e7399b0316
Co-authored-by: glepnir <glephunter@gmail.com>
Diffstat:
5 files changed, 52 insertions(+), 19 deletions(-)
diff --git a/src/nvim/buffer_defs.h b/src/nvim/buffer_defs.h
@@ -821,9 +821,10 @@ struct diffline_S {
int lineoff;
};
-#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.
/// Note: Most values are NOT valid for the current tab page! Use "curwin",
diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c
@@ -3884,6 +3884,13 @@ static int qf_open_new_cwindow(qf_info_T *qi, int height)
flags = IS_QF_STACK(qi) ? WSP_BOT : 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
}
diff --git a/src/nvim/window.c b/src/nvim/window.c
@@ -1057,6 +1057,12 @@ int win_split(int size, int flags)
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) == NULL ? FAIL : OK;
}
@@ -2747,6 +2753,7 @@ int win_close(win_T *win, bool free_buf, bool force)
}
bool help_window = false;
+ bool quickfix_window = false;
// When closing the help window, try restoring a snapshot after closing
// the window. Otherwise clear the snapshot, it's now invalid.
@@ -2756,6 +2763,12 @@ int win_close(win_T *win, bool free_buf, bool force)
clear_snapshot(curtab, SNAP_HELP_IDX);
}
+ if (bt_quickfix(win->w_buffer)) {
+ quickfix_window = true;
+ } else {
+ clear_snapshot(curtab, SNAP_QUICKFIX_IDX);
+ }
+
win_T *wp;
bool other_buffer = false;
@@ -2861,10 +2874,10 @@ int win_close(win_T *win, bool free_buf, bool force)
int dir;
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 +2952,10 @@ int win_close(win_T *win, bool free_buf, bool force)
split_disallowed--;
- // 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);
}
// If the window had 'diff' set and now there is only one window left in
diff --git a/src/nvim/window.h b/src/nvim/window.h
@@ -10,16 +10,17 @@
/// arguments for win_split()
enum {
- WSP_ROOM = 0x01, ///< require enough room
- WSP_VERT = 0x02, ///< split/equalize vertically
- WSP_HOR = 0x04, ///< equalize horizontally
- WSP_TOP = 0x08, ///< window at top-left of shell
- WSP_BOT = 0x10, ///< window at bottom-right of shell
- WSP_HELP = 0x20, ///< creating the help window
- WSP_BELOW = 0x40, ///< put new window below/right
- WSP_ABOVE = 0x80, ///< put new window above/left
- WSP_NEWLOC = 0x100, ///< don't copy location list
- WSP_NOENTER = 0x200, ///< don't enter the new window
+ WSP_ROOM = 0x01, ///< require enough room
+ WSP_VERT = 0x02, ///< split/equalize vertically
+ WSP_HOR = 0x04, ///< equalize horizontally
+ WSP_TOP = 0x08, ///< window at top-left of shell
+ WSP_BOT = 0x10, ///< window at bottom-right of shell
+ WSP_HELP = 0x20, ///< creating the help window
+ WSP_BELOW = 0x40, ///< put new window below/right
+ WSP_ABOVE = 0x80, ///< put new window above/left
+ WSP_NEWLOC = 0x100, ///< don't copy location list
+ WSP_NOENTER = 0x200, ///< don't enter the new window
+ WSP_QUICKFIX = 0x400, ///< creating the quickfix window
};
enum {
diff --git a/test/old/testdir/test_quickfix.vim b/test/old/testdir/test_quickfix.vim
@@ -6980,4 +6980,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