diff options
author | Björn Linse <bjorn.linse@gmail.com> | 2019-03-04 10:59:44 +0100 |
---|---|---|
committer | Björn Linse <bjorn.linse@gmail.com> | 2019-03-16 19:53:21 +0100 |
commit | be8ebba325451b387c0aedacfcda6c53e6c51188 (patch) | |
tree | 6ee90da21194166b5163fa6375e4f50ab1813626 /src | |
parent | 175398f21645552b708a7626309b826ae0f3d8a8 (diff) | |
download | rneovim-be8ebba325451b387c0aedacfcda6c53e6c51188.tar.gz rneovim-be8ebba325451b387c0aedacfcda6c53e6c51188.tar.bz2 rneovim-be8ebba325451b387c0aedacfcda6c53e6c51188.zip |
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).
Diffstat (limited to 'src')
-rw-r--r-- | src/nvim/api/ui.c | 36 | ||||
-rw-r--r-- | src/nvim/api/ui_events.in.h | 6 | ||||
-rw-r--r-- | src/nvim/edit.c | 2 | ||||
-rw-r--r-- | src/nvim/ex_docmd.c | 2 | ||||
-rw-r--r-- | src/nvim/ex_getln.c | 65 | ||||
-rw-r--r-- | src/nvim/mbyte.c | 18 | ||||
-rw-r--r-- | src/nvim/option.c | 9 | ||||
-rw-r--r-- | src/nvim/option_defs.h | 6 | ||||
-rw-r--r-- | src/nvim/options.lua | 2 | ||||
-rw-r--r-- | src/nvim/popupmnu.c | 36 | ||||
-rw-r--r-- | src/nvim/screen.c | 4 |
11 files changed, 149 insertions, 37 deletions
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); + } + 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); } - ui_call_wildmenu_show(args); + 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()) { |