patch 9.1.0990: Inconsistent behavior when changing cmdheight

Commit: 
https://github.com/vim/vim/commit/e15cbc1af47e9dea90448c714eb4908e5d4302fc
Author: Luuk van Baal <luukvb...@gmail.com>
Date:   Sat Jan 4 17:18:08 2025 +0100

    patch 9.1.0990: Inconsistent behavior when changing cmdheight
    
    Problem:  Inconsistent behavior when changing cmdheight by resizing the
              topframe through wincmds and dragging laststatus. Changing
              cmdheight by resizing the topframe does not trigger OptionSet.
    Solution: Consolidate logic for changing the cmdheight, set the option
              value to handle side-effects (Luuk van Baal)
    
    closes: #16359
    
    Signed-off-by: Luuk van Baal <luukvb...@gmail.com>
    Signed-off-by: Christian Brabandt <c...@256bit.org>

diff --git a/src/testdir/dumps/Test_changing_cmdheight_1.dump 
b/src/testdir/dumps/Test_changing_cmdheight_1.dump
index db6d41110..127fe26f0 100644
--- a/src/testdir/dumps/Test_changing_cmdheight_1.dump
+++ b/src/testdir/dumps/Test_changing_cmdheight_1.dump
@@ -5,4 +5,4 @@
 | +0&&@74
 @75
 @75
-|:|r|e|s|i|z|e| |-|3| @64
+@75
diff --git a/src/testdir/dumps/Test_changing_cmdheight_2.dump 
b/src/testdir/dumps/Test_changing_cmdheight_2.dump
index 76d944040..d652cc631 100644
--- a/src/testdir/dumps/Test_changing_cmdheight_2.dump
+++ b/src/testdir/dumps/Test_changing_cmdheight_2.dump
@@ -1,8 +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&&|s|e|t| |c|m|d|h|e|i|g|h|t|+|=|3| @57
+| +0&&@74
+@75
 @75
 @75
 @75
diff --git a/src/testdir/test_autocmd.vim b/src/testdir/test_autocmd.vim
index d6f8ef4ce..5868f1c03 100644
--- a/src/testdir/test_autocmd.vim
+++ b/src/testdir/test_autocmd.vim
@@ -4902,4 +4902,28 @@ func Test_autocmd_BufWinLeave_with_vsp()
   exe "bw! " .. dummy
 endfunc
 
+func Test_OptionSet_cmdheight()
+  set mouse=a laststatus=2
+  au OptionSet cmdheight :let &l:ch = v:option_new
+
+  resize -1
+  call assert_equal(2, &l:ch)
+  resize +1
+  call assert_equal(1, &l:ch)
+
+  call test_setmouse(&lines - 1, 1)
+  call feedkeys("\<LeftMouse>", 'xt')
+  call test_setmouse(&lines - 2, 1)
+  call feedkeys("\<LeftDrag>", 'xt')
+  call assert_equal(2, &l:ch)
+
+  tabnew | resize +1
+  call assert_equal(1, &l:ch)
+  tabfirst
+  call assert_equal(2, &l:ch)
+
+  tabonly
+  set cmdheight& mouse& laststatus&
+endfunc
+
 " vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/testdir/test_cmdline.vim b/src/testdir/test_cmdline.vim
index 6d4fdd781..2b81dc05a 100644
--- a/src/testdir/test_cmdline.vim
+++ b/src/testdir/test_cmdline.vim
@@ -290,9 +290,10 @@ func Test_changing_cmdheight()
   call term_sendkeys(buf, ":resize -3\<CR>")
   call VerifyScreenDump(buf, 'Test_changing_cmdheight_1', {})
 
-  " using the space available doesn't change the status line
-  call term_sendkeys(buf, ":set cmdheight+=3\<CR>")
+  " :resize now also changes 'cmdheight' accordingly
+  call term_sendkeys(buf, ":set cmdheight+=1\<CR>")
   call VerifyScreenDump(buf, 'Test_changing_cmdheight_2', {})
+  call term_sendkeys(buf, ":set cmdheight-=1\<CR>")
 
   " using more space moves the status line up
   call term_sendkeys(buf, ":set cmdheight+=1\<CR>")
@@ -311,7 +312,7 @@ func Test_changing_cmdheight()
   call term_sendkeys(buf, ":call EchoTwo()\<CR>")
   call VerifyScreenDump(buf, 'Test_changing_cmdheight_6', {})
 
-  " increasing 'cmdheight' doesn't clear the messages that need hit-enter
+  " decreasing 'cmdheight' doesn't clear the messages that need hit-enter
   call term_sendkeys(buf, ":call EchoOne()\<CR>")
   call VerifyScreenDump(buf, 'Test_changing_cmdheight_7', {})
 
diff --git a/src/version.c b/src/version.c
index 99f41030f..b42c2fc26 100644
--- a/src/version.c
+++ b/src/version.c
@@ -704,6 +704,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    990,
 /**/
     989,
 /**/
diff --git a/src/window.c b/src/window.c
index af29a698d..93b0a327d 100644
--- a/src/window.c
+++ b/src/window.c
@@ -27,7 +27,7 @@ static win_T *frame2win(frame_T *frp);
 static int frame_has_win(frame_T *frp, win_T *wp);
 static void win_fix_scroll(int resize);
 static void win_fix_cursor(int normal);
-static void frame_new_height(frame_T *topfrp, int height, int topfirst, int 
wfh);
+static void frame_new_height(frame_T *topfrp, int height, int topfirst, int 
wfh, int set_ch);
 static int frame_fixed_height(frame_T *frp);
 static int frame_fixed_width(frame_T *frp);
 static void frame_add_statusline(frame_T *frp);
@@ -1404,13 +1404,14 @@ win_split_ins(
        if (flags & (WSP_TOP | WSP_BOT))
        {
            int new_fr_height = curfrp->fr_height - new_size
-                                                         + WINBAR_HEIGHT(wp) ;
+                                                         + WINBAR_HEIGHT(wp);
 
            if (!((flags & WSP_BOT) && p_ls == 0))
                new_fr_height -= STATUS_HEIGHT;
            if (flags & WSP_BOT)
                frame_add_statusline(curfrp);
-           frame_new_height(curfrp, new_fr_height, flags & WSP_TOP, FALSE);
+           frame_new_height(curfrp, new_fr_height, flags & WSP_TOP, FALSE,
+                                                                       FALSE);
        }
        else
            win_new_height(oldwin, oldwin_height - (new_size + STATUS_HEIGHT));
@@ -2126,7 +2127,7 @@ win_equal_rec(
           )
        {
            topfr->fr_win->w_winrow = row;
-           frame_new_height(topfr, height, FALSE, FALSE);
+           frame_new_height(topfr, height, FALSE, FALSE, FALSE);
            topfr->fr_win->w_wincol = col;
            frame_new_width(topfr, width, FALSE, FALSE);
            redraw_all_later(UPD_NOT_VALID);
@@ -3551,7 +3552,7 @@ winframe_remove(
            }
        }
        frame_new_height(frp2, frp2->fr_height + frp_close->fr_height,
-                           frp2 == frp_close->fr_next, FALSE);
+                           frp2 == frp_close->fr_next, FALSE, FALSE);
        *dirp = 'v';
     }
     else
@@ -3691,7 +3692,7 @@ winframe_restore(win_T *wp, int dir, frame_T 
*unflat_altfr)
     if (dir == 'v')
     {
        frame_new_height(unflat_altfr, unflat_altfr->fr_height - frp->fr_height,
-               unflat_altfr == frp->fr_next, FALSE);
+               unflat_altfr == frp->fr_next, FALSE, FALSE);
     }
     else if (dir == 'h')
     {
@@ -3840,13 +3841,22 @@ frame_new_height(
     frame_T    *topfrp,
     int                height,
     int                topfirst,       // resize topmost contained frame first
-    int                wfh)            // obey 'winfixheight' when there is a 
choice;
+    int                wfh,            // obey 'winfixheight' when there is a 
choice;
                                // may cause the height not to be set
+    int                set_ch)         // set 'cmdheight' to resize topframe
 {
     frame_T    *frp;
     int                extra_lines;
     int                h;
 
+    if (topfrp->fr_parent == NULL && set_ch)
+    {
+       // topframe: update the command line height, with side effects.
+       int new_ch = MAX(1, p_ch + topfrp->fr_height - height);
+       if (new_ch != p_ch)
+           set_option_value((char_u *)"cmdheight", new_ch, NULL, 0);
+       height = MIN(height, ROWS_AVAIL);
+    }
     if (topfrp->fr_win != NULL)
     {
        // Simple case: just one window.
@@ -3861,7 +3871,7 @@ frame_new_height(
            // All frames in this row get the same new height.
            FOR_ALL_FRAMES(frp, topfrp->fr_child)
            {
-               frame_new_height(frp, height, topfirst, wfh);
+               frame_new_height(frp, height, topfirst, wfh, set_ch);
                if (frp->fr_height > height)
                {
                    // Could not fit the windows, make the whole row higher.
@@ -3907,12 +3917,12 @@ frame_new_height(
                if (frp->fr_height + extra_lines < h)
                {
                    extra_lines += frp->fr_height - h;
-                   frame_new_height(frp, h, topfirst, wfh);
+                   frame_new_height(frp, h, topfirst, wfh, set_ch);
                }
                else
                {
                    frame_new_height(frp, frp->fr_height + extra_lines,
-                                                              topfirst, wfh);
+                                                       topfirst, wfh, set_ch);
                    break;
                }
                if (topfirst)
@@ -3935,7 +3945,8 @@ frame_new_height(
        else if (extra_lines > 0)
        {
            // increase height of bottom or top frame
-           frame_new_height(frp, frp->fr_height + extra_lines, topfirst, wfh);
+           frame_new_height(frp, frp->fr_height + extra_lines, topfirst, wfh,
+                                                                       set_ch);
        }
     }
     topfrp->fr_height = height;
@@ -4381,6 +4392,10 @@ unuse_tabpage(tabpage_T *tp)
     tp->tp_curwin = curwin;
 }
 
+// When switching tabpage, handle other side-effects in command_height(), but
+// avoid setting frame sizes which are still correct.
+static int command_frame_height = TRUE;
+
 /*
  * Set the relevant pointers to use tab page "tp".  May want to call
  * unuse_tabpage() first.
@@ -4915,13 +4930,23 @@ enter_tabpage(
     int                trigger_enter_autocmds,
     int                trigger_leave_autocmds)
 {
-    int                row;
     int                old_off = tp->tp_firstwin->w_winrow;
     win_T      *next_prevwin = tp->tp_prevwin;
     tabpage_T  *last_tab = curtab;
 
     use_tabpage(tp);
 
+    if (p_ch != curtab->tp_ch_used)
+    {
+       // Use the stored value of p_ch, so that it can be different for each
+       // tab page.
+       int new_ch = curtab->tp_ch_used;
+       curtab->tp_ch_used = p_ch;
+       command_frame_height = FALSE;
+       set_option_value((char_u *)"cmdheight", new_ch, NULL, 0);
+       command_frame_height = TRUE;
+    }
+
     // We would like doing the TabEnter event first, but we don't have a
     // valid current window yet, which may break some commands.
     // This triggers autocommands, thus may make "tp" invalid.
@@ -4931,23 +4956,11 @@ enter_tabpage(
     prevwin = next_prevwin;
 
     last_status(FALSE);                // status line may appear or disappear
-    row = win_comp_pos();      // recompute w_winrow for all windows
+    win_comp_pos();            // recompute w_winrow for all windows
 #ifdef FEAT_DIFF
     diff_need_scrollbind = TRUE;
 #endif
 
-    // Use the stored value of p_ch, so that it can be different for each tab
-    // page.
-    if (p_ch != curtab->tp_ch_used)
-       clear_cmdline = TRUE;
-    p_ch = curtab->tp_ch_used;
-
-    // When cmdheight is changed in a tab page with '<C-w>-', cmdline_row is
-    // changed but p_ch and tp_ch_used are not changed. Thus we also need to
-    // check cmdline_row.
-    if (row < cmdline_row && cmdline_row <= Rows - p_ch)
-       clear_cmdline = TRUE;
-
     // If there was a click in a window, it won't be usable for a following
     // drag.
     reset_dragwin();
@@ -6091,9 +6104,9 @@ shell_new_rows(void)
 
     // First try setting the heights of windows with 'winfixheight'.  If
     // that doesn't result in the right height, forget about that option.
-    frame_new_height(topframe, h, FALSE, TRUE);
+    frame_new_height(topframe, h, FALSE, TRUE, FALSE);
     if (!frame_check_height(topframe, h))
-       frame_new_height(topframe, h, FALSE, FALSE);
+       frame_new_height(topframe, h, FALSE, FALSE, FALSE);
 
     (void)win_comp_pos();              // recompute w_winrow and w_wincol
     compute_cmdrow();
@@ -6275,8 +6288,6 @@ win_setheight(int height)
     void
 win_setheight_win(int height, win_T *win)
 {
-    int                row;
-
     if (win == curwin)
     {
        // Always keep current window at least one line high, even when
@@ -6291,18 +6302,7 @@ win_setheight_win(int height, win_T *win)
     frame_setheight(win->w_frame, height + win->w_status_height);
 
     // recompute the window positions
-    row = win_comp_pos();
-
-    /*
-     * If there is extra space created between the last window and the command
-     * line, clear it.
-     */
-    if (full_screen && msg_scrolled == 0 && row < cmdline_row)
-       screen_fill(row, cmdline_row, 0, (int)Columns, ' ', ' ', 0);
-    cmdline_row = row;
-    msg_row = row;
-    msg_col = 0;
-
+    win_comp_pos();
     win_fix_scroll(TRUE);
 
     redraw_all_later(UPD_NOT_VALID);
@@ -6339,10 +6339,8 @@ frame_setheight(frame_T *curfrp, int height)
     if (curfrp->fr_parent == NULL)
     {
        // topframe: can only change the command line height
-       if (height > ROWS_AVAIL)
-           height = ROWS_AVAIL;
        if (height > 0)
-           frame_new_height(curfrp, height, FALSE, FALSE);
+           frame_new_height(curfrp, height, FALSE, FALSE, TRUE);
     }
     else if (curfrp->fr_parent->fr_layout == FR_ROW)
     {
@@ -6428,7 +6426,7 @@ frame_setheight(frame_T *curfrp, int height)
        /*
         * set the current frame to the new height
         */
-       frame_new_height(curfrp, height, FALSE, FALSE);
+       frame_new_height(curfrp, height, FALSE, FALSE, TRUE);
 
        /*
         * First take lines from the frames after the current frame.  If
@@ -6455,7 +6453,8 @@ frame_setheight(frame_T *curfrp, int height)
                        if (frp->fr_height - room_reserved > take)
                            room_reserved = frp->fr_height - take;
                        take -= frp->fr_height - room_reserved;
-                       frame_new_height(frp, room_reserved, FALSE, FALSE);
+                       frame_new_height(frp, room_reserved, FALSE, FALSE,
+                                                                       TRUE);
                        room_reserved = 0;
                    }
                }
@@ -6464,12 +6463,12 @@ frame_setheight(frame_T *curfrp, int height)
                    if (frp->fr_height - take < h)
                    {
                        take -= frp->fr_height - h;
-                       frame_new_height(frp, h, FALSE, FALSE);
+                       frame_new_height(frp, h, FALSE, FALSE, TRUE);
                    }
                    else
                    {
                        frame_new_height(frp, frp->fr_height - take,
-                                                               FALSE, FALSE);
+                                                           FALSE, FALSE, TRUE);
                        take = 0;
                    }
                }
@@ -6718,7 +6717,6 @@ win_drag_status_line(win_T *dragwin, int offset)
     frame_T    *curfr;
     frame_T    *fr;
     int                room;
-    int                row;
     int                up;     // if TRUE, drag status line up, otherwise down
     int                n;
 
@@ -6799,7 +6797,7 @@ win_drag_status_line(win_T *dragwin, int offset)
      * Doesn't happen when dragging the last status line up.
      */
     if (fr != NULL)
-       frame_new_height(fr, fr->fr_height + offset, up, FALSE);
+       frame_new_height(fr, fr->fr_height + offset, up, FALSE, TRUE);
 
     if (up)
        fr = curfr;             // current frame gets smaller
@@ -6815,11 +6813,11 @@ win_drag_status_line(win_T *dragwin, int offset)
        if (fr->fr_height - offset <= n)
        {
            offset -= fr->fr_height - n;
-           frame_new_height(fr, n, !up, FALSE);
+           frame_new_height(fr, n, !up, FALSE, TRUE);
        }
        else
        {
-           frame_new_height(fr, fr->fr_height - offset, !up, FALSE);
+           frame_new_height(fr, fr->fr_height - offset, !up, FALSE, TRUE);
            break;
        }
        if (up)
@@ -6827,12 +6825,7 @@ win_drag_status_line(win_T *dragwin, int offset)
        else
            fr = fr->fr_next;
     }
-    row = win_comp_pos();
-    screen_fill(row, cmdline_row, 0, (int)Columns, ' ', ' ', 0);
-    cmdline_row = row;
-    p_ch = MAX(Rows - cmdline_row, MIN_CMDHEIGHT);
-    curtab->tp_ch_used = p_ch;
-
+    win_comp_pos();
     win_fix_scroll(TRUE);
 
     redraw_all_later(UPD_SOME_VALID);
@@ -7287,31 +7280,10 @@ win_comp_scroll(win_T *wp)
     void
 command_height(void)
 {
-    int                h;
-    frame_T    *frp;
     int                old_p_ch = curtab->tp_ch_used;
 
-    // Use the value of p_ch that we remembered.  This is needed for when the
-    // GUI starts up, we can't be sure in what order things happen.  And when
-    // p_ch was changed in another tab page.
-    curtab->tp_ch_used = p_ch;
-
-    // If the space for the command line is already more than 'cmdheight' there
-    // is nothing to do (window size must have decreased).
-    // Note: this makes curtab->tp_ch_used unreliable
-    if (p_ch > old_p_ch && cmdline_row <= Rows - p_ch)
-       return;
-
-    // Update cmdline_row to what it should be: just below the last window.
-    cmdline_row = topframe->fr_height + tabline_height();
-
-    // old_p_ch may be unreliable, because of the early return above, so
-    // set old_p_ch to what it would be, so that the windows get resized
-    // properly for the new value.
-    old_p_ch = Rows - cmdline_row;
-
     // Find bottom frame with width of screen.
-    frp = lastwin->w_frame;
+    frame_T *frp = lastwin->w_frame;
     while (frp->fr_width != Columns && frp->fr_parent != NULL)
        frp = frp->fr_parent;
 
@@ -7320,54 +7292,39 @@ command_height(void)
                                                      && frp->fr_win->w_p_wfh)
        frp = frp->fr_prev;
 
-    if (starting != NO_SCREEN)
+    while (p_ch > old_p_ch && command_frame_height)
     {
-       cmdline_row = Rows - p_ch;
-
-       if (p_ch > old_p_ch)                // p_ch got bigger
+       if (frp == NULL)
        {
-           while (p_ch > old_p_ch)
-           {
-               if (frp == NULL)
-               {
-                   emsg(_(e_not_enough_room));
-                   p_ch = old_p_ch;
-                   curtab->tp_ch_used = p_ch;
-                   cmdline_row = Rows - p_ch;
-                   break;
-               }
-               h = frp->fr_height - frame_minheight(frp, NULL);
-               if (h > p_ch - old_p_ch)
-                   h = p_ch - old_p_ch;
-               old_p_ch += h;
-               frame_add_height(frp, -h);
-               frp = frp->fr_prev;
-           }
-
-           // Recompute window positions.
-           (void)win_comp_pos();
-
-           if (!need_wait_return)
-           {
-               // clear the lines added to cmdline
-               if (full_screen)
-                   screen_fill(cmdline_row, (int)Rows, 0,
-                                                      (int)Columns, ' ', ' ', 
0);
-               msg_row = cmdline_row;
-           }
-           redraw_cmdline = TRUE;
-           return;
+           emsg(_(e_not_enough_room));
+           p_ch = old_p_ch;
+           break;
        }
-
-       if (msg_row < cmdline_row)
-           msg_row = cmdline_row;
-       redraw_cmdline = TRUE;
+       int h = MIN(p_ch - old_p_ch,
+                       frp->fr_height - frame_minheight(frp, NULL));
+       frame_add_height(frp, -h);
+       old_p_ch += h;
+       frp = frp->fr_prev;
     }
-    frame_add_height(frp, (int)(old_p_ch - p_ch));
+    if (p_ch < old_p_ch && command_frame_height)
+       frame_add_height(frp, (int)(old_p_ch - p_ch));
 
     // Recompute window positions.
-    if (frp != lastwin->w_frame)
-       (void)win_comp_pos();
+    win_comp_pos();
+    cmdline_row = Rows - p_ch;
+    redraw_cmdline = TRUE;
+
+    // Clear the cmdheight area.
+    if (msg_scrolled == 0 && full_screen)
+    {
+       screen_fill(cmdline_row, (int)Rows, 0, (int)Columns, ' ', ' ', 0);
+       msg_row = cmdline_row;
+    }
+
+    // Use the value of p_ch that we remembered.  This is needed for when the
+    // GUI starts up, we can't be sure in what order things happen.  And when
+    // p_ch was changed in another tab page.
+    curtab->tp_ch_used = p_ch;
 }
 
 /*
@@ -7377,7 +7334,7 @@ command_height(void)
     static void
 frame_add_height(frame_T *frp, int n)
 {
-    frame_new_height(frp, frp->fr_height + n, FALSE, FALSE);
+    frame_new_height(frp, frp->fr_height + n, FALSE, FALSE, FALSE);
     for (;;)
     {
        frp = frp->fr_parent;
@@ -7436,7 +7393,7 @@ last_status_rec(frame_T *fr, int statusline)
            wp->w_status_height = 1;
            if (fp != fr)
            {
-               frame_new_height(fp, fp->fr_height - 1, FALSE, FALSE);
+               frame_new_height(fp, fp->fr_height - 1, FALSE, FALSE, FALSE);
                frame_fix_height(wp);
                (void)win_comp_pos();
            }
@@ -7819,7 +7776,7 @@ restore_snapshot_rec(frame_T *sn, frame_T *fr)
     fr->fr_width = sn->fr_width;
     if (fr->fr_layout == FR_LEAF)
     {
-       frame_new_height(fr, fr->fr_height, FALSE, FALSE);
+       frame_new_height(fr, fr->fr_height, FALSE, FALSE, FALSE);
        frame_new_width(fr, fr->fr_width, FALSE, FALSE);
        wp = sn->fr_win;
     }

-- 
-- 
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 vim_dev+unsubscr...@googlegroups.com.
To view this discussion visit 
https://groups.google.com/d/msgid/vim_dev/E1tU72I-007OqG-Ve%40256bit.org.

Raspunde prin e-mail lui