Merge pull request #16107 from zeertzjq/vim-8.1.1542

vim-patch:8.1.1542,8.2.3549: an OptionSet autocommand does not get enough info
This commit is contained in:
Jan Edmund Lazo 2021-12-06 22:35:05 -05:00 committed by GitHub
commit 18d81a6724
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 1131 additions and 188 deletions

View File

@ -2042,10 +2042,29 @@ v:option_new New value of the option. Valid while executing an |OptionSet|
autocommand. autocommand.
*v:option_old* *v:option_old*
v:option_old Old value of the option. Valid while executing an |OptionSet| v:option_old Old value of the option. Valid while executing an |OptionSet|
autocommand. autocommand. Depending on the command used for setting and the
kind of option this is either the local old value or the
global old value.
*v:option_oldlocal*
v:option_oldlocal
Old local value of the option. Valid while executing an
|OptionSet| autocommand.
*v:option_oldglobal*
v:option_oldglobal
Old global value of the option. Valid while executing an
|OptionSet| autocommand.
*v:option_type* *v:option_type*
v:option_type Scope of the set command. Valid while executing an v:option_type Scope of the set command. Valid while executing an
|OptionSet| autocommand. Can be either "global" or "local" |OptionSet| autocommand. Can be either "global" or "local"
*v:option_command*
v:option_command
Command used to set the option. Valid while executing an
|OptionSet| autocommand.
value option was set via ~
"setlocal" |:setlocal| or ":let l:xxx"
"setglobal" |:setglobal| or ":let g:xxx"
"set" |:set| or |:let|
"modeline" |modeline|
*v:operator* *operator-variable* *v:operator* *operator-variable*
v:operator The last operator given in Normal mode. This is a single v:operator The last operator given in Normal mode. This is a single
character except for commands starting with <g> or <z>, character except for commands starting with <g> or <z>,

View File

@ -134,13 +134,15 @@ typedef struct {
.vv_flags = flags, \ .vv_flags = flags, \
} }
#define VIMVAR_KEY_LEN 16 // Maximum length of the key of v:variables
// Array to hold the value of v: variables. // Array to hold the value of v: variables.
// The value is in a dictitem, so that it can also be used in the v: scope. // The value is in a dictitem, so that it can also be used in the v: scope.
// The reason to use this table anyway is for very quick access to the // The reason to use this table anyway is for very quick access to the
// variables with the VV_ defines. // variables with the VV_ defines.
static struct vimvar { static struct vimvar {
char *vv_name; ///< Name of the variable, without v:. char *vv_name; ///< Name of the variable, without v:.
TV_DICTITEM_STRUCT(17) vv_di; ///< Value and name for key (max 16 chars). TV_DICTITEM_STRUCT(VIMVAR_KEY_LEN + 1) vv_di; ///< Value and name for key (max 16 chars).
char vv_flags; ///< Flags: #VV_COMPAT, #VV_RO, #VV_RO_SBX. char vv_flags; ///< Flags: #VV_COMPAT, #VV_RO, #VV_RO_SBX.
} vimvars[] = } vimvars[] =
{ {
@ -150,100 +152,103 @@ static struct vimvar {
// VV_SEND_SERVER "servername" // VV_SEND_SERVER "servername"
// VV_REG "register" // VV_REG "register"
// VV_OP "operator" // VV_OP "operator"
VV(VV_COUNT, "count", VAR_NUMBER, VV_RO), VV(VV_COUNT, "count", VAR_NUMBER, VV_RO),
VV(VV_COUNT1, "count1", VAR_NUMBER, VV_RO), VV(VV_COUNT1, "count1", VAR_NUMBER, VV_RO),
VV(VV_PREVCOUNT, "prevcount", VAR_NUMBER, VV_RO), VV(VV_PREVCOUNT, "prevcount", VAR_NUMBER, VV_RO),
VV(VV_ERRMSG, "errmsg", VAR_STRING, 0), VV(VV_ERRMSG, "errmsg", VAR_STRING, 0),
VV(VV_WARNINGMSG, "warningmsg", VAR_STRING, 0), VV(VV_WARNINGMSG, "warningmsg", VAR_STRING, 0),
VV(VV_STATUSMSG, "statusmsg", VAR_STRING, 0), VV(VV_STATUSMSG, "statusmsg", VAR_STRING, 0),
VV(VV_SHELL_ERROR, "shell_error", VAR_NUMBER, VV_RO), VV(VV_SHELL_ERROR, "shell_error", VAR_NUMBER, VV_RO),
VV(VV_THIS_SESSION, "this_session", VAR_STRING, 0), VV(VV_THIS_SESSION, "this_session", VAR_STRING, 0),
VV(VV_VERSION, "version", VAR_NUMBER, VV_COMPAT+VV_RO), VV(VV_VERSION, "version", VAR_NUMBER, VV_COMPAT+VV_RO),
VV(VV_LNUM, "lnum", VAR_NUMBER, VV_RO_SBX), VV(VV_LNUM, "lnum", VAR_NUMBER, VV_RO_SBX),
VV(VV_TERMRESPONSE, "termresponse", VAR_STRING, VV_RO), VV(VV_TERMRESPONSE, "termresponse", VAR_STRING, VV_RO),
VV(VV_FNAME, "fname", VAR_STRING, VV_RO), VV(VV_FNAME, "fname", VAR_STRING, VV_RO),
VV(VV_LANG, "lang", VAR_STRING, VV_RO), VV(VV_LANG, "lang", VAR_STRING, VV_RO),
VV(VV_LC_TIME, "lc_time", VAR_STRING, VV_RO), VV(VV_LC_TIME, "lc_time", VAR_STRING, VV_RO),
VV(VV_CTYPE, "ctype", VAR_STRING, VV_RO), VV(VV_CTYPE, "ctype", VAR_STRING, VV_RO),
VV(VV_CC_FROM, "charconvert_from", VAR_STRING, VV_RO), VV(VV_CC_FROM, "charconvert_from", VAR_STRING, VV_RO),
VV(VV_CC_TO, "charconvert_to", VAR_STRING, VV_RO), VV(VV_CC_TO, "charconvert_to", VAR_STRING, VV_RO),
VV(VV_FNAME_IN, "fname_in", VAR_STRING, VV_RO), VV(VV_FNAME_IN, "fname_in", VAR_STRING, VV_RO),
VV(VV_FNAME_OUT, "fname_out", VAR_STRING, VV_RO), VV(VV_FNAME_OUT, "fname_out", VAR_STRING, VV_RO),
VV(VV_FNAME_NEW, "fname_new", VAR_STRING, VV_RO), VV(VV_FNAME_NEW, "fname_new", VAR_STRING, VV_RO),
VV(VV_FNAME_DIFF, "fname_diff", VAR_STRING, VV_RO), VV(VV_FNAME_DIFF, "fname_diff", VAR_STRING, VV_RO),
VV(VV_CMDARG, "cmdarg", VAR_STRING, VV_RO), VV(VV_CMDARG, "cmdarg", VAR_STRING, VV_RO),
VV(VV_FOLDSTART, "foldstart", VAR_NUMBER, VV_RO_SBX), VV(VV_FOLDSTART, "foldstart", VAR_NUMBER, VV_RO_SBX),
VV(VV_FOLDEND, "foldend", VAR_NUMBER, VV_RO_SBX), VV(VV_FOLDEND, "foldend", VAR_NUMBER, VV_RO_SBX),
VV(VV_FOLDDASHES, "folddashes", VAR_STRING, VV_RO_SBX), VV(VV_FOLDDASHES, "folddashes", VAR_STRING, VV_RO_SBX),
VV(VV_FOLDLEVEL, "foldlevel", VAR_NUMBER, VV_RO_SBX), VV(VV_FOLDLEVEL, "foldlevel", VAR_NUMBER, VV_RO_SBX),
VV(VV_PROGNAME, "progname", VAR_STRING, VV_RO), VV(VV_PROGNAME, "progname", VAR_STRING, VV_RO),
VV(VV_SEND_SERVER, "servername", VAR_STRING, VV_RO), VV(VV_SEND_SERVER, "servername", VAR_STRING, VV_RO),
VV(VV_DYING, "dying", VAR_NUMBER, VV_RO), VV(VV_DYING, "dying", VAR_NUMBER, VV_RO),
VV(VV_EXCEPTION, "exception", VAR_STRING, VV_RO), VV(VV_EXCEPTION, "exception", VAR_STRING, VV_RO),
VV(VV_THROWPOINT, "throwpoint", VAR_STRING, VV_RO), VV(VV_THROWPOINT, "throwpoint", VAR_STRING, VV_RO),
VV(VV_REG, "register", VAR_STRING, VV_RO), VV(VV_REG, "register", VAR_STRING, VV_RO),
VV(VV_CMDBANG, "cmdbang", VAR_NUMBER, VV_RO), VV(VV_CMDBANG, "cmdbang", VAR_NUMBER, VV_RO),
VV(VV_INSERTMODE, "insertmode", VAR_STRING, VV_RO), VV(VV_INSERTMODE, "insertmode", VAR_STRING, VV_RO),
VV(VV_VAL, "val", VAR_UNKNOWN, VV_RO), VV(VV_VAL, "val", VAR_UNKNOWN, VV_RO),
VV(VV_KEY, "key", VAR_UNKNOWN, VV_RO), VV(VV_KEY, "key", VAR_UNKNOWN, VV_RO),
VV(VV_PROFILING, "profiling", VAR_NUMBER, VV_RO), VV(VV_PROFILING, "profiling", VAR_NUMBER, VV_RO),
VV(VV_FCS_REASON, "fcs_reason", VAR_STRING, VV_RO), VV(VV_FCS_REASON, "fcs_reason", VAR_STRING, VV_RO),
VV(VV_FCS_CHOICE, "fcs_choice", VAR_STRING, 0), VV(VV_FCS_CHOICE, "fcs_choice", VAR_STRING, 0),
VV(VV_BEVAL_BUFNR, "beval_bufnr", VAR_NUMBER, VV_RO), VV(VV_BEVAL_BUFNR, "beval_bufnr", VAR_NUMBER, VV_RO),
VV(VV_BEVAL_WINNR, "beval_winnr", VAR_NUMBER, VV_RO), VV(VV_BEVAL_WINNR, "beval_winnr", VAR_NUMBER, VV_RO),
VV(VV_BEVAL_WINID, "beval_winid", VAR_NUMBER, VV_RO), VV(VV_BEVAL_WINID, "beval_winid", VAR_NUMBER, VV_RO),
VV(VV_BEVAL_LNUM, "beval_lnum", VAR_NUMBER, VV_RO), VV(VV_BEVAL_LNUM, "beval_lnum", VAR_NUMBER, VV_RO),
VV(VV_BEVAL_COL, "beval_col", VAR_NUMBER, VV_RO), VV(VV_BEVAL_COL, "beval_col", VAR_NUMBER, VV_RO),
VV(VV_BEVAL_TEXT, "beval_text", VAR_STRING, VV_RO), VV(VV_BEVAL_TEXT, "beval_text", VAR_STRING, VV_RO),
VV(VV_SCROLLSTART, "scrollstart", VAR_STRING, 0), VV(VV_SCROLLSTART, "scrollstart", VAR_STRING, 0),
VV(VV_SWAPNAME, "swapname", VAR_STRING, VV_RO), VV(VV_SWAPNAME, "swapname", VAR_STRING, VV_RO),
VV(VV_SWAPCHOICE, "swapchoice", VAR_STRING, 0), VV(VV_SWAPCHOICE, "swapchoice", VAR_STRING, 0),
VV(VV_SWAPCOMMAND, "swapcommand", VAR_STRING, VV_RO), VV(VV_SWAPCOMMAND, "swapcommand", VAR_STRING, VV_RO),
VV(VV_CHAR, "char", VAR_STRING, 0), VV(VV_CHAR, "char", VAR_STRING, 0),
VV(VV_MOUSE_WIN, "mouse_win", VAR_NUMBER, 0), VV(VV_MOUSE_WIN, "mouse_win", VAR_NUMBER, 0),
VV(VV_MOUSE_WINID, "mouse_winid", VAR_NUMBER, 0), VV(VV_MOUSE_WINID, "mouse_winid", VAR_NUMBER, 0),
VV(VV_MOUSE_LNUM, "mouse_lnum", VAR_NUMBER, 0), VV(VV_MOUSE_LNUM, "mouse_lnum", VAR_NUMBER, 0),
VV(VV_MOUSE_COL, "mouse_col", VAR_NUMBER, 0), VV(VV_MOUSE_COL, "mouse_col", VAR_NUMBER, 0),
VV(VV_OP, "operator", VAR_STRING, VV_RO), VV(VV_OP, "operator", VAR_STRING, VV_RO),
VV(VV_SEARCHFORWARD, "searchforward", VAR_NUMBER, 0), VV(VV_SEARCHFORWARD, "searchforward", VAR_NUMBER, 0),
VV(VV_HLSEARCH, "hlsearch", VAR_NUMBER, 0), VV(VV_HLSEARCH, "hlsearch", VAR_NUMBER, 0),
VV(VV_OLDFILES, "oldfiles", VAR_LIST, 0), VV(VV_OLDFILES, "oldfiles", VAR_LIST, 0),
VV(VV_WINDOWID, "windowid", VAR_NUMBER, VV_RO_SBX), VV(VV_WINDOWID, "windowid", VAR_NUMBER, VV_RO_SBX),
VV(VV_PROGPATH, "progpath", VAR_STRING, VV_RO), VV(VV_PROGPATH, "progpath", VAR_STRING, VV_RO),
VV(VV_COMPLETED_ITEM, "completed_item", VAR_DICT, VV_RO), VV(VV_COMPLETED_ITEM, "completed_item", VAR_DICT, VV_RO),
VV(VV_OPTION_NEW, "option_new", VAR_STRING, VV_RO), VV(VV_OPTION_NEW, "option_new", VAR_STRING, VV_RO),
VV(VV_OPTION_OLD, "option_old", VAR_STRING, VV_RO), VV(VV_OPTION_OLD, "option_old", VAR_STRING, VV_RO),
VV(VV_OPTION_TYPE, "option_type", VAR_STRING, VV_RO), VV(VV_OPTION_OLDLOCAL, "option_oldlocal", VAR_STRING, VV_RO),
VV(VV_ERRORS, "errors", VAR_LIST, 0), VV(VV_OPTION_OLDGLOBAL, "option_oldglobal", VAR_STRING, VV_RO),
VV(VV_FALSE, "false", VAR_BOOL, VV_RO), VV(VV_OPTION_COMMAND, "option_command", VAR_STRING, VV_RO),
VV(VV_TRUE, "true", VAR_BOOL, VV_RO), VV(VV_OPTION_TYPE, "option_type", VAR_STRING, VV_RO),
VV(VV_NULL, "null", VAR_SPECIAL, VV_RO), VV(VV_ERRORS, "errors", VAR_LIST, 0),
VV(VV_NUMBERMAX, "numbermax", VAR_NUMBER, VV_RO), VV(VV_FALSE, "false", VAR_BOOL, VV_RO),
VV(VV_NUMBERMIN, "numbermin", VAR_NUMBER, VV_RO), VV(VV_TRUE, "true", VAR_BOOL, VV_RO),
VV(VV_NUMBERSIZE, "numbersize", VAR_NUMBER, VV_RO), VV(VV_NULL, "null", VAR_SPECIAL, VV_RO),
VV(VV_VIM_DID_ENTER, "vim_did_enter", VAR_NUMBER, VV_RO), VV(VV_NUMBERMAX, "numbermax", VAR_NUMBER, VV_RO),
VV(VV_TESTING, "testing", VAR_NUMBER, 0), VV(VV_NUMBERMIN, "numbermin", VAR_NUMBER, VV_RO),
VV(VV_TYPE_NUMBER, "t_number", VAR_NUMBER, VV_RO), VV(VV_NUMBERSIZE, "numbersize", VAR_NUMBER, VV_RO),
VV(VV_TYPE_STRING, "t_string", VAR_NUMBER, VV_RO), VV(VV_VIM_DID_ENTER, "vim_did_enter", VAR_NUMBER, VV_RO),
VV(VV_TYPE_FUNC, "t_func", VAR_NUMBER, VV_RO), VV(VV_TESTING, "testing", VAR_NUMBER, 0),
VV(VV_TYPE_LIST, "t_list", VAR_NUMBER, VV_RO), VV(VV_TYPE_NUMBER, "t_number", VAR_NUMBER, VV_RO),
VV(VV_TYPE_DICT, "t_dict", VAR_NUMBER, VV_RO), VV(VV_TYPE_STRING, "t_string", VAR_NUMBER, VV_RO),
VV(VV_TYPE_FLOAT, "t_float", VAR_NUMBER, VV_RO), VV(VV_TYPE_FUNC, "t_func", VAR_NUMBER, VV_RO),
VV(VV_TYPE_BOOL, "t_bool", VAR_NUMBER, VV_RO), VV(VV_TYPE_LIST, "t_list", VAR_NUMBER, VV_RO),
VV(VV_TYPE_BLOB, "t_blob", VAR_NUMBER, VV_RO), VV(VV_TYPE_DICT, "t_dict", VAR_NUMBER, VV_RO),
VV(VV_EVENT, "event", VAR_DICT, VV_RO), VV(VV_TYPE_FLOAT, "t_float", VAR_NUMBER, VV_RO),
VV(VV_ECHOSPACE, "echospace", VAR_NUMBER, VV_RO), VV(VV_TYPE_BOOL, "t_bool", VAR_NUMBER, VV_RO),
VV(VV_ARGV, "argv", VAR_LIST, VV_RO), VV(VV_TYPE_BLOB, "t_blob", VAR_NUMBER, VV_RO),
VV(VV_COLLATE, "collate", VAR_STRING, VV_RO), VV(VV_EVENT, "event", VAR_DICT, VV_RO),
VV(VV_EXITING, "exiting", VAR_NUMBER, VV_RO), VV(VV_ECHOSPACE, "echospace", VAR_NUMBER, VV_RO),
VV(VV_ARGV, "argv", VAR_LIST, VV_RO),
VV(VV_COLLATE, "collate", VAR_STRING, VV_RO),
VV(VV_EXITING, "exiting", VAR_NUMBER, VV_RO),
// Neovim // Neovim
VV(VV_STDERR, "stderr", VAR_NUMBER, VV_RO), VV(VV_STDERR, "stderr", VAR_NUMBER, VV_RO),
VV(VV_MSGPACK_TYPES, "msgpack_types", VAR_DICT, VV_RO), VV(VV_MSGPACK_TYPES, "msgpack_types", VAR_DICT, VV_RO),
VV(VV__NULL_STRING, "_null_string", VAR_STRING, VV_RO), VV(VV__NULL_STRING, "_null_string", VAR_STRING, VV_RO),
VV(VV__NULL_LIST, "_null_list", VAR_LIST, VV_RO), VV(VV__NULL_LIST, "_null_list", VAR_LIST, VV_RO),
VV(VV__NULL_DICT, "_null_dict", VAR_DICT, VV_RO), VV(VV__NULL_DICT, "_null_dict", VAR_DICT, VV_RO),
VV(VV__NULL_BLOB, "_null_blob", VAR_BLOB, VV_RO), VV(VV__NULL_BLOB, "_null_blob", VAR_BLOB, VV_RO),
VV(VV_LUA, "lua", VAR_PARTIAL, VV_RO), VV(VV_LUA, "lua", VAR_PARTIAL, VV_RO),
}; };
#undef VV #undef VV
@ -344,7 +349,7 @@ void eval_init(void)
for (size_t i = 0; i < ARRAY_SIZE(vimvars); i++) { for (size_t i = 0; i < ARRAY_SIZE(vimvars); i++) {
p = &vimvars[i]; p = &vimvars[i];
assert(STRLEN(p->vv_name) <= 16); assert(STRLEN(p->vv_name) <= VIMVAR_KEY_LEN);
STRCPY(p->vv_di.di_key, p->vv_name); STRCPY(p->vv_di.di_key, p->vv_name);
if (p->vv_flags & VV_RO) { if (p->vv_flags & VV_RO) {
p->vv_di.di_flags = DI_FLAGS_RO | DI_FLAGS_FIX; p->vv_di.di_flags = DI_FLAGS_RO | DI_FLAGS_FIX;
@ -10447,11 +10452,15 @@ void option_last_set_msg(LastSet last_set)
} }
} }
// reset v:option_new, v:option_old and v:option_type // reset v:option_new, v:option_old, v:option_oldlocal, v:option_oldglobal,
// v:option_type, and v:option_command.
void reset_v_option_vars(void) void reset_v_option_vars(void)
{ {
set_vim_var_string(VV_OPTION_NEW, NULL, -1); set_vim_var_string(VV_OPTION_NEW, NULL, -1);
set_vim_var_string(VV_OPTION_OLD, NULL, -1); set_vim_var_string(VV_OPTION_OLD, NULL, -1);
set_vim_var_string(VV_OPTION_OLDLOCAL, NULL, -1);
set_vim_var_string(VV_OPTION_OLDGLOBAL, NULL, -1);
set_vim_var_string(VV_OPTION_COMMAND, NULL, -1);
set_vim_var_string(VV_OPTION_TYPE, NULL, -1); set_vim_var_string(VV_OPTION_TYPE, NULL, -1);
} }

View File

@ -138,6 +138,9 @@ typedef enum {
VV_COMPLETED_ITEM, VV_COMPLETED_ITEM,
VV_OPTION_NEW, VV_OPTION_NEW,
VV_OPTION_OLD, VV_OPTION_OLD,
VV_OPTION_OLDLOCAL,
VV_OPTION_OLDGLOBAL,
VV_OPTION_COMMAND,
VV_OPTION_TYPE, VV_OPTION_TYPE,
VV_ERRORS, VV_ERRORS,
VV_FALSE, VV_FALSE,

View File

@ -1301,7 +1301,11 @@ int do_set(char_u *arg, int opt_flags)
char_u *oldval = NULL; // previous value if *varp char_u *oldval = NULL; // previous value if *varp
char_u *newval; char_u *newval;
char_u *origval = NULL; char_u *origval = NULL;
char_u *origval_l = NULL;
char_u *origval_g = NULL;
char *saved_origval = NULL; char *saved_origval = NULL;
char *saved_origval_l = NULL;
char *saved_origval_g = NULL;
char *saved_newval = NULL; char *saved_newval = NULL;
unsigned newlen; unsigned newlen;
int comma; int comma;
@ -1319,10 +1323,21 @@ int do_set(char_u *arg, int opt_flags)
// new value is valid. // new value is valid.
oldval = *(char_u **)varp; 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 // When setting the local value of a global
// option, the old value may be the global value. // option, the old value may be the global value.
if (((int)options[opt_idx].indir & PV_BOTH) && (opt_flags if (((int)options[opt_idx].indir & PV_BOTH) && (opt_flags & OPT_LOCAL)) {
& OPT_LOCAL)) {
origval = *(char_u **)get_varp(&options[opt_idx]); origval = *(char_u **)get_varp(&options[opt_idx]);
} else { } else {
origval = oldval; origval = oldval;
@ -1388,6 +1403,12 @@ int do_set(char_u *arg, int opt_flags)
if (origval == oldval) { if (origval == oldval) {
origval = *(char_u **)varp; 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; oldval = *(char_u **)varp;
} }
/* /*
@ -1596,6 +1617,8 @@ int do_set(char_u *arg, int opt_flags)
// origval may be freed by // origval may be freed by
// did_set_string_option(), make a copy. // did_set_string_option(), make a copy.
saved_origval = (origval != NULL) ? xstrdup((char *)origval) : 0; 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 // newval (and varp) may become invalid if the
// buffer is closed by autocommands. // buffer is closed by autocommands.
@ -1630,8 +1653,8 @@ int do_set(char_u *arg, int opt_flags)
if (errmsg == NULL) { if (errmsg == NULL) {
if (!starting) { if (!starting) {
trigger_optionsset_string(opt_idx, opt_flags, saved_origval, trigger_optionsset_string(opt_idx, opt_flags, saved_origval, saved_origval_l,
saved_newval); saved_origval_g, saved_newval);
} }
if (options[opt_idx].flags & P_UI_OPTION) { if (options[opt_idx].flags & P_UI_OPTION) {
ui_call_option_set(cstr_as_string(options[opt_idx].fullname), ui_call_option_set(cstr_as_string(options[opt_idx].fullname),
@ -1639,6 +1662,8 @@ int do_set(char_u *arg, int opt_flags)
} }
} }
xfree(saved_origval); xfree(saved_origval);
xfree(saved_origval_l);
xfree(saved_origval_g);
xfree(saved_newval); xfree(saved_newval);
// If error detected, print the error message. // If error detected, print the error message.
@ -2233,9 +2258,19 @@ static char *set_string_option(const int opt_idx, const char *const value, const
? OPT_GLOBAL : OPT_LOCAL) ? OPT_GLOBAL : OPT_LOCAL)
: opt_flags)); : opt_flags));
char *const oldval = *varp; 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; *varp = s;
char *const saved_oldval = xstrdup(oldval); char *const saved_oldval = xstrdup(oldval);
char *const saved_oldval_l = (oldval_l != NULL) ? xstrdup((char *)oldval_l) : 0;
char *const saved_oldval_g = (oldval_g != NULL) ? xstrdup((char *)oldval_g) : 0;
char *const saved_newval = xstrdup(s); char *const saved_newval = xstrdup(s);
int value_checked = false; int value_checked = false;
@ -2249,7 +2284,8 @@ static char *set_string_option(const int opt_idx, const char *const value, const
// call autocommand after handling side effects // call autocommand after handling side effects
if (r == NULL) { if (r == NULL) {
if (!starting) { 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) { if (options[opt_idx].flags & P_UI_OPTION) {
ui_call_option_set(cstr_as_string(options[opt_idx].fullname), ui_call_option_set(cstr_as_string(options[opt_idx].fullname),
@ -2257,6 +2293,8 @@ static char *set_string_option(const int opt_idx, const char *const value, const
} }
} }
xfree(saved_oldval); xfree(saved_oldval);
xfree(saved_oldval_l);
xfree(saved_oldval_g);
xfree(saved_newval); xfree(saved_newval);
return r; return r;
@ -3851,6 +3889,7 @@ static char *set_bool_option(const int opt_idx, char_u *const varp, const int va
const int opt_flags) const int opt_flags)
{ {
int old_value = *(int *)varp; int old_value = *(int *)varp;
int old_global_value = 0;
// Disallow changing some options from secure mode // Disallow changing some options from secure mode
if ((secure || sandbox != 0) if ((secure || sandbox != 0)
@ -3858,6 +3897,13 @@ static char *set_bool_option(const int opt_idx, char_u *const varp, const int va
return (char *)e_secure; 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 *(int *)varp = value; // set the new value
// Remember where the option was set. // Remember where the option was set.
set_option_sctx_idx(opt_idx, opt_flags, current_sctx); set_option_sctx_idx(opt_idx, opt_flags, current_sctx);
@ -4134,20 +4180,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. // Don't do this while starting up or recursively.
if (!starting && *get_vim_var_str(VV_OPTION_TYPE) == NUL) { if (!starting && *get_vim_var_str(VV_OPTION_TYPE) == NUL) {
char buf_old[2]; char buf_old[2];
char buf_old_global[2];
char buf_new[2]; char buf_new[2];
char buf_type[7]; char buf_type[7];
vim_snprintf(buf_old, ARRAY_SIZE(buf_old), "%d", vim_snprintf(buf_old, ARRAY_SIZE(buf_old), "%d", old_value ? true : false);
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", vim_snprintf(buf_new, ARRAY_SIZE(buf_new), "%d", value ? true : false);
value ? true: false);
vim_snprintf(buf_type, ARRAY_SIZE(buf_type), "%s", vim_snprintf(buf_type, ARRAY_SIZE(buf_type), "%s",
(opt_flags & OPT_LOCAL) ? "local" : "global"); (opt_flags & OPT_LOCAL) ? "local" : "global");
set_vim_var_string(VV_OPTION_NEW, buf_new, -1); 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_OLD, buf_old, -1);
set_vim_var_string(VV_OPTION_TYPE, buf_type, -1); set_vim_var_string(VV_OPTION_TYPE, buf_type, -1);
apply_autocmds(EVENT_OPTIONSET, if (opt_flags & OPT_LOCAL) {
(char_u *)options[opt_idx].fullname, set_vim_var_string(VV_OPTION_COMMAND, "setlocal", -1);
NULL, false, NULL); 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(); reset_v_option_vars();
} }
@ -4181,7 +4242,8 @@ static char *set_num_option(int opt_idx, char_u *varp, long value, char *errbuf,
{ {
char *errmsg = NULL; char *errmsg = NULL;
long old_value = *(long *)varp; 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; long *pp = (long *)varp;
// Disallow changing some options from secure mode. // Disallow changing some options from secure mode.
@ -4190,6 +4252,13 @@ static char *set_num_option(int opt_idx, char_u *varp, long value, char *errbuf,
return e_secure; return e_secure;
} }
// Save the global value before changing anything. This is needed as for
// a global-only option setting the "local value" infact 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. // Many number options assume their value is in the signed int range.
if (value < INT_MIN || value > INT_MAX) { if (value < INT_MIN || value > INT_MAX) {
return e_invarg; return e_invarg;
@ -4534,19 +4603,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. // Don't do this while starting up, failure or recursively.
if (!starting && errmsg == NULL && *get_vim_var_str(VV_OPTION_TYPE) == NUL) { if (!starting && errmsg == NULL && *get_vim_var_str(VV_OPTION_TYPE) == NUL) {
char buf_old[NUMBUFLEN]; char buf_old[NUMBUFLEN];
char buf_old_global[NUMBUFLEN];
char buf_new[NUMBUFLEN]; char buf_new[NUMBUFLEN];
char buf_type[7]; char buf_type[7];
vim_snprintf(buf_old, ARRAY_SIZE(buf_old), "%ld", old_value); 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_new, ARRAY_SIZE(buf_new), "%ld", value);
vim_snprintf(buf_type, ARRAY_SIZE(buf_type), "%s", vim_snprintf(buf_type, ARRAY_SIZE(buf_type), "%s",
(opt_flags & OPT_LOCAL) ? "local" : "global"); (opt_flags & OPT_LOCAL) ? "local" : "global");
set_vim_var_string(VV_OPTION_NEW, buf_new, -1); 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_OLD, buf_old, -1);
set_vim_var_string(VV_OPTION_TYPE, buf_type, -1); set_vim_var_string(VV_OPTION_TYPE, buf_type, -1);
apply_autocmds(EVENT_OPTIONSET, if (opt_flags & OPT_LOCAL) {
(char_u *)options[opt_idx].fullname, set_vim_var_string(VV_OPTION_COMMAND, "setlocal", -1);
NULL, false, NULL); 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(); reset_v_option_vars();
} }
@ -4565,7 +4651,15 @@ static char *set_num_option(int opt_idx, char_u *varp, long value, char *errbuf,
return (char *)errmsg; return (char *)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. // Don't do this recursively.
if (oldval != NULL if (oldval != NULL
@ -4578,8 +4672,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_OLD, oldval, -1);
set_vim_var_string(VV_OPTION_NEW, newval, -1); set_vim_var_string(VV_OPTION_NEW, newval, -1);
set_vim_var_string(VV_OPTION_TYPE, buf_type, -1); set_vim_var_string(VV_OPTION_TYPE, buf_type, -1);
apply_autocmds(EVENT_OPTIONSET, if (opt_flags & OPT_LOCAL) {
(char_u *)options[opt_idx].fullname, NULL, false, NULL); 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(); reset_v_option_vars();
} }
} }

View File

@ -580,9 +580,10 @@ func Test_empty_doau()
endfunc endfunc
func s:AutoCommandOptionSet(match) func s:AutoCommandOptionSet(match)
let template = "Option: <%s>, OldVal: <%s>, OldValLocal: <%s>, OldValGlobal: <%s>, NewVal: <%s>, Scope: <%s>, Command: <%s>\n"
let item = remove(g:options, 0) let item = remove(g:options, 0)
let expected = printf("Option: <%s>, Oldval: <%s>, NewVal: <%s>, Scope: <%s>\n", item[0], item[1], item[2], item[3]) let expected = printf(template, item[0], item[1], item[2], item[3], item[4], item[5], item[6])
let actual = printf("Option: <%s>, Oldval: <%s>, NewVal: <%s>, Scope: <%s>\n", a:match, v:option_old, v:option_new, v:option_type) let actual = printf(template, a:match, v:option_old, v:option_oldlocal, v:option_oldglobal, v:option_new, v:option_type, v:option_command)
let g:opt = [expected, actual] let g:opt = [expected, actual]
"call assert_equal(expected, actual) "call assert_equal(expected, actual)
endfunc endfunc
@ -596,130 +597,593 @@ func Test_OptionSet()
au OptionSet * :call s:AutoCommandOptionSet(expand("<amatch>")) au OptionSet * :call s:AutoCommandOptionSet(expand("<amatch>"))
" 1: Setting number option" " 1: Setting number option"
let g:options = [['number', 0, 1, 'global']] let g:options = [['number', 0, 0, 0, 1, 'global', 'set']]
set nu set nu
call assert_equal([], g:options) call assert_equal([], g:options)
call assert_equal(g:opt[0], g:opt[1]) call assert_equal(g:opt[0], g:opt[1])
" 2: Setting local number option" " 2: Setting local number option"
let g:options = [['number', 1, 0, 'local']] let g:options = [['number', 1, 1, '', 0, 'local', 'setlocal']]
setlocal nonu setlocal nonu
call assert_equal([], g:options) call assert_equal([], g:options)
call assert_equal(g:opt[0], g:opt[1]) call assert_equal(g:opt[0], g:opt[1])
" 3: Setting global number option" " 3: Setting global number option"
let g:options = [['number', 1, 0, 'global']] let g:options = [['number', 1, '', 1, 0, 'global', 'setglobal']]
setglobal nonu setglobal nonu
call assert_equal([], g:options) call assert_equal([], g:options)
call assert_equal(g:opt[0], g:opt[1]) call assert_equal(g:opt[0], g:opt[1])
" 4: Setting local autoindent option" " 4: Setting local autoindent option"
let g:options = [['autoindent', 0, 1, 'local']] let g:options = [['autoindent', 0, 0, '', 1, 'local', 'setlocal']]
setlocal ai setlocal ai
call assert_equal([], g:options) call assert_equal([], g:options)
call assert_equal(g:opt[0], g:opt[1]) call assert_equal(g:opt[0], g:opt[1])
" 5: Setting global autoindent option" " 5: Setting global autoindent option"
let g:options = [['autoindent', 0, 1, 'global']] let g:options = [['autoindent', 0, '', 0, 1, 'global', 'setglobal']]
setglobal ai setglobal ai
call assert_equal([], g:options) call assert_equal([], g:options)
call assert_equal(g:opt[0], g:opt[1]) call assert_equal(g:opt[0], g:opt[1])
" 6: Setting global autoindent option" " 6: Setting global autoindent option"
let g:options = [['autoindent', 1, 0, 'global']] let g:options = [['autoindent', 1, 1, 1, 0, 'global', 'set']]
set ai!
call assert_equal([], g:options)
call assert_equal(g:opt[0], g:opt[1])
" 6a: Setting global autoindent option"
let g:options = [['autoindent', 1, 1, 0, 0, 'global', 'set']]
noa setlocal ai
noa setglobal noai
set ai! set ai!
call assert_equal([], g:options) call assert_equal([], g:options)
call assert_equal(g:opt[0], g:opt[1]) call assert_equal(g:opt[0], g:opt[1])
" Should not print anything, use :noa " Should not print anything, use :noa
" 7: don't trigger OptionSet" " 7: don't trigger OptionSet"
let g:options = [['invalid', 1, 1, 'invalid']] let g:options = [['invalid', 'invalid', 'invalid', 'invalid', 'invalid', 'invalid', 'invalid']]
noa set nonu noa set nonu
call assert_equal([['invalid', 1, 1, 'invalid']], g:options) call assert_equal([['invalid', 'invalid', 'invalid', 'invalid', 'invalid', 'invalid', 'invalid']], g:options)
call assert_equal(g:opt[0], g:opt[1]) call assert_equal(g:opt[0], g:opt[1])
" 8: Setting several global list and number option" " 8: Setting several global list and number option"
let g:options = [['list', 0, 1, 'global'], ['number', 0, 1, 'global']] let g:options = [['list', 0, 0, 0, 1, 'global', 'set'], ['number', 0, 0, 0, 1, 'global', 'set']]
set list nu set list nu
call assert_equal([], g:options) call assert_equal([], g:options)
call assert_equal(g:opt[0], g:opt[1]) call assert_equal(g:opt[0], g:opt[1])
" 9: don't trigger OptionSet" " 9: don't trigger OptionSet"
let g:options = [['invalid', 1, 1, 'invalid'], ['invalid', 1, 1, 'invalid']] let g:options = [['invalid', 'invalid', 'invalid', 'invalid', 'invalid', 'invalid', 'invalid'], ['invalid', 'invalid', 'invalid', 'invalid', 'invalid', 'invalid', 'invalid']]
noa set nolist nonu noa set nolist nonu
call assert_equal([['invalid', 1, 1, 'invalid'], ['invalid', 1, 1, 'invalid']], g:options) call assert_equal([['invalid', 'invalid', 'invalid', 'invalid', 'invalid', 'invalid', 'invalid'], ['invalid', 'invalid', 'invalid', 'invalid', 'invalid', 'invalid', 'invalid']], g:options)
call assert_equal(g:opt[0], g:opt[1]) call assert_equal(g:opt[0], g:opt[1])
" 10: Setting global acd" " 10: Setting global acd"
let g:options = [['autochdir', 0, 1, 'local']] let g:options = [['autochdir', 0, 0, '', 1, 'local', 'setlocal']]
setlocal acd setlocal acd
call assert_equal([], g:options) call assert_equal([], g:options)
call assert_equal(g:opt[0], g:opt[1]) call assert_equal(g:opt[0], g:opt[1])
" 11: Setting global autoread (also sets local value)" " 11: Setting global autoread (also sets local value)"
let g:options = [['autoread', 0, 1, 'global']] let g:options = [['autoread', 0, 0, 0, 1, 'global', 'set']]
set ar set ar
call assert_equal([], g:options) call assert_equal([], g:options)
call assert_equal(g:opt[0], g:opt[1]) call assert_equal(g:opt[0], g:opt[1])
" 12: Setting local autoread" " 12: Setting local autoread"
let g:options = [['autoread', 1, 1, 'local']] let g:options = [['autoread', 1, 1, '', 1, 'local', 'setlocal']]
setlocal ar setlocal ar
call assert_equal([], g:options) call assert_equal([], g:options)
call assert_equal(g:opt[0], g:opt[1]) call assert_equal(g:opt[0], g:opt[1])
" 13: Setting global autoread" " 13: Setting global autoread"
let g:options = [['autoread', 1, 0, 'global']] let g:options = [['autoread', 1, '', 1, 0, 'global', 'setglobal']]
setglobal invar setglobal invar
call assert_equal([], g:options) call assert_equal([], g:options)
call assert_equal(g:opt[0], g:opt[1]) call assert_equal(g:opt[0], g:opt[1])
" 14: Setting option backspace through :let" " 14: Setting option backspace through :let"
let g:options = [['backspace', '', 'eol,indent,start', 'global']] let g:options = [['backspace', '', '', '', 'eol,indent,start', 'global', 'set']]
let &bs = "eol,indent,start" let &bs = "eol,indent,start"
call assert_equal([], g:options) call assert_equal([], g:options)
call assert_equal(g:opt[0], g:opt[1]) call assert_equal(g:opt[0], g:opt[1])
" 15: Setting option backspace through setbufvar()" " 15: Setting option backspace through setbufvar()"
let g:options = [['backup', 0, 1, 'local']] let g:options = [['backup', 0, 0, '', 1, 'local', 'setlocal']]
" try twice, first time, shouldn't trigger because option name is invalid, " try twice, first time, shouldn't trigger because option name is invalid,
" second time, it should trigger " second time, it should trigger
call assert_fails("call setbufvar(1, '&l:bk', 1)", "E355") let bnum = bufnr('%')
call assert_fails("call setbufvar(bnum, '&l:bk', 1)", 'E355:')
" should trigger, use correct option name " should trigger, use correct option name
call setbufvar(1, '&backup', 1) call setbufvar(bnum, '&backup', 1)
call assert_equal([], g:options) call assert_equal([], g:options)
call assert_equal(g:opt[0], g:opt[1]) call assert_equal(g:opt[0], g:opt[1])
" 16: Setting number option using setwinvar" " 16: Setting number option using setwinvar"
let g:options = [['number', 0, 1, 'local']] let g:options = [['number', 0, 0, '', 1, 'local', 'setlocal']]
call setwinvar(0, '&number', 1) call setwinvar(0, '&number', 1)
call assert_equal([], g:options) call assert_equal([], g:options)
call assert_equal(g:opt[0], g:opt[1]) call assert_equal(g:opt[0], g:opt[1])
" 17: Setting key option, shouldn't trigger" " 17: Setting key option, shouldn't trigger"
let g:options = [['key', 'invalid', 'invalid1', 'invalid']] let g:options = [['key', 'invalid', 'invalid1', 'invalid2', 'invalid3', 'invalid4', 'invalid5']]
setlocal key=blah setlocal key=blah
setlocal key= setlocal key=
call assert_equal([['key', 'invalid', 'invalid1', 'invalid']], g:options) call assert_equal([['key', 'invalid', 'invalid1', 'invalid2', 'invalid3', 'invalid4', 'invalid5']], g:options)
call assert_equal(g:opt[0], g:opt[1]) call assert_equal(g:opt[0], g:opt[1])
" 18: Setting string option"
" 18a: Setting string global option"
let oldval = &backupext
let g:options = [['backupext', oldval, oldval, oldval, 'foo', 'global', 'set']]
set backupext=foo
call assert_equal([], g:options)
call assert_equal(g:opt[0], g:opt[1])
" 18b: Resetting string global option"
let g:options = [['backupext', 'foo', 'foo', 'foo', oldval, 'global', 'set']]
set backupext&
call assert_equal([], g:options)
call assert_equal(g:opt[0], g:opt[1])
" 18c: Setting global string global option"
let g:options = [['backupext', oldval, '', oldval, 'bar', 'global', 'setglobal']]
setglobal backupext=bar
call assert_equal([], g:options)
call assert_equal(g:opt[0], g:opt[1])
" 18d: Setting local string global option"
" As this is a global option this sets the global value even though
" :setlocal is used!
noa set backupext& " Reset global and local value (without triggering autocmd)
let g:options = [['backupext', oldval, oldval, '', 'baz', 'local', 'setlocal']]
setlocal backupext=baz
call assert_equal([], g:options)
call assert_equal(g:opt[0], g:opt[1])
" 18e: Setting again string global option"
noa setglobal backupext=ext_global " Reset global and local value (without triggering autocmd)
noa setlocal backupext=ext_local " Sets the global(!) value!
let g:options = [['backupext', 'ext_local', 'ext_local', 'ext_local', 'fuu', 'global', 'set']]
set backupext=fuu
call assert_equal([], g:options)
call assert_equal(g:opt[0], g:opt[1])
" 19a: Setting string global-local (to buffer) option"
let oldval = &tags let oldval = &tags
let g:options = [['tags', oldval, 'tagpath', 'global']] let g:options = [['tags', oldval, oldval, oldval, 'tagpath', 'global', 'set']]
set tags=tagpath set tags=tagpath
call assert_equal([], g:options) call assert_equal([], g:options)
call assert_equal(g:opt[0], g:opt[1]) call assert_equal(g:opt[0], g:opt[1])
" 1l: Resetting string option" " 19b: Resetting string global-local (to buffer) option"
let g:options = [['tags', 'tagpath', oldval, 'global']] let g:options = [['tags', 'tagpath', 'tagpath', 'tagpath', oldval, 'global', 'set']]
set tags& set tags&
call assert_equal([], g:options) call assert_equal([], g:options)
call assert_equal(g:opt[0], g:opt[1]) call assert_equal(g:opt[0], g:opt[1])
" 19c: Setting global string global-local (to buffer) option "
let g:options = [['tags', oldval, '', oldval, 'tagpath1', 'global', 'setglobal']]
setglobal tags=tagpath1
call assert_equal([], g:options)
call assert_equal(g:opt[0], g:opt[1])
" 19d: Setting local string global-local (to buffer) option"
let g:options = [['tags', 'tagpath1', 'tagpath1', '', 'tagpath2', 'local', 'setlocal']]
setlocal tags=tagpath2
call assert_equal([], g:options)
call assert_equal(g:opt[0], g:opt[1])
" 19e: Setting again string global-local (to buffer) option"
" Note: v:option_old is the old global value for global-local string options
" but the old local value for all other kinds of options.
noa setglobal tags=tag_global " Reset global and local value (without triggering autocmd)
noa setlocal tags=tag_local
let g:options = [['tags', 'tag_global', 'tag_local', 'tag_global', 'tagpath', 'global', 'set']]
set tags=tagpath
call assert_equal([], g:options)
call assert_equal(g:opt[0], g:opt[1])
" 19f: Setting string global-local (to buffer) option to an empty string"
" Note: v:option_old is the old global value for global-local string options
" but the old local value for all other kinds of options.
noa set tags=tag_global " Reset global and local value (without triggering autocmd)
noa setlocal tags= " empty string
let g:options = [['tags', 'tag_global', '', 'tag_global', 'tagpath', 'global', 'set']]
set tags=tagpath
call assert_equal([], g:options)
call assert_equal(g:opt[0], g:opt[1])
" 20a: Setting string local (to buffer) option"
let oldval = &spelllang
let g:options = [['spelllang', oldval, oldval, oldval, 'elvish,klingon', 'global', 'set']]
set spelllang=elvish,klingon
call assert_equal([], g:options)
call assert_equal(g:opt[0], g:opt[1])
" 20b: Resetting string local (to buffer) option"
let g:options = [['spelllang', 'elvish,klingon', 'elvish,klingon', 'elvish,klingon', oldval, 'global', 'set']]
set spelllang&
call assert_equal([], g:options)
call assert_equal(g:opt[0], g:opt[1])
" 20c: Setting global string local (to buffer) option"
let g:options = [['spelllang', oldval, '', oldval, 'elvish', 'global', 'setglobal']]
setglobal spelllang=elvish
call assert_equal([], g:options)
call assert_equal(g:opt[0], g:opt[1])
" 20d: Setting local string local (to buffer) option"
noa set spelllang& " Reset global and local value (without triggering autocmd)
let g:options = [['spelllang', oldval, oldval, '', 'klingon', 'local', 'setlocal']]
setlocal spelllang=klingon
call assert_equal([], g:options)
call assert_equal(g:opt[0], g:opt[1])
" 20e: Setting again string local (to buffer) option"
" Note: v:option_old is the old global value for global-local string options
" but the old local value for all other kinds of options.
noa setglobal spelllang=spellglobal " Reset global and local value (without triggering autocmd)
noa setlocal spelllang=spelllocal
let g:options = [['spelllang', 'spelllocal', 'spelllocal', 'spellglobal', 'foo', 'global', 'set']]
set spelllang=foo
call assert_equal([], g:options)
call assert_equal(g:opt[0], g:opt[1])
" 21a: Setting string global-local (to window) option"
let oldval = &statusline
let g:options = [['statusline', oldval, oldval, oldval, 'foo', 'global', 'set']]
set statusline=foo
call assert_equal([], g:options)
call assert_equal(g:opt[0], g:opt[1])
" 21b: Resetting string global-local (to window) option"
" Note: v:option_old is the old global value for global-local string options
" but the old local value for all other kinds of options.
let g:options = [['statusline', 'foo', 'foo', 'foo', oldval, 'global', 'set']]
set statusline&
call assert_equal([], g:options)
call assert_equal(g:opt[0], g:opt[1])
" 21c: Setting global string global-local (to window) option"
let g:options = [['statusline', oldval, '', oldval, 'bar', 'global', 'setglobal']]
setglobal statusline=bar
call assert_equal([], g:options)
call assert_equal(g:opt[0], g:opt[1])
" 21d: Setting local string global-local (to window) option"
noa set statusline& " Reset global and local value (without triggering autocmd)
let g:options = [['statusline', oldval, oldval, '', 'baz', 'local', 'setlocal']]
setlocal statusline=baz
call assert_equal([], g:options)
call assert_equal(g:opt[0], g:opt[1])
" 21e: Setting again string global-local (to window) option"
" Note: v:option_old is the old global value for global-local string options
" but the old local value for all other kinds of options.
noa setglobal statusline=bar " Reset global and local value (without triggering autocmd)
noa setlocal statusline=baz
let g:options = [['statusline', 'bar', 'baz', 'bar', 'foo', 'global', 'set']]
set statusline=foo
call assert_equal([], g:options)
call assert_equal(g:opt[0], g:opt[1])
" 22a: Setting string local (to window) option"
let oldval = &foldignore
let g:options = [['foldignore', oldval, oldval, oldval, 'fo', 'global', 'set']]
set foldignore=fo
call assert_equal([], g:options)
call assert_equal(g:opt[0], g:opt[1])
" 22b: Resetting string local (to window) option"
let g:options = [['foldignore', 'fo', 'fo', 'fo', oldval, 'global', 'set']]
set foldignore&
call assert_equal([], g:options)
call assert_equal(g:opt[0], g:opt[1])
" 22c: Setting global string local (to window) option"
let g:options = [['foldignore', oldval, '', oldval, 'bar', 'global', 'setglobal']]
setglobal foldignore=bar
call assert_equal([], g:options)
call assert_equal(g:opt[0], g:opt[1])
" 22d: Setting local string local (to window) option"
noa set foldignore& " Reset global and local value (without triggering autocmd)
let g:options = [['foldignore', oldval, oldval, '', 'baz', 'local', 'setlocal']]
setlocal foldignore=baz
call assert_equal([], g:options)
call assert_equal(g:opt[0], g:opt[1])
" 22e: Setting again string local (to window) option"
noa setglobal foldignore=glob " Reset global and local value (without triggering autocmd)
noa setlocal foldignore=loc
let g:options = [['foldignore', 'loc', 'loc', 'glob', 'fo', 'global', 'set']]
set foldignore=fo
call assert_equal([], g:options)
call assert_equal(g:opt[0], g:opt[1])
" 23a: Setting global number global option"
noa setglobal cmdheight=8 " Reset global and local value (without triggering autocmd)
noa setlocal cmdheight=1 " Sets the global(!) value!
let g:options = [['cmdheight', '1', '', '1', '2', 'global', 'setglobal']]
setglobal cmdheight=2
call assert_equal([], g:options)
call assert_equal(g:opt[0], g:opt[1])
" 23b: Setting local number global option"
noa setglobal cmdheight=8 " Reset global and local value (without triggering autocmd)
noa setlocal cmdheight=1 " Sets the global(!) value!
let g:options = [['cmdheight', '1', '1', '', '2', 'local', 'setlocal']]
setlocal cmdheight=2
call assert_equal([], g:options)
call assert_equal(g:opt[0], g:opt[1])
" 23c: Setting again number global option"
noa setglobal cmdheight=8 " Reset global and local value (without triggering autocmd)
noa setlocal cmdheight=1 " Sets the global(!) value!
let g:options = [['cmdheight', '1', '1', '1', '2', 'global', 'set']]
set cmdheight=2
call assert_equal([], g:options)
call assert_equal(g:opt[0], g:opt[1])
" 23d: Setting again number global option"
noa set cmdheight=8 " Reset global and local value (without triggering autocmd)
let g:options = [['cmdheight', '8', '8', '8', '2', 'global', 'set']]
set cmdheight=2
call assert_equal([], g:options)
call assert_equal(g:opt[0], g:opt[1])
" 24a: Setting global number global-local (to buffer) option"
noa setglobal undolevels=8 " Reset global and local value (without triggering autocmd)
noa setlocal undolevels=1
let g:options = [['undolevels', '8', '', '8', '2', 'global', 'setglobal']]
setglobal undolevels=2
call assert_equal([], g:options)
call assert_equal(g:opt[0], g:opt[1])
" 24b: Setting local number global-local (to buffer) option"
noa setglobal undolevels=8 " Reset global and local value (without triggering autocmd)
noa setlocal undolevels=1
let g:options = [['undolevels', '1', '1', '', '2', 'local', 'setlocal']]
setlocal undolevels=2
call assert_equal([], g:options)
call assert_equal(g:opt[0], g:opt[1])
" 24c: Setting again number global-local (to buffer) option"
noa setglobal undolevels=8 " Reset global and local value (without triggering autocmd)
noa setlocal undolevels=1
let g:options = [['undolevels', '1', '1', '8', '2', 'global', 'set']]
set undolevels=2
call assert_equal([], g:options)
call assert_equal(g:opt[0], g:opt[1])
" 24d: Setting again global number global-local (to buffer) option"
noa set undolevels=8 " Reset global and local value (without triggering autocmd)
let g:options = [['undolevels', '8', '8', '8', '2', 'global', 'set']]
set undolevels=2
call assert_equal([], g:options)
call assert_equal(g:opt[0], g:opt[1])
" 25a: Setting global number local (to buffer) option"
noa setglobal wrapmargin=8 " Reset global and local value (without triggering autocmd)
noa setlocal wrapmargin=1
let g:options = [['wrapmargin', '8', '', '8', '2', 'global', 'setglobal']]
setglobal wrapmargin=2
call assert_equal([], g:options)
call assert_equal(g:opt[0], g:opt[1])
" 25b: Setting local number local (to buffer) option"
noa setglobal wrapmargin=8 " Reset global and local value (without triggering autocmd)
noa setlocal wrapmargin=1
let g:options = [['wrapmargin', '1', '1', '', '2', 'local', 'setlocal']]
setlocal wrapmargin=2
call assert_equal([], g:options)
call assert_equal(g:opt[0], g:opt[1])
" 25c: Setting again number local (to buffer) option"
noa setglobal wrapmargin=8 " Reset global and local value (without triggering autocmd)
noa setlocal wrapmargin=1
let g:options = [['wrapmargin', '1', '1', '8', '2', 'global', 'set']]
set wrapmargin=2
call assert_equal([], g:options)
call assert_equal(g:opt[0], g:opt[1])
" 25d: Setting again global number local (to buffer) option"
noa set wrapmargin=8 " Reset global and local value (without triggering autocmd)
let g:options = [['wrapmargin', '8', '8', '8', '2', 'global', 'set']]
set wrapmargin=2
call assert_equal([], g:options)
call assert_equal(g:opt[0], g:opt[1])
" 26: Setting number global-local (to window) option.
" Such option does currently not exist.
" 27a: Setting global number local (to window) option"
noa setglobal foldcolumn=8 " Reset global and local value (without triggering autocmd)
noa setlocal foldcolumn=1
let g:options = [['foldcolumn', '8', '', '8', '2', 'global', 'setglobal']]
setglobal foldcolumn=2
call assert_equal([], g:options)
call assert_equal(g:opt[0], g:opt[1])
" 27b: Setting local number local (to window) option"
noa setglobal foldcolumn=8 " Reset global and local value (without triggering autocmd)
noa setlocal foldcolumn=1
let g:options = [['foldcolumn', '1', '1', '', '2', 'local', 'setlocal']]
setlocal foldcolumn=2
call assert_equal([], g:options)
call assert_equal(g:opt[0], g:opt[1])
" 27c: Setting again number local (to window) option"
noa setglobal foldcolumn=8 " Reset global and local value (without triggering autocmd)
noa setlocal foldcolumn=1
let g:options = [['foldcolumn', '1', '1', '8', '2', 'global', 'set']]
set foldcolumn=2
call assert_equal([], g:options)
call assert_equal(g:opt[0], g:opt[1])
" 27d: Setting again global number local (to window) option"
noa set foldcolumn=8 " Reset global and local value (without triggering autocmd)
let g:options = [['foldcolumn', '8', '8', '8', '2', 'global', 'set']]
set foldcolumn=2
call assert_equal([], g:options)
call assert_equal(g:opt[0], g:opt[1])
" 28a: Setting global boolean global option"
noa setglobal nowrapscan " Reset global and local value (without triggering autocmd)
noa setlocal wrapscan " Sets the global(!) value!
let g:options = [['wrapscan', '1', '', '1', '0', 'global', 'setglobal']]
setglobal nowrapscan
call assert_equal([], g:options)
call assert_equal(g:opt[0], g:opt[1])
" 28b: Setting local boolean global option"
noa setglobal nowrapscan " Reset global and local value (without triggering autocmd)
noa setlocal wrapscan " Sets the global(!) value!
let g:options = [['wrapscan', '1', '1', '', '0', 'local', 'setlocal']]
setlocal nowrapscan
call assert_equal([], g:options)
call assert_equal(g:opt[0], g:opt[1])
" 28c: Setting again boolean global option"
noa setglobal nowrapscan " Reset global and local value (without triggering autocmd)
noa setlocal wrapscan " Sets the global(!) value!
let g:options = [['wrapscan', '1', '1', '1', '0', 'global', 'set']]
set nowrapscan
call assert_equal([], g:options)
call assert_equal(g:opt[0], g:opt[1])
" 28d: Setting again global boolean global option"
noa set nowrapscan " Reset global and local value (without triggering autocmd)
let g:options = [['wrapscan', '0', '0', '0', '1', 'global', 'set']]
set wrapscan
call assert_equal([], g:options)
call assert_equal(g:opt[0], g:opt[1])
" 29a: Setting global boolean global-local (to buffer) option"
noa setglobal noautoread " Reset global and local value (without triggering autocmd)
noa setlocal autoread
let g:options = [['autoread', '0', '', '0', '1', 'global', 'setglobal']]
setglobal autoread
call assert_equal([], g:options)
call assert_equal(g:opt[0], g:opt[1])
" 29b: Setting local boolean global-local (to buffer) option"
noa setglobal noautoread " Reset global and local value (without triggering autocmd)
noa setlocal autoread
let g:options = [['autoread', '1', '1', '', '0', 'local', 'setlocal']]
setlocal noautoread
call assert_equal([], g:options)
call assert_equal(g:opt[0], g:opt[1])
" 29c: Setting again boolean global-local (to buffer) option"
noa setglobal noautoread " Reset global and local value (without triggering autocmd)
noa setlocal autoread
let g:options = [['autoread', '1', '1', '0', '1', 'global', 'set']]
set autoread
call assert_equal([], g:options)
call assert_equal(g:opt[0], g:opt[1])
" 29d: Setting again global boolean global-local (to buffer) option"
noa set noautoread " Reset global and local value (without triggering autocmd)
let g:options = [['autoread', '0', '0', '0', '1', 'global', 'set']]
set autoread
call assert_equal([], g:options)
call assert_equal(g:opt[0], g:opt[1])
" 30a: Setting global boolean local (to buffer) option"
noa setglobal nocindent " Reset global and local value (without triggering autocmd)
noa setlocal cindent
let g:options = [['cindent', '0', '', '0', '1', 'global', 'setglobal']]
setglobal cindent
call assert_equal([], g:options)
call assert_equal(g:opt[0], g:opt[1])
" 30b: Setting local boolean local (to buffer) option"
noa setglobal nocindent " Reset global and local value (without triggering autocmd)
noa setlocal cindent
let g:options = [['cindent', '1', '1', '', '0', 'local', 'setlocal']]
setlocal nocindent
call assert_equal([], g:options)
call assert_equal(g:opt[0], g:opt[1])
" 30c: Setting again boolean local (to buffer) option"
noa setglobal nocindent " Reset global and local value (without triggering autocmd)
noa setlocal cindent
let g:options = [['cindent', '1', '1', '0', '1', 'global', 'set']]
set cindent
call assert_equal([], g:options)
call assert_equal(g:opt[0], g:opt[1])
" 30d: Setting again global boolean local (to buffer) option"
noa set nocindent " Reset global and local value (without triggering autocmd)
let g:options = [['cindent', '0', '0', '0', '1', 'global', 'set']]
set cindent
call assert_equal([], g:options)
call assert_equal(g:opt[0], g:opt[1])
" 31: Setting boolean global-local (to window) option
" Currently no such option exists.
" 32a: Setting global boolean local (to window) option"
noa setglobal nocursorcolumn " Reset global and local value (without triggering autocmd)
noa setlocal cursorcolumn
let g:options = [['cursorcolumn', '0', '', '0', '1', 'global', 'setglobal']]
setglobal cursorcolumn
call assert_equal([], g:options)
call assert_equal(g:opt[0], g:opt[1])
" 32b: Setting local boolean local (to window) option"
noa setglobal nocursorcolumn " Reset global and local value (without triggering autocmd)
noa setlocal cursorcolumn
let g:options = [['cursorcolumn', '1', '1', '', '0', 'local', 'setlocal']]
setlocal nocursorcolumn
call assert_equal([], g:options)
call assert_equal(g:opt[0], g:opt[1])
" 32c: Setting again boolean local (to window) option"
noa setglobal nocursorcolumn " Reset global and local value (without triggering autocmd)
noa setlocal cursorcolumn
let g:options = [['cursorcolumn', '1', '1', '0', '1', 'global', 'set']]
set cursorcolumn
call assert_equal([], g:options)
call assert_equal(g:opt[0], g:opt[1])
" 32d: Setting again global boolean local (to window) option"
noa set nocursorcolumn " Reset global and local value (without triggering autocmd)
let g:options = [['cursorcolumn', '0', '0', '0', '1', 'global', 'set']]
set cursorcolumn
call assert_equal([], g:options)
call assert_equal(g:opt[0], g:opt[1])
" 33: Test autocommands when an option value is converted internally.
noa set backspace=1 " Reset global and local value (without triggering autocmd)
let g:options = [['backspace', 'indent,eol', 'indent,eol', 'indent,eol', '2', 'global', 'set']]
set backspace=2
call assert_equal([], g:options)
call assert_equal(g:opt[0], g:opt[1])
" Cleanup " Cleanup
au! OptionSet au! OptionSet
" set tags& " set tags&
for opt in ['nu', 'ai', 'acd', 'ar', 'bs', 'backup', 'cul', 'cp', 'tags'] for opt in ['nu', 'ai', 'acd', 'ar', 'bs', 'backup', 'cul', 'cp', 'backupext', 'tags', 'spelllang', 'statusline', 'foldignore', 'cmdheight', 'undolevels', 'wrapmargin', 'foldcolumn', 'wrapscan', 'autoread', 'cindent', 'cursorcolumn']
exe printf(":set %s&vim", opt) exe printf(":set %s&vim", opt)
endfor endfor
call test_override('starting', 0) call test_override('starting', 0)

View File

@ -1,6 +1,6 @@
local helpers = require('test.functional.helpers')(after_each) local helpers = require('test.functional.helpers')(after_each)
local nvim = helpers.meths local nvim = helpers.meths
local clear, eq, neq = helpers.clear, helpers.eq, helpers.neq local clear, eq, neq, eval = helpers.clear, helpers.eq, helpers.neq, helpers.eval
local curbuf, buf = helpers.curbuf, helpers.bufmeths local curbuf, buf = helpers.curbuf, helpers.bufmeths
local curwin = helpers.curwin local curwin = helpers.curwin
local exec_capture = helpers.exec_capture local exec_capture = helpers.exec_capture
@ -10,11 +10,14 @@ local function declare_hook_function()
source([[ source([[
fu! AutoCommand(match, bufnr, winnr) fu! AutoCommand(match, bufnr, winnr)
let l:acc = { let l:acc = {
\ 'option' : a:match, \ 'option' : a:match,
\ 'oldval' : v:option_old, \ 'oldval' : v:option_old,
\ 'newval' : v:option_new, \ 'oldval_l' : v:option_oldlocal,
\ 'scope' : v:option_type, \ 'oldval_g' : v:option_oldglobal,
\ 'attr' : { \ 'newval' : v:option_new,
\ 'scope' : v:option_type,
\ 'cmd' : v:option_command,
\ 'attr' : {
\ 'bufnr' : a:bufnr, \ 'bufnr' : a:bufnr,
\ 'winnr' : a:winnr, \ 'winnr' : a:winnr,
\ } \ }
@ -42,13 +45,16 @@ local function get_result()
return ret return ret
end end
local function expected_table(option, oldval, newval, scope, attr) local function expected_table(option, oldval, oldval_l, oldval_g, newval, scope, cmd, attr)
return { return {
option = option, option = option,
oldval = tostring(oldval), oldval = tostring(oldval),
newval = tostring(newval), oldval_l = tostring(oldval_l),
scope = scope, oldval_g = tostring(oldval_g),
attr = attr, newval = tostring(newval),
scope = scope,
cmd = cmd,
attr = attr,
} }
end end
@ -66,7 +72,7 @@ local function expected_combination(...)
end end
for i, v in ipairs(args) do for i, v in ipairs(args) do
local attr = v[5] local attr = v[8]
if not attr then if not attr then
-- remove attr entries -- remove attr entries
ret[i].attr = nil ret[i].attr = nil
@ -112,7 +118,7 @@ local function get_new_window_number()
end end
describe('au OptionSet', function() describe('au OptionSet', function()
describe('with any opton (*)', function() describe('with any option (*)', function()
before_each(function() before_each(function()
clear() clear()
@ -123,44 +129,44 @@ describe('au OptionSet', function()
it('should be called in setting number option', function() it('should be called in setting number option', function()
command('set nu') command('set nu')
expected_combination({'number', 0, 1, 'global'}) expected_combination({'number', 0, 0, 0, 1, 'global', 'set'})
command('setlocal nonu') command('setlocal nonu')
expected_combination({'number', 1, 0, 'local'}) expected_combination({'number', 1, 1, '', 0, 'local', 'setlocal'})
command('setglobal nonu') command('setglobal nonu')
expected_combination({'number', 1, 0, 'global'}) expected_combination({'number', 1, '', 1, 0, 'global', 'setglobal'})
end) end)
it('should be called in setting autoindent option',function() it('should be called in setting autoindent option',function()
command('setlocal ai') command('setlocal ai')
expected_combination({'autoindent', 0, 1, 'local'}) expected_combination({'autoindent', 0, 0, '', 1, 'local', 'setlocal'})
command('setglobal ai') command('setglobal ai')
expected_combination({'autoindent', 0, 1, 'global'}) expected_combination({'autoindent', 0, '', 0, 1, 'global', 'setglobal'})
command('set noai') command('set noai')
expected_combination({'autoindent', 1, 0, 'global'}) expected_combination({'autoindent', 1, 1, 1, 0, 'global', 'set'})
end) end)
it('should be called in inverting global autoindent option',function() it('should be called in inverting global autoindent option',function()
command('set ai!') command('set ai!')
expected_combination({'autoindent', 0, 1, 'global'}) expected_combination({'autoindent', 0, 0, 0, 1, 'global', 'set'})
end) end)
it('should be called in being unset local autoindent option',function() it('should be called in being unset local autoindent option',function()
command('setlocal ai') command('setlocal ai')
expected_combination({'autoindent', 0, 1, 'local'}) expected_combination({'autoindent', 0, 0, '', 1, 'local', 'setlocal'})
command('setlocal ai<') command('setlocal ai<')
expected_combination({'autoindent', 1, 0, 'local'}) expected_combination({'autoindent', 1, 1, '', 0, 'local', 'setlocal'})
end) end)
it('should be called in setting global list and number option at the same time',function() it('should be called in setting global list and number option at the same time',function()
command('set list nu') command('set list nu')
expected_combination( expected_combination(
{'list', 0, 1, 'global'}, {'list', 0, 0, 0, 1, 'global', 'set'},
{'number', 0, 1, 'global'} {'number', 0, 0, 0, 1, 'global', 'set'}
) )
end) end)
@ -171,25 +177,27 @@ describe('au OptionSet', function()
it('should be called in setting local acd', function() it('should be called in setting local acd', function()
command('setlocal acd') command('setlocal acd')
expected_combination({'autochdir', 0, 1, 'local'}) expected_combination({'autochdir', 0, 0, '', 1, 'local', 'setlocal'})
end) end)
it('should be called in setting autoread', function() it('should be called in setting autoread', function()
command('set noar') command('set noar')
expected_combination({'autoread', 1, 0, 'global'}) expected_combination({'autoread', 1, 1, 1, 0, 'global', 'set'})
command('setlocal ar') command('setlocal ar')
expected_combination({'autoread', 0, 1, 'local'}) expected_combination({'autoread', 0, 0, '', 1, 'local', 'setlocal'})
end) end)
it('should be called in inverting global autoread', function() it('should be called in inverting global autoread', function()
command('setglobal invar') command('setglobal invar')
expected_combination({'autoread', 1, 0, 'global'}) expected_combination({'autoread', 1, '', 1, 0, 'global', 'setglobal'})
end) end)
it('should be called in setting backspace option through :let', function() it('should be called in setting backspace option through :let', function()
local oldval = eval('&backspace')
command('let &bs=""') command('let &bs=""')
expected_combination({'backspace', 'indent,eol,start', '', 'global'}) expected_combination({'backspace', oldval, oldval, oldval, '', 'global', 'set'})
end) end)
describe('being set by setbufvar()', function() describe('being set by setbufvar()', function()
@ -200,7 +208,7 @@ describe('au OptionSet', function()
it('should trigger using correct option name', function() it('should trigger using correct option name', function()
command('call setbufvar(1, "&backup", 1)') command('call setbufvar(1, "&backup", 1)')
expected_combination({'backup', 0, 1, 'local'}) expected_combination({'backup', 0, 0, '', 1, 'local', 'setlocal'})
end) end)
it('should trigger if the current buffer is different from the targetted buffer', function() it('should trigger if the current buffer is different from the targetted buffer', function()
@ -208,9 +216,339 @@ describe('au OptionSet', function()
local new_bufnr = buf.get_number(new_buffer) local new_bufnr = buf.get_number(new_buffer)
command('call setbufvar(' .. new_bufnr .. ', "&buftype", "nofile")') command('call setbufvar(' .. new_bufnr .. ', "&buftype", "nofile")')
expected_combination({'buftype', '', 'nofile', 'local', {bufnr = new_bufnr}}) expected_combination({'buftype', '', '', '', 'nofile', 'local', 'setlocal', {bufnr = new_bufnr}})
end) end)
end) end)
it('with string global option', function()
local oldval = eval('&backupext')
command('set backupext=foo')
expected_combination({'backupext', oldval, oldval, oldval, 'foo', 'global', 'set'})
command('set backupext&')
expected_combination({'backupext', 'foo', 'foo', 'foo', oldval, 'global', 'set'})
command('setglobal backupext=bar')
expected_combination({'backupext', oldval, '', oldval, 'bar', 'global', 'setglobal'})
command('noa set backupext&')
-- As this is a global option this sets the global value even though :setlocal is used!
command('setlocal backupext=baz')
expected_combination({'backupext', oldval, oldval, '', 'baz', 'local', 'setlocal'})
command('noa setglobal backupext=ext_global')
command('noa setlocal backupext=ext_local') -- Sets the global(!) value
command('set backupext=foo')
expected_combination({
'backupext', 'ext_local', 'ext_local', 'ext_local', 'foo', 'global', 'set'
})
end)
it('with string global-local (to buffer) option', function()
local oldval = eval('&tags')
command('set tags=tagpath')
expected_combination({'tags', oldval, oldval, oldval, 'tagpath', 'global', 'set'})
command('set tags&')
expected_combination({'tags', 'tagpath', 'tagpath', 'tagpath', oldval, 'global', 'set'})
command('setglobal tags=tagpath1')
expected_combination({'tags', oldval, '', oldval, 'tagpath1', 'global', 'setglobal'})
command('setlocal tags=tagpath2')
expected_combination({'tags', 'tagpath1', 'tagpath1', '', 'tagpath2', 'local', 'setlocal'})
-- Note: v:option_old is the old global value for global-local string options
-- but the old local value for all other kinds of options.
command('noa setglobal tags=tag_global')
command('noa setlocal tags=tag_local')
command('set tags=tagpath')
expected_combination({
'tags', 'tag_global', 'tag_local', 'tag_global', 'tagpath', 'global', 'set'
})
-- Note: v:option_old is the old global value for global-local string options
-- but the old local value for all other kinds of options.
command('noa set tags=tag_global')
command('noa setlocal tags=')
command('set tags=tagpath')
expected_combination({'tags', 'tag_global', '', 'tag_global', 'tagpath', 'global', 'set'})
end)
it('with string local (to buffer) option', function()
local oldval = eval('&spelllang')
command('set spelllang=elvish,klingon')
expected_combination({'spelllang', oldval, oldval, oldval, 'elvish,klingon', 'global', 'set'})
command('set spelllang&')
expected_combination({
'spelllang', 'elvish,klingon', 'elvish,klingon', 'elvish,klingon', oldval, 'global', 'set'
})
command('setglobal spelllang=elvish')
expected_combination({'spelllang', oldval, '', oldval, 'elvish', 'global', 'setglobal'})
command('noa set spelllang&')
command('setlocal spelllang=klingon')
expected_combination({'spelllang', oldval, oldval, '', 'klingon', 'local', 'setlocal'})
-- Note: v:option_old is the old global value for global-local string options
-- but the old local value for all other kinds of options.
command('noa setglobal spelllang=spellglobal')
command('noa setlocal spelllang=spelllocal')
command('set spelllang=foo')
expected_combination({
'spelllang', 'spelllocal', 'spelllocal', 'spellglobal', 'foo', 'global', 'set'
})
end)
it('with string global-local (to window) option', function()
local oldval = eval('&statusline')
command('set statusline=foo')
expected_combination({'statusline', oldval, oldval, '', 'foo', 'global', 'set'})
-- Note: v:option_old is the old global value for global-local string options
-- but the old local value for all other kinds of options.
command('set statusline&')
expected_combination({'statusline', 'foo', 'foo', 'foo', oldval, 'global', 'set'})
command('setglobal statusline=bar')
expected_combination({'statusline', oldval, '', oldval, 'bar', 'global', 'setglobal'})
command('noa set statusline&')
command('setlocal statusline=baz')
expected_combination({'statusline', oldval, oldval, '', 'baz', 'local', 'setlocal'})
-- Note: v:option_old is the old global value for global-local string options
-- but the old local value for all other kinds of options.
command('noa setglobal statusline=bar')
command('noa setlocal statusline=baz')
command('set statusline=foo')
expected_combination({'statusline', 'bar', 'baz', 'bar', 'foo', 'global', 'set'})
end)
it('with string local (to window) option', function()
local oldval = eval('&foldignore')
command('set foldignore=fo')
expected_combination({'foldignore', oldval, oldval, oldval, 'fo', 'global', 'set'})
command('set foldignore&')
expected_combination({'foldignore', 'fo', 'fo', 'fo', oldval, 'global', 'set'})
command('setglobal foldignore=bar')
expected_combination({'foldignore', oldval, '', oldval, 'bar', 'global', 'setglobal'})
command('noa set foldignore&')
command('setlocal foldignore=baz')
expected_combination({'foldignore', oldval, oldval, '', 'baz', 'local', 'setlocal'})
command('noa setglobal foldignore=glob')
command('noa setlocal foldignore=loc')
command('set foldignore=fo')
expected_combination({'foldignore', 'loc', 'loc', 'glob', 'fo', 'global', 'set'})
end)
it('with number global option', function()
command('noa setglobal cmdheight=8')
command('noa setlocal cmdheight=1') -- Sets the global(!) value
command('setglobal cmdheight=2')
expected_combination({'cmdheight', 1, '', 1, 2, 'global', 'setglobal'})
command('noa setglobal cmdheight=8')
command('noa setlocal cmdheight=1') -- Sets the global(!) value
command('setlocal cmdheight=2')
expected_combination({'cmdheight', 1, 1, '', 2, 'local', 'setlocal'})
command('noa setglobal cmdheight=8')
command('noa setlocal cmdheight=1') -- Sets the global(!) value
command('set cmdheight=2')
expected_combination({'cmdheight', 1, 1, 1, 2, 'global', 'set'})
command('noa set cmdheight=8')
command('set cmdheight=2')
expected_combination({'cmdheight', 8, 8, 8, 2, 'global', 'set'})
end)
it('with number global-local (to buffer) option', function()
command('noa setglobal undolevels=8')
command('noa setlocal undolevels=1')
command('setglobal undolevels=2')
expected_combination({'undolevels', 8, '', 8, 2, 'global', 'setglobal'})
command('noa setglobal undolevels=8')
command('noa setlocal undolevels=1')
command('setlocal undolevels=2')
expected_combination({'undolevels', 1, 1, '', 2, 'local', 'setlocal'})
command('noa setglobal undolevels=8')
command('noa setlocal undolevels=1')
command('set undolevels=2')
expected_combination({'undolevels', 1, 1, 8, 2, 'global', 'set'})
command('noa set undolevels=8')
command('set undolevels=2')
expected_combination({'undolevels', 8, 8, 8, 2, 'global', 'set'})
end)
it('with number local (to buffer) option', function()
command('noa setglobal wrapmargin=8')
command('noa setlocal wrapmargin=1')
command('setglobal wrapmargin=2')
expected_combination({'wrapmargin', 8, '', 8, 2, 'global', 'setglobal'})
command('noa setglobal wrapmargin=8')
command('noa setlocal wrapmargin=1')
command('setlocal wrapmargin=2')
expected_combination({'wrapmargin', 1, 1, '', 2, 'local', 'setlocal'})
command('noa setglobal wrapmargin=8')
command('noa setlocal wrapmargin=1')
command('set wrapmargin=2')
expected_combination({'wrapmargin', 1, 1, 8, 2, 'global', 'set'})
command('noa set wrapmargin=8')
command('set wrapmargin=2')
expected_combination({'wrapmargin', 8, 8, 8, 2, 'global', 'set'})
end)
it('with number global-local (to window) option', function()
command('noa setglobal scrolloff=8')
command('noa setlocal scrolloff=1')
command('setglobal scrolloff=2')
expected_combination({'scrolloff', 8, '', 8, 2, 'global', 'setglobal'})
command('noa setglobal scrolloff=8')
command('noa setlocal scrolloff=1')
command('setlocal scrolloff=2')
expected_combination({'scrolloff', 1, 1, '', 2, 'local', 'setlocal'})
command('noa setglobal scrolloff=8')
command('noa setlocal scrolloff=1')
command('set scrolloff=2')
expected_combination({'scrolloff', 1, 1, 8, 2, 'global', 'set'})
command('noa set scrolloff=8')
command('set scrolloff=2')
expected_combination({'scrolloff', 8, 8, 8, 2, 'global', 'set'})
end)
it('with number local (to window) option', function()
command('noa setglobal foldcolumn=8')
command('noa setlocal foldcolumn=1')
command('setglobal foldcolumn=2')
expected_combination({'foldcolumn', 8, '', 8, 2, 'global', 'setglobal'})
command('noa setglobal foldcolumn=8')
command('noa setlocal foldcolumn=1')
command('setlocal foldcolumn=2')
expected_combination({'foldcolumn', 1, 1, '', 2, 'local', 'setlocal'})
command('noa setglobal foldcolumn=8')
command('noa setlocal foldcolumn=1')
command('set foldcolumn=2')
expected_combination({'foldcolumn', 1, 1, 8, 2, 'global', 'set'})
command('noa set foldcolumn=8')
command('set foldcolumn=2')
expected_combination({'foldcolumn', 8, 8, 8, 2, 'global', 'set'})
end)
it('with boolean global option', function()
command('noa setglobal nowrapscan')
command('noa setlocal wrapscan') -- Sets the global(!) value
command('setglobal nowrapscan')
expected_combination({'wrapscan', 1, '', 1, 0, 'global', 'setglobal'})
command('noa setglobal nowrapscan')
command('noa setlocal wrapscan') -- Sets the global(!) value
command('setlocal nowrapscan')
expected_combination({'wrapscan', 1, 1, '', 0, 'local', 'setlocal'})
command('noa setglobal nowrapscan')
command('noa setlocal wrapscan') -- Sets the global(!) value
command('set nowrapscan')
expected_combination({'wrapscan', 1, 1, 1, 0, 'global', 'set'})
command('noa set nowrapscan')
command('set wrapscan')
expected_combination({'wrapscan', 0, 0, 0, 1, 'global', 'set'})
end)
it('with boolean global-local (to buffer) option', function()
command('noa setglobal noautoread')
command('noa setlocal autoread')
command('setglobal autoread')
expected_combination({'autoread', 0, '', 0, 1, 'global', 'setglobal'})
command('noa setglobal noautoread')
command('noa setlocal autoread')
command('setlocal noautoread')
expected_combination({'autoread', 1, 1, '', 0, 'local', 'setlocal'})
command('noa setglobal noautoread')
command('noa setlocal autoread')
command('set autoread')
expected_combination({'autoread', 1, 1, 0, 1, 'global', 'set'})
command('noa set noautoread')
command('set autoread')
expected_combination({'autoread', 0, 0, 0, 1, 'global', 'set'})
end)
it('with boolean local (to buffer) option', function()
command('noa setglobal nocindent')
command('noa setlocal cindent')
command('setglobal cindent')
expected_combination({'cindent', 0, '', 0, 1, 'global', 'setglobal'})
command('noa setglobal nocindent')
command('noa setlocal cindent')
command('setlocal nocindent')
expected_combination({'cindent', 1, 1, '', 0, 'local', 'setlocal'})
command('noa setglobal nocindent')
command('noa setlocal cindent')
command('set cindent')
expected_combination({'cindent', 1, 1, 0, 1, 'global', 'set'})
command('noa set nocindent')
command('set cindent')
expected_combination({'cindent', 0, 0, 0, 1, 'global', 'set'})
end)
it('with boolean local (to window) option', function()
command('noa setglobal nocursorcolumn')
command('noa setlocal cursorcolumn')
command('setglobal cursorcolumn')
expected_combination({'cursorcolumn', 0, '', 0, 1, 'global', 'setglobal'})
command('noa setglobal nocursorcolumn')
command('noa setlocal cursorcolumn')
command('setlocal nocursorcolumn')
expected_combination({'cursorcolumn', 1, 1, '', 0, 'local', 'setlocal'})
command('noa setglobal nocursorcolumn')
command('noa setlocal cursorcolumn')
command('set cursorcolumn')
expected_combination({'cursorcolumn', 1, 1, 0, 1, 'global', 'set'})
command('noa set nocursorcolumn')
command('set cursorcolumn')
expected_combination({'cursorcolumn', 0, 0, 0, 1, 'global', 'set'})
end)
it('with option value converted internally', function()
command('noa set backspace=1')
command('set backspace=2')
expected_combination(({
'backspace', 'indent,eol', 'indent,eol', 'indent,eol', '2', 'global', 'set'
}))
end)
end) end)
describe('with specific option', function() describe('with specific option', function()
@ -228,13 +566,13 @@ describe('au OptionSet', function()
expected_empty() expected_empty()
command('setlocal ro') command('setlocal ro')
expected_combination({'readonly', 0, 1, 'local'}) expected_combination({'readonly', 0, 0, '', 1, 'local', 'setlocal'})
command('setglobal ro') command('setglobal ro')
expected_combination({'readonly', 0, 1, 'global'}) expected_combination({'readonly', 0, '', 0, 1, 'global', 'setglobal'})
command('set noro') command('set noro')
expected_combination({'readonly', 1, 0, 'global'}) expected_combination({'readonly', 1, 1, 1, 0, 'global', 'set'})
end) end)
describe('being set by setbufvar()', function() describe('being set by setbufvar()', function()
@ -249,7 +587,7 @@ describe('au OptionSet', function()
set_hook('backup') set_hook('backup')
command('call setbufvar(1, "&backup", 1)') command('call setbufvar(1, "&backup", 1)')
expected_combination({'backup', 0, 1, 'local'}) expected_combination({'backup', 0, 0, '', 1, 'local', 'setlocal'})
end) end)
it('should trigger if the current buffer is different from the targetted buffer', function() it('should trigger if the current buffer is different from the targetted buffer', function()
@ -259,7 +597,7 @@ describe('au OptionSet', function()
local new_bufnr = buf.get_number(new_buffer) local new_bufnr = buf.get_number(new_buffer)
command('call setbufvar(' .. new_bufnr .. ', "&buftype", "nofile")') command('call setbufvar(' .. new_bufnr .. ', "&buftype", "nofile")')
expected_combination({'buftype', '', 'nofile', 'local', {bufnr = new_bufnr}}) expected_combination({'buftype', '', '', '', 'nofile', 'local', 'setlocal', {bufnr = new_bufnr}})
end) end)
end) end)
@ -275,7 +613,7 @@ describe('au OptionSet', function()
set_hook('backup') set_hook('backup')
command('call setwinvar(1, "&backup", 1)') command('call setwinvar(1, "&backup", 1)')
expected_combination({'backup', 0, 1, 'local'}) expected_combination({'backup', 0, 0, '', 1, 'local', 'setlocal'})
end) end)
it('should not trigger if the current window is different from the targetted window', function() it('should not trigger if the current window is different from the targetted window', function()
@ -295,7 +633,7 @@ describe('au OptionSet', function()
nvim.set_option('autochdir', true) nvim.set_option('autochdir', true)
eq(true, nvim.get_option('autochdir')) eq(true, nvim.get_option('autochdir'))
expected_combination({'autochdir', '0', '1', 'global'}) expected_combination({'autochdir', 0, '', 0, 1, 'global', 'setglobal'})
end) end)
it('should trigger if a number option be set globally', function() it('should trigger if a number option be set globally', function()
@ -303,7 +641,7 @@ describe('au OptionSet', function()
nvim.set_option('cmdheight', 5) nvim.set_option('cmdheight', 5)
eq(5, nvim.get_option('cmdheight')) eq(5, nvim.get_option('cmdheight'))
expected_combination({'cmdheight', 1, 5, 'global'}) expected_combination({'cmdheight', 1, '', 1, 5, 'global', 'setglobal'})
end) end)
it('should trigger if a string option be set globally', function() it('should trigger if a string option be set globally', function()
@ -311,7 +649,7 @@ describe('au OptionSet', function()
nvim.set_option('ambiwidth', 'double') nvim.set_option('ambiwidth', 'double')
eq('double', nvim.get_option('ambiwidth')) eq('double', nvim.get_option('ambiwidth'))
expected_combination({'ambiwidth', 'single', 'double', 'global'}) expected_combination({'ambiwidth', 'single', '', 'single', 'double', 'global', 'setglobal'})
end) end)
end) end)
end) end)