Skip to content

Commit da9c966

Browse files
girishjichrisbra
authored andcommitted
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 <[email protected]> Signed-off-by: Christian Brabandt <[email protected]>
1 parent 4fca92f commit da9c966

8 files changed

Lines changed: 101 additions & 12 deletions

src/cmdexpand.c

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -455,9 +455,8 @@ cmdline_pum_active(void)
455455
* items and refresh the screen.
456456
*/
457457
void
458-
cmdline_pum_remove(cmdline_info_T *cclp UNUSED)
458+
cmdline_pum_remove(cmdline_info_T *cclp UNUSED, int defer_redraw)
459459
{
460-
int save_p_lz = p_lz;
461460
int save_KeyTyped = KeyTyped;
462461
#ifdef FEAT_EVAL
463462
int save_RedrawingDisabled = RedrawingDisabled;
@@ -468,9 +467,15 @@ cmdline_pum_remove(cmdline_info_T *cclp UNUSED)
468467
pum_undisplay();
469468
VIM_CLEAR(compl_match_array);
470469
compl_match_arraysize = 0;
471-
p_lz = FALSE; // avoid the popup menu hanging around
472-
update_screen(0);
473-
p_lz = save_p_lz;
470+
if (!defer_redraw)
471+
{
472+
int save_p_lz = p_lz;
473+
p_lz = FALSE; // avoid the popup menu hanging around
474+
update_screen(0);
475+
p_lz = save_p_lz;
476+
}
477+
else
478+
pum_call_update_screen();
474479
redrawcmd();
475480

476481
// When a function is called (e.g. for 'foldtext') KeyTyped might be reset
@@ -485,7 +490,7 @@ cmdline_pum_remove(cmdline_info_T *cclp UNUSED)
485490
void
486491
cmdline_pum_cleanup(cmdline_info_T *cclp)
487492
{
488-
cmdline_pum_remove(cclp);
493+
cmdline_pum_remove(cclp, FALSE);
489494
wildmenu_cleanup(cclp);
490495
}
491496

@@ -1068,7 +1073,7 @@ ExpandOne(
10681073

10691074
// The entries from xp_files may be used in the PUM, remove it.
10701075
if (compl_match_array != NULL)
1071-
cmdline_pum_remove(get_cmdline_info());
1076+
cmdline_pum_remove(get_cmdline_info(), FALSE);
10721077
}
10731078
xp->xp_selected = 0;
10741079

src/ex_getln.c

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -939,6 +939,7 @@ cmdline_wildchar_complete(
939939
int *wim_index_p,
940940
expand_T *xp,
941941
int *gotesc,
942+
int redraw_if_menu_empty,
942943
pos_T *pre_incsearch_pos)
943944
{
944945
int wim_index = *wim_index_p;
@@ -991,6 +992,10 @@ cmdline_wildchar_complete(
991992
else
992993
res = nextwild(xp, WILD_EXPAND_KEEP, options, escape);
993994

995+
// Remove popup window if no completion items are available
996+
if (redraw_if_menu_empty && xp->xp_numfiles <= 0)
997+
update_screen(0);
998+
994999
// if interrupted while completing, behave like it failed
9951000
if (got_int)
9961001
{
@@ -1633,7 +1638,7 @@ getcmdline_int(
16331638
int clear_ccline) // clear ccline first
16341639
{
16351640
static int depth = 0; // call depth
1636-
int c;
1641+
int c = 0;
16371642
int i;
16381643
int j;
16391644
int gotesc = FALSE; // TRUE when <ESC> just typed
@@ -1838,6 +1843,7 @@ getcmdline_int(
18381843
int trigger_cmdlinechanged = TRUE;
18391844
int end_wildmenu;
18401845
int prev_cmdpos = ccline.cmdpos;
1846+
int skip_pum_redraw = FALSE;
18411847

18421848
VIM_CLEAR(prev_cmdbuff);
18431849

@@ -1863,6 +1869,10 @@ getcmdline_int(
18631869
goto returncmd;
18641870
}
18651871

1872+
// Defer screen update to avoid pum flicker during wildtrigger()
1873+
if (c == K_WILD && firstc != '@')
1874+
skip_pum_redraw = TRUE;
1875+
18661876
// Get a character. Ignore K_IGNORE and K_NOP, they should not do
18671877
// anything, such as stop completion.
18681878
do
@@ -2002,7 +2012,12 @@ getcmdline_int(
20022012
if (end_wildmenu)
20032013
{
20042014
if (cmdline_pum_active())
2005-
cmdline_pum_remove(&ccline);
2015+
{
2016+
skip_pum_redraw = skip_pum_redraw && (vim_isprintc(c)
2017+
|| c == K_BS || c == Ctrl_H || c == K_DEL
2018+
|| c == K_KDEL || c == Ctrl_W || c == Ctrl_U);
2019+
cmdline_pum_remove(&ccline, skip_pum_redraw);
2020+
}
20062021
if (xpc.xp_numfiles != -1)
20072022
(void)ExpandOne(&xpc, NULL, NULL, 0, WILD_FREE);
20082023
did_wild_list = FALSE;
@@ -2081,7 +2096,7 @@ getcmdline_int(
20812096
if (c == K_WILD)
20822097
++emsg_silent; // Silence the bell
20832098
res = cmdline_wildchar_complete(c, firstc != '@', &did_wild_list,
2084-
&wim_index, &xpc, &gotesc,
2099+
&wim_index, &xpc, &gotesc, c == K_WILD,
20852100
#ifdef FEAT_SEARCH_EXTRA
20862101
&is_state.search_start
20872102
#else
@@ -2647,7 +2662,7 @@ getcmdline_int(
26472662
// if certain special keys like <Esc> or <C-\> were used as wildchar. Make
26482663
// sure to still clean up to avoid memory corruption.
26492664
if (cmdline_pum_active())
2650-
cmdline_pum_remove(&ccline);
2665+
cmdline_pum_remove(&ccline, FALSE);
26512666
wildmenu_cleanup(&ccline);
26522667
did_wild_list = FALSE;
26532668
wim_index = 0;

src/proto/cmdexpand.pro

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ int cmdline_fuzzy_complete(char_u *fuzzystr);
33
int nextwild(expand_T *xp, int type, int options, int escape);
44
void cmdline_pum_display(void);
55
int cmdline_pum_active(void);
6-
void cmdline_pum_remove(cmdline_info_T *cclp);
6+
void cmdline_pum_remove(cmdline_info_T *cclp, int defer);
77
void cmdline_pum_cleanup(cmdline_info_T *cclp);
88
int cmdline_compl_startcol(void);
99
char_u *cmdline_compl_pattern(void);
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
| +0&#ffffff0@74
2+
|~+0#4040ff13&| @73
3+
|~| @73
4+
|~| @73
5+
|~| @6| +0#0000001#ffd7ff255|a|b|c|1| @10| +0#4040ff13#ffffff0@50
6+
|~| @6| +0#0000001#ffd7ff255|a|b|c|2| @10| +0#4040ff13#ffffff0@50
7+
|~| @6| +0#0000001#ffd7ff255|a|b|c|3| @10| +0#4040ff13#ffffff0@50
8+
|~| @6| +0#0000001#ffd7ff255|a|b|c|4| @10| +0#4040ff13#ffffff0@50
9+
|~| @6| +0#0000001#ffd7ff255|a|b|c|5| @10| +0#4040ff13#ffffff0@50
10+
|:+0#0000000&|T|e|s|t|C|m|d| |a> @64
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
| +0&#ffffff0@74
2+
|~+0#4040ff13&| @73
3+
|~| @73
4+
|~| @73
5+
|~| @6| +0#0000001#ffd7ff255|a|b|c|1| @10| +0#4040ff13#ffffff0@50
6+
|~| @6| +0#0000001#ffd7ff255|a|b|c|2| @10| +0#4040ff13#ffffff0@50
7+
|~| @6| +0#0000001#ffd7ff255|a|b|c|3| @10| +0#4040ff13#ffffff0@50
8+
|~| @6| +0#0000001#ffd7ff255|a|b|c|4| @10| +0#4040ff13#ffffff0@50
9+
|~| @6| +0#0000001#ffd7ff255|a|b|c|5| @10| +0#4040ff13#ffffff0@50
10+
|:+0#0000000&|T|e|s|t|C|m|d| |a|x> @63
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
| +0&#ffffff0@74
2+
|~+0#4040ff13&| @73
3+
|~| @73
4+
|~| @73
5+
|~| @73
6+
|~| @73
7+
|~| @73
8+
|~| @73
9+
|~| @73
10+
|:+0#0000000&|T|e|s|t|C|m|d| |a|x> @45|0|,|0|-|1| @8|A|l@1|

src/testdir/test_cmdline.vim

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4822,4 +4822,41 @@ func Test_cmdline_changed()
48224822
call test_override("char_avail", 0)
48234823
endfunc
48244824

4825+
func Test_wildtrigger_update_screen()
4826+
CheckScreendump
4827+
let lines =<< trim [SCRIPT]
4828+
command! -nargs=* -complete=customlist,TestFn TestCmd echo
4829+
func TestFn(cmdarg, b, c)
4830+
if a:cmdarg == 'ax'
4831+
return []
4832+
else
4833+
return map(range(1, 5), 'printf("abc%d", v:val)')
4834+
endif
4835+
endfunc
4836+
set wildmode=noselect,full
4837+
set wildoptions=pum
4838+
set wildmenu
4839+
cnoremap <F8> <C-R>=wildtrigger()[-1]<CR>
4840+
[SCRIPT]
4841+
call writefile(lines, 'XTest_wildtrigger', 'D')
4842+
let buf = RunVimInTerminal('-S XTest_wildtrigger', {'rows': 10})
4843+
4844+
call term_sendkeys(buf, ":TestCmd a\<F8>")
4845+
call VerifyScreenDump(buf, 'Test_wildtrigger_update_screen_1', {})
4846+
4847+
" Typing a character when pum is open does not close the pum window
4848+
" This is needed to prevent pum window from flickering during
4849+
" ':h cmdline-autocompletion'.
4850+
call term_sendkeys(buf, "x")
4851+
call VerifyScreenDump(buf, 'Test_wildtrigger_update_screen_2', {})
4852+
4853+
" pum window is closed when no completion candidates are available
4854+
call term_sendkeys(buf, "\<F8>")
4855+
call VerifyScreenDump(buf, 'Test_wildtrigger_update_screen_3', {})
4856+
4857+
call term_sendkeys(buf, "\<esc>")
4858+
call StopVimInTerminal(buf)
4859+
cnoremap <buffer> <F8> <C-R>=wildtrigger()[-1]<CR>
4860+
endfunc
4861+
48254862
" vim: shiftwidth=2 sts=2 expandtab

src/version.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -719,6 +719,8 @@ static char *(features[]) =
719719

720720
static int included_patches[] =
721721
{ /* Add new patch number below this line */
722+
/**/
723+
1621,
722724
/**/
723725
1620,
724726
/**/

0 commit comments

Comments
 (0)