From b2570e685255891d2e0f68da6eb665c4d3e6ea17 Mon Sep 17 00:00:00 2001 From: Barrett Ruth <62671086+barrettruth@users.noreply.github.com> Date: Wed, 15 Jul 2026 05:10:09 -0500 Subject: [PATCH] fix(showcmd): avoid stale %S contents #40747 Co-authored-by: zeertzjq --- src/nvim/normal.c | 3 +-- src/nvim/normal.h | 1 + src/nvim/statusline.c | 5 +++++ test/functional/api/vim_spec.lua | 19 +++++++++++++++++++ test/functional/ui/statusline_spec.lua | 9 +++++++++ 5 files changed, 35 insertions(+), 2 deletions(-) diff --git a/src/nvim/normal.c b/src/nvim/normal.c index 9dc1ece393..cc181bea88 100644 --- a/src/nvim/normal.c +++ b/src/nvim/normal.c @@ -1851,7 +1851,6 @@ void may_clear_cmdline(void) // Routines for displaying a partly typed command static char old_showcmd_buf[SHOWCMD_BUFLEN]; // For push_showcmd() -static bool showcmd_is_clear = true; static bool showcmd_visual = false; void clear_showcmd(void) @@ -1951,7 +1950,7 @@ bool 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_EVENT, + K_EVENT, K_COMMAND, K_LUA, 0 }; diff --git a/src/nvim/normal.h b/src/nvim/normal.h index 125bc7ad62..c4881d906a 100644 --- a/src/nvim/normal.h +++ b/src/nvim/normal.h @@ -16,5 +16,6 @@ enum { /// 'showcmd' buffer shared between normal.c and statusline.c EXTERN char showcmd_buf[SHOWCMD_BUFLEN]; +EXTERN bool showcmd_is_clear INIT( = true); #include "normal.h.generated.h" diff --git a/src/nvim/statusline.c b/src/nvim/statusline.c index 4913dc9a02..574f16c405 100644 --- a/src/nvim/statusline.c +++ b/src/nvim/statusline.c @@ -418,6 +418,10 @@ static void win_redr_stl_expr(win_T *wp, bool draw_winbar, bool draw_ruler, bool } } + if (p_sc && find_option(p_sloc) == opt_idx) { + showcmd_is_clear = (showcmd_buf[0] == NUL); + } + if (ui_event) { ui_call_msg_ruler(content); did_show_ext_ruler = true; @@ -809,6 +813,7 @@ void draw_tabline(void) grid_line_puts(Columns - sc_width - (tabcount > 1) * 2, showcmd_buf, sc_width, attr_nosel); } + showcmd_is_clear = (showcmd_buf[0] == NUL); } // Put an "X" for closing the current tab if there are several. diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua index 2702fd17fd..a84de55a23 100644 --- a/test/functional/api/vim_spec.lua +++ b/test/functional/api/vim_spec.lua @@ -4652,6 +4652,25 @@ describe('API', function() eq({ str = '<3456', width = 5 }, api.nvim_eval_statusline('%S', { maxwidth = 5 })) end) + it('does not include internal mapping keys in %S', function() + command('set showcmd') + command( + [[nnoremap let g:showcmd_statusline = nvim_eval_statusline('AAA%SBBB', {}).str]] + ) + exec_lua([[vim.api.nvim_feedkeys(vim.keycode(''), 'xt', false)]]) + eq('AAABBB', api.nvim_get_var('showcmd_statusline')) + command('nunmap ') + + exec_lua [[ + vim.g.showcmd_statusline = '' + vim.keymap.set('n', '', function() + vim.g.showcmd_statusline = vim.api.nvim_eval_statusline('AAA%SBBB', {}).str + end) + vim.api.nvim_feedkeys(vim.keycode(''), 'xt', false) + ]] + eq('AAABBB', api.nvim_get_var('showcmd_statusline')) + end) + describe('highlight parsing', function() it('works', function() eq( diff --git a/test/functional/ui/statusline_spec.lua b/test/functional/ui/statusline_spec.lua index ca3b151b77..7372c26879 100644 --- a/test/functional/ui/statusline_spec.lua +++ b/test/functional/ui/statusline_spec.lua @@ -883,6 +883,15 @@ describe('statusline', function() ]]) end) + it('clears showcmd rendered by tabline redraw', function() + command('set showcmd showcmdloc=tabline showtabline=2 tabline=%S timeoutlen=0') + command('nnoremap g :redraw') + command('nnoremap gc ') + feed('g') + screen:expect({ any = ':redraw', none = '{2::' }) + eq('', api.nvim_eval_statusline('%S', {}).str) + end) + it('showcmdloc=statusline works with vertical splits', function() command('rightbelow vsplit') command('set showcmd showcmdloc=statusline')