From be8ebba325451b387c0aedacfcda6c53e6c51188 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Linse?= Date: Mon, 4 Mar 2019 10:59:44 +0100 Subject: [PATCH] Allow using internal popupmenu or ext_popupmenu for wildmenu Deprecate ext_wildmenu. ext_popupmenu already contains more state (anchor position), and will allow further expansion (info about items). --- runtime/doc/options.txt | 3 +- runtime/doc/ui.txt | 18 +- runtime/doc/vim_diff.txt | 1 + src/nvim/api/ui.c | 36 ++++ src/nvim/api/ui_events.in.h | 6 +- src/nvim/edit.c | 2 +- src/nvim/ex_docmd.c | 2 +- src/nvim/ex_getln.c | 65 +++++-- src/nvim/mbyte.c | 18 ++ src/nvim/option.c | 9 +- src/nvim/option_defs.h | 6 + src/nvim/options.lua | 2 +- src/nvim/popupmnu.c | 36 ++-- src/nvim/screen.c | 4 + test/functional/ui/cmdline_spec.lua | 131 +++++++++++++ test/functional/ui/float_spec.lua | 8 +- test/functional/ui/messages_spec.lua | 6 +- test/functional/ui/popupmenu_spec.lua | 264 ++++++++++++++++++++++++-- test/functional/ui/screen.lua | 5 +- 19 files changed, 553 insertions(+), 69 deletions(-) diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt index 505c0c5ea0..7bb9ae68bc 100644 --- a/runtime/doc/options.txt +++ b/runtime/doc/options.txt @@ -6599,12 +6599,13 @@ A jump table for the options with a short description can be found at |Q_op|. 'wildoptions' 'wop' string (default "") global A list of words that change how command line completion is done. - Currently only one word is allowed: tagfile When using CTRL-D to list matching tags, the kind of tag and the file of the tag is listed. Only one match is displayed per line. Often used tag kinds are: d #define f function + pum Display the completion matches using the popupmenu + in the same style as the |ins-completion-menu|. Also see |cmdline-completion|. *'winaltkeys'* *'wak'* diff --git a/runtime/doc/ui.txt b/runtime/doc/ui.txt index 270c4fb556..6976efe60a 100644 --- a/runtime/doc/ui.txt +++ b/runtime/doc/ui.txt @@ -31,7 +31,7 @@ a dictionary with these (optional) keys: `ext_popupmenu` Externalize the popupmenu. |ui-popupmenu| `ext_tabline` Externalize the tabline. |ui-tabline| `ext_cmdline` Externalize the cmdline. |ui-cmdline| - `ext_wildmenu` Externalize the wildmenu. |ui-wildmenu| + `ext_wildmenu` Externalize the wildmenu (deprecated). |ui-wildmenu| `ext_messages` Externalize messages. |ui-messages| `ext_linegrid` Use new revision of the grid events. |ui-linegrid| `ext_multigrid` Use per-window grid based events. |ui-multigrid| @@ -554,7 +554,7 @@ See |nvim_input_mouse| for sending mouse events to Nvim. ============================================================================== Popupmenu Events *ui-popupmenu* -Only sent if `ext_popupmenu` option is set in |ui-options| +Only sent if `ext_popupmenu` option is set in |ui-options|. ["popupmenu_show", items, selected, row, col, grid] Show |popupmenu-completion|. `items` is an array of completion items @@ -564,7 +564,9 @@ Only sent if `ext_popupmenu` option is set in |ui-options| index into the array of items (-1 if no item is selected). `row` and `col` give the anchor position, where the first character of the completed word will be. When |ui-multigrid| is used, `grid` is the - grid for the anchor position. + grid for the anchor position. When `ext_cmdline` is active, `grid` is + set to -1 to indicate the popupmenu should be anchored to the external + cmdline. Then `col` will be a byte position in the cmdline text. ["popupmenu_select", selected] Select an item in the current popupmenu. `selected` is a zero-based @@ -588,7 +590,10 @@ Only sent if `ext_tabline` option is set in |ui-options| ============================================================================== Cmdline Events *ui-cmdline* -Only sent if `ext_cmdline` option is set in |ui-options|. +Only sent if `ext_cmdline` option is set in |ui-options|. To handle +command-line completion (wildmenu), use |ui-popupmenu| events activated by +|ext_popupmenu| option. (The `ext_wildmenu` option only exists for backwards +compatibility). ["cmdline_show", content, pos, firstc, prompt, indent, level] content: List of [attrs, string] @@ -648,6 +653,11 @@ Wildmenu Events *ui-wildmenu* Only sent if `ext_wildmenu` option is set in |ui-options| +Deprecated. When `ext_cmdline` and `ext_popupmenu` are both set, +|ui-popupmenu| events will be used for command-line completion. But if +`ext_wildmenu` is also set, these events are still used for backwards +compatibility. New clients should use `ext_popupmenu` instead. + ["wildmenu_show", items] Activate the wildmenu (command-line completion). `items` is an array with the completion items. diff --git a/runtime/doc/vim_diff.txt b/runtime/doc/vim_diff.txt index 55c3be9a57..d3ac0ba613 100644 --- a/runtime/doc/vim_diff.txt +++ b/runtime/doc/vim_diff.txt @@ -195,6 +195,7 @@ Options: 'scrollback' 'statusline' supports unlimited alignment sections 'tabline' %@Func@foo%X can call any function on mouse-click + 'wildoptions' `pum` flag to use popupmenu for wildmode completion 'winhighlight' window-local highlights Variables: diff --git a/src/nvim/api/ui.c b/src/nvim/api/ui.c index d3cbb46dad..93502d7306 100644 --- a/src/nvim/api/ui.c +++ b/src/nvim/api/ui.c @@ -34,6 +34,7 @@ typedef struct { // Position of legacy cursor, used both for drawing and visible user cursor. Integer client_row, client_col; + bool wildmenu_active; } UIData; static PMap(uint64_t) *connected_uis = NULL; @@ -146,6 +147,7 @@ void nvim_ui_attach(uint64_t channel_id, Integer width, Integer height, data->buffer = (Array)ARRAY_DICT_INIT; data->hl_id = 0; data->client_col = -1; + data->wildmenu_active = false; ui->data = data; pmap_put(uint64_t)(connected_uis, channel_id, ui); @@ -586,6 +588,7 @@ static Array translate_firstarg(UI *ui, Array args) static void remote_ui_event(UI *ui, char *name, Array args, bool *args_consumed) { + UIData *data = ui->data; if (!ui->ui_ext[kUILinegrid]) { // the representation of highlights in cmdline changed, translate back // never consumes args @@ -611,6 +614,39 @@ static void remote_ui_event(UI *ui, char *name, Array args, bool *args_consumed) } } + // Back-compat: translate popupmenu_xx to legacy wildmenu_xx. + if (ui->ui_ext[kUIWildmenu]) { + if (strequal(name, "popupmenu_show")) { + data->wildmenu_active = (args.items[4].data.integer == -1) + || !ui->ui_ext[kUIPopupmenu]; + if (data->wildmenu_active) { + Array new_args = ARRAY_DICT_INIT; + Array items = args.items[0].data.array; + Array new_items = ARRAY_DICT_INIT; + for (size_t i = 0; i < items.size; i++) { + ADD(new_items, copy_object(items.items[i].data.array.items[0])); + } + ADD(new_args, ARRAY_OBJ(new_items)); + push_call(ui, "wildmenu_show", new_args); + if (args.items[1].data.integer != -1) { + Array new_args2 = ARRAY_DICT_INIT; + ADD(new_args2, args.items[1]); + push_call(ui, "wildmenu_select", new_args); + } + return; + } + } else if (strequal(name, "popupmenu_select")) { + if (data->wildmenu_active) { + name = "wildmenu_select"; + } + } else if (strequal(name, "popupmenu_hide")) { + if (data->wildmenu_active) { + name = "wildmenu_hide"; + } + } + } + + Array my_args = ARRAY_DICT_INIT; // Objects are currently single-reference // make a copy, but only if necessary diff --git a/src/nvim/api/ui_events.in.h b/src/nvim/api/ui_events.in.h index b89c5b6014..a1d25766fe 100644 --- a/src/nvim/api/ui_events.in.h +++ b/src/nvim/api/ui_events.in.h @@ -143,11 +143,11 @@ void cmdline_block_hide(void) FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY; void wildmenu_show(Array items) - FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY; + FUNC_API_SINCE(3) FUNC_API_REMOTE_IMPL FUNC_API_BRIDGE_IMPL; void wildmenu_select(Integer selected) - FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY; + FUNC_API_SINCE(3) FUNC_API_REMOTE_IMPL FUNC_API_BRIDGE_IMPL; void wildmenu_hide(void) - FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY; + FUNC_API_SINCE(3) FUNC_API_REMOTE_IMPL FUNC_API_BRIDGE_IMPL; void msg_show(String kind, Array content, Boolean replace_last) FUNC_API_SINCE(6) FUNC_API_REMOTE_ONLY; diff --git a/src/nvim/edit.c b/src/nvim/edit.c index f6b5a01915..c8d98bce3b 100644 --- a/src/nvim/edit.c +++ b/src/nvim/edit.c @@ -2656,7 +2656,7 @@ void ins_compl_show_pum(void) col = curwin->w_cursor.col; curwin->w_cursor.col = compl_col; pum_selected_item = cur; - pum_display(compl_match_array, compl_match_arraysize, cur, array_changed); + pum_display(compl_match_array, compl_match_arraysize, cur, array_changed, 0); curwin->w_cursor.col = col; if (!has_event(EVENT_MENUPOPUPCHANGED)) { diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index 5b9b4fed12..3467bc8b92 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -3235,7 +3235,7 @@ const char * set_one_cmd_context( case CMD_tjump: case CMD_stjump: case CMD_ptjump: - if (*p_wop != NUL) { + if (wop_flags & WOP_TAGFILE) { xp->xp_context = EXPAND_TAGS_LISTFILES; } else { xp->xp_context = EXPAND_TAGS; diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c index 8e6fc5ad4f..2dbd6375f1 100644 --- a/src/nvim/ex_getln.c +++ b/src/nvim/ex_getln.c @@ -214,6 +214,15 @@ static int hislen = 0; /* actual length of history tables */ /// user interrupting highlight function to not interrupt command-line. static bool getln_interrupted_highlight = false; +// "compl_match_array" points the currently displayed list of entries in the +// popup menu. It is NULL when there is no popup menu. +static pumitem_T *compl_match_array = NULL; +static int compl_match_arraysize; +// First column in cmdline of the matched item for completion. +static int compl_startcol; +static int compl_selected; + + #ifdef INCLUDE_GENERATED_DECLARATIONS # include "ex_getln.c.generated.h" @@ -600,6 +609,13 @@ static int command_line_execute(VimState *state, int key) } else if (s->c == K_RIGHT) { s->c = Ctrl_N; } + if (compl_match_array) { + if (s->c == K_UP) { + s->c = Ctrl_P; + } else if (s->c == K_DOWN) { + s->c = Ctrl_N; + } + } } // Hitting CR after "emenu Name.": complete submenu @@ -615,8 +631,10 @@ static int command_line_execute(VimState *state, int key) if (!(s->c == p_wc && KeyTyped) && s->c != p_wcm && s->c != Ctrl_N && s->c != Ctrl_P && s->c != Ctrl_A && s->c != Ctrl_L) { - if (ui_has(kUIWildmenu)) { - ui_call_wildmenu_hide(); + if (compl_match_array) { + pum_undisplay(true); + xfree(compl_match_array); + compl_match_array = NULL; } if (s->xpc.xp_numfiles != -1) { (void)ExpandOne(&s->xpc, NULL, NULL, 0, WILD_FREE); @@ -3746,13 +3764,12 @@ ExpandOne ( else findex = -1; } - if (p_wmnu) { - if (ui_has(kUIWildmenu)) { - ui_call_wildmenu_select(findex); - } else { - win_redr_status_matches(xp, xp->xp_numfiles, xp->xp_files, - findex, cmd_showtail); - } + if (compl_match_array) { + compl_selected = findex; + cmdline_pum_display(false); + } else if (p_wmnu) { + win_redr_status_matches(xp, xp->xp_numfiles, xp->xp_files, + findex, cmd_showtail); } if (findex == -1) { return vim_strsave(orig_save); @@ -4069,6 +4086,12 @@ void tilde_replace(char_u *orig_pat, int num_files, char_u **files) } } +void cmdline_pum_display(bool changed_array) +{ + pum_display(compl_match_array, compl_match_arraysize, compl_selected, + changed_array, compl_startcol); +} + /* * Show all matches for completion on the command line. * Returns EXPAND_NOTHING when the character that triggered expansion should @@ -4102,12 +4125,28 @@ static int showmatches(expand_T *xp, int wildmenu) showtail = cmd_showtail; } - if (ui_has(kUIWildmenu)) { - Array args = ARRAY_DICT_INIT; + bool compl_use_pum = (ui_has(kUICmdline) + ? ui_has(kUIPopupmenu) + : wildmenu && (wop_flags & WOP_PUM)) + || ui_has(kUIWildmenu); + + if (compl_use_pum) { + compl_match_arraysize = num_files; + compl_match_array = xcalloc(compl_match_arraysize, sizeof(pumitem_T)); for (i = 0; i < num_files; i++) { - ADD(args, STRING_OBJ(cstr_to_string((char *)files_found[i]))); + compl_match_array[i].pum_text = L_SHOWFILE(i); } - ui_call_wildmenu_show(args); + ssize_t offset = showtail ? sm_gettail(xp->xp_pattern)-xp->xp_pattern : 0; + if (ui_has(kUICmdline)) { + compl_startcol = ccline.cmdpos - strnlen((char *)xp->xp_pattern+offset, + xp->xp_pattern_len-offset); + } else { + compl_startcol = ccline.cmdspos + - mb_string2cells_len(xp->xp_pattern+offset, + xp->xp_pattern_len-offset); + } + compl_selected = -1; + cmdline_pum_display(true); return EXPAND_OK; } diff --git a/src/nvim/mbyte.c b/src/nvim/mbyte.c index 5ed2b4c564..6c34cacb8d 100644 --- a/src/nvim/mbyte.c +++ b/src/nvim/mbyte.c @@ -555,6 +555,24 @@ size_t mb_string2cells(const char_u *str) return clen; } +/// Get the number of cells occupied by string `str` with maximum length `size` +/// +/// @param str The source string, may not be NULL, must be a NUL-terminated +/// string. +/// @param size maximum length of string. It will terminate on earlier NUL. +/// @return The number of cells occupied by string `str` +size_t mb_string2cells_len(const char_u *str, size_t size) +{ + size_t clen = 0; + + for (const char_u *p = str; *p != NUL && p < str+size; + p += utf_ptr2len_len(p, size+(p-str))) { + clen += utf_ptr2cells(p); + } + + return clen; +} + /// Convert a UTF-8 byte sequence to a wide character /// /// If the sequence is illegal or truncated by a NUL then the first byte is diff --git a/src/nvim/option.c b/src/nvim/option.c index 2346c84b54..ad0ccd9f15 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -284,7 +284,6 @@ static char *(p_ambw_values[]) = { "single", "double", NULL }; static char *(p_bg_values[]) = { "light", "dark", NULL }; static char *(p_nf_values[]) = { "bin", "octal", "hex", "alpha", NULL }; static char *(p_ff_values[]) = { FF_UNIX, FF_DOS, FF_MAC, NULL }; -static char *(p_wop_values[]) = { "tagfile", NULL }; static char *(p_wak_values[]) = { "yes", "menu", "no", NULL }; static char *(p_mousem_values[]) = { "extend", "popup", "popup_setpos", "mac", NULL }; @@ -2608,11 +2607,11 @@ ambw_end: else if (varp == &p_wim) { if (check_opt_wim() == FAIL) errmsg = e_invarg; - } - /* 'wildoptions' */ - else if (varp == &p_wop) { - if (check_opt_strings(p_wop, p_wop_values, TRUE) != OK) + // 'wildoptions' + } else if (varp == &p_wop) { + if (opt_strings_flags(p_wop, p_wop_values, &wop_flags, true) != OK) { errmsg = e_invarg; + } } /* 'winaltkeys' */ else if (varp == &p_wak) { diff --git a/src/nvim/option_defs.h b/src/nvim/option_defs.h index 74047e7cef..c71ce9175b 100644 --- a/src/nvim/option_defs.h +++ b/src/nvim/option_defs.h @@ -659,6 +659,12 @@ extern char_u *p_vfile; /* 'verbosefile' */ #endif EXTERN int p_warn; // 'warn' EXTERN char_u *p_wop; // 'wildoptions' +EXTERN unsigned wop_flags; +# ifdef IN_OPTION_C +static char *(p_wop_values[]) = { "tagfile", "pum", NULL }; +#endif +#define WOP_TAGFILE 0x01 +#define WOP_PUM 0x02 EXTERN long p_window; // 'window' EXTERN char_u *p_wak; // 'winaltkeys' EXTERN char_u *p_wig; // 'wildignore' diff --git a/src/nvim/options.lua b/src/nvim/options.lua index 2398f9d61c..81133ae15c 100644 --- a/src/nvim/options.lua +++ b/src/nvim/options.lua @@ -2699,7 +2699,7 @@ return { }, { full_name='wildoptions', abbreviation='wop', - type='string', scope={'global'}, + type='string', list='onecomma', scope={'global'}, vi_def=true, varname='p_wop', defaults={if_true={vi=""}} diff --git a/src/nvim/popupmnu.c b/src/nvim/popupmnu.c index e9b3f04454..8cf09b14d7 100644 --- a/src/nvim/popupmnu.c +++ b/src/nvim/popupmnu.c @@ -66,7 +66,9 @@ static bool pum_invalid = false; // the screen was just cleared /// @param array_changed if true, array contains different items since last call /// if false, a new item is selected, but the array /// is the same -void pum_display(pumitem_T *array, int size, int selected, bool array_changed) +/// @param cmd_startcol only for cmdline mode: column of completed match +void pum_display(pumitem_T *array, int size, int selected, bool array_changed, + int cmd_startcol) { int w; int def_width; @@ -84,7 +86,8 @@ void pum_display(pumitem_T *array, int size, int selected, bool array_changed) if (!pum_is_visible) { // To keep the code simple, we only allow changing the // draw mode when the popup menu is not being displayed - pum_external = ui_has(kUIPopupmenu); + pum_external = ui_has(kUIPopupmenu) + || (State == CMDLINE && ui_has(kUIWildmenu)); } do { @@ -96,19 +99,26 @@ void pum_display(pumitem_T *array, int size, int selected, bool array_changed) above_row = 0; below_row = cmdline_row; - // anchor position: the start of the completed word - row = curwin->w_wrow; - if (curwin->w_p_rl) { - col = curwin->w_width - curwin->w_wcol - 1; + // wildoptions=pum + if (State == CMDLINE) { + row = ui_has(kUICmdline) ? 0 : cmdline_row; + col = cmd_startcol; + pum_anchor_grid = ui_has(kUICmdline) ? -1 : DEFAULT_GRID_HANDLE; } else { - col = curwin->w_wcol; - } + // anchor position: the start of the completed word + row = curwin->w_wrow; + if (curwin->w_p_rl) { + col = curwin->w_width - curwin->w_wcol - 1; + } else { + col = curwin->w_wcol; + } - pum_anchor_grid = (int)curwin->w_grid.handle; - if (!ui_has(kUIMultigrid)) { - pum_anchor_grid = (int)default_grid.handle; - row += curwin->w_winrow; - col += curwin->w_wincol; + pum_anchor_grid = (int)curwin->w_grid.handle; + if (!ui_has(kUIMultigrid)) { + pum_anchor_grid = (int)default_grid.handle; + row += curwin->w_winrow; + col += curwin->w_wincol; + } } if (pum_external) { diff --git a/src/nvim/screen.c b/src/nvim/screen.c index 5255fd2a51..32371b8aba 100644 --- a/src/nvim/screen.c +++ b/src/nvim/screen.c @@ -7151,8 +7151,12 @@ void screen_resize(int width, int height) if (curwin->w_p_scb) do_check_scrollbind(TRUE); if (State & CMDLINE) { + redraw_popupmenu = false; update_screen(NOT_VALID); redrawcmdline(); + if (pum_drawn()) { + cmdline_pum_display(false); + } } else { update_topline(); if (pum_drawn()) { diff --git a/test/functional/ui/cmdline_spec.lua b/test/functional/ui/cmdline_spec.lua index 5d112d7f35..16be846647 100644 --- a/test/functional/ui/cmdline_spec.lua +++ b/test/functional/ui/cmdline_spec.lua @@ -600,6 +600,137 @@ local function test_cmdline(linegrid) pos = 12, }}} end) + + it('works together with ext_popupmenu', function() + local expected = { + {'define', '', '', ''}, + {'jump', '', '', ''}, + {'list', '', '', ''}, + {'place', '', '', ''}, + {'undefine', '', '', ''}, + {'unplace', '', '', ''}, + } + + command('set wildmode=full') + command('set wildmenu') + screen:set_option('ext_popupmenu', true) + feed(':sign ') + + screen:expect{grid=[[ + ^ | + {1:~ }| + {1:~ }| + {1:~ }| + | + ]], cmdline={{ + firstc = ":", + content = {{"sign define"}}, + pos = 11, + }}, popupmenu={items=expected, pos=0, anchor={-1, 0, 5}}} + + feed('') + screen:expect{grid=[[ + ^ | + {1:~ }| + {1:~ }| + {1:~ }| + | + ]], cmdline={{ + firstc = ":", + content = {{"sign jump"}}, + pos = 9, + }}, popupmenu={items=expected, pos=1, anchor={-1, 0, 5}}} + + feed('') + screen:expect{grid=[[ + ^ | + {1:~ }| + {1:~ }| + {1:~ }| + | + ]], cmdline={{ + firstc = ":", + content = {{"sign "}}, + pos = 5, + }}, popupmenu={items=expected, pos=-1, anchor={-1, 0, 5}}} + + feed('') + screen:expect{grid=[[ + ^ | + {1:~ }| + {1:~ }| + {1:~ }| + | + ]], cmdline={{ + firstc = ":", + content = {{"sign define"}}, + pos = 11, + }}, popupmenu={items=expected, pos=0, anchor={-1, 0, 5}}} + + feed('a') + screen:expect{grid=[[ + ^ | + {1:~ }| + {1:~ }| + {1:~ }| + | + ]], cmdline={{ + firstc = ":", + content = {{"sign definea"}}, + pos = 12, + }}} + feed('') + + -- check positioning with multibyte char in pattern + command("e långfile1") + command("sp långfile2") + feed(':b lå') + screen:expect{grid=[[ + ^ | + {3:långfile2 }| + | + {2:långfile1 }| + | + ]], popupmenu={ + anchor = { -1, 0, 2 }, + items = {{ "långfile1", "", "", "" }, { "långfile2", "", "", "" }}, + pos = 0 + }, cmdline={{ + content = {{ "b långfile1" }}, + firstc = ":", + pos = 12 + }}} + end) + + it('ext_wildmenu takes precedence over ext_popupmenu', function() + local expected = { + 'define', + 'jump', + 'list', + 'place', + 'undefine', + 'unplace', + } + + command('set wildmode=full') + command('set wildmenu') + screen:set_option('ext_wildmenu', true) + screen:set_option('ext_popupmenu', true) + feed(':sign ') + + screen:expect{grid=[[ + ^ | + {1:~ }| + {1:~ }| + {1:~ }| + | + ]], cmdline={{ + firstc = ":", + content = {{"sign define"}}, + pos = 11, + }}, wildmenu_items=expected, wildmenu_pos=0} + end) + end -- the representation of cmdline and cmdline_block contents changed with ext_linegrid diff --git a/test/functional/ui/float_spec.lua b/test/functional/ui/float_spec.lua index bb3255840e..375e98379a 100644 --- a/test/functional/ui/float_spec.lua +++ b/test/functional/ui/float_spec.lua @@ -1341,7 +1341,7 @@ describe('floating windows', function() ]], float_pos={ [3] = {{ id = 1001 }, "NW", 1, 2, 5, true}, }, popupmenu={ - anchor = {0, 2, 3}, items = items, pos = 0 + anchor = {3, 0, 2}, items = items, pos = 0 }} else screen:expect{grid=[[ @@ -1353,7 +1353,7 @@ describe('floating windows', function() {0:~ }{12:~ }{0: }| {3:-- INSERT --} | ]], popupmenu={ - anchor = {2, 7}, items = items, pos = 0 + anchor = {1, 2, 7}, items = items, pos = 0 }} end @@ -1423,7 +1423,7 @@ describe('floating windows', function() ]], float_pos={ [3] = {{ id = 1001 }, "NW", 1, 2, 5, true}, }, popupmenu={ - anchor = {0, 0, 2}, items = items, pos = 0 + anchor = {2, 0, 0}, items = items, pos = 0 }} else screen:expect{grid=[[ @@ -1435,7 +1435,7 @@ describe('floating windows', function() {0:~ }{12:~ }{0: }| {3:-- INSERT --} | ]], popupmenu={ - anchor = {0, 0}, items = items, pos = 0 + anchor = {1, 0, 0}, items = items, pos = 0 }} end diff --git a/test/functional/ui/messages_spec.lua b/test/functional/ui/messages_spec.lua index 388c6b3e95..efa776762b 100644 --- a/test/functional/ui/messages_spec.lua +++ b/test/functional/ui/messages_spec.lua @@ -179,7 +179,7 @@ describe('ui/ext_messages', function() {1:~ }| {1:~ }| ]], popupmenu={ - anchor = { 2, 0 }, + anchor = { 1, 2, 0 }, items = { { "alphpabet", "", "", "" }, { "alphanum", "", "", "" } }, pos = 1 }, showmode={ { "-- Keyword Local completion (^N^P) ", 3 }, { "match 1 of 2", 4 } }} @@ -194,7 +194,7 @@ describe('ui/ext_messages', function() {1:~ }| {1:~ }| ]], popupmenu={ - anchor = { 2, 0 }, + anchor = { 1, 2, 0 }, items = { { "alphpabet", "", "", "" }, { "alphanum", "", "", "" } }, pos = 1 }, messages={ { @@ -210,7 +210,7 @@ describe('ui/ext_messages', function() {1:~ }| {1:~ }| ]], popupmenu={ - anchor = { 2, 0 }, + anchor = { 1, 2, 0 }, items = { { "alphpabet", "", "", "" }, { "alphanum", "", "", "" } }, pos = 0 }, messages={ { diff --git a/test/functional/ui/popupmenu_spec.lua b/test/functional/ui/popupmenu_spec.lua index 1e6ebb87f5..b457ebebab 100644 --- a/test/functional/ui/popupmenu_spec.lua +++ b/test/functional/ui/popupmenu_spec.lua @@ -50,7 +50,7 @@ describe('ui/ext_popupmenu', function() ]], popupmenu={ items=expected, pos=0, - anchor={1,0}, + anchor={1,1,0}, }} feed('') @@ -66,7 +66,7 @@ describe('ui/ext_popupmenu', function() ]], popupmenu={ items=expected, pos=-1, - anchor={1,0}, + anchor={1,1,0}, }} -- down moves the selection in the menu, but does not insert anything @@ -83,7 +83,7 @@ describe('ui/ext_popupmenu', function() ]], popupmenu={ items=expected, pos=1, - anchor={1,0}, + anchor={1,1,0}, }} feed('') @@ -113,7 +113,7 @@ describe('ui/ext_popupmenu', function() ]], popupmenu={ items=expected, pos=0, - anchor={1,0}, + anchor={1,1,0}, }} meths.select_popupmenu_item(1,false,false,{}) @@ -129,7 +129,7 @@ describe('ui/ext_popupmenu', function() ]], popupmenu={ items=expected, pos=1, - anchor={1,0}, + anchor={1,1,0}, }} meths.select_popupmenu_item(2,true,false,{}) @@ -145,7 +145,7 @@ describe('ui/ext_popupmenu', function() ]], popupmenu={ items=expected, pos=2, - anchor={1,0}, + anchor={1,1,0}, }} meths.select_popupmenu_item(0,true,true,{}) @@ -174,7 +174,7 @@ describe('ui/ext_popupmenu', function() ]], popupmenu={ items=expected, pos=0, - anchor={1,0}, + anchor={1,1,0}, }} meths.select_popupmenu_item(-1,false,false,{}) @@ -190,7 +190,7 @@ describe('ui/ext_popupmenu', function() ]], popupmenu={ items=expected, pos=-1, - anchor={1,0}, + anchor={1,1,0}, }} meths.select_popupmenu_item(1,true,false,{}) @@ -206,7 +206,7 @@ describe('ui/ext_popupmenu', function() ]], popupmenu={ items=expected, pos=1, - anchor={1,0}, + anchor={1,1,0}, }} meths.select_popupmenu_item(-1,true,false,{}) @@ -222,7 +222,7 @@ describe('ui/ext_popupmenu', function() ]], popupmenu={ items=expected, pos=-1, - anchor={1,0}, + anchor={1,1,0}, }} meths.select_popupmenu_item(0,true,false,{}) @@ -238,7 +238,7 @@ describe('ui/ext_popupmenu', function() ]], popupmenu={ items=expected, pos=0, - anchor={1,0}, + anchor={1,1,0}, }} meths.select_popupmenu_item(-1,true,true,{}) @@ -269,7 +269,7 @@ describe('ui/ext_popupmenu', function() ]], popupmenu={ items=expected, pos=0, - anchor={1,0}, + anchor={1,1,0}, }} feed('') @@ -285,7 +285,7 @@ describe('ui/ext_popupmenu', function() ]], popupmenu={ items=expected, pos=2, - anchor={1,0}, + anchor={1,1,0}, }} feed('') @@ -301,7 +301,7 @@ describe('ui/ext_popupmenu', function() ]], popupmenu={ items=expected, pos=-1, - anchor={1,0}, + anchor={1,1,0}, }} feed('') @@ -366,6 +366,113 @@ describe('ui/ext_popupmenu', function() {2:-- INSERT --} | ]]) end) + + it('works with wildoptions=pum', function() + screen:try_resize(32,10) + command('set wildmenu') + command('set wildoptions=pum') + + local wild_expected = { + {'define', '', '', ''}, + {'jump', '', '', ''}, + {'list', '', '', ''}, + {'place', '', '', ''}, + {'undefine', '', '', ''}, + {'unplace', '', '', ''}, + } + + feed(':sign ') + screen:expect([[ + | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + :sign ^ | + ]]) + + feed('') + screen:expect{grid=[[ + | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + :sign define^ | + ]], popupmenu={items=wild_expected, pos=0, anchor={1, 9, 6}}} + + feed('') + screen:expect{grid=[[ + | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + :sign ^ | + ]], popupmenu={items=wild_expected, pos=-1, anchor={1, 9, 6}}} + + feed('') + screen:expect{grid=[[ + | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + :sign unplace^ | + ]], popupmenu={items=wild_expected, pos=5, anchor={1, 9, 6}}} + + feed('x') + screen:expect([[ + | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + :sign unplacex^ | + ]]) + feed('') + + -- check positioning with multibyte char in pattern + command("e långfile1") + command("sp långfile2") + feed(':b lå') + screen:expect{grid=[[ + | + {1:~ }| + {1:~ }| + {1:~ }| + {4:långfile2 }| + | + {1:~ }| + {1:~ }| + {3:långfile1 }| + :b långfile1^ | + ]], popupmenu={ + anchor = {1, 9, 3}, + items = {{"långfile1", "", "", "" }, {"långfile2", "", "", ""}}, + pos = 0, + }} + end) end) @@ -1209,7 +1316,7 @@ describe('builtin popupmenu', function() ]]) meths.input_mouse('wheel', 'down', '', 0, 6, 15) - screen:expect([[ + screen:expect{grid=[[ choice^ | {1:~ }| {n:word }{1: }| @@ -1218,7 +1325,7 @@ describe('builtin popupmenu', function() {n:thing }{1: }| {3:[No Name] [+] }| {2:-- INSERT --} | - ]]) + ]], unchanged=true} end) it('works with kind, menu and abbr attributes', function() @@ -1273,6 +1380,131 @@ describe('builtin popupmenu', function() ]]) end) + it('works with wildoptions=pum', function() + screen:try_resize(32,10) + command('set wildmenu') + command('set wildoptions=pum') + + feed(':sign ') + screen:expect([[ + | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + :sign ^ | + ]]) + + feed('') + screen:expect([[ + | + {1:~ }| + {1:~ }| + {1:~ }{s: define }{1: }| + {1:~ }{n: jump }{1: }| + {1:~ }{n: list }{1: }| + {1:~ }{n: place }{1: }| + {1:~ }{n: undefine }{1: }| + {1:~ }{n: unplace }{1: }| + :sign define^ | + ]]) + + feed('') + screen:expect([[ + | + {1:~ }| + {1:~ }| + {1:~ }{n: define }{1: }| + {1:~ }{n: jump }{1: }| + {1:~ }{n: list }{1: }| + {1:~ }{n: place }{1: }| + {1:~ }{n: undefine }{1: }| + {1:~ }{n: unplace }{1: }| + :sign ^ | + ]]) + + feed('') + screen:expect([[ + | + {1:~ }| + {1:~ }| + {1:~ }{n: define }{1: }| + {1:~ }{n: jump }{1: }| + {1:~ }{n: list }{1: }| + {1:~ }{n: place }{1: }| + {1:~ }{n: undefine }{1: }| + {1:~ }{s: unplace }{1: }| + :sign unplace^ | + ]]) + + feed('x') + screen:expect([[ + | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + :sign unplacex^ | + ]]) + + feed('') + + -- check positioning with multibyte char in pattern + command("e långfile1") + command("sp långfile2") + feed(':b lå') + screen:expect([[ + | + {1:~ }| + {1:~ }| + {1:~ }| + {4:långfile2 }| + | + {1:~ }| + {1:~ }{s: långfile1 }{1: }| + {3:lå}{n: långfile2 }{3: }| + :b långfile1^ | + ]]) + + -- check doesn't crash on screen resize + screen:try_resize(20,6) + screen:expect([[ + | + {1:~ }| + {4:långfile2 }| + {s: långfile1 } | + {3:lå}{n: långfile2 }{3: }| + :b långfile1^ | + ]]) + + screen:try_resize(50,15) + screen:expect([[ + | + {1:~ }| + {4:långfile2 }| + | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }{s: långfile1 }{1: }| + {3:lå}{n: långfile2 }{3: }| + :b långfile1^ | + ]]) + end) + it("'pumblend' RGB-color", function() screen:try_resize(60,14) screen:set_default_attr_ids({ diff --git a/test/functional/ui/screen.lua b/test/functional/ui/screen.lua index 8b1b77eb81..d072444ee1 100644 --- a/test/functional/ui/screen.lua +++ b/test/functional/ui/screen.lua @@ -937,10 +937,7 @@ function Screen:_handle_option_set(name, value) end function Screen:_handle_popupmenu_show(items, selected, row, col, grid) - if (not self._options.ext_multigrid) and grid == 1 then - grid = nil - end - self.popupmenu = {items=items, pos=selected, anchor={row, col, grid}} + self.popupmenu = {items=items, pos=selected, anchor={grid, row, col}} end function Screen:_handle_popupmenu_select(selected)