aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMatthieu Coudron <mattator@gmail.com>2020-04-13 22:49:00 +0200
committerGitHub <noreply@github.com>2020-04-13 22:49:00 +0200
commit93b2cb7a3824f91ee24ddf57406d5682699f684b (patch)
tree4ea7bb4aca7520a26a749b0958046ba52b450d4f /src
parent13b4a6fd4fa67794e76892cb362121a33a756f58 (diff)
parentcf223e7d78df5e8a63b84d423be55a29eefd8883 (diff)
downloadrneovim-93b2cb7a3824f91ee24ddf57406d5682699f684b.tar.gz
rneovim-93b2cb7a3824f91ee24ddf57406d5682699f684b.tar.bz2
rneovim-93b2cb7a3824f91ee24ddf57406d5682699f684b.zip
Merge pull request #11997 from janlazo/vim-8.1.2389
[RDY]vim-patch:8.1.{1745,2147,2280,2282,},8.2.{41,134,365,366,381,387,389,397,398,406,415,457,464,473,474,507,544,549}
Diffstat (limited to 'src')
-rw-r--r--src/nvim/api/buffer.c2
-rw-r--r--src/nvim/buffer.c1
-rw-r--r--src/nvim/eval.c22
-rw-r--r--src/nvim/eval.h2
-rw-r--r--src/nvim/eval/funcs.c27
-rw-r--r--src/nvim/extmark.c4
-rw-r--r--src/nvim/fileio.c22
-rw-r--r--src/nvim/normal.c5
-rw-r--r--src/nvim/ops.c2
-rw-r--r--src/nvim/option.c5
-rw-r--r--src/nvim/quickfix.c24
-rw-r--r--src/nvim/regexp.c35
-rw-r--r--src/nvim/screen.c80
-rw-r--r--src/nvim/search.c1
-rw-r--r--src/nvim/spell.c25
-rw-r--r--src/nvim/tag.c18
-rw-r--r--src/nvim/testdir/test_autocmd.vim77
-rw-r--r--src/nvim/testdir/test_expr.vim2
-rw-r--r--src/nvim/testdir/test_filetype.vim5
-rw-r--r--src/nvim/testdir/test_functions.vim10
-rw-r--r--src/nvim/testdir/test_hardcopy.vim169
-rw-r--r--src/nvim/testdir/test_maparg.vim7
-rw-r--r--src/nvim/testdir/test_mapping.vim74
-rw-r--r--src/nvim/testdir/test_profile.vim26
-rw-r--r--src/nvim/testdir/test_quickfix.vim8
-rw-r--r--src/nvim/testdir/test_quotestar.vim3
-rw-r--r--src/nvim/testdir/test_substitute.vim19
-rw-r--r--src/nvim/testdir/test_taglist.vim17
-rw-r--r--src/nvim/window.c12
29 files changed, 534 insertions, 170 deletions
diff --git a/src/nvim/api/buffer.c b/src/nvim/api/buffer.c
index 7578f0fbc5..b345dcaccd 100644
--- a/src/nvim/api/buffer.c
+++ b/src/nvim/api/buffer.c
@@ -1402,7 +1402,7 @@ Integer nvim_buf_add_highlight(Buffer buffer,
uint64_t ns_id = src2ns(&src_id);
- if (!(0 <= line && line < buf->b_ml.ml_line_count)) {
+ if (!(line < buf->b_ml.ml_line_count)) {
// safety check, we can't add marks outside the range
return src_id;
}
diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c
index c2573cf942..24ba43676a 100644
--- a/src/nvim/buffer.c
+++ b/src/nvim/buffer.c
@@ -1750,6 +1750,7 @@ buf_T * buflist_new(char_u *ffname, char_u *sfname, linenr_T lnum, int flags)
apply_autocmds(EVENT_BUFWIPEOUT, NULL, NULL, false, curbuf);
}
if (aborting()) { // autocmds may abort script processing
+ xfree(ffname);
return NULL;
}
if (buf == curbuf) {
diff --git a/src/nvim/eval.c b/src/nvim/eval.c
index dc20940166..12b13a1f08 100644
--- a/src/nvim/eval.c
+++ b/src/nvim/eval.c
@@ -6328,6 +6328,10 @@ call_func(
}
if (error == ERROR_NONE && partial->pt_argc > 0) {
for (argv_clear = 0; argv_clear < partial->pt_argc; argv_clear++) {
+ if (argv_clear + argcount_in >= MAX_FUNC_ARGS) {
+ error = ERROR_TOOMANY;
+ goto theend;
+ }
tv_copy(&partial->pt_argv[argv_clear], &argv[argv_clear]);
}
for (int i = 0; i < argcount_in; i++) {
@@ -6382,7 +6386,9 @@ call_func(
error = ERROR_DELETED;
} else if (fp != NULL) {
if (argv_func != NULL) {
- argcount = argv_func(argcount, argvars, fp->uf_args.ga_len);
+ // postponed filling in the arguments, do it now
+ argcount = argv_func(argcount, argvars, argv_clear,
+ fp->uf_args.ga_len);
}
if (fp->uf_flags & FC_RANGE) {
*doesrange = true;
@@ -6430,10 +6436,9 @@ call_func(
if (error == ERROR_NONE)
ret = OK;
- /*
- * Report an error unless the argument evaluation or function call has been
- * cancelled due to an aborting error, an interrupt, or an exception.
- */
+theend:
+ // Report an error unless the argument evaluation or function call has been
+ // cancelled due to an aborting error, an interrupt, or an exception.
if (!aborting()) {
switch (error) {
case ERROR_UNKNOWN:
@@ -7130,6 +7135,10 @@ void common_function(typval_T *argvars, typval_T *rettv,
list = argvars[arg_idx].vval.v_list;
if (tv_list_len(list) == 0) {
arg_idx = 0;
+ } else if (tv_list_len(list) > MAX_FUNC_ARGS) {
+ emsg_funcname((char *)e_toomanyarg, name);
+ xfree(name);
+ goto theend;
}
}
}
@@ -9527,7 +9536,8 @@ dictitem_T *find_var(const char *const name, const size_t name_len,
return find_var_in_scoped_ht(name, name_len, no_autoload || htp != NULL);
}
-/// Find variable in hashtab
+/// Find variable in hashtab.
+/// When "varname" is empty returns curwin/curtab/etc vars dictionary.
///
/// @param[in] ht Hashtab to find variable in.
/// @param[in] htname Hashtab name (first character).
diff --git a/src/nvim/eval.h b/src/nvim/eval.h
index 918823c311..7606d16f5d 100644
--- a/src/nvim/eval.h
+++ b/src/nvim/eval.h
@@ -187,7 +187,7 @@ extern const list_T *eval_msgpack_type_lists[LAST_MSGPACK_TYPE + 1];
#undef LAST_MSGPACK_TYPE
-typedef int (*ArgvFunc)(int current_argcount, typval_T *argv,
+typedef int (*ArgvFunc)(int current_argcount, typval_T *argv, int argskip,
int called_func_argcount);
/// trans_function_name() flags
diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c
index 8800e02295..21a6904674 100644
--- a/src/nvim/eval/funcs.c
+++ b/src/nvim/eval/funcs.c
@@ -2807,11 +2807,12 @@ static void f_getbufvar(typval_T *argvars, typval_T *rettv, FunPtr fptr)
buf_T *const buf = tv_get_buf(&argvars[0], false);
if (buf != NULL && varname != NULL) {
- // set curbuf to be our buf, temporarily
- buf_T *const save_curbuf = curbuf;
- curbuf = buf;
-
if (*varname == '&') { // buffer-local-option
+ buf_T *const save_curbuf = curbuf;
+
+ // set curbuf to be our buf, temporarily
+ curbuf = buf;
+
if (varname[1] == NUL) {
// get all buffer-local options in a dict
dict_T *opts = get_winbuf_options(true);
@@ -2824,19 +2825,21 @@ static void f_getbufvar(typval_T *argvars, typval_T *rettv, FunPtr fptr)
// buffer-local-option
done = true;
}
+
+ // restore previous notion of curbuf
+ curbuf = save_curbuf;
} else {
// Look up the variable.
// Let getbufvar({nr}, "") return the "b:" dictionary.
- dictitem_T *const v = find_var_in_ht(&curbuf->b_vars->dv_hashtab, 'b',
- varname, strlen(varname), false);
+ dictitem_T *const v = *varname == NUL
+ ? (dictitem_T *)&buf->b_bufvar
+ : find_var_in_ht(&buf->b_vars->dv_hashtab, 'b',
+ varname, strlen(varname), false);
if (v != NULL) {
tv_copy(&v->di_tv, rettv);
done = true;
}
}
-
- // restore previous notion of curbuf
- curbuf = save_curbuf;
}
emsg_off--;
@@ -5648,8 +5651,11 @@ static void f_matchadd(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
char grpbuf[NUMBUFLEN];
char patbuf[NUMBUFLEN];
+ // group
const char *const grp = tv_get_string_buf_chk(&argvars[0], grpbuf);
+ // pattern
const char *const pat = tv_get_string_buf_chk(&argvars[1], patbuf);
+ // default priority
int prio = 10;
int id = -1;
bool error = false;
@@ -7821,10 +7827,9 @@ static void f_setbufvar(typval_T *argvars, typval_T *rettv, FunPtr fptr)
// reset notion of buffer
aucmd_restbuf(&aco);
} else {
- buf_T *save_curbuf = curbuf;
-
const size_t varname_len = STRLEN(varname);
char *const bufvarname = xmalloc(varname_len + 3);
+ buf_T *const save_curbuf = curbuf;
curbuf = buf;
memcpy(bufvarname, "b:", 2);
memcpy(bufvarname + 2, varname, varname_len + 1);
diff --git a/src/nvim/extmark.c b/src/nvim/extmark.c
index e77b556024..38d111f2aa 100644
--- a/src/nvim/extmark.c
+++ b/src/nvim/extmark.c
@@ -789,7 +789,7 @@ bool decorations_redraw_start(buf_T *buf, int top_row,
ExtmarkItem *item = map_ref(uint64_t, ExtmarkItem)(buf->b_extmark_index,
start_id, false);
if ((!(mark.id&MARKTREE_END_FLAG) && altpos.row < top_row
- && !kv_size(item->virt_text))
+ && item && !kv_size(item->virt_text))
|| ((mark.id&MARKTREE_END_FLAG) && altpos.row >= top_row)) {
goto next_mark;
}
@@ -854,7 +854,7 @@ int decorations_redraw_col(buf_T *buf, int col, DecorationRedrawState *state)
if (endpos.row < mark.row
|| (endpos.row == mark.row && endpos.col <= mark.col)) {
- if (!kv_size(item->virt_text)) {
+ if (item && !kv_size(item->virt_text)) {
goto next_mark;
}
}
diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c
index e5845e0749..88e9390c65 100644
--- a/src/nvim/fileio.c
+++ b/src/nvim/fileio.c
@@ -407,11 +407,27 @@ readfile(
if (newfile) {
if (apply_autocmds_exarg(EVENT_BUFREADCMD, NULL, sfname,
- FALSE, curbuf, eap))
- return aborting() ? FAIL : OK;
+ false, curbuf, eap)) {
+ int status = OK;
+
+ if (aborting()) {
+ status = FAIL;
+ }
+
+ // The BufReadCmd code usually uses ":read" to get the text and
+ // perhaps ":file" to change the buffer name. But we should
+ // consider this to work like ":edit", thus reset the
+ // BF_NOTEDITED flag. Then ":write" will work to overwrite the
+ // same file.
+ if (status == OK) {
+ curbuf->b_flags &= ~BF_NOTEDITED;
+ }
+ return status;
+ }
} else if (apply_autocmds_exarg(EVENT_FILEREADCMD, sfname, sfname,
- FALSE, NULL, eap))
+ false, NULL, eap)) {
return aborting() ? FAIL : OK;
+ }
curbuf->b_op_start = pos;
}
diff --git a/src/nvim/normal.c b/src/nvim/normal.c
index be131f7e00..aca27e0208 100644
--- a/src/nvim/normal.c
+++ b/src/nvim/normal.c
@@ -615,7 +615,9 @@ static void normal_redraw_mode_message(NormalState *s)
kmsg = keep_msg;
keep_msg = NULL;
- // showmode() will clear keep_msg, but we want to use it anyway
+ // Showmode() will clear keep_msg, but we want to use it anyway.
+ // First update w_topline.
+ setcursor();
update_screen(0);
// now reset it, otherwise it's put in the history again
keep_msg = kmsg;
@@ -623,6 +625,7 @@ static void normal_redraw_mode_message(NormalState *s)
xfree(kmsg);
}
setcursor();
+ ui_cursor_shape(); // show different cursor shape
ui_flush();
if (msg_scroll || emsg_on_display) {
os_delay(1000L, true); // wait at least one second
diff --git a/src/nvim/ops.c b/src/nvim/ops.c
index 5457400b76..a70224f98b 100644
--- a/src/nvim/ops.c
+++ b/src/nvim/ops.c
@@ -261,7 +261,7 @@ void op_shift(oparg_T *oap, int curs_top, int amount)
sprintf((char *)IObuff, _("%" PRId64 " lines %sed %d times"),
(int64_t)oap->line_count, s, amount);
}
- msg(IObuff);
+ msg_attr_keep(IObuff, 0, true, false);
}
/*
diff --git a/src/nvim/option.c b/src/nvim/option.c
index 43a4a9fdf9..86a7d9b3c2 100644
--- a/src/nvim/option.c
+++ b/src/nvim/option.c
@@ -3668,7 +3668,7 @@ static char_u *set_chars_option(win_T *wp, char_u **varp, bool set)
}
// first round: check for valid value, second round: assign values
- for (round = 0; round <= set ? 1 : 0; round++) {
+ for (round = 0; round <= (set ? 1 : 0); round++) {
if (round > 0) {
// After checking that the value is valid: set defaults
for (i = 0; i < entries; i++) {
@@ -3843,11 +3843,12 @@ static char_u *did_set_spell_option(bool is_spellfile)
* Return error message when failed, NULL when OK.
*/
static char_u *compile_cap_prog(synblock_T *synblock)
+ FUNC_ATTR_NONNULL_ALL
{
regprog_T *rp = synblock->b_cap_prog;
char_u *re;
- if (*synblock->b_p_spc == NUL) {
+ if (synblock->b_p_spc == NULL || *synblock->b_p_spc == NUL) {
synblock->b_cap_prog = NULL;
} else {
// Prepend a ^ so that we only match at one column
diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c
index c444326533..484168e798 100644
--- a/src/nvim/quickfix.c
+++ b/src/nvim/quickfix.c
@@ -5134,6 +5134,7 @@ theend:
// Restore current working directory to "dirname_start" if they differ, taking
// into account whether it is set locally or globally.
static void restore_start_dir(char_u *dirname_start)
+ FUNC_ATTR_NONNULL_ALL
{
char_u *dirname_now = xmalloc(MAXPATHL);
@@ -5251,8 +5252,29 @@ load_dummy_buffer (
// directory to "dirname_start" prior to returning, if autocmds or the
// 'autochdir' option have changed it.
static void wipe_dummy_buffer(buf_T *buf, char_u *dirname_start)
+ FUNC_ATTR_NONNULL_ALL
{
- if (curbuf != buf) { // safety check
+ // If any autocommand opened a window on the dummy buffer, close that
+ // window. If we can't close them all then give up.
+ while (buf->b_nwindows > 0) {
+ bool did_one = false;
+
+ if (firstwin->w_next != NULL) {
+ for (win_T *wp = firstwin; wp != NULL; wp = wp->w_next) {
+ if (wp->w_buffer == buf) {
+ if (win_close(wp, false) == OK) {
+ did_one = true;
+ }
+ break;
+ }
+ }
+ }
+ if (!did_one) {
+ return;
+ }
+ }
+
+ if (curbuf != buf && buf->b_nwindows == 0) { // safety check
cleanup_T cs;
// Reset the error/interrupt/exception state here so that aborting()
diff --git a/src/nvim/regexp.c b/src/nvim/regexp.c
index 90dc8ab90f..5ad7ce9a16 100644
--- a/src/nvim/regexp.c
+++ b/src/nvim/regexp.c
@@ -6491,20 +6491,24 @@ typedef struct {
static regsubmatch_T rsm; // can only be used when can_f_submatch is true
-/// Put the submatches in "argv[0]" which is a list passed into call_func() by
-/// vim_regsub_both().
-static int fill_submatch_list(int argc, typval_T *argv, int argcount)
+/// Put the submatches in "argv[argskip]" which is a list passed into
+/// call_func() by vim_regsub_both().
+static int fill_submatch_list(int argc FUNC_ATTR_UNUSED, typval_T *argv,
+ int argskip, int argcount)
+ FUNC_ATTR_NONNULL_ALL
{
- if (argcount == 0) {
- // called function doesn't take an argument
- return 0;
+ typval_T *listarg = argv + argskip;
+
+ if (argcount == argskip) {
+ // called function doesn't take a submatches argument
+ return argskip;
}
// Relies on sl_list to be the first item in staticList10_T.
- tv_list_init_static10((staticList10_T *)argv->vval.v_list);
+ tv_list_init_static10((staticList10_T *)listarg->vval.v_list);
// There are always 10 list items in staticList10_T.
- listitem_T *li = tv_list_first(argv->vval.v_list);
+ listitem_T *li = tv_list_first(listarg->vval.v_list);
for (int i = 0; i < 10; i++) {
char_u *s = rsm.sm_match->startp[i];
if (s == NULL || rsm.sm_match->endp[i] == NULL) {
@@ -6516,7 +6520,7 @@ static int fill_submatch_list(int argc, typval_T *argv, int argcount)
TV_LIST_ITEM_TV(li)->vval.v_string = s;
li = TV_LIST_ITEM_NEXT(argv->vval.v_list, li);
}
- return 1;
+ return argskip + 1;
}
static void clear_submatch_list(staticList10_T *sl)
@@ -6679,10 +6683,15 @@ static int vim_regsub_both(char_u *source, typval_T *expr, char_u *dest,
// fill_submatch_list() was called.
clear_submatch_list(&matchList);
}
- char buf[NUMBUFLEN];
- eval_result = (char_u *)tv_get_string_buf_chk(&rettv, buf);
- if (eval_result != NULL) {
- eval_result = vim_strsave(eval_result);
+ if (rettv.v_type == VAR_UNKNOWN) {
+ // something failed, no need to report another error
+ eval_result = NULL;
+ } else {
+ char buf[NUMBUFLEN];
+ eval_result = (char_u *)tv_get_string_buf_chk(&rettv, buf);
+ if (eval_result != NULL) {
+ eval_result = vim_strsave(eval_result);
+ }
}
tv_clear(&rettv);
} else {
diff --git a/src/nvim/screen.c b/src/nvim/screen.c
index 5e303b0a47..9c590efdbc 100644
--- a/src/nvim/screen.c
+++ b/src/nvim/screen.c
@@ -2220,7 +2220,6 @@ win_line (
int tocol = MAXCOL; // end of inverting
int fromcol_prev = -2; // start of inverting after cursor
bool noinvcur = false; // don't invert the cursor
- pos_T *top, *bot;
int lnum_in_visual_area = false;
pos_T pos;
long v;
@@ -2420,6 +2419,8 @@ win_line (
// handle Visual active in this window
if (VIsual_active && wp->w_buffer == curwin->w_buffer) {
+ pos_T *top, *bot;
+
if (ltoreq(curwin->w_cursor, VIsual)) {
// Visual is after curwin->w_cursor
top = &curwin->w_cursor;
@@ -3160,8 +3161,8 @@ win_line (
shl->endcol += (*mb_ptr2len)(line + shl->endcol);
}
- /* Loop to check if the match starts at the
- * current position */
+ // Loop to check if the match starts at the
+ // current position
continue;
}
}
@@ -5732,12 +5733,11 @@ static void end_search_hl(void)
* Init for calling prepare_search_hl().
*/
static void init_search_hl(win_T *wp)
+ FUNC_ATTR_NONNULL_ALL
{
- matchitem_T *cur;
-
- /* Setup for match and 'hlsearch' highlighting. Disable any previous
- * match */
- cur = wp->w_match_head;
+ // Setup for match and 'hlsearch' highlighting. Disable any previous
+ // match
+ matchitem_T *cur = wp->w_match_head;
while (cur != NULL) {
cur->hl.rm = cur->match;
if (cur->hlg_id == 0)
@@ -5747,7 +5747,7 @@ static void init_search_hl(win_T *wp)
cur->hl.buf = wp->w_buffer;
cur->hl.lnum = 0;
cur->hl.first_lnum = 0;
- /* Set the time limit to 'redrawtime'. */
+ // Set the time limit to 'redrawtime'.
cur->hl.tm = profile_setlimit(p_rdt);
cur = cur->next;
}
@@ -5763,18 +5763,16 @@ static void init_search_hl(win_T *wp)
* Advance to the match in window "wp" line "lnum" or past it.
*/
static void prepare_search_hl(win_T *wp, linenr_T lnum)
+ FUNC_ATTR_NONNULL_ALL
{
- matchitem_T *cur; /* points to the match list */
- match_T *shl; /* points to search_hl or a match */
- int shl_flag; /* flag to indicate whether search_hl
- has been processed or not */
- int n;
-
- /*
- * When using a multi-line pattern, start searching at the top
- * of the window or just after a closed fold.
- * Do this both for search_hl and the match list.
- */
+ matchitem_T *cur; // points to the match list
+ match_T *shl; // points to search_hl or a match
+ bool shl_flag; // flag to indicate whether search_hl
+ // has been processed or not
+
+ // When using a multi-line pattern, start searching at the top
+ // of the window or just after a closed fold.
+ // Do this both for search_hl and the match list.
cur = wp->w_match_head;
shl_flag = false;
while (cur != NULL || shl_flag == false) {
@@ -5801,7 +5799,7 @@ static void prepare_search_hl(win_T *wp, linenr_T lnum)
}
bool pos_inprogress = true; // mark that a position match search is
// in progress
- n = 0;
+ int n = 0;
while (shl->first_lnum < lnum && (shl->rm.regprog != NULL
|| (cur != NULL && pos_inprogress))) {
next_search_hl(wp, shl, shl->first_lnum, (colnr_T)n,
@@ -5839,6 +5837,7 @@ next_search_hl (
colnr_T mincol, /* minimal column for a match */
matchitem_T *cur /* to retrieve match positions if any */
)
+ FUNC_ATTR_NONNULL_ARG(2)
{
linenr_T l;
colnr_T matchcol;
@@ -5846,11 +5845,10 @@ next_search_hl (
int save_called_emsg = called_emsg;
if (shl->lnum != 0) {
- /* Check for three situations:
- * 1. If the "lnum" is below a previous match, start a new search.
- * 2. If the previous match includes "mincol", use it.
- * 3. Continue after the previous match.
- */
+ // Check for three situations:
+ // 1. If the "lnum" is below a previous match, start a new search.
+ // 2. If the previous match includes "mincol", use it.
+ // 3. Continue after the previous match.
l = shl->lnum + shl->rm.endpos[0].lnum - shl->rm.startpos[0].lnum;
if (lnum > l)
shl->lnum = 0;
@@ -5864,22 +5862,21 @@ next_search_hl (
*/
called_emsg = FALSE;
for (;; ) {
- /* Stop searching after passing the time limit. */
+ // Stop searching after passing the time limit.
if (profile_passed_limit(shl->tm)) {
shl->lnum = 0; /* no match found in time */
break;
}
- /* Three situations:
- * 1. No useful previous match: search from start of line.
- * 2. Not Vi compatible or empty match: continue at next character.
- * Break the loop if this is beyond the end of the line.
- * 3. Vi compatible searching: continue at end of previous match.
- */
- if (shl->lnum == 0)
+ // Three situations:
+ // 1. No useful previous match: search from start of line.
+ // 2. Not Vi compatible or empty match: continue at next character.
+ // Break the loop if this is beyond the end of the line.
+ // 3. Vi compatible searching: continue at end of previous match.
+ if (shl->lnum == 0) {
matchcol = 0;
- else if (vim_strchr(p_cpo, CPO_SEARCH) == NULL
- || (shl->rm.endpos[0].lnum == 0
- && shl->rm.endpos[0].col <= shl->rm.startpos[0].col)) {
+ } else if (vim_strchr(p_cpo, CPO_SEARCH) == NULL
+ || (shl->rm.endpos[0].lnum == 0
+ && shl->rm.endpos[0].col <= shl->rm.startpos[0].col)) {
char_u *ml;
matchcol = shl->rm.startpos[0].col;
@@ -5896,8 +5893,8 @@ next_search_hl (
shl->lnum = lnum;
if (shl->rm.regprog != NULL) {
- /* Remember whether shl->rm is using a copy of the regprog in
- * cur->match. */
+ // Remember whether shl->rm is using a copy of the regprog in
+ // cur->match.
bool regprog_is_copy = (shl != &search_hl
&& cur != NULL
&& shl == &cur->hl
@@ -5926,7 +5923,7 @@ next_search_hl (
nmatched = next_search_hl_pos(shl, lnum, &(cur->pos), matchcol);
}
if (nmatched == 0) {
- shl->lnum = 0; /* no match found */
+ shl->lnum = 0; // no match found
break;
}
if (shl->rm.startpos[0].lnum > 0
@@ -5934,7 +5931,7 @@ next_search_hl (
|| nmatched > 1
|| shl->rm.endpos[0].col > mincol) {
shl->lnum += shl->rm.startpos[0].lnum;
- break; /* useful match found */
+ break; // useful match found
}
// Restore called_emsg for assert_fails().
@@ -5951,6 +5948,7 @@ next_search_hl_pos(
posmatch_T *posmatch, // match positions
colnr_T mincol // minimal column for a match
)
+ FUNC_ATTR_NONNULL_ALL
{
int i;
int found = -1;
diff --git a/src/nvim/search.c b/src/nvim/search.c
index 7d00785c74..23086c629b 100644
--- a/src/nvim/search.c
+++ b/src/nvim/search.c
@@ -1192,6 +1192,7 @@ int do_search(
len = STRLEN(p) + off_len + 3;
}
+ xfree(msgbuf);
msgbuf = xmalloc(len);
{
memset(msgbuf, ' ', len);
diff --git a/src/nvim/spell.c b/src/nvim/spell.c
index 6cb8d01f51..180073ade1 100644
--- a/src/nvim/spell.c
+++ b/src/nvim/spell.c
@@ -2827,9 +2827,6 @@ void spell_suggest(int count)
smsg(_("Sorry, only %" PRId64 " suggestions"),
(int64_t)sug.su_ga.ga_len);
} else {
- XFREE_CLEAR(repl_from);
- XFREE_CLEAR(repl_to);
-
// When 'rightleft' is set the list is drawn right-left.
cmdmsg_rl = curwin->w_p_rl;
if (cmdmsg_rl)
@@ -2909,6 +2906,9 @@ void spell_suggest(int count)
if (selected > 0 && selected <= sug.su_ga.ga_len && u_save_cursor() == OK) {
// Save the from and to text for :spellrepall.
+ XFREE_CLEAR(repl_from);
+ XFREE_CLEAR(repl_to);
+
stp = &SUG(sug.su_ga, selected - 1);
if (sug.su_badlen > stp->st_orglen) {
// Replacing less than "su_badlen", append the remainder to
@@ -5761,19 +5761,22 @@ cleanup_suggestions (
int maxscore,
int keep // nr of suggestions to keep
)
+ FUNC_ATTR_NONNULL_ALL
{
suggest_T *stp = &SUG(*gap, 0);
- // Sort the list.
- qsort(gap->ga_data, (size_t)gap->ga_len, sizeof(suggest_T), sug_compare);
+ if (gap->ga_len > 0) {
+ // Sort the list.
+ qsort(gap->ga_data, (size_t)gap->ga_len, sizeof(suggest_T), sug_compare);
- // Truncate the list to the number of suggestions that will be displayed.
- if (gap->ga_len > keep) {
- for (int i = keep; i < gap->ga_len; ++i) {
- xfree(stp[i].st_word);
+ // Truncate the list to the number of suggestions that will be displayed.
+ if (gap->ga_len > keep) {
+ for (int i = keep; i < gap->ga_len; i++) {
+ xfree(stp[i].st_word);
+ }
+ gap->ga_len = keep;
+ return stp[keep - 1].st_score;
}
- gap->ga_len = keep;
- return stp[keep - 1].st_score;
}
return maxscore;
}
diff --git a/src/nvim/tag.c b/src/nvim/tag.c
index 57bb43c846..ff07a00952 100644
--- a/src/nvim/tag.c
+++ b/src/nvim/tag.c
@@ -2540,7 +2540,9 @@ parse_match(
}
p += 2; // skip ";\""
if (*p++ == TAB) {
- while (ASCII_ISALPHA(*p)) {
+ // Accept ASCII alphabetic kind characters and any multi-byte
+ // character.
+ while (ASCII_ISALPHA(*p) || utfc_ptr2len(p) > 1) {
if (STRNCMP(p, "kind:", 5) == 0) {
tagp->tagkind = p + 5;
} else if (STRNCMP(p, "user_data:", 10) == 0) {
@@ -2559,19 +2561,22 @@ parse_match(
}
if (pt == NULL)
break;
- p = pt + 1;
+ p = pt;
+ MB_PTR_ADV(p);
}
}
}
if (tagp->tagkind != NULL) {
for (p = tagp->tagkind;
- *p && *p != '\t' && *p != '\r' && *p != '\n'; ++p)
- ;
+ *p && *p != '\t' && *p != '\r' && *p != '\n';
+ MB_PTR_ADV(p)) {
+ }
tagp->tagkind_end = p;
}
if (tagp->user_data != NULL) {
for (p = tagp->user_data;
- *p && *p != '\t' && *p != '\r' && *p != '\n'; p++) {
+ *p && *p != '\t' && *p != '\r' && *p != '\n';
+ MB_PTR_ADV(p)) {
}
tagp->user_data_end = p;
}
@@ -3181,7 +3186,8 @@ int get_tags(list_T *list, char_u *pat, char_u *buf_fname)
if (tp.command_end != NULL) {
for (char_u *p = tp.command_end + 3;
- *p != NUL && *p != '\n' && *p != '\r'; p++) {
+ *p != NUL && *p != '\n' && *p != '\r';
+ MB_PTR_ADV(p)) {
if (p == tp.tagkind
|| (p + 5 == tp.tagkind && STRNCMP(p, "kind:", 5) == 0)) {
// skip "kind:<kind>" and "<kind>"
diff --git a/src/nvim/testdir/test_autocmd.vim b/src/nvim/testdir/test_autocmd.vim
index e3547aea5b..954e5d875f 100644
--- a/src/nvim/testdir/test_autocmd.vim
+++ b/src/nvim/testdir/test_autocmd.vim
@@ -1072,6 +1072,40 @@ func Test_Cmd_Autocmds()
enew!
endfunc
+func s:ReadFile()
+ setl noswapfile nomodified
+ let filename = resolve(expand("<afile>:p"))
+ execute 'read' fnameescape(filename)
+ 1d_
+ exe 'file' fnameescape(filename)
+ setl buftype=acwrite
+endfunc
+
+func s:WriteFile()
+ let filename = resolve(expand("<afile>:p"))
+ setl buftype=
+ noautocmd execute 'write' fnameescape(filename)
+ setl buftype=acwrite
+ setl nomodified
+endfunc
+
+func Test_BufReadCmd()
+ autocmd BufReadCmd *.test call s:ReadFile()
+ autocmd BufWriteCmd *.test call s:WriteFile()
+
+ call writefile(['one', 'two', 'three'], 'Xcmd.test')
+ edit Xcmd.test
+ call assert_match('Xcmd.test" line 1 of 3', execute('file'))
+ normal! Gofour
+ write
+ call assert_equal(['one', 'two', 'three', 'four'], readfile('Xcmd.test'))
+
+ bwipe!
+ call delete('Xcmd.test')
+ au! BufReadCmd
+ au! BufWriteCmd
+endfunc
+
func SetChangeMarks(start, end)
exe a:start. 'mark ['
exe a:end. 'mark ]'
@@ -1786,3 +1820,46 @@ func Test_FileChangedShell_reload()
bwipe!
call delete('Xchanged')
endfunc
+
+" Test for FileReadCmd autocmd
+func Test_autocmd_FileReadCmd()
+ func ReadFileCmd()
+ call append(line('$'), "v:cmdarg = " .. v:cmdarg)
+ endfunc
+ augroup FileReadCmdTest
+ au!
+ au FileReadCmd Xtest call ReadFileCmd()
+ augroup END
+
+ new
+ read ++bin Xtest
+ read ++nobin Xtest
+ read ++edit Xtest
+ read ++bad=keep Xtest
+ read ++bad=drop Xtest
+ read ++bad=- Xtest
+ read ++ff=unix Xtest
+ read ++ff=dos Xtest
+ read ++ff=mac Xtest
+ read ++enc=utf-8 Xtest
+
+ call assert_equal(['',
+ \ 'v:cmdarg = ++bin',
+ \ 'v:cmdarg = ++nobin',
+ \ 'v:cmdarg = ++edit',
+ \ 'v:cmdarg = ++bad=keep',
+ \ 'v:cmdarg = ++bad=drop',
+ \ 'v:cmdarg = ++bad=-',
+ \ 'v:cmdarg = ++ff=unix',
+ \ 'v:cmdarg = ++ff=dos',
+ \ 'v:cmdarg = ++ff=mac',
+ \ 'v:cmdarg = ++enc=utf-8'], getline(1, '$'))
+
+ close!
+ augroup FileReadCmdTest
+ au!
+ augroup END
+ delfunc ReadFileCmd
+endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_expr.vim b/src/nvim/testdir/test_expr.vim
index dd546dbf71..264d8b000f 100644
--- a/src/nvim/testdir/test_expr.vim
+++ b/src/nvim/testdir/test_expr.vim
@@ -475,6 +475,8 @@ func Test_funcref()
let OneByRef = funcref('One')
call assert_equal(2, OneByRef())
call assert_fails('echo funcref("{")', 'E475:')
+ let OneByRef = funcref("One", repeat(["foo"], 20))
+ call assert_fails('let OneByRef = funcref("One", repeat(["foo"], 21))', 'E118:')
endfunc
func Test_empty_concatenate()
diff --git a/src/nvim/testdir/test_filetype.vim b/src/nvim/testdir/test_filetype.vim
index 9605348389..e4e48d2d35 100644
--- a/src/nvim/testdir/test_filetype.vim
+++ b/src/nvim/testdir/test_filetype.vim
@@ -79,6 +79,7 @@ let s:filename_checks = {
\ 'bib': ['file.bib'],
\ 'bindzone': ['named.root'],
\ 'blank': ['file.bl'],
+ \ 'bsdl': ['file.bsdl'],
\ 'bst': ['file.bst'],
\ 'bzr': ['bzr_log.any'],
\ 'c': ['enlightenment/file.cfg', 'file.qc', 'file.c'],
@@ -436,7 +437,7 @@ let s:filename_checks = {
\ 'swiftgyb': ['file.swift.gyb'],
\ 'sil': ['file.sil'],
\ 'sysctl': ['/etc/sysctl.conf', '/etc/sysctl.d/file.conf'],
- \ 'systemd': ['any/systemd/file.automount', 'any/systemd/file.mount', 'any/systemd/file.path', 'any/systemd/file.service', 'any/systemd/file.socket', 'any/systemd/file.swap', 'any/systemd/file.target', 'any/systemd/file.timer', '/etc/systemd/system/some.d/file.conf', '/etc/systemd/system/some.d/.#file'],
+ \ 'systemd': ['any/systemd/file.automount', 'any/systemd/file.mount', 'any/systemd/file.path', 'any/systemd/file.service', 'any/systemd/file.socket', 'any/systemd/file.swap', 'any/systemd/file.target', 'any/systemd/file.timer', '/etc/systemd/system/some.d/file.conf', '/etc/systemd/system/some.d/.#file', '/home/user/.config/systemd/user/some.d/mine.conf', '/home/user/.config/systemd/user/some.d/.#file'],
\ 'systemverilog': ['file.sv', 'file.svh'],
\ 'tags': ['tags'],
\ 'tak': ['file.tak'],
@@ -480,7 +481,7 @@ let s:filename_checks = {
\ 'verilog': ['file.v'],
\ 'verilogams': ['file.va', 'file.vams'],
\ 'vgrindefs': ['vgrindefs'],
- \ 'vhdl': ['file.hdl', 'file.vhd', 'file.vhdl', 'file.vbe', 'file.vst', 'file.vhdl_123'],
+ \ 'vhdl': ['file.hdl', 'file.vhd', 'file.vhdl', 'file.vbe', 'file.vst', 'file.vhdl_123', 'file.vho'],
\ 'vim': ['file.vim', 'file.vba', '.exrc', '_exrc'],
\ 'viminfo': ['.viminfo', '_viminfo'],
\ 'vmasm': ['file.mar'],
diff --git a/src/nvim/testdir/test_functions.vim b/src/nvim/testdir/test_functions.vim
index b75b095841..bd5cb6ad19 100644
--- a/src/nvim/testdir/test_functions.vim
+++ b/src/nvim/testdir/test_functions.vim
@@ -666,6 +666,16 @@ func Test_getbufvar()
call assert_equal('iso-8859-2', getbufvar(bufnr('%'), '&fenc'))
close
+ " Get the b: dict.
+ let b:testvar = 'one'
+ new
+ let b:testvar = 'two'
+ let thebuf = bufnr()
+ wincmd w
+ call assert_equal('two', getbufvar(thebuf, 'testvar'))
+ call assert_equal('two', getbufvar(thebuf, '').testvar)
+ bwipe!
+
set fileformats&
endfunc
diff --git a/src/nvim/testdir/test_hardcopy.vim b/src/nvim/testdir/test_hardcopy.vim
index ced13b107c..6125f9b993 100644
--- a/src/nvim/testdir/test_hardcopy.vim
+++ b/src/nvim/testdir/test_hardcopy.vim
@@ -1,39 +1,137 @@
" Test :hardcopy
-func Test_printoptions_parsing()
- " Only test that this doesn't throw an error.
- set printoptions=left:5in,right:10pt,top:8mm,bottom:2pc
- set printoptions=left:2in,top:30pt,right:16mm,bottom:3pc
- set printoptions=header:3,syntax:y,number:7,wrap:n
- set printoptions=duplex:short,collate:n,jobsplit:y,portrait:n
- set printoptions=paper:10x14
- set printoptions=paper:A3
- set printoptions=paper:A4
- set printoptions=paper:A5
- set printoptions=paper:B4
- set printoptions=paper:B5
- set printoptions=paper:executive
- set printoptions=paper:folio
- set printoptions=paper:ledger
- set printoptions=paper:legal
- set printoptions=paper:letter
- set printoptions=paper:quarto
- set printoptions=paper:statement
- set printoptions=paper:tabloid
- set printoptions=formfeed:y
- set printoptions=
- set printoptions&
+func Test_printoptions()
+ edit test_hardcopy.vim
+ syn on
+
+ for opt in ['left:5in,right:10pt,top:8mm,bottom:2pc',
+ \ 'left:2in,top:30pt,right:16mm,bottom:3pc',
+ \ 'header:3,syntax:y,number:y,wrap:n',
+ \ 'header:3,syntax:n,number:y,wrap:y',
+ \ 'duplex:short,collate:n,jobsplit:y,portrait:n',
+ \ 'duplex:long,collate:y,jobsplit:n,portrait:y',
+ \ 'paper:10x14',
+ \ 'paper:A3',
+ \ 'paper:A4',
+ \ 'paper:A5',
+ \ 'paper:B4',
+ \ 'paper:B5',
+ \ 'paper:executive',
+ \ 'paper:folio',
+ \ 'paper:ledger',
+ \ 'paper:legal',
+ \ 'paper:letter',
+ \ 'paper:quarto',
+ \ 'paper:statement',
+ \ 'paper:tabloid',
+ \ 'formfeed:y',
+ \ '']
+ exe 'set printoptions=' .. opt
+ if has('postscript')
+ hardcopy > Xhardcopy_printoptions
+ let lines = readfile('Xhardcopy_printoptions')
+ call assert_true(len(lines) > 20, opt)
+ call assert_true(lines[0] =~ 'PS-Adobe', opt)
+ call delete('Xhardcopy_printoptions')
+ endif
+ endfor
call assert_fails('set printoptions=paper', 'E550:')
call assert_fails('set printoptions=shredder:on', 'E551:')
call assert_fails('set printoptions=left:no', 'E552:')
+ set printoptions&
+ bwipe
endfunc
-func Test_printmbfont_parsing()
- " Only test that this doesn't throw an error.
- set printmbfont=r:WadaMin-Regular,b:WadaMin-Bold,i:WadaMin-Italic,o:WadaMin-Bold-Italic,c:yes,a:no
- set printmbfont=
+func Test_printmbfont()
+ " Print a small help page which contains tabs to cover code that expands tabs to spaces.
+ help help
+ syn on
+
+ for opt in [':WadaMin-Regular,b:WadaMin-Bold,i:WadaMin-Italic,o:WadaMin-Bold-Italic,c:yes,a:no',
+ \ '']
+ exe 'set printmbfont=' .. opt
+ if has('postscript')
+ hardcopy > Xhardcopy_printmbfont
+ let lines = readfile('Xhardcopy_printmbfont')
+ call assert_true(len(lines) > 20, opt)
+ call assert_true(lines[0] =~ 'PS-Adobe', opt)
+ call delete('Xhardcopy_printmbfont')
+ endif
+ endfor
set printmbfont&
+ bwipe
+endfunc
+
+func Test_printexpr()
+ if !has('unix')
+ return
+ endif
+
+ " Not a very useful printexpr value, but enough to test
+ " hardcopy with 'printexpr'.
+ function PrintFile(fname)
+ call writefile(['Test printexpr: ' .. v:cmdarg],
+ \ 'Xhardcopy_printexpr')
+ call delete(a:fname)
+ return 0
+ endfunc
+ set printexpr=PrintFile(v:fname_in)
+
+ help help
+ hardcopy dummy args
+ call assert_equal(['Test printexpr: dummy args'],
+ \ readfile('Xhardcopy_printexpr'))
+ call delete('Xhardcopy_printexpr')
+
+ " Function return 1 to test print failure.
+ function PrintFails(fname)
+ call delete(a:fname)
+ return 1
+ endfunc
+ set printexpr=PrintFails(v:fname_in)
+ call assert_fails('hardcopy', 'E365:')
+
+ set printexpr&
+ bwipe
+endfunc
+
+func Test_errors()
+ " FIXME: Windows fails differently than Unix.
+ if has('unix')
+ edit test_hardcopy.vim
+ call assert_fails('hardcopy >', 'E324:')
+ bwipe
+ endif
+endfunc
+
+func Test_dark_background()
+ edit test_hardcopy.vim
+ syn on
+
+ for bg in ['dark', 'light']
+ exe 'set background=' .. bg
+
+ if has('postscript')
+ hardcopy > Xhardcopy_dark_background
+ let lines = readfile('Xhardcopy_dark_background')
+ call assert_true(len(lines) > 20)
+ call assert_true(lines[0] =~ 'PS-Adobe')
+ call delete('Xhardcopy_dark_background')
+ endif
+ endfor
+
+ set background&
+ bwipe
+endfun
+
+func Test_empty_buffer()
+ " FIXME: Unclear why this fails on Windows.
+ if has('unix')
+ new
+ call assert_equal("\nNo text to be printed", execute('hardcopy'))
+ bwipe
+ endif
endfunc
func Test_printheader_parsing()
@@ -46,22 +144,6 @@ func Test_printheader_parsing()
set printheader&
endfunc
-" Test that :hardcopy produces a non-empty file.
-" We don't check much of the contents.
-func Test_with_syntax()
- if has('postscript')
- edit test_hardcopy.vim
- set printoptions=syntax:y
- syn on
- hardcopy > Xhardcopy
- let lines = readfile('Xhardcopy')
- call assert_true(len(lines) > 20)
- call assert_true(lines[0] =~ 'PS-Adobe')
- call delete('Xhardcopy')
- set printoptions&
- endif
-endfunc
-
func Test_fname_with_spaces()
if !has('postscript')
return
@@ -86,4 +168,3 @@ func Test_illegal_byte()
bwipe!
call delete('Xpstest')
endfunc
-
diff --git a/src/nvim/testdir/test_maparg.vim b/src/nvim/testdir/test_maparg.vim
index 0b941d51ec..5f73bd80ad 100644
--- a/src/nvim/testdir/test_maparg.vim
+++ b/src/nvim/testdir/test_maparg.vim
@@ -41,6 +41,11 @@ function Test_maparg()
map abc y<S-char-114>y
call assert_equal("yRy", maparg('abc'))
+ omap { w
+ let d = maparg('{', 'o', 0, 1)
+ call assert_equal(['{', 'w', 'o'], [d.lhs, d.rhs, d.mode])
+ ounmap {
+
map abc <Nop>
call assert_equal("<Nop>", maparg('abc'))
unmap abc
@@ -62,3 +67,5 @@ function Test_range_map()
execute "normal a\uf040\<Esc>"
call assert_equal("abcd", getline(1))
endfunction
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_mapping.vim b/src/nvim/testdir/test_mapping.vim
index f14f292a92..82562339f6 100644
--- a/src/nvim/testdir/test_mapping.vim
+++ b/src/nvim/testdir/test_mapping.vim
@@ -390,3 +390,77 @@ func Test_motionforce_omap()
delfunc Select
delfunc GetCommand
endfunc
+
+" Test for mapping errors
+func Test_map_error()
+ call assert_fails('unmap', 'E474:')
+ call assert_fails("exe 'map ' .. repeat('a', 51) .. ' :ls'", 'E474:')
+ call assert_fails('unmap abc', 'E31:')
+ call assert_fails('unabbr abc', 'E24:')
+ call assert_equal('', maparg(''))
+ call assert_fails('echo maparg("abc", [])', 'E730:')
+
+ " unique map
+ map ,w /[#&!]<CR>
+ call assert_fails("map <unique> ,w /[#&!]<CR>", 'E227:')
+ " unique buffer-local map
+ call assert_fails("map <buffer> <unique> ,w /[.,;]<CR>", 'E225:')
+ unmap ,w
+
+ " unique abbreviation
+ abbr SP special
+ call assert_fails("abbr <unique> SP special", 'E226:')
+ " unique buffer-local map
+ call assert_fails("abbr <buffer> <unique> SP special", 'E224:')
+ unabbr SP
+
+ call assert_fails('mapclear abc', 'E474:')
+ call assert_fails('abclear abc', 'E474:')
+endfunc
+
+" Test for <special> key mapping
+func Test_map_special()
+ throw 'skipped: Nvim does not support cpoptions flag "<"'
+ new
+ let old_cpo = &cpo
+ set cpo+=<
+ imap <F12> Blue
+ call feedkeys("i\<F12>", "x")
+ call assert_equal("<F12>", getline(1))
+ call feedkeys("ddi<F12>", "x")
+ call assert_equal("Blue", getline(1))
+ iunmap <F12>
+ imap <special> <F12> Green
+ call feedkeys("ddi\<F12>", "x")
+ call assert_equal("Green", getline(1))
+ call feedkeys("ddi<F12>", "x")
+ call assert_equal("<F12>", getline(1))
+ iunmap <special> <F12>
+ let &cpo = old_cpo
+ %bwipe!
+endfunc
+
+" Test for hasmapto()
+func Test_hasmapto()
+ call assert_equal(0, hasmapto('/^\k\+ ('))
+ call assert_equal(0, hasmapto('/^\k\+ (', 'n'))
+ nmap ,f /^\k\+ (<CR>
+ call assert_equal(1, hasmapto('/^\k\+ ('))
+ call assert_equal(1, hasmapto('/^\k\+ (', 'n'))
+ call assert_equal(0, hasmapto('/^\k\+ (', 'v'))
+
+ call assert_equal(0, hasmapto('/^\k\+ (', 'n', 1))
+endfunc
+
+" Test for command-line completion of maps
+func Test_mapcomplete()
+ call assert_equal(['<buffer>', '<expr>', '<nowait>', '<script>',
+ \ '<silent>', '<special>', '<unique>'],
+ \ getcompletion('', 'mapping'))
+ call assert_equal([], getcompletion(',d', 'mapping'))
+
+ call feedkeys(":abbr! \<C-A>\<C-B>\"\<CR>", 'tx')
+ call assert_match("abbr! \x01", @:)
+endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_profile.vim b/src/nvim/testdir/test_profile.vim
index f3eb88abf0..4b0097617e 100644
--- a/src/nvim/testdir/test_profile.vim
+++ b/src/nvim/testdir/test_profile.vim
@@ -16,6 +16,7 @@ func Test_profile_func()
while l:count > 0
let l:count = l:count - 1
endwhile
+ sleep 1m
endfunc
func! Foo3()
endfunc
@@ -51,7 +52,7 @@ func Test_profile_func()
" - Unlike Foo3(), Foo2() should not be deleted since there is a check
" for v:profiling.
" - Bar() is not reported since it does not match "profile func Foo*".
- call assert_equal(30, len(lines))
+ call assert_equal(31, len(lines))
call assert_equal('FUNCTION Foo1()', lines[0])
call assert_match('Defined:.*Xprofile_func.vim:3', lines[1])
@@ -71,17 +72,18 @@ func Test_profile_func()
call assert_match('^\s*101\s\+.*\swhile l:count > 0$', lines[16])
call assert_match('^\s*100\s\+.*\s let l:count = l:count - 1$', lines[17])
call assert_match('^\s*101\s\+.*\sendwhile$', lines[18])
- call assert_equal('', lines[19])
- call assert_equal('FUNCTIONS SORTED ON TOTAL TIME', lines[20])
- call assert_equal('count total (s) self (s) function', lines[21])
- call assert_match('^\s*1\s\+\d\+\.\d\+\s\+Foo2()$', lines[22])
- call assert_match('^\s*2\s\+\d\+\.\d\+\s\+Foo1()$', lines[23])
- call assert_equal('', lines[24])
- call assert_equal('FUNCTIONS SORTED ON SELF TIME', lines[25])
- call assert_equal('count total (s) self (s) function', lines[26])
- call assert_match('^\s*1\s\+\d\+\.\d\+\s\+Foo2()$', lines[27])
- call assert_match('^\s*2\s\+\d\+\.\d\+\s\+Foo1()$', lines[28])
- call assert_equal('', lines[29])
+ call assert_match('^\s*1\s\+.\+sleep 1m$', lines[19])
+ call assert_equal('', lines[20])
+ call assert_equal('FUNCTIONS SORTED ON TOTAL TIME', lines[21])
+ call assert_equal('count total (s) self (s) function', lines[22])
+ call assert_match('^\s*1\s\+\d\+\.\d\+\s\+Foo2()$', lines[23])
+ call assert_match('^\s*2\s\+\d\+\.\d\+\s\+Foo1()$', lines[24])
+ call assert_equal('', lines[25])
+ call assert_equal('FUNCTIONS SORTED ON SELF TIME', lines[26])
+ call assert_equal('count total (s) self (s) function', lines[27])
+ call assert_match('^\s*1\s\+\d\+\.\d\+\s\+Foo2()$', lines[28])
+ call assert_match('^\s*2\s\+\d\+\.\d\+\s\+Foo1()$', lines[29])
+ call assert_equal('', lines[30])
call delete('Xprofile_func.vim')
call delete('Xprofile_func.log')
diff --git a/src/nvim/testdir/test_quickfix.vim b/src/nvim/testdir/test_quickfix.vim
index 015f771435..35555ca9d3 100644
--- a/src/nvim/testdir/test_quickfix.vim
+++ b/src/nvim/testdir/test_quickfix.vim
@@ -3318,6 +3318,14 @@ func Test_lvimgrep_crash()
enew | only
endfunc
+func Test_lvimgrep_crash2()
+ au BufNewFile x sfind
+ call assert_fails('lvimgrep x x', 'E480:')
+ call assert_fails('lvimgrep x x x', 'E480:')
+
+ au! BufNewFile
+endfunc
+
" Test for the position of the quickfix and location list window
func Test_qfwin_pos()
" Open two windows
diff --git a/src/nvim/testdir/test_quotestar.vim b/src/nvim/testdir/test_quotestar.vim
index ce5a9ee827..77a5153a81 100644
--- a/src/nvim/testdir/test_quotestar.vim
+++ b/src/nvim/testdir/test_quotestar.vim
@@ -108,7 +108,8 @@ func Do_test_quotestar_for_x11()
call remote_send(name, ":gui -f\<CR>")
endif
" Wait for the server in the GUI to be up and answering requests.
- call WaitForAssert({-> assert_match("1", remote_expr(name, "has('gui_running')", "", 1))})
+ " On some systems and with valgrind this can be very slow.
+ call WaitForAssert({-> assert_match("1", remote_expr(name, "has('gui_running')", "", 1))}, 10000)
call remote_send(name, ":let @* = 'maybe'\<CR>")
call WaitForAssert({-> assert_equal("maybe", remote_expr(name, "@*", "", 2))})
diff --git a/src/nvim/testdir/test_substitute.vim b/src/nvim/testdir/test_substitute.vim
index e94bd22cea..ff07d8eceb 100644
--- a/src/nvim/testdir/test_substitute.vim
+++ b/src/nvim/testdir/test_substitute.vim
@@ -613,6 +613,25 @@ func Test_sub_replace_10()
call assert_equal('1aaa', substitute('123', '1\zs\|[23]', 'a', 'g'))
endfunc
+func SubReplacer(text, submatches)
+ return a:text .. a:submatches[0] .. a:text
+endfunc
+func SubReplacer20(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15, t16, t17, t18, t19, submatches)
+ return a:t3 .. a:submatches[0] .. a:t11
+endfunc
+
+func Test_substitute_partial()
+ call assert_equal('1foo2foo3', substitute('123', '2', function('SubReplacer', ['foo']), 'g'))
+
+ " 19 arguments plus one is just OK
+ let Replacer = function('SubReplacer20', repeat(['foo'], 19))
+ call assert_equal('1foo2foo3', substitute('123', '2', Replacer, 'g'))
+
+ " 20 arguments plus one is too many
+ let Replacer = function('SubReplacer20', repeat(['foo'], 20))
+ call assert_fails("call substitute('123', '2', Replacer, 'g')", 'E118')
+endfunc
+
func Test_sub_cmd_9()
new
let input = ['1 aaa', '2 aaa', '3 aaa']
diff --git a/src/nvim/testdir/test_taglist.vim b/src/nvim/testdir/test_taglist.vim
index cb54ace695..d4ff42fd68 100644
--- a/src/nvim/testdir/test_taglist.vim
+++ b/src/nvim/testdir/test_taglist.vim
@@ -7,6 +7,7 @@ func Test_taglist()
\ "BFoo\tXbar\t1",
\ "BBar\tXbar\t2",
\ "Kindly\tXbar\t3;\"\tv\tfile:",
+ \ "Lambda\tXbar\t3;\"\tλ\tfile:",
\ "Command\tXbar\tcall cursor(3, 4)|;\"\td",
\ ], 'Xtags')
set tags=Xtags
@@ -17,12 +18,16 @@ func Test_taglist()
call assert_equal(['FFoo', 'BFoo'], map(taglist("Foo", "Xfoo"), {i, v -> v.name}))
call assert_equal(['BFoo', 'FFoo'], map(taglist("Foo", "Xbar"), {i, v -> v.name}))
- let kind = taglist("Kindly")
- call assert_equal(1, len(kind))
- call assert_equal('v', kind[0]['kind'])
- call assert_equal('3', kind[0]['cmd'])
- call assert_equal(1, kind[0]['static'])
- call assert_equal('Xbar', kind[0]['filename'])
+ let kindly = taglist("Kindly")
+ call assert_equal(1, len(kindly))
+ call assert_equal('v', kindly[0]['kind'])
+ call assert_equal('3', kindly[0]['cmd'])
+ call assert_equal(1, kindly[0]['static'])
+ call assert_equal('Xbar', kindly[0]['filename'])
+
+ let lambda = taglist("Lambda")
+ call assert_equal(1, len(lambda))
+ call assert_equal('λ', lambda[0]['kind'])
let cmd = taglist("Command")
call assert_equal(1, len(cmd))
diff --git a/src/nvim/window.c b/src/nvim/window.c
index 9ec47f8e89..a89715ff79 100644
--- a/src/nvim/window.c
+++ b/src/nvim/window.c
@@ -6544,10 +6544,12 @@ void restore_buffer(bufref_T *save_curbuf)
/// @param[in] id a desired ID 'id' can be specified
/// (greater than or equal to 1). -1 must be specified if no
/// particular ID is desired
+/// @param[in] conceal_char pointer to conceal replacement char
/// @return ID of added match, -1 on failure.
int match_add(win_T *wp, const char *const grp, const char *const pat,
int prio, int id, list_T *pos_list,
const char *const conceal_char)
+ FUNC_ATTR_NONNULL_ARG(1, 2)
{
matchitem_T *cur;
matchitem_T *prev;
@@ -6584,7 +6586,7 @@ int match_add(win_T *wp, const char *const grp, const char *const pat,
return -1;
}
- /* Find available match ID. */
+ // Find available match ID.
while (id == -1) {
cur = wp->w_match_head;
while (cur != NULL && cur->id != wp->w_next_match_id)
@@ -6594,7 +6596,7 @@ int match_add(win_T *wp, const char *const grp, const char *const pat,
wp->w_next_match_id++;
}
- /* Build new match. */
+ // Build new match.
m = xcalloc(1, sizeof(matchitem_T));
m->id = id;
m->priority = prio;
@@ -6702,9 +6704,9 @@ int match_add(win_T *wp, const char *const grp, const char *const pat,
rtype = VALID;
}
}
-
- /* Insert new match. The match list is in ascending order with regard to
- * the match priorities. */
+
+ // Insert new match. The match list is in ascending order with regard to
+ // the match priorities.
cur = wp->w_match_head;
prev = cur;
while (cur != NULL && prio >= cur->priority) {