diff options
-rw-r--r-- | src/nvim/cmdexpand.c | 19 | ||||
-rw-r--r-- | src/nvim/insexpand.c | 4 | ||||
-rw-r--r-- | src/nvim/lua/executor.c | 40 | ||||
-rw-r--r-- | test/functional/editor/completion_spec.lua | 52 |
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')) |