]> git.ipfire.org Git - thirdparty/vim.git/commitdiff
patch 9.1.2001: cursor may end up in wrong window after :botright copen v9.1.2001
authorglepnir <glephunter@gmail.com>
Sat, 20 Dec 2025 17:26:39 +0000 (17:26 +0000)
committerChristian Brabandt <cb@256bit.org>
Sat, 20 Dec 2025 17:26:39 +0000 (17:26 +0000)
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 <glephunter@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
src/quickfix.c
src/structs.h
src/testdir/test_quickfix.vim
src/version.c
src/vim.h
src/window.c

index cc4abcd00afd699e42953ec11d59b15278b37d2c..c3c1ea84f8545447ad5d3bc2ef5d737ad6cf7fdf 100644 (file)
@@ -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);
index d2043bbfb96afa6f54c66b683e592fed2398febd..bc2f49f7d5940202bfa9bf6a41054c03a80e5b32 100644 (file)
@@ -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.
index fed9dcf8d4905fa39ea5f9b648c91dc1a1722c3d..6e939a653fe9806e6e87eaf73b8ae8b2d28aaf99 100644 (file)
@@ -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
index f080339dcc25c33b2b58c6f6297d48d6b8331b34..a8602f71b25d3eab8b7e4d088343a3f6c780ba86 100644 (file)
@@ -734,6 +734,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    2001,
 /**/
     2000,
 /**/
index fccb31b3dc4976998922a9b29fb7641628b5f46c..4bd6c7001b376e8d9bdd4be82b8d11ec421a0443 100644 (file)
--- 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()
index 28c68800c0285332a88c234e3d94c8fbd601cae1..3ceee02f6202829b32ed0b36519bd691fe76e8d8 100644 (file)
@@ -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