# HG changeset patch # User Bram Moolenaar # Date 1547756106 -3600 # Node ID 6d949e552e993d415b823d738cf79fcc2197b56a # Parent f356d2eb8202c47d80b5c8fb3c64529b2b916cb0 patch 8.1.0768: updating completions may cause the popup menu to flicker commit https://github.com/vim/vim/commit/ae654385dfb2ae4c1d70789d1dce3676dba4dfbc Author: Bram Moolenaar Date: Thu Jan 17 21:09:05 2019 +0100 patch 8.1.0768: updating completions may cause the popup menu to flicker Problem: Updating completions may cause the popup menu to flicker. Solution: Avoid updating the text below the popup menu before drawing the popup menu. diff --git a/src/edit.c b/src/edit.c --- a/src/edit.c +++ b/src/edit.c @@ -3020,7 +3020,8 @@ ins_compl_upd_pum(void) if (compl_match_array != NULL) { h = curwin->w_cline_height; - update_screen(0); + // Update the screen later, before drawing the popup menu over it. + pum_call_update_screen(); if (h != curwin->w_cline_height) ins_compl_del_pum(); } @@ -3110,8 +3111,8 @@ ins_compl_show_pum(void) do_cmdline_cmd((char_u *)"if exists('g:loaded_matchparen')|3match none|endif"); #endif - /* Update the screen before drawing the popup menu over it. */ - update_screen(0); + // Update the screen later, before drawing the popup menu over it. + pum_call_update_screen(); if (compl_match_array == NULL) { @@ -3668,11 +3669,11 @@ ins_compl_new_leader(void) spell_bad_len = 0; /* need to redetect bad word */ #endif /* - * Matches were cleared, need to search for them now. First display - * the changed text before the cursor. Set "compl_restarting" to - * avoid that the first match is inserted. + * Matches were cleared, need to search for them now. Befor drawing + * the popup menu display the changed text before the cursor. Set + * "compl_restarting" to avoid that the first match is inserted. */ - update_screen(0); + pum_call_update_screen(); #ifdef FEAT_GUI if (gui.in_use) { @@ -5077,8 +5078,9 @@ ins_compl_next( /* may undisplay the popup menu first */ ins_compl_upd_pum(); - /* redraw to show the user what was inserted */ - update_screen(0); + // Redraw before showing the popup menu to show the user what was + // inserted. + pum_call_update_screen(); /* display the updated popup menu */ ins_compl_show_pum(); diff --git a/src/popupmnu.c b/src/popupmnu.c --- a/src/popupmnu.c +++ b/src/popupmnu.c @@ -19,6 +19,8 @@ static int pum_size; /* nr of items in static int pum_selected; /* index of selected item or -1 */ static int pum_first = 0; /* index of top item */ +static int call_update_screen = FALSE; + static int pum_height; /* nr of displayed pum items */ static int pum_width; /* width of displayed pum items */ static int pum_base_width; /* width of pum items base */ @@ -36,7 +38,8 @@ static int pum_win_col; static int pum_win_wcol; static int pum_win_width; -static int pum_do_redraw = FALSE; /* do redraw anyway */ +static int pum_do_redraw = FALSE; // do redraw anyway +static int pum_skip_redraw = FALSE; // skip redraw static int pum_set_selected(int n, int repeat); @@ -354,6 +357,36 @@ pum_display( } /* + * Set a flag that when pum_redraw() is called it first calls update_screen(). + * This will avoid clearing and redrawing the popup menu, prevent flicker. + */ + void +pum_call_update_screen() +{ + call_update_screen = TRUE; + + // Update the cursor position to be able to compute the popup menu + // position. The cursor line length may have changed because of the + // inserted completion. + curwin->w_valid &= VALID_CROW|VALID_CHEIGHT; + validate_cursor(); +} + +/* + * Return TRUE if we are going to redraw the popup menu and the screen position + * "row"/"col" is under the popup menu. + */ + int +pum_under_menu(int row, int col) +{ + return pum_skip_redraw + && row >= pum_row + && row < pum_row + pum_height + && col >= pum_col - 1 + && col < pum_col + pum_width; +} + +/* * Redraw the popup menu, using "pum_first" and "pum_selected". */ void @@ -376,7 +409,15 @@ pum_redraw(void) int round; int n; - /* Never display more than we have */ + if (call_update_screen) + { + call_update_screen = FALSE; + pum_skip_redraw = TRUE; // do not redraw in pum_may_redraw(). + update_screen(0); + pum_skip_redraw = FALSE; + } + + // never display more than we have if (pum_first > pum_size - pum_height) pum_first = pum_size - pum_height; @@ -789,6 +830,7 @@ pum_set_selected(int n, int repeat) pum_do_redraw = TRUE; update_screen(0); pum_do_redraw = FALSE; + call_update_screen = FALSE; } } } @@ -844,7 +886,7 @@ pum_may_redraw(void) int len = pum_size; int selected = pum_selected; - if (!pum_visible()) + if (!pum_visible() || pum_skip_redraw) return; // nothing to do if (pum_window != curwin diff --git a/src/proto/popupmnu.pro b/src/proto/popupmnu.pro --- a/src/proto/popupmnu.pro +++ b/src/proto/popupmnu.pro @@ -1,5 +1,7 @@ /* popupmnu.c */ void pum_display(pumitem_T *array, int size, int selected); +void pum_call_update_screen(void); +int pum_under_menu(int row, int col); void pum_redraw(void); void pum_undisplay(void); void pum_clear(void); diff --git a/src/screen.c b/src/screen.c --- a/src/screen.c +++ b/src/screen.c @@ -183,7 +183,7 @@ static int screen_char_attr = 0; /* * Redraw the current window later, with update_screen(type). * Set must_redraw only if not already set to a higher value. - * e.g. if must_redraw is CLEAR, type NOT_VALID will do nothing. + * E.g. if must_redraw is CLEAR, type NOT_VALID will do nothing. */ void redraw_later(int type) @@ -8475,6 +8475,10 @@ screen_char(unsigned off, int row, int c if (row >= screen_Rows || col >= screen_Columns) return; +#ifdef FEAT_INS_EXPAND + if (pum_under_menu(row, col)) + return; +#endif /* Outputting a character in the last cell on the screen may scroll the * screen up. Only do it when the "xn" termcap property is set, otherwise * mark the character invalid (update it when scrolled up). */ diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -792,6 +792,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 768, +/**/ 767, /**/ 766,