From f89558848b119048a2656fbf127f4cd85129330b Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sun, 21 Dec 2025 10:41:53 +0800 Subject: [PATCH] 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 --- src/nvim/buffer_defs.h | 7 ++++--- src/nvim/quickfix.c | 7 +++++++ src/nvim/window.c | 25 +++++++++++++++++++------ src/nvim/window.h | 21 +++++++++++---------- test/old/testdir/test_quickfix.vim | 11 +++++++++++ 5 files changed, 52 insertions(+), 19 deletions(-) diff --git a/src/nvim/buffer_defs.h b/src/nvim/buffer_defs.h index 7db9ddc75e..b9d8da1a8d 100644 --- 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 index ab9a22747b..8644baa307 100644 --- 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 index 16808a7132..d8800c15f9 100644 --- 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 index 781445f01c..c4199d6e0f 100644 --- 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 index 7f9a0a3f17..fd134b8548 100644 --- 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