diff options
Diffstat (limited to 'src/nvim/option.c')
-rw-r--r-- | src/nvim/option.c | 631 |
1 files changed, 467 insertions, 164 deletions
diff --git a/src/nvim/option.c b/src/nvim/option.c index 44b7d98e88..f6037fc20a 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -47,6 +47,7 @@ #include "nvim/getchar.h" #include "nvim/hardcopy.h" #include "nvim/highlight.h" +#include "nvim/highlight_group.h" #include "nvim/indent_c.h" #include "nvim/keymap.h" #include "nvim/macros.h" @@ -55,7 +56,6 @@ #include "nvim/memline.h" #include "nvim/memory.h" #include "nvim/message.h" -#include "nvim/misc1.h" #include "nvim/mouse.h" #include "nvim/move.h" #include "nvim/normal.h" @@ -133,6 +133,7 @@ static int p_cin; static char_u *p_cink; static char_u *p_cino; static char_u *p_cinw; +static char_u *p_cinsd; static char_u *p_com; static char_u *p_cms; static char_u *p_cpt; @@ -262,6 +263,7 @@ typedef struct vimoption { #define HIGHLIGHT_INIT \ "8:SpecialKey,~:EndOfBuffer,z:TermCursor,Z:TermCursorNC,@:NonText,d:Directory,e:ErrorMsg," \ "i:IncSearch,l:Search,m:MoreMsg,M:ModeMsg,n:LineNr,a:LineNrAbove,b:LineNrBelow,N:CursorLineNr," \ + "G:CursorLineSign,O:CursorLineFold" \ "r:Question,s:StatusLine,S:StatusLineNC,c:VertSplit,t:Title,v:Visual,V:VisualNOS,w:WarningMsg," \ "W:WildMenu,f:Folded,F:FoldColumn,A:DiffAdd,C:DiffChange,D:DiffDelete,T:DiffText,>:SignColumn," \ "-:Conceal,B:SpellBad,P:SpellCap,R:SpellRare,L:SpellLocal,+:Pmenu,=:PmenuSel,x:PmenuSbar," \ @@ -281,7 +283,7 @@ typedef struct vimoption { # include "options.generated.h" #endif -#define PARAM_COUNT ARRAY_SIZE(options) +#define OPTION_COUNT ARRAY_SIZE(options) static char *(p_ambw_values[]) = { "single", "double", NULL }; static char *(p_bg_values[]) = { "light", "dark", NULL }; @@ -931,6 +933,21 @@ void set_title_defaults(void) } } +void ex_set(exarg_T *eap) +{ + int flags = 0; + + if (eap->cmdidx == CMD_setlocal) { + flags = OPT_LOCAL; + } else if (eap->cmdidx == CMD_setglobal) { + flags = OPT_GLOBAL; + } + if (eap->forceit) { + flags |= OPT_ONECOLUMN; + } + (void)do_set(eap->arg, flags); +} + /// Parse 'arg' for option settings. /// /// 'arg' may be IObuff, but only when no errors can be present and option @@ -1301,7 +1318,11 @@ int do_set(char_u *arg, int opt_flags) char_u *oldval = NULL; // previous value if *varp char_u *newval; char_u *origval = NULL; + char_u *origval_l = NULL; + char_u *origval_g = NULL; char *saved_origval = NULL; + char *saved_origval_l = NULL; + char *saved_origval_g = NULL; char *saved_newval = NULL; unsigned newlen; int comma; @@ -1319,10 +1340,21 @@ int do_set(char_u *arg, int opt_flags) // new value is valid. oldval = *(char_u **)varp; + if ((opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0) { + origval_l = *(char_u **)get_varp_scope(&(options[opt_idx]), OPT_LOCAL); + origval_g = *(char_u **)get_varp_scope(&(options[opt_idx]), OPT_GLOBAL); + + // A global-local string option might have an empty + // option as value to indicate that the global + // value should be used. + if (((int)options[opt_idx].indir & PV_BOTH) && origval_l == empty_option) { + origval_l = origval_g; + } + } + // When setting the local value of a global // option, the old value may be the global value. - if (((int)options[opt_idx].indir & PV_BOTH) && (opt_flags - & OPT_LOCAL)) { + if (((int)options[opt_idx].indir & PV_BOTH) && (opt_flags & OPT_LOCAL)) { origval = *(char_u **)get_varp(&options[opt_idx]); } else { origval = oldval; @@ -1330,7 +1362,7 @@ int do_set(char_u *arg, int opt_flags) if (nextchar == '&') { // set to default val newval = options[opt_idx].def_val; - // expand environment variables and ~ (since the + // expand environment variables and ~ since the // default value was already expanded, only // required when an environment variable was set // later @@ -1388,6 +1420,12 @@ int do_set(char_u *arg, int opt_flags) if (origval == oldval) { origval = *(char_u **)varp; } + if (origval_l == oldval) { + origval_l = *(char_u **)varp; + } + if (origval_g == oldval) { + origval_g = *(char_u **)varp; + } oldval = *(char_u **)varp; } /* @@ -1596,6 +1634,8 @@ int do_set(char_u *arg, int opt_flags) // origval may be freed by // did_set_string_option(), make a copy. saved_origval = (origval != NULL) ? xstrdup((char *)origval) : 0; + saved_origval_l = (origval_l != NULL) ? xstrdup((char *)origval_l) : 0; + saved_origval_g = (origval_g != NULL) ? xstrdup((char *)origval_g) : 0; // newval (and varp) may become invalid if the // buffer is closed by autocommands. @@ -1630,8 +1670,8 @@ int do_set(char_u *arg, int opt_flags) if (errmsg == NULL) { if (!starting) { - trigger_optionsset_string(opt_idx, opt_flags, saved_origval, - saved_newval); + trigger_optionsset_string(opt_idx, opt_flags, saved_origval, saved_origval_l, + saved_origval_g, saved_newval); } if (options[opt_idx].flags & P_UI_OPTION) { ui_call_option_set(cstr_as_string(options[opt_idx].fullname), @@ -1639,6 +1679,8 @@ int do_set(char_u *arg, int opt_flags) } } xfree(saved_origval); + xfree(saved_origval_l); + xfree(saved_origval_g); xfree(saved_newval); // If error detected, print the error message. @@ -1741,7 +1783,7 @@ static char *illegal_char(char *errbuf, size_t errbuflen, int c) if (errbuf == NULL) { return ""; } - vim_snprintf((char *)errbuf, errbuflen, _("E539: Illegal character <%s>"), + vim_snprintf(errbuf, errbuflen, _("E539: Illegal character <%s>"), (char *)transchar(c)); return errbuf; } @@ -1944,10 +1986,9 @@ static void didset_options(void) (void)did_set_spell_option(true); // set cedit_key (void)check_cedit(); - briopt_check(curwin); // initialize the table for 'breakat'. fill_breakat_flags(); - fill_culopt_flags(NULL, curwin); + didset_window_options(curwin); } // More side effects of setting options. @@ -1968,9 +2009,9 @@ static void didset_options2(void) // Parse default for 'wildmode'. check_opt_wim(); xfree(curbuf->b_p_vsts_array); - tabstop_set(curbuf->b_p_vsts, &curbuf->b_p_vsts_array); + (void)tabstop_set(curbuf->b_p_vsts, &curbuf->b_p_vsts_array); xfree(curbuf->b_p_vts_array); - tabstop_set(curbuf->b_p_vts, &curbuf->b_p_vts_array); + (void)tabstop_set(curbuf->b_p_vts, &curbuf->b_p_vts_array); } /// Check for string options that are NULL (normally only termcap options). @@ -2020,6 +2061,7 @@ void check_buf_options(buf_T *buf) parse_cino(buf); check_string_option(&buf->b_p_ft); check_string_option(&buf->b_p_cinw); + check_string_option(&buf->b_p_cinsd); check_string_option(&buf->b_p_cpt); check_string_option(&buf->b_p_cfu); check_string_option(&buf->b_p_ofu); @@ -2233,13 +2275,23 @@ static char *set_string_option(const int opt_idx, const char *const value, const ? OPT_GLOBAL : OPT_LOCAL) : opt_flags)); char *const oldval = *varp; + char *oldval_l = NULL; + char *oldval_g = NULL; + + if ((opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0) { + oldval_l = *(char **)get_varp_scope(&(options[opt_idx]), OPT_LOCAL); + oldval_g = *(char **)get_varp_scope(&(options[opt_idx]), OPT_GLOBAL); + } + *varp = s; char *const saved_oldval = xstrdup(oldval); + char *const saved_oldval_l = (oldval_l != NULL) ? xstrdup(oldval_l) : 0; + char *const saved_oldval_g = (oldval_g != NULL) ? xstrdup(oldval_g) : 0; char *const saved_newval = xstrdup(s); int value_checked = false; - char *const r = did_set_string_option(opt_idx, (char_u **)varp, (int)true, + char *const r = did_set_string_option(opt_idx, (char_u **)varp, true, (char_u *)oldval, NULL, 0, opt_flags, &value_checked); if (r == NULL) { @@ -2249,7 +2301,8 @@ static char *set_string_option(const int opt_idx, const char *const value, const // call autocommand after handling side effects if (r == NULL) { if (!starting) { - trigger_optionsset_string(opt_idx, opt_flags, saved_oldval, saved_newval); + trigger_optionsset_string(opt_idx, opt_flags, saved_oldval, saved_oldval_l, saved_oldval_g, + saved_newval); } if (options[opt_idx].flags & P_UI_OPTION) { ui_call_option_set(cstr_as_string(options[opt_idx].fullname), @@ -2257,6 +2310,8 @@ static char *set_string_option(const int opt_idx, const char *const value, const } } xfree(saved_oldval); + xfree(saved_oldval_l); + xfree(saved_oldval_g); xfree(saved_newval); return r; @@ -2650,24 +2705,38 @@ ambw_end: } s = skip_to_option_part(s); } - } else if (varp == &p_lcs) { // 'listchars' + } else if (varp == &p_lcs) { // global 'listchars' errmsg = set_chars_option(curwin, varp, false); - if (!errmsg) { + if (errmsg == NULL) { + // The current window is set to use the global 'listchars' value. + // So clear the window-local value. + if (!(opt_flags & OPT_GLOBAL)) { + clear_string_option(&curwin->w_p_lcs); + } FOR_ALL_TAB_WINDOWS(tp, wp) { - set_chars_option(wp, &wp->w_p_lcs, true); + // If no error was returned above, we don't expect an error + // here, so ignore the return value. + (void)set_chars_option(wp, &wp->w_p_lcs, true); } + redraw_all_later(NOT_VALID); } - redraw_all_later(NOT_VALID); } else if (varp == &curwin->w_p_lcs) { // local 'listchars' errmsg = set_chars_option(curwin, varp, true); - } else if (varp == &p_fcs) { // 'fillchars' + } else if (varp == &p_fcs) { // global 'fillchars' errmsg = set_chars_option(curwin, varp, false); - if (!errmsg) { + if (errmsg == NULL) { + // The current window is set to use the global 'fillchars' value. + // So clear the window-local value. + if (!(opt_flags & OPT_GLOBAL)) { + clear_string_option(&curwin->w_p_fcs); + } FOR_ALL_TAB_WINDOWS(tp, wp) { - set_chars_option(wp, &wp->w_p_fcs, true); + // If no error was returned above, we don't expect an error + // here, so ignore the return value. + (void)set_chars_option(wp, &wp->w_p_fcs, true); } + redraw_all_later(NOT_VALID); } - redraw_all_later(NOT_VALID); } else if (varp == &curwin->w_p_fcs) { // local 'fillchars' errmsg = set_chars_option(curwin, varp, true); } else if (varp == &p_cedit) { // 'cedit' @@ -2710,7 +2779,7 @@ ambw_end: if (!ascii_isdigit(*(s - 1))) { if (errbuf != NULL) { - vim_snprintf((char *)errbuf, errbuflen, + vim_snprintf(errbuf, errbuflen, _("E526: Missing number after <%s>"), transchar_byte(*(s - 1))); errmsg = errbuf; @@ -2844,7 +2913,7 @@ ambw_end: || check_opt_strings(curbuf->b_p_bt, p_buftype_values, false) != OK) { errmsg = e_invarg; } else { - if (curwin->w_status_height) { + if (curwin->w_status_height || global_stl_height()) { curwin->w_redr_status = true; redraw_later(curwin, VALID); } @@ -2901,7 +2970,7 @@ ambw_end: } } else { if (errbuf != NULL) { - vim_snprintf((char *)errbuf, errbuflen, + vim_snprintf(errbuf, errbuflen, _("E535: Illegal character after <%c>"), *--s); errmsg = errbuf; @@ -2939,7 +3008,7 @@ ambw_end: } } else if (varp == &curwin->w_p_fdc || varp == &curwin->w_allbuf_opt.wo_fdc) { // 'foldcolumn' - if (check_opt_strings(*varp, p_fdc_values, false) != OK) { + if (**varp == NUL || check_opt_strings(*varp, p_fdc_values, false) != OK) { errmsg = e_invarg; } } else if (varp == &p_pt) { @@ -3032,14 +3101,27 @@ ambw_end: if (foldmethodIsIndent(curwin)) { foldUpdateAll(curwin); } - } else if (varp == &p_ve) { // 'virtualedit' - if (opt_strings_flags(p_ve, p_ve_values, &ve_flags, true) != OK) { - errmsg = e_invarg; - } else if (STRCMP(p_ve, oldval) != 0) { - // Recompute cursor position in case the new 've' setting - // changes something. - validate_virtcol(); - coladvance(curwin->w_virtcol); + } else if (gvarp == &p_ve) { // 'virtualedit' + char_u *ve = p_ve; + unsigned int *flags = &ve_flags; + + if (opt_flags & OPT_LOCAL) { + ve = curwin->w_p_ve; + flags = &curwin->w_ve_flags; + } + + if ((opt_flags & OPT_LOCAL) && *ve == NUL) { + // make the local value empty: use the global value + *flags = 0; + } else { + if (opt_strings_flags(ve, p_ve_values, flags, true) != OK) { + errmsg = e_invarg; + } else if (STRCMP(p_ve, oldval) != 0) { + // Recompute cursor position in case the new 've' setting + // changes something. + validate_virtcol(); + coladvance(curwin->w_virtcol); + } } } else if (varp == &p_csqf) { if (p_csqf != NULL) { @@ -3098,10 +3180,7 @@ ambw_end: char_u *cp; if (!(*varp)[0] || ((*varp)[0] == '0' && !(*varp)[1])) { - if (curbuf->b_p_vsts_array) { - xfree(curbuf->b_p_vsts_array); - curbuf->b_p_vsts_array = 0; - } + XFREE_CLEAR(curbuf->b_p_vsts_array); } else { for (cp = *varp; *cp; cp++) { if (ascii_isdigit(*cp)) { @@ -3126,10 +3205,7 @@ ambw_end: char_u *cp; if (!(*varp)[0] || ((*varp)[0] == '0' && !(*varp)[1])) { - if (curbuf->b_p_vts_array) { - xfree(curbuf->b_p_vts_array); - curbuf->b_p_vts_array = NULL; - } + XFREE_CLEAR(curbuf->b_p_vts_array); } else { for (cp = *varp; *cp; cp++) { if (ascii_isdigit(*cp)) { @@ -3318,6 +3394,9 @@ static int int_cmp(const void *a, const void *b) /// @return OK when the value is valid, FAIL otherwise int check_signcolumn(char_u *val) { + if (*val == NUL) { + return FAIL; + } // check for basic match if (check_opt_strings(val, p_scl_values, false) == OK) { return OK; @@ -3477,16 +3556,22 @@ static char *set_chars_option(win_T *wp, char_u **varp, bool set) struct chars_tab *tab; struct chars_tab fcs_tab[] = { - { &wp->w_p_fcs_chars.stl, "stl", ' ' }, - { &wp->w_p_fcs_chars.stlnc, "stlnc", ' ' }, - { &wp->w_p_fcs_chars.vert, "vert", 9474 }, // │ - { &wp->w_p_fcs_chars.fold, "fold", 183 }, // · - { &wp->w_p_fcs_chars.foldopen, "foldopen", '-' }, - { &wp->w_p_fcs_chars.foldclosed, "foldclose", '+' }, - { &wp->w_p_fcs_chars.foldsep, "foldsep", 9474 }, // │ - { &wp->w_p_fcs_chars.diff, "diff", '-' }, - { &wp->w_p_fcs_chars.msgsep, "msgsep", ' ' }, - { &wp->w_p_fcs_chars.eob, "eob", '~' }, + { &wp->w_p_fcs_chars.stl, "stl", ' ' }, + { &wp->w_p_fcs_chars.stlnc, "stlnc", ' ' }, + { &wp->w_p_fcs_chars.horiz, "horiz", 9472 }, // ─ + { &wp->w_p_fcs_chars.horizup, "horizup", 9524 }, // ┴ + { &wp->w_p_fcs_chars.horizdown, "horizdown", 9516 }, // ┬ + { &wp->w_p_fcs_chars.vert, "vert", 9474 }, // │ + { &wp->w_p_fcs_chars.vertleft, "vertleft", 9508 }, // ┤ + { &wp->w_p_fcs_chars.vertright, "vertright", 9500 }, // ├ + { &wp->w_p_fcs_chars.verthoriz, "verthoriz", 9532 }, // ┼ + { &wp->w_p_fcs_chars.fold, "fold", 183 }, // · + { &wp->w_p_fcs_chars.foldopen, "foldopen", '-' }, + { &wp->w_p_fcs_chars.foldclosed, "foldclose", '+' }, + { &wp->w_p_fcs_chars.foldsep, "foldsep", 9474 }, // │ + { &wp->w_p_fcs_chars.diff, "diff", '-' }, + { &wp->w_p_fcs_chars.msgsep, "msgsep", ' ' }, + { &wp->w_p_fcs_chars.eob, "eob", '~' }, }; struct chars_tab lcs_tab[] = { { &wp->w_p_lcs_chars.eol, "eol", NUL }, @@ -3513,15 +3598,17 @@ static char *set_chars_option(win_T *wp, char_u **varp, bool set) varp = &p_fcs; } if (*p_ambw == 'd') { - // XXX: If ambiwidth=double then "|" and "·" take 2 columns, which is - // forbidden (TUI limitation?). Set old defaults. - fcs_tab[2].def = '|'; - fcs_tab[6].def = '|'; - fcs_tab[3].def = '-'; - } else { - fcs_tab[2].def = 9474; // │ - fcs_tab[6].def = 9474; // │ - fcs_tab[3].def = 183; // · + // XXX: If ambiwidth=double then some characters take 2 columns, + // which is forbidden (TUI limitation?). Set old defaults. + fcs_tab[2].def = '-'; + fcs_tab[3].def = '-'; + fcs_tab[4].def = '-'; + fcs_tab[5].def = '|'; + fcs_tab[6].def = '|'; + fcs_tab[7].def = '|'; + fcs_tab[8].def = '+'; + fcs_tab[9].def = '-'; + fcs_tab[12].def = '|'; } } @@ -3558,7 +3645,7 @@ static char *set_chars_option(win_T *wp, char_u **varp, bool set) c2 = c3 = 0; s = p + len + 1; c1 = get_encoded_char_adv(&s); - if (c1 == 0 || utf_char2cells(c1) > 1) { + if (c1 == 0 || char2cells(c1) > 1) { return e_invarg; } if (tab[i].cp == &wp->w_p_lcs_chars.tab2) { @@ -3566,12 +3653,12 @@ static char *set_chars_option(win_T *wp, char_u **varp, bool set) return e_invarg; } c2 = get_encoded_char_adv(&s); - if (c2 == 0 || utf_char2cells(c2) > 1) { + if (c2 == 0 || char2cells(c2) > 1) { return e_invarg; } if (!(*s == ',' || *s == NUL)) { c3 = get_encoded_char_adv(&s); - if (c3 == 0 || utf_char2cells(c3) > 1) { + if (c3 == 0 || char2cells(c3) > 1) { return e_invarg; } } @@ -3605,7 +3692,7 @@ static char *set_chars_option(win_T *wp, char_u **varp, bool set) multispace_len = 0; while (*s != NUL && *s != ',') { c1 = get_encoded_char_adv(&s); - if (c1 == 0 || utf_char2cells(c1) > 1) { + if (c1 == 0 || char2cells(c1) > 1) { return e_invarg; } multispace_len++; @@ -3769,13 +3856,13 @@ static bool parse_winhl_opt(win_T *wp) size_t nlen = (size_t)(colon-p); char *hi = colon+1; char *commap = xstrchrnul(hi, ','); - int len = (int)(commap-hi); + size_t len = (size_t)(commap-hi); int hl_id = len ? syn_check_group(hi, len) : -1; if (strncmp("Normal", p, nlen) == 0) { w_hl_id_normal = hl_id; } else { - for (hlf = 0; hlf < (int)HLF_COUNT; hlf++) { + for (hlf = 0; hlf < HLF_COUNT; hlf++) { if (strlen(hlf_names[hlf]) == nlen && strncmp(hlf_names[hlf], p, nlen) == 0) { w_hl_ids[hlf] = hl_id; @@ -3802,6 +3889,7 @@ static void set_option_sctx_idx(int opt_idx, int opt_flags, sctx_T script_ctx) { int both = (opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0; int indir = (int)options[opt_idx].indir; + nlua_set_sctx(&script_ctx); const LastSet last_set = { .script_ctx = { script_ctx.sc_sid, @@ -3837,6 +3925,7 @@ static char *set_bool_option(const int opt_idx, char_u *const varp, const int va 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) @@ -3844,6 +3933,13 @@ static char *set_bool_option(const int opt_idx, char_u *const varp, const int va return (char *)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); @@ -3868,11 +3964,8 @@ static char *set_bool_option(const int opt_idx, char_u *const varp, const int va } else if ((int *)varp == &p_lnr) { // 'langnoremap' -> !'langremap' p_lrm = !p_lnr; - } else if ((int *)varp == &curwin->w_p_cul && !value && old_value) { - // 'cursorline' - reset_cursorline(); - // 'undofile' } else if ((int *)varp == &curbuf->b_p_udf || (int *)varp == &p_udf) { + // 'undofile' // Only take action when the option was set. When reset we do not // delete the undo file, the option may be set again without making // any changes in between. @@ -4069,7 +4162,7 @@ static char *set_bool_option(const int opt_idx, char_u *const varp, const int va } } - // Arabic requires a utf-8 encoding, inform the user if its not + // 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'"); @@ -4120,20 +4213,35 @@ static char *set_bool_option(const int opt_idx, char_u *const varp, const int va // Don't do this while starting up or recursively. if (!starting && *get_vim_var_str(VV_OPTION_TYPE) == NUL) { char buf_old[2]; + char buf_old_global[2]; char buf_new[2]; char buf_type[7]; - vim_snprintf(buf_old, ARRAY_SIZE(buf_old), "%d", - old_value ? true: false); - vim_snprintf(buf_new, ARRAY_SIZE(buf_new), "%d", - value ? true: false); + vim_snprintf(buf_old, ARRAY_SIZE(buf_old), "%d", old_value ? true : false); + vim_snprintf(buf_old_global, ARRAY_SIZE(buf_old_global), "%d", old_global_value ? true : false); + vim_snprintf(buf_new, ARRAY_SIZE(buf_new), "%d", value ? true : false); vim_snprintf(buf_type, ARRAY_SIZE(buf_type), "%s", (opt_flags & OPT_LOCAL) ? "local" : "global"); set_vim_var_string(VV_OPTION_NEW, buf_new, -1); set_vim_var_string(VV_OPTION_OLD, buf_old, -1); set_vim_var_string(VV_OPTION_TYPE, buf_type, -1); - apply_autocmds(EVENT_OPTIONSET, - (char_u *)options[opt_idx].fullname, - NULL, false, NULL); + if (opt_flags & OPT_LOCAL) { + set_vim_var_string(VV_OPTION_COMMAND, "setlocal", -1); + set_vim_var_string(VV_OPTION_OLDLOCAL, buf_old, -1); + } + if (opt_flags & OPT_GLOBAL) { + set_vim_var_string(VV_OPTION_COMMAND, "setglobal", -1); + set_vim_var_string(VV_OPTION_OLDGLOBAL, buf_old, -1); + } + if ((opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0) { + set_vim_var_string(VV_OPTION_COMMAND, "set", -1); + set_vim_var_string(VV_OPTION_OLDLOCAL, buf_old, -1); + set_vim_var_string(VV_OPTION_OLDGLOBAL, buf_old_global, -1); + } + if (opt_flags & OPT_MODELINE) { + set_vim_var_string(VV_OPTION_COMMAND, "modeline", -1); + set_vim_var_string(VV_OPTION_OLDLOCAL, buf_old, -1); + } + apply_autocmds(EVENT_OPTIONSET, (char_u *)options[opt_idx].fullname, NULL, false, NULL); reset_v_option_vars(); } @@ -4167,7 +4275,8 @@ static char *set_num_option(int opt_idx, char_u *varp, long value, char *errbuf, { char *errmsg = NULL; long old_value = *(long *)varp; - long old_Rows = Rows; // remember old Rows + long old_global_value = 0; // only used when setting a local and global option + long old_Rows = Rows; // remember old Rows long *pp = (long *)varp; // Disallow changing some options from secure mode. @@ -4176,6 +4285,13 @@ static char *set_num_option(int opt_idx, char_u *varp, long value, char *errbuf, 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 = *(long *)get_varp_scope(&(options[opt_idx]), OPT_GLOBAL); + } + // Many number options assume their value is in the signed int range. if (value < INT_MIN || value > INT_MAX) { return e_invarg; @@ -4235,6 +4351,12 @@ static char *set_num_option(int opt_idx, char_u *varp, long value, char *errbuf, } else if (value > 10000) { errmsg = e_invarg; } + } else if (pp == &p_pyx) { + if (value == 0) { + value = 3; + } else if (value != 3) { + errmsg = e_invarg; + } } else if (pp == &p_re) { if (value < 0 || value > 2) { errmsg = e_invarg; @@ -4300,6 +4422,8 @@ static char *set_num_option(int opt_idx, char_u *varp, long value, char *errbuf, } else if (pp == &curbuf->b_p_ts || pp == &p_ts) { if (value < 1) { errmsg = e_positive; + } else if (value > TABSTOP_MAX) { + errmsg = e_invarg; } } else if (pp == &curbuf->b_p_tw || pp == &p_tw) { if (value < 0) { @@ -4313,7 +4437,7 @@ static char *set_num_option(int opt_idx, char_u *varp, long value, char *errbuf, // Don't change the value and return early if validation failed. if (errmsg != NULL) { - return (char *)errmsg; + return errmsg; } *pp = value; @@ -4359,6 +4483,20 @@ static char *set_num_option(int opt_idx, char_u *varp, long value, char *errbuf, // 'winminwidth' win_setminwidth(); } else if (pp == &p_ls) { + // 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. } else if (pp == &p_stal) { // (re)set tab page line @@ -4409,10 +4547,6 @@ static char *set_num_option(int opt_idx, char_u *varp, long value, char *errbuf, if (pum_drawn()) { pum_redraw(); } - } else if (pp == &p_pyx) { - if (p_pyx != 0 && p_pyx != 2 && p_pyx != 3) { - errmsg = e_invarg; - } } else if (pp == &p_ul || pp == &curbuf->b_p_ul) { // sync undo before 'undolevels' changes // use the old value, otherwise u_sync() may not work properly @@ -4441,7 +4575,7 @@ static char *set_num_option(int opt_idx, char_u *varp, long value, char *errbuf, // Check the (new) bounds for Rows and Columns here. if (p_lines < min_rows() && full_screen) { if (errbuf != NULL) { - vim_snprintf((char *)errbuf, errbuflen, + vim_snprintf(errbuf, errbuflen, _("E593: Need at least %d lines"), min_rows()); errmsg = errbuf; } @@ -4449,7 +4583,7 @@ static char *set_num_option(int opt_idx, char_u *varp, long value, char *errbuf, } if (p_columns < MIN_COLUMNS && full_screen) { if (errbuf != NULL) { - vim_snprintf((char *)errbuf, errbuflen, + vim_snprintf(errbuf, errbuflen, _("E594: Need at least %d columns"), MIN_COLUMNS); errmsg = errbuf; } @@ -4520,19 +4654,36 @@ static char *set_num_option(int opt_idx, char_u *varp, long value, char *errbuf, // Don't do this while starting up, failure or recursively. if (!starting && errmsg == NULL && *get_vim_var_str(VV_OPTION_TYPE) == NUL) { char buf_old[NUMBUFLEN]; + char buf_old_global[NUMBUFLEN]; char buf_new[NUMBUFLEN]; char buf_type[7]; vim_snprintf(buf_old, ARRAY_SIZE(buf_old), "%ld", old_value); + vim_snprintf(buf_old_global, ARRAY_SIZE(buf_old_global), "%ld", old_global_value); vim_snprintf(buf_new, ARRAY_SIZE(buf_new), "%ld", value); vim_snprintf(buf_type, ARRAY_SIZE(buf_type), "%s", (opt_flags & OPT_LOCAL) ? "local" : "global"); set_vim_var_string(VV_OPTION_NEW, buf_new, -1); set_vim_var_string(VV_OPTION_OLD, buf_old, -1); set_vim_var_string(VV_OPTION_TYPE, buf_type, -1); - apply_autocmds(EVENT_OPTIONSET, - (char_u *)options[opt_idx].fullname, - NULL, false, NULL); + if (opt_flags & OPT_LOCAL) { + set_vim_var_string(VV_OPTION_COMMAND, "setlocal", -1); + set_vim_var_string(VV_OPTION_OLDLOCAL, buf_old, -1); + } + if (opt_flags & OPT_GLOBAL) { + set_vim_var_string(VV_OPTION_COMMAND, "setglobal", -1); + set_vim_var_string(VV_OPTION_OLDGLOBAL, buf_old, -1); + } + if ((opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0) { + set_vim_var_string(VV_OPTION_COMMAND, "set", -1); + set_vim_var_string(VV_OPTION_OLDLOCAL, buf_old, -1); + set_vim_var_string(VV_OPTION_OLDGLOBAL, buf_old_global, -1); + } + if (opt_flags & OPT_MODELINE) { + set_vim_var_string(VV_OPTION_COMMAND, "modeline", -1); + set_vim_var_string(VV_OPTION_OLDLOCAL, buf_old, -1); + } + apply_autocmds(EVENT_OPTIONSET, (char_u *)options[opt_idx].fullname, NULL, false, NULL); reset_v_option_vars(); } @@ -4548,10 +4699,18 @@ static char *set_num_option(int opt_idx, char_u *varp, long value, char *errbuf, } check_redraw(options[opt_idx].flags); - return (char *)errmsg; + return errmsg; } -static void trigger_optionsset_string(int opt_idx, int opt_flags, char *oldval, char *newval) +/// Trigger the OptionSet autocommand. +/// "opt_idx" is the index of the option being set. +/// "opt_flags" can be OPT_LOCAL etc. +/// "oldval" the old value +/// "oldval_l" the old local value (only non-NULL if global and local value are set) +/// "oldval_g" the old global value (only non-NULL if global and local value are set) +/// "newval" the new value +static void trigger_optionsset_string(int opt_idx, int opt_flags, char *oldval, char *oldval_l, + char *oldval_g, char *newval) { // Don't do this recursively. if (oldval != NULL @@ -4564,8 +4723,24 @@ static void trigger_optionsset_string(int opt_idx, int opt_flags, char *oldval, set_vim_var_string(VV_OPTION_OLD, oldval, -1); set_vim_var_string(VV_OPTION_NEW, newval, -1); set_vim_var_string(VV_OPTION_TYPE, buf_type, -1); - apply_autocmds(EVENT_OPTIONSET, - (char_u *)options[opt_idx].fullname, NULL, false, NULL); + if (opt_flags & OPT_LOCAL) { + set_vim_var_string(VV_OPTION_COMMAND, "setlocal", -1); + set_vim_var_string(VV_OPTION_OLDLOCAL, oldval, -1); + } + if (opt_flags & OPT_GLOBAL) { + set_vim_var_string(VV_OPTION_COMMAND, "setglobal", -1); + set_vim_var_string(VV_OPTION_OLDGLOBAL, oldval, -1); + } + if ((opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0) { + set_vim_var_string(VV_OPTION_COMMAND, "set", -1); + set_vim_var_string(VV_OPTION_OLDLOCAL, oldval_l, -1); + set_vim_var_string(VV_OPTION_OLDGLOBAL, oldval_g, -1); + } + if (opt_flags & OPT_MODELINE) { + set_vim_var_string(VV_OPTION_COMMAND, "modeline", -1); + set_vim_var_string(VV_OPTION_OLDLOCAL, oldval, -1); + } + apply_autocmds(EVENT_OPTIONSET, (char_u *)options[opt_idx].fullname, NULL, false, NULL); reset_v_option_vars(); } } @@ -4757,7 +4932,8 @@ static int findoption(const char *const arg) /// @param stringval NULL when only checking existence /// /// @returns: -/// Number or Toggle option: 1, *numval gets value. +/// Toggle option: 2, *numval gets value. +/// Number option: 1, *numval gets value. /// String option: 0, *stringval gets allocated string. /// Hidden Number or Toggle option: -1. /// hidden String option: -2. @@ -4790,16 +4966,18 @@ int get_option_value(const char *name, long *numval, char_u **stringval, int opt } if (options[opt_idx].flags & P_NUM) { *numval = *(long *)varp; + return 1; + } + + // Special case: 'modified' is b_changed, but we also want to consider + // it set when 'ff' or 'fenc' changed. + if ((int *)varp == &curbuf->b_changed) { + *numval = curbufIsChanged(); } else { - // Special case: 'modified' is b_changed, but we also want to consider - // it set when 'ff' or 'fenc' changed. - if ((int *)varp == &curbuf->b_changed) { - *numval = curbufIsChanged(); - } else { - *numval = (long)*(int *)varp; // NOLINT(whitespace/cast) - } + *numval = (long)*(int *)varp; // NOLINT(whitespace/cast) } - return 1; + + return 2; } // Returns the option attributes and its value. Unlike the above function it @@ -4895,7 +5073,7 @@ int get_option_value_strict(char *name, int64_t *numval, char **stringval, int o // only getting a pointer, no need to use aucmd_prepbuf() curbuf = (buf_T *)from; curwin->w_buffer = curbuf; - varp = get_varp(p); + varp = get_varp_scope(p, OPT_LOCAL); curbuf = save_curbuf; curwin->w_buffer = curbuf; } @@ -4903,7 +5081,7 @@ int get_option_value_strict(char *name, int64_t *numval, char **stringval, int o win_T *save_curwin = curwin; curwin = (win_T *)from; curbuf = curwin->w_buffer; - varp = get_varp(p); + varp = get_varp_scope(p, OPT_LOCAL); curwin = save_curwin; curbuf = curwin->w_buffer; } @@ -4932,6 +5110,9 @@ int get_option_value_strict(char *name, int64_t *numval, char **stringval, int o /// @param[in] number New value for the number or boolean option. /// @param[in] string New value for string option. /// @param[in] opt_flags Flags: OPT_LOCAL, OPT_GLOBAL, or 0 (both). +/// If OPT_CLEAR is set, the value of the option +/// is cleared (the exact semantics of this depend +/// on the option). /// /// @return NULL on success, error message on error. char *set_option_value(const char *const name, const long number, const char *const string, @@ -4957,34 +5138,47 @@ char *set_option_value(const char *const name, const long number, const char *co } if (flags & P_STRING) { const char *s = string; - if (s == NULL) { + if (s == NULL || opt_flags & OPT_CLEAR) { s = ""; } return set_string_option(opt_idx, s, opt_flags); - } else { - varp = get_varp_scope(&(options[opt_idx]), opt_flags); - if (varp != NULL) { // hidden option is not changed - if (number == 0 && string != NULL) { - int idx; - - // Either we are given a string or we are setting option - // to zero. - for (idx = 0; string[idx] == '0'; idx++) {} - if (string[idx] != NUL || idx == 0) { - // There's another character after zeros or the string - // is empty. In both cases, we are trying to set a - // num option using a string. - semsg(_("E521: Number required: &%s = '%s'"), - name, string); - return NULL; // do nothing as we hit an error - } + } + + varp = get_varp_scope(&(options[opt_idx]), opt_flags); + if (varp != NULL) { // hidden option is not changed + if (number == 0 && string != NULL) { + int idx; + + // Either we are given a string or we are setting option + // to zero. + for (idx = 0; string[idx] == '0'; idx++) {} + if (string[idx] != NUL || idx == 0) { + // There's another character after zeros or the string + // is empty. In both cases, we are trying to set a + // num option using a string. + semsg(_("E521: Number required: &%s = '%s'"), + name, string); + return NULL; // do nothing as we hit an error } - if (flags & P_NUM) { - return set_num_option(opt_idx, varp, number, NULL, 0, opt_flags); + } + long numval = number; + if (opt_flags & OPT_CLEAR) { + if ((int *)varp == &curbuf->b_p_ar) { + numval = -1; + } else if ((long *)varp == &curbuf->b_p_ul) { + numval = NO_LOCAL_UNDOLEVEL; + } else if ((long *)varp == &curwin->w_p_so || (long *)varp == &curwin->w_p_siso) { + numval = -1; } else { - return set_bool_option(opt_idx, varp, (int)number, opt_flags); + char *s = NULL; + (void)get_option_value(name, &numval, (char_u **)&s, OPT_GLOBAL); } } + if (flags & P_NUM) { + return set_num_option(opt_idx, varp, numval, NULL, 0, opt_flags); + } else { + return set_bool_option(opt_idx, varp, (int)numval, opt_flags); + } } } return NULL; @@ -5038,7 +5232,7 @@ static void showoptions(int all, int opt_flags) #define INC 20 #define GAP 3 - vimoption_T **items = xmalloc(sizeof(vimoption_T *) * PARAM_COUNT); + vimoption_T **items = xmalloc(sizeof(vimoption_T *) * OPTION_COUNT); // Highlight title if (opt_flags & OPT_GLOBAL) { @@ -5052,6 +5246,7 @@ static void showoptions(int all, int opt_flags) // Do the loop two times: // 1. display the short items // 2. display the long items (only strings and numbers) + // When "opt_flags" has OPT_ONECOLUMN do everything in run 2. for (run = 1; run <= 2 && !got_int; run++) { // collect the items in items[] item_count = 0; @@ -5062,7 +5257,7 @@ static void showoptions(int all, int opt_flags) } varp = NULL; - if (opt_flags != 0) { + if ((opt_flags & (OPT_LOCAL | OPT_GLOBAL)) != 0) { if (p->indir != PV_NONE) { varp = get_varp_scope(p, opt_flags); } @@ -5071,8 +5266,10 @@ static void showoptions(int all, int opt_flags) } if (varp != NULL && (all == 1 || (all == 0 && !optval_default(p, varp)))) { - if (p->flags & P_BOOL) { - len = 1; // a toggle option fits always + if (opt_flags & OPT_ONECOLUMN) { + len = Columns; + } else if (p->flags & P_BOOL) { + len = 1; // a toggle option fits always } else { option_value2string(p, opt_flags); len = (int)STRLEN(p->fullname) + vim_strsize(NameBuff) + 1; @@ -5092,7 +5289,7 @@ static void showoptions(int all, int opt_flags) && Columns + GAP >= INT_MIN + 3 && (Columns + GAP - 3) / INC >= INT_MIN && (Columns + GAP - 3) / INC <= INT_MAX); - cols = (int)((Columns + GAP - 3) / INC); + cols = (Columns + GAP - 3) / INC; if (cols == 0) { cols = 1; } @@ -5471,7 +5668,7 @@ static int put_setbool(FILE *fd, char *cmd, char *name, int value) void comp_col(void) { - int last_has_status = (p_ls == 2 || (p_ls == 1 && !ONE_WINDOW)); + int last_has_status = (p_ls > 1 || (p_ls == 1 && !ONE_WINDOW)); sc_col = 0; ru_col = 0; @@ -5489,13 +5686,11 @@ void comp_col(void) } } assert(sc_col >= 0 - && INT_MIN + sc_col <= Columns - && Columns - sc_col <= INT_MAX); - sc_col = (int)(Columns - sc_col); + && INT_MIN + sc_col <= Columns); + sc_col = Columns - sc_col; assert(ru_col >= 0 - && INT_MIN + ru_col <= Columns - && Columns - ru_col <= INT_MAX); - ru_col = (int)(Columns - ru_col); + && INT_MIN + ru_col <= Columns); + ru_col = Columns - ru_col; if (sc_col <= 0) { // screen too narrow, will become a mess sc_col = 1; } @@ -5602,6 +5797,10 @@ void unset_global_local_option(char *name, void *from) set_chars_option((win_T *)from, &((win_T *)from)->w_p_fcs, true); redraw_later((win_T *)from, NOT_VALID); break; + case PV_VE: + clear_string_option(&((win_T *)from)->w_p_ve); + ((win_T *)from)->w_ve_flags = 0; + break; } } @@ -5668,6 +5867,8 @@ static char_u *get_varp_scope(vimoption_T *p, int opt_flags) return (char_u *)&(curwin->w_p_fcs); case PV_LCS: return (char_u *)&(curwin->w_p_lcs); + case PV_VE: + return (char_u *)&(curwin->w_p_ve); } return NULL; // "cannot happen" } @@ -5762,6 +5963,9 @@ static char_u *get_varp(vimoption_T *p) case PV_LCS: return *curwin->w_p_lcs != NUL ? (char_u *)&(curwin->w_p_lcs) : p->var; + case PV_VE: + return *curwin->w_p_ve != NUL + ? (char_u *)&curwin->w_p_ve : p->var; case PV_ARAB: return (char_u *)&(curwin->w_p_arab); @@ -5856,6 +6060,8 @@ static char_u *get_varp(vimoption_T *p) return (char_u *)&(curbuf->b_p_cink); case PV_CINO: return (char_u *)&(curbuf->b_p_cino); + case PV_CINSD: + return (char_u *)&(curbuf->b_p_cinsd); case PV_CINW: return (char_u *)&(curbuf->b_p_cinw); case PV_COM: @@ -5990,6 +6196,7 @@ void win_copy_options(win_T *wp_from, win_T *wp_to) { copy_winopt(&wp_from->w_onebuf_opt, &wp_to->w_onebuf_opt); copy_winopt(&wp_from->w_allbuf_opt, &wp_to->w_allbuf_opt); + didset_window_options(wp_to); } /// Copy the options from one winopt_T to another. @@ -6002,6 +6209,8 @@ void copy_winopt(winopt_T *from, winopt_T *to) to->wo_list = from->wo_list; to->wo_nu = from->wo_nu; to->wo_rnu = from->wo_rnu; + to->wo_ve = vim_strsave(from->wo_ve); + to->wo_ve_flags = from->wo_ve_flags; to->wo_nuw = from->wo_nuw; to->wo_rl = from->wo_rl; to->wo_rlc = vim_strsave(from->wo_rlc); @@ -6046,6 +6255,9 @@ void copy_winopt(winopt_T *from, winopt_T *to) to->wo_fcs = vim_strsave(from->wo_fcs); to->wo_lcs = vim_strsave(from->wo_lcs); to->wo_winbl = from->wo_winbl; + + // Copy the script context so that we know were the value was last set. + memmove(to->wo_script_ctx, from->wo_script_ctx, sizeof(to->wo_script_ctx)); check_winopt(to); // don't want NULL pointers } @@ -6078,6 +6290,7 @@ static void check_winopt(winopt_T *wop) check_string_option(&wop->wo_winhl); check_string_option(&wop->wo_fcs); check_string_option(&wop->wo_lcs); + check_string_option(&wop->wo_ve); } /// Free the allocated memory inside a winopt_T. @@ -6102,6 +6315,7 @@ void clear_winopt(winopt_T *wop) clear_string_option(&wop->wo_winhl); clear_string_option(&wop->wo_fcs); clear_string_option(&wop->wo_lcs); + clear_string_option(&wop->wo_ve); } void didset_window_options(win_T *wp) @@ -6116,11 +6330,30 @@ void didset_window_options(win_T *wp) wp->w_grid_alloc.blending = wp->w_p_winbl > 0; } +/// Index into the options table for a buffer-local option enum. +static int buf_opt_idx[BV_COUNT]; +#define COPY_OPT_SCTX(buf, bv) buf->b_p_script_ctx[bv] = options[buf_opt_idx[bv]].last_set + +/// Initialize buf_opt_idx[] if not done already. +static void init_buf_opt_idx(void) +{ + static int did_init_buf_opt_idx = false; + + if (did_init_buf_opt_idx) { + return; + } + did_init_buf_opt_idx = true; + for (int i = 0; options[i].fullname != NULL; i++) { + if (options[i].indir & PV_BUF) { + buf_opt_idx[options[i].indir & PV_MASK] = i; + } + } +} /// Copy global option values to local options for one buffer. /// Used when creating a new buffer and sometimes when entering a buffer. /// flags: -/// BCO_ENTER We will enter the buf buffer. +/// BCO_ENTER We will enter the buffer "buf". /// BCO_ALWAYS Always copy the options, but only set b_p_initialized when /// appropriate. /// BCO_NOHELP Don't copy the values to a help buffer. @@ -6156,11 +6389,12 @@ void buf_copy_options(buf_T *buf, int flags) } if (should_copy || (flags & BCO_ALWAYS)) { - /* Don't copy the options specific to a help buffer when - * BCO_NOHELP is given or the options were initialized already - * (jumping back to a help file with CTRL-T or CTRL-O) */ - dont_do_help = ((flags & BCO_NOHELP) && buf->b_help) - || buf->b_p_initialized; + memset(buf->b_p_script_ctx, 0, sizeof(buf->b_p_script_ctx)); + init_buf_opt_idx(); + // Don't copy the options specific to a help buffer when + // BCO_NOHELP is given or the options were initialized already + // (jumping back to a help file with CTRL-T or CTRL-O) + dont_do_help = ((flags & BCO_NOHELP) && buf->b_help) || buf->b_p_initialized; if (dont_do_help) { // don't free b_p_isk save_p_isk = buf->b_p_isk; buf->b_p_isk = NULL; @@ -6192,80 +6426,131 @@ void buf_copy_options(buf_T *buf, int flags) } buf->b_p_ai = p_ai; + COPY_OPT_SCTX(buf, BV_AI); buf->b_p_ai_nopaste = p_ai_nopaste; buf->b_p_sw = p_sw; + COPY_OPT_SCTX(buf, BV_SW); buf->b_p_scbk = p_scbk; + COPY_OPT_SCTX(buf, BV_SCBK); buf->b_p_tw = p_tw; + COPY_OPT_SCTX(buf, BV_TW); buf->b_p_tw_nopaste = p_tw_nopaste; buf->b_p_tw_nobin = p_tw_nobin; buf->b_p_wm = p_wm; + COPY_OPT_SCTX(buf, BV_WM); buf->b_p_wm_nopaste = p_wm_nopaste; buf->b_p_wm_nobin = p_wm_nobin; buf->b_p_bin = p_bin; + COPY_OPT_SCTX(buf, BV_BIN); buf->b_p_bomb = p_bomb; + COPY_OPT_SCTX(buf, BV_BOMB); buf->b_p_et = p_et; + COPY_OPT_SCTX(buf, BV_ET); buf->b_p_fixeol = p_fixeol; + COPY_OPT_SCTX(buf, BV_FIXEOL); buf->b_p_et_nobin = p_et_nobin; buf->b_p_et_nopaste = p_et_nopaste; buf->b_p_ml = p_ml; + COPY_OPT_SCTX(buf, BV_ML); buf->b_p_ml_nobin = p_ml_nobin; buf->b_p_inf = p_inf; - buf->b_p_swf = cmdmod.noswapfile ? false : p_swf; + COPY_OPT_SCTX(buf, BV_INF); + if (cmdmod.noswapfile) { + buf->b_p_swf = false; + } else { + buf->b_p_swf = p_swf; + COPY_OPT_SCTX(buf, BV_SWF); + } buf->b_p_cpt = vim_strsave(p_cpt); + COPY_OPT_SCTX(buf, BV_CPT); #ifdef BACKSLASH_IN_FILENAME buf->b_p_csl = vim_strsave(p_csl); + COPY_OPT_SCTX(buf, BV_CSL); #endif buf->b_p_cfu = vim_strsave(p_cfu); + COPY_OPT_SCTX(buf, BV_CFU); buf->b_p_ofu = vim_strsave(p_ofu); + COPY_OPT_SCTX(buf, BV_OFU); buf->b_p_tfu = vim_strsave(p_tfu); + COPY_OPT_SCTX(buf, BV_TFU); buf->b_p_sts = p_sts; + COPY_OPT_SCTX(buf, BV_STS); buf->b_p_sts_nopaste = p_sts_nopaste; buf->b_p_vsts = vim_strsave(p_vsts); + COPY_OPT_SCTX(buf, BV_VSTS); if (p_vsts && p_vsts != empty_option) { - tabstop_set(p_vsts, &buf->b_p_vsts_array); + (void)tabstop_set(p_vsts, &buf->b_p_vsts_array); } else { - buf->b_p_vsts_array = 0; + buf->b_p_vsts_array = NULL; } buf->b_p_vsts_nopaste = p_vsts_nopaste ? vim_strsave(p_vsts_nopaste) : NULL; buf->b_p_com = vim_strsave(p_com); + COPY_OPT_SCTX(buf, BV_COM); buf->b_p_cms = vim_strsave(p_cms); + COPY_OPT_SCTX(buf, BV_CMS); buf->b_p_fo = vim_strsave(p_fo); + COPY_OPT_SCTX(buf, BV_FO); buf->b_p_flp = vim_strsave(p_flp); + COPY_OPT_SCTX(buf, BV_FLP); buf->b_p_nf = vim_strsave(p_nf); + COPY_OPT_SCTX(buf, BV_NF); buf->b_p_mps = vim_strsave(p_mps); + COPY_OPT_SCTX(buf, BV_MPS); buf->b_p_si = p_si; + COPY_OPT_SCTX(buf, BV_SI); buf->b_p_channel = 0; buf->b_p_ci = p_ci; + COPY_OPT_SCTX(buf, BV_CI); buf->b_p_cin = p_cin; + COPY_OPT_SCTX(buf, BV_CIN); buf->b_p_cink = vim_strsave(p_cink); + COPY_OPT_SCTX(buf, BV_CINK); buf->b_p_cino = vim_strsave(p_cino); + COPY_OPT_SCTX(buf, BV_CINO); + buf->b_p_cinsd = vim_strsave(p_cinsd); + COPY_OPT_SCTX(buf, BV_CINSD); // Don't copy 'filetype', it must be detected buf->b_p_ft = empty_option; buf->b_p_pi = p_pi; + COPY_OPT_SCTX(buf, BV_PI); buf->b_p_cinw = vim_strsave(p_cinw); + COPY_OPT_SCTX(buf, BV_CINW); buf->b_p_lisp = p_lisp; + COPY_OPT_SCTX(buf, BV_LISP); // Don't copy 'syntax', it must be set buf->b_p_syn = empty_option; buf->b_p_smc = p_smc; + COPY_OPT_SCTX(buf, BV_SMC); buf->b_s.b_syn_isk = empty_option; buf->b_s.b_p_spc = vim_strsave(p_spc); + COPY_OPT_SCTX(buf, BV_SPC); (void)compile_cap_prog(&buf->b_s); buf->b_s.b_p_spf = vim_strsave(p_spf); + COPY_OPT_SCTX(buf, BV_SPF); buf->b_s.b_p_spl = vim_strsave(p_spl); + COPY_OPT_SCTX(buf, BV_SPL); buf->b_s.b_p_spo = vim_strsave(p_spo); + COPY_OPT_SCTX(buf, BV_SPO); buf->b_p_inde = vim_strsave(p_inde); + COPY_OPT_SCTX(buf, BV_INDE); buf->b_p_indk = vim_strsave(p_indk); + COPY_OPT_SCTX(buf, BV_INDK); buf->b_p_fp = empty_option; buf->b_p_fex = vim_strsave(p_fex); + COPY_OPT_SCTX(buf, BV_FEX); buf->b_p_sua = vim_strsave(p_sua); + COPY_OPT_SCTX(buf, BV_SUA); buf->b_p_keymap = vim_strsave(p_keymap); + COPY_OPT_SCTX(buf, BV_KMAP); buf->b_kmap_state |= KEYMAP_INIT; // This isn't really an option, but copying the langmap and IME // state from the current buffer is better than resetting it. buf->b_p_iminsert = p_iminsert; + COPY_OPT_SCTX(buf, BV_IMI); buf->b_p_imsearch = p_imsearch; + COPY_OPT_SCTX(buf, BV_IMS); // options that are normally global but also have a local value // are not copied, start using the global value @@ -6285,11 +6570,14 @@ void buf_copy_options(buf_T *buf, int flags) buf->b_p_def = empty_option; buf->b_p_inc = empty_option; buf->b_p_inex = vim_strsave(p_inex); + COPY_OPT_SCTX(buf, BV_INEX); buf->b_p_dict = empty_option; buf->b_p_tsr = empty_option; buf->b_p_tsrfu = empty_option; buf->b_p_qe = vim_strsave(p_qe); + COPY_OPT_SCTX(buf, BV_QE); buf->b_p_udf = p_udf; + COPY_OPT_SCTX(buf, BV_UDF); buf->b_p_lw = empty_option; buf->b_p_menc = empty_option; @@ -6302,17 +6590,20 @@ void buf_copy_options(buf_T *buf, int flags) if (dont_do_help) { buf->b_p_isk = save_p_isk; if (p_vts && p_vts != empty_option && !buf->b_p_vts_array) { - tabstop_set(p_vts, &buf->b_p_vts_array); + (void)tabstop_set(p_vts, &buf->b_p_vts_array); } else { buf->b_p_vts_array = NULL; } } else { buf->b_p_isk = vim_strsave(p_isk); + COPY_OPT_SCTX(buf, BV_ISK); did_isk = true; buf->b_p_ts = p_ts; + COPY_OPT_SCTX(buf, BV_TS); buf->b_p_vts = vim_strsave(p_vts); + COPY_OPT_SCTX(buf, BV_VTS); if (p_vts && p_vts != empty_option && !buf->b_p_vts_array) { - tabstop_set(p_vts, &buf->b_p_vts_array); + (void)tabstop_set(p_vts, &buf->b_p_vts_array); } else { buf->b_p_vts_array = NULL; } @@ -6321,6 +6612,7 @@ void buf_copy_options(buf_T *buf, int flags) clear_string_option(&buf->b_p_bt); } buf->b_p_ma = p_ma; + COPY_OPT_SCTX(buf, BV_MA); } } @@ -6961,10 +7253,7 @@ static void paste_option_changed(void) free_string_option(buf->b_p_vsts); } buf->b_p_vsts = empty_option; - if (buf->b_p_vsts_array) { - xfree(buf->b_p_vsts_array); - } - buf->b_p_vsts_array = 0; + XFREE_CLEAR(buf->b_p_vsts_array); } // set global options @@ -7001,13 +7290,11 @@ static void paste_option_changed(void) buf->b_p_vsts = buf->b_p_vsts_nopaste ? vim_strsave(buf->b_p_vsts_nopaste) : empty_option; - if (buf->b_p_vsts_array) { - xfree(buf->b_p_vsts_array); - } + xfree(buf->b_p_vsts_array); if (buf->b_p_vsts && buf->b_p_vsts != empty_option) { - tabstop_set(buf->b_p_vsts, &buf->b_p_vsts_array); + (void)tabstop_set(buf->b_p_vsts, &buf->b_p_vsts_array); } else { - buf->b_p_vsts_array = 0; + buf->b_p_vsts_array = NULL; } } @@ -7323,6 +7610,7 @@ int check_ff_value(char_u *p) // Set the integer values corresponding to the string setting of 'vartabstop'. // "array" will be set, caller must free it if needed. +// Return false for an error. bool tabstop_set(char_u *var, long **array) { long valcount = 1; @@ -7342,7 +7630,7 @@ bool tabstop_set(char_u *var, long **array) if (cp != end) { emsg(_(e_positive)); } else { - emsg(_(e_invarg)); + semsg(_(e_invarg2), cp); } return false; } @@ -7355,7 +7643,7 @@ bool tabstop_set(char_u *var, long **array) valcount++; continue; } - emsg(_(e_invarg)); + semsg(_(e_invarg2), var); return false; } @@ -7364,7 +7652,15 @@ bool tabstop_set(char_u *var, long **array) t = 1; for (cp = var; *cp != NUL;) { - (*array)[t++] = atoi((char *)cp); + int n = atoi((char *)cp); + + // Catch negative values, overflow and ridiculous big values. + if (n <= 0 || n > TABSTOP_MAX) { + semsg(_(e_invarg2), cp); + XFREE_CLEAR(*array); + return false; + } + (*array)[t++] = n; while (*cp != NUL && *cp != ',') { cp++; } @@ -7669,6 +7965,12 @@ unsigned int get_bkc_value(buf_T *buf) return buf->b_bkc_flags ? buf->b_bkc_flags : bkc_flags; } +/// Get the local or global value of the 'virtualedit' flags. +unsigned int get_ve_flags(void) +{ + return (curwin->w_ve_flags ? curwin->w_ve_flags : ve_flags) & ~(VE_NONE | VE_NONEU); +} + /// Get the local or global value of 'showbreak'. /// /// @param win If not NULL, the window to get the local option from; global @@ -7771,7 +8073,7 @@ void set_fileformat(int eol_style, int opt_flags) } // This may cause the buffer to become (un)modified. - check_status(curbuf); + redraw_buf_status_later(curbuf); redraw_tabline = true; need_maketitle = true; // Set window title later. } @@ -7848,7 +8150,6 @@ int win_signcol_count(win_T *wp) /// Return the number of requested sign columns, based on user / configuration. int win_signcol_configured(win_T *wp, int *is_fixed) { - int minimum = 0, maximum = 1, needed_signcols; const char *scl = (const char *)wp->w_p_scl; if (is_fixed) { @@ -7861,7 +8162,6 @@ int win_signcol_configured(win_T *wp, int *is_fixed) && (wp->w_p_nu || wp->w_p_rnu)))) { return 0; } - needed_signcols = buf_signcols(wp->w_buffer); // yes or yes if (!strncmp(scl, "yes:", 4)) { @@ -7877,6 +8177,8 @@ int win_signcol_configured(win_T *wp, int *is_fixed) *is_fixed = 0; } + int minimum = 0, maximum = 1; + if (!strncmp(scl, "auto:", 5)) { // Variable depending on a configuration maximum = scl[5] - '0'; @@ -7887,6 +8189,7 @@ int win_signcol_configured(win_T *wp, int *is_fixed) } } + int needed_signcols = buf_signcols(wp->w_buffer, maximum); int ret = MAX(minimum, MIN(maximum, needed_signcols)); assert(ret <= SIGN_SHOW_MAX); return ret; |