aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--runtime/autoload/provider/clipboard.vim4
-rw-r--r--runtime/doc/options.txt3
-rw-r--r--runtime/doc/ui.txt18
-rw-r--r--runtime/doc/vim_diff.txt1
-rw-r--r--src/nvim/api/ui.c36
-rw-r--r--src/nvim/api/ui_events.in.h6
-rw-r--r--src/nvim/buffer_defs.h28
-rw-r--r--src/nvim/edit.c2
-rw-r--r--src/nvim/eval.c8
-rw-r--r--src/nvim/ex_docmd.c2
-rw-r--r--src/nvim/ex_getln.c65
-rw-r--r--src/nvim/fileio.c5
-rw-r--r--src/nvim/fileio.h1
-rw-r--r--src/nvim/lua/executor.c27
-rw-r--r--src/nvim/mbyte.c18
-rw-r--r--src/nvim/misc1.c3
-rw-r--r--src/nvim/option.c9
-rw-r--r--src/nvim/option_defs.h6
-rw-r--r--src/nvim/options.lua2
-rw-r--r--src/nvim/os/env.c43
-rw-r--r--src/nvim/popupmnu.c36
-rw-r--r--src/nvim/screen.c4
-rw-r--r--src/nvim/testdir/test_edit.vim13
-rw-r--r--src/nvim/testdir/test_lambda.vim6
-rw-r--r--src/nvim/testdir/test_timers.vim3
-rw-r--r--test/functional/api/buffer_spec.lua56
-rw-r--r--test/functional/lua/overrides_spec.lua16
-rw-r--r--test/functional/ui/cmdline_spec.lua131
-rw-r--r--test/functional/ui/float_spec.lua8
-rw-r--r--test/functional/ui/messages_spec.lua6
-rw-r--r--test/functional/ui/popupmenu_spec.lua264
-rw-r--r--test/functional/ui/screen.lua5
-rw-r--r--test/functional/ui/wildmode_spec.lua21
33 files changed, 723 insertions, 133 deletions
diff --git a/runtime/autoload/provider/clipboard.vim b/runtime/autoload/provider/clipboard.vim
index 2fb9d74d8d..2b06ee8c48 100644
--- a/runtime/autoload/provider/clipboard.vim
+++ b/runtime/autoload/provider/clipboard.vim
@@ -73,9 +73,9 @@ function! provider#clipboard#Executable() abort
let s:cache_enabled = 0
return 'pbcopy'
elseif exists('$WAYLAND_DISPLAY') && executable('wl-copy') && executable('wl-paste')
- let s:copy['+'] = 'wl-copy --foreground'
+ let s:copy['+'] = 'wl-copy --foreground --type text/plain'
let s:paste['+'] = 'wl-paste --no-newline'
- let s:copy['*'] = 'wl-copy --foreground --primary'
+ let s:copy['*'] = 'wl-copy --foreground --primary --type text/plain'
let s:paste['*'] = 'wl-paste --no-newline --primary'
return 'wl-copy'
elseif exists('$DISPLAY') && executable('xclip')
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/buffer_defs.h b/src/nvim/buffer_defs.h
index 614185a463..2f2546b360 100644
--- a/src/nvim/buffer_defs.h
+++ b/src/nvim/buffer_defs.h
@@ -996,18 +996,16 @@ typedef struct {
.relative = 0, .external = false, \
.focusable = true })
-/*
- * Structure which contains all information that belongs to a window
- *
- * All row numbers are relative to the start of the window, except w_winrow.
- */
+/// Structure which contains all information that belongs to a window.
+///
+/// All row numbers are relative to the start of the window, except w_winrow.
struct window_S {
handle_T handle; ///< unique identifier for the window
buf_T *w_buffer; ///< buffer we are a window into (used
///< often, keep it the first item!)
- synblock_T *w_s; /* for :ownsyntax */
+ synblock_T *w_s; ///< for :ownsyntax
int w_hl_id_normal; ///< 'winhighlight' normal id
int w_hl_attr_normal; ///< 'winhighlight' normal final attrs
@@ -1017,18 +1015,18 @@ struct window_S {
int w_hl_needs_update; ///< attrs need to be recalculated
- win_T *w_prev; /* link to previous window */
- win_T *w_next; /* link to next window */
- bool w_closing; /* window is being closed, don't let
- autocommands close it too. */
+ win_T *w_prev; ///< link to previous window
+ win_T *w_next; ///< link to next window
+ bool w_closing; ///< window is being closed, don't let
+ /// autocommands close it too.
- frame_T *w_frame; /* frame containing this window */
+ frame_T *w_frame; ///< frame containing this window
- pos_T w_cursor; /* cursor position in buffer */
+ pos_T w_cursor; ///< cursor position in buffer
- colnr_T w_curswant; /* The column we'd like to be at. This is
- used to try to stay in the same column
- for up/down cursor motions. */
+ colnr_T w_curswant; ///< Column we want to be at. This is
+ /// used to try to stay in the same column
+ /// for up/down cursor motions.
int w_set_curswant; // If set, then update w_curswant the next
// time through cursupdate() to the
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/eval.c b/src/nvim/eval.c
index 5ef2a8772e..df677a3a13 100644
--- a/src/nvim/eval.c
+++ b/src/nvim/eval.c
@@ -6328,8 +6328,12 @@ call_func(
}
- /* execute the function if no errors detected and executing */
- if (evaluate && error == ERROR_NONE) {
+ // Execute the function if executing and no errors were detected.
+ if (!evaluate) {
+ // Not evaluating, which means the return value is unknown. This
+ // matters for giving error messages.
+ rettv->v_type = VAR_UNKNOWN;
+ } else if (error == ERROR_NONE) {
char_u *rfname = fname;
/* Ignore "g:" before a function name. */
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/fileio.c b/src/nvim/fileio.c
index 7be4107c94..53b945d983 100644
--- a/src/nvim/fileio.c
+++ b/src/nvim/fileio.c
@@ -6527,6 +6527,7 @@ aucmd_prepbuf (
win = curwin;
aco->save_curwin = curwin;
+ aco->save_prevwin = prevwin;
aco->save_curbuf = curbuf;
if (win != NULL) {
/* There is a window for "buf" in the current tab page, make it the
@@ -6624,6 +6625,8 @@ win_found:
// Hmm, original window disappeared. Just use the first one.
curwin = firstwin;
}
+ prevwin = win_valid(aco->save_prevwin) ? aco->save_prevwin
+ : firstwin; // window disappeared?
vars_clear(&aucmd_win->w_vars->dv_hashtab); // free all w: variables
hash_init(&aucmd_win->w_vars->dv_hashtab); // re-use the hashtab
curbuf = curwin->w_buffer;
@@ -6656,6 +6659,8 @@ win_found:
}
curwin = aco->save_curwin;
+ prevwin = win_valid(aco->save_prevwin) ? aco->save_prevwin
+ : firstwin; // window disappeared?
curbuf = curwin->w_buffer;
// In case the autocommand moves the cursor to a position that does not
// exist in curbuf
diff --git a/src/nvim/fileio.h b/src/nvim/fileio.h
index 8db4b89806..a6011ec414 100644
--- a/src/nvim/fileio.h
+++ b/src/nvim/fileio.h
@@ -23,6 +23,7 @@ typedef struct {
buf_T *save_curbuf; ///< saved curbuf
int use_aucmd_win; ///< using aucmd_win
win_T *save_curwin; ///< saved curwin
+ win_T *save_prevwin; ///< saved prevwin
win_T *new_curwin; ///< new curwin
bufref_T new_curbuf; ///< new curbuf
char_u *globaldir; ///< saved value of globaldir
diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c
index 93069893cf..72b97736fc 100644
--- a/src/nvim/lua/executor.c
+++ b/src/nvim/lua/executor.c
@@ -24,6 +24,10 @@
#include "nvim/undo.h"
#include "nvim/ascii.h"
+#ifdef WIN32
+#include "nvim/os/os.h"
+#endif
+
#include "nvim/lua/executor.h"
#include "nvim/lua/converter.h"
@@ -118,6 +122,14 @@ static int nlua_state_init(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL
lua_setfield(lstate, -2, "debug");
lua_pop(lstate, 1);
+#ifdef WIN32
+ // os.getenv
+ lua_getglobal(lstate, "os");
+ lua_pushcfunction(lstate, &nlua_getenv);
+ lua_setfield(lstate, -2, "getenv");
+ lua_pop(lstate, 1);
+#endif
+
// vim
if (luaL_dostring(lstate, (char *)&vim_module[0])) {
nlua_error(lstate, _("E5106: Error while creating vim module: %.*s"));
@@ -297,7 +309,7 @@ nlua_print_error:
return 0;
}
-/// debug.debug implementation: interaction with user while debugging
+/// debug.debug: interaction with user while debugging.
///
/// @param lstate Lua interpreter state.
int nlua_debug(lua_State *lstate)
@@ -337,6 +349,19 @@ int nlua_debug(lua_State *lstate)
return 0;
}
+#ifdef WIN32
+/// os.getenv: override os.getenv to maintain coherency. #9681
+///
+/// uv_os_setenv uses SetEnvironmentVariableW which does not update _environ.
+///
+/// @param lstate Lua interpreter state.
+static int nlua_getenv(lua_State *lstate)
+{
+ lua_pushstring(lstate, os_getenv(luaL_checkstring(lstate, 1)));
+ return 1;
+}
+#endif
+
/// Evaluate lua string
///
/// Used for luaeval().
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/misc1.c b/src/nvim/misc1.c
index 64a4b8b0b4..d06fa8f762 100644
--- a/src/nvim/misc1.c
+++ b/src/nvim/misc1.c
@@ -710,9 +710,6 @@ open_line (
less_cols_off++;
}
}
- if (*p_extra != NUL) {
- did_ai = false; // append some text, don't truncate now
- }
/* columns for marks adjusted for removed columns */
less_cols = (int)(p_extra - saved_line);
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/os/env.c b/src/nvim/os/env.c
index e7bfbc8240..7d1021962c 100644
--- a/src/nvim/os/env.c
+++ b/src/nvim/os/env.c
@@ -151,25 +151,36 @@ int os_unsetenv(const char *name)
char *os_getenvname_at_index(size_t index)
{
#ifdef _WIN32
- // Check if index is inside the environ array and is not the last element.
- for (size_t i = 0; i <= index; i++) {
- if (_wenviron[i] == NULL) {
- return NULL;
- }
- }
- wchar_t *utf16_str = _wenviron[index];
- char *utf8_str;
- int conversion_result = utf16_to_utf8(utf16_str, &utf8_str);
- if (conversion_result != 0) {
- EMSG2("utf16_to_utf8 failed: %d", conversion_result);
+ wchar_t *env = GetEnvironmentStringsW();
+ if (!env) {
return NULL;
}
- size_t namesize = 0;
- while (utf8_str[namesize] != '=' && utf8_str[namesize] != NUL) {
- namesize++;
+ char *name = NULL;
+ size_t current_index = 0;
+ // GetEnvironmentStringsW() result has this format:
+ // var1=value1\0var2=value2\0...varN=valueN\0\0
+ for (wchar_t *it = env; *it != L'\0' || *(it + 1) != L'\0'; it++) {
+ if (index == current_index) {
+ char *utf8_str;
+ int conversion_result = utf16_to_utf8(it, &utf8_str);
+ if (conversion_result != 0) {
+ EMSG2("utf16_to_utf8 failed: %d", conversion_result);
+ break;
+ }
+ size_t namesize = 0;
+ while (utf8_str[namesize] != '=' && utf8_str[namesize] != NUL) {
+ namesize++;
+ }
+ name = (char *)vim_strnsave((char_u *)utf8_str, namesize);
+ xfree(utf8_str);
+ break;
+ }
+ if (*it == L'\0') {
+ current_index++;
+ }
}
- char *name = (char *)vim_strnsave((char_u *)utf8_str, namesize);
- xfree(utf8_str);
+
+ FreeEnvironmentStringsW(env);
return name;
#else
# if defined(HAVE__NSGETENVIRON)
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/src/nvim/testdir/test_edit.vim b/src/nvim/testdir/test_edit.vim
index f8946c6929..fa7cfaa40c 100644
--- a/src/nvim/testdir/test_edit.vim
+++ b/src/nvim/testdir/test_edit.vim
@@ -402,8 +402,19 @@ func! Test_edit_13()
call feedkeys("A {\<cr>more\<cr>}\<esc>", 'tnix')
call assert_equal(["\tabc {", "\t\tmore", "\t}"], getline(1, '$'))
set smartindent& autoindent&
- bw!
+ bwipe!
endif
+
+ " Test autoindent removing indent of blank line.
+ new
+ call setline(1, ' foo bar baz')
+ set autoindent
+ exe "normal 0eea\<CR>\<CR>\<Esc>"
+ call assert_equal(" foo bar", getline(1))
+ call assert_equal("", getline(2))
+ call assert_equal(" baz", getline(3))
+ set autoindent&
+ bwipe!
endfunc
func! Test_edit_CR()
diff --git a/src/nvim/testdir/test_lambda.vim b/src/nvim/testdir/test_lambda.vim
index ada25da4a8..bc7817cef8 100644
--- a/src/nvim/testdir/test_lambda.vim
+++ b/src/nvim/testdir/test_lambda.vim
@@ -291,3 +291,9 @@ func Test_named_function_closure()
call garbagecollect()
call assert_equal(14, s:Abar())
endfunc
+
+func Test_lambda_with_index()
+ let List = {x -> [x]}
+ let Extract = {-> function(List, ['foobar'])()[0]}
+ call assert_equal('foobar', Extract())
+endfunc
diff --git a/src/nvim/testdir/test_timers.vim b/src/nvim/testdir/test_timers.vim
index 62ddad5dce..5a0939a6a1 100644
--- a/src/nvim/testdir/test_timers.vim
+++ b/src/nvim/testdir/test_timers.vim
@@ -47,6 +47,9 @@ func Test_repeat_many()
call timer_stopall()
let g:val = 0
let timer = timer_start(50, 'MyHandler', {'repeat': -1})
+ if has('mac')
+ sleep 200m
+ endif
sleep 200m
call timer_stop(timer)
call assert_inrange((has('mac') ? 1 : 2), 4, g:val)
diff --git a/test/functional/api/buffer_spec.lua b/test/functional/api/buffer_spec.lua
index 93599c04f1..d26cb0dbb3 100644
--- a/test/functional/api/buffer_spec.lua
+++ b/test/functional/api/buffer_spec.lua
@@ -24,8 +24,8 @@ describe('api/buf', function()
end
- describe('line_count, insert and del_line', function()
- it('works', function()
+ describe('nvim_buf_set_lines, nvim_buf_line_count', function()
+ it('deprecated forms', function()
eq(1, curbuf_depr('line_count'))
curbuf_depr('insert', -1, {'line'})
eq(2, curbuf_depr('line_count'))
@@ -70,7 +70,7 @@ describe('api/buf', function()
end)
end)
- describe('{get,set,del}_line', function()
+ describe('deprecated: {get,set,del}_line', function()
it('works', function()
eq('', curbuf_depr('get_line', 0))
curbuf_depr('set_line', 0, 'line1')
@@ -102,7 +102,7 @@ describe('api/buf', function()
end)
end)
- describe('{get,set}_line_slice', function()
+ describe('deprecated: {get,set}_line_slice', function()
it('get_line_slice: out-of-bounds returns empty array', function()
curbuf_depr('set_line_slice', 0, 0, true, true, {'a', 'b', 'c'})
eq({'a', 'b', 'c'}, curbuf_depr('get_line_slice', 0, 2, true, true)) --sanity
@@ -149,7 +149,7 @@ describe('api/buf', function()
end)
end)
- describe('{get,set}_lines', function()
+ describe('nvim_buf_get_lines, nvim_buf_set_lines', function()
local get_lines, set_lines = curbufmeths.get_lines, curbufmeths.set_lines
local line_count = curbufmeths.line_count
@@ -272,7 +272,7 @@ describe('api/buf', function()
eq({}, get_lines(-3, -4, true))
end)
- it('set_line_slice: out-of-bounds can extend past end', function()
+ it('set_lines: out-of-bounds can extend past end', function()
set_lines(0, -1, true, {'a', 'b', 'c'})
eq({'a', 'b', 'c'}, get_lines(0, -1, true)) --sanity
@@ -286,7 +286,7 @@ describe('api/buf', function()
eq({'e', 'a', 'b', 'c', 'd'}, get_lines(0, -1, true))
end)
- it("set_line on alternate buffer does not access invalid line (E315)", function()
+ it("set_lines on alternate buffer does not access invalid line (E315)", function()
feed_command('set hidden')
insert('Initial file')
command('enew')
@@ -334,9 +334,27 @@ describe('api/buf', function()
{2:-- INSERT --} |
]])
end)
+
+ it('set_lines on hidden buffer preserves "previous window" #9741', function()
+ insert([[
+ visible buffer line 1
+ line 2
+ ]])
+ local hiddenbuf = meths.create_buf(false,true)
+ command('vsplit')
+ command('vsplit')
+ feed('<c-w>l<c-w>l<c-w>l')
+ eq(3, funcs.winnr())
+ feed('<c-w>h')
+ eq(2, funcs.winnr())
+ meths.buf_set_lines(hiddenbuf, 0, -1, true,
+ {'hidden buffer line 1', 'line 2'})
+ feed('<c-w>p')
+ eq(3, funcs.winnr())
+ end)
end)
- describe('get_offset', function()
+ describe('nvim_buf_get_offset', function()
local get_offset = curbufmeths.get_offset
it('works', function()
curbufmeths.set_lines(0,-1,true,{'Some\r','exa\000mple', '', 'buf\rfer', 'text'})
@@ -373,7 +391,7 @@ describe('api/buf', function()
end)
end)
- describe('{get,set,del}_var', function()
+ describe('nvim_buf_get_var, nvim_buf_set_var, nvim_buf_del_var', function()
it('works', function()
curbuf('set_var', 'lua', {1, 2, {['3'] = 1}})
eq({1, 2, {['3'] = 1}}, curbuf('get_var', 'lua'))
@@ -393,7 +411,7 @@ describe('api/buf', function()
end)
end)
- describe('get_changedtick', function()
+ describe('nvim_buf_get_changedtick', function()
it('works', function()
eq(2, curbufmeths.get_changedtick())
curbufmeths.set_lines(0, 1, false, {'abc\0', '\0def', 'ghi'})
@@ -417,7 +435,7 @@ describe('api/buf', function()
end)
end)
- describe('{get,set}_option', function()
+ describe('nvim_buf_get_option, nvim_buf_set_option', function()
it('works', function()
eq(8, curbuf('get_option', 'shiftwidth'))
curbuf('set_option', 'shiftwidth', 4)
@@ -430,7 +448,7 @@ describe('api/buf', function()
end)
end)
- describe('{get,set}_name', function()
+ describe('nvim_buf_get_name, nvim_buf_set_name', function()
it('works', function()
nvim('command', 'new')
eq('', curbuf('get_name'))
@@ -438,14 +456,12 @@ describe('api/buf', function()
curbuf('set_name', new_name)
eq(new_name, curbuf('get_name'))
nvim('command', 'w!')
- local f = io.open(new_name)
- ok(f ~= nil)
- f:close()
+ eq(1, funcs.filereadable(new_name))
os.remove(new_name)
end)
end)
- describe('is_loaded', function()
+ describe('nvim_buf_is_loaded', function()
it('works', function()
-- record our buffer number for when we unload it
local bufnr = curbuf('get_number')
@@ -470,7 +486,7 @@ describe('api/buf', function()
end)
end)
- describe('is_valid', function()
+ describe('nvim_buf_is_valid', function()
it('works', function()
nvim('command', 'new')
local b = nvim('get_current_buf')
@@ -480,12 +496,12 @@ describe('api/buf', function()
end)
end)
- describe('get_mark', function()
+ describe('nvim_buf_get_mark', function()
it('works', function()
curbuf('set_lines', -1, -1, true, {'a', 'bit of', 'text'})
curwin('set_cursor', {3, 4})
- nvim('command', 'mark V')
- eq({3, 0}, curbuf('get_mark', 'V'))
+ nvim('command', 'mark v')
+ eq({3, 0}, curbuf('get_mark', 'v'))
end)
end)
end)
diff --git a/test/functional/lua/overrides_spec.lua b/test/functional/lua/overrides_spec.lua
index 007d40874f..8f318e3503 100644
--- a/test/functional/lua/overrides_spec.lua
+++ b/test/functional/lua/overrides_spec.lua
@@ -300,3 +300,19 @@ describe('package.path/package.cpath', function()
eq(new_paths_str, eval_lua('package.path'):sub(1, #new_paths_str))
end)
end)
+
+describe('os.getenv', function()
+ it('returns nothing for undefined env var', function()
+ eq(NIL, funcs.luaeval('os.getenv("XTEST_1")'))
+ end)
+ it('returns env var set by the parent process', function()
+ local value = 'foo'
+ clear({env = {['XTEST_1']=value}})
+ eq(value, funcs.luaeval('os.getenv("XTEST_1")'))
+ end)
+ it('returns env var set by let', function()
+ local value = 'foo'
+ meths.command('let $XTEST_1 = "'..value..'"')
+ eq(value, funcs.luaeval('os.getenv("XTEST_1")'))
+ end)
+end)
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 <tab>')
+
+ screen:expect{grid=[[
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ |
+ ]], cmdline={{
+ firstc = ":",
+ content = {{"sign define"}},
+ pos = 11,
+ }}, popupmenu={items=expected, pos=0, anchor={-1, 0, 5}}}
+
+ feed('<tab>')
+ screen:expect{grid=[[
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ |
+ ]], cmdline={{
+ firstc = ":",
+ content = {{"sign jump"}},
+ pos = 9,
+ }}, popupmenu={items=expected, pos=1, anchor={-1, 0, 5}}}
+
+ feed('<left><left>')
+ screen:expect{grid=[[
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ |
+ ]], cmdline={{
+ firstc = ":",
+ content = {{"sign "}},
+ pos = 5,
+ }}, popupmenu={items=expected, pos=-1, anchor={-1, 0, 5}}}
+
+ feed('<right>')
+ 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('<esc>')
+
+ -- check positioning with multibyte char in pattern
+ command("e långfile1")
+ command("sp långfile2")
+ feed(':b lå<tab>')
+ 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 <tab>')
+
+ 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 06d3b6bdda..d18d91de56 100644
--- a/test/functional/ui/float_spec.lua
+++ b/test/functional/ui/float_spec.lua
@@ -1352,7 +1352,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=[[
@@ -1364,7 +1364,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
@@ -1434,7 +1434,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=[[
@@ -1446,7 +1446,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('<c-p>')
@@ -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('<cr>')
@@ -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('<f1>')
@@ -285,7 +285,7 @@ describe('ui/ext_popupmenu', function()
]], popupmenu={
items=expected,
pos=2,
- anchor={1,0},
+ anchor={1,1,0},
}}
feed('<f2>')
@@ -301,7 +301,7 @@ describe('ui/ext_popupmenu', function()
]], popupmenu={
items=expected,
pos=-1,
- anchor={1,0},
+ anchor={1,1,0},
}}
feed('<f3>')
@@ -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('<tab>')
+ screen:expect{grid=[[
+ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ :sign define^ |
+ ]], popupmenu={items=wild_expected, pos=0, anchor={1, 9, 6}}}
+
+ feed('<left>')
+ screen:expect{grid=[[
+ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ :sign ^ |
+ ]], popupmenu={items=wild_expected, pos=-1, anchor={1, 9, 6}}}
+
+ feed('<left>')
+ 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('<esc>')
+
+ -- check positioning with multibyte char in pattern
+ command("e långfile1")
+ command("sp långfile2")
+ feed(':b lå<tab>')
+ 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('<tab>')
+ 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('<left>')
+ 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('<left>')
+ 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('<esc>')
+
+ -- check positioning with multibyte char in pattern
+ command("e långfile1")
+ command("sp långfile2")
+ feed(':b lå<tab>')
+ 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)
diff --git a/test/functional/ui/wildmode_spec.lua b/test/functional/ui/wildmode_spec.lua
index 7cd09fb222..cf22bb0a6f 100644
--- a/test/functional/ui/wildmode_spec.lua
+++ b/test/functional/ui/wildmode_spec.lua
@@ -29,8 +29,7 @@ describe("'wildmenu'", function()
end
it(':sign <tab> shows wildmenu completions', function()
- command('set wildmode=full')
- command('set wildmenu')
+ command('set wildmenu wildmode=full')
feed(':sign <tab>')
screen:expect([[
|
@@ -201,14 +200,28 @@ describe('command line completion', function()
]])
end)
+ it('completes env var names #9681', function()
+ clear()
+ screen:attach()
+ command('let $XTEST_1 = "foo" | let $XTEST_2 = "bar"')
+ command('set wildmenu wildmode=full')
+ feed(':!echo $XTEST_<tab>')
+ screen:expect([[
+ |
+ {1:~ }|
+ {1:~ }|
+ {2:XTEST_1}{3: XTEST_2 }|
+ :!echo $XTEST_1^ |
+ ]])
+ end)
+
it('completes (multibyte) env var names #9655', function()
clear({env={
['XTEST_1AaあB']='foo',
['XTEST_2']='bar',
}})
screen:attach()
- command('set wildmode=full')
- command('set wildmenu')
+ command('set wildmenu wildmode=full')
feed(':!echo $XTEST_<tab>')
screen:expect([[
|