Commit: patch 9.2.0968: status line height is wrong after exchanging or rotating windows

Christian Brabandt <[email protected]>
Newsgroups gmane.editors.vim.devel
Message-ID <[email protected]>
patch 9.2.0968: status line height is wrong after exchanging or rotating windows

Commit: https://github.com/vim/vim/commit/21e9249838018d5c06973ca17d0b51697b997d33
Author: Hirohito Higashi <[email protected]>
Date:   Tue Aug 18 17:52:21 2026 +0000

    patch 9.2.0968: status line height is wrong after exchanging or rotating windows
    
    Problem:  Exchanging windows with CTRL-W x or rotating them with CTRL-W r
              leaves a window with the status line height of the other one, so
              with 'statuslineopt' the windows in a row no longer line up.
    Solution: Keep the total height of each window when the status line height
              is exchanged, and compute the height needed for the status line of
              each window afterwards.
    
    closes: #21079
    
    Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
    Signed-off-by: Hirohito Higashi <[email protected]>
    Signed-off-by: Christian Brabandt <[email protected]>

diff --git a/src/testdir/test_statusline.vim b/src/testdir/test_statusline.vim
index ad182fcf3..0010bb182 100644
--- a/src/testdir/test_statusline.vim
+++ b/src/testdir/test_statusline.vim
@@ -894,6 +894,131 @@ func Test_statusline_click_multiple_regions()
   let &laststatus = save_ls
 endfunc
 
+func StlExchangeEnter()
+  let &l:statusline = 'one%@two%@three'
+endfunc
+
+func StlExchangeLeave()
+  setlocal statusline<
+endfunc
+
+" Rows used by the status line of window "nr", derived from where the window
+" ends on the screen.
+func s:StlHeight(nr)
+  return &lines - &cmdheight - win_screenpos(a:nr)[0] - winheight(a:nr) + 1
+endfunc
+
+" Exchanging two windows keeps the status line height with the window.
+func Test_statuslineopt_win_exchange()
+  let save_stlo = &statuslineopt
+  let save_stl = &statusline
+  let save_ls = &laststatus
+  set laststatus=2
+  set statusline=global
+  set statuslineopt=maxheight:3
+
+  augroup TestStlExchange
+    autocmd!
+    autocmd WinEnter * call StlExchangeEnter()
+    autocmd WinLeave * call StlExchangeLeave()
+  augroup END
+
+  new
+  only
+  call StlExchangeEnter()
+  vsplit
+  redraw
+
+  " The current window needs three rows for its status line, the other one.
+  call assert_equal(1, winnr())
+  call assert_equal(3, s:StlHeight(1))
+  call assert_equal(1, s:StlHeight(2))
+
+  " Exchanging puts the cursor in the other window, which then is the one
+  " needing three rows.
+  wincmd x
+  redraw
+  call assert_equal(1, winnr())
+  call assert_equal(3, s:StlHeight(1))
+  call assert_equal(1, s:StlHeight(2))
+
+  augroup TestStlExchange
+    autocmd!
+  augroup END
+  augroup! TestStlExchange
+  delfunc StlExchangeEnter
+  delfunc StlExchangeLeave
+  only
+  bwipe!
+  let &laststatus = save_ls
+  let &statusline = save_stl
+  let &statuslineopt = save_stlo
+endfunc
+
+" Exchanging two windows keeps a fixed status line height with the window.
+func Test_statuslineopt_fixed_win_exchange()
+  let save_stlo = &statuslineopt
+  let save_ls = &laststatus
+  set laststatus=2
+
+  new
+  only
+  vsplit
+  setlocal statuslineopt=fixedheight,maxheight:3
+  redraw
+
+  " Only the current window has a local 'statuslineopt'.
+  call assert_equal(1, winnr())
+  call assert_equal(3, s:StlHeight(1))
+  call assert_equal(1, s:StlHeight(2))
+
+  " The window that was exchanged keeps needing three rows.
+  wincmd x
+  redraw
+  call assert_equal(1, winnr())
+  call assert_equal(1, s:StlHeight(1))
+  call assert_equal(3, s:StlHeight(2))
+
+  only
+  bwipe!
+  let &laststatus = save_ls
+  let &statuslineopt = save_stlo
+endfunc
+
+" Rotating windows keeps a fixed status line height with the window.
+func Test_statuslineopt_fixed_win_rotate()
+  let save_stlo = &statuslineopt
+  let save_ls = &laststatus
+  set laststatus=2
+
+  new
+  only
+  vsplit
+  setlocal statuslineopt=fixedheight,maxheight:3
+  redraw
+
+  call assert_equal(1, winnr())
+  call assert_equal(3, s:StlHeight(1))
+  call assert_equal(1, s:StlHeight(2))
+
+  " Rotating moves the window that needs three rows to the other position.
+  wincmd r
+  redraw
+  call assert_equal(1, s:StlHeight(1))
+  call assert_equal(3, s:StlHeight(2))
+
+  " Rotating back restores it.
+  wincmd r
+  redraw
+  call assert_equal(3, s:StlHeight(1))
+  call assert_equal(1, s:StlHeight(2))
+
+  only
+  bwipe!
+  let &laststatus = save_ls
+  let &statuslineopt = save_stlo
+endfunc
+
 " Click on a region in any row of a multi-line statusline (issue #20116).
 func Test_statusline_click_multiline()
   let save_mouse = &mouse
diff --git a/src/version.c b/src/version.c
index 047699420..0115e9423 100644
--- a/src/version.c
+++ b/src/version.c
@@ -763,6 +763,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    968,
 /**/
     967,
 /**/
diff --git a/src/window.c b/src/window.c
index 4d4cfab44..b2ed04e4d 100644
--- a/src/window.c
+++ b/src/window.c
@@ -1905,7 +1905,14 @@ win_exchange(long Prenum)
 	else
 	    frame_append(frp2, wp->w_frame);
     }
+    // Keep the total height of each window the same, so that the frames keep
+    // their height; the status line height is computed below.
     temp = curwin->w_status_height;
+    if (temp != wp->w_status_height)
+    {
+	win_new_height(curwin, curwin->w_height + temp - wp->w_status_height);
+	win_new_height(wp, wp->w_height + wp->w_status_height - temp);
+    }
     curwin->w_status_height = wp->w_status_height;
     wp->w_status_height = temp;
     temp = curwin->w_vsep_width;
@@ -1918,6 +1925,9 @@ win_exchange(long Prenum)
     frame_fix_width(wp);
 
     win_comp_pos();		// recompute window positions
+#if defined(FEAT_STL_OPT)
+    frame_change_statusline_height();
+#endif
 
     if (wp->w_buffer != curbuf)
 	reset_VIsual_and_resel();
@@ -1993,7 +2003,14 @@ win_rotate(int upwards, int count)
 	}
 
 	// exchange status height and vsep width of old and new last window
+	// Keep the total height of each window the same, so that the frames
+	// keep their height; the status line height is computed below.
 	n = wp2->w_status_height;
+	if (n != wp1->w_status_height)
+	{
+	    win_new_height(wp2, wp2->w_height + n - wp1->w_status_height);
+	    win_new_height(wp1, wp1->w_height + wp1->w_status_height - n);
+	}
 	wp2->w_status_height = wp1->w_status_height;
 	wp1->w_status_height = n;
 	frame_fix_height(wp1);
@@ -2007,6 +2024,9 @@ win_rotate(int upwards, int count)
 	// recompute w_winrow and w_wincol for all windows
 	win_comp_pos();
     }
+#if defined(FEAT_STL_OPT)
+    frame_change_statusline_height();
+#endif
 
     redraw_all_later(UPD_NOT_VALID);
 }

-- 
-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- 
You received this message because you are subscribed to the Google Groups "vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [email protected].
To view this discussion visit https://groups.google.com/d/msgid/vim_dev/E1wwOL3-00AXTN-5W%40256bit.org.
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.