aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/optionstr.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nvim/optionstr.c')
-rw-r--r--src/nvim/optionstr.c109
1 files changed, 67 insertions, 42 deletions
diff --git a/src/nvim/optionstr.c b/src/nvim/optionstr.c
index 07e2e5eed1..17afd10ee3 100644
--- a/src/nvim/optionstr.c
+++ b/src/nvim/optionstr.c
@@ -419,7 +419,9 @@ void set_string_option_direct_in_buf(buf_T *buf, const char *name, int opt_idx,
curbuf = save_curbuf;
unblock_autocmds();
}
+
/// Set a string option to a new value, handling the effects
+/// Must not be called with a hidden option!
///
/// @param[in] opt_idx Option to set.
/// @param[in] value New value.
@@ -427,56 +429,86 @@ 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, const char *const value, const int opt_flags,
- char *const errbuf, const size_t errbuflen)
- FUNC_ATTR_NONNULL_ARG(2) FUNC_ATTR_WARN_UNUSED_RESULT
+const char *set_string_option(const int opt_idx, void *varp_arg, 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);
- if (opt->var == NULL) { // don't set hidden option
- return NULL;
+ void *varp = (char **)varp_arg;
+ char *origval_l = NULL;
+ char *origval_g = NULL;
+
+ // When using ":set opt=val" for a global option
+ // with a local value the local value will be
+ // reset, use the global value here.
+ if ((opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0
+ && ((int)opt->indir & PV_BOTH)) {
+ varp = opt->var;
}
- char *const s = xstrdup(value);
- char **const varp
- = (char **)get_varp_scope(opt, ((opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0
- ? ((opt->indir & PV_BOTH) ? OPT_GLOBAL : OPT_LOCAL)
- : opt_flags));
- char *const oldval = *varp;
- char *oldval_l = NULL;
- char *oldval_g = NULL;
+ // The old value is kept until we are sure that the new value is valid.
+ char *oldval = *(char **)varp;
if ((opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0) {
- oldval_l = *(char **)get_varp_scope(opt, OPT_LOCAL);
- oldval_g = *(char **)get_varp_scope(opt, OPT_GLOBAL);
+ origval_l = *(char **)get_varp_scope(opt, OPT_LOCAL);
+ origval_g = *(char **)get_varp_scope(opt, OPT_GLOBAL);
+
+ // A global-local string option might have an empty option as value to
+ // indicate that the global value should be used.
+ if (((int)opt->indir & PV_BOTH) && origval_l == empty_option) {
+ origval_l = origval_g;
+ }
}
- *varp = s;
+ char *origval;
+ // When setting the local value of a global option, the old value may be
+ // the global value.
+ if (((int)opt->indir & PV_BOTH) && (opt_flags & OPT_LOCAL)) {
+ origval = *(char **)get_varp_from(opt, curbuf, curwin);
+ } else {
+ origval = oldval;
+ }
- char *const saved_oldval = xstrdup(oldval);
- char *const saved_oldval_l = (oldval_l != NULL) ? xstrdup(oldval_l) : 0;
- char *const saved_oldval_g = (oldval_g != NULL) ? xstrdup(oldval_g) : 0;
- char *const saved_newval = xstrdup(s);
+ *(char **)varp = xstrdup(value != NULL ? value : empty_option);
- int value_checked = false;
- const char *const errmsg = did_set_string_option(opt_idx, varp, oldval, s, errbuf, errbuflen,
- opt_flags, &value_checked);
- if (errmsg == NULL) {
- did_set_option(opt_idx, opt_flags, true, value_checked);
+ char *const saved_origval = (origval != NULL) ? xstrdup(origval) : NULL;
+ char *const saved_oldval_l = (origval_l != NULL) ? xstrdup(origval_l) : 0;
+ char *const saved_oldval_g = (origval_g != NULL) ? xstrdup(origval_g) : 0;
+
+ // newval (and varp) may become invalid if the buffer is closed by
+ // autocommands.
+ char *const saved_newval = xstrdup(*(char **)varp);
+
+ const int secure_saved = secure;
+
+ // When an option is set in the sandbox, from a modeline or in secure
+ // mode, then deal with side effects in secure mode. Also when the
+ // value was set with the P_INSECURE flag and is not completely
+ // replaced.
+ if ((opt_flags & OPT_MODELINE)
+ || sandbox != 0) {
+ secure = 1;
}
+ const char *const errmsg = did_set_string_option(curbuf, curwin, opt_idx, varp, oldval, errbuf,
+ errbuflen, opt_flags, value_checked);
+
+ secure = secure_saved;
+
// call autocommand after handling side effects
if (errmsg == NULL) {
if (!starting) {
- trigger_optionset_string(opt_idx, opt_flags, saved_oldval, saved_oldval_l, saved_oldval_g,
- saved_newval);
+ trigger_optionset_string(opt_idx, opt_flags, saved_origval, saved_oldval_l,
+ saved_oldval_g, saved_newval);
}
if (opt->flags & P_UI_OPTION) {
ui_call_option_set(cstr_as_string(opt->fullname),
- STRING_OBJ(cstr_as_string(saved_newval)));
+ CSTR_AS_OBJ(saved_newval));
}
}
- xfree(saved_oldval);
+ xfree(saved_origval);
xfree(saved_oldval_l);
xfree(saved_oldval_g);
xfree(saved_newval);
@@ -2066,9 +2098,9 @@ static void do_spelllang_source(win_T *win)
/// @param value_checked value was checked to be safe, no need to set P_INSECURE
///
/// @return NULL for success, or an untranslated error message for an error
-static const char *did_set_string_option_for(buf_T *buf, win_T *win, int opt_idx, char **varp,
- char *oldval, const char *value, char *errbuf,
- size_t errbuflen, int opt_flags, int *value_checked)
+const char *did_set_string_option(buf_T *buf, win_T *win, int opt_idx, char **varp, char *oldval,
+ char *errbuf, size_t errbuflen, int opt_flags,
+ bool *value_checked)
{
const char *errmsg = NULL;
int restore_chartab = false;
@@ -2082,14 +2114,14 @@ static const char *did_set_string_option_for(buf_T *buf, win_T *win, int opt_idx
.os_idx = opt_idx,
.os_flags = opt_flags,
.os_oldval.string = oldval,
- .os_newval.string = value,
+ .os_newval.string = *varp,
.os_value_checked = false,
.os_value_changed = false,
.os_restore_chartab = false,
.os_errbuf = errbuf,
.os_errbuflen = errbuflen,
- .os_win = curwin,
- .os_buf = curbuf,
+ .os_win = win,
+ .os_buf = buf,
};
// Disallow changing some options from secure mode
@@ -2186,13 +2218,6 @@ static const char *did_set_string_option_for(buf_T *buf, win_T *win, int opt_idx
return errmsg;
}
-const char *did_set_string_option(int opt_idx, char **varp, char *oldval, char *value, char *errbuf,
- size_t errbuflen, int opt_flags, int *value_checked)
-{
- return did_set_string_option_for(curbuf, curwin, opt_idx, varp, oldval, value, errbuf,
- errbuflen, opt_flags, value_checked);
-}
-
/// Check an option that can be a range of string values.
///
/// @param list when true: accept a list of values