diff options
-rw-r--r-- | src/nvim/option.c | 998 | ||||
-rw-r--r-- | src/nvim/optionstr.c | 1510 |
2 files changed, 1257 insertions, 1251 deletions
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,46 +2192,175 @@ 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) +{ + win_T *win = (win_T *)args->os_win; + if (p_ea && !args->os_oldval.boolean) { + win_equal(win, false, 0); + } + + 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) +{ + win_T *win = (win_T *)args->os_win; + if (foldmethodIsSyntax(win) || foldmethodIsIndent(win)) { + foldUpdateAll(win); + } + return NULL; +} + +/// Process the new 'helpheight' option value. +static const char *did_set_helpheight(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); + } + } + + 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 '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 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; +} - // when 'bin' is set also set some other options - set_options_bin((int)args->os_oldval.boolean, buf->b_p_bin, args->os_flags); +/// 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 'buflisted' option value. -static const char *did_set_buflisted(optset_T *args) +/// Process the updated 'modified' option value. +static const char *did_set_modified(optset_T *args) { 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); + 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 'swapfile' option value. -static const char *did_set_swapfile(optset_T *args) +/// Process the updated 'number' or 'relativenumber' option value. +static const char *did_set_number_relativenumber(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 + 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) { @@ -2286,39 +2490,6 @@ static const char *did_set_paste(optset_T *args FUNC_ATTR_UNUSED) 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) { @@ -2340,32 +2511,63 @@ static const char *did_set_previewwindow(optset_T *args) return NULL; } -/// Process the updated 'lisp' option value. -static const char *did_set_lisp(optset_T *args) +/// Process the new 'pumblend' option value. +static const char *did_set_pumblend(optset_T *args FUNC_ATTR_UNUSED) { - 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 + p_pb = MAX(MIN(p_pb, 100), 0); + hl_invalidate_blends(); + pum_grid.blending = (p_pb > 0); + if (pum_drawn()) { + pum_redraw(); + } + return NULL; } -/// Process the updated 'title' or the 'icon' option value. -static const char *did_set_title_icon(optset_T *args FUNC_ATTR_UNUSED) +/// Process the updated 'readonly' option value. +static const char *did_set_readonly(optset_T *args) { - // when 'title' changed, may need to change the title; same for 'icon' - did_set_title(); + // 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 updated 'modified' option value. -static const char *did_set_modified(optset_T *args) +/// Process the new 'scrollback' option value. +static const char *did_set_scrollback(optset_T *args) { buf_T *buf = (buf_T *)args->os_buf; - if (!args->os_newval.boolean) { - save_file_ff(buf); // Buffer is unchanged + 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); } - redraw_titles(); - modified_was_set = (int)args->os_newval.boolean; + 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; } @@ -2391,46 +2593,43 @@ static const char *did_set_shellslash(optset_T *args FUNC_ATTR_UNUSED) } #endif -/// Process the updated 'wrap' option value. -static const char *did_set_wrap(optset_T *args) +/// 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 'wrap' is set, set w_leftcol to zero. - if (win->w_p_wrap) { - win->w_leftcol = 0; + if (foldmethodIsIndent(win)) { + foldUpdateAll(win); } - 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); + // 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); } return NULL; } -/// Process the updated 'autochdir' option value. -static const char *did_set_autochdir(optset_T *args FUNC_ATTR_UNUSED) +/// Process the new 'showtabline' option value. +static const char *did_set_showtabline(optset_T *args FUNC_ATTR_UNUSED) { - // Change directories when the 'acd' option is set now. - do_autochdir(); + // (re)set tab page line + win_new_screen_rows(); // recompute window positions and heights return NULL; } -/// Process the updated 'diff' option value. -static const char *did_set_diff(optset_T *args) +/// Process the updated 'smoothscroll' option value. +static const char *did_set_smoothscroll(optset_T *args FUNC_ATTR_UNUSED) { 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); + if (win->w_p_sms) { + return NULL; } + + win->w_skipcol = 0; + changed_line_abv_curs_win(win); return NULL; } @@ -2445,74 +2644,189 @@ static const char *did_set_spell(optset_T *args) return NULL; } -/// Process the updated 'arabic' option value. -static const char *did_set_arabic(optset_T *args) +/// Process the updated 'swapfile' option value. +static const char *did_set_swapfile(optset_T *args) { - win_T *win = (win_T *)args->os_win; - const char *errmsg = NULL; + 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 + } + return 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(); - } +/// Process the new 'textwidth' option value. +static const char *did_set_textwidth(optset_T *args FUNC_ATTR_UNUSED) +{ + FOR_ALL_TAB_WINDOWS(tp, wp) { + check_colorcolumn(wp); + } - // Enable Arabic shaping (major part of what Arabic requires) - if (!p_arshape) { - p_arshape = true; - redraw_all_later(UPD_NOT_VALID); - } - } + return NULL; +} - // 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'"); +/// 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; +} - msg_source(HL_ATTR(HLF_W)); - msg(_(w_arabic), HL_ATTR(HLF_W)); - set_vim_var_string(VV_WARNINGMSG, _(w_arabic), -1); - } +/// Process the new 'titlelen' option value. +static const char *did_set_titlelen(optset_T *args) +{ + OptInt old_value = args->os_oldval.number; - // set 'delcombine' - p_deco = true; + // if 'titlelen' has changed, redraw the title + if (starting != NO_SCREEN && old_value != p_titlelen) { + need_maketitle = 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(); - } + return NULL; +} - // 'arabicshape' isn't reset, it is a global option and - // another window may still need it "on". +/// Process the updated 'undofile' option value. +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 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]; + + 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); } + } - // 'delcombine' isn't reset, it is a global option and another - // window may still want it "on". + return NULL; +} - // Revert to the default keymap - curbuf->b_p_iminsert = B_IMODE_NONE; - curbuf->b_p_imsearch = B_IMODE_USE_INSERT; +/// Process the new global 'undolevels' option value. +const char *did_set_global_undolevels(OptInt value, OptInt 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. +const char *did_set_buflocal_undolevels(buf_T *buf, OptInt value, OptInt 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 'undolevels' option value. +static const char *did_set_undolevels(optset_T *args) +{ + buf_T *buf = (buf_T *)args->os_buf; + OptInt *pp = (OptInt *)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; } -/// Process the updated 'number' or 'relativenumber' option value. -static const char *did_set_number_relativenumber(optset_T *args) +/// Process the new 'updatecount' option value. +static const char *did_set_updatecount(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(); + } + + return NULL; +} + +/// Process the new 'winblend' option value. +static const char *did_set_winblend(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; + OptInt old_value = args->os_oldval.number; + OptInt 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; +} + +/// Process the new 'window' option value. +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 '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; } @@ -2606,304 +2920,6 @@ static const char *set_bool_option(const int opt_idx, char *const varp, const in return errmsg; } -/// 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 'helpheight' option value. -static const char *did_set_helpheight(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); - } - } - - 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 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 new 'showtabline' option value. -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 updated 'smoothscroll' option value. -static const char *did_set_smoothscroll(optset_T *args FUNC_ATTR_UNUSED) -{ - win_T *win = (win_T *)args->os_win; - if (win->w_p_sms) { - return NULL; - } - - win->w_skipcol = 0; - changed_line_abv_curs_win(win); - 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) -{ - 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 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 '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); - } - - 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) -{ - 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 const char *did_set_titlelen(optset_T *args) -{ - OptInt 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 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) -{ - 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; -} - -/// 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(); - } - - return NULL; -} - -/// Process the new global 'undolevels' option value. -const char *did_set_global_undolevels(OptInt value, OptInt 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. -const char *did_set_buflocal_undolevels(buf_T *buf, OptInt value, OptInt 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 const char *did_set_scrollback(optset_T *args) -{ - 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 '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) -{ - FOR_ALL_TAB_WINDOWS(tp, wp) { - check_colorcolumn(wp); - } - - return NULL; -} - -/// Process the new 'winblend' option value. -static const char *did_set_winblend(optset_T *args) -{ - win_T *win = (win_T *)args->os_win; - OptInt old_value = args->os_oldval.number; - OptInt 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; -} - -/// Process the new 'undolevels' option value. -static const char *did_set_undolevels(optset_T *args) -{ - buf_T *buf = (buf_T *)args->os_buf; - OptInt *pp = (OptInt *)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 NULL; -} - /// 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) { diff --git a/src/nvim/optionstr.c b/src/nvim/optionstr.c index 62073a2323..750941da07 100644 --- a/src/nvim/optionstr.c +++ b/src/nvim/optionstr.c @@ -519,71 +519,6 @@ static bool valid_filetype(const char *val) return valid_name(val, ".-_"); } -/// Handle setting 'mousescroll'. -/// @return error message, NULL if it's OK. -const char *did_set_mousescroll(optset_T *args FUNC_ATTR_UNUSED) -{ - OptInt vertical = -1; - OptInt horizontal = -1; - - char *string = p_mousescroll; - - while (true) { - char *end = vim_strchr(string, ','); - size_t length = end ? (size_t)(end - string) : strlen(string); - - // Both "ver:" and "hor:" are 4 bytes long. - // They should be followed by at least one digit. - if (length <= 4) { - return e_invarg; - } - - OptInt *direction; - - if (memcmp(string, "ver:", 4) == 0) { - direction = &vertical; - } else if (memcmp(string, "hor:", 4) == 0) { - direction = &horizontal; - } else { - return e_invarg; - } - - // If the direction has already been set, this is a duplicate. - if (*direction != -1) { - return e_invarg; - } - - // Verify that only digits follow the colon. - for (size_t i = 4; i < length; i++) { - if (!ascii_isdigit(string[i])) { - return N_("E5080: Digit expected"); - } - } - - string += 4; - *direction = getdigits_int(&string, false, -1); - - // Num options are generally kept within the signed int range. - // We know this number won't be negative because we've already checked for - // a minus sign. We'll allow 0 as a means of disabling mouse scrolling. - if (*direction == -1) { - return e_invarg; - } - - if (!end) { - break; - } - - string = end + 1; - } - - // If a direction wasn't set, fallback to the default value. - p_mousescroll_vert = (vertical == -1) ? MOUSESCROLL_VERT_DFLT : vertical; - p_mousescroll_hor = (horizontal == -1) ? MOUSESCROLL_HOR_DFLT : horizontal; - - return NULL; -} - /// Handle setting 'signcolumn' for value 'val' /// /// @return OK when the value is valid, FAIL otherwise @@ -695,6 +630,81 @@ static bool check_illegal_path_names(char *val, uint32_t flags) && strpbrk(val, "*?[|;&<>\r\n") != NULL)); } +/// An option that accepts a list of flags is changed. +/// e.g. 'viewoptions', 'switchbuf', 'casemap', etc. +static const char *did_set_opt_flags(char *val, char **values, unsigned *flagp, bool list) +{ + if (opt_strings_flags(val, values, flagp, list) != OK) { + return e_invarg; + } + return NULL; +} + +/// An option that accepts a list of string values is changed. +/// e.g. 'nrformats', 'scrollopt', 'wildoptions', etc. +static const char *did_set_opt_strings(char *val, char **values, bool list) +{ + return did_set_opt_flags(val, values, NULL, list); +} + +/// 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) { + return illegal_char(errbuf, errbuflen, (uint8_t)(*s)); + } + } + + return NULL; +} + +/// 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) { + return e_invarg; + } + return check_chars_options(); +} + +/// 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) { + return e_invarg; + } + + int dark = (*p_bg == 'd'); + + init_highlight(false, false); + + if (dark != (*p_bg == 'd') && get_var_value("g:colors_name") != NULL) { + // The color scheme must have set 'background' back to another + // value, that's not what we want here. Disable the color + // scheme and set the colors again. + do_unlet(S_LEN("g:colors_name"), true); + free_string_option(p_bg); + p_bg = xstrdup((dark ? "dark" : "light")); + check_string_option(&p_bg); + init_highlight(false, false); + } + return NULL; +} + +/// The 'backspace' option is changed. +const char *did_set_backspace(optset_T *args FUNC_ATTR_UNUSED) +{ + if (ascii_isdigit(*p_bs)) { + if (*p_bs != '2') { + return e_invarg; + } + } else if (check_opt_strings(p_bs, p_bs_values, true) != OK) { + return e_invarg; + } + return NULL; +} + /// The 'backupcopy' option is changed. const char *did_set_backupcopy(optset_T *args) { @@ -746,12 +756,6 @@ 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) { @@ -767,160 +771,236 @@ const char *did_set_breakindentopt(optset_T *args) return NULL; } -/// The 'isident' or the 'iskeyword' or the 'isprint' or the 'isfname' option is -/// changed. -const char *did_set_isopt(optset_T *args) +/// The 'bufhidden' option is changed. +const char *did_set_bufhidden(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) { - args->os_restore_chartab = true; // need to restore it below - return e_invarg; // error in value - } - return NULL; + return did_set_opt_strings(buf->b_p_bh, p_bufhidden_values, false); } -/// The 'helpfile' option is changed. -const char *did_set_helpfile(optset_T *args FUNC_ATTR_UNUSED) +/// The 'buftype' option is changed. +const char *did_set_buftype(optset_T *args) { - // May compute new values for $VIM and $VIMRUNTIME - if (didset_vim) { - vim_unsetenv_ext("VIM"); + 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) { + return e_invarg; } - if (didset_vimruntime) { - vim_unsetenv_ext("VIMRUNTIME"); + 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; } -/// The 'cursorlineopt' option is changed. -const char *did_set_cursorlineopt(optset_T *args) +/// The 'casemap' option is changed. +const char *did_set_casemap(optset_T *args FUNC_ATTR_UNUSED) { - win_T *win = (win_T *)args->os_win; - char **varp = (char **)args->os_varp; + return did_set_opt_flags(p_cmp, p_cmp_values, &cmp_flags, true); +} - if (**varp == NUL || fill_culopt_flags(*varp, win) != OK) { - return e_invarg; +/// 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) +{ + 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; } - return 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); + } -/// 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)) { - return e_invarg; - } - if (s[2] == NUL) { - break; + 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); + return NULL; } -/// The 'highlight' option is changed. -const char *did_set_highlight(optset_T *args) +/// 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 (strcmp(*varp, HIGHLIGHT_INIT) != 0) { - return e_unsupportedoption; + 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 NULL; + + return errmsg; } -static const char *did_set_opt_flags(char *val, char **values, unsigned *flagp, bool list) +/// The 'cinoptions' option is changed. +const char *did_set_cinoptions(optset_T *args FUNC_ATTR_UNUSED) { - if (opt_strings_flags(val, values, flagp, list) != OK) { - return e_invarg; - } + // TODO(vim): recognize errors + parse_cino(curbuf); + return NULL; } -static const char *did_set_opt_strings(char *val, char **values, bool list) +/// The 'clipboard' option is changed. +const char *did_set_clipboard(optset_T *args FUNC_ATTR_UNUSED) { - return did_set_opt_flags(val, values, NULL, list); + return did_set_opt_flags(p_cb, p_cb_values, &cb_flags, true); } -/// The 'selectmode' option is changed. -const char *did_set_selectmode(optset_T *args FUNC_ATTR_UNUSED) +/// The 'colorcolumn' option is changed. +const char *did_set_colorcolumn(optset_T *args) { - return did_set_opt_strings(p_slm, p_slm_values, true); + win_T *win = (win_T *)args->os_win; + return check_colorcolumn(win); } -/// The 'inccommand' option is changed. -const char *did_set_inccommand(optset_T *args FUNC_ATTR_UNUSED) +/// The 'comments' option is changed. +const char *did_set_comments(optset_T *args) { - return did_set_opt_strings(p_icm, p_icm_values, false); + 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(args->os_errbuf, args->os_errbuflen, (uint8_t)(*s)); + break; + } + s++; + } + if (*s++ == NUL) { + errmsg = N_("E524: Missing colon"); + } else if (*s == ',' || *s == NUL) { + errmsg = N_("E525: Zero length string"); + } + if (errmsg != NULL) { + break; + } + while (*s && *s != ',') { + if (*s == '\\' && s[1] != NUL) { + s++; + } + s++; + } + s = skip_to_option_part(s); + } + return errmsg; } -/// The 'sessionoptions' option is changed. -const char *did_set_sessionoptions(optset_T *args) +/// The 'commentstring' option is changed. +const char *did_set_commentstring(optset_T *args) { - if (opt_strings_flags(p_ssop, p_ssop_values, &ssop_flags, true) != OK) { - 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); - return e_invarg; + char **varp = (char **)args->os_varp; + + if (**varp != NUL && strstr(*varp, "%s") == NULL) { + return N_("E537: 'commentstring' must be empty or contain %s"); } return NULL; } -/// The 'ambiwidth' option is changed. -const char *did_set_ambiwidth(optset_T *args FUNC_ATTR_UNUSED) +/// The 'complete' option is changed. +const char *did_set_complete(optset_T *args) { - if (check_opt_strings(p_ambw, p_ambw_values, false) != OK) { - return e_invarg; + char **varp = (char **)args->os_varp; + + // check if it is a valid value for 'complete' -- Acevedo + for (char *s = *varp; *s;) { + while (*s == ',' || *s == ' ') { + s++; + } + if (!*s) { + break; + } + if (vim_strchr(".wbuksid]tU", (uint8_t)(*s)) == NULL) { + return illegal_char(args->os_errbuf, args->os_errbuflen, (uint8_t)(*s)); + } + if (*++s != NUL && *s != ',' && *s != ' ') { + if (s[-1] == 'k' || s[-1] == 's') { + // skip optional filename after 'k' and 's' + while (*s && *s != ',' && *s != ' ') { + if (*s == '\\' && s[1] != NUL) { + s++; + } + s++; + } + } else { + if (args->os_errbuf != NULL) { + vim_snprintf(args->os_errbuf, args->os_errbuflen, + _("E535: Illegal character after <%c>"), + *--s); + return args->os_errbuf; + } + return ""; + } + } } - return check_chars_options(); + return NULL; } -/// The 'background' option is changed. -const char *did_set_background(optset_T *args FUNC_ATTR_UNUSED) +/// The 'completeopt' option is changed. +const char *did_set_completeopt(optset_T *args FUNC_ATTR_UNUSED) { - if (check_opt_strings(p_bg, p_bg_values, false) != OK) { + if (check_opt_strings(p_cot, p_cot_values, true) != OK) { return e_invarg; } - - int dark = (*p_bg == 'd'); - - init_highlight(false, false); - - if (dark != (*p_bg == 'd') && get_var_value("g:colors_name") != NULL) { - // The color scheme must have set 'background' back to another - // value, that's not what we want here. Disable the color - // scheme and set the colors again. - do_unlet(S_LEN("g:colors_name"), true); - free_string_option(p_bg); - p_bg = xstrdup((dark ? "dark" : "light")); - check_string_option(&p_bg); - init_highlight(false, false); - } + completeopt_was_set(); return NULL; } -/// The 'whichwrap' option is changed. -const char *did_set_whichwrap(optset_T *args) +#ifdef BACKSLASH_IN_FILENAME +/// The 'completeslash' option is changed. +const char *did_set_completeslash(optset_T *args) { - char **varp = (char **)args->os_varp; - - return did_set_option_listflag(*varp, WW_ALL, args->os_errbuf, args->os_errbuflen); + 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) { + return e_invarg; + } + return NULL; } +#endif -/// The 'shortmess' option is changed. -const char *did_set_shortmess(optset_T *args) +/// 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, SHM_ALL, args->os_errbuf, args->os_errbuflen); + return did_set_option_listflag(*varp, COCU_ALL, args->os_errbuf, args->os_errbuflen); } /// The 'cpoptions' option is changed. @@ -931,66 +1011,42 @@ const char *did_set_cpoptions(optset_T *args) 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) +/// 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; - 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; + if (**varp == NUL || fill_culopt_flags(*varp, win) != OK) { + return e_invarg; + } - return did_set_option_listflag(*varp, MOUSE_ALL, args->os_errbuf, args->os_errbuflen); + return NULL; } -/// The 'wildmode' option is changed. -const char *did_set_wildmode(optset_T *args FUNC_ATTR_UNUSED) +/// The 'debug' option is changed. +const char *did_set_debug(optset_T *args FUNC_ATTR_UNUSED) { - if (check_opt_wim() == FAIL) { - return e_invarg; - } - return NULL; + return did_set_opt_strings(p_debug, p_debug_values, false); } -/// The 'winaltkeys' option is changed. -const char *did_set_winaltkeys(optset_T *args FUNC_ATTR_UNUSED) +/// The 'diffopt' option is changed. +const char *did_set_diffopt(optset_T *args FUNC_ATTR_UNUSED) { - if (*p_wak == NUL || check_opt_strings(p_wak, p_wak_values, false) != OK) { + if (diffopt_changed() == FAIL) { return e_invarg; } return NULL; } -/// The 'eventignore' option is changed. -const char *did_set_eventignore(optset_T *args FUNC_ATTR_UNUSED) +/// The 'display' option is changed. +const char *did_set_display(optset_T *args FUNC_ATTR_UNUSED) { - if (check_ei() == FAIL) { + if (opt_strings_flags(p_dy, p_dy_values, &dy_flags, true) != OK) { return e_invarg; } + (void)init_chartab(); + msg_grid_validate(); return NULL; } @@ -1042,6 +1098,229 @@ const char *did_set_encoding(optset_T *args) return NULL; } +/// The 'eventignore' option is changed. +const char *did_set_eventignore(optset_T *args FUNC_ATTR_UNUSED) +{ + if (check_ei() == FAIL) { + return e_invarg; + } + return NULL; +} + +/// 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)) { + return e_modifiable; + } else if (check_opt_strings(*varp, p_ff_values, false) != OK) { + 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; +} + +/// 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 '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. + args->os_value_checked = true; + + 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); +} + +/// 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) { + return e_invarg; + } + return NULL; +} + +/// The 'foldexpr' option is changed. +const char *did_set_foldexpr(optset_T *args) +{ + win_T *win = (win_T *)args->os_win; + (void)did_set_optexpr(args); + if (foldmethodIsExpr(win)) { + foldUpdateAll(win); + } + return NULL; +} + +/// 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; +} + +/// 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) { + return e_comma_required; + } + + if (p == *varp || p[1] == NUL) { + return e_invarg; + } + + if (foldmethodIsMarker(win)) { + foldUpdateAll(win); + } + + return NULL; +} + +/// 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) { + return e_invarg; + } + foldUpdateAll(win); + if (foldmethodIsDiff(win)) { + newFoldLevel(); + } + return NULL; +} + +/// 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 'guicursor' option is changed. +const char *did_set_guicursor(optset_T *args FUNC_ATTR_UNUSED) +{ + return parse_shape_opt(SHAPE_CURSOR); +} + +/// 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) { + vim_unsetenv_ext("VIM"); + } + if (didset_vimruntime) { + vim_unsetenv_ext("VIMRUNTIME"); + } + return NULL; +} + +/// 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)) { + return e_invarg; + } + if (s[2] == NUL) { + break; + } + } + return NULL; +} + +/// 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) { + return e_unsupportedoption; + } + return NULL; +} + +/// The 'iconstring' option is changed. +const char *did_set_iconstring(optset_T *args) +{ + return did_set_titleiconstring(args, STL_IN_ICON); +} + +/// 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 '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) { + args->os_restore_chartab = true; // need to restore it below + return e_invarg; // error in value + } + return NULL; +} + +/// 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 'keymap' option has changed. const char *did_set_keymap(optset_T *args) { @@ -1094,33 +1373,26 @@ const char *did_set_keymap(optset_T *args) return errmsg; } -/// The 'fileformat' option is changed. -const char *did_set_fileformat(optset_T *args) +/// The 'keymodel' option is changed. +const char *did_set_keymodel(optset_T *args FUNC_ATTR_UNUSED) { - 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)) { - return e_modifiable; - } else if (check_opt_strings(*varp, p_ff_values, false) != OK) { + if (check_opt_strings(p_km, p_km_values, true) != OK) { 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); - } + km_stopsel = (vim_strchr(p_km, 'o') != NULL); + km_startsel = (vim_strchr(p_km, 'a') != NULL); return NULL; } -/// The 'fileformats' option is changed. -const char *did_set_fileformats(optset_T *args) +/// The 'lispoptions' option is changed. +const char *did_set_lispoptions(optset_T *args) { - return did_set_opt_strings(p_ffs, p_ff_values, true); + char **varp = (char **)args->os_varp; + + if (**varp != NUL && strcmp(*varp, "expr:0") != 0 && strcmp(*varp, "expr:1") != 0) { + return e_invarg; + } + return NULL; } /// The 'matchpairs' option is changed. @@ -1150,150 +1422,183 @@ const char *did_set_matchpairs(optset_T *args) return NULL; } -/// The 'cinoptions' option is changed. -const char *did_set_cinoptions(optset_T *args FUNC_ATTR_UNUSED) +/// The 'mkspellmem' option is changed. +const char *did_set_mkspellmem(optset_T *args FUNC_ATTR_UNUSED) { - // TODO(vim): recognize errors - parse_cino(curbuf); - + if (spell_check_msm() != OK) { + return e_invarg; + } return NULL; } -/// The 'colorcolumn' option is changed. -const char *did_set_colorcolumn(optset_T *args) +/// The 'mouse' option is changed. +const char *did_set_mouse(optset_T *args) { - win_T *win = (win_T *)args->os_win; - return check_colorcolumn(win); + char **varp = (char **)args->os_varp; + + return did_set_option_listflag(*varp, MOUSE_ALL, args->os_errbuf, args->os_errbuflen); } -const char *did_set_comments(optset_T *args) +/// The 'mousemodel' option is changed. +const char *did_set_mousemodel(optset_T *args FUNC_ATTR_UNUSED) { - 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(args->os_errbuf, args->os_errbuflen, (uint8_t)(*s)); - break; - } - s++; - } - if (*s++ == NUL) { - errmsg = N_("E524: Missing colon"); - } else if (*s == ',' || *s == NUL) { - errmsg = N_("E525: Zero length string"); - } - if (errmsg != NULL) { - break; - } - while (*s && *s != ',') { - if (*s == '\\' && s[1] != NUL) { - s++; - } - s++; - } - s = skip_to_option_part(s); - } - return errmsg; + return did_set_opt_strings(p_mousem, p_mousem_values, false); } -/// 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) +/// Handle setting 'mousescroll'. +/// @return error message, NULL if it's OK. +const char *did_set_mousescroll(optset_T *args FUNC_ATTR_UNUSED) { - const char *errmsg = NULL; - char **local_ptr = opt_lcs ? &win->w_p_lcs : &win->w_p_fcs; + OptInt vertical = -1; + OptInt horizontal = -1; - // 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; - } + char *string = p_mousescroll; - // 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); - } + while (true) { + char *end = vim_strchr(string, ','); + size_t length = end ? (size_t)(end - string) : strlen(string); - 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); - } + // Both "ver:" and "hor:" are 4 bytes long. + // They should be followed by at least one digit. + if (length <= 4) { + return e_invarg; + } + + OptInt *direction; + + if (memcmp(string, "ver:", 4) == 0) { + direction = &vertical; + } else if (memcmp(string, "hor:", 4) == 0) { + direction = &horizontal; } else { - if (*wp->w_p_fcs == NUL) { - (void)set_fillchars_option(wp, wp->w_p_fcs, true); + return e_invarg; + } + + // If the direction has already been set, this is a duplicate. + if (*direction != -1) { + return e_invarg; + } + + // Verify that only digits follow the colon. + for (size_t i = 4; i < length; i++) { + if (!ascii_isdigit(string[i])) { + return N_("E5080: Digit expected"); } } + + string += 4; + *direction = getdigits_int(&string, false, -1); + + // Num options are generally kept within the signed int range. + // We know this number won't be negative because we've already checked for + // a minus sign. We'll allow 0 as a means of disabling mouse scrolling. + if (*direction == -1) { + return e_invarg; + } + + if (!end) { + break; + } + + string = end + 1; } - redraw_all_later(UPD_NOT_VALID); + // If a direction wasn't set, fallback to the default value. + p_mousescroll_vert = (vertical == -1) ? MOUSESCROLL_VERT_DFLT : vertical; + p_mousescroll_hor = (horizontal == -1) ? MOUSESCROLL_HOR_DFLT : horizontal; return NULL; } -/// Handle the new value of 'fillchars'. -const char *set_fillchars_option(win_T *wp, char *val, int apply) +/// The 'nrformats' option is changed. +const char *did_set_nrformats(optset_T *args) { - return set_chars_option(wp, val, false, apply); + char **varp = (char **)args->os_varp; + + return did_set_opt_strings(*varp, p_nf_values, true); } -/// Handle the new value of 'listchars'. -const char *set_listchars_option(win_T *wp, char *val, int apply) +/// One of the '*expr' options is changed:, 'diffexpr', 'foldexpr', 'foldtext', +/// 'formatexpr', 'includeexpr', 'indentexpr', 'patchexpr' and 'charconvert'. +const char *did_set_optexpr(optset_T *args) { - return set_chars_option(wp, val, true, apply); + char **varp = (char **)args->os_varp; + + // If the option value starts with <SID> 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; } -/// The 'fillchars' option or the 'listchars' option is changed. -const char *did_set_chars_option(optset_T *args) +/// 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 'rightleftcmd' option is changed. +const char *did_set_rightleftcmd(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); + // Currently only "search" is a supported value. + if (**varp != NUL && strcmp(*varp, "search") != 0) { + return e_invarg; } - return errmsg; + return NULL; } -/// The 'verbosefile' option is changed. -const char *did_set_verbosefile(optset_T *args) +/// The 'rulerformat' option is changed. +const char *did_set_rulerformat(optset_T *args) { - verbose_stop(); - if (*p_vfile != NUL && verbose_open() == FAIL) { - return (char *)e_invarg; + return did_set_statustabline_rulerformat(args, true, false); +} + +/// 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 '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) { + return e_invarg; } return NULL; } -/// The 'viewoptions' option is changed. -const char *did_set_viewoptions(optset_T *args FUNC_ATTR_UNUSED) +/// The 'selectmode' option is changed. +const char *did_set_selectmode(optset_T *args FUNC_ATTR_UNUSED) { - return did_set_opt_flags(p_vop, p_ssop_values, &vop_flags, true); + return did_set_opt_strings(p_slm, p_slm_values, true); } -static int shada_idx = -1; +/// 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) { + 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); + return e_invarg; + } + return NULL; +} static const char *did_set_shada(vimoption_T **opt, int *opt_idx, bool *free_oldval, char *errbuf, size_t errbuflen) { + static int shada_idx = -1; // TODO(ZyX-I): Remove this code in the future, alongside with &viminfo // option. *opt_idx = (((*opt)->fullname[0] == 'v') @@ -1348,6 +1653,14 @@ static const char *did_set_shada(vimoption_T **opt, int *opt_idx, bool *free_old return NULL; } +/// 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 'showbreak' option is changed. const char *did_set_showbreak(optset_T *args) { @@ -1362,63 +1675,37 @@ const char *did_set_showbreak(optset_T *args) return NULL; } -/// The 'titlestring' or the 'iconstring' option is changed. -static const char *did_set_titleiconstring(optset_T *args, int flagval) -{ - char **varp = (char **)args->os_varp; - - // NULL => statusline syntax - if (vim_strchr(*varp, '%') && check_stl_option(*varp) == NULL) { - stl_syntax |= flagval; - } else { - stl_syntax &= ~flagval; - } - did_set_title(); - - return NULL; -} - -/// 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) +/// The 'showcmdloc' option is changed. +const char *did_set_showcmdloc(optset_T *args FUNC_ATTR_UNUSED) { - return did_set_titleiconstring(args, STL_IN_ICON); + return did_set_opt_strings(p_sloc, p_sloc_values, true); } -/// The 'selection' option is changed. -const char *did_set_selection(optset_T *args FUNC_ATTR_UNUSED) +/// The 'signcolumn' option is changed. +const char *did_set_signcolumn(optset_T *args) { - if (*p_sel == NUL || check_opt_strings(p_sel, p_sel_values, false) != OK) { + 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) { return e_invarg; } - return NULL; -} - -/// 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) { - return e_invarg; + // When changing the 'signcolumn' to or from 'number', recompute the + // width of the number column if 'number' or 'relativenumber' is set. + if (((*oldval == 'n' && *(oldval + 1) == 'u') + || (*win->w_p_scl == 'n' && *(win->w_p_scl + 1) == 'u')) + && (win->w_p_nu || win->w_p_rnu)) { + win->w_nrwidth_line_count = 0; } - km_stopsel = (vim_strchr(p_km, 'o') != NULL); - km_startsel = (vim_strchr(p_km, 'a') != NULL); return NULL; } -/// The 'display' option is changed. -const char *did_set_display(optset_T *args FUNC_ATTR_UNUSED) +/// The 'spellcapcheck' option is changed. +const char *did_set_spellcapcheck(optset_T *args) { - if (opt_strings_flags(p_dy, p_dy_values, &dy_flags, true) != OK) { - return e_invarg; - } - (void)init_chartab(); - msg_grid_validate(); - return NULL; + win_T *win = (win_T *)args->os_win; + // When 'spellcapcheck' is set compile the regexp program. + return compile_cap_prog(win->w_s); } /// The 'spellfile' option is changed. @@ -1434,6 +1721,7 @@ const char *did_set_spellfile(optset_T *args) return did_set_spell_option(true); } +/// The 'spelllang' option is changed. const char *did_set_spelllang(optset_T *args) { char **varp = (char **)args->os_varp; @@ -1446,14 +1734,6 @@ const char *did_set_spelllang(optset_T *args) return did_set_spell_option(false); } -/// 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. - return compile_cap_prog(win->w_s); -} - /// The 'spelloptions' option is changed. const char *did_set_spelloptions(optset_T *args) { @@ -1480,52 +1760,16 @@ 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) { - return e_invarg; - } - return NULL; -} - -/// 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) +/// The 'statuscolumn' option is changed. +const char *did_set_statuscolumn(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) { - 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; + return did_set_statustabline_rulerformat(args, false, true); } -/// The 'casemap' option is changed. -const char *did_set_casemap(optset_T *args FUNC_ATTR_UNUSED) +/// The 'statusline' option is changed. +const char *did_set_statusline(optset_T *args) { - return did_set_opt_flags(p_cmp, p_cmp_values, &cmp_flags, true); + return did_set_statustabline_rulerformat(args, false, false); } /// The 'statusline', 'winbar', 'tabline', 'rulerformat' or 'statuscolumn' option is changed. @@ -1567,10 +1811,10 @@ static const char *did_set_statustabline_rulerformat(optset_T *args, bool rulerf return errmsg; } -/// The 'statusline' option is changed. -const char *did_set_statusline(optset_T *args) +/// The 'switchbuf' option is changed. +const char *did_set_switchbuf(optset_T *args FUNC_ATTR_UNUSED) { - return did_set_statustabline_rulerformat(args, false, false); + return did_set_opt_flags(p_swb, p_swb_values, &swb_flags, true); } /// The 'tabline' option is changed. @@ -1579,146 +1823,6 @@ 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 == ' ') { - s++; - } - if (!*s) { - break; - } - if (vim_strchr(".wbuksid]tU", (uint8_t)(*s)) == NULL) { - return illegal_char(args->os_errbuf, args->os_errbuflen, (uint8_t)(*s)); - } - if (*++s != NUL && *s != ',' && *s != ' ') { - if (s[-1] == 'k' || s[-1] == 's') { - // skip optional filename after 'k' and 's' - while (*s && *s != ',' && *s != ' ') { - if (*s == '\\' && s[1] != NUL) { - s++; - } - s++; - } - } else { - if (args->os_errbuf != NULL) { - vim_snprintf(args->os_errbuf, args->os_errbuflen, - _("E535: Illegal character after <%c>"), - *--s); - return args->os_errbuf; - } - return ""; - } - } - } - return NULL; -} - -/// 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) { - return e_invarg; - } - completeopt_was_set(); - return NULL; -} - -#ifdef BACKSLASH_IN_FILENAME -/// 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) { - return e_invarg; - } - return NULL; -} -#endif - -/// 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) { - return e_invarg; - } - // When changing the 'signcolumn' to or from 'number', recompute the - // width of the number column if 'number' or 'relativenumber' is set. - if (((*oldval == 'n' && *(oldval + 1) == 'u') - || (*win->w_p_scl == 'n' && *(win->w_p_scl + 1) == 'u')) - && (win->w_p_nu || win->w_p_rnu)) { - win->w_nrwidth_line_count = 0; - } - return NULL; -} - -/// 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) { - return e_invarg; - } - return NULL; -} - -/// The 'backspace' option is changed. -const char *did_set_backspace(optset_T *args FUNC_ATTR_UNUSED) -{ - if (ascii_isdigit(*p_bs)) { - if (*p_bs != '2') { - return e_invarg; - } - } else if (check_opt_strings(p_bs, p_bs_values, true) != OK) { - return e_invarg; - } - return NULL; -} - -/// 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) { @@ -1746,177 +1850,32 @@ const char *did_set_tagcase(optset_T *args) return NULL; } -/// 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) { - return e_invarg; - } - return NULL; -} - -/// 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) { - return e_invarg; - } - foldUpdateAll(win); - if (foldmethodIsDiff(win)) { - newFoldLevel(); - } - return NULL; -} - -/// The 'foldmarker' option is changed. -const char *did_set_foldmarker(optset_T *args) +/// The 'termpastefilter' option is changed. +const char *did_set_termpastefilter(optset_T *args FUNC_ATTR_UNUSED) { - win_T *win = (win_T *)args->os_win; - char **varp = (char **)args->os_varp; - char *p = vim_strchr(*varp, ','); - - if (p == NULL) { - return e_comma_required; - } - - if (p == *varp || p[1] == NUL) { - return e_invarg; - } - - if (foldmethodIsMarker(win)) { - foldUpdateAll(win); - } - - return NULL; + return did_set_opt_flags(p_tpf, p_tpf_values, &tpf_flags, true); } -/// The 'commentstring' option is changed. -const char *did_set_commentstring(optset_T *args) +/// The 'titlestring' or the 'iconstring' option is changed. +static const char *did_set_titleiconstring(optset_T *args, int flagval) { char **varp = (char **)args->os_varp; - if (**varp != NUL && strstr(*varp, "%s") == NULL) { - return N_("E537: 'commentstring' must be empty or contain %s"); - } - return NULL; -} - -/// 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; -} - -/// 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 (args->os_flags & OPT_LOCAL) { - ve = win->w_p_ve; - flags = &win->w_ve_flags; - } - - if ((args->os_flags & OPT_LOCAL) && *ve == NUL) { - // make the local value empty: use the global value - *flags = 0; + // NULL => statusline syntax + if (vim_strchr(*varp, '%') && check_stl_option(*varp) == NULL) { + stl_syntax |= flagval; } else { - if (opt_strings_flags(ve, p_ve_values, flags, true) != OK) { - 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); - // XXX: this only works when win == curwin - coladvance(win->w_virtcol); - } - } - return NULL; -} - -/// 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) { - return e_invarg; - } - return NULL; -} - -/// The 'rightleftcmd' option is changed. -const char *did_set_rightleftcmd(optset_T *args) -{ - char **varp = (char **)args->os_varp; - - // Currently only "search" is a supported value. - if (**varp != NUL && strcmp(*varp, "search") != 0) { - return e_invarg; - } - - 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; + stl_syntax &= ~flagval; } - - 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. - args->os_value_checked = true; + did_set_title(); return NULL; } -const char *did_set_winhl(optset_T *args) +/// The 'titlestring' option is changed. +const char *did_set_titlestring(optset_T *args) { - win_T *win = (win_T *)args->os_win; - if (!parse_winhl_opt(win)) { - return e_invarg; - } - return NULL; + return did_set_titleiconstring(args, STL_IN_TITLE); } /// The 'varsofttabstop' option is changed. @@ -1983,62 +1942,97 @@ const char *did_set_vartabstop(optset_T *args) return NULL; } -/// The 'nrformats' option is changed. -const char *did_set_nrformats(optset_T *args) +/// The 'verbosefile' option is changed. +const char *did_set_verbosefile(optset_T *args) { - char **varp = (char **)args->os_varp; + verbose_stop(); + if (*p_vfile != NUL && verbose_open() == FAIL) { + return (char *)e_invarg; + } + return NULL; +} - return did_set_opt_strings(*varp, p_nf_values, true); +/// 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); } -/// One of the '*expr' options is changed:, 'diffexpr', 'foldexpr', 'foldtext', -/// 'formatexpr', 'includeexpr', 'indentexpr', 'patchexpr' and 'charconvert'. -const char *did_set_optexpr(optset_T *args) +/// The 'virtualedit' option is changed. +const char *did_set_virtualedit(optset_T *args) { - char **varp = (char **)args->os_varp; + win_T *win = (win_T *)args->os_win; - // If the option value starts with <SID> or s:, then replace that with - // the script identifier. - char *name = get_scriptlocal_funcname(*varp); - if (name != NULL) { - free_string_option(*varp); - *varp = name; + char *ve = p_ve; + unsigned *flags = &ve_flags; + + if (args->os_flags & OPT_LOCAL) { + ve = win->w_p_ve; + flags = &win->w_ve_flags; + } + + 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) { + 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); + // XXX: this only works when win == curwin + coladvance(win->w_virtcol); + } } return NULL; } -/// The 'foldexpr' option is changed. -const char *did_set_foldexpr(optset_T *args) +/// The 'whichwrap' option is changed. +const char *did_set_whichwrap(optset_T *args) { - win_T *win = (win_T *)args->os_win; - (void)did_set_optexpr(args); - if (foldmethodIsExpr(win)) { - foldUpdateAll(win); + char **varp = (char **)args->os_varp; + + return did_set_option_listflag(*varp, WW_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) { + return e_invarg; } return NULL; } -/// The 'foldclose' option is changed. -const char *did_set_foldclose(optset_T *args FUNC_ATTR_UNUSED) +/// The 'wildoptions' option is changed. +const char *did_set_wildoptions(optset_T *args FUNC_ATTR_UNUSED) { - return did_set_opt_strings(p_fcl, p_fcl_values, true); + return did_set_opt_flags(p_wop, p_wop_values, &wop_flags, 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) +/// The 'winaltkeys' option is changed. +const char *did_set_winaltkeys(optset_T *args FUNC_ATTR_UNUSED) { - for (char *s = val; *s; s++) { - if (vim_strchr(flags, (uint8_t)(*s)) == NULL) { - return illegal_char(errbuf, errbuflen, (uint8_t)(*s)); - } + if (*p_wak == NUL || check_opt_strings(p_wak, p_wak_values, false) != OK) { + return e_invarg; } - return NULL; } -const char *did_set_guicursor(optset_T *args FUNC_ATTR_UNUSED) +/// The 'winbar' option is changed. +const char *did_set_winbar(optset_T *args) { - return parse_shape_opt(SHAPE_CURSOR); + return did_set_statustabline_rulerformat(args, false, false); +} + +const char *did_set_winhl(optset_T *args) +{ + win_T *win = (win_T *)args->os_win; + if (!parse_winhl_opt(win)) { + return e_invarg; + } + return NULL; } // When 'syntax' is set, load the syntax of that name @@ -2564,3 +2558,15 @@ const char *check_chars_options(void) } return NULL; } + +/// Handle the new value of 'fillchars'. +const char *set_fillchars_option(win_T *wp, char *val, bool 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, bool apply) +{ + return set_chars_option(wp, val, true, apply); +} |