]> git.ipfire.org Git - thirdparty/vim.git/commitdiff
patch 9.2.0190: Status line height mismatch in vertical splits v9.2.0190
authorHirohito Higashi <h.east.727@gmail.com>
Tue, 17 Mar 2026 21:00:45 +0000 (21:00 +0000)
committerChristian Brabandt <cb@256bit.org>
Tue, 17 Mar 2026 21:00:45 +0000 (21:00 +0000)
Problem:  When 'laststatus' changes, the status line can become
          misaligned.
Solution: Update last_status_rec() to calculate the maximum status line
          height required across all windows in a vertical row.

closes: #19688

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Hirohito Higashi <h.east.727@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
src/testdir/dumps/Test_laststatus_vsplit_row_height2_1.dump [new file with mode: 0644]
src/testdir/dumps/Test_laststatus_vsplit_row_height3_1.dump [new file with mode: 0644]
src/testdir/dumps/Test_laststatus_vsplit_row_height_1.dump [new file with mode: 0644]
src/testdir/test_window_cmd.vim
src/version.c
src/window.c

diff --git a/src/testdir/dumps/Test_laststatus_vsplit_row_height2_1.dump b/src/testdir/dumps/Test_laststatus_vsplit_row_height2_1.dump
new file mode 100644 (file)
index 0000000..12701b1
--- /dev/null
@@ -0,0 +1,8 @@
+> +0&#ffffff0@74
+|~+0#4040ff13&| @73
+|~| @73
+|[+3#0000000&|N|o| |N|a|m|e|]| @47|0|,|0|-|1| @9|A|l@1
+| +0&&@36||+1&&| +0&&@36
+|[+1&&|N|o| |N|a|m|e|]| @9|0|,|0|-|1| @9|A|l@1| |~+0#4040ff13&| @35
+| +1#0000000&@37|[|N|o| |N|a|m|e|]| @9|0|,|0|-|1| @9|A|l@1
+| +0&&@74
diff --git a/src/testdir/dumps/Test_laststatus_vsplit_row_height3_1.dump b/src/testdir/dumps/Test_laststatus_vsplit_row_height3_1.dump
new file mode 100644 (file)
index 0000000..6d24637
--- /dev/null
@@ -0,0 +1,8 @@
+> +0&#ffffff0@74
+|~+0#4040ff13&| @73
+|~| @73
+|[+3#0000000&|N|o| |N|a|m|e|]| @47|0|,|0|-|1| @9|A|l@1
+| +0&&@36||+1&&| +0&&@36
+|~+0#4040ff13&| @35||+1#0000000&|[|N|o| |N|a|m|e|]| @9|0|,|0|-|1| @9|A|l@1
+|[|N|o| |N|a|m|e|]| @9|0|,|0|-|1| @9|A|l@1| @37
+| +0&&@74
diff --git a/src/testdir/dumps/Test_laststatus_vsplit_row_height_1.dump b/src/testdir/dumps/Test_laststatus_vsplit_row_height_1.dump
new file mode 100644 (file)
index 0000000..86db528
--- /dev/null
@@ -0,0 +1,8 @@
+> +0&#ffffff0@74
+|~+0#4040ff13&| @73
+|~| @73
+|~| @73
+|[+3#0000000&|N|o| |N|a|m|e|]| @47|0|,|0|-|1| @9|A|l@1
+| +0&&@36||+1&&| +0&&@36
+|[+1&&|N|o| |N|a|m|e|]| @9|0|,|0|-|1| @9|A|l@1| |[|N|o| |N|a|m|e|]| @9|0|,|0|-|1| @9|A|l@1
+| +0&&@74
index 1832a9790dd109ffedf31b1c86e42c82f085ca4c..6ead70a1a785d272b6860e4fc5d629c87c6b3dd7 100644 (file)
@@ -2377,8 +2377,9 @@ endfunc
 " When shrinking a window and the only other window has 'winfixheight'
 " with 'winminheight'=0, freed rows must go to the wfh window.
 func Test_winfixheight_resize_wmh_zero()
-  set winminheight=0 laststatus=0
+  CheckFeature quickfix
 
+  set winminheight=0 laststatus=0
   let id1 = win_getid()
   copen
   let id2 = win_getid()
@@ -2438,4 +2439,61 @@ func Test_winfixheight_resize_wmh_zero()
   set winminheight& laststatus&
 endfunc
 
+" Test that setting 'laststatus' from 0 to 2 gives all windows in a vertical
+" split (FR_ROW) the same height and correct status line position.
+func Test_laststatus_vsplit_row_height()
+  CheckScreendump
+
+  let lines =<< trim END
+    set ls=0
+    vsplit
+    topleft new
+    wincmd _
+    set ls=2
+  END
+  call writefile(lines, 'XTestLaststatusVsplitRowHeight', 'D')
+  let buf = RunVimInTerminal('-S XTestLaststatusVsplitRowHeight', #{rows: 8})
+  call VerifyScreenDump(buf, 'Test_laststatus_vsplit_row_height_1', {})
+  call StopVimInTerminal(buf)
+endfunc
+
+" Test that when FR_ROW windows have different status line heights (due to
+" window-local 'statuslineopt'), content heights compensate so that total
+" rows are equal across the row.
+func Test_laststatus_vsplit_row_height_mixed_stlo()
+  CheckScreendump
+
+  let lines =<< trim END
+    set ls=0
+    setlocal stlo=fixedheight,maxheight:2
+    rightbelow vnew
+    topleft new
+    wincmd _
+    set ls=2
+  END
+  call writefile(lines, 'XTestLaststatusVsplitRowHeight2', 'D')
+  let buf = RunVimInTerminal('-S XTestLaststatusVsplitRowHeight2', #{rows: 8})
+  call VerifyScreenDump(buf, 'Test_laststatus_vsplit_row_height2_1', {})
+  call StopVimInTerminal(buf)
+endfunc
+
+" Same as above but with the stlo window on the right (second leaf in FR_ROW).
+func Test_laststatus_vsplit_row_height_mixed_stlo_reversed()
+  CheckScreendump
+
+  let lines =<< trim END
+    set ls=0
+    leftabove vnew
+    wincmd p
+    setlocal stlo=fixedheight,maxheight:2
+    topleft new
+    wincmd _
+    set ls=2
+  END
+  call writefile(lines, 'XTestLaststatusVsplitRowHeight3', 'D')
+  let buf = RunVimInTerminal('-S XTestLaststatusVsplitRowHeight3', #{rows: 8})
+  call VerifyScreenDump(buf, 'Test_laststatus_vsplit_row_height3_1', {})
+  call StopVimInTerminal(buf)
+endfunc
+
 " vim: shiftwidth=2 sts=2 expandtab
index d7c480a67cd47e2f584ca07dda7be1761ff5fe51..c480833be6bc69d38960f93c87b142100b847eef 100644 (file)
@@ -734,6 +734,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    190,
 /**/
     189,
 /**/
index 4b6626cc31bc444ed36543d92441f55a2f2d3585..390c084fa6744a2f1f634b84e3c6280e2cd734e1 100644 (file)
@@ -7654,8 +7654,78 @@ last_status_rec(frame_T *fr, int statusline)
     else if (fr->fr_layout == FR_ROW)
     {
        // vertically split windows, set status line for each one
-       FOR_ALL_FRAMES(fp, fr->fr_child)
-           last_status_rec(fp, statusline);
+       if (!statusline)
+       {
+           FOR_ALL_FRAMES(fp, fr->fr_child)
+               last_status_rec(fp, statusline);
+       }
+       else
+       {
+           frame_T     *fp2;
+           int         max_stlh = 0;
+           int         new_row_height;
+
+           // Find the max status height needed across all leaf windows.
+           FOR_ALL_FRAMES(fp, fr->fr_child)
+               if (fp->fr_win != NULL && fp->fr_win->w_status_height == 0)
+               {
+                   int h = statusline_height(fp->fr_win);
+                   if (h > max_stlh)
+                       max_stlh = h;
+               }
+           if (max_stlh == 0)
+               return;
+
+           // Find a frame to take max_stlh lines from.
+           fp2 = fr;
+           while (fp2->fr_height - frame_minheight(fp2, NULL) < max_stlh)
+           {
+               if (fp2 == topframe)
+               {
+                   emsg(_(e_not_enough_room));
+                   return;
+               }
+               if (fp2->fr_parent->fr_layout == FR_COL
+                                               && fp2->fr_prev != NULL)
+                   fp2 = fp2->fr_prev;
+               else
+                   fp2 = fp2->fr_parent;
+           }
+
+           if (fp2 != fr)
+           {
+               frame_new_height(fp2, fp2->fr_height - max_stlh,
+                                                       FALSE, FALSE, FALSE);
+               new_row_height = fr->fr_height + max_stlh;
+           }
+           else
+               new_row_height = fr->fr_height;
+
+           // Set status and content heights for all leaves.
+           FOR_ALL_FRAMES(fp, fr->fr_child)
+           {
+               if (fp->fr_win != NULL)
+               {
+                   wp = fp->fr_win;
+                   if (wp->w_status_height == 0)
+                   {
+                       wp->w_status_height = statusline_height(wp);
+                       win_new_height(wp,
+                                 new_row_height - wp->w_status_height);
+                       frame_fix_height(wp);
+                       comp_col();
+                       redraw_all_later(UPD_SOME_VALID);
+                       if (abs(wp->w_height - wp->w_prev_height) == 1)
+                           wp->w_prev_height = wp->w_height;
+                   }
+               }
+               else
+                   last_status_rec(fp, statusline); // nested frames
+           }
+
+           fr->fr_height = new_row_height;
+           win_comp_pos();
+       }
     }
     else
     {