From 83ef740e150c5f29bd8ed92681d892160474fd7f Mon Sep 17 00:00:00 2001 From: Jan Edmund Lazo Date: Thu, 20 Jun 2019 22:05:29 -0400 Subject: vim-patch:8.0.1239: cannot use a lambda for the skip argument to searchpair() Problem: Cannot use a lambda for the skip argument to searchpair(). Solution: Evaluate a partial, funcref and lambda. (LemonBoy, closes vim/vim#1454, closes vim/vim#2265) https://github.com/vim/vim/commit/48570488f17e397183ea7d5c7ca67d6e4ffb013d --- src/nvim/eval.c | 118 ++++++++++++++++++++++++++------------- src/nvim/search.c | 4 +- src/nvim/testdir/test_search.vim | 19 +++++++ 3 files changed, 99 insertions(+), 42 deletions(-) (limited to 'src') diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 42ff6ceef2..8c27956242 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -955,6 +955,63 @@ eval_to_bool( return retval; } +static int eval_expr_typval(const typval_T *expr, typval_T *argv, + int argc, typval_T *rettv) +{ + int dummy; + + if (expr->v_type == VAR_FUNC) { + const char_u *const s = expr->vval.v_string; + if (s == NULL || *s == NUL) { + return FAIL; + } + if (call_func(s, (int)STRLEN(s), rettv, argc, argv, NULL, + 0L, 0L, &dummy, true, NULL, NULL) == FAIL) { + return FAIL; + } + } else if (expr->v_type == VAR_PARTIAL) { + partial_T *const partial = expr->vval.v_partial; + const char_u *const s = partial_name(partial); + if (s == NULL || *s == NUL) { + return FAIL; + } + if (call_func(s, (int)STRLEN(s), rettv, argc, argv, NULL, + 0L, 0L, &dummy, true, partial, NULL) == FAIL) { + return FAIL; + } + } else { + char buf[NUMBUFLEN]; + char_u *s = (char_u *)tv_get_string_buf_chk(expr, buf); + if (s == NULL) { + return FAIL; + } + s = skipwhite(s); + if (eval1(&s, rettv, true) == FAIL) { + return FAIL; + } + if (*s != NUL) { // check for trailing chars after expr + emsgf(_(e_invexpr2), s); + return FAIL; + } + } + return OK; +} + +/// Like eval_to_bool() but using a typval_T instead of a string. +/// Works for string, funcref and partial. +static bool eval_expr_to_bool(const typval_T *expr, bool *error) +{ + typval_T rettv; + + if (eval_expr_typval(expr, NULL, 0, &rettv) == FAIL) { + *error = true; + return false; + } + const bool res = (tv_get_number_chk(&rettv, error) != 0); + tv_clear(&rettv); + return res; +} + /// Top level evaluation function, returning a string /// /// @param[in] arg String to evaluate. @@ -8864,40 +8921,12 @@ static int filter_map_one(typval_T *tv, typval_T *expr, int map, int *remp) typval_T rettv; typval_T argv[3]; int retval = FAIL; - int dummy; tv_copy(tv, &vimvars[VV_VAL].vv_tv); argv[0] = vimvars[VV_KEY].vv_tv; argv[1] = vimvars[VV_VAL].vv_tv; - if (expr->v_type == VAR_FUNC) { - const char_u *const s = expr->vval.v_string; - if (call_func(s, (int)STRLEN(s), &rettv, 2, argv, NULL, - 0L, 0L, &dummy, true, NULL, NULL) == FAIL) { - goto theend; - } - } else if (expr->v_type == VAR_PARTIAL) { - partial_T *partial = expr->vval.v_partial; - - const char_u *const s = partial_name(partial); - if (call_func(s, (int)STRLEN(s), &rettv, 2, argv, NULL, - 0L, 0L, &dummy, true, partial, NULL) == FAIL) { - goto theend; - } - } else { - char buf[NUMBUFLEN]; - const char *s = tv_get_string_buf_chk(expr, buf); - if (s == NULL) { - goto theend; - } - s = (const char *)skipwhite((const char_u *)s); - if (eval1((char_u **)&s, &rettv, true) == FAIL) { - goto theend; - } - - if (*s != NUL) { // check for trailing chars after expr - emsgf(_(e_invexpr2), s); - goto theend; - } + if (eval_expr_typval(expr, argv, 2, &rettv) == FAIL) { + goto theend; } if (map) { // map(): replace the list item value. @@ -14501,7 +14530,6 @@ static int searchpair_cmn(typval_T *argvars, pos_T *match_pos) // Get the three pattern arguments: start, middle, end. char nbuf1[NUMBUFLEN]; char nbuf2[NUMBUFLEN]; - char nbuf3[NUMBUFLEN]; const char *spat = tv_get_string_chk(&argvars[0]); const char *mpat = tv_get_string_buf_chk(&argvars[1], nbuf1); const char *epat = tv_get_string_buf_chk(&argvars[2], nbuf2); @@ -14529,13 +14557,15 @@ static int searchpair_cmn(typval_T *argvars, pos_T *match_pos) } // Optional fifth argument: skip expression. - const char *skip; + const typval_T *skip; if (argvars[3].v_type == VAR_UNKNOWN || argvars[4].v_type == VAR_UNKNOWN) { - skip = ""; + skip = NULL; } else { - skip = tv_get_string_buf_chk(&argvars[4], nbuf3); - if (skip == NULL) { + skip = &argvars[4]; + if (skip->v_type != VAR_FUNC + && skip->v_type != VAR_PARTIAL + && skip->v_type != VAR_STRING) { goto theend; // Type error. } if (argvars[5].v_type != VAR_UNKNOWN) { @@ -14553,7 +14583,7 @@ static int searchpair_cmn(typval_T *argvars, pos_T *match_pos) } retval = do_searchpair( - (char_u *)spat, (char_u *)mpat, (char_u *)epat, dir, (char_u *)skip, + (char_u *)spat, (char_u *)mpat, (char_u *)epat, dir, skip, flags, match_pos, lnum_stop, time_limit); theend: @@ -14601,7 +14631,7 @@ do_searchpair( char_u *mpat, // middle pattern char_u *epat, // end pattern int dir, // BACKWARD or FORWARD - char_u *skip, // skip expression + const typval_T *skip, // skip expression int flags, // SP_SETPCMARK and other SP_ values pos_T *match_pos, linenr_T lnum_stop, // stop at this line if not zero @@ -14619,6 +14649,7 @@ do_searchpair( int n; int r; int nest = 1; + bool use_skip = false; int options = SEARCH_KEEP; proftime_T tm; size_t pat2_len; @@ -14648,6 +14679,13 @@ do_searchpair( options |= SEARCH_START; } + if (skip != NULL) { + // Empty string means to not use the skip expression. + if (skip->v_type == VAR_STRING || skip->v_type == VAR_FUNC) { + use_skip = skip->vval.v_string != NULL && *skip->vval.v_string != NUL; + } + } + save_cursor = curwin->w_cursor; pos = curwin->w_cursor; clearpos(&firstpos); @@ -14678,11 +14716,11 @@ do_searchpair( options &= ~SEARCH_START; /* If the skip pattern matches, ignore this match. */ - if (*skip != NUL) { + if (use_skip) { save_pos = curwin->w_cursor; curwin->w_cursor = pos; - bool err; - r = eval_to_bool(skip, &err, NULL, false); + bool err = false; + r = eval_expr_to_bool(skip, &err); curwin->w_cursor = save_pos; if (err) { /* Evaluating {skip} caused an error, break here. */ diff --git a/src/nvim/search.c b/src/nvim/search.c index 9cbe21bdc8..0b18d4bdde 100644 --- a/src/nvim/search.c +++ b/src/nvim/search.c @@ -3432,7 +3432,7 @@ again: if (do_searchpair((char_u *) "<[^ \t>/!]\\+\\%(\\_s\\_[^>]\\{-}[^/]>\\|$\\|\\_s\\=>\\)", (char_u *)"", - (char_u *)"]*>", BACKWARD, (char_u *)"", 0, + (char_u *)"]*>", BACKWARD, NULL, 0, NULL, (linenr_T)0, 0L) <= 0) { curwin->w_cursor = old_pos; goto theend; @@ -3459,7 +3459,7 @@ again: sprintf((char *)spat, "<%.*s\\>\\%%(\\s\\_[^>]\\{-}[^/]>\\|>\\)\\c", len, p); sprintf((char *)epat, "\\c", len, p); - r = do_searchpair(spat, (char_u *)"", epat, FORWARD, (char_u *)"", + r = do_searchpair(spat, (char_u *)"", epat, FORWARD, NULL, 0, NULL, (linenr_T)0, 0L); xfree(spat); diff --git a/src/nvim/testdir/test_search.vim b/src/nvim/testdir/test_search.vim index 87cad241e2..24ea8cd75a 100644 --- a/src/nvim/testdir/test_search.vim +++ b/src/nvim/testdir/test_search.vim @@ -298,6 +298,25 @@ func Test_searchpair() q! endfunc +func Test_searchpair_skip() + func Zero() + return 0 + endfunc + func Partial(x) + return a:x + endfunc + new + call setline(1, ['{', 'foo', 'foo', 'foo', '}']) + 3 | call assert_equal(1, searchpair('{', '', '}', 'bWn', '')) + 3 | call assert_equal(1, searchpair('{', '', '}', 'bWn', '0')) + 3 | call assert_equal(1, searchpair('{', '', '}', 'bWn', {-> 0})) + 3 | call assert_equal(1, searchpair('{', '', '}', 'bWn', function('Zero'))) + 3 | call assert_equal(1, searchpair('{', '', '}', 'bWn', function('Partial', [0]))) + " invalid argument + 3 | call assert_equal(0, searchpair('{', '', '}', 'bWn', 0)) + bw! +endfunc + func Test_searchc() " These commands used to cause memory overflow in searchc(). new -- cgit From 8bc365c886ecd9ba502dc0d4a7b46ec9bc92387d Mon Sep 17 00:00:00 2001 From: Jan Edmund Lazo Date: Fri, 21 Jun 2019 07:31:42 -0400 Subject: lint --- src/nvim/eval.c | 2 +- src/nvim/misc1.c | 1 + src/nvim/search.c | 18 ++++++++---------- 3 files changed, 10 insertions(+), 11 deletions(-) (limited to 'src') diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 8c27956242..05f001496a 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -14715,7 +14715,7 @@ do_searchpair( /* clear the start flag to avoid getting stuck here */ options &= ~SEARCH_START; - /* If the skip pattern matches, ignore this match. */ + // If the skip pattern matches, ignore this match. if (use_skip) { save_pos = curwin->w_cursor; curwin->w_cursor = pos; diff --git a/src/nvim/misc1.c b/src/nvim/misc1.c index 4e47311dda..6738e59bb2 100644 --- a/src/nvim/misc1.c +++ b/src/nvim/misc1.c @@ -1765,6 +1765,7 @@ del_lines ( } int gchar_pos(pos_T *pos) + FUNC_ATTR_NONNULL_ARG(1) { // When searching columns is sometimes put at the end of a line. if (pos->col == MAXCOL) { diff --git a/src/nvim/search.c b/src/nvim/search.c index 0b18d4bdde..b6d666cbe8 100644 --- a/src/nvim/search.c +++ b/src/nvim/search.c @@ -3370,7 +3370,6 @@ current_tagblock( ) { long count = count_arg; - long n; pos_T old_pos; pos_T start_pos; pos_T end_pos; @@ -3379,7 +3378,6 @@ current_tagblock( char_u *p; char_u *cp; int len; - int r; bool do_include = include; bool save_p_ws = p_ws; int retval = FAIL; @@ -3428,12 +3426,12 @@ again: * Search backwards for unclosed "". * Put this position in start_pos. */ - for (n = 0; n < count; ++n) { - if (do_searchpair((char_u *) - "<[^ \t>/!]\\+\\%(\\_s\\_[^>]\\{-}[^/]>\\|$\\|\\_s\\=>\\)", - (char_u *)"", - (char_u *)"]*>", BACKWARD, NULL, 0, - NULL, (linenr_T)0, 0L) <= 0) { + for (long n = 0; n < count; n++) { + if (do_searchpair( + (char_u *)"<[^ \t>/!]\\+\\%(\\_s\\_[^>]\\{-}[^/]>\\|$\\|\\_s\\=>\\)", + (char_u *)"", + (char_u *)"]*>", BACKWARD, NULL, 0, + NULL, (linenr_T)0, 0L) <= 0) { curwin->w_cursor = old_pos; goto theend; } @@ -3459,8 +3457,8 @@ again: sprintf((char *)spat, "<%.*s\\>\\%%(\\s\\_[^>]\\{-}[^/]>\\|>\\)\\c", len, p); sprintf((char *)epat, "\\c", len, p); - r = do_searchpair(spat, (char_u *)"", epat, FORWARD, NULL, - 0, NULL, (linenr_T)0, 0L); + const int r = do_searchpair(spat, (char_u *)"", epat, FORWARD, NULL, + 0, NULL, (linenr_T)0, 0L); xfree(spat); xfree(epat); -- cgit From efdc0f6a6949ec9bfb0d9ef454871458489773f0 Mon Sep 17 00:00:00 2001 From: Jan Edmund Lazo Date: Fri, 21 Jun 2019 07:38:43 -0400 Subject: vim-patch:8.1.0112: no error when using bad arguments with searchpair() Problem: No error when using bad arguments with searchpair(). Solution: Add error messages. https://github.com/vim/vim/commit/3dddb09c98825acefa6f2d94bb369b8e00d7b3e5 --- src/nvim/eval.c | 6 +++++- src/nvim/testdir/test_search.vim | 16 ++++++++++++---- 2 files changed, 17 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 05f001496a..6c138729a2 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -14527,7 +14527,8 @@ static int searchpair_cmn(typval_T *argvars, pos_T *match_pos) long lnum_stop = 0; long time_limit = 0; - // Get the three pattern arguments: start, middle, end. + // Get the three pattern arguments: start, middle, end. Will result in an + // error if not a valid argument. char nbuf1[NUMBUFLEN]; char nbuf2[NUMBUFLEN]; const char *spat = tv_get_string_chk(&argvars[0]); @@ -14566,16 +14567,19 @@ static int searchpair_cmn(typval_T *argvars, pos_T *match_pos) if (skip->v_type != VAR_FUNC && skip->v_type != VAR_PARTIAL && skip->v_type != VAR_STRING) { + emsgf(_(e_invarg2), tv_get_string(&argvars[4])); goto theend; // Type error. } if (argvars[5].v_type != VAR_UNKNOWN) { lnum_stop = tv_get_number_chk(&argvars[5], NULL); if (lnum_stop < 0) { + emsgf(_(e_invarg2), tv_get_string(&argvars[5])); goto theend; } if (argvars[6].v_type != VAR_UNKNOWN) { time_limit = tv_get_number_chk(&argvars[6], NULL); if (time_limit < 0) { + emsgf(_(e_invarg2), tv_get_string(&argvars[6])); goto theend; } } diff --git a/src/nvim/testdir/test_search.vim b/src/nvim/testdir/test_search.vim index 24ea8cd75a..c455279a59 100644 --- a/src/nvim/testdir/test_search.vim +++ b/src/nvim/testdir/test_search.vim @@ -288,16 +288,26 @@ func Test_searchpair() new call setline(1, ['other code here', '', '[', '" cursor here', ']']) 4 - let a=searchpair('\[','',']','bW') + let a = searchpair('\[','',']','bW') call assert_equal(3, a) set nomagic 4 - let a=searchpair('\[','',']','bW') + let a = searchpair('\[','',']','bW') call assert_equal(3, a) set magic q! endfunc +func Test_searchpair_errors() + call assert_fails("call searchpair([0], 'middle', 'end', 'bW', 'skip', 99, 100)", 'E730: using List as a String') + call assert_fails("call searchpair('start', {-> 0}, 'end', 'bW', 'skip', 99, 100)", 'E729: using Funcref as a String') + call assert_fails("call searchpair('start', 'middle', {'one': 1}, 'bW', 'skip', 99, 100)", 'E731: using Dictionary as a String') + call assert_fails("call searchpair('start', 'middle', 'end', 'flags', 'skip', 99, 100)", 'E475: Invalid argument: flags') + call assert_fails("call searchpair('start', 'middle', 'end', 'bW', 0, 99, 100)", 'E475: Invalid argument: 0') + call assert_fails("call searchpair('start', 'middle', 'end', 'bW', 'func', -99, 100)", 'E475: Invalid argument: -99') + call assert_fails("call searchpair('start', 'middle', 'end', 'bW', 'func', 99, -100)", 'E475: Invalid argument: -100') +endfunc + func Test_searchpair_skip() func Zero() return 0 @@ -312,8 +322,6 @@ func Test_searchpair_skip() 3 | call assert_equal(1, searchpair('{', '', '}', 'bWn', {-> 0})) 3 | call assert_equal(1, searchpair('{', '', '}', 'bWn', function('Zero'))) 3 | call assert_equal(1, searchpair('{', '', '}', 'bWn', function('Partial', [0]))) - " invalid argument - 3 | call assert_equal(0, searchpair('{', '', '}', 'bWn', 0)) bw! endfunc -- cgit From 6eae28f090b694282bed37fb73e547b34dc3261d Mon Sep 17 00:00:00 2001 From: Jan Edmund Lazo Date: Fri, 21 Jun 2019 19:50:05 -0400 Subject: eval: require nonnull func args to pass ASAN build --- src/nvim/eval.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 6c138729a2..3c50647848 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -957,6 +957,7 @@ eval_to_bool( static int eval_expr_typval(const typval_T *expr, typval_T *argv, int argc, typval_T *rettv) + FUNC_ATTR_NONNULL_ARG(1, 2, 4) { int dummy; @@ -1000,10 +1001,11 @@ static int eval_expr_typval(const typval_T *expr, typval_T *argv, /// Like eval_to_bool() but using a typval_T instead of a string. /// Works for string, funcref and partial. static bool eval_expr_to_bool(const typval_T *expr, bool *error) + FUNC_ATTR_NONNULL_ARG(1, 2) { - typval_T rettv; + typval_T argv, rettv; - if (eval_expr_typval(expr, NULL, 0, &rettv) == FAIL) { + if (eval_expr_typval(expr, &argv, 0, &rettv) == FAIL) { *error = true; return false; } @@ -6365,6 +6367,7 @@ call_func( partial_T *partial, // optional, can be NULL dict_T *selfdict_in // Dictionary for "self" ) + FUNC_ATTR_NONNULL_ARG(5) { int ret = FAIL; int error = ERROR_NONE; -- cgit From f0d6695e7cc13cd5f1ee006575a369faf2546893 Mon Sep 17 00:00:00 2001 From: Jan Edmund Lazo Date: Fri, 21 Jun 2019 20:46:43 -0400 Subject: vim-patch:8.1.0181: memory leak with trailing characters in skip expression Problem: Memory leak with trailing characters in skip expression. Solution: Free the return value. https://github.com/vim/vim/commit/a43ebe9454386427ca38c75810e2d36991f17812 --- src/nvim/eval.c | 1 + src/nvim/testdir/test_search.vim | 10 ++++++++++ 2 files changed, 11 insertions(+) (limited to 'src') diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 3c50647848..3e6e183847 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -991,6 +991,7 @@ static int eval_expr_typval(const typval_T *expr, typval_T *argv, return FAIL; } if (*s != NUL) { // check for trailing chars after expr + tv_clear(rettv); emsgf(_(e_invexpr2), s); return FAIL; } diff --git a/src/nvim/testdir/test_search.vim b/src/nvim/testdir/test_search.vim index c455279a59..5e5ec96fd1 100644 --- a/src/nvim/testdir/test_search.vim +++ b/src/nvim/testdir/test_search.vim @@ -325,6 +325,16 @@ func Test_searchpair_skip() bw! endfunc +func Test_searchpair_leak() + new + call setline(1, 'if one else another endif') + + " The error in the skip expression caused memory to leak. + call assert_fails("call searchpair('\\', '\\', '\\', '', '\"foo\" 2')", 'E15:') + + bwipe! +endfunc + func Test_searchc() " These commands used to cause memory overflow in searchc(). new -- cgit From 3abffe7015701f2468f94af3280871cd34653747 Mon Sep 17 00:00:00 2001 From: Jan Edmund Lazo Date: Fri, 21 Jun 2019 21:29:21 -0400 Subject: vim-patch:8.1.0125: virtual edit replace with multi-byte fails at end of line Problem: Virtual edit replace with multi-byte fails at end of line. (Lukas Werling) Solution: use ins_char() to add the character. (Christian Brabandt, closes vim/vim#3114) Rename PCHAR() to PBYTE() to avoid mistakes like this. https://github.com/vim/vim/commit/630afe889a2a02b367ea8eaaa48e66ed81e77ff3 --- src/nvim/ops.c | 35 ++++++++++++++++++++++++----------- src/nvim/testdir/test_virtualedit.vim | 16 ++++++++++++++++ 2 files changed, 40 insertions(+), 11 deletions(-) (limited to 'src') diff --git a/src/nvim/ops.c b/src/nvim/ops.c index 2a3b7beb8e..ef440a27a2 100644 --- a/src/nvim/ops.c +++ b/src/nvim/ops.c @@ -1638,12 +1638,25 @@ static void mb_adjust_opend(oparg_T *oap) /* * Put character 'c' at position 'lp' */ -static inline void pchar(pos_T lp, int c) +static inline void pbyte(pos_T lp, int c) { assert(c <= UCHAR_MAX); *(ml_get_buf(curbuf, lp.lnum, true) + lp.col) = (char_u)c; } +// Replace the character under the cursor with "c". +// This takes care of multi-byte characters. +static void replace_character(int c) +{ + const int n = State; + + State = REPLACE; + ins_char(c); + State = n; + // Backup to the replaced character. + dec_cursor(); +} + /* * Replace a whole area with one character. */ @@ -1795,12 +1808,7 @@ int op_replace(oparg_T *oap, int c) * with a multi-byte and the other way around. */ if (curwin->w_cursor.lnum == oap->end.lnum) oap->end.col += (*mb_char2len)(c) - (*mb_char2len)(n); - n = State; - State = REPLACE; - ins_char(c); - State = n; - /* Backup to the replaced character. */ - dec_cursor(); + replace_character(c); } else { if (n == TAB) { int end_vcol = 0; @@ -1815,7 +1823,7 @@ int op_replace(oparg_T *oap, int c) if (curwin->w_cursor.lnum == oap->end.lnum) getvpos(&oap->end, end_vcol); } - pchar(curwin->w_cursor, c); + pbyte(curwin->w_cursor, c); } } else if (virtual_op && curwin->w_cursor.lnum == oap->end.lnum) { int virtcols = oap->end.coladd; @@ -1830,9 +1838,14 @@ int op_replace(oparg_T *oap, int c) coladvance_force(getviscol2(oap->end.col, oap->end.coladd) + 1); curwin->w_cursor.col -= (virtcols + 1); for (; virtcols >= 0; virtcols--) { - pchar(curwin->w_cursor, c); - if (inc(&curwin->w_cursor) == -1) + if (utf_char2len(c) > 1) { + replace_character(c); + } else { + pbyte(curwin->w_cursor, c); + } + if (inc(&curwin->w_cursor) == -1) { break; + } } } @@ -2007,7 +2020,7 @@ int swapchar(int op_type, pos_T *pos) ins_char(nc); curwin->w_cursor = sp; } else - pchar(*pos, nc); + pbyte(*pos, nc); return TRUE; } return FALSE; diff --git a/src/nvim/testdir/test_virtualedit.vim b/src/nvim/testdir/test_virtualedit.vim index d49025237b..abe79f6a4a 100644 --- a/src/nvim/testdir/test_virtualedit.vim +++ b/src/nvim/testdir/test_virtualedit.vim @@ -42,6 +42,22 @@ func Test_paste_end_of_line() set virtualedit= endfunc +func Test_replace_end_of_line() + new + set virtualedit=all + call setline(1, range(20)) + exe "normal! gg2jv10lr-" + call assert_equal(["1", "-----------", "3"], getline(2,4)) + if has('multi_byte') + call setline(1, range(20)) + exe "normal! gg2jv10lr\hh" + call assert_equal(["1", "───────────", "3"], getline(2,4)) + endif + + bwipe! + set virtualedit= +endfunc + func Test_edit_CTRL_G() new set virtualedit=insert -- cgit From f99e314da06fa50fcc2a6a2bf0833ea365f121a9 Mon Sep 17 00:00:00 2001 From: Jan Edmund Lazo Date: Fri, 21 Jun 2019 22:11:15 -0400 Subject: ops: refactor swapchar() to return bool --- src/nvim/ops.c | 38 ++++++++++++++++++-------------------- 1 file changed, 18 insertions(+), 20 deletions(-) (limited to 'src') diff --git a/src/nvim/ops.c b/src/nvim/ops.c index ef440a27a2..b5408fab9a 100644 --- a/src/nvim/ops.c +++ b/src/nvim/ops.c @@ -1966,23 +1966,20 @@ static int swapchars(int op_type, pos_T *pos, int length) return did_change; } -/* - * If op_type == OP_UPPER: make uppercase, - * if op_type == OP_LOWER: make lowercase, - * if op_type == OP_ROT13: do rot13 encoding, - * else swap case of character at 'pos' - * returns TRUE when something actually changed. - */ -int swapchar(int op_type, pos_T *pos) +// If op_type == OP_UPPER: make uppercase, +// if op_type == OP_LOWER: make lowercase, +// if op_type == OP_ROT13: do rot13 encoding, +// else swap case of character at 'pos' +// returns true when something actually changed. +bool swapchar(int op_type, pos_T *pos) + FUNC_ATTR_NONNULL_ARG(2) { - int c; - int nc; - - c = gchar_pos(pos); + const int c = gchar_pos(pos); - /* Only do rot13 encoding for ASCII characters. */ - if (c >= 0x80 && op_type == OP_ROT13) - return FALSE; + // Only do rot13 encoding for ASCII characters. + if (c >= 0x80 && op_type == OP_ROT13) { + return false; + } if (op_type == OP_UPPER && c == 0xdf) { pos_T sp = curwin->w_cursor; @@ -1996,7 +1993,7 @@ int swapchar(int op_type, pos_T *pos) inc(pos); } - nc = c; + int nc = c; if (mb_islower(c)) { if (op_type == OP_ROT13) { nc = ROT13(c, 'a'); @@ -2011,7 +2008,7 @@ int swapchar(int op_type, pos_T *pos) } } if (nc != c) { - if (enc_utf8 && (c >= 0x80 || nc >= 0x80)) { + if (c >= 0x80 || nc >= 0x80) { pos_T sp = curwin->w_cursor; curwin->w_cursor = *pos; @@ -2019,11 +2016,12 @@ int swapchar(int op_type, pos_T *pos) del_bytes(utf_ptr2len(get_cursor_pos_ptr()), FALSE, FALSE); ins_char(nc); curwin->w_cursor = sp; - } else + } else { pbyte(*pos, nc); - return TRUE; + } + return true; } - return FALSE; + return false; } /* -- cgit From ff244a1309482e818c6731038f0232fae613431c Mon Sep 17 00:00:00 2001 From: Jan Edmund Lazo Date: Fri, 21 Jun 2019 22:44:33 -0400 Subject: vim-patch:8.1.0165: :clist output can be very long Problem: :clist output can be very long. Solution: Support filtering :clist entries. (Yegappan Lakshmanan) https://github.com/vim/vim/commit/4cde86c2ef885e82fff3d925dee9fb5671c025cf --- src/nvim/quickfix.c | 22 ++++++++++++++++++++-- src/nvim/testdir/test_quickfix.vim | 17 +++++++++++++++++ 2 files changed, 37 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c index 3c744310b3..fb753609bd 100644 --- a/src/nvim/quickfix.c +++ b/src/nvim/quickfix.c @@ -2528,9 +2528,9 @@ void qf_list(exarg_T *eap) qfp = qi->qf_lists[qi->qf_curlist].qf_start; for (i = 1; !got_int && i <= qi->qf_lists[qi->qf_curlist].qf_count; ) { if ((qfp->qf_valid || all) && idx1 <= i && i <= idx2) { - msg_putchar('\n'); - if (got_int) + if (got_int) { break; + } fname = NULL; if (qfp->qf_module != NULL && *qfp->qf_module != NUL) { @@ -2549,6 +2549,23 @@ void qf_list(exarg_T *eap) vim_snprintf((char *)IObuff, IOSIZE, "%2d %s", i, (char *)fname); } } + + // Support for filtering entries using :filter /pat/ clist + int filter_entry = 1; + if (qfp->qf_module != NULL && *qfp->qf_module != NUL) { + filter_entry &= message_filtered(qfp->qf_module); + } + if (fname != NULL) { + filter_entry &= message_filtered(fname); + } + if (qfp->qf_pattern != NULL) { + filter_entry &= message_filtered(qfp->qf_pattern); + } + filter_entry &= message_filtered(qfp->qf_text); + if (filter_entry) { + goto next_entry; + } + msg_putchar('\n'); msg_outtrans_attr(IObuff, i == qi->qf_lists[qi->qf_curlist].qf_index ? HL_ATTR(HLF_QFL) : HL_ATTR(HLF_D)); if (qfp->qf_lnum == 0) { @@ -2579,6 +2596,7 @@ void qf_list(exarg_T *eap) ui_flush(); /* show one line at a time */ } +next_entry: qfp = qfp->qf_next; if (qfp == NULL) { break; diff --git a/src/nvim/testdir/test_quickfix.vim b/src/nvim/testdir/test_quickfix.vim index 4d78c67f5c..ce0b8f1be8 100644 --- a/src/nvim/testdir/test_quickfix.vim +++ b/src/nvim/testdir/test_quickfix.vim @@ -3373,6 +3373,23 @@ func Test_lbuffer_with_bwipe() augroup END endfunc +" Tests for the ':filter /pat/ clist' command +func Test_filter_clist() + cexpr ['Xfile1:10:10:Line 10', 'Xfile2:15:15:Line 15'] + call assert_equal([' 2 Xfile2:15 col 15: Line 15'], + \ split(execute('filter /Line 15/ clist'), "\n")) + call assert_equal([' 1 Xfile1:10 col 10: Line 10'], + \ split(execute('filter /Xfile1/ clist'), "\n")) + call assert_equal([], split(execute('filter /abc/ clist'), "\n")) + + call setqflist([{'module' : 'abc', 'pattern' : 'pat1'}, + \ {'module' : 'pqr', 'pattern' : 'pat2'}], ' ') + call assert_equal([' 2 pqr:pat2: '], + \ split(execute('filter /pqr/ clist'), "\n")) + call assert_equal([' 1 abc:pat1: '], + \ split(execute('filter /pat1/ clist'), "\n")) +endfunc + func Test_setloclist_in_aucmd() " This was using freed memory. augroup nasty -- cgit From 98801ec7aea199b80373d1dc072021a98db63a8b Mon Sep 17 00:00:00 2001 From: Jan Edmund Lazo Date: Sat, 22 Jun 2019 04:30:48 -0400 Subject: vim-patch:8.1.0166: using dict_add_nr_str() is clumsy Problem: Using dict_add_nr_str() is clumsy. Solution: Split into two functions. (Ozaki Kiichi, closes vim/vim#3154) https://github.com/vim/vim/commit/e0be167a805fd547c25ec1ec97fd4c7f13046236 --- src/nvim/ex_cmds2.c | 2 +- src/nvim/quickfix.c | 7 ++----- 2 files changed, 3 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/nvim/ex_cmds2.c b/src/nvim/ex_cmds2.c index 3b83c59675..2fb818760a 100644 --- a/src/nvim/ex_cmds2.c +++ b/src/nvim/ex_cmds2.c @@ -611,7 +611,7 @@ static int dbg_parsearg(char_u *arg, garray_T *gap) return OK; } -/// ":breakadd". +/// ":breakadd". Also used for ":profile". void ex_breakadd(exarg_T *eap) { struct debuggy *bp; diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c index fb753609bd..81da410826 100644 --- a/src/nvim/quickfix.c +++ b/src/nvim/quickfix.c @@ -4739,11 +4739,8 @@ static int qf_getprop_defaults(qf_info_T *qi, int flags, dict_T *retdict) /// Return the quickfix list title as 'title' in retdict static int qf_getprop_title(qf_info_T *qi, int qf_idx, dict_T *retdict) { - char_u *t = qi->qf_lists[qf_idx].qf_title; - if (t == NULL) { - t = (char_u *)""; - } - return tv_dict_add_str(retdict, S_LEN("title"), (const char *)t); + return tv_dict_add_str(retdict, S_LEN("title"), + (const char *)qi->qf_lists[qf_idx].qf_title); } /// Return the quickfix list items/entries as 'items' in retdict -- cgit From bb02ca6defb65110a426b579e81cd1a6f9eb886a Mon Sep 17 00:00:00 2001 From: Jan Edmund Lazo Date: Sat, 22 Jun 2019 05:58:58 -0400 Subject: vim-patch:8.1.0167: lock flag in new dictitem is reset in many places Problem: Lock flag in new dictitem is reset in many places. Solution: Always reset the lock flag. https://github.com/vim/vim/commit/c89d4b35300b98cf68b14c89c8e1add51bd857e3 --- src/nvim/eval.c | 2 -- src/nvim/eval/typval.c | 12 +++++------- 2 files changed, 5 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 3e6e183847..ce0b192545 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -17819,7 +17819,6 @@ static void add_timer_info(typval_T *rettv, timer_T *timer) di->di_tv.v_type = VAR_FUNC; di->di_tv.vval.v_string = vim_strsave(timer->callback.data.funcref); } - di->di_tv.v_lock = 0; } static void add_timer_info_all(typval_T *rettv) @@ -21180,7 +21179,6 @@ void ex_function(exarg_T *eap) tv_clear(&fudi.fd_di->di_tv); } fudi.fd_di->di_tv.v_type = VAR_FUNC; - fudi.fd_di->di_tv.v_lock = 0; fudi.fd_di->di_tv.vval.v_string = vim_strsave(name); /* behave like "dict" was used */ diff --git a/src/nvim/eval/typval.c b/src/nvim/eval/typval.c index ffb46abfea..91a1d083c7 100644 --- a/src/nvim/eval/typval.c +++ b/src/nvim/eval/typval.c @@ -1221,7 +1221,8 @@ void tv_dict_watcher_notify(dict_T *const dict, const char *const key, /// Allocate a dictionary item /// -/// @note that the value of the item (->di_tv) still needs to be initialized. +/// @note that the type and value of the item (->di_tv) still needs to +/// be initialized. /// /// @param[in] key Key, is copied to the new item. /// @param[in] key_len Key length. @@ -1235,12 +1236,14 @@ dictitem_T *tv_dict_item_alloc_len(const char *const key, const size_t key_len) memcpy(di->di_key, key, key_len); di->di_key[key_len] = NUL; di->di_flags = DI_FLAGS_ALLOC; + di->di_tv.v_lock = VAR_UNLOCKED; return di; } /// Allocate a dictionary item /// -/// @note that the value of the item (->di_tv) still needs to be initialized. +/// @note that the type and value of the item (->di_tv) still needs to +/// be initialized. /// /// @param[in] key Key, is copied to the new item. /// @@ -1572,7 +1575,6 @@ int tv_dict_add_list(dict_T *const d, const char *const key, { dictitem_T *const item = tv_dict_item_alloc_len(key, key_len); - item->di_tv.v_lock = VAR_UNLOCKED; item->di_tv.v_type = VAR_LIST; item->di_tv.vval.v_list = list; tv_list_ref(list); @@ -1597,7 +1599,6 @@ int tv_dict_add_dict(dict_T *const d, const char *const key, { dictitem_T *const item = tv_dict_item_alloc_len(key, key_len); - item->di_tv.v_lock = VAR_UNLOCKED; item->di_tv.v_type = VAR_DICT; item->di_tv.vval.v_dict = dict; dict->dv_refcount++; @@ -1621,7 +1622,6 @@ int tv_dict_add_nr(dict_T *const d, const char *const key, { dictitem_T *const item = tv_dict_item_alloc_len(key, key_len); - item->di_tv.v_lock = VAR_UNLOCKED; item->di_tv.v_type = VAR_NUMBER; item->di_tv.vval.v_number = nr; if (tv_dict_add(d, item) == FAIL) { @@ -1644,7 +1644,6 @@ int tv_dict_add_special(dict_T *const d, const char *const key, { dictitem_T *const item = tv_dict_item_alloc_len(key, key_len); - item->di_tv.v_lock = VAR_UNLOCKED; item->di_tv.v_type = VAR_SPECIAL; item->di_tv.vval.v_special = val; if (tv_dict_add(d, item) == FAIL) { @@ -1706,7 +1705,6 @@ int tv_dict_add_allocated_str(dict_T *const d, { dictitem_T *const item = tv_dict_item_alloc_len(key, key_len); - item->di_tv.v_lock = VAR_UNLOCKED; item->di_tv.v_type = VAR_STRING; item->di_tv.vval.v_string = (char_u *)val; if (tv_dict_add(d, item) == FAIL) { -- cgit From 3a49fa8f8b348b48e90860ec3fdf005d301ba9d0 Mon Sep 17 00:00:00 2001 From: Jan Edmund Lazo Date: Sat, 22 Jun 2019 06:28:49 -0400 Subject: vim-patch:8.1.0169: calling message_filtered() a bit too often Problem: Calling message_filtered() a bit too often. Solution: Only call message_filtered() when filtering is already false. https://github.com/vim/vim/commit/a9defadb8f03ecd03f3297305d5482ba380774dc --- src/nvim/quickfix.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c index 81da410826..6779f4e05d 100644 --- a/src/nvim/quickfix.c +++ b/src/nvim/quickfix.c @@ -2551,17 +2551,21 @@ void qf_list(exarg_T *eap) } // Support for filtering entries using :filter /pat/ clist - int filter_entry = 1; + // Match against the module name, file name, search pattern and + // text of the entry. + bool filter_entry = true; if (qfp->qf_module != NULL && *qfp->qf_module != NUL) { filter_entry &= message_filtered(qfp->qf_module); } - if (fname != NULL) { + if (filter_entry && fname != NULL) { filter_entry &= message_filtered(fname); } - if (qfp->qf_pattern != NULL) { + if (filter_entry && qfp->qf_pattern != NULL) { filter_entry &= message_filtered(qfp->qf_pattern); } - filter_entry &= message_filtered(qfp->qf_text); + if (filter_entry) { + filter_entry &= message_filtered(qfp->qf_text); + } if (filter_entry) { goto next_entry; } -- cgit From 1935cc263993a9c0cb1bae510347a7c344b5b37c Mon Sep 17 00:00:00 2001 From: Jan Edmund Lazo Date: Sat, 22 Jun 2019 07:55:01 -0400 Subject: vim-patch:8.1.0242: Insert mode completion may use an invalid buffer pointer Problem: Insert mode completion may use an invalid buffer pointer. Solution: Check for ins_buf to be valid. (closes vim/vim#3290) https://github.com/vim/vim/commit/02ab97709d5c56fb7fe42e134bb9fc54f76a1f9f --- src/nvim/edit.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/nvim/edit.c b/src/nvim/edit.c index 9af003f140..8040109685 100644 --- a/src/nvim/edit.c +++ b/src/nvim/edit.c @@ -3838,11 +3838,14 @@ static int ins_compl_get_exp(pos_T *ini) e_cpt = (compl_cont_status & CONT_LOCAL) ? (char_u *)"." : curbuf->b_p_cpt; last_match_pos = first_match_pos = *ini; + } else if (ins_buf != curbuf && !buf_valid(ins_buf)) { + ins_buf = curbuf; // In case the buffer was wiped out. } compl_old_match = compl_curr_match; // remember the last current match pos = (compl_direction == FORWARD) ? &last_match_pos : &first_match_pos; - /* For ^N/^P loop over all the flags/windows/buffers in 'complete' */ + + // For ^N/^P loop over all the flags/windows/buffers in 'complete' for (;; ) { found_new_match = FAIL; set_match_pos = FALSE; -- cgit From 450d9e6bdf8c05329245a0c61e26b1eb97f783cf Mon Sep 17 00:00:00 2001 From: Jan Edmund Lazo Date: Sat, 22 Jun 2019 11:33:55 -0400 Subject: vim-patch:8.1.0270: checking for a Tab in a line could be faster Problem: Checking for a Tab in a line could be faster. Solution: Use strchr() instead of strrchr(). (closes vim/vim#3312) https://github.com/vim/vim/commit/b31a3acce13231643b006988c1ce76b8a12b2982 --- src/nvim/ex_cmds.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c index 71ed5f6ec1..17b66fd32c 100644 --- a/src/nvim/ex_cmds.c +++ b/src/nvim/ex_cmds.c @@ -335,7 +335,7 @@ static int linelen(int *has_tab) len = linetabsize(line); // Check for embedded TAB. if (has_tab != NULL) { - *has_tab = STRRCHR(first, TAB) != NULL; + *has_tab = vim_strchr(first, TAB) != NULL; } *last = save; -- cgit From 25f99dde9480bcfa32f172c0032a2d24d7c32153 Mon Sep 17 00:00:00 2001 From: Jan Edmund Lazo Date: Sat, 22 Jun 2019 11:41:41 -0400 Subject: vim-patch:8.1.0272: options test fails if temp var ends in slash Problem: Options test fails if temp var ends in slash. (Tom Briden) Solution: Check for optional slash. (closes vim/vim#3308) https://github.com/vim/vim/commit/f53c692240851f71b930e80a0b0b5d4cfcc1b4a3 --- src/nvim/testdir/test_options.vim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/nvim/testdir/test_options.vim b/src/nvim/testdir/test_options.vim index da87a22f1e..9aa003f475 100644 --- a/src/nvim/testdir/test_options.vim +++ b/src/nvim/testdir/test_options.vim @@ -357,7 +357,7 @@ func Test_backupskip() for var in ['$TEMPDIR', '$TMP', '$TEMP'] if exists(var) let varvalue = substitute(expand(var), '\\', '/', 'g') - call assert_match(varvalue . '.\*', bskvalue) + call assert_match(varvalue . '/\=\*', bskvalue) endif endfor endfunc -- cgit From ca6b42d7fdb4e533e7875b1ed23e4a07b900b09d Mon Sep 17 00:00:00 2001 From: Jan Edmund Lazo Date: Sat, 22 Jun 2019 14:55:25 -0400 Subject: vim-patch:8.1.0850: test for 'backupskip' is not correct Problem: Test for 'backupskip' is not correct. Solution: Split the option in parts and use expand(). (Michael Soyka) https://github.com/vim/vim/commit/98ad1e17c3f71962862f959c6ba57dd01e8a83c2 --- src/nvim/testdir/test_options.vim | 45 ++++++++++++++++++++++++++++++++------- 1 file changed, 37 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/nvim/testdir/test_options.vim b/src/nvim/testdir/test_options.vim index 9aa003f475..eedf8c23c4 100644 --- a/src/nvim/testdir/test_options.vim +++ b/src/nvim/testdir/test_options.vim @@ -92,9 +92,6 @@ function! Test_path_keep_commas() endfunction func Test_filetype_valid() - if !has('autocmd') - return - endif set ft=valid_name call assert_equal("valid_name", &filetype) set ft=valid-name @@ -347,17 +344,49 @@ func Test_set_indentexpr() endfunc func Test_backupskip() + " Option 'backupskip' may contain several comma-separated path + " specifications if one or more of the environment variables TMPDIR, TMP, + " or TEMP is defined. To simplify testing, convert the string value into a + " list. + let bsklist = split(&bsk, ',') + if has("mac") - call assert_match('/private/tmp/\*', &bsk) + let found = (index(bsklist, '/private/tmp/*') >= 0) + call assert_true(found, '/private/tmp not in option bsk: ' . &bsk) elseif has("unix") - call assert_match('/tmp/\*', &bsk) + let found = (index(bsklist, '/tmp/*') >= 0) + call assert_true(found, '/tmp not in option bsk: ' . &bsk) + endif + + " If our test platform is Windows, the path(s) in option bsk will use + " backslash for the path separator and the components could be in short + " (8.3) format. As such, we need to replace the backslashes with forward + " slashes and convert the path components to long format. The expand() + " function will do this but it cannot handle comma-separated paths. This is + " why bsk was converted from a string into a list of strings above. + " + " One final complication is that the wildcard "/*" is at the end of each + " path and so expand() might return a list of matching files. To prevent + " this, we need to remove the wildcard before calling expand() and then + " append it afterwards. + if has('win32') + let item_nbr = 0 + while item_nbr < len(bsklist) + let path_spec = bsklist[item_nbr] + let path_spec = strcharpart(path_spec, 0, strlen(path_spec)-2) + let path_spec = substitute(expand(path_spec), '\\', '/', 'g') + let bsklist[item_nbr] = path_spec . '/*' + let item_nbr += 1 + endwhile endif - let bskvalue = substitute(&bsk, '\\', '/', 'g') - for var in ['$TEMPDIR', '$TMP', '$TEMP'] + " Option bsk will also include these environment variables if defined. + " If they're defined, verify they appear in the option value. + for var in ['$TMPDIR', '$TMP', '$TEMP'] if exists(var) let varvalue = substitute(expand(var), '\\', '/', 'g') - call assert_match(varvalue . '/\=\*', bskvalue) + let found = (index(bsklist, varvalue.'/*') >= 0) + call assert_true(found, var . ' not in option bsk: ' . &bsk) endif endfor endfunc -- cgit From 6558e02b95d94a8be60757cc39df227836ec1f9c Mon Sep 17 00:00:00 2001 From: Jan Edmund Lazo Date: Sat, 22 Jun 2019 14:56:53 -0400 Subject: vim-patch:8.1.0853: options test fails on Mac Problem: Options test fails on Mac. Solution: Remove a trailing slash from $TMPDIR. https://github.com/vim/vim/commit/cbbd0f657803a9a3a9f5e2c66bce6e1ea1d6a64b --- src/nvim/testdir/test_options.vim | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/nvim/testdir/test_options.vim b/src/nvim/testdir/test_options.vim index eedf8c23c4..ecfc84432a 100644 --- a/src/nvim/testdir/test_options.vim +++ b/src/nvim/testdir/test_options.vim @@ -385,8 +385,10 @@ func Test_backupskip() for var in ['$TMPDIR', '$TMP', '$TEMP'] if exists(var) let varvalue = substitute(expand(var), '\\', '/', 'g') - let found = (index(bsklist, varvalue.'/*') >= 0) - call assert_true(found, var . ' not in option bsk: ' . &bsk) + let varvalue = substitute(varvalue, '/$', '', '') + let varvalue .= '/*' + let found = (index(bsklist, varvalue) >= 0) + call assert_true(found, var . ' (' . varvalue . ') not in option bsk: ' . &bsk) endif endfor endfunc -- cgit From 2813c83ea10b157974bdff7ceec9c3fc7f0d3380 Mon Sep 17 00:00:00 2001 From: Jan Edmund Lazo Date: Sat, 22 Jun 2019 15:19:01 -0400 Subject: vim-patch:8.1.1519: 'backupskip' may contain duplicates Problem: 'backupskip' may contain duplicates. Solution: Add the P_NODUP flag. (Tom Ryder) https://github.com/vim/vim/commit/06e2c81f6d213d197aa60019b33a263cd5176d68 --- src/nvim/testdir/test_options.vim | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'src') diff --git a/src/nvim/testdir/test_options.vim b/src/nvim/testdir/test_options.vim index ecfc84432a..28576709a3 100644 --- a/src/nvim/testdir/test_options.vim +++ b/src/nvim/testdir/test_options.vim @@ -391,6 +391,15 @@ func Test_backupskip() call assert_true(found, var . ' (' . varvalue . ') not in option bsk: ' . &bsk) endif endfor + + " Duplicates should be filtered out (option has P_NODUP) + let backupskip = &backupskip + set backupskip= + set backupskip+=/test/dir + set backupskip+=/other/dir + set backupskip+=/test/dir + call assert_equal('/test/dir,/other/dir', &backupskip) + let &backupskip = backupskip endfunc func Test_copy_winopt() -- cgit From 4653b5943f2ccdb65fa1e099853d4d680abc3f83 Mon Sep 17 00:00:00 2001 From: Jan Edmund Lazo Date: Sat, 22 Jun 2019 19:40:12 -0400 Subject: vim-patch:8.1.0747: map() with a bad expression doesn't give an error Problem: map() with a bad expression doesn't give an error. (Ingo Karkat) Solution: Check for giving an error message. (closes vim/vim#3800) https://github.com/vim/vim/commit/ce9d50df07402cb8e196537a9c4505845adecabc --- src/nvim/eval.c | 45 +++++++++++++++++++++++------------- src/nvim/testdir/test_filter_map.vim | 5 ++++ 2 files changed, 34 insertions(+), 16 deletions(-) (limited to 'src') diff --git a/src/nvim/eval.c b/src/nvim/eval.c index ce0b192545..c5caf80700 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -955,6 +955,28 @@ eval_to_bool( return retval; } +// Call eval1() and give an error message if not done at a lower level. +static int eval1_emsg(char_u **arg, typval_T *rettv, bool evaluate) + FUNC_ATTR_NONNULL_ARG(1, 2) +{ + const int did_emsg_before = did_emsg; + const int called_emsg_before = called_emsg; + + const int ret = eval1(arg, rettv, evaluate); + if (ret == FAIL) { + // Report the invalid expression unless the expression evaluation has + // been cancelled due to an aborting error, an interrupt, or an + // exception, or we already gave a more specific error. + // Also check called_emsg for when using assert_fails(). + if (!aborting() + && did_emsg == did_emsg_before + && called_emsg == called_emsg_before) { + emsgf(_(e_invexpr2), arg); + } + } + return ret; +} + static int eval_expr_typval(const typval_T *expr, typval_T *argv, int argc, typval_T *rettv) FUNC_ATTR_NONNULL_ARG(1, 2, 4) @@ -987,7 +1009,7 @@ static int eval_expr_typval(const typval_T *expr, typval_T *argv, return FAIL; } s = skipwhite(s); - if (eval1(&s, rettv, true) == FAIL) { + if (eval1_emsg(&s, rettv, true) == FAIL) { return FAIL; } if (*s != NUL) { // check for trailing chars after expr @@ -6368,7 +6390,7 @@ call_func( partial_T *partial, // optional, can be NULL dict_T *selfdict_in // Dictionary for "self" ) - FUNC_ATTR_NONNULL_ARG(5) + FUNC_ATTR_NONNULL_ARG(1, 3, 5, 9) { int ret = FAIL; int error = ERROR_NONE; @@ -8891,6 +8913,7 @@ static void filter_map(typval_T *argvars, typval_T *rettv, int map) } hash_unlock(ht); } else { + // argvars[0].v_type == VAR_LIST vimvars[VV_KEY].vv_type = VAR_NUMBER; for (listitem_T *li = tv_list_first(l); li != NULL;) { @@ -8921,6 +8944,7 @@ static void filter_map(typval_T *argvars, typval_T *rettv, int map) } static int filter_map_one(typval_T *tv, typval_T *expr, int map, int *remp) + FUNC_ATTR_NONNULL_ARG(1, 2) { typval_T rettv; typval_T argv[3]; @@ -14655,7 +14679,6 @@ do_searchpair( pos_T save_cursor; pos_T save_pos; int n; - int r; int nest = 1; bool use_skip = false; int options = SEARCH_KEEP; @@ -14728,7 +14751,7 @@ do_searchpair( save_pos = curwin->w_cursor; curwin->w_cursor = pos; bool err = false; - r = eval_expr_to_bool(skip, &err); + const bool r = eval_expr_to_bool(skip, &err); curwin->w_cursor = save_pos; if (err) { /* Evaluating {skip} caused an error, break here. */ @@ -20525,7 +20548,6 @@ void ex_execute(exarg_T *eap) char_u *arg = eap->arg; typval_T rettv; int ret = OK; - char_u *p; garray_T ga; int save_did_emsg = did_emsg; @@ -20534,17 +20556,8 @@ void ex_execute(exarg_T *eap) if (eap->skip) ++emsg_skip; while (*arg != NUL && *arg != '|' && *arg != '\n') { - p = arg; - if (eval1(&arg, &rettv, !eap->skip) == FAIL) { - /* - * Report the invalid expression unless the expression evaluation - * has been cancelled due to an aborting error, an interrupt, or an - * exception. - */ - if (!aborting() && did_emsg == save_did_emsg) { - EMSG2(_(e_invexpr2), p); - } - ret = FAIL; + ret = eval1_emsg(&arg, &rettv, !eap->skip); + if (ret == FAIL) { break; } diff --git a/src/nvim/testdir/test_filter_map.vim b/src/nvim/testdir/test_filter_map.vim index c8d64ce0a4..1dd3a5b29f 100644 --- a/src/nvim/testdir/test_filter_map.vim +++ b/src/nvim/testdir/test_filter_map.vim @@ -79,3 +79,8 @@ func Test_filter_map_dict_expr_funcref() endfunc call assert_equal({"foo": "f", "bar": "b", "baz": "b"}, map(copy(dict), function('s:filter4'))) endfunc + +func Test_map_fails() + call assert_fails('call map([1], "42 +")', 'E15:') + call assert_fails('call filter([1], "42 +")', 'E15:') +endfunc -- cgit From fa3db26f100bcb1c27b62b491bd63aed0800795b Mon Sep 17 00:00:00 2001 From: Jan Edmund Lazo Date: Sun, 23 Jun 2019 19:10:59 -0400 Subject: eval: assert VAR_LIST branch in filter_map() --- src/nvim/eval.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/nvim/eval.c b/src/nvim/eval.c index c5caf80700..f19fbe112f 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -8913,7 +8913,7 @@ static void filter_map(typval_T *argvars, typval_T *rettv, int map) } hash_unlock(ht); } else { - // argvars[0].v_type == VAR_LIST + assert(argvars[0].v_type == VAR_LIST); vimvars[VV_KEY].vv_type = VAR_NUMBER; for (listitem_T *li = tv_list_first(l); li != NULL;) { -- cgit