diff options
| author | Josh Rahm <joshuarahm@gmail.com> | 2024-03-09 14:57:57 -0700 |
|---|---|---|
| committer | Josh Rahm <joshuarahm@gmail.com> | 2024-03-09 14:57:57 -0700 |
| commit | c324271b99eee4c621463f368914d57cd729bd9c (patch) | |
| tree | 5d979d333a2d5f9c080991d5482fd5916f8579c6 /src/nvim/option.c | |
| parent | 931bffbda3668ddc609fc1da8f9eb576b170aa52 (diff) | |
| parent | ade1b12f49c3b3914c74847d791eb90ea90b56b7 (diff) | |
| download | rneovim-c324271b99eee4c621463f368914d57cd729bd9c.tar.gz rneovim-c324271b99eee4c621463f368914d57cd729bd9c.tar.bz2 rneovim-c324271b99eee4c621463f368914d57cd729bd9c.zip | |
Merge remote-tracking branch 'upstream/master' into userreg
Diffstat (limited to 'src/nvim/option.c')
| -rw-r--r-- | src/nvim/option.c | 1897 |
1 files changed, 995 insertions, 902 deletions
diff --git a/src/nvim/option.c b/src/nvim/option.c index 69f02bf2f6..d5df8385f8 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -1,8 +1,7 @@ // User-settable options. Checklist for adding a new option: // - Put it in options.lua -// - For a global option: Add a variable for it in option_defs.h. +// - For a global option: Add a variable for it in option_vars.h. // - For a buffer or window local option: -// - Add a BV_XX or WV_XX entry to option_defs.h // - Add a variable to the window or buffer struct in buffer_defs.h. // - For a window option, add some code to copy_winopt(). // - For a window string option, add code to check_winopt() @@ -12,7 +11,7 @@ // - For a buffer string option, add code to check_buf_options(). // - If it's a numeric option, add any necessary bounds checks to check_num_option_bounds(). // - If it's a list of flags, add some code in do_set(), search for WW_ALL. -// - Add documentation! doc/options.txt, and any other related places. +// - Add documentation! "desc" in options.lua, and any other related places. // - Add an entry in runtime/optwin.vim. #define IN_OPTION_C @@ -31,29 +30,35 @@ #include "nvim/api/private/helpers.h" #include "nvim/api/private/validate.h" #include "nvim/ascii_defs.h" +#include "nvim/assert_defs.h" #include "nvim/autocmd.h" +#include "nvim/autocmd_defs.h" #include "nvim/buffer.h" +#include "nvim/buffer_defs.h" #include "nvim/change.h" #include "nvim/charset.h" #include "nvim/cmdexpand.h" #include "nvim/cmdexpand_defs.h" #include "nvim/cursor_shape.h" +#include "nvim/decoration_defs.h" #include "nvim/decoration_provider.h" #include "nvim/diff.h" #include "nvim/drawscreen.h" #include "nvim/eval.h" #include "nvim/eval/typval.h" #include "nvim/eval/vars.h" +#include "nvim/eval/window.h" #include "nvim/ex_cmds_defs.h" #include "nvim/ex_docmd.h" #include "nvim/ex_getln.h" #include "nvim/ex_session.h" #include "nvim/fold.h" -#include "nvim/func_attr.h" #include "nvim/garray.h" -#include "nvim/gettext.h" +#include "nvim/garray_defs.h" +#include "nvim/gettext_defs.h" #include "nvim/globals.h" #include "nvim/highlight.h" +#include "nvim/highlight_defs.h" #include "nvim/highlight_group.h" #include "nvim/indent.h" #include "nvim/indent_c.h" @@ -63,6 +68,7 @@ #include "nvim/lua/executor.h" #include "nvim/macros_defs.h" #include "nvim/mapping.h" +#include "nvim/math.h" #include "nvim/mbyte.h" #include "nvim/memfile.h" #include "nvim/memline.h" @@ -79,13 +85,14 @@ #include "nvim/os/input.h" #include "nvim/os/lang.h" #include "nvim/os/os.h" +#include "nvim/os/os_defs.h" #include "nvim/path.h" #include "nvim/popupmenu.h" #include "nvim/pos_defs.h" #include "nvim/regexp.h" +#include "nvim/regexp_defs.h" #include "nvim/runtime.h" #include "nvim/search.h" -#include "nvim/sign_defs.h" #include "nvim/spell.h" #include "nvim/spellfile.h" #include "nvim/spellsuggest.h" @@ -95,7 +102,9 @@ #include "nvim/terminal.h" #include "nvim/types_defs.h" #include "nvim/ui.h" +#include "nvim/ui_defs.h" #include "nvim/undo.h" +#include "nvim/undo_defs.h" #include "nvim/vim_defs.h" #include "nvim/window.h" @@ -109,8 +118,6 @@ static const char e_not_allowed_in_modeline[] = N_("E520: Not allowed in a modeline"); static const char e_not_allowed_in_modeline_when_modelineexpr_is_off[] = N_("E992: Not allowed in a modeline when 'modelineexpr' is off"); -static const char e_key_code_not_set[] - = N_("E846: Key code not set"); static const char e_number_required_after_equal[] = N_("E521: Number required after ="); static const char e_preview_window_already_exists[] @@ -146,30 +153,28 @@ typedef enum { # include "option.c.generated.h" #endif -// options[] is initialized here. -// The order of the options MUST be alphabetic for ":set all" and findoption(). -// All option names MUST start with a lowercase letter (for findoption()). -// Exception: "t_" options are at the end. +// options[] is initialized in options.generated.h. // The options with a NULL variable are 'hidden': a set command for them is // ignored and they are not printed. #ifdef INCLUDE_GENERATED_DECLARATIONS # include "options.generated.h" +# include "options_map.generated.h" #endif -static char *(p_bin_dep_opts[]) = { - "textwidth", "wrapmargin", "modeline", "expandtab", NULL +static int p_bin_dep_opts[] = { + kOptTextwidth, kOptWrapmargin, kOptModeline, kOptExpandtab, kOptInvalid }; -static char *(p_paste_dep_opts[]) = { - "autoindent", "expandtab", "ruler", "showmatch", "smarttab", - "softtabstop", "textwidth", "wrapmargin", "revins", "varsofttabstop", NULL + +static int p_paste_dep_opts[] = { + kOptAutoindent, kOptExpandtab, kOptRuler, kOptShowmatch, kOptSmarttab, kOptSofttabstop, + kOptTextwidth, kOptWrapmargin, kOptRevins, kOptVarsofttabstop, kOptInvalid }; void set_init_tablocal(void) { // susy baka: cmdheight calls itself OPT_GLOBAL but is really tablocal! - int ch_idx = findoption("cmdheight"); - p_ch = (OptInt)(intptr_t)options[ch_idx].def_val; + p_ch = options[kOptCmdheight].def_val.number; } /// Initialize the 'shell' option to a default value. @@ -183,9 +188,9 @@ static void set_init_default_shell(void) const size_t len = strlen(shell) + 3; // two quotes and a trailing NUL char *const cmd = xmalloc(len); snprintf(cmd, len, "\"%s\"", shell); - set_string_default("sh", cmd, true); + set_string_default(kOptShell, cmd, true); } else { - set_string_default("sh", (char *)shell, false); + set_string_default(kOptShell, (char *)shell, false); } } } @@ -200,7 +205,7 @@ static void set_init_default_backupskip(void) static char *(names[3]) = { "TMPDIR", "TEMP", "TMP" }; #endif garray_T ga; - int opt_idx = findoption("backupskip"); + OptIndex opt_idx = kOptBackupskip; ga_init(&ga, 1, 100); for (size_t n = 0; n < ARRAY_SIZE(names); n++) { @@ -214,7 +219,7 @@ static void set_init_default_backupskip(void) p = "/tmp"; # endif mustfree = false; - } else // NOLINT(readability/braces) + } else #endif { p = vim_getenv(names[n]); @@ -244,7 +249,7 @@ static void set_init_default_backupskip(void) } } if (ga.ga_data != NULL) { - set_string_default("bsk", ga.ga_data, true); + set_string_default(kOptBackupskip, ga.ga_data, true); } } @@ -270,13 +275,8 @@ static void set_init_default_cdpath(void) } } buf[j] = NUL; - int opt_idx = findoption("cdpath"); - if (opt_idx >= 0) { - options[opt_idx].def_val = buf; - options[opt_idx].flags |= P_DEF_ALLOCED; - } else { - xfree(buf); // cannot happen - } + options[kOptCdpath].def_val.string = buf; + options[kOptCdpath].flags |= P_DEF_ALLOCED; xfree(cdpath); } @@ -289,7 +289,7 @@ static void set_init_default_cdpath(void) /// default. static void set_init_expand_env(void) { - for (int opt_idx = 0; options[opt_idx].fullname; opt_idx++) { + for (OptIndex opt_idx = 0; opt_idx < kOptIndexCount; opt_idx++) { vimoption_T *opt = &options[opt_idx]; if (opt->flags & P_NO_DEF_EXP) { continue; @@ -304,9 +304,9 @@ static void set_init_expand_env(void) p = xstrdup(p); *(char **)opt->var = p; if (opt->flags & P_DEF_ALLOCED) { - xfree(opt->def_val); + xfree(opt->def_val.string); } - opt->def_val = p; + opt->def_val.string = p; opt->flags |= P_DEF_ALLOCED; } } @@ -347,20 +347,20 @@ void set_init_1(bool clean_arg) backupdir = xrealloc(backupdir, backupdir_len + 3); memmove(backupdir + 2, backupdir, backupdir_len + 1); memmove(backupdir, ".,", 2); - set_string_default("backupdir", backupdir, true); - set_string_default("viewdir", stdpaths_user_state_subpath("view", 2, true), + set_string_default(kOptBackupdir, backupdir, true); + set_string_default(kOptViewdir, stdpaths_user_state_subpath("view", 2, true), true); - set_string_default("directory", stdpaths_user_state_subpath("swap", 2, true), + set_string_default(kOptDirectory, stdpaths_user_state_subpath("swap", 2, true), true); - set_string_default("undodir", stdpaths_user_state_subpath("undo", 2, true), + set_string_default(kOptUndodir, stdpaths_user_state_subpath("undo", 2, true), true); // Set default for &runtimepath. All necessary expansions are performed in // this function. char *rtp = runtimepath_default(clean_arg); if (rtp) { - set_string_default("runtimepath", rtp, true); + set_string_default(kOptRuntimepath, rtp, true); // Make a copy of 'rtp' for 'packpath' - set_string_default("packpath", rtp, false); + set_string_default(kOptPackpath, rtp, false); rtp = NULL; // ownership taken } @@ -375,9 +375,6 @@ void set_init_1(bool clean_arg) check_win_options(curwin); check_options(); - // Set all options to their default value - set_options_default(OPT_FREE); - // set 'laststatus' last_status(false); @@ -399,7 +396,7 @@ void set_init_1(bool clean_arg) // NOTE: mlterm's author is being asked to 'set' a variable // instead of an environment variable due to inheritance. if (os_env_exists("MLTERM")) { - set_option_value_give_err("tbidi", BOOLEAN_OPTVAL(true), 0); + set_option_value_give_err(kOptTermbidi, BOOLEAN_OPTVAL(true), 0); } didset_options2(); @@ -420,33 +417,35 @@ void set_init_1(bool clean_arg) /// Set an option to its default value. /// This does not take care of side effects! /// -/// @param opt_flags OPT_FREE, OPT_LOCAL and/or OPT_GLOBAL -static void set_option_default(const int opt_idx, int opt_flags) +/// @param opt_flags OPT_FREE, OPT_LOCAL and/or OPT_GLOBAL. +/// +/// TODO(famiu): Refactor this when def_val uses OptVal. +static void set_option_default(const OptIndex opt_idx, int opt_flags) { - int both = (opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0; + bool both = (opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0; // pointer to variable for current option vimoption_T *opt = &options[opt_idx]; void *varp = get_varp_scope(opt, both ? OPT_LOCAL : opt_flags); uint32_t flags = opt->flags; if (varp != NULL) { // skip hidden option, nothing to do for it - if (flags & P_STRING) { - // Use set_string_option_direct() for local options to handle - // freeing and allocating the value. + if (option_has_type(opt_idx, kOptValTypeString)) { + // Use set_string_option_direct() for local options to handle freeing and allocating the + // value. if (opt->indir != PV_NONE) { - set_string_option_direct(NULL, opt_idx, opt->def_val, opt_flags, 0); + set_string_option_direct(opt_idx, opt->def_val.string, opt_flags, 0); } else { - if ((opt_flags & OPT_FREE) && (flags & P_ALLOCED)) { + if (flags & P_ALLOCED) { free_string_option(*(char **)(varp)); } - *(char **)varp = opt->def_val; + *(char **)varp = opt->def_val.string; opt->flags &= ~P_ALLOCED; } - } else if (flags & P_NUM) { + } else if (option_has_type(opt_idx, kOptValTypeNumber)) { if (opt->indir == PV_SCROLL) { win_comp_scroll(curwin); } else { - OptInt def_val = (OptInt)(intptr_t)opt->def_val; + OptInt def_val = opt->def_val.number; if ((OptInt *)varp == &curwin->w_p_so || (OptInt *)varp == &curwin->w_p_siso) { // 'scrolloff' and 'sidescrolloff' local values have a @@ -460,8 +459,8 @@ static void set_option_default(const int opt_idx, int opt_flags) *(OptInt *)get_varp_scope(opt, OPT_GLOBAL) = def_val; } } - } else { // P_BOOL - *(int *)varp = (int)(intptr_t)opt->def_val; + } else { // boolean + *(int *)varp = opt->def_val.boolean; #ifdef UNIX // 'modeline' defaults to off for root if (opt->indir == PV_ML && getuid() == ROOT_UID) { @@ -480,17 +479,17 @@ static void set_option_default(const int opt_idx, int opt_flags) *flagsp = *flagsp & ~P_INSECURE; } - set_option_sctx_idx(opt_idx, opt_flags, current_sctx); + set_option_sctx(opt_idx, opt_flags, current_sctx); } /// Set all options (except terminal options) to their default value. /// -/// @param opt_flags OPT_FREE, OPT_LOCAL and/or OPT_GLOBAL +/// @param opt_flags Option flags. static void set_options_default(int opt_flags) { - for (int i = 0; options[i].fullname; i++) { - if (!(options[i].flags & P_NODEFAULT)) { - set_option_default(i, opt_flags); + for (OptIndex opt_idx = 0; opt_idx < kOptIndexCount; opt_idx++) { + if (!(options[opt_idx].flags & P_NODEFAULT)) { + set_option_default(opt_idx, opt_flags); } } @@ -505,22 +504,23 @@ static void set_options_default(int opt_flags) /// Set the Vi-default value of a string option. /// Used for 'sh', 'backupskip' and 'term'. /// -/// @param name The name of the option -/// @param val The value of the option -/// @param allocated If true, do not copy default as it was already allocated. -static void set_string_default(const char *name, char *val, bool allocated) +/// @param opt_idx Option index in options[] table. +/// @param val The value of the option. +/// @param allocated If true, do not copy default as it was already allocated. +static void set_string_default(OptIndex opt_idx, char *val, bool allocated) FUNC_ATTR_NONNULL_ALL { - int opt_idx = findoption(name); - if (opt_idx >= 0) { - vimoption_T *opt = &options[opt_idx]; - if (opt->flags & P_DEF_ALLOCED) { - xfree(opt->def_val); - } + if (opt_idx == kOptInvalid) { + return; + } - opt->def_val = allocated ? val : xstrdup(val); - opt->flags |= P_DEF_ALLOCED; + vimoption_T *opt = &options[opt_idx]; + if (opt->flags & P_DEF_ALLOCED) { + xfree(opt->def_val.string); } + + opt->def_val.string = allocated ? val : xstrdup(val); + opt->flags |= P_DEF_ALLOCED; } /// For an option value that contains comma separated items, find "newval" in @@ -556,11 +556,10 @@ static char *find_dup_item(char *origval, const char *newval, uint32_t flags) /// Set the Vi-default value of a number option. /// Used for 'lines' and 'columns'. -void set_number_default(char *name, OptInt val) +void set_number_default(OptIndex opt_idx, OptInt val) { - int opt_idx = findoption(name); - if (opt_idx >= 0) { - options[opt_idx].def_val = (void *)(intptr_t)val; + if (opt_idx != kOptInvalid) { + options[opt_idx].def_val.number = val; } } @@ -568,22 +567,25 @@ void set_number_default(char *name, OptInt val) /// Free all options. void free_all_options(void) { - for (int i = 0; options[i].fullname; i++) { - if (options[i].indir == PV_NONE) { + for (OptIndex opt_idx = 0; opt_idx < kOptIndexCount; opt_idx++) { + if (options[opt_idx].indir == PV_NONE) { // global option: free value and default value. - if ((options[i].flags & P_ALLOCED) && options[i].var != NULL) { - optval_free(optval_from_varp(i, options[i].var)); + if ((options[opt_idx].flags & P_ALLOCED) && options[opt_idx].var != NULL) { + optval_free(optval_from_varp(opt_idx, options[opt_idx].var)); } - if (options[i].flags & P_DEF_ALLOCED) { - optval_free(optval_from_varp(i, &options[i].def_val)); + if (options[opt_idx].flags & P_DEF_ALLOCED) { + optval_free(optval_from_varp(opt_idx, &options[opt_idx].def_val)); } - } else if (options[i].var != VAR_WIN) { + } else if (options[opt_idx].var != VAR_WIN) { // buffer-local option: free global value - optval_free(optval_from_varp(i, options[i].var)); + optval_free(optval_from_varp(opt_idx, options[opt_idx].var)); } } free_operatorfunc_option(); free_tagfunc_option(); + XFREE_CLEAR(fenc_default); + XFREE_CLEAR(p_term); + XFREE_CLEAR(p_ttytype); } #endif @@ -595,18 +597,17 @@ void set_init_2(bool headless) // 'scroll' defaults to half the window height. The stored default is zero, // which results in the actual value computed from the window height. - int idx = findoption("scroll"); - if (idx >= 0 && !(options[idx].flags & P_WAS_SET)) { - set_option_default(idx, OPT_LOCAL); + if (!(options[kOptScroll].flags & P_WAS_SET)) { + set_option_default(kOptScroll, OPT_LOCAL); } comp_col(); // 'window' is only for backwards compatibility with Vi. // Default is Rows - 1. - if (!option_was_set("window")) { + if (!option_was_set(kOptWindow)) { p_window = Rows - 1; } - set_number_default("window", Rows - 1); + set_number_default(kOptWindow, Rows - 1); } /// Initialize the options, part three: After reading the .vimrc @@ -617,14 +618,8 @@ void set_init_3(void) // Set 'shellpipe' and 'shellredir', depending on the 'shell' option. // This is done after other initializations, where 'shell' might have been // set, but only if they have not been set before. - int idx_srr = findoption("srr"); - int do_srr = (idx_srr < 0) - ? false - : !(options[idx_srr].flags & P_WAS_SET); - int idx_sp = findoption("sp"); - int do_sp = (idx_sp < 0) - ? false - : !(options[idx_sp].flags & P_WAS_SET); + bool do_srr = !(options[kOptShellredir].flags & P_WAS_SET); + bool do_sp = !(options[kOptShellpipe].flags & P_WAS_SET); size_t len = 0; char *p = (char *)invocation_path_tail(p_sh, &len); @@ -639,11 +634,11 @@ void set_init_3(void) || path_fnamecmp(p, "tcsh") == 0) { if (do_sp) { p_sp = "|& tee"; - options[idx_sp].def_val = p_sp; + options[kOptShellpipe].def_val.string = p_sp; } if (do_srr) { p_srr = ">&"; - options[idx_srr].def_val = p_srr; + options[kOptShellredir].def_val.string = p_srr; } } else if (path_fnamecmp(p, "sh") == 0 || path_fnamecmp(p, "ksh") == 0 @@ -658,18 +653,18 @@ void set_init_3(void) // Always use POSIX shell style redirection if we reach this if (do_sp) { p_sp = "2>&1| tee"; - options[idx_sp].def_val = p_sp; + options[kOptShellpipe].def_val.string = p_sp; } if (do_srr) { p_srr = ">%s 2>&1"; - options[idx_srr].def_val = p_srr; + options[kOptShellredir].def_val.string = p_srr; } } xfree(p); } if (buf_is_empty(curbuf)) { - int idx_ffs = findoption_len(S_LEN("ffs")); + int idx_ffs = find_option("ffs"); // Apply the first entry of 'fileformats' to the initial buffer. if (idx_ffs >= 0 && (options[idx_ffs].flags & P_WAS_SET)) { @@ -692,12 +687,11 @@ void set_helplang_default(const char *lang) if (lang_len < 2) { // safety check return; } - int idx = findoption("hlg"); - if (idx < 0 || (options[idx].flags & P_WAS_SET)) { + if (options[kOptHelplang].flags & P_WAS_SET) { return; } - if (options[idx].flags & P_ALLOCED) { + if (options[kOptHelplang].flags & P_ALLOCED) { free_string_option(p_hlg); } p_hlg = xmemdupz(lang, lang_len); @@ -711,7 +705,7 @@ void set_helplang_default(const char *lang) p_hlg[1] = 'n'; } p_hlg[2] = NUL; - options[idx].flags |= P_ALLOCED; + options[kOptHelplang].flags |= P_ALLOCED; } /// 'title' and 'icon' only default to true if they have not been set or reset @@ -724,15 +718,13 @@ void set_title_defaults(void) // If GUI is (going to be) used, we can always set the window title and // icon name. Saves a bit of time, because the X11 display server does // not need to be contacted. - int idx1 = findoption("title"); - if (idx1 >= 0 && !(options[idx1].flags & P_WAS_SET)) { - options[idx1].def_val = 0; - p_title = 0; + if (!(options[kOptTitle].flags & P_WAS_SET)) { + options[kOptTitle].def_val.boolean = false; + p_title = false; } - idx1 = findoption("icon"); - if (idx1 >= 0 && !(options[idx1].flags & P_WAS_SET)) { - options[idx1].def_val = 0; - p_icon = 0; + if (!(options[kOptIcon].flags & P_WAS_SET)) { + options[kOptIcon].def_val.boolean = false; + p_icon = false; } } @@ -748,13 +740,13 @@ void ex_set(exarg_T *eap) if (eap->forceit) { flags |= OPT_ONECOLUMN; } - (void)do_set(eap->arg, flags); + do_set(eap->arg, flags); } /// Get the default value for a string option. -static char *stropt_get_default_val(int opt_idx, uint64_t flags) +static char *stropt_get_default_val(OptIndex opt_idx, uint64_t flags) { - char *newval = options[opt_idx].def_val; + char *newval = options[opt_idx].def_val.string; // expand environment variables and ~ since the default value was // already expanded, only required when an environment variable was set // later @@ -773,8 +765,7 @@ static char *stropt_get_default_val(int opt_idx, uint64_t flags) } /// Copy the new string value into allocated memory for the option. -/// Can't use set_string_option_direct(), because we need to remove the -/// backslashes. +/// Can't use set_string_option_direct(), because we need to remove the backslashes. static char *stropt_copy_value(char *origval, char **argp, set_op_T op, uint32_t flags FUNC_ATTR_UNUSED) { @@ -822,7 +813,7 @@ static char *stropt_copy_value(char *origval, char **argp, set_op_T op, } /// Expand environment variables and ~ in string option value 'newval'. -static char *stropt_expand_envvar(int opt_idx, char *origval, char *newval, set_op_T op) +static char *stropt_expand_envvar(OptIndex opt_idx, char *origval, char *newval, set_op_T op) { char *s = option_expand(opt_idx, newval); if (s == NULL) { @@ -922,8 +913,8 @@ static void stropt_remove_dupflags(char *newval, uint32_t flags) /// set {opt}< /// set {opt}={val} /// set {opt}:{val} -static char *stropt_get_newval(int nextchar, int opt_idx, char **argp, void *varp, char *origval, - set_op_T *op_arg, uint32_t flags) +static char *stropt_get_newval(int nextchar, OptIndex opt_idx, char **argp, void *varp, + char *origval, set_op_T *op_arg, uint32_t flags) { char *arg = *argp; set_op_T op = *op_arg; @@ -1024,81 +1015,23 @@ static set_prefix_T get_option_prefix(char **argp) return PREFIX_NONE; } -/// @param[in] arg Pointer to start option name -/// @param[out] opt_idxp Option index in options[] table. -/// @param[out] keyp -/// @param[out] len Length of option name -/// @return FAIL if an error is detected, OK otherwise -static int parse_option_name(char *arg, int *keyp, int *lenp, int *opt_idxp) -{ - // find end of name - int key = 0; - int len; - int opt_idx; - - if (*arg == '<') { - opt_idx = -1; - // look out for <t_>;> - if (arg[1] == 't' && arg[2] == '_' && arg[3] && arg[4]) { - len = 5; - } else { - len = 1; - while (arg[len] != NUL && arg[len] != '>') { - len++; - } - } - if (arg[len] != '>') { - return FAIL; - } - if (arg[1] == 't' && arg[2] == '_') { // could be term code - opt_idx = findoption_len(arg + 1, (size_t)(len - 1)); - } - len++; - if (opt_idx == -1) { - key = find_key_option(arg + 1, true); - } - } else { - // The two characters after "t_" may not be alphanumeric. - if (arg[0] == 't' && arg[1] == '_' && arg[2] && arg[3]) { - len = 4; - } else { - len = 0; - while (ASCII_ISALNUM(arg[len]) || arg[len] == '_') { - len++; - } - } - opt_idx = findoption_len(arg, (size_t)len); - if (opt_idx == -1) { - key = find_key_option(arg, false); - } - } - - *keyp = key; - *lenp = len; - *opt_idxp = opt_idx; - - return OK; -} - -static int validate_opt_idx(win_T *win, int opt_idx, int opt_flags, uint32_t flags, +static int validate_opt_idx(win_T *win, OptIndex opt_idx, int opt_flags, uint32_t flags, set_prefix_T prefix, const char **errmsg) { // Only bools can have a prefix of 'inv' or 'no' - if (!(flags & P_BOOL) && prefix != PREFIX_NONE) { + if (!option_has_type(opt_idx, kOptValTypeBoolean) && prefix != PREFIX_NONE) { *errmsg = e_invarg; return FAIL; } // Skip all options that are not window-local (used when showing // an already loaded buffer in a window). - if ((opt_flags & OPT_WINONLY) - && (opt_idx < 0 || options[opt_idx].var != VAR_WIN)) { + if ((opt_flags & OPT_WINONLY) && (opt_idx == kOptInvalid || options[opt_idx].var != VAR_WIN)) { return FAIL; } // Skip all options that are window-local (used for :vimgrep). - if ((opt_flags & OPT_NOWIN) && opt_idx >= 0 - && options[opt_idx].var == VAR_WIN) { + if ((opt_flags & OPT_NOWIN) && opt_idx != kOptInvalid && options[opt_idx].var == VAR_WIN) { return FAIL; } @@ -1116,7 +1049,7 @@ static int validate_opt_idx(win_T *win, int opt_idx, int opt_flags, uint32_t fla // 'foldmethod' becomes "marker" instead of "diff" and that // "wrap" gets set. if (win->w_p_diff - && opt_idx >= 0 // shut up coverity warning + && opt_idx != kOptInvalid // shut up coverity warning && (options[opt_idx].indir == PV_FDM || options[opt_idx].indir == PV_WRAP)) { return FAIL; @@ -1132,8 +1065,79 @@ static int validate_opt_idx(win_T *win, int opt_idx, int opt_flags, uint32_t fla return OK; } +/// Skip over the name of a TTY option or keycode option. +/// +/// @param[in] arg Start of TTY or keycode option name. +/// +/// @return NULL when option isn't a TTY or keycode option. Otherwise pointer to the char after the +/// option name. +static const char *find_tty_option_end(const char *arg) +{ + if (strequal(arg, "term")) { + return arg + sizeof("term") - 1; + } else if (strequal(arg, "ttytype")) { + return arg + sizeof("ttytype") - 1; + } + + const char *p = arg; + bool delimit = false; // whether to delimit < + + if (arg[0] == '<') { + // look out for <t_>;> + delimit = true; + p++; + } + if (p[0] == 't' && p[1] == '_' && p[2] && p[3]) { + p += 4; + } else if (delimit) { + // Search for delimiting >. + while (*p != NUL && *p != '>') { + p++; + } + } + // Return NULL when delimiting > is not found. + if (delimit) { + if (*p != '>') { + return NULL; + } + p++; + } + + return arg == p ? NULL : p; +} + +/// Skip over the name of an option. +/// +/// @param[in] arg Start of option name. +/// @param[out] opt_idxp Set to option index in options[] table. +/// +/// @return NULL when no option name found. Otherwise pointer to the char after the option name. +const char *find_option_end(const char *arg, OptIndex *opt_idxp) +{ + const char *p; + + // Handle TTY and keycode options separately. + if ((p = find_tty_option_end(arg)) != NULL) { + *opt_idxp = kOptInvalid; + return p; + } else { + p = arg; + } + + if (!ASCII_ISALPHA(*p)) { + *opt_idxp = kOptInvalid; + return NULL; + } + while (ASCII_ISALPHA(*p)) { + p++; + } + + *opt_idxp = find_option_len(arg, (size_t)(p - arg)); + return p; +} + /// Get new option value from argp. Allocated OptVal must be freed by caller. -static OptVal get_option_newval(int opt_idx, int opt_flags, set_prefix_T prefix, char **argp, +static OptVal get_option_newval(OptIndex opt_idx, int opt_flags, set_prefix_T prefix, char **argp, int nextchar, set_op_T op, uint32_t flags, void *varp, char *errbuf, const size_t errbuflen, const char **errmsg) FUNC_ATTR_WARN_UNUSED_RESULT @@ -1169,7 +1173,7 @@ static OptVal get_option_newval(int opt_idx, int opt_flags, set_prefix_T prefix, break; } } else if (nextchar == '&') { - newval_bool = TRISTATE_FROM_INT((int)(intptr_t)options[opt_idx].def_val); + newval_bool = TRISTATE_FROM_INT(options[opt_idx].def_val.boolean); } else if (nextchar == '<') { // For 'autoread', kNone means to use global value. if ((int *)varp == &curbuf->b_p_ar && opt_flags == OPT_LOCAL) { @@ -1203,7 +1207,7 @@ static OptVal get_option_newval(int opt_idx, int opt_flags, set_prefix_T prefix, // other error arg++; if (nextchar == '&') { - newval_num = (OptInt)(intptr_t)options[opt_idx].def_val; + newval_num = options[opt_idx].def_val.number; } else if (nextchar == '<') { if ((OptInt *)varp == &curbuf->b_p_ul && opt_flags == OPT_LOCAL) { // for 'undolevels' NO_LOCAL_UNDOLEVEL means using the global newval_num @@ -1271,61 +1275,56 @@ static void do_one_set_option(int opt_flags, char **argp, bool *did_show, char * char *arg = *argp; // find end of name - int key = 0; - int len; - int opt_idx; - if (parse_option_name(arg, &key, &len, &opt_idx) == FAIL) { - *errmsg = e_invarg; + OptIndex opt_idx; + const char *const option_end = find_option_end(arg, &opt_idx); + + if (opt_idx != kOptInvalid) { + assert(option_end >= arg); + } else if (is_tty_option(arg)) { // Silently ignore TTY options. + return; + } else { // Invalid option name, skip. + *errmsg = e_unknown_option; return; } - // remember character after option name - int afterchar = (uint8_t)arg[len]; + // Remember character after option name. + uint8_t afterchar = (uint8_t)(*option_end); + char *p = (char *)option_end; - // skip white space, allow ":set ai ?" - while (ascii_iswhite(arg[len])) { - len++; + // Skip white space, allow ":set ai ?". + while (ascii_iswhite(*p)) { + p++; } - set_op_T op = get_op(arg + len); + set_op_T op = get_op(p); if (op != OP_NONE) { - len++; - } - - uint8_t nextchar = (uint8_t)arg[len]; // next non-white char after option name - - if (opt_idx == -1 && key == 0) { // found a mismatch: skip - *errmsg = e_unknown_option; - return; + p++; } - uint32_t flags; // flags for current option + uint8_t nextchar = (uint8_t)(*p); // next non-white char after option name + uint32_t flags = 0; // flags for current option void *varp = NULL; // pointer to variable for current option - if (opt_idx >= 0) { - if (options[opt_idx].var == NULL) { // hidden option: skip - // Only give an error message when requesting the value of - // a hidden option, ignore setting it. - if (vim_strchr("=:!&<", nextchar) == NULL - && (!(options[opt_idx].flags & P_BOOL) - || nextchar == '?')) { - *errmsg = e_unsupportedoption; - } - return; + if (options[opt_idx].var == NULL) { // hidden option: skip + // Only give an error message when requesting the value of + // a hidden option, ignore setting it. + if (vim_strchr("=:!&<", nextchar) == NULL + && (!option_has_type(opt_idx, kOptValTypeBoolean) || nextchar == '?')) { + *errmsg = e_unsupportedoption; } - - flags = options[opt_idx].flags; - varp = get_varp_scope(&(options[opt_idx]), opt_flags); - } else { - flags = P_STRING; + return; } + flags = options[opt_idx].flags; + varp = get_varp_scope(&(options[opt_idx]), opt_flags); + if (validate_opt_idx(curwin, opt_idx, opt_flags, flags, prefix, errmsg) == FAIL) { return; } if (vim_strchr("?=:!&<", nextchar) != NULL) { - *argp += len; + *argp = p; + if (nextchar == '&' && (*argp)[1] == 'v' && (*argp)[2] == 'i') { if ((*argp)[3] == 'm') { // "opt&vim": set to Vim default *argp += 3; @@ -1340,14 +1339,10 @@ static void do_one_set_option(int opt_flags, char **argp, bool *did_show, char * } } - // - // allow '=' and ':' as MS-DOS command.com allows only one - // '=' character per "set" command line. grrr. (jw) - // + // Allow '=' and ':' as MS-DOS command.com allows only one '=' character per "set" command line. if (nextchar == '?' - || (prefix == PREFIX_NONE - && vim_strchr("=:&<", nextchar) == NULL - && !(flags & P_BOOL))) { + || (prefix == PREFIX_NONE && vim_strchr("=:&<", nextchar) == NULL + && !option_has_type(opt_idx, kOptValTypeBoolean))) { // print value if (*did_show) { msg_putchar('\n'); // cursor below last one @@ -1355,29 +1350,26 @@ static void do_one_set_option(int opt_flags, char **argp, bool *did_show, char * gotocmdline(true); // cursor at status line *did_show = true; // remember that we did a line } - if (opt_idx >= 0) { - showoneopt(&options[opt_idx], opt_flags); - if (p_verbose > 0) { - // Mention where the option was last set. - if (varp == options[opt_idx].var) { - option_last_set_msg(options[opt_idx].last_set); - } else if ((int)options[opt_idx].indir & PV_WIN) { - option_last_set_msg(curwin->w_p_script_ctx[(int)options[opt_idx].indir & PV_MASK]); - } else if ((int)options[opt_idx].indir & PV_BUF) { - option_last_set_msg(curbuf->b_p_script_ctx[(int)options[opt_idx].indir & PV_MASK]); - } + showoneopt(&options[opt_idx], opt_flags); + + if (p_verbose > 0) { + // Mention where the option was last set. + if (varp == options[opt_idx].var) { + option_last_set_msg(options[opt_idx].last_set); + } else if ((int)options[opt_idx].indir & PV_WIN) { + option_last_set_msg(curwin->w_p_script_ctx[(int)options[opt_idx].indir & PV_MASK]); + } else if ((int)options[opt_idx].indir & PV_BUF) { + option_last_set_msg(curbuf->b_p_script_ctx[(int)options[opt_idx].indir & PV_MASK]); } - } else { - *errmsg = e_key_code_not_set; - return; } + if (nextchar != '?' && nextchar != NUL && !ascii_iswhite(afterchar)) { *errmsg = e_trailing; } return; } - if (flags & P_BOOL) { + if (option_has_type(opt_idx, kOptValTypeBoolean)) { if (vim_strchr("=:", nextchar) != NULL) { *errmsg = e_invarg; return; @@ -1441,7 +1433,7 @@ int do_set(char *arg, int opt_flags) if (*arg == '&') { arg++; // Only for :set command set global value of local options. - set_options_default(OPT_FREE | opt_flags); + set_options_default(opt_flags); didset_options(); didset_options2(); ui_refresh_options(); @@ -1453,7 +1445,7 @@ int do_set(char *arg, int opt_flags) } else { char *startarg = arg; // remember for error message const char *errmsg = NULL; - char errbuf[80]; + char errbuf[ERR_BUFLEN]; do_one_set_option(opt_flags, &arg, &did_show, errbuf, sizeof(errbuf), &errmsg); @@ -1497,21 +1489,45 @@ int do_set(char *arg, int opt_flags) if (silent_mode && did_show) { // After displaying option values in silent mode. |