changeset 32947:306f51627f50 v9.0.1774

commit 92997dda789ad8061841128cbc99b15ec0374411 Author: Shougo Matsushita <Shougo.Matsu@gmail.com> 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 <cb@256bit.org> Co-authored-by: Shougo Matsushita <Shougo.Matsu@gmail.com>
author Christian Brabandt <cb@256bit.org>
date Sun, 20 Aug 2023 22:11:05 +0200
parents 50dd2a4504d7
children 8df33f0a3da1
files runtime/doc/builtin.txt src/cmdexpand.c src/ex_getln.c src/testdir/test_cmdline.vim src/usercmd.c src/version.c
diffstat 6 files changed, 86 insertions(+), 4 deletions(-) [+]
line wrap: on
line diff
--- 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
--- 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)
 	{
--- 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);
 }
 
 /*
--- 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 \<C-R>=Check_custom_completion()\<CR>\<Esc>", "xt")
+  call feedkeys(":Test2 \<C-R>=Check_customlist_completion()\<CR>\<Esc>", "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
--- 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;
--- 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,