From: Hirohito Higashi Date: Fri, 31 Jul 2026 18:48:43 +0000 (+0000) Subject: patch 9.2.0886: :set completion works for an invalid sub-option name X-Git-Tag: v9.2.0886^0 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=7872568f4240027f1bb6b458eee58c96a474fe25;p=thirdparty%2Fvim.git 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) Signed-off-by: Hirohito Higashi Signed-off-by: Christian Brabandt --- diff --git a/src/optionstr.c b/src/optionstr.c index b656288cb5..59a5a7e1d1 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 b1201eb397..93d0e61442 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:\\\"\", '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: and inline: 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 55f755f23f..59e9c7bb4b 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, /**/