aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFamiu Haque <famiuhaque@proton.me>2023-09-27 23:30:17 +0600
committerFamiu Haque <famiuhaque@proton.me>2023-10-17 00:08:47 +0600
commit93b9c889465ee6a55e71c1fd681c1c6b1d5ed060 (patch)
treeb1cf69e4b844c5c67b005a980d0d09a8a67e15c3
parent0892c1cd94672e0dffe3b97fc4a85ea517b05598 (diff)
downloadrneovim-93b9c889465ee6a55e71c1fd681c1c6b1d5ed060.tar.gz
rneovim-93b9c889465ee6a55e71c1fd681c1c6b1d5ed060.tar.bz2
rneovim-93b9c889465ee6a55e71c1fd681c1c6b1d5ed060.zip
refactor(options): unify set_num_option and set_bool_option
-rw-r--r--src/nvim/api/options.c41
-rw-r--r--src/nvim/eval/vars.c5
-rw-r--r--src/nvim/option.c488
-rw-r--r--src/nvim/optionstr.c3
-rw-r--r--src/nvim/types.h2
5 files changed, 253 insertions, 286 deletions
diff --git a/src/nvim/api/options.c b/src/nvim/api/options.c
index 867d1d5e5c..498638d606 100644
--- a/src/nvim/api/options.c
+++ b/src/nvim/api/options.c
@@ -133,47 +133,6 @@ static buf_T *do_ft_buf(char *filetype, aco_save_T *aco, Error *err)
return ftbuf;
}
-/// Consume an OptVal and convert it to an API Object.
-static Object optval_as_object(OptVal o)
-{
- switch (o.type) {
- case kOptValTypeNil:
- return NIL;
- case kOptValTypeBoolean:
- switch (o.data.boolean) {
- case kFalse:
- case kTrue:
- return BOOLEAN_OBJ(o.data.boolean);
- case kNone:
- return NIL;
- }
- UNREACHABLE;
- case kOptValTypeNumber:
- return INTEGER_OBJ(o.data.number);
- case kOptValTypeString:
- return STRING_OBJ(o.data.string);
- }
- UNREACHABLE;
-}
-
-/// Consume an API Object and convert it to an OptVal.
-static OptVal object_as_optval(Object o, bool *error)
-{
- switch (o.type) {
- case kObjectTypeNil:
- return NIL_OPTVAL;
- case kObjectTypeBoolean:
- return BOOLEAN_OPTVAL(o.data.boolean);
- case kObjectTypeInteger:
- return NUMBER_OPTVAL((OptInt)o.data.integer);
- case kObjectTypeString:
- return STRING_OPTVAL(o.data.string);
- default:
- *error = true;
- return NIL_OPTVAL;
- }
-}
-
/// Gets the value of an option. The behavior of this function matches that of
/// |:set|: the local value of an option is returned if it exists; otherwise,
/// the global value is returned. Local values always correspond to the current
diff --git a/src/nvim/eval/vars.c b/src/nvim/eval/vars.c
index f9dcfb3d9d..4b314ca338 100644
--- a/src/nvim/eval/vars.c
+++ b/src/nvim/eval/vars.c
@@ -822,7 +822,7 @@ static char *ex_let_option(char *arg, typval_T *const tv, const bool is_const,
if (curval.type == kOptValTypeNumber) {
newval = NUMBER_OPTVAL(new_n);
} else {
- newval = BOOLEAN_OPTVAL(new_n == 0 ? kFalse : (new_n >= 1 ? kTrue : kNone));
+ newval = BOOLEAN_OPTVAL(TRISTATE_FROM_INT(new_n));
}
} else if (!hidden && is_string
&& curval.data.string.data != NULL && newval.data.string.data != NULL) { // string
@@ -1875,8 +1875,7 @@ static OptVal tv_to_optval(typval_T *tv, const char *option, uint32_t flags, boo
semsg(_("E521: Number required: &%s = '%s'"), option, tv->vval.v_string);
}
}
- value = (flags & P_NUM) ? NUMBER_OPTVAL((OptInt)n)
- : BOOLEAN_OPTVAL(n == 0 ? kFalse : (n >= 1 ? kTrue : kNone));
+ value = (flags & P_NUM) ? NUMBER_OPTVAL((OptInt)n) : BOOLEAN_OPTVAL(TRISTATE_FROM_INT(n));
} else if ((flags & P_STRING) || is_tty_option(option)) {
// Avoid setting string option to a boolean or a special value.
if (tv->v_type != VAR_BOOL && tv->v_type != VAR_SPECIAL) {
diff --git a/src/nvim/option.c b/src/nvim/option.c
index 4b50f27ef2..156a13af81 100644
--- a/src/nvim/option.c
+++ b/src/nvim/option.c
@@ -13,8 +13,7 @@
// add some code to didset_window_options().
// - For a buffer option, add some code to buf_copy_options().
// - For a buffer string option, add code to check_buf_options().
-// - If it's a numeric option, add any necessary bounds checks to
-// set_num_option().
+// - 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 an entry in runtime/optwin.vim.
@@ -782,7 +781,10 @@ static void do_set_bool(int opt_idx, int opt_flags, set_prefix_T prefix, int nex
}
}
- *errmsg = set_bool_option(opt_idx, (void *)varp, (int)value, opt_flags);
+ static char errbuf[IOSIZE];
+ size_t errbuflen = sizeof(errbuf);
+ *errmsg = set_option(opt_idx, (void *)varp, BOOLEAN_OPTVAL(TRISTATE_FROM_INT(value)), opt_flags,
+ errbuf, errbuflen);
}
static void do_set_num(int opt_idx, int opt_flags, char **argp, int nextchar, const set_op_T op,
@@ -846,8 +848,8 @@ static void do_set_num(int opt_idx, int opt_flags, char **argp, int nextchar, co
if (op == OP_REMOVING) {
value = *(OptInt *)varp - value;
}
- *errmsg = set_num_option(opt_idx, (void *)varp, value,
- errbuf, errbuflen, opt_flags);
+ *errmsg
+ = set_option(opt_idx, (void *)varp, NUMBER_OPTVAL((OptInt)value), opt_flags, errbuf, errbuflen);
}
/// Get the default value for a string option.
@@ -2019,22 +2021,22 @@ static void apply_optionset_autocmd(int opt_idx, int opt_flags, OptInt oldval, O
}
/// Ensure that options set to p_force_on cannot be disabled.
-static const char *did_set_force_on(bool *doskip)
+static const char *did_set_force_on(optset_T *args FUNC_ATTR_UNUSED)
{
if (p_force_on == false) {
p_force_on = true;
- *doskip = true;
+ args->os_doskip = true;
return e_unsupportedoption;
}
return NULL;
}
/// Ensure that options set to p_force_off cannot be enabled.
-static const char *did_set_force_off(bool *doskip)
+static const char *did_set_force_off(optset_T *args FUNC_ATTR_UNUSED)
{
if (p_force_off == true) {
p_force_off = false;
- *doskip = true;
+ args->os_doskip = true;
return e_unsupportedoption;
}
return NULL;
@@ -2833,100 +2835,11 @@ static const char *did_set_wrap(optset_T *args)
}
return NULL;
}
-
-/// Set the value of a boolean option, taking care of side effects
-///
-/// @param[in] opt_idx Option index in options[] table.
-/// @param[out] varp Pointer to the option variable.
-/// @param[in] value New value.
-/// @param[in] opt_flags OPT_LOCAL and/or OPT_GLOBAL.
-///
-/// @return NULL on success, error message on error.
-static const char *set_bool_option(const int opt_idx, char *const varp, const int value,
- const int opt_flags)
-{
- int old_value = *(int *)varp;
- int old_global_value = 0;
-
- // Disallow changing some options from secure mode
- if ((secure || sandbox != 0)
- && (options[opt_idx].flags & P_SECURE)) {
- return e_secure;
- }
-
- // Save the global value before changing anything. This is needed as for
- // a global-only option setting the "local value" in fact sets the global
- // value (since there is only one value).
- if ((opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0) {
- old_global_value = *(int *)get_varp_scope(&(options[opt_idx]), OPT_GLOBAL);
- }
-
- *(int *)varp = value; // set the new value
- // Remember where the option was set.
- set_option_sctx_idx(opt_idx, opt_flags, current_sctx);
-
- // May set global value for local option.
- if ((opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0) {
- *(int *)get_varp_scope(&(options[opt_idx]), OPT_GLOBAL) = value;
- }
-
- // Handle side effects for changing a bool option.
- const char *errmsg = NULL;
- bool doskip = false;
- if ((int *)varp == &p_force_on) {
- errmsg = did_set_force_on(&doskip);
- } else if ((int *)varp == &p_force_off) {
- errmsg = did_set_force_off(&doskip);
- } else if (options[opt_idx].opt_did_set_cb != NULL) {
- optset_T args = {
- .os_varp = varp,
- .os_flags = opt_flags,
- .os_oldval.boolean = old_value,
- .os_newval.boolean = value,
- .os_doskip = false,
- .os_errbuf = NULL,
- .os_errbuflen = 0,
- .os_buf = curbuf,
- .os_win = curwin
- };
-
- errmsg = options[opt_idx].opt_did_set_cb(&args);
- doskip = args.os_doskip;
- }
- if (doskip) {
- return errmsg;
- }
-
- // after handling side effects, call autocommand
-
- options[opt_idx].flags |= P_WAS_SET;
-
- apply_optionset_autocmd(opt_idx, opt_flags,
- (old_value ? true : false),
- (old_global_value ? true : false),
- (value ? true : false), NULL);
-
- if (options[opt_idx].flags & P_UI_OPTION) {
- ui_call_option_set(cstr_as_string(options[opt_idx].fullname),
- BOOLEAN_OBJ(*varp));
- }
- if ((int *)varp == &p_ru || (int *)varp == &p_sc) {
- // in case 'ruler' or 'showcmd' changed
- comp_col();
- }
- if (curwin->w_curswant != MAXCOL
- && (options[opt_idx].flags & (P_CURSWANT | P_RALL)) != 0) {
- curwin->w_set_curswant = true;
- }
- check_redraw(options[opt_idx].flags);
-
- return errmsg;
-}
-
/// Check the bounds of numeric options.
-static const char *check_num_option_bounds(OptInt *pp, OptInt old_value, int old_Rows, char *errbuf,
+static const char *check_num_option_bounds(OptInt *pp, OptInt old_value, char *errbuf,
size_t errbuflen, const char *errmsg)
{
+ int old_Rows = Rows; // remember old Rows
// Check the (new) bounds for Rows and Columns here.
if (p_lines < min_rows() && full_screen) {
if (errbuf != NULL) {
@@ -3150,91 +3063,6 @@ static const char *validate_num_option(const OptInt *pp, OptInt *valuep)
return NULL;
}
-/// Set the value of a number option, taking care of side effects
-///
-/// @param[in] opt_idx Option index in options[] table.
-/// @param[out] varp Pointer to the option variable.
-/// @param[in] value New value.
-/// @param errbuf Buffer for error messages.
-/// @param[in] errbuflen Length of `errbuf`.
-/// @param[in] opt_flags OPT_LOCAL, OPT_GLOBAL or OPT_MODELINE.
-///
-/// @return NULL on success, error message on error.
-static const char *set_num_option(int opt_idx, void *varp, OptInt value, char *errbuf,
- size_t errbuflen, int opt_flags)
-{
- OptInt old_value = *(OptInt *)varp;
- OptInt old_global_value = 0; // only used when setting a local and global option
- int old_Rows = Rows; // remember old Rows
- OptInt *pp = (OptInt *)varp;
-
- // Disallow changing some options from secure mode.
- if ((secure || sandbox != 0) && (options[opt_idx].flags & P_SECURE)) {
- return e_secure;
- }
-
- // Save the global value before changing anything. This is needed as for
- // a global-only option setting the "local value" in fact sets the global
- // value (since there is only one value).
- if ((opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0) {
- old_global_value = *(OptInt *)get_varp_scope(&(options[opt_idx]), OPT_GLOBAL);
- }
-
- const char *errmsg = validate_num_option(pp, &value);
-
- // Don't change the value and return early if validation failed.
- if (errmsg != NULL) {
- return errmsg;
- }
-
- *pp = value;
- // Remember where the option was set.
- set_option_sctx_idx(opt_idx, opt_flags, current_sctx);
-
- // Invoke the option specific callback function to validate and apply the
- // new value.
- if (options[opt_idx].opt_did_set_cb != NULL) {
- optset_T args = {
- .os_varp = varp,
- .os_flags = opt_flags,
- .os_oldval.number = old_value,
- .os_newval.number = value,
- .os_errbuf = NULL,
- .os_errbuflen = 0,
- .os_buf = curbuf,
- .os_win = curwin
- };
- errmsg = options[opt_idx].opt_did_set_cb(&args);
- }
-
- // Check the bounds for numeric options here
- errmsg = check_num_option_bounds(pp, old_value, old_Rows, errbuf, errbuflen, errmsg);
-
- // May set global value for local option.
- if ((opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0) {
- *(OptInt *)get_varp_scope(&(options[opt_idx]), OPT_GLOBAL) = *pp;
- }
-
- options[opt_idx].flags |= P_WAS_SET;
-
- apply_optionset_autocmd(opt_idx, opt_flags, old_value, old_global_value,
- (int)value, errmsg);
-
- if (errmsg == NULL && options[opt_idx].flags & P_UI_OPTION) {
- ui_call_option_set(cstr_as_string(options[opt_idx].fullname),
- INTEGER_OBJ(*pp));
- }
-
- comp_col(); // in case 'columns' or 'ls' changed
- if (curwin->w_curswant != MAXCOL
- && (options[opt_idx].flags & (P_CURSWANT | P_RALL)) != 0) {
- curwin->w_set_curswant = true;
- }
- check_redraw(options[opt_idx].flags);
-
- return errmsg;
-}
-
/// Called after an option changed: check if something needs to be redrawn.
void check_redraw_for(buf_T *buf, win_T *win, uint32_t flags)
{
@@ -3465,8 +3293,8 @@ OptVal optval_copy(OptVal o)
UNREACHABLE;
}
-// Match type of OptVal with the type of the target option. Returns true if the types match and
-// false otherwise.
+/// Match type of OptVal with the type of the target option. Returns true if the types match and
+/// false otherwise.
static bool optval_match_type(OptVal o, int opt_idx)
{
assert(opt_idx >= 0);
@@ -3485,7 +3313,42 @@ static bool optval_match_type(OptVal o, int opt_idx)
UNREACHABLE;
}
-// Return C-string representation of OptVal. Caller must free the returned C-string.
+/// Create OptVal from var pointer.
+static OptVal optval_from_varp(OptValType type, void *varp)
+{
+ switch (type) {
+ case kOptValTypeNil:
+ return NIL_OPTVAL;
+ case kOptValTypeBoolean:
+ return BOOLEAN_OPTVAL(TRISTATE_FROM_INT(*(int *)varp));
+ case kOptValTypeNumber:
+ return NUMBER_OPTVAL(*(OptInt *)varp);
+ case kOptValTypeString:
+ return STRING_OPTVAL(cstr_as_string(*(char **)varp));
+ }
+ UNREACHABLE;
+}
+
+/// Set option var pointer value from Optval.
+static void set_option_varp(void *varp, OptVal value)
+{
+ switch (value.type) {
+ case kOptValTypeNil:
+ return;
+ case kOptValTypeBoolean:
+ *(int *)varp = value.data.boolean;
+ return;
+ case kOptValTypeNumber:
+ *(OptInt *)varp = value.data.number;
+ return;
+ case kOptValTypeString:
+ *(char **)varp = value.data.string.data;
+ return;
+ }
+ UNREACHABLE;
+}
+
+/// Return C-string representation of OptVal. Caller must free the returned C-string.
static char *optval_to_cstr(OptVal o)
{
switch (o.type) {
@@ -3507,10 +3370,91 @@ static char *optval_to_cstr(OptVal o)
UNREACHABLE;
}
-// Get an allocated string containing a list of valid types for an option.
-// For options with a singular type, it returns the name of the type. For options with multiple
-// possible types, it returns a slash separated list of types. For example, if an option can be a
-// number, boolean or string, the function returns "Number/Boolean/String"
+/// Consume an OptVal and convert it to an API Object.
+Object optval_as_object(OptVal o)
+{
+ switch (o.type) {
+ case kOptValTypeNil:
+ return NIL;
+ case kOptValTypeBoolean:
+ switch (o.data.boolean) {
+ case kFalse:
+ case kTrue:
+ return BOOLEAN_OBJ(o.data.boolean);
+ case kNone:
+ return NIL;
+ }
+ UNREACHABLE;
+ case kOptValTypeNumber:
+ return INTEGER_OBJ(o.data.number);
+ case kOptValTypeString:
+ return STRING_OBJ(o.data.string);
+ }
+ UNREACHABLE;
+}
+
+/// Consume an API Object and convert it to an OptVal.
+OptVal object_as_optval(Object o, bool *error)
+{
+ switch (o.type) {
+ case kObjectTypeNil:
+ return NIL_OPTVAL;
+ case kObjectTypeBoolean:
+ return BOOLEAN_OPTVAL(o.data.boolean);
+ case kObjectTypeInteger:
+ return NUMBER_OPTVAL((OptInt)o.data.integer);
+ case kObjectTypeString:
+ return STRING_OPTVAL(o.data.string);
+ default:
+ *error = true;
+ return NIL_OPTVAL;
+ }
+ UNREACHABLE;
+}
+
+/// Clear an option value.
+///
+/// The exact semantics of this depend on the option.
+static OptVal optval_clear(const char *name, uint32_t flags, void *varp, buf_T *buf, win_T *win)
+{
+ OptVal v = NIL_OPTVAL;
+
+ // Change the type of the OptVal to the type used by the option so that it can be cleared.
+ // TODO(famiu): Clean up all of this after set_(num|bool|string)_option() is unified.
+
+ if (flags & P_BOOL) {
+ v.type = kOptValTypeBoolean;
+ if ((int *)varp == &buf->b_p_ar) {
+ // TODO(lewis6991): replace this with a more general condition that
+ // indicates we are setting the local value of a global-local option
+ v.data.boolean = kNone;
+ } else {
+ v = get_option_value(name, NULL, OPT_GLOBAL, NULL);
+ }
+ } else if (flags & P_NUM) {
+ v.type = kOptValTypeNumber;
+ if ((OptInt *)varp == &curbuf->b_p_ul) {
+ // The one true special case
+ v.data.number = NO_LOCAL_UNDOLEVEL;
+ } else if ((OptInt *)varp == &win->w_p_so || (OptInt *)varp == &win->w_p_siso) {
+ // TODO(lewis6991): replace this with a more general condition that
+ // indicates we are setting the local value of a global-local option
+ v.data.number = -1;
+ } else {
+ v = get_option_value(name, NULL, OPT_GLOBAL, NULL);
+ }
+ } else if (flags & P_STRING) {
+ v.type = kOptValTypeString;
+ v.data.string.data = NULL;
+ }
+
+ return v;
+}
+
+/// Get an allocated string containing a list of valid types for an option.
+/// For options with a singular type, it returns the name of the type. For options with multiple
+/// possible types, it returns a slash separated list of types. For example, if an option can be a
+/// number, boolean or string, the function returns "Number/Boolean/String"
static char *option_get_valid_types(int opt_idx)
{
uint32_t flags = options[opt_idx].flags;
@@ -3604,7 +3548,7 @@ OptVal get_option_value(const char *name, uint32_t *flagsp, int scope, bool *hid
return BOOLEAN_OPTVAL(curbufIsChanged());
} else {
int n = *(int *)varp;
- return BOOLEAN_OPTVAL(n == 0 ? kFalse : (n >= 1 ? kTrue : kNone));
+ return BOOLEAN_OPTVAL(TRISTATE_FROM_INT(n));
}
}
}
@@ -3731,67 +3675,131 @@ int get_option_value_strict(char *name, int64_t *numval, char **stringval, int o
return rv;
}
-// Return information for option at 'opt_idx'
+/// Return information for option at 'opt_idx'
vimoption_T *get_option(int opt_idx)
{
return &options[opt_idx];
}
-/// Clear an option
-///
-/// The exact semantics of this depend on the option.
-static OptVal clear_optval(const char *name, uint32_t flags, void *varp, buf_T *buf, win_T *win)
+static const char *set_option(int opt_idx, void *varp, OptVal value, int opt_flags, char *errbuf,
+ size_t errbuflen)
{
- OptVal v = NIL_OPTVAL;
+ const char *errmsg = NULL;
+ bool value_checked = false;
- // Change the type of the OptVal to the type used by the option so that it can be cleared.
- // TODO(famiu): Clean up all of this after set_(num|bool|string)_option() is unified.
+ // TODO(famiu): Unify set_string_option with set_option.
+ if (value.type == kOptValTypeString) {
+ errmsg = set_string_option(opt_idx, varp, value.data.string.data, opt_flags, &value_checked,
+ errbuf, errbuflen);
+ goto end;
+ }
- if (flags & P_BOOL) {
- v.type = kOptValTypeBoolean;
- if ((int *)varp == &buf->b_p_ar) {
- // TODO(lewis6991): replace this with a more general condition that
- // indicates we are setting the local value of a global-local option
- v.data.boolean = kNone;
- } else {
- v = get_option_value(name, NULL, OPT_GLOBAL, NULL);
- }
- } else if (flags & P_NUM) {
- v.type = kOptValTypeNumber;
- if ((OptInt *)varp == &curbuf->b_p_ul) {
- // The one true special case
- v.data.number = NO_LOCAL_UNDOLEVEL;
- } else if ((OptInt *)varp == &win->w_p_so || (OptInt *)varp == &win->w_p_siso) {
- // TODO(lewis6991): replace this with a more general condition that
- // indicates we are setting the local value of a global-local option
- v.data.number = -1;
- } else {
- v = get_option_value(name, NULL, OPT_GLOBAL, NULL);
+ OptVal old_value = optval_from_varp(value.type, varp);
+ OptVal old_global_value = NIL_OPTVAL;
+
+ // Disallow changing some options from secure mode.
+ if ((secure || sandbox != 0) && (options[opt_idx].flags & P_SECURE)) {
+ return e_secure;
+ }
+
+ // Save the global value before changing anything. This is needed as for
+ // a global-only option setting the "local value" in fact sets the global
+ // value (since there is only one value).
+ if ((opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0) {
+ old_global_value =
+ optval_from_varp(value.type, get_varp_scope(&(options[opt_idx]), OPT_GLOBAL));
+ }
+
+ if (value.type == kOptValTypeNumber) {
+ errmsg = validate_num_option((OptInt *)varp, &value.data.number);
+
+ // Don't change the value and return early if validation failed.
+ if (errmsg != NULL) {
+ return errmsg;
}
- } else if (flags & P_STRING) {
- v.type = kOptValTypeString;
- v.data.string.data = NULL;
}
- return v;
-}
+ // Set the new option value.
+ set_option_varp(varp, value);
+ // Remember where the option was set.
+ set_option_sctx_idx(opt_idx, opt_flags, current_sctx);
+ // May set global value for local option.
+ if ((opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0) {
+ set_option_varp(get_varp_scope(&(options[opt_idx]), OPT_GLOBAL), value);
+ }
-static const char *set_option(int opt_idx, void *varp, OptVal *v, int opt_flags, char *errbuf,
- size_t errbuflen)
-{
- const char *errmsg = NULL;
+ // Invoke the option specific callback function to validate and apply the new value.
+ bool doskip = false;
+ opt_did_set_cb_T did_set_cb;
- bool value_checked = false;
+ if ((int *)varp == &p_force_on) {
+ did_set_cb = did_set_force_on;
+ } else if ((int *)varp == &p_force_off) {
+ did_set_cb = did_set_force_off;
+ } else {
+ did_set_cb = options[opt_idx].opt_did_set_cb;
+ }
+ if (did_set_cb != NULL) {
+ // TODO(famiu): make os_oldval and os_newval use OptVal.
+ optset_T did_set_cb_args = (value.type == kOptValTypeNumber)
+ ? (optset_T){ .os_varp = varp,
+ .os_flags = opt_flags,
+ .os_oldval.number = old_value.data.number,
+ .os_newval.number = value.data.number,
+ .os_doskip = false,
+ .os_errbuf = NULL,
+ .os_errbuflen = 0,
+ .os_buf = curbuf,
+ .os_win = curwin }
+ : (optset_T){ .os_varp = varp,
+ .os_flags = opt_flags,
+ .os_oldval.boolean = old_value.data.boolean,
+ .os_newval.boolean = value.data.boolean,
+ .os_doskip = false,
+ .os_errbuf = NULL,
+ .os_errbuflen = 0,
+ .os_buf = curbuf,
+ .os_win = curwin };
+
+ errmsg = did_set_cb(&did_set_cb_args);
+ doskip = did_set_cb_args.os_doskip;
+ }
+ if (doskip) {
+ return errmsg;
+ }
- if (v->type == kOptValTypeBoolean) {
- errmsg = set_bool_option(opt_idx, varp, (int)v->data.boolean, opt_flags);
- } else if (v->type == kOptValTypeNumber) {
- errmsg = set_num_option(opt_idx, varp, v->data.number, errbuf, errbuflen, opt_flags);
- } else if (v->type == kOptValTypeString) {
- errmsg = set_string_option(opt_idx, varp, v->data.string.data, opt_flags, &value_checked,
- errbuf, errbuflen);
+ // Check the bound for num options.
+ if (value.type == kOptValTypeNumber) {
+ errmsg
+ = check_num_option_bounds((OptInt *)varp, old_value.data.number, errbuf, errbuflen, errmsg);
}
+ // Clean this later when set_string_option() is unified with set_option().
+#define NUMERIC_OPTVAL_TO_OPTINT(x) \
+ (OptInt)((x).type == kOptValTypeNumber ? x.data.number : x.data.boolean)
+
+ apply_optionset_autocmd(opt_idx, opt_flags,
+ NUMERIC_OPTVAL_TO_OPTINT(old_value),
+ NUMERIC_OPTVAL_TO_OPTINT(old_global_value),
+ NUMERIC_OPTVAL_TO_OPTINT(value),
+ errmsg);
+
+#undef NUMERIC_OPTVAL_TO_OPTINT
+
+ if (options[opt_idx].flags & P_UI_OPTION) {
+ OptVal value_copy = optval_copy(optval_from_varp(value.type, varp));
+ ui_call_option_set(cstr_as_string(options[opt_idx].fullname),
+ optval_as_object(value_copy));
+ }
+
+ comp_col(); // in case 'columns' or 'ls' changed
+ if (curwin->w_curswant != MAXCOL
+ && (options[opt_idx].flags & (P_CURSWANT | P_RALL)) != 0) {
+ curwin->w_set_curswant = true;
+ }
+ check_redraw(options[opt_idx].flags);
+
+end:
if (errmsg == NULL) {
did_set_option(opt_idx, opt_flags, true, value_checked);
}
@@ -3845,7 +3853,7 @@ const char *set_option_value(const char *const name, const OptVal value, int opt
OptVal v = optval_copy(value);
if (v.type == kOptValTypeNil) {
- v = clear_optval(name, flags, varp, curbuf, curwin);
+ v = optval_clear(name, flags, varp, curbuf, curwin);
} else if (!optval_match_type(v, opt_idx)) {
char *rep = optval_to_cstr(v);
char *valid_types = option_get_valid_types(opt_idx);
@@ -3857,7 +3865,7 @@ const char *set_option_value(const char *const name, const OptVal value, int opt
goto end;
}
- errmsg = set_option(opt_idx, varp, &v, opt_flags, errbuf, sizeof(errbuf));
+ errmsg = set_option(opt_idx, varp, v, opt_flags, errbuf, sizeof(errbuf));
end:
optval_free(v); // Free the copied OptVal.
diff --git a/src/nvim/optionstr.c b/src/nvim/optionstr.c
index 88e7ebd991..08618406e6 100644
--- a/src/nvim/optionstr.c
+++ b/src/nvim/optionstr.c
@@ -441,14 +441,13 @@ void set_string_option_direct_in_buf(buf_T *buf, const char *name, int opt_idx,
/// #OPT_GLOBAL.
///
/// @return NULL on success, an untranslated error message on error.
-const char *set_string_option(const int opt_idx, void *varp_arg, const char *value,
+const char *set_string_option(const int opt_idx, void *varp, const char *value,
const int opt_flags, bool *value_checked, char *const errbuf,
const size_t errbuflen)
FUNC_ATTR_WARN_UNUSED_RESULT
{
vimoption_T *opt = get_option(opt_idx);
- void *varp = (char **)varp_arg;
char *origval_l = NULL;
char *origval_g = NULL;
diff --git a/src/nvim/types.h b/src/nvim/types.h
index 7b23fe419b..86ef64a9a9 100644
--- a/src/nvim/types.h
+++ b/src/nvim/types.h
@@ -42,6 +42,8 @@ typedef enum {
#define TRISTATE_TO_BOOL(val, \
default) ((val) == kTrue ? true : ((val) == kFalse ? false : (default)))
+#define TRISTATE_FROM_INT(val) ((val) == 0 ? kFalse : ((val) >= 1 ? kTrue : kNone))
+
typedef struct Decoration Decoration;
#ifndef ORDER_BIG_ENDIAN