refactor(option.c): factor out loop code from do_set()

This commit is contained in:
Lewis Russell
2023-01-25 14:50:29 +00:00
parent 18c37c616e
commit e368560c80

View File

@@ -1164,64 +1164,21 @@ static void do_set_string(int opt_idx, int opt_flags, char **argp, int nextchar,
*argp = arg; *argp = arg;
} }
/// Parse 'arg' for option settings. static void do_set_option(int opt_flags, char **argp, bool *did_show, char *errbuf,
/// size_t errbuflen, char **errmsg)
/// '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
///
/// @param arg option string (may be written to!)
///
/// @return FAIL if an error is detected, OK otherwise
int do_set(char *arg, int opt_flags)
{ {
int did_show = false; // already showed one value
if (*arg == NUL) {
showoptions(0, opt_flags);
did_show = true;
goto theend;
}
char errbuf[80];
while (*arg != NUL) { // loop to process all options
char *errmsg = NULL;
char *startarg = arg; // remember for error message
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();
ui_refresh_options();
redraw_all_later(UPD_CLEAR);
} else {
showoptions(1, opt_flags);
did_show = true;
}
} else {
int prefix = 1; // 1: nothing, 0: "no", 2: "inv" in front of name int prefix = 1; // 1: nothing, 0: "no", 2: "inv" in front of name
if (strncmp(arg, "no", 2) == 0) {
if (strncmp(*argp, "no", 2) == 0) {
prefix = 0; prefix = 0;
arg += 2; *argp += 2;
} else if (strncmp(arg, "inv", 3) == 0) { } else if (strncmp(*argp, "inv", 3) == 0) {
prefix = 2; prefix = 2;
arg += 3; *argp += 3;
} }
char *arg = *argp;
// find end of name // find end of name
int key = 0; int key = 0;
int len; int len;
@@ -1238,8 +1195,8 @@ int do_set(char *arg, int opt_flags)
} }
} }
if (arg[len] != '>') { if (arg[len] != '>') {
errmsg = e_invarg; *errmsg = e_invarg;
goto skip; return;
} }
if (arg[1] == 't' && arg[2] == '_') { // could be term code if (arg[1] == 't' && arg[2] == '_') { // could be term code
opt_idx = findoption_len((const char *)arg + 1, (size_t)(len - 1)); opt_idx = findoption_len((const char *)arg + 1, (size_t)(len - 1));
@@ -1288,8 +1245,8 @@ int do_set(char *arg, int opt_flags)
char_u nextchar = (uint8_t)arg[len]; // next non-white char after option name char_u nextchar = (uint8_t)arg[len]; // next non-white char after option name
if (opt_idx == -1 && key == 0) { // found a mismatch: skip if (opt_idx == -1 && key == 0) { // found a mismatch: skip
errmsg = e_unknown_option; *errmsg = e_unknown_option;
goto skip; return;
} }
uint32_t flags; // flags for current option uint32_t flags; // flags for current option
@@ -1302,9 +1259,9 @@ int do_set(char *arg, int opt_flags)
if (vim_strchr("=:!&<", (uint8_t)nextchar) == NULL if (vim_strchr("=:!&<", (uint8_t)nextchar) == NULL
&& (!(options[opt_idx].flags & P_BOOL) && (!(options[opt_idx].flags & P_BOOL)
|| nextchar == '?')) { || nextchar == '?')) {
errmsg = e_unsupportedoption; *errmsg = e_unsupportedoption;
} }
goto skip; return;
} }
flags = options[opt_idx].flags; flags = options[opt_idx].flags;
@@ -1317,24 +1274,24 @@ int do_set(char *arg, int opt_flags)
// an already loaded buffer in a window). // an already loaded buffer in a window).
if ((opt_flags & OPT_WINONLY) if ((opt_flags & OPT_WINONLY)
&& (opt_idx < 0 || options[opt_idx].var != VAR_WIN)) { && (opt_idx < 0 || options[opt_idx].var != VAR_WIN)) {
goto skip; return;
} }
// Skip all options that are window-local (used for :vimgrep). // Skip all options that are window-local (used for :vimgrep).
if ((opt_flags & OPT_NOWIN) && opt_idx >= 0 if ((opt_flags & OPT_NOWIN) && opt_idx >= 0
&& options[opt_idx].var == VAR_WIN) { && options[opt_idx].var == VAR_WIN) {
goto skip; return;
} }
// Disallow changing some options from modelines. // Disallow changing some options from modelines.
if (opt_flags & OPT_MODELINE) { if (opt_flags & OPT_MODELINE) {
if (flags & (P_SECURE | P_NO_ML)) { if (flags & (P_SECURE | P_NO_ML)) {
errmsg = e_not_allowed_in_modeline; *errmsg = e_not_allowed_in_modeline;
goto skip; return;
} }
if ((flags & P_MLE) && !p_mle) { if ((flags & P_MLE) && !p_mle) {
errmsg = e_not_allowed_in_modeline_when_modelineexpr_is_off; *errmsg = e_not_allowed_in_modeline_when_modelineexpr_is_off;
goto skip; return;
} }
// In diff mode some options are overruled. This avoids that // In diff mode some options are overruled. This avoids that
// 'foldmethod' becomes "marker" instead of "diff" and that // 'foldmethod' becomes "marker" instead of "diff" and that
@@ -1343,29 +1300,29 @@ int do_set(char *arg, int opt_flags)
&& opt_idx >= 0 // shut up coverity warning && opt_idx >= 0 // shut up coverity warning
&& (options[opt_idx].indir == PV_FDM && (options[opt_idx].indir == PV_FDM
|| options[opt_idx].indir == PV_WRAP)) { || options[opt_idx].indir == PV_WRAP)) {
goto skip; return;
} }
} }
// Disallow changing some options in the sandbox // Disallow changing some options in the sandbox
if (sandbox != 0 && (flags & P_SECURE)) { if (sandbox != 0 && (flags & P_SECURE)) {
errmsg = e_sandbox; *errmsg = e_sandbox;
goto skip; return;
} }
if (vim_strchr("?=:!&<", (uint8_t)nextchar) != NULL) { if (vim_strchr("?=:!&<", (uint8_t)nextchar) != NULL) {
arg += len; *argp += len;
if (nextchar == '&' && arg[1] == 'v' && arg[2] == 'i') { if (nextchar == '&' && (*argp)[1] == 'v' && (*argp)[2] == 'i') {
if (arg[3] == 'm') { // "opt&vim": set to Vim default if ((*argp)[3] == 'm') { // "opt&vim": set to Vim default
arg += 3; *argp += 3;
} else { // "opt&vi": set to Vi default } else { // "opt&vi": set to Vi default
arg += 2; *argp += 2;
} }
} }
if (vim_strchr("?!&<", (uint8_t)nextchar) != NULL if (vim_strchr("?!&<", (uint8_t)nextchar) != NULL
&& arg[1] != NUL && !ascii_iswhite(arg[1])) { && (*argp)[1] != NUL && !ascii_iswhite((*argp)[1])) {
errmsg = e_trailing; *errmsg = e_trailing;
goto skip; return;
} }
} }
@@ -1378,11 +1335,11 @@ int do_set(char *arg, int opt_flags)
&& vim_strchr("=:&<", (uint8_t)nextchar) == NULL && vim_strchr("=:&<", (uint8_t)nextchar) == NULL
&& !(flags & P_BOOL))) { && !(flags & P_BOOL))) {
// print value // print value
if (did_show) { if (*did_show) {
msg_putchar('\n'); // cursor below last one msg_putchar('\n'); // cursor below last one
} else { } else {
gotocmdline(true); // cursor at status line gotocmdline(true); // cursor at status line
did_show = true; // remember that we did a line *did_show = true; // remember that we did a line
} }
if (opt_idx >= 0) { if (opt_idx >= 0) {
showoneopt(&options[opt_idx], opt_flags); showoneopt(&options[opt_idx], opt_flags);
@@ -1391,54 +1348,101 @@ int do_set(char *arg, int opt_flags)
if (varp == (char *)options[opt_idx].var) { if (varp == (char *)options[opt_idx].var) {
option_last_set_msg(options[opt_idx].last_set); option_last_set_msg(options[opt_idx].last_set);
} else if ((int)options[opt_idx].indir & PV_WIN) { } else if ((int)options[opt_idx].indir & PV_WIN) {
option_last_set_msg(curwin->w_p_script_ctx[ option_last_set_msg(curwin->w_p_script_ctx[(int)options[opt_idx].indir & PV_MASK]);
(int)options[opt_idx].indir & PV_MASK]);
} else if ((int)options[opt_idx].indir & PV_BUF) { } else if ((int)options[opt_idx].indir & PV_BUF) {
option_last_set_msg(curbuf->b_p_script_ctx[ option_last_set_msg(curbuf->b_p_script_ctx[(int)options[opt_idx].indir & PV_MASK]);
(int)options[opt_idx].indir & PV_MASK]);
} }
} }
} else { } else {
errmsg = e_key_code_not_set; *errmsg = e_key_code_not_set;
goto skip; return;
} }
if (nextchar != '?' if (nextchar != '?' && nextchar != NUL && !ascii_iswhite(afterchar)) {
&& nextchar != NUL && !ascii_iswhite(afterchar)) { *errmsg = e_trailing;
errmsg = e_trailing;
} }
} else { } else {
int value_checked = false; int value_checked = false;
if (flags & P_BOOL) { // boolean if (flags & P_BOOL) { // boolean
do_set_bool(opt_idx, opt_flags, prefix, nextchar, afterchar, varp, &errmsg); do_set_bool(opt_idx, opt_flags, prefix, nextchar, afterchar, varp, errmsg);
} else { // Numeric or string. } else { // Numeric or string.
if (vim_strchr("=:&<", (uint8_t)nextchar) == NULL if (vim_strchr("=:&<", (uint8_t)nextchar) == NULL
|| prefix != 1) { || prefix != 1) {
errmsg = e_invarg; *errmsg = e_invarg;
goto skip; return;
} }
if (flags & P_NUM) { // numeric if (flags & P_NUM) { // numeric
do_set_num(opt_idx, opt_flags, &arg, nextchar, op, varp, errbuf, sizeof(errbuf), do_set_num(opt_idx, opt_flags, argp, nextchar, op, varp, errbuf, errbuflen, errmsg);
&errmsg);
} else if (opt_idx >= 0) { // String. } else if (opt_idx >= 0) { // String.
do_set_string(opt_idx, opt_flags, &arg, nextchar, op, flags, varp, errbuf, do_set_string(opt_idx, opt_flags, argp, nextchar, op, flags, varp, errbuf,
sizeof(errbuf), &value_checked, &errmsg); errbuflen, &value_checked, errmsg);
} else { } else {
// key code option(FIXME(tarruda): Show a warning or something // key code option(FIXME(tarruda): Show a warning or something
// similar) // similar)
} }
} }
if (errmsg != NULL) { if (*errmsg != NULL) {
goto skip; return;
} }
if (opt_idx >= 0) { if (opt_idx >= 0) {
did_set_option(opt_idx, opt_flags, op == OP_NONE, value_checked); did_set_option(opt_idx, opt_flags, op == OP_NONE, value_checked);
} }
} }
}
/// 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
///
/// @param arg option string (may be written to!)
///
/// @return FAIL if an error is detected, OK otherwise
int do_set(char *arg, int opt_flags)
{
bool did_show = false; // already showed one value
if (*arg == NUL) {
showoptions(0, opt_flags);
did_show = true;
goto theend;
}
char errbuf[80];
while (*arg != NUL) { // loop to process all options
char *errmsg = NULL;
char *startarg = arg; // remember for error message
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();
ui_refresh_options();
redraw_all_later(UPD_CLEAR);
} else {
showoptions(1, opt_flags);
did_show = true;
}
} else {
do_set_option(opt_flags, &arg, &did_show, errbuf, sizeof(errbuf), &errmsg);
skip:
// Advance to next argument. // Advance to next argument.
// - skip until a blank found, taking care of backslashes // - skip until a blank found, taking care of backslashes
// - skip blanks // - skip blanks