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