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

b43f9ded7e

Co-authored-by: glepnir <glephunter@gmail.com>
This commit is contained in:
zeertzjq
2025-12-21 10:41:53 +08:00
committed by GitHub
parent 69167006a4
commit f89558848b
5 changed files with 52 additions and 19 deletions

View File

@@ -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",

View File

@@ -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
}

View File

@@ -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

View File

@@ -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 {

View File

@@ -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