diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c index c63ab804af..14a07489a0 100644 --- a/src/nvim/buffer.c +++ b/src/nvim/buffer.c @@ -1687,7 +1687,7 @@ void enter_buffer(buf_T *buf) // May need to set the spell language. Can only do this after the buffer // has been properly setup. if (!curbuf->b_help && curwin->w_p_spell && *curwin->w_s->b_p_spl != NUL) { - (void)did_set_spelllang(curwin); + (void)parse_spelllang(curwin); } curbuf->b_last_used = time(NULL); diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index ebc34564e2..f898063fb0 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -7711,7 +7711,7 @@ static void f_spellbadword(typval_T *argvars, typval_T *rettv, EvalFuncData fptr const int wo_spell_save = curwin->w_p_spell; if (!curwin->w_p_spell) { - did_set_spelllang(curwin); + parse_spelllang(curwin); curwin->w_p_spell = true; } @@ -7768,7 +7768,7 @@ static void f_spellsuggest(typval_T *argvars, typval_T *rettv, EvalFuncData fptr const int wo_spell_save = curwin->w_p_spell; if (!curwin->w_p_spell) { - did_set_spelllang(curwin); + parse_spelllang(curwin); curwin->w_p_spell = true; } diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c index 7a77ffb4da..f276e8ae24 100644 --- a/src/nvim/ex_cmds.c +++ b/src/nvim/ex_cmds.c @@ -2640,7 +2640,7 @@ int do_ecmd(int fnum, char *ffname, char *sfname, exarg_T *eap, linenr_T newlnum // If the window options were changed may need to set the spell language. // Can only do this after the buffer has been properly setup. if (did_get_winopts && curwin->w_p_spell && *curwin->w_s->b_p_spl != NUL) { - (void)did_set_spelllang(curwin); + (void)parse_spelllang(curwin); } if (command == NULL) { diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c index 33a8dcafc2..c0c8a5605b 100644 --- a/src/nvim/ex_getln.c +++ b/src/nvim/ex_getln.c @@ -4277,7 +4277,7 @@ void cmdline_init(void) /// Check value of 'cedit' and set cedit_key. /// Returns NULL if value is OK, error message otherwise. -const char *check_cedit(void) +const char *did_set_cedit(optset_T *args) { if (*p_cedit == NUL) { cedit_key = -1; diff --git a/src/nvim/generators/gen_options.lua b/src/nvim/generators/gen_options.lua index 35302e1222..ecb1a0c11b 100644 --- a/src/nvim/generators/gen_options.lua +++ b/src/nvim/generators/gen_options.lua @@ -154,6 +154,9 @@ local dump_option = function(i, o) table.insert(defines, { 'PV_' .. varname:sub(3):upper() , pv_name}) w(' .indir=' .. pv_name) end + if o.cb then + w(' .opt_did_set_cb=' .. o.cb) + end if o.enable_if then w('#else') w(' .var=NULL') diff --git a/src/nvim/insexpand.c b/src/nvim/insexpand.c index 6624b39d0c..d6860fff30 100644 --- a/src/nvim/insexpand.c +++ b/src/nvim/insexpand.c @@ -2257,14 +2257,14 @@ static void copy_global_to_buflocal_cb(Callback *globcb, Callback *bufcb) /// Invoked when the 'completefunc' option is set. The option value can be a /// name of a function (string), or function() or funcref() or a /// lambda expression. -void set_completefunc_option(const char **errmsg) +const char *did_set_completefunc(optset_T *args FUNC_ATTR_UNUSED) { if (option_set_callback_func(curbuf->b_p_cfu, &cfu_cb) == FAIL) { - *errmsg = e_invarg; - return; + return e_invarg; } set_buflocal_cfu_callback(curbuf); + return NULL; } /// Copy the global 'completefunc' callback function to the buffer-local @@ -2278,13 +2278,14 @@ void set_buflocal_cfu_callback(buf_T *buf) /// Invoked when the 'omnifunc' option is set. The option value can be a /// name of a function (string), or function() or funcref() or a /// lambda expression. -void set_omnifunc_option(buf_T *buf, const char **errmsg) +const char *did_set_omnifunc(optset_T *args) { + buf_T *buf = (buf_T *)args->os_buf; if (option_set_callback_func(buf->b_p_ofu, &ofu_cb) == FAIL) { - *errmsg = e_invarg; - return; + return e_invarg; } set_buflocal_ofu_callback(buf); + return NULL; } /// Copy the global 'omnifunc' callback function to the buffer-local 'omnifunc' @@ -2298,7 +2299,7 @@ void set_buflocal_ofu_callback(buf_T *buf) /// Invoked when the 'thesaurusfunc' option is set. The option value can be a /// name of a function (string), or function() or funcref() or a /// lambda expression. -void set_thesaurusfunc_option(const char **errmsg) +const char *did_set_thesaurusfunc(optset_T *args FUNC_ATTR_UNUSED) { int retval; @@ -2310,9 +2311,7 @@ void set_thesaurusfunc_option(const char **errmsg) retval = option_set_callback_func(p_tsrfu, &tsrfu_cb); } - if (retval == FAIL) { - *errmsg = e_invarg; - } + return retval == FAIL ? e_invarg : NULL; } /// Mark the global 'completefunc' 'omnifunc' and 'thesaurusfunc' callbacks with diff --git a/src/nvim/lua/spell.c b/src/nvim/lua/spell.c index 742e8720f9..37f1c5216d 100644 --- a/src/nvim/lua/spell.c +++ b/src/nvim/lua/spell.c @@ -39,7 +39,7 @@ int nlua_spell_check(lua_State *lstate) const int wo_spell_save = curwin->w_p_spell; if (!curwin->w_p_spell) { - did_set_spelllang(curwin); + parse_spelllang(curwin); curwin->w_p_spell = true; } diff --git a/src/nvim/mapping.c b/src/nvim/mapping.c index 9a835e0eb8..c1d02e89b8 100644 --- a/src/nvim/mapping.c +++ b/src/nvim/mapping.c @@ -2386,7 +2386,7 @@ void langmap_init(void) /// Called when langmap option is set; the language map can be /// changed at any time! -void langmap_set(void) +const char *did_set_langmap(optset_T *args) { char *p; char *p2; @@ -2434,9 +2434,10 @@ void langmap_set(void) } } if (to == NUL) { - semsg(_("E357: 'langmap': Matching character missing for %s"), - transchar(from)); - return; + snprintf(args->os_errbuf, args->os_errbuflen, + _("E357: 'langmap': Matching character missing for %s"), + transchar(from)); + return args->os_errbuf; } if (from >= 256) { @@ -2454,8 +2455,10 @@ void langmap_set(void) p = p2; if (p[0] != NUL) { if (p[0] != ',') { - semsg(_("E358: 'langmap': Extra characters after semicolon: %s"), p); - return; + snprintf(args->os_errbuf, args->os_errbuflen, + _("E358: 'langmap': Extra characters after semicolon: %s"), + p); + return args->os_errbuf; } p++; } @@ -2464,6 +2467,8 @@ void langmap_set(void) } } } + + return NULL; } static void do_exmap(exarg_T *eap, int isabbrev) diff --git a/src/nvim/ops.c b/src/nvim/ops.c index 2919b94d41..89fe9b464d 100644 --- a/src/nvim/ops.c +++ b/src/nvim/ops.c @@ -5628,11 +5628,12 @@ static void op_colon(oparg_T *oap) static Callback opfunc_cb; /// Process the 'operatorfunc' option value. -void set_operatorfunc_option(const char **errmsg) +const char *did_set_operatorfunc(optset_T *args FUNC_ATTR_UNUSED) { if (option_set_callback_func(p_opfunc, &opfunc_cb) == FAIL) { - *errmsg = e_invarg; + return e_invarg; } + return NULL; } #if defined(EXITFREE) diff --git a/src/nvim/option.c b/src/nvim/option.c index 040ab1b847..3264d80a2f 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -84,6 +84,7 @@ #include "nvim/path.h" #include "nvim/popupmenu.h" #include "nvim/pos.h" +#include "nvim/quickfix.h" #include "nvim/regexp.h" #include "nvim/runtime.h" #include "nvim/search.h" @@ -135,17 +136,6 @@ static long p_tw_nopaste; static long p_wm_nopaste; static char *p_vsts_nopaste; -// options[] is initialized here. -// The order of the options MUST be alphabetic for ":set all" and findoption(). -// All option names MUST start with a lowercase letter (for findoption()). -// Exception: "t_" options are at the end. -// The options with a NULL variable are 'hidden': a set command for them is -// ignored and they are not printed. - -#ifdef INCLUDE_GENERATED_DECLARATIONS -# include "options.generated.h" -#endif - #define OPTION_COUNT ARRAY_SIZE(options) typedef enum { @@ -159,6 +149,17 @@ typedef enum { # include "option.c.generated.h" #endif +// options[] is initialized here. +// The order of the options MUST be alphabetic for ":set all" and findoption(). +// All option names MUST start with a lowercase letter (for findoption()). +// Exception: "t_" options are at the end. +// The options with a NULL variable are 'hidden': a set command for them is +// ignored and they are not printed. + +#ifdef INCLUDE_GENERATED_DECLARATIONS +# include "options.generated.h" +#endif + void set_init_tablocal(void) { // susy baka: cmdheight calls itself OPT_GLOBAL but is really tablocal! @@ -1237,7 +1238,7 @@ static void do_set_option_string(int opt_idx, int opt_flags, char **argp, int ne // Handle side effects, and set the global value for ":set" on local // options. Note: when setting 'syntax' or 'filetype' autocommands may // be triggered that can cause havoc. - *errmsg = did_set_string_option(opt_idx, (char **)varp, oldval, + *errmsg = did_set_string_option(opt_idx, (char **)varp, oldval, newval, errbuf, errbuflen, opt_flags, value_checked); @@ -1840,9 +1841,9 @@ static void didset_options(void) (void)compile_cap_prog(curwin->w_s); (void)did_set_spell_option(true); // set cedit_key - (void)check_cedit(); + (void)did_set_cedit(NULL); // initialize the table for 'breakat'. - fill_breakat_flags(); + (void)did_set_breakat(NULL); didset_window_options(curwin, true); } @@ -1853,10 +1854,10 @@ static void didset_options2(void) highlight_changed(); // Parse default for 'fillchars'. - (void)set_chars_option(curwin, &curwin->w_p_fcs, true); + (void)set_fillchars_option(curwin, curwin->w_p_fcs, true); // Parse default for 'listchars'. - (void)set_chars_option(curwin, &curwin->w_p_lcs, true); + (void)set_listchars_option(curwin, curwin->w_p_lcs, true); // Parse default for 'wildmode'. check_opt_wim(); @@ -2101,25 +2102,27 @@ static const char *did_set_force_off(bool *doskip) } /// Process the updated 'langremap' option value. -static void did_set_langremap(void) +static const char *did_set_langremap(optset_T *args FUNC_ATTR_UNUSED) { // 'langremap' -> !'langnoremap' p_lnr = !p_lrm; + return NULL; } /// Process the updated 'langnoremap' option value. -static void did_set_langnoremap(void) +static const char *did_set_langnoremap(optset_T *args FUNC_ATTR_UNUSED) { // 'langnoremap' -> !'langremap' p_lrm = !p_lnr; + return NULL; } /// Process the updated 'undofile' option value. -static void did_set_undofile(int opt_flags) +static const char *did_set_undofile(optset_T *args) { // Only take action when the option was set. if (!curbuf->b_p_udf && !p_udf) { - return; + return NULL; } // When reset we do not delete the undo file, the option may be set again @@ -2132,19 +2135,21 @@ static void did_set_undofile(int opt_flags) // if one exists, the buffer wasn't changed and the buffer was // loaded if ((curbuf == bp - || (opt_flags & OPT_GLOBAL) || opt_flags == 0) + || (args->os_flags & OPT_GLOBAL) || args->os_flags == 0) && !bufIsChanged(bp) && bp->b_ml.ml_mfp != NULL) { u_compute_hash(bp, hash); u_read_undo(NULL, hash, bp->b_fname); } } + + return NULL; } /// Process the updated 'readonly' option value. -static void did_set_readonly(int opt_flags) +static const char *did_set_readonly(optset_T *args) { // when 'readonly' is reset globally, also reset readonlymode - if (!curbuf->b_p_ro && (opt_flags & OPT_LOCAL) == 0) { + if (!curbuf->b_p_ro && (args->os_flags & OPT_LOCAL) == 0) { readonlymode = false; } @@ -2154,10 +2159,12 @@ static void did_set_readonly(int opt_flags) } redraw_titles(); + + return NULL; } /// Process the updated 'modifiable' option value. -static char *did_set_modifiable(void) +static const char *did_set_modifiable(optset_T *args FUNC_ATTR_UNUSED) { // when 'modifiable' is changed, redraw the window title redraw_titles(); @@ -2167,90 +2174,108 @@ static char *did_set_modifiable(void) /// Process the updated 'endoffile' or 'endofline' or 'fixendofline' or 'bomb' /// option value. -static void did_set_eof_eol_fixeol_bomb(void) +static const char *did_set_eof_eol_fixeol_bomb(optset_T *args FUNC_ATTR_UNUSED) { // redraw the window title and tab page text redraw_titles(); + return NULL; } /// Process the updated 'binary' option value. -static void did_set_binary(int opt_flags, long old_value) +static const char *did_set_binary(optset_T *args) { + buf_T *buf = (buf_T *)args->os_buf; + // when 'bin' is set also set some other options - set_options_bin((int)old_value, curbuf->b_p_bin, opt_flags); + set_options_bin((int)args->os_oldval.boolean, buf->b_p_bin, args->os_flags); redraw_titles(); + + return NULL; } /// Process the updated 'buflisted' option value. -static void did_set_buflisted(long old_value) +static const char *did_set_buflisted(optset_T *args) { + buf_T *buf = (buf_T *)args->os_buf; + // when 'buflisted' changes, trigger autocommands - if (old_value != curbuf->b_p_bl) { - apply_autocmds(curbuf->b_p_bl ? EVENT_BUFADD : EVENT_BUFDELETE, - NULL, NULL, true, curbuf); + if (args->os_oldval.boolean != buf->b_p_bl) { + apply_autocmds(buf->b_p_bl ? EVENT_BUFADD : EVENT_BUFDELETE, + NULL, NULL, true, buf); } + return NULL; } /// Process the updated 'swapfile' option value. -static void did_set_swapfile(void) +static const char *did_set_swapfile(optset_T *args) { + buf_T *buf = (buf_T *)args->os_buf; // when 'swf' is set, create swapfile, when reset remove swapfile - if (curbuf->b_p_swf && p_uc) { - ml_open_file(curbuf); // create the swap file + if (buf->b_p_swf && p_uc) { + ml_open_file(buf); // create the swap file } else { // no need to reset curbuf->b_may_swap, ml_open_file() will check // buf->b_p_swf - mf_close_file(curbuf, true); // remove the swap file + mf_close_file(buf, true); // remove the swap file } + return NULL; } /// Process the updated 'paste' option value. -static void did_set_paste(void) +static const char *did_set_paste(optset_T *args FUNC_ATTR_UNUSED) { // when 'paste' is set or reset also change other options paste_option_changed(); + return NULL; } /// Process the updated 'ignorecase' option value. -static void did_set_ignorecase(void) +static const char *did_set_ignorecase(optset_T *args FUNC_ATTR_UNUSED) { // when 'ignorecase' is set or reset and 'hlsearch' is set, redraw if (p_hls) { redraw_all_later(UPD_SOME_VALID); } + return NULL; } /// Process the updated 'hlsearch' option value. -static void did_set_hlsearch(void) +static const char *did_set_hlsearch(optset_T *args FUNC_ATTR_UNUSED) { // when 'hlsearch' is set or reset: reset no_hlsearch set_no_hlsearch(false); + return NULL; } /// Process the updated 'scrollbind' option value. -static void did_set_scrollbind(void) +static const char *did_set_scrollbind(optset_T *args) { + win_T *win = (win_T *)args->os_win; + // when 'scrollbind' is set: snapshot the current position to avoid a jump // at the end of normal_cmd() - if (!curwin->w_p_scb) { - return; + if (!win->w_p_scb) { + return NULL; } do_check_scrollbind(false); - curwin->w_scbind_pos = curwin->w_topline; + win->w_scbind_pos = win->w_topline; + return NULL; } /// Process the updated 'previewwindow' option value. -static const char *did_set_previewwindow(bool *doskip) +static const char *did_set_previewwindow(optset_T *args) { - if (!curwin->w_p_pvw) { + win_T *win = (win_T *)args->os_win; + + if (!win->w_p_pvw) { return NULL; } // There can be only one window with 'previewwindow' set. - FOR_ALL_WINDOWS_IN_TAB(win, curtab) { - if (win->w_p_pvw && win != curwin) { - curwin->w_p_pvw = false; - *doskip = true; + FOR_ALL_WINDOWS_IN_TAB(wp, curtab) { + if (wp->w_p_pvw && wp != win) { + win->w_p_pvw = false; + args->os_doskip = true; return e_preview_window_already_exists; } } @@ -2259,32 +2284,37 @@ static const char *did_set_previewwindow(bool *doskip) } /// Process the updated 'lisp' option value. -static void did_set_lisp(void) +static const char *did_set_lisp(optset_T *args) { + buf_T *buf = (buf_T *)args->os_buf; // When 'lisp' option changes include/exclude '-' in keyword characters. - (void)buf_init_chartab(curbuf, false); // ignore errors + (void)buf_init_chartab(buf, false); // ignore errors + return NULL; } /// Process the updated 'title' or the 'icon' option value. -static void did_set_title_icon(void) +static const char *did_set_title_icon(optset_T *args FUNC_ATTR_UNUSED) { // when 'title' changed, may need to change the title; same for 'icon' did_set_title(); + return NULL; } /// Process the updated 'modified' option value. -static void did_set_modified(long value) +static const char *did_set_modified(optset_T *args) { - if (!value) { - save_file_ff(curbuf); // Buffer is unchanged + buf_T *buf = (buf_T *)args->os_buf; + if (!args->os_newval.boolean) { + save_file_ff(buf); // Buffer is unchanged } redraw_titles(); - modified_was_set = (int)value; + modified_was_set = (int)args->os_newval.boolean; + return NULL; } #ifdef BACKSLASH_IN_FILENAME /// Process the updated 'shellslash' option value. -static void did_set_shellslash(void) +static const char *did_set_shellslash(optset_T *args FUNC_ATTR_UNUSED) { if (p_ssl) { psepc = '/'; @@ -2300,63 +2330,76 @@ static void did_set_shellslash(void) buflist_slash_adjust(); alist_slash_adjust(); scriptnames_slash_adjust(); + return NULL; } #endif /// Process the updated 'wrap' option value. -static void did_set_wrap(void) +static const char *did_set_wrap(optset_T *args) { + win_T *win = (win_T *)args->os_win; + // If 'wrap' is set, set w_leftcol to zero. - if (curwin->w_p_wrap) { - curwin->w_leftcol = 0; + if (win->w_p_wrap) { + win->w_leftcol = 0; } + return NULL; } /// Process the updated 'equalalways' option value. -static void did_set_equalalways(long old_value) +static const char *did_set_equalalways(optset_T *args) { - if (p_ea && !old_value) { - win_equal(curwin, false, 0); + win_T *win = (win_T *)args->os_win; + if (p_ea && !args->os_oldval.boolean) { + win_equal(win, false, 0); } + + return NULL; } /// Process the updated 'autochdir' option value. -static void did_set_autochdir(void) +static const char *did_set_autochdir(optset_T *args FUNC_ATTR_UNUSED) { // Change directories when the 'acd' option is set now. do_autochdir(); + return NULL; } /// Process the updated 'diff' option value. -static void did_set_diff(void) +static const char *did_set_diff(optset_T *args) { + win_T *win = (win_T *)args->os_win; // May add or remove the buffer from the list of diff buffers. - diff_buf_adjust(curwin); - if (foldmethodIsDiff(curwin)) { - foldUpdateAll(curwin); + diff_buf_adjust(win); + if (foldmethodIsDiff(win)) { + foldUpdateAll(win); } + return NULL; } /// Process the updated 'spell' option value. -static char *did_set_spell(void) +static const char *did_set_spell(optset_T *args) { - if (curwin->w_p_spell) { - return did_set_spelllang(curwin); + win_T *win = (win_T *)args->os_win; + if (win->w_p_spell) { + return parse_spelllang(win); } return NULL; } /// Process the updated 'arabic' option value. -static const char *did_set_arabic(void) +static const char *did_set_arabic(optset_T *args) { + win_T *win = (win_T *)args->os_win; const char *errmsg = NULL; - if (curwin->w_p_arab) { + + if (win->w_p_arab) { // 'arabic' is set, handle various sub-settings. if (!p_tbidi) { // set rightleft mode - if (!curwin->w_p_rl) { - curwin->w_p_rl = true; + if (!win->w_p_rl) { + win->w_p_rl = true; changed_window_setting(); } @@ -2386,8 +2429,8 @@ static const char *did_set_arabic(void) // 'arabic' is reset, handle various sub-settings. if (!p_tbidi) { // reset rightleft mode - if (curwin->w_p_rl) { - curwin->w_p_rl = false; + if (win->w_p_rl) { + win->w_p_rl = false; changed_window_setting(); } @@ -2406,85 +2449,15 @@ static const char *did_set_arabic(void) return errmsg; } -static void did_set_number_relativenumber(void) +/// Process the updated 'number' or 'relativenumber' option value. +static const char *did_set_number_relativenumber(optset_T *args) { - if (*curwin->w_p_stc != NUL) { + win_T *win = (win_T *)args->os_win; + if (*win->w_p_stc != NUL) { // When 'relativenumber'/'number' is changed and 'statuscolumn' is set, reset width. - curwin->w_nrwidth_line_count = 0; + win->w_nrwidth_line_count = 0; } -} - -/// When some boolean options are changed, need to take some action. -static const char *did_set_bool_option(const char *varp, int opt_flags, long value, long old_value, - bool *doskip) -{ - const char *errmsg = NULL; - - if ((int *)varp == &p_force_on) { - errmsg = did_set_force_on(doskip); - } else if ((int *)varp == &p_force_off) { - errmsg = did_set_force_off(doskip); - } else if ((int *)varp == &p_lrm) { // 'langremap' - did_set_langremap(); - } else if ((int *)varp == &p_lnr) { // 'langnoremap' - did_set_langnoremap(); - } else if ((int *)varp == &curbuf->b_p_udf // buffer local 'undofile' - || (int *)varp == &p_udf) { // 'undofile' - did_set_undofile(opt_flags); - } else if ((int *)varp == &curbuf->b_p_ro) { // 'readonly' - did_set_readonly(opt_flags); - } else if ((int *)varp == &curbuf->b_p_ma) { - errmsg = did_set_modifiable(); // 'modifiable' - } else if ((int *)varp == &curbuf->b_p_eof // 'endoffile' - || (int *)varp == &curbuf->b_p_eol // 'endofline' - || (int *)varp == &curbuf->b_p_fixeol // 'fixendofline' - || (int *)varp == &curbuf->b_p_bomb) { // 'bomb' - did_set_eof_eol_fixeol_bomb(); - } else if ((int *)varp == &curbuf->b_p_bin) { // 'binary' - did_set_binary(opt_flags, old_value); - } else if ((int *)varp == &curbuf->b_p_bl) { // 'buflisted' - did_set_buflisted(old_value); - } else if ((int *)varp == &curbuf->b_p_swf) { // 'swapfile' - did_set_swapfile(); - } else if ((int *)varp == &p_paste) { // 'paste' - did_set_paste(); - } else if ((int *)varp == &p_ic) { // 'ignorecase' - did_set_ignorecase(); - } else if ((int *)varp == &p_hls) { // 'hlsearch' - did_set_hlsearch(); - } else if ((int *)varp == &curwin->w_p_scb) { // 'scrollbind' - did_set_scrollbind(); - } else if ((int *)varp == &curwin->w_p_pvw) { // 'previewwindow' - errmsg = did_set_previewwindow(doskip); - } else if (varp == (char *)&(curbuf->b_p_lisp)) { // 'lisp' - did_set_lisp(); - } else if ((int *)varp == &p_title // 'title' - || (int *)varp == &p_icon) { // 'icon' - did_set_title_icon(); - } else if ((int *)varp == &curbuf->b_changed) { // 'modified' - did_set_modified(value); -#ifdef BACKSLASH_IN_FILENAME - } else if ((int *)varp == &p_ssl) { // 'shellslash' - did_set_shellslash(); -#endif - } else if ((int *)varp == &curwin->w_p_wrap) { // 'wrap' - did_set_wrap(); - } else if ((int *)varp == &p_ea) { // 'equalalways' - did_set_equalalways(old_value); - } else if ((int *)varp == &p_acd) { // 'autochdir' - did_set_autochdir(); - } else if ((int *)varp == &curwin->w_p_diff) { // 'diff' - did_set_diff(); - } else if ((int *)varp == &curwin->w_p_spell) { // 'spell' - errmsg = did_set_spell(); - } else if ((int *)varp == &curwin->w_p_arab) { // 'arabic' - errmsg = did_set_arabic(); - } else if ((int *)varp == &curwin->w_p_nu // 'number' - || (int *)varp == &curwin->w_p_rnu) { // 'relativenumber' - did_set_number_relativenumber(); - } - - return errmsg; + return NULL; } /// Set the value of a boolean option, taking care of side effects @@ -2524,8 +2497,28 @@ static const char *set_bool_option(const int opt_idx, char *const varp, const in } // Handle side effects for changing a bool option. + const char *errmsg = NULL; bool doskip = false; - const char *errmsg = did_set_bool_option(varp, opt_flags, value, old_value, &doskip); + if ((int *)varp == &p_force_on) { + errmsg = did_set_force_on(&doskip); + } else if ((int *)varp == &p_force_off) { + errmsg = did_set_force_off(&doskip); + } else if (options[opt_idx].opt_did_set_cb != NULL) { + optset_T args = { + .os_varp = varp, + .os_flags = opt_flags, + .os_oldval.boolean = old_value, + .os_newval.boolean = value, + .os_doskip = false, + .os_errbuf = NULL, + .os_errbuflen = 0, + .os_buf = curbuf, + .os_win = curwin + }; + + errmsg = options[opt_idx].opt_did_set_cb(&args); + doskip = args.os_doskip; + } if (doskip) { return errmsg; } @@ -2557,38 +2550,51 @@ static const char *set_bool_option(const int opt_idx, char *const varp, const in } /// Process the new 'winheight' value. -static void did_set_winheight(win_T *win, long value) +static const char *did_set_winheight(optset_T *args) { // Change window height NOW if (!ONE_WINDOW) { - if (win->w_height < value) { - win_setheight((int)value); + win_T *win = (win_T *)args->os_win; + if (win->w_height < p_wh) { + win_setheight((int)p_wh); } } + + return NULL; } /// Process the new 'helpheight' option value. -static void did_set_helpheight(buf_T *buf, win_T *win, long value) +static const char *did_set_helpheight(optset_T *args) { // Change window height NOW if (!ONE_WINDOW) { - if (buf->b_help && win->w_height < value) { - win_setheight((int)value); + buf_T *buf = (buf_T *)args->os_buf; + win_T *win = (win_T *)args->os_win; + if (buf->b_help && win->w_height < p_hh) { + win_setheight((int)p_hh); } } + + return NULL; } /// Process the new 'winwidth' option value. -static void did_set_winwidth(win_T *win, long value) +static const char *did_set_winwidth(optset_T *args) { - if (!ONE_WINDOW && win->w_width < value) { - win_setwidth((int)value); + win_T *win = (win_T *)args->os_win; + + if (!ONE_WINDOW && win->w_width < p_wiw) { + win_setwidth((int)p_wiw); } + return NULL; } /// Process the new 'laststatus' option value. -static void did_set_laststatus(long value, long old_value) +static const char *did_set_laststatus(optset_T *args) { + long old_value = args->os_oldval.number; + long value = args->os_newval.number; + // When switching to global statusline, decrease topframe height // Also clear the cmdline to remove the ruler if there is one if (value == 3 && old_value != 3) { @@ -2604,38 +2610,49 @@ static void did_set_laststatus(long value, long old_value) } last_status(false); // (re)set last window status line. + return NULL; } /// Process the new 'showtabline' option value. -static void did_set_showtabline(void) +static const char *did_set_showtabline(optset_T *args FUNC_ATTR_UNUSED) { // (re)set tab page line win_new_screen_rows(); // recompute window positions and heights + return NULL; } /// Process the new 'foldlevel' option value. -static void did_set_foldlevel(void) +static const char *did_set_foldlevel(optset_T *args FUNC_ATTR_UNUSED) { newFoldLevel(); + return NULL; } /// Process the new 'foldminlines' option value. -static void did_set_foldminlines(win_T *win) +static const char *did_set_foldminlines(optset_T *args) { + win_T *win = (win_T *)args->os_win; foldUpdateAll(win); + return NULL; } /// Process the new 'foldnestmax' option value. -static void did_set_foldnestmax(win_T *win) +static const char *did_set_foldnestmax(optset_T *args) { + win_T *win = (win_T *)args->os_win; if (foldmethodIsSyntax(win) || foldmethodIsIndent(win)) { foldUpdateAll(win); } + return NULL; } /// Process the new 'shiftwidth' or the 'tabstop' option value. -static void did_set_shiftwidth_tabstop(buf_T *buf, win_T *win, const long *pp) +static const char *did_set_shiftwidth_tabstop(optset_T *args) { + buf_T *buf = (buf_T *)args->os_buf; + win_T *win = (win_T *)args->os_win; + long *pp = (long *)args->os_varp; + if (foldmethodIsIndent(win)) { foldUpdateAll(win); } @@ -2644,38 +2661,49 @@ static void did_set_shiftwidth_tabstop(buf_T *buf, win_T *win, const long *pp) if (pp == &buf->b_p_sw || buf->b_p_sw == 0) { parse_cino(buf); } + + return NULL; } /// Process the new 'iminset' option value. -static void did_set_iminsert(void) +static const char *did_set_iminsert(optset_T *args FUNC_ATTR_UNUSED) { showmode(); // Show/unshow value of 'keymap' in status lines. status_redraw_curbuf(); + + return NULL; } /// Process the new 'window' option value. -static void did_set_window(void) +static const char *did_set_window(optset_T *args FUNC_ATTR_UNUSED) { if (p_window < 1) { p_window = Rows - 1; } else if (p_window >= Rows) { p_window = Rows - 1; } + return NULL; } /// Process the new 'titlelen' option value. -static void did_set_titlelen(long old_value) +static const char *did_set_titlelen(optset_T *args) { + long old_value = args->os_oldval.number; + // if 'titlelen' has changed, redraw the title if (starting != NO_SCREEN && old_value != p_titlelen) { need_maketitle = true; } + + return NULL; } /// Process the new 'cmdheight' option value. -static void did_set_cmdheight(long old_value) +static const char *did_set_cmdheight(optset_T *args) { + long old_value = args->os_oldval.number; + if (ui_has(kUIMessages)) { p_ch = 0; } @@ -2691,19 +2719,25 @@ static void did_set_cmdheight(long old_value) && full_screen) { command_height(); } + + return NULL; } /// Process the new 'updatecount' option value. -static void did_set_updatecount(long old_value) +static const char *did_set_updatecount(optset_T *args) { + long old_value = args->os_oldval.number; + // when 'updatecount' changes from zero to non-zero, open swap files if (p_uc && !old_value) { ml_open_files(); } + + return NULL; } /// Process the new 'pumblend' option value. -static void did_set_pumblend(void) +static const char *did_set_pumblend(optset_T *args FUNC_ATTR_UNUSED) { p_pb = MAX(MIN(p_pb, 100), 0); hl_invalidate_blends(); @@ -2711,113 +2745,93 @@ static void did_set_pumblend(void) if (pum_drawn()) { pum_redraw(); } + + return NULL; } /// Process the new global 'undolevels' option value. -static void did_set_global_undolevels(long value, long old_value) +const char *did_set_global_undolevels(long value, long old_value) { // sync undo before 'undolevels' changes // use the old value, otherwise u_sync() may not work properly p_ul = old_value; u_sync(true); p_ul = value; + return NULL; } /// Process the new buffer local 'undolevels' option value. -static void did_set_buflocal_undolevels(buf_T *buf, long value, long old_value) +const char *did_set_buflocal_undolevels(buf_T *buf, long value, long old_value) { // use the old value, otherwise u_sync() may not work properly buf->b_p_ul = old_value; u_sync(true); buf->b_p_ul = value; + return NULL; } /// Process the new 'scrollback' option value. -static void did_set_scrollback(buf_T *buf, long value, long old_value) +static const char *did_set_scrollback(optset_T *args) { + buf_T *buf = (buf_T *)args->os_buf; + long old_value = args->os_oldval.number; + long value = args->os_newval.number; + if (buf->terminal && value < old_value) { // Force the scrollback to take immediate effect only when decreasing it. on_scrollback_option_changed(buf->terminal); } + return NULL; } /// Process the new 'numberwidth' option value. -static void did_set_numberwidth(void) +static const char *did_set_numberwidth(optset_T *args) { - curwin->w_nrwidth_line_count = 0; // trigger a redraw + win_T *win = (win_T *)args->os_win; + win->w_nrwidth_line_count = 0; // trigger a redraw + + return NULL; } /// Process the new 'textwidth' option value. -static void did_set_textwidth(void) +static const char *did_set_textwidth(optset_T *args FUNC_ATTR_UNUSED) { FOR_ALL_TAB_WINDOWS(tp, wp) { check_colorcolumn(wp); } + + return NULL; } /// Process the new 'winblend' option value. -static void did_set_winblend(win_T *win, long value, long old_value) +static const char *did_set_winblend(optset_T *args) { + win_T *win = (win_T *)args->os_win; + long old_value = args->os_oldval.number; + long value = args->os_newval.number; + if (value != old_value) { win->w_p_winbl = MAX(MIN(win->w_p_winbl, 100), 0); win->w_hl_needs_update = true; check_blending(curwin); } + + return NULL; } -/// When some number options are changed, need to take some action. -static const char *did_set_num_option(long *pp, long value, long old_value, const char *errmsg) +/// Process the new 'undolevels' option value. +static const char *did_set_undolevels(optset_T *args) { - if (pp == &p_wh) { // 'winheight' - did_set_winheight(curwin, value); - } else if (pp == &p_hh) { // 'helpheight' - did_set_helpheight(curbuf, curwin, value); - } else if (pp == &p_wmh) { // 'winminheight' - did_set_winminheight(); - } else if (pp == &p_wiw) { // 'winwidth' - did_set_winwidth(curwin, value); - } else if (pp == &p_wmw) { // 'winminwidth' - did_set_winminwidth(); - } else if (pp == &p_window) { // 'window' - did_set_window(); - } else if (pp == &p_ls) { // 'laststatus' - did_set_laststatus(value, old_value); - } else if (pp == &p_stal) { - did_set_showtabline(); // 'showtabline' - } else if (pp == &curwin->w_p_fdl) { - did_set_foldlevel(); - } else if (pp == &curwin->w_p_fml) { - did_set_foldminlines(curwin); - } else if (pp == &curwin->w_p_fdn) { - did_set_foldnestmax(curwin); - } else if (pp == &curbuf->b_p_sw // 'shiftwidth' - || pp == &curbuf->b_p_ts) { // 'tabstop' - did_set_shiftwidth_tabstop(curbuf, curwin, pp); - } else if (pp == &curbuf->b_p_iminsert) { // 'iminsert' - did_set_iminsert(); - } else if (pp == &p_titlelen) { // 'titlelen' - did_set_titlelen(old_value); - } else if (pp == &p_ch) { // 'cmdheight' - did_set_cmdheight(old_value); - } else if (pp == &p_uc) { // 'updatecount' - did_set_updatecount(old_value); - } else if (pp == &p_pb) { // 'pumblend - did_set_pumblend(); - } else if (pp == &p_ul) { // global 'undolevels' - did_set_global_undolevels(value, old_value); - } else if (pp == &curbuf->b_p_ul) { // buffer local 'undolevels' - did_set_buflocal_undolevels(curbuf, value, old_value); - } else if (pp == &curbuf->b_p_scbk || pp == &p_scbk) { - did_set_scrollback(curbuf, value, old_value); - } else if (pp == &curwin->w_p_nuw) { // 'numberwidth' - did_set_numberwidth(); - } else if (pp == &curbuf->b_p_tw) { // 'textwidth' - did_set_textwidth(); - } else if (pp == &curwin->w_p_winbl) { - did_set_winblend(curwin, value, old_value); + buf_T *buf = (buf_T *)args->os_buf; + long *pp = (long *)args->os_varp; + + if (pp == &p_ul) { // global 'undolevels' + did_set_global_undolevels(args->os_newval.number, args->os_oldval.number); + } else if (pp == &curbuf->b_p_ul) { // buffer local 'undolevels' + did_set_buflocal_undolevels(buf, args->os_newval.number, args->os_oldval.number); } - return errmsg; + return NULL; } /// Check the bounds of numeric options. @@ -3080,8 +3094,21 @@ static const char *set_num_option(int opt_idx, char *varp, long value, char *err // Remember where the option was set. set_option_sctx_idx(opt_idx, opt_flags, current_sctx); - // Number options that need some action when changed - errmsg = did_set_num_option(pp, value, old_value, errmsg); + // Invoke the option specific callback function to validate and apply the + // new value. + if (options[opt_idx].opt_did_set_cb != NULL) { + optset_T args = { + .os_varp = varp, + .os_flags = opt_flags, + .os_oldval.number = old_value, + .os_newval.number = value, + .os_errbuf = NULL, + .os_errbuflen = 0, + .os_buf = curbuf, + .os_win = curwin + }; + errmsg = options[opt_idx].opt_did_set_cb(&args); + } // Check the bounds for numeric options here errmsg = check_num_option_bounds(pp, old_value, old_Rows, errbuf, errbuflen, errmsg); @@ -4137,12 +4164,12 @@ void unset_global_local_option(char *name, void *from) break; case PV_LCS: clear_string_option(&((win_T *)from)->w_p_lcs); - set_chars_option((win_T *)from, &((win_T *)from)->w_p_lcs, true); + set_listchars_option((win_T *)from, ((win_T *)from)->w_p_lcs, true); redraw_later((win_T *)from, UPD_NOT_VALID); break; case PV_FCS: clear_string_option(&((win_T *)from)->w_p_fcs); - set_chars_option((win_T *)from, &((win_T *)from)->w_p_fcs, true); + set_fillchars_option((win_T *)from, ((win_T *)from)->w_p_fcs, true); redraw_later((win_T *)from, UPD_NOT_VALID); break; case PV_VE: @@ -4562,6 +4589,12 @@ static inline char *get_varp(vimoption_T *p) return get_varp_from(p, curbuf, curwin); } +/// Return the did_set callback function for the option at 'opt_idx' +opt_did_set_cb_T get_option_did_set_cb(int opt_idx) +{ + return options[opt_idx].opt_did_set_cb; +} + /// Get the value of 'equalprg', either the buffer-local one or the global one. char *get_equalprg(void) { @@ -4716,8 +4749,8 @@ void didset_window_options(win_T *wp, bool valid_cursor) check_colorcolumn(wp); briopt_check(wp); fill_culopt_flags(NULL, wp); - set_chars_option(wp, &wp->w_p_fcs, true); - set_chars_option(wp, &wp->w_p_lcs, true); + set_fillchars_option(wp, wp->w_p_fcs, true); + set_listchars_option(wp, wp->w_p_lcs, true); parse_winhl_opt(wp); // sets w_hl_needs_update also for w_p_winbl check_blending(wp); set_winbar_win(wp, false, valid_cursor); @@ -5621,8 +5654,8 @@ void reset_option_was_set(const char *name) options[idx].flags &= ~P_WAS_SET; } -/// fill_breakat_flags() -- called when 'breakat' changes value. -void fill_breakat_flags(void) +/// Called when the 'breakat' option changes value. +static const char *did_set_breakat(optset_T *args FUNC_ATTR_UNUSED) { for (int i = 0; i < 256; i++) { breakat_flags[i] = false; @@ -5633,6 +5666,8 @@ void fill_breakat_flags(void) breakat_flags[(uint8_t)(*p)] = true; } } + + return NULL; } /// fill_culopt_flags() -- called when 'culopt' changes value diff --git a/src/nvim/option_defs.h b/src/nvim/option_defs.h index 0715177bba..c2d62d772b 100644 --- a/src/nvim/option_defs.h +++ b/src/nvim/option_defs.h @@ -7,7 +7,7 @@ // option_defs.h: definition of global variables for settable options -// Flags +// Option Flags #define P_BOOL 0x01U ///< the option is boolean #define P_NUM 0x02U ///< the option is numeric #define P_STRING 0x04U ///< the option is a string @@ -290,7 +290,7 @@ enum { #define GO_FOOTER 'F' // add footer #define GO_VERTICAL 'v' // arrange dialog buttons vertically #define GO_KEEPWINSIZE 'k' // keep GUI window size -#define GO_ALL "aAbcdefFghilmMprTvk" // all possible flags for 'go' +#define GO_ALL "!aAbcdefFghilLmMpPrRtTvk" // all possible flags for 'go' // flags for 'comments' option #define COM_NEST 'n' // comments strings nest @@ -978,6 +978,56 @@ enum { #define TABSTOP_MAX 9999 +// Argument for the callback function (opt_did_set_cb_T) invoked after an +// option value is modified. +typedef struct { + // Pointer to the option variable. The variable can be a long (numeric + // option), an int (boolean option) or a char pointer (string option). + char *os_varp; + int os_idx; + int os_flags; + + // old value of the option (can be a string, number or a boolean) + union { + const long number; + const bool boolean; + const char *string; + } os_oldval; + + // new value of the option (can be a string, number or a boolean) + union { + const long number; + const bool boolean; + const char *string; + } os_newval; + + // When set by the called function: Stop processing the option further. + // Currently only used for boolean options. + int os_doskip; + + // Option value was checked to be safe, no need to set P_INSECURE + // Used for the 'keymap', 'filetype' and 'syntax' options. + int os_value_checked; + // Option value changed. Used for the 'filetype' and 'syntax' options. + int os_value_changed; + + // Used by the 'isident', 'iskeyword', 'isprint' and 'isfname' options. + // Set to true if the character table is modified when processing the + // option and need to be restored because of a failure. + int os_restore_chartab; + + // If the value specified for an option is not valid and the error message + // is parameterized, then the "os_errbuf" buffer is used to store the error + // message (when it is not NULL). + char *os_errbuf; + size_t os_errbuflen; + + void *os_win; + void *os_buf; +} optset_T; + +typedef const char *(*opt_did_set_cb_T)(optset_T *args); + /// Stores an identifier of a script or channel that last set an option. typedef struct { sctx_T script_ctx; /// script context where the option was last set @@ -993,12 +1043,15 @@ typedef enum { typedef struct vimoption { char *fullname; // full option name char *shortname; // permissible abbreviation - uint32_t flags; // see below + uint32_t flags; // see above char *var; // global option: pointer to variable; // window-local option: VAR_WIN; // buffer-local option: global value idopt_T indir; // global option: PV_NONE; // local option: indirect option index + // callback function to invoke after an option is modified to validate and + // apply the new value. + opt_did_set_cb_T opt_did_set_cb; char *def_val; // default values for variable (neovim!!) LastSet last_set; // script in which the option was last set } vimoption_T; diff --git a/src/nvim/options.lua b/src/nvim/options.lua index dffebcf14e..e028fbb6a6 100644 --- a/src/nvim/options.lua +++ b/src/nvim/options.lua @@ -62,7 +62,8 @@ return { short_desc=N_("Arabic as a default second language"), type='bool', scope={'window'}, redraw={'curswant'}, - defaults={if_true=false} + defaults={if_true=false}, + cb='did_set_arabic' }, { full_name='arabicshape', abbreviation='arshape', @@ -86,14 +87,16 @@ return { type='string', scope={'global'}, redraw={'all_windows', 'ui_option'}, varname='p_ambw', - defaults={if_true="single"} + defaults={if_true="single"}, + cb='did_set_ambiwidth' }, { full_name='autochdir', abbreviation='acd', short_desc=N_("change directory to the file in the current window"), type='bool', scope={'global'}, varname='p_acd', - defaults={if_true=false} + defaults={if_true=false}, + cb='did_set_autochdir' }, { full_name='autoindent', abbreviation='ai', @@ -128,7 +131,8 @@ return { short_desc=N_("\"dark\" or \"light\", used for highlight colors"), type='string', scope={'global'}, varname='p_bg', - defaults={if_true="dark"} + defaults={if_true="dark"}, + cb='did_set_background' }, { full_name='backspace', abbreviation='bs', @@ -136,7 +140,8 @@ return { type='string', list='onecomma', scope={'global'}, deny_duplicates=true, varname='p_bs', - defaults={if_true="indent,eol,start"} + defaults={if_true="indent,eol,start"}, + cb='did_set_backspace' }, { full_name='backup', abbreviation='bk', @@ -156,6 +161,7 @@ return { if_true="auto", if_false="auto" }, + cb='did_set_backupcopy' }, { full_name='backupdir', abbreviation='bdir', @@ -173,7 +179,8 @@ return { type='string', scope={'global'}, normal_fname_chars=true, varname='p_bex', - defaults={if_true="~"} + defaults={if_true="~"}, + cb='did_set_backupext_or_patchmode' }, { full_name='backupskip', abbreviation='bsk', @@ -189,7 +196,8 @@ return { type='string', list='comma', scope={'global'}, deny_duplicates=true, varname='p_bo', - defaults={if_true="all"} + defaults={if_true="all"}, + cb='did_set_belloff' }, { full_name='binary', abbreviation='bin', @@ -197,7 +205,8 @@ return { type='bool', scope={'buffer'}, redraw={'statuslines'}, varname='p_bin', - defaults={if_true=false} + defaults={if_true=false}, + cb='did_set_binary' }, { full_name='bomb', @@ -206,7 +215,8 @@ return { no_mkrc=true, redraw={'statuslines'}, varname='p_bomb', - defaults={if_true=false} + defaults={if_true=false}, + cb='did_set_eof_eol_fixeol_bomb' }, { full_name='breakat', abbreviation='brk', @@ -214,7 +224,8 @@ return { type='string', list='flags', scope={'global'}, redraw={'all_windows'}, varname='p_breakat', - defaults={if_true=" \t!@*-+;:,./?"} + defaults={if_true=" \t!@*-+;:,./?"}, + cb='did_set_breakat' }, { full_name='breakindent', abbreviation='bri', @@ -231,6 +242,7 @@ return { alloced=true, redraw={'current_buffer'}, defaults={if_true=""}, + cb='did_set_breakindentopt' }, { full_name='browsedir', abbreviation='bsdir', @@ -245,7 +257,8 @@ return { noglob=true, alloced=true, varname='p_bh', - defaults={if_true=""} + defaults={if_true=""}, + cb='did_set_bufhidden' }, { full_name='buflisted', abbreviation='bl', @@ -253,7 +266,8 @@ return { type='bool', scope={'buffer'}, noglob=true, varname='p_bl', - defaults={if_true=1} + defaults={if_true=1}, + cb='did_set_buflisted' }, { full_name='buftype', abbreviation='bt', @@ -262,7 +276,8 @@ return { noglob=true, alloced=true, varname='p_bt', - defaults={if_true=""} + defaults={if_true=""}, + cb='did_set_buftype' }, { full_name='casemap', abbreviation='cmp', @@ -270,7 +285,8 @@ return { type='string', list='onecomma', scope={'global'}, deny_duplicates=true, varname='p_cmp', - defaults={if_true="internal,keepascii"} + defaults={if_true="internal,keepascii"}, + cb='did_set_casemap' }, { full_name='cdhome', abbreviation='cdh', @@ -295,7 +311,8 @@ return { short_desc=N_("used to open the command-line window"), type='string', scope={'global'}, varname='p_cedit', - defaults={if_true=macros('CTRL_F_STR')} + defaults={if_true=macros('CTRL_F_STR')}, + cb='did_set_cedit' }, { full_name='channel', @@ -312,7 +329,8 @@ return { type='string', scope={'global'}, secure=true, varname='p_ccv', - defaults={if_true=""} + defaults={if_true=""}, + cb='did_set_optexpr' }, { full_name='cindent', abbreviation='cin', @@ -337,7 +355,8 @@ return { deny_duplicates=true, alloced=true, varname='p_cino', - defaults={if_true=""} + defaults={if_true=""}, + cb='did_set_cinoptions' }, { full_name='cinwords', abbreviation='cinw', @@ -363,7 +382,8 @@ return { type='string', list='onecomma', scope={'global'}, deny_duplicates=true, varname='p_cb', - defaults={if_true=""} + defaults={if_true=""}, + cb='did_set_clipboard' }, { full_name='cmdheight', abbreviation='ch', @@ -371,7 +391,8 @@ return { type='number', scope={'global'}, redraw={'all_windows'}, varname='p_ch', - defaults={if_true=1} + defaults={if_true=1}, + cb='did_set_cmdheight' }, { full_name='cmdwinheight', abbreviation='cwh', @@ -386,7 +407,8 @@ return { type='string', list='onecomma', scope={'window'}, deny_duplicates=true, redraw={'current_window'}, - defaults={if_true=""} + defaults={if_true=""}, + cb='did_set_colorcolumn' }, { full_name='columns', abbreviation='co', @@ -404,7 +426,8 @@ return { alloced=true, redraw={'curswant'}, varname='p_com', - defaults={if_true="s1:/*,mb:*,ex:*/,://,b:#,:%,:XCOMM,n:>,fb:-"} + defaults={if_true="s1:/*,mb:*,ex:*/,://,b:#,:%,:XCOMM,n:>,fb:-"}, + cb='did_set_comments' }, { full_name='commentstring', abbreviation='cms', @@ -413,7 +436,8 @@ return { alloced=true, redraw={'curswant'}, varname='p_cms', - defaults={if_true=""} + defaults={if_true=""}, + cb='did_set_commentstring' }, { full_name='compatible', abbreviation='cp', @@ -431,7 +455,8 @@ return { deny_duplicates=true, alloced=true, varname='p_cpt', - defaults={if_true=".,w,b,u,t"} + defaults={if_true=".,w,b,u,t"}, + cb='did_set_complete' }, { full_name='concealcursor', abbreviation='cocu', @@ -439,7 +464,8 @@ return { type='string', scope={'window'}, alloced=true, redraw={'current_window'}, - defaults={if_true=""} + defaults={if_true=""}, + cb='did_set_concealcursor' }, { full_name='conceallevel', abbreviation='cole', @@ -456,7 +482,8 @@ return { alloced=true, func=true, varname='p_cfu', - defaults={if_true=""} + defaults={if_true=""}, + cb='did_set_completefunc' }, { full_name='completeopt', abbreviation='cot', @@ -464,14 +491,16 @@ return { type='string', list='onecomma', scope={'global'}, deny_duplicates=true, varname='p_cot', - defaults={if_true="menu,preview"} + defaults={if_true="menu,preview"}, + cb='did_set_completeopt' }, { full_name='completeslash', abbreviation='csl', type='string', scope={'buffer'}, varname='p_csl', enable_if='BACKSLASH_IN_FILENAME', - defaults={if_true=""} + defaults={if_true=""}, + cb='did_set_completeslash' }, { full_name='confirm', abbreviation='cf', @@ -493,7 +522,8 @@ return { type='string', list='flags', scope={'global'}, redraw={'all_windows'}, varname='p_cpo', - defaults={if_true=macros('CPO_VIM')} + defaults={if_true=macros('CPO_VIM')}, + cb='did_set_cpoptions' }, { full_name='cursorbind', abbreviation='crb', @@ -522,14 +552,16 @@ return { type='string', list='onecomma', scope={'window'}, deny_duplicates=true, redraw={'current_window_only'}, - defaults={if_true="both"} + defaults={if_true="both"}, + cb='did_set_cursorlineopt' }, { full_name='debug', short_desc=N_("to \"msg\" to see all error messages"), type='string', scope={'global'}, varname='p_debug', - defaults={if_true=""} + defaults={if_true=""}, + cb='did_set_debug' }, { full_name='define', abbreviation='def', @@ -563,7 +595,8 @@ return { type='bool', scope={'window'}, noglob=true, redraw={'current_window'}, - defaults={if_true=false} + defaults={if_true=false}, + cb='did_set_diff' }, { full_name='diffexpr', abbreviation='dex', @@ -572,7 +605,8 @@ return { secure=true, redraw={'curswant'}, varname='p_dex', - defaults={if_true=""} + defaults={if_true=""}, + cb='did_set_optexpr' }, { full_name='diffopt', abbreviation='dip', @@ -582,7 +616,8 @@ return { alloced=true, redraw={'current_window'}, varname='p_dip', - defaults={if_true="internal,filler,closeoff"} + defaults={if_true="internal,filler,closeoff"}, + cb='did_set_diffopt' }, { full_name='digraph', abbreviation='dg', @@ -608,14 +643,16 @@ return { deny_duplicates=true, redraw={'all_windows'}, varname='p_dy', - defaults={if_true="lastline"} + defaults={if_true="lastline"}, + cb='did_set_display' }, { full_name='eadirection', abbreviation='ead', short_desc=N_("in which direction 'equalalways' works"), type='string', scope={'global'}, varname='p_ead', - defaults={if_true="both"} + defaults={if_true="both"}, + cb='did_set_eadirection' }, { full_name='edcompatible', abbreviation='ed', @@ -630,7 +667,8 @@ return { type='bool', scope={'global'}, redraw={'all_windows', 'ui_option'}, varname='p_emoji', - defaults={if_true=true} + defaults={if_true=true}, + cb='did_set_ambiwidth' }, { full_name='encoding', abbreviation='enc', @@ -638,7 +676,8 @@ return { type='string', scope={'global'}, deny_in_modelines=true, varname='p_enc', - defaults={if_true=macros('ENC_DFLT')} + defaults={if_true=macros('ENC_DFLT')}, + cb='did_set_encoding' }, { full_name='endoffile', abbreviation='eof', @@ -647,7 +686,8 @@ return { no_mkrc=true, redraw={'statuslines'}, varname='p_eof', - defaults={if_true=false} + defaults={if_true=false}, + cb='did_set_eof_eol_fixeol_bomb' }, { full_name='endofline', abbreviation='eol', @@ -656,14 +696,16 @@ return { no_mkrc=true, redraw={'statuslines'}, varname='p_eol', - defaults={if_true=true} + defaults={if_true=true}, + cb='did_set_eof_eol_fixeol_bomb' }, { full_name='equalalways', abbreviation='ea', short_desc=N_("windows are automatically made the same size"), type='bool', scope={'global'}, varname='p_ea', - defaults={if_true=true} + defaults={if_true=true}, + cb='did_set_equalalways' }, { full_name='equalprg', abbreviation='ep', @@ -704,7 +746,8 @@ return { type='string', list='onecomma', scope={'global'}, deny_duplicates=true, varname='p_ei', - defaults={if_true=""} + defaults={if_true=""}, + cb='did_set_eventignore' }, { full_name='expandtab', abbreviation='et', @@ -729,7 +772,8 @@ return { alloced=true, redraw={'statuslines', 'current_buffer'}, varname='p_fenc', - defaults={if_true=""} + defaults={if_true=""}, + cb='did_set_encoding' }, { full_name='fileencodings', abbreviation='fencs', @@ -747,7 +791,8 @@ return { alloced=true, redraw={'curswant', 'statuslines'}, varname='p_ff', - defaults={if_true=macros('DFLT_FF')} + defaults={if_true=macros('DFLT_FF')}, + cb='did_set_fileformat' }, { full_name='fileformats', abbreviation='ffs', @@ -755,7 +800,8 @@ return { type='string', list='onecomma', scope={'global'}, deny_duplicates=true, varname='p_ffs', - defaults={if_true=macros('DFLT_FFS_VIM')} + defaults={if_true=macros('DFLT_FFS_VIM')}, + cb='did_set_fileformats' }, { full_name='fileignorecase', abbreviation='fic', @@ -777,7 +823,8 @@ return { alloced=true, expand=true, varname='p_ft', - defaults={if_true=""} + defaults={if_true=""}, + cb='did_set_filetype_or_syntax' }, { full_name='fillchars', abbreviation='fcs', @@ -787,7 +834,8 @@ return { alloced=true, redraw={'current_window'}, varname='p_fcs', - defaults={if_true=''} + defaults={if_true=''}, + cb='did_set_chars_option' }, { full_name='fixendofline', abbreviation='fixeol', @@ -795,7 +843,8 @@ return { type='bool', scope={'buffer'}, redraw={'statuslines'}, varname='p_fixeol', - defaults={if_true=true} + defaults={if_true=true}, + cb='did_set_eof_eol_fixeol_bomb' }, { full_name='foldclose', abbreviation='fcl', @@ -804,7 +853,8 @@ return { deny_duplicates=true, redraw={'current_window'}, varname='p_fcl', - defaults={if_true=""} + defaults={if_true=""}, + cb='did_set_foldclose' }, { full_name='foldcolumn', abbreviation='fdc', @@ -812,7 +862,8 @@ return { type='string', scope={'window'}, alloced=true, redraw={'current_window'}, - defaults={if_true="0"} + defaults={if_true="0"}, + cb='did_set_foldcolumn' }, { full_name='foldenable', abbreviation='fen', @@ -828,7 +879,8 @@ return { modelineexpr=true, alloced=true, redraw={'current_window'}, - defaults={if_true="0"} + defaults={if_true="0"}, + cb='did_set_foldexpr' }, { full_name='foldignore', abbreviation='fdi', @@ -836,14 +888,16 @@ return { type='string', scope={'window'}, alloced=true, redraw={'current_window'}, - defaults={if_true="#"} + defaults={if_true="#"}, + cb='did_set_foldignore' }, { full_name='foldlevel', abbreviation='fdl', short_desc=N_("close folds with a level higher than this"), type='number', scope={'window'}, redraw={'current_window'}, - defaults={if_true=0} + defaults={if_true=0}, + cb='did_set_foldlevel' }, { full_name='foldlevelstart', abbreviation='fdls', @@ -860,7 +914,8 @@ return { deny_duplicates=true, alloced=true, redraw={'current_window'}, - defaults={if_true="{{{,}}}"} + defaults={if_true="{{{,}}}"}, + cb='did_set_foldmarker' }, { full_name='foldmethod', abbreviation='fdm', @@ -868,21 +923,24 @@ return { type='string', scope={'window'}, alloced=true, redraw={'current_window'}, - defaults={if_true="manual"} + defaults={if_true="manual"}, + cb='did_set_foldmethod' }, { full_name='foldminlines', abbreviation='fml', short_desc=N_("minimum number of lines for a fold to be closed"), type='number', scope={'window'}, redraw={'current_window'}, - defaults={if_true=1} + defaults={if_true=1}, + cb='did_set_foldminlines' }, { full_name='foldnestmax', abbreviation='fdn', short_desc=N_("maximum fold depth"), type='number', scope={'window'}, redraw={'current_window'}, - defaults={if_true=20} + defaults={if_true=20}, + cb='did_set_foldnestmax' }, { full_name='foldopen', abbreviation='fdo', @@ -891,7 +949,8 @@ return { deny_duplicates=true, redraw={'curswant'}, varname='p_fdo', - defaults={if_true="block,hor,mark,percent,quickfix,search,tag,undo"} + defaults={if_true="block,hor,mark,percent,quickfix,search,tag,undo"}, + cb='did_set_foldopen' }, { full_name='foldtext', abbreviation='fdt', @@ -900,7 +959,8 @@ return { modelineexpr=true, alloced=true, redraw={'current_window'}, - defaults={if_true="foldtext()"} + defaults={if_true="foldtext()"}, + cb='did_set_optexpr' }, { full_name='formatexpr', abbreviation='fex', @@ -909,7 +969,8 @@ return { modelineexpr=true, alloced=true, varname='p_fex', - defaults={if_true=""} + defaults={if_true=""}, + cb='did_set_optexpr' }, { full_name='formatoptions', abbreviation='fo', @@ -917,7 +978,8 @@ return { type='string', list='flags', scope={'buffer'}, alloced=true, varname='p_fo', - defaults={if_true=macros('DFLT_FO_VIM')} + defaults={if_true=macros('DFLT_FO_VIM')}, + cb='did_set_formatoptions' }, { full_name='formatlistpat', abbreviation='flp', @@ -980,7 +1042,8 @@ return { type='string', list='onecomma', scope={'global'}, deny_duplicates=true, varname='p_guicursor', - defaults={if_true="n-v-c-sm:block,i-ci-ve:ver25,r-cr-o:hor20"} + defaults={if_true="n-v-c-sm:block,i-ci-ve:ver25,r-cr-o:hor20"}, + cb='did_set_guicursor' }, { full_name='guifont', abbreviation='gfn', @@ -1028,14 +1091,16 @@ return { secure=true, expand=true, varname='p_hf', - defaults={if_true=macros('DFLT_HELPFILE')} + defaults={if_true=macros('DFLT_HELPFILE')}, + cb='did_set_helpfile' }, { full_name='helpheight', abbreviation='hh', short_desc=N_("minimum height of a new help window"), type='number', scope={'global'}, varname='p_hh', - defaults={if_true=20} + defaults={if_true=20}, + cb='did_set_helpheight' }, { full_name='helplang', abbreviation='hlg', @@ -1043,7 +1108,8 @@ return { type='string', list='onecomma', scope={'global'}, deny_duplicates=true, varname='p_hlg', - defaults={if_true=""} + defaults={if_true=""}, + cb='did_set_helplang' }, { full_name='hidden', abbreviation='hid', @@ -1058,7 +1124,8 @@ return { type='string', list='onecomma', scope={'global'}, deny_duplicates=true, varname='p_hl', - defaults={if_true=macros('HIGHLIGHT_INIT')} + defaults={if_true=macros('HIGHLIGHT_INIT')}, + cb='did_set_highlight' }, { full_name='history', abbreviation='hi', @@ -1087,14 +1154,16 @@ return { type='bool', scope={'global'}, redraw={'all_windows'}, varname='p_hls', - defaults={if_true=true} + defaults={if_true=true}, + cb='did_set_hlsearch' }, { full_name='icon', short_desc=N_("Vim set the text of the window icon"), type='bool', scope={'global'}, varname='p_icon', - defaults={if_true=false} + defaults={if_true=false}, + cb='did_set_title_icon' }, { full_name='iconstring', @@ -1102,14 +1171,16 @@ return { type='string', scope={'global'}, modelineexpr=true, varname='p_iconstring', - defaults={if_true=""} + defaults={if_true=""}, + cb='did_set_iconstring' }, { full_name='ignorecase', abbreviation='ic', short_desc=N_("ignore case in search patterns"), type='bool', scope={'global'}, varname='p_ic', - defaults={if_true=false} + defaults={if_true=false}, + cb='did_set_ignorecase' }, { full_name='imcmdline', abbreviation='imc', @@ -1130,9 +1201,8 @@ return { short_desc=N_("use :lmap or IM in Insert mode"), type='number', scope={'buffer'}, varname='p_iminsert', pv_name='p_imi', - defaults={ - if_true=macros('B_IMODE_NONE'), - } + defaults={if_true=macros('B_IMODE_NONE')}, + cb='did_set_iminsert' }, { full_name='imsearch', abbreviation='ims', @@ -1148,7 +1218,8 @@ return { short_desc=N_("Live preview of substitution"), type='string', scope={'global'}, varname='p_icm', - defaults={if_true="nosplit"} + defaults={if_true="nosplit"}, + cb='did_set_inccommand' }, { full_name='include', abbreviation='inc', @@ -1165,7 +1236,8 @@ return { modelineexpr=true, alloced=true, varname='p_inex', - defaults={if_true=""} + defaults={if_true=""}, + cb='did_set_optexpr' }, { full_name='incsearch', abbreviation='is', @@ -1181,7 +1253,8 @@ return { modelineexpr=true, alloced=true, varname='p_inde', - defaults={if_true=""} + defaults={if_true=""}, + cb='did_set_optexpr' }, { full_name='indentkeys', abbreviation='indk', @@ -1218,7 +1291,8 @@ return { -- ( and ) are used in text separating fnames */ if_true="@,48-57,/,\\,.,-,_,+,,,#,$,%,{,},[,],:,@-@,!,~,=", if_false="@,48-57,/,.,-,_,+,,,#,$,%,~,=" - } + }, + cb='did_set_isopt' }, { full_name='isident', abbreviation='isi', @@ -1230,7 +1304,8 @@ return { condition='MSWIN', if_true="@,48-57,_,128-167,224-235", if_false="@,48-57,_,192-255" - } + }, + cb='did_set_isopt' }, { full_name='iskeyword', abbreviation='isk', @@ -1239,7 +1314,8 @@ return { deny_duplicates=true, alloced=true, varname='p_isk', - defaults={if_true="@,48-57,_,192-255"} + defaults={if_true="@,48-57,_,192-255"}, + cb='did_set_isopt' }, { full_name='isprint', abbreviation='isp', @@ -1248,8 +1324,8 @@ return { deny_duplicates=true, redraw={'all_windows'}, varname='p_isp', - defaults={if_true="@,161-255" - } + defaults={if_true="@,161-255"}, + cb='did_set_isopt' }, { full_name='joinspaces', abbreviation='js', @@ -1264,7 +1340,8 @@ return { type='string', list='onecomma', scope={'global'}, deny_duplicates=true, varname='p_jop', - defaults={if_true=''} + defaults={if_true=''}, + cb='did_set_jumpoptions' }, { full_name='keymap', abbreviation='kmp', @@ -1275,7 +1352,8 @@ return { alloced=true, redraw={'statuslines', 'current_buffer'}, varname='p_keymap', pv_name='p_kmap', - defaults={if_true=""} + defaults={if_true=""}, + cb='did_set_keymap' }, { full_name='keymodel', abbreviation='km', @@ -1283,7 +1361,8 @@ return { type='string', list='onecomma', scope={'global'}, deny_duplicates=true, varname='p_km', - defaults={if_true=""} + defaults={if_true=""}, + cb='did_set_keymodel' }, { full_name='keywordprg', abbreviation='kp', @@ -1303,7 +1382,8 @@ return { deny_duplicates=true, secure=true, varname='p_langmap', - defaults={if_true=""} + defaults={if_true=""}, + cb='did_set_langmap' }, { full_name='langmenu', abbreviation='lm', @@ -1318,14 +1398,16 @@ return { short_desc=N_("do not apply 'langmap' to mapped characters"), type='bool', scope={'global'}, varname='p_lnr', - defaults={if_true=true} + defaults={if_true=true}, + cb='did_set_langnoremap' }, { full_name='langremap', abbreviation='lrm', short_desc=N_('No description'), type='bool', scope={'global'}, varname='p_lrm', - defaults={if_true=false} + defaults={if_true=false}, + cb='did_set_langremap' }, { full_name='laststatus', abbreviation='ls', @@ -1333,7 +1415,8 @@ return { type='number', scope={'global'}, redraw={'all_windows'}, varname='p_ls', - defaults={if_true=2} + defaults={if_true=2}, + cb='did_set_laststatus' }, { full_name='lazyredraw', abbreviation='lz', @@ -1370,7 +1453,8 @@ return { short_desc=N_("indenting for Lisp"), type='bool', scope={'buffer'}, varname='p_lisp', - defaults={if_true=false} + defaults={if_true=false}, + cb='did_set_lisp' }, { full_name='lispoptions', abbreviation='lop', @@ -1378,7 +1462,8 @@ return { type='string', list='onecomma', scope={'buffer'}, deny_duplicates=true, varname='p_lop', pv_name='p_lop', - defaults={if_true=''} + defaults={if_true=''}, + cb='did_set_lispoptions' }, { full_name='lispwords', abbreviation='lw', @@ -1403,7 +1488,8 @@ return { alloced=true, redraw={'current_window'}, varname='p_lcs', - defaults={if_true="tab:> ,trail:-,nbsp:+"} + defaults={if_true="tab:> ,trail:-,nbsp:+"}, + cb='did_set_chars_option' }, { full_name='loadplugins', abbreviation='lpl', @@ -1433,7 +1519,8 @@ return { short_desc=N_("Converts the output of external commands"), type='string', scope={'global', 'buffer'}, varname='p_menc', - defaults={if_true=""} + defaults={if_true=""}, + cb='did_set_encoding' }, { full_name='makeprg', abbreviation='mp', @@ -1451,7 +1538,8 @@ return { deny_duplicates=true, alloced=true, varname='p_mps', - defaults={if_true="(:),{:},[:]"} + defaults={if_true="(:),{:},[:]"}, + cb='did_set_matchpairs' }, { full_name='matchtime', abbreviation='mat', @@ -1502,7 +1590,8 @@ return { secure=true, expand=true, varname='p_msm', - defaults={if_true="460000,2000,500"} + defaults={if_true="460000,2000,500"}, + cb='did_set_mkspellmem' }, { full_name='modeline', abbreviation='ml', @@ -1532,7 +1621,8 @@ return { type='bool', scope={'buffer'}, noglob=true, varname='p_ma', - defaults={if_true=true} + defaults={if_true=true}, + cb='did_set_modifiable' }, { full_name='modified', abbreviation='mod', @@ -1541,7 +1631,8 @@ return { no_mkrc=true, redraw={'statuslines'}, varname='p_mod', - defaults={if_true=false} + defaults={if_true=false}, + cb='did_set_modified' }, { full_name='more', @@ -1555,7 +1646,8 @@ return { short_desc=N_("the use of mouse clicks"), type='string', list='flags', scope={'global'}, varname='p_mouse', - defaults={if_true="nvi"} + defaults={if_true="nvi"}, + cb='did_set_mouse' }, { full_name='mousefocus', abbreviation='mousef', @@ -1577,7 +1669,8 @@ return { short_desc=N_("changes meaning of mouse buttons"), type='string', scope={'global'}, varname='p_mousem', - defaults={if_true="popup_setpos"} + defaults={if_true="popup_setpos"}, + cb='did_set_mousemodel' }, { full_name='mousemoveevent', abbreviation='mousemev', @@ -1593,7 +1686,8 @@ return { type='string', list='comma', scope={'global'}, vi_def=true, varname='p_mousescroll', - defaults={if_true="ver:3,hor:6"} + defaults={if_true="ver:3,hor:6"}, + cb='did_set_mousescroll' }, { full_name='mouseshape', abbreviation='mouses', @@ -1616,21 +1710,24 @@ return { deny_duplicates=true, alloced=true, varname='p_nf', - defaults={if_true="bin,hex"} + defaults={if_true="bin,hex"}, + cb='did_set_nrformats' }, { full_name='number', abbreviation='nu', short_desc=N_("print the line number in front of each line"), type='bool', scope={'window'}, redraw={'current_window'}, - defaults={if_true=false} + defaults={if_true=false}, + cb='did_set_number_relativenumber' }, { full_name='numberwidth', abbreviation='nuw', short_desc=N_("number of columns used for the line number"), type='number', scope={'window'}, redraw={'current_window'}, - defaults={if_true=4} + defaults={if_true=4}, + cb='did_set_numberwidth' }, { full_name='omnifunc', abbreviation='ofu', @@ -1640,7 +1737,8 @@ return { alloced=true, func=true, varname='p_ofu', - defaults={if_true=""} + defaults={if_true=""}, + cb='did_set_omnifunc' }, { full_name='opendevice', abbreviation='odev', @@ -1656,7 +1754,8 @@ return { secure=true, func=true, varname='p_opfunc', - defaults={if_true=""} + defaults={if_true=""}, + cb='did_set_operatorfunc' }, { full_name='packpath', abbreviation='pp', @@ -1666,7 +1765,8 @@ return { secure=true, expand=true, varname='p_pp', - defaults={if_true=''} + defaults={if_true=''}, + cb='did_set_runtimepackpath' }, { full_name='paragraphs', abbreviation='para', @@ -1681,7 +1781,8 @@ return { type='bool', scope={'global'}, pri_mkrc=true, varname='p_paste', - defaults={if_true=false} + defaults={if_true=false}, + cb='did_set_paste' }, { full_name='pastetoggle', abbreviation='pt', @@ -1695,7 +1796,8 @@ return { type='string', scope={'global'}, secure=true, varname='p_pex', - defaults={if_true=""} + defaults={if_true=""}, + cb='did_set_optexpr' }, { full_name='patchmode', abbreviation='pm', @@ -1703,7 +1805,8 @@ return { type='string', scope={'global'}, normal_fname_chars=true, varname='p_pm', - defaults={if_true=""} + defaults={if_true=""}, + cb='did_set_backupext_or_patchmode' }, { full_name='path', abbreviation='pa', @@ -1734,7 +1837,8 @@ return { type='bool', scope={'window'}, noglob=true, redraw={'statuslines'}, - defaults={if_true=false} + defaults={if_true=false}, + cb='did_set_previewwindow' }, { full_name='prompt', @@ -1749,7 +1853,8 @@ return { type='number', scope={'global'}, redraw={'ui_option'}, varname='p_pb', - defaults={if_true=0} + defaults={if_true=0}, + cb='did_set_pumblend' }, { full_name='pumheight', abbreviation='ph', @@ -1780,7 +1885,8 @@ return { secure=true, func=true, varname='p_qftf', - defaults={if_true=""} + defaults={if_true=""}, + cb='did_set_quickfixtextfunc' }, { full_name='quoteescape', abbreviation='qe', @@ -1797,14 +1903,16 @@ return { noglob=true, redraw={'statuslines'}, varname='p_ro', - defaults={if_true=false} + defaults={if_true=false}, + cb='did_set_readonly' }, { full_name='redrawdebug', abbreviation='rdb', short_desc=N_("Changes the way redrawing works (debug)"), type='string', list='onecomma', scope={'global'}, varname='p_rdb', - defaults={if_true=''} + defaults={if_true=''}, + cb='did_set_redrawdebug' }, { full_name='redrawtime', abbreviation='rdt', @@ -1825,7 +1933,8 @@ return { short_desc=N_("show relative line number in front of each line"), type='bool', scope={'window'}, redraw={'current_window'}, - defaults={if_true=false} + defaults={if_true=false}, + cb='did_set_number_relativenumber' }, { full_name='remap', @@ -1861,7 +1970,8 @@ return { type='string', scope={'window'}, alloced=true, redraw={'current_window'}, - defaults={if_true="search"} + defaults={if_true="search"}, + cb='did_set_rightleftcmd' }, { full_name='ruler', abbreviation='ru', @@ -1879,7 +1989,8 @@ return { modelineexpr=true, redraw={'statuslines'}, varname='p_ruf', - defaults={if_true=""} + defaults={if_true=""}, + cb='did_set_rulerformat' }, { full_name='runtimepath', abbreviation='rtp', @@ -1889,7 +2000,8 @@ return { secure=true, expand='nodefault', varname='p_rtp', - defaults={if_true=''} + defaults={if_true=''}, + cb='did_set_runtimepackpath' }, { full_name='scroll', abbreviation='scr', @@ -1905,14 +2017,16 @@ return { type='number', scope={'buffer'}, varname='p_scbk', redraw={'current_buffer'}, - defaults={if_true=-1} + defaults={if_true=-1}, + cb='did_set_scrollback' }, { full_name='scrollbind', abbreviation='scb', short_desc=N_("scroll in window as other windows scroll"), type='bool', scope={'window'}, pv_name='p_scbind', - defaults={if_true=false} + defaults={if_true=false}, + cb='did_set_scrollbind' }, { full_name='scrolljump', abbreviation='sj', @@ -1934,7 +2048,8 @@ return { type='string', list='onecomma', scope={'global'}, deny_duplicates=true, varname='p_sbo', - defaults={if_true="ver,jump"} + defaults={if_true="ver,jump"}, + cb='did_set_scrollopt' }, { full_name='sections', abbreviation='sect', @@ -1956,7 +2071,8 @@ return { short_desc=N_("what type of selection to use"), type='string', scope={'global'}, varname='p_sel', - defaults={if_true="inclusive"} + defaults={if_true="inclusive"}, + cb='did_set_selection' }, { full_name='selectmode', abbreviation='slm', @@ -1964,7 +2080,8 @@ return { type='string', list='onecomma', scope={'global'}, deny_duplicates=true, varname='p_slm', - defaults={if_true=""} + defaults={if_true=""}, + cb='did_set_selectmode' }, { full_name='sessionoptions', abbreviation='ssop', @@ -1972,7 +2089,8 @@ return { type='string', list='onecomma', scope={'global'}, deny_duplicates=true, varname='p_ssop', - defaults={if_true="blank,buffers,curdir,folds,help,tabpages,winsize,terminal"} + defaults={if_true="blank,buffers,curdir,folds,help,tabpages,winsize,terminal"}, + cb='did_set_sessionoptions', }, { full_name='shada', abbreviation='sd', @@ -2056,7 +2174,8 @@ return { type='bool', scope={'global'}, varname='p_ssl', enable_if='BACKSLASH_IN_FILENAME', - defaults={if_true=false} + defaults={if_true=false}, + cb='did_set_shellslash' }, { full_name='shelltemp', abbreviation='stmp', @@ -2097,14 +2216,16 @@ return { short_desc=N_("number of spaces to use for (auto)indent step"), type='number', scope={'buffer'}, varname='p_sw', - defaults={if_true=8} + defaults={if_true=8}, + cb='did_set_shiftwidth_tabstop' }, { full_name='shortmess', abbreviation='shm', short_desc=N_("list of flags, reduce length of messages"), type='string', list='flags', scope={'global'}, varname='p_shm', - defaults={if_true="filnxtToOF"} + defaults={if_true="filnxtToOF"}, + cb='did_set_shortmess' }, { full_name='showbreak', abbreviation='sbr', @@ -2112,7 +2233,8 @@ return { type='string', scope={'global', 'window'}, redraw={'all_windows'}, varname='p_sbr', - defaults={if_true=""} + defaults={if_true=""}, + cb='did_set_showbreak' }, { full_name='showcmd', abbreviation='sc', @@ -2126,7 +2248,8 @@ return { short_desc=N_("change location of partial command"), type='string', scope={'global'}, varname='p_sloc', - defaults={if_true="last"} + defaults={if_true="last"}, + cb='did_set_showcmdloc' }, { full_name='showfulltag', abbreviation='sft', @@ -2155,7 +2278,8 @@ return { type='number', scope={'global'}, redraw={'all_windows', 'ui_option'}, varname='p_stal', - defaults={if_true=1} + defaults={if_true=1}, + cb='did_set_showtabline' }, { full_name='sidescroll', abbreviation='ss', @@ -2177,7 +2301,8 @@ return { type='string', scope={'window'}, alloced=true, redraw={'current_window'}, - defaults={if_true="auto"} + defaults={if_true="auto"}, + cb='did_set_signcolumn' }, { full_name='smartcase', abbreviation='scs', @@ -2212,7 +2337,8 @@ return { short_desc=N_("spell checking"), type='bool', scope={'window'}, redraw={'current_window'}, - defaults={if_true=false} + defaults={if_true=false}, + cb='did_set_spell' }, { full_name='spellcapcheck', abbreviation='spc', @@ -2221,7 +2347,8 @@ return { alloced=true, redraw={'current_buffer'}, varname='p_spc', - defaults={if_true="[.?!]\\_[\\])'\" ]\\+"} + defaults={if_true="[.?!]\\_[\\])'\" ]\\+"}, + cb='did_set_spellcapcheck' }, { full_name='spellfile', abbreviation='spf', @@ -2232,7 +2359,8 @@ return { alloced=true, expand=true, varname='p_spf', - defaults={if_true=""} + defaults={if_true=""}, + cb='did_set_spellfile' }, { full_name='spelllang', abbreviation='spl', @@ -2243,7 +2371,8 @@ return { expand=true, redraw={'current_buffer'}, varname='p_spl', - defaults={if_true="en"} + defaults={if_true="en"}, + cb='did_set_spelllang' }, { full_name='spellsuggest', abbreviation='sps', @@ -2253,7 +2382,8 @@ return { secure=true, expand=true, varname='p_sps', - defaults={if_true="best"} + defaults={if_true="best"}, + cb='did_set_spellsuggest' }, { full_name='spelloptions', abbreviation='spo', @@ -2263,7 +2393,8 @@ return { expand=true, varname='p_spo', redraw={'current_buffer'}, - defaults={if_true=""} + defaults={if_true=""}, + cb='did_set_spelloptions' }, { full_name='splitbelow', abbreviation='sb', @@ -2277,7 +2408,8 @@ return { short_desc=N_("determines scroll behavior for split windows"), type='string', scope={'global'}, varname='p_spk', - defaults={if_true='cursor'} + defaults={if_true='cursor'}, + cb='did_set_splitkeep' }, { full_name='splitright', abbreviation='spr', @@ -2301,7 +2433,8 @@ return { redraw={'current_window'}, secure=true, alloced=true, - defaults={if_true=""} + defaults={if_true=""}, + cb='did_set_statuscolumn' }, { full_name='statusline', abbreviation='stl', @@ -2311,7 +2444,8 @@ return { modelineexpr=true, redraw={'statuslines'}, varname='p_stl', - defaults={if_true=""} + defaults={if_true=""}, + cb='did_set_statusline' }, { full_name='suffixes', abbreviation='su', @@ -2336,7 +2470,8 @@ return { type='bool', scope={'buffer'}, redraw={'statuslines'}, varname='p_swf', - defaults={if_true=true} + defaults={if_true=true}, + cb='did_set_swapfile' }, { full_name='switchbuf', abbreviation='swb', @@ -2344,7 +2479,8 @@ return { type='string', list='onecomma', scope={'global'}, deny_duplicates=true, varname='p_swb', - defaults={if_true="uselast"} + defaults={if_true="uselast"}, + cb='did_set_switchbuf' }, { full_name='synmaxcol', abbreviation='smc', @@ -2362,7 +2498,8 @@ return { normal_fname_chars=true, alloced=true, varname='p_syn', - defaults={if_true=""} + defaults={if_true=""}, + cb='did_set_filetype_or_syntax' }, { full_name='tagfunc', abbreviation='tfu', @@ -2371,7 +2508,8 @@ return { secure=true, func=true, varname='p_tfu', - defaults={if_true=""} + defaults={if_true=""}, + cb='did_set_tagfunc' }, { full_name='tabline', abbreviation='tal', @@ -2380,7 +2518,8 @@ return { modelineexpr=true, redraw={'tabline'}, varname='p_tal', - defaults={if_true=""} + defaults={if_true=""}, + cb='did_set_tabline' }, { full_name='tabpagemax', abbreviation='tpm', @@ -2395,7 +2534,8 @@ return { type='number', scope={'buffer'}, redraw={'current_buffer'}, varname='p_ts', - defaults={if_true=8} + defaults={if_true=8}, + cb='did_set_shiftwidth_tabstop' }, { full_name='tagbsearch', abbreviation='tbs', @@ -2409,7 +2549,8 @@ return { short_desc=N_("how to handle case when searching in tags files"), type='string', scope={'global', 'buffer'}, varname='p_tc', - defaults={if_true="followic"} + defaults={if_true="followic"}, + cb='did_set_tagcase' }, { full_name='taglength', abbreviation='tl', @@ -2467,7 +2608,8 @@ return { type='string', list='onecomma', scope={'global'}, deny_duplicates=true, varname='p_tpf', - defaults={if_true="BS,HT,ESC,DEL"} + defaults={if_true="BS,HT,ESC,DEL"}, + cb='did_set_termpastefilter' }, { full_name='terse', @@ -2482,7 +2624,8 @@ return { type='number', scope={'buffer'}, redraw={'current_buffer'}, varname='p_tw', - defaults={if_true=0} + defaults={if_true=0}, + cb='did_set_textwidth' }, { full_name='thesaurus', abbreviation='tsr', @@ -2502,7 +2645,8 @@ return { alloced=true, func=true, varname='p_tsrfu', - defaults={if_true=""} + defaults={if_true=""}, + cb='did_set_thesaurusfunc' }, { full_name='tildeop', abbreviation='top', @@ -2530,14 +2674,16 @@ return { short_desc=N_("Vim set the title of the window"), type='bool', scope={'global'}, varname='p_title', - defaults={if_true=false} + defaults={if_true=false}, + cb='did_set_title_icon' }, { full_name='titlelen', short_desc=N_("of 'columns' used for window title"), type='number', scope={'global'}, varname='p_titlelen', - defaults={if_true=85} + defaults={if_true=85}, + cb='did_set_titlelen' }, { full_name='titleold', @@ -2554,7 +2700,8 @@ return { type='string', scope={'global'}, modelineexpr=true, varname='p_titlestring', - defaults={if_true=""} + defaults={if_true=""}, + cb='did_set_titlestring' }, { full_name='ttimeout', @@ -2595,14 +2742,16 @@ return { short_desc=N_("save undo information in a file"), type='bool', scope={'buffer'}, varname='p_udf', - defaults={if_true=false} + defaults={if_true=false}, + cb='did_set_undofile' }, { full_name='undolevels', abbreviation='ul', short_desc=N_("maximum number of changes that can be undone"), type='number', scope={'global', 'buffer'}, varname='p_ul', - defaults={if_true=1000} + defaults={if_true=1000}, + cb='did_set_undolevels' }, { full_name='undoreload', abbreviation='ur', @@ -2616,7 +2765,8 @@ return { short_desc=N_("after this many characters flush swap file"), type='number', scope={'global'}, varname='p_uc', - defaults={if_true=200} + defaults={if_true=200}, + cb='did_set_updatecount' }, { full_name='updatetime', abbreviation='ut', @@ -2630,7 +2780,8 @@ return { short_desc=N_("list of numbers of spaces that uses while editing"), type='string', list='comma', scope={'buffer'}, varname='p_vsts', - defaults={if_true=""} + defaults={if_true=""}, + cb='did_set_varsofttabstop' }, { full_name='vartabstop', abbreviation='vts', @@ -2638,7 +2789,8 @@ return { type='string', list='comma', scope={'buffer'}, varname='p_vts', redraw={'current_buffer'}, - defaults={if_true=""} + defaults={if_true=""}, + cb='did_set_vartabstop' }, { full_name='verbose', abbreviation='vbs', @@ -2654,7 +2806,8 @@ return { secure=true, expand=true, varname='p_vfile', - defaults={if_true=""} + defaults={if_true=""}, + cb='did_set_verbosefile' }, { full_name='viewdir', abbreviation='vdir', @@ -2671,7 +2824,8 @@ return { type='string', list='onecomma', scope={'global'}, deny_duplicates=true, varname='p_vop', - defaults={if_true="folds,cursor,curdir"} + defaults={if_true="folds,cursor,curdir"}, + cb='did_set_viewoptions' }, { -- Alias for "shada". @@ -2692,7 +2846,8 @@ return { deny_duplicates=true, redraw={'curswant'}, varname='p_ve', - defaults={if_true=""} + defaults={if_true=""}, + cb='did_set_virtualedit' }, { full_name='visualbell', abbreviation='vb', @@ -2713,7 +2868,8 @@ return { short_desc=N_("allow specified keys to cross line boundaries"), type='string', list='flagscomma', scope={'global'}, varname='p_ww', - defaults={if_true="b,s"} + defaults={if_true="b,s"}, + cb='did_set_whichwrap' }, { full_name='wildchar', abbreviation='wc', @@ -2757,7 +2913,8 @@ return { type='string', list='onecomma', scope={'global'}, deny_duplicates=false, varname='p_wim', - defaults={if_true="full"} + defaults={if_true="full"}, + cb='did_set_wildmode' }, { full_name='wildoptions', abbreviation='wop', @@ -2765,14 +2922,16 @@ return { type='string', list='onecomma', scope={'global'}, deny_duplicates=true, varname='p_wop', - defaults={if_true='pum,tagfile'} + defaults={if_true='pum,tagfile'}, + cb='did_set_wildoptions' }, { full_name='winaltkeys', abbreviation='wak', short_desc=N_("when the windows system handles ALT keys"), type='string', scope={'global'}, varname='p_wak', - defaults={if_true="menu"} + defaults={if_true="menu"}, + cb='did_set_winaltkeys' }, { full_name='winbar', abbreviation='wbr', @@ -2782,14 +2941,16 @@ return { modelineexpr=true, redraw={'statuslines'}, varname='p_wbr', - defaults={if_true=""} + defaults={if_true=""}, + cb='did_set_winbar' }, { full_name='winblend', abbreviation='winbl', short_desc=N_("Controls transparency level for floating windows"), type='number', scope={'window'}, redraw={'current_window'}, - defaults={if_true=0} + defaults={if_true=0}, + cb='did_set_winblend' }, { full_name='winhighlight', abbreviation='winhl', @@ -2798,21 +2959,24 @@ return { deny_duplicates=true, alloced=true, redraw={'current_window'}, - defaults={if_true=""} + defaults={if_true=""}, + cb='did_set_winhl' }, { full_name='window', abbreviation='wi', short_desc=N_("nr of lines to scroll for CTRL-F and CTRL-B"), type='number', scope={'global'}, varname='p_window', - defaults={if_true=0} + defaults={if_true=0}, + cb='did_set_window' }, { full_name='winheight', abbreviation='wh', short_desc=N_("minimum number of lines for the current window"), type='number', scope={'global'}, varname='p_wh', - defaults={if_true=1} + defaults={if_true=1}, + cb='did_set_winheight' }, { full_name='winfixheight', abbreviation='wfh', @@ -2833,28 +2997,32 @@ return { short_desc=N_("minimum number of lines for any window"), type='number', scope={'global'}, varname='p_wmh', - defaults={if_true=1} + defaults={if_true=1}, + cb='did_set_winminheight' }, { full_name='winminwidth', abbreviation='wmw', short_desc=N_("minimal number of columns for any window"), type='number', scope={'global'}, varname='p_wmw', - defaults={if_true=1} + defaults={if_true=1}, + cb='did_set_winminwidth' }, { full_name='winwidth', abbreviation='wiw', short_desc=N_("minimal number of columns for current window"), type='number', scope={'global'}, varname='p_wiw', - defaults={if_true=20} + defaults={if_true=20}, + cb='did_set_winwidth' }, { full_name='wrap', short_desc=N_("lines wrap and continue on the next line"), type='bool', scope={'window'}, redraw={'current_window'}, - defaults={if_true=true} + defaults={if_true=true}, + cb='did_set_wrap' }, { full_name='wrapmargin', abbreviation='wm', diff --git a/src/nvim/optionstr.c b/src/nvim/optionstr.c index ece7a90b4a..96d383bbb1 100644 --- a/src/nvim/optionstr.c +++ b/src/nvim/optionstr.c @@ -444,7 +444,7 @@ const char *set_string_option(const int opt_idx, const char *const value, const char *const saved_newval = xstrdup(s); int value_checked = false; - const char *const errmsg = did_set_string_option(opt_idx, varp, oldval, errbuf, errbuflen, + const char *const errmsg = did_set_string_option(opt_idx, varp, oldval, s, errbuf, errbuflen, opt_flags, &value_checked); if (errmsg == NULL) { did_set_option(opt_idx, opt_flags, true, value_checked); @@ -479,11 +479,13 @@ static bool valid_filetype(const char *val) /// Handle setting 'mousescroll'. /// @return error message, NULL if it's OK. -static const char *check_mousescroll(char *string) +const char *did_set_mousescroll(optset_T *args FUNC_ATTR_UNUSED) { long vertical = -1; long horizontal = -1; + char *string = p_mousescroll; + while (true) { char *end = vim_strchr(string, ','); size_t length = end ? (size_t)(end - string) : strlen(string); @@ -651,8 +653,12 @@ static bool check_illegal_path_names(char *val, uint32_t flags) && strpbrk(val, "*?[|;&<>\r\n") != NULL)); } -static void did_set_backupcopy(buf_T *buf, char *oldval, int opt_flags, const char **errmsg) +/// The 'backupcopy' option is changed. +const char *did_set_backupcopy(optset_T *args) { + buf_T *buf = (buf_T *)args->os_buf; + const char *oldval = args->os_oldval.string; + int opt_flags = args->os_flags; char *bkc = p_bkc; unsigned *flags = &bkc_flags; @@ -666,7 +672,7 @@ static void did_set_backupcopy(buf_T *buf, char *oldval, int opt_flags, const ch *flags = 0; } else { if (opt_strings_flags(bkc, p_bkc_values, flags, true) != OK) { - *errmsg = e_invarg; + return e_invarg; } if (((*flags & BKC_AUTO) != 0) @@ -674,42 +680,68 @@ static void did_set_backupcopy(buf_T *buf, char *oldval, int opt_flags, const ch + ((*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; + return e_invarg; } } + + return NULL; } -static void did_set_backupext_or_patchmode(const char **errmsg) +/// The 'backupext' or the 'patchmode' option is changed. +const char *did_set_backupext_or_patchmode(optset_T *args FUNC_ATTR_UNUSED) { if (strcmp(*p_bex == '.' ? p_bex + 1 : p_bex, *p_pm == '.' ? p_pm + 1 : p_pm) == 0) { - *errmsg = e_backupext_and_patchmode_are_equal; + return e_backupext_and_patchmode_are_equal; } + + return NULL; } -static void did_set_breakindentopt(win_T *win, const char **errmsg) +/// The 'belloff' option is changed. +const char *did_set_belloff(optset_T *args FUNC_ATTR_UNUSED) { + return did_set_opt_flags(p_bo, p_bo_values, &bo_flags, true); +} + +/// The 'termpastefilter' option is changed. +const char *did_set_termpastefilter(optset_T *args FUNC_ATTR_UNUSED) +{ + return did_set_opt_flags(p_tpf, p_tpf_values, &tpf_flags, true); +} + +/// The 'breakindentopt' option is changed. +const char *did_set_breakindentopt(optset_T *args) +{ + win_T *win = (win_T *)args->os_win; if (briopt_check(win) == FAIL) { - *errmsg = e_invarg; + return e_invarg; } // list setting requires a redraw if (win == curwin && win->w_briopt_list) { redraw_all_later(UPD_NOT_VALID); } + + return NULL; } -static void did_set_isopt(buf_T *buf, bool *did_chartab, const char **errmsg) +/// The 'isident' or the 'iskeyword' or the 'isprint' or the 'isfname' option is +/// changed. +const char *did_set_isopt(optset_T *args) { + buf_T *buf = (buf_T *)args->os_buf; // '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 + args->os_restore_chartab = true; // need to restore it below + return e_invarg; // error in value } + return NULL; } -static void did_set_helpfile(void) +/// The 'helpfile' option is changed. +const char *did_set_helpfile(optset_T *args FUNC_ATTR_UNUSED) { // May compute new values for $VIM and $VIMRUNTIME if (didset_vim) { @@ -718,75 +750,102 @@ static void did_set_helpfile(void) if (didset_vimruntime) { vim_unsetenv_ext("VIMRUNTIME"); } + return NULL; } -static void did_set_cursorlineopt(win_T *win, char **varp, const char **errmsg) +/// The 'cursorlineopt' option is changed. +const char *did_set_cursorlineopt(optset_T *args) { + win_T *win = (win_T *)args->os_win; + char **varp = (char **)args->os_varp; + if (**varp == NUL || fill_culopt_flags(*varp, win) != OK) { - *errmsg = e_invarg; + return e_invarg; } + + return NULL; } -static void did_set_helplang(const char **errmsg) +/// The 'helplang' option is changed. +const char *did_set_helplang(optset_T *args FUNC_ATTR_UNUSED) { // 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; + return e_invarg; } if (s[2] == NUL) { break; } } + return NULL; } -static void did_set_highlight(char **varp, const char **errmsg) +/// The 'highlight' option is changed. +const char *did_set_highlight(optset_T *args) { + char **varp = (char **)args->os_varp; + if (strcmp(*varp, HIGHLIGHT_INIT) != 0) { - *errmsg = e_unsupportedoption; + return e_unsupportedoption; } + return NULL; } -static void did_set_opt_flags(char *val, char **values, unsigned *flagp, bool list, - const char **errmsg) +static const char *did_set_opt_flags(char *val, char **values, unsigned *flagp, bool list) { if (opt_strings_flags(val, values, flagp, list) != OK) { - *errmsg = e_invarg; + return e_invarg; } + return NULL; } -static void did_set_opt_strings(char *val, char **values, bool list, const char **errmsg) +static const char *did_set_opt_strings(char *val, char **values, bool list) { - did_set_opt_flags(val, values, NULL, list, errmsg); + return did_set_opt_flags(val, values, NULL, list); } -static void did_set_sessionoptions(char *oldval, const char **errmsg) +/// The 'selectmode' option is changed. +const char *did_set_selectmode(optset_T *args FUNC_ATTR_UNUSED) +{ + return did_set_opt_strings(p_slm, p_slm_values, true); +} + +/// The 'inccommand' option is changed. +const char *did_set_inccommand(optset_T *args FUNC_ATTR_UNUSED) +{ + return did_set_opt_strings(p_icm, p_icm_values, false); +} + +/// The 'sessionoptions' option is changed. +const char *did_set_sessionoptions(optset_T *args) { if (opt_strings_flags(p_ssop, p_ssop_values, &ssop_flags, true) != OK) { - *errmsg = e_invarg; + return e_invarg; } if ((ssop_flags & SSOP_CURDIR) && (ssop_flags & SSOP_SESDIR)) { // Don't allow both "sesdir" and "curdir". + const char *oldval = args->os_oldval.string; (void)opt_strings_flags(oldval, p_ssop_values, &ssop_flags, true); - *errmsg = e_invarg; + return e_invarg; } + return NULL; } -static void did_set_ambiwidth(const char **errmsg) +/// The 'ambiwidth' option is changed. +const char *did_set_ambiwidth(optset_T *args FUNC_ATTR_UNUSED) { if (check_opt_strings(p_ambw, p_ambw_values, false) != OK) { - *errmsg = e_invarg; - } else { - *errmsg = check_chars_options(); + return e_invarg; } + return check_chars_options(); } -static void did_set_background(const char **errmsg) +/// The 'background' option is changed. +const char *did_set_background(optset_T *args FUNC_ATTR_UNUSED) { if (check_opt_strings(p_bg, p_bg_values, false) != OK) { - *errmsg = e_invarg; - return; + return e_invarg; } int dark = (*p_bg == 'd'); @@ -803,44 +862,122 @@ static void did_set_background(const char **errmsg) check_string_option(&p_bg); init_highlight(false, false); } + return NULL; } -static void did_set_wildmode(const char **errmsg) +/// The 'whichwrap' option is changed. +const char *did_set_whichwrap(optset_T *args) +{ + char **varp = (char **)args->os_varp; + + return did_set_option_listflag(*varp, WW_ALL, args->os_errbuf, args->os_errbuflen); +} + +/// The 'shortmess' option is changed. +const char *did_set_shortmess(optset_T *args) +{ + char **varp = (char **)args->os_varp; + + return did_set_option_listflag(*varp, SHM_ALL, args->os_errbuf, args->os_errbuflen); +} + +/// The 'cpoptions' option is changed. +const char *did_set_cpoptions(optset_T *args) +{ + char **varp = (char **)args->os_varp; + + return did_set_option_listflag(*varp, CPO_VI, args->os_errbuf, args->os_errbuflen); +} + +/// The 'clipboard' option is changed. +const char *did_set_clipboard(optset_T *args FUNC_ATTR_UNUSED) +{ + return did_set_opt_flags(p_cb, p_cb_values, &cb_flags, true); +} + +/// The 'foldopen' option is changed. +const char *did_set_foldopen(optset_T *args FUNC_ATTR_UNUSED) +{ + return did_set_opt_flags(p_fdo, p_fdo_values, &fdo_flags, true); +} + +/// The 'formatoptions' option is changed. +const char *did_set_formatoptions(optset_T *args) +{ + char **varp = (char **)args->os_varp; + + return did_set_option_listflag(*varp, FO_ALL, args->os_errbuf, args->os_errbuflen); +} + +/// The 'concealcursor' option is changed. +const char *did_set_concealcursor(optset_T *args) +{ + char **varp = (char **)args->os_varp; + + return did_set_option_listflag(*varp, COCU_ALL, args->os_errbuf, args->os_errbuflen); +} + +/// The 'mouse' option is changed. +const char *did_set_mouse(optset_T *args) +{ + char **varp = (char **)args->os_varp; + + return did_set_option_listflag(*varp, MOUSE_ALL, args->os_errbuf, args->os_errbuflen); +} + +/// The 'wildmode' option is changed. +const char *did_set_wildmode(optset_T *args FUNC_ATTR_UNUSED) { if (check_opt_wim() == FAIL) { - *errmsg = e_invarg; + return e_invarg; } + return NULL; } -static void did_set_winaltkeys(const char **errmsg) +/// The 'winaltkeys' option is changed. +const char *did_set_winaltkeys(optset_T *args FUNC_ATTR_UNUSED) { if (*p_wak == NUL || check_opt_strings(p_wak, p_wak_values, false) != OK) { - *errmsg = e_invarg; + return e_invarg; } + return NULL; } -static void did_set_eventignore(const char **errmsg) +/// The 'eventignore' option is changed. +const char *did_set_eventignore(optset_T *args FUNC_ATTR_UNUSED) { if (check_ei() == FAIL) { - *errmsg = e_invarg; + return e_invarg; } + return NULL; } -// 'encoding', 'fileencoding' and 'makeencoding' -static void did_set_encoding(buf_T *buf, char **varp, char **gvarp, int opt_flags, - const char **errmsg) +/// The 'eadirection' option is changed. +const char *did_set_eadirection(optset_T *args FUNC_ATTR_UNUSED) { + return did_set_opt_strings(p_ead, p_ead_values, false); +} + +/// One of the 'encoding', 'fileencoding' or 'makeencoding' +/// options is changed. +const char *did_set_encoding(optset_T *args) +{ + buf_T *buf = (buf_T *)args->os_buf; + char **varp = (char **)args->os_varp; + int opt_flags = args->os_flags; + // Get the global option to compare with, otherwise we would have to check + // two values for all local options. + char **gvarp = (char **)get_option_varp_scope_from(args->os_idx, OPT_GLOBAL, buf, NULL); + if (gvarp == &p_fenc) { if (!MODIFIABLE(buf) && opt_flags != OPT_GLOBAL) { - *errmsg = e_modifiable; - return; + return e_modifiable; } if (vim_strchr(*varp, ',') != NULL) { // No comma allowed in 'fileencoding'; catches confusing it // with 'fileencodings'. - *errmsg = e_invarg; - return; + return e_invarg; } // May show a "+" in the title now. @@ -856,19 +993,22 @@ static void did_set_encoding(buf_T *buf, char **varp, char **gvarp, int opt_flag if (varp == &p_enc) { // only encoding=utf-8 allowed if (strcmp(p_enc, "utf-8") != 0) { - *errmsg = e_unsupportedoption; - return; + return e_unsupportedoption; } spell_reload(); } + return NULL; } -static void did_set_keymap(buf_T *buf, char **varp, int opt_flags, int *value_checked, - const char **errmsg) +/// The 'keymap' option has changed. +const char *did_set_keymap(optset_T *args) { + buf_T *buf = (buf_T *)args->os_buf; + char **varp = (char **)args->os_varp; + int opt_flags = args->os_flags; + if (!valid_filetype(*varp)) { - *errmsg = e_invarg; - return; + return e_invarg; } int secure_save = secure; @@ -878,15 +1018,15 @@ static void did_set_keymap(buf_T *buf, char **varp, int opt_flags, int *value_ch secure = 0; // load or unload key mapping tables - *errmsg = keymap_init(); + const char *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; + args->os_value_checked = true; - if (*errmsg == NULL) { + if (errmsg == NULL) { if (*buf->b_p_keymap != NUL) { // Installed a new keymap, switch on using it. buf->b_p_iminsert = B_IMODE_LMAP; @@ -908,29 +1048,44 @@ static void did_set_keymap(buf_T *buf, char **varp, int opt_flags, int *value_ch } status_redraw_buf(buf); } + + return errmsg; } -static void did_set_fileformat(buf_T *buf, char **varp, const char *oldval, int opt_flags, - const char **errmsg) +/// The 'fileformat' option is changed. +const char *did_set_fileformat(optset_T *args) { + buf_T *buf = (buf_T *)args->os_buf; + char **varp = (char **)args->os_varp; + const char *oldval = args->os_oldval.string; + int opt_flags = args->os_flags; if (!MODIFIABLE(buf) && !(opt_flags & OPT_GLOBAL)) { - *errmsg = e_modifiable; + return 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); - } + return e_invarg; } + 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); + } + return NULL; } -static void did_set_matchpairs(char **varp, const char **errmsg) +/// The 'fileformats' option is changed. +const char *did_set_fileformats(optset_T *args) { + return did_set_opt_strings(p_ffs, p_ff_values, true); +} + +/// The 'matchpairs' option is changed. +const char *did_set_matchpairs(optset_T *args) +{ + char **varp = (char **)args->os_varp; + for (char *p = *varp; *p != NUL; p++) { int x2 = -1; int x3 = -1; @@ -944,32 +1099,50 @@ static void did_set_matchpairs(char **varp, const char **errmsg) p += utfc_ptr2len(p); } if (x2 != ':' || x3 == -1 || (*p != NUL && *p != ',')) { - *errmsg = e_invarg; - break; + return e_invarg; } if (*p == NUL) { break; } } + return NULL; } -static void did_set_comments(char **varp, char *errbuf, size_t errbuflen, const char **errmsg) +/// The 'cinoptions' option is changed. +const char *did_set_cinoptions(optset_T *args FUNC_ATTR_UNUSED) { + // TODO(vim): recognize errors + parse_cino(curbuf); + + return NULL; +} + +/// The 'colorcolumn' option is changed. +const char *did_set_colorcolumn(optset_T *args) +{ + win_T *win = (win_T *)args->os_win; + return check_colorcolumn(win); +} + +const char *did_set_comments(optset_T *args) +{ + char **varp = (char **)args->os_varp; + char *errmsg = NULL; 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, (uint8_t)(*s)); + errmsg = illegal_char(args->os_errbuf, args->os_errbuflen, (uint8_t)(*s)); break; } s++; } if (*s++ == NUL) { - *errmsg = N_("E524: Missing colon"); + errmsg = N_("E524: Missing colon"); } else if (*s == ',' || *s == NUL) { - *errmsg = N_("E525: Zero length string"); + errmsg = N_("E525: Zero length string"); } - if (*errmsg != NULL) { + if (errmsg != NULL) { break; } while (*s && *s != ',') { @@ -980,46 +1153,104 @@ static void did_set_comments(char **varp, char *errbuf, size_t errbuflen, const } s = skip_to_option_part(s); } + return errmsg; } -static void did_set_global_listfillchars(win_T *win, char **varp, int opt_flags, - const char **errmsg) +/// The global 'listchars' or 'fillchars' option is changed. +static const char *did_set_global_listfillchars(win_T *win, char *val, bool opt_lcs, int opt_flags) { - 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); + const char *errmsg = NULL; + char **local_ptr = opt_lcs ? &win->w_p_lcs : &win->w_p_fcs; + + // only apply the global value to "win" when it does not have a + // local value + if (opt_lcs) { + errmsg = set_listchars_option(win, val, **local_ptr == NUL || !(opt_flags & OPT_GLOBAL)); + } else { + errmsg = set_fillchars_option(win, val, **local_ptr == NUL || !(opt_flags & OPT_GLOBAL)); + } + if (errmsg != NULL) { + return errmsg; + } + + // 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. + if (opt_lcs) { + if (*wp->w_p_lcs == NUL) { + (void)set_listchars_option(wp, wp->w_p_lcs, true); + } + } else { + if (*wp->w_p_fcs == NUL) { + (void)set_fillchars_option(wp, wp->w_p_fcs, true); } } - redraw_all_later(UPD_NOT_VALID); } + + redraw_all_later(UPD_NOT_VALID); + + return NULL; } -static void did_set_verbosefile(const char **errmsg) +/// Handle the new value of 'fillchars'. +const char *set_fillchars_option(win_T *wp, char *val, int apply) +{ + return set_chars_option(wp, val, false, apply); +} + +/// Handle the new value of 'listchars'. +const char *set_listchars_option(win_T *wp, char *val, int apply) +{ + return set_chars_option(wp, val, true, apply); +} + +/// The 'fillchars' option or the 'listchars' option is changed. +const char *did_set_chars_option(optset_T *args) +{ + win_T *win = (win_T *)args->os_win; + char **varp = (char **)args->os_varp; + const char *errmsg = NULL; + + if (varp == &p_lcs // global 'listchars' + || varp == &p_fcs) { // global 'fillchars' + errmsg = did_set_global_listfillchars(win, *varp, varp == &p_lcs, args->os_flags); + } else if (varp == &win->w_p_lcs) { // local 'listchars' + errmsg = set_listchars_option(win, *varp, true); + } else if (varp == &win->w_p_fcs) { // local 'fillchars' + errmsg = set_fillchars_option(win, *varp, true); + } + + return errmsg; +} + +/// The 'verbosefile' option is changed. +const char *did_set_verbosefile(optset_T *args) { verbose_stop(); if (*p_vfile != NUL && verbose_open() == FAIL) { - *errmsg = e_invarg; + return (char *)e_invarg; } + return NULL; +} + +/// The 'viewoptions' option is changed. +const char *did_set_viewoptions(optset_T *args FUNC_ATTR_UNUSED) +{ + return did_set_opt_flags(p_vop, p_ssop_values, &vop_flags, true); } static int shada_idx = -1; -static void did_set_shada(vimoption_T **opt, int *opt_idx, bool *free_oldval, char *errbuf, - size_t errbuflen, const char **errmsg) +static const char *did_set_shada(vimoption_T **opt, int *opt_idx, bool *free_oldval, char *errbuf, + size_t errbuflen) { // TODO(ZyX-I): Remove this code in the future, alongside with &viminfo // option. @@ -1034,8 +1265,7 @@ static void did_set_shada(vimoption_T **opt, int *opt_idx, bool *free_oldval, ch 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, (uint8_t)(*s)); - break; + return illegal_char(errbuf, errbuflen, (uint8_t)(*s)); } if (*s == 'n') { // name is always last one break; @@ -1054,43 +1284,46 @@ static void did_set_shada(vimoption_T **opt, int *opt_idx, bool *free_oldval, ch vim_snprintf(errbuf, errbuflen, _("E526: Missing number after <%s>"), transchar_byte((uint8_t)(*(s - 1)))); - *errmsg = errbuf; + return errbuf; } else { - *errmsg = ""; + return ""; } - break; } } if (*s == ',') { s++; } else if (*s) { if (errbuf != NULL) { - *errmsg = N_("E527: Missing comma"); + return N_("E527: Missing comma"); } else { - *errmsg = ""; + return ""; } - break; } } - if (*p_shada && *errmsg == NULL && get_shada_parameter('\'') < 0) { - *errmsg = N_("E528: Must specify a ' value"); + if (*p_shada && get_shada_parameter('\'') < 0) { + return N_("E528: Must specify a ' value"); } + return NULL; } -static void did_set_showbreak(char **varp, const char **errmsg) +/// The 'showbreak' option is changed. +const char *did_set_showbreak(optset_T *args) { + char **varp = (char **)args->os_varp; + for (char *s = *varp; *s;) { if (ptr2cells(s) != 1) { - *errmsg = e_showbreak_contains_unprintable_or_wide_character; + return e_showbreak_contains_unprintable_or_wide_character; } MB_PTR_ADV(s); } + return NULL; } -static void did_set_titleiconstring(char **varp) +/// The 'titlestring' or the 'iconstring' option is changed. +static const char *did_set_titleiconstring(optset_T *args, int flagval) { - // 'titlestring' and 'iconstring' - int flagval = (varp == &p_titlestring) ? STL_IN_TITLE : STL_IN_ICON; + char **varp = (char **)args->os_varp; // NULL => statusline syntax if (vim_strchr(*varp, '%') && check_stl_option(*varp) == NULL) { @@ -1099,140 +1332,240 @@ static void did_set_titleiconstring(char **varp) stl_syntax &= ~flagval; } did_set_title(); + + return NULL; } -static void did_set_selection(const char **errmsg) +/// The 'titlestring' option is changed. +const char *did_set_titlestring(optset_T *args) +{ + return did_set_titleiconstring(args, STL_IN_TITLE); +} + +/// The 'iconstring' option is changed. +const char *did_set_iconstring(optset_T *args) +{ + return did_set_titleiconstring(args, STL_IN_ICON); +} + +/// The 'selection' option is changed. +const char *did_set_selection(optset_T *args FUNC_ATTR_UNUSED) { if (*p_sel == NUL || check_opt_strings(p_sel, p_sel_values, false) != OK) { - *errmsg = e_invarg; + return e_invarg; } + return NULL; } -static void did_set_keymodel(const char **errmsg) +/// The 'keymodel' option is changed. +const char *did_set_keymodel(optset_T *args FUNC_ATTR_UNUSED) { if (check_opt_strings(p_km, p_km_values, true) != OK) { - *errmsg = e_invarg; - return; + return e_invarg; } km_stopsel = (vim_strchr(p_km, 'o') != NULL); km_startsel = (vim_strchr(p_km, 'a') != NULL); + return NULL; } -static void did_set_display(const char **errmsg) +/// The 'display' option is changed. +const char *did_set_display(optset_T *args FUNC_ATTR_UNUSED) { if (opt_strings_flags(p_dy, p_dy_values, &dy_flags, true) != OK) { - *errmsg = e_invarg; - return; + return e_invarg; } (void)init_chartab(); msg_grid_validate(); + return NULL; } -static void did_set_spellfile(char **varp, const char **errmsg) +/// The 'spellfile' option is changed. +const char *did_set_spellfile(optset_T *args) { + char **varp = (char **)args->os_varp; + // 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); + return e_invarg; } + return did_set_spell_option(true); } -static void did_set_spell(char **varp, const char **errmsg) +const char *did_set_spelllang(optset_T *args) { + char **varp = (char **)args->os_varp; + // 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); + return e_invarg; } + return did_set_spell_option(false); } -static void did_set_spellcapcheck(win_T *win, const char **errmsg) +/// The 'spellcapcheck' option is changed. +const char *did_set_spellcapcheck(optset_T *args) { + win_T *win = (win_T *)args->os_win; // When 'spellcapcheck' is set compile the regexp program. - *errmsg = compile_cap_prog(win->w_s); + return compile_cap_prog(win->w_s); } -static void did_set_spelloptions(win_T *win, const char **errmsg) +/// The 'spelloptions' option is changed. +const char *did_set_spelloptions(optset_T *args) { + win_T *win = (win_T *)args->os_win; 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; + return e_invarg; } + return NULL; } -static void did_set_spellsuggest(const char **errmsg) +/// The 'spellsuggest' option is changed. +const char *did_set_spellsuggest(optset_T *args FUNC_ATTR_UNUSED) { if (spell_check_sps() != OK) { - *errmsg = e_invarg; + return e_invarg; } + return NULL; } -static void did_set_mkspellmem(const char **errmsg) +/// The 'splitkeep' option is changed. +const char *did_set_splitkeep(optset_T *args FUNC_ATTR_UNUSED) +{ + return did_set_opt_strings(p_spk, p_spk_values, false); +} + +/// The 'mkspellmem' option is changed. +const char *did_set_mkspellmem(optset_T *args FUNC_ATTR_UNUSED) { if (spell_check_msm() != OK) { - *errmsg = e_invarg; + return e_invarg; } + return NULL; } -static void did_set_buftype(buf_T *buf, win_T *win, const char **errmsg) +/// The 'mousemodel' option is changed. +const char *did_set_mousemodel(optset_T *args FUNC_ATTR_UNUSED) { + return did_set_opt_strings(p_mousem, p_mousem_values, false); +} + +/// The 'bufhidden' option is changed. +const char *did_set_bufhidden(optset_T *args) +{ + buf_T *buf = (buf_T *)args->os_buf; + return did_set_opt_strings(buf->b_p_bh, p_bufhidden_values, false); +} + +/// The 'buftype' option is changed. +const char *did_set_buftype(optset_T *args) +{ + buf_T *buf = (buf_T *)args->os_buf; + win_T *win = (win_T *)args->os_win; // 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(); + return e_invarg; } + 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(); + return NULL; } -// 'statusline', 'winbar', 'tabline', 'rulerformat' or 'statuscolumn' -static void did_set_statusline(win_T *win, char **varp, char **gvarp, const char **errmsg) +/// The 'casemap' option is changed. +const char *did_set_casemap(optset_T *args FUNC_ATTR_UNUSED) { - if (varp == &p_ruf) { // reset ru_wid first + return did_set_opt_flags(p_cmp, p_cmp_values, &cmp_flags, true); +} + +/// The 'statusline', 'winbar', 'tabline', 'rulerformat' or 'statuscolumn' option is changed. +/// +/// @param rulerformat true if the 'rulerformat' option is changed +/// @param statuscolumn true if the 'statuscolumn' option is changed +static const char *did_set_statustabline_rulerformat(optset_T *args, bool rulerformat, + bool statuscolumn) +{ + win_T *win = (win_T *)args->os_win; + char **varp = (char **)args->os_varp; + if (rulerformat) { // reset ru_wid first ru_wid = 0; - } else if (varp == &win->w_p_stc) { + } else if (statuscolumn) { // reset 'statuscolumn' width win->w_nrwidth_line_count = 0; } + const char *errmsg = NULL; char *s = *varp; - if (varp == &p_ruf && *s == '%') { + if (rulerformat && *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) { + if (wid && *s == '(' && (errmsg = check_stl_option(p_ruf)) == NULL) { ru_wid = wid; } else { - *errmsg = check_stl_option(p_ruf); + errmsg = check_stl_option(p_ruf); } - } else if (varp == &p_ruf || s[0] != '%' || s[1] != '!') { + } else if (rulerformat || s[0] != '%' || s[1] != '!') { // check 'statusline', 'winbar', 'tabline' or 'statuscolumn' // only if it doesn't start with "%!" - *errmsg = check_stl_option(s); + errmsg = check_stl_option(s); } - if (varp == &p_ruf && *errmsg == NULL) { + if (rulerformat && errmsg == NULL) { comp_col(); } - // add / remove window bars for 'winbar' - if (gvarp == &p_wbr) { - set_winbar(true); - } + return errmsg; } -static void did_set_complete(char **varp, char *errbuf, size_t errbuflen, const char **errmsg) +/// The 'statusline' option is changed. +const char *did_set_statusline(optset_T *args) { + return did_set_statustabline_rulerformat(args, false, false); +} + +/// The 'tabline' option is changed. +const char *did_set_tabline(optset_T *args) +{ + return did_set_statustabline_rulerformat(args, false, false); +} + +/// The 'rulerformat' option is changed. +const char *did_set_rulerformat(optset_T *args) +{ + return did_set_statustabline_rulerformat(args, true, false); +} + +/// The 'winbar' option is changed. +const char *did_set_winbar(optset_T *args) +{ + return did_set_statustabline_rulerformat(args, false, false); +} + +/// The 'statuscolumn' option is changed. +const char *did_set_statuscolumn(optset_T *args) +{ + return did_set_statustabline_rulerformat(args, false, true); +} + +/// The 'scrollopt' option is changed. +const char *did_set_scrollopt(optset_T *args FUNC_ATTR_UNUSED) +{ + return did_set_opt_strings(p_sbo, p_scbopt_values, true); +} + +/// The 'complete' option is changed. +const char *did_set_complete(optset_T *args) +{ + char **varp = (char **)args->os_varp; + // check if it is a valid value for 'complete' -- Acevedo for (char *s = *varp; *s;) { while (*s == ',' || *s == ' ') { @@ -1242,8 +1575,7 @@ static void did_set_complete(char **varp, char *errbuf, size_t errbuflen, const break; } if (vim_strchr(".wbuksid]tU", (uint8_t)(*s)) == NULL) { - *errmsg = illegal_char(errbuf, errbuflen, (uint8_t)(*s)); - break; + return illegal_char(args->os_errbuf, args->os_errbuflen, (uint8_t)(*s)); } if (*++s != NUL && *s != ',' && *s != ' ') { if (s[-1] == 'k' || s[-1] == 's') { @@ -1255,43 +1587,56 @@ static void did_set_complete(char **varp, char *errbuf, size_t errbuflen, const s++; } } else { - if (errbuf != NULL) { - vim_snprintf(errbuf, errbuflen, + if (args->os_errbuf != NULL) { + vim_snprintf(args->os_errbuf, args->os_errbuflen, _("E535: Illegal character after <%c>"), *--s); - *errmsg = errbuf; - } else { - *errmsg = ""; + return args->os_errbuf; } - break; + return ""; } } } + return NULL; } -static void did_set_completeopt(const char **errmsg) +/// The 'completeopt' option is changed. +const char *did_set_completeopt(optset_T *args FUNC_ATTR_UNUSED) { if (check_opt_strings(p_cot, p_cot_values, true) != OK) { - *errmsg = e_invarg; - } else { - completeopt_was_set(); + return e_invarg; } + completeopt_was_set(); + return NULL; } #ifdef BACKSLASH_IN_FILENAME -static void did_set_completeslash(buf_T *buf, const char **errmsg) +/// The 'completeslash' option is changed. +const char *did_set_completeslash(optset_T *args) { + buf_T *buf = (buf_T *)args->os_buf; if (check_opt_strings(p_csl, p_csl_values, false) != OK || check_opt_strings(buf->b_p_csl, p_csl_values, false) != OK) { - *errmsg = e_invarg; + return e_invarg; } + return NULL; } #endif -static void did_set_signcolumn(win_T *win, char **varp, const char *oldval, const char **errmsg) +/// The 'showcmdloc' option is changed. +const char *did_set_showcmdloc(optset_T *args FUNC_ATTR_UNUSED) { + return did_set_opt_strings(p_sloc, p_sloc_values, true); +} + +/// The 'signcolumn' option is changed. +const char *did_set_signcolumn(optset_T *args) +{ + win_T *win = (win_T *)args->os_win; + char **varp = (char **)args->os_varp; + const char *oldval = args->os_oldval.string; if (check_signcolumn(*varp) != OK) { - *errmsg = e_invarg; + return e_invarg; } // When changing the 'signcolumn' to or from 'number', recompute the // width of the number column if 'number' or 'relativenumber' is set. @@ -1300,28 +1645,44 @@ static void did_set_signcolumn(win_T *win, char **varp, const char *oldval, cons && (win->w_p_nu || win->w_p_rnu)) { win->w_nrwidth_line_count = 0; } + return NULL; } -static void did_set_foldcolumn(char **varp, const char **errmsg) +/// The 'foldcolumn' option is changed. +const char *did_set_foldcolumn(optset_T *args) { + char **varp = (char **)args->os_varp; if (**varp == NUL || check_opt_strings(*varp, p_fdc_values, false) != OK) { - *errmsg = e_invarg; + return e_invarg; } + return NULL; } -static void did_set_backspace(const char **errmsg) +/// The 'backspace' option is changed. +const char *did_set_backspace(optset_T *args FUNC_ATTR_UNUSED) { if (ascii_isdigit(*p_bs)) { if (*p_bs > '3' || p_bs[1] != NUL) { - *errmsg = e_invarg; + return e_invarg; } } else if (check_opt_strings(p_bs, p_bs_values, true) != OK) { - *errmsg = e_invarg; + return e_invarg; } + return NULL; } -static void did_set_tagcase(buf_T *buf, int opt_flags, const char **errmsg) +/// The 'switchbuf' option is changed. +const char *did_set_switchbuf(optset_T *args FUNC_ATTR_UNUSED) { + return did_set_opt_flags(p_swb, p_swb_values, &swb_flags, true); +} + +/// The 'tagcase' option is changed. +const char *did_set_tagcase(optset_T *args) +{ + buf_T *buf = (buf_T *)args->os_buf; + int opt_flags = args->os_flags; + unsigned *flags; char *p; @@ -1338,73 +1699,105 @@ static void did_set_tagcase(buf_T *buf, int opt_flags, const char **errmsg) *flags = 0; } else if (*p == NUL || opt_strings_flags(p, p_tc_values, flags, false) != OK) { - *errmsg = e_invarg; + return e_invarg; } + return NULL; } -static void did_set_diffopt(const char **errmsg) +/// The 'debug' option is changed. +const char *did_set_debug(optset_T *args FUNC_ATTR_UNUSED) +{ + return did_set_opt_strings(p_debug, p_debug_values, false); +} + +/// The 'diffopt' option is changed. +const char *did_set_diffopt(optset_T *args FUNC_ATTR_UNUSED) { if (diffopt_changed() == FAIL) { - *errmsg = e_invarg; + return e_invarg; } + return NULL; } -static void did_set_foldmethod(win_T *win, char **varp, const char **errmsg) +/// The 'foldmethod' option is changed. +const char *did_set_foldmethod(optset_T *args) { + win_T *win = (win_T *)args->os_win; + char **varp = (char **)args->os_varp; 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(); - } + return e_invarg; } + foldUpdateAll(win); + if (foldmethodIsDiff(win)) { + newFoldLevel(); + } + return NULL; } -static void did_set_foldmarker(win_T *win, char **varp, const char **errmsg) +/// The 'foldmarker' option is changed. +const char *did_set_foldmarker(optset_T *args) { + win_T *win = (win_T *)args->os_win; + char **varp = (char **)args->os_varp; 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)) { + return N_("E536: comma required"); + } + + if (p == *varp || p[1] == NUL) { + return e_invarg; + } + + if (foldmethodIsMarker(win)) { foldUpdateAll(win); } + + return NULL; } -static void did_set_commentstring(char **varp, const char **errmsg) +/// The 'commentstring' option is changed. +const char *did_set_commentstring(optset_T *args) { + char **varp = (char **)args->os_varp; + if (**varp != NUL && strstr(*varp, "%s") == NULL) { - *errmsg = N_("E537: 'commentstring' must be empty or contain %s"); + return N_("E537: 'commentstring' must be empty or contain %s"); } + return NULL; } -static void did_set_foldignore(win_T *win) +/// The 'foldignore' option is changed. +const char *did_set_foldignore(optset_T *args) { + win_T *win = (win_T *)args->os_win; if (foldmethodIsIndent(win)) { foldUpdateAll(win); } + return NULL; } -static void did_set_virtualedit(win_T *win, int opt_flags, char *oldval, const char **errmsg) +/// The 'virtualedit' option is changed. +const char *did_set_virtualedit(optset_T *args) { + win_T *win = (win_T *)args->os_win; + char *ve = p_ve; unsigned *flags = &ve_flags; - if (opt_flags & OPT_LOCAL) { + if (args->os_flags & OPT_LOCAL) { ve = win->w_p_ve; flags = &win->w_ve_flags; } - if ((opt_flags & OPT_LOCAL) && *ve == NUL) { + if ((args->os_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(ve, oldval) != 0) { + return e_invarg; + } else if (strcmp(ve, args->os_oldval.string) != 0) { // Recompute cursor position in case the new 've' setting // changes something. validate_virtcol_win(win); @@ -1412,42 +1805,87 @@ static void did_set_virtualedit(win_T *win, int opt_flags, char *oldval, const c coladvance(win->w_virtcol); } } + return NULL; } -static void did_set_lispoptions(char **varp, const char **errmsg) +/// The 'jumpoptions' option is changed. +const char *did_set_jumpoptions(optset_T *args FUNC_ATTR_UNUSED) { + return did_set_opt_flags(p_jop, p_jop_values, &jop_flags, true); +} + +/// The 'redrawdebug' option is changed. +const char *did_set_redrawdebug(optset_T *args FUNC_ATTR_UNUSED) +{ + return did_set_opt_flags(p_rdb, p_rdb_values, &rdb_flags, true); +} + +/// The 'wildoptions' option is changed. +const char *did_set_wildoptions(optset_T *args FUNC_ATTR_UNUSED) +{ + return did_set_opt_flags(p_wop, p_wop_values, &wop_flags, true); +} + +/// The 'lispoptions' option is changed. +const char *did_set_lispoptions(optset_T *args) +{ + char **varp = (char **)args->os_varp; + if (**varp != NUL && strcmp(*varp, "expr:0") != 0 && strcmp(*varp, "expr:1") != 0) { - *errmsg = e_invarg; + return e_invarg; } + return NULL; } -static void did_set_filetype_or_syntax(char **varp, char *oldval, int *value_checked, - bool *value_changed, const char **errmsg) +/// The 'rightleftcmd' option is changed. +const char *did_set_rightleftcmd(optset_T *args) { - if (!valid_filetype(*varp)) { - *errmsg = e_invarg; - return; + char **varp = (char **)args->os_varp; + + // Currently only "search" is a supported value. + if (**varp != NUL && strcmp(*varp, "search") != 0) { + return e_invarg; } - *value_changed = strcmp(oldval, *varp) != 0; + return NULL; +} + +/// The 'filetype' or the 'syntax' option is changed. +const char *did_set_filetype_or_syntax(optset_T *args) +{ + char **varp = (char **)args->os_varp; + + if (!valid_filetype(*varp)) { + return e_invarg; + } + + args->os_value_changed = strcmp(args->os_oldval.string, *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; + args->os_value_checked = true; + + return NULL; } -static void did_set_winhl(win_T *win, const char **errmsg) +const char *did_set_winhl(optset_T *args) { + win_T *win = (win_T *)args->os_win; if (!parse_winhl_opt(win)) { - *errmsg = e_invarg; + return e_invarg; } + return NULL; } -static void did_set_varsoftabstop(buf_T *buf, char **varp, const char **errmsg) +/// The 'varsofttabstop' option is changed. +const char *did_set_varsofttabstop(optset_T *args) { + buf_T *buf = (buf_T *)args->os_buf; + char **varp = (char **)args->os_varp; + if (!(*varp)[0] || ((*varp)[0] == '0' && !(*varp)[1])) { XFREE_CLEAR(buf->b_p_vsts_array); - return; + return NULL; } for (char *cp = *varp; *cp; cp++) { @@ -1457,23 +1895,28 @@ static void did_set_varsoftabstop(buf_T *buf, char **varp, const char **errmsg) if (*cp == ',' && cp > *varp && *(cp - 1) != ',') { continue; } - *errmsg = e_invarg; - return; + return e_invarg; } long *oldarray = buf->b_p_vsts_array; if (tabstop_set(*varp, &(buf->b_p_vsts_array))) { xfree(oldarray); } else { - *errmsg = e_invarg; + return e_invarg; } + return NULL; } -static void did_set_vartabstop(buf_T *buf, win_T *win, char **varp, const char **errmsg) +/// The 'varstabstop' option is changed. +const char *did_set_vartabstop(optset_T *args) { + buf_T *buf = (buf_T *)args->os_buf; + win_T *win = (win_T *)args->os_win; + char **varp = (char **)args->os_varp; + if (!(*varp)[0] || ((*varp)[0] == '0' && !(*varp)[1])) { XFREE_CLEAR(buf->b_p_vts_array); - return; + return NULL; } for (char *cp = *varp; *cp; cp++) { @@ -1483,8 +1926,7 @@ static void did_set_vartabstop(buf_T *buf, win_T *win, char **varp, const char * if (*cp == ',' && cp > *varp && *(cp - 1) != ',') { continue; } - *errmsg = e_invarg; - return; + return e_invarg; } long *oldarray = buf->b_p_vts_array; @@ -1494,29 +1936,67 @@ static void did_set_vartabstop(buf_T *buf, win_T *win, char **varp, const char * foldUpdateAll(win); } } else { - *errmsg = e_invarg; + return e_invarg; } + return NULL; } -static void did_set_optexpr(char **varp) +/// The 'nrformats' option is changed. +const char *did_set_nrformats(optset_T *args) { + char **varp = (char **)args->os_varp; + + return did_set_opt_strings(*varp, p_nf_values, true); +} + +/// One of the '*expr' options is changed:, 'diffexpr', 'foldexpr', 'foldtext', +/// 'formatexpr', 'includeexpr', 'indentexpr', 'patchexpr' and 'charconvert'. +const char *did_set_optexpr(optset_T *args) +{ + char **varp = (char **)args->os_varp; + + // If the option value starts with or s:, then replace that with + // the script identifier. char *name = get_scriptlocal_funcname(*varp); if (name != NULL) { free_string_option(*varp); *varp = name; } + return NULL; } -// handle option that is a list of flags. -static void did_set_option_listflag(char **varp, char *flags, char *errbuf, size_t errbuflen, - const char **errmsg) +/// The 'foldexpr' option is changed. +const char *did_set_foldexpr(optset_T *args) { - for (char *s = *varp; *s; s++) { + win_T *win = (win_T *)args->os_win; + (void)did_set_optexpr(args); + if (foldmethodIsExpr(win)) { + foldUpdateAll(win); + } + return NULL; +} + +/// The 'foldclose' option is changed. +const char *did_set_foldclose(optset_T *args FUNC_ATTR_UNUSED) +{ + return did_set_opt_strings(p_fcl, p_fcl_values, true); +} + +/// An option which is a list of flags is set. Valid values are in 'flags'. +static const char *did_set_option_listflag(char *val, char *flags, char *errbuf, size_t errbuflen) +{ + for (char *s = val; *s; s++) { if (vim_strchr(flags, (uint8_t)(*s)) == NULL) { - *errmsg = illegal_char(errbuf, errbuflen, (uint8_t)(*s)); - break; + return illegal_char(errbuf, errbuflen, (uint8_t)(*s)); } } + + return NULL; +} + +const char *did_set_guicursor(optset_T *args FUNC_ATTR_UNUSED) +{ + return parse_shape_opt(SHAPE_CURSOR); } // When 'syntax' is set, load the syntax of that name @@ -1574,18 +2054,30 @@ static void do_spelllang_source(win_T *win) /// /// @return NULL for success, or an untranslated error message for an error static const char *did_set_string_option_for(buf_T *buf, win_T *win, int opt_idx, char **varp, - char *oldval, char *errbuf, size_t errbuflen, - int opt_flags, int *value_checked) + char *oldval, const char *value, char *errbuf, + size_t errbuflen, int opt_flags, int *value_checked) { const char *errmsg = NULL; - bool did_chartab = false; + int restore_chartab = false; vimoption_T *opt = get_option(opt_idx); bool free_oldval = (opt->flags & P_ALLOCED); + opt_did_set_cb_T did_set_cb = get_option_did_set_cb(opt_idx); bool value_changed = false; - // Get the global option to compare with, otherwise we would have to check - // two values for all local options. - char **gvarp = (char **)get_varp_scope(opt, OPT_GLOBAL); + optset_T args = { + .os_varp = (char *)varp, + .os_idx = opt_idx, + .os_flags = opt_flags, + .os_oldval.string = oldval, + .os_newval.string = value, + .os_value_checked = false, + .os_value_changed = false, + .os_restore_chartab = false, + .os_errbuf = errbuf, + .os_errbuflen = errbuflen, + .os_win = curwin, + .os_buf = curbuf, + }; // Disallow changing some options from secure mode if ((secure || sandbox != 0) && (opt->flags & P_SECURE)) { @@ -1593,236 +2085,22 @@ static const char *did_set_string_option_for(buf_T *buf, win_T *win, int opt_idx // Check for a "normal" directory or file name in some options. } else if (check_illegal_path_names(*varp, opt->flags)) { errmsg = e_invarg; - } else if (gvarp == &p_bkc) { // 'backupcopy' - did_set_backupcopy(buf, oldval, opt_flags, &errmsg); - } else if (varp == &p_bex // 'backupext' - || varp == &p_pm) { // 'patchmode' - did_set_backupext_or_patchmode(&errmsg); - } else if (varp == &win->w_p_briopt) { // 'breakindentopt' - did_set_breakindentopt(win, &errmsg); - } else if (varp == &p_isi // 'isident' - || varp == &buf->b_p_isk // 'iskeyword' - || varp == &p_isp // 'isprint' - || varp == &p_isf) { // 'isfname' - did_set_isopt(buf, &did_chartab, &errmsg); - } else if (varp == &p_hf) { // 'helpfile' - did_set_helpfile(); - } else if (varp == &p_rtp // 'runtimepath' - || varp == &p_pp) { // 'packpath' - runtime_search_path_invalidate(); - } else if (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' - did_set_highlight(varp, &errmsg); - } else if (varp == &p_jop) { // 'jumpoptions' - did_set_opt_flags(p_jop, p_jop_values, &jop_flags, true, &errmsg); - } else if (gvarp == &p_nf) { // 'nrformats' - did_set_opt_strings(*varp, p_nf_values, true, &errmsg); - } else if (varp == &p_ssop) { // 'sessionoptions' - did_set_sessionoptions(oldval, &errmsg); - } else if (varp == &p_vop) { // 'viewoptions' - did_set_opt_flags(p_vop, p_ssop_values, &vop_flags, true, &errmsg); - } else if (varp == &p_rdb) { // 'redrawdebug' - did_set_opt_flags(p_rdb, p_rdb_values, &rdb_flags, true, &errmsg); - } else if (varp == &p_sbo) { // 'scrollopt' - did_set_opt_strings(p_sbo, p_scbopt_values, true, &errmsg); - } else if (varp == &p_ambw // 'ambiwidth' - || (int *)varp == &p_emoji) { // 'emoji' - did_set_ambiwidth(&errmsg); - } else if (varp == &p_bg) { // 'background' - did_set_background(&errmsg); - } else if (varp == &p_wim) { // 'wildmode' - did_set_wildmode(&errmsg); - } else if (varp == &p_wop) { // 'wildoptions' - did_set_opt_flags(p_wop, p_wop_values, &wop_flags, true, &errmsg); - } else if (varp == &p_wak) { // 'winaltkeys' - did_set_winaltkeys(&errmsg); - } else if (varp == &p_ei) { // 'eventignore' - did_set_eventignore(&errmsg); - } else if (varp == &p_enc // 'encoding' - || gvarp == &p_fenc // 'fileencoding' - || gvarp == &p_menc) { // 'makeencoding' - did_set_encoding(buf, varp, gvarp, opt_flags, &errmsg); - } else if (varp == &buf->b_p_keymap) { // 'keymap' - did_set_keymap(buf, varp, opt_flags, value_checked, &errmsg); - } else if (gvarp == &p_ff) { // 'fileformat' - did_set_fileformat(buf, varp, oldval, opt_flags, &errmsg); - } else if (varp == &p_ffs) { // 'fileformats' - did_set_opt_strings(p_ffs, p_ff_values, true, &errmsg); - } else if (gvarp == &p_mps) { // 'matchpairs' - did_set_matchpairs(varp, &errmsg); - } else if (gvarp == &p_com) { // 'comments' - did_set_comments(varp, errbuf, errbuflen, &errmsg); - } else if (varp == &p_lcs // global 'listchars' - || varp == &p_fcs) { // global 'fillchars' - 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' - did_set_verbosefile(&errmsg); + } else if (did_set_cb != NULL) { + // Invoke the option specific callback function to validate and apply + // the new option value. + errmsg = did_set_cb(&args); + + // The 'filetype' and 'syntax' option callback functions may change + // the os_value_changed field. + value_changed = args.os_value_changed; + // The 'keymap', 'filetype' and 'syntax' option callback functions + // may change the os_value_checked field. + *value_checked = args.os_value_checked; + // The 'isident', 'iskeyword', 'isprint' and 'isfname' options may + // change the character table. On failure, this needs to be restored. + restore_chartab = args.os_restore_chartab; } else if (varp == &p_shada) { // 'shada' - did_set_shada(&opt, &opt_idx, &free_oldval, errbuf, errbuflen, &errmsg); - } else if (gvarp == &p_sbr) { // 'showbreak' - did_set_showbreak(varp, &errmsg); - } else if (varp == &p_guicursor) { // 'guicursor' - errmsg = parse_shape_opt(SHAPE_CURSOR); - } else if (varp == &p_langmap) { // 'langmap' - langmap_set(); - } else if (varp == &p_breakat) { // 'breakat' - fill_breakat_flags(); - } else if (varp == &p_titlestring // 'titlestring' - || varp == &p_iconstring) { // 'iconstring' - did_set_titleiconstring(varp); - } else if (varp == &p_sel) { // 'selection' - did_set_selection(&errmsg); - } else if (varp == &p_slm) { // 'selectmode' - did_set_opt_strings(p_slm, p_slm_values, true, &errmsg); - } else if (varp == &p_km) { // 'keymodel' - did_set_keymodel(&errmsg); - } else if (varp == &p_mousem) { // 'mousemodel' - 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' - did_set_opt_flags(p_swb, p_swb_values, &swb_flags, true, &errmsg); - } else if (varp == &p_spk) { // 'splitkeep' - did_set_opt_strings(p_spk, p_spk_values, false, &errmsg); - } else if (varp == &p_debug) { // 'debug' - did_set_opt_strings(p_debug, p_debug_values, true, &errmsg); - } else if (varp == &p_dy) { // 'display' - did_set_display(&errmsg); - } else if (varp == &p_ead) { // 'eadirection' - did_set_opt_strings(p_ead, p_ead_values, false, &errmsg); - } else if (varp == &p_cb) { // 'clipboard' - did_set_opt_flags(p_cb, p_cb_values, &cb_flags, true, &errmsg); - } else if (varp == &win->w_s->b_p_spf) { // 'spellfile' - 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) { // 'spellcapcheck' - 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' - did_set_spellsuggest(&errmsg); - } else if (varp == &p_msm) { // 'mkspellmem' - did_set_mkspellmem(&errmsg); - } else if (gvarp == &p_bh) { // 'bufhidden' - 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 // 'statusline' - || gvarp == &p_wbr // 'winbar' - || varp == &p_tal // 'tabline' - || varp == &p_ruf // 'rulerformat' - || varp == &win->w_p_stc) { // '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' - did_set_completeopt(&errmsg); -#ifdef BACKSLASH_IN_FILENAME - } else if (gvarp == &p_csl) { // 'completeslash' - did_set_completeslash(buf, &errmsg); -#endif - } 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 (gvarp == &win->w_allbuf_opt.wo_fdc) { // 'foldcolumn' - did_set_foldcolumn(varp, &errmsg); - } else if (varp == &p_bs) { // 'backspace' - did_set_backspace(&errmsg); - } else if (varp == &p_bo) { - did_set_opt_flags(p_bo, p_bo_values, &bo_flags, true, &errmsg); - } else if (gvarp == &p_tc) { // 'tagcase' - did_set_tagcase(buf, opt_flags, &errmsg); - } else if (varp == &p_cmp) { // 'casemap' - did_set_opt_flags(p_cmp, p_cmp_values, &cmp_flags, true, &errmsg); - } else if (varp == &p_dip) { // 'diffopt' - 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' - did_set_commentstring(varp, &errmsg); - } else if (varp == &p_fdo) { // 'foldopen' - did_set_opt_flags(p_fdo, p_fdo_values, &fdo_flags, true, &errmsg); - } else if (varp == &p_fcl) { // 'foldclose' - 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' - did_set_virtualedit(win, opt_flags, oldval, &errmsg); - } else if (gvarp == &p_cino) { // 'cinoptions' - // TODO(vim): recognize errors - parse_cino(buf); - } else if (gvarp == &p_lop) { // 'lispoptions' - did_set_lispoptions(varp, &errmsg); - } else if (varp == &p_icm) { // 'inccommand' - did_set_opt_strings(*varp, p_icm_values, false, &errmsg); - } else if (gvarp == &p_ft // 'filetype' - || gvarp == &p_syn) { // 'syntax' - did_set_filetype_or_syntax(varp, oldval, value_checked, &value_changed, &errmsg); - } else if (varp == &win->w_p_winhl) { // 'winhighlight' - did_set_winhl(win, &errmsg); - } else if (varp == &p_tpf) { - 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' - || gvarp == &win->w_allbuf_opt.wo_fde // 'foldexpr' - || gvarp == &win->w_allbuf_opt.wo_fdt // 'foldtext' - || gvarp == &p_fex // 'formatexpr' - || gvarp == &p_inex // 'includeexpr' - || gvarp == &p_inde // 'indentexpr' - || varp == &p_pex // 'patchexpr' - || varp == &p_ccv) { // 'charconvert' - did_set_optexpr(varp); - if (varp == &win->w_p_fde && foldmethodIsExpr(win)) { - foldUpdateAll(win); - } - } 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' - set_operatorfunc_option(&errmsg); - } else if (varp == &p_qftf) { // 'quickfixtextfunc' - 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) { // 'formatlistpat' - if (win->w_briopt_list) { - // Changing Formatlistpattern when briopt includes the list setting: - // redraw - redraw_all_later(UPD_NOT_VALID); - } + errmsg = did_set_shada(&opt, &opt_idx, &free_oldval, errbuf, errbuflen); } // If an error is detected, restore the previous value. @@ -1830,7 +2108,7 @@ static const char *did_set_string_option_for(buf_T *buf, win_T *win, int opt_idx free_string_option(*varp); *varp = oldval; // When resetting some values, need to act on it. - if (did_chartab) { + if (restore_chartab) { (void)buf_init_chartab(buf, true); } } else { @@ -1875,6 +2153,16 @@ static const char *did_set_string_option_for(buf_T *buf, win_T *win, int opt_idx setmouse(); // in case 'mouse' changed } + if ((varp == &p_flp || varp == &(buf->b_p_flp)) + && win->w_briopt_list) { + // Changing Formatlistpattern when briopt includes the list setting: + // redraw + redraw_all_later(UPD_NOT_VALID); + } else if (varp == &p_wbr || varp == &(win->w_p_wbr)) { + // add / remove window bars for 'winbar' + set_winbar(true); + } + if (win->w_curswant != MAXCOL && (opt->flags & (P_CURSWANT | P_RALL)) != 0) { win->w_set_curswant = true; @@ -1885,11 +2173,11 @@ static const char *did_set_string_option_for(buf_T *buf, win_T *win, int opt_idx return errmsg; } -const char *did_set_string_option(int opt_idx, char **varp, char *oldval, char *errbuf, +const char *did_set_string_option(int opt_idx, char **varp, char *oldval, char *value, char *errbuf, size_t errbuflen, int opt_flags, int *value_checked) { - return did_set_string_option_for(curbuf, curwin, opt_idx, varp, oldval, errbuf, errbuflen, - opt_flags, value_checked); + return did_set_string_option_for(curbuf, curwin, opt_idx, varp, oldval, value, errbuf, + errbuflen, opt_flags, value_checked); } /// Check an option that can be a range of string values. @@ -1910,7 +2198,7 @@ static int check_opt_strings(char *val, char **values, int list) /// @param list when true: accept a list of values /// /// @return OK for correct value, FAIL otherwise. Empty is always OK. -static int opt_strings_flags(char *val, char **values, unsigned *flagp, bool list) +static int opt_strings_flags(const char *val, char **values, unsigned *flagp, bool list) { unsigned new_flags = 0; @@ -1946,9 +2234,8 @@ int check_ff_value(char *p) static char shm_buf[SHM_LEN]; static int set_shm_recursive = 0; -/// Save the acutal shortmess Flags and clear them -/// temporarily to avoid that file messages -/// overwrites any output from the following commands. +/// Save the actual shortmess Flags and clear them temporarily to avoid that +/// file messages overwrites any output from the following commands. /// /// Caller must make sure to first call save_clear_shm_value() and then /// restore_shm_value() exactly the same number of times. @@ -2012,16 +2299,17 @@ static int get_encoded_char_adv(const char **p) /// Handle setting 'listchars' or 'fillchars'. /// Assume monocell characters /// -/// @param varp either the global or the window-local value. +/// @param value points to either the global or the window-local value. +/// @param opt_lcs is tue for "listchars" and FALSE for "fillchars". /// @param apply if false, do not store the flags, only check for errors. /// @return error message, NULL if it's OK. -const char *set_chars_option(win_T *wp, char **varp, bool apply) +static const char *set_chars_option(win_T *wp, const char *value, bool opt_lcs, bool apply) { const char *last_multispace = NULL; // Last occurrence of "multispace:" const char *last_lmultispace = NULL; // Last occurrence of "leadmultispace:" int multispace_len = 0; // Length of lcs-multispace string int lead_multispace_len = 0; // Length of lcs-leadmultispace string - const bool is_listchars = (varp == &p_lcs || varp == &wp->w_p_lcs); + const bool is_listchars = opt_lcs; struct chars_tab { int *cp; ///< char value @@ -2065,17 +2353,16 @@ const char *set_chars_option(win_T *wp, char **varp, bool apply) struct chars_tab *tab; int entries; - const char *value = *varp; if (is_listchars) { tab = lcs_tab; entries = ARRAY_SIZE(lcs_tab); - if (varp == &wp->w_p_lcs && wp->w_p_lcs[0] == NUL) { + if (opt_lcs && wp->w_p_lcs[0] == NUL) { value = p_lcs; // local value is empty, use the global value } } else { tab = fcs_tab; entries = ARRAY_SIZE(fcs_tab); - if (varp == &wp->w_p_fcs && wp->w_p_fcs[0] == NUL) { + if (!opt_lcs && wp->w_p_fcs[0] == NUL) { value = p_fcs; // local value is empty, use the global value } } @@ -2241,17 +2528,17 @@ const char *set_chars_option(win_T *wp, char **varp, bool apply) /// @return an untranslated error message if any of them is invalid, NULL otherwise. const char *check_chars_options(void) { - if (set_chars_option(curwin, &p_lcs, false) != NULL) { + if (set_listchars_option(curwin, p_lcs, false) != NULL) { return e_conflicts_with_value_of_listchars; } - if (set_chars_option(curwin, &p_fcs, false) != NULL) { + if (set_fillchars_option(curwin, p_fcs, false) != NULL) { return e_conflicts_with_value_of_fillchars; } FOR_ALL_TAB_WINDOWS(tp, wp) { - if (set_chars_option(wp, &wp->w_p_lcs, true) != NULL) { + if (set_listchars_option(wp, wp->w_p_lcs, true) != NULL) { return e_conflicts_with_value_of_listchars; } - if (set_chars_option(wp, &wp->w_p_fcs, true) != NULL) { + if (set_fillchars_option(wp, wp->w_p_fcs, true) != NULL) { return e_conflicts_with_value_of_fillchars; } } diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c index 36714d816a..48a558197f 100644 --- a/src/nvim/quickfix.c +++ b/src/nvim/quickfix.c @@ -3885,11 +3885,12 @@ static buf_T *qf_find_buf(qf_info_T *qi) } /// Process the 'quickfixtextfunc' option value. -void qf_process_qftf_option(const char **errmsg) +const char *did_set_quickfixtextfunc(optset_T *args FUNC_ATTR_UNUSED) { if (option_set_callback_func(p_qftf, &qftf_cb) == FAIL) { - *errmsg = e_invarg; + return e_invarg; } + return NULL; } /// Update the w:quickfix_title variable in the quickfix/location list window in diff --git a/src/nvim/runtime.c b/src/nvim/runtime.c index 2d82ff1bba..b4a23d544e 100644 --- a/src/nvim/runtime.c +++ b/src/nvim/runtime.c @@ -780,9 +780,10 @@ RuntimeSearchPath runtime_search_path_build(void) return search_path; } -void runtime_search_path_invalidate(void) +const char *did_set_runtimepackpath(optset_T *args) { runtime_search_path_valid = false; + return NULL; } void runtime_search_path_free(RuntimeSearchPath path) diff --git a/src/nvim/spell.c b/src/nvim/spell.c index a571131ba1..0784c4c8ff 100644 --- a/src/nvim/spell.c +++ b/src/nvim/spell.c @@ -1851,7 +1851,7 @@ static int count_syllables(slang_T *slang, const char *word) /// Parse 'spelllang' and set w_s->b_langp accordingly. /// @return NULL if it's OK, an untranslated error message otherwise. -char *did_set_spelllang(win_T *wp) +char *parse_spelllang(win_T *wp) { garray_T ga; char *splp; @@ -2309,7 +2309,7 @@ void spell_reload(void) // window for this buffer in which 'spell' is set. if (*wp->w_s->b_p_spl != NUL) { if (wp->w_p_spell) { - (void)did_set_spelllang(wp); + (void)parse_spelllang(wp); break; } } @@ -3637,7 +3637,7 @@ const char *did_set_spell_option(bool is_spellfile) FOR_ALL_WINDOWS_IN_TAB(wp, curtab) { if (wp->w_buffer == curbuf && wp->w_p_spell) { - errmsg = did_set_spelllang(wp); + errmsg = parse_spelllang(wp); break; } } diff --git a/src/nvim/spellfile.c b/src/nvim/spellfile.c index d5d07df7b8..b93dd55042 100644 --- a/src/nvim/spellfile.c +++ b/src/nvim/spellfile.c @@ -1851,7 +1851,7 @@ static void spell_reload_one(char *fname, bool added_word) // When "zg" was used and the file wasn't loaded yet, should redo // 'spelllang' to load it now. if (added_word && !didit) { - did_set_spelllang(curwin); + parse_spelllang(curwin); } } diff --git a/src/nvim/spellsuggest.c b/src/nvim/spellsuggest.c index bde853fa20..84be88be7b 100644 --- a/src/nvim/spellsuggest.c +++ b/src/nvim/spellsuggest.c @@ -453,7 +453,7 @@ void spell_suggest(int count) const int wo_spell_save = curwin->w_p_spell; if (!curwin->w_p_spell) { - did_set_spelllang(curwin); + parse_spelllang(curwin); curwin->w_p_spell = true; } diff --git a/src/nvim/tag.c b/src/nvim/tag.c index 19c62e2b0e..2ee1a0335b 100644 --- a/src/nvim/tag.c +++ b/src/nvim/tag.c @@ -210,20 +210,23 @@ static Callback tfu_cb; // 'tagfunc' callback function /// Reads the 'tagfunc' option value and convert that to a callback value. /// Invoked when the 'tagfunc' option is set. The option value can be a name of /// a function (string), or function() or funcref() or a lambda. -void set_tagfunc_option(const char **errmsg) +const char *did_set_tagfunc(optset_T *args) { + buf_T *buf = (buf_T *)args->os_buf; + callback_free(&tfu_cb); - callback_free(&curbuf->b_tfu_cb); + callback_free(&buf->b_tfu_cb); - if (*curbuf->b_p_tfu == NUL) { - return; + if (*buf->b_p_tfu == NUL) { + return NULL; } - if (option_set_callback_func(curbuf->b_p_tfu, &tfu_cb) == FAIL) { - *errmsg = e_invarg; + if (option_set_callback_func(buf->b_p_tfu, &tfu_cb) == FAIL) { + return e_invarg; } - callback_copy(&curbuf->b_tfu_cb, &tfu_cb); + callback_copy(&buf->b_tfu_cb, &tfu_cb); + return NULL; } #if defined(EXITFREE) diff --git a/src/nvim/window.c b/src/nvim/window.c index 88d9b95208..2e037aa699 100644 --- a/src/nvim/window.c +++ b/src/nvim/window.c @@ -6089,7 +6089,7 @@ static void frame_setwidth(frame_T *curfrp, int width) } // Check 'winminheight' for a valid value and reduce it if needed. -void did_set_winminheight(void) +const char *did_set_winminheight(optset_T *args FUNC_ATTR_UNUSED) { bool first = true; @@ -6106,10 +6106,11 @@ void did_set_winminheight(void) first = false; } } + return NULL; } // Check 'winminwidth' for a valid value and reduce it if needed. -void did_set_winminwidth(void) +const char *did_set_winminwidth(optset_T *args FUNC_ATTR_UNUSED) { bool first = true; @@ -6126,6 +6127,7 @@ void did_set_winminwidth(void) first = false; } } + return NULL; } /// Status line of dragwin is dragged "offset" lines down (negative is up). diff --git a/test/old/testdir/test_options.vim b/test/old/testdir/test_options.vim index d18802adc1..769aa1c35f 100644 --- a/test/old/testdir/test_options.vim +++ b/test/old/testdir/test_options.vim @@ -45,6 +45,10 @@ func Test_isfname() set isfname= call assert_equal("~X", expand("~X")) set isfname& + " Test for setting 'isfname' to an unsupported character + let save_isfname = &isfname + call assert_fails('exe $"set isfname+={"\u1234"}"', 'E474:') + call assert_equal(save_isfname, &isfname) endfunc " Test for getting the value of 'pastetoggle' @@ -396,7 +400,16 @@ func Test_set_errors() if has('mouseshape') call assert_fails('se mouseshape=i-r:x', 'E547:') endif - call assert_fails('set backupext=~ patchmode=~', 'E589:') + + " Test for 'backupext' and 'patchmode' set to the same value + set backupext=.bak + set patchmode=.patch + call assert_fails('set patchmode=.bak', 'E589:') + call assert_equal('.patch', &patchmode) + call assert_fails('set backupext=.patch', 'E589:') + call assert_equal('.bak', &backupext) + set backupext& patchmode& + call assert_fails('set winminheight=10 winheight=9', 'E591:') call assert_fails('set winminwidth=10 winwidth=9', 'E592:') call assert_fails("set showbreak=\x01", 'E595:') @@ -1344,4 +1357,155 @@ func Test_set_min_lines_columns() let &columns = save_columns endfunc +" Test for reverting a string option value if the new value is invalid. +func Test_string_option_revert_on_failure() + new + let optlist = [ + \ ['ambiwidth', 'double', 'a123'], + \ ['background', 'dark', 'a123'], + \ ['backspace', 'eol', 'a123'], + \ ['backupcopy', 'no', 'a123'], + \ ['belloff', 'showmatch', 'a123'], + \ ['breakindentopt', 'min:10', 'list'], + \ ['bufhidden', 'wipe', 'a123'], + \ ['buftype', 'nowrite', 'a123'], + \ ['casemap', 'keepascii', 'a123'], + \ ['cedit', "\", 'z'], + \ ['colorcolumn', '10', 'z'], + \ ['commentstring', '#%s', 'a123'], + \ ['complete', '.,t', 'a'], + \ ['completefunc', 'MyCmplFunc', '1a-'], + "\ ['completeopt', 'popup', 'a123'], + \ ['completeopt', 'preview', 'a123'], + "\ ['completepopup', 'width:20', 'border'], + \ ['concealcursor', 'v', 'xyz'], + "\ ['cpoptions', 'HJ', '~'], + \ ['cpoptions', 'J', '~'], + "\ ['cryptmethod', 'zip', 'a123'], + \ ['cursorlineopt', 'screenline', 'a123'], + \ ['debug', 'throw', 'a123'], + \ ['diffopt', 'iwhite', 'a123'], + \ ['display', 'uhex', 'a123'], + \ ['eadirection', 'hor', 'a123'], + \ ['encoding', 'utf-8', 'a123'], + \ ['eventignore', 'TextYankPost', 'a123'], + \ ['fileencoding', 'utf-8', 'a123,'], + \ ['fileformat', 'mac', 'a123'], + \ ['fileformats', 'mac', 'a123'], + \ ['filetype', 'abc', 'a^b'], + \ ['fillchars', 'diff:~', 'a123'], + \ ['foldclose', 'all', 'a123'], + \ ['foldmarker', '[[[,]]]', '[[['], + \ ['foldmethod', 'marker', 'a123'], + \ ['foldopen', 'percent', 'a123'], + \ ['formatoptions', 'an', '*'], + \ ['guicursor', 'n-v-c:block-Cursor/lCursor', 'n-v-c'], + \ ['helplang', 'en', 'a'], + "\ ['highlight', '!:CursorColumn', '8:'], + \ ['keymodel', 'stopsel', 'a123'], + "\ ['keyprotocol', 'kitty:kitty', 'kitty:'], + \ ['lispoptions', 'expr:1', 'a123'], + \ ['listchars', 'tab:->', 'tab:'], + \ ['matchpairs', '<:>', '<:'], + \ ['mkspellmem', '100000,1000,100', '100000'], + \ ['mouse', 'nvi', 'z'], + \ ['mousemodel', 'extend', 'a123'], + \ ['nrformats', 'alpha', 'a123'], + \ ['omnifunc', 'MyOmniFunc', '1a-'], + \ ['operatorfunc', 'MyOpFunc', '1a-'], + "\ ['previewpopup', 'width:20', 'a123'], + "\ ['printoptions', 'paper:A4', 'a123:'], + \ ['quickfixtextfunc', 'MyQfFunc', '1a-'], + \ ['rulerformat', '%l', '%['], + \ ['scrollopt', 'hor,jump', 'a123'], + \ ['selection', 'exclusive', 'a123'], + \ ['selectmode', 'cmd', 'a123'], + \ ['sessionoptions', 'options', 'a123'], + \ ['shortmess', 'w', '2'], + \ ['showbreak', '>>', "\x01"], + \ ['showcmdloc', 'statusline', 'a123'], + \ ['signcolumn', 'no', 'a123'], + \ ['spellcapcheck', '[.?!]\+', '%\{'], + \ ['spellfile', 'MySpell.en.add', "\x01"], + \ ['spelllang', 'en', "#"], + \ ['spelloptions', 'camel', 'a123'], + \ ['spellsuggest', 'double', 'a123'], + \ ['splitkeep', 'topline', 'a123'], + \ ['statusline', '%f', '%['], + "\ ['swapsync', 'sync', 'a123'], + \ ['switchbuf', 'usetab', 'a123'], + \ ['syntax', 'abc', 'a^b'], + \ ['tabline', '%f', '%['], + \ ['tagcase', 'ignore', 'a123'], + \ ['tagfunc', 'MyTagFunc', '1a-'], + \ ['thesaurusfunc', 'MyThesaurusFunc', '1a-'], + \ ['viewoptions', 'options', 'a123'], + \ ['virtualedit', 'onemore', 'a123'], + \ ['whichwrap', '<,>', '{,}'], + \ ['wildmode', 'list', 'a123'], + \ ['wildoptions', 'pum', 'a123'] + \ ] + if has('gui') + call add(optlist, ['browsedir', 'buffer', 'a123']) + endif + if has('clipboard_working') + call add(optlist, ['clipboard', 'unnamed', 'a123']) + endif + if has('win32') + call add(optlist, ['completeslash', 'slash', 'a123']) + endif + if has('cscope') + call add(optlist, ['cscopequickfix', 't-', 'z-']) + endif + if !has('win32') && !has('nvim') + call add(optlist, ['imactivatefunc', 'MyActFunc', '1a-']) + call add(optlist, ['imstatusfunc', 'MyStatusFunc', '1a-']) + endif + if has('keymap') + call add(optlist, ['keymap', 'greek', '[]']) + endif + if has('mouseshape') + call add(optlist, ['mouseshape', 'm:no', 'a123:']) + endif + if has('win32') && has('gui') + call add(optlist, ['renderoptions', 'type:directx', 'type:directx,a123']) + endif + if has('rightleft') + call add(optlist, ['rightleftcmd', 'search', 'a123']) + endif + if has('terminal') + call add(optlist, ['termwinkey', '', 'string()}") + endtry + call assert_fails($"let &{opt[0]} = '{opt[2]}'", '', opt[0]) + call assert_equal(opt[1], eval($"&{opt[0]}"), opt[0]) + exe $"let &{opt[0]} = save_opt" + endfor + bw! +endfunc + " vim: shiftwidth=2 sts=2 expandtab