aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/eval/vars.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nvim/eval/vars.c')
-rw-r--r--src/nvim/eval/vars.c131
1 files changed, 75 insertions, 56 deletions
diff --git a/src/nvim/eval/vars.c b/src/nvim/eval/vars.c
index 2968f75f4d..91ac60d8ea 100644
--- a/src/nvim/eval/vars.c
+++ b/src/nvim/eval/vars.c
@@ -7,10 +7,11 @@
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
-#include <sys/types.h>
+#include <uv.h>
#include "nvim/ascii_defs.h"
#include "nvim/autocmd.h"
+#include "nvim/autocmd_defs.h"
#include "nvim/buffer_defs.h"
#include "nvim/charset.h"
#include "nvim/drawscreen.h"
@@ -18,16 +19,17 @@
#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"
+#include "nvim/eval_defs.h"
#include "nvim/ex_cmds.h"
#include "nvim/ex_cmds_defs.h"
#include "nvim/ex_docmd.h"
#include "nvim/ex_eval.h"
-#include "nvim/func_attr.h"
#include "nvim/garray.h"
-#include "nvim/gettext.h"
+#include "nvim/gettext_defs.h"
#include "nvim/globals.h"
#include "nvim/hashtab.h"
#include "nvim/macros_defs.h"
@@ -44,6 +46,8 @@
#include "nvim/vim_defs.h"
#include "nvim/window.h"
+typedef int (*ex_unletlock_callback)(lval_T *, char *, exarg_T *, int);
+
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "eval/vars.c.generated.h"
#endif
@@ -377,7 +381,7 @@ void ex_let(exarg_T *eap)
if (!eap->skip) {
op[0] = '=';
op[1] = NUL;
- (void)ex_let_vars(eap->arg, &rettv, false, semicolon, var_count, is_const, op);
+ ex_let_vars(eap->arg, &rettv, false, semicolon, var_count, is_const, op);
}
tv_clear(&rettv);
}
@@ -414,7 +418,7 @@ void ex_let(exarg_T *eap)
clear_evalarg(&evalarg, eap);
if (!eap->skip && eval_res != FAIL) {
- (void)ex_let_vars(eap->arg, &rettv, false, semicolon, var_count, is_const, op);
+ ex_let_vars(eap->arg, &rettv, false, semicolon, var_count, is_const, op);
}
if (eval_res != FAIL) {
tv_clear(&rettv);
@@ -553,7 +557,7 @@ const char *skip_var_list(const char *arg, int *var_count, int *semicolon)
static const char *skip_var_one(const char *arg)
{
if (*arg == '@' && arg[1] != NUL) {
- return arg + 2;
+ return arg + 1 + utfc_ptr2len(arg + 1);
}
return find_name_end(*arg == '$' || *arg == '&' ? arg + 1 : arg,
NULL, NULL, FNE_INCL_BR | FNE_CHECK_START);
@@ -617,7 +621,7 @@ static void list_tab_vars(int *first)
/// List variables in "arg".
static const char *list_arg_vars(exarg_T *eap, const char *arg, int *first)
{
- int error = false;
+ bool error = false;
int len;
const char *name;
const char *name_start;
@@ -762,11 +766,12 @@ static char *ex_let_option(char *arg, typval_T *const tv, const bool is_const,
// Find the end of the name.
char *arg_end = NULL;
+ OptIndex opt_idx;
int scope;
- char *const p = (char *)find_option_end((const char **)&arg, &scope);
- if (p == NULL
- || (endchars != NULL
- && vim_strchr(endchars, (uint8_t)(*skipwhite(p))) == NULL)) {
+
+ char *const p = (char *)find_option_var_end((const char **)&arg, &opt_idx, &scope);
+
+ if (p == NULL || (endchars != NULL && vim_strchr(endchars, (uint8_t)(*skipwhite(p))) == NULL)) {
emsg(_(e_letunexp));
return NULL;
}
@@ -774,11 +779,12 @@ static char *ex_let_option(char *arg, typval_T *const tv, const bool is_const,
const char c1 = *p;
*p = NUL;
- uint32_t opt_p_flags;
- bool hidden;
- OptVal curval = get_option_value(arg, &opt_p_flags, scope, &hidden);
+ bool is_tty_opt = is_tty_option(arg);
+ bool hidden = is_option_hidden(opt_idx);
+ OptVal curval = is_tty_opt ? get_tty_option(arg) : get_option_value(opt_idx, scope);
OptVal newval = NIL_OPTVAL;
- if (curval.type == kOptValTypeNil && arg[0] != 't' && arg[1] != '_') {
+
+ if (curval.type == kOptValTypeNil) {
semsg(_(e_unknown_option2), arg);
goto theend;
}
@@ -790,7 +796,7 @@ static char *ex_let_option(char *arg, typval_T *const tv, const bool is_const,
}
bool error;
- newval = tv_to_optval(tv, arg, opt_p_flags, &error);
+ newval = tv_to_optval(tv, opt_idx, arg, &error);
if (error) {
goto theend;
}
@@ -832,7 +838,7 @@ static char *ex_let_option(char *arg, typval_T *const tv, const bool is_const,
}
}
- const char *err = set_option_value(arg, newval, scope);
+ const char *err = set_option_value_handle_tty(arg, opt_idx, newval, scope);
arg_end = p;
if (err != NULL) {
emsg(_(err));
@@ -857,16 +863,20 @@ static char *ex_let_register(char *arg, typval_T *const tv, const bool is_const,
char *arg_end = NULL;
arg++;
+
+ int regname = utf_ptr2char(arg);
+ int mblen = utf_ptr2len(arg);
+
if (op != NULL && vim_strchr("+-*/%", (uint8_t)(*op)) != NULL) {
semsg(_(e_letwrong), op);
} else if (endchars != NULL
- && vim_strchr(endchars, (uint8_t)(*skipwhite(arg + 1))) == NULL) {
+ && vim_strchr(endchars, (uint8_t)(*skipwhite(arg + mblen))) == NULL) {
emsg(_(e_letunexp));
} else {
char *ptofree = NULL;
const char *p = tv_get_string_chk(tv);
if (p != NULL && op != NULL && *op == '.') {
- char *s = get_reg_contents(*arg == '@' ? '"' : *arg, kGRegExprSrc);
+ char *s = get_reg_contents(*arg == '@' ? '"' : regname, kGRegExprSrc);
if (s != NULL) {
ptofree = concat_str(s, p);
p = ptofree;
@@ -874,8 +884,9 @@ static char *ex_let_register(char *arg, typval_T *const tv, const bool is_const,
}
}
if (p != NULL) {
- write_reg_contents(*arg == '@' ? '"' : *arg, p, (ssize_t)strlen(p), false);
- arg_end = arg + 1;
+ write_reg_contents(*arg == '@' ? '"' : regname,
+ p, (ssize_t)strlen(p), false);
+ arg_end = arg + mblen;
}
xfree(ptofree);
}
@@ -1300,7 +1311,7 @@ void vars_clear(hashtab_T *ht)
}
/// Like vars_clear(), but only free the value if "free_val" is true.
-void vars_clear_ext(hashtab_T *ht, int free_val)
+void vars_clear_ext(hashtab_T *ht, bool free_val)
{
int todo;
hashitem_T *hi;
@@ -1847,22 +1858,27 @@ static void getwinvar(typval_T *argvars, typval_T *rettv, int off)
///
/// @return Typval converted to OptVal. Must be freed by caller.
/// Returns NIL_OPTVAL for invalid option name.
-static OptVal tv_to_optval(typval_T *tv, const char *option, uint32_t flags, bool *error)
+///
+/// TODO(famiu): Refactor this to support multitype options.
+static OptVal tv_to_optval(typval_T *tv, OptIndex opt_idx, const char *option, bool *error)
{
OptVal value = NIL_OPTVAL;
char nbuf[NUMBUFLEN];
bool err = false;
+ const bool is_tty_opt = is_tty_option(option);
+ const bool option_has_bool = !is_tty_opt && option_has_type(opt_idx, kOptValTypeBoolean);
+ const bool option_has_num = !is_tty_opt && option_has_type(opt_idx, kOptValTypeNumber);
+ const bool option_has_str = is_tty_opt || option_has_type(opt_idx, kOptValTypeString);
- if ((flags & P_FUNC) && tv_is_func(*tv)) {
+ if (!is_tty_opt && (get_option(opt_idx)->flags & P_FUNC) && tv_is_func(*tv)) {
// If the option can be set to a function reference or a lambda
// and the passed value is a function reference, then convert it to
// the name (string) of the function reference.
char *strval = encode_tv2string(tv, NULL);
err = strval == NULL;
value = CSTR_AS_OPTVAL(strval);
- } else if (flags & (P_NUM | P_BOOL)) {
- varnumber_T n = (flags & P_NUM) ? tv_get_number_chk(tv, &err)
- : tv_get_bool_chk(tv, &err);
+ } else if (option_has_bool || option_has_num) {
+ varnumber_T n = option_has_num ? tv_get_number_chk(tv, &err) : tv_get_bool_chk(tv, &err);
// This could be either "0" or a string that's not a number.
// So we need to check if it's actually a number.
if (!err && tv->v_type == VAR_STRING && n == 0) {
@@ -1875,14 +1891,14 @@ 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(TRISTATE_FROM_INT(n));
- } else if ((flags & P_STRING) || is_tty_option(option)) {
+ value = option_has_num ? NUMBER_OPTVAL((OptInt)n) : BOOLEAN_OPTVAL(TRISTATE_FROM_INT(n));
+ } else if (option_has_str) {
// Avoid setting string option to a boolean or a special value.
if (tv->v_type != VAR_BOOL && tv->v_type != VAR_SPECIAL) {
const char *strval = tv_get_string_buf_chk(tv, nbuf);
err = strval == NULL;
value = CSTR_TO_OPTVAL(strval);
- } else if (flags & P_STRING) {
+ } else if (!is_tty_opt) {
err = true;
emsg(_(e_stringreq));
}
@@ -1898,10 +1914,12 @@ static OptVal tv_to_optval(typval_T *tv, const char *option, uint32_t flags, boo
/// Convert an option value to typval.
///
-/// @param[in] value Option value to convert.
+/// @param[in] value Option value to convert.
+/// @param numbool Whether to convert boolean values to number.
+/// Used for backwards compatibility.
///
/// @return OptVal converted to typval.
-typval_T optval_as_tv(OptVal value)
+typval_T optval_as_tv(OptVal value, bool numbool)
{
typval_T rettv = { .v_type = VAR_SPECIAL, .vval = { .v_special = kSpecialVarNull } };
@@ -1909,19 +1927,16 @@ typval_T optval_as_tv(OptVal value)
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
+ if (value.data.boolean != kNone) {
+ if (numbool) {
+ rettv.v_type = VAR_NUMBER;
+ rettv.vval.v_number = value.data.boolean == kTrue;
+ } else {
+ rettv.v_type = VAR_BOOL;
+ rettv.vval.v_bool = value.data.boolean == kTrue;
+ }
}
- break;
+ break; // return v:null for None boolean value.
case kOptValTypeNumber:
rettv.v_type = VAR_NUMBER;
rettv.vval.v_number = value.data.number;
@@ -1938,25 +1953,27 @@ typval_T optval_as_tv(OptVal value)
/// 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)
{
- int opt_idx = findoption(varname);
- if (opt_idx < 0) {
+ OptIndex opt_idx = find_option(varname);
+ if (opt_idx == kOptInvalid) {
semsg(_(e_unknown_option2), varname);
return;
}
- uint32_t opt_p_flags = get_option(opt_idx)->flags;
bool error = false;
- OptVal value = tv_to_optval(varp, varname, opt_p_flags, &error);
+ OptVal value = tv_to_optval(varp, opt_idx, varname, &error);
if (!error) {
- set_option_value_give_err(varname, value, OPT_LOCAL);
- }
+ const char *errmsg = set_option_value_handle_tty(varname, opt_idx, value, OPT_LOCAL);
+ if (errmsg) {
+ emsg(errmsg);
+ }
+ }
optval_free(value);
}
/// "setwinvar()" and "settabwinvar()" functions
-static void setwinvar(typval_T *argvars, typval_T *rettv, int off)
+static void setwinvar(typval_T *argvars, int off)
{
if (check_secure()) {
return;
@@ -2065,8 +2082,6 @@ void f_getbufvar(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
/// "settabvar()" function
void f_settabvar(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
- rettv->vval.v_number = 0;
-
if (check_secure()) {
return;
}
@@ -2080,6 +2095,7 @@ void f_settabvar(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
}
tabpage_T *const save_curtab = curtab;
+ tabpage_T *const save_lu_tp = lastused_tabpage;
goto_tabpage_tp(tp, false, false);
const size_t varname_len = strlen(varname);
@@ -2089,22 +2105,25 @@ void f_settabvar(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
set_var(tabvarname, varname_len + 2, varp, true);
xfree(tabvarname);
- // Restore current tabpage.
+ // Restore current tabpage and last accessed tabpage.
if (valid_tabpage(save_curtab)) {
goto_tabpage_tp(save_curtab, false, false);
+ if (valid_tabpage(save_lu_tp)) {
+ lastused_tabpage = save_lu_tp;
+ }
}
}
/// "settabwinvar()" function
void f_settabwinvar(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
- setwinvar(argvars, rettv, 1);
+ setwinvar(argvars, 1);
}
/// "setwinvar()" function
void f_setwinvar(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
- setwinvar(argvars, rettv, 0);
+ setwinvar(argvars, 0);
}
/// "setbufvar()" function