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.c289
1 files changed, 212 insertions, 77 deletions
diff --git a/src/nvim/eval.c b/src/nvim/eval.c
index 55fa974797..7839a7f645 100644
--- a/src/nvim/eval.c
+++ b/src/nvim/eval.c
@@ -3297,6 +3297,26 @@ char_u *get_user_var_name(expand_T *xp, int idx)
}
+/// Return TRUE if "pat" matches "text".
+/// Does not use 'cpo' and always uses 'magic'.
+static int pattern_match(char_u *pat, char_u *text, int ic)
+{
+ int matches = 0;
+ regmatch_T regmatch;
+
+ // avoid 'l' flag in 'cpoptions'
+ char_u *save_cpo = p_cpo;
+ p_cpo = (char_u *)"";
+ regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
+ if (regmatch.regprog != NULL) {
+ regmatch.rm_ic = ic;
+ matches = vim_regexec_nl(&regmatch, text, (colnr_T)0);
+ vim_regfree(regmatch.regprog);
+ }
+ p_cpo = save_cpo;
+ return matches;
+}
+
/*
* types for expressions.
*/
@@ -3572,9 +3592,7 @@ static int eval4(char_u **arg, typval_T *rettv, int evaluate)
long n1, n2;
char_u *s1, *s2;
char_u buf1[NUMBUFLEN], buf2[NUMBUFLEN];
- regmatch_T regmatch;
int ic;
- char_u *save_cpo;
/*
* Get the first variable.
@@ -3783,19 +3801,10 @@ static int eval4(char_u **arg, typval_T *rettv, int evaluate)
case TYPE_MATCH:
case TYPE_NOMATCH:
- /* avoid 'l' flag in 'cpoptions' */
- save_cpo = p_cpo;
- p_cpo = (char_u *)"";
- regmatch.regprog = vim_regcomp(s2,
- RE_MAGIC + RE_STRING);
- regmatch.rm_ic = ic;
- if (regmatch.regprog != NULL) {
- n1 = vim_regexec_nl(&regmatch, s1, (colnr_T)0);
- vim_regfree(regmatch.regprog);
- if (type == TYPE_NOMATCH)
- n1 = !n1;
+ n1 = pattern_match(s2, s1, ic);
+ if (type == TYPE_NOMATCH) {
+ n1 = !n1;
}
- p_cpo = save_cpo;
break;
case TYPE_UNKNOWN: break; /* avoid gcc warning */
@@ -6697,6 +6706,9 @@ static struct fst {
{ "assert_exception", 1, 2, f_assert_exception },
{ "assert_fails", 1, 2, f_assert_fails },
{ "assert_false", 1, 2, f_assert_false },
+ { "assert_match", 2, 3, f_assert_match },
+ { "assert_notequal", 2, 3, f_assert_notequal },
+ { "assert_notmatch", 2, 3, f_assert_notmatch },
{ "assert_true", 1, 2, f_assert_true },
{ "atan", 1, 1, f_atan },
{ "atan2", 2, 2, f_atan2 },
@@ -6715,7 +6727,6 @@ static struct fst {
{ "byteidx", 2, 2, f_byteidx },
{ "byteidxcomp", 2, 2, f_byteidxcomp },
{ "call", 2, 3, f_call },
- { "capture", 1, 1, f_capture },
{ "ceil", 1, 1, f_ceil },
{ "changenr", 0, 0, f_changenr },
{ "char2nr", 1, 2, f_char2nr },
@@ -6744,6 +6755,7 @@ static struct fst {
{ "eval", 1, 1, f_eval },
{ "eventhandler", 0, 0, f_eventhandler },
{ "executable", 1, 1, f_executable },
+ { "execute", 1, 1, f_execute },
{ "exepath", 1, 1, f_exepath },
{ "exists", 1, 1, f_exists },
{ "exp", 1, 1, f_exp },
@@ -6779,6 +6791,7 @@ static struct fst {
{ "getcmdpos", 0, 0, f_getcmdpos },
{ "getcmdtype", 0, 0, f_getcmdtype },
{ "getcmdwintype", 0, 0, f_getcmdwintype },
+ { "getcompletion", 2, 2, f_getcompletion },
{ "getcurpos", 0, 0, f_getcurpos },
{ "getcwd", 0, 2, f_getcwd },
{ "getfontname", 0, 1, f_getfontname },
@@ -6974,6 +6987,10 @@ static struct fst {
{ "virtcol", 1, 1, f_virtcol },
{ "visualmode", 0, 1, f_visualmode },
{ "wildmenumode", 0, 0, f_wildmenumode },
+ { "win_getid", 0, 2, f_win_getid },
+ { "win_gotoid", 1, 1, f_win_gotoid },
+ { "win_id2tabwin", 1, 1, f_win_id2tabwin },
+ { "win_id2win", 1, 1, f_win_id2win },
{ "winbufnr", 1, 1, f_winbufnr },
{ "wincol", 0, 0, f_wincol },
{ "winheight", 1, 1, f_winheight },
@@ -7606,7 +7623,7 @@ static void prepare_assert_error(garray_T *gap)
// Fill "gap" with information about an assert error.
static void fill_assert_error(garray_T *gap, typval_T *opt_msg_tv,
char_u *exp_str, typval_T *exp_tv,
- typval_T *got_tv)
+ typval_T *got_tv, assert_type_T atype)
{
char_u *tofree;
@@ -7615,7 +7632,11 @@ static void fill_assert_error(garray_T *gap, typval_T *opt_msg_tv,
ga_concat(gap, tofree);
xfree(tofree);
} else {
- ga_concat(gap, (char_u *)"Expected ");
+ if (atype == ASSERT_MATCH || atype == ASSERT_NOTMATCH) {
+ ga_concat(gap, (char_u *)"Pattern ");
+ } else {
+ ga_concat(gap, (char_u *)"Expected ");
+ }
if (exp_str == NULL) {
tofree = (char_u *) encode_tv2string(exp_tv, NULL);
ga_concat(gap, tofree);
@@ -7623,8 +7644,16 @@ static void fill_assert_error(garray_T *gap, typval_T *opt_msg_tv,
} else {
ga_concat(gap, exp_str);
}
- tofree = (char_u *) encode_tv2string(got_tv, NULL);
- ga_concat(gap, (char_u *)" but got ");
+ tofree = (char_u *)encode_tv2string(got_tv, NULL);
+ if (atype == ASSERT_MATCH) {
+ ga_concat(gap, (char_u *)" does not match ");
+ } else if (atype == ASSERT_NOTMATCH) {
+ ga_concat(gap, (char_u *)" does match ");
+ } else if (atype == ASSERT_NOTEQUAL) {
+ ga_concat(gap, (char_u *)" differs from ");
+ } else {
+ ga_concat(gap, (char_u *)" but got ");
+ }
ga_concat(gap, tofree);
xfree(tofree);
}
@@ -7643,20 +7672,32 @@ static void assert_error(garray_T *gap)
gap->ga_data, gap->ga_len);
}
-// "assert_equal(expected, actual[, msg])" function
-static void f_assert_equal(typval_T *argvars, typval_T *rettv)
+static void assert_equal_common(typval_T *argvars, assert_type_T atype)
{
garray_T ga;
- if (!tv_equal(&argvars[0], &argvars[1], false, false)) {
+ if (tv_equal(&argvars[0], &argvars[1], false, false)
+ != (atype == ASSERT_EQUAL)) {
prepare_assert_error(&ga);
fill_assert_error(&ga, &argvars[2], NULL,
- &argvars[0], &argvars[1]);
+ &argvars[0], &argvars[1], atype);
assert_error(&ga);
ga_clear(&ga);
}
}
+// "assert_equal(expected, actual[, msg])" function
+static void f_assert_equal(typval_T *argvars, typval_T *rettv)
+{
+ assert_equal_common(argvars, ASSERT_EQUAL);
+}
+
+// "assert_notequal(expected, actual[, msg])" function
+static void f_assert_notequal(typval_T *argvars, typval_T *rettv)
+{
+ assert_equal_common(argvars, ASSERT_NOTEQUAL);
+}
+
/// "assert_exception(string[, msg])" function
static void f_assert_exception(typval_T *argvars, typval_T *rettv)
{
@@ -7672,7 +7713,7 @@ static void f_assert_exception(typval_T *argvars, typval_T *rettv)
&& strstr((char *)vimvars[VV_EXCEPTION].vv_str, error) == NULL) {
prepare_assert_error(&ga);
fill_assert_error(&ga, &argvars[1], NULL, &argvars[0],
- &vimvars[VV_EXCEPTION].vv_tv);
+ &vimvars[VV_EXCEPTION].vv_tv, ASSERT_OTHER);
assert_error(&ga);
ga_clear(&ga);
}
@@ -7702,7 +7743,7 @@ static void f_assert_fails(typval_T *argvars, typval_T *rettv)
|| strstr((char *)vimvars[VV_ERRMSG].vv_str, error) == NULL) {
prepare_assert_error(&ga);
fill_assert_error(&ga, &argvars[2], NULL, &argvars[1],
- &vimvars[VV_ERRMSG].vv_tv);
+ &vimvars[VV_ERRMSG].vv_tv, ASSERT_OTHER);
assert_error(&ga);
ga_clear(&ga);
}
@@ -7732,7 +7773,7 @@ static void assert_bool(typval_T *argvars, bool is_true)
prepare_assert_error(&ga);
fill_assert_error(&ga, &argvars[1],
(char_u *)(is_true ? "True" : "False"),
- NULL, &argvars[0]);
+ NULL, &argvars[0], ASSERT_OTHER);
assert_error(&ga);
ga_clear(&ga);
}
@@ -7744,6 +7785,36 @@ static void f_assert_false(typval_T *argvars, typval_T *rettv)
assert_bool(argvars, false);
}
+static void assert_match_common(typval_T *argvars, assert_type_T atype)
+{
+ char_u buf1[NUMBUFLEN];
+ char_u buf2[NUMBUFLEN];
+ char_u *pat = get_tv_string_buf_chk(&argvars[0], buf1);
+ char_u *text = get_tv_string_buf_chk(&argvars[1], buf2);
+
+ if (pat == NULL || text == NULL) {
+ EMSG(_(e_invarg));
+ } else if (pattern_match(pat, text, false) != (atype == ASSERT_MATCH)) {
+ garray_T ga;
+ prepare_assert_error(&ga);
+ fill_assert_error(&ga, &argvars[2], NULL, &argvars[0], &argvars[1], atype);
+ assert_error(&ga);
+ ga_clear(&ga);
+ }
+}
+
+/// "assert_match(pattern, actual[, msg])" function
+static void f_assert_match(typval_T *argvars, typval_T *rettv)
+{
+ assert_match_common(argvars, ASSERT_MATCH);
+}
+
+/// "assert_notmatch(pattern, actual[, msg])" function
+static void f_assert_notmatch(typval_T *argvars, typval_T *rettv)
+{
+ assert_match_common(argvars, ASSERT_NOTMATCH);
+}
+
// "assert_true(actual[, msg])" function
static void f_assert_true(typval_T *argvars, typval_T *rettv)
{
@@ -8087,38 +8158,6 @@ static void f_call(typval_T *argvars, typval_T *rettv)
(void)func_call(func, &argvars[1], selfdict, rettv);
}
-// "capture(command)" function
-static void f_capture(typval_T *argvars, typval_T *rettv)
-{
- int save_msg_silent = msg_silent;
- garray_T *save_capture_ga = capture_ga;
-
- if (check_secure()) {
- return;
- }
-
- garray_T capture_local;
- capture_ga = &capture_local;
- ga_init(capture_ga, (int)sizeof(char), 80);
-
- msg_silent++;
- if (argvars[0].v_type != VAR_LIST) {
- do_cmdline_cmd((char *)get_tv_string(&argvars[0]));
- } else if (argvars[0].vval.v_list != NULL) {
- for (listitem_T *li = argvars[0].vval.v_list->lv_first;
- li != NULL; li = li->li_next) {
- do_cmdline_cmd((char *)get_tv_string(&li->li_tv));
- }
- }
- msg_silent = save_msg_silent;
-
- ga_append(capture_ga, NUL);
- rettv->v_type = VAR_STRING;
- rettv->vval.v_string = capture_ga->ga_data;
-
- capture_ga = save_capture_ga;
-}
-
/*
* "ceil({float})" function
*/
@@ -8803,6 +8842,38 @@ static void f_executable(typval_T *argvars, typval_T *rettv)
|| (gettail_dir(name) != name && os_can_exe(name, NULL, false));
}
+// "execute(command)" function
+static void f_execute(typval_T *argvars, typval_T *rettv)
+{
+ int save_msg_silent = msg_silent;
+ garray_T *save_capture_ga = capture_ga;
+
+ if (check_secure()) {
+ return;
+ }
+
+ garray_T capture_local;
+ capture_ga = &capture_local;
+ ga_init(capture_ga, (int)sizeof(char), 80);
+
+ msg_silent++;
+ if (argvars[0].v_type != VAR_LIST) {
+ do_cmdline_cmd((char *)get_tv_string(&argvars[0]));
+ } else if (argvars[0].vval.v_list != NULL) {
+ for (listitem_T *li = argvars[0].vval.v_list->lv_first;
+ li != NULL; li = li->li_next) {
+ do_cmdline_cmd((char *)get_tv_string(&li->li_tv));
+ }
+ }
+ msg_silent = save_msg_silent;
+
+ ga_append(capture_ga, NUL);
+ rettv->v_type = VAR_STRING;
+ rettv->vval.v_string = capture_ga->ga_data;
+
+ capture_ga = save_capture_ga;
+}
+
/// "exepath()" function
static void f_exepath(typval_T *argvars, typval_T *rettv)
{
@@ -9917,6 +9988,50 @@ static void f_getcmdwintype(typval_T *argvars, typval_T *rettv)
rettv->vval.v_string[0] = cmdwin_type;
}
+// "getcompletion()" function
+static void f_getcompletion(typval_T *argvars, typval_T *rettv)
+{
+ char_u *pat;
+ expand_T xpc;
+ int options = WILD_KEEP_ALL | WILD_SILENT | WILD_USE_NL
+ | WILD_LIST_NOTFOUND | WILD_NO_BEEP;
+
+ if (p_wic) {
+ options |= WILD_ICASE;
+ }
+
+ ExpandInit(&xpc);
+ xpc.xp_pattern = get_tv_string(&argvars[0]);
+ xpc.xp_pattern_len = STRLEN(xpc.xp_pattern);
+ xpc.xp_context = cmdcomplete_str_to_type(get_tv_string(&argvars[1]));
+ if (xpc.xp_context == EXPAND_NOTHING) {
+ if (argvars[1].v_type == VAR_STRING) {
+ EMSG2(_(e_invarg2), argvars[1].vval.v_string);
+ } else {
+ EMSG(_(e_invarg));
+ }
+ return;
+ }
+
+ if (xpc.xp_context == EXPAND_MENUS) {
+ set_context_in_menu_cmd(&xpc, (char_u *)"menu", xpc.xp_pattern, false);
+ xpc.xp_pattern_len = STRLEN(xpc.xp_pattern);
+ }
+
+ pat = addstar(xpc.xp_pattern, xpc.xp_pattern_len, xpc.xp_context);
+ if ((rettv_list_alloc(rettv) != FAIL) && (pat != NULL)) {
+ int i;
+
+ ExpandOne(&xpc, pat, NULL, options, WILD_ALL_KEEP);
+
+ for (i = 0; i < xpc.xp_numfiles; i++) {
+ list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
+ }
+ }
+ xfree(pat);
+ ExpandCleanup(&xpc);
+}
+
/// `getcwd([{win}[, {tab}]])` function
///
/// Every scope not specified implies the currently selected scope object.
@@ -13526,11 +13641,12 @@ static void f_resolve(typval_T *argvars, typval_T *rettv)
{
char_u *v = NULL;
- v = mch_resolve_shortcut(p);
- if (v != NULL)
+ v = os_resolve_shortcut(p);
+ if (v != NULL) {
rettv->vval.v_string = v;
- else
+ } else {
rettv->vval.v_string = vim_strsave(p);
+ }
}
#else
# ifdef HAVE_READLINK
@@ -17038,6 +17154,32 @@ static void f_wildmenumode(typval_T *argvars, typval_T *rettv)
rettv->vval.v_number = 1;
}
+/// "win_getid()" function
+static void f_win_getid(typval_T *argvars, typval_T *rettv)
+{
+ rettv->vval.v_number = win_getid(argvars);
+}
+
+/// "win_gotoid()" function
+static void f_win_gotoid(typval_T *argvars, typval_T *rettv)
+{
+ rettv->vval.v_number = win_gotoid(argvars);
+}
+
+/// "win_id2tabwin()" function
+static void f_win_id2tabwin(typval_T *argvars, typval_T *rettv)
+{
+ if (rettv_list_alloc(rettv) != FAIL) {
+ win_id2tabwin(argvars, rettv->vval.v_list);
+ }
+}
+
+/// "win_id2win()" function
+static void f_win_id2win(typval_T *argvars, typval_T *rettv)
+{
+ rettv->vval.v_number = win_id2win(argvars);
+}
+
/*
* "winbufnr(nr)" function
*/
@@ -18325,7 +18467,7 @@ static void init_tv(typval_T *varp)
* caller of incompatible types: it sets *denote to TRUE if "denote"
* is not NULL or returns -1 otherwise.
*/
-static long get_tv_number(typval_T *varp)
+long get_tv_number(typval_T *varp)
{
int error = FALSE;
@@ -18886,19 +19028,6 @@ set_var (
|| tv_check_lock(v->di_tv.v_lock, name, false)) {
return;
}
- if (v->di_tv.v_type != tv->v_type
- && !((v->di_tv.v_type == VAR_STRING
- || v->di_tv.v_type == VAR_NUMBER)
- && (tv->v_type == VAR_STRING
- || tv->v_type == VAR_NUMBER))
- && !((v->di_tv.v_type == VAR_NUMBER
- || v->di_tv.v_type == VAR_FLOAT)
- && (tv->v_type == VAR_NUMBER
- || tv->v_type == VAR_FLOAT))
- ) {
- EMSG2(_("E706: Variable type mismatch for: %s"), name);
- return;
- }
// Handle setting internal v: variables separately where needed to
// prevent changing the type.
@@ -18908,7 +19037,7 @@ set_var (
if (copy || tv->v_type != VAR_STRING)
v->di_tv.vval.v_string = vim_strsave(get_tv_string(tv));
else {
- /* Take over the string to avoid an extra alloc/free. */
+ // Take over the string to avoid an extra alloc/free.
v->di_tv.vval.v_string = tv->vval.v_string;
tv->vval.v_string = NULL;
}
@@ -22344,7 +22473,10 @@ bool eval_has_provider(char *name)
} \
}
- static int has_clipboard = -1, has_python = -1, has_python3 = -1;
+ static int has_clipboard = -1;
+ static int has_python = -1;
+ static int has_python3 = -1;
+ static int has_ruby = -1;
if (!strcmp(name, "clipboard")) {
check_provider(clipboard);
@@ -22355,6 +22487,9 @@ bool eval_has_provider(char *name)
} else if (!strcmp(name, "python")) {
check_provider(python);
return has_python;
+ } else if (!strcmp(name, "ruby")) {
+ check_provider(ruby);
+ return has_ruby;
}
return false;