aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/option.c
diff options
context:
space:
mode:
authorJosh Rahm <joshuarahm@gmail.com>2024-03-09 14:57:57 -0700
committerJosh Rahm <joshuarahm@gmail.com>2024-03-09 14:57:57 -0700
commitc324271b99eee4c621463f368914d57cd729bd9c (patch)
tree5d979d333a2d5f9c080991d5482fd5916f8579c6 /src/nvim/option.c
parent931bffbda3668ddc609fc1da8f9eb576b170aa52 (diff)
parentade1b12f49c3b3914c74847d791eb90ea90b56b7 (diff)
downloadrneovim-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.c1897
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.