patch 9.1.1621: flicker in popup menu during cmdline autocompletion

Problem:  When the popup menu (PUM) occupies more than half the screen
          height, it flickers whenever a character is typed or erased.
          This happens because the PUM is cleared and the screen is
          redrawn before a new PUM is rendered. The extra redraw between
          menu updates causes visible flicker.
Solution: A complete, non-hacky fix would require removing the
          CmdlineChanged event from the loop and letting autocompletion
          manage the process end-to-end. This is because screen redraws
          after any cmdline change are necessary for other features to
          work.
          This change modifies wildtrigger() so that the next typed
          character defers the screen update instead of redrawing
          immediately. This removes the intermediate redraw, eliminating
          flicker and making cmdline autocompletion feel smooth
          (Girish Palya).

Trade-offs:
This behavior change in wildtrigger() is tailored specifically for
:h cmdline-autocompletion. wildtrigger() now has no general-purpose use
outside this scenario.

closes: #17932

Signed-off-by: Girish Palya <girishji@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
This commit is contained in:
Girish Palya
2025-08-08 08:26:03 +02:00
committed by Christian Brabandt
parent 4fca92faa2
commit da9c966893
8 changed files with 101 additions and 12 deletions

View File

@ -939,6 +939,7 @@ cmdline_wildchar_complete(
int *wim_index_p,
expand_T *xp,
int *gotesc,
int redraw_if_menu_empty,
pos_T *pre_incsearch_pos)
{
int wim_index = *wim_index_p;
@ -991,6 +992,10 @@ cmdline_wildchar_complete(
else
res = nextwild(xp, WILD_EXPAND_KEEP, options, escape);
// Remove popup window if no completion items are available
if (redraw_if_menu_empty && xp->xp_numfiles <= 0)
update_screen(0);
// if interrupted while completing, behave like it failed
if (got_int)
{
@ -1633,7 +1638,7 @@ getcmdline_int(
int clear_ccline) // clear ccline first
{
static int depth = 0; // call depth
int c;
int c = 0;
int i;
int j;
int gotesc = FALSE; // TRUE when <ESC> just typed
@ -1838,6 +1843,7 @@ getcmdline_int(
int trigger_cmdlinechanged = TRUE;
int end_wildmenu;
int prev_cmdpos = ccline.cmdpos;
int skip_pum_redraw = FALSE;
VIM_CLEAR(prev_cmdbuff);
@ -1863,6 +1869,10 @@ getcmdline_int(
goto returncmd;
}
// Defer screen update to avoid pum flicker during wildtrigger()
if (c == K_WILD && firstc != '@')
skip_pum_redraw = TRUE;
// Get a character. Ignore K_IGNORE and K_NOP, they should not do
// anything, such as stop completion.
do
@ -2002,7 +2012,12 @@ getcmdline_int(
if (end_wildmenu)
{
if (cmdline_pum_active())
cmdline_pum_remove(&ccline);
{
skip_pum_redraw = skip_pum_redraw && (vim_isprintc(c)
|| c == K_BS || c == Ctrl_H || c == K_DEL
|| c == K_KDEL || c == Ctrl_W || c == Ctrl_U);
cmdline_pum_remove(&ccline, skip_pum_redraw);
}
if (xpc.xp_numfiles != -1)
(void)ExpandOne(&xpc, NULL, NULL, 0, WILD_FREE);
did_wild_list = FALSE;
@ -2081,7 +2096,7 @@ getcmdline_int(
if (c == K_WILD)
++emsg_silent; // Silence the bell
res = cmdline_wildchar_complete(c, firstc != '@', &did_wild_list,
&wim_index, &xpc, &gotesc,
&wim_index, &xpc, &gotesc, c == K_WILD,
#ifdef FEAT_SEARCH_EXTRA
&is_state.search_start
#else
@ -2647,7 +2662,7 @@ returncmd:
// if certain special keys like <Esc> or <C-\> were used as wildchar. Make
// sure to still clean up to avoid memory corruption.
if (cmdline_pum_active())
cmdline_pum_remove(&ccline);
cmdline_pum_remove(&ccline, FALSE);
wildmenu_cleanup(&ccline);
did_wild_list = FALSE;
wim_index = 0;