]> git.ipfire.org Git - thirdparty/vim.git/commitdiff
patch 9.2.0806: 'showcmd' may show internal command keys v9.2.0806
authorBarrett Ruth <br@barrettruth.com>
Sun, 19 Jul 2026 14:53:55 +0000 (14:53 +0000)
committerChristian Brabandt <cb@256bit.org>
Sun, 19 Jul 2026 14:53:55 +0000 (14:53 +0000)
Problem:  The `showcmd` statusline item may show internal command keys when a
          `<Cmd>` or `<ScriptCmd>` mapping redraws the statusline, and may
          leave stale text behind when `%S` is rendered directly.
Solution: Do not add these internal mapping dispatch keys to the `showcmd`
          buffer, and keep the clear state in sync when `%S` renders it
          (Barrett Ruth)

closes: #20769

Co-authored-by: zeertzjq <35768171+zeertzjq@users.noreply.github.com>
Signed-off-by: Barrett Ruth <br@barrettruth.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
src/drawscreen.c
src/normal.c
src/proto/normal.pro
src/screen.c
src/testdir/test_statusline.vim
src/version.c

index 65d6a88d31b3bf623caca44d1fc8881b0bdaccf2..2c932d4ba749d25e925f14dae3628251a034cebf 100644 (file)
@@ -620,6 +620,7 @@ win_redr_status(win_T *wp, int ignore_pum UNUSED)
            if (width > 0)
                screen_puts_len(showcmd_buf, width, row,
                                wp->w_wincol + this_ru_col - width - 1, attr);
+           showcmd_update_clear_state();
        }
     }
 
index 08b9e9f0cfe0852d79fb92d9a0bf660fc0ee6146..d5de6abe5115f4046fdee469070d5c4fb7591890 100644 (file)
@@ -1739,7 +1739,7 @@ add_to_showcmd(int c)
        K_RIGHTMOUSE, K_RIGHTDRAG, K_RIGHTRELEASE,
        K_MOUSEDOWN, K_MOUSEUP, K_MOUSELEFT, K_MOUSERIGHT,
        K_X1MOUSE, K_X1DRAG, K_X1RELEASE, K_X2MOUSE, K_X2DRAG, K_X2RELEASE,
-       K_CURSORHOLD,
+       K_CURSORHOLD, K_COMMAND, K_SCRIPT_COMMAND,
        0
     };
 
@@ -1834,12 +1834,18 @@ pop_showcmd(void)
     display_showcmd();
 }
 
+    void
+showcmd_update_clear_state(void)
+{
+    showcmd_is_clear = (showcmd_buf[0] == NUL);
+}
+
     static void
 display_showcmd(void)
 {
     int            len = vim_strsize(showcmd_buf);
 
-    showcmd_is_clear = (len == 0);
+    showcmd_update_clear_state();
     cursor_off();
 
     if (*p_sloc == 's')
index cf873f20bb5ddaa98473d0c3117aab0dae8455a6..6f45b1a3ad37d437e6ea7784d01bb95603f8c8e1 100644 (file)
@@ -19,6 +19,7 @@ int add_to_showcmd(int c);
 void add_to_showcmd_c(int c);
 void push_showcmd(void);
 void pop_showcmd(void);
+void showcmd_update_clear_state(void);
 void do_check_scrollbind(int check);
 void check_scrollbind(linenr_T topline_diff, long leftcol_diff);
 int find_decl(char_u *ptr, int len, int locally, int thisblock, int flags_arg);
index 17d4c1563c6e52ba060769a36a7b642bc03a7c0b..07a237b0c61bc98f0641081ce6438a631b0cfd33 100644 (file)
@@ -1676,6 +1676,9 @@ win_redr_custom(
     }
     ewp->w_p_crb = p_crb_save;
 
+    if (p_sc && STRCMP(opt_name, p_sloc) == 0)
+       showcmd_update_clear_state();
+
     // Note: In the loop, build_stl_str_hl_mline() may replace stl_tmp with
     // a newly allocated buffer (when "%!" evaluation occurs), freeing the
     // original "stl" internally.  After the loop, stl_tmp must be freed
@@ -5317,6 +5320,7 @@ draw_tabline(void)
            if (width > 0)
                screen_puts_len(showcmd_buf, width, 0, (int)Columns
                            - width - (tabcount > 1) * 2, attr_nosel);
+           showcmd_update_clear_state();
        }
 
        // Put an "X" for closing the current tab if there are several.
index c00582d5fdd145eb525b99c04136375710a29bad..69699a2d4dfcb813cad69241ef5d436f952d9276 100644 (file)
@@ -657,6 +657,47 @@ func Test_statusline_showcmd()
   call StopVimInTerminal(buf)
 endfunc
 
+func Test_statusline_showcmd_redraw_tabline()
+  CheckRunVimInTerminal
+
+  let lines =<< trim END
+    set showcmd showcmdloc=tabline showtabline=2 tabline=%S timeoutlen=0
+    nnoremap g :redraw<CR>
+    nnoremap gc <Nop>
+  END
+  call writefile(lines, 'XTest_statusline_showcmd_redraw', 'D')
+
+  let buf = RunVimInTerminal('-S XTest_statusline_showcmd_redraw', #{rows: 6, cols: 40})
+  call term_sendkeys(buf, 'g')
+  call WaitForAssert({-> assert_match(':redraw', term_getline(buf, 6))})
+  call WaitForAssert({-> assert_notmatch('^:', term_getline(buf, 1))})
+  call StopVimInTerminal(buf)
+endfunc
+
+func Test_statusline_showcmd_cmd_mapping()
+  set showcmd
+  set statusline=AAA%SBBB
+  set showcmdloc=statusline
+  try
+    let g:showcmd_statusline = ''
+    nnoremap <F3> <Cmd>let g:showcmd_statusline = <SID>get_statusline()<CR>
+    call feedkeys("\<F3>", 'xt')
+    call assert_equal('AAABBB', trim(g:showcmd_statusline))
+    let g:showcmd_statusline = ''
+    nunmap <F3>
+
+    nnoremap <F3> <ScriptCmd>let g:showcmd_statusline = <SID>get_statusline()<CR>
+    call feedkeys("\<F3>", 'xt')
+    call assert_equal('AAABBB', trim(g:showcmd_statusline))
+  finally
+    silent! nunmap <F3>
+    unlet! g:showcmd_statusline
+    set showcmd&
+    set statusline&
+    set showcmdloc&
+  endtry
+endfunc
+
 func Test_statusline_highlight_group_cleared()
   CheckScreendump
 
index 4b9c6318d699af4ee79b329219506b4556da96a7..712e652ee9dc8b1c0056c1fd577a74b9d90d512e 100644 (file)
@@ -759,6 +759,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    806,
 /**/
     805,
 /**/