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.c551
1 files changed, 418 insertions, 133 deletions
diff --git a/src/nvim/eval.c b/src/nvim/eval.c
index 5ef2a8772e..6479163028 100644
--- a/src/nvim/eval.c
+++ b/src/nvim/eval.c
@@ -241,13 +241,14 @@ typedef enum {
///< the value (prevents error message).
} GetLvalFlags;
-// function flags
+// flags used in uf_flags
#define FC_ABORT 0x01 // abort function on error
#define FC_RANGE 0x02 // function accepts range
#define FC_DICT 0x04 // Dict function, uses "self"
#define FC_CLOSURE 0x08 // closure, uses outer scope variables
#define FC_DELETED 0x10 // :delfunction used while uf_refcount > 0
#define FC_REMOVED 0x20 // function redefined while uf_refcount > 0
+#define FC_SANDBOX 0x40 // function defined in the sandbox
// The names of packages that once were loaded are remembered.
static garray_T ga_loaded = { 0, 0, sizeof(char_u *), 4, NULL };
@@ -448,6 +449,7 @@ typedef struct {
int timer_id;
int repeat_count;
int refcount;
+ int emsg_count; ///< Errors in a repeating timer.
long timeout;
bool stopped;
bool paused;
@@ -3933,7 +3935,7 @@ static int eval6(char_u **arg, typval_T *rettv, int evaluate, int want_string)
int op;
varnumber_T n1, n2;
bool use_float = false;
- float_T f1 = 0, f2;
+ float_T f1 = 0, f2 = 0;
bool error = false;
/*
@@ -5219,7 +5221,7 @@ bool garbage_collect(bool testing)
(void)garbage_collect(testing);
}
} else if (p_verbose > 0) {
- verb_msg((char_u *)_(
+ verb_msg(_(
"Not enough memory to set references, garbage collection aborted!"));
}
#undef ABORTING
@@ -5853,6 +5855,9 @@ static int get_lambda_tv(char_u **arg, typval_T *rettv, bool evaluate)
if (prof_def_func()) {
func_do_profile(fp);
}
+ if (sandbox) {
+ flags |= FC_SANDBOX;
+ }
fp->uf_varargs = true;
fp->uf_flags = flags;
fp->uf_calls = 0;
@@ -6328,8 +6333,12 @@ call_func(
}
- /* execute the function if no errors detected and executing */
- if (evaluate && error == ERROR_NONE) {
+ // Execute the function if executing and no errors were detected.
+ if (!evaluate) {
+ // Not evaluating, which means the return value is unknown. This
+ // matters for giving error messages.
+ rettv->v_type = VAR_UNKNOWN;
+ } else if (error == ERROR_NONE) {
char_u *rfname = fname;
/* Ignore "g:" before a function name. */
@@ -6654,12 +6663,24 @@ static void f_append(typval_T *argvars, typval_T *rettv, FunPtr fptr)
rettv->vval.v_number = 1; /* Failed */
}
-/*
- * "argc()" function
- */
static void f_argc(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- rettv->vval.v_number = ARGCOUNT;
+ if (argvars[0].v_type == VAR_UNKNOWN) {
+ // use the current window
+ rettv->vval.v_number = ARGCOUNT;
+ } else if (argvars[0].v_type == VAR_NUMBER
+ && tv_get_number(&argvars[0]) == -1) {
+ // use the global argument list
+ rettv->vval.v_number = GARGCOUNT;
+ } else {
+ // use the argument list of the specified window
+ win_T *wp = find_win_by_nr_or_id(&argvars[0]);
+ if (wp != NULL) {
+ rettv->vval.v_number = WARGCOUNT(wp);
+ } else {
+ rettv->vval.v_number = -1;
+ }
+ }
}
/*
@@ -6680,28 +6701,54 @@ static void f_arglistid(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
}
+/// Get the argument list for a given window
+static void get_arglist_as_rettv(aentry_T *arglist, int argcount,
+ typval_T *rettv)
+{
+ tv_list_alloc_ret(rettv, argcount);
+ if (arglist != NULL) {
+ for (int idx = 0; idx < argcount; idx++) {
+ tv_list_append_string(rettv->vval.v_list,
+ (const char *)alist_name(&arglist[idx]), -1);
+ }
+ }
+}
+
/*
* "argv(nr)" function
*/
static void f_argv(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- int idx;
+ aentry_T *arglist = NULL;
+ int argcount = -1;
if (argvars[0].v_type != VAR_UNKNOWN) {
- idx = (int)tv_get_number_chk(&argvars[0], NULL);
- if (idx >= 0 && idx < ARGCOUNT) {
- rettv->vval.v_string = (char_u *)xstrdup(
- (const char *)alist_name(&ARGLIST[idx]));
+ if (argvars[1].v_type == VAR_UNKNOWN) {
+ arglist = ARGLIST;
+ argcount = ARGCOUNT;
+ } else if (argvars[1].v_type == VAR_NUMBER
+ && tv_get_number(&argvars[1]) == -1) {
+ arglist = GARGLIST;
+ argcount = GARGCOUNT;
} else {
- rettv->vval.v_string = NULL;
+ win_T *wp = find_win_by_nr_or_id(&argvars[1]);
+ if (wp != NULL) {
+ // Use the argument list of the specified window
+ arglist = WARGLIST(wp);
+ argcount = WARGCOUNT(wp);
+ }
}
rettv->v_type = VAR_STRING;
- } else {
- tv_list_alloc_ret(rettv, ARGCOUNT);
- for (idx = 0; idx < ARGCOUNT; idx++) {
- tv_list_append_string(rettv->vval.v_list,
- (const char *)alist_name(&ARGLIST[idx]), -1);
+ rettv->vval.v_string = NULL;
+ int idx = tv_get_number_chk(&argvars[0], NULL);
+ if (arglist != NULL && idx >= 0 && idx < argcount) {
+ rettv->vval.v_string = (char_u *)xstrdup(
+ (const char *)alist_name(&arglist[idx]));
+ } else if (idx == -1) {
+ get_arglist_as_rettv(arglist, argcount, rettv);
}
+ } else {
+ get_arglist_as_rettv(ARGLIST, ARGCOUNT, rettv);
}
}
@@ -6830,6 +6877,27 @@ static void assert_equal_common(typval_T *argvars, assert_type_T atype)
}
}
+static void f_assert_beeps(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+{
+ const char *const cmd = tv_get_string_chk(&argvars[0]);
+ garray_T ga;
+
+ called_vim_beep = false;
+ suppress_errthrow = true;
+ emsg_silent = false;
+ do_cmdline_cmd(cmd);
+ if (!called_vim_beep) {
+ prepare_assert_error(&ga);
+ ga_concat(&ga, (const char_u *)"command did not beep: ");
+ ga_concat(&ga, (const char_u *)cmd);
+ assert_error(&ga);
+ ga_clear(&ga);
+ }
+
+ suppress_errthrow = false;
+ emsg_on_display = false;
+}
+
// "assert_equal(expected, actual[, msg])" function
static void f_assert_equal(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
@@ -7556,6 +7624,23 @@ static void f_complete_check(typval_T *argvars, typval_T *rettv, FunPtr fptr)
RedrawingDisabled = saved;
}
+// "complete_info()" function
+static void f_complete_info(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+{
+ tv_dict_alloc_ret(rettv);
+
+ list_T *what_list = NULL;
+
+ if (argvars[0].v_type != VAR_UNKNOWN) {
+ if (argvars[0].v_type != VAR_LIST) {
+ EMSG(_(e_listreq));
+ return;
+ }
+ what_list = argvars[0].vval.v_list;
+ }
+ get_complete_info(what_list, rettv->vval.v_dict);
+}
+
/*
* "confirm(message, buttons[, default [, type]])" function
*/
@@ -7983,7 +8068,7 @@ static void f_diff_hlID(typval_T *argvars, typval_T *rettv, FunPtr fptr)
hlID = HLF_CHD; // Changed line.
}
}
- rettv->vval.v_number = hlID == (hlf_T)0 ? 0 : (int)hlID;
+ rettv->vval.v_number = hlID == (hlf_T)0 ? 0 : (int)(hlID + 1);
}
/*
@@ -8194,6 +8279,19 @@ static void f_exepath(typval_T *argvars, typval_T *rettv, FunPtr fptr)
rettv->vval.v_string = path;
}
+/// Find a window: When using a Window ID in any tab page, when using a number
+/// in the current tab page.
+win_T * find_win_by_nr_or_id(typval_T *vp)
+{
+ int nr = (int)tv_get_number_chk(vp, NULL);
+
+ if (nr >= LOWEST_WIN_ID) {
+ return win_id2wp(vp);
+ }
+
+ return find_win_by_nr(vp, NULL);
+}
+
/*
* "exists()" function
*/
@@ -9953,6 +10051,37 @@ static void f_getftype(typval_T *argvars, typval_T *rettv, FunPtr fptr)
rettv->vval.v_string = type;
}
+// "getjumplist()" function
+static void f_getjumplist(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+{
+ tv_list_alloc_ret(rettv, kListLenMayKnow);
+ win_T *const wp = find_tabwin(&argvars[0], &argvars[1]);
+ if (wp == NULL) {
+ return;
+ }
+
+ cleanup_jumplist(wp, true);
+
+ list_T *const l = tv_list_alloc(wp->w_jumplistlen);
+ tv_list_append_list(rettv->vval.v_list, l);
+ tv_list_append_number(rettv->vval.v_list, wp->w_jumplistidx);
+
+ for (int i = 0; i < wp->w_jumplistlen; i++) {
+ if (wp->w_jumplist[i].fmark.mark.lnum == 0) {
+ continue;
+ }
+ dict_T *const d = tv_dict_alloc();
+ tv_list_append_dict(l, d);
+ tv_dict_add_nr(d, S_LEN("lnum"), wp->w_jumplist[i].fmark.mark.lnum);
+ tv_dict_add_nr(d, S_LEN("col"), wp->w_jumplist[i].fmark.mark.col);
+ tv_dict_add_nr(d, S_LEN("coladd"), wp->w_jumplist[i].fmark.mark.coladd);
+ tv_dict_add_nr(d, S_LEN("bufnr"), wp->w_jumplist[i].fmark.fnum);
+ if (wp->w_jumplist[i].fname != NULL) {
+ tv_dict_add_str(d, S_LEN("filename"), (char *)wp->w_jumplist[i].fname);
+ }
+ }
+}
+
/*
* "getline(lnum, [end])" function
*/
@@ -9988,7 +10117,7 @@ static void get_qf_loc_list(int is_qf, win_T *wp, typval_T *what_arg,
dict_T *d = what_arg->vval.v_dict;
if (d != NULL) {
- get_errorlist_properties(wp, d, rettv->vval.v_dict);
+ qf_get_properties(wp, d, rettv->vval.v_dict);
}
} else {
EMSG(_(e_dictreq));
@@ -10000,7 +10129,7 @@ static void get_qf_loc_list(int is_qf, win_T *wp, typval_T *what_arg,
/// "getloclist()" function
static void f_getloclist(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- win_T *wp = find_win_by_nr(&argvars[0], NULL);
+ win_T *wp = find_win_by_nr_or_id(&argvars[0]);
get_qf_loc_list(false, wp, &argvars[1], rettv);
}
@@ -10019,7 +10148,7 @@ static void f_getmatches(typval_T *argvars, typval_T *rettv, FunPtr fptr)
// match added with matchaddpos()
for (i = 0; i < MAXPOSMATCH; i++) {
llpos_T *llpos;
- char buf[6];
+ char buf[30]; // use 30 to avoid compiler warning
llpos = &cur->pos.pos[i];
if (llpos->lnum == 0) {
@@ -10306,6 +10435,23 @@ static void f_gettabwinvar(typval_T *argvars, typval_T *rettv, FunPtr fptr)
getwinvar(argvars, rettv, 1);
}
+// "gettagstack()" function
+static void f_gettagstack(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+{
+ win_T *wp = curwin; // default is current window
+
+ tv_dict_alloc_ret(rettv);
+
+ if (argvars[0].v_type != VAR_UNKNOWN) {
+ wp = find_win_by_nr_or_id(&argvars[0]);
+ if (wp == NULL) {
+ return;
+ }
+ }
+
+ get_tagstack(wp, rettv->vval.v_dict);
+}
+
/// Returns information about a window as a dictionary.
static dict_T *get_win_info(win_T *wp, int16_t tpnr, int16_t winnr)
{
@@ -10371,11 +10517,19 @@ static void f_getwininfo(typval_T *argvars, typval_T *rettv, FunPtr fptr)
static void f_win_screenpos(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
tv_list_alloc_ret(rettv, 2);
- const win_T *const wp = find_win_by_nr(&argvars[0], NULL);
+ const win_T *const wp = find_win_by_nr_or_id(&argvars[0]);
tv_list_append_number(rettv->vval.v_list, wp == NULL ? 0 : wp->w_winrow + 1);
tv_list_append_number(rettv->vval.v_list, wp == NULL ? 0 : wp->w_wincol + 1);
}
+// "getwinpos({timeout})" function
+static void f_getwinpos(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+{
+ tv_list_alloc_ret(rettv, 2);
+ tv_list_append_number(rettv->vval.v_list, -1);
+ tv_list_append_number(rettv->vval.v_list, -1);
+}
+
/*
* "getwinposx()" function
*/
@@ -10707,6 +10861,7 @@ static void f_has(typval_T *argvars, typval_T *rettv, FunPtr fptr)
#ifdef __APPLE__
"mac",
"macunix",
+ "osx",
#endif
"menu",
"mksession",
@@ -11180,7 +11335,6 @@ static void f_index(typval_T *argvars, typval_T *rettv, FunPtr fptr)
static int inputsecret_flag = 0;
-
/*
* This function is used by f_input() and f_inputdialog() functions. The third
* argument to f_input() specifies the type of completion to use at the
@@ -11369,25 +11523,21 @@ static void f_inputlist(typval_T *argvars, typval_T *rettv, FunPtr fptr)
static garray_T ga_userinput = {0, 0, sizeof(tasave_T), 4, NULL};
-/*
- * "inputrestore()" function
- */
+/// "inputrestore()" function
static void f_inputrestore(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
if (!GA_EMPTY(&ga_userinput)) {
- --ga_userinput.ga_len;
+ ga_userinput.ga_len--;
restore_typeahead((tasave_T *)(ga_userinput.ga_data)
- + ga_userinput.ga_len);
- /* default return is zero == OK */
+ + ga_userinput.ga_len);
+ // default return is zero == OK
} else if (p_verbose > 1) {
- verb_msg((char_u *)_("called inputrestore() more often than inputsave()"));
- rettv->vval.v_number = 1; /* Failed */
+ verb_msg(_("called inputrestore() more often than inputsave()"));
+ rettv->vval.v_number = 1; // Failed
}
}
-/*
- * "inputsave()" function
- */
+/// "inputsave()" function
static void f_inputsave(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
// Add an entry to the stack of typeahead storage.
@@ -11395,9 +11545,7 @@ static void f_inputsave(typval_T *argvars, typval_T *rettv, FunPtr fptr)
save_typeahead(p);
}
-/*
- * "inputsecret()" function
- */
+/// "inputsecret()" function
static void f_inputsecret(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
cmdline_star++;
@@ -11564,10 +11712,11 @@ static void dict_list(typval_T *const tv, typval_T *const rettv,
static void f_id(typval_T *argvars, typval_T *rettv, FunPtr fptr)
FUNC_ATTR_NONNULL_ALL
{
- const int len = vim_vsnprintf(NULL, 0, "%p", dummy_ap, argvars);
+ const int len = vim_vsnprintf_typval(NULL, 0, "%p", dummy_ap, argvars);
rettv->v_type = VAR_STRING;
rettv->vval.v_string = xmalloc(len + 1);
- vim_vsnprintf((char *)rettv->vval.v_string, len + 1, "%p", dummy_ap, argvars);
+ vim_vsnprintf_typval((char *)rettv->vval.v_string, len + 1, "%p",
+ dummy_ap, argvars);
}
/*
@@ -12503,6 +12652,31 @@ static void f_match(typval_T *argvars, typval_T *rettv, FunPtr fptr)
find_some_match(argvars, rettv, kSomeMatch);
}
+static int matchadd_dict_arg(typval_T *tv, const char **conceal_char,
+ win_T **win)
+{
+ dictitem_T *di;
+
+ if (tv->v_type != VAR_DICT) {
+ EMSG(_(e_dictreq));
+ return FAIL;
+ }
+
+ if ((di = tv_dict_find(tv->vval.v_dict, S_LEN("conceal"))) != NULL) {
+ *conceal_char = tv_get_string(&di->di_tv);
+ }
+
+ if ((di = tv_dict_find(tv->vval.v_dict, S_LEN("window"))) != NULL) {
+ *win = find_win_by_nr_or_id(&di->di_tv);
+ if (*win == NULL) {
+ EMSG(_("E957: Invalid window number"));
+ return FAIL;
+ }
+ }
+
+ return OK;
+}
+
/*
* "matchadd()" function
*/
@@ -12516,6 +12690,7 @@ static void f_matchadd(typval_T *argvars, typval_T *rettv, FunPtr fptr)
int id = -1;
bool error = false;
const char *conceal_char = NULL;
+ win_T *win = curwin;
rettv->vval.v_number = -1;
@@ -12526,16 +12701,9 @@ static void f_matchadd(typval_T *argvars, typval_T *rettv, FunPtr fptr)
prio = tv_get_number_chk(&argvars[2], &error);
if (argvars[3].v_type != VAR_UNKNOWN) {
id = tv_get_number_chk(&argvars[3], &error);
- if (argvars[4].v_type != VAR_UNKNOWN) {
- if (argvars[4].v_type != VAR_DICT) {
- EMSG(_(e_dictreq));
- return;
- }
- dictitem_T *di;
- if ((di = tv_dict_find(argvars[4].vval.v_dict, S_LEN("conceal")))
- != NULL) {
- conceal_char = tv_get_string(&di->di_tv);
- }
+ if (argvars[4].v_type != VAR_UNKNOWN
+ && matchadd_dict_arg(&argvars[4], &conceal_char, &win) == FAIL) {
+ return;
}
}
}
@@ -12547,8 +12715,7 @@ static void f_matchadd(typval_T *argvars, typval_T *rettv, FunPtr fptr)
return;
}
- rettv->vval.v_number = match_add(curwin, grp, pat, prio, id, NULL,
- conceal_char);
+ rettv->vval.v_number = match_add(win, grp, pat, prio, id, NULL, conceal_char);
}
static void f_matchaddpos(typval_T *argvars, typval_T *rettv, FunPtr fptr)
@@ -12576,21 +12743,15 @@ static void f_matchaddpos(typval_T *argvars, typval_T *rettv, FunPtr fptr)
int prio = 10;
int id = -1;
const char *conceal_char = NULL;
+ win_T *win = curwin;
if (argvars[2].v_type != VAR_UNKNOWN) {
prio = tv_get_number_chk(&argvars[2], &error);
if (argvars[3].v_type != VAR_UNKNOWN) {
id = tv_get_number_chk(&argvars[3], &error);
- if (argvars[4].v_type != VAR_UNKNOWN) {
- if (argvars[4].v_type != VAR_DICT) {
- EMSG(_(e_dictreq));
- return;
- }
- dictitem_T *di;
- if ((di = tv_dict_find(argvars[4].vval.v_dict, S_LEN("conceal")))
- != NULL) {
- conceal_char = tv_get_string(&di->di_tv);
- }
+ if (argvars[4].v_type != VAR_UNKNOWN
+ && matchadd_dict_arg(&argvars[4], &conceal_char, &win) == FAIL) {
+ return;
}
}
}
@@ -12604,8 +12765,7 @@ static void f_matchaddpos(typval_T *argvars, typval_T *rettv, FunPtr fptr)
return;
}
- rettv->vval.v_number = match_add(curwin, group, NULL, prio, id, l,
- conceal_char);
+ rettv->vval.v_number = match_add(win, group, NULL, prio, id, l, conceal_char);
}
/*
@@ -12752,33 +12912,36 @@ static void f_mkdir(typval_T *argvars, typval_T *rettv, FunPtr fptr)
char buf[NUMBUFLEN];
const char *const dir = tv_get_string_buf(&argvars[0], buf);
if (*dir == NUL) {
- rettv->vval.v_number = FAIL;
- } else {
- if (*path_tail((char_u *)dir) == NUL) {
- // Remove trailing slashes.
- *path_tail_with_sep((char_u *)dir) = NUL;
- }
+ return;
+ }
- if (argvars[1].v_type != VAR_UNKNOWN) {
- if (argvars[2].v_type != VAR_UNKNOWN) {
- prot = tv_get_number_chk(&argvars[2], NULL);
- }
- if (prot != -1 && strcmp(tv_get_string(&argvars[1]), "p") == 0) {
- char *failed_dir;
- int ret = os_mkdir_recurse(dir, prot, &failed_dir);
- if (ret != 0) {
- EMSG3(_(e_mkdir), failed_dir, os_strerror(ret));
- xfree(failed_dir);
- rettv->vval.v_number = FAIL;
- return;
- } else {
- rettv->vval.v_number = OK;
- return;
- }
+ if (*path_tail((char_u *)dir) == NUL) {
+ // Remove trailing slashes.
+ *path_tail_with_sep((char_u *)dir) = NUL;
+ }
+
+ if (argvars[1].v_type != VAR_UNKNOWN) {
+ if (argvars[2].v_type != VAR_UNKNOWN) {
+ prot = tv_get_number_chk(&argvars[2], NULL);
+ if (prot == -1) {
+ return;
+ }
+ }
+ if (strcmp(tv_get_string(&argvars[1]), "p") == 0) {
+ char *failed_dir;
+ int ret = os_mkdir_recurse(dir, prot, &failed_dir);
+ if (ret != 0) {
+ EMSG3(_(e_mkdir), failed_dir, os_strerror(ret));
+ xfree(failed_dir);
+ rettv->vval.v_number = FAIL;
+ return;
+ } else {
+ rettv->vval.v_number = OK;
+ return;
}
}
- rettv->vval.v_number = prot == -1 ? FAIL : vim_mkdir_emsg(dir, prot);
}
+ rettv->vval.v_number = vim_mkdir_emsg(dir, prot);
}
/// "mode()" function
@@ -13020,11 +13183,11 @@ static void f_printf(typval_T *argvars, typval_T *rettv, FunPtr fptr)
did_emsg = false;
char buf[NUMBUFLEN];
const char *fmt = tv_get_string_buf(&argvars[0], buf);
- len = vim_vsnprintf(NULL, 0, fmt, dummy_ap, argvars + 1);
+ len = vim_vsnprintf_typval(NULL, 0, fmt, dummy_ap, argvars + 1);
if (!did_emsg) {
char *s = xmalloc(len + 1);
rettv->vval.v_string = (char_u *)s;
- (void)vim_vsnprintf(s, len + 1, fmt, dummy_ap, argvars + 1);
+ (void)vim_vsnprintf_typval(s, len + 1, fmt, dummy_ap, argvars + 1);
}
did_emsg |= saved_did_emsg;
}
@@ -14761,7 +14924,7 @@ static void set_qf_ll_list(win_T *wp, typval_T *args, typval_T *rettv)
skip_args:
if (!title) {
- title = (wp ? "setloclist()" : "setqflist()");
+ title = (wp ? ":setloclist()" : ":setqflist()");
}
recursive++;
@@ -14781,7 +14944,7 @@ static void f_setloclist(typval_T *argvars, typval_T *rettv, FunPtr fptr)
rettv->vval.v_number = -1;
- win = find_win_by_nr(&argvars[0], NULL);
+ win = find_win_by_nr_or_id(&argvars[0]);
if (win != NULL) {
set_qf_ll_list(win, &argvars[1], rettv);
}
@@ -14837,7 +15000,7 @@ static void f_setmatches(typval_T *argvars, typval_T *rettv, FunPtr fptr)
// match from matchaddpos()
for (i = 1; i < 9; i++) {
- char buf[5];
+ char buf[30]; // use 30 to avoid compiler warning
snprintf(buf, sizeof(buf), "pos%d", i);
dictitem_T *const pos_di = tv_dict_find(d, buf, -1);
if (pos_di != NULL) {
@@ -15087,6 +15250,60 @@ static void f_settabwinvar(typval_T *argvars, typval_T *rettv, FunPtr fptr)
setwinvar(argvars, rettv, 1);
}
+// "settagstack()" function
+static void f_settagstack(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+{
+ static char *e_invact2 = N_("E962: Invalid action: '%s'");
+ win_T *wp;
+ dict_T *d;
+ int action = 'r';
+
+ rettv->vval.v_number = -1;
+
+ // first argument: window number or id
+ wp = find_win_by_nr_or_id(&argvars[0]);
+ if (wp == NULL) {
+ return;
+ }
+
+ // second argument: dict with items to set in the tag stack
+ if (argvars[1].v_type != VAR_DICT) {
+ EMSG(_(e_dictreq));
+ return;
+ }
+ d = argvars[1].vval.v_dict;
+ if (d == NULL) {
+ return;
+ }
+
+ // third argument: action - 'a' for append and 'r' for replace.
+ // default is to replace the stack.
+ if (argvars[2].v_type == VAR_UNKNOWN) {
+ action = 'r';
+ } else if (argvars[2].v_type == VAR_STRING) {
+ const char *actstr;
+ actstr = tv_get_string_chk(&argvars[2]);
+ if (actstr == NULL) {
+ return;
+ }
+ if ((*actstr == 'r' || *actstr == 'a') && actstr[1] == NUL) {
+ action = *actstr;
+ } else {
+ EMSG2(_(e_invact2), actstr);
+ return;
+ }
+ } else {
+ EMSG(_(e_stringreq));
+ return;
+ }
+
+ if (set_tagstack(wp, d, action) == OK) {
+ rettv->vval.v_number = 0;
+ } else {
+ EMSG(_(e_listreq));
+ }
+}
+
/*
* "setwinvar()" function
*/
@@ -16306,6 +16523,27 @@ static void f_substitute(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
}
+/// "swapinfo(swap_filename)" function
+static void f_swapinfo(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+{
+ tv_dict_alloc_ret(rettv);
+ get_b0_dict(tv_get_string(argvars), rettv->vval.v_dict);
+}
+
+/// "swapname(expr)" function
+static void f_swapname(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+{
+ rettv->v_type = VAR_STRING;
+ buf_T *buf = tv_get_buf(&argvars[0], false);
+ if (buf == NULL
+ || buf->b_ml.ml_mfp == NULL
+ || buf->b_ml.ml_mfp->mf_fname == NULL) {
+ rettv->vval.v_string = NULL;
+ } else {
+ rettv->vval.v_string = vim_strsave(buf->b_ml.ml_mfp->mf_fname);
+ }
+}
+
/// "synID(lnum, col, trans)" function
static void f_synID(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
@@ -16631,7 +16869,6 @@ static void f_tabpagebuflist(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
}
-
/*
* "tabpagenr()" function
*/
@@ -16668,6 +16905,7 @@ static int get_winnr(tabpage_T *tp, typval_T *argvar)
twin = (tp == curtab) ? curwin : tp->tp_curwin;
if (argvar->v_type != VAR_UNKNOWN) {
+ bool invalid_arg = false;
const char *const arg = tv_get_string_chk(argvar);
if (arg == NULL) {
nr = 0; // Type error; errmsg already given.
@@ -16679,6 +16917,31 @@ static int get_winnr(tabpage_T *tp, typval_T *argvar)
nr = 0;
}
} else {
+ // Extract the window count (if specified). e.g. winnr('3j')
+ char_u *endp;
+ long count = strtol((char *)arg, (char **)&endp, 10);
+ if (count <= 0) {
+ // if count is not specified, default to 1
+ count = 1;
+ }
+ if (endp != NULL && *endp != '\0') {
+ if (strequal((char *)endp, "j")) {
+ twin = win_vert_neighbor(tp, twin, false, count);
+ } else if (strequal((char *)endp, "k")) {
+ twin = win_vert_neighbor(tp, twin, true, count);
+ } else if (strequal((char *)endp, "h")) {
+ twin = win_horz_neighbor(tp, twin, true, count);
+ } else if (strequal((char *)endp, "l")) {
+ twin = win_horz_neighbor(tp, twin, false, count);
+ } else {
+ invalid_arg = true;
+ }
+ } else {
+ invalid_arg = true;
+ }
+ }
+
+ if (invalid_arg) {
EMSG2(_(e_invexpr2), arg);
nr = 0;
}
@@ -16712,7 +16975,6 @@ static void f_tabpagewinnr(typval_T *argvars, typval_T *rettv, FunPtr fptr)
rettv->vval.v_number = nr;
}
-
/*
* "tagfiles()" function
*/
@@ -17075,6 +17337,7 @@ static void f_timer_start(typval_T *argvars, typval_T *rettv, FunPtr fptr)
timer->refcount = 1;
timer->stopped = false;
timer->paused = false;
+ timer->emsg_count = 0;
timer->repeat_count = repeat;
timer->timeout = timeout;
timer->timer_id = last_timer_id++;
@@ -17117,6 +17380,9 @@ static void f_timer_stopall(typval_T *argvars, typval_T *unused, FunPtr fptr)
static void timer_due_cb(TimeWatcher *tw, void *data)
{
timer_T *timer = (timer_T *)data;
+ int save_did_emsg = did_emsg;
+ int save_called_emsg = called_emsg;
+
if (timer->stopped || timer->paused) {
return;
}
@@ -17131,8 +17397,24 @@ static void timer_due_cb(TimeWatcher *tw, void *data)
argv[0].v_type = VAR_NUMBER;
argv[0].vval.v_number = timer->timer_id;
typval_T rettv = TV_INITIAL_VALUE;
+ called_emsg = false;
callback_call(&timer->callback, 1, argv, &rettv);
+
+ // Handle error message
+ if (called_emsg && did_emsg) {
+ timer->emsg_count++;
+ if (current_exception != NULL) {
+ discard_current_exception();
+ }
+ }
+ did_emsg = save_did_emsg;
+ called_emsg = save_called_emsg;
+
+ if (timer->emsg_count >= 3) {
+ timer_stop(timer);
+ }
+
tv_clear(&rettv);
if (!timer->stopped && timer->timeout == 0) {
@@ -17419,7 +17701,7 @@ static void f_undofile(typval_T *argvars, typval_T *rettv, FunPtr fptr)
// If there is no file name there will be no undo file.
rettv->vval.v_string = NULL;
} else {
- char *ffname = FullName_save(fname, false);
+ char *ffname = FullName_save(fname, true);
if (ffname != NULL) {
rettv->vval.v_string = (char_u *)u_get_undo_file_name(ffname, false);
@@ -17532,18 +17814,15 @@ static void f_win_id2win(typval_T *argvars, typval_T *rettv, FunPtr fptr)
rettv->vval.v_number = win_id2win(argvars);
}
-/*
- * "winbufnr(nr)" function
- */
+/// "winbufnr(nr)" function
static void f_winbufnr(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- win_T *wp;
-
- wp = find_win_by_nr(&argvars[0], NULL);
- if (wp == NULL)
+ win_T *wp = find_win_by_nr_or_id(&argvars[0]);
+ if (wp == NULL) {
rettv->vval.v_number = -1;
- else
+ } else {
rettv->vval.v_number = wp->w_buffer->b_fnum;
+ }
}
/*
@@ -17555,18 +17834,15 @@ static void f_wincol(typval_T *argvars, typval_T *rettv, FunPtr fptr)
rettv->vval.v_number = curwin->w_wcol + 1;
}
-/*
- * "winheight(nr)" function
- */
+/// "winheight(nr)" function
static void f_winheight(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- win_T *wp;
-
- wp = find_win_by_nr(&argvars[0], NULL);
- if (wp == NULL)
+ win_T *wp = find_win_by_nr_or_id(&argvars[0]);
+ if (wp == NULL) {
rettv->vval.v_number = -1;
- else
+ } else {
rettv->vval.v_number = wp->w_height;
+ }
}
/*
@@ -17830,18 +18106,15 @@ static char *save_tv_as_string(typval_T *tv, ptrdiff_t *const len, bool endnl)
return ret;
}
-/*
- * "winwidth(nr)" function
- */
+/// "winwidth(nr)" function
static void f_winwidth(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- win_T *wp;
-
- wp = find_win_by_nr(&argvars[0], NULL);
- if (wp == NULL)
+ win_T *wp = find_win_by_nr_or_id(&argvars[0]);
+ if (wp == NULL) {
rettv->vval.v_number = -1;
- else
+ } else {
rettv->vval.v_number = wp->w_width;
+ }
}
/// "wordcount()" function
@@ -18053,7 +18326,7 @@ pos_T *var2fpos(const typval_T *const tv, const int dollar_lnum,
* Return FAIL when conversion is not possible, doesn't check the position for
* validity.
*/
-static int list2fpos(typval_T *arg, pos_T *posp, int *fnump, colnr_T *curswantp)
+int list2fpos(typval_T *arg, pos_T *posp, int *fnump, colnr_T *curswantp)
{
list_T *l;
long i = 0;
@@ -19570,16 +19843,15 @@ void ex_echo(exarg_T *eap)
{
char_u *arg = eap->arg;
typval_T rettv;
- bool needclr = true;
bool atstart = true;
const int did_emsg_before = did_emsg;
if (eap->skip)
++emsg_skip;
while (*arg != NUL && *arg != '|' && *arg != '\n' && !got_int) {
- /* If eval1() causes an error message the text from the command may
- * still need to be cleared. E.g., "echo 22,44". */
- need_clr_eos = needclr;
+ // If eval1() causes an error message the text from the command may
+ // still need to be cleared. E.g., "echo 22,44".
+ need_clr_eos = true;
{
char_u *p = arg;
@@ -19623,14 +19895,14 @@ void ex_echo(exarg_T *eap)
}
eap->nextcmd = check_nextcmd(arg);
- if (eap->skip)
- --emsg_skip;
- else {
- /* remove text that may still be there from the command */
- if (needclr)
- msg_clr_eos();
- if (eap->cmdidx == CMD_echo)
+ if (eap->skip) {
+ emsg_skip--;
+ } else {
+ // remove text that may still be there from the command
+ msg_clr_eos();
+ if (eap->cmdidx == CMD_echo) {
msg_end();
+ }
}
}
@@ -20348,6 +20620,9 @@ void ex_function(exarg_T *eap)
if (prof_def_func())
func_do_profile(fp);
fp->uf_varargs = varargs;
+ if (sandbox) {
+ flags |= FC_SANDBOX;
+ }
fp->uf_flags = flags;
fp->uf_calls = 0;
fp->uf_script_ID = current_SID;
@@ -21338,6 +21613,7 @@ void call_user_func(ufunc_T *fp, int argcount, typval_T *argvars,
char_u *save_sourcing_name;
linenr_T save_sourcing_lnum;
scid_T save_current_SID;
+ bool using_sandbox = false;
funccall_T *fc;
int save_did_emsg;
static int depth = 0;
@@ -21495,6 +21771,12 @@ void call_user_func(ufunc_T *fp, int argcount, typval_T *argvars,
save_sourcing_name = sourcing_name;
save_sourcing_lnum = sourcing_lnum;
sourcing_lnum = 1;
+
+ if (fp->uf_flags & FC_SANDBOX) {
+ using_sandbox = true;
+ sandbox++;
+ }
+
// need space for new sourcing_name:
// * save_sourcing_name
// * "["number"].." or "function "
@@ -21655,6 +21937,9 @@ void call_user_func(ufunc_T *fp, int argcount, typval_T *argvars,
if (do_profiling_yes) {
script_prof_restore(&wait_start);
}
+ if (using_sandbox) {
+ sandbox--;
+ }
if (p_verbose >= 12 && sourcing_name != NULL) {
++no_wait_return;