Merge remote-tracking branch 'vim/master'

This commit is contained in:
Kazuki Sakamoto
2018-02-13 20:52:20 -08:00
23 changed files with 493 additions and 251 deletions
+25
View File
@@ -2017,6 +2017,7 @@ argidx() Number current index in the argument list
arglistid([{winnr} [, {tabnr}]]) Number argument list id
argv({nr}) String {nr} entry of the argument list
argv() List the argument list
assert_beeps({cmd}) none assert {cmd} causes a beep
assert_equal({exp}, {act} [, {msg}])
none assert {exp} is equal to {act}
assert_exception({error} [, {msg}])
@@ -2151,6 +2152,7 @@ getbufline({expr}, {lnum} [, {end}])
List lines {lnum} to {end} of buffer {expr}
getbufvar({expr}, {varname} [, {def}])
any variable {varname} in buffer {expr}
getchangelist({expr}) List list of change list items
getchar([expr]) Number get one character from the user
getcharmod() Number modifiers for the last typed character
getcharsearch() Dict last character search
@@ -2568,6 +2570,11 @@ argv([{nr}]) The result is the {nr}th file in the argument list of the
< Without the {nr} argument a |List| with the whole |arglist| is
returned.
assert_beeps({cmd}) *assert_beeps()*
Run {cmd} and add an error message to |v:errors| if it does
NOT produce a beep or visual bell.
Also see |assert_fails()|.
*assert_equal()*
assert_equal({expected}, {actual} [, {msg}])
When {expected} and {actual} are not equal an error message is
@@ -2600,6 +2607,8 @@ assert_fails({cmd} [, {error}]) *assert_fails()*
Run {cmd} and add an error message to |v:errors| if it does
NOT produce an error.
When {error} is given it must match in |v:errmsg|.
Note that beeping is not considered an error, and some failing
commands only beep. Use |assert_beeps()| for those.
assert_false({actual} [, {msg}]) *assert_false()*
When {actual} is not false an error message is added to
@@ -4270,6 +4279,22 @@ getbufvar({expr}, {varname} [, {def}]) *getbufvar()*
:let bufmodified = getbufvar(1, "&mod")
:echo "todo myvar = " . getbufvar("todo", "myvar")
<
getchangelist({expr}) *getchangelist()*
Returns the |changelist| for the buffer {expr}. For the use
of {expr}, see |bufname()| above. If buffer {expr} doesn't
exist, an empty list is returned.
The returned list contains two entries: a list with the change
locations and the current position in the list. Each
entry in the change list is a dictionary with the following
entries:
col column number
coladd column offset for 'virtualedit'
lnum line number
If buffer {expr} is the current buffer, then the current
position refers to the position in the list. For other
buffers, it is set to the length of the list.
getchar([expr]) *getchar()*
Get a single character from the user or input stream.
If [expr] is omitted, wait until a character is available.
+1
View File
@@ -807,6 +807,7 @@ Buffers, windows and the argument list:
getbufinfo() get a list with buffer information
gettabinfo() get a list with tab page information
getwininfo() get a list with window information
getchangelist() get a list of change list entries
getjumplist() get a list of jump list entries
Command line: *command-line-functions*
+1
View File
@@ -2144,6 +2144,7 @@ test_arglist \
test_cd \
test_cdo \
test_changedtick \
test_changelist \
test_channel \
test_charsearch \
test_charsearch_utf8 \
+17 -17
View File
@@ -4493,7 +4493,7 @@ get_job_options(typval_T *tv, jobopt_T *opt, int supported, int supported2)
return OK;
if (tv->v_type != VAR_DICT)
{
EMSG(_(e_invarg));
EMSG(_(e_dictreq));
return FAIL;
}
dict = tv->vval.v_dict;
@@ -4576,7 +4576,7 @@ get_job_options(typval_T *tv, jobopt_T *opt, int supported, int supported2)
opt->jo_io_buf[part] = get_tv_number(item);
if (opt->jo_io_buf[part] <= 0)
{
EMSG2(_(e_invarg2), get_tv_string(item));
EMSG3(_(e_invargNval), hi->hi_key, get_tv_string(item));
return FAIL;
}
if (buflist_findnr(opt->jo_io_buf[part]) == NULL)
@@ -4625,7 +4625,7 @@ get_job_options(typval_T *tv, jobopt_T *opt, int supported, int supported2)
*lp = get_tv_number(item);
if (*lp < 0)
{
EMSG2(_(e_invarg2), get_tv_string(item));
EMSG3(_(e_invargNval), hi->hi_key, get_tv_string(item));
return FAIL;
}
}
@@ -4636,7 +4636,7 @@ get_job_options(typval_T *tv, jobopt_T *opt, int supported, int supported2)
opt->jo_set |= JO_CHANNEL;
if (item->v_type != VAR_CHANNEL)
{
EMSG2(_(e_invarg2), "channel");
EMSG2(_(e_invargval), "channel");
return FAIL;
}
opt->jo_channel = item->vval.v_channel;
@@ -4649,7 +4649,7 @@ get_job_options(typval_T *tv, jobopt_T *opt, int supported, int supported2)
opt->jo_callback = get_callback(item, &opt->jo_partial);
if (opt->jo_callback == NULL)
{
EMSG2(_(e_invarg2), "callback");
EMSG2(_(e_invargval), "callback");
return FAIL;
}
}
@@ -4661,7 +4661,7 @@ get_job_options(typval_T *tv, jobopt_T *opt, int supported, int supported2)
opt->jo_out_cb = get_callback(item, &opt->jo_out_partial);
if (opt->jo_out_cb == NULL)
{
EMSG2(_(e_invarg2), "out_cb");
EMSG2(_(e_invargval), "out_cb");
return FAIL;
}
}
@@ -4673,7 +4673,7 @@ get_job_options(typval_T *tv, jobopt_T *opt, int supported, int supported2)
opt->jo_err_cb = get_callback(item, &opt->jo_err_partial);
if (opt->jo_err_cb == NULL)
{
EMSG2(_(e_invarg2), "err_cb");
EMSG2(_(e_invargval), "err_cb");
return FAIL;
}
}
@@ -4685,7 +4685,7 @@ get_job_options(typval_T *tv, jobopt_T *opt, int supported, int supported2)
opt->jo_close_cb = get_callback(item, &opt->jo_close_partial);
if (opt->jo_close_cb == NULL)
{
EMSG2(_(e_invarg2), "close_cb");
EMSG2(_(e_invargval), "close_cb");
return FAIL;
}
}
@@ -4698,7 +4698,7 @@ get_job_options(typval_T *tv, jobopt_T *opt, int supported, int supported2)
never = TRUE;
else if (STRCMP(val, "auto") != 0)
{
EMSG2(_(e_invarg2), "drop");
EMSG3(_(e_invargNval), "drop", val);
return FAIL;
}
opt->jo_drop_never = never;
@@ -4711,7 +4711,7 @@ get_job_options(typval_T *tv, jobopt_T *opt, int supported, int supported2)
opt->jo_exit_cb = get_callback(item, &opt->jo_exit_partial);
if (opt->jo_exit_cb == NULL)
{
EMSG2(_(e_invarg2), "exit_cb");
EMSG2(_(e_invargval), "exit_cb");
return FAIL;
}
}
@@ -4724,7 +4724,7 @@ get_job_options(typval_T *tv, jobopt_T *opt, int supported, int supported2)
opt->jo_term_name = get_tv_string_chk(item);
if (opt->jo_term_name == NULL)
{
EMSG2(_(e_invarg2), "term_name");
EMSG2(_(e_invargval), "term_name");
return FAIL;
}
}
@@ -4735,7 +4735,7 @@ get_job_options(typval_T *tv, jobopt_T *opt, int supported, int supported2)
val = get_tv_string(item);
if (STRCMP(val, "open") != 0 && STRCMP(val, "close") != 0)
{
EMSG2(_(e_invarg2), val);
EMSG3(_(e_invargNval), "term_finish", val);
return FAIL;
}
opt->jo_set2 |= JO2_TERM_FINISH;
@@ -4759,7 +4759,7 @@ get_job_options(typval_T *tv, jobopt_T *opt, int supported, int supported2)
}
if (p == NULL)
{
EMSG2(_(e_invarg2), "term_opencmd");
EMSG2(_(e_invargval), "term_opencmd");
return FAIL;
}
}
@@ -4773,7 +4773,7 @@ get_job_options(typval_T *tv, jobopt_T *opt, int supported, int supported2)
p = opt->jo_eof_chars = get_tv_string_chk(item);
if (p == NULL)
{
EMSG2(_(e_invarg2), "term_opencmd");
EMSG2(_(e_invargval), "eof_chars");
return FAIL;
}
}
@@ -4828,7 +4828,7 @@ get_job_options(typval_T *tv, jobopt_T *opt, int supported, int supported2)
opt->jo_cwd = get_tv_string_buf_chk(item, opt->jo_cwd_buf);
if (opt->jo_cwd == NULL || !mch_isdir(opt->jo_cwd))
{
EMSG2(_(e_invarg2), "cwd");
EMSG2(_(e_invargval), "cwd");
return FAIL;
}
opt->jo_set |= JO2_CWD;
@@ -4873,7 +4873,7 @@ get_job_options(typval_T *tv, jobopt_T *opt, int supported, int supported2)
opt->jo_part = PART_OUT;
else
{
EMSG2(_(e_invarg2), val);
EMSG3(_(e_invargNval), "part", val);
return FAIL;
}
}
@@ -4893,7 +4893,7 @@ get_job_options(typval_T *tv, jobopt_T *opt, int supported, int supported2)
opt->jo_soe_buf);
if (opt->jo_stoponexit == NULL)
{
EMSG2(_(e_invarg2), "stoponexit");
EMSG2(_(e_invargval), "stoponexit");
return FAIL;
}
}
+207 -197
View File
@@ -3596,7 +3596,13 @@ eval4(char_u **arg, typval_T *rettv, int evaluate)
clear_tv(rettv);
return FAIL;
}
return typval_compare(rettv, &var2, type, type_is, ic, evaluate);
if (evaluate)
{
int ret = typval_compare(rettv, &var2, type, type_is, ic);
clear_tv(&var2);
return ret;
}
}
return OK;
@@ -8941,6 +8947,29 @@ assert_exception(typval_T *argvars)
}
}
void
assert_beeps(typval_T *argvars)
{
char_u *cmd = get_tv_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, (char_u *)"command did not beep: ");
ga_concat(&ga, cmd);
assert_error(&ga);
ga_clear(&ga);
}
suppress_errthrow = FALSE;
emsg_on_display = FALSE;
}
void
assert_fails(typval_T *argvars)
{
@@ -9068,229 +9097,210 @@ fill_assert_error(
}
}
/*
* Compare "typ1" and "typ2". Put the result in "typ1".
*/
int
typval_compare(
typval_T *typ1, /* first operand */
typval_T *typ2, /* second operand */
exptype_T type, /* operator */
int type_is, /* TRUE for "is" and "isnot" */
int ic, /* ignore case */
int evaluate)
int ic) /* ignore case */
{
int i;
varnumber_T n1, n2;
char_u *s1, *s2;
char_u buf1[NUMBUFLEN], buf2[NUMBUFLEN];
if (evaluate)
if (type_is && typ1->v_type != typ2->v_type)
{
if (type_is && typ1->v_type != typ2->v_type)
/* For "is" a different type always means FALSE, for "notis"
* it means TRUE. */
n1 = (type == TYPE_NEQUAL);
}
else if (typ1->v_type == VAR_LIST || typ2->v_type == VAR_LIST)
{
if (type_is)
{
/* For "is" a different type always means FALSE, for "notis"
* it means TRUE. */
n1 = (type == TYPE_NEQUAL);
}
else if (typ1->v_type == VAR_LIST || typ2->v_type == VAR_LIST)
{
if (type_is)
{
n1 = (typ1->v_type == typ2->v_type
&& typ1->vval.v_list == typ2->vval.v_list);
if (type == TYPE_NEQUAL)
n1 = !n1;
}
else if (typ1->v_type != typ2->v_type
|| (type != TYPE_EQUAL && type != TYPE_NEQUAL))
{
if (typ1->v_type != typ2->v_type)
EMSG(_("E691: Can only compare List with List"));
else
EMSG(_("E692: Invalid operation for List"));
clear_tv(typ1);
clear_tv(typ2);
return FAIL;
}
else
{
/* Compare two Lists for being equal or unequal. */
n1 = list_equal(typ1->vval.v_list, typ2->vval.v_list,
ic, FALSE);
if (type == TYPE_NEQUAL)
n1 = !n1;
}
}
else if (typ1->v_type == VAR_DICT || typ2->v_type == VAR_DICT)
{
if (type_is)
{
n1 = (typ1->v_type == typ2->v_type
&& typ1->vval.v_dict == typ2->vval.v_dict);
if (type == TYPE_NEQUAL)
n1 = !n1;
}
else if (typ1->v_type != typ2->v_type
|| (type != TYPE_EQUAL && type != TYPE_NEQUAL))
{
if (typ1->v_type != typ2->v_type)
EMSG(_("E735: Can only compare Dictionary with Dictionary"));
else
EMSG(_("E736: Invalid operation for Dictionary"));
clear_tv(typ1);
clear_tv(typ2);
return FAIL;
}
else
{
/* Compare two Dictionaries for being equal or unequal. */
n1 = dict_equal(typ1->vval.v_dict, typ2->vval.v_dict,
ic, FALSE);
if (type == TYPE_NEQUAL)
n1 = !n1;
}
}
else if (typ1->v_type == VAR_FUNC || typ2->v_type == VAR_FUNC
|| typ1->v_type == VAR_PARTIAL || typ2->v_type == VAR_PARTIAL)
{
if (type != TYPE_EQUAL && type != TYPE_NEQUAL)
{
EMSG(_("E694: Invalid operation for Funcrefs"));
clear_tv(typ1);
clear_tv(typ2);
return FAIL;
}
if ((typ1->v_type == VAR_PARTIAL
&& typ1->vval.v_partial == NULL)
|| (typ2->v_type == VAR_PARTIAL
&& typ2->vval.v_partial == NULL))
/* when a partial is NULL assume not equal */
n1 = FALSE;
else if (type_is)
{
if (typ1->v_type == VAR_FUNC && typ2->v_type == VAR_FUNC)
/* strings are considered the same if their value is
* the same */
n1 = tv_equal(typ1, typ2, ic, FALSE);
else if (typ1->v_type == VAR_PARTIAL
&& typ2->v_type == VAR_PARTIAL)
n1 = (typ1->vval.v_partial == typ2->vval.v_partial);
else
n1 = FALSE;
}
else
n1 = tv_equal(typ1, typ2, ic, FALSE);
n1 = (typ1->v_type == typ2->v_type
&& typ1->vval.v_list == typ2->vval.v_list);
if (type == TYPE_NEQUAL)
n1 = !n1;
}
#ifdef FEAT_FLOAT
/*
* If one of the two variables is a float, compare as a float.
* When using "=~" or "!~", always compare as string.
*/
else if ((typ1->v_type == VAR_FLOAT || typ2->v_type == VAR_FLOAT)
&& type != TYPE_MATCH && type != TYPE_NOMATCH)
else if (typ1->v_type != typ2->v_type
|| (type != TYPE_EQUAL && type != TYPE_NEQUAL))
{
float_T f1, f2;
if (typ1->v_type == VAR_FLOAT)
f1 = typ1->vval.v_float;
if (typ1->v_type != typ2->v_type)
EMSG(_("E691: Can only compare List with List"));
else
f1 = get_tv_number(typ1);
if (typ2->v_type == VAR_FLOAT)
f2 = typ2->vval.v_float;
else
f2 = get_tv_number(typ2);
n1 = FALSE;
switch (type)
{
case TYPE_EQUAL: n1 = (f1 == f2); break;
case TYPE_NEQUAL: n1 = (f1 != f2); break;
case TYPE_GREATER: n1 = (f1 > f2); break;
case TYPE_GEQUAL: n1 = (f1 >= f2); break;
case TYPE_SMALLER: n1 = (f1 < f2); break;
case TYPE_SEQUAL: n1 = (f1 <= f2); break;
case TYPE_UNKNOWN:
case TYPE_MATCH:
case TYPE_NOMATCH: break; /* avoid gcc warning */
}
}
#endif
/*
* If one of the two variables is a number, compare as a number.
* When using "=~" or "!~", always compare as string.
*/
else if ((typ1->v_type == VAR_NUMBER || typ2->v_type == VAR_NUMBER)
&& type != TYPE_MATCH && type != TYPE_NOMATCH)
{
n1 = get_tv_number(typ1);
n2 = get_tv_number(typ2);
switch (type)
{
case TYPE_EQUAL: n1 = (n1 == n2); break;
case TYPE_NEQUAL: n1 = (n1 != n2); break;
case TYPE_GREATER: n1 = (n1 > n2); break;
case TYPE_GEQUAL: n1 = (n1 >= n2); break;
case TYPE_SMALLER: n1 = (n1 < n2); break;
case TYPE_SEQUAL: n1 = (n1 <= n2); break;
case TYPE_UNKNOWN:
case TYPE_MATCH:
case TYPE_NOMATCH: break; /* avoid gcc warning */
}
EMSG(_("E692: Invalid operation for List"));
clear_tv(typ1);
return FAIL;
}
else
{
s1 = get_tv_string_buf(typ1, buf1);
s2 = get_tv_string_buf(typ2, buf2);
if (type != TYPE_MATCH && type != TYPE_NOMATCH)
i = ic ? MB_STRICMP(s1, s2) : STRCMP(s1, s2);
else
i = 0;
n1 = FALSE;
switch (type)
{
case TYPE_EQUAL: n1 = (i == 0); break;
case TYPE_NEQUAL: n1 = (i != 0); break;
case TYPE_GREATER: n1 = (i > 0); break;
case TYPE_GEQUAL: n1 = (i >= 0); break;
case TYPE_SMALLER: n1 = (i < 0); break;
case TYPE_SEQUAL: n1 = (i <= 0); break;
case TYPE_MATCH:
case TYPE_NOMATCH:
n1 = pattern_match(s2, s1, ic);
if (type == TYPE_NOMATCH)
n1 = !n1;
break;
case TYPE_UNKNOWN: break; /* avoid gcc warning */
}
/* Compare two Lists for being equal or unequal. */
n1 = list_equal(typ1->vval.v_list, typ2->vval.v_list,
ic, FALSE);
if (type == TYPE_NEQUAL)
n1 = !n1;
}
clear_tv(typ1);
clear_tv(typ2);
typ1->v_type = VAR_NUMBER;
typ1->vval.v_number = n1;
}
else if (typ1->v_type == VAR_DICT || typ2->v_type == VAR_DICT)
{
if (type_is)
{
n1 = (typ1->v_type == typ2->v_type
&& typ1->vval.v_dict == typ2->vval.v_dict);
if (type == TYPE_NEQUAL)
n1 = !n1;
}
else if (typ1->v_type != typ2->v_type
|| (type != TYPE_EQUAL && type != TYPE_NEQUAL))
{
if (typ1->v_type != typ2->v_type)
EMSG(_("E735: Can only compare Dictionary with Dictionary"));
else
EMSG(_("E736: Invalid operation for Dictionary"));
clear_tv(typ1);
return FAIL;
}
else
{
/* Compare two Dictionaries for being equal or unequal. */
n1 = dict_equal(typ1->vval.v_dict, typ2->vval.v_dict,
ic, FALSE);
if (type == TYPE_NEQUAL)
n1 = !n1;
}
}
else if (typ1->v_type == VAR_FUNC || typ2->v_type == VAR_FUNC
|| typ1->v_type == VAR_PARTIAL || typ2->v_type == VAR_PARTIAL)
{
if (type != TYPE_EQUAL && type != TYPE_NEQUAL)
{
EMSG(_("E694: Invalid operation for Funcrefs"));
clear_tv(typ1);
return FAIL;
}
if ((typ1->v_type == VAR_PARTIAL
&& typ1->vval.v_partial == NULL)
|| (typ2->v_type == VAR_PARTIAL
&& typ2->vval.v_partial == NULL))
/* when a partial is NULL assume not equal */
n1 = FALSE;
else if (type_is)
{
if (typ1->v_type == VAR_FUNC && typ2->v_type == VAR_FUNC)
/* strings are considered the same if their value is
* the same */
n1 = tv_equal(typ1, typ2, ic, FALSE);
else if (typ1->v_type == VAR_PARTIAL
&& typ2->v_type == VAR_PARTIAL)
n1 = (typ1->vval.v_partial == typ2->vval.v_partial);
else
n1 = FALSE;
}
else
n1 = tv_equal(typ1, typ2, ic, FALSE);
if (type == TYPE_NEQUAL)
n1 = !n1;
}
#ifdef FEAT_FLOAT
/*
* If one of the two variables is a float, compare as a float.
* When using "=~" or "!~", always compare as string.
*/
else if ((typ1->v_type == VAR_FLOAT || typ2->v_type == VAR_FLOAT)
&& type != TYPE_MATCH && type != TYPE_NOMATCH)
{
float_T f1, f2;
if (typ1->v_type == VAR_FLOAT)
f1 = typ1->vval.v_float;
else
f1 = get_tv_number(typ1);
if (typ2->v_type == VAR_FLOAT)
f2 = typ2->vval.v_float;
else
f2 = get_tv_number(typ2);
n1 = FALSE;
switch (type)
{
case TYPE_EQUAL: n1 = (f1 == f2); break;
case TYPE_NEQUAL: n1 = (f1 != f2); break;
case TYPE_GREATER: n1 = (f1 > f2); break;
case TYPE_GEQUAL: n1 = (f1 >= f2); break;
case TYPE_SMALLER: n1 = (f1 < f2); break;
case TYPE_SEQUAL: n1 = (f1 <= f2); break;
case TYPE_UNKNOWN:
case TYPE_MATCH:
case TYPE_NOMATCH: break; /* avoid gcc warning */
}
}
#endif
/*
* If one of the two variables is a number, compare as a number.
* When using "=~" or "!~", always compare as string.
*/
else if ((typ1->v_type == VAR_NUMBER || typ2->v_type == VAR_NUMBER)
&& type != TYPE_MATCH && type != TYPE_NOMATCH)
{
n1 = get_tv_number(typ1);
n2 = get_tv_number(typ2);
switch (type)
{
case TYPE_EQUAL: n1 = (n1 == n2); break;
case TYPE_NEQUAL: n1 = (n1 != n2); break;
case TYPE_GREATER: n1 = (n1 > n2); break;
case TYPE_GEQUAL: n1 = (n1 >= n2); break;
case TYPE_SMALLER: n1 = (n1 < n2); break;
case TYPE_SEQUAL: n1 = (n1 <= n2); break;
case TYPE_UNKNOWN:
case TYPE_MATCH:
case TYPE_NOMATCH: break; /* avoid gcc warning */
}
}
else
{
s1 = get_tv_string_buf(typ1, buf1);
s2 = get_tv_string_buf(typ2, buf2);
if (type != TYPE_MATCH && type != TYPE_NOMATCH)
i = ic ? MB_STRICMP(s1, s2) : STRCMP(s1, s2);
else
i = 0;
n1 = FALSE;
switch (type)
{
case TYPE_EQUAL: n1 = (i == 0); break;
case TYPE_NEQUAL: n1 = (i != 0); break;
case TYPE_GREATER: n1 = (i > 0); break;
case TYPE_GEQUAL: n1 = (i >= 0); break;
case TYPE_SMALLER: n1 = (i < 0); break;
case TYPE_SEQUAL: n1 = (i <= 0); break;
case TYPE_MATCH:
case TYPE_NOMATCH:
n1 = pattern_match(s2, s1, ic);
if (type == TYPE_NOMATCH)
n1 = !n1;
break;
case TYPE_UNKNOWN: break; /* avoid gcc warning */
}
}
clear_tv(typ1);
typ1->v_type = VAR_NUMBER;
typ1->vval.v_number = n1;
return OK;
}
int
typval_copy(typ1, typ2)
typval_T *typ1;
typval_T *typ2;
{
if (typ2 == NULL)
rettv_list_alloc(typ2);
if (typ1 != NULL && typ2 != NULL)
return item_copy(typ1, typ2, TRUE, 0);
return FAIL;
}
char_u *
typval_tostring(arg)
typval_T *arg;
+70 -3
View File
@@ -44,6 +44,7 @@ static void f_argc(typval_T *argvars, typval_T *rettv);
static void f_argidx(typval_T *argvars, typval_T *rettv);
static void f_arglistid(typval_T *argvars, typval_T *rettv);
static void f_argv(typval_T *argvars, typval_T *rettv);
static void f_assert_beeps(typval_T *argvars, typval_T *rettv);
static void f_assert_equal(typval_T *argvars, typval_T *rettv);
static void f_assert_exception(typval_T *argvars, typval_T *rettv);
static void f_assert_fails(typval_T *argvars, typval_T *rettv);
@@ -164,6 +165,7 @@ static void f_get(typval_T *argvars, typval_T *rettv);
static void f_getbufinfo(typval_T *argvars, typval_T *rettv);
static void f_getbufline(typval_T *argvars, typval_T *rettv);
static void f_getbufvar(typval_T *argvars, typval_T *rettv);
static void f_getchangelist(typval_T *argvars, typval_T *rettv);
static void f_getchar(typval_T *argvars, typval_T *rettv);
static void f_getcharmod(typval_T *argvars, typval_T *rettv);
static void f_getcharsearch(typval_T *argvars, typval_T *rettv);
@@ -483,6 +485,7 @@ static struct fst
#ifdef FEAT_FLOAT
{"asin", 1, 1, f_asin}, /* WJMc */
#endif
{"assert_beeps", 1, 2, f_assert_beeps},
{"assert_equal", 2, 3, f_assert_equal},
{"assert_exception", 1, 2, f_assert_exception},
{"assert_fails", 1, 2, f_assert_fails},
@@ -605,6 +608,7 @@ static struct fst
{"getbufinfo", 0, 1, f_getbufinfo},
{"getbufline", 2, 3, f_getbufline},
{"getbufvar", 2, 3, f_getbufvar},
{"getchangelist", 1, 1, f_getchangelist},
{"getchar", 0, 1, f_getchar},
{"getcharmod", 0, 0, f_getcharmod},
{"getcharsearch", 0, 0, f_getcharsearch},
@@ -1274,6 +1278,15 @@ f_argv(typval_T *argvars, typval_T *rettv)
alist_name(&ARGLIST[idx]), -1);
}
/*
* "assert_beeps(cmd [, error])" function
*/
static void
f_assert_beeps(typval_T *argvars, typval_T *rettv UNUSED)
{
assert_beeps(argvars);
}
/*
* "assert_equal(expected, actual[, msg])" function
*/
@@ -4335,6 +4348,61 @@ f_getbufvar(typval_T *argvars, typval_T *rettv)
--emsg_off;
}
/*
* "getchangelist()" function
*/
static void
f_getchangelist(typval_T *argvars, typval_T *rettv)
{
#ifdef FEAT_JUMPLIST
buf_T *buf;
int i;
list_T *l;
dict_T *d;
#endif
if (rettv_list_alloc(rettv) != OK)
return;
#ifdef FEAT_JUMPLIST
(void)get_tv_number(&argvars[0]); /* issue errmsg if type error */
++emsg_off;
buf = get_buf_tv(&argvars[0], FALSE);
--emsg_off;
if (buf == NULL)
return;
l = list_alloc();
if (l == NULL)
return;
if (list_append_list(rettv->vval.v_list, l) == FAIL)
return;
/*
* The current window change list index tracks only the position in the
* current buffer change list. For other buffers, use the change list
* length as the current index.
*/
list_append_number(rettv->vval.v_list,
(varnumber_T)((buf == curwin->w_buffer)
? curwin->w_changelistidx : buf->b_changelistlen));
for (i = 0; i < buf->b_changelistlen; ++i)
{
if (buf->b_changelist[i].lnum == 0)
continue;
if ((d = dict_alloc()) == NULL)
return;
if (list_append_dict(l, d) == FAIL)
return;
dict_add_nr_str(d, "lnum", (long)buf->b_changelist[i].lnum, NULL);
dict_add_nr_str(d, "col", (long)buf->b_changelist[i].col, NULL);
# ifdef FEAT_VIRTUALEDIT
dict_add_nr_str(d, "coladd", (long)buf->b_changelist[i].coladd, NULL);
# endif
}
#endif
}
/*
* "getchar()" function
*/
@@ -4854,13 +4922,12 @@ f_getjumplist(typval_T *argvars, typval_T *rettv)
return;
list_append_number(rettv->vval.v_list, (varnumber_T)wp->w_jumplistidx);
cleanup_jumplist(wp);
cleanup_jumplist(wp, TRUE);
for (i = 0; i < wp->w_jumplistlen; ++i)
{
if (wp->w_jumplist[i].fmark.mark.lnum == 0)
continue;
if (wp->w_jumplist[i].fmark.fnum == 0)
fname2fnum(&wp->w_jumplist[i]);
if ((d = dict_alloc()) == NULL)
return;
if (list_append_dict(l, d) == FAIL)
+1 -1
View File
@@ -6918,7 +6918,7 @@ fix_help_buffer(void)
copy_option_part(&p, NameBuff, MAXPATHL, ",");
mustfree = FALSE;
rt = vim_getenv((char_u *)"VIMRUNTIME", &mustfree);
if (fullpathcmp(rt, NameBuff, FALSE) != FPC_SAME)
if (rt != NULL && fullpathcmp(rt, NameBuff, FALSE) != FPC_SAME)
{
int fcount;
char_u **fnames;
+12 -15
View File
@@ -988,23 +988,20 @@ debuggy_find(
}
else
{
typval_T val3;
if (typval_copy(bp->dbg_val, &val3) == OK)
if (typval_compare(tv, bp->dbg_val, TYPE_EQUAL,
TRUE, FALSE) == OK
&& tv->vval.v_number == FALSE)
{
if (typval_compare(tv, &val3, TYPE_EQUAL,
TRUE, FALSE, TRUE) == OK
&& tv->vval.v_number == FALSE)
{
typval_T *v;
typval_T *v;
line = TRUE;
debug_oldval = typval_tostring(bp->dbg_val);
v = eval_expr(bp->dbg_name, NULL);
debug_newval = typval_tostring(v);
free_tv(bp->dbg_val);
bp->dbg_val = v;
}
line = TRUE;
debug_oldval = typval_tostring(bp->dbg_val);
/* Need to evaluate again, typval_compare() overwrites
* "tv". */
v = eval_expr(bp->dbg_name, NULL);
debug_newval = typval_tostring(v);
free_tv(bp->dbg_val);
bp->dbg_val = v;
}
free_tv(tv);
}
+11 -1
View File
@@ -2887,8 +2887,18 @@ do_one_cmd(
}
#endif
/* The :try command saves the emsg_silent flag, reset it here when
* ":silent! try" was used, it should only apply to :try itself. */
if (ea.cmdidx == CMD_try && did_esilent > 0)
{
emsg_silent -= did_esilent;
if (emsg_silent < 0)
emsg_silent = 0;
did_esilent = 0;
}
/*
* 7. Switch on command name.
* 7. Execute the command.
*
* The "ea" structure holds the arguments that can be used.
*/
+3
View File
@@ -181,6 +181,7 @@ EXTERN dict_T globvardict; /* Dictionary with g: variables */
EXTERN int did_emsg; /* set by emsg() when the message
is displayed or thrown */
#ifdef FEAT_EVAL
EXTERN int called_vim_beep; /* set if vim_beep() is called */
EXTERN int did_uncaught_emsg; /* emsg() was called and did not
cause an exception */
#endif
@@ -1441,6 +1442,8 @@ EXTERN char_u e_interr[] INIT(= N_("Interrupted"));
EXTERN char_u e_invaddr[] INIT(= N_("E14: Invalid address"));
EXTERN char_u e_invarg[] INIT(= N_("E474: Invalid argument"));
EXTERN char_u e_invarg2[] INIT(= N_("E475: Invalid argument: %s"));
EXTERN char_u e_invargval[] INIT(= N_("E475: Invalid value for argument %s"));
EXTERN char_u e_invargNval[] INIT(= N_("E475: Invalid value for argument %s: %s"));
#ifdef FEAT_EVAL
EXTERN char_u e_invexpr2[] INIT(= N_("E15: Invalid expression: %s"));
#endif
+19 -6
View File
@@ -221,7 +221,7 @@ movemark(int count)
pos_T *pos;
xfmark_T *jmp;
cleanup_jumplist(curwin);
cleanup_jumplist(curwin, TRUE);
if (curwin->w_jumplistlen == 0) /* nothing to jump to */
return (pos_T *)NULL;
@@ -891,7 +891,7 @@ ex_jumps(exarg_T *eap UNUSED)
int i;
char_u *name;
cleanup_jumplist(curwin);
cleanup_jumplist(curwin, TRUE);
/* Highlight title */
MSG_PUTS_TITLE(_("\n jump line col file/text"));
@@ -899,8 +899,6 @@ ex_jumps(exarg_T *eap UNUSED)
{
if (curwin->w_jumplist[i].fmark.mark.lnum != 0)
{
if (curwin->w_jumplist[i].fmark.fnum == 0)
fname2fnum(&curwin->w_jumplist[i]);
name = fm_getname(&curwin->w_jumplist[i].fmark, 16);
if (name == NULL) /* file name not available */
continue;
@@ -1303,13 +1301,28 @@ mark_col_adjust(
/*
* When deleting lines, this may create duplicate marks in the
* jumplist. They will be removed here for the specified window.
* When "loadfiles" is TRUE first ensure entries have the "fnum" field set
* (this may be a bit slow).
*/
void
cleanup_jumplist(win_T *wp)
cleanup_jumplist(win_T *wp, int loadfiles)
{
int i;
int from, to;
if (loadfiles)
{
/* If specified, load all the files from the jump list. This is
* needed to properly clean up duplicate entries, but will take some
* time. */
for (i = 0; i < wp->w_jumplistlen; ++i)
{
if ((wp->w_jumplist[i].fmark.fnum == 0) &&
(wp->w_jumplist[i].fmark.mark.lnum != 0))
fname2fnum(&wp->w_jumplist[i]);
}
}
to = 0;
for (from = 0; from < wp->w_jumplistlen; ++from)
{
@@ -1738,7 +1751,7 @@ write_viminfo_filemarks(FILE *fp)
/* Write the jumplist with -' */
fputs(_("\n# Jumplist (newest first):\n"), fp);
setpcmark(); /* add current cursor position */
cleanup_jumplist(curwin);
cleanup_jumplist(curwin, FALSE);
vi_idx = 0;
idx = curwin->w_jumplistlen - 1;
for (i = 0; i < JUMPLISTSIZE; ++i)
+7 -2
View File
@@ -3694,6 +3694,10 @@ beep_flush(void)
vim_beep(
unsigned val) /* one of the BO_ values, e.g., BO_OPER */
{
#ifdef FEAT_EVAL
called_vim_beep = TRUE;
#endif
if (emsg_silent == 0)
{
if (!((bo_flags & val) || (bo_flags & BO_ALL)))
@@ -3724,8 +3728,9 @@ vim_beep(
#endif
}
/* When 'verbose' is set and we are sourcing a script or executing a
* function give the user a hint where the beep comes from. */
/* When 'debug' contains "beep" produce a message. If we are sourcing
* a script or executing a function give the user a hint where the beep
* comes from. */
if (vim_strchr(p_debug, 'e') != NULL)
{
msg_source(HL_ATTR(HLF_W));
+2 -2
View File
@@ -127,10 +127,10 @@ void assert_inrange(typval_T *argvars);
void assert_bool(typval_T *argvars, int isTrue);
void assert_report(typval_T *argvars);
void assert_exception(typval_T *argvars);
void assert_beeps(typval_T *argvars);
void assert_fails(typval_T *argvars);
void fill_assert_error(garray_T *gap, typval_T *opt_msg_tv, char_u *exp_str, typval_T *exp_tv, typval_T *got_tv, assert_type_T atype);
int typval_compare(typval_T *typ1, typval_T *typ2, exptype_T type, int type_is, int ic, int evaluate);
int typval_copy(typval_T *typ1, typval_T *typ2);
int typval_compare(typval_T *typ1, typval_T *typ2, exptype_T type, int type_is, int ic);
char_u *typval_tostring(typval_T *arg);
int var_exists(char_u *var);
int modify_fname(char_u *src, int *usedlen, char_u **fnamep, char_u **bufp, int *fnamelen);
+1 -1
View File
@@ -24,7 +24,7 @@ void mark_adjust_nofold(linenr_T line1, linenr_T line2, long amount, long amount
void mark_col_adjust(linenr_T lnum, colnr_T mincol, long lnum_amount, long col_amount);
void copy_jumplist(win_T *from, win_T *to);
void free_jumplist(win_T *wp);
void cleanup_jumplist(win_T *wp);
void cleanup_jumplist(win_T *wp, int loadfiles);
void set_last_cursor(win_T *win);
void free_all_marks(void);
int read_viminfo_filemark(vir_T *virp, int force);
+6 -1
View File
@@ -5585,9 +5585,14 @@ regmatch(
{
#ifdef FEAT_MBYTE
if (has_mbyte)
{
char_u *line =
reg_getline(behind_pos.rs_u.pos.lnum);
rp->rs_un.regsave.rs_u.pos.col -=
(*mb_head_off)(regline, regline
(*mb_head_off)(line, line
+ rp->rs_un.regsave.rs_u.pos.col - 1) + 1;
}
else
#endif
--rp->rs_un.regsave.rs_u.pos.col;
+5
View File
@@ -1176,6 +1176,11 @@ win_update(win_T *wp)
*/
if (term_update_window(wp) == OK)
{
# ifdef FEAT_MENU
/* Draw the window toolbar, if there is one. */
if (winbar_height(wp) > 0)
redraw_win_toolbar(wp);
# endif
wp->w_redr_type = 0;
return;
}
+8 -5
View File
@@ -475,9 +475,12 @@ term_start(typval_T *argvar, jobopt_T *opt, int forceit)
channel_set_nonblock(term->tl_job->jv_channel, PART_IN);
#ifdef FEAT_AUTOCMD
++curbuf->b_locked;
apply_autocmds(EVENT_BUFWINENTER, NULL, NULL, FALSE, curbuf);
--curbuf->b_locked;
if (!opt->jo_hidden)
{
++curbuf->b_locked;
apply_autocmds(EVENT_BUFWINENTER, NULL, NULL, FALSE, curbuf);
--curbuf->b_locked;
}
#endif
if (old_curbuf != NULL)
@@ -2400,8 +2403,8 @@ term_update_window(win_T *wp)
else
pos.col = 0;
screen_line(wp->w_winrow + pos.row, wp->w_wincol,
pos.col, wp->w_width, FALSE);
screen_line(wp->w_winrow + pos.row + winbar_height(wp),
wp->w_wincol, pos.col, wp->w_width, FALSE);
}
term->tl_dirty_row_start = MAX_ROW;
term->tl_dirty_row_end = 0;
+1
View File
@@ -75,6 +75,7 @@ NEW_TESTS = test_arabic.res \
test_breakindent.res \
test_bufwintabinfo.res \
test_cdo.res \
test_changelist.res \
test_channel.res \
test_charsearch.res \
test_cindent.res \
+10
View File
@@ -111,6 +111,16 @@ func Test_assert_fail_fails()
call remove(v:errors, 0)
endfunc
func Test_assert_beeps()
new
call assert_beeps('normal h')
call assert_beeps('normal 0')
call assert_match("command did not beep: normal 0", v:errors[0])
call remove(v:errors, 0)
bwipe
endfunc
func Test_assert_inrange()
call assert_inrange(7, 7, 7)
call assert_inrange(5, 7, 5)
+48
View File
@@ -0,0 +1,48 @@
" Tests for the changelist functionality
" Tests for the getchangelist() function
func Test_getchangelist()
if !has("jumplist")
return
endif
bwipe!
enew
call assert_equal([], getchangelist(10))
call assert_equal([[], 0], getchangelist('%'))
call writefile(['line1', 'line2', 'line3'], 'Xfile1.txt')
call writefile(['line1', 'line2', 'line3'], 'Xfile2.txt')
edit Xfile1.txt
exe "normal 1Goline\<C-G>u1.1"
exe "normal 3Goline\<C-G>u2.1"
exe "normal 5Goline\<C-G>u3.1"
normal g;
call assert_equal([[
\ {'lnum' : 2, 'col' : 4, 'coladd' : 0},
\ {'lnum' : 4, 'col' : 4, 'coladd' : 0},
\ {'lnum' : 6, 'col' : 4, 'coladd' : 0}], 2],
\ getchangelist('%'))
hide edit Xfile2.txt
exe "normal 1GOline\<C-G>u1.0"
exe "normal 2Goline\<C-G>u2.0"
call assert_equal([[
\ {'lnum' : 1, 'col' : 6, 'coladd' : 0},
\ {'lnum' : 3, 'col' : 6, 'coladd' : 0}], 2],
\ getchangelist('%'))
hide enew
call assert_equal([[
\ {'lnum' : 2, 'col' : 4, 'coladd' : 0},
\ {'lnum' : 4, 'col' : 4, 'coladd' : 0},
\ {'lnum' : 6, 'col' : 4, 'coladd' : 0}], 3], getchangelist(2))
call assert_equal([[
\ {'lnum' : 1, 'col' : 6, 'coladd' : 0},
\ {'lnum' : 3, 'col' : 6, 'coladd' : 0}], 2], getchangelist(3))
bwipe!
call delete('Xfile1.txt')
call delete('Xfile2.txt')
endfunc
+14
View File
@@ -11,3 +11,17 @@ endfunction
func Test_catch_return_with_error()
call assert_equal(1, s:foo())
endfunc
func Test_nocatch_restore_silent_emsg()
silent! try
throw 1
catch
endtry
echoerr 'wrong'
let c1 = nr2char(screenchar(&lines, 1))
let c2 = nr2char(screenchar(&lines, 2))
let c3 = nr2char(screenchar(&lines, 3))
let c4 = nr2char(screenchar(&lines, 4))
let c5 = nr2char(screenchar(&lines, 5))
call assert_equal('wrong', c1 . c2 . c3 . c4 . c5)
endfunc
+2
View File
@@ -2177,6 +2177,8 @@ endfunc
func! Test_normal45_drop()
if !has('dnd')
" The ~ register does not exist
call assert_beeps('norm! "~')
return
endif
+22
View File
@@ -786,6 +786,28 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
1520,
/**/
1519,
/**/
1518,
/**/
1517,
/**/
1516,
/**/
1515,
/**/
1514,
/**/
1513,
/**/
1512,
/**/
1511,
/**/
1510,
/**/
1509,
/**/