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