aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/eval.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nvim/eval.c')
-rw-r--r--src/nvim/eval.c158
1 files changed, 127 insertions, 31 deletions
diff --git a/src/nvim/eval.c b/src/nvim/eval.c
index 5f8f3f96f7..0a83c3a586 100644
--- a/src/nvim/eval.c
+++ b/src/nvim/eval.c
@@ -213,8 +213,8 @@ static struct vimvar {
VV(VV_ERRORS, "errors", VAR_LIST, 0),
VV(VV_MSGPACK_TYPES, "msgpack_types", VAR_DICT, VV_RO),
VV(VV_EVENT, "event", VAR_DICT, VV_RO),
- VV(VV_FALSE, "false", VAR_SPECIAL, VV_RO),
- VV(VV_TRUE, "true", VAR_SPECIAL, VV_RO),
+ VV(VV_FALSE, "false", VAR_BOOL, VV_RO),
+ VV(VV_TRUE, "true", VAR_BOOL, VV_RO),
VV(VV_NULL, "null", VAR_SPECIAL, VV_RO),
VV(VV__NULL_LIST, "_null_list", VAR_LIST, VV_RO),
VV(VV__NULL_DICT, "_null_dict", VAR_DICT, VV_RO),
@@ -237,6 +237,7 @@ static struct vimvar {
// shorthand
#define vv_type vv_di.di_tv.v_type
#define vv_nr vv_di.di_tv.vval.v_number
+#define vv_bool vv_di.di_tv.vval.v_bool
#define vv_special vv_di.di_tv.vval.v_special
#define vv_float vv_di.di_tv.vval.v_float
#define vv_str vv_di.di_tv.vval.v_string
@@ -388,8 +389,8 @@ void eval_init(void)
set_vim_var_nr(VV_TYPE_FLOAT, VAR_TYPE_FLOAT);
set_vim_var_nr(VV_TYPE_BOOL, VAR_TYPE_BOOL);
- set_vim_var_special(VV_FALSE, kSpecialVarFalse);
- set_vim_var_special(VV_TRUE, kSpecialVarTrue);
+ set_vim_var_bool(VV_FALSE, kBoolVarFalse);
+ set_vim_var_bool(VV_TRUE, kBoolVarTrue);
set_vim_var_special(VV_NULL, kSpecialVarNull);
set_vim_var_special(VV_EXITING, kSpecialVarNull);
@@ -1837,12 +1838,15 @@ static char_u *ex_let_one(char_u *arg, typval_T *const tv,
int opt_type;
long numval;
char *stringval = NULL;
+ const char *s = NULL;
const char c1 = *p;
*p = NUL;
varnumber_T n = tv_get_number(tv);
- const char *s = tv_get_string_chk(tv); // != NULL if number or string.
+ if (tv->v_type != VAR_BOOL && tv->v_type != VAR_SPECIAL) {
+ s = tv_get_string_chk(tv); // != NULL if number or string.
+ }
if (s != NULL && op != NULL && *op != '=') {
opt_type = get_option_value(arg, &numval, (char_u **)&stringval,
opt_flags);
@@ -1868,7 +1872,8 @@ static char_u *ex_let_one(char_u *arg, typval_T *const tv,
}
}
}
- if (s != NULL) {
+ if (s != NULL || tv->v_type == VAR_BOOL
+ || tv->v_type == VAR_SPECIAL) {
set_option_value((const char *)arg, n, s, opt_flags);
arg_end = (char_u *)p;
}
@@ -2813,7 +2818,7 @@ static int do_unlet_var(lval_T *const lp, char_u *const name_end, int forceit)
/// @param[in] fonceit If true, do not complain if variable doesn’t exist.
///
/// @return OK if it existed, FAIL otherwise.
-int do_unlet(const char *const name, const size_t name_len, const int forceit)
+int do_unlet(const char *const name, const size_t name_len, const bool forceit)
FUNC_ATTR_NONNULL_ALL
{
const char *varname;
@@ -4199,6 +4204,7 @@ eval_index(
}
return FAIL;
}
+ case VAR_BOOL:
case VAR_SPECIAL: {
if (verbose) {
EMSG(_("E909: Cannot index a special variable"));
@@ -4420,6 +4426,7 @@ eval_index(
*rettv = var1;
break;
}
+ case VAR_BOOL:
case VAR_SPECIAL:
case VAR_FUNC:
case VAR_FLOAT:
@@ -5273,6 +5280,7 @@ bool set_ref_in_item(typval_T *tv, int copyID, ht_stack_T **ht_stack,
abort = set_ref_in_func(tv->vval.v_string, NULL, copyID);
break;
case VAR_UNKNOWN:
+ case VAR_BOOL:
case VAR_SPECIAL:
case VAR_FLOAT:
case VAR_NUMBER:
@@ -5544,19 +5552,18 @@ void prepare_assert_error(garray_T *gap)
}
}
-// Append "str" to "gap", escaping unprintable characters.
+// Append "p[clen]" to "gap", escaping unprintable characters.
// Changes NL to \n, CR to \r, etc.
-static void ga_concat_esc(garray_T *gap, char_u *str)
+static void ga_concat_esc(garray_T *gap, const char_u *p, int clen)
+ FUNC_ATTR_NONNULL_ALL
{
- char_u *p;
char_u buf[NUMBUFLEN];
- if (str == NULL) {
- ga_concat(gap, (char_u *)"NULL");
- return;
- }
-
- for (p = str; *p != NUL; p++) {
+ if (clen > 1) {
+ memmove(buf, p, clen);
+ buf[clen] = NUL;
+ ga_concat(gap, buf);
+ } else {
switch (*p) {
case BS: ga_concat(gap, (char_u *)"\\b"); break;
case ESC: ga_concat(gap, (char_u *)"\\e"); break;
@@ -5577,6 +5584,41 @@ static void ga_concat_esc(garray_T *gap, char_u *str)
}
}
+// Append "str" to "gap", escaping unprintable characters.
+// Changes NL to \n, CR to \r, etc.
+static void ga_concat_shorten_esc(garray_T *gap, const char_u *str)
+ FUNC_ATTR_NONNULL_ARG(1)
+{
+ char_u buf[NUMBUFLEN];
+
+ if (str == NULL) {
+ ga_concat(gap, (char_u *)"NULL");
+ return;
+ }
+
+ for (const char_u *p = str; *p != NUL; p++) {
+ int same_len = 1;
+ const char_u *s = p;
+ const int c = mb_ptr2char_adv(&s);
+ const int clen = s - p;
+ while (*s != NUL && c == utf_ptr2char(s)) {
+ same_len++;
+ s += clen;
+ }
+ if (same_len > 20) {
+ ga_concat(gap, (char_u *)"\\[");
+ ga_concat_esc(gap, p, clen);
+ ga_concat(gap, (char_u *)" occurs ");
+ vim_snprintf((char *)buf, NUMBUFLEN, "%d", same_len);
+ ga_concat(gap, buf);
+ ga_concat(gap, (char_u *)" times]");
+ p = s - 1;
+ } else {
+ ga_concat_esc(gap, p, clen);
+ }
+ }
+}
+
// Fill "gap" with information about an assert error.
void fill_assert_error(garray_T *gap, typval_T *opt_msg_tv,
char_u *exp_str, typval_T *exp_tv,
@@ -5601,10 +5643,10 @@ void fill_assert_error(garray_T *gap, typval_T *opt_msg_tv,
if (exp_str == NULL) {
tofree = (char_u *)encode_tv2string(exp_tv, NULL);
- ga_concat_esc(gap, tofree);
+ ga_concat_shorten_esc(gap, tofree);
xfree(tofree);
} else {
- ga_concat_esc(gap, exp_str);
+ ga_concat_shorten_esc(gap, exp_str);
}
if (atype != ASSERT_NOTEQUAL) {
@@ -5616,7 +5658,7 @@ void fill_assert_error(garray_T *gap, typval_T *opt_msg_tv,
ga_concat(gap, (char_u *)" but got ");
}
tofree = (char_u *)encode_tv2string(got_tv, NULL);
- ga_concat_esc(gap, tofree);
+ ga_concat_shorten_esc(gap, tofree);
xfree(tofree);
}
}
@@ -5666,6 +5708,9 @@ int assert_equalfile(typval_T *argvars)
IObuff[0] = NUL;
FILE *const fd1 = os_fopen(fname1, READBIN);
+ char line1[200];
+ char line2[200];
+ ptrdiff_t lineidx = 0;
if (fd1 == NULL) {
snprintf((char *)IObuff, IOSIZE, (char *)e_notread, fname1);
} else {
@@ -5674,6 +5719,7 @@ int assert_equalfile(typval_T *argvars)
fclose(fd1);
snprintf((char *)IObuff, IOSIZE, (char *)e_notread, fname2);
} else {
+ int64_t linecount = 1;
for (int64_t count = 0; ; count++) {
const int c1 = fgetc(fd1);
const int c2 = fgetc(fd2);
@@ -5685,10 +5731,24 @@ int assert_equalfile(typval_T *argvars)
} else if (c2 == EOF) {
STRCPY(IObuff, "second file is shorter");
break;
- } else if (c1 != c2) {
- snprintf((char *)IObuff, IOSIZE,
- "difference at byte %" PRId64, count);
- break;
+ } else {
+ line1[lineidx] = c1;
+ line2[lineidx] = c2;
+ lineidx++;
+ if (c1 != c2) {
+ snprintf((char *)IObuff, IOSIZE,
+ "difference at byte %" PRId64 ", line %" PRId64,
+ count, linecount);
+ break;
+ }
+ }
+ if (c1 == NL) {
+ linecount++;
+ lineidx = 0;
+ } else if (lineidx + 2 == (ptrdiff_t)sizeof(line1)) {
+ memmove(line1, line1 + 100, lineidx - 100);
+ memmove(line2, line2 + 100, lineidx - 100);
+ lineidx -= 100;
}
}
fclose(fd1);
@@ -5697,7 +5757,24 @@ int assert_equalfile(typval_T *argvars)
}
if (IObuff[0] != NUL) {
prepare_assert_error(&ga);
+ if (argvars[2].v_type != VAR_UNKNOWN) {
+ char *const tofree = encode_tv2echo(&argvars[2], NULL);
+ ga_concat(&ga, (char_u *)tofree);
+ xfree(tofree);
+ ga_concat(&ga, (char_u *)": ");
+ }
ga_concat(&ga, IObuff);
+ if (lineidx > 0) {
+ line1[lineidx] = NUL;
+ line2[lineidx] = NUL;
+ ga_concat(&ga, (char_u *)" after \"");
+ ga_concat(&ga, (char_u *)line1);
+ if (STRCMP(line1, line2) != 0) {
+ ga_concat(&ga, (char_u *)"\" vs \"");
+ ga_concat(&ga, (char_u *)line2);
+ }
+ ga_concat(&ga, (char_u *)"\"");
+ }
assert_error(&ga);
ga_clear(&ga);
return 1;
@@ -5743,11 +5820,11 @@ int assert_bool(typval_T *argvars, bool is_true)
if ((argvars[0].v_type != VAR_NUMBER
|| (tv_get_number_chk(&argvars[0], &error) == 0) == is_true
|| error)
- && (argvars[0].v_type != VAR_SPECIAL
- || (argvars[0].vval.v_special
- != (SpecialVarValue) (is_true
- ? kSpecialVarTrue
- : kSpecialVarFalse)))) {
+ && (argvars[0].v_type != VAR_BOOL
+ || (argvars[0].vval.v_bool
+ != (BoolVarValue)(is_true
+ ? kBoolVarTrue
+ : kBoolVarFalse)))) {
prepare_assert_error(&ga);
fill_assert_error(&ga, &argvars[1],
(char_u *)(is_true ? "True" : "False"),
@@ -7135,6 +7212,16 @@ bool callback_from_typval(Callback *const callback, typval_T *const arg)
func_ref(name);
callback->data.funcref = vim_strsave(name);
callback->type = kCallbackFuncref;
+ } else if (nlua_is_table_from_lua(arg)) {
+ char_u *name = nlua_register_table_as_callable(arg);
+
+ if (name != NULL) {
+ func_ref(name);
+ callback->data.funcref = vim_strsave(name);
+ callback->type = kCallbackFuncref;
+ } else {
+ r = FAIL;
+ }
} else if (arg->v_type == VAR_NUMBER && arg->vval.v_number == 0) {
callback->type = kCallbackNone;
} else {
@@ -8049,6 +8136,17 @@ void set_vim_var_nr(const VimVarIndex idx, const varnumber_T val)
vimvars[idx].vv_nr = val;
}
+/// Set boolean v: {true, false} to the given value
+///
+/// @param[in] idx Index of variable to set.
+/// @param[in] val Value to set to.
+void set_vim_var_bool(const VimVarIndex idx, const BoolVarValue val)
+{
+ tv_clear(&vimvars[idx].vv_tv);
+ vimvars[idx].vv_type = VAR_BOOL;
+ vimvars[idx].vv_bool = val;
+}
+
/// Set special v: variable to the given value
///
/// @param[in] idx Index of variable to set.
@@ -8118,9 +8216,6 @@ void set_argv_var(char **argv, int argc)
list_T *l = tv_list_alloc(argc);
int i;
- if (l == NULL) {
- getout(1);
- }
tv_list_set_lock(l, VAR_FIXED);
for (i = 0; i < argc; i++) {
tv_list_append_string(l, (const char *const)argv[i], -1);
@@ -9143,6 +9238,7 @@ int var_item_copy(const vimconv_T *const conv,
case VAR_FLOAT:
case VAR_FUNC:
case VAR_PARTIAL:
+ case VAR_BOOL:
case VAR_SPECIAL:
tv_copy(from, to);
break;