changeset 35808:b6dc79a71f47 v9.1.0624

patch 9.1.0624: ex command modifiers not found Commit: https://github.com/vim/vim/commit/70a11a6bf69f477844470ce59958b686024d2a41 Author: Christian Brabandt <cb@256bit.org> Date: Fri Jul 26 19:13:55 2024 +0200 patch 9.1.0624: ex command modifiers not found Problem: ex command modifiers are not found (Ingo Karkat, after v9.1.0352) Solution: partly revert patch v9.1.0352, ignore :{ and :} when expanding ex commands The issue is, that the :keepmarks command can be abbreviated to :kee or :keep or :keepm but not to e.g. :ke (because that would be the :exe command :k with register e). This basically means, we need `:kee` sorted before `:keepalt` but at the same time `:keepmarks` sorted after the `:keepalt` command in the cmdmod_info_tab table. Due to this, the binary search may not work correctly, so let's revert that part of patch v9.1.0352. fixes: #15305 closes: #15336 Signed-off-by: Christian Brabandt <cb@256bit.org>
author Christian Brabandt <cb@256bit.org>
date Fri, 26 Jul 2024 19:30:03 +0200
parents fb7d911ae9b9
children 8e5303bebacf
files src/ex_docmd.c src/testdir/test_cmdline.vim src/version.c
diffstat 3 files changed, 46 insertions(+), 64 deletions(-) [+]
line wrap: on
line diff
--- a/src/ex_docmd.c
+++ b/src/ex_docmd.c
@@ -19,10 +19,6 @@ static int	ex_pressedreturn = FALSE;
 # define ex_hardcopy	ex_ni
 #endif
 
-#if defined(FEAT_EVAL) || defined(PROTO)
-static int cmp_cmdmod_info(const void *a, const void *b);
-#endif
-
 #ifdef FEAT_EVAL
 static char_u	*do_one_cmd(char_u **, int, cstack_T *, char_u *(*fgetline)(int, void *, int, getline_opt_T), void *cookie);
 #else
@@ -4050,16 +4046,6 @@ static cmdmod_info_T cmdmod_info_tab[] =
     {"vim9cmd", 4, FALSE}
 };	// cmdmod_info_tab
 
-// compare two cmdmod_info_T structs by case sensitive name with length
-    static int
-cmp_cmdmod_info(const void *a, const void *b)
-{
-    cmdmod_info_T *cm1 = (cmdmod_info_T *)a;
-    cmdmod_info_T *cm2 = (cmdmod_info_T *)b;
-
-    return STRNCMP(cm1->name, cm2->name, cm2->minlen);
-}
-
 /*
  * Return length of a command modifier (including optional count).
  * Return zero when it's not a modifier.
@@ -4067,36 +4053,20 @@ cmp_cmdmod_info(const void *a, const voi
     int
 modifier_len(char_u *cmd)
 {
+    int		i, j;
     char_u	*p = cmd;
-    cmdmod_info_T	target;
-    cmdmod_info_T	*entry;
 
     if (VIM_ISDIGIT(*cmd))
 	p = skipwhite(skipdigits(cmd + 1));
-
-    // only lowercase characters can match
-    if (!ASCII_ISLOWER(*p))
-	return 0;
-
-    target.name = (char *)p;
-    target.minlen = 0;		// not used, see cmp_cmdmod_info()
-    target.has_count = FALSE;
-
-    entry = (cmdmod_info_T *)bsearch(&target, &cmdmod_info_tab, ARRAY_LENGTH(cmdmod_info_tab), sizeof(cmdmod_info_tab[0]), cmp_cmdmod_info);
-    if (entry != NULL)
-    {
-	int i;
-
-	for (i = entry->minlen; p[i] != NUL; ++i)
-	{
-	    if (p[i] != entry->name[i])
+    for (i = 0; i < (int)ARRAY_LENGTH(cmdmod_info_tab); ++i)
+    {
+	for (j = 0; p[j] != NUL; ++j)
+	    if (p[j] != cmdmod_info_tab[i].name[j])
 		break;
-	}
-
-	if (!ASCII_ISALPHA(p[i]) && i >= entry->minlen && (p == cmd || entry->has_count))
-	    return i + (int)(p - cmd);
-    }
-
+	if (!ASCII_ISALPHA(p[j]) && j >= cmdmod_info_tab[i].minlen
+					&& (p == cmd || cmdmod_info_tab[i].has_count))
+	    return j + (int)(p - cmd);
+    }
     return 0;
 }
 
@@ -4110,33 +4080,18 @@ cmd_exists(char_u *name)
 {
     exarg_T	ea;
     int		full = FALSE;
+    int		i;
+    int		j;
     char_u	*p;
 
-    // only lowercase characters can match
-    if (ASCII_ISLOWER(*name))
-    {
-	cmdmod_info_T	target;
-	cmdmod_info_T	*entry;
-
-	target.name = (char *)name;
-	target.minlen = 0;		// not used, see cmp_cmdmod_info()
-	target.has_count = FALSE;
-
-	// Check command modifiers.
-	entry = (cmdmod_info_T *)bsearch(&target, &cmdmod_info_tab, ARRAY_LENGTH(cmdmod_info_tab), sizeof(cmdmod_info_tab[0]), cmp_cmdmod_info);
-	if (entry != NULL)
-	{
-	    int i;
-
-	    for (i = entry->minlen; name[i] != NUL; ++i)
-	    {
-		if (name[i] != entry->name[i])
-		    break;
-	    }
-
-	    if (name[i] == NUL && i >= entry->minlen)
-		return (entry->name[i] == NUL ? 2 : 1);
-	}
+    // Check command modifiers.
+    for (i = 0; i < (int)ARRAY_LENGTH(cmdmod_info_tab); ++i)
+    {
+	for (j = 0; name[j] != NUL; ++j)
+	    if (name[j] != cmdmod_info_tab[i].name[j])
+		break;
+	if (name[j] == NUL && j >= cmdmod_info_tab[i].minlen)
+	    return (cmdmod_info_tab[i].name[j] == NUL ? 2 : 1);
     }
 
     // Check built-in commands and user defined commands.
@@ -5993,6 +5948,10 @@ get_command_name(expand_T *xp UNUSED, in
 {
     if (idx >= (int)CMD_SIZE)
 	return expand_user_command_name(idx);
+    // the following are no real commands
+    if (STRNCMP(cmdnames[idx].cmd_name, "{", 1) == 0 ||
+        STRNCMP(cmdnames[idx].cmd_name, "}", 1) == 0)
+	return (char_u *)"";
     return cmdnames[idx].cmd_name;
 }
 
--- a/src/testdir/test_cmdline.vim
+++ b/src/testdir/test_cmdline.vim
@@ -3870,4 +3870,25 @@ func Test_term_option()
   let &cpo = _cpo
 endfunc
 
+func Test_ex_command_completion()
+  " required for :*
+  set cpo+=*
+  let list = filter(getcompletion('', 'command'), 'exists(":" . v:val) == 0')
+  " :++ and :-- are only valid in Vim9 Script context, so they can be ignored
+  call assert_equal(['++', '--'], sort(list))
+  call assert_equal(1, exists(':k'))
+  call assert_equal(0, exists(':ke'))
+  call assert_equal(1, exists(':kee'))
+  call assert_equal(1, exists(':keep'))
+  call assert_equal(1, exists(':keepm'))
+  call assert_equal(1, exists(':keepma'))
+  call assert_equal(1, exists(':keepmar'))
+  call assert_equal(1, exists(':keepmark'))
+  call assert_equal(2, exists(':keepmarks'))
+  call assert_equal(2, exists(':keepalt'))
+  call assert_equal(2, exists(':keepjumps'))
+  call assert_equal(2, exists(':keeppatterns'))
+  set cpo-=*
+endfunc
+
 " vim: shiftwidth=2 sts=2 expandtab
--- a/src/version.c
+++ b/src/version.c
@@ -705,6 +705,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    624,
+/**/
     623,
 /**/
     622,