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.c230
1 files changed, 129 insertions, 101 deletions
diff --git a/src/nvim/eval.c b/src/nvim/eval.c
index 9553c7a7ed..d84bdfebfe 100644
--- a/src/nvim/eval.c
+++ b/src/nvim/eval.c
@@ -2266,8 +2266,8 @@ static void set_var_lval(lval_T *lp, char_u *endp, typval_T *rettv, int copy, ch
if (get_var_tv(lp->ll_name, (int)STRLEN(lp->ll_name),
&tv, &di, true, false) == OK) {
if ((di == NULL
- || (!var_check_ro(di->di_flags, lp->ll_name, false) &&
- !tv_check_lock(di->di_tv.v_lock, lp->ll_name, false)))
+ || (!var_check_ro(di->di_flags, lp->ll_name, false)
+ && !tv_check_lock(di->di_tv.v_lock, lp->ll_name, false)))
&& tv_op(&tv, rettv, op) == OK) {
set_var(lp->ll_name, &tv, false);
}
@@ -4740,13 +4740,14 @@ static int get_string_tv(char_u **arg, typval_T *rettv, int evaluate)
++name;
break;
- /* Special key, e.g.: "\<C-W>" */
- case '<': extra = trans_special(&p, name, TRUE);
+ // Special key, e.g.: "\<C-W>"
+ case '<':
+ extra = trans_special((const char_u **) &p, STRLEN(p), name, true);
if (extra != 0) {
name += extra;
break;
}
- /* FALLTHROUGH */
+ // FALLTHROUGH
default: MB_COPY_CHAR(p, name);
break;
@@ -6665,6 +6666,7 @@ static struct fst {
{ "argv", 0, 1, f_argv },
{ "asin", 1, 1, f_asin }, // WJMc
{ "assert_equal", 2, 3, f_assert_equal },
+ { "assert_exception", 1, 2, f_assert_exception },
{ "assert_false", 1, 2, f_assert_false },
{ "assert_true", 1, 2, f_assert_true },
{ "atan", 1, 1, f_atan },
@@ -7627,14 +7629,35 @@ static void f_assert_equal(typval_T *argvars, typval_T *rettv)
}
}
+/// "assert_exception(string[, msg])" function
+static void f_assert_exception(typval_T *argvars, typval_T *rettv)
+{
+ garray_T ga;
+
+ char *error = (char *)get_tv_string_chk(&argvars[0]);
+ if (vimvars[VV_EXCEPTION].vv_str == NULL) {
+ prepare_assert_error(&ga);
+ ga_concat(&ga, (char_u *)"v:exception is not set");
+ assert_error(&ga);
+ ga_clear(&ga);
+ } else if (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);
+ assert_error(&ga);
+ ga_clear(&ga);
+ }
+}
+
// Common for assert_true() and assert_false().
static void assert_bool(typval_T *argvars, bool is_true)
{
int error = (int)false;
garray_T ga;
- if ((argvars[0].v_type != VAR_NUMBER ||
- (get_tv_number_chk(&argvars[0], &error) == 0) == is_true || error)
+ if ((argvars[0].v_type != VAR_NUMBER
+ || (get_tv_number_chk(&argvars[0], &error) == 0) == is_true
+ || error)
&& (argvars[0].v_type != VAR_SPECIAL
|| (argvars[0].vval.v_special
!= (SpecialVarValue) (is_true
@@ -8669,7 +8692,11 @@ static void f_eventhandler(typval_T *argvars, typval_T *rettv)
*/
static void f_executable(typval_T *argvars, typval_T *rettv)
{
- rettv->vval.v_number = os_can_exe(get_tv_string(&argvars[0]), NULL);
+ char_u *name = get_tv_string(&argvars[0]);
+
+ // Check in $PATH and also check directly if there is a directory name
+ rettv->vval.v_number = os_can_exe(name, NULL, true)
+ || (gettail_dir(name) != name && os_can_exe(name, NULL, false));
}
/// "exepath()" function
@@ -8678,7 +8705,7 @@ static void f_exepath(typval_T *argvars, typval_T *rettv)
char_u *arg = get_tv_string(&argvars[0]);
char_u *path = NULL;
- (void)os_can_exe(arg, &path);
+ (void)os_can_exe(arg, &path, true);
rettv->v_type = VAR_STRING;
rettv->vval.v_string = path;
@@ -9798,7 +9825,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 = kCdScopeWindow;
+ CdScope scope = MIN_CD_SCOPE;
// 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.
@@ -9817,7 +9844,8 @@ static void f_getcwd(typval_T *argvars, typval_T *rettv)
rettv->vval.v_string = NULL;
// Pre-conditions and scope extraction together
- for (int i = 0; i < kCdScopeGlobal; i++) {
+ for (int i = MIN_CD_SCOPE; i < MAX_CD_SCOPE; i++) {
+ // If there is no argument there are no more scopes after it, break out.
if (argvars[i].v_type == VAR_UNKNOWN) {
break;
}
@@ -9828,34 +9856,17 @@ static void f_getcwd(typval_T *argvars, typval_T *rettv)
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;
- }
- }
-
- // Allocate and initialize the string to return.
- cwd = xmalloc(MAXPATHL);
-
- // Get the scope and numbers from the arguments
- for (int i = 0; i < MAX_CD_SCOPE; i++) {
- // If there is no argument there are no more scopes after it, break out.
- if (argvars[i].v_type == VAR_UNKNOWN) {
- break;
- }
- 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));
- goto end;
+ return;
}
}
- // If the deepest scope number is `-1` advance the scope.
+ // 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++;
}
@@ -9866,7 +9877,7 @@ static void f_getcwd(typval_T *argvars, typval_T *rettv)
tp = find_tabpage(scope_number[kCdScopeTab]);
if (!tp) {
EMSG(_("E5000: Cannot find tab number."));
- goto end;
+ return;
}
}
@@ -9876,25 +9887,29 @@ static void f_getcwd(typval_T *argvars, typval_T *rettv)
} else if (scope_number[kCdScopeWindow] >= 0) {
if (!tp) {
EMSG(_("E5001: Higher scope cannot be -1 if lower scope is >= 0."));
- goto end;
+ return;
}
if (scope_number[kCdScopeWindow] > 0) {
win = find_win_by_nr(&argvars[0], curtab);
if (!win) {
EMSG(_("E5002: Cannot find window number."));
- goto end;
+ return;
}
}
}
+ cwd = xmalloc(MAXPATHL);
+
switch (scope) {
case kCdScopeWindow:
+ assert(win);
from = win->w_localdir;
if (from) {
break;
}
case kCdScopeTab: // FALLTHROUGH
+ assert(tp);
from = tp->localdir;
if (from) {
break;
@@ -9904,7 +9919,7 @@ static void f_getcwd(typval_T *argvars, typval_T *rettv)
if (globaldir) {
from = globaldir;
} else {
- // Copy the OS path directly into output string and jump to the end.
+ // We have to copy the OS path directly into output string.
if (os_dirname(cwd, MAXPATHL) == FAIL) {
EMSG(_("E41: Could not display path."));
goto end;
@@ -9921,7 +9936,6 @@ static void f_getcwd(typval_T *argvars, typval_T *rettv)
#ifdef BACKSLASH_IN_FILENAME
slash_adjust(rettv->vval.v_string);
#endif
-
end:
xfree(cwd);
}
@@ -10173,6 +10187,7 @@ static void getpos_both(typval_T *argvars, typval_T *rettv, bool getcurpos)
list_append_number(l,
(fp != NULL) ? (varnumber_T)fp->coladd : (varnumber_T)0);
if (getcurpos) {
+ update_curswant();
list_append_number(l, curwin->w_curswant == MAXCOL
? (varnumber_T)MAXCOL
: (varnumber_T)curwin->w_curswant + 1);
@@ -10280,7 +10295,7 @@ static void f_getregtype(typval_T *argvars, typval_T *rettv)
colnr_T reglen = 0;
char buf[NUMBUFLEN + 2];
- char_u reg_type = get_reg_type(regname, &reglen);
+ MotionType reg_type = get_reg_type(regname, &reglen);
format_reg_type(reg_type, reglen, buf, ARRAY_SIZE(buf));
rettv->v_type = VAR_STRING;
@@ -10756,7 +10771,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 = kCdScopeWindow;
+ CdScope scope = MIN_CD_SCOPE;
// 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.
@@ -10772,7 +10787,7 @@ static void f_haslocaldir(typval_T *argvars, typval_T *rettv)
rettv->vval.v_number = 0;
// Pre-conditions and scope extraction together
- for (int i = 0; i < kCdScopeGlobal; i++) {
+ for (int i = MIN_CD_SCOPE; i < MAX_CD_SCOPE; i++) {
if (argvars[i].v_type == VAR_UNKNOWN) {
break;
}
@@ -10789,9 +10804,11 @@ static void f_haslocaldir(typval_T *argvars, typval_T *rettv)
}
}
- // It the deepest scope number is `-1` advance the scope by one.
+ // Normalize scope, the number of the new scope will be 0.
if (scope_number[scope] < 0) {
- ++scope;
+ // Arguments to `haslocaldir` always end at second-highest scope, so scope
+ // will always be <= `MAX_CD_SCOPE`.
+ scope++;
}
// Find the tabpage by number
@@ -10825,13 +10842,16 @@ static void f_haslocaldir(typval_T *argvars, typval_T *rettv)
switch (scope) {
case kCdScopeWindow:
+ assert(win);
rettv->vval.v_number = win->w_localdir ? 1 : 0;
break;
case kCdScopeTab:
+ assert(tp);
rettv->vval.v_number = tp->localdir ? 1 : 0;
break;
case kCdScopeGlobal:
- assert(0);
+ // The global scope never has a local directory
+ rettv->vval.v_number = 0;
break;
}
}
@@ -10866,21 +10886,22 @@ static void f_hasmapto(typval_T *argvars, typval_T *rettv)
*/
static void f_histadd(typval_T *argvars, typval_T *rettv)
{
- int histype;
+ HistoryType histype;
char_u *str;
char_u buf[NUMBUFLEN];
- rettv->vval.v_number = FALSE;
- if (check_restricted() || check_secure())
+ rettv->vval.v_number = false;
+ if (check_restricted() || check_secure()) {
return;
- str = get_tv_string_chk(&argvars[0]); /* NULL on type error */
- histype = str != NULL ? get_histtype(str) : -1;
- if (histype >= 0) {
+ }
+ str = get_tv_string_chk(&argvars[0]); // NULL on type error
+ histype = str != NULL ? get_histtype(str, STRLEN(str), false) : HIST_INVALID;
+ if (histype != HIST_INVALID) {
str = get_tv_string_buf(&argvars[1], buf);
if (*str != NUL) {
init_history();
- add_to_history(histype, str, FALSE, NUL);
- rettv->vval.v_number = TRUE;
+ add_to_history(histype, str, false, NUL);
+ rettv->vval.v_number = true;
return;
}
}
@@ -10895,20 +10916,21 @@ static void f_histdel(typval_T *argvars, typval_T *rettv)
char_u buf[NUMBUFLEN];
char_u *str;
- str = get_tv_string_chk(&argvars[0]); /* NULL on type error */
- if (str == NULL)
+ str = get_tv_string_chk(&argvars[0]); // NULL on type error
+ if (str == NULL) {
n = 0;
- else if (argvars[1].v_type == VAR_UNKNOWN)
- /* only one argument: clear entire history */
- n = clr_history(get_histtype(str));
- else if (argvars[1].v_type == VAR_NUMBER)
- /* index given: remove that entry */
- n = del_history_idx(get_histtype(str),
- (int)get_tv_number(&argvars[1]));
- else
- /* string given: remove all matching entries */
- n = del_history_entry(get_histtype(str),
- get_tv_string_buf(&argvars[1], buf));
+ } else if (argvars[1].v_type == VAR_UNKNOWN) {
+ // only one argument: clear entire history
+ n = clr_history(get_histtype(str, STRLEN(str), false));
+ } else if (argvars[1].v_type == VAR_NUMBER) {
+ // index given: remove that entry
+ n = del_history_idx(get_histtype(str, STRLEN(str), false),
+ (int) get_tv_number(&argvars[1]));
+ } else {
+ // string given: remove all matching entries
+ n = del_history_entry(get_histtype(str, STRLEN(str), false),
+ get_tv_string_buf(&argvars[1], buf));
+ }
rettv->vval.v_number = n;
}
@@ -10917,20 +10939,21 @@ static void f_histdel(typval_T *argvars, typval_T *rettv)
*/
static void f_histget(typval_T *argvars, typval_T *rettv)
{
- int type;
+ HistoryType type;
int idx;
char_u *str;
- str = get_tv_string_chk(&argvars[0]); /* NULL on type error */
- if (str == NULL)
+ str = get_tv_string_chk(&argvars[0]); // NULL on type error
+ if (str == NULL) {
rettv->vval.v_string = NULL;
- else {
- type = get_histtype(str);
- if (argvars[1].v_type == VAR_UNKNOWN)
+ } else {
+ type = get_histtype(str, STRLEN(str), false);
+ if (argvars[1].v_type == VAR_UNKNOWN) {
idx = get_history_idx(type);
- else
+ } else {
idx = (int)get_tv_number_chk(&argvars[1], NULL);
- /* -1 on type error */
+ }
+ // -1 on type error
rettv->vval.v_string = vim_strsave(get_history_entry(type, idx));
}
rettv->v_type = VAR_STRING;
@@ -10945,11 +10968,13 @@ static void f_histnr(typval_T *argvars, typval_T *rettv)
char_u *history = get_tv_string_chk(&argvars[0]);
- i = history == NULL ? HIST_CMD - 1 : get_histtype(history);
- if (i >= HIST_CMD && i < HIST_COUNT)
+ i = history == NULL ? HIST_CMD - 1 : get_histtype(history, STRLEN(history),
+ false);
+ if (i != HIST_INVALID) {
i = get_history_idx(i);
- else
+ } else {
i = -1;
+ }
rettv->vval.v_number = i;
}
@@ -11585,7 +11610,7 @@ static char **tv_to_argv(typval_T *cmd_tv, char **cmd)
assert(argl->lv_first);
const char_u *exe = get_tv_string_chk(&argl->lv_first->li_tv);
- if (!exe || !os_can_exe(exe, NULL)) {
+ if (!exe || !os_can_exe(exe, NULL, true)) {
// String is not executable
if (exe) {
EMSG2(e_jobexe, exe);
@@ -12086,8 +12111,9 @@ static void get_maparg(typval_T *argvars, typval_T *rettv, int exact)
mode = get_map_mode(&which, 0);
- keys = replace_termcodes(keys, &keys_buf, TRUE, TRUE, FALSE);
- rhs = check_map(keys, mode, exact, FALSE, abbr, &mp, &buffer_local);
+ keys = replace_termcodes(keys, STRLEN(keys), &keys_buf, true, true, false,
+ CPO_TO_CPO_FLAGS);
+ rhs = check_map(keys, mode, exact, false, abbr, &mp, &buffer_local);
xfree(keys_buf);
if (!get_dict) {
@@ -14696,11 +14722,11 @@ static void f_setreg(typval_T *argvars, typval_T *rettv)
char_u *strregname;
char_u *stropt;
bool append = false;
- char_u yank_type;
+ MotionType yank_type;
long block_len;
block_len = -1;
- yank_type = MAUTO;
+ yank_type = kMTUnknown;
strregname = get_tv_string_chk(argvars);
rettv->vval.v_number = 1; /* FAIL is default */
@@ -14717,17 +14743,17 @@ static void f_setreg(typval_T *argvars, typval_T *rettv)
return; /* type error */
for (; *stropt != NUL; ++stropt)
switch (*stropt) {
- case 'a': case 'A': /* append */
+ case 'a': case 'A': // append
append = true;
break;
- case 'v': case 'c': /* character-wise selection */
- yank_type = MCHAR;
+ case 'v': case 'c': // character-wise selection
+ yank_type = kMTCharWise;
break;
- case 'V': case 'l': /* line-wise selection */
- yank_type = MLINE;
+ case 'V': case 'l': // line-wise selection
+ yank_type = kMTLineWise;
break;
- case 'b': case Ctrl_V: /* block-wise selection */
- yank_type = MBLOCK;
+ case 'b': case Ctrl_V: // block-wise selection
+ yank_type = kMTBlockWise;
if (ascii_isdigit(stropt[1])) {
++stropt;
block_len = getdigits_long(&stropt) - 1;
@@ -15119,12 +15145,12 @@ static void do_sort_uniq(typval_T *argvars, typval_T *rettv, bool sort)
EMSG2(_(e_listarg), sort ? "sort()" : "uniq()");
} else {
l = argvars[0].vval.v_list;
- if (l == NULL ||
- tv_check_lock(l->lv_lock,
- (char_u *)(sort
- ? N_("sort() argument")
- : N_("uniq() argument")),
- true)) {
+ if (l == NULL
+ || tv_check_lock(l->lv_lock,
+ (char_u *)(sort
+ ? N_("sort() argument")
+ : N_("uniq() argument")),
+ true)) {
return;
}
rettv->vval.v_list = l;
@@ -19244,9 +19270,10 @@ void ex_function(exarg_T *eap)
if ((p[0] == 'a' && (!ASCII_ISALPHA(p[1]) || p[1] == 'p'))
|| (p[0] == 'i'
&& (!ASCII_ISALPHA(p[1]) || (p[1] == 'n'
- && (!ASCII_ISALPHA(p[2]) ||
- (p[2] == 's'))))))
+ && (!ASCII_ISALPHA(p[2])
+ || (p[2] == 's')))))) {
skip_until = vim_strsave((char_u *)".");
+ }
// Check for ":python <<EOF", ":lua <<EOF", etc.
arg = skipwhite(skiptowhite(p));
@@ -19513,11 +19540,12 @@ trans_function_name (
*pp = end;
} else {
if (!skip && !(flags & TFN_QUIET) && (fdp == NULL
- || lv.ll_dict == NULL ||
- fdp->fd_newkey == NULL))
+ || lv.ll_dict == NULL
+ || fdp->fd_newkey == NULL)) {
EMSG(_(e_funcref));
- else
+ } else {
*pp = end;
+ }
name = NULL;
}
goto theend;
@@ -20417,9 +20445,9 @@ call_user_func (
--RedrawingDisabled;
- /* when the function was aborted because of an error, return -1 */
- if ((did_emsg &&
- (fp->uf_flags & FC_ABORT)) || rettv->v_type == VAR_UNKNOWN) {
+ // when the function was aborted because of an error, return -1
+ if ((did_emsg
+ && (fp->uf_flags & FC_ABORT)) || rettv->v_type == VAR_UNKNOWN) {
clear_tv(rettv);
rettv->v_type = VAR_NUMBER;
rettv->vval.v_number = -1;