summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/option.c980
-rw-r--r--src/optionstr.c3
-rw-r--r--src/version.c2
3 files changed, 511 insertions, 474 deletions
diff --git a/src/option.c b/src/option.c
index 528be65aa..1aed4e1a0 100644
--- a/src/option.c
+++ b/src/option.c
@@ -10,16 +10,20 @@
/*
* Code to handle user-settable options. This is all pretty much table-
* driven. Checklist for adding a new option:
- * - Put it in the options array below (copy an existing entry).
+ * - Put it in the options array in optiondefs.h (copy an existing entry).
* - For a global option: Add a variable for it in option.h.
* - For a buffer or window local option:
- * - Add a PV_XX entry to the enum below.
+ * - Add a PV_XX macro definition to the optiondefs.h file.
* - Add a variable to the window or buffer struct in structs.h.
* - For a window option, add some code to copy_winopt().
+ * - For a window string option, add code to check_win_options() and
+ * clear_winopt().
* - 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 do_set().
- * - If it's a list of flags, add some code in do_set(), search for WW_ALL.
+ * - If it's a numeric option, add any necessary bounds checks to
+ * set_num_option().
+ * - If it's a list of flags, add some code in did_set_string_option(), search
+ * for WW_ALL.
* - When adding an option with expansion (P_EXPAND), but with a different
* default for Vi and Vim (no P_VI_DEF), add some code at VIMEXP.
* - Add documentation! One line in doc/quickref.txt, full description in
@@ -1633,533 +1637,563 @@ do_set_string(
}
/*
- * Parse 'arg' for option settings.
- *
- * 'arg' may be IObuff, but only when no errors can be present and option
- * does not need to be expanded with option_expand().
- * "opt_flags":
- * 0 for ":set"
- * OPT_GLOBAL for ":setglobal"
- * OPT_LOCAL for ":setlocal" and a modeline
- * OPT_MODELINE for a modeline
- * OPT_WINONLY to only set window-local options
- * OPT_NOWIN to skip setting window-local options
- * OPT_ONECOLUMN do not use multiple columns
- *
- * returns FAIL if an error is detected, OK otherwise
+ * Set an option to a new value.
+ * Return NULL if OK, return an untranslated error message when something is
+ * wrong. "errbuf[errbuflen]" can be used to create the error message.
*/
- int
-do_set(
- char_u *arg_start, // option string (may be written to!)
- int opt_flags)
+ static char *
+do_set_option(
+ int opt_flags,
+ char_u **argp,
+ char_u *arg_start,
+ char_u **startarg,
+ int *did_show,
+ int *stopopteval,
+ char *errbuf,
+ size_t errbuflen)
{
- char_u *arg = arg_start;
+ char *errmsg = NULL;
+ int prefix; // 1: nothing, 0: "no", 2: "inv" in front of name
+ int nextchar; // next non-white char after option name
+ int afterchar; // character just after option name
+ char_u *arg = *argp;
+ int key;
int opt_idx;
- char *errmsg;
- char errbuf[80];
- char_u *startarg;
- int prefix; // 1: nothing, 0: "no", 2: "inv" in front of name
- int nextchar; // next non-white char after option name
- int afterchar; // character just after option name
int len;
- int i;
- varnumber_T value;
- int key;
+ set_op_T op = 0;
long_u flags; // flags for current option
char_u *varp = NULL; // pointer to variable for current option
- int did_show = FALSE; // already showed one value
- set_op_T op = 0;
- int cp_val = 0;
char_u key_name[2];
+ int cp_val = 0;
+ varnumber_T value;
+ int i;
- if (*arg == NUL)
+ prefix = 1;
+ if (STRNCMP(arg, "no", 2) == 0 && STRNCMP(arg, "novice", 6) != 0)
{
- showoptions(0, opt_flags);
- did_show = TRUE;
- goto theend;
+ prefix = 0;
+ arg += 2;
+ }
+ else if (STRNCMP(arg, "inv", 3) == 0)
+ {
+ prefix = 2;
+ arg += 3;
}
- while (*arg != NUL) // loop to process all options
+ // find end of name
+ key = 0;
+ 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] != '>')
+ {
+ errmsg = e_invalid_argument;
+ goto skip;
+ }
+ arg[len] = NUL; // put NUL after name
+ if (arg[1] == 't' && arg[2] == '_') // could be term code
+ opt_idx = findoption(arg + 1);
+ arg[len++] = '>'; // restore '>'
+ if (opt_idx == -1)
+ key = find_key_option(arg + 1, TRUE);
+ }
+ else
{
- errmsg = NULL;
- startarg = arg; // remember for error message
+ len = 0;
+ /*
+ * The two characters after "t_" may not be alphanumeric.
+ */
+ if (arg[0] == 't' && arg[1] == '_' && arg[2] && arg[3])
+ len = 4;
+ else
+ while (ASCII_ISALNUM(arg[len]) || arg[len] == '_')
+ ++len;
+ nextchar = arg[len];
+ arg[len] = NUL; // put NUL after name
+ opt_idx = findoption(arg);
+ arg[len] = nextchar; // restore nextchar
+ if (opt_idx == -1)
+ key = find_key_option(arg, FALSE);
+ }
- if (STRNCMP(arg, "all", 3) == 0 && !ASCII_ISALPHA(arg[3])
- && !(opt_flags & OPT_MODELINE))
+ // remember character after option name
+ afterchar = arg[len];
+
+ if (in_vim9script())
+ {
+ char_u *p = skipwhite(arg + len);
+
+ // disallow white space before =val, +=val, -=val, ^=val
+ if (p > arg + len && (p[0] == '='
+ || (vim_strchr((char_u *)"+-^", p[0]) != NULL
+ && p[1] == '=')))
{
- /*
- * ":set all" show all options.
- * ":set all&" set all options to their default value.
- */
- arg += 3;
- if (*arg == '&')
- {
- ++arg;
- // Only for :set command set global value of local options.
- set_options_default(OPT_FREE | opt_flags);
- didset_options();
- didset_options2();
- redraw_all_later(UPD_CLEAR);
- }
- else
- {
- showoptions(1, opt_flags);
- did_show = TRUE;
- }
+ errmsg = e_no_white_space_allowed_between_option_and;
+ arg = p;
+ *startarg = p;
+ goto skip;
}
- else if (STRNCMP(arg, "termcap", 7) == 0 && !(opt_flags & OPT_MODELINE))
+ }
+ else
+ // skip white space, allow ":set ai ?", ":set hlsearch !"
+ while (VIM_ISWHITE(arg[len]))
+ ++len;
+
+ op = OP_NONE;
+ if (arg[len] != NUL && arg[len + 1] == '=')
+ {
+ if (arg[len] == '+')
{
- showoptions(2, opt_flags);
- show_termcodes(opt_flags);
- did_show = TRUE;
- arg += 7;
+ op = OP_ADDING; // "+="
+ ++len;
+ }
+ else if (arg[len] == '^')
+ {
+ op = OP_PREPENDING; // "^="
+ ++len;
+ }
+ else if (arg[len] == '-')
+ {
+ op = OP_REMOVING; // "-="
+ ++len;
+ }
+ }
+ nextchar = arg[len];
+
+ if (opt_idx == -1 && key == 0) // found a mismatch: skip
+ {
+ if (in_vim9script() && arg > arg_start
+ && vim_strchr((char_u *)"!&<", *arg) != NULL)
+ errmsg = e_no_white_space_allowed_between_option_and;
+ else
+ errmsg = e_unknown_option;
+ goto skip;
+ }
+
+ 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((char_u *)"=:!&<", nextchar) == NULL
+ && (!(options[opt_idx].flags & P_BOOL)
+ || nextchar == '?'))
+ errmsg = e_option_not_supported;
+ goto skip;
+ }
+
+ flags = options[opt_idx].flags;
+ varp = get_varp_scope(&(options[opt_idx]), opt_flags);
+ }
+ else
+ {
+ flags = P_STRING;
+ if (key < 0)
+ {
+ key_name[0] = KEY2TERMCAP0(key);
+ key_name[1] = KEY2TERMCAP1(key);
}
else
{
- prefix = 1;
- if (STRNCMP(arg, "no", 2) == 0 && STRNCMP(arg, "novice", 6) != 0)
- {
- prefix = 0;
- arg += 2;
- }
- else if (STRNCMP(arg, "inv", 3) == 0)
- {
- prefix = 2;
- arg += 3;
- }
+ key_name[0] = KS_KEY;
+ key_name[1] = (key & 0xff);
+ }
+ }
- // find end of name
- key = 0;
- if (*arg == '<')
+ // 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))
+ goto skip;
+
+ // Skip all options that are window-local (used for :vimgrep).
+ if ((opt_flags & OPT_NOWIN) && opt_idx >= 0
+ && options[opt_idx].var == VAR_WIN)
+ goto skip;
+
+ // Disallow changing some options from modelines.
+ if (opt_flags & OPT_MODELINE)
+ {
+ if (flags & (P_SECURE | P_NO_ML))
+ {
+ errmsg = e_not_allowed_in_modeline;
+ goto skip;
+ }
+ if ((flags & P_MLE) && !p_mle)
+ {
+ errmsg = e_not_allowed_in_modeline_when_modelineexpr_is_off;
+ goto skip;
+ }
+#ifdef FEAT_DIFF
+ // In diff mode some options are overruled. This avoids that
+ // 'foldmethod' becomes "marker" instead of "diff" and that
+ // "wrap" gets set.
+ if (curwin->w_p_diff
+ && opt_idx >= 0 // shut up coverity warning
+ && (
+#ifdef FEAT_FOLDING
+ options[opt_idx].indir == PV_FDM ||
+#endif
+ options[opt_idx].indir == PV_WRAP))
+ goto skip;
+#endif
+ }
+
+#ifdef HAVE_SANDBOX
+ // Disallow changing some options in the sandbox
+ if (sandbox != 0 && (flags & P_SECURE))
+ {
+ errmsg = e_not_allowed_in_sandbox;
+ goto skip;
+ }
+#endif
+
+ if (vim_strchr((char_u *)"?=:!&<", nextchar) != NULL)
+ {
+ arg += len;
+ cp_val = p_cp;
+ if (nextchar == '&' && arg[1] == 'v' && arg[2] == 'i')
+ {
+ if (arg[3] == 'm') // "opt&vim": set to Vim default
{
- 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] != '>')
- {
- errmsg = e_invalid_argument;
- goto skip;
- }
- arg[len] = NUL; // put NUL after name
- if (arg[1] == 't' && arg[2] == '_') // could be term code
- opt_idx = findoption(arg + 1);
- arg[len++] = '>'; // restore '>'
- if (opt_idx == -1)
- key = find_key_option(arg + 1, TRUE);
+ cp_val = FALSE;
+ arg += 3;
}
- else
+ else // "opt&vi": set to Vi default
{
- len = 0;
- /*
- * The two characters after "t_" may not be alphanumeric.
- */
- if (arg[0] == 't' && arg[1] == '_' && arg[2] && arg[3])
- len = 4;
- else
- while (ASCII_ISALNUM(arg[len]) || arg[len] == '_')
- ++len;
- nextchar = arg[len];
- arg[len] = NUL; // put NUL after name
- opt_idx = findoption(arg);
- arg[len] = nextchar; // restore nextchar
- if (opt_idx == -1)
- key = find_key_option(arg, FALSE);
+ cp_val = TRUE;
+ arg += 2;
}
+ }
+ if (vim_strchr((char_u *)"?!&<", nextchar) != NULL
+ && arg[1] != NUL && !VIM_ISWHITE(arg[1]))
+ {
+ errmsg = e_trailing_characters;
+ goto skip;
+ }
+ }
- // remember character after option name
- afterchar = arg[len];
-
- if (in_vim9script())
+ /*
+ * allow '=' and ':' for historical reasons (MSDOS command.com
+ * allows only one '=' character per "set" command line. grrr. (jw)
+ */
+ if (nextchar == '?'
+ || (prefix == 1
+ && vim_strchr((char_u *)"=:&<", nextchar) == NULL
+ && !(flags & P_BOOL)))
+ {
+ /*
+ * print value
+ */
+ if (*did_show)
+ msg_putchar('\n'); // cursor below last one
+ else
+ {
+ 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);
+#ifdef FEAT_EVAL
+ if (p_verbose > 0)
{
- char_u *p = skipwhite(arg + len);
-
- // disallow white space before =val, +=val, -=val, ^=val
- if (p > arg + len && (p[0] == '='
- || (vim_strchr((char_u *)"+-^", p[0]) != NULL
- && p[1] == '=')))
- {
- errmsg = e_no_white_space_allowed_between_option_and;
- arg = p;
- startarg = p;
- goto skip;
- }
+ // Mention where the option was last set.
+ if (varp == options[opt_idx].var)
+ last_set_msg(options[opt_idx].script_ctx);
+ else if ((int)options[opt_idx].indir & PV_WIN)
+ last_set_msg(curwin->w_p_script_ctx[
+ (int)options[opt_idx].indir & PV_MASK]);
+ else if ((int)options[opt_idx].indir & PV_BUF)
+ last_set_msg(curbuf->b_p_script_ctx[
+ (int)options[opt_idx].indir & PV_MASK]);
}
- else
- // skip white space, allow ":set ai ?", ":set hlsearch !"
- while (VIM_ISWHITE(arg[len]))
- ++len;
+#endif
+ }
+ else
+ {
+ char_u *p;
- op = OP_NONE;
- if (arg[len] != NUL && arg[len + 1] == '=')
+ p = find_termcode(key_name);
+ if (p == NULL)
{
- if (arg[len] == '+')
- {
- op = OP_ADDING; // "+="
- ++len;
- }
- else if (arg[len] == '^')
- {
- op = OP_PREPENDING; // "^="
- ++len;
- }
- else if (arg[len] == '-')
- {
- op = OP_REMOVING; // "-="
- ++len;
- }
+ errmsg = e_key_code_not_set;
+ goto skip;
}
- nextchar = arg[len];
+ else
+ (void)show_one_termcode(key_name, p, TRUE);
+ }
+ if (nextchar != '?'
+ && nextchar != NUL && !VIM_ISWHITE(afterchar))
+ errmsg = e_trailing_characters;
+ }
+ else
+ {
+ int value_checked = FALSE;
- if (opt_idx == -1 && key == 0) // found a mismatch: skip
+ if (flags & P_BOOL) // boolean
+ {
+ if (nextchar == '=' || nextchar == ':')
{
- if (in_vim9script() && arg > arg_start
- && vim_strchr((char_u *)"!&<", *arg) != NULL)
- errmsg = e_no_white_space_allowed_between_option_and;
- else
- errmsg = e_unknown_option;
+ errmsg = e_invalid_argument;
goto skip;
}
- 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((char_u *)"=:!&<", nextchar) == NULL
- && (!(options[opt_idx].flags & P_BOOL)
- || nextchar == '?'))
- errmsg = e_option_not_supported;
- goto skip;
- }
-
- flags = options[opt_idx].flags;
- varp = get_varp_scope(&(options[opt_idx]), opt_flags);
- }
- else
+ /*
+ * ":set opt!": invert
+ * ":set opt&": reset to default value
+ * ":set opt<": reset to global value
+ */
+ if (nextchar == '!')
+ value = *(int *)(varp) ^ 1;
+ else if (nextchar == '&')
+ value = (int)(long)(long_i)options[opt_idx].def_val[
+ ((flags & P_VI_DEF) || cp_val)
+ ? VI_DEFAULT : VIM_DEFAULT];
+ else if (nextchar == '<')
{
- flags = P_STRING;
- if (key < 0)
- {
- key_name[0] = KEY2TERMCAP0(key);
- key_name[1] = KEY2TERMCAP1(key);
- }
+ // For 'autoread' -1 means to use global value.
+ if ((int *)varp == &curbuf->b_p_ar
+ && opt_flags == OPT_LOCAL)
+ value = -1;
else
- {
- key_name[0] = KS_KEY;
- key_name[1] = (key & 0xff);
- }
+ value = *(int *)get_varp_scope(&(options[opt_idx]),
+ OPT_GLOBAL);
}
-
- // 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))
- goto skip;
-
- // Skip all options that are window-local (used for :vimgrep).
- if ((opt_flags & OPT_NOWIN) && opt_idx >= 0
- && options[opt_idx].var == VAR_WIN)
- goto skip;
-
- // Disallow changing some options from modelines.
- if (opt_flags & OPT_MODELINE)
+ else
{
- if (flags & (P_SECURE | P_NO_ML))
- {
- errmsg = e_not_allowed_in_modeline;
- goto skip;
- }
- if ((flags & P_MLE) && !p_mle)
+ /*
+ * ":set invopt": invert
+ * ":set opt" or ":set noopt": set or reset
+ */
+ if (nextchar != NUL && !VIM_ISWHITE(afterchar))
{
- errmsg = e_not_allowed_in_modeline_when_modelineexpr_is_off;
+ errmsg = e_trailing_characters;
goto skip;
}
-#ifdef FEAT_DIFF
- // In diff mode some options are overruled. This avoids that
- // 'foldmethod' becomes "marker" instead of "diff" and that
- // "wrap" gets set.
- if (curwin->w_p_diff
- && opt_idx >= 0 // shut up coverity warning
- && (
-#ifdef FEAT_FOLDING
- options[opt_idx].indir == PV_FDM ||
-#endif
- options[opt_idx].indir == PV_WRAP))
- goto skip;
-#endif
+ if (prefix == 2) // inv
+ value = *(int *)(varp) ^ 1;
+ else
+ value = prefix;
}
-#ifdef HAVE_SANDBOX
- // Disallow changing some options in the sandbox
- if (sandbox != 0 && (flags & P_SECURE))
+ errmsg = set_bool_option(opt_idx, varp, (int)value,
+ opt_flags);
+ }
+ else // numeric or string
+ {
+ if (vim_strchr((char_u *)"=:&<", nextchar) == NULL
+ || prefix != 1)
{
- errmsg = e_not_allowed_in_sandbox;
+ errmsg = e_invalid_argument;
goto skip;
}
-#endif
- if (vim_strchr((char_u *)"?=:!&<", nextchar) != NULL)
- {
- arg += len;
- cp_val = p_cp;
- if (nextchar == '&' && arg[1] == 'v' && arg[2] == 'i')
- {
- if (arg[3] == 'm') // "opt&vim": set to Vim default
- {
- cp_val = FALSE;
- arg += 3;
- }
- else // "opt&vi": set to Vi default
- {
- cp_val = TRUE;
- arg += 2;
- }
- }
- if (vim_strchr((char_u *)"?!&<", nextchar) != NULL
- && arg[1] != NUL && !VIM_ISWHITE(arg[1]))
- {
- errmsg = e_trailing_characters;
- goto skip;
- }
- }
-
- /*
- * allow '=' and ':' for historical reasons (MSDOS command.com
- * allows only one '=' character per "set" command line. grrr. (jw)
- */
- if (nextchar == '?'
- || (prefix == 1
- && vim_strchr((char_u *)"=:&<", nextchar) == NULL
- && !(flags & P_BOOL)))
+ if (flags & P_NUM) // numeric
{
/*
- * print value
+ * Different ways to set a number option:
+ * & set to default value
+ * < set to global value
+ * <xx> accept special key codes for 'wildchar'
+ * c accept any non-digit for 'wildchar'
+ * [-]0-9 set number
+ * other error
*/
- if (did_show)
- msg_putchar('\n'); // cursor below last one
- else
+ ++arg;
+ if (nextchar == '&')
+ value = (long)(long_i)options[opt_idx].def_val[
+ ((flags & P_VI_DEF) || cp_val)
+ ? VI_DEFAULT : VIM_DEFAULT];
+ else if (nextchar == '<')
{
- gotocmdline(TRUE); // cursor at status line
- did_show = TRUE; // remember that we did a line
+ // For 'undolevels' NO_LOCAL_UNDOLEVEL means to
+ // use the global value.
+ if ((long *)varp == &curbuf->b_p_ul
+ && opt_flags == OPT_LOCAL)
+ value = NO_LOCAL_UNDOLEVEL;
+ else
+ value = *(long *)get_varp_scope(
+ &(options[opt_idx]), OPT_GLOBAL);
}
- if (opt_idx >= 0)
+ else if (((long *)varp == &p_wc
+ || (long *)varp == &p_wcm)
+ && (*arg == '<'
+ || *arg == '^'
+ || (*arg != NUL
+ && (!arg[1] || VIM_ISWHITE(arg[1]))
+ && !VIM_ISDIGIT(*arg))))
{
- showoneopt(&options[opt_idx], opt_flags);
-#ifdef FEAT_EVAL
- if (p_verbose > 0)
+ value = string_to_key(arg, FALSE);
+ if (value == 0 && (long *)varp != &p_wcm)
{
- // Mention where the option was last set.
- if (varp == options[opt_idx].var)
- last_set_msg(options[opt_idx].script_ctx);
- else if ((int)options[opt_idx].indir & PV_WIN)
- last_set_msg(curwin->w_p_script_ctx[
- (int)options[opt_idx].indir & PV_MASK]);
- else if ((int)options[opt_idx].indir & PV_BUF)
- last_set_msg(curbuf->b_p_script_ctx[
- (int)options[opt_idx].indir & PV_MASK]);
+ errmsg = e_invalid_argument;
+ goto skip;
}
-#endif
}
- else
+ else if (*arg == '-' || VIM_ISDIGIT(*arg))
{
- char_u *p;
-
- p = find_termcode(key_name);
- if (p == NULL)
+ // Allow negative (for 'undolevels'), octal and
+ // hex numbers.
+ vim_str2nr(arg, NULL, &i, STR2NR_ALL,
+ &value, NULL, 0, TRUE);
+ if (i == 0 || (arg[i] != NUL
+ && !VIM_ISWHITE(arg[i])))
{
- errmsg = e_key_code_not_set;
+ errmsg = e_number_required_after_equal;
goto skip;
}
- else
- (void)show_one_termcode(key_name, p, TRUE);
}
- if (nextchar != '?'
- && nextchar != NUL && !VIM_ISWHITE(afterchar))
- errmsg = e_trailing_characters;
+ else
+ {
+ errmsg = e_number_required_after_equal;
+ goto skip;
+ }
+
+ if (op == OP_ADDING)
+ value = *(long *)varp + value;
+ else if (op == OP_PREPENDING)
+ value = *(long *)varp * value;
+ else if (op == OP_REMOVING)
+ value = *(long *)varp - value;
+ errmsg = set_num_option(opt_idx, varp, value,
+ errbuf, errbuflen, opt_flags);
}
- else
+ else if (opt_idx >= 0) // string
{
- int value_checked = FALSE;
-
- if (flags & P_BOOL) // boolean
+ if (do_set_string(opt_idx, opt_flags, &arg, nextchar,
+ op, flags, cp_val, varp, errbuf,
+ &value_checked, &errmsg) == FAIL)
{
- if (nextchar == '=' || nextchar == ':')
- {
- errmsg = e_invalid_argument;
+ if (errmsg != NULL)
goto skip;
- }
-
- /*
- * ":set opt!": invert
- * ":set opt&": reset to default value
- * ":set opt<": reset to global value
- */
- if (nextchar == '!')
- value = *(int *)(varp) ^ 1;
- else if (nextchar == '&')
- value = (int)(long)(long_i)options[opt_idx].def_val[
- ((flags & P_VI_DEF) || cp_val)
- ? VI_DEFAULT : VIM_DEFAULT];
- else if (nextchar == '<')
- {
- // For 'autoread' -1 means to use global value.
- if ((int *)varp == &curbuf->b_p_ar
- && opt_flags == OPT_LOCAL)
- value = -1;
- else
- value = *(int *)get_varp_scope(&(options[opt_idx]),
- OPT_GLOBAL);
- }
- else
- {
- /*
- * ":set invopt": invert
- * ":set opt" or ":set noopt": set or reset
- */
- if (nextchar != NUL && !VIM_ISWHITE(afterchar))
- {
- errmsg = e_trailing_characters;
- goto skip;
- }
- if (prefix == 2) // inv
- value = *(int *)(varp) ^ 1;
- else
- value = prefix;
- }
+ *stopopteval = TRUE;
+ goto skip;
+ }
+ }
+ else // key code option
+ {
+ char_u *p;
- errmsg = set_bool_option(opt_idx, varp, (int)value,
- opt_flags);
+ if (nextchar == '&')
+ {
+ if (add_termcap_entry(key_name, TRUE) == FAIL)
+ errmsg = e_not_found_in_termcap;
}
- else // numeric or string
+ else
{
- if (vim_strchr((char_u *)"=:&<", nextchar) == NULL
- || prefix != 1)
- {
- errmsg = e_invalid_argument;
- goto skip;
- }
+ ++arg; // jump to after the '=' or ':'
+ for (p = arg; *p && !VIM_ISWHITE(*p); ++p)
+ if (*p == '\\' && p[1] != NUL)
+ ++p;
+ nextchar = *p;
+ *p = NUL;
+ add_termcode(key_name, arg, FALSE);
+ *p = nextchar;
+ }
+ if (full_screen)
+ ttest(FALSE);
+ redraw_all_later(UPD_CLEAR);
+ }
+ }
- if (flags & P_NUM) // numeric
- {
- /*
- * Different ways to set a number option:
- * & set to default value
- * < set to global value
- * <xx> accept special key codes for 'wildchar'
- * c accept any non-digit for 'wildchar'
- * [-]0-9 set number
- * other error
- */
- ++arg;
- if (nextchar == '&')
- value = (long)(long_i)options[opt_idx].def_val[
- ((flags & P_VI_DEF) || cp_val)
- ? VI_DEFAULT : VIM_DEFAULT];
- else if (nextchar == '<')
- {
- // For 'undolevels' NO_LOCAL_UNDOLEVEL means to
- // use the global value.
- if ((long *)varp == &curbuf->b_p_ul
- && opt_flags == OPT_LOCAL)
- value = NO_LOCAL_UNDOLEVEL;
- else
- value = *(long *)get_varp_scope(
- &(options[opt_idx]), OPT_GLOBAL);
- }
- else if (((long *)varp == &p_wc
- || (long *)varp == &p_wcm)
- && (*arg == '<'
- || *arg == '^'
- || (*arg != NUL
- && (!arg[1] || VIM_ISWHITE(arg[1]))
- && !VIM_ISDIGIT(*arg))))
- {
- value = string_to_key(arg, FALSE);
- if (value == 0 && (long *)varp != &p_wcm)
- {
- errmsg = e_invalid_argument;
- goto skip;
- }
- }
- else if (*arg == '-' || VIM_ISDIGIT(*arg))
- {
- // Allow negative (for 'undolevels'), octal and
- // hex numbers.
- vim_str2nr(arg, NULL, &i, STR2NR_ALL,
- &value, NULL, 0, TRUE);
- if (i == 0 || (arg[i] != NUL
- && !VIM_ISWHITE(arg[i])))
- {
- errmsg = e_number_required_after_equal;
- goto skip;
- }
- }
- else
- {
- errmsg = e_number_required_after_equal;
- goto skip;
- }
+ if (opt_idx >= 0)
+ did_set_option(
+ opt_idx, opt_flags, op == OP_NONE, value_checked);
+ }
- if (op == OP_ADDING)
- value = *(long *)varp + value;
- else if (op == OP_PREPENDING)
- value = *(long *)varp * value;
- else if (op == OP_REMOVING)
- value = *(long *)varp - value;
- errmsg = set_num_option(opt_idx, varp, value,
- errbuf, sizeof(errbuf), opt_flags);
- }
- else if (opt_idx >= 0) // string
- {
- if (do_set_string(opt_idx, opt_flags, &arg, nextchar,
- op, flags, cp_val, varp, errbuf,
- &value_checked, &errmsg) == FAIL)
- {
- if (errmsg != NULL)
- goto skip;
- break;
- }
- }
- else // key code option
- {
- char_u *p;
+skip:
+ *argp = arg;
+ return errmsg;
+}
- if (nextchar == '&')
- {
- if (add_termcap_entry(key_name, TRUE) == FAIL)
- errmsg = e_not_found_in_termcap;
- }
- else
- {
- ++arg; // jump to after the '=' or ':'
- for (p = arg; *p && !VIM_ISWHITE(*p); ++p)
- if (*p == '\\' && p[1] != NUL)
- ++p;
- nextchar = *p;
- *p = NUL;
- add_termcode(key_name, arg, FALSE);
- *p = nextchar;
- }
- if (full_screen)
- ttest(FALSE);
- redraw_all_later(UPD_CLEAR);
- }
- }
+/*
+ * Parse 'arg' for option settings.
+ *
+ * 'arg' may be IObuff, but only when no errors can be present and option
+ * does not need to be expanded with option_expand().
+ * "opt_flags":
+ * 0 for ":set"
+ * OPT_GLOBAL for ":setglobal"
+ * OPT_LOCAL for ":setlocal" and a modeline
+ * OPT_MODELINE for a modeline
+ * OPT_WINONLY to only set window-local options
+ * OPT_NOWIN to skip setting window-local options
+ * OPT_ONECOLUMN do not use multiple columns
+ *
+ * Returns FAIL if an error is detected, OK otherwise.
+ */
+ int
+do_set(
+ char_u *arg_start, // option string (may be written to!)
+ int opt_flags)
+{
+ char_u *arg = arg_start;
+ int i;
+ int did_show = FALSE; // already showed one value
- if (opt_idx >= 0)
- did_set_option(
- opt_idx, opt_flags, op == OP_NONE, value_checked);
+ if (*arg == NUL)
+ {
+ showoptions(0, opt_flags);
+ did_show = TRUE;
+ goto theend;
+ }
+
+ while (*arg != NUL) // loop to process all options
+ {
+ if (STRNCMP(arg, "all", 3) == 0 && !ASCII_ISALPHA(arg[3])
+ && !(opt_flags & OPT_MODELINE))
+ {
+ /*
+ * ":set all" show all options.
+ * ":set all&" set all options to their default value.
+ */
+ arg += 3;
+ if (*arg == '&')
+ {
+ ++arg;
+ // Only for :set command set global value of local options.
+ set_options_default(OPT_FREE | opt_flags);
+ didset_options();
+ didset_options2();
+ redraw_all_later(UPD_CLEAR);
}
+ else
+ {
+ showoptions(1, opt_flags);
+ did_show = TRUE;
+ }
+ }
+ else if (STRNCMP(arg, "termcap", 7) == 0 && !(opt_flags & OPT_MODELINE))
+ {
+ showoptions(2, opt_flags);
+ show_termcodes(opt_flags);
+ did_show = TRUE;
+ arg += 7;
+ }
+ else
+ {
+ int stopopteval = FALSE;
+ char *errmsg = NULL;
+ char errbuf[80];
+ char_u *startarg = arg;
+
+ errmsg = do_set_option(opt_flags, &arg, arg_start, &startarg,
+ &did_show, &stopopteval, errbuf,
+ sizeof(errbuf));
+ if (stopopteval)
+ break;
-skip:
/*
* Advance to next argument.
* - skip until a blank found, taking care of backslashes
@@ -2175,27 +2209,27 @@ skip:
if (*arg != '=')
break;
}
- }
- if (errmsg != NULL)
- {
- vim_strncpy(IObuff, (char_u *)_(errmsg), IOSIZE - 1);
- i = (int)STRLEN(IObuff) + 2;
- if (i + (arg - startarg) < IOSIZE)
+ if (errmsg != NULL)
{
- // append the argument with the error
- STRCAT(IObuff, ": ");
- mch_memmove(IObuff + i, startarg, (arg - startarg));
- IObuff[i + (arg - startarg)] = NUL;
- }
- // make sure all characters are printable
- trans_characters(IObuff, IOSIZE);
+ vim_strncpy(IObuff, (char_u *)_(errmsg), IOSIZE - 1);
+ i = (int)STRLEN(IObuff) + 2;
+ if (i + (arg - startarg) < IOSIZE)
+ {
+ // append the argument with the error
+ STRCAT(IObuff, ": ");
+ mch_memmove(IObuff + i, startarg, (arg - startarg));
+ IObuff[i + (arg - startarg)] = NUL;
+ }
+ // make sure all characters are printable
+ trans_characters(IObuff, IOSIZE);
- ++no_wait_return; // wait_return() done later
- emsg((char *)IObuff); // show error highlighted
- --no_wait_return;
+ ++no_wait_return; // wait_return() done later
+ emsg((char *)IObuff); // show error highlighted
+ --no_wait_return;
- return FAIL;
+ return FAIL;
+ }
}
arg = skipwhite(arg);
diff --git a/src/optionstr.c b/src/optionstr.c
index 46e9ac00b..d218d5662 100644
--- a/src/optionstr.c
+++ b/src/optionstr.c
@@ -680,7 +680,8 @@ did_set_term(int *opt_idx, long_u *free_oldval)
// Both 'term' and 'ttytype' point to T_NAME, only set the
// P_ALLOCED flag on 'term'.
*opt_idx = findoption((char_u *)"term");
- *free_oldval = (get_option_flags(*opt_idx) & P_ALLOCED);
+ if (*opt_idx >= 0)
+ *free_oldval = (get_option_flags(*opt_idx) & P_ALLOCED);
}
return errmsg;
diff --git a/src/version.c b/src/version.c
index 8facdc4e7..926cd7f65 100644
--- a/src/version.c
+++ b/src/version.c
@@ -696,6 +696,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 1275,
+/**/
1274,
/**/
1273,