Merge pull request #25394 from famiu/refactor/options/set_option

refactor(options)!: unify interfaces for setting options
This commit is contained in:
bfredl 2023-10-16 20:41:35 +02:00 committed by GitHub
commit a63c67005b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 670 additions and 727 deletions

View File

@ -71,6 +71,10 @@ The following changes may require adaptations in user config or plugins.
defined by LSP, and hence previously parsed snippets might now be considered
invalid input.
• |OptionSet| autocommand args |v:option_new|, |v:option_old|,
|v:option_oldlocal|, |v:option_oldglobal| now have the type of the option
instead of always being strings.
==============================================================================
NEW FEATURES *news-features*

View File

@ -379,6 +379,9 @@ UI/Display:
Variables:
|v:progpath| is always absolute ("full")
|v:windowid| is always available (for use by external UIs)
|OptionSet| autocommand args |v:option_new|, |v:option_old|,
|v:option_oldlocal|, |v:option_oldglobal| have the type of the option
instead of always being strings.
Vimscript:
|:redir| nested in |execute()| works.

View File

@ -133,47 +133,6 @@ static buf_T *do_ft_buf(char *filetype, aco_save_T *aco, Error *err)
return ftbuf;
}
/// Consume an OptVal and convert it to an API Object.
static Object optval_as_object(OptVal o)
{
switch (o.type) {
case kOptValTypeNil:
return NIL;
case kOptValTypeBoolean:
switch (o.data.boolean) {
case kFalse:
case kTrue:
return BOOLEAN_OBJ(o.data.boolean);
case kNone:
return NIL;
}
UNREACHABLE;
case kOptValTypeNumber:
return INTEGER_OBJ(o.data.number);
case kOptValTypeString:
return STRING_OBJ(o.data.string);
}
UNREACHABLE;
}
/// Consume an API Object and convert it to an OptVal.
static OptVal object_as_optval(Object o, bool *error)
{
switch (o.type) {
case kObjectTypeNil:
return NIL_OPTVAL;
case kObjectTypeBoolean:
return BOOLEAN_OPTVAL(o.data.boolean);
case kObjectTypeInteger:
return NUMBER_OPTVAL((OptInt)o.data.integer);
case kObjectTypeString:
return STRING_OPTVAL(o.data.string);
default:
*error = true;
return NIL_OPTVAL;
}
}
/// Gets the value of an option. The behavior of this function matches that of
/// |:set|: the local value of an option is returned if it exists; otherwise,
/// the global value is returned. Local values always correspond to the current

View File

@ -140,7 +140,7 @@ void alist_expand(int *fnum_list, int fnum_len)
// Don't use 'suffixes' here. This should work like the shell did the
// expansion. Also, the vimrc file isn't read yet, thus the user
// can't set the options.
p_su = empty_option;
p_su = empty_string_option;
for (int i = 0; i < GARGCOUNT; i++) {
old_arg_files[i] = xstrdup(GARGLIST[i].ae_fname);
}

View File

@ -2237,7 +2237,7 @@ int pattern_match(const char *pat, const char *text, bool ic)
// avoid 'l' flag in 'cpoptions'
char *save_cpo = p_cpo;
p_cpo = empty_option;
p_cpo = empty_string_option;
regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
if (regmatch.regprog != NULL) {
regmatch.rm_ic = ic;
@ -7226,6 +7226,17 @@ void set_vim_var_dict(const VimVarIndex idx, dict_T *const val)
tv_dict_set_keys_readonly(val);
}
/// Set v:variable to tv.
///
/// @param[in] idx Index of variable to set.
/// @param[in,out] val Value to set to. Reference count will be incremented.
/// Also keys of the dictionary will be made read-only.
void set_vim_var_tv(const VimVarIndex idx, typval_T *const tv)
{
tv_clear(&vimvars[idx].vv_di.di_tv);
vimvars[idx].vv_di.di_tv = *tv;
}
/// Set the v:argv list.
void set_argv_var(char **argv, int argc)
{
@ -8634,7 +8645,7 @@ char *do_string_sub(char *str, char *pat, char *sub, typval_T *expr, const char
// Make 'cpoptions' empty, so that the 'l' flag doesn't work here
char *save_cpo = p_cpo;
p_cpo = empty_option;
p_cpo = empty_string_option;
ga_init(&ga, 1, 200);
@ -8699,7 +8710,7 @@ char *do_string_sub(char *str, char *pat, char *sub, typval_T *expr, const char
char *ret = xstrdup(ga.ga_data == NULL ? str : ga.ga_data);
ga_clear(&ga);
if (p_cpo == empty_option) {
if (p_cpo == empty_string_option) {
p_cpo = save_cpo;
} else {
// Darn, evaluating {sub} expression or {expr} changed the value.

View File

@ -482,7 +482,7 @@ buf_T *tv_get_buf(typval_T *tv, int curtab_only)
int save_magic = p_magic;
p_magic = true;
char *save_cpo = p_cpo;
p_cpo = empty_option;
p_cpo = empty_string_option;
buf_T *buf = buflist_findnr(buflist_findpat(name, name + strlen(name),
true, false, curtab_only));
@ -1733,7 +1733,7 @@ static void f_expand(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
char *p_csl_save = p_csl;
// avoid using 'completeslash' here
p_csl = empty_option;
p_csl = empty_string_option;
#endif
rettv->v_type = VAR_STRING;
@ -4516,7 +4516,7 @@ static void find_some_match(typval_T *const argvars, typval_T *const rettv,
// Make 'cpoptions' empty, the 'l' flag should not be used here.
char *save_cpo = p_cpo;
p_cpo = empty_option;
p_cpo = empty_string_option;
rettv->vval.v_number = -1;
switch (type) {
@ -7108,7 +7108,7 @@ long do_searchpair(const char *spat, const char *mpat, const char *epat, int dir
// Make 'cpoptions' empty, the 'l' flag should not be used here.
char *save_cpo = p_cpo;
p_cpo = empty_option;
p_cpo = empty_string_option;
// Set the time limit, if there is one.
proftime_T tm = profile_setlimit(time_limit);
@ -7234,7 +7234,7 @@ long do_searchpair(const char *spat, const char *mpat, const char *epat, int dir
xfree(pat2);
xfree(pat3);
if (p_cpo == empty_option) {
if (p_cpo == empty_string_option) {
p_cpo = save_cpo;
} else {
// Darn, evaluating the {skip} expression changed the value.
@ -7966,7 +7966,7 @@ static void f_split(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
// Make 'cpoptions' empty, the 'l' flag should not be used here.
char *save_cpo = p_cpo;
p_cpo = empty_option;
p_cpo = empty_string_option;
const char *str = tv_get_string(&argvars[0]);
const char *pat = NULL;

View File

@ -20,6 +20,7 @@
#include "nvim/eval/encode.h"
#include "nvim/eval/funcs.h"
#include "nvim/eval/typval.h"
#include "nvim/eval/typval_defs.h"
#include "nvim/eval/userfunc.h"
#include "nvim/eval/vars.h"
#include "nvim/eval/window.h"
@ -822,7 +823,7 @@ static char *ex_let_option(char *arg, typval_T *const tv, const bool is_const,
if (curval.type == kOptValTypeNumber) {
newval = NUMBER_OPTVAL(new_n);
} else {
newval = BOOLEAN_OPTVAL(new_n == 0 ? kFalse : (new_n >= 1 ? kTrue : kNone));
newval = BOOLEAN_OPTVAL(TRISTATE_FROM_INT(new_n));
}
} else if (!hidden && is_string
&& curval.data.string.data != NULL && newval.data.string.data != NULL) { // string
@ -1875,8 +1876,7 @@ static OptVal tv_to_optval(typval_T *tv, const char *option, uint32_t flags, boo
semsg(_("E521: Number required: &%s = '%s'"), option, tv->vval.v_string);
}
}
value = (flags & P_NUM) ? NUMBER_OPTVAL((OptInt)n)
: BOOLEAN_OPTVAL(n == 0 ? kFalse : (n >= 1 ? kTrue : kNone));
value = (flags & P_NUM) ? NUMBER_OPTVAL((OptInt)n) : BOOLEAN_OPTVAL(TRISTATE_FROM_INT(n));
} else if ((flags & P_STRING) || is_tty_option(option)) {
// Avoid setting string option to a boolean or a special value.
if (tv->v_type != VAR_BOOL && tv->v_type != VAR_SPECIAL) {
@ -1897,6 +1897,45 @@ static OptVal tv_to_optval(typval_T *tv, const char *option, uint32_t flags, boo
return value;
}
/// Convert an option value to typval.
///
/// @param[in] value Option value to convert.
///
/// @return OptVal converted to typval.
typval_T optval_as_tv(OptVal value)
{
typval_T rettv = { .v_type = VAR_SPECIAL, .vval = { .v_special = kSpecialVarNull } };
switch (value.type) {
case kOptValTypeNil:
break;
case kOptValTypeBoolean:
switch (value.data.boolean) {
case kTrue:
rettv.v_type = VAR_BOOL;
rettv.vval.v_bool = kBoolVarTrue;
break;
case kFalse:
rettv.v_type = VAR_BOOL;
rettv.vval.v_bool = kBoolVarFalse;
break;
case kNone:
break; // return v:null for None boolean value
}
break;
case kOptValTypeNumber:
rettv.v_type = VAR_NUMBER;
rettv.vval.v_number = value.data.number;
break;
case kOptValTypeString:
rettv.v_type = VAR_STRING;
rettv.vval.v_string = value.data.string.data;
break;
}
return rettv;
}
/// Set option "varname" to the value of "varp" for the current buffer/window.
static void set_option_from_tv(const char *varname, typval_T *varp)
{

View File

@ -2,6 +2,7 @@
#define NVIM_EVAL_VARS_H
#include "nvim/ex_cmds_defs.h"
#include "nvim/option_defs.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "eval/vars.h.generated.h"

View File

@ -1342,7 +1342,7 @@ void ex_catch(exarg_T *eap)
*end = NUL;
}
save_cpo = p_cpo;
p_cpo = empty_option;
p_cpo = empty_string_option;
// Disable error messages, it will make current exception
// invalid
emsg_off++;

View File

@ -789,10 +789,11 @@ EXTERN char *escape_chars INIT(= " \t\\\"|"); // need backslash in cmd line
EXTERN bool keep_help_flag INIT(= false); // doing :ta from help file
// When a string option is NULL (which only happens in out-of-memory
// situations), it is set to empty_option, to avoid having to check for NULL
// everywhere.
EXTERN char *empty_option INIT(= "");
// When a string option is NULL (which only happens in out-of-memory situations), it is set to
// empty_string_option, to avoid having to check for NULL everywhere.
//
// TODO(famiu): Remove this when refcounted strings are used for string options.
EXTERN char *empty_string_option INIT(= "");
EXTERN bool redir_off INIT(= false); // no redirection for a moment
EXTERN FILE *redir_fd INIT(= NULL); // message redirection file

View File

@ -1878,8 +1878,8 @@ void clear_showcmd(void)
char *const saved_w_sbr = curwin->w_p_sbr;
// Make 'sbr' empty for a moment to get the correct size.
p_sbr = empty_option;
curwin->w_p_sbr = empty_option;
p_sbr = empty_string_option;
curwin->w_p_sbr = empty_string_option;
getvcols(curwin, &curwin->w_cursor, &VIsual, &leftcol, &rightcol);
p_sbr = saved_sbr;
curwin->w_p_sbr = saved_w_sbr;

View File

@ -5365,8 +5365,8 @@ void cursor_pos_info(dict_T *dict)
char *const saved_w_sbr = curwin->w_p_sbr;
// Make 'sbr' empty for a moment to get the correct size.
p_sbr = empty_option;
curwin->w_p_sbr = empty_option;
p_sbr = empty_string_option;
curwin->w_p_sbr = empty_string_option;
oparg.is_VIsual = true;
oparg.motion_type = kMTBlockWise;
oparg.op_type = OP_NOP;

File diff suppressed because it is too large Load Diff

View File

@ -17,16 +17,17 @@ typedef enum {
kOptValTypeString,
} OptValType;
typedef union {
// boolean options are actually tri-states because they have a third "None" value.
TriState boolean;
OptInt number;
String string;
} OptValData;
/// Option value
typedef struct {
OptValType type;
union {
// boolean options are actually tri-states because they have a third "None" value.
TriState boolean;
OptInt number;
String string;
} data;
OptValData data;
} OptVal;
/// :set operator types
@ -45,21 +46,11 @@ typedef struct {
void *os_varp;
int os_idx;
int os_flags;
set_op_T os_op;
/// old value of the option (can be a string, number or a boolean)
union {
const OptInt number;
const bool boolean;
const char *string;
} os_oldval;
/// new value of the option (can be a string, number or a boolean)
union {
const OptInt number;
const bool boolean;
const char *string;
} os_newval;
/// Old value of the option.
OptValData os_oldval;
/// New value of the option.
OptValData os_newval;
/// When set by the called function: Stop processing the option further.
/// Currently only used for boolean options.

View File

@ -6824,6 +6824,7 @@ return {
},
{
abbreviation = 'sd',
cb = 'did_set_shada',
defaults = {
if_true = "!,'100,<50,s10,h",
doc = [[for

View File

@ -287,29 +287,28 @@ void check_buf_options(buf_T *buf)
}
/// Free the string allocated for an option.
/// Checks for the string being empty_option. This may happen if we're out of
/// memory, xstrdup() returned NULL, which was replaced by empty_option by
/// check_options().
/// Checks for the string being empty_string_option. This may happen if we're out of memory,
/// xstrdup() returned NULL, which was replaced by empty_string_option by check_options().
/// Does NOT check for P_ALLOCED flag!
void free_string_option(char *p)
{
if (p != empty_option) {
if (p != empty_string_option) {
xfree(p);
}
}
void clear_string_option(char **pp)
{
if (*pp != empty_option) {
if (*pp != empty_string_option) {
xfree(*pp);
}
*pp = empty_option;
*pp = empty_string_option;
}
void check_string_option(char **pp)
{
if (*pp == NULL) {
*pp = empty_option;
*pp = empty_string_option;
}
}
@ -385,7 +384,7 @@ void set_string_option_direct(const char *name, int opt_idx, const char *val, in
// make the local value empty, so that the global value is used.
if ((opt->indir & PV_BOTH) && both) {
free_string_option(*varp);
*varp = empty_option;
*varp = empty_string_option;
}
if (set_sid != SID_NONE) {
sctx_T script_ctx;
@ -441,14 +440,13 @@ void set_string_option_direct_in_buf(buf_T *buf, const char *name, int opt_idx,
/// #OPT_GLOBAL.
///
/// @return NULL on success, an untranslated error message on error.
const char *set_string_option(const int opt_idx, void *varp_arg, const char *value,
const int opt_flags, bool *value_checked, char *const errbuf,
const char *set_string_option(const int opt_idx, void *varp, const char *value, const int opt_flags,
const bool new_value, bool *value_checked, char *const errbuf,
const size_t errbuflen)
FUNC_ATTR_WARN_UNUSED_RESULT
{
vimoption_T *opt = get_option(opt_idx);
void *varp = (char **)varp_arg;
char *origval_l = NULL;
char *origval_g = NULL;
@ -469,7 +467,7 @@ const char *set_string_option(const int opt_idx, void *varp_arg, const char *val
// A global-local string option might have an empty option as value to
// indicate that the global value should be used.
if (((int)opt->indir & PV_BOTH) && origval_l == empty_option) {
if (((int)opt->indir & PV_BOTH) && origval_l == empty_string_option) {
origval_l = origval_g;
}
}
@ -483,7 +481,7 @@ const char *set_string_option(const int opt_idx, void *varp_arg, const char *val
origval = oldval;
}
*(char **)varp = xstrdup(value != NULL ? value : empty_option);
*(char **)varp = xstrdup(value != NULL ? value : empty_string_option);
char *const saved_origval = (origval != NULL) ? xstrdup(origval) : NULL;
char *const saved_oldval_l = (origval_l != NULL) ? xstrdup(origval_l) : 0;
@ -494,19 +492,17 @@ const char *set_string_option(const int opt_idx, void *varp_arg, const char *val
char *const saved_newval = xstrdup(*(char **)varp);
const int secure_saved = secure;
const uint32_t *p = insecure_flag(curwin, opt_idx, opt_flags);
// When an option is set in the sandbox, from a modeline or in secure
// mode, then deal with side effects in secure mode. Also when the
// value was set with the P_INSECURE flag and is not completely
// replaced.
if ((opt_flags & OPT_MODELINE)
|| sandbox != 0) {
// When an option is set in the sandbox, from a modeline or in secure mode, then deal with side
// effects in secure mode. Also when the value was set with the P_INSECURE flag and is not
// completely replaced.
if ((opt_flags & OPT_MODELINE) || sandbox != 0 || (!new_value && (*p & P_INSECURE))) {
secure = 1;
}
const char *const errmsg = did_set_string_option(curbuf, curwin, opt_idx, varp, oldval,
errbuf, errbuflen,
opt_flags, OP_NONE, value_checked);
errbuf, errbuflen, opt_flags, value_checked);
secure = secure_saved;
@ -864,7 +860,7 @@ int expand_set_backspace(optexpand_T *args, int *numMatches, char ***matches)
const char *did_set_backupcopy(optset_T *args)
{
buf_T *buf = (buf_T *)args->os_buf;
const char *oldval = args->os_oldval.string;
const char *oldval = args->os_oldval.string.data;
int opt_flags = args->os_flags;
char *bkc = p_bkc;
unsigned *flags = &bkc_flags;
@ -1463,7 +1459,7 @@ const char *did_set_fileformat(optset_T *args)
{
buf_T *buf = (buf_T *)args->os_buf;
char **varp = (char **)args->os_varp;
const char *oldval = args->os_oldval.string;
const char *oldval = args->os_oldval.string.data;
int opt_flags = args->os_flags;
if (!MODIFIABLE(buf) && !(opt_flags & OPT_GLOBAL)) {
return e_modifiable;
@ -1516,7 +1512,7 @@ const char *did_set_filetype_or_syntax(optset_T *args)
return e_invarg;
}
args->os_value_changed = strcmp(args->os_oldval.string, *varp) != 0;
args->os_value_changed = strcmp(args->os_oldval.string.data, *varp) != 0;
// Since we check the value, there is no need to set P_INSECURE,
// even when the value comes from a modeline.
@ -2107,7 +2103,7 @@ const char *did_set_sessionoptions(optset_T *args)
}
if ((ssop_flags & SSOP_CURDIR) && (ssop_flags & SSOP_SESDIR)) {
// Don't allow both "sesdir" and "curdir".
const char *oldval = args->os_oldval.string;
const char *oldval = args->os_oldval.string.data;
(void)opt_strings_flags(oldval, p_ssop_values, &ssop_flags, true);
return e_invarg;
}
@ -2123,20 +2119,11 @@ int expand_set_sessionoptions(optexpand_T *args, int *numMatches, char ***matche
matches);
}
static const char *did_set_shada(vimoption_T **opt, int *opt_idx, bool *free_oldval, char *errbuf,
size_t errbuflen)
const char *did_set_shada(optset_T *args)
{
static int shada_idx = -1;
// TODO(ZyX-I): Remove this code in the future, alongside with &viminfo
// option.
*opt_idx = (((*opt)->fullname[0] == 'v')
? (shada_idx == -1 ? ((shada_idx = findoption("shada"))) : shada_idx)
: *opt_idx);
*opt = get_option(*opt_idx);
// Update free_oldval now that we have the opt_idx for 'shada', otherwise
// there would be a disconnect between the check for P_ALLOCED at the start
// of the function and the set of P_ALLOCED at the end of the function.
*free_oldval = ((*opt)->flags & P_ALLOCED);
char *errbuf = args->os_errbuf;
size_t errbuflen = args->os_errbuflen;
for (char *s = p_shada; *s;) {
// Check it's a valid character
if (vim_strchr("!\"%'/:<@cfhnrs", (uint8_t)(*s)) == NULL) {
@ -2228,7 +2215,7 @@ const char *did_set_signcolumn(optset_T *args)
{
win_T *win = (win_T *)args->os_win;
char **varp = (char **)args->os_varp;
const char *oldval = args->os_oldval.string;
const char *oldval = args->os_oldval.string.data;
if (check_signcolumn(*varp) != OK) {
return e_invarg;
}
@ -2582,7 +2569,7 @@ const char *did_set_virtualedit(optset_T *args)
} else {
if (opt_strings_flags(ve, p_ve_values, flags, true) != OK) {
return e_invarg;
} else if (strcmp(ve, args->os_oldval.string) != 0) {
} else if (strcmp(ve, args->os_oldval.string.data) != 0) {
// Recompute cursor position in case the new 've' setting
// changes something.
validate_virtcol_win(win);
@ -2743,7 +2730,7 @@ static void do_spelllang_source(win_T *win)
///
/// @return NULL for success, or an untranslated error message for an error
const char *did_set_string_option(buf_T *buf, win_T *win, int opt_idx, char **varp, char *oldval,
char *errbuf, size_t errbuflen, int opt_flags, set_op_T op,
char *errbuf, size_t errbuflen, int opt_flags,
bool *value_checked)
{
const char *errmsg = NULL;
@ -2757,9 +2744,8 @@ const char *did_set_string_option(buf_T *buf, win_T *win, int opt_idx, char **va
.os_varp = varp,
.os_idx = opt_idx,
.os_flags = opt_flags,
.os_op = op,
.os_oldval.string = oldval,
.os_newval.string = *varp,
.os_oldval.string = cstr_as_string(oldval),
.os_newval.string = cstr_as_string(*varp),
.os_value_checked = false,
.os_value_changed = false,
.os_restore_chartab = false,
@ -2789,8 +2775,6 @@ const char *did_set_string_option(buf_T *buf, win_T *win, int opt_idx, char **va
// The 'isident', 'iskeyword', 'isprint' and 'isfname' options may
// change the character table. On failure, this needs to be restored.
restore_chartab = args.os_restore_chartab;
} else if (varp == &p_shada) { // 'shada'
errmsg = did_set_shada(&opt, &opt_idx, &free_oldval, errbuf, errbuflen);
}
// If an error is detected, restore the previous value.
@ -2818,7 +2802,7 @@ const char *did_set_string_option(buf_T *buf, win_T *win, int opt_idx, char **va
// the local value and make it empty
char *p = get_varp_scope(opt, OPT_LOCAL);
free_string_option(*(char **)p);
*(char **)p = empty_option;
*(char **)p = empty_string_option;
} else if (!(opt_flags & OPT_LOCAL) && opt_flags != OPT_GLOBAL) {
// May set global value for local option.
set_string_option_global(opt, varp);

View File

@ -2596,7 +2596,7 @@ static int qf_open_new_file_win(qf_info_T *ll_ref)
if (win_split(0, flags) == FAIL) {
return FAIL; // not enough room for window
}
p_swb = empty_option; // don't split again
p_swb = empty_string_option; // don't split again
swb_flags = 0;
RESET_BINDING(curwin);
if (ll_ref != NULL) {
@ -3073,7 +3073,7 @@ theend:
qfl->qf_ptr = qf_ptr;
qfl->qf_index = qf_index;
}
if (p_swb != old_swb && p_swb == empty_option) {
if (p_swb != old_swb && p_swb == empty_string_option) {
// Restore old 'switchbuf' value, but not when an autocommand or
// modeline has changed the value.
p_swb = old_swb;
@ -7201,7 +7201,7 @@ void ex_helpgrep(exarg_T *eap)
// Make 'cpoptions' empty, the 'l' flag should not be used here.
char *const save_cpo = p_cpo;
const bool save_cpo_allocated = is_option_allocated("cpo");
p_cpo = empty_option;
p_cpo = empty_string_option;
bool new_qi = false;
if (is_loclist_cmd(eap->cmdidx)) {
@ -7232,7 +7232,7 @@ void ex_helpgrep(exarg_T *eap)
updated = true;
}
if (p_cpo == empty_option) {
if (p_cpo == empty_string_option) {
p_cpo = save_cpo;
} else {
// Darn, some plugin changed the value. If it's still empty it was

View File

@ -729,7 +729,7 @@ static void syn_sync(win_T *wp, linenr_T start_lnum, synstate_T *last_valid)
static void save_chartab(char *chartab)
{
if (syn_block->b_syn_isk == empty_option) {
if (syn_block->b_syn_isk == empty_string_option) {
return;
}
@ -739,7 +739,7 @@ static void save_chartab(char *chartab)
static void restore_chartab(char *chartab)
{
if (syn_win->w_s->b_syn_isk != empty_option) {
if (syn_win->w_s->b_syn_isk != empty_string_option) {
memmove(syn_buf->b_chartab, chartab, (size_t)32);
}
}
@ -2946,7 +2946,7 @@ static void syn_cmd_iskeyword(exarg_T *eap, int syncing)
arg = skipwhite(arg);
if (*arg == NUL) {
msg_puts("\n");
if (curwin->w_s->b_syn_isk != empty_option) {
if (curwin->w_s->b_syn_isk != empty_string_option) {
msg_puts("syntax iskeyword ");
msg_outtrans(curwin->w_s->b_syn_isk, 0);
} else {
@ -4758,7 +4758,7 @@ static char *get_syn_pattern(char *arg, synpat_T *ci)
// Make 'cpoptions' empty, to avoid the 'l' flag
char *cpo_save = p_cpo;
p_cpo = empty_option;
p_cpo = empty_string_option;
ci->sp_prog = vim_regcomp(ci->sp_pattern, RE_MAGIC);
p_cpo = cpo_save;
@ -4915,7 +4915,7 @@ static void syn_cmd_sync(exarg_T *eap, int syncing)
// Make 'cpoptions' empty, to avoid the 'l' flag
cpo_save = p_cpo;
p_cpo = empty_option;
p_cpo = empty_string_option;
curwin->w_s->b_syn_linecont_prog =
vim_regcomp(curwin->w_s->b_syn_linecont_pat, RE_MAGIC);
p_cpo = cpo_save;
@ -5298,7 +5298,7 @@ void ex_ownsyntax(exarg_T *eap)
hash_init(&curwin->w_s->b_keywtab_ic);
// TODO(vim): Keep the spell checking as it was.
curwin->w_p_spell = false; // No spell checking
// make sure option values are "empty_option" instead of NULL
// make sure option values are "empty_string_option" instead of NULL
clear_string_option(&curwin->w_s->b_p_spc);
clear_string_option(&curwin->w_s->b_p_spf);
clear_string_option(&curwin->w_s->b_p_spl);

View File

@ -42,6 +42,8 @@ typedef enum {
#define TRISTATE_TO_BOOL(val, \
default) ((val) == kTrue ? true : ((val) == kFalse ? false : (default)))
#define TRISTATE_FROM_INT(val) ((val) == 0 ? kFalse : ((val) >= 1 ? kTrue : kNone))
typedef struct Decoration Decoration;
#ifndef ORDER_BIG_ENDIAN

View File

@ -48,10 +48,10 @@ end
local function expected_table(option, oldval, oldval_l, oldval_g, newval, scope, cmd, attr)
return {
option = option,
oldval = tostring(oldval),
oldval_l = tostring(oldval_l),
oldval_g = tostring(oldval_g),
newval = tostring(newval),
oldval = oldval,
oldval_l = oldval_l,
oldval_g = oldval_g,
newval = newval,
scope = scope,
cmd = cmd,
attr = attr,
@ -129,44 +129,44 @@ describe('au OptionSet', function()
it('should be called in setting number option', function()
command('set nu')
expected_combination({'number', 0, 0, 0, 1, 'global', 'set'})
expected_combination({'number', false, false, false, true, 'global', 'set'})
command('setlocal nonu')
expected_combination({'number', 1, 1, '', 0, 'local', 'setlocal'})
expected_combination({'number', true, true, '', false, 'local', 'setlocal'})
command('setglobal nonu')
expected_combination({'number', 1, '', 1, 0, 'global', 'setglobal'})
expected_combination({'number', true, '', true, false, 'global', 'setglobal'})
end)
it('should be called in setting autoindent option',function()
command('setlocal ai')
expected_combination({'autoindent', 0, 0, '', 1, 'local', 'setlocal'})
expected_combination({'autoindent', false, false, '', true, 'local', 'setlocal'})
command('setglobal ai')
expected_combination({'autoindent', 0, '', 0, 1, 'global', 'setglobal'})
expected_combination({'autoindent', false, '', false, true, 'global', 'setglobal'})
command('set noai')
expected_combination({'autoindent', 1, 1, 1, 0, 'global', 'set'})
expected_combination({'autoindent', true, true, true, false, 'global', 'set'})
end)
it('should be called in inverting global autoindent option',function()
command('set ai!')
expected_combination({'autoindent', 0, 0, 0, 1, 'global', 'set'})
expected_combination({'autoindent', false, false, false, true, 'global', 'set'})
end)
it('should be called in being unset local autoindent option',function()
command('setlocal ai')
expected_combination({'autoindent', 0, 0, '', 1, 'local', 'setlocal'})
expected_combination({'autoindent', false, false, '', true, 'local', 'setlocal'})
command('setlocal ai<')
expected_combination({'autoindent', 1, 1, '', 0, 'local', 'setlocal'})
expected_combination({'autoindent', true, true, '', false, 'local', 'setlocal'})
end)
it('should be called in setting global list and number option at the same time',function()
command('set list nu')
expected_combination(
{'list', 0, 0, 0, 1, 'global', 'set'},
{'number', 0, 0, 0, 1, 'global', 'set'}
{'list', false, false, false, true, 'global', 'set'},
{'number', false, false, false, true, 'global', 'set'}
)
end)
@ -177,20 +177,20 @@ describe('au OptionSet', function()
it('should be called in setting local acd', function()
command('setlocal acd')
expected_combination({'autochdir', 0, 0, '', 1, 'local', 'setlocal'})
expected_combination({'autochdir', false, false, '', true, 'local', 'setlocal'})
end)
it('should be called in setting autoread', function()
command('set noar')
expected_combination({'autoread', 1, 1, 1, 0, 'global', 'set'})
expected_combination({'autoread', true, true, true, false, 'global', 'set'})
command('setlocal ar')
expected_combination({'autoread', 0, 0, '', 1, 'local', 'setlocal'})
expected_combination({'autoread', false, false, '', true, 'local', 'setlocal'})
end)
it('should be called in inverting global autoread', function()
command('setglobal invar')
expected_combination({'autoread', 1, '', 1, 0, 'global', 'setglobal'})
expected_combination({'autoread', true, '', true, false, 'global', 'setglobal'})
end)
it('should be called in setting backspace option through :let', function()
@ -208,7 +208,7 @@ describe('au OptionSet', function()
it('should trigger using correct option name', function()
command('call setbufvar(1, "&backup", 1)')
expected_combination({'backup', 0, 0, '', 1, 'local', 'setlocal'})
expected_combination({'backup', false, false, '', true, 'local', 'setlocal'})
end)
it('should trigger if the current buffer is different from the targeted buffer', function()
@ -441,105 +441,105 @@ describe('au OptionSet', function()
command('noa setglobal foldcolumn=8')
command('noa setlocal foldcolumn=1')
command('setglobal foldcolumn=2')
expected_combination({'foldcolumn', 8, '', 8, 2, 'global', 'setglobal'})
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'})
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'})
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'})
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'})
expected_combination({'wrapscan', true, '', true, false, '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'})
expected_combination({'wrapscan', true, true, '', false, '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'})
expected_combination({'wrapscan', true, true, true, false, 'global', 'set'})
command('noa set nowrapscan')
command('set wrapscan')
expected_combination({'wrapscan', 0, 0, 0, 1, 'global', 'set'})
expected_combination({'wrapscan', false, false, false, true, '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'})
expected_combination({'autoread', false, '', false, true, 'global', 'setglobal'})
command('noa setglobal noautoread')
command('noa setlocal autoread')
command('setlocal noautoread')
expected_combination({'autoread', 1, 1, '', 0, 'local', 'setlocal'})
expected_combination({'autoread', true, true, '', false, 'local', 'setlocal'})
command('noa setglobal noautoread')
command('noa setlocal autoread')
command('set autoread')
expected_combination({'autoread', 1, 1, 0, 1, 'global', 'set'})
expected_combination({'autoread', true, true, false, true, 'global', 'set'})
command('noa set noautoread')
command('set autoread')
expected_combination({'autoread', 0, 0, 0, 1, 'global', 'set'})
expected_combination({'autoread', false, false, false, true, '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'})
expected_combination({'cindent', false, '', false, true, 'global', 'setglobal'})
command('noa setglobal nocindent')
command('noa setlocal cindent')
command('setlocal nocindent')
expected_combination({'cindent', 1, 1, '', 0, 'local', 'setlocal'})
expected_combination({'cindent', true, true, '', false, 'local', 'setlocal'})
command('noa setglobal nocindent')
command('noa setlocal cindent')
command('set cindent')
expected_combination({'cindent', 1, 1, 0, 1, 'global', 'set'})
expected_combination({'cindent', true, true, false, true, 'global', 'set'})
command('noa set nocindent')
command('set cindent')
expected_combination({'cindent', 0, 0, 0, 1, 'global', 'set'})
expected_combination({'cindent', false, false, false, true, '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'})
expected_combination({'cursorcolumn', false, '', false, true, 'global', 'setglobal'})
command('noa setglobal nocursorcolumn')
command('noa setlocal cursorcolumn')
command('setlocal nocursorcolumn')
expected_combination({'cursorcolumn', 1, 1, '', 0, 'local', 'setlocal'})
expected_combination({'cursorcolumn', true, true, '', false, 'local', 'setlocal'})
command('noa setglobal nocursorcolumn')
command('noa setlocal cursorcolumn')
command('set cursorcolumn')
expected_combination({'cursorcolumn', 1, 1, 0, 1, 'global', 'set'})
expected_combination({'cursorcolumn', true, true, false, true, 'global', 'set'})
command('noa set nocursorcolumn')
command('set cursorcolumn')
expected_combination({'cursorcolumn', 0, 0, 0, 1, 'global', 'set'})
expected_combination({'cursorcolumn', false, false, false, true, 'global', 'set'})
end)
end)
@ -559,13 +559,13 @@ describe('au OptionSet', function()
expected_empty()
command('setlocal ro')
expected_combination({'readonly', 0, 0, '', 1, 'local', 'setlocal'})
expected_combination({'readonly', false, false, '', true, 'local', 'setlocal'})
command('setglobal ro')
expected_combination({'readonly', 0, '', 0, 1, 'global', 'setglobal'})
expected_combination({'readonly', false, '', false, true, 'global', 'setglobal'})
command('set noro')
expected_combination({'readonly', 1, 1, 1, 0, 'global', 'set'})
expected_combination({'readonly', true, true, true, false, 'global', 'set'})
end)
describe('being set by setbufvar()', function()
@ -580,7 +580,7 @@ describe('au OptionSet', function()
set_hook('backup')
command('call setbufvar(1, "&backup", 1)')
expected_combination({'backup', 0, 0, '', 1, 'local', 'setlocal'})
expected_combination({'backup', false, false, '', true, 'local', 'setlocal'})
end)
it('should trigger if the current buffer is different from the targeted buffer', function()
@ -590,7 +590,8 @@ describe('au OptionSet', function()
local new_bufnr = buf.get_number(new_buffer)
command('call setbufvar(' .. new_bufnr .. ', "&buftype", "nofile")')
expected_combination({'buftype', '', '', '', 'nofile', 'local', 'setlocal', {bufnr = new_bufnr}})
expected_combination({ 'buftype', '', '', '', 'nofile', 'local', 'setlocal',
{ bufnr = new_bufnr } })
end)
end)
@ -606,7 +607,7 @@ describe('au OptionSet', function()
set_hook('backup')
command('call setwinvar(1, "&backup", 1)')
expected_combination({'backup', 0, 0, '', 1, 'local', 'setlocal'})
expected_combination({'backup', false, false, '', true, 'local', 'setlocal'})
end)
it('should not trigger if the current window is different from the targeted window', function()
@ -615,7 +616,7 @@ describe('au OptionSet', function()
local new_winnr = get_new_window_number()
command('call setwinvar(' .. new_winnr .. ', "&cursorcolumn", 1)')
-- expected_combination({'cursorcolumn', 0, 1, 'local', {winnr = new_winnr}})
-- expected_combination({'cursorcolumn', false, true, 'local', {winnr = new_winnr}})
expected_empty()
end)
end)
@ -626,7 +627,7 @@ describe('au OptionSet', function()
nvim.set_option_value('autochdir', true, {scope='global'})
eq(true, nvim.get_option_value('autochdir', {scope='global'}))
expected_combination({'autochdir', 0, '', 0, 1, 'global', 'setglobal'})
expected_combination({'autochdir', false, '', false, true, 'global', 'setglobal'})
end)
it('should trigger if a number option be set globally', function()