diff options
author | Josh Rahm <joshuarahm@gmail.com> | 2023-01-25 18:23:01 +0000 |
---|---|---|
committer | Josh Rahm <joshuarahm@gmail.com> | 2023-01-25 18:23:01 +0000 |
commit | 142d9041391780ac15b89886a54015fdc5c73995 (patch) | |
tree | 0f6b5cac1a60810a03f52826c9e67c9e2780b033 /src/nvim/optionstr.c | |
parent | ad86b5db74922285699ab2a1dbb2ff20e6268a33 (diff) | |
parent | 3c48d3c83fc21dbc0841f9210f04bdb073d73cd1 (diff) | |
download | rneovim-142d9041391780ac15b89886a54015fdc5c73995.tar.gz rneovim-142d9041391780ac15b89886a54015fdc5c73995.tar.bz2 rneovim-142d9041391780ac15b89886a54015fdc5c73995.zip |
Merge remote-tracking branch 'upstream/master' into userreg
Diffstat (limited to 'src/nvim/optionstr.c')
-rw-r--r-- | src/nvim/optionstr.c | 2069 |
1 files changed, 1183 insertions, 886 deletions
diff --git a/src/nvim/optionstr.c b/src/nvim/optionstr.c index 1da6fa15d7..a5a708600f 100644 --- a/src/nvim/optionstr.c +++ b/src/nvim/optionstr.c @@ -2,14 +2,14 @@ // it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com #include <assert.h> -#include <inttypes.h> #include <stdbool.h> -#include <stdlib.h> +#include <stdint.h> #include <string.h> #include "nvim/api/private/helpers.h" #include "nvim/ascii.h" #include "nvim/autocmd.h" +#include "nvim/buffer_defs.h" #include "nvim/charset.h" #include "nvim/cursor.h" #include "nvim/cursor_shape.h" @@ -17,27 +17,40 @@ #include "nvim/digraph.h" #include "nvim/drawscreen.h" #include "nvim/eval.h" +#include "nvim/eval/typval_defs.h" +#include "nvim/eval/userfunc.h" #include "nvim/eval/vars.h" #include "nvim/ex_getln.h" -#include "nvim/hardcopy.h" +#include "nvim/fold.h" +#include "nvim/gettext.h" +#include "nvim/globals.h" #include "nvim/highlight_group.h" #include "nvim/indent.h" #include "nvim/indent_c.h" #include "nvim/insexpand.h" #include "nvim/keycodes.h" +#include "nvim/macros.h" #include "nvim/mapping.h" +#include "nvim/mbyte.h" #include "nvim/memline.h" +#include "nvim/memory.h" +#include "nvim/message.h" #include "nvim/mouse.h" #include "nvim/move.h" #include "nvim/ops.h" #include "nvim/option.h" +#include "nvim/option_defs.h" #include "nvim/optionstr.h" +#include "nvim/os/os.h" +#include "nvim/pos.h" #include "nvim/quickfix.h" #include "nvim/runtime.h" +#include "nvim/screen.h" #include "nvim/spell.h" #include "nvim/spellfile.h" #include "nvim/spellsuggest.h" #include "nvim/strings.h" +#include "nvim/tag.h" #include "nvim/ui.h" #include "nvim/vim.h" #include "nvim/window.h" @@ -78,7 +91,7 @@ static char *(p_swb_values[]) = { "useopen", "usetab", "split", "newtab", "vspli static char *(p_spk_values[]) = { "cursor", "screen", "topline", NULL }; static char *(p_tc_values[]) = { "followic", "ignore", "match", "followscs", "smart", NULL }; static char *(p_ve_values[]) = { "block", "insert", "all", "onemore", "none", "NONE", NULL }; -static char *(p_wop_values[]) = { "tagfile", "pum", NULL }; +static char *(p_wop_values[]) = { "tagfile", "pum", "fuzzy", NULL }; static char *(p_wak_values[]) = { "yes", "menu", "no", NULL }; static char *(p_mousem_values[]) = { "extend", "popup", "popup_setpos", "mac", NULL }; static char *(p_sel_values[]) = { "inclusive", "exclusive", "old", NULL }; @@ -113,12 +126,14 @@ static char *(p_icm_values[]) = { "nosplit", "split", NULL }; static char *(p_jop_values[]) = { "stack", "view", NULL }; static char *(p_tpf_values[]) = { "BS", "HT", "FF", "ESC", "DEL", "C0", "C1", NULL }; static char *(p_rdb_values[]) = { "compositor", "nothrottle", "invalid", "nodelta", NULL }; +static char *(p_sloc_values[]) = { "last", "statusline", "tabline", NULL }; /// All possible flags for 'shm'. static char SHM_ALL[] = { SHM_RO, SHM_MOD, SHM_FILE, SHM_LAST, SHM_TEXT, SHM_LINES, SHM_NEW, SHM_WRI, SHM_ABBREVIATIONS, SHM_WRITE, SHM_TRUNC, SHM_TRUNCALL, SHM_OVER, SHM_OVERALL, SHM_SEARCH, SHM_ATTENTION, SHM_INTRO, - SHM_COMPLETIONMENU, SHM_RECORDING, SHM_FILEINFO, SHM_SEARCHCOUNT, 0, }; + SHM_COMPLETIONMENU, SHM_COMPLETIONSCAN, SHM_RECORDING, SHM_FILEINFO, + SHM_SEARCHCOUNT, 0, }; /// After setting various option values: recompute variables that depend on /// option values. @@ -148,40 +163,41 @@ void didset_string_options(void) /// "oldval_l" the old local value (only non-NULL if global and local value are set) /// "oldval_g" the old global value (only non-NULL if global and local value are set) /// "newval" the new value -void trigger_optionsset_string(int opt_idx, int opt_flags, char *oldval, char *oldval_l, - char *oldval_g, char *newval) +void trigger_optionset_string(int opt_idx, int opt_flags, char *oldval, char *oldval_l, + char *oldval_g, char *newval) { // Don't do this recursively. - if (oldval != NULL - && newval != NULL - && *get_vim_var_str(VV_OPTION_TYPE) == NUL) { - char buf_type[7]; + if (oldval == NULL || newval == NULL + || *get_vim_var_str(VV_OPTION_TYPE) != NUL) { + return; + } - vim_snprintf(buf_type, ARRAY_SIZE(buf_type), "%s", - (opt_flags & OPT_LOCAL) ? "local" : "global"); - set_vim_var_string(VV_OPTION_OLD, oldval, -1); - set_vim_var_string(VV_OPTION_NEW, newval, -1); - set_vim_var_string(VV_OPTION_TYPE, buf_type, -1); - if (opt_flags & OPT_LOCAL) { - set_vim_var_string(VV_OPTION_COMMAND, "setlocal", -1); - set_vim_var_string(VV_OPTION_OLDLOCAL, oldval, -1); - } - if (opt_flags & OPT_GLOBAL) { - set_vim_var_string(VV_OPTION_COMMAND, "setglobal", -1); - set_vim_var_string(VV_OPTION_OLDGLOBAL, oldval, -1); - } - if ((opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0) { - set_vim_var_string(VV_OPTION_COMMAND, "set", -1); - set_vim_var_string(VV_OPTION_OLDLOCAL, oldval_l, -1); - set_vim_var_string(VV_OPTION_OLDGLOBAL, oldval_g, -1); - } - if (opt_flags & OPT_MODELINE) { - set_vim_var_string(VV_OPTION_COMMAND, "modeline", -1); - set_vim_var_string(VV_OPTION_OLDLOCAL, oldval, -1); - } - apply_autocmds(EVENT_OPTIONSET, get_option(opt_idx)->fullname, NULL, false, NULL); - reset_v_option_vars(); + char buf_type[7]; + + vim_snprintf(buf_type, ARRAY_SIZE(buf_type), "%s", + (opt_flags & OPT_LOCAL) ? "local" : "global"); + set_vim_var_string(VV_OPTION_OLD, oldval, -1); + set_vim_var_string(VV_OPTION_NEW, newval, -1); + set_vim_var_string(VV_OPTION_TYPE, buf_type, -1); + if (opt_flags & OPT_LOCAL) { + set_vim_var_string(VV_OPTION_COMMAND, "setlocal", -1); + set_vim_var_string(VV_OPTION_OLDLOCAL, oldval, -1); + } + if (opt_flags & OPT_GLOBAL) { + set_vim_var_string(VV_OPTION_COMMAND, "setglobal", -1); + set_vim_var_string(VV_OPTION_OLDGLOBAL, oldval, -1); + } + if ((opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0) { + set_vim_var_string(VV_OPTION_COMMAND, "set", -1); + set_vim_var_string(VV_OPTION_OLDLOCAL, oldval_l, -1); + set_vim_var_string(VV_OPTION_OLDGLOBAL, oldval_g, -1); + } + if (opt_flags & OPT_MODELINE) { + set_vim_var_string(VV_OPTION_COMMAND, "modeline", -1); + set_vim_var_string(VV_OPTION_OLDLOCAL, oldval, -1); } + apply_autocmds(EVENT_OPTIONSET, get_option(opt_idx)->fullname, NULL, false, NULL); + reset_v_option_vars(); } static char *illegal_char(char *errbuf, size_t errbuflen, int c) @@ -190,7 +206,7 @@ static char *illegal_char(char *errbuf, size_t errbuflen, int c) return ""; } vim_snprintf(errbuf, errbuflen, _("E539: Illegal character <%s>"), - (char *)transchar(c)); + transchar(c)); return errbuf; } @@ -227,6 +243,7 @@ void check_buf_options(buf_T *buf) check_string_option(&buf->b_p_cink); check_string_option(&buf->b_p_cino); parse_cino(buf); + check_string_option(&buf->b_p_lop); check_string_option(&buf->b_p_ft); check_string_option(&buf->b_p_cinw); check_string_option(&buf->b_p_cinsd); @@ -434,8 +451,8 @@ char *set_string_option(const int opt_idx, const char *const value, const int op // call autocommand after handling side effects if (errmsg == NULL) { if (!starting) { - trigger_optionsset_string(opt_idx, opt_flags, saved_oldval, saved_oldval_l, saved_oldval_g, - saved_newval); + trigger_optionset_string(opt_idx, opt_flags, saved_oldval, saved_oldval_l, saved_oldval_g, + saved_newval); } if (opt->flags & P_UI_OPTION) { ui_call_option_set(cstr_as_string(opt->fullname), @@ -536,7 +553,7 @@ static int check_signcolumn(char *val) // check for 'auto:<NUMBER>-<NUMBER>' if (strlen(val) == 8 - && !STRNCMP(val, "auto:", 5) + && !strncmp(val, "auto:", 5) && ascii_isdigit(val[5]) && val[6] == '-' && ascii_isdigit(val[7])) { @@ -597,7 +614,7 @@ char *check_stl_option(char *s) groupdepth++; continue; } - if (vim_strchr(STL_ALL, *s) == NULL) { + if (vim_strchr(STL_ALL, (uint8_t)(*s)) == NULL) { return illegal_char(errbuf, sizeof(errbuf), *s); } if (*s == '{') { @@ -623,6 +640,952 @@ char *check_stl_option(char *s) static int shada_idx = -1; +static bool check_illegal_path_names(char *val, uint32_t flags) +{ + // Disallow a path separator (slash and/or backslash), wildcards and + // characters that are often illegal in a file name. Be more permissive + // if "secure" is off. + return (((flags & P_NFNAME) + && strpbrk(val, (secure ? "/\\*?[|;&<>\r\n" : "/\\*?[<>\r\n")) != NULL) + || ((flags & P_NDNAME) + && strpbrk(val, "*?[|;&<>\r\n") != NULL)); +} + +static void did_set_backupcopy(buf_T *buf, char *oldval, int opt_flags, char **errmsg) +{ + char *bkc = p_bkc; + unsigned int *flags = &bkc_flags; + + if (opt_flags & OPT_LOCAL) { + bkc = buf->b_p_bkc; + flags = &buf->b_bkc_flags; + } + + if ((opt_flags & OPT_LOCAL) && *bkc == NUL) { + // make the local value empty: use the global value + *flags = 0; + } else { + if (opt_strings_flags(bkc, p_bkc_values, flags, true) != OK) { + *errmsg = e_invarg; + } + + if (((*flags & BKC_AUTO) != 0) + + ((*flags & BKC_YES) != 0) + + ((*flags & BKC_NO) != 0) != 1) { + // Must have exactly one of "auto", "yes" and "no". + (void)opt_strings_flags(oldval, p_bkc_values, flags, true); + *errmsg = e_invarg; + } + } +} + +static void did_set_backupext_or_patchmode(char **errmsg) +{ + if (strcmp(*p_bex == '.' ? p_bex + 1 : p_bex, + *p_pm == '.' ? p_pm + 1 : p_pm) == 0) { + *errmsg = e_backupext_and_patchmode_are_equal; + } +} + +static void did_set_breakindentopt(win_T *win, char **errmsg) +{ + if (briopt_check(win) == FAIL) { + *errmsg = e_invarg; + } + // list setting requires a redraw + if (win == curwin && win->w_briopt_list) { + redraw_all_later(UPD_NOT_VALID); + } +} + +static void did_set_isopt(buf_T *buf, bool *did_chartab, char **errmsg) +{ + // 'isident', 'iskeyword', 'isprint or 'isfname' option: refill g_chartab[] + // If the new option is invalid, use old value. 'lisp' option: refill + // g_chartab[] for '-' char + if (buf_init_chartab(buf, true) == FAIL) { + *did_chartab = true; // need to restore it below + *errmsg = e_invarg; // error in value + } +} + +static void did_set_helpfile(void) +{ + // May compute new values for $VIM and $VIMRUNTIME + if (didset_vim) { + vim_unsetenv_ext("VIM"); + } + if (didset_vimruntime) { + vim_unsetenv_ext("VIMRUNTIME"); + } +} + +static void did_set_cursorlineopt(win_T *win, char **varp, char **errmsg) +{ + if (**varp == NUL || fill_culopt_flags(*varp, win) != OK) { + *errmsg = e_invarg; + } +} + +static void did_set_helplang(char **errmsg) +{ + // Check for "", "ab", "ab,cd", etc. + for (char *s = p_hlg; *s != NUL; s += 3) { + if (s[1] == NUL || ((s[2] != ',' || s[3] == NUL) && s[2] != NUL)) { + *errmsg = e_invarg; + break; + } + if (s[2] == NUL) { + break; + } + } +} + +static void did_set_highlight(char **varp, char **errmsg) +{ + if (strcmp(*varp, HIGHLIGHT_INIT) != 0) { + *errmsg = e_unsupportedoption; + } +} + +static void did_set_opt_flags(char *val, char **values, unsigned *flagp, bool list, char **errmsg) +{ + if (opt_strings_flags(val, values, flagp, list) != OK) { + *errmsg = e_invarg; + } +} + +static void did_set_opt_strings(char *val, char **values, bool list, char **errmsg) +{ + did_set_opt_flags(val, values, NULL, list, errmsg); +} + +static void did_set_sessionoptions(char *oldval, char **errmsg) +{ + if (opt_strings_flags(p_ssop, p_ssop_values, &ssop_flags, true) != OK) { + *errmsg = e_invarg; + } + if ((ssop_flags & SSOP_CURDIR) && (ssop_flags & SSOP_SESDIR)) { + // Don't allow both "sesdir" and "curdir". + (void)opt_strings_flags(oldval, p_ssop_values, &ssop_flags, true); + *errmsg = e_invarg; + } +} + +static void did_set_ambiwidth(char **errmsg) +{ + if (check_opt_strings(p_ambw, p_ambw_values, false) != OK) { + *errmsg = e_invarg; + } else { + *errmsg = check_chars_options(); + } +} + +static void did_set_background(char **errmsg) +{ + if (check_opt_strings(p_bg, p_bg_values, false) != OK) { + *errmsg = e_invarg; + return; + } + + int dark = (*p_bg == 'd'); + + init_highlight(false, false); + + if (dark != (*p_bg == 'd') && get_var_value("g:colors_name") != NULL) { + // The color scheme must have set 'background' back to another + // value, that's not what we want here. Disable the color + // scheme and set the colors again. + do_unlet(S_LEN("g:colors_name"), true); + free_string_option(p_bg); + p_bg = xstrdup((dark ? "dark" : "light")); + check_string_option(&p_bg); + init_highlight(false, false); + } +} + +static void did_set_wildmode(char **errmsg) +{ + if (check_opt_wim() == FAIL) { + *errmsg = e_invarg; + } +} + +static void did_set_winaltkeys(char **errmsg) +{ + if (*p_wak == NUL || check_opt_strings(p_wak, p_wak_values, false) != OK) { + *errmsg = e_invarg; + } +} + +static void did_set_eventignore(char **errmsg) +{ + if (check_ei() == FAIL) { + *errmsg = e_invarg; + } +} + +// 'encoding', 'fileencoding' and 'makeencoding' +static void did_set_encoding(buf_T *buf, char **varp, char **gvarp, int opt_flags, char **errmsg) +{ + if (gvarp == &p_fenc) { + if (!MODIFIABLE(buf) && opt_flags != OPT_GLOBAL) { + *errmsg = e_modifiable; + return; + } + + if (vim_strchr(*varp, ',') != NULL) { + // No comma allowed in 'fileencoding'; catches confusing it + // with 'fileencodings'. + *errmsg = e_invarg; + return; + } + + // May show a "+" in the title now. + redraw_titles(); + // Add 'fileencoding' to the swap file. + ml_setflags(buf); + } + + // canonize the value, so that strcmp() can be used on it + char *p = enc_canonize(*varp); + xfree(*varp); + *varp = p; + if (varp == &p_enc) { + // only encoding=utf-8 allowed + if (strcmp(p_enc, "utf-8") != 0) { + *errmsg = e_unsupportedoption; + return; + } + spell_reload(); + } +} + +static void did_set_keymap(buf_T *buf, char **varp, int opt_flags, int *value_checked, + char **errmsg) +{ + if (!valid_filetype(*varp)) { + *errmsg = e_invarg; + return; + } + + int secure_save = secure; + + // Reset the secure flag, since the value of 'keymap' has + // been checked to be safe. + secure = 0; + + // load or unload key mapping tables + *errmsg = keymap_init(); + + secure = secure_save; + + // Since we check the value, there is no need to set P_INSECURE, + // even when the value comes from a modeline. + *value_checked = true; + + if (*errmsg == NULL) { + if (*buf->b_p_keymap != NUL) { + // Installed a new keymap, switch on using it. + buf->b_p_iminsert = B_IMODE_LMAP; + if (buf->b_p_imsearch != B_IMODE_USE_INSERT) { + buf->b_p_imsearch = B_IMODE_LMAP; + } + } else { + // Cleared the keymap, may reset 'iminsert' and 'imsearch'. + if (buf->b_p_iminsert == B_IMODE_LMAP) { + buf->b_p_iminsert = B_IMODE_NONE; + } + if (buf->b_p_imsearch == B_IMODE_LMAP) { + buf->b_p_imsearch = B_IMODE_USE_INSERT; + } + } + if ((opt_flags & OPT_LOCAL) == 0) { + set_iminsert_global(buf); + set_imsearch_global(buf); + } + status_redraw_buf(buf); + } +} + +static void did_set_fileformat(buf_T *buf, char **varp, const char *oldval, int opt_flags, + char **errmsg) +{ + if (!MODIFIABLE(buf) && !(opt_flags & OPT_GLOBAL)) { + *errmsg = e_modifiable; + } else if (check_opt_strings(*varp, p_ff_values, false) != OK) { + *errmsg = e_invarg; + } else { + redraw_titles(); + // update flag in swap file + ml_setflags(buf); + // Redraw needed when switching to/from "mac": a CR in the text + // will be displayed differently. + if (get_fileformat(buf) == EOL_MAC || *oldval == 'm') { + redraw_buf_later(buf, UPD_NOT_VALID); + } + } +} + +static void did_set_matchpairs(char **varp, char **errmsg) +{ + for (char *p = *varp; *p != NUL; p++) { + int x2 = -1; + int x3 = -1; + + p += utfc_ptr2len(p); + if (*p != NUL) { + x2 = (unsigned char)(*p++); + } + if (*p != NUL) { + x3 = utf_ptr2char(p); + p += utfc_ptr2len(p); + } + if (x2 != ':' || x3 == -1 || (*p != NUL && *p != ',')) { + *errmsg = e_invarg; + break; + } + if (*p == NUL) { + break; + } + } +} + +static void did_set_comments(char **varp, char *errbuf, size_t errbuflen, char **errmsg) +{ + for (char *s = *varp; *s;) { + while (*s && *s != ':') { + if (vim_strchr(COM_ALL, (uint8_t)(*s)) == NULL + && !ascii_isdigit(*s) && *s != '-') { + *errmsg = illegal_char(errbuf, errbuflen, *s); + break; + } + s++; + } + if (*s++ == NUL) { + *errmsg = N_("E524: Missing colon"); + } else if (*s == ',' || *s == NUL) { + *errmsg = N_("E525: Zero length string"); + } + if (*errmsg != NULL) { + break; + } + while (*s && *s != ',') { + if (*s == '\\' && s[1] != NUL) { + s++; + } + s++; + } + s = skip_to_option_part(s); + } +} + +static void did_set_global_listfillchars(win_T *win, char **varp, int opt_flags, char **errmsg) +{ + char **local_ptr = varp == &p_lcs ? &win->w_p_lcs : &win->w_p_fcs; + // only apply the global value to "win" when it does not have a local value + *errmsg = set_chars_option(win, varp, **local_ptr == NUL || !(opt_flags & OPT_GLOBAL)); + if (*errmsg == NULL) { + // If the current window is set to use the global + // 'listchars'/'fillchars' value, clear the window-local value. + if (!(opt_flags & OPT_GLOBAL)) { + clear_string_option(local_ptr); + } + FOR_ALL_TAB_WINDOWS(tp, wp) { + // If the current window has a local value need to apply it + // again, it was changed when setting the global value. + // If no error was returned above, we don't expect an error + // here, so ignore the return value. + local_ptr = varp == &p_lcs ? &wp->w_p_lcs : &wp->w_p_fcs; + if (**local_ptr == NUL) { + (void)set_chars_option(wp, local_ptr, true); + } + } + redraw_all_later(UPD_NOT_VALID); + } +} + +static void did_set_verbosefile(char **errmsg) +{ + verbose_stop(); + if (*p_vfile != NUL && verbose_open() == FAIL) { + *errmsg = e_invarg; + } +} + +static void did_set_shada(vimoption_T **opt, int *opt_idx, bool *free_oldval, char *errbuf, + size_t errbuflen, char **errmsg) +{ + // TODO(ZyX-I): Remove this code in the future, alongside with &viminfo + // option. + *opt_idx = (((*opt)->fullname[0] == 'v') + ? (shada_idx == -1 ? ((shada_idx = findoption("shada"))) : shada_idx) + : *opt_idx); + *opt = get_option(*opt_idx); + // Update free_oldval now that we have the opt_idx for 'shada', otherwise + // there would be a disconnect between the check for P_ALLOCED at the start + // of the function and the set of P_ALLOCED at the end of the function. + *free_oldval = ((*opt)->flags & P_ALLOCED); + for (char *s = p_shada; *s;) { + // Check it's a valid character + if (vim_strchr("!\"%'/:<@cfhnrs", (uint8_t)(*s)) == NULL) { + *errmsg = illegal_char(errbuf, errbuflen, *s); + break; + } + if (*s == 'n') { // name is always last one + break; + } else if (*s == 'r') { // skip until next ',' + while (*++s && *s != ',') {} + } else if (*s == '%') { + // optional number + while (ascii_isdigit(*++s)) {} + } else if (*s == '!' || *s == 'h' || *s == 'c') { + s++; // no extra chars + } else { // must have a number + while (ascii_isdigit(*++s)) {} + + if (!ascii_isdigit(*(s - 1))) { + if (errbuf != NULL) { + vim_snprintf(errbuf, errbuflen, + _("E526: Missing number after <%s>"), + transchar_byte((uint8_t)(*(s - 1)))); + *errmsg = errbuf; + } else { + *errmsg = ""; + } + break; + } + } + if (*s == ',') { + s++; + } else if (*s) { + if (errbuf != NULL) { + *errmsg = N_("E527: Missing comma"); + } else { + *errmsg = ""; + } + break; + } + } + if (*p_shada && *errmsg == NULL && get_shada_parameter('\'') < 0) { + *errmsg = N_("E528: Must specify a ' value"); + } +} + +static void did_set_showbreak(char **varp, char **errmsg) +{ + for (char *s = *varp; *s;) { + if (ptr2cells(s) != 1) { + *errmsg = e_showbreak_contains_unprintable_or_wide_character; + } + MB_PTR_ADV(s); + } +} + +static void did_set_titleiconstring(char **varp) +{ + // 'titlestring' and 'iconstring' + int flagval = (varp == &p_titlestring) ? STL_IN_TITLE : STL_IN_ICON; + + // NULL => statusline syntax + if (vim_strchr(*varp, '%') && check_stl_option(*varp) == NULL) { + stl_syntax |= flagval; + } else { + stl_syntax &= ~flagval; + } + did_set_title(); +} + +static void did_set_selection(char **errmsg) +{ + if (*p_sel == NUL || check_opt_strings(p_sel, p_sel_values, false) != OK) { + *errmsg = e_invarg; + } +} + +static void did_set_keymodel(char **errmsg) +{ + if (check_opt_strings(p_km, p_km_values, true) != OK) { + *errmsg = e_invarg; + return; + } + km_stopsel = (vim_strchr(p_km, 'o') != NULL); + km_startsel = (vim_strchr(p_km, 'a') != NULL); +} + +static void did_set_display(char **errmsg) +{ + if (opt_strings_flags(p_dy, p_dy_values, &dy_flags, true) != OK) { + *errmsg = e_invarg; + return; + } + (void)init_chartab(); + msg_grid_validate(); +} + +static void did_set_spellfile(char **varp, char **errmsg) +{ + // When there is a window for this buffer in which 'spell' + // is set load the wordlists. + + if ((!valid_spellfile(*varp))) { + *errmsg = e_invarg; + } else { + *errmsg = did_set_spell_option(true); + } +} + +static void did_set_spell(char **varp, char **errmsg) +{ + // When there is a window for this buffer in which 'spell' + // is set load the wordlists. + if (!valid_spelllang(*varp)) { + *errmsg = e_invarg; + } else { + *errmsg = did_set_spell_option(false); + } +} + +static void did_set_spellcapcheck(win_T *win, char **errmsg) +{ + // When 'spellcapcheck' is set compile the regexp program. + *errmsg = compile_cap_prog(win->w_s); +} + +static void did_set_spelloptions(win_T *win, char **errmsg) +{ + if (opt_strings_flags(win->w_s->b_p_spo, p_spo_values, &(win->w_s->b_p_spo_flags), + true) != OK) { + *errmsg = e_invarg; + } +} + +static void did_set_spellsuggest(char **errmsg) +{ + if (spell_check_sps() != OK) { + *errmsg = e_invarg; + } +} + +static void did_set_mkspellmem(char **errmsg) +{ + if (spell_check_msm() != OK) { + *errmsg = e_invarg; + } +} + +static void did_set_buftype(buf_T *buf, win_T *win, char **errmsg) +{ + // When 'buftype' is set, check for valid value. + if ((buf->terminal && buf->b_p_bt[0] != 't') + || (!buf->terminal && buf->b_p_bt[0] == 't') + || check_opt_strings(buf->b_p_bt, p_buftype_values, false) != OK) { + *errmsg = e_invarg; + } else { + if (win->w_status_height || global_stl_height()) { + win->w_redr_status = true; + redraw_later(win, UPD_VALID); + } + buf->b_help = (buf->b_p_bt[0] == 'h'); + redraw_titles(); + } +} + +// 'statusline', 'winbar', 'tabline', 'rulerformat' or 'statuscolumn' +static void did_set_statusline(win_T *win, char **varp, char **gvarp, char **errmsg) +{ + if (varp == &p_ruf) { // reset ru_wid first + ru_wid = 0; + } else if (varp == &win->w_p_stc) { + win->w_nrwidth_line_count = 0; + } + char *s = *varp; + if (varp == &p_ruf && *s == '%') { + // set ru_wid if 'ruf' starts with "%99(" + if (*++s == '-') { // ignore a '-' + s++; + } + int wid = getdigits_int(&s, true, 0); + if (wid && *s == '(' && (*errmsg = check_stl_option(p_ruf)) == NULL) { + ru_wid = wid; + } else { + *errmsg = check_stl_option(p_ruf); + } + } else if (varp == &p_ruf || s[0] != '%' || s[1] != '!') { + // check 'statusline', 'winbar', 'tabline' or 'statuscolumn' + // only if it doesn't start with "%!" + *errmsg = check_stl_option(s); + } + if (varp == &p_ruf && *errmsg == NULL) { + comp_col(); + } + // add / remove window bars for 'winbar' + if (gvarp == &p_wbr) { + set_winbar(true); + } +} + +static void did_set_complete(char **varp, char *errbuf, size_t errbuflen, char **errmsg) +{ + // check if it is a valid value for 'complete' -- Acevedo + for (char *s = *varp; *s;) { + while (*s == ',' || *s == ' ') { + s++; + } + if (!*s) { + break; + } + if (vim_strchr(".wbuksid]tU", (uint8_t)(*s)) == NULL) { + *errmsg = illegal_char(errbuf, errbuflen, *s); + break; + } + if (*++s != NUL && *s != ',' && *s != ' ') { + if (s[-1] == 'k' || s[-1] == 's') { + // skip optional filename after 'k' and 's' + while (*s && *s != ',' && *s != ' ') { + if (*s == '\\' && s[1] != NUL) { + s++; + } + s++; + } + } else { + if (errbuf != NULL) { + vim_snprintf(errbuf, errbuflen, + _("E535: Illegal character after <%c>"), + *--s); + *errmsg = errbuf; + } else { + *errmsg = ""; + } + break; + } + } + } +} + +static void did_set_completeopt(char **errmsg) +{ + if (check_opt_strings(p_cot, p_cot_values, true) != OK) { + *errmsg = e_invarg; + } else { + completeopt_was_set(); + } +} + +static void did_set_signcolumn(win_T *win, char **varp, const char *oldval, char **errmsg) +{ + if (check_signcolumn(*varp) != OK) { + *errmsg = e_invarg; + } + // When changing the 'signcolumn' to or from 'number', recompute the + // width of the number column if 'number' or 'relativenumber' is set. + if (((*oldval == 'n' && *(oldval + 1) == 'u') + || (*win->w_p_scl == 'n' && *(win->w_p_scl + 1) == 'u')) + && (win->w_p_nu || win->w_p_rnu)) { + win->w_nrwidth_line_count = 0; + } +} + +static void did_set_foldcolumn(char **varp, char **errmsg) +{ + if (**varp == NUL || check_opt_strings(*varp, p_fdc_values, false) != OK) { + *errmsg = e_invarg; + } +} + +static void did_set_pastetoggle(void) +{ + // 'pastetoggle': translate key codes like in a mapping + if (*p_pt) { + char *p = NULL; + (void)replace_termcodes(p_pt, + strlen(p_pt), + &p, REPTERM_FROM_PART | REPTERM_DO_LT, NULL, + CPO_TO_CPO_FLAGS); + if (p != NULL) { + free_string_option(p_pt); + p_pt = p; + } + } +} + +static void did_set_backspace(char **errmsg) +{ + if (ascii_isdigit(*p_bs)) { + if (*p_bs > '3' || p_bs[1] != NUL) { + *errmsg = e_invarg; + } + } else if (check_opt_strings(p_bs, p_bs_values, true) != OK) { + *errmsg = e_invarg; + } +} + +static void did_set_tagcase(buf_T *buf, int opt_flags, char **errmsg) +{ + unsigned int *flags; + char *p; + + if (opt_flags & OPT_LOCAL) { + p = buf->b_p_tc; + flags = &buf->b_tc_flags; + } else { + p = p_tc; + flags = &tc_flags; + } + + if ((opt_flags & OPT_LOCAL) && *p == NUL) { + // make the local value empty: use the global value + *flags = 0; + } else if (*p == NUL + || opt_strings_flags(p, p_tc_values, flags, false) != OK) { + *errmsg = e_invarg; + } +} + +static void did_set_diffopt(char **errmsg) +{ + if (diffopt_changed() == FAIL) { + *errmsg = e_invarg; + } +} + +static void did_set_foldmethod(win_T *win, char **varp, char **errmsg) +{ + if (check_opt_strings(*varp, p_fdm_values, false) != OK + || *win->w_p_fdm == NUL) { + *errmsg = e_invarg; + } else { + foldUpdateAll(win); + if (foldmethodIsDiff(win)) { + newFoldLevel(); + } + } +} + +static void did_set_foldmarker(win_T *win, char **varp, char **errmsg) +{ + char *p = vim_strchr(*varp, ','); + if (p == NULL) { + *errmsg = N_("E536: comma required"); + } else if (p == *varp || p[1] == NUL) { + *errmsg = e_invarg; + } else if (foldmethodIsMarker(win)) { + foldUpdateAll(win); + } +} + +static void did_set_commentstring(char **varp, char **errmsg) +{ + if (**varp != NUL && strstr(*varp, "%s") == NULL) { + *errmsg = N_("E537: 'commentstring' must be empty or contain %s"); + } +} + +static void did_set_foldignore(win_T *win) +{ + if (foldmethodIsIndent(win)) { + foldUpdateAll(win); + } +} + +static void did_set_virtualedit(win_T *win, int opt_flags, char *oldval, char **errmsg) +{ + char *ve = p_ve; + unsigned int *flags = &ve_flags; + + if (opt_flags & OPT_LOCAL) { + ve = win->w_p_ve; + flags = &win->w_ve_flags; + } + + if ((opt_flags & OPT_LOCAL) && *ve == NUL) { + // make the local value empty: use the global value + *flags = 0; + } else { + if (opt_strings_flags(ve, p_ve_values, flags, true) != OK) { + *errmsg = e_invarg; + } else if (strcmp(p_ve, oldval) != 0) { + // Recompute cursor position in case the new 've' setting + // changes something. + validate_virtcol_win(win); + coladvance(win->w_virtcol); + } + } +} + +static void did_set_lispoptions(char **varp, char **errmsg) +{ + if (**varp != NUL && strcmp(*varp, "expr:0") != 0 && strcmp(*varp, "expr:1") != 0) { + *errmsg = e_invarg; + } +} + +static void did_set_filetype_or_syntax(char **varp, char *oldval, int *value_checked, + bool *value_changed, char **errmsg) +{ + if (!valid_filetype(*varp)) { + *errmsg = e_invarg; + return; + } + + *value_changed = strcmp(oldval, *varp) != 0; + + // Since we check the value, there is no need to set P_INSECURE, + // even when the value comes from a modeline. + *value_checked = true; +} + +static void did_set_winhl(win_T *win, char **errmsg) +{ + if (!parse_winhl_opt(win)) { + *errmsg = e_invarg; + } +} + +static void did_set_varsoftabstop(buf_T *buf, char **varp, char **errmsg) +{ + if (!(*varp)[0] || ((*varp)[0] == '0' && !(*varp)[1])) { + XFREE_CLEAR(buf->b_p_vsts_array); + return; + } + + for (char *cp = *varp; *cp; cp++) { + if (ascii_isdigit(*cp)) { + continue; + } + if (*cp == ',' && cp > *varp && *(cp - 1) != ',') { + continue; + } + *errmsg = e_invarg; + return; + } + + long *oldarray = buf->b_p_vsts_array; + if (tabstop_set(*varp, &(buf->b_p_vsts_array))) { + xfree(oldarray); + } else { + *errmsg = e_invarg; + } +} + +static void did_set_vartabstop(buf_T *buf, win_T *win, char **varp, char **errmsg) +{ + if (!(*varp)[0] || ((*varp)[0] == '0' && !(*varp)[1])) { + XFREE_CLEAR(buf->b_p_vts_array); + return; + } + + for (char *cp = *varp; *cp; cp++) { + if (ascii_isdigit(*cp)) { + continue; + } + if (*cp == ',' && cp > *varp && *(cp - 1) != ',') { + continue; + } + *errmsg = e_invarg; + return; + } + + long *oldarray = buf->b_p_vts_array; + if (tabstop_set(*varp, &(buf->b_p_vts_array))) { + xfree(oldarray); + if (foldmethodIsIndent(win)) { + foldUpdateAll(win); + } + } else { + *errmsg = e_invarg; + } +} + +static void did_set_optexpr(win_T *win, char **p_opt, char **varp, char **gvarp) +{ + char *name = get_scriptlocal_funcname(*p_opt); + if (name != NULL) { + free_string_option(*p_opt); + *p_opt = name; + } +} + +// handle option that is a list of flags. +static void did_set_option_listflag(char **varp, char *flags, char *errbuf, size_t errbuflen, + char **errmsg) +{ + for (char *s = *varp; *s; s++) { + if (vim_strchr(flags, *s) == NULL) { + *errmsg = illegal_char(errbuf, errbuflen, *s); + break; + } + } +} + +// When 'syntax' is set, load the syntax of that name +static void do_syntax_autocmd(buf_T *buf, bool value_changed) +{ + static int syn_recursive = 0; + + syn_recursive++; + // Only pass true for "force" when the value changed or not used + // recursively, to avoid endless recurrence. + apply_autocmds(EVENT_SYNTAX, buf->b_p_syn, buf->b_fname, + value_changed || syn_recursive == 1, buf); + buf->b_flags |= BF_SYN_SET; + syn_recursive--; +} + +static void do_filetype_autocmd(buf_T *buf, char **varp, int opt_flags, bool value_changed) +{ + // 'filetype' is set, trigger the FileType autocommand + // Skip this when called from a modeline and the filetype was + // already set to this value. + if (!(opt_flags & OPT_MODELINE) || value_changed) { + static int ft_recursive = 0; + int secure_save = secure; + + // Reset the secure flag, since the value of 'filetype' has + // been checked to be safe. + secure = 0; + + ft_recursive++; + did_filetype = true; + // Only pass true for "force" when the value changed or not + // used recursively, to avoid endless recurrence. + apply_autocmds(EVENT_FILETYPE, buf->b_p_ft, buf->b_fname, + value_changed || ft_recursive == 1, buf); + ft_recursive--; + // Just in case the old "buf" is now invalid + if (varp != &(buf->b_p_ft)) { + varp = NULL; + } + secure = secure_save; + } +} + +static void did_set_spelllang_source(win_T *win) +{ + char fname[200]; + char *q = win->w_s->b_p_spl; + + // Skip the first name if it is "cjk". + if (strncmp(q, "cjk,", 4) == 0) { + q += 4; + } + + // Source the spell/LANG.vim in 'runtimepath'. + // They could set 'spellcapcheck' depending on the language. + // Use the first name in 'spelllang' up to '_region' or + // '.encoding'. + char *p; + for (p = q; *p != NUL; p++) { + if (!ASCII_ISALNUM(*p) && *p != '-') { + break; + } + } + if (p > q) { + vim_snprintf(fname, sizeof(fname), "spell/%.*s.vim", (int)(p - q), q); + source_runtime(fname, DIP_ALL); + } +} + /// Handle string options that need some action to perform when changed. /// The new value must be allocated. /// @@ -635,12 +1598,12 @@ static int shada_idx = -1; /// @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 -char *did_set_string_option(int opt_idx, char **varp, char *oldval, char *errbuf, size_t errbuflen, - int opt_flags, int *value_checked) +static char *did_set_string_option_for(buf_T *buf, win_T *win, int opt_idx, char **varp, + char *oldval, char *errbuf, size_t errbuflen, int opt_flags, + int *value_checked) { char *errmsg = NULL; - char *s, *p; - int did_chartab = false; + bool did_chartab = false; vimoption_T *opt = get_option(opt_idx); bool free_oldval = (opt->flags & P_ALLOCED); bool value_changed = false; @@ -653,864 +1616,244 @@ char *did_set_string_option(int opt_idx, char **varp, char *oldval, char *errbuf if ((secure || sandbox != 0) && (opt->flags & P_SECURE)) { errmsg = e_secure; - } else if (((opt->flags & P_NFNAME) - && strpbrk(*varp, (secure ? "/\\*?[|;&<>\r\n" : "/\\*?[<>\r\n")) != NULL) - || ((opt->flags & P_NDNAME) - && strpbrk(*varp, "*?[|;&<>\r\n") != NULL)) { - // Check for a "normal" directory or file name in some options. Disallow a - // path separator (slash and/or backslash), wildcards and characters that - // are often illegal in a file name. Be more permissive if "secure" is off. + } else if (check_illegal_path_names(*varp, opt->flags)) { + // Check for a "normal" directory or file name in some options. errmsg = e_invarg; } else if (gvarp == &p_bkc) { // 'backupcopy' - char *bkc = p_bkc; - unsigned int *flags = &bkc_flags; - - if (opt_flags & OPT_LOCAL) { - bkc = curbuf->b_p_bkc; - flags = &curbuf->b_bkc_flags; - } - - if ((opt_flags & OPT_LOCAL) && *bkc == NUL) { - // make the local value empty: use the global value - *flags = 0; - } else { - if (opt_strings_flags(bkc, p_bkc_values, flags, true) != OK) { - errmsg = e_invarg; - } - - if (((*flags & BKC_AUTO) != 0) - + ((*flags & BKC_YES) != 0) - + ((*flags & BKC_NO) != 0) != 1) { - // Must have exactly one of "auto", "yes" and "no". - (void)opt_strings_flags(oldval, p_bkc_values, flags, true); - errmsg = e_invarg; - } - } + did_set_backupcopy(buf, oldval, opt_flags, &errmsg); } else if (varp == &p_bex || varp == &p_pm) { // 'backupext' and 'patchmode' - if (strcmp(*p_bex == '.' ? p_bex + 1 : p_bex, - *p_pm == '.' ? p_pm + 1 : p_pm) == 0) { - errmsg = e_backupext_and_patchmode_are_equal; - } - } else if (varp == &curwin->w_p_briopt) { // 'breakindentopt' - if (briopt_check(curwin) == FAIL) { - errmsg = e_invarg; - } + did_set_backupext_or_patchmode(&errmsg); + } else if (varp == &win->w_p_briopt) { // 'breakindentopt' + did_set_breakindentopt(win, &errmsg); } else if (varp == &p_isi - || varp == &(curbuf->b_p_isk) + || varp == &buf->b_p_isk || varp == &p_isp || varp == &p_isf) { - // 'isident', 'iskeyword', 'isprint or 'isfname' option: refill g_chartab[] - // If the new option is invalid, use old value. 'lisp' option: refill - // g_chartab[] for '-' char - if (init_chartab() == FAIL) { - did_chartab = true; // need to restore it below - errmsg = e_invarg; // error in value - } + // 'isident', 'iskeyword', 'isprint or 'isfname' option + did_set_isopt(buf, &did_chartab, &errmsg); } else if (varp == &p_hf) { // 'helpfile' - // May compute new values for $VIM and $VIMRUNTIME - if (didset_vim) { - vim_unsetenv_ext("VIM"); - } - if (didset_vimruntime) { - vim_unsetenv_ext("VIMRUNTIME"); - } + did_set_helpfile(); } else if (varp == &p_rtp || varp == &p_pp) { // 'runtimepath' 'packpath' runtime_search_path_invalidate(); - } else if (varp == &curwin->w_p_culopt - || gvarp == &curwin->w_allbuf_opt.wo_culopt) { // 'cursorlineopt' - if (**varp == NUL || fill_culopt_flags(*varp, curwin) != OK) { - errmsg = e_invarg; - } - } else if (varp == &curwin->w_p_cc) { // 'colorcolumn' - errmsg = check_colorcolumn(curwin); - } else if (varp == (char **)&p_hlg) { // 'helplang' - // Check for "", "ab", "ab,cd", etc. - for (s = (char *)p_hlg; *s != NUL; s += 3) { - if (s[1] == NUL || ((s[2] != ',' || s[3] == NUL) && s[2] != NUL)) { - errmsg = e_invarg; - break; - } - if (s[2] == NUL) { - break; - } - } + } else if (varp == &win->w_p_culopt + || gvarp == &win->w_allbuf_opt.wo_culopt) { // 'cursorlineopt' + did_set_cursorlineopt(win, varp, &errmsg); + } else if (varp == &win->w_p_cc) { // 'colorcolumn' + errmsg = check_colorcolumn(win); + } else if (varp == &p_hlg) { // 'helplang' + did_set_helplang(&errmsg); } else if (varp == &p_hl) { // 'highlight' - if (strcmp(*varp, HIGHLIGHT_INIT) != 0) { - errmsg = e_unsupportedoption; - } + did_set_highlight(varp, &errmsg); } else if (varp == &p_jop) { // 'jumpoptions' - if (opt_strings_flags(p_jop, p_jop_values, &jop_flags, true) != OK) { - errmsg = e_invarg; - } + did_set_opt_flags(p_jop, p_jop_values, &jop_flags, true, &errmsg); } else if (gvarp == &p_nf) { // 'nrformats' - if (check_opt_strings(*varp, p_nf_values, true) != OK) { - errmsg = e_invarg; - } + did_set_opt_strings(*varp, p_nf_values, true, &errmsg); } else if (varp == &p_ssop) { // 'sessionoptions' - if (opt_strings_flags(p_ssop, p_ssop_values, &ssop_flags, true) != OK) { - errmsg = e_invarg; - } - if ((ssop_flags & SSOP_CURDIR) && (ssop_flags & SSOP_SESDIR)) { - // Don't allow both "sesdir" and "curdir". - (void)opt_strings_flags(oldval, p_ssop_values, &ssop_flags, true); - errmsg = e_invarg; - } + did_set_sessionoptions(oldval, &errmsg); } else if (varp == &p_vop) { // 'viewoptions' - if (opt_strings_flags(p_vop, p_ssop_values, &vop_flags, true) != OK) { - errmsg = e_invarg; - } + did_set_opt_flags(p_vop, p_ssop_values, &vop_flags, true, &errmsg); } else if (varp == &p_rdb) { // 'redrawdebug' - if (opt_strings_flags(p_rdb, p_rdb_values, &rdb_flags, true) != OK) { - errmsg = e_invarg; - } + did_set_opt_flags(p_rdb, p_rdb_values, &rdb_flags, true, &errmsg); } else if (varp == &p_sbo) { // 'scrollopt' - if (check_opt_strings(p_sbo, p_scbopt_values, true) != OK) { - errmsg = e_invarg; - } + did_set_opt_strings(p_sbo, p_scbopt_values, true, &errmsg); } else if (varp == &p_ambw || (int *)varp == &p_emoji) { // 'ambiwidth' - if (check_opt_strings(p_ambw, p_ambw_values, false) != OK) { - errmsg = e_invarg; - } else { - errmsg = check_chars_options(); - } + did_set_ambiwidth(&errmsg); } else if (varp == &p_bg) { // 'background' - if (check_opt_strings(p_bg, p_bg_values, false) == OK) { - int dark = (*p_bg == 'd'); - - init_highlight(false, false); - - if (dark != (*p_bg == 'd') && get_var_value("g:colors_name") != NULL) { - // The color scheme must have set 'background' back to another - // value, that's not what we want here. Disable the color - // scheme and set the colors again. - do_unlet(S_LEN("g:colors_name"), true); - free_string_option(p_bg); - p_bg = xstrdup((dark ? "dark" : "light")); - check_string_option(&p_bg); - init_highlight(false, false); - } - } else { - errmsg = e_invarg; - } + did_set_background(&errmsg); } else if (varp == &p_wim) { // 'wildmode' - if (check_opt_wim() == FAIL) { - errmsg = e_invarg; - } + did_set_wildmode(&errmsg); } else if (varp == &p_wop) { // 'wildoptions' - if (opt_strings_flags(p_wop, p_wop_values, &wop_flags, true) != OK) { - errmsg = e_invarg; - } + did_set_opt_flags(p_wop, p_wop_values, &wop_flags, true, &errmsg); } else if (varp == &p_wak) { // 'winaltkeys' - if (*p_wak == NUL - || check_opt_strings(p_wak, p_wak_values, false) != OK) { - errmsg = e_invarg; - } + did_set_winaltkeys(&errmsg); } else if (varp == &p_ei) { // 'eventignore' - if (check_ei() == FAIL) { - errmsg = e_invarg; - } + did_set_eventignore(&errmsg); } else if (varp == &p_enc || gvarp == &p_fenc || gvarp == &p_menc) { // 'encoding', 'fileencoding' and 'makeencoding' - if (gvarp == &p_fenc) { - if (!MODIFIABLE(curbuf) && opt_flags != OPT_GLOBAL) { - errmsg = e_modifiable; - } else if (vim_strchr(*varp, ',') != NULL) { - // No comma allowed in 'fileencoding'; catches confusing it - // with 'fileencodings'. - errmsg = e_invarg; - } else { - // May show a "+" in the title now. - redraw_titles(); - // Add 'fileencoding' to the swap file. - ml_setflags(curbuf); - } - } - - if (errmsg == NULL) { - // canonize the value, so that strcmp() can be used on it - p = enc_canonize(*varp); - xfree(*varp); - *varp = p; - if (varp == &p_enc) { - // only encoding=utf-8 allowed - if (strcmp(p_enc, "utf-8") != 0) { - errmsg = e_unsupportedoption; - } else { - spell_reload(); - } - } - } - } else if (varp == &p_penc) { - // Canonize printencoding if VIM standard one - p = enc_canonize(p_penc); - xfree(p_penc); - p_penc = p; - } else if (varp == &curbuf->b_p_keymap) { - if (!valid_filetype(*varp)) { - errmsg = e_invarg; - } else { - int secure_save = secure; - - // Reset the secure flag, since the value of 'keymap' has - // been checked to be safe. - secure = 0; - - // load or unload key mapping tables - errmsg = keymap_init(); - - secure = secure_save; - - // Since we check the value, there is no need to set P_INSECURE, - // even when the value comes from a modeline. - *value_checked = true; - } - - if (errmsg == NULL) { - if (*curbuf->b_p_keymap != NUL) { - // Installed a new keymap, switch on using it. - curbuf->b_p_iminsert = B_IMODE_LMAP; - if (curbuf->b_p_imsearch != B_IMODE_USE_INSERT) { - curbuf->b_p_imsearch = B_IMODE_LMAP; - } - } else { - // Cleared the keymap, may reset 'iminsert' and 'imsearch'. - if (curbuf->b_p_iminsert == B_IMODE_LMAP) { - curbuf->b_p_iminsert = B_IMODE_NONE; - } - if (curbuf->b_p_imsearch == B_IMODE_LMAP) { - curbuf->b_p_imsearch = B_IMODE_USE_INSERT; - } - } - if ((opt_flags & OPT_LOCAL) == 0) { - set_iminsert_global(); - set_imsearch_global(); - } - status_redraw_curbuf(); - } + did_set_encoding(buf, varp, gvarp, opt_flags, &errmsg); + } else if (varp == &buf->b_p_keymap) { + did_set_keymap(buf, varp, opt_flags, value_checked, &errmsg); } else if (gvarp == &p_ff) { // 'fileformat' - if (!MODIFIABLE(curbuf) && !(opt_flags & OPT_GLOBAL)) { - errmsg = e_modifiable; - } else if (check_opt_strings(*varp, p_ff_values, false) != OK) { - errmsg = e_invarg; - } else { - redraw_titles(); - // update flag in swap file - ml_setflags(curbuf); - // Redraw needed when switching to/from "mac": a CR in the text - // will be displayed differently. - if (get_fileformat(curbuf) == EOL_MAC || *oldval == 'm') { - redraw_curbuf_later(UPD_NOT_VALID); - } - } + did_set_fileformat(buf, varp, oldval, opt_flags, &errmsg); } else if (varp == &p_ffs) { // 'fileformats' - if (check_opt_strings(p_ffs, p_ff_values, true) != OK) { - errmsg = e_invarg; - } + did_set_opt_strings(p_ffs, p_ff_values, true, &errmsg); } else if (gvarp == &p_mps) { // 'matchpairs' - for (p = *varp; *p != NUL; p++) { - int x2 = -1; - int x3 = -1; - - p += utfc_ptr2len(p); - if (*p != NUL) { - x2 = (unsigned char)(*p++); - } - if (*p != NUL) { - x3 = utf_ptr2char(p); - p += utfc_ptr2len(p); - } - if (x2 != ':' || x3 == -1 || (*p != NUL && *p != ',')) { - errmsg = e_invarg; - break; - } - if (*p == NUL) { - break; - } - } + did_set_matchpairs(varp, &errmsg); } else if (gvarp == &p_com) { // 'comments' - for (s = *varp; *s;) { - while (*s && *s != ':') { - if (vim_strchr(COM_ALL, *s) == NULL - && !ascii_isdigit(*s) && *s != '-') { - errmsg = illegal_char(errbuf, errbuflen, *s); - break; - } - s++; - } - if (*s++ == NUL) { - errmsg = N_("E524: Missing colon"); - } else if (*s == ',' || *s == NUL) { - errmsg = N_("E525: Zero length string"); - } - if (errmsg != NULL) { - break; - } - while (*s && *s != ',') { - if (*s == '\\' && s[1] != NUL) { - s++; - } - s++; - } - s = skip_to_option_part(s); - } + did_set_comments(varp, errbuf, errbuflen, &errmsg); } else if (varp == &p_lcs || varp == &p_fcs) { // global 'listchars' or 'fillchars' - char **local_ptr = varp == &p_lcs ? &curwin->w_p_lcs : &curwin->w_p_fcs; - // only apply the global value to "curwin" when it does not have a local value - errmsg = - set_chars_option(curwin, varp, **local_ptr == NUL || !(opt_flags & OPT_GLOBAL)); - if (errmsg == NULL) { - // If the current window is set to use the global - // 'listchars'/'fillchars' value, clear the window-local value. - if (!(opt_flags & OPT_GLOBAL)) { - clear_string_option(local_ptr); - } - FOR_ALL_TAB_WINDOWS(tp, wp) { - // If the current window has a local value need to apply it - // again, it was changed when setting the global value. - // If no error was returned above, we don't expect an error - // here, so ignore the return value. - local_ptr = varp == &p_lcs ? &wp->w_p_lcs : &wp->w_p_fcs; - if (**local_ptr == NUL) { - (void)set_chars_option(wp, local_ptr, true); - } - } - redraw_all_later(UPD_NOT_VALID); - } - } else if (varp == &curwin->w_p_lcs) { // local 'listchars' - errmsg = set_chars_option(curwin, varp, true); - } else if (varp == &curwin->w_p_fcs) { // local 'fillchars' - errmsg = set_chars_option(curwin, varp, true); + did_set_global_listfillchars(win, varp, opt_flags, &errmsg); + } else if (varp == &win->w_p_lcs) { // local 'listchars' + errmsg = set_chars_option(win, varp, true); + } else if (varp == &win->w_p_fcs) { // local 'fillchars' + errmsg = set_chars_option(win, varp, true); } else if (varp == &p_cedit) { // 'cedit' errmsg = check_cedit(); } else if (varp == &p_vfile) { // 'verbosefile' - verbose_stop(); - if (*p_vfile != NUL && verbose_open() == FAIL) { - errmsg = e_invarg; - } + did_set_verbosefile(&errmsg); } else if (varp == &p_shada) { // 'shada' - // TODO(ZyX-I): Remove this code in the future, alongside with &viminfo - // option. - opt_idx = ((opt->fullname[0] == 'v') - ? (shada_idx == -1 ? ((shada_idx = findoption("shada"))) : shada_idx) - : opt_idx); - opt = get_option(opt_idx); - // Update free_oldval now that we have the opt_idx for 'shada', otherwise - // there would be a disconnect between the check for P_ALLOCED at the start - // of the function and the set of P_ALLOCED at the end of the function. - free_oldval = (opt->flags & P_ALLOCED); - for (s = p_shada; *s;) { - // Check it's a valid character - if (vim_strchr("!\"%'/:<@cfhnrs", *s) == NULL) { - errmsg = illegal_char(errbuf, errbuflen, *s); - break; - } - if (*s == 'n') { // name is always last one - break; - } else if (*s == 'r') { // skip until next ',' - while (*++s && *s != ',') {} - } else if (*s == '%') { - // optional number - while (ascii_isdigit(*++s)) {} - } else if (*s == '!' || *s == 'h' || *s == 'c') { - s++; // no extra chars - } else { // must have a number - while (ascii_isdigit(*++s)) {} - - if (!ascii_isdigit(*(s - 1))) { - if (errbuf != NULL) { - vim_snprintf(errbuf, errbuflen, - _("E526: Missing number after <%s>"), - transchar_byte(*(s - 1))); - errmsg = errbuf; - } else { - errmsg = ""; - } - break; - } - } - if (*s == ',') { - s++; - } else if (*s) { - if (errbuf != NULL) { - errmsg = N_("E527: Missing comma"); - } else { - errmsg = ""; - } - break; - } - } - if (*p_shada && errmsg == NULL && get_shada_parameter('\'') < 0) { - errmsg = N_("E528: Must specify a ' value"); - } + did_set_shada(&opt, &opt_idx, &free_oldval, errbuf, errbuflen, &errmsg); } else if (gvarp == &p_sbr) { // 'showbreak' - for (s = *varp; *s;) { - if (ptr2cells(s) != 1) { - errmsg = e_showbreak_contains_unprintable_or_wide_character; - } - MB_PTR_ADV(s); - } + did_set_showbreak(varp, &errmsg); } else if (varp == &p_guicursor) { // 'guicursor' errmsg = parse_shape_opt(SHAPE_CURSOR); - } else if (varp == &p_popt) { - errmsg = parse_printoptions(); - } else if (varp == &p_pmfn) { - errmsg = parse_printmbfont(); } else if (varp == &p_langmap) { // 'langmap' langmap_set(); } else if (varp == &p_breakat) { // 'breakat' fill_breakat_flags(); } else if (varp == &p_titlestring || varp == &p_iconstring) { // 'titlestring' and 'iconstring' - int flagval = (varp == &p_titlestring) ? STL_IN_TITLE : STL_IN_ICON; - - // NULL => statusline syntax - if (vim_strchr(*varp, '%') && check_stl_option(*varp) == NULL) { - stl_syntax |= flagval; - } else { - stl_syntax &= ~flagval; - } - did_set_title(); + did_set_titleiconstring(varp); } else if (varp == &p_sel) { // 'selection' - if (*p_sel == NUL - || check_opt_strings(p_sel, p_sel_values, false) != OK) { - errmsg = e_invarg; - } + did_set_selection(&errmsg); } else if (varp == &p_slm) { // 'selectmode' - if (check_opt_strings(p_slm, p_slm_values, true) != OK) { - errmsg = e_invarg; - } + did_set_opt_strings(p_slm, p_slm_values, true, &errmsg); } else if (varp == &p_km) { // 'keymodel' - if (check_opt_strings(p_km, p_km_values, true) != OK) { - errmsg = e_invarg; - } else { - km_stopsel = (vim_strchr(p_km, 'o') != NULL); - km_startsel = (vim_strchr(p_km, 'a') != NULL); - } + did_set_keymodel(&errmsg); } else if (varp == &p_mousem) { // 'mousemodel' - if (check_opt_strings(p_mousem, p_mousem_values, false) != OK) { - errmsg = e_invarg; - } + did_set_opt_strings(p_mousem, p_mousem_values, false, &errmsg); } else if (varp == &p_mousescroll) { // 'mousescroll' errmsg = check_mousescroll(p_mousescroll); } else if (varp == &p_swb) { // 'switchbuf' - if (opt_strings_flags(p_swb, p_swb_values, &swb_flags, true) != OK) { - errmsg = e_invarg; - } + did_set_opt_flags(p_swb, p_swb_values, &swb_flags, true, &errmsg); } else if (varp == &p_spk) { // 'splitkeep' - if (check_opt_strings(p_spk, p_spk_values, false) != OK) { - errmsg = e_invarg; - } + did_set_opt_strings(p_spk, p_spk_values, false, &errmsg); } else if (varp == &p_debug) { // 'debug' - if (check_opt_strings(p_debug, p_debug_values, true) != OK) { - errmsg = e_invarg; - } + did_set_opt_strings(p_debug, p_debug_values, true, &errmsg); } else if (varp == &p_dy) { // 'display' - if (opt_strings_flags(p_dy, p_dy_values, &dy_flags, true) != OK) { - errmsg = e_invarg; - } else { - (void)init_chartab(); - msg_grid_validate(); - } + did_set_display(&errmsg); } else if (varp == &p_ead) { // 'eadirection' - if (check_opt_strings(p_ead, p_ead_values, false) != OK) { - errmsg = e_invarg; - } + did_set_opt_strings(p_ead, p_ead_values, false, &errmsg); } else if (varp == &p_cb) { // 'clipboard' - if (opt_strings_flags(p_cb, p_cb_values, &cb_flags, true) != OK) { - errmsg = e_invarg; - } - } else if (varp == &(curwin->w_s->b_p_spl) // 'spell' - || varp == &(curwin->w_s->b_p_spf)) { - // When 'spelllang' or 'spellfile' is set and there is a window for this - // buffer in which 'spell' is set load the wordlists. - const bool is_spellfile = varp == &(curwin->w_s->b_p_spf); - - if ((is_spellfile && !valid_spellfile(*varp)) - || (!is_spellfile && !valid_spelllang(*varp))) { - errmsg = e_invarg; - } else { - errmsg = did_set_spell_option(is_spellfile); - } - } else if (varp == &(curwin->w_s->b_p_spc)) { - // When 'spellcapcheck' is set compile the regexp program. - errmsg = compile_cap_prog(curwin->w_s); - } else if (varp == &(curwin->w_s->b_p_spo)) { // 'spelloptions' - if (opt_strings_flags(curwin->w_s->b_p_spo, p_spo_values, &(curwin->w_s->b_p_spo_flags), - true) != OK) { - errmsg = e_invarg; - } + did_set_opt_flags(p_cb, p_cb_values, &cb_flags, true, &errmsg); + } else if (varp == &win->w_s->b_p_spf) { + did_set_spellfile(varp, &errmsg); + } else if (varp == &win->w_s->b_p_spl) { // 'spell' + did_set_spell(varp, &errmsg); + } else if (varp == &win->w_s->b_p_spc) { + did_set_spellcapcheck(win, &errmsg); + } else if (varp == &win->w_s->b_p_spo) { // 'spelloptions' + did_set_spelloptions(win, &errmsg); } else if (varp == &p_sps) { // 'spellsuggest' - if (spell_check_sps() != OK) { - errmsg = e_invarg; - } + did_set_spellsuggest(&errmsg); } else if (varp == &p_msm) { // 'mkspellmem' - if (spell_check_msm() != OK) { - errmsg = e_invarg; - } + did_set_mkspellmem(&errmsg); } else if (gvarp == &p_bh) { - // When 'bufhidden' is set, check for valid value. - if (check_opt_strings(curbuf->b_p_bh, p_bufhidden_values, false) != OK) { - errmsg = e_invarg; - } - } else if (gvarp == &p_bt) { - // When 'buftype' is set, check for valid value. - if ((curbuf->terminal && curbuf->b_p_bt[0] != 't') - || (!curbuf->terminal && curbuf->b_p_bt[0] == 't') - || check_opt_strings(curbuf->b_p_bt, p_buftype_values, false) != OK) { - errmsg = e_invarg; - } else { - if (curwin->w_status_height || global_stl_height()) { - curwin->w_redr_status = true; - redraw_later(curwin, UPD_VALID); - } - curbuf->b_help = (curbuf->b_p_bt[0] == 'h'); - redraw_titles(); - } + did_set_opt_strings(buf->b_p_bh, p_bufhidden_values, false, &errmsg); + } else if (gvarp == &p_bt) { // 'buftype' + did_set_buftype(buf, win, &errmsg); } else if (gvarp == &p_stl || gvarp == &p_wbr || varp == &p_tal - || varp == &p_ruf) { - // 'statusline', 'winbar', 'tabline' or 'rulerformat' - int wid; - - if (varp == &p_ruf) { // reset ru_wid first - ru_wid = 0; - } - s = *varp; - if (varp == &p_ruf && *s == '%') { - // set ru_wid if 'ruf' starts with "%99(" - if (*++s == '-') { // ignore a '-' - s++; - } - wid = getdigits_int(&s, true, 0); - if (wid && *s == '(' && (errmsg = check_stl_option(p_ruf)) == NULL) { - ru_wid = wid; - } else { - errmsg = check_stl_option(p_ruf); - } - } else if (varp == &p_ruf || s[0] != '%' || s[1] != '!') { - // check 'statusline', 'winbar' or 'tabline' only if it doesn't start with "%!" - errmsg = check_stl_option(s); - } - if (varp == &p_ruf && errmsg == NULL) { - comp_col(); - } - // add / remove window bars for 'winbar' - if (gvarp == &p_wbr) { - set_winbar(true); - } - } else if (gvarp == &p_cpt) { - // check if it is a valid value for 'complete' -- Acevedo - for (s = *varp; *s;) { - while (*s == ',' || *s == ' ') { - s++; - } - if (!*s) { - break; - } - if (vim_strchr(".wbuksid]tU", *s) == NULL) { - errmsg = illegal_char(errbuf, errbuflen, *s); - break; - } - if (*++s != NUL && *s != ',' && *s != ' ') { - if (s[-1] == 'k' || s[-1] == 's') { - // skip optional filename after 'k' and 's' - while (*s && *s != ',' && *s != ' ') { - if (*s == '\\' && s[1] != NUL) { - s++; - } - s++; - } - } else { - if (errbuf != NULL) { - vim_snprintf(errbuf, errbuflen, - _("E535: Illegal character after <%c>"), - *--s); - errmsg = errbuf; - } else { - errmsg = ""; - } - break; - } - } - } + || varp == &p_ruf || varp == &win->w_p_stc) { + // 'statusline', 'winbar', 'tabline', 'rulerformat' or 'statuscolumn' + did_set_statusline(win, varp, gvarp, &errmsg); + } else if (gvarp == &p_cpt) { // 'complete' + did_set_complete(varp, errbuf, errbuflen, &errmsg); } else if (varp == &p_cot) { // 'completeopt' - if (check_opt_strings(p_cot, p_cot_values, true) != OK) { - errmsg = e_invarg; - } else { - completeopt_was_set(); - } + did_set_completeopt(&errmsg); #ifdef BACKSLASH_IN_FILENAME } else if (gvarp == &p_csl) { // 'completeslash' if (check_opt_strings(p_csl, p_csl_values, false) != OK - || check_opt_strings(curbuf->b_p_csl, p_csl_values, false) != OK) { + || check_opt_strings(buf->b_p_csl, p_csl_values, false) != OK) { errmsg = e_invarg; } #endif - } else if (varp == &curwin->w_p_scl) { // 'signcolumn' - if (check_signcolumn(*varp) != OK) { - errmsg = e_invarg; - } - // When changing the 'signcolumn' to or from 'number', recompute the - // width of the number column if 'number' or 'relativenumber' is set. - if (((*oldval == 'n' && *(oldval + 1) == 'u') - || (*curwin->w_p_scl == 'n' && *(curwin->w_p_scl + 1) == 'u')) - && (curwin->w_p_nu || curwin->w_p_rnu)) { - curwin->w_nrwidth_line_count = 0; - } - } else if (varp == &curwin->w_p_fdc - || varp == &curwin->w_allbuf_opt.wo_fdc) { + } else if (varp == &win->w_p_scl) { // 'signcolumn' + did_set_signcolumn(win, varp, oldval, &errmsg); + } else if (varp == &p_sloc) { // 'showcmdloc' + did_set_opt_strings(*varp, p_sloc_values, false, &errmsg); + } else if (varp == &win->w_p_fdc + || varp == &win->w_allbuf_opt.wo_fdc) { // 'foldcolumn' - if (**varp == NUL || check_opt_strings(*varp, p_fdc_values, false) != OK) { - errmsg = e_invarg; - } - } else if (varp == &p_pt) { - // 'pastetoggle': translate key codes like in a mapping - if (*p_pt) { - p = NULL; - (void)replace_termcodes(p_pt, - strlen(p_pt), - &p, REPTERM_FROM_PART | REPTERM_DO_LT, NULL, - CPO_TO_CPO_FLAGS); - if (p != NULL) { - free_string_option(p_pt); - p_pt = p; - } - } + did_set_foldcolumn(varp, &errmsg); + } else if (varp == &p_pt) { // 'pastetoggle' + did_set_pastetoggle(); } else if (varp == &p_bs) { // 'backspace' - if (ascii_isdigit(*p_bs)) { - if (*p_bs > '3' || p_bs[1] != NUL) { - errmsg = e_invarg; - } - } else if (check_opt_strings(p_bs, p_bs_values, true) != OK) { - errmsg = e_invarg; - } + did_set_backspace(&errmsg); } else if (varp == &p_bo) { - if (opt_strings_flags(p_bo, p_bo_values, &bo_flags, true) != OK) { - errmsg = e_invarg; - } + did_set_opt_flags(p_bo, p_bo_values, &bo_flags, true, &errmsg); } else if (gvarp == &p_tc) { // 'tagcase' - unsigned int *flags; - - if (opt_flags & OPT_LOCAL) { - p = curbuf->b_p_tc; - flags = &curbuf->b_tc_flags; - } else { - p = p_tc; - flags = &tc_flags; - } - - if ((opt_flags & OPT_LOCAL) && *p == NUL) { - // make the local value empty: use the global value - *flags = 0; - } else if (*p == NUL - || opt_strings_flags(p, p_tc_values, flags, false) != OK) { - errmsg = e_invarg; - } + did_set_tagcase(buf, opt_flags, &errmsg); } else if (varp == &p_cmp) { // 'casemap' - if (opt_strings_flags(p_cmp, p_cmp_values, &cmp_flags, true) != OK) { - errmsg = e_invarg; - } + did_set_opt_flags(p_cmp, p_cmp_values, &cmp_flags, true, &errmsg); } else if (varp == &p_dip) { // 'diffopt' - if (diffopt_changed() == FAIL) { - errmsg = e_invarg; - } - } else if (gvarp == &curwin->w_allbuf_opt.wo_fdm) { // 'foldmethod' - if (check_opt_strings(*varp, p_fdm_values, false) != OK - || *curwin->w_p_fdm == NUL) { - errmsg = e_invarg; - } else { - foldUpdateAll(curwin); - if (foldmethodIsDiff(curwin)) { - newFoldLevel(); - } - } - } else if (varp == &curwin->w_p_fde) { // 'foldexpr' - if (foldmethodIsExpr(curwin)) { - foldUpdateAll(curwin); - } - } else if (gvarp == &curwin->w_allbuf_opt.wo_fmr) { // 'foldmarker' - p = vim_strchr(*varp, ','); - if (p == NULL) { - errmsg = N_("E536: comma required"); - } else if (p == *varp || p[1] == NUL) { - errmsg = e_invarg; - } else if (foldmethodIsMarker(curwin)) { - foldUpdateAll(curwin); - } + did_set_diffopt(&errmsg); + } else if (gvarp == &win->w_allbuf_opt.wo_fdm) { // 'foldmethod' + did_set_foldmethod(win, varp, &errmsg); + } else if (gvarp == &win->w_allbuf_opt.wo_fmr) { // 'foldmarker' + did_set_foldmarker(win, varp, &errmsg); } else if (gvarp == &p_cms) { // 'commentstring' - if (**varp != NUL && strstr(*varp, "%s") == NULL) { - errmsg = N_("E537: 'commentstring' must be empty or contain %s"); - } + did_set_commentstring(varp, &errmsg); } else if (varp == &p_fdo) { // 'foldopen' - if (opt_strings_flags(p_fdo, p_fdo_values, &fdo_flags, true) != OK) { - errmsg = e_invarg; - } + did_set_opt_flags(p_fdo, p_fdo_values, &fdo_flags, true, &errmsg); } else if (varp == &p_fcl) { // 'foldclose' - if (check_opt_strings(p_fcl, p_fcl_values, true) != OK) { - errmsg = e_invarg; - } - } else if (gvarp == &curwin->w_allbuf_opt.wo_fdi) { // 'foldignore' - if (foldmethodIsIndent(curwin)) { - foldUpdateAll(curwin); - } + did_set_opt_strings(*varp, p_fcl_values, true, &errmsg); + } else if (gvarp == &win->w_allbuf_opt.wo_fdi) { // 'foldignore' + did_set_foldignore(win); } else if (gvarp == &p_ve) { // 'virtualedit' - char *ve = p_ve; - unsigned int *flags = &ve_flags; - - if (opt_flags & OPT_LOCAL) { - ve = curwin->w_p_ve; - flags = &curwin->w_ve_flags; - } - - if ((opt_flags & OPT_LOCAL) && *ve == NUL) { - // make the local value empty: use the global value - *flags = 0; - } else { - if (opt_strings_flags(ve, p_ve_values, flags, true) != OK) { - errmsg = e_invarg; - } else if (strcmp(p_ve, oldval) != 0) { - // Recompute cursor position in case the new 've' setting - // changes something. - validate_virtcol(); - coladvance(curwin->w_virtcol); - } - } - } else if (varp == &p_csqf) { - if (p_csqf != NULL) { - p = p_csqf; - while (*p != NUL) { - if (vim_strchr(CSQF_CMDS, *p) == NULL - || p[1] == NUL - || vim_strchr(CSQF_FLAGS, p[1]) == NULL - || (p[2] != NUL && p[2] != ',')) { - errmsg = e_invarg; - break; - } else if (p[2] == NUL) { - break; - } else { - p += 3; - } - } - } + did_set_virtualedit(win, opt_flags, oldval, &errmsg); } else if (gvarp == &p_cino) { // 'cinoptions' // TODO(vim): recognize errors - parse_cino(curbuf); + parse_cino(buf); + } else if (gvarp == &p_lop) { // 'lispoptions' + did_set_lispoptions(varp, &errmsg); } else if (varp == &p_icm) { // 'inccommand' - if (check_opt_strings(p_icm, p_icm_values, false) != OK) { - errmsg = e_invarg; - } - } else if (gvarp == &p_ft) { - if (!valid_filetype(*varp)) { - errmsg = e_invarg; - } else { - value_changed = strcmp(oldval, *varp) != 0; - - // Since we check the value, there is no need to set P_INSECURE, - // even when the value comes from a modeline. - *value_checked = true; - } - } else if (gvarp == &p_syn) { - if (!valid_filetype(*varp)) { - errmsg = e_invarg; - } else { - value_changed = strcmp(oldval, *varp) != 0; - - // Since we check the value, there is no need to set P_INSECURE, - // even when the value comes from a modeline. - *value_checked = true; - } - } else if (varp == &curwin->w_p_winhl) { - if (!parse_winhl_opt(curwin)) { - errmsg = e_invarg; - } + did_set_opt_strings(*varp, p_icm_values, false, &errmsg); + } else if (gvarp == &p_ft || gvarp == &p_syn) { + did_set_filetype_or_syntax(varp, oldval, value_checked, &value_changed, &errmsg); + } else if (varp == &win->w_p_winhl) { + did_set_winhl(win, &errmsg); } else if (varp == &p_tpf) { - if (opt_strings_flags(p_tpf, p_tpf_values, &tpf_flags, true) != OK) { - errmsg = e_invarg; - } - } else if (varp == &(curbuf->b_p_vsts)) { // 'varsofttabstop' - char *cp; - - if (!(*varp)[0] || ((*varp)[0] == '0' && !(*varp)[1])) { - XFREE_CLEAR(curbuf->b_p_vsts_array); - } else { - for (cp = *varp; *cp; cp++) { - if (ascii_isdigit(*cp)) { - continue; - } - if (*cp == ',' && cp > *varp && *(cp - 1) != ',') { - continue; - } - errmsg = e_invarg; - break; - } - if (errmsg == NULL) { - long *oldarray = curbuf->b_p_vsts_array; - if (tabstop_set(*varp, &(curbuf->b_p_vsts_array))) { - xfree(oldarray); - } else { - errmsg = e_invarg; - } - } - } - } else if (varp == &(curbuf->b_p_vts)) { // 'vartabstop' - char *cp; - - if (!(*varp)[0] || ((*varp)[0] == '0' && !(*varp)[1])) { - XFREE_CLEAR(curbuf->b_p_vts_array); - } else { - for (cp = *varp; *cp; cp++) { - if (ascii_isdigit(*cp)) { - continue; - } - if (*cp == ',' && cp > *varp && *(cp - 1) != ',') { - continue; - } - errmsg = e_invarg; - break; - } - if (errmsg == NULL) { - long *oldarray = curbuf->b_p_vts_array; - if (tabstop_set(*varp, &(curbuf->b_p_vts_array))) { - xfree(oldarray); - if (foldmethodIsIndent(curwin)) { - foldUpdateAll(curwin); - } - } else { - errmsg = e_invarg; - } - } - } + did_set_opt_flags(p_tpf, p_tpf_values, &tpf_flags, true, &errmsg); + } else if (varp == &buf->b_p_vsts) { // 'varsofttabstop' + did_set_varsoftabstop(buf, varp, &errmsg); + } else if (varp == &buf->b_p_vts) { // 'vartabstop' + did_set_vartabstop(buf, win, varp, &errmsg); + } else if (varp == &p_dex) { // 'diffexpr' + did_set_optexpr(win, &p_dex, varp, gvarp); + } else if (varp == &win->w_p_fde) { // 'foldexpr' + did_set_optexpr(win, &win->w_p_fde, varp, gvarp); + if (foldmethodIsExpr(win)) { + foldUpdateAll(win); + } + } else if (varp == &win->w_p_fdt) { // 'foldtext' + did_set_optexpr(win, &win->w_p_fdt, varp, gvarp); + } else if (varp == &p_pex) { // 'patchexpr' + did_set_optexpr(win, &p_pex, varp, gvarp); + } else if (gvarp == &p_fex) { // 'formatexpr' + did_set_optexpr(win, &buf->b_p_fex, varp, gvarp); + } else if (gvarp == &p_inex) { // 'includeexpr' + did_set_optexpr(win, &buf->b_p_inex, varp, gvarp); + } else if (gvarp == &p_inde) { // 'indentexpr' + did_set_optexpr(win, &buf->b_p_inde, varp, gvarp); + } else if (gvarp == &p_cfu) { // 'completefunc' + set_completefunc_option(&errmsg); + } else if (gvarp == &p_ofu) { // 'omnifunc' + set_omnifunc_option(buf, &errmsg); + } else if (gvarp == &p_tsrfu) { // 'thesaurusfunc' + set_thesaurusfunc_option(&errmsg); } else if (varp == &p_opfunc) { // 'operatorfunc' - if (set_operatorfunc_option() == FAIL) { - errmsg = e_invarg; - } + set_operatorfunc_option(&errmsg); } else if (varp == &p_qftf) { // 'quickfixtextfunc' - if (qf_process_qftf_option() == FAIL) { - errmsg = e_invarg; - } - } else { - // Options that are a list of flags. - p = NULL; - if (varp == &p_ww) { // 'whichwrap' - p = WW_ALL; - } - if (varp == &p_shm) { // 'shortmess' - p = SHM_ALL; - } else if (varp == &(p_cpo)) { // 'cpoptions' - p = CPO_VI; - } else if (varp == &(curbuf->b_p_fo)) { // 'formatoptions' - p = FO_ALL; - } else if (varp == &curwin->w_p_cocu) { // 'concealcursor' - p = COCU_ALL; - } else if (varp == &p_mouse) { // 'mouse' - p = MOUSE_ALL; - } - if (p != NULL) { - for (s = *varp; *s; s++) { - if (vim_strchr(p, *s) == NULL) { - errmsg = illegal_char(errbuf, errbuflen, *s); - break; - } - } + qf_process_qftf_option(&errmsg); + } else if (gvarp == &p_tfu) { // 'tagfunc' + set_tagfunc_option(&errmsg); + } else if (varp == &p_ww) { // 'whichwrap' + did_set_option_listflag(varp, WW_ALL, errbuf, errbuflen, &errmsg); + } else if (varp == &p_shm) { // 'shortmess' + did_set_option_listflag(varp, SHM_ALL, errbuf, errbuflen, &errmsg); + } else if (varp == &p_cpo) { // 'cpoptions' + did_set_option_listflag(varp, CPO_VI, errbuf, errbuflen, &errmsg); + } else if (varp == &buf->b_p_fo) { // 'formatoptions' + did_set_option_listflag(varp, FO_ALL, errbuf, errbuflen, &errmsg); + } else if (varp == &win->w_p_cocu) { // 'concealcursor' + did_set_option_listflag(varp, COCU_ALL, errbuf, errbuflen, &errmsg); + } else if (varp == &p_mouse) { // 'mouse' + did_set_option_listflag(varp, MOUSE_ALL, errbuf, errbuflen, &errmsg); + } else if (gvarp == &p_flp) { + if (win->w_briopt_list) { + // Changing Formatlistpattern when briopt includes the list setting: + // redraw + redraw_all_later(UPD_NOT_VALID); } } @@ -1520,7 +1863,7 @@ char *did_set_string_option(int opt_idx, char **varp, char *oldval, char *errbuf *varp = oldval; // When resetting some values, need to act on it. if (did_chartab) { - (void)init_chartab(); + (void)buf_init_chartab(buf, true); } } else { // Remember where the option was set. @@ -1537,7 +1880,7 @@ char *did_set_string_option(int opt_idx, char **varp, char *oldval, char *errbuf && (opt->indir & PV_BOTH)) { // global option with local value set to use global value; free // the local value and make it empty - p = get_varp_scope(opt, OPT_LOCAL); + char *p = get_varp_scope(opt, OPT_LOCAL); free_string_option(*(char **)p); *(char **)p = empty_option; } else if (!(opt_flags & OPT_LOCAL) && opt_flags != OPT_GLOBAL) { @@ -1546,65 +1889,12 @@ char *did_set_string_option(int opt_idx, char **varp, char *oldval, char *errbuf } // Trigger the autocommand only after setting the flags. - // When 'syntax' is set, load the syntax of that name - if (varp == &(curbuf->b_p_syn)) { - static int syn_recursive = 0; - - syn_recursive++; - // Only pass true for "force" when the value changed or not used - // recursively, to avoid endless recurrence. - apply_autocmds(EVENT_SYNTAX, curbuf->b_p_syn, curbuf->b_fname, - value_changed || syn_recursive == 1, curbuf); - curbuf->b_flags |= BF_SYN_SET; - syn_recursive--; - } else if (varp == &(curbuf->b_p_ft)) { - // 'filetype' is set, trigger the FileType autocommand - // Skip this when called from a modeline and the filetype was - // already set to this value. - if (!(opt_flags & OPT_MODELINE) || value_changed) { - static int ft_recursive = 0; - int secure_save = secure; - - // Reset the secure flag, since the value of 'filetype' has - // been checked to be safe. - secure = 0; - - ft_recursive++; - did_filetype = true; - // Only pass true for "force" when the value changed or not - // used recursively, to avoid endless recurrence. - apply_autocmds(EVENT_FILETYPE, curbuf->b_p_ft, curbuf->b_fname, - value_changed || ft_recursive == 1, curbuf); - ft_recursive--; - // Just in case the old "curbuf" is now invalid - if (varp != &(curbuf->b_p_ft)) { - varp = NULL; - } - secure = secure_save; - } - } - if (varp == &(curwin->w_s->b_p_spl)) { - char fname[200]; - char *q = curwin->w_s->b_p_spl; - - // Skip the first name if it is "cjk". - if (STRNCMP(q, "cjk,", 4) == 0) { - q += 4; - } - - // Source the spell/LANG.vim in 'runtimepath'. - // They could set 'spellcapcheck' depending on the language. - // Use the first name in 'spelllang' up to '_region' or - // '.encoding'. - for (p = q; *p != NUL; p++) { - if (!ASCII_ISALNUM(*p) && *p != '-') { - break; - } - } - if (p > q) { - vim_snprintf(fname, sizeof(fname), "spell/%.*s.vim", (int)(p - q), q); - source_runtime(fname, DIP_ALL); - } + if (varp == &buf->b_p_syn) { + do_syntax_autocmd(buf, value_changed); + } else if (varp == &buf->b_p_ft) { + do_filetype_autocmd(buf, varp, opt_flags, value_changed); + } else if (varp == &win->w_s->b_p_spl) { + did_set_spelllang_source(win); } } @@ -1612,16 +1902,23 @@ char *did_set_string_option(int opt_idx, char **varp, char *oldval, char *errbuf setmouse(); // in case 'mouse' changed } - if (curwin->w_curswant != MAXCOL + if (win->w_curswant != MAXCOL && (opt->flags & (P_CURSWANT | P_RALL)) != 0) { - curwin->w_set_curswant = true; + win->w_set_curswant = true; } - check_redraw(opt->flags); + check_redraw_for(buf, win, opt->flags); return errmsg; } +char *did_set_string_option(int opt_idx, char **varp, char *oldval, char *errbuf, size_t errbuflen, + int opt_flags, int *value_checked) +{ + return did_set_string_option_for(curbuf, curwin, opt_idx, varp, oldval, 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 @@ -1651,7 +1948,7 @@ static int opt_strings_flags(char *val, char **values, unsigned *flagp, bool lis } size_t len = strlen(values[i]); - if (STRNCMP(values[i], val, len) == 0 + if (strncmp(values[i], val, len) == 0 && ((list && val[len] == ',') || val[len] == NUL)) { val += len + (val[len] == ','); assert(i < sizeof(1U) * 8); |