aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/nvim/cmdexpand.c19
-rw-r--r--src/nvim/insexpand.c4
-rw-r--r--src/nvim/lua/executor.c40
-rw-r--r--test/functional/editor/completion_spec.lua52
4 files changed, 89 insertions, 26 deletions
diff --git a/src/nvim/cmdexpand.c b/src/nvim/cmdexpand.c
index 9ee5cde5b2..d235617ae1 100644
--- a/src/nvim/cmdexpand.c
+++ b/src/nvim/cmdexpand.c
@@ -240,6 +240,9 @@ int nextwild(expand_T *xp, int type, int options, bool escape)
if (xp->xp_numfiles == -1) {
set_expand_context(xp);
+ if (xp->xp_context == EXPAND_LUA) {
+ nlua_expand_pat(xp, xp->xp_pattern);
+ }
cmd_showtail = expand_showtail(xp);
}
@@ -287,11 +290,6 @@ int nextwild(expand_T *xp, int type, int options, bool escape)
use_options, type);
xfree(p1);
- // xp->xp_pattern might have been modified by ExpandOne (for example,
- // in lua completion), so recompute the pattern index and length
- i = (int)(xp->xp_pattern - ccline->cmdbuff);
- xp->xp_pattern_len = (size_t)ccline->cmdpos - (size_t)i;
-
// Longest match: make sure it is not shorter, happens with :help.
if (p2 != NULL && type == WILD_LONGEST) {
int j;
@@ -1061,6 +1059,9 @@ int showmatches(expand_T *xp, bool wildmenu)
if (xp->xp_numfiles == -1) {
set_expand_context(xp);
+ if (xp->xp_context == EXPAND_LUA) {
+ nlua_expand_pat(xp, xp->xp_pattern);
+ }
int i = expand_cmdline(xp, ccline->cmdbuff, ccline->cmdpos,
&numMatches, &matches);
showtail = expand_showtail(xp);
@@ -2797,8 +2798,7 @@ static int ExpandFromContext(expand_T *xp, char *pat, char ***matches, int *numM
}
if (xp->xp_context == EXPAND_LUA) {
- ILOG("PAT %s", pat);
- return nlua_expand_pat(xp, pat, numMatches, matches);
+ return nlua_expand_get_matches(numMatches, matches);
}
if (!fuzzy) {
@@ -3610,7 +3610,10 @@ void f_getcompletion(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
}
theend:
- ;
+ if (xpc.xp_context == EXPAND_LUA) {
+ nlua_expand_pat(&xpc, xpc.xp_pattern);
+ xpc.xp_pattern_len = strlen(xpc.xp_pattern);
+ }
char *pat;
if (cmdline_fuzzy_completion_supported(&xpc)) {
// when fuzzy matching, don't modify the search string
diff --git a/src/nvim/insexpand.c b/src/nvim/insexpand.c
index ded5c6e3c3..353efb6442 100644
--- a/src/nvim/insexpand.c
+++ b/src/nvim/insexpand.c
@@ -43,6 +43,7 @@
#include "nvim/indent_c.h"
#include "nvim/insexpand.h"
#include "nvim/keycodes.h"
+#include "nvim/lua/executor.h"
#include "nvim/macros_defs.h"
#include "nvim/mark_defs.h"
#include "nvim/mbyte.h"
@@ -4144,6 +4145,9 @@ static int get_cmdline_compl_info(char *line, colnr_T curs_col)
compl_pattern = xstrnsave(line, (size_t)curs_col);
compl_patternlen = (size_t)curs_col;
set_cmd_context(&compl_xp, compl_pattern, (int)compl_patternlen, curs_col, false);
+ if (compl_xp.xp_context == EXPAND_LUA) {
+ nlua_expand_pat(&compl_xp, compl_xp.xp_pattern);
+ }
if (compl_xp.xp_context == EXPAND_UNSUCCESSFUL
|| compl_xp.xp_context == EXPAND_NOTHING) {
// No completion possible, use an empty pattern to get a
diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c
index 6246452b92..af218443b9 100644
--- a/src/nvim/lua/executor.c
+++ b/src/nvim/lua/executor.c
@@ -1924,10 +1924,14 @@ static void nlua_add_treesitter(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL
lua_setfield(lstate, -2, "_ts_get_minimum_language_version");
}
-int nlua_expand_pat(expand_T *xp, char *pat, int *num_results, char ***results)
+static garray_T expand_result_array = GA_EMPTY_INIT_VALUE;
+
+/// Finds matches for Lua cmdline completion and advances xp->xp_pattern after prefix.
+/// This should be called before xp->xp_pattern is first used.
+void nlua_expand_pat(expand_T *xp, const char *pat)
{
lua_State *const lstate = global_lstate;
- int ret = OK;
+ int status = OK;
// [ vim ]
lua_getglobal(lstate, "vim");
@@ -1942,54 +1946,54 @@ int nlua_expand_pat(expand_T *xp, char *pat, int *num_results, char ***results)
if (nlua_pcall(lstate, 1, 2) != 0) {
nlua_error(lstate,
_("Error executing vim._expand_pat: %.*s"));
- return FAIL;
+ return;
}
Error err = ERROR_INIT;
- *num_results = 0;
- *results = NULL;
-
Arena arena = ARENA_EMPTY;
int prefix_len = (int)nlua_pop_Integer(lstate, &arena, &err);
if (ERROR_SET(&err)) {
- ret = FAIL;
+ status = FAIL;
goto cleanup;
}
Array completions = nlua_pop_Array(lstate, &arena, &err);
if (ERROR_SET(&err)) {
- ret = FAIL;
+ status = FAIL;
goto cleanup_array;
}
- garray_T result_array;
- ga_init(&result_array, (int)sizeof(char *), 80);
+ ga_clear(&expand_result_array);
+ ga_init(&expand_result_array, (int)sizeof(char *), 80);
for (size_t i = 0; i < completions.size; i++) {
Object v = completions.items[i];
if (v.type != kObjectTypeString) {
- ret = FAIL;
+ status = FAIL;
goto cleanup_array;
}
- GA_APPEND(char *, &result_array, string_to_cstr(v.data.string));
+ GA_APPEND(char *, &expand_result_array, string_to_cstr(v.data.string));
}
xp->xp_pattern += prefix_len;
- *results = result_array.ga_data;
- *num_results = result_array.ga_len;
cleanup_array:
arena_mem_free(arena_finish(&arena));
cleanup:
-
- if (ret == FAIL) {
- ga_clear(&result_array);
+ if (status == FAIL) {
+ ga_clear(&expand_result_array);
}
+}
- return ret;
+int nlua_expand_get_matches(int *num_results, char ***results)
+{
+ *results = expand_result_array.ga_data;
+ *num_results = expand_result_array.ga_len;
+ expand_result_array = (garray_T)GA_EMPTY_INIT_VALUE;
+ return *num_results > 0;
}
static int nlua_is_thread(lua_State *lstate)
diff --git a/test/functional/editor/completion_spec.lua b/test/functional/editor/completion_spec.lua
index a28e449f49..b42310fa81 100644
--- a/test/functional/editor/completion_spec.lua
+++ b/test/functional/editor/completion_spec.lua
@@ -812,11 +812,63 @@ describe('completion', function()
}
end)
+ it('prefix is not included in completion for cmdline mode', function()
+ feed(':lua math.a<Tab>')
+ screen:expect([[
+ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {100:abs}{3: acos asin atan atan2 }|
+ :lua math.abs^ |
+ ]])
+ feed('<Tab>')
+ screen:expect([[
+ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {3:abs }{100:acos}{3: asin atan atan2 }|
+ :lua math.acos^ |
+ ]])
+ end)
+
+ it('prefix is not included in completion for i_CTRL-X_CTRL-V #19623', function()
+ feed('ilua math.a<C-X><C-V>')
+ screen:expect([[
+ lua math.abs^ |
+ {1:~ }{12: abs }{1: }|
+ {1:~ }{4: acos }{1: }|
+ {1:~ }{4: asin }{1: }|
+ {1:~ }{4: atan }{1: }|
+ {1:~ }{4: atan2 }{1: }|
+ {1:~ }|
+ {5:-- Command-line completion (^V^N^P) }{6:match 1 of 5} |
+ ]])
+ feed('<C-V>')
+ screen:expect([[
+ lua math.acos^ |
+ {1:~ }{4: abs }{1: }|
+ {1:~ }{12: acos }{1: }|
+ {1:~ }{4: asin }{1: }|
+ {1:~ }{4: atan }{1: }|
+ {1:~ }{4: atan2 }{1: }|
+ {1:~ }|
+ {5:-- Command-line completion (^V^N^P) }{6:match 2 of 5} |
+ ]])
+ end)
+
it('provides completion from `getcompletion()`', function()
eq({ 'vim' }, fn.getcompletion('vi', 'lua'))
eq({ 'api' }, fn.getcompletion('vim.ap', 'lua'))
eq({ 'tbl_filter' }, fn.getcompletion('vim.tbl_fil', 'lua'))
eq({ 'vim' }, fn.getcompletion('print(vi', 'lua'))
+ eq({ 'abs', 'acos', 'asin', 'atan', 'atan2' }, fn.getcompletion('math.a', 'lua'))
+ eq({ 'abs', 'acos', 'asin', 'atan', 'atan2' }, fn.getcompletion('lua math.a', 'cmdline'))
-- fuzzy completion is not supported, so the result should be the same
command('set wildoptions+=fuzzy')
eq({ 'vim' }, fn.getcompletion('vi', 'lua'))