summaryrefslogtreecommitdiffstats
path: root/src/optionstr.c
diff options
context:
space:
mode:
authorYee Cheng Chin <ychin.git@gmail.com>2023-09-29 20:42:32 +0200
committerChristian Brabandt <cb@256bit.org>2023-09-29 20:42:32 +0200
commit900894b09a95398dfc75599e9f0aa2ea25723384 (patch)
tree62d287cb3235349c75c60884f280e3c5f47beb5e /src/optionstr.c
parent3695d0e41ba26db074dd5680564a6f87d522fb61 (diff)
patch 9.0.1958: cannot complete option valuesv9.0.1958
Problem: cannot complete option values Solution: Add completion functions for several options Add cmdline tab-completion for setting string options Add tab-completion for setting string options on the cmdline using `:set=` (along with `:set+=` and `:set-=`). The existing tab completion for setting options currently only works when nothing is typed yet, and it only fills in with the existing value, e.g. when the user does `:set diffopt=<Tab>` it will be completed to `set diffopt=internal,filler,closeoff` and nothing else. This isn't too useful as a user usually wants auto-complete to suggest all the possible values, such as 'iblank', or 'algorithm:patience'. For set= and set+=, this adds a new optional callback function for each option that can be invoked when doing completion. This allows for each option to have control over how completion works. For example, in 'diffopt', it will suggest the default enumeration, but if `algorithm:` is selected, it will further suggest different algorithm types like 'meyers' and 'patience'. When using set=, the existing option value will be filled in as the first choice to preserve the existing behavior. When using set+= this won't happen as it doesn't make sense. For flag list options (e.g. 'mouse' and 'guioptions'), completion will take into account existing typed values (and in the case of set+=, the existing option value) to make sure it doesn't suggest duplicates. For set-=, there is a new `ExpandSettingSubtract` function which will handle flag list and comma-separated options smartly, by only suggesting values that currently exist in the option. Note that Vim has some existing code that adds special handling for 'filetype', 'syntax', and misc dir options like 'backupdir'. This change preserves them as they already work, instead of converting to the new callback API for each option. closes: #13182 Signed-off-by: Christian Brabandt <cb@256bit.org> Co-authored-by: Yee Cheng Chin <ychin.git@gmail.com>
Diffstat (limited to 'src/optionstr.c')
-rw-r--r--src/optionstr.c1118
1 files changed, 1117 insertions, 1 deletions
diff --git a/src/optionstr.c b/src/optionstr.c
index 9b4464d85c..010bec769f 100644
--- a/src/optionstr.c
+++ b/src/optionstr.c
@@ -24,8 +24,21 @@ static char *(p_bo_values[]) = {"all", "backspace", "cursor", "complete",
"hangul", "insertmode", "lang", "mess",
"showmatch", "operator", "register", "shell",
"spell", "term", "wildmode", NULL};
+#if defined(FEAT_LINEBREAK)
+// Note: Keep this in sync with briopt_check()
+static char *(p_briopt_values[]) = {"shift:", "min:", "sbr", "list:", "column:", NULL};
+#endif
+#if defined(FEAT_DIFF)
+// Note: Keep this in sync with diffopt_changed()
+static char *(p_dip_values[]) = {"filler", "context:", "iblank", "icase", "iwhite", "iwhiteall", "iwhiteeol", "horizontal", "vertical", "closeoff", "hiddenoff", "foldcolumn:", "followwrap", "internal", "indent-heuristic", "algorithm:", NULL};
+static char *(p_dip_algorithm_values[]) = {"myers", "minimal", "patience", "histogram", NULL};
+#endif
static char *(p_nf_values[]) = {"bin", "octal", "hex", "alpha", "unsigned", NULL};
static char *(p_ff_values[]) = {FF_UNIX, FF_DOS, FF_MAC, NULL};
+#ifdef FEAT_CLIPBOARD
+// Note: Keep this in sync with did_set_clipboard()
+static char *(p_cb_values[]) = {"unnamed", "unnamedplus", "autoselect", "autoselectplus", "autoselectml", "html", "exclude:", NULL};
+#endif
#ifdef FEAT_CRYPT
static char *(p_cm_values[]) = {"zip", "blowfish", "blowfish2",
# ifdef FEAT_SODIUM
@@ -34,6 +47,10 @@ static char *(p_cm_values[]) = {"zip", "blowfish", "blowfish2",
NULL};
#endif
static char *(p_cmp_values[]) = {"internal", "keepascii", NULL};
+#ifdef FEAT_SYN_HL
+// Note: Keep this in sync with fill_culopt_flags()
+static char *(p_culopt_values[]) = {"line", "screenline", "number", "both", NULL};
+#endif
static char *(p_dy_values[]) = {"lastline", "truncate", "uhex", NULL};
static char *(p_jop_values[]) = {"stack", NULL};
#ifdef FEAT_FOLDING
@@ -41,6 +58,18 @@ static char *(p_fdo_values[]) = {"all", "block", "hor", "mark", "percent",
"quickfix", "search", "tag", "insert",
"undo", "jump", NULL};
#endif
+// Note: Keep this in sync with match_keyprotocol()
+static char *(p_kpc_protocol_values[]) = {"none", "mok2", "kitty", NULL};
+#ifdef FEAT_PROP_POPUP
+// Note: Keep this in sync with parse_popup_option()
+static char *(p_popup_option_values[]) = {"height:", "width:", "highlight:", "border:", "align:", NULL};
+static char *(p_popup_option_border_values[]) = {"on", "off", NULL};
+static char *(p_popup_option_align_values[]) = {"item", "menu", NULL};
+#endif
+#if defined(FEAT_SPELL)
+// Note: Keep this in sync with spell_check_sps()
+static char *(p_sps_values[]) = {"best", "fast", "double", "expr:", "file:", "timeout:", NULL};
+#endif
#ifdef FEAT_SESSION
// Also used for 'viewoptions'! Keep in sync with SSOP_ flags.
static char *(p_ssop_values[]) = {"buffers", "winpos", "resize", "winsize",
@@ -62,6 +91,8 @@ static char *(p_tbis_values[]) = {"tiny", "small", "medium", "large", "huge", "g
static char *(p_ttym_values[]) = {"xterm", "xterm2", "dec", "netterm", "jsbterm", "pterm", "urxvt", "sgr", NULL};
#endif
static char *(p_ve_values[]) = {"block", "insert", "all", "onemore", "none", "NONE", NULL};
+// Note: Keep this in sync with check_opt_wim()
+static char *(p_wim_values[]) = {"full", "longest", "list", "lastused", NULL};
static char *(p_wop_values[]) = {"fuzzy", "tagfile", "pum", NULL};
#ifdef FEAT_WAK
static char *(p_wak_values[]) = {"yes", "menu", "no", NULL};
@@ -700,6 +731,198 @@ did_set_option_listflag(char_u *val, char_u *flags, char *errbuf)
}
/*
+ * Expand an option that accepts a list of string values.
+ */
+ int
+expand_set_opt_string(
+ optexpand_T *args,
+ char **values,
+ int numValues,
+ int *numMatches,
+ char_u ***matches)
+{
+ char_u *p;
+ regmatch_T *regmatch = args->oe_regmatch;
+ int include_orig_val = args->oe_include_orig_val;
+ char_u *option_val = args->oe_opt_value;
+
+ // Assume numValues is small since they are fixed enums, so just allocate
+ // upfront instead of needing two passes to calculate output size.
+ *matches = ALLOC_MULT(char_u *, numValues + 1);
+ if (*matches == NULL)
+ return FAIL;
+
+ int count = 0;
+
+ if (include_orig_val && *option_val != NUL)
+ {
+ p = vim_strsave(option_val);
+ if (p == NULL)
+ {
+ VIM_CLEAR(*matches);
+ return FAIL;
+ }
+ (*matches)[count++] = p;
+ }
+
+ for (char **val = values; *val != NULL; val++)
+ {
+ if (include_orig_val && *option_val != NUL)
+ {
+ if (STRCMP((char_u*)*val, option_val) == 0)
+ continue;
+ }
+ if (vim_regexec(regmatch, (char_u*)(*val), (colnr_T)0))
+ {
+ p = vim_strsave((char_u*)*val);
+ if (p == NULL)
+ {
+ if (count == 0)
+ {
+ VIM_CLEAR(*matches);
+ return FAIL;
+ }
+ else
+ break;
+ }
+ (*matches)[count++] = p;
+ }
+ }
+ if (count == 0)
+ {
+ VIM_CLEAR(*matches);
+ return FAIL;
+ }
+ *numMatches = count;
+ return OK;
+}
+
+static char_u *set_opt_callback_orig_option = NULL;
+static char_u *((*set_opt_callback_func)(expand_T *, int));
+
+/*
+ * Callback used by expand_set_opt_generic to also include the original value.
+ */
+ static char_u *
+expand_set_opt_callback(expand_T *xp, int idx)
+{
+ if (idx == 0)
+ {
+ if (set_opt_callback_orig_option != NULL)
+ return set_opt_callback_orig_option;
+ else
+ return (char_u *)""; // empty strings are ignored
+ }
+ return set_opt_callback_func(xp, idx - 1);
+}
+
+/*
+ * Expand an option with a callback that iterates through a list of possible names.
+ */
+ int
+expand_set_opt_generic(
+ optexpand_T *args,
+ char_u *((*func)(expand_T *, int)),
+ int *numMatches,
+ char_u ***matches)
+{
+ int ret;
+
+ set_opt_callback_orig_option = args->oe_include_orig_val ?
+ args->oe_opt_value : NULL;
+ set_opt_callback_func = func;
+
+ ret = ExpandGeneric(
+ (char_u*)"", // not using fuzzy as currently EXPAND_STRING_SETTING doesn't use it
+ args->oe_xp,
+ args->oe_regmatch,
+ matches,
+ numMatches,
+ expand_set_opt_callback,
+ FALSE);
+
+ set_opt_callback_orig_option = NULL;
+ set_opt_callback_func = NULL;
+ return ret;
+}
+
+
+/*
+ * Expand an option which is a list of flags.
+ */
+ int
+expand_set_opt_listflag(
+ optexpand_T *args,
+ char_u *flags,
+ int *numMatches,
+ char_u ***matches)
+{
+ char_u *p;
+ char_u *option_val = args->oe_opt_value;
+ char_u *cmdline_val = args->oe_set_arg;
+ int append = args->oe_append;
+ int include_orig_val = args->oe_include_orig_val && (*option_val != NUL);
+
+ int num_flags = STRLEN(flags);
+
+ // Assume we only have small number of flags, so just allocate max size.
+ *matches = ALLOC_MULT(char_u *, num_flags + 1);
+ if (*matches == NULL)
+ return FAIL;
+
+ int count = 0;
+
+ if (include_orig_val)
+ {
+ p = vim_strsave(option_val);
+ if (p == NULL)
+ {
+ VIM_CLEAR(*matches);
+ return FAIL;
+ }
+ (*matches)[count++] = p;
+ }
+
+ for (char_u *flag = flags; *flag != NUL; flag++)
+ {
+ if (append && vim_strchr(option_val, *flag) != NULL)
+ continue;
+
+ if (vim_strchr(cmdline_val, *flag) == NULL)
+ {
+ if (include_orig_val
+ && option_val[1] == NUL
+ && *flag == option_val[0])
+ {
+ // This value is already used as the first choice as it's the
+ // existing flag. Just skip it to avoid duplicate.
+ continue;
+ }
+ p = vim_strnsave(flag, 1);
+ if (p == NULL)
+ {
+ if (count == 0)
+ {
+ VIM_CLEAR(*matches);
+ return FAIL;
+ }
+ else
+ break;
+ }
+ (*matches)[count++] = p;
+ }
+ }
+
+ if (count == 0)
+ {
+ VIM_CLEAR(*matches);
+ return FAIL;
+ }
+ *numMatches = count;
+ return OK;
+}
+
+/*
* The 'ambiwidth' option is changed.
*/
char *
@@ -711,6 +934,17 @@ did_set_ambiwidth(optset_T *args UNUSED)
return check_chars_options();
}
+ int
+expand_set_ambiwidth(optexpand_T *args, int *numMatches, char_u ***matches)
+{
+ return expand_set_opt_string(
+ args,
+ p_ambw_values,
+ sizeof(p_ambw_values) / sizeof(p_ambw_values[0]) - 1,
+ numMatches,
+ matches);
+}
+
/*
* The 'background' option is changed.
*/
@@ -747,6 +981,17 @@ did_set_background(optset_T *args UNUSED)
return NULL;
}
+ int
+expand_set_background(optexpand_T *args, int *numMatches, char_u ***matches)
+{
+ return expand_set_opt_string(
+ args,
+ p_bg_values,
+ sizeof(p_bg_values) / sizeof(p_bg_values[0]) - 1,
+ numMatches,
+ matches);
+}
+
/*
* The 'backspace' option is changed.
*/
@@ -764,6 +1009,17 @@ did_set_backspace(optset_T *args UNUSED)
return NULL;
}
+ int
+expand_set_backspace(optexpand_T *args, int *numMatches, char_u ***matches)
+{
+ return expand_set_opt_string(
+ args,
+ p_bs_values,
+ sizeof(p_bs_values) / sizeof(p_bs_values[0]) - 1,
+ numMatches,
+ matches);
+}
+
/*
* The 'backupcopy' option is changed.
*/
@@ -801,6 +1057,17 @@ did_set_backupcopy(optset_T *args)
return errmsg;
}
+ int
+expand_set_backupcopy(optexpand_T *args, int *numMatches, char_u ***matches)
+{
+ return expand_set_opt_string(
+ args,
+ p_bkc_values,
+ sizeof(p_bkc_values) / sizeof(p_bkc_values[0]) - 1,
+ numMatches,
+ matches);
+}
+
/*
* The 'backupext' or the 'patchmode' option is changed.
*/
@@ -823,6 +1090,17 @@ did_set_belloff(optset_T *args UNUSED)
return did_set_opt_flags(p_bo, p_bo_values, &bo_flags, TRUE);
}
+ int
+expand_set_belloff(optexpand_T *args, int *numMatches, char_u ***matches)
+{
+ return expand_set_opt_string(
+ args,
+ p_bo_values,
+ sizeof(p_bo_values) / sizeof(p_bo_values[0]) - 1,
+ numMatches,
+ matches);
+}
+
#if defined(FEAT_LINEBREAK) || defined(PROTO)
/*
* The 'breakindentopt' option is changed.
@@ -840,6 +1118,17 @@ did_set_breakindentopt(optset_T *args UNUSED)
return errmsg;
}
+
+ int
+expand_set_breakindentopt(optexpand_T *args, int *numMatches, char_u ***matches)
+{
+ return expand_set_opt_string(
+ args,
+ p_briopt_values,
+ sizeof(p_briopt_values) / sizeof(p_briopt_values[0]) - 1,
+ numMatches,
+ matches);
+}
#endif
#if defined(FEAT_BROWSE) || defined(PROTO)
@@ -855,6 +1144,17 @@ did_set_browsedir(optset_T *args UNUSED)
return NULL;
}
+
+ int
+expand_set_browsedir(optexpand_T *args, int *numMatches, char_u ***matches)
+{
+ return expand_set_opt_string(
+ args,
+ p_bsdir_values,
+ sizeof(p_bsdir_values) / sizeof(p_bsdir_values[0]) - 1,
+ numMatches,
+ matches);
+}
#endif
/*
@@ -866,6 +1166,17 @@ did_set_bufhidden(optset_T *args UNUSED)
return did_set_opt_strings(curbuf->b_p_bh, p_bufhidden_values, FALSE);
}
+ int
+expand_set_bufhidden(optexpand_T *args, int *numMatches, char_u ***matches)
+{
+ return expand_set_opt_string(
+ args,
+ p_bufhidden_values,
+ sizeof(p_bufhidden_values) / sizeof(p_bufhidden_values[0]) - 1,
+ numMatches,
+ matches);
+}
+
/*
* The 'buftype' option is changed.
*/
@@ -886,6 +1197,17 @@ did_set_buftype(optset_T *args UNUSED)
return NULL;
}
+ int
+expand_set_buftype(optexpand_T *args, int *numMatches, char_u ***matches)
+{
+ return expand_set_opt_string(
+ args,
+ p_buftype_values,
+ sizeof(p_buftype_values) / sizeof(p_buftype_values[0]) - 1,
+ numMatches,
+ matches);
+}
+
/*
* The 'casemap' option is changed.
*/
@@ -895,6 +1217,30 @@ did_set_casemap(optset_T *args UNUSED)
return did_set_opt_flags(p_cmp, p_cmp_values, &cmp_flags, TRUE);
}
+ int
+expand_set_casemap(optexpand_T *args, int *numMatches, char_u ***matches)
+{
+ return expand_set_opt_string(
+ args,
+ p_cmp_values,
+ sizeof(p_cmp_values) / sizeof(p_cmp_values[0]) - 1,
+ numMatches,
+ matches);
+}
+
+#if defined(FEAT_CLIPBOARD) || defined(PROTO)
+ int
+expand_set_clipboard(optexpand_T *args, int *numMatches, char_u ***matches)
+{
+ return expand_set_opt_string(
+ args,
+ p_cb_values,
+ sizeof(p_cb_values) / sizeof(p_cb_values[0]) - 1,
+ numMatches,
+ matches);
+}
+#endif
+
/*
* The global 'listchars' or 'fillchars' option is changed.
*/
@@ -967,6 +1313,21 @@ did_set_chars_option(optset_T *args)
}
/*
+ * Expand 'fillchars' or 'listchars' option value.
+ */
+ int
+expand_set_chars_option(optexpand_T *args, int *numMatches, char_u ***matches)
+{
+ char_u **varp = (char_u **)args->oe_varp;
+ int is_lcs = (varp == &p_lcs || varp == &curwin->w_p_lcs);
+ return expand_set_opt_generic(
+ args,
+ is_lcs ? get_listchars_name : get_fillchars_name,
+ numMatches,
+ matches);
+}
+
+/*
* The 'cinoptions' option is changed.
*/
char *
@@ -1091,6 +1452,20 @@ did_set_complete(optset_T *args)
return NULL;
}
+ int
+expand_set_complete(optexpand_T *args, int *numMatches, char_u ***matches)
+{
+ static char *(p_cpt_values[]) = {
+ ".", "w", "b", "u", "k", "kspell", "s", "i", "d", "]", "t", "U",
+ NULL};
+ return expand_set_opt_string(
+ args,
+ p_cpt_values,
+ sizeof(p_cpt_values) / sizeof(p_cpt_values[0]) - 1,
+ numMatches,
+ matches);
+}
+
/*
* The 'completeopt' option is changed.
*/
@@ -1104,6 +1479,17 @@ did_set_completeopt(optset_T *args UNUSED)
return NULL;
}
+ int
+expand_set_completeopt(optexpand_T *args, int *numMatches, char_u ***matches)
+{
+ return expand_set_opt_string(
+ args,
+ p_cot_values,
+ sizeof(p_cot_values) / sizeof(p_cot_values[0]) - 1,
+ numMatches,
+ matches);
+}
+
#if (defined(FEAT_PROP_POPUP) && defined(FEAT_QUICKFIX)) || defined(PROTO)
/*
* The 'completepopup' option is changed.
@@ -1132,6 +1518,17 @@ did_set_completeslash(optset_T *args UNUSED)
return NULL;
}
+
+ int
+expand_set_completeslash(optexpand_T *args, int *numMatches, char_u ***matches)
+{
+ return expand_set_opt_string(
+ args,
+ p_csl_values,
+ sizeof(p_csl_values) / sizeof(p_csl_values[0]) - 1,
+ numMatches,
+ matches);
+}
#endif
#if defined(FEAT_CONCEAL) || defined(PROTO)
@@ -1145,6 +1542,12 @@ did_set_concealcursor(optset_T *args)
return did_set_option_listflag(*varp, (char_u *)COCU_ALL, args->os_errbuf);
}
+
+ int
+expand_set_concealcursor(optexpand_T *args, int *numMatches, char_u ***matches)
+{
+ return expand_set_opt_listflag(args, (char_u*)COCU_ALL, numMatches, matches);
+}
#endif
/*
@@ -1158,6 +1561,12 @@ did_set_cpoptions(optset_T *args)
return did_set_option_listflag(*varp, (char_u *)CPO_ALL, args->os_errbuf);
}
+ int
+expand_set_cpoptions(optexpand_T *args, int *numMatches, char_u ***matches)
+{
+ return expand_set_opt_listflag(args, (char_u*)CPO_ALL, numMatches, matches);
+}
+
#if defined(FEAT_CRYPT) || defined(PROTO)
/*
* The 'cryptkey' option is changed.
@@ -1244,6 +1653,17 @@ did_set_cryptmethod(optset_T *args)
}
return NULL;
}
+
+ int
+expand_set_cryptmethod(optexpand_T *args, int *numMatches, char_u ***matches)
+{
+ return expand_set_opt_string(
+ args,
+ p_cm_values,
+ sizeof(p_cm_values) / sizeof(p_cm_values[0]) - 1,
+ numMatches,
+ matches);
+}
#endif
#if (defined(FEAT_CSCOPE) && defined(FEAT_QUICKFIX)) || defined(PROTO)
@@ -1285,11 +1705,23 @@ did_set_cursorlineopt(optset_T *args)
{
char_u **varp = (char_u **)args->os_varp;
+ // This could be changed to use opt_strings_flags() instead.
if (**varp == NUL || fill_culopt_flags(*varp, curwin) != OK)
return e_invalid_argument;
return NULL;
}
+
+ int
+expand_set_cursorlineopt(optexpand_T *args, int *numMatches, char_u ***matches)
+{
+ return expand_set_opt_string(
+ args,
+ p_culopt_values,
+ sizeof(p_culopt_values) / sizeof(p_culopt_values[0]) - 1,
+ numMatches,
+ matches);
+}
#endif
/*
@@ -1301,6 +1733,17 @@ did_set_debug(optset_T *args UNUSED)
return did_set_opt_strings(p_debug, p_debug_values, TRUE);
}
+ int
+expand_set_debug(optexpand_T *args, int *numMatches, char_u ***matches)
+{
+ return expand_set_opt_string(
+ args,
+ p_debug_values,
+ sizeof(p_debug_values) / sizeof(p_debug_values[0]) - 1,
+ numMatches,
+ matches);
+}
+
#if defined(FEAT_DIFF) || defined(PROTO)
/*
* The 'diffopt' option is changed.
@@ -1313,6 +1756,36 @@ did_set_diffopt(optset_T *args UNUSED)
return NULL;
}
+
+ int
+expand_set_diffopt(optexpand_T *args, int *numMatches, char_u ***matches)
+{
+ expand_T *xp = args->oe_xp;
+
+ if (xp->xp_pattern > args->oe_set_arg && *(xp->xp_pattern-1) == ':')
+ {
+ // Within "algorithm:", we have a subgroup of possible options.
+ int algo_len = STRLEN("algorithm:");
+ if (xp->xp_pattern - args->oe_set_arg >= algo_len &&
+ STRNCMP(xp->xp_pattern - algo_len, "algorithm:", algo_len) == 0)
+ {
+ return expand_set_opt_string(
+ args,
+ p_dip_algorithm_values,
+ sizeof(p_dip_algorithm_values) / sizeof(p_dip_algorithm_values[0]) - 1,
+ numMatches,
+ matches);
+ }
+ return FAIL;
+ }
+
+ return expand_set_opt_string(
+ args,
+ p_dip_values,
+ sizeof(p_dip_values) / sizeof(p_dip_values[0]) - 1,
+ numMatches,
+ matches);
+}
#endif
/*
@@ -1328,6 +1801,17 @@ did_set_display(optset_T *args UNUSED)
return NULL;
}
+ int
+expand_set_display(optexpand_T *args, int *numMatches, char_u ***matches)
+{
+ return expand_set_opt_string(
+ args,
+ p_dy_values,
+ sizeof(p_dy_values) / sizeof(p_dy_values[0]) - 1,
+ numMatches,
+ matches);
+}
+
/*
* The 'eadirection' option is changed.
*/
@@ -1337,6 +1821,17 @@ did_set_eadirection(optset_T *args UNUSED)
return did_set_opt_strings(p_ead, p_ead_values, FALSE);
}
+ int
+expand_set_eadirection(optexpand_T *args, int *numMatches, char_u ***matches)
+{
+ return expand_set_opt_string(
+ args,
+ p_ead_values,
+ sizeof(p_ead_values) / sizeof(p_ead_values[0]) - 1,
+ numMatches,
+ matches);
+}
+
/*
* One of the 'encoding', 'fileencoding', 'termencoding' or 'makeencoding'
* options is changed.
@@ -1430,6 +1925,16 @@ did_set_encoding(optset_T *args)
return errmsg;
}
+ int
+expand_set_encoding(optexpand_T *args, int *numMatches, char_u ***matches)
+{
+ return expand_set_opt_generic(
+ args,
+ get_encoding_name,
+ numMatches,
+ matches);
+}
+
/*
* The 'eventignore' option is changed.
*/
@@ -1441,6 +1946,26 @@ did_set_eventignore(optset_T *args UNUSED)
return NULL;
}
+ static char_u *
+get_eventignore_name(expand_T *xp, int idx)
+{
+ // 'eventignore' allows special keyword "all" in addition to
+ // all event names.
+ if (idx == 0)
+ return (char_u *)"all";
+ return get_event_name_no_group(xp, idx - 1);
+}
+
+ int
+expand_set_eventignore(optexpand_T *args, int *numMatches, char_u ***matches)
+{
+ return expand_set_opt_generic(
+ args,
+ get_eventignore_name,
+ numMatches,
+ matches);
+}
+
/*
* The 'fileformat' option is changed.
*/
@@ -1470,6 +1995,17 @@ did_set_fileformat(optset_T *args)
return NULL;
}
+ int
+expand_set_fileformat(optexpand_T *args, int *numMatches, char_u ***matches)
+{
+ return expand_set_opt_string(
+ args,
+ p_ff_values,
+ sizeof(p_ff_values) / sizeof(p_ff_values[0]) - 1,
+ numMatches,
+ matches);
+}
+
/*
* The 'fileformats' option is changed.
*/
@@ -1517,6 +2053,17 @@ did_set_foldclose(optset_T *args UNUSED)
{
return did_set_opt_strings(p_fcl, p_fcl_values, TRUE);
}
+
+ int
+expand_set_foldclose(optexpand_T *args, int *numMatches, char_u ***matches)
+{
+ return expand_set_opt_string(
+ args,
+ p_fcl_values,
+ sizeof(p_fcl_values) / sizeof(p_fcl_values[0]) - 1,
+ numMatches,
+ matches);
+}
#endif
#if (defined(FEAT_EVAL) && defined(FEAT_FOLDING)) || defined(PROTO)
@@ -1583,6 +2130,17 @@ did_set_foldmethod(optset_T *args)
return NULL;
}
+ int
+expand_set_foldmethod(optexpand_T *args, int *numMatches, char_u ***matches)
+{
+ return expand_set_opt_string(
+ args,
+ p_fdm_values,
+ sizeof(p_fdm_values) / sizeof(p_fdm_values[0]) - 1,
+ numMatches,
+ matches);
+}
+
/*
* The 'foldopen' option is changed.
*/
@@ -1591,6 +2149,17 @@ did_set_foldopen(optset_T *args UNUSED)
{
return did_set_opt_flags(p_fdo, p_fdo_values, &fdo_flags, TRUE);
}
+
+ int
+expand_set_foldopen(optexpand_T *args, int *numMatches, char_u ***matches)
+{
+ return expand_set_opt_string(
+ args,
+ p_fdo_values,
+ sizeof(p_fdo_values) / sizeof(p_fdo_values[0]) - 1,
+ numMatches,
+ matches);
+}
#endif
/*
@@ -1604,6 +2173,12 @@ did_set_formatoptions(optset_T *args)
return did_set_option_listflag(*varp, (char_u *)FO_ALL, args->os_errbuf);
}
+ int
+expand_set_formatoptions(optexpand_T *args, int *numMatches, char_u ***matches)
+{
+ return expand_set_opt_listflag(args, (char_u*)FO_ALL, numMatches, matches);
+}
+
#if defined(CURSOR_SHAPE) || defined(PROTO)
/*
* The 'guicursor' option is changed.
@@ -1722,6 +2297,12 @@ did_set_guioptions(optset_T *args)
gui_init_which_components(args->os_oldval.string);
return NULL;
}
+
+ int
+expand_set_guioptions(optexpand_T *args, int *numMatches, char_u ***matches)
+{
+ return expand_set_opt_listflag(args, (char_u*)GO_ALL, numMatches, matches);
+}
#endif
#if defined(FEAT_GUI_TABLINE) || defined(PROTO)
@@ -1788,6 +2369,125 @@ did_set_highlight(optset_T *args UNUSED)
}
/*
+ * Expand 'highlight' option.
+ */
+ int
+expand_set_highlight(optexpand_T *args, int *numMatches, char_u ***matches)
+{
+ char_u *p;
+ expand_T *xp = args->oe_xp;
+ static char_u hl_flags[HLF_COUNT] = HL_FLAGS;
+ int i;
+ int count = 0;
+
+ if (xp->xp_pattern > args->oe_set_arg && *(xp->xp_pattern-1) == ':')
+ {
+ // Right after a ':', meaning we just return all highlight names.
+ return expand_set_opt_generic(
+ args,
+ get_highlight_name,
+ numMatches,
+ matches);
+ }
+
+ if (*xp->xp_pattern == NUL)
+ {
+ // At beginning of a comma-separated list. Return the specific list of
+ // supported occasions.
+ *matches = ALLOC_MULT(char_u *, HLF_COUNT + 1);
+ if (*matches == NULL)
+ return FAIL;
+
+ // We still want to return the full option if it's requested.
+ if (args->oe_include_orig_val)
+ {
+ p = vim_strsave(args->oe_opt_value);
+ if (p == NULL)
+ {
+ VIM_CLEAR(*matches);
+ return FAIL;
+ }
+ (*matches)[count++] = p;
+ }
+
+ for (i = 0; i < HLF_COUNT; i++)
+ {
+ p = vim_strnsave(&hl_flags[i], 1);
+ if (p == NULL)
+ {
+ if (count == 0)
+ {
+ VIM_CLEAR(*matches);
+ return FAIL;
+ }
+ else
+ break;
+ }
+ (*matches)[count++] = p;
+ }
+
+ if (count == 0)
+ {
+ VIM_CLEAR(*matches);
+ return FAIL;
+ }
+ *numMatches = count;
+ return OK;
+ }
+
+ // We are after the initial character (which indicates the occasion). We
+ // already made sure we are not matching after a ':' above, so now we want
+ // to match against display mode modifiers.
+ // Since the xp_pattern starts from the beginning, we need to include it in
+ // the returned match.
+
+ // Note: Keep this in sync with highlight_changed()
+ static char p_hl_mode_values[] =
+ {':', 'b', 'i', '-', 'n', 'r', 's', 'u', 'c', '2', 'd', '=', 't'};
+ int num_hl_modes = sizeof(p_hl_mode_values) / sizeof(p_hl_mode_values[0]);
+
+ *matches = ALLOC_MULT(char_u *, num_hl_modes);
+ if (*matches == NULL)
+ return FAIL;
+
+ int pattern_len = STRLEN(xp->xp_pattern);
+
+ for (i = 0; i < num_hl_modes; i++)
+ {
+ // Don't allow duplicates as these are unique flags
+ if (vim_strchr(xp->xp_pattern + 1, p_hl_mode_values[i]) != NULL)
+ continue;
+
+ // ':' only works by itself, not with other flags.
+ if (pattern_len > 1 && p_hl_mode_values[i] == ':')
+ continue;
+
+ p = vim_strnsave(xp->xp_pattern, pattern_len + 1);
+ if (p == NULL)
+ {
+ if (i == 0)
+ {
+ VIM_CLEAR(*matches);
+ return FAIL;
+ }
+ else
+ break;
+ }
+ p[pattern_len] = p_hl_mode_values[i];
+ p[pattern_len + 1] = NUL;
+ (*matches)[count++] = p;
+ }
+ if (count == 0)
+ {
+ VIM_CLEAR(*matches);
+ return FAIL;
+ }
+ *numMatches = count;
+
+ return OK;
+}
+
+/*
* The 'titlestring' or the 'iconstring' option is changed.
*/
static char *
@@ -1866,6 +2566,17 @@ did_set_jumpoptions(optset_T *args UNUSED)
return NULL;
}
+ int
+expand_set_jumpoptions(optexpand_T *args, int *numMatches, char_u ***matches)
+{
+ return expand_set_opt_string(
+ args,
+ p_jop_values,
+ sizeof(p_jop_values) / sizeof(p_jop_values[0]) - 1,
+ numMatches,
+ matches);
+}
+
#if defined(FEAT_KEYMAP) || defined(PROTO)
/*
* The 'keymap' option is changed.
@@ -1939,6 +2650,17 @@ did_set_keymodel(optset_T *args UNUSED)
return NULL;
}
+ int
+expand_set_keymodel(optexpand_T *args, int *numMatches, char_u ***matches)
+{
+ return expand_set_opt_string(
+ args,
+ p_km_values,
+ sizeof(p_km_values) / sizeof(p_km_values[0]) - 1,
+ numMatches,
+ matches);
+}
+
/*
* The 'keyprotocol' option is changed.
*/
@@ -1955,6 +2677,27 @@ did_set_keyprotocol(optset_T *args UNUSED)
return NULL;
}
+ int
+expand_set_keyprotocol(optexpand_T *args, int *numMatches, char_u ***matches)
+{
+ expand_T *xp = args->oe_xp;
+ if (xp->xp_pattern > args->oe_set_arg && *(xp->xp_pattern-1) == ':')
+ {
+ // 'keyprotocol' only has well-defined terms for completion for the
+ // protocol part after the colon.
+ return expand_set_opt_string(
+ args,
+ p_kpc_protocol_values,
+ sizeof(p_kpc_protocol_values) / sizeof(p_kpc_protocol_values[0]) - 1,
+ numMatches,
+ matches);
+ }
+ // Use expand_set_opt_string instead of returning FAIL so that we can
+ // include the original value if args->oe_include_orig_val is set.
+ static char *(empty[]) = {NULL};
+ return expand_set_opt_string(args, empty, 0, numMatches, matches);
+}
+
/*
* The 'lispoptions' option is changed.
*/
@@ -1971,6 +2714,18 @@ did_set_lispoptions(optset_T *args)
return NULL;
}
+ int
+expand_set_lispoptions(optexpand_T *args, int *numMatches, char_u ***matches)
+{
+ static char *(p_lop_values[]) = {"expr:0", "expr:1", NULL};
+ return expand_set_opt_string(
+ args,
+ p_lop_values,
+ sizeof(p_lop_values) / sizeof(p_lop_values[0]) - 1,
+ numMatches,
+ matches);
+}
+
/*
* The 'matchpairs' option is changed.
*/
@@ -2042,6 +2797,12 @@ did_set_mouse(optset_T *args)
args->os_errbuf);
}
+ int
+expand_set_mouse(optexpand_T *args, int *numMatches, char_u ***matches)
+{
+ return expand_set_opt_listflag(args, (char_u*)MOUSE_ALL, numMatches, matches);
+}
+
/*
* The 'mousemodel' option is changed.
*/
@@ -2060,6 +2821,17 @@ did_set_mousemodel(optset_T *args UNUSED)
return NULL;
}
+ int
+expand_set_mousemodel(optexpand_T *args, int *numMatches, char_u ***matches)
+{
+ return expand_set_opt_string(
+ args,
+ p_mousem_values,
+ sizeof(p_mousem_values) / sizeof(p_mousem_values[0]) - 1,
+ numMatches,
+ matches);
+}
+
#if defined(FEAT_MOUSESHAPE) || defined(PROTO)
char *
did_set_mouseshape(optset_T *args UNUSED)
@@ -2084,6 +2856,17 @@ did_set_nrformats(optset_T *args)
return did_set_opt_strings(*varp, p_nf_values, TRUE);
}
+ int
+expand_set_nrformats(optexpand_T *args, int *numMatches, char_u ***matches)
+{
+ return expand_set_opt_string(
+ args,
+ p_nf_values,
+ sizeof(p_nf_values) / sizeof(p_nf_values[0]) - 1,
+ numMatches,
+ matches);
+}
+
#if defined(FEAT_EVAL) || defined(PROTO)
/*
* One of the '*expr' options is changed: 'balloonexpr', 'diffexpr',
@@ -2144,6 +2927,58 @@ did_set_previewpopup(optset_T *args UNUSED)
return NULL;
}
+
+ int
+expand_set_popupoption(optexpand_T *args, int *numMatches, char_u ***matches)
+{
+ expand_T *xp = args->oe_xp;
+
+ if (xp->xp_pattern > args->oe_set_arg && *(xp->xp_pattern-1) == ':')
+ {
+ // Within "highlight:"/"border:"/"align:", we have a subgroup of possible options.
+ int border_len = STRLEN("border:");
+ if (xp->xp_pattern - args->oe_set_arg >= border_len &&
+ STRNCMP(xp->xp_pattern - border_len, "border:", border_len) == 0)
+ {
+ return expand_set_opt_string(
+ args,
+ p_popup_option_border_values,
+ sizeof(p_popup_option_border_values) / sizeof(p_popup_option_border_values[0]) - 1,
+ numMatches,
+ matches);
+ }
+ int align_len = STRLEN("align:");
+ if (xp->xp_pattern - args->oe_set_arg >= align_len &&
+ STRNCMP(xp->xp_pattern - align_len, "align:", align_len) == 0)
+ {
+ return expand_set_opt_string(
+ args,
+ p_popup_option_align_values,
+ sizeof(p_popup_option_align_values) / sizeof(p_popup_option_align_values[0]) - 1,
+ numMatches,
+ matches);
+ }
+ int highlight_len = STRLEN("highlight:");
+ if (xp->xp_pattern - args->oe_set_arg >= highlight_len &&
+ STRNCMP(xp->xp_pattern - highlight_len, "highlight:", highlight_len) == 0)
+ {
+ // Return the list of all highlight names
+ return expand_set_opt_generic(
+ args,
+ get_highlight_name,
+ numMatches,
+ matches);
+ }
+ return FAIL;
+ }
+
+ return expand_set_opt_string(
+ args,
+ p_popup_option_values,
+ sizeof(p_popup_option_values) / sizeof(p_popup_option_values[0]) - 1,
+ numMatches,
+ matches);
+}
#endif
#if defined(FEAT_POSTSCRIPT) || defined(PROTO)
@@ -2178,6 +3013,30 @@ did_set_printencoding(optset_T *args UNUSED)
}
#endif
+#if defined(FEAT_PRINTER) || defined(PROTO)
+
+ static char_u *
+get_printoptions_names(expand_T *xp UNUSED, int idx)
+{
+ if (idx >= (int)(sizeof(printer_opts) / sizeof(printer_opts[0])))
+ return NULL;
+ return (char_u*)printer_opts[idx].name;
+}
+
+/*
+ * Expand 'printoptions' option
+ */
+ int
+expand_set_printoptions(optexpand_T *args, int *numMatches, char_u ***matches)
+{
+ return expand_set_opt_generic(
+ args,
+ get_printoptions_names,
+ numMatches,
+ matches);
+}
+#endif
+