# HG changeset patch # User Bram Moolenaar # Date 1571589004 -7200 # Node ID ba5d8c5d77d76d77e61ee8cb3ce3fe69c1fa52f1 # Parent dbfbbb32cf0782eb8ae1fc0f77e70a3e57e120d5 patch 8.1.2192: cannot easily fill the info popup asynchronously Commit: https://github.com/vim/vim/commit/dca7abe79cc4f0933473c3e4bcc75b46cc2c48fd Author: Bram Moolenaar Date: Sun Oct 20 18:17:57 2019 +0200 patch 8.1.2192: cannot easily fill the info popup asynchronously Problem: Cannot easily fill the info popup asynchronously. Solution: Add the "popuphidden" value to 'completeopt'. (closes https://github.com/vim/vim/issues/4924) diff --git a/runtime/doc/insert.txt b/runtime/doc/insert.txt --- a/runtime/doc/insert.txt +++ b/runtime/doc/insert.txt @@ -1,4 +1,4 @@ -*insert.txt* For Vim version 8.1. Last change: 2019 Sep 27 +*insert.txt* For Vim version 8.1. Last change: 2019 Oct 20 VIM REFERENCE MANUAL by Bram Moolenaar @@ -1138,6 +1138,27 @@ below the text, and the bottom of the me After the info popup is created it can be found with |popup_findinfo()| and properties can be changed with |popup_setoptions()|. + *complete-popuphidden* +If the information for the popup is obtained asynchronously, use "popuphidden" +in 'completeopt'. The info popup will then be initally hidden and +|popup_show()| must be called once it has been filled with the info. This can +be done with a |CompleteChanged| autocommand, something like this: > + set completeopt+=popuphidden + au CompleteChanged * call UpdateCompleteInfo() + func UpdateCompleteInfo() + " Cancel any pending info fetch + let item = v:event.completed_item + " Start fetching info for the item then call ShowCompleteInfo(info) + endfunc + func ShowCompleteInfo(info) + let id = popup_findinfo() + if id + call popup_settext(id, 'async info: ' .. a:info) + call popup_show(id) + endif + endfunc + +< *complete-item-kind* The "kind" item uses a single letter to indicate the kind of completion. This may be used to show the completion differently (different color or icon). Currently these types can be used: diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt --- a/runtime/doc/options.txt +++ b/runtime/doc/options.txt @@ -1,4 +1,4 @@ -*options.txt* For Vim version 8.1. Last change: 2019 Sep 28 +*options.txt* For Vim version 8.1. Last change: 2019 Oct 20 VIM REFERENCE MANUAL by Bram Moolenaar @@ -1919,6 +1919,13 @@ A jump table for the options with a shor See |'completepopup'| for specifying properties. {only works when compiled with the |+textprop| feature} + popuphidden + Just like "popup" but initially hide the popup. Use a + |CompleteChanged| autocommand to fetch the info and call + |popup_show()| once the popup has been filled. + See the example at |complete-popuphidden|. + {only works when compiled with the |+textprop| feature} + noinsert Do not insert any text for a match until the user selects a match from the menu. Only works in combination with "menu" or "menuone". No effect if "longest" is present. diff --git a/src/ex_cmds.c b/src/ex_cmds.c --- a/src/ex_cmds.c +++ b/src/ex_cmds.c @@ -4919,13 +4919,14 @@ free_old_sub(void) #if defined(FEAT_QUICKFIX) || defined(PROTO) /* * Set up for a tagpreview. + * Makes the preview window the current window. * Return TRUE when it was created. */ int prepare_tagpreview( int undo_sync, // sync undo when leaving the window int use_previewpopup, // use popup if 'previewpopup' set - int use_popup) // use other popup window + use_popup_T use_popup) // use other popup window { win_T *wp; @@ -4945,11 +4946,16 @@ prepare_tagpreview( if (wp != NULL) popup_set_wantpos_cursor(wp, wp->w_minwidth); } - else if (use_popup) + else if (use_popup != USEPOPUP_NONE) { wp = popup_find_info_window(); if (wp != NULL) - popup_show(wp); + { + if (use_popup == USEPOPUP_NORMAL) + popup_show(wp); + else + popup_hide(wp); + } } else # endif @@ -4966,8 +4972,9 @@ prepare_tagpreview( * There is no preview window open yet. Create one. */ # ifdef FEAT_TEXT_PROP - if ((use_previewpopup && *p_pvp != NUL) || use_popup) - return popup_create_preview_window(use_popup); + if ((use_previewpopup && *p_pvp != NUL) + || use_popup != USEPOPUP_NONE) + return popup_create_preview_window(use_popup != USEPOPUP_NONE); # endif if (win_split(g_do_tagpreview > 0 ? g_do_tagpreview : 0, 0) == FAIL) return FALSE; diff --git a/src/optionstr.c b/src/optionstr.c --- a/src/optionstr.c +++ b/src/optionstr.c @@ -76,7 +76,7 @@ static char *(p_fdm_values[]) = {"manual NULL}; static char *(p_fcl_values[]) = {"all", NULL}; #endif -static char *(p_cot_values[]) = {"menu", "menuone", "longest", "preview", "popup", "noinsert", "noselect", NULL}; +static char *(p_cot_values[]) = {"menu", "menuone", "longest", "preview", "popup", "popuphidden", "noinsert", "noselect", NULL}; #ifdef BACKSLASH_IN_FILENAME static char *(p_csl_values[]) = {"slash", "backslash", NULL}; #endif diff --git a/src/popupmenu.c b/src/popupmenu.c --- a/src/popupmenu.c +++ b/src/popupmenu.c @@ -622,33 +622,36 @@ pum_redraw(void) } #if defined(FEAT_TEXT_PROP) && defined(FEAT_QUICKFIX) - static void -pum_position_info_popup(void) +/* + * Position the info popup relative to the popup menu item. + */ + void +pum_position_info_popup(win_T *wp) { int col = pum_col + pum_width + 1; int row = pum_row; int botpos = POPPOS_BOTLEFT; - curwin->w_popup_pos = POPPOS_TOPLEFT; + wp->w_popup_pos = POPPOS_TOPLEFT; if (Columns - col < 20 && Columns - col < pum_col) { col = pum_col - 1; - curwin->w_popup_pos = POPPOS_TOPRIGHT; + wp->w_popup_pos = POPPOS_TOPRIGHT; botpos = POPPOS_BOTRIGHT; - curwin->w_maxwidth = pum_col - 1; + wp->w_maxwidth = pum_col - 1; } else - curwin->w_maxwidth = Columns - col + 1; - curwin->w_maxwidth -= popup_extra_width(curwin); + wp->w_maxwidth = Columns - col + 1; + wp->w_maxwidth -= popup_extra_width(wp); - row -= popup_top_extra(curwin); - if (curwin->w_popup_flags & POPF_INFO_MENU) + row -= popup_top_extra(wp); + if (wp->w_popup_flags & POPF_INFO_MENU) { if (pum_row < pum_win_row) { // menu above cursor line, align with bottom row += pum_height; - curwin->w_popup_pos = botpos; + wp->w_popup_pos = botpos; } else // menu below cursor line, align with top @@ -658,7 +661,7 @@ pum_position_info_popup(void) // align with the selected item row += pum_selected - pum_first + 1; - popup_set_wantpos_rowcol(curwin, row, col); + popup_set_wantpos_rowcol(wp, row, col); } #endif @@ -756,15 +759,21 @@ pum_set_selected(int n, int repeat UNUSE tabpage_T *curtab_save = curtab; int res = OK; # ifdef FEAT_TEXT_PROP - int use_popup = strstr((char *)p_cot, "popup") != NULL; + use_popup_T use_popup; # else -# define use_popup 0 +# define use_popup POPUP_NONE # endif # ifdef FEAT_TEXT_PROP has_info = TRUE; + if (strstr((char *)p_cot, "popuphidden") != NULL) + use_popup = USEPOPUP_HIDDEN; + else if (strstr((char *)p_cot, "popup") != NULL) + use_popup = USEPOPUP_NORMAL; + else + use_popup = USEPOPUP_NONE; # endif - // Open a preview window. 3 lines by default. Prefer - // 'previewheight' if set and smaller. + // Open a preview window and set "curwin" to it. + // 3 lines by default, prefer 'previewheight' if set and smaller. g_do_tagpreview = 3; if (p_pvh > 0 && p_pvh < g_do_tagpreview) g_do_tagpreview = p_pvh; @@ -838,7 +847,7 @@ pum_set_selected(int n, int repeat UNUSE /* Increase the height of the preview window to show the * text, but no more than 'previewheight' lines. */ - if (repeat == 0 && !use_popup) + if (repeat == 0 && use_popup == USEPOPUP_NONE) { if (lnum > p_pvh) lnum = p_pvh; @@ -863,9 +872,9 @@ pum_set_selected(int n, int repeat UNUSE curwin->w_cursor.lnum = curwin->w_topline; curwin->w_cursor.col = 0; # ifdef FEAT_TEXT_PROP - if (use_popup) + if (use_popup != USEPOPUP_NONE) { - pum_position_info_popup(); + pum_position_info_popup(curwin); if (win_valid(curwin_save)) redraw_win_later(curwin_save, SOME_VALID); } @@ -907,9 +916,16 @@ pum_set_selected(int n, int repeat UNUSE if (!resized && win_valid(curwin_save)) { +# ifdef FEAT_TEXT_PROP + win_T *wp = curwin; +# endif ++no_u_sync; win_enter(curwin_save, TRUE); --no_u_sync; +# ifdef FEAT_TEXT_PROP + if (use_popup == USEPOPUP_HIDDEN && win_valid(wp)) + popup_hide(wp); +# endif } /* May need to update the screen again when there are diff --git a/src/popupwin.c b/src/popupwin.c --- a/src/popupwin.c +++ b/src/popupwin.c @@ -2225,7 +2225,7 @@ f_popup_close(typval_T *argvars, typval_ popup_close_and_callback(wp, &argvars[1]); } - static void + void popup_hide(win_T *wp) { if ((wp->w_popup_flags & POPF_HIDDEN) == 0) @@ -2272,7 +2272,11 @@ f_popup_show(typval_T *argvars, typval_T win_T *wp = find_popup_win(id); if (wp != NULL) + { popup_show(wp); + if (wp->w_popup_flags & POPF_INFO) + pum_position_info_popup(wp); + } } /* diff --git a/src/proto/ex_cmds.pro b/src/proto/ex_cmds.pro --- a/src/proto/ex_cmds.pro +++ b/src/proto/ex_cmds.pro @@ -35,7 +35,7 @@ void global_exe(char_u *cmd); char_u *get_old_sub(void); void set_old_sub(char_u *val); void free_old_sub(void); -int prepare_tagpreview(int undo_sync, int use_previewpopup, int use_popup); +int prepare_tagpreview(int undo_sync, int use_previewpopup, use_popup_T use_popup); void ex_help(exarg_T *eap); void ex_helpclose(exarg_T *eap); char_u *check_help_lang(char_u *arg); diff --git a/src/proto/popupmenu.pro b/src/proto/popupmenu.pro --- a/src/proto/popupmenu.pro +++ b/src/proto/popupmenu.pro @@ -3,6 +3,7 @@ void pum_display(pumitem_T *array, int s void pum_call_update_screen(void); int pum_under_menu(int row, int col); void pum_redraw(void); +void pum_position_info_popup(win_T *wp); void pum_undisplay(void); void pum_clear(void); int pum_visible(void); diff --git a/src/proto/popupwin.pro b/src/proto/popupwin.pro --- a/src/proto/popupwin.pro +++ b/src/proto/popupwin.pro @@ -26,6 +26,7 @@ void f_popup_dialog(typval_T *argvars, t void f_popup_menu(typval_T *argvars, typval_T *rettv); void f_popup_notification(typval_T *argvars, typval_T *rettv); void f_popup_close(typval_T *argvars, typval_T *rettv); +void popup_hide(win_T *wp); void f_popup_hide(typval_T *argvars, typval_T *rettv); void popup_show(win_T *wp); void f_popup_show(typval_T *argvars, typval_T *rettv); diff --git a/src/testdir/dumps/Test_popupwin_infopopup_hidden_1.dump b/src/testdir/dumps/Test_popupwin_infopopup_hidden_1.dump new file mode 100644 --- /dev/null +++ b/src/testdir/dumps/Test_popupwin_infopopup_hidden_1.dump @@ -0,0 +1,14 @@ +|t+0&#ffffff0|e|x|t| |t|e|x|t| |t|e|x|t| |t|e|x|t| |t|e|x|t| |t|a|w|o|r|d> @43 +|~+0#4040ff13&| @23| +0#0000001#e0e0e08|w|r|d| @4|W| |e|x|t|r|a| |t|e|x|t| | +0#4040ff13#ffffff0@27 +|~| @23| +0#0000001#ffd7ff255|a|n|o|t|w|r|d| |W| |e|x|t|r|a| |t|e|x|t| | +0#4040ff13#ffffff0@27 +|~| @23| +0#0000001#ffd7ff255|n|o|a|w|r|d| @1|W| |e|x|t|r|a| |t|e|x|t| | +0#4040ff13#ffffff0@27 +|~| @23| +0#0000001#ffd7ff255|t|h|a|t|w|r|d| |W| |e|x|t|r|a| |t|e|x|t| | +0#4040ff13#ffffff0@27 +|~| @73 +|~| @73 +|~| @73 +|~| @73 +|~| @73 +|~| @73 +|~| @73 +|~| @73 +|-+2#0000000&@1| |U|s|e|r| |d|e|f|i|n|e|d| |c|o|m|p|l|e|t|i|o|n| |(|^|U|^|N|^|P|)| |m+0#00e0003&|a|t|c|h| |1| |o|f| |4| +0#0000000&@26 diff --git a/src/testdir/dumps/Test_popupwin_infopopup_hidden_2.dump b/src/testdir/dumps/Test_popupwin_infopopup_hidden_2.dump new file mode 100644 --- /dev/null +++ b/src/testdir/dumps/Test_popupwin_infopopup_hidden_2.dump @@ -0,0 +1,14 @@ +|t+0&#ffffff0|e|x|t| |t|e|x|t| |t|e|x|t| |t|e|x|t| |t|e|x|t| |t|a|n|o|t|h|e|r|w|o|r|d> @37 +|~+0#4040ff13&| @23| +0#0000001#ffd7ff255|w|r|d| @4|W| |e|x|t|r|a| |t|e|x|t| | +0&#e0e0e08|i|m@1|e|d|i|a|t|e| |i|n|f|o| |3| | +0#4040ff13#ffffff0@9 +|~| @23| +0#0000001#e0e0e08|a|n|o|t|w|r|d| |W| |e|x|t|r|a| |t|e|x|t| | +0#4040ff13#ffffff0@27 +|~| @23| +0#0000001#ffd7ff255|n|o|a|w|r|d| @1|W| |e|x|t|r|a| |t|e|x|t| | +0#4040ff13#ffffff0@27 +|~| @23| +0#0000001#ffd7ff255|t|h|a|t|w|r|d| |W| |e|x|t|r|a| |t|e|x|t| | +0#4040ff13#ffffff0@27 +|~| @73 +|~| @73 +|~| @73 +|~| @73 +|~| @73 +|~| @73 +|~| @73 +|~| @73 +|-+2#0000000&@1| |U|s|e|r| |d|e|f|i|n|e|d| |c|o|m|p|l|e|t|i|o|n| |(|^|U|^|N|^|P|)| |m+0#00e0003&|a|t|c|h| |2| |o|f| |4| +0#0000000&@26 diff --git a/src/testdir/dumps/Test_popupwin_infopopup_hidden_3.dump b/src/testdir/dumps/Test_popupwin_infopopup_hidden_3.dump new file mode 100644 --- /dev/null +++ b/src/testdir/dumps/Test_popupwin_infopopup_hidden_3.dump @@ -0,0 +1,14 @@ +|t+0&#ffffff0|e|x|t| |t|e|x|t| |t|e|x|t| |t|e|x|t| |t|e|x|t| |t|n|o|i|n|f|o> @42 +|~+0#4040ff13&| @23| +0#0000001#ffd7ff255|w|r|d| @4|W| |e|x|t|r|a| |t|e|x|t| | +0&#e0e0e08|a|s|y|n|c| |i|n|f|o| |4| | +0#4040ff13#ffffff0@13 +|~| @23| +0#0000001#ffd7ff255|a|n|o|t|w|r|d| |W| |e|x|t|r|a| |t|e|x|t| | +0#4040ff13#ffffff0@27 +|~| @23| +0#0000001#e0e0e08|n|o|a|w|r|d| @1|W| |e|x|t|r|a| |t|e|x|t| | +0#4040ff13#ffffff0@27 +|~| @23| +0#0000001#ffd7ff255|t|h|a|t|w|r|d| |W| |e|x|t|r|a| |t|e|x|t| | +0#4040ff13#ffffff0@27 +|~| @73 +|~| @73 +|~| @73 +|~| @73 +|~| @73 +|~| @73 +|~| @73 +|~| @73 +|-+2#0000000&@1| |U|s|e|r| |d|e|f|i|n|e|d| |c|o|m|p|l|e|t|i|o|n| |(|^|U|^|N|^|P|)| |m+0#00e0003&|a|t|c|h| |3| |o|f| |4| +0#0000000&@26 diff --git a/src/testdir/test_popupwin.vim b/src/testdir/test_popupwin.vim --- a/src/testdir/test_popupwin.vim +++ b/src/testdir/test_popupwin.vim @@ -2498,6 +2498,41 @@ func Get_popupmenu_lines() let id = popup_findinfo() eval id->popup_setoptions(#{highlight: 'InfoPopup'}) endfunc + + func InfoHidden() + set completepopup=height:4,border:off,align:menu + set completeopt-=popup completeopt+=popuphidden + au CompleteChanged * call HandleChange() + endfunc + + let s:counter = 0 + func HandleChange() + let s:counter += 1 + let selected = complete_info(['selected']).selected + if selected <= 0 + " First time: do nothing, info remains hidden + return + endif + if selected == 1 + " Second time: show info right away + let id = popup_findinfo() + if id + call popup_settext(id, 'immediate info ' .. s:counter) + call popup_show(id) + endif + else + " Third time: show info after a short delay + call timer_start(100, 'ShowInfo') + endif + endfunc + + func ShowInfo(...) + let id = popup_findinfo() + if id + call popup_settext(id, 'async info ' .. s:counter) + call popup_show(id) + endif + endfunc END return lines endfunc @@ -2580,6 +2615,30 @@ func Test_popupmenu_info_align_menu() call delete('XtestInfoPopupNb') endfunc +func Test_popupmenu_info_hidden() + CheckScreendump + + let lines = Get_popupmenu_lines() + call add(lines, 'call InfoHidden()') + call writefile(lines, 'XtestInfoPopupHidden') + + let buf = RunVimInTerminal('-S XtestInfoPopupHidden', #{rows: 14}) + call term_wait(buf, 50) + + call term_sendkeys(buf, "A\\") + call VerifyScreenDump(buf, 'Test_popupwin_infopopup_hidden_1', {}) + + call term_sendkeys(buf, "\") + call VerifyScreenDump(buf, 'Test_popupwin_infopopup_hidden_2', {}) + + call term_sendkeys(buf, "\") + call VerifyScreenDump(buf, 'Test_popupwin_infopopup_hidden_3', {}) + + call term_sendkeys(buf, "\") + call StopVimInTerminal(buf) + call delete('XtestInfoPopupHidden') +endfunc + func Test_popupwin_recycle_bnr() let bufnr = popup_notification('nothing wrong', {})->winbufnr() call popup_clear() diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -742,6 +742,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 2192, +/**/ 2191, /**/ 2190, diff --git a/src/vim.h b/src/vim.h --- a/src/vim.h +++ b/src/vim.h @@ -2112,6 +2112,13 @@ typedef enum { FLUSH_INPUT // flush typebuf and inchar() input } flush_buffers_T; +// Argument for prepare_tagpreview() +typedef enum { + USEPOPUP_NONE, + USEPOPUP_NORMAL, // use info popup + USEPOPUP_HIDDEN // use info popup initially hidden +} use_popup_T; + #include "ex_cmds.h" // Ex command defines #include "spell.h" // spell checking stuff