Skip to content

Commit

Permalink
Merge pull request #25394 from famiu/refactor/options/set_option
Browse files Browse the repository at this point in the history
refactor(options)!: unify interfaces for setting options
  • Loading branch information
bfredl committed Oct 16, 2023
2 parents b80a8e2 + 3642f2f commit a63c670
Show file tree
Hide file tree
Showing 20 changed files with 665 additions and 722 deletions.
4 changes: 4 additions & 0 deletions runtime/doc/news.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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*

Expand Down
3 changes: 3 additions & 0 deletions runtime/doc/vim_diff.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
41 changes: 0 additions & 41 deletions src/nvim/api/options.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion src/nvim/arglist.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down
17 changes: 14 additions & 3 deletions src/nvim/eval.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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)
{
Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -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.
Expand Down
12 changes: 6 additions & 6 deletions src/nvim/eval/funcs.c
Original file line number Diff line number Diff line change
Expand Up @@ -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));
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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;
Expand Down
45 changes: 42 additions & 3 deletions src/nvim/eval/vars.c
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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) {
Expand All @@ -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)
{
Expand Down
1 change: 1 addition & 0 deletions src/nvim/eval/vars.h
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
2 changes: 1 addition & 1 deletion src/nvim/ex_eval.c
Original file line number Diff line number Diff line change
Expand Up @@ -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++;
Expand Down
9 changes: 5 additions & 4 deletions src/nvim/globals.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions src/nvim/normal.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
4 changes: 2 additions & 2 deletions src/nvim/ops.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down

0 comments on commit a63c670

Please sign in to comment.