From 960170e4469b96c5c3d06ba1bb84c9edeaa04b8b Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sat, 30 Sep 2023 19:36:33 +0800 Subject: vim-patch:9.0.1366: functions for setting options are in random order (#25440) Problem: Functions for setting options are in random order. Solution: Sort functions alphabetically. (Yegappan Lakshmanan, closes vim/vim#12082) https://github.com/vim/vim/commit/ad60898aa47b44fdece12d28c471fb50df27fb50 Co-authored-by: Yegappan Lakshmanan --- src/nvim/option.c | 1160 ++++++++++++++++++++++++++--------------------------- 1 file changed, 580 insertions(+), 580 deletions(-) (limited to 'src/nvim/option.c') diff --git a/src/nvim/option.c b/src/nvim/option.c index 7e7e387521..eef5e66aeb 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -2037,74 +2037,149 @@ static const char *did_set_force_off(bool *doskip) return NULL; } -/// Process the updated 'langremap' option value. -static const char *did_set_langremap(optset_T *args FUNC_ATTR_UNUSED) +/// Process the updated 'arabic' option value. +static const char *did_set_arabic(optset_T *args) { - // 'langremap' -> !'langnoremap' - p_lnr = !p_lrm; + win_T *win = (win_T *)args->os_win; + const char *errmsg = NULL; + + if (win->w_p_arab) { + // 'arabic' is set, handle various sub-settings. + if (!p_tbidi) { + // set rightleft mode + if (!win->w_p_rl) { + win->w_p_rl = true; + changed_window_setting(); + } + + // Enable Arabic shaping (major part of what Arabic requires) + if (!p_arshape) { + p_arshape = true; + redraw_all_later(UPD_NOT_VALID); + } + } + + // Arabic requires a utf-8 encoding, inform the user if it's not + // set. + if (strcmp(p_enc, "utf-8") != 0) { + static char *w_arabic = N_("W17: Arabic requires UTF-8, do ':set encoding=utf-8'"); + + msg_source(HL_ATTR(HLF_W)); + msg(_(w_arabic), HL_ATTR(HLF_W)); + set_vim_var_string(VV_WARNINGMSG, _(w_arabic), -1); + } + + // set 'delcombine' + p_deco = true; + + // Force-set the necessary keymap for arabic. + errmsg = set_option_value("keymap", STATIC_CSTR_AS_OPTVAL("arabic"), OPT_LOCAL); + } else { + // 'arabic' is reset, handle various sub-settings. + if (!p_tbidi) { + // reset rightleft mode + if (win->w_p_rl) { + win->w_p_rl = false; + changed_window_setting(); + } + + // 'arabicshape' isn't reset, it is a global option and + // another window may still need it "on". + } + + // 'delcombine' isn't reset, it is a global option and another + // window may still want it "on". + + // Revert to the default keymap + curbuf->b_p_iminsert = B_IMODE_NONE; + curbuf->b_p_imsearch = B_IMODE_USE_INSERT; + } + + return errmsg; +} + +/// Process the updated 'autochdir' option value. +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 'langnoremap' option value. -static const char *did_set_langnoremap(optset_T *args FUNC_ATTR_UNUSED) +/// Process the updated 'binary' option value. +static const char *did_set_binary(optset_T *args) { - // 'langnoremap' -> !'langremap' - p_lrm = !p_lnr; + buf_T *buf = (buf_T *)args->os_buf; + + // when 'bin' is set also set some other options + set_options_bin((int)args->os_oldval.boolean, buf->b_p_bin, args->os_flags); + redraw_titles(); + return NULL; } -/// Process the updated 'undofile' option value. -static const char *did_set_undofile(optset_T *args) +/// Called when the 'breakat' option changes value. +static const char *did_set_breakat(optset_T *args FUNC_ATTR_UNUSED) { - // Only take action when the option was set. - if (!curbuf->b_p_udf && !p_udf) { - return NULL; + for (int i = 0; i < 256; i++) { + breakat_flags[i] = false; } - // When reset we do not delete the undo file, the option may be set again - // without making any changes in between. - uint8_t hash[UNDO_HASH_SIZE]; - - FOR_ALL_BUFFERS(bp) { - // When 'undofile' is set globally: for every buffer, otherwise - // only for the current buffer: Try to read in the undofile, - // if one exists, the buffer wasn't changed and the buffer was - // loaded - if ((curbuf == bp - || (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); + if (p_breakat != NULL) { + for (char *p = p_breakat; *p; p++) { + breakat_flags[(uint8_t)(*p)] = true; } } return NULL; } -/// Process the updated 'readonly' option value. -static const char *did_set_readonly(optset_T *args) +/// Process the updated 'buflisted' option value. +static const char *did_set_buflisted(optset_T *args) { - // when 'readonly' is reset globally, also reset readonlymode - if (!curbuf->b_p_ro && (args->os_flags & OPT_LOCAL) == 0) { - readonlymode = false; + buf_T *buf = (buf_T *)args->os_buf; + + // when 'buflisted' changes, trigger autocommands + 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; +} - // when 'readonly' is set may give W10 again - if (curbuf->b_p_ro) { - curbuf->b_did_warn = false; +/// Process the new 'cmdheight' option value. +static const char *did_set_cmdheight(optset_T *args) +{ + OptInt old_value = args->os_oldval.number; + + if (ui_has(kUIMessages)) { + p_ch = 0; + } + if (p_ch > Rows - min_rows() + 1) { + p_ch = Rows - min_rows() + 1; } - redraw_titles(); + // if p_ch changed value, change the command line height + // Only compute the new window layout when startup has been + // completed. Otherwise the frame sizes may be wrong. + if ((p_ch != old_value + || tabline_height() + global_stl_height() + topframe->fr_height != Rows - p_ch) + && full_screen) { + command_height(); + } return NULL; } -/// Process the updated 'modifiable' option value. -static const char *did_set_modifiable(optset_T *args FUNC_ATTR_UNUSED) +/// Process the updated 'diff' option value. +static const char *did_set_diff(optset_T *args) { - // when 'modifiable' is changed, redraw the window title - redraw_titles(); - + win_T *win = (win_T *)args->os_win; + // May add or remove the buffer from the list of diff buffers. + diff_buf_adjust(win); + if (foldmethodIsDiff(win)) { + foldUpdateAll(win); + } return NULL; } @@ -2117,76 +2192,205 @@ static const char *did_set_eof_eol_fixeol_bomb(optset_T *args FUNC_ATTR_UNUSED) return NULL; } -/// Process the updated 'binary' option value. -static const char *did_set_binary(optset_T *args) +/// Process the updated 'equalalways' option value. +static const char *did_set_equalalways(optset_T *args) { - buf_T *buf = (buf_T *)args->os_buf; + win_T *win = (win_T *)args->os_win; + if (p_ea && !args->os_oldval.boolean) { + win_equal(win, false, 0); + } - // when 'bin' is set also set some other options - set_options_bin((int)args->os_oldval.boolean, buf->b_p_bin, args->os_flags); - redraw_titles(); + return NULL; +} +/// Process the new 'foldlevel' option value. +static const char *did_set_foldlevel(optset_T *args FUNC_ATTR_UNUSED) +{ + newFoldLevel(); return NULL; } -/// Process the updated 'buflisted' option value. -static const char *did_set_buflisted(optset_T *args) +/// Process the new 'foldminlines' option value. +static const char *did_set_foldminlines(optset_T *args) { - buf_T *buf = (buf_T *)args->os_buf; + win_T *win = (win_T *)args->os_win; + foldUpdateAll(win); + return NULL; +} - // when 'buflisted' changes, trigger autocommands - if (args->os_oldval.boolean != buf->b_p_bl) { - apply_autocmds(buf->b_p_bl ? EVENT_BUFADD : EVENT_BUFDELETE, - NULL, NULL, true, buf); +/// Process the new 'foldnestmax' option value. +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 updated 'swapfile' option value. -static const char *did_set_swapfile(optset_T *args) +/// Process the new 'helpheight' option value. +static const char *did_set_helpheight(optset_T *args) { - buf_T *buf = (buf_T *)args->os_buf; - // when 'swf' is set, create swapfile, when reset remove swapfile - 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(buf, true); // remove the swap file + // Change window height NOW + if (!ONE_WINDOW) { + 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 updated 'paste' option value. -static const char *did_set_paste(optset_T *args FUNC_ATTR_UNUSED) +/// Process the updated 'hlsearch' option value. +static const char *did_set_hlsearch(optset_T *args FUNC_ATTR_UNUSED) { - static int old_p_paste = false; - static int save_sm = 0; - static int save_sta = 0; - static int save_ru = 0; - static int save_ri = 0; + // when 'hlsearch' is set or reset: reset no_hlsearch + set_no_hlsearch(false); + return NULL; +} - if (p_paste) { - // Paste switched from off to on. - // Save the current values, so they can be restored later. - if (!old_p_paste) { - // save options for each buffer - FOR_ALL_BUFFERS(buf) { - buf->b_p_tw_nopaste = buf->b_p_tw; - buf->b_p_wm_nopaste = buf->b_p_wm; - buf->b_p_sts_nopaste = buf->b_p_sts; - buf->b_p_ai_nopaste = buf->b_p_ai; - buf->b_p_et_nopaste = buf->b_p_et; - if (buf->b_p_vsts_nopaste) { - xfree(buf->b_p_vsts_nopaste); - } - buf->b_p_vsts_nopaste = buf->b_p_vsts && buf->b_p_vsts != empty_option - ? xstrdup(buf->b_p_vsts) - : NULL; - } +/// Process the updated 'ignorecase' option value. +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; +} - // save global options - save_sm = p_sm; +/// Process the new 'iminset' option value. +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 updated 'langnoremap' option value. +static const char *did_set_langnoremap(optset_T *args FUNC_ATTR_UNUSED) +{ + // 'langnoremap' -> !'langremap' + p_lrm = !p_lnr; + return NULL; +} + +/// Process the updated 'langremap' option value. +static const char *did_set_langremap(optset_T *args FUNC_ATTR_UNUSED) +{ + // 'langremap' -> !'langnoremap' + p_lnr = !p_lrm; + return NULL; +} + +/// Process the new 'laststatus' option value. +static const char *did_set_laststatus(optset_T *args) +{ + OptInt old_value = args->os_oldval.number; + OptInt 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) { + frame_new_height(topframe, topframe->fr_height - STATUS_HEIGHT, false, false); + (void)win_comp_pos(); + clear_cmdline = true; + } + // When switching from global statusline, increase height of topframe by STATUS_HEIGHT + // in order to to re-add the space that was previously taken by the global statusline + if (old_value == 3 && value != 3) { + frame_new_height(topframe, topframe->fr_height + STATUS_HEIGHT, false, false); + (void)win_comp_pos(); + } + + last_status(false); // (re)set last window status line. + return NULL; +} + +/// Process the updated 'lisp' option value. +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(buf, false); // ignore errors + return NULL; +} + +/// Process the updated 'modifiable' option value. +static const char *did_set_modifiable(optset_T *args FUNC_ATTR_UNUSED) +{ + // when 'modifiable' is changed, redraw the window title + redraw_titles(); + + return NULL; +} + +/// Process the updated 'modified' option value. +static const char *did_set_modified(optset_T *args) +{ + 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)args->os_newval.boolean; + return NULL; +} + +/// Process the updated 'number' or 'relativenumber' option value. +static const char *did_set_number_relativenumber(optset_T *args) +{ + 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. + win->w_nrwidth_line_count = 0; + } + return NULL; +} + +/// Process the new 'numberwidth' option value. +static const char *did_set_numberwidth(optset_T *args) +{ + win_T *win = (win_T *)args->os_win; + win->w_nrwidth_line_count = 0; // trigger a redraw + + return NULL; +} + +/// Process the updated 'paste' option value. +static const char *did_set_paste(optset_T *args FUNC_ATTR_UNUSED) +{ + static int old_p_paste = false; + static int save_sm = 0; + static int save_sta = 0; + static int save_ru = 0; + static int save_ri = 0; + + if (p_paste) { + // Paste switched from off to on. + // Save the current values, so they can be restored later. + if (!old_p_paste) { + // save options for each buffer + FOR_ALL_BUFFERS(buf) { + buf->b_p_tw_nopaste = buf->b_p_tw; + buf->b_p_wm_nopaste = buf->b_p_wm; + buf->b_p_sts_nopaste = buf->b_p_sts; + buf->b_p_ai_nopaste = buf->b_p_ai; + buf->b_p_et_nopaste = buf->b_p_et; + if (buf->b_p_vsts_nopaste) { + xfree(buf->b_p_vsts_nopaste); + } + buf->b_p_vsts_nopaste = buf->b_p_vsts && buf->b_p_vsts != empty_option + ? xstrdup(buf->b_p_vsts) + : NULL; + } + + // save global options + save_sm = p_sm; save_sta = p_sta; save_ru = p_ru; save_ri = p_ri; @@ -2273,400 +2477,138 @@ static const char *did_set_paste(optset_T *args FUNC_ATTR_UNUSED) p_tw = p_tw_nopaste; p_wm = p_wm_nopaste; if (p_vsts) { - free_string_option(p_vsts); - } - p_vsts = p_vsts_nopaste ? xstrdup(p_vsts_nopaste) : empty_option; - } - - old_p_paste = p_paste; - - // Remember where the dependent options were reset - didset_options_sctx((OPT_LOCAL | OPT_GLOBAL), p_paste_dep_opts); - - return NULL; -} - -/// Process the updated 'ignorecase' option value. -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 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 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 (!win->w_p_scb) { - return NULL; - } - do_check_scrollbind(false); - win->w_scbind_pos = win->w_topline; - return NULL; -} - -/// Process the updated 'previewwindow' option value. -static const char *did_set_previewwindow(optset_T *args) -{ - 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(wp, curtab) { - if (wp->w_p_pvw && wp != win) { - win->w_p_pvw = false; - args->os_doskip = true; - return e_preview_window_already_exists; - } - } - - return NULL; -} - -/// Process the updated 'lisp' option value. -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(buf, false); // ignore errors - return NULL; -} - -/// Process the updated 'title' or the 'icon' option value. -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 const char *did_set_modified(optset_T *args) -{ - 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)args->os_newval.boolean; - return NULL; -} - -#ifdef BACKSLASH_IN_FILENAME -/// Process the updated 'shellslash' option value. -static const char *did_set_shellslash(optset_T *args FUNC_ATTR_UNUSED) -{ - if (p_ssl) { - psepc = '/'; - psepcN = '\\'; - pseps[0] = '/'; - } else { - psepc = '\\'; - psepcN = '/'; - pseps[0] = '\\'; - } - - // need to adjust the file name arguments and buffer names. - buflist_slash_adjust(); - alist_slash_adjust(); - scriptnames_slash_adjust(); - return NULL; -} -#endif - -/// Process the updated 'wrap' option value. -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 (win->w_p_wrap) { - win->w_leftcol = 0; - } - return NULL; -} - -/// Process the updated 'equalalways' option value. -static const char *did_set_equalalways(optset_T *args) -{ - 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 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 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(win); - if (foldmethodIsDiff(win)) { - foldUpdateAll(win); - } - return NULL; -} - -/// Process the updated 'spell' option value. -static const char *did_set_spell(optset_T *args) -{ - 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(optset_T *args) -{ - win_T *win = (win_T *)args->os_win; - const char *errmsg = NULL; - - if (win->w_p_arab) { - // 'arabic' is set, handle various sub-settings. - if (!p_tbidi) { - // set rightleft mode - if (!win->w_p_rl) { - win->w_p_rl = true; - changed_window_setting(); - } - - // Enable Arabic shaping (major part of what Arabic requires) - if (!p_arshape) { - p_arshape = true; - redraw_all_later(UPD_NOT_VALID); - } - } - - // Arabic requires a utf-8 encoding, inform the user if it's not - // set. - if (strcmp(p_enc, "utf-8") != 0) { - static char *w_arabic = N_("W17: Arabic requires UTF-8, do ':set encoding=utf-8'"); - - msg_source(HL_ATTR(HLF_W)); - msg(_(w_arabic), HL_ATTR(HLF_W)); - set_vim_var_string(VV_WARNINGMSG, _(w_arabic), -1); - } - - // set 'delcombine' - p_deco = true; - - // Force-set the necessary keymap for arabic. - errmsg = set_option_value("keymap", STATIC_CSTR_AS_OPTVAL("arabic"), OPT_LOCAL); - } else { - // 'arabic' is reset, handle various sub-settings. - if (!p_tbidi) { - // reset rightleft mode - if (win->w_p_rl) { - win->w_p_rl = false; - changed_window_setting(); - } - - // 'arabicshape' isn't reset, it is a global option and - // another window may still need it "on". - } - - // 'delcombine' isn't reset, it is a global option and another - // window may still want it "on". - - // Revert to the default keymap - curbuf->b_p_iminsert = B_IMODE_NONE; - curbuf->b_p_imsearch = B_IMODE_USE_INSERT; - } - - return errmsg; -} - -/// Process the updated 'number' or 'relativenumber' option value. -static const char *did_set_number_relativenumber(optset_T *args) -{ - 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. - win->w_nrwidth_line_count = 0; - } - return NULL; -} - -/// Set the value of a boolean option, taking care of side effects -/// -/// @param[in] opt_idx Option index in options[] table. -/// @param[out] varp Pointer to the option variable. -/// @param[in] value New value. -/// @param[in] opt_flags OPT_LOCAL and/or OPT_GLOBAL. -/// -/// @return NULL on success, error message on error. -static const char *set_bool_option(const int opt_idx, char *const varp, const int value, - const int opt_flags) -{ - int old_value = *(int *)varp; - int old_global_value = 0; - - // Disallow changing some options from secure mode - if ((secure || sandbox != 0) - && (options[opt_idx].flags & P_SECURE)) { - return e_secure; + free_string_option(p_vsts); + } + p_vsts = p_vsts_nopaste ? xstrdup(p_vsts_nopaste) : empty_option; } - // Save the global value before changing anything. This is needed as for - // a global-only option setting the "local value" in fact sets the global - // value (since there is only one value). - if ((opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0) { - old_global_value = *(int *)get_varp_scope(&(options[opt_idx]), OPT_GLOBAL); - } + old_p_paste = p_paste; - *(int *)varp = value; // set the new value - // Remember where the option was set. - set_option_sctx_idx(opt_idx, opt_flags, current_sctx); + // Remember where the dependent options were reset + didset_options_sctx((OPT_LOCAL | OPT_GLOBAL), p_paste_dep_opts); - // May set global value for local option. - if ((opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0) { - *(int *)get_varp_scope(&(options[opt_idx]), OPT_GLOBAL) = value; - } + return NULL; +} - // Handle side effects for changing a bool option. - const char *errmsg = NULL; - bool doskip = false; - 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 - }; +/// Process the updated 'previewwindow' option value. +static const char *did_set_previewwindow(optset_T *args) +{ + win_T *win = (win_T *)args->os_win; - errmsg = options[opt_idx].opt_did_set_cb(&args); - doskip = args.os_doskip; - } - if (doskip) { - return errmsg; + if (!win->w_p_pvw) { + return NULL; } - // after handling side effects, call autocommand - - options[opt_idx].flags |= P_WAS_SET; + // There can be only one window with 'previewwindow' set. + 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; + } + } - apply_optionset_autocmd(opt_idx, opt_flags, - (long)(old_value ? true : false), - (long)(old_global_value ? true : false), - (long)(value ? true : false), NULL); + return NULL; +} - if (options[opt_idx].flags & P_UI_OPTION) { - ui_call_option_set(cstr_as_string(options[opt_idx].fullname), - BOOLEAN_OBJ(*varp)); - } - if ((int *)varp == &p_ru || (int *)varp == &p_sc) { - // in case 'ruler' or 'showcmd' changed - comp_col(); - } - if (curwin->w_curswant != MAXCOL - && (options[opt_idx].flags & (P_CURSWANT | P_RALL)) != 0) { - curwin->w_set_curswant = true; +/// Process the new 'pumblend' option value. +static const char *did_set_pumblend(optset_T *args FUNC_ATTR_UNUSED) +{ + p_pb = MAX(MIN(p_pb, 100), 0); + hl_invalidate_blends(); + pum_grid.blending = (p_pb > 0); + if (pum_drawn()) { + pum_redraw(); } - check_redraw(options[opt_idx].flags); - return errmsg; + return NULL; } -/// Process the new 'winheight' value. -static const char *did_set_winheight(optset_T *args) +/// Process the updated 'readonly' option value. +static const char *did_set_readonly(optset_T *args) { - // Change window height NOW - if (!ONE_WINDOW) { - win_T *win = (win_T *)args->os_win; - if (win->w_height < p_wh) { - win_setheight((int)p_wh); - } + // when 'readonly' is reset globally, also reset readonlymode + if (!curbuf->b_p_ro && (args->os_flags & OPT_LOCAL) == 0) { + readonlymode = false; + } + + // when 'readonly' is set may give W10 again + if (curbuf->b_p_ro) { + curbuf->b_did_warn = false; } + redraw_titles(); + return NULL; } -/// Process the new 'helpheight' option value. -static const char *did_set_helpheight(optset_T *args) +/// Process the new 'scrollback' option value. +static const char *did_set_scrollback(optset_T *args) { - // Change window height NOW - if (!ONE_WINDOW) { - 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); - } - } + buf_T *buf = (buf_T *)args->os_buf; + OptInt old_value = args->os_oldval.number; + OptInt 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 'winwidth' option value. -static const char *did_set_winwidth(optset_T *args) +/// Process the updated 'scrollbind' option value. +static const char *did_set_scrollbind(optset_T *args) { win_T *win = (win_T *)args->os_win; - if (!ONE_WINDOW && win->w_width < p_wiw) { - win_setwidth((int)p_wiw); + // when 'scrollbind' is set: snapshot the current position to avoid a jump + // at the end of normal_cmd() + if (!win->w_p_scb) { + return NULL; } + do_check_scrollbind(false); + win->w_scbind_pos = win->w_topline; return NULL; } -/// Process the new 'laststatus' option value. -static const char *did_set_laststatus(optset_T *args) +#ifdef BACKSLASH_IN_FILENAME +/// Process the updated 'shellslash' option value. +static const char *did_set_shellslash(optset_T *args FUNC_ATTR_UNUSED) { - OptInt old_value = args->os_oldval.number; - OptInt value = args->os_newval.number; + if (p_ssl) { + psepc = '/'; + psepcN = '\\'; + pseps[0] = '/'; + } else { + psepc = '\\'; + psepcN = '/'; + pseps[0] = '\\'; + } - // 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) { - frame_new_height(topframe, topframe->fr_height - STATUS_HEIGHT, false, false); - (void)win_comp_pos(); - clear_cmdline = true; + // need to adjust the file name arguments and buffer names. + buflist_slash_adjust(); + alist_slash_adjust(); + scriptnames_slash_adjust(); + return NULL; +} +#endif + +/// Process the new 'shiftwidth' or the 'tabstop' option value. +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; + OptInt *pp = (OptInt *)args->os_varp; + + if (foldmethodIsIndent(win)) { + foldUpdateAll(win); } - // When switching from global statusline, increase height of topframe by STATUS_HEIGHT - // in order to to re-add the space that was previously taken by the global statusline - if (old_value == 3 && value != 3) { - frame_new_height(topframe, topframe->fr_height + STATUS_HEIGHT, false, false); - (void)win_comp_pos(); + // When 'shiftwidth' changes, or it's zero and 'tabstop' changes: + // parse 'cinoptions'. + if (pp == &buf->b_p_sw || buf->b_p_sw == 0) { + parse_cino(buf); } - last_status(false); // (re)set last window status line. return NULL; } @@ -2691,68 +2633,47 @@ static const char *did_set_smoothscroll(optset_T *args FUNC_ATTR_UNUSED) return NULL; } -/// Process the new 'foldlevel' option value. -static const char *did_set_foldlevel(optset_T *args FUNC_ATTR_UNUSED) -{ - newFoldLevel(); - return NULL; -} - -/// Process the new 'foldminlines' option value. -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 const char *did_set_foldnestmax(optset_T *args) +/// Process the updated 'spell' option value. +static const char *did_set_spell(optset_T *args) { win_T *win = (win_T *)args->os_win; - if (foldmethodIsSyntax(win) || foldmethodIsIndent(win)) { - foldUpdateAll(win); + if (win->w_p_spell) { + return parse_spelllang(win); } + return NULL; } -/// Process the new 'shiftwidth' or the 'tabstop' option value. -static const char *did_set_shiftwidth_tabstop(optset_T *args) +/// Process the updated 'swapfile' option value. +static const char *did_set_swapfile(optset_T *args) { buf_T *buf = (buf_T *)args->os_buf; - win_T *win = (win_T *)args->os_win; - OptInt *pp = (OptInt *)args->os_varp; - - if (foldmethodIsIndent(win)) { - foldUpdateAll(win); - } - // When 'shiftwidth' changes, or it's zero and 'tabstop' changes: - // parse 'cinoptions'. - if (pp == &buf->b_p_sw || buf->b_p_sw == 0) { - parse_cino(buf); + // when 'swf' is set, create swapfile, when reset remove swapfile + 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(buf, true); // remove the swap file } - - return NULL; -} - -/// Process the new 'iminset' option value. -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 const char *did_set_window(optset_T *args FUNC_ATTR_UNUSED) +/// Process the new 'textwidth' option value. +static const char *did_set_textwidth(optset_T *args FUNC_ATTR_UNUSED) { - if (p_window < 1) { - p_window = Rows - 1; - } else if (p_window >= Rows) { - p_window = Rows - 1; + FOR_ALL_TAB_WINDOWS(tp, wp) { + check_colorcolumn(wp); } + + return NULL; +} + +/// Process the updated 'title' or the 'icon' option value. +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; } @@ -2769,51 +2690,29 @@ static const char *did_set_titlelen(optset_T *args) return NULL; } -/// Process the new 'cmdheight' option value. -static const char *did_set_cmdheight(optset_T *args) -{ - OptInt old_value = args->os_oldval.number; - - if (ui_has(kUIMessages)) { - p_ch = 0; - } - if (p_ch > Rows - min_rows() + 1) { - p_ch = Rows - min_rows() + 1; - } - - // if p_ch changed value, change the command line height - // Only compute the new window layout when startup has been - // completed. Otherwise the frame sizes may be wrong. - if ((p_ch != old_value - || tabline_height() + global_stl_height() + topframe->fr_height != Rows - p_ch) - && full_screen) { - command_height(); - } - - return NULL; -} - -/// Process the new 'updatecount' option value. -static const char *did_set_updatecount(optset_T *args) +/// Process the updated 'undofile' option value. +static const char *did_set_undofile(optset_T *args) { - OptInt 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(); + // Only take action when the option was set. + if (!curbuf->b_p_udf && !p_udf) { + return NULL; } - return NULL; -} + // When reset we do not delete the undo file, the option may be set again + // without making any changes in between. + uint8_t hash[UNDO_HASH_SIZE]; -/// Process the new 'pumblend' option value. -static const char *did_set_pumblend(optset_T *args FUNC_ATTR_UNUSED) -{ - p_pb = MAX(MIN(p_pb, 100), 0); - hl_invalidate_blends(); - pum_grid.blending = (p_pb > 0); - if (pum_drawn()) { - pum_redraw(); + FOR_ALL_BUFFERS(bp) { + // When 'undofile' is set globally: for every buffer, otherwise + // only for the current buffer: Try to read in the undofile, + // if one exists, the buffer wasn't changed and the buffer was + // loaded + if ((curbuf == bp + || (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; @@ -2840,34 +2739,29 @@ const char *did_set_buflocal_undolevels(buf_T *buf, OptInt value, OptInt old_val return NULL; } -/// Process the new 'scrollback' option value. -static const char *did_set_scrollback(optset_T *args) +/// Process the new 'undolevels' option value. +static const char *did_set_undolevels(optset_T *args) { buf_T *buf = (buf_T *)args->os_buf; - OptInt old_value = args->os_oldval.number; - OptInt value = args->os_newval.number; + OptInt *pp = (OptInt *)args->os_varp; - if (buf->terminal && value < old_value) { - // Force the scrollback to take immediate effect only when decreasing it. - on_scrollback_option_changed(buf->terminal); + 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 NULL; -} - -/// Process the new 'numberwidth' option value. -static const char *did_set_numberwidth(optset_T *args) -{ - 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 const char *did_set_textwidth(optset_T *args FUNC_ATTR_UNUSED) +/// Process the new 'updatecount' option value. +static const char *did_set_updatecount(optset_T *args) { - FOR_ALL_TAB_WINDOWS(tp, wp) { - check_colorcolumn(wp); + OptInt 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; @@ -2889,21 +2783,143 @@ static const char *did_set_winblend(optset_T *args) return NULL; } -/// Process the new 'undolevels' option value. -static const char *did_set_undolevels(optset_T *args) +/// Process the new 'window' option value. +static const char *did_set_window(optset_T *args FUNC_ATTR_UNUSED) { - buf_T *buf = (buf_T *)args->os_buf; - OptInt *pp = (OptInt *)args->os_varp; + if (p_window < 1) { + p_window = Rows - 1; + } else if (p_window >= Rows) { + p_window = Rows - 1; + } + return NULL; +} - 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); +/// Process the new 'winheight' value. +static const char *did_set_winheight(optset_T *args) +{ + // Change window height NOW + if (!ONE_WINDOW) { + win_T *win = (win_T *)args->os_win; + if (win->w_height < p_wh) { + win_setheight((int)p_wh); + } } return NULL; } +/// Process the new 'winwidth' option value. +static const char *did_set_winwidth(optset_T *args) +{ + 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 updated 'wrap' option value. +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 (win->w_p_wrap) { + win->w_leftcol = 0; + } + return NULL; +} + +/// Set the value of a boolean option, taking care of side effects +/// +/// @param[in] opt_idx Option index in options[] table. +/// @param[out] varp Pointer to the option variable. +/// @param[in] value New value. +/// @param[in] opt_flags OPT_LOCAL and/or OPT_GLOBAL. +/// +/// @return NULL on success, error message on error. +static const char *set_bool_option(const int opt_idx, char *const varp, const int value, + const int opt_flags) +{ + int old_value = *(int *)varp; + int old_global_value = 0; + + // Disallow changing some options from secure mode + if ((secure || sandbox != 0) + && (options[opt_idx].flags & P_SECURE)) { + return e_secure; + } + + // Save the global value before changing anything. This is needed as for + // a global-only option setting the "local value" in fact sets the global + // value (since there is only one value). + if ((opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0) { + old_global_value = *(int *)get_varp_scope(&(options[opt_idx]), OPT_GLOBAL); + } + + *(int *)varp = value; // set the new value + // Remember where the option was set. + set_option_sctx_idx(opt_idx, opt_flags, current_sctx); + + // May set global value for local option. + if ((opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0) { + *(int *)get_varp_scope(&(options[opt_idx]), OPT_GLOBAL) = value; + } + + // Handle side effects for changing a bool option. + const char *errmsg = NULL; + bool doskip = false; + 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; + } + + // after handling side effects, call autocommand + + options[opt_idx].flags |= P_WAS_SET; + + apply_optionset_autocmd(opt_idx, opt_flags, + (long)(old_value ? true : false), + (long)(old_global_value ? true : false), + (long)(value ? true : false), NULL); + + if (options[opt_idx].flags & P_UI_OPTION) { + ui_call_option_set(cstr_as_string(options[opt_idx].fullname), + BOOLEAN_OBJ(*varp)); + } + if ((int *)varp == &p_ru || (int *)varp == &p_sc) { + // in case 'ruler' or 'showcmd' changed + comp_col(); + } + if (curwin->w_curswant != MAXCOL + && (options[opt_idx].flags & (P_CURSWANT | P_RALL)) != 0) { + curwin->w_set_curswant = true; + } + check_redraw(options[opt_idx].flags); + + return errmsg; +} + /// Check the bounds of numeric options. static const char *check_num_option_bounds(OptInt *pp, OptInt old_value, long old_Rows, char *errbuf, size_t errbuflen, const char *errmsg) @@ -5744,22 +5760,6 @@ void reset_option_was_set(const char *name) options[idx].flags &= ~P_WAS_SET; } -/// 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; - } - - if (p_breakat != NULL) { - for (char *p = p_breakat; *p; p++) { - breakat_flags[(uint8_t)(*p)] = true; - } - } - - return NULL; -} - /// fill_culopt_flags() -- called when 'culopt' changes value int fill_culopt_flags(char *val, win_T *wp) { -- cgit