diff options
author | Lewis Russell <lewis6991@gmail.com> | 2025-01-10 10:20:43 +0000 |
---|---|---|
committer | Lewis Russell <me@lewisr.dev> | 2025-01-13 16:58:25 +0000 |
commit | 34e2185022ab698827b72751d77e218a1b6b6afe (patch) | |
tree | 9b8c0fe0a24b77a60e1e6511cfb3e2135b7789af /src/nvim | |
parent | cb7b4e296238b46025de05203c886d67da401728 (diff) | |
download | rneovim-34e2185022ab698827b72751d77e218a1b6b6afe.tar.gz rneovim-34e2185022ab698827b72751d77e218a1b6b6afe.tar.bz2 rneovim-34e2185022ab698827b72751d77e218a1b6b6afe.zip |
fix(options): better handling of empty values
Problem:
Whether an option is allowed to be empty isn't well defined and
isn't properly checked.
Solution:
- For non-list string options, explicitly check the option value
if it is empty.
- Annotate non-list string options that can accept an empty value.
- Adjust command completion to ignore the empty value.
- Render values in Lua meta files
Diffstat (limited to 'src/nvim')
-rw-r--r-- | src/nvim/options.lua | 17 | ||||
-rw-r--r-- | src/nvim/optionstr.c | 16 |
2 files changed, 22 insertions, 11 deletions
diff --git a/src/nvim/options.lua b/src/nvim/options.lua index 15a4e8ddc2..2425dcb93e 100644 --- a/src/nvim/options.lua +++ b/src/nvim/options.lua @@ -7,7 +7,7 @@ --- @field alias? string|string[] --- @field short_desc? string|fun(): string --- @field varname? string ---- @field type vim.option_type|vim.option_type[] +--- @field type vim.option_type --- @field immutable? boolean --- @field list? 'comma'|'onecomma'|'commacolon'|'onecommacolon'|'flags'|'flagscomma' --- @field scope vim.option_scope[] @@ -834,7 +834,7 @@ return { abbreviation = 'bh', cb = 'did_set_bufhidden', defaults = { if_true = '' }, - values = { 'hide', 'unload', 'delete', 'wipe' }, + values = { '', 'hide', 'unload', 'delete', 'wipe' }, desc = [=[ This option specifies what happens when a buffer is no longer displayed in a window: @@ -888,11 +888,12 @@ return { cb = 'did_set_buftype', defaults = { if_true = '' }, values = { + '', + 'acwrite', + 'help', 'nofile', 'nowrite', 'quickfix', - 'help', - 'acwrite', 'terminal', 'prompt', }, @@ -1554,7 +1555,7 @@ return { abbreviation = 'csl', cb = 'did_set_completeslash', defaults = { if_true = '' }, - values = { 'slash', 'backslash' }, + values = { '', 'slash', 'backslash' }, desc = [=[ only modifiable in MS-Windows When this option is set it overrules 'shellslash' for completion: @@ -2017,8 +2018,10 @@ return { "msg" and "throw" are useful for debugging 'foldexpr', 'formatexpr' or 'indentexpr'. ]=], + -- TODO(lewis6991): bug, values currently cannot be combined expand_cb = 'expand_set_debug', full_name = 'debug', + list = 'comma', scope = { 'global' }, short_desc = N_('to "msg" to see all error messages'), type = 'string', @@ -4299,7 +4302,7 @@ return { abbreviation = 'icm', cb = 'did_set_inccommand', defaults = { if_true = 'nosplit' }, - values = { 'nosplit', 'split' }, + values = { 'nosplit', 'split', '' }, desc = [=[ When nonempty, shows the effects of |:substitute|, |:smagic|, |:snomagic| and user commands with the |:command-preview| flag as you @@ -5735,7 +5738,7 @@ return { abbreviation = 'mousem', cb = 'did_set_mousemodel', defaults = { if_true = 'popup_setpos' }, - values = { 'extend', 'popup', 'popup_setpos', 'mac' }, + values = { 'extend', 'popup', 'popup_setpos' }, desc = [=[ Sets the model to use for the mouse. The name mostly specifies what the right mouse button is used for: diff --git a/src/nvim/optionstr.c b/src/nvim/optionstr.c index 9b7b50ae04..eac9ea02e0 100644 --- a/src/nvim/optionstr.c +++ b/src/nvim/optionstr.c @@ -395,7 +395,9 @@ static int expand_set_opt_string(optexpand_T *args, const char **values, size_t } for (const char **val = values; *val != NULL; val++) { - if (include_orig_val && *option_val != NUL) { + if (**val == NUL) { + continue; // Ignore empty + } else if (include_orig_val && *option_val != NUL) { if (strcmp(*val, option_val) == 0) { continue; } @@ -1091,7 +1093,7 @@ int expand_set_cursorlineopt(optexpand_T *args, int *numMatches, char ***matches /// The 'debug' option is changed. const char *did_set_debug(optset_T *args FUNC_ATTR_UNUSED) { - return did_set_opt_strings(p_debug, opt_debug_values, false); + return did_set_opt_strings(p_debug, opt_debug_values, true); } int expand_set_debug(optexpand_T *args, int *numMatches, char ***matches) @@ -2545,7 +2547,7 @@ int expand_set_winhighlight(optexpand_T *args, int *numMatches, char ***matches) /// @param list when true: accept a list of values /// /// @return OK for correct value, FAIL otherwise. Empty is always OK. -static int check_opt_strings(char *val, const char **values, int list) +static int check_opt_strings(char *val, const char **values, bool list) { return opt_strings_flags(val, values, NULL, list); } @@ -2562,7 +2564,10 @@ static int opt_strings_flags(const char *val, const char **values, unsigned *fla { unsigned new_flags = 0; - while (*val) { + // If not list and val is empty, then force one iteration of the while loop + bool iter_one = (*val == NUL) && !list; + + while (*val || iter_one) { for (unsigned i = 0;; i++) { if (values[i] == NULL) { // val not found in values[] return FAIL; @@ -2577,6 +2582,9 @@ static int opt_strings_flags(const char *val, const char **values, unsigned *fla break; // check next item in val list } } + if (iter_one) { + break; + } } if (flagp != NULL) { *flagp = new_flags; |