From: Barrett Ruth Date: Sun, 19 Jul 2026 14:53:55 +0000 (+0000) Subject: patch 9.2.0806: 'showcmd' may show internal command keys X-Git-Tag: v9.2.0806^0 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=bd730293dccaa166cd99321be674cb059d498b73;p=thirdparty%2Fvim.git patch 9.2.0806: 'showcmd' may show internal command keys Problem: The `showcmd` statusline item may show internal command keys when a `` or `` 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 Signed-off-by: Christian Brabandt --- diff --git a/src/drawscreen.c b/src/drawscreen.c index 65d6a88d31..2c932d4ba7 100644 --- a/src/drawscreen.c +++ b/src/drawscreen.c @@ -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(); } } diff --git a/src/normal.c b/src/normal.c index 08b9e9f0cf..d5de6abe51 100644 --- a/src/normal.c +++ b/src/normal.c @@ -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') diff --git a/src/proto/normal.pro b/src/proto/normal.pro index cf873f20bb..6f45b1a3ad 100644 --- a/src/proto/normal.pro +++ b/src/proto/normal.pro @@ -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); diff --git a/src/screen.c b/src/screen.c index 17d4c1563c..07a237b0c6 100644 --- a/src/screen.c +++ b/src/screen.c @@ -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. diff --git a/src/testdir/test_statusline.vim b/src/testdir/test_statusline.vim index c00582d5fd..69699a2d4d 100644 --- a/src/testdir/test_statusline.vim +++ b/src/testdir/test_statusline.vim @@ -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 + nnoremap gc + 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 let g:showcmd_statusline = get_statusline() + call feedkeys("\", 'xt') + call assert_equal('AAABBB', trim(g:showcmd_statusline)) + let g:showcmd_statusline = '' + nunmap + + nnoremap let g:showcmd_statusline = get_statusline() + call feedkeys("\", 'xt') + call assert_equal('AAABBB', trim(g:showcmd_statusline)) + finally + silent! nunmap + unlet! g:showcmd_statusline + set showcmd& + set statusline& + set showcmdloc& + endtry +endfunc + func Test_statusline_highlight_group_cleared() CheckScreendump diff --git a/src/version.c b/src/version.c index 4b9c6318d6..712e652ee9 100644 --- a/src/version.c +++ b/src/version.c @@ -759,6 +759,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 806, /**/ 805, /**/