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.c261
1 files changed, 156 insertions, 105 deletions
diff --git a/src/nvim/eval.c b/src/nvim/eval.c
index 7edf511c18..d8f1ce8494 100644
--- a/src/nvim/eval.c
+++ b/src/nvim/eval.c
@@ -77,7 +77,7 @@
#include "nvim/eval/decode.h"
#include "nvim/os/os.h"
#include "nvim/event/libuv_process.h"
-#include "nvim/event/pty_process.h"
+#include "nvim/os/pty_process.h"
#include "nvim/event/rstream.h"
#include "nvim/event/wstream.h"
#include "nvim/event/time.h"
@@ -508,6 +508,7 @@ void eval_init(void)
/* add to compat scope dict */
hash_add(&compat_hashtab, p->vv_di.di_key);
}
+ vimvars[VV_VERSION].vv_nr = VIM_VERSION_100;
dict_T *const msgpack_types_dict = dict_alloc();
for (size_t i = 0; i < ARRAY_SIZE(msgpack_type_names); i++) {
@@ -2978,11 +2979,16 @@ int do_unlet(char_u *name, int forceit)
} else if (current_funccal != NULL
&& ht == &current_funccal->l_vars.dv_hashtab) {
d = &current_funccal->l_vars;
+ } else if (ht == &compat_hashtab) {
+ d = &vimvardict;
} else {
di = find_var_in_ht(ht, *name, (char_u *)"", false);
d = di->di_tv.vval.v_dict;
}
-
+ if (d == NULL) {
+ EMSG2(_(e_intern2), "do_unlet()");
+ return FAIL;
+ }
hi = hash_find(ht, varname);
if (!HASHITEM_EMPTY(hi)) {
di = HI2DI(hi);
@@ -2991,6 +2997,11 @@ int do_unlet(char_u *name, int forceit)
|| tv_check_lock(d->dv_lock, name, false)) {
return FAIL;
}
+
+ if (d == NULL || tv_check_lock(d->dv_lock, name, false)) {
+ return FAIL;
+ }
+
typval_T oldtv;
bool watched = is_watched(dict);
@@ -9888,7 +9899,7 @@ static void f_getcmdwintype(typval_T *argvars, typval_T *rettv)
static void f_getcwd(typval_T *argvars, typval_T *rettv)
{
// Possible scope of working directory to return.
- CdScope scope = MIN_CD_SCOPE;
+ CdScope scope = kCdScopeInvalid;
// Numbers of the scope objects (window, tab) we want the working directory
// of. A `-1` means to skip this scope, a `0` means the current object.
@@ -9917,26 +9928,27 @@ static void f_getcwd(typval_T *argvars, typval_T *rettv)
return;
}
scope_number[i] = argvars[i].vval.v_number;
- // The scope is the current iteration step.
- scope = i;
// It is an error for the scope number to be less than `-1`.
if (scope_number[i] < -1) {
EMSG(_(e_invarg));
return;
}
+ // Use the narrowest scope the user requested
+ if (scope_number[i] >= 0 && scope == kCdScopeInvalid) {
+ // The scope is the current iteration step.
+ scope = i;
+ } else if (scope_number[i] < 0) {
+ scope = i + 1;
+ }
}
- // Normalize scope, the number of the new scope will be 0.
- if (scope_number[scope] < 0) {
- // Arguments to `getcwd` always end at second-highest scope, so scope will
- // always be <= `MAX_CD_SCOPE`.
- scope++;
+ // If the user didn't specify anything, default to window scope
+ if (scope == kCdScopeInvalid) {
+ scope = MIN_CD_SCOPE;
}
// Find the tabpage by number
- if (scope_number[kCdScopeTab] == -1) {
- tp = NULL;
- } else if (scope_number[kCdScopeTab] > 0) {
+ if (scope_number[kCdScopeTab] > 0) {
tp = find_tabpage(scope_number[kCdScopeTab]);
if (!tp) {
EMSG(_("E5000: Cannot find tab number."));
@@ -9945,16 +9957,14 @@ static void f_getcwd(typval_T *argvars, typval_T *rettv)
}
// Find the window in `tp` by number, `NULL` if none.
- if (scope_number[kCdScopeWindow] == -1) {
- win = NULL;
- } else if (scope_number[kCdScopeWindow] >= 0) {
- if (!tp) {
+ if (scope_number[kCdScopeWindow] >= 0) {
+ if (scope_number[kCdScopeTab] < 0) {
EMSG(_("E5001: Higher scope cannot be -1 if lower scope is >= 0."));
return;
}
if (scope_number[kCdScopeWindow] > 0) {
- win = find_win_by_nr(&argvars[0], curtab);
+ win = find_win_by_nr(&argvars[0], tp);
if (!win) {
EMSG(_("E5002: Cannot find window number."));
return;
@@ -9989,6 +9999,9 @@ static void f_getcwd(typval_T *argvars, typval_T *rettv)
}
}
break;
+ case kCdScopeInvalid:
+ // We should never get here
+ assert(false);
}
if (from) {
@@ -10836,7 +10849,7 @@ static void f_has_key(typval_T *argvars, typval_T *rettv)
static void f_haslocaldir(typval_T *argvars, typval_T *rettv)
{
// Possible scope of working directory to return.
- CdScope scope = MIN_CD_SCOPE;
+ CdScope scope = kCdScopeInvalid;
// Numbers of the scope objects (window, tab) we want the working directory
// of. A `-1` means to skip this scope, a `0` means the current object.
@@ -10861,25 +10874,26 @@ static void f_haslocaldir(typval_T *argvars, typval_T *rettv)
return;
}
scope_number[i] = argvars[i].vval.v_number;
- // The scope is the current iteration step.
- scope = i;
if (scope_number[i] < -1) {
EMSG(_(e_invarg));
return;
}
+ // Use the narrowest scope the user requested
+ if (scope_number[i] >= 0 && scope == kCdScopeInvalid) {
+ // The scope is the current iteration step.
+ scope = i;
+ } else if (scope_number[i] < 0) {
+ scope = i + 1;
+ }
}
- // Normalize scope, the number of the new scope will be 0.
- if (scope_number[scope] < 0) {
- // Arguments to `haslocaldir` always end at second-highest scope, so scope
- // will always be <= `MAX_CD_SCOPE`.
- scope++;
+ // If the user didn't specify anything, default to window scope
+ if (scope == kCdScopeInvalid) {
+ scope = MIN_CD_SCOPE;
}
// Find the tabpage by number
- if (scope_number[kCdScopeTab] == -1) {
- tp = NULL;
- } else if (scope_number[kCdScopeTab] > 0) {
+ if (scope_number[kCdScopeTab] > 0) {
tp = find_tabpage(scope_number[kCdScopeTab]);
if (!tp) {
EMSG(_("5000: Cannot find tab number."));
@@ -10888,16 +10902,14 @@ static void f_haslocaldir(typval_T *argvars, typval_T *rettv)
}
// Find the window in `tp` by number, `NULL` if none.
- if (scope_number[kCdScopeWindow] == -1) {
- win = NULL;
- } else if (scope_number[kCdScopeWindow] >= 0) {
- if (!tp) {
+ if (scope_number[kCdScopeWindow] >= 0) {
+ if (scope_number[kCdScopeTab] < 0) {
EMSG(_("E5001: Higher scope cannot be -1 if lower scope is >= 0."));
return;
}
if (scope_number[kCdScopeWindow] > 0) {
- win = find_win_by_nr(&argvars[0], curtab);
+ win = find_win_by_nr(&argvars[0], tp);
if (!win) {
EMSG(_("E5002: Cannot find window number."));
return;
@@ -10918,6 +10930,9 @@ static void f_haslocaldir(typval_T *argvars, typval_T *rettv)
// The global scope never has a local directory
rettv->vval.v_number = 0;
break;
+ case kCdScopeInvalid:
+ // We should never get here
+ assert(false);
}
}
@@ -15079,13 +15094,18 @@ typedef struct {
int idx;
} sortItem_T;
-static int item_compare_ic;
-static bool item_compare_numeric;
-static bool item_compare_numbers;
-static bool item_compare_float;
-static char_u *item_compare_func;
-static dict_T *item_compare_selfdict;
-static int item_compare_func_err;
+/// struct storing information about current sort
+typedef struct {
+ int item_compare_ic;
+ bool item_compare_numeric;
+ bool item_compare_numbers;
+ bool item_compare_float;
+ char_u *item_compare_func;
+ dict_T *item_compare_selfdict;
+ int item_compare_func_err;
+} sortinfo_T;
+static sortinfo_T *sortinfo = NULL;
+
#define ITEM_COMPARE_FAIL 999
/*
@@ -15105,14 +15125,14 @@ static int item_compare(const void *s1, const void *s2, bool keep_zero)
typval_T *tv1 = &si1->item->li_tv;
typval_T *tv2 = &si2->item->li_tv;
- if (item_compare_numbers) {
+ if (sortinfo->item_compare_numbers) {
long v1 = get_tv_number(tv1);
long v2 = get_tv_number(tv2);
return v1 == v2 ? 0 : v1 > v2 ? 1 : -1;
}
- if (item_compare_float) {
+ if (sortinfo->item_compare_float) {
float_T v1 = get_tv_float(tv1);
float_T v2 = get_tv_float(tv2);
@@ -15123,7 +15143,7 @@ static int item_compare(const void *s1, const void *s2, bool keep_zero)
// do that for string variables. Use a single quote when comparing with
// a non-string to do what the docs promise.
if (tv1->v_type == VAR_STRING) {
- if (tv2->v_type != VAR_STRING || item_compare_numeric) {
+ if (tv2->v_type != VAR_STRING || sortinfo->item_compare_numeric) {
p1 = (char_u *)"'";
} else {
p1 = tv1->vval.v_string;
@@ -15132,7 +15152,7 @@ static int item_compare(const void *s1, const void *s2, bool keep_zero)
tofree1 = p1 = (char_u *) encode_tv2string(tv1, NULL);
}
if (tv2->v_type == VAR_STRING) {
- if (tv1->v_type != VAR_STRING || item_compare_numeric) {
+ if (tv1->v_type != VAR_STRING || sortinfo->item_compare_numeric) {
p2 = (char_u *)"'";
} else {
p2 = tv2->vval.v_string;
@@ -15140,12 +15160,14 @@ static int item_compare(const void *s1, const void *s2, bool keep_zero)
} else {
tofree2 = p2 = (char_u *) encode_tv2string(tv2, NULL);
}
- if (p1 == NULL)
+ if (p1 == NULL) {
p1 = (char_u *)"";
- if (p2 == NULL)
+ }
+ if (p2 == NULL) {
p2 = (char_u *)"";
- if (!item_compare_numeric) {
- if (item_compare_ic) {
+ }
+ if (!sortinfo->item_compare_numeric) {
+ if (sortinfo->item_compare_ic) {
res = STRICMP(p1, p2);
} else {
res = STRCMP(p1, p2);
@@ -15186,9 +15208,10 @@ static int item_compare2(const void *s1, const void *s2, bool keep_zero)
typval_T argv[3];
int dummy;
- /* shortcut after failure in previous call; compare all items equal */
- if (item_compare_func_err)
+ // shortcut after failure in previous call; compare all items equal
+ if (sortinfo->item_compare_func_err) {
return 0;
+ }
si1 = (sortItem_T *)s1;
si2 = (sortItem_T *)s2;
@@ -15198,19 +15221,22 @@ static int item_compare2(const void *s1, const void *s2, bool keep_zero)
copy_tv(&si1->item->li_tv, &argv[0]);
copy_tv(&si2->item->li_tv, &argv[1]);
- rettv.v_type = VAR_UNKNOWN; /* clear_tv() uses this */
- res = call_func(item_compare_func, (int)STRLEN(item_compare_func),
- &rettv, 2, argv, 0L, 0L, &dummy, TRUE,
- item_compare_selfdict);
+ rettv.v_type = VAR_UNKNOWN; // clear_tv() uses this
+ res = call_func(sortinfo->item_compare_func,
+ (int)STRLEN(sortinfo->item_compare_func),
+ &rettv, 2, argv, 0L, 0L, &dummy, true,
+ sortinfo->item_compare_selfdict);
clear_tv(&argv[0]);
clear_tv(&argv[1]);
- if (res == FAIL)
+ if (res == FAIL) {
res = ITEM_COMPARE_FAIL;
- else
- res = get_tv_number_chk(&rettv, &item_compare_func_err);
- if (item_compare_func_err)
- res = ITEM_COMPARE_FAIL; /* return value has wrong type */
+ } else {
+ res = get_tv_number_chk(&rettv, &sortinfo->item_compare_func_err);
+ }
+ if (sortinfo->item_compare_func_err) {
+ res = ITEM_COMPARE_FAIL; // return value has wrong type
+ }
clear_tv(&rettv);
// When the result would be zero, compare the pointers themselves. Makes
@@ -15243,6 +15269,12 @@ static void do_sort_uniq(typval_T *argvars, typval_T *rettv, bool sort)
long len;
long i;
+ // Pointer to current info struct used in compare function. Save and restore
+ // the current one for nested calls.
+ sortinfo_T info;
+ sortinfo_T *old_sortinfo = sortinfo;
+ sortinfo = &info;
+
if (argvars[0].v_type != VAR_LIST) {
EMSG2(_(e_listarg), sort ? "sort()" : "uniq()");
} else {
@@ -15253,61 +15285,70 @@ static void do_sort_uniq(typval_T *argvars, typval_T *rettv, bool sort)
? N_("sort() argument")
: N_("uniq() argument")),
true)) {
- return;
+ goto theend;
}
rettv->vval.v_list = l;
rettv->v_type = VAR_LIST;
++l->lv_refcount;
len = list_len(l);
- if (len <= 1)
- return; /* short list sorts pretty quickly */
+ if (len <= 1) {
+ goto theend; // short list sorts pretty quickly
+ }
- item_compare_ic = FALSE;
- item_compare_numeric = false;
- item_compare_numbers = false;
- item_compare_float = false;
- item_compare_func = NULL;
- item_compare_selfdict = NULL;
+ info.item_compare_ic = false;
+ info.item_compare_numeric = false;
+ info.item_compare_numbers = false;
+ info.item_compare_float = false;
+ info.item_compare_func = NULL;
+ info.item_compare_selfdict = NULL;
if (argvars[1].v_type != VAR_UNKNOWN) {
/* optional second argument: {func} */
if (argvars[1].v_type == VAR_FUNC) {
- item_compare_func = argvars[1].vval.v_string;
+ info.item_compare_func = argvars[1].vval.v_string;
} else {
int error = FALSE;
i = get_tv_number_chk(&argvars[1], &error);
- if (error)
- return; /* type error; errmsg already given */
- if (i == 1)
- item_compare_ic = TRUE;
- else
- item_compare_func = get_tv_string(&argvars[1]);
- if (item_compare_func != NULL) {
- if (STRCMP(item_compare_func, "n") == 0) {
- item_compare_func = NULL;
- item_compare_numeric = true;
- } else if (STRCMP(item_compare_func, "N") == 0) {
- item_compare_func = NULL;
- item_compare_numbers = true;
- } else if (STRCMP(item_compare_func, "f") == 0) {
- item_compare_func = NULL;
- item_compare_float = true;
- } else if (STRCMP(item_compare_func, "i") == 0) {
- item_compare_func = NULL;
- item_compare_ic = TRUE;
+ if (error) {
+ goto theend; // type error; errmsg already given
+ }
+ if (i == 1) {
+ info.item_compare_ic = true;
+ } else if (argvars[1].v_type != VAR_NUMBER) {
+ info.item_compare_func = get_tv_string(&argvars[1]);
+ } else if (i != 0) {
+ EMSG(_(e_invarg));
+ goto theend;
+ }
+ if (info.item_compare_func != NULL) {
+ if (*info.item_compare_func == NUL) {
+ // empty string means default sort
+ info.item_compare_func = NULL;
+ } else if (STRCMP(info.item_compare_func, "n") == 0) {
+ info.item_compare_func = NULL;
+ info.item_compare_numeric = true;
+ } else if (STRCMP(info.item_compare_func, "N") == 0) {
+ info.item_compare_func = NULL;
+ info.item_compare_numbers = true;
+ } else if (STRCMP(info.item_compare_func, "f") == 0) {
+ info.item_compare_func = NULL;
+ info.item_compare_float = true;
+ } else if (STRCMP(info.item_compare_func, "i") == 0) {
+ info.item_compare_func = NULL;
+ info.item_compare_ic = true;
}
}
}
if (argvars[2].v_type != VAR_UNKNOWN) {
- /* optional third argument: {dict} */
+ // optional third argument: {dict}
if (argvars[2].v_type != VAR_DICT) {
EMSG(_(e_dictreq));
- return;
+ goto theend;
}
- item_compare_selfdict = argvars[2].vval.v_dict;
+ info.item_compare_selfdict = argvars[2].vval.v_dict;
}
}
@@ -15323,19 +15364,20 @@ static void do_sort_uniq(typval_T *argvars, typval_T *rettv, bool sort)
i++;
}
- item_compare_func_err = FALSE;
+ info.item_compare_func_err = false;
// Test the compare function.
- if (item_compare_func != NULL
+ if (info.item_compare_func != NULL
&& item_compare2_not_keeping_zero(&ptrs[0], &ptrs[1])
== ITEM_COMPARE_FAIL) {
EMSG(_("E702: Sort compare function failed"));
} else {
// Sort the array with item pointers.
qsort(ptrs, (size_t)len, sizeof (sortItem_T),
- item_compare_func == NULL ? item_compare_not_keeping_zero :
- item_compare2_not_keeping_zero);
+ (info.item_compare_func == NULL ?
+ item_compare_not_keeping_zero :
+ item_compare2_not_keeping_zero));
- if (!item_compare_func_err) {
+ if (!info.item_compare_func_err) {
// Clear the list and append the items in the sorted order.
l->lv_first = NULL;
l->lv_last = NULL;
@@ -15351,21 +15393,24 @@ static void do_sort_uniq(typval_T *argvars, typval_T *rettv, bool sort)
int (*item_compare_func_ptr)(const void *, const void *);
// f_uniq(): ptrs will be a stack of items to remove.
- item_compare_func_err = FALSE;
- item_compare_func_ptr = item_compare_func ? item_compare2_keeping_zero :
- item_compare_keeping_zero;
+ info.item_compare_func_err = false;
+ if (info.item_compare_func != NULL) {
+ item_compare_func_ptr = item_compare2_keeping_zero;
+ } else {
+ item_compare_func_ptr = item_compare_keeping_zero;
+ }
for (li = l->lv_first; li != NULL && li->li_next != NULL; li = li->li_next) {
if (item_compare_func_ptr(&li, &li->li_next) == 0) {
ptrs[i++].item = li;
}
- if (item_compare_func_err) {
+ if (info.item_compare_func_err) {
EMSG(_("E882: Uniq compare function failed"));
break;
}
}
- if (!item_compare_func_err) {
+ if (!info.item_compare_func_err) {
while (--i >= 0) {
assert(ptrs[i].item->li_next);
li = ptrs[i].item->li_next;
@@ -15384,6 +15429,9 @@ static void do_sort_uniq(typval_T *argvars, typval_T *rettv, bool sort)
xfree(ptrs);
}
+
+theend:
+ sortinfo = old_sortinfo;
}
/// "sort"({list})" function
@@ -17716,7 +17764,8 @@ void set_vim_var_special(const VimVarIndex idx, const SpecialVarValue val)
void set_vim_var_string(const VimVarIndex idx, const char *const val,
const ptrdiff_t len)
{
- xfree(vimvars[idx].vv_str);
+ clear_tv(&vimvars[idx].vv_di.di_tv);
+ vimvars[idx].vv_type = VAR_STRING;
if (val == NULL) {
vimvars[idx].vv_str = NULL;
} else if (len == -1) {
@@ -17732,7 +17781,8 @@ void set_vim_var_string(const VimVarIndex idx, const char *const val,
/// @param[in,out] val Value to set to. Reference count will be incremented.
void set_vim_var_list(const VimVarIndex idx, list_T *const val)
{
- list_unref(vimvars[idx].vv_list);
+ clear_tv(&vimvars[idx].vv_di.di_tv);
+ vimvars[idx].vv_type = VAR_LIST;
vimvars[idx].vv_list = val;
if (val != NULL) {
val->lv_refcount++;
@@ -17746,7 +17796,8 @@ void set_vim_var_list(const VimVarIndex idx, list_T *const val)
/// Also keys of the dictionary will be made read-only.
void set_vim_var_dict(const VimVarIndex idx, dict_T *const val)
{
- dict_unref(vimvars[idx].vv_dict);
+ clear_tv(&vimvars[idx].vv_di.di_tv);
+ vimvars[idx].vv_type = VAR_DICT;
vimvars[idx].vv_dict = val;
if (val != NULL) {