mirror of
				https://github.com/vim/vim.git
				synced 2025-10-30 09:47:20 -04:00 
			
		
		
		
	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:
		
				
					committed by
					
						 Christian Brabandt
						Christian Brabandt
					
				
			
			
				
	
			
			
			
						parent
						
							4fca92faa2
						
					
				
				
					commit
					da9c966893
				
			| @@ -455,9 +455,8 @@ cmdline_pum_active(void) | |||||||
|  * items and refresh the screen. |  * items and refresh the screen. | ||||||
|  */ |  */ | ||||||
|     void |     void | ||||||
| cmdline_pum_remove(cmdline_info_T *cclp UNUSED) | cmdline_pum_remove(cmdline_info_T *cclp UNUSED, int defer_redraw) | ||||||
| { | { | ||||||
|     int save_p_lz = p_lz; |  | ||||||
|     int	save_KeyTyped = KeyTyped; |     int	save_KeyTyped = KeyTyped; | ||||||
| #ifdef FEAT_EVAL | #ifdef FEAT_EVAL | ||||||
|     int	save_RedrawingDisabled = RedrawingDisabled; |     int	save_RedrawingDisabled = RedrawingDisabled; | ||||||
| @@ -468,9 +467,15 @@ cmdline_pum_remove(cmdline_info_T *cclp UNUSED) | |||||||
|     pum_undisplay(); |     pum_undisplay(); | ||||||
|     VIM_CLEAR(compl_match_array); |     VIM_CLEAR(compl_match_array); | ||||||
|     compl_match_arraysize = 0; |     compl_match_arraysize = 0; | ||||||
|  |     if (!defer_redraw) | ||||||
|  |     { | ||||||
|  | 	int save_p_lz = p_lz; | ||||||
| 	p_lz = FALSE;  // avoid the popup menu hanging around | 	p_lz = FALSE;  // avoid the popup menu hanging around | ||||||
| 	update_screen(0); | 	update_screen(0); | ||||||
| 	p_lz = save_p_lz; | 	p_lz = save_p_lz; | ||||||
|  |     } | ||||||
|  |     else | ||||||
|  | 	pum_call_update_screen(); | ||||||
|     redrawcmd(); |     redrawcmd(); | ||||||
|  |  | ||||||
|     // When a function is called (e.g. for 'foldtext') KeyTyped might be reset |     // 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) | |||||||
|     void |     void | ||||||
| cmdline_pum_cleanup(cmdline_info_T *cclp) | cmdline_pum_cleanup(cmdline_info_T *cclp) | ||||||
| { | { | ||||||
|     cmdline_pum_remove(cclp); |     cmdline_pum_remove(cclp, FALSE); | ||||||
|     wildmenu_cleanup(cclp); |     wildmenu_cleanup(cclp); | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -1068,7 +1073,7 @@ ExpandOne( | |||||||
|  |  | ||||||
| 	// The entries from xp_files may be used in the PUM, remove it. | 	// The entries from xp_files may be used in the PUM, remove it. | ||||||
| 	if (compl_match_array != NULL) | 	if (compl_match_array != NULL) | ||||||
| 	    cmdline_pum_remove(get_cmdline_info()); | 	    cmdline_pum_remove(get_cmdline_info(), FALSE); | ||||||
|     } |     } | ||||||
|     xp->xp_selected = 0; |     xp->xp_selected = 0; | ||||||
|  |  | ||||||
|   | |||||||
| @@ -939,6 +939,7 @@ cmdline_wildchar_complete( | |||||||
| 	int		*wim_index_p, | 	int		*wim_index_p, | ||||||
| 	expand_T	*xp, | 	expand_T	*xp, | ||||||
| 	int		*gotesc, | 	int		*gotesc, | ||||||
|  | 	int		redraw_if_menu_empty, | ||||||
| 	pos_T		*pre_incsearch_pos) | 	pos_T		*pre_incsearch_pos) | ||||||
| { | { | ||||||
|     int		wim_index = *wim_index_p; |     int		wim_index = *wim_index_p; | ||||||
| @@ -991,6 +992,10 @@ cmdline_wildchar_complete( | |||||||
| 	else | 	else | ||||||
| 	    res = nextwild(xp, WILD_EXPAND_KEEP, options, escape); | 	    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 interrupted while completing, behave like it failed | ||||||
| 	if (got_int) | 	if (got_int) | ||||||
| 	{ | 	{ | ||||||
| @@ -1633,7 +1638,7 @@ getcmdline_int( | |||||||
|     int		clear_ccline)	// clear ccline first |     int		clear_ccline)	// clear ccline first | ||||||
| { | { | ||||||
|     static int	depth = 0;	    // call depth |     static int	depth = 0;	    // call depth | ||||||
|     int		c; |     int		c = 0; | ||||||
|     int		i; |     int		i; | ||||||
|     int		j; |     int		j; | ||||||
|     int		gotesc = FALSE;		// TRUE when <ESC> just typed |     int		gotesc = FALSE;		// TRUE when <ESC> just typed | ||||||
| @@ -1838,6 +1843,7 @@ getcmdline_int( | |||||||
| 	int	trigger_cmdlinechanged = TRUE; | 	int	trigger_cmdlinechanged = TRUE; | ||||||
| 	int	end_wildmenu; | 	int	end_wildmenu; | ||||||
| 	int	prev_cmdpos = ccline.cmdpos; | 	int	prev_cmdpos = ccline.cmdpos; | ||||||
|  | 	int	skip_pum_redraw = FALSE; | ||||||
|  |  | ||||||
| 	VIM_CLEAR(prev_cmdbuff); | 	VIM_CLEAR(prev_cmdbuff); | ||||||
|  |  | ||||||
| @@ -1863,6 +1869,10 @@ getcmdline_int( | |||||||
| 		goto returncmd; | 		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 | 	// Get a character.  Ignore K_IGNORE and K_NOP, they should not do | ||||||
| 	// anything, such as stop completion. | 	// anything, such as stop completion. | ||||||
| 	do | 	do | ||||||
| @@ -2002,7 +2012,12 @@ getcmdline_int( | |||||||
| 	if (end_wildmenu) | 	if (end_wildmenu) | ||||||
| 	{ | 	{ | ||||||
| 	    if (cmdline_pum_active()) | 	    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) | 	    if (xpc.xp_numfiles != -1) | ||||||
| 		(void)ExpandOne(&xpc, NULL, NULL, 0, WILD_FREE); | 		(void)ExpandOne(&xpc, NULL, NULL, 0, WILD_FREE); | ||||||
| 	    did_wild_list = FALSE; | 	    did_wild_list = FALSE; | ||||||
| @@ -2081,7 +2096,7 @@ getcmdline_int( | |||||||
| 	    if (c == K_WILD) | 	    if (c == K_WILD) | ||||||
| 		++emsg_silent;  // Silence the bell | 		++emsg_silent;  // Silence the bell | ||||||
| 	    res = cmdline_wildchar_complete(c, firstc != '@', &did_wild_list, | 	    res = cmdline_wildchar_complete(c, firstc != '@', &did_wild_list, | ||||||
| 		    &wim_index, &xpc, &gotesc, | 		    &wim_index, &xpc, &gotesc, c == K_WILD, | ||||||
| #ifdef FEAT_SEARCH_EXTRA | #ifdef FEAT_SEARCH_EXTRA | ||||||
| 		    &is_state.search_start | 		    &is_state.search_start | ||||||
| #else | #else | ||||||
| @@ -2647,7 +2662,7 @@ returncmd: | |||||||
|     // if certain special keys like <Esc> or <C-\> were used as wildchar. Make |     // if certain special keys like <Esc> or <C-\> were used as wildchar. Make | ||||||
|     // sure to still clean up to avoid memory corruption. |     // sure to still clean up to avoid memory corruption. | ||||||
|     if (cmdline_pum_active()) |     if (cmdline_pum_active()) | ||||||
| 	cmdline_pum_remove(&ccline); | 	cmdline_pum_remove(&ccline, FALSE); | ||||||
|     wildmenu_cleanup(&ccline); |     wildmenu_cleanup(&ccline); | ||||||
|     did_wild_list = FALSE; |     did_wild_list = FALSE; | ||||||
|     wim_index = 0; |     wim_index = 0; | ||||||
|   | |||||||
| @@ -3,7 +3,7 @@ int cmdline_fuzzy_complete(char_u *fuzzystr); | |||||||
| int nextwild(expand_T *xp, int type, int options, int escape); | int nextwild(expand_T *xp, int type, int options, int escape); | ||||||
| void cmdline_pum_display(void); | void cmdline_pum_display(void); | ||||||
| int cmdline_pum_active(void); | int cmdline_pum_active(void); | ||||||
| void cmdline_pum_remove(cmdline_info_T *cclp); | void cmdline_pum_remove(cmdline_info_T *cclp, int defer); | ||||||
| void cmdline_pum_cleanup(cmdline_info_T *cclp); | void cmdline_pum_cleanup(cmdline_info_T *cclp); | ||||||
| int cmdline_compl_startcol(void); | int cmdline_compl_startcol(void); | ||||||
| char_u *cmdline_compl_pattern(void); | char_u *cmdline_compl_pattern(void); | ||||||
|   | |||||||
							
								
								
									
										10
									
								
								src/testdir/dumps/Test_wildtrigger_update_screen_1.dump
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								src/testdir/dumps/Test_wildtrigger_update_screen_1.dump
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,10 @@ | |||||||
|  | | +0&#ffffff0@74 | ||||||
|  | |~+0#4040ff13&| @73 | ||||||
|  | |~| @73 | ||||||
|  | |~| @73 | ||||||
|  | |~| @6| +0#0000001#ffd7ff255|a|b|c|1| @10| +0#4040ff13#ffffff0@50 | ||||||
|  | |~| @6| +0#0000001#ffd7ff255|a|b|c|2| @10| +0#4040ff13#ffffff0@50 | ||||||
|  | |~| @6| +0#0000001#ffd7ff255|a|b|c|3| @10| +0#4040ff13#ffffff0@50 | ||||||
|  | |~| @6| +0#0000001#ffd7ff255|a|b|c|4| @10| +0#4040ff13#ffffff0@50 | ||||||
|  | |~| @6| +0#0000001#ffd7ff255|a|b|c|5| @10| +0#4040ff13#ffffff0@50 | ||||||
|  | |:+0#0000000&|T|e|s|t|C|m|d| |a> @64 | ||||||
							
								
								
									
										10
									
								
								src/testdir/dumps/Test_wildtrigger_update_screen_2.dump
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								src/testdir/dumps/Test_wildtrigger_update_screen_2.dump
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,10 @@ | |||||||
|  | | +0&#ffffff0@74 | ||||||
|  | |~+0#4040ff13&| @73 | ||||||
|  | |~| @73 | ||||||
|  | |~| @73 | ||||||
|  | |~| @6| +0#0000001#ffd7ff255|a|b|c|1| @10| +0#4040ff13#ffffff0@50 | ||||||
|  | |~| @6| +0#0000001#ffd7ff255|a|b|c|2| @10| +0#4040ff13#ffffff0@50 | ||||||
|  | |~| @6| +0#0000001#ffd7ff255|a|b|c|3| @10| +0#4040ff13#ffffff0@50 | ||||||
|  | |~| @6| +0#0000001#ffd7ff255|a|b|c|4| @10| +0#4040ff13#ffffff0@50 | ||||||
|  | |~| @6| +0#0000001#ffd7ff255|a|b|c|5| @10| +0#4040ff13#ffffff0@50 | ||||||
|  | |:+0#0000000&|T|e|s|t|C|m|d| |a|x> @63 | ||||||
							
								
								
									
										10
									
								
								src/testdir/dumps/Test_wildtrigger_update_screen_3.dump
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								src/testdir/dumps/Test_wildtrigger_update_screen_3.dump
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,10 @@ | |||||||
|  | | +0&#ffffff0@74 | ||||||
|  | |~+0#4040ff13&| @73 | ||||||
|  | |~| @73 | ||||||
|  | |~| @73 | ||||||
|  | |~| @73 | ||||||
|  | |~| @73 | ||||||
|  | |~| @73 | ||||||
|  | |~| @73 | ||||||
|  | |~| @73 | ||||||
|  | |:+0#0000000&|T|e|s|t|C|m|d| |a|x> @45|0|,|0|-|1| @8|A|l@1|  | ||||||
| @@ -4822,4 +4822,41 @@ func Test_cmdline_changed() | |||||||
|   call test_override("char_avail", 0) |   call test_override("char_avail", 0) | ||||||
| endfunc | endfunc | ||||||
|  |  | ||||||
|  | func Test_wildtrigger_update_screen() | ||||||
|  |   CheckScreendump | ||||||
|  |   let lines =<< trim [SCRIPT] | ||||||
|  |     command! -nargs=* -complete=customlist,TestFn TestCmd echo | ||||||
|  |     func TestFn(cmdarg, b, c) | ||||||
|  |       if a:cmdarg == 'ax' | ||||||
|  |         return [] | ||||||
|  |       else | ||||||
|  |         return map(range(1, 5), 'printf("abc%d", v:val)') | ||||||
|  |       endif | ||||||
|  |     endfunc | ||||||
|  |     set wildmode=noselect,full | ||||||
|  |     set wildoptions=pum | ||||||
|  |     set wildmenu | ||||||
|  |     cnoremap <F8> <C-R>=wildtrigger()[-1]<CR> | ||||||
|  |   [SCRIPT] | ||||||
|  |   call writefile(lines, 'XTest_wildtrigger', 'D') | ||||||
|  |   let buf = RunVimInTerminal('-S XTest_wildtrigger', {'rows': 10}) | ||||||
|  |  | ||||||
|  |   call term_sendkeys(buf, ":TestCmd a\<F8>") | ||||||
|  |   call VerifyScreenDump(buf, 'Test_wildtrigger_update_screen_1', {}) | ||||||
|  |  | ||||||
|  |   " Typing a character when pum is open does not close the pum window | ||||||
|  |   " This is needed to prevent pum window from flickering during | ||||||
|  |   " ':h cmdline-autocompletion'. | ||||||
|  |   call term_sendkeys(buf, "x") | ||||||
|  |   call VerifyScreenDump(buf, 'Test_wildtrigger_update_screen_2', {}) | ||||||
|  |  | ||||||
|  |   " pum window is closed when no completion candidates are available | ||||||
|  |   call term_sendkeys(buf, "\<F8>") | ||||||
|  |   call VerifyScreenDump(buf, 'Test_wildtrigger_update_screen_3', {}) | ||||||
|  |  | ||||||
|  |   call term_sendkeys(buf, "\<esc>") | ||||||
|  |   call StopVimInTerminal(buf) | ||||||
|  |   cnoremap <buffer> <F8> <C-R>=wildtrigger()[-1]<CR> | ||||||
|  | endfunc | ||||||
|  |  | ||||||
| " vim: shiftwidth=2 sts=2 expandtab | " vim: shiftwidth=2 sts=2 expandtab | ||||||
|   | |||||||
| @@ -719,6 +719,8 @@ static char *(features[]) = | |||||||
|  |  | ||||||
| static int included_patches[] = | static int included_patches[] = | ||||||
| {   /* Add new patch number below this line */ | {   /* Add new patch number below this line */ | ||||||
|  | /**/ | ||||||
|  |     1621, | ||||||
| /**/ | /**/ | ||||||
|     1620, |     1620, | ||||||
| /**/ | /**/ | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user