Commit: patch 9.2.0886: :set completion works for an invalid sub-option name

Christian Brabandt <[email protected]> Fri, 31 Jul 2026 21:00:07 +0200
Newsgroups gmane.editors.vim.devel
Message-ID <[email protected]>
patch 9.2.0886: :set completion works for an invalid sub-option name

Commit: https://github.com/vim/vim/commit/7872568f4240027f1bb6b458eee58c96a474fe25
Author: Hirohito Higashi <[email protected]>
Date:   Fri Jul 31 18:48:43 2026 +0000

    patch 9.2.0886: :set completion works for an invalid sub-option name
    
    Problem:  Completing the value after a sub-option name also works when the
              name merely ends in a valid one, e.g. "invalid_close:".
    Solution: Require the name to start the option value or to follow a comma.
              Compute the length of the name at compile time.
    
    closes: #20893
    
    Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
    Signed-off-by: Hirohito Higashi <[email protected]>
    Signed-off-by: Christian Brabandt <[email protected]>

diff --git a/src/optionstr.c b/src/optionstr.c
index b656288cb..59a5a7e1d 100644
--- a/src/optionstr.c
+++ b/src/optionstr.c
@@ -1132,14 +1132,28 @@ did_set_ambiwidth(optset_T *args UNUSED)
 }
 
 #if defined(FEAT_TABPANEL) || defined(FEAT_DIFF) || defined(FEAT_PROP_POPUP)
+
+// "name" must be a string literal, the length is computed at compile time.
+# define completing_value_for_subopt(args, name) \
+	  completing_value_for_subopt_len(args, name, (int)STRLEN_LITERAL(name))
+
+/*
+ * Return true when completing the value of the sub-option "name" with length
+ * "len", e.g. the value after "close:" in 'completepopup'.
+ */
     static bool
-completing_value_for_subopt(optexpand_T *args, char *name_suffix)
+completing_value_for_subopt_len(optexpand_T *args, char *name, int len)
 {
-    char_u *colon = args->oe_xp->xp_pattern - 1;
-    int len = (int)STRLEN(name_suffix);
+    char_u  *colon = args->oe_xp->xp_pattern - 1;
+    int	    off = (int)(colon - args->oe_set_arg);
+
+    if (off < len)
+	return false;
+    // The name must follow a comma when it does not start the option value.
+    if (off > len && *(colon - len - 1) != ',')
+	return false;
 
-    return colon - args->oe_set_arg >= len
-	   && STRNCMP(colon - len, name_suffix, len) == 0;
+    return STRNCMP(colon - len, name, len) == 0;
 }
 #endif
 
diff --git a/src/testdir/test_options.vim b/src/testdir/test_options.vim
index b1201eb39..93d0e6144 100644
--- a/src/testdir/test_options.vim
+++ b/src/testdir/test_options.vim
@@ -663,6 +663,12 @@ func Test_set_completion_string_values()
   call feedkeys(":set completepopup=height:10,align:\<Tab>\<C-B>\"\<CR>", 'xt')
   call assert_equal('"set completepopup=height:10,align:item', @:)
   call assert_equal([], getcompletion('set completepopup=bogusname:', 'cmdline'))
+  " a name ending in a known sub-option name is not a sub-option
+  call assert_equal([], getcompletion('set completepopup=invalid_close:', 'cmdline'))
+  call assert_equal([], getcompletion('set completepopup=xborder:', 'cmdline'))
+  call assert_equal([], getcompletion('set completepopup=xhighlight:', 'cmdline'))
+  call assert_equal(['on', 'off'],
+        \ getcompletion('set completepopup=border:on,close:', 'cmdline'))
   call assert_equal(['on', 'off'], getcompletion('set completepopup=close:', 'cmdline'))
   call assert_equal(['on', 'off'], getcompletion('set completepopup=close:o', 'cmdline'))
   call assert_equal(['off'], getcompletion('set previewpopup=close:of', 'cmdline'))
@@ -687,6 +693,8 @@ func Test_set_completion_string_values()
   " diffopt: special handling of algorithm:<alg_list> and inline:<inline_type>
   call assert_equal('filler', getcompletion('set diffopt+=', 'cmdline')[0])
   call assert_equal([], getcompletion('set diffopt+=iblank,foldcolumn:', 'cmdline'))
+  call assert_equal([], getcompletion('set diffopt+=Xalgorithm:', 'cmdline'))
+  call assert_equal([], getcompletion('set diffopt+=iblank,Xinline:', 'cmdline'))
   call assert_equal('patience', getcompletion('set diffopt+=iblank,algorithm:pat*', 'cmdline')[0])
   call assert_equal('char', getcompletion('set diffopt+=iwhite,inline:ch*', 'cmdline')[0])
 
diff --git a/src/version.c b/src/version.c
index 55f755f23..59e9c7bb4 100644
--- a/src/version.c
+++ b/src/version.c
@@ -758,6 +758,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    886,
 /**/
     885,
 /**/

-- 
-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- 
You received this message because you are subscribed to the Google Groups "vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [email protected].
To view this discussion visit https://groups.google.com/d/msgid/vim_dev/E1wpsSl-006Ffb-Fj%40256bit.org.