mirror of
https://github.com/vim/vim.git
synced 2025-09-30 04:44:14 -04:00
patch 9.0.1283: the code for setting options is too complicated
Problem: The code for setting options is too complicated. Solution: Refactor the do_set() function. (Yegappan Lakshmanan, Lewis Russell, closes #11945)
This commit is contained in:
committed by
Bram Moolenaar
parent
c8ef30bc2e
commit
c72078b631
764
src/option.c
764
src/option.c
@@ -1211,6 +1211,9 @@ ex_set(exarg_T *eap)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* :set operator types
|
||||
*/
|
||||
typedef enum {
|
||||
OP_NONE = 0,
|
||||
OP_ADDING, // "opt+=arg"
|
||||
@@ -1218,6 +1221,181 @@ typedef enum {
|
||||
OP_REMOVING, // "opt-=arg"
|
||||
} set_op_T;
|
||||
|
||||
typedef enum {
|
||||
PREFIX_NO = 0, // "no" prefix
|
||||
PREFIX_NONE, // no prefix
|
||||
PREFIX_INV, // "inv" prefix
|
||||
} set_prefix_T;
|
||||
|
||||
/*
|
||||
* Return the prefix type for the option name in *argp.
|
||||
*/
|
||||
static set_prefix_T
|
||||
get_option_prefix(char_u **argp)
|
||||
{
|
||||
int prefix = PREFIX_NONE;
|
||||
char_u *arg = *argp;
|
||||
|
||||
if (STRNCMP(arg, "no", 2) == 0 && STRNCMP(arg, "novice", 6) != 0)
|
||||
{
|
||||
prefix = PREFIX_NO;
|
||||
arg += 2;
|
||||
}
|
||||
else if (STRNCMP(arg, "inv", 3) == 0)
|
||||
{
|
||||
prefix = PREFIX_INV;
|
||||
arg += 3;
|
||||
}
|
||||
|
||||
*argp = arg;
|
||||
return prefix;
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse the option name in "arg" and return the option index in "*opt_idxp",
|
||||
* and the option name length in "*lenp". For a <t_xx> option, return the key
|
||||
* number in "*keyp".
|
||||
*
|
||||
* Returns FAIL if an option starting with "<" doesn't end with a ">",
|
||||
* otherwise returns OK.
|
||||
*/
|
||||
static int
|
||||
parse_option_name(char_u *arg, int *opt_idxp, int *lenp, int *keyp)
|
||||
{
|
||||
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;
|
||||
|
||||
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
|
||||
{
|
||||
int nextchar; // next non-white char after option name
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
*keyp = key;
|
||||
*lenp = len;
|
||||
*opt_idxp = opt_idx;
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the option operator (+=, ^=, -=).
|
||||
*/
|
||||
static set_op_T
|
||||
get_opt_op(char_u *arg)
|
||||
{
|
||||
set_op_T op = OP_NONE;
|
||||
|
||||
if (*arg != NUL && *(arg + 1) == '=')
|
||||
{
|
||||
if (*arg == '+')
|
||||
op = OP_ADDING; // "+="
|
||||
else if (*arg == '^')
|
||||
op = OP_PREPENDING; // "^="
|
||||
else if (*arg == '-')
|
||||
op = OP_REMOVING; // "-="
|
||||
}
|
||||
|
||||
return op;
|
||||
}
|
||||
|
||||
/*
|
||||
* Validate whether the value of the option in "opt_idx" can be changed.
|
||||
* Returns FAIL if the option can be skipped or cannot be changed. Returns OK
|
||||
* if it can be changed.
|
||||
*/
|
||||
static int
|
||||
validate_opt_idx(int opt_idx, int opt_flags, long_u flags, char **errmsg)
|
||||
{
|
||||
// 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))
|
||||
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)
|
||||
return FAIL;
|
||||
|
||||
// Disallow changing some options from modelines.
|
||||
if (opt_flags & OPT_MODELINE)
|
||||
{
|
||||
if (flags & (P_SECURE | P_NO_ML))
|
||||
{
|
||||
*errmsg = e_not_allowed_in_modeline;
|
||||
return FAIL;
|
||||
}
|
||||
if ((flags & P_MLE) && !p_mle)
|
||||
{
|
||||
*errmsg = e_not_allowed_in_modeline_when_modelineexpr_is_off;
|
||||
return FAIL;
|
||||
}
|
||||
#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))
|
||||
return FAIL;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef HAVE_SANDBOX
|
||||
// Disallow changing some options in the sandbox
|
||||
if (sandbox != 0 && (flags & P_SECURE))
|
||||
{
|
||||
*errmsg = e_not_allowed_in_sandbox;
|
||||
return FAIL;
|
||||
}
|
||||
#endif
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* Part of do_set() for string options.
|
||||
* Returns FAIL on failure, do not process further options.
|
||||
@@ -1636,6 +1814,263 @@ do_set_string(
|
||||
return *errmsg == NULL ? OK : FAIL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set a boolean option
|
||||
*/
|
||||
static char *
|
||||
do_set_option_bool(
|
||||
int opt_idx,
|
||||
int opt_flags,
|
||||
set_prefix_T prefix,
|
||||
long_u flags,
|
||||
char_u *varp,
|
||||
int nextchar,
|
||||
int afterchar,
|
||||
int cp_val)
|
||||
|
||||
{
|
||||
varnumber_T value;
|
||||
|
||||
if (nextchar == '=' || nextchar == ':')
|
||||
return e_invalid_argument;
|
||||
|
||||
/*
|
||||
* ":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))
|
||||
return e_trailing_characters;
|
||||
if (prefix == PREFIX_INV)
|
||||
value = *(int *)(varp) ^ 1;
|
||||
else
|
||||
value = prefix == PREFIX_NO ? 0 : 1;
|
||||
}
|
||||
|
||||
return set_bool_option(opt_idx, varp, (int)value, opt_flags);
|
||||
}
|
||||
|
||||
/*
|
||||
* Set a numeric option
|
||||
*/
|
||||
static char *
|
||||
do_set_option_numeric(
|
||||
int opt_idx,
|
||||
int opt_flags,
|
||||
char_u **argp,
|
||||
int nextchar,
|
||||
set_op_T op,
|
||||
long_u flags,
|
||||
int cp_val,
|
||||
char_u *varp,
|
||||
char *errbuf,
|
||||
size_t errbuflen)
|
||||
{
|
||||
char_u *arg = *argp;
|
||||
varnumber_T value;
|
||||
int i;
|
||||
char *errmsg = NULL;
|
||||
|
||||
/*
|
||||
* 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 (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);
|
||||
|
||||
skip:
|
||||
*argp = arg;
|
||||
return errmsg;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set a key code (t_xx) option
|
||||
*/
|
||||
static char *
|
||||
do_set_option_keycode(char_u **argp, char_u *key_name, int nextchar)
|
||||
{
|
||||
char_u *arg = *argp;
|
||||
char_u *p;
|
||||
|
||||
if (nextchar == '&')
|
||||
{
|
||||
if (add_termcap_entry(key_name, TRUE) == FAIL)
|
||||
return 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);
|
||||
|
||||
*argp = arg;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set an option to a new value.
|
||||
*/
|
||||
static char *
|
||||
do_set_option_value(
|
||||
int opt_idx,
|
||||
int opt_flags,
|
||||
char_u **argp,
|
||||
set_prefix_T prefix,
|
||||
set_op_T op,
|
||||
long_u flags,
|
||||
char_u *varp,
|
||||
char_u *key_name,
|
||||
int nextchar,
|
||||
int afterchar,
|
||||
int cp_val,
|
||||
int *stopopteval,
|
||||
char *errbuf,
|
||||
size_t errbuflen)
|
||||
{
|
||||
int value_checked = FALSE;
|
||||
char *errmsg = NULL;
|
||||
char_u *arg = *argp;
|
||||
|
||||
if (flags & P_BOOL)
|
||||
{
|
||||
// boolean option
|
||||
errmsg = do_set_option_bool(opt_idx, opt_flags, prefix, flags, varp,
|
||||
nextchar, afterchar, cp_val);
|
||||
if (errmsg != NULL)
|
||||
goto skip;
|
||||
}
|
||||
else
|
||||
{
|
||||
// numeric or string option
|
||||
if (vim_strchr((char_u *)"=:&<", nextchar) == NULL
|
||||
|| prefix != PREFIX_NONE)
|
||||
{
|
||||
errmsg = e_invalid_argument;
|
||||
goto skip;
|
||||
}
|
||||
|
||||
if (flags & P_NUM)
|
||||
{
|
||||
// numeric option
|
||||
errmsg = do_set_option_numeric(opt_idx, opt_flags, &arg, nextchar,
|
||||
op, flags, cp_val, varp,
|
||||
errbuf, errbuflen);
|
||||
if (errmsg != NULL)
|
||||
goto skip;
|
||||
}
|
||||
else if (opt_idx >= 0)
|
||||
{
|
||||
// string option
|
||||
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;
|
||||
*stopopteval = TRUE;
|
||||
goto skip;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// key code option
|
||||
errmsg = do_set_option_keycode(&arg, key_name, nextchar);
|
||||
if (errmsg != NULL)
|
||||
goto skip;
|
||||
}
|
||||
}
|
||||
|
||||
if (opt_idx >= 0)
|
||||
did_set_option(opt_idx, opt_flags, op == OP_NONE, value_checked);
|
||||
|
||||
skip:
|
||||
*argp = arg;
|
||||
return errmsg;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set an option to a new value.
|
||||
* Return NULL if OK, return an untranslated error message when something is
|
||||
@@ -1652,78 +2087,27 @@ do_set_option(
|
||||
char *errbuf,
|
||||
size_t errbuflen)
|
||||
{
|
||||
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;
|
||||
int len;
|
||||
set_op_T op = 0;
|
||||
long_u flags; // flags for current option
|
||||
char_u *varp = NULL; // pointer to variable for current option
|
||||
char_u *arg;
|
||||
set_prefix_T prefix; // no prefix, "no" prefix or "inv" prefix
|
||||
set_op_T op;
|
||||
long_u flags; // flags for current option
|
||||
char_u *varp; // pointer to variable for current option
|
||||
char_u key_name[2];
|
||||
int cp_val = 0;
|
||||
varnumber_T value;
|
||||
int i;
|
||||
int nextchar; // next non-white char after option name
|
||||
int afterchar; // character just after option name
|
||||
int cp_val;
|
||||
char *errmsg = NULL;
|
||||
int key;
|
||||
int len;
|
||||
|
||||
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;
|
||||
}
|
||||
prefix = get_option_prefix(argp);
|
||||
arg = *argp;
|
||||
|
||||
// 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
|
||||
{
|
||||
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 (parse_option_name(arg, &opt_idx, &len, &key) == FAIL)
|
||||
return e_invalid_argument;
|
||||
|
||||
// remember character after option name
|
||||
afterchar = arg[len];
|
||||
@@ -1748,25 +2132,10 @@ do_set_option(
|
||||
while (VIM_ISWHITE(arg[len]))
|
||||
++len;
|
||||
|
||||
op = OP_NONE;
|
||||
if (arg[len] != NUL && arg[len + 1] == '=')
|
||||
{
|
||||
if (arg[len] == '+')
|
||||
{
|
||||
op = OP_ADDING; // "+="
|
||||
++len;
|
||||
}
|
||||
else if (arg[len] == '^')
|
||||
{
|
||||
op = OP_PREPENDING; // "^="
|
||||
++len;
|
||||
}
|
||||
else if (arg[len] == '-')
|
||||
{
|
||||
op = OP_REMOVING; // "-="
|
||||
++len;
|
||||
}
|
||||
}
|
||||
op = get_opt_op(arg + len);
|
||||
if (op != OP_NONE)
|
||||
len++;
|
||||
|
||||
nextchar = arg[len];
|
||||
|
||||
if (opt_idx == -1 && key == 0) // found a mismatch: skip
|
||||
@@ -1810,54 +2179,10 @@ do_set_option(
|
||||
}
|
||||
}
|
||||
|
||||
// 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))
|
||||
// Make sure the option value can be changed.
|
||||
if (validate_opt_idx(opt_idx, opt_flags, flags, &errmsg) == FAIL)
|
||||
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;
|
||||
@@ -1888,7 +2213,7 @@ do_set_option(
|
||||
* allows only one '=' character per "set" command line. grrr. (jw)
|
||||
*/
|
||||
if (nextchar == '?'
|
||||
|| (prefix == 1
|
||||
|| (prefix == PREFIX_NONE
|
||||
&& vim_strchr((char_u *)"=:&<", nextchar) == NULL
|
||||
&& !(flags & P_BOOL)))
|
||||
{
|
||||
@@ -1939,177 +2264,10 @@ do_set_option(
|
||||
}
|
||||
else
|
||||
{
|
||||
int value_checked = FALSE;
|
||||
|
||||
if (flags & P_BOOL) // boolean
|
||||
{
|
||||
if (nextchar == '=' || nextchar == ':')
|
||||
{
|
||||
errmsg = e_invalid_argument;
|
||||
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;
|
||||
}
|
||||
|
||||
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_invalid_argument;
|
||||
goto skip;
|
||||
}
|
||||
|
||||
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 (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 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;
|
||||
*stopopteval = TRUE;
|
||||
goto skip;
|
||||
}
|
||||
}
|
||||
else // key code option
|
||||
{
|
||||
char_u *p;
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
if (opt_idx >= 0)
|
||||
did_set_option(
|
||||
opt_idx, opt_flags, op == OP_NONE, value_checked);
|
||||
errmsg = do_set_option_value(opt_idx, opt_flags, &arg, prefix, op,
|
||||
flags, varp, key_name, nextchar,
|
||||
afterchar, cp_val, stopopteval, errbuf,
|
||||
errbuflen);
|
||||
}
|
||||
|
||||
skip:
|
||||
|
@@ -695,6 +695,8 @@ static char *(features[]) =
|
||||
|
||||
static int included_patches[] =
|
||||
{ /* Add new patch number below this line */
|
||||
/**/
|
||||
1283,
|
||||
/**/
|
||||
1282,
|
||||
/**/
|
||||
|
Reference in New Issue
Block a user