aboutsummaryrefslogtreecommitdiff
path: root/src/nvim
diff options
context:
space:
mode:
authorJustin M. Keyes <justinkz@gmail.com>2019-10-02 22:43:59 -0700
committerGitHub <noreply@github.com>2019-10-02 22:43:59 -0700
commit30479417e808eac338025dbbfbd3724e158fb344 (patch)
treea8f0e660fc18436506f323d0e2be0eb3236485b6 /src/nvim
parentb069e9b20f9e1f24fde34bee7d6e5d95f47ef10d (diff)
parent4518f230fa84e66737f6fc313fb669984974a1fd (diff)
downloadrneovim-30479417e808eac338025dbbfbd3724e158fb344.tar.gz
rneovim-30479417e808eac338025dbbfbd3724e158fb344.tar.bz2
rneovim-30479417e808eac338025dbbfbd3724e158fb344.zip
Merge #11087 from janlazo/vim-8.1.0010
vim-patch:8.1.{10,230,315,330,514,517,518,1327,1347,1758,2072,2074,2091,2095,2103}
Diffstat (limited to 'src/nvim')
-rw-r--r--src/nvim/buffer.c7
-rw-r--r--src/nvim/eval.c2
-rw-r--r--src/nvim/ex_docmd.c2
-rw-r--r--src/nvim/fileio.c2
-rw-r--r--src/nvim/getchar.c4
-rw-r--r--src/nvim/normal.c19
-rw-r--r--src/nvim/quickfix.c420
-rw-r--r--src/nvim/testdir/runtest.vim1
-rw-r--r--src/nvim/testdir/test_normal.vim240
-rw-r--r--src/nvim/testdir/test_quickfix.vim14
-rw-r--r--src/nvim/testdir/test_window_cmd.vim102
-rw-r--r--src/nvim/window.c24
12 files changed, 577 insertions, 260 deletions
diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c
index b50c764ac3..e5b80693a4 100644
--- a/src/nvim/buffer.c
+++ b/src/nvim/buffer.c
@@ -5179,6 +5179,13 @@ bool bt_help(const buf_T *const buf)
return buf != NULL && buf->b_help;
}
+// Return true if "buf" is a normal buffer, 'buftype' is empty.
+bool bt_normal(const buf_T *const buf)
+ FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
+{
+ return buf != NULL && buf->b_p_bt[0] == NUL;
+}
+
// Return true if "buf" is the quickfix buffer.
bool bt_quickfix(const buf_T *const buf)
FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
diff --git a/src/nvim/eval.c b/src/nvim/eval.c
index cb1dd1d631..e3e5bb9a90 100644
--- a/src/nvim/eval.c
+++ b/src/nvim/eval.c
@@ -5746,13 +5746,13 @@ static int dict_get_tv(char_u **arg, typval_T *rettv, int evaluate)
goto failret;
}
item = tv_dict_item_alloc((const char *)key);
- tv_clear(&tvkey);
item->di_tv = tv;
item->di_tv.v_lock = 0;
if (tv_dict_add(d, item) == FAIL) {
tv_dict_item_free(item);
}
}
+ tv_clear(&tvkey);
if (**arg == '}')
break;
diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c
index a6931f3acd..34b4c10d3e 100644
--- a/src/nvim/ex_docmd.c
+++ b/src/nvim/ex_docmd.c
@@ -9553,7 +9553,7 @@ put_view(
*/
if ((*flagp & SSOP_FOLDS)
&& wp->w_buffer->b_ffname != NULL
- && (*wp->w_buffer->b_p_bt == NUL || bt_help(wp->w_buffer))
+ && (bt_normal(wp->w_buffer) || bt_help(wp->w_buffer))
) {
if (put_folds(fd, wp) == FAIL)
return FAIL;
diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c
index 4cf42b41e9..0394639a16 100644
--- a/src/nvim/fileio.c
+++ b/src/nvim/fileio.c
@@ -4834,7 +4834,7 @@ buf_check_timestamp(
if (buf->terminal
|| buf->b_ffname == NULL
|| buf->b_ml.ml_mfp == NULL
- || *buf->b_p_bt != NUL
+ || !bt_normal(buf)
|| buf->b_saving
|| busy
)
diff --git a/src/nvim/getchar.c b/src/nvim/getchar.c
index 2469bb5baa..af642a8e11 100644
--- a/src/nvim/getchar.c
+++ b/src/nvim/getchar.c
@@ -1165,12 +1165,12 @@ void free_typebuf(void)
if (typebuf.tb_buf == typebuf_init) {
internal_error("Free typebuf 1");
} else {
- xfree(typebuf.tb_buf);
+ XFREE_CLEAR(typebuf.tb_buf);
}
if (typebuf.tb_noremap == noremapbuf_init) {
internal_error("Free typebuf 2");
} else {
- xfree(typebuf.tb_noremap);
+ XFREE_CLEAR(typebuf.tb_noremap);
}
}
diff --git a/src/nvim/normal.c b/src/nvim/normal.c
index 4dfde96e94..e32b738c7e 100644
--- a/src/nvim/normal.c
+++ b/src/nvim/normal.c
@@ -3932,11 +3932,11 @@ static bool nv_screengo(oparg_T *oap, int dir, long dist)
while (dist--) {
if (dir == BACKWARD) {
- if ((long)curwin->w_curswant >= width2)
- /* move back within line */
+ if (curwin->w_curswant > width2) {
+ // move back within line
curwin->w_curswant -= width2;
- else {
- /* to previous line */
+ } else {
+ // to previous line
if (curwin->w_cursor.lnum == 1) {
retval = false;
break;
@@ -4680,9 +4680,8 @@ static void nv_ctrlo(cmdarg_T *cap)
}
}
-/*
- * CTRL-^ command, short for ":e #"
- */
+// CTRL-^ command, short for ":e #". Works even when the alternate buffer is
+// not named.
static void nv_hat(cmdarg_T *cap)
{
if (!checkclearopq(cap->oap))
@@ -6795,10 +6794,14 @@ static void nv_g_cmd(cmdarg_T *cap)
} else if (nv_screengo(oap, FORWARD, cap->count1 - 1) == false)
clearopbeep(oap);
} else {
+ if (cap->count1 > 1) {
+ // if it fails, let the cursor still move to the last char
+ cursor_down(cap->count1 - 1, false);
+ }
i = curwin->w_leftcol + curwin->w_width_inner - col_off - 1;
coladvance((colnr_T)i);
- /* Make sure we stick in this column. */
+ // Make sure we stick in this column.
validate_virtcol();
curwin->w_curswant = curwin->w_virtcol;
curwin->w_set_curswant = false;
diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c
index 528829e63d..c5e8d4b490 100644
--- a/src/nvim/quickfix.c
+++ b/src/nvim/quickfix.c
@@ -264,15 +264,152 @@ static struct fmtpattern
{ 'o', ".\\+" }
};
+// Convert an errorformat pattern to a regular expression pattern.
+// See fmt_pat definition above for the list of supported patterns.
+static char_u *fmtpat_to_regpat(
+ const char_u *efmp,
+ efm_T *fmt_ptr,
+ int idx,
+ int round,
+ char_u *ptr,
+ char_u *errmsg,
+ size_t errmsglen)
+ FUNC_ATTR_NONNULL_ALL
+{
+ if (fmt_ptr->addr[idx]) {
+ // Each errorformat pattern can occur only once
+ snprintf((char *)errmsg, errmsglen,
+ _("E372: Too many %%%c in format string"), *efmp);
+ EMSG(errmsg);
+ return NULL;
+ }
+ if ((idx && idx < 6
+ && vim_strchr((char_u *)"DXOPQ", fmt_ptr->prefix) != NULL)
+ || (idx == 6
+ && vim_strchr((char_u *)"OPQ", fmt_ptr->prefix) == NULL)) {
+ snprintf((char *)errmsg, errmsglen,
+ _("E373: Unexpected %%%c in format string"), *efmp);
+ EMSG(errmsg);
+ return NULL;
+ }
+ fmt_ptr->addr[idx] = (char_u)++round;
+ *ptr++ = '\\';
+ *ptr++ = '(';
+#ifdef BACKSLASH_IN_FILENAME
+ if (*efmp == 'f') {
+ // Also match "c:" in the file name, even when
+ // checking for a colon next: "%f:".
+ // "\%(\a:\)\="
+ STRCPY(ptr, "\\%(\\a:\\)\\=");
+ ptr += 10;
+ }
+#endif
+ if (*efmp == 'f' && efmp[1] != NUL) {
+ if (efmp[1] != '\\' && efmp[1] != '%') {
+ // A file name may contain spaces, but this isn't
+ // in "\f". For "%f:%l:%m" there may be a ":" in
+ // the file name. Use ".\{-1,}x" instead (x is
+ // the next character), the requirement that :999:
+ // follows should work.
+ STRCPY(ptr, ".\\{-1,}");
+ ptr += 7;
+ } else {
+ // File name followed by '\\' or '%': include as
+ // many file name chars as possible.
+ STRCPY(ptr, "\\f\\+");
+ ptr += 4;
+ }
+ } else {
+ char_u *srcptr = (char_u *)fmt_pat[idx].pattern;
+ while ((*ptr = *srcptr++) != NUL) {
+ ptr++;
+ }
+ }
+ *ptr++ = '\\';
+ *ptr++ = ')';
+
+ return ptr;
+}
+
+// Convert a scanf like format in 'errorformat' to a regular expression.
+static char_u *scanf_fmt_to_regpat(
+ const char_u *efm,
+ int len,
+ const char_u **pefmp,
+ char_u *ptr,
+ char_u *errmsg,
+ size_t errmsglen)
+ FUNC_ATTR_NONNULL_ALL
+{
+ const char_u *efmp = *pefmp;
+
+ if (*++efmp == '[' || *efmp == '\\') {
+ if ((*ptr++ = *efmp) == '[') { // %*[^a-z0-9] etc.
+ if (efmp[1] == '^') {
+ *ptr++ = *++efmp;
+ }
+ if (efmp < efm + len) {
+ *ptr++ = *++efmp; // could be ']'
+ while (efmp < efm + len && (*ptr++ = *++efmp) != ']') {
+ }
+ if (efmp == efm + len) {
+ EMSG(_("E374: Missing ] in format string"));
+ return NULL;
+ }
+ }
+ } else if (efmp < efm + len) { // %*\D, %*\s etc.
+ *ptr++ = *++efmp;
+ }
+ *ptr++ = '\\';
+ *ptr++ = '+';
+ } else {
+ // TODO(vim): scanf()-like: %*ud, %*3c, %*f, ... ?
+ snprintf((char *)errmsg, errmsglen,
+ _("E375: Unsupported %%%c in format string"), *efmp);
+ EMSG(errmsg);
+ return NULL;
+ }
+
+ *pefmp = efmp;
+
+ return ptr;
+}
+
+// Analyze/parse an errorformat prefix.
+static int efm_analyze_prefix(const char_u **pefmp, efm_T *fmt_ptr,
+ char_u *errmsg, size_t errmsglen)
+ FUNC_ATTR_NONNULL_ALL
+{
+ const char_u *efmp = *pefmp;
+
+ if (vim_strchr((char_u *)"+-", *efmp) != NULL) {
+ fmt_ptr->flags = *efmp++;
+ }
+ if (vim_strchr((char_u *)"DXAEWICZGOPQ", *efmp) != NULL) {
+ fmt_ptr->prefix = *efmp;
+ } else {
+ snprintf((char *)errmsg, errmsglen,
+ _("E376: Invalid %%%c in format string prefix"), *efmp);
+ EMSG(errmsg);
+ return FAIL;
+ }
+
+ *pefmp = efmp;
+
+ return OK;
+}
+
+
// Converts a 'errorformat' string to regular expression pattern
-static int efm_to_regpat(char_u *efm, int len, efm_T *fmt_ptr,
- char_u *regpat, char_u *errmsg)
+static int efm_to_regpat(const char_u *efm, int len, efm_T *fmt_ptr,
+ char_u *regpat, char_u *errmsg, size_t errmsglen)
+ FUNC_ATTR_NONNULL_ALL
{
// Build regexp pattern from current 'errorformat' option
char_u *ptr = regpat;
*ptr++ = '^';
int round = 0;
- for (char_u *efmp = efm; efmp < efm + len; efmp++) {
+ for (const char_u *efmp = efm; efmp < efm + len; efmp++) {
if (*efmp == '%') {
efmp++;
int idx;
@@ -282,89 +419,15 @@ static int efm_to_regpat(char_u *efm, int len, efm_T *fmt_ptr,
}
}
if (idx < FMT_PATTERNS) {
- if (fmt_ptr->addr[idx]) {
- snprintf((char *)errmsg, CMDBUFFSIZE + 1,
- _("E372: Too many %%%c in format string"), *efmp);
- EMSG(errmsg);
- return -1;
- }
- if ((idx
- && idx < 6
- && vim_strchr((char_u *)"DXOPQ", fmt_ptr->prefix) != NULL)
- || (idx == 6
- && vim_strchr((char_u *)"OPQ", fmt_ptr->prefix) == NULL)) {
- snprintf((char *)errmsg, CMDBUFFSIZE + 1,
- _("E373: Unexpected %%%c in format string"), *efmp);
- EMSG(errmsg);
+ ptr = fmtpat_to_regpat(efmp, fmt_ptr, idx, round, ptr,
+ errmsg, errmsglen);
+ if (ptr == NULL) {
return -1;
}
round++;
- fmt_ptr->addr[idx] = (char_u)round;
- *ptr++ = '\\';
- *ptr++ = '(';
-#ifdef BACKSLASH_IN_FILENAME
- if (*efmp == 'f') {
- // Also match "c:" in the file name, even when
- // checking for a colon next: "%f:".
- // "\%(\a:\)\="
- STRCPY(ptr, "\\%(\\a:\\)\\=");
- ptr += 10;
- }
-#endif
- if (*efmp == 'f' && efmp[1] != NUL) {
- if (efmp[1] != '\\' && efmp[1] != '%') {
- // A file name may contain spaces, but this isn't
- // in "\f". For "%f:%l:%m" there may be a ":" in
- // the file name. Use ".\{-1,}x" instead (x is
- // the next character), the requirement that :999:
- // follows should work.
- STRCPY(ptr, ".\\{-1,}");
- ptr += 7;
- } else {
- // File name followed by '\\' or '%': include as
- // many file name chars as possible.
- STRCPY(ptr, "\\f\\+");
- ptr += 4;
- }
- } else {
- char_u *srcptr = (char_u *)fmt_pat[idx].pattern;
- while ((*ptr = *srcptr++) != NUL) {
- ptr++;
- }
- }
- *ptr++ = '\\';
- *ptr++ = ')';
} else if (*efmp == '*') {
- if (*++efmp == '[' || *efmp == '\\') {
- if ((*ptr++ = *efmp) == '[') { // %*[^a-z0-9] etc.
- if (efmp[1] == '^') {
- *ptr++ = *++efmp;
- }
- if (efmp < efm + len) {
- efmp++;
- *ptr++ = *efmp; // could be ']'
- while (efmp < efm + len) {
- efmp++;
- if ((*ptr++ = *efmp) == ']') {
- break;
- }
- }
- if (efmp == efm + len) {
- EMSG(_("E374: Missing ] in format string"));
- return -1;
- }
- }
- } else if (efmp < efm + len) { // %*\D, %*\s etc.
- efmp++;
- *ptr++ = *efmp;
- }
- *ptr++ = '\\';
- *ptr++ = '+';
- } else {
- // TODO(vim): scanf()-like: %*ud, %*3c, %*f, ... ?
- snprintf((char *)errmsg, CMDBUFFSIZE + 1,
- _("E375: Unsupported %%%c in format string"), *efmp);
- EMSG(errmsg);
+ ptr = scanf_fmt_to_regpat(efm, len, &efmp, ptr, errmsg, errmsglen);
+ if (ptr == NULL) {
return -1;
}
} else if (vim_strchr((char_u *)"%\\.^$~[", *efmp) != NULL) {
@@ -374,15 +437,7 @@ static int efm_to_regpat(char_u *efm, int len, efm_T *fmt_ptr,
} else if (*efmp == '>') {
fmt_ptr->conthere = true;
} else if (efmp == efm + 1) { // analyse prefix
- if (vim_strchr((char_u *)"+-", *efmp) != NULL) {
- fmt_ptr->flags = *efmp++;
- }
- if (vim_strchr((char_u *)"DXAEWICZGOPQ", *efmp) != NULL) {
- fmt_ptr->prefix = *efmp;
- } else {
- snprintf((char *)errmsg, CMDBUFFSIZE + 1,
- _("E376: Invalid %%%c in format string prefix"), *efmp);
- EMSG(errmsg);
+ if (efm_analyze_prefix(&efmp, fmt_ptr, errmsg, errmsglen) == FAIL) {
return -1;
}
} else {
@@ -461,7 +516,7 @@ static efm_T * parse_efm_option(char_u *efm)
}
}
- if (efm_to_regpat(efm, len, fmt_ptr, fmtstr, errmsg) == -1) {
+ if (efm_to_regpat(efm, len, fmt_ptr, fmtstr, errmsg, errmsglen) == -1) {
goto parse_efm_error;
}
if ((fmt_ptr->prog = vim_regcomp(fmtstr, RE_MAGIC + RE_STRING)) == NULL) {
@@ -1499,6 +1554,7 @@ static int qf_add_entry(qf_info_T *qi, int qf_idx, char_u *dir, char_u *fname,
* Allocate a new location list
*/
static qf_info_T *ll_new_list(void)
+ FUNC_ATTR_NONNULL_RET
{
qf_info_T *qi = xcalloc(1, sizeof(qf_info_T));
qi->qf_refcount++;
@@ -2084,7 +2140,7 @@ static win_T *qf_find_win_with_normal_buf(void)
FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
{
FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
- if (wp->w_buffer->b_p_bt[0] == NUL) {
+ if (bt_normal(wp->w_buffer)) {
return wp;
}
}
@@ -2148,7 +2204,7 @@ static void qf_goto_win_with_ll_file(win_T *use_win, int qf_fnum,
// Find a previous usable window
win = curwin;
do {
- if (win->w_buffer->b_p_bt[0] == NUL) {
+ if (bt_normal(win->w_buffer)) {
break;
}
if (win->w_prev == NULL) {
@@ -2202,7 +2258,7 @@ static void qf_goto_win_with_qfl_file(int qf_fnum)
// Remember a usable window.
if (altwin == NULL
&& !win->w_p_pvw
- && win->w_buffer->b_p_bt[0] == NUL) {
+ && bt_normal(win->w_buffer)) {
altwin = win;
}
}
@@ -4412,7 +4468,7 @@ void ex_vimgrep(exarg_T *eap)
goto theend;
}
- /* Jump to first match. */
+ // Jump to first match.
if (qi->qf_lists[qi->qf_curlist].qf_count > 0) {
if ((flags & VGR_NOJUMP) == 0) {
vgr_jump_to_match(qi, eap->forceit, &redraw_for_dummy, first_match_buf,
@@ -4974,15 +5030,86 @@ int qf_get_properties(win_T *wp, dict_T *what, dict_T *retdict)
return status;
}
+// Add a new quickfix entry to list at 'qf_idx' in the stack 'qi' from the
+// items in the dict 'd'.
+static int qf_add_entry_from_dict(
+ qf_info_T *qi,
+ int qf_idx,
+ const dict_T *d,
+ bool first_entry)
+ FUNC_ATTR_NONNULL_ALL
+{
+ static bool did_bufnr_emsg;
+
+ if (first_entry) {
+ did_bufnr_emsg = false;
+ }
+
+ char *const filename = tv_dict_get_string(d, "filename", true);
+ char *const module = tv_dict_get_string(d, "module", true);
+ int bufnum = (int)tv_dict_get_number(d, "bufnr");
+ const long lnum = (long)tv_dict_get_number(d, "lnum");
+ const int col = (int)tv_dict_get_number(d, "col");
+ const char_u vcol = (char_u)tv_dict_get_number(d, "vcol");
+ const int nr = (int)tv_dict_get_number(d, "nr");
+ const char *const type = tv_dict_get_string(d, "type", false);
+ char *const pattern = tv_dict_get_string(d, "pattern", true);
+ char *text = tv_dict_get_string(d, "text", true);
+ if (text == NULL) {
+ text = xcalloc(1, 1);
+ }
+ bool valid = true;
+ if ((filename == NULL && bufnum == 0)
+ || (lnum == 0 && pattern == NULL)) {
+ valid = false;
+ }
+
+ // Mark entries with non-existing buffer number as not valid. Give the
+ // error message only once.
+ if (bufnum != 0 && (buflist_findnr(bufnum) == NULL)) {
+ if (!did_bufnr_emsg) {
+ did_bufnr_emsg = true;
+ EMSGN(_("E92: Buffer %" PRId64 " not found"), bufnum);
+ }
+ valid = false;
+ bufnum = 0;
+ }
+
+ // If the 'valid' field is present it overrules the detected value.
+ if (tv_dict_find(d, "valid", -1) != NULL) {
+ valid = tv_dict_get_number(d, "valid");
+ }
+
+ const int status = qf_add_entry(qi,
+ qf_idx,
+ NULL, // dir
+ (char_u *)filename,
+ (char_u *)module,
+ bufnum,
+ (char_u *)text,
+ lnum,
+ col,
+ vcol, // vis_col
+ (char_u *)pattern, // search pattern
+ nr,
+ (char_u)(type == NULL ? NUL : *type),
+ valid);
+
+ xfree(filename);
+ xfree(module);
+ xfree(pattern);
+ xfree(text);
+
+ return status;
+}
+
/// Add list of entries to quickfix/location list. Each list entry is
/// a dictionary with item information.
static int qf_add_entries(qf_info_T *qi, int qf_idx, list_T *list,
char_u *title, int action)
{
- dict_T *d;
qfline_T *old_last = NULL;
int retval = OK;
- bool did_bufnr_emsg = false;
if (action == ' ' || qf_idx == qi->qf_listcount) {
// make place for a new list
@@ -5001,68 +5128,13 @@ static int qf_add_entries(qf_info_T *qi, int qf_idx, list_T *list,
continue; // Skip non-dict items.
}
- d = TV_LIST_ITEM_TV(li)->vval.v_dict;
+ const dict_T *const d = TV_LIST_ITEM_TV(li)->vval.v_dict;
if (d == NULL) {
continue;
}
- char *const filename = tv_dict_get_string(d, "filename", true);
- char *const module = tv_dict_get_string(d, "module", true);
- int bufnum = (int)tv_dict_get_number(d, "bufnr");
- long lnum = (long)tv_dict_get_number(d, "lnum");
- int col = (int)tv_dict_get_number(d, "col");
- char_u vcol = (char_u)tv_dict_get_number(d, "vcol");
- int nr = (int)tv_dict_get_number(d, "nr");
- const char *type_str = tv_dict_get_string(d, "type", false);
- const char_u type = (char_u)(uint8_t)(type_str == NULL ? NUL : *type_str);
- char *const pattern = tv_dict_get_string(d, "pattern", true);
- char *text = tv_dict_get_string(d, "text", true);
- if (text == NULL) {
- text = xcalloc(1, 1);
- }
- bool valid = true;
- if ((filename == NULL && bufnum == 0) || (lnum == 0 && pattern == NULL)) {
- valid = false;
- }
-
- /* Mark entries with non-existing buffer number as not valid. Give the
- * error message only once. */
- if (bufnum != 0 && (buflist_findnr(bufnum) == NULL)) {
- if (!did_bufnr_emsg) {
- did_bufnr_emsg = TRUE;
- EMSGN(_("E92: Buffer %" PRId64 " not found"), bufnum);
- }
- valid = false;
- bufnum = 0;
- }
-
- // If the 'valid' field is present it overrules the detected value.
- if (tv_dict_find(d, "valid", -1) != NULL) {
- valid = (int)tv_dict_get_number(d, "valid");
- }
-
- int status = qf_add_entry(qi,
- qf_idx,
- NULL, // dir
- (char_u *)filename,
- (char_u *)module,
- bufnum,
- (char_u *)text,
- lnum,
- col,
- vcol, // vis_col
- (char_u *)pattern, // search pattern
- nr,
- type,
- valid);
-
- xfree(filename);
- xfree(module);
- xfree(pattern);
- xfree(text);
-
- if (status == FAIL) {
- retval = FAIL;
+ retval = qf_add_entry_from_dict(qi, qf_idx, d, li == tv_list_first(list));
+ if (retval == FAIL) {
break;
}
});
@@ -5595,7 +5667,7 @@ void ex_cexpr(exarg_T *eap)
// Get the location list for ":lhelpgrep"
static qf_info_T *hgr_get_ll(bool *new_ll)
- FUNC_ATTR_NONNULL_ALL
+ FUNC_ATTR_NONNULL_ALL FUNC_ATTR_NONNULL_RET
{
win_T *wp;
qf_info_T *qi;
@@ -5615,9 +5687,7 @@ static qf_info_T *hgr_get_ll(bool *new_ll)
}
if (qi == NULL) {
// Allocate a new location list for help text matches
- if ((qi = ll_new_list()) == NULL) {
- return NULL;
- }
+ qi = ll_new_list();
*new_ll = true;
}
@@ -5713,14 +5783,14 @@ static void hgr_search_files_in_dir(
}
}
-// Search for a pattern in all the help files in the 'runtimepath'.
+// Search for a pattern in all the help files in the 'runtimepath'
+// and add the matches to a quickfix list.
+// 'lang' is the language specifier. If supplied, then only matches in the
+// specified language are found.
static void hgr_search_in_rtp(qf_info_T *qi, regmatch_T *p_regmatch,
- char_u *arg)
- FUNC_ATTR_NONNULL_ALL
+ const char_u *lang)
+ FUNC_ATTR_NONNULL_ARG(1, 2)
{
- // Check for a specified language
- char_u *const lang = check_help_lang(arg);
-
// Go through all directories in 'runtimepath'
char_u *p = p_rtp;
while (*p != NUL && !got_int) {
@@ -5755,11 +5825,10 @@ void ex_helpgrep(exarg_T *eap)
if (eap->cmdidx == CMD_lhelpgrep) {
qi = hgr_get_ll(&new_qi);
- if (qi == NULL) {
- return;
- }
}
+ // Check for a specified language
+ char_u *const lang = check_help_lang(eap->arg);
regmatch_T regmatch = {
.regprog = vim_regcomp(eap->arg, RE_MAGIC + RE_STRING),
.rm_ic = false,
@@ -5768,7 +5837,7 @@ void ex_helpgrep(exarg_T *eap)
// Create a new quickfix list.
qf_new_list(qi, qf_cmdtitle(*eap->cmdlinep));
- hgr_search_in_rtp(qi, &regmatch, eap->arg);
+ hgr_search_in_rtp(qi, &regmatch, lang);
vim_regfree(regmatch.regprog);
@@ -5778,11 +5847,12 @@ void ex_helpgrep(exarg_T *eap)
qi->qf_lists[qi->qf_curlist].qf_index = 1;
}
- if (p_cpo == empty_option)
+ if (p_cpo == empty_option) {
p_cpo = save_cpo;
- else
- /* Darn, some plugin changed the value. */
+ } else {
+ // Darn, some plugin changed the value.
free_string_option(save_cpo);
+ }
qf_list_changed(qi, qi->qf_curlist);
qf_update_buffer(qi, NULL);
@@ -5803,8 +5873,8 @@ void ex_helpgrep(exarg_T *eap)
EMSG2(_(e_nomatch2), eap->arg);
if (eap->cmdidx == CMD_lhelpgrep) {
- /* If the help window is not opened or if it already points to the
- * correct location list, then free the new location list. */
+ // If the help window is not opened or if it already points to the
+ // correct location list, then free the new location list.
if (!bt_help(curwin->w_buffer) || curwin->w_llist == qi) {
if (new_qi) {
ll_free_all(&qi);
diff --git a/src/nvim/testdir/runtest.vim b/src/nvim/testdir/runtest.vim
index 593ce6fcdc..8f5f3f82e7 100644
--- a/src/nvim/testdir/runtest.vim
+++ b/src/nvim/testdir/runtest.vim
@@ -282,6 +282,7 @@ endif
" Names of flaky tests.
let s:flaky_tests = [
+ \ 'Test_autocmd_SafeState()',
\ 'Test_cursorhold_insert()',
\ 'Test_exit_callback_interval()',
\ 'Test_map_timeout_with_timer_interrupt()',
diff --git a/src/nvim/testdir/test_normal.vim b/src/nvim/testdir/test_normal.vim
index 532beb9c39..b3e43640bb 100644
--- a/src/nvim/testdir/test_normal.vim
+++ b/src/nvim/testdir/test_normal.vim
@@ -2,12 +2,12 @@
source shared.vim
-func! Setup_NewWindow()
+func Setup_NewWindow()
10new
call setline(1, range(1,100))
endfunc
-func! MyFormatExpr()
+func MyFormatExpr()
" Adds '->$' at lines having numbers followed by trailing whitespace
for ln in range(v:lnum, v:lnum+v:count-1)
let line = getline(ln)
@@ -17,7 +17,7 @@ func! MyFormatExpr()
endfor
endfunc
-func! CountSpaces(type, ...)
+func CountSpaces(type, ...)
" for testing operatorfunc
" will count the number of spaces
" and return the result in g:a
@@ -37,7 +37,7 @@ func! CountSpaces(type, ...)
let @@ = reg_save
endfunc
-func! OpfuncDummy(type, ...)
+func OpfuncDummy(type, ...)
" for testing operatorfunc
let g:opt=&linebreak
@@ -81,7 +81,7 @@ fun! Test_normal00_optrans()
bw!
endfunc
-func! Test_normal01_keymodel()
+func Test_normal01_keymodel()
call Setup_NewWindow()
" Test 1: depending on 'keymodel' <s-down> does something different
50
@@ -115,7 +115,7 @@ func! Test_normal01_keymodel()
bw!
endfunc
-func! Test_normal02_selectmode()
+func Test_normal02_selectmode()
" some basic select mode tests
call Setup_NewWindow()
50
@@ -129,7 +129,7 @@ func! Test_normal02_selectmode()
bw!
endfunc
-func! Test_normal02_selectmode2()
+func Test_normal02_selectmode2()
" some basic select mode tests
call Setup_NewWindow()
50
@@ -139,7 +139,7 @@ func! Test_normal02_selectmode2()
bw!
endfunc
-func! Test_normal03_join()
+func Test_normal03_join()
" basic join test
call Setup_NewWindow()
50
@@ -159,7 +159,7 @@ func! Test_normal03_join()
bw!
endfunc
-func! Test_normal04_filter()
+func Test_normal04_filter()
" basic filter test
" only test on non windows platform
if has('win32')
@@ -185,7 +185,7 @@ func! Test_normal04_filter()
bw!
endfunc
-func! Test_normal05_formatexpr()
+func Test_normal05_formatexpr()
" basic formatexpr test
call Setup_NewWindow()
%d_
@@ -222,7 +222,7 @@ func Test_normal05_formatexpr_setopt()
set formatexpr=
endfunc
-func! Test_normal06_formatprg()
+func Test_normal06_formatprg()
" basic test for formatprg
" only test on non windows platform
if has('win32')
@@ -256,7 +256,7 @@ func! Test_normal06_formatprg()
call delete('Xsed_format.sh')
endfunc
-func! Test_normal07_internalfmt()
+func Test_normal07_internalfmt()
" basic test for internal formmatter to textwidth of 12
let list=range(1,11)
call map(list, 'v:val." "')
@@ -270,7 +270,7 @@ func! Test_normal07_internalfmt()
bw!
endfunc
-func! Test_normal08_fold()
+func Test_normal08_fold()
" basic tests for foldopen/folddelete
if !has("folding")
return
@@ -329,7 +329,7 @@ func! Test_normal08_fold()
bw!
endfunc
-func! Test_normal09_operatorfunc()
+func Test_normal09_operatorfunc()
" Test operatorfunc
call Setup_NewWindow()
" Add some spaces for counting
@@ -359,7 +359,7 @@ func! Test_normal09_operatorfunc()
bw!
endfunc
-func! Test_normal09a_operatorfunc()
+func Test_normal09a_operatorfunc()
" Test operatorfunc
call Setup_NewWindow()
" Add some spaces for counting
@@ -385,7 +385,7 @@ func! Test_normal09a_operatorfunc()
unlet! g:opt
endfunc
-func! Test_normal10_expand()
+func Test_normal10_expand()
" Test for expand()
10new
call setline(1, ['1', 'ifooar,,cbar'])
@@ -420,7 +420,7 @@ func! Test_normal10_expand()
bw!
endfunc
-func! Test_normal11_showcmd()
+func Test_normal11_showcmd()
" test for 'showcmd'
10new
exe "norm! ofoobar\<esc>"
@@ -435,7 +435,7 @@ func! Test_normal11_showcmd()
bw!
endfunc
-func! Test_normal12_nv_error()
+func Test_normal12_nv_error()
" Test for nv_error
10new
call setline(1, range(1,5))
@@ -445,7 +445,7 @@ func! Test_normal12_nv_error()
bw!
endfunc
-func! Test_normal13_help()
+func Test_normal13_help()
" Test for F1
call assert_equal(1, winnr())
call feedkeys("\<f1>", 'txi')
@@ -454,7 +454,7 @@ func! Test_normal13_help()
bw!
endfunc
-func! Test_normal14_page()
+func Test_normal14_page()
" basic test for Ctrl-F and Ctrl-B
call Setup_NewWindow()
exe "norm! \<c-f>"
@@ -488,7 +488,7 @@ func! Test_normal14_page()
bw!
endfunc
-func! Test_normal14_page_eol()
+func Test_normal14_page_eol()
10new
norm oxxxxxxx
exe "norm 2\<c-f>"
@@ -497,7 +497,7 @@ func! Test_normal14_page_eol()
bw!
endfunc
-func! Test_normal15_z_scroll_vert()
+func Test_normal15_z_scroll_vert()
" basic test for z commands that scroll the window
call Setup_NewWindow()
100
@@ -586,7 +586,7 @@ func! Test_normal15_z_scroll_vert()
bw!
endfunc
-func! Test_normal16_z_scroll_hor()
+func Test_normal16_z_scroll_hor()
" basic test for z commands that scroll the window
10new
15vsp
@@ -652,7 +652,7 @@ func! Test_normal16_z_scroll_hor()
bw!
endfunc
-func! Test_normal17_z_scroll_hor2()
+func Test_normal17_z_scroll_hor2()
" basic test for z commands that scroll the window
" using 'sidescrolloff' setting
10new
@@ -719,7 +719,7 @@ func! Test_normal17_z_scroll_hor2()
bw!
endfunc
-func! Test_normal18_z_fold()
+func Test_normal18_z_fold()
" basic tests for foldopen/folddelete
if !has("folding")
return
@@ -1090,7 +1090,7 @@ func! Test_normal18_z_fold()
bw!
endfunc
-func! Test_normal19_z_spell()
+func Test_normal19_z_spell()
if !has("spell") || !has('syntax')
return
endif
@@ -1245,7 +1245,7 @@ func! Test_normal19_z_spell()
bw!
endfunc
-func! Test_normal20_exmode()
+func Test_normal20_exmode()
if !has("unix")
" Reading from redirected file doesn't work on MS-Windows
return
@@ -1263,24 +1263,38 @@ func! Test_normal20_exmode()
bw!
endfunc
-func! Test_normal21_nv_hat()
- set hidden
- new
- " to many buffers opened already, will not work
- "call assert_fails(":b#", 'E23')
- "call assert_equal('', @#)
- e Xfoobar
- e Xfile2
- call feedkeys("\<c-^>", 't')
- call assert_equal("Xfile2", fnamemodify(buf