From b48e96f61c87a64e38e3ac50732c92a84a4833b8 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Tue, 13 Feb 2018 12:26:14 +0100 Subject: [PATCH 01/11] patch 8.0.1510: cannot test if a command causes a beep Problem: Cannot test if a command causes a beep. Solution: Add assert_beeps(). --- runtime/doc/eval.txt | 8 ++++++++ src/eval.c | 23 +++++++++++++++++++++++ src/evalfunc.c | 11 +++++++++++ src/globals.h | 1 + src/misc1.c | 9 +++++++-- src/proto/eval.pro | 1 + src/testdir/test_assert.vim | 10 ++++++++++ src/testdir/test_normal.vim | 2 ++ src/version.c | 2 ++ 9 files changed, 65 insertions(+), 2 deletions(-) diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt index 9158f3850a..8f14ddd321 100644 --- a/runtime/doc/eval.txt +++ b/runtime/doc/eval.txt @@ -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}]) @@ -2568,6 +2569,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 +2606,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 diff --git a/src/eval.c b/src/eval.c index 2c93e4ec4b..b1f7a86061 100644 --- a/src/eval.c +++ b/src/eval.c @@ -8941,6 +8941,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) { diff --git a/src/evalfunc.c b/src/evalfunc.c index 3977944ca3..959be0cf8e 100644 --- a/src/evalfunc.c +++ b/src/evalfunc.c @@ -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); @@ -483,6 +484,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}, @@ -1274,6 +1276,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 */ diff --git a/src/globals.h b/src/globals.h index 1b2b1e8bf1..2504d2ec4b 100644 --- a/src/globals.h +++ b/src/globals.h @@ -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 diff --git a/src/misc1.c b/src/misc1.c index 821869aa32..e639fbe41b 100644 --- a/src/misc1.c +++ b/src/misc1.c @@ -3688,6 +3688,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))) @@ -3718,8 +3722,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)); diff --git a/src/proto/eval.pro b/src/proto/eval.pro index 855946ce29..e3e4a532bc 100644 --- a/src/proto/eval.pro +++ b/src/proto/eval.pro @@ -127,6 +127,7 @@ 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); diff --git a/src/testdir/test_assert.vim b/src/testdir/test_assert.vim index 8359eb11c8..29c853409e 100644 --- a/src/testdir/test_assert.vim +++ b/src/testdir/test_assert.vim @@ -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) diff --git a/src/testdir/test_normal.vim b/src/testdir/test_normal.vim index 27c589783a..2d1446bfd6 100644 --- a/src/testdir/test_normal.vim +++ b/src/testdir/test_normal.vim @@ -2177,6 +2177,8 @@ endfunc func! Test_normal45_drop() if !has('dnd') + " The ~ register does not exist + call assert_beeps('norm! "~') return endif diff --git a/src/version.c b/src/version.c index beffe2a861..7028ad39c4 100644 --- a/src/version.c +++ b/src/version.c @@ -771,6 +771,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 1510, /**/ 1509, /**/ From 3198870137df64214317151726648af8e56f1729 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Tue, 13 Feb 2018 12:57:42 +0100 Subject: [PATCH 02/11] patch 8.0.1511: some code for the debugger watch expression is clumsy Problem: Some code for the debugger watch expression is clumsy. Solution: Clean up the code. --- src/eval.c | 381 ++++++++++++++++++++++----------------------- src/ex_cmds2.c | 27 ++-- src/proto/eval.pro | 3 +- src/version.c | 2 + 4 files changed, 199 insertions(+), 214 deletions(-) diff --git a/src/eval.c b/src/eval.c index b1f7a86061..e5c1dbf88c 100644 --- a/src/eval.c +++ b/src/eval.c @@ -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; @@ -9091,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; diff --git a/src/ex_cmds2.c b/src/ex_cmds2.c index c36435cc17..6476d55169 100644 --- a/src/ex_cmds2.c +++ b/src/ex_cmds2.c @@ -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); } diff --git a/src/proto/eval.pro b/src/proto/eval.pro index e3e4a532bc..ba7dcec59c 100644 --- a/src/proto/eval.pro +++ b/src/proto/eval.pro @@ -130,8 +130,7 @@ 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); diff --git a/src/version.c b/src/version.c index 7028ad39c4..a9643caea8 100644 --- a/src/version.c +++ b/src/version.c @@ -771,6 +771,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 1511, /**/ 1510, /**/ From e4db7aedab65abadcc84c78e7a10ec7bb62f11cf Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Tue, 13 Feb 2018 13:12:11 +0100 Subject: [PATCH 03/11] patch 8.0.1512: warning for possibly using NULL pointer Problem: Warning for possibly using NULL pointer. (Coverity) Solution: Skip using the pointer if it's NULL. --- src/ex_cmds.c | 2 +- src/version.c | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/ex_cmds.c b/src/ex_cmds.c index 788e9eb828..a4d6221b01 100644 --- a/src/ex_cmds.c +++ b/src/ex_cmds.c @@ -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; diff --git a/src/version.c b/src/version.c index a9643caea8..965df225a2 100644 --- a/src/version.c +++ b/src/version.c @@ -771,6 +771,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 1512, /**/ 1511, /**/ From 486797413791f6be12dcec6e5faf4f952e4647ae Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Tue, 13 Feb 2018 13:33:29 +0100 Subject: [PATCH 04/11] patch 8.0.1513: the jumplist is not always properly cleaned up Problem: The jumplist is not always properly cleaned up. Solution: Call fname2fnum() before cleanup_jumplist(). (Yegappan Lakshmanan) --- src/evalfunc.c | 5 ++--- src/mark.c | 25 +++++++++++++++++++------ src/proto/mark.pro | 2 +- src/version.c | 2 ++ 4 files changed, 24 insertions(+), 10 deletions(-) diff --git a/src/evalfunc.c b/src/evalfunc.c index 959be0cf8e..7ea106bf65 100644 --- a/src/evalfunc.c +++ b/src/evalfunc.c @@ -4858,13 +4858,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) diff --git a/src/mark.c b/src/mark.c index 9ebc9c24c4..dd714d800d 100644 --- a/src/mark.c +++ b/src/mark.c @@ -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) diff --git a/src/proto/mark.pro b/src/proto/mark.pro index aa6f44efcc..448b452739 100644 --- a/src/proto/mark.pro +++ b/src/proto/mark.pro @@ -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); diff --git a/src/version.c b/src/version.c index 965df225a2..e4f6f968c9 100644 --- a/src/version.c +++ b/src/version.c @@ -771,6 +771,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 1513, /**/ 1512, /**/ From 07ad816525da67cab3c0db21d1286d221dbc7477 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Tue, 13 Feb 2018 13:59:59 +0100 Subject: [PATCH 05/11] patch 8.0.1514: getting the list of changes is not easy Problem: Getting the list of changes is not easy. Solution: Add the getchangelist() function. (Yegappan Lakshmanan, closes #2634) --- runtime/doc/eval.txt | 17 +++++++++++ runtime/doc/usr_41.txt | 1 + src/Makefile | 1 + src/evalfunc.c | 54 +++++++++++++++++++++++++++++++++ src/testdir/Make_all.mak | 1 + src/testdir/test_changelist.vim | 48 +++++++++++++++++++++++++++++ src/version.c | 2 ++ 7 files changed, 124 insertions(+) create mode 100644 src/testdir/test_changelist.vim diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt index 8f14ddd321..87c84bbc53 100644 --- a/runtime/doc/eval.txt +++ b/runtime/doc/eval.txt @@ -2152,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 @@ -4278,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. diff --git a/runtime/doc/usr_41.txt b/runtime/doc/usr_41.txt index 590fde4827..ccf59d6176 100644 --- a/runtime/doc/usr_41.txt +++ b/runtime/doc/usr_41.txt @@ -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* diff --git a/src/Makefile b/src/Makefile index 7cd501e9b8..f814c83b27 100644 --- a/src/Makefile +++ b/src/Makefile @@ -2127,6 +2127,7 @@ test_arglist \ test_cd \ test_cdo \ test_changedtick \ + test_changelist \ test_channel \ test_charsearch \ test_charsearch_utf8 \ diff --git a/src/evalfunc.c b/src/evalfunc.c index 7ea106bf65..daef9a8c97 100644 --- a/src/evalfunc.c +++ b/src/evalfunc.c @@ -165,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); @@ -607,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}, @@ -4346,6 +4348,58 @@ 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 + buf = find_buffer(&argvars[0]); + 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 */ diff --git a/src/testdir/Make_all.mak b/src/testdir/Make_all.mak index 2d98fa6a11..e3230c5540 100644 --- a/src/testdir/Make_all.mak +++ b/src/testdir/Make_all.mak @@ -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 \ diff --git a/src/testdir/test_changelist.vim b/src/testdir/test_changelist.vim new file mode 100644 index 0000000000..0880fce840 --- /dev/null +++ b/src/testdir/test_changelist.vim @@ -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(bufnr('%'))) + + call writefile(['line1', 'line2', 'line3'], 'Xfile1.txt') + call writefile(['line1', 'line2', 'line3'], 'Xfile2.txt') + + edit Xfile1.txt + exe "normal 1Goline\u1.1" + exe "normal 3Goline\u2.1" + exe "normal 5Goline\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(bufnr('%'))) + + hide edit Xfile2.txt + exe "normal 1GOline\u1.0" + exe "normal 2Goline\u2.0" + call assert_equal([[ + \ {'lnum' : 1, 'col' : 6, 'coladd' : 0}, + \ {'lnum' : 3, 'col' : 6, 'coladd' : 0}], 2], + \ getchangelist(bufnr('%'))) + 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 diff --git a/src/version.c b/src/version.c index e4f6f968c9..adedd8541e 100644 --- a/src/version.c +++ b/src/version.c @@ -771,6 +771,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 1514, /**/ 1513, /**/ From ab5e7c3deb40328e1c7d40534ed8cd9da47a92f8 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Tue, 13 Feb 2018 14:07:18 +0100 Subject: [PATCH 06/11] patch 8.0.1515: BufWinEnter event fired when opening hidden terminal Problem: BufWinEnter event fired when opening hidden terminal. Solution: Do not fire BufWinEnter when the terminal is midden and does not open a window. (Kenta Sato, closes #2636) --- src/terminal.c | 9 ++++++--- src/version.c | 2 ++ 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/terminal.c b/src/terminal.c index 6b8d35394e..eca9f1bd86 100644 --- a/src/terminal.c +++ b/src/terminal.c @@ -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) diff --git a/src/version.c b/src/version.c index adedd8541e..52479de74c 100644 --- a/src/version.c +++ b/src/version.c @@ -771,6 +771,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 1515, /**/ 1514, /**/ From b3292fa2d362b064ff8a115fc0ad794c1f1265d7 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Tue, 13 Feb 2018 15:17:58 +0100 Subject: [PATCH 07/11] patch 8.0.1516: errors for job options are not very specific Problem: Errors for job options are not very specific. Solution: Add more specific error messages. --- src/channel.c | 34 +++++++++++++++++----------------- src/globals.h | 2 ++ src/version.c | 2 ++ 3 files changed, 21 insertions(+), 17 deletions(-) diff --git a/src/channel.c b/src/channel.c index 77df42dd92..93c809ca63 100644 --- a/src/channel.c +++ b/src/channel.c @@ -4458,7 +4458,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; @@ -4541,7 +4541,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) @@ -4590,7 +4590,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; } } @@ -4601,7 +4601,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; @@ -4614,7 +4614,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; } } @@ -4626,7 +4626,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; } } @@ -4638,7 +4638,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; } } @@ -4650,7 +4650,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; } } @@ -4663,7 +4663,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; @@ -4676,7 +4676,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; } } @@ -4689,7 +4689,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; } } @@ -4700,7 +4700,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; @@ -4724,7 +4724,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; } } @@ -4738,7 +4738,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; } } @@ -4793,7 +4793,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; @@ -4838,7 +4838,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; } } @@ -4858,7 +4858,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; } } diff --git a/src/globals.h b/src/globals.h index 2504d2ec4b..225e78a654 100644 --- a/src/globals.h +++ b/src/globals.h @@ -1437,6 +1437,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 diff --git a/src/version.c b/src/version.c index 52479de74c..9e1983342e 100644 --- a/src/version.c +++ b/src/version.c @@ -771,6 +771,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 1516, /**/ 1515, /**/ From bc197195b097707d08fd44a476dbc374366504cb Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Tue, 13 Feb 2018 16:35:06 +0100 Subject: [PATCH 08/11] patch 8.0.1517: invalid memory acces with pattern using look-behind match Problem: Invalid memory acces with pattern using look-behind match. (Dominique Pelle) Solution: Get a pointer to the right line. --- src/regexp.c | 7 ++++++- src/version.c | 2 ++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/regexp.c b/src/regexp.c index d07391eefb..b1cad99c33 100644 --- a/src/regexp.c +++ b/src/regexp.c @@ -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; diff --git a/src/version.c b/src/version.c index 9e1983342e..931037d3d3 100644 --- a/src/version.c +++ b/src/version.c @@ -771,6 +771,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 1517, /**/ 1516, /**/ From 2be57331524e93da52a0663f4a334d21c05123bb Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Tue, 13 Feb 2018 18:05:18 +0100 Subject: [PATCH 09/11] patch 8.0.1518: error messages suppressed after ":silent! try" Problem: Error messages suppressed after ":silent! try". (Ben Reilly) Solution: Restore emsg_silent before executing :try. (closes #2531) --- src/ex_docmd.c | 12 +++++++++++- src/testdir/test_eval_stuff.vim | 14 ++++++++++++++ src/version.c | 2 ++ 3 files changed, 27 insertions(+), 1 deletion(-) diff --git a/src/ex_docmd.c b/src/ex_docmd.c index 5825bf1d1b..b923980e35 100644 --- a/src/ex_docmd.c +++ b/src/ex_docmd.c @@ -2880,8 +2880,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. */ diff --git a/src/testdir/test_eval_stuff.vim b/src/testdir/test_eval_stuff.vim index 92e1ec5335..12222303d3 100644 --- a/src/testdir/test_eval_stuff.vim +++ b/src/testdir/test_eval_stuff.vim @@ -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 diff --git a/src/version.c b/src/version.c index 931037d3d3..92fd162fa4 100644 --- a/src/version.c +++ b/src/version.c @@ -771,6 +771,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 1518, /**/ 1517, /**/ From 341a64c9cabff08e4a7dc8cd932a598e12134457 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Tue, 13 Feb 2018 19:21:17 +0100 Subject: [PATCH 10/11] patch 8.0.1519: getchangelist() does not use argument as bufname() Problem: Getchangelist() does not use argument as bufname(). Solution: Use get_buf_tv(). (Yegappan Lakshmanan, closes #2641) --- src/evalfunc.c | 5 ++++- src/testdir/test_changelist.vim | 6 +++--- src/version.c | 2 ++ 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/evalfunc.c b/src/evalfunc.c index daef9a8c97..57929d6d79 100644 --- a/src/evalfunc.c +++ b/src/evalfunc.c @@ -4365,7 +4365,10 @@ f_getchangelist(typval_T *argvars, typval_T *rettv) return; #ifdef FEAT_JUMPLIST - buf = find_buffer(&argvars[0]); + (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; diff --git a/src/testdir/test_changelist.vim b/src/testdir/test_changelist.vim index 0880fce840..dd6ea9600c 100644 --- a/src/testdir/test_changelist.vim +++ b/src/testdir/test_changelist.vim @@ -9,7 +9,7 @@ func Test_getchangelist() bwipe! enew call assert_equal([], getchangelist(10)) - call assert_equal([[], 0], getchangelist(bufnr('%'))) + call assert_equal([[], 0], getchangelist('%')) call writefile(['line1', 'line2', 'line3'], 'Xfile1.txt') call writefile(['line1', 'line2', 'line3'], 'Xfile2.txt') @@ -23,7 +23,7 @@ func Test_getchangelist() \ {'lnum' : 2, 'col' : 4, 'coladd' : 0}, \ {'lnum' : 4, 'col' : 4, 'coladd' : 0}, \ {'lnum' : 6, 'col' : 4, 'coladd' : 0}], 2], - \ getchangelist(bufnr('%'))) + \ getchangelist('%')) hide edit Xfile2.txt exe "normal 1GOline\u1.0" @@ -31,7 +31,7 @@ func Test_getchangelist() call assert_equal([[ \ {'lnum' : 1, 'col' : 6, 'coladd' : 0}, \ {'lnum' : 3, 'col' : 6, 'coladd' : 0}], 2], - \ getchangelist(bufnr('%'))) + \ getchangelist('%')) hide enew call assert_equal([[ diff --git a/src/version.c b/src/version.c index 92fd162fa4..24eef2e8a1 100644 --- a/src/version.c +++ b/src/version.c @@ -771,6 +771,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 1519, /**/ 1518, /**/ From 181ca99e163b145cd1a4ec47a50cc25cf3994109 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Tue, 13 Feb 2018 21:19:21 +0100 Subject: [PATCH 11/11] patch 8.0.1520: cursor in wrong line when using a WinBar in Terminal window Problem: Cursor is in the wrong line when using a WinBar in a Terminal window. Solution: Adjust the row number. (Christian Brabandt, closes #2362) --- src/screen.c | 5 +++++ src/terminal.c | 4 ++-- src/version.c | 2 ++ 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/screen.c b/src/screen.c index ce9b6e98e8..97f69882bf 100644 --- a/src/screen.c +++ b/src/screen.c @@ -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; } diff --git a/src/terminal.c b/src/terminal.c index eca9f1bd86..039c8b26b0 100644 --- a/src/terminal.c +++ b/src/terminal.c @@ -2398,8 +2398,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; diff --git a/src/version.c b/src/version.c index 24eef2e8a1..c7240f1a67 100644 --- a/src/version.c +++ b/src/version.c @@ -771,6 +771,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 1520, /**/ 1519, /**/