diff options
Diffstat (limited to 'src/nvim/eval/vars.c')
-rw-r--r-- | src/nvim/eval/vars.c | 131 |
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 |