# HG changeset patch # User Christian Brabandt # Date 1692562265 -7200 # Node ID 306f51627f50b81a0ec854dd841bb591347d28ab # Parent 50dd2a4504d759025353c39c7e2842e9673a4218 commit 92997dda789ad8061841128cbc99b15ec0374411 Author: Shougo Matsushita Date: Sun Aug 20 20:55:55 2023 +0200 patch 9.0.1774: no support for custom cmdline completion Problem: no support for custom cmdline completion Solution: Add new vimscript functions Add the following two functions: - getcmdcompltype() returns custom and customlist functions - getcompletion() supports both custom and customlist closes: #12228 Signed-off-by: Christian Brabandt Co-authored-by: Shougo Matsushita diff --git a/runtime/doc/builtin.txt b/runtime/doc/builtin.txt --- a/runtime/doc/builtin.txt +++ b/runtime/doc/builtin.txt @@ -3551,6 +3551,8 @@ getcompletion({pat}, {type} [, {filtered cmdline |cmdline-completion| result compiler compilers cscope |:cscope| suboptions + custom,{func} custom completion, defined via {func} + customlist,{func} custom completion, defined via {func} diff_buffer |:diffget| and |:diffput| completion dir directory names environment environment variable names diff --git a/src/cmdexpand.c b/src/cmdexpand.c --- a/src/cmdexpand.c +++ b/src/cmdexpand.c @@ -4022,6 +4022,7 @@ f_getcompletion(typval_T *argvars, typva { xpc.xp_pattern = pat; xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern); + xpc.xp_line = pat; xpc.xp_context = cmdcomplete_str_to_type(type); if (xpc.xp_context == EXPAND_NOTHING) @@ -4030,6 +4031,30 @@ f_getcompletion(typval_T *argvars, typva return; } + if (xpc.xp_context == EXPAND_USER_DEFINED) + { + // Must be "custom,funcname" pattern + if (STRNCMP(type, "custom,", 7) != 0) + { + semsg(_(e_invalid_argument_str), type); + return; + } + + xpc.xp_arg = type + 7; + } + + if (xpc.xp_context == EXPAND_USER_LIST) + { + // Must be "customlist,funcname" pattern + if (STRNCMP(type, "customlist,", 11) != 0) + { + semsg(_(e_invalid_argument_str), type); + return; + } + + xpc.xp_arg = type + 11; + } + # if defined(FEAT_MENU) if (xpc.xp_context == EXPAND_MENUS) { diff --git a/src/ex_getln.c b/src/ex_getln.c --- a/src/ex_getln.c +++ b/src/ex_getln.c @@ -4152,6 +4152,7 @@ get_cmdline_str(void) get_cmdline_completion(void) { cmdline_info_T *p; + char_u *buffer; if (cmdline_star > 0) return NULL; @@ -4165,10 +4166,19 @@ get_cmdline_completion(void) return NULL; char_u *cmd_compl = cmdcomplete_type_to_str(p->xpc->xp_context); - if (cmd_compl != NULL) - return vim_strsave(cmd_compl); - - return NULL; + if (cmd_compl == NULL) + return NULL; + + if (p->xpc->xp_context == EXPAND_USER_LIST || p->xpc->xp_context == EXPAND_USER_DEFINED) + { + buffer = alloc(STRLEN(cmd_compl) + STRLEN(p->xpc->xp_arg) + 2); + if (buffer == NULL) + return NULL; + sprintf((char *)buffer, "%s,%s", cmd_compl, p->xpc->xp_arg); + return buffer; + } + + return vim_strsave(cmd_compl); } /* diff --git a/src/testdir/test_cmdline.vim b/src/testdir/test_cmdline.vim --- a/src/testdir/test_cmdline.vim +++ b/src/testdir/test_cmdline.vim @@ -3511,4 +3511,42 @@ func Test_getcompletion_usercmd() delcom TestCompletion endfunc +func Test_custom_completion() + func CustomComplete1(lead, line, pos) + return "a\nb\nc" + endfunc + func CustomComplete2(lead, line, pos) + return ['a', 'b']->filter({ _, val -> val->stridx(a:lead) == 0 }) + endfunc + func Check_custom_completion() + call assert_equal('custom,CustomComplete1', getcmdcompltype()) + return '' + endfunc + func Check_customlist_completion() + call assert_equal('customlist,CustomComplete2', getcmdcompltype()) + return '' + endfunc + + command -nargs=1 -complete=custom,CustomComplete1 Test1 echo + command -nargs=1 -complete=customlist,CustomComplete2 Test2 echo + + call feedkeys(":Test1 \=Check_custom_completion()\\", "xt") + call feedkeys(":Test2 \=Check_customlist_completion()\\", "xt") + + call assert_fails("call getcompletion('', 'custom')", 'E475:') + call assert_fails("call getcompletion('', 'customlist')", 'E475:') + + call assert_equal(getcompletion('', 'custom,CustomComplete1'), ['a', 'b', 'c']) + call assert_equal(getcompletion('', 'customlist,CustomComplete2'), ['a', 'b']) + call assert_equal(getcompletion('b', 'customlist,CustomComplete2'), ['b']) + + delcom Test1 + delcom Test2 + + delfunc CustomComplete1 + delfunc CustomComplete2 + delfunc Check_custom_completion + delfunc Check_customlist_completion +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/usercmd.c b/src/usercmd.c --- a/src/usercmd.c +++ b/src/usercmd.c @@ -481,6 +481,11 @@ cmdcomplete_str_to_type(char_u *complete { int i; + if (STRNCMP(complete_str, "custom,", 7) == 0) + return EXPAND_USER_DEFINED; + if (STRNCMP(complete_str, "customlist,", 11) == 0) + return EXPAND_USER_LIST; + for (i = 0; command_complete[i].expand != 0; ++i) if (STRCMP(complete_str, command_complete[i].name) == 0) return command_complete[i].expand; diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -700,6 +700,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 1774, +/**/ 1776, /**/ 1775,