diff --git a/runtime/doc/api.txt b/runtime/doc/api.txt index 48bbdc33df..72ac357ac0 100644 --- a/runtime/doc/api.txt +++ b/runtime/doc/api.txt @@ -700,6 +700,21 @@ nvim_chan_send({chan}, {data}) *nvim_chan_send()* • {chan} id of the channel • {data} data to write. 8-bit clean: can contain NUL bytes. +nvim_complete_set({index}, {*opts}) *nvim_complete_set()* + Set info for the completion candidate index. if the info was shown in a + window, then the window and buffer ids are returned for further + customization. If the text was not shown, an empty dict is returned. + + Parameters: ~ + • {index} the completion candidate index + • {opts} Optional parameters. + • info: (string) info text. + + Return: ~ + Dictionary containing these keys: + • winid: (number) floating window id + • bufnr: (number) buffer id in floating window + nvim_create_buf({listed}, {scratch}) *nvim_create_buf()* Creates a new, empty, unnamed buffer. diff --git a/runtime/doc/builtin.txt b/runtime/doc/builtin.txt index 714320279a..98201c0eed 100644 --- a/runtime/doc/builtin.txt +++ b/runtime/doc/builtin.txt @@ -802,6 +802,8 @@ complete_info([{what}]) *complete_info()* no item is selected when using the or keys) inserted Inserted string. [NOT IMPLEMENTED YET] + preview_winid Info floating preview window id. + preview_bufnr Info floating preview buffer id. *complete_info_mode* mode values are: diff --git a/runtime/doc/news.txt b/runtime/doc/news.txt index ad2de7a40a..406ac879eb 100644 --- a/runtime/doc/news.txt +++ b/runtime/doc/news.txt @@ -252,6 +252,9 @@ The following new APIs and features were added. • |vim.text.hexencode()| and |vim.text.hexdecode()| convert strings to and from byte representations. +• 'completeopt' option supports "popup" flags to show extra information in + in floating window. + ============================================================================== CHANGED FEATURES *news-changed* diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt index fda60eaab2..970f687c99 100644 --- a/runtime/doc/options.txt +++ b/runtime/doc/options.txt @@ -1516,6 +1516,10 @@ A jump table for the options with a short description can be found at |Q_op|. select one from the menu. Only works in combination with "menu" or "menuone". + popup Show extra information about the currently selected + completion in a popup window. Only works in combination + with "menu" or "menuone". Overrides "preview". + *'completeslash'* *'csl'* 'completeslash' 'csl' string (default "") local to buffer diff --git a/runtime/lua/vim/_meta/api.lua b/runtime/lua/vim/_meta/api.lua index 231e1c3404..c8afbd58dd 100644 --- a/runtime/lua/vim/_meta/api.lua +++ b/runtime/lua/vim/_meta/api.lua @@ -773,6 +773,16 @@ function vim.api.nvim_command(command) end --- @return string function vim.api.nvim_command_output(command) end +--- Set info for the completion candidate index. if the info was shown in a +--- window, then the window and buffer ids are returned for further +--- customization. If the text was not shown, an empty dict is returned. +--- +--- @param index integer the completion candidate index +--- @param opts vim.api.keyset.complete_set Optional parameters. +--- • info: (string) info text. +--- @return table +function vim.api.nvim_complete_set(index, opts) end + --- Create or get an autocommand group `autocmd-groups`. --- To get an existing group id, do: --- diff --git a/runtime/lua/vim/_meta/api_keysets.lua b/runtime/lua/vim/_meta/api_keysets.lua index f64cdb8afd..4ec8b03d30 100644 --- a/runtime/lua/vim/_meta/api_keysets.lua +++ b/runtime/lua/vim/_meta/api_keysets.lua @@ -68,6 +68,9 @@ error('Cannot require a meta file') --- @class vim.api.keyset.cmd_opts --- @field output? boolean +--- @class vim.api.keyset.complete_set +--- @field info? string + --- @class vim.api.keyset.context --- @field types? any[] diff --git a/runtime/lua/vim/_meta/options.lua b/runtime/lua/vim/_meta/options.lua index 5e65ca6b1b..c908d7ae54 100644 --- a/runtime/lua/vim/_meta/options.lua +++ b/runtime/lua/vim/_meta/options.lua @@ -1061,6 +1061,10 @@ vim.bo.cfu = vim.bo.completefunc --- select one from the menu. Only works in combination with --- "menu" or "menuone". --- +--- popup Show extra information about the currently selected +--- completion in a popup window. Only works in combination +--- with "menu" or "menuone". Overrides "preview". +--- --- @type string vim.o.completeopt = "menu,preview" vim.o.cot = vim.o.completeopt diff --git a/runtime/lua/vim/_meta/vimfn.lua b/runtime/lua/vim/_meta/vimfn.lua index ead5d8d13b..59d9836688 100644 --- a/runtime/lua/vim/_meta/vimfn.lua +++ b/runtime/lua/vim/_meta/vimfn.lua @@ -1024,6 +1024,8 @@ function vim.fn.complete_check() end --- no item is selected when using the or --- keys) --- inserted Inserted string. [NOT IMPLEMENTED YET] +--- preview_winid Info floating preview window id. +--- preview_bufnr Info floating preview buffer id. --- --- *complete_info_mode* --- mode values are: diff --git a/src/nvim/api/keysets_defs.h b/src/nvim/api/keysets_defs.h index c0daa0ca74..fa9a2cb013 100644 --- a/src/nvim/api/keysets_defs.h +++ b/src/nvim/api/keysets_defs.h @@ -346,3 +346,8 @@ typedef struct { LuaRef on_input; Boolean force_crlf; } Dict(open_term); + +typedef struct { + OptionalKeys is_set__complete_set_; + String info; +} Dict(complete_set); diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index 2f3d527b9e..91f908bb88 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -2300,3 +2300,29 @@ void nvim_error_event(uint64_t channel_id, Integer lvl, String data) // if we fork nvim processes as async workers ELOG("async error on channel %" PRId64 ": %s", channel_id, data.size ? data.data : ""); } + +/// Set info for the completion candidate index. +/// if the info was shown in a window, then the +/// window and buffer ids are returned for further +/// customization. If the text was not shown, an +/// empty dict is returned. +/// +/// @param index the completion candidate index +/// @param opts Optional parameters. +/// - info: (string) info text. +/// @return Dictionary containing these keys: +/// - winid: (number) floating window id +/// - bufnr: (number) buffer id in floating window +Dictionary nvim_complete_set(Integer index, Dict(complete_set) *opts) + FUNC_API_SINCE(12) +{ + Dictionary rv = ARRAY_DICT_INIT; + if (HAS_KEY(opts, complete_set, info)) { + win_T *wp = pum_set_info((int)index, opts->info.data); + if (wp) { + PUT(rv, "winid", WINDOW_OBJ(wp->handle)); + PUT(rv, "bufnr", BUFFER_OBJ(wp->w_buffer->handle)); + } + } + return rv; +} diff --git a/src/nvim/buffer_defs.h b/src/nvim/buffer_defs.h index beb3ec95b8..dc93243fad 100644 --- a/src/nvim/buffer_defs.h +++ b/src/nvim/buffer_defs.h @@ -1286,7 +1286,8 @@ struct window_S { ScreenGrid w_grid; // the grid specific to the window ScreenGrid w_grid_alloc; // the grid specific to the window bool w_pos_changed; // true if window position changed - bool w_floating; ///< whether the window is floating + bool w_floating; ///< whether the window is floating + bool w_float_is_info; // the floating window is info float FloatConfig w_float_config; // w_fraction is the fractional row of the cursor within the window, from diff --git a/src/nvim/eval.lua b/src/nvim/eval.lua index a86ca9c1ea..984935d009 100644 --- a/src/nvim/eval.lua +++ b/src/nvim/eval.lua @@ -1373,6 +1373,8 @@ M.funcs = { no item is selected when using the or keys) inserted Inserted string. [NOT IMPLEMENTED YET] + preview_winid Info floating preview window id. + preview_bufnr Info floating preview buffer id. *complete_info_mode* mode values are: diff --git a/src/nvim/insexpand.c b/src/nvim/insexpand.c index 8791aeb10c..54651eb48d 100644 --- a/src/nvim/insexpand.c +++ b/src/nvim/insexpand.c @@ -63,6 +63,7 @@ #include "nvim/undo.h" #include "nvim/vim_defs.h" #include "nvim/window.h" +#include "nvim/winfloat.h" // Definitions used for CTRL-X submode. // Note: If you change CTRL-X submode, you must also maintain ctrl_x_msgs[] @@ -1290,6 +1291,28 @@ void ins_compl_show_pum(void) } } +/// used for set or update info +void compl_set_info(int pum_idx) +{ + compl_T *comp = compl_first_match; + char *pum_text = compl_match_array[pum_idx].pum_text; + + while (comp != NULL) { + if (pum_text == comp->cp_str + || pum_text == comp->cp_text[CPT_ABBR]) { + comp->cp_text[CPT_INFO] = compl_match_array[pum_idx].pum_info; + + // if comp is current match update completed_item value + if (comp == compl_curr_match) { + dict_T *dict = ins_compl_dict_alloc(compl_curr_match); + set_vim_var_dict(VV_COMPLETED_ITEM, dict); + } + break; + } + comp = comp->cp_next; + } +} + #define DICT_FIRST (1) ///< use just first element in "dict" #define DICT_EXACT (2) ///< "dict" is the exact name of a file @@ -2813,6 +2836,11 @@ static void get_complete_info(list_T *what_list, dict_T *retdict) ret = tv_dict_add_nr(retdict, S_LEN("selected"), (compl_curr_match != NULL) ? compl_curr_match->cp_number - 1 : -1); + win_T *wp = win_float_find_preview(); + if (wp != NULL) { + tv_dict_add_nr(retdict, S_LEN("preview_winid"), wp->handle); + tv_dict_add_nr(retdict, S_LEN("preview_bufnr"), wp->w_buffer->handle); + } } (void)ret; diff --git a/src/nvim/options.lua b/src/nvim/options.lua index edd7423e69..2621cc2eb1 100644 --- a/src/nvim/options.lua +++ b/src/nvim/options.lua @@ -1450,6 +1450,10 @@ return { noselect Do not select a match in the menu, force the user to select one from the menu. Only works in combination with "menu" or "menuone". + + popup Show extra information about the currently selected + completion in a popup window. Only works in combination + with "menu" or "menuone". Overrides "preview". ]=], expand_cb = 'expand_set_completeopt', full_name = 'completeopt', diff --git a/src/nvim/optionstr.c b/src/nvim/optionstr.c index 002cc68a3b..1aab9d4344 100644 --- a/src/nvim/optionstr.c +++ b/src/nvim/optionstr.c @@ -116,7 +116,7 @@ static char *(p_fdm_values[]) = { "manual", "expr", "marker", "indent", "syntax", "diff", NULL }; static char *(p_fcl_values[]) = { "all", NULL }; static char *(p_cot_values[]) = { "menu", "menuone", "longest", "preview", "noinsert", "noselect", - NULL }; + "popup", NULL }; #ifdef BACKSLASH_IN_FILENAME static char *(p_csl_values[]) = { "slash", "backslash", NULL }; #endif diff --git a/src/nvim/popupmenu.c b/src/nvim/popupmenu.c index 56fc16a82e..a3e92fb595 100644 --- a/src/nvim/popupmenu.c +++ b/src/nvim/popupmenu.c @@ -8,8 +8,11 @@ #include "nvim/api/private/defs.h" #include "nvim/api/private/helpers.h" +#include "nvim/api/vim.h" #include "nvim/ascii_defs.h" +#include "nvim/autocmd.h" #include "nvim/buffer.h" +#include "nvim/buffer_defs.h" #include "nvim/charset.h" #include "nvim/drawscreen.h" #include "nvim/eval/typval.h" @@ -29,6 +32,8 @@ #include "nvim/move.h" #include "nvim/option.h" #include "nvim/option_vars.h" +#include "nvim/optionstr.h" +#include "nvim/plines.h" #include "nvim/popupmenu.h" #include "nvim/pos_defs.h" #include "nvim/state_defs.h" @@ -37,6 +42,7 @@ #include "nvim/ui_compositor.h" #include "nvim/vim_defs.h" #include "nvim/window.h" +#include "nvim/winfloat.h" static pumitem_T *pum_array = NULL; // items of displayed pum static int pum_size; // nr of items in "pum_array" @@ -654,6 +660,142 @@ void pum_redraw(void) } } +/// create a floting preview window for info +/// @return NULL when no enough room to show +static win_T *pum_create_float_preview(bool enter) +{ + FloatConfig config = FLOAT_CONFIG_INIT; + config.relative = kFloatRelativeEditor; + // when pum_above is SW otherwise is NW + config.anchor = pum_above ? kFloatAnchorSouth : 0; + int col = pum_col + pum_width + pum_scrollbar + 1; + // TODO(glepnir): support config align border by using completepopup + // align menu + config.row = pum_row; + int right_extra = Columns - col; + if (right_extra > 0) { + config.width = right_extra; + config.col = col - 1; + } else if (pum_col - 2 > 0) { + config.width = pum_col - 2; + config.col = pum_col - config.width - 1; + } else { + return NULL; + } + config.height = pum_height; + config.style = kWinStyleMinimal; + config.hide = true; + Error err = ERROR_INIT; + win_T *wp = win_new_float(NULL, true, config, &err); + // TODO(glepnir): remove win_enter usage + if (enter) { + win_enter(wp, false); + } + + // create a new buffer + Buffer b = nvim_create_buf(false, true, &err); + if (!b) { + win_free(wp, NULL); + return NULL; + } + buf_T *buf = find_buffer_by_handle(b, &err); + set_string_option_direct_in_buf(buf, kOptBufhidden, "wipe", OPT_FREE | OPT_LOCAL, 0); + wp->w_float_is_info = true; + wp->w_p_diff = false; + buf->b_p_bl = false; + win_set_buf(wp, buf, true, &err); + return wp; +} + +/// set info text to preview buffer. +static void pum_preview_set_text(buf_T *buf, char *info, linenr_T *lnum, int *max_width) +{ + for (char *p = info; *p != NUL;) { + int text_width = 0; + char *e = vim_strchr(p, '\n'); + if (e == NULL) { + ml_append_buf(buf, (*lnum)++, p, 0, false); + text_width = (int)mb_string2cells(p); + if (text_width > *max_width) { + *max_width = text_width; + } + break; + } + *e = NUL; + ml_append_buf(buf, (*lnum)++, p, (int)(e - p + 1), false); + text_width = (int)mb_string2cells(p); + if (text_width > *max_width) { + *max_width = text_width; + } + *e = '\n'; + p = e + 1; + } + // delete the empty last line + ml_delete_buf(buf, buf->b_ml.ml_line_count, false); +} + +/// adjust floating preview window width and height +static void pum_adjust_float_position(win_T *wp, int height, int width) +{ + // when floating window in right and right no enough room to show + // but left has enough room, adjust floating window to left. + if (wp->w_float_config.width < width && wp->w_float_config.col > pum_col) { + if ((pum_col - 2) > width) { + wp->w_float_config.width = width; + wp->w_float_config.col = pum_col - width - 1; + } + } + wp->w_float_config.width = MIN(wp->w_float_config.width, width); + wp->w_float_config.height = MIN(Rows, height); + wp->w_float_config.hide = false; + win_config_float(wp, wp->w_float_config); +} + +/// used in nvim_complete_set +win_T *pum_set_info(int pum_idx, char *info) +{ + if (!pum_is_visible || pum_idx < 0 || pum_idx > pum_size) { + return NULL; + } + pum_array[pum_idx].pum_info = xstrdup(info); + compl_set_info(pum_idx); + bool use_float = strstr(p_cot, "popup") != NULL ? true : false; + if (pum_idx != pum_selected || !use_float) { + return NULL; + } + + block_autocmds(); + RedrawingDisabled++; + no_u_sync++; + win_T *wp = win_float_find_preview(); + if (wp == NULL) { + wp = pum_create_float_preview(false); + // no enough room to show + if (!wp) { + return NULL; + } + } else { + // clean exist buffer + while (!buf_is_empty(wp->w_buffer)) { + ml_delete_buf(wp->w_buffer, (linenr_T)1, false); + } + } + no_u_sync--; + RedrawingDisabled--; + + linenr_T lnum = 0; + int max_info_width = 0; + pum_preview_set_text(wp->w_buffer, info, &lnum, &max_info_width); + redraw_later(wp, UPD_SOME_VALID); + + if (wp->w_p_wrap) { + lnum += plines_win(wp, lnum, true); + } + pum_adjust_float_position(wp, lnum, max_info_width); + unblock_autocmds(); + return wp; +} + /// Set the index of the currently selected item. The menu will scroll when /// necessary. When "n" is out of range don't scroll. /// This may be repeated when the preview window is used: @@ -670,6 +812,7 @@ static bool pum_set_selected(int n, int repeat) { int resized = false; int context = pum_height / 2; + int prev_selected = pum_selected; pum_selected = n; @@ -718,6 +861,10 @@ static bool pum_set_selected(int n, int repeat) pum_first = pum_selected + context - pum_height + 1; } } + // adjust for the number of lines displayed + if (pum_first > pum_size - pum_height) { + pum_first = pum_size - pum_height; + } // Show extra info in the preview window if there is something and // 'completeopt' contains "preview". @@ -730,6 +877,11 @@ static bool pum_set_selected(int n, int repeat) && (vim_strchr(p_cot, 'p') != NULL)) { win_T *curwin_save = curwin; tabpage_T *curtab_save = curtab; + bool use_float = strstr(p_cot, "popup") != NULL ? true : false; + + if (use_float) { + block_autocmds(); + } // Open a preview window. 3 lines by default. Prefer // 'previewheight' if set and smaller. @@ -742,12 +894,26 @@ static bool pum_set_selected(int n, int repeat) // Prevent undo sync here, if an autocommand syncs undo weird // things can happen to the undo tree. no_u_sync++; - resized = prepare_tagpreview(false); + + if (!use_float) { + resized = prepare_tagpreview(false); + } else { + win_T *wp = win_float_find_preview(); + if (wp) { + win_enter(wp, false); + } else { + wp = pum_create_float_preview(true); + if (wp) { + resized = true; + } + } + } + no_u_sync--; RedrawingDisabled--; g_do_tagpreview = 0; - if (curwin->w_p_pvw) { + if (curwin->w_p_pvw || curwin->w_float_is_info) { int res = OK; if (!resized && (curbuf->b_nwindows == 1) @@ -777,22 +943,11 @@ static bool pum_set_selected(int n, int repeat) if (res == OK) { linenr_T lnum = 0; - - for (char *p = pum_array[pum_selected].pum_info; *p != NUL;) { - char *e = vim_strchr(p, '\n'); - if (e == NULL) { - ml_append(lnum++, p, 0, false); - break; - } - *e = NUL; - ml_append(lnum++, p, (int)(e - p + 1), false); - *e = '\n'; - p = e + 1; - } - + int max_info_width = 0; + pum_preview_set_text(curbuf, pum_array[pum_selected].pum_info, &lnum, &max_info_width); // Increase the height of the preview window to show the // text, but no more than 'previewheight' lines. - if (repeat == 0) { + if (repeat == 0 && !use_float) { if (lnum > p_pvh) { lnum = (linenr_T)p_pvh; } @@ -805,9 +960,22 @@ static bool pum_set_selected(int n, int repeat) curbuf->b_changed = false; curbuf->b_p_ma = false; + if (pum_selected != prev_selected) { + curwin->w_topline = 1; + } else if (curwin->w_topline > curbuf->b_ml.ml_line_count) { + curwin->w_topline = curbuf->b_ml.ml_line_count; + } curwin->w_cursor.lnum = 1; curwin->w_cursor.col = 0; + if (use_float) { + if (curwin->w_p_wrap) { + lnum += plines_win(curwin, lnum, true); + } + // adjust floting window by actually height and max info text width + pum_adjust_float_position(curwin, lnum, max_info_width); + } + if ((curwin != curwin_save && win_valid(curwin_save)) || (curtab != curtab_save && valid_tabpage(curtab_save))) { if (curtab != curtab_save && valid_tabpage(curtab_save)) { @@ -829,7 +997,7 @@ static bool pum_set_selected(int n, int repeat) // update the view on the buffer. Only go back to // the window when needed, otherwise it will always be // redrawn. - if (resized) { + if (resized && win_valid(curwin_save)) { no_u_sync++; win_enter(curwin_save, true); no_u_sync--; @@ -858,6 +1026,10 @@ static bool pum_set_selected(int n, int repeat) } } } + + if (use_float) { + unblock_autocmds(); + } } } @@ -892,6 +1064,10 @@ void pum_check_clear(void) } pum_is_drawn = false; pum_external = false; + win_T *wp = win_float_find_preview(); + if (wp != NULL) { + win_close(wp, false, false); + } } } diff --git a/src/nvim/popupmenu.h b/src/nvim/popupmenu.h index 24a3f8713a..dc741d1b77 100644 --- a/src/nvim/popupmenu.h +++ b/src/nvim/popupmenu.h @@ -2,6 +2,7 @@ #include +#include "nvim/buffer_defs.h" #include "nvim/eval/typval_defs.h" // IWYU pragma: keep #include "nvim/grid_defs.h" #include "nvim/macros_defs.h" diff --git a/src/nvim/window.c b/src/nvim/window.c index 98c62d6f44..618a3f760e 100644 --- a/src/nvim/window.c +++ b/src/nvim/window.c @@ -4978,7 +4978,7 @@ void free_wininfo(wininfo_T *wip, buf_T *bp) /// Remove window 'wp' from the window list and free the structure. /// /// @param tp tab page "win" is in, NULL for current -static void win_free(win_T *wp, tabpage_T *tp) +void win_free(win_T *wp, tabpage_T *tp) { pmap_del(int)(&window_handles, wp->handle, NULL); clearFolding(wp); diff --git a/src/nvim/winfloat.c b/src/nvim/winfloat.c index 0eea21eb9d..4efff3cfab 100644 --- a/src/nvim/winfloat.c +++ b/src/nvim/winfloat.c @@ -286,3 +286,13 @@ bool win_float_valid(const win_T *win) } return false; } + +win_T *win_float_find_preview(void) +{ + for (win_T *wp = lastwin; wp && wp->w_floating; wp = wp->w_prev) { + if (wp->w_float_is_info) { + return wp; + } + } + return NULL; +} diff --git a/test/functional/ui/popupmenu_spec.lua b/test/functional/ui/popupmenu_spec.lua index 042b7dbabf..956173b86e 100644 --- a/test/functional/ui/popupmenu_spec.lua +++ b/test/functional/ui/popupmenu_spec.lua @@ -1431,7 +1431,7 @@ describe('builtin popupmenu', function() feed('') screen:expect([[ 1info | - | + {1:~ }| {1:~ }| {3:[Scratch] [Preview] }| one^ | @@ -1469,6 +1469,208 @@ describe('builtin popupmenu', function() end) end + describe("floating window preview #popup", function() + it('pum popup preview', function() + --row must > 10 + screen:try_resize(30, 11) + exec([[ + funct Omni_test(findstart, base) + if a:findstart + return col(".") - 1 + endif + return [#{word: "one", info: "1info"}, #{word: "two", info: "2info"}, #{word: "three"}] + endfunc + set omnifunc=Omni_test + set completeopt=menu,popup + + funct Set_info() + let comp_info = complete_info() + if comp_info['selected'] == 2 + call nvim_complete_set(comp_info['selected'], {"info": "3info"}) + endif + endfunc + autocmd CompleteChanged * call Set_info() + ]]) + feed('Gi') + + --floating preview in right + if multigrid then + screen:expect{grid=[[ + ## grid 1 + [2:------------------------------]| + [2:------------------------------]| + [2:------------------------------]| + [2:------------------------------]| + [2:------------------------------]| + [2:------------------------------]| + [2:------------------------------]| + [2:------------------------------]| + [2:------------------------------]| + [2:------------------------------]| + [3:------------------------------]| + ## grid 2 + one^ | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + ## grid 3 + {2:-- }{5:match 1 of 3} | + ## grid 4 + {n:1info}| + {n: }| + ## grid 5 + {s:one }| + {n:two }| + {n:three }| + ]], float_pos={ + [5] = {{id = -1}, "NW", 2, 1, 0, false, 100}; + [4] = {{id = 1001}, "NW", 1, 1, 15, true, 50}; + }} + else + screen:expect{grid=[[ + one^ | + {s:one }{n:1info}{1: }| + {n:two }{1: }| + {n:three }{1: }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {2:-- }{5:match 1 of 3} | + ]], unchanged = true} + end + + -- test nvim_complete_set_info + feed('') + helpers.sleep(10) + if multigrid then + screen:expect{grid=[[ + ## grid 1 + [2:------------------------------]| + [2:------------------------------]| + [2:------------------------------]| + [2:------------------------------]| + [2:------------------------------]| + [2:------------------------------]| + [2:------------------------------]| + [2:------------------------------]| + [2:------------------------------]| + [2:------------------------------]| + [3:------------------------------]| + ## grid 2 + three^ | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + ## grid 3 + {2:-- }{5:match 3 of 3} | + ## grid 4 + {n:3info}| + {n: }| + ## grid 5 + {n:one }| + {n:two }| + {s:three }| + ]], float_pos={ + [5] = {{id = -1}, "NW", 2, 1, 0, false, 100}; + [4] = {{id = 1001}, "NW", 1, 1, 15, true, 50}; + }} + else + screen:expect{grid=[[ + three^ | + {n:one 3info}{1: }| + {n:two }{1: }| + {s:three }{1: }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {2:-- }{5:match 3 of 3} | + ]]} + end + -- make sure info has set + feed('') + eq('3info', exec_lua('return vim.v.completed_item.info')) + + -- preview in left + feed('cc') + insert(('test'):rep(5)) + feed('i') + if multigrid then + screen:expect{grid=[[ + ## grid 1 + [2:------------------------------]| + [2:------------------------------]| + [2:------------------------------]| + [2:------------------------------]| + [2:------------------------------]| + [2:------------------------------]| + [2:------------------------------]| + [2:------------------------------]| + [2:------------------------------]| + [2:------------------------------]| + [3:------------------------------]| + ## grid 2 + itesttesttesttesttesone^t | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + ## grid 3 + {2:-- }{5:match 1 of 3} | + ## grid 5 + {s: one }| + {n: two }| + {n: three }| + ## grid 6 + {n:1info}| + {n: }| + ]], float_pos={ + [5] = {{id = -1}, "NW", 2, 1, 19, false, 100}; + [6] = {{id = 1002}, "NW", 1, 1, 1, true, 50}; + }, win_viewport={ + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 23, linecount = 1, sum_scroll_delta = 0}; + [6] = {win = {id = 1002}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; + }} + else + screen:expect{grid=[[ + itesttesttesttesttesone^t | + {1:~}{n:1info}{1: }{s: one }{1: }| + {1:~}{n: }{1: }{n: two }{1: }| + {1:~ }{n: three }{1: }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {2:-- }{5:match 1 of 3} | + ]]} + end + end) + end) + it('with vsplits', function() screen:try_resize(32, 8) insert('aaa aab aac\n')