aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/quickfix.c
diff options
context:
space:
mode:
authorJosh Rahm <joshuarahm@gmail.com>2023-11-29 21:52:58 +0000
committerJosh Rahm <joshuarahm@gmail.com>2023-11-29 21:52:58 +0000
commit931bffbda3668ddc609fc1da8f9eb576b170aa52 (patch)
treed8c1843a95da5ea0bb4acc09f7e37843d9995c86 /src/nvim/quickfix.c
parent142d9041391780ac15b89886a54015fdc5c73995 (diff)
parent4a8bf24ac690004aedf5540fa440e788459e5e34 (diff)
downloadrneovim-931bffbda3668ddc609fc1da8f9eb576b170aa52.tar.gz
rneovim-931bffbda3668ddc609fc1da8f9eb576b170aa52.tar.bz2
rneovim-931bffbda3668ddc609fc1da8f9eb576b170aa52.zip
Merge remote-tracking branch 'upstream/master' into userreguserreg
Diffstat (limited to 'src/nvim/quickfix.c')
-rw-r--r--src/nvim/quickfix.c609
1 files changed, 357 insertions, 252 deletions
diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c
index 5518fdfa51..4e20eb8925 100644
--- a/src/nvim/quickfix.c
+++ b/src/nvim/quickfix.c
@@ -1,6 +1,3 @@
-// This is an open source non-commercial project. Dear PVS-Studio, please check
-// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
-
// quickfix.c: functions for quickfix mode, using a file with error messages
#include <assert.h>
@@ -14,7 +11,7 @@
#include <time.h>
#include "nvim/arglist.h"
-#include "nvim/ascii.h"
+#include "nvim/ascii_defs.h"
#include "nvim/autocmd.h"
#include "nvim/buffer.h"
#include "nvim/charset.h"
@@ -23,7 +20,6 @@
#include "nvim/edit.h"
#include "nvim/eval.h"
#include "nvim/eval/typval.h"
-#include "nvim/eval/typval_defs.h"
#include "nvim/eval/window.h"
#include "nvim/ex_cmds.h"
#include "nvim/ex_cmds2.h"
@@ -33,34 +29,37 @@
#include "nvim/ex_getln.h"
#include "nvim/fileio.h"
#include "nvim/fold.h"
+#include "nvim/func_attr.h"
+#include "nvim/garray.h"
#include "nvim/gettext.h"
#include "nvim/globals.h"
#include "nvim/help.h"
-#include "nvim/highlight_defs.h"
+#include "nvim/highlight.h"
#include "nvim/highlight_group.h"
-#include "nvim/macros.h"
+#include "nvim/macros_defs.h"
#include "nvim/mark.h"
#include "nvim/mbyte.h"
-#include "nvim/memfile_defs.h"
#include "nvim/memline.h"
#include "nvim/memory.h"
#include "nvim/message.h"
#include "nvim/move.h"
#include "nvim/normal.h"
#include "nvim/option.h"
+#include "nvim/option_defs.h"
+#include "nvim/option_vars.h"
#include "nvim/optionstr.h"
-#include "nvim/os/fs_defs.h"
+#include "nvim/os/fs.h"
#include "nvim/os/input.h"
#include "nvim/os/os.h"
#include "nvim/path.h"
-#include "nvim/pos.h"
+#include "nvim/pos_defs.h"
#include "nvim/quickfix.h"
#include "nvim/regexp.h"
#include "nvim/search.h"
#include "nvim/strings.h"
-#include "nvim/types.h"
+#include "nvim/types_defs.h"
#include "nvim/ui.h"
-#include "nvim/vim.h"
+#include "nvim/vim_defs.h"
#include "nvim/window.h"
struct dir_stack_T {
@@ -80,14 +79,14 @@ struct qfline_S {
int qf_col; ///< column where the error occurred
int qf_end_col; ///< column when the error has range or zero
int qf_nr; ///< error number
- char *qf_module; ///< module name for this error
- char *qf_pattern; ///< search pattern for the error
- char *qf_text; ///< description of the error
- char qf_viscol; ///< set to true if qf_col and qf_end_col is
- // screen column
- char qf_cleared; ///< set to true if line has been deleted
- char qf_type; ///< type of the error (mostly 'E'); 1 for :helpgrep
- char qf_valid; ///< valid error message detected
+ char *qf_module; ///< module name for this error
+ char *qf_pattern; ///< search pattern for the error
+ char *qf_text; ///< description of the error
+ char qf_viscol; ///< set to true if qf_col and qf_end_col is screen column
+ char qf_cleared; ///< set to true if line has been deleted
+ char qf_type; ///< type of the error (mostly 'E'); 1 for :helpgrep
+ typval_T qf_user_data; ///< custom user data associated with this item
+ char qf_valid; ///< valid error message detected
};
// There is a stack of error lists.
@@ -109,18 +108,19 @@ typedef enum {
/// created using setqflist()/setloclist() with a title and/or user context
/// information and entries can be added later using setqflist()/setloclist().
typedef struct qf_list_S {
- unsigned qf_id; ///< Unique identifier for this list
+ unsigned qf_id; ///< Unique identifier for this list
qfltype_T qfl_type;
- qfline_T *qf_start; ///< pointer to the first error
- qfline_T *qf_last; ///< pointer to the last error
- qfline_T *qf_ptr; ///< pointer to the current error
- int qf_count; ///< number of errors (0 means empty list)
- int qf_index; ///< current index in the error list
- int qf_nonevalid; ///< true if not a single valid entry found
- char *qf_title; ///< title derived from the command that created
- ///< the error list or set by setqflist
- typval_T *qf_ctx; ///< context set by setqflist/setloclist
- Callback qf_qftf_cb; ///< 'quickfixtextfunc' callback function
+ qfline_T *qf_start; ///< pointer to the first error
+ qfline_T *qf_last; ///< pointer to the last error
+ qfline_T *qf_ptr; ///< pointer to the current error
+ int qf_count; ///< number of errors (0 means empty list)
+ int qf_index; ///< current index in the error list
+ bool qf_nonevalid; ///< true if not a single valid entry found
+ bool qf_has_user_data; ///< true if at least one item has user_data attached
+ char *qf_title; ///< title derived from the command that created
+ ///< the error list or set by setqflist
+ typval_T *qf_ctx; ///< context set by setqflist/setloclist
+ Callback qf_qftf_cb; ///< 'quickfixtextfunc' callback function
struct dir_stack_T *qf_dir_stack;
char *qf_directory;
@@ -129,7 +129,7 @@ typedef struct qf_list_S {
bool qf_multiline;
bool qf_multiignore;
bool qf_multiscan;
- long qf_changedtick;
+ int qf_changedtick;
} qf_list_T;
/// Quickfix/Location list stack definition
@@ -150,7 +150,7 @@ struct qf_info_S {
static qf_info_T ql_info; // global quickfix list
static unsigned last_qf_id = 0; // Last Used quickfix list id
-#define FMT_PATTERNS 13 // maximum number of % recognized
+#define FMT_PATTERNS 14 // maximum number of % recognized
// Structure used to hold the info of one part of 'errorformat'
typedef struct efm_S efm_T;
@@ -215,6 +215,7 @@ typedef struct {
typedef struct {
char *namebuf;
+ int bnr;
char *module;
char *errmsg;
size_t errmsglen;
@@ -226,12 +227,13 @@ typedef struct {
char *pattern;
int enr;
char type;
+ typval_T *user_data;
bool valid;
} qffields_T;
/// :vimgrep command arguments
typedef struct vgr_args_S {
- long tomatch; ///< maximum number of matches to find
+ int tomatch; ///< maximum number of matches to find
char *spat; ///< search pattern
int flags; ///< search modifier
char **fnames; ///< list of files to search
@@ -244,7 +246,13 @@ typedef struct vgr_args_S {
# include "quickfix.c.generated.h"
#endif
-static char *e_no_more_items = N_("E553: No more items");
+static const char *e_no_more_items = N_("E553: No more items");
+static const char *e_current_quickfix_list_was_changed =
+ N_("E925: Current quickfix list was changed");
+static const char *e_current_location_list_was_changed =
+ N_("E926: Current location list was changed");
+
+enum { QF_WINHEIGHT = 10, }; ///< default height for quickfix window
// Quickfix window check helper macro
#define IS_QF_WINDOW(wp) (bt_quickfix((wp)->w_buffer) && (wp)->w_llist_ref == NULL)
@@ -257,10 +265,8 @@ static char *e_no_more_items = N_("E553: No more items");
#define IS_QF_LIST(qfl) ((qfl)->qfl_type == QFLT_QUICKFIX)
#define IS_LL_LIST(qfl) ((qfl)->qfl_type == QFLT_LOCATION)
-//
// Return location list for window 'wp'
// For location list window, return the referenced location list
-//
#define GET_LOC_LIST(wp) (IS_LL_WINDOW(wp) ? (wp)->w_llist_ref : (wp)->w_llist)
// Macro to loop through all the items in a quickfix list
@@ -275,10 +281,38 @@ static char *e_no_more_items = N_("E553: No more items");
static char *qf_last_bufname = NULL;
static bufref_T qf_last_bufref = { NULL, 0, 0 };
-static char *e_current_quickfix_list_was_changed =
- N_("E925: Current quickfix list was changed");
-static char *e_current_location_list_was_changed =
- N_("E926: Current location list was changed");
+static garray_T qfga;
+
+/// Get a growarray to buffer text in. Shared between various commands to avoid
+/// many alloc/free calls.
+static garray_T *qfga_get(void)
+{
+ static bool initialized = false;
+
+ if (!initialized) {
+ initialized = true;
+ ga_init(&qfga, 1, 256);
+ }
+
+ // Reset the length to zero. Retain ga_data from previous use to avoid
+ // many alloc/free calls.
+ qfga.ga_len = 0;
+
+ return &qfga;
+}
+
+/// The "qfga" grow array buffer is reused across multiple quickfix commands as
+/// a temporary buffer to reduce the number of alloc/free calls. But if the
+/// buffer size is large, then to avoid holding on to that memory, clear the
+/// grow array. Otherwise just reset the grow array length.
+static void qfga_clear(void)
+{
+ if (qfga.ga_maxlen > 1000) {
+ ga_clear(&qfga);
+ } else {
+ qfga.ga_len = 0;
+ }
+}
// Counter to prevent autocmds from freeing up location lists when they are
// still being used.
@@ -309,7 +343,7 @@ static int qf_init_process_nextline(qf_list_T *qfl, efm_T *fmt_first, qfstate_T
: ((qfl->qf_currfile != NULL && fields->valid)
? qfl->qf_currfile : NULL),
fields->module,
- 0,
+ fields->bnr,
fields->errmsg,
fields->lnum,
fields->end_lnum,
@@ -319,6 +353,7 @@ static int qf_init_process_nextline(qf_list_T *qfl, efm_T *fmt_first, qfstate_T
fields->pattern,
fields->enr,
fields->type,
+ fields->user_data,
fields->valid);
}
@@ -342,8 +377,8 @@ int qf_init(win_T *wp, const char *restrict efile, char *restrict errorformat, i
qi = ll_get_or_alloc_list(wp);
}
- return qf_init_ext(qi, qi->qf_curlist, (char *)efile, curbuf, NULL, errorformat,
- newlist, (linenr_T)0, (linenr_T)0, (char *)qf_title, enc);
+ return qf_init_ext(qi, qi->qf_curlist, efile, curbuf, NULL, errorformat,
+ newlist, 0, 0, qf_title, enc);
}
// Maximum number of bytes allowed per line while reading an errorfile.
@@ -355,20 +390,21 @@ static struct fmtpattern {
char *pattern;
} fmt_pat[FMT_PATTERNS] = {
{ 'f', ".\\+" }, // only used when at end
- { 'n', "\\d\\+" }, // 1
- { 'l', "\\d\\+" }, // 2
- { 'e', "\\d\\+" }, // 3
- { 'c', "\\d\\+" }, // 4
- { 'k', "\\d\\+" }, // 5
- { 't', "." }, // 6
-#define FMT_PATTERN_M 7
- { 'm', ".\\+" }, // 7
-#define FMT_PATTERN_R 8
- { 'r', ".*" }, // 8
- { 'p', "[- \t.]*" }, // 9
- { 'v', "\\d\\+" }, // 10
- { 's', ".\\+" }, // 11
- { 'o', ".\\+" } // 12
+ { 'b', "\\d\\+" }, // 1
+ { 'n', "\\d\\+" }, // 2
+ { 'l', "\\d\\+" }, // 3
+ { 'e', "\\d\\+" }, // 4
+ { 'c', "\\d\\+" }, // 5
+ { 'k', "\\d\\+" }, // 6
+ { 't', "." }, // 7
+#define FMT_PATTERN_M 8
+ { 'm', ".\\+" }, // 8
+#define FMT_PATTERN_R 9
+ { 'r', ".*" }, // 9
+ { 'p', "[-\t .]*" }, // 10
+ { 'v', "\\d\\+" }, // 11
+ { 's', ".\\+" }, // 12
+ { 'o', ".\\+" } // 13
};
/// Convert an errorformat pattern to a regular expression pattern.
@@ -499,7 +535,7 @@ static int efm_to_regpat(const char *efm, int len, efm_T *fmt_ptr, char *regpat)
}
}
if (idx < FMT_PATTERNS) {
- ptr = efmpat_to_regpat((char *)efmp, ptr, fmt_ptr, idx, round);
+ ptr = efmpat_to_regpat(efmp, ptr, fmt_ptr, idx, round);
if (ptr == NULL) {
return FAIL;
}
@@ -726,7 +762,7 @@ static int qf_get_next_buf_line(qfstate_T *state)
if (state->buflnum > state->lnumlast) {
return QF_END_OF_INPUT;
}
- char *p_buf = ml_get_buf(state->buf, state->buflnum, false);
+ char *p_buf = ml_get_buf(state->buf, state->buflnum);
state->buflnum += 1;
size_t len = strlen(p_buf);
@@ -768,7 +804,7 @@ retry:
memcpy(state->growbuf, IObuff, IOSIZE - 1);
size_t growbuflen = state->linelen;
- for (;;) {
+ while (true) {
errno = 0;
if (fgets(state->growbuf + growbuflen,
(int)(state->growbufsiz - growbuflen), state->fd) == NULL) {
@@ -788,7 +824,7 @@ retry:
}
state->growbufsiz = (2 * state->growbufsiz < LINE_MAXLEN)
- ? 2 * state->growbufsiz : LINE_MAXLEN;
+ ? 2 * state->growbufsiz : LINE_MAXLEN;
state->growbuf = xrealloc(state->growbuf, state->growbufsiz);
}
@@ -825,7 +861,7 @@ retry:
state->linebuf = line;
state->growbuf = line;
state->growbufsiz = state->linelen < LINE_MAXLEN
- ? state->linelen : LINE_MAXLEN;
+ ? state->linelen : LINE_MAXLEN;
}
}
}
@@ -1209,7 +1245,7 @@ static char *qf_cmdtitle(char *cmd)
{
static char qftitle_str[IOSIZE];
- snprintf((char *)qftitle_str, IOSIZE, ":%s", cmd);
+ snprintf(qftitle_str, IOSIZE, ":%s", cmd);
return qftitle_str;
}
@@ -1249,6 +1285,7 @@ static void qf_new_list(qf_info_T *qi, const char *qf_title)
qf_store_title(qfl, qf_title);
qfl->qfl_type = qi->qfl_type;
qfl->qf_id = ++last_qf_id;
+ qfl->qf_has_user_data = false;
}
/// Parse the match for filename ('%f') pattern in regmatch.
@@ -1275,6 +1312,21 @@ static int qf_parse_fmt_f(regmatch_T *rmp, int midx, qffields_T *fields, int pre
return QF_OK;
}
+/// Parse the match for buffer number ('%b') pattern in regmatch.
+/// Return the matched value in "fields->bnr".
+static int qf_parse_fmt_b(regmatch_T *rmp, int midx, qffields_T *fields)
+{
+ if (rmp->startp[midx] == NULL) {
+ return QF_FAIL;
+ }
+ int bnr = (int)atol(rmp->startp[midx]);
+ if (buflist_findnr(bnr) == NULL) {
+ return QF_FAIL;
+ }
+ fields->bnr = bnr;
+ return QF_OK;
+}
+
/// Parse the match for error number ('%n') pattern in regmatch.
/// Return the matched value in "fields->enr".
static int qf_parse_fmt_n(regmatch_T *rmp, int midx, qffields_T *fields)
@@ -1459,6 +1511,7 @@ static int qf_parse_fmt_o(regmatch_T *rmp, int midx, qffields_T *fields)
/// Keep in sync with fmt_pat[].
static int (*qf_parse_fmt[FMT_PATTERNS])(regmatch_T *, int, qffields_T *) = {
NULL, // %f
+ qf_parse_fmt_b,
qf_parse_fmt_n,
qf_parse_fmt_l,
qf_parse_fmt_e,
@@ -1531,6 +1584,7 @@ static int qf_parse_get_fields(char *linebuf, size_t linelen, efm_T *fmt_ptr, qf
}
fields->namebuf[0] = NUL;
+ fields->bnr = 0;
fields->module[0] = NUL;
fields->pattern[0] = NUL;
if (!qf_multiscan) {
@@ -1549,7 +1603,7 @@ static int qf_parse_get_fields(char *linebuf, size_t linelen, efm_T *fmt_ptr, qf
// Always ignore case when looking for a matching error.
regmatch.rm_ic = true;
regmatch.regprog = fmt_ptr->prog;
- int r = vim_regexec(&regmatch, linebuf, (colnr_T)0);
+ int r = vim_regexec(&regmatch, linebuf, 0);
fmt_ptr->prog = regmatch.regprog;
int status = QF_FAIL;
if (r) {
@@ -1624,7 +1678,7 @@ static int qf_parse_multiline_pfx(int idx, qf_list_T *qfl, qffields_T *fields)
}
if (*fields->errmsg) {
size_t textlen = strlen(qfprev->qf_text);
- size_t errlen = strlen(fields->errmsg);
+ size_t errlen = strlen(fields->errmsg);
qfprev->qf_text = xrealloc(qfprev->qf_text, textlen + errlen + 2);
qfprev->qf_text[textlen] = '\n';
STRCPY(qfprev->qf_text + textlen + 1, fields->errmsg);
@@ -1804,12 +1858,14 @@ void check_quickfix_busy(void)
/// @param pattern search pattern
/// @param nr error number
/// @param type type character
+/// @param user_data custom user data or NULL
/// @param valid valid entry
///
/// @return QF_OK on success or QF_FAIL on failure.
static int qf_add_entry(qf_list_T *qfl, char *dir, char *fname, char *module, int bufnum,
char *mesg, linenr_T lnum, linenr_T end_lnum, int col, int end_col,
- char vis_col, char *pattern, int nr, char type, char valid)
+ char vis_col, char *pattern, int nr, char type, typval_T *user_data,
+ char valid)
{
qfline_T *qfp = xmalloc(sizeof(qfline_T));
@@ -1830,6 +1886,12 @@ static int qf_add_entry(qf_list_T *qfl, char *dir, char *fname, char *module, in
qfp->qf_col = col;
qfp->qf_end_col = end_col;
qfp->qf_viscol = vis_col;
+ if (user_data == NULL || user_data->v_type == VAR_UNKNOWN) {
+ qfp->qf_user_data.v_type = VAR_UNKNOWN;
+ } else {
+ tv_copy(user_data, &qfp->qf_user_data);
+ qfl->qf_has_user_data = true;
+ }
if (pattern == NULL || *pattern == NUL) {
qfp->qf_pattern = NULL;
} else {
@@ -1965,6 +2027,7 @@ static int copy_loclist_entries(const qf_list_T *from_qfl, qf_list_T *to_qfl)
from_qfp->qf_pattern,
from_qfp->qf_nr,
0,
+ &from_qfp->qf_user_data,
from_qfp->qf_valid) == QF_FAIL) {
return FAIL;
}
@@ -1990,6 +2053,7 @@ static int copy_loclist(qf_list_T *from_qfl, qf_list_T *to_qfl)
// Some of the fields are populated by qf_add_entry()
to_qfl->qfl_type = from_qfl->qfl_type;
to_qfl->qf_nonevalid = from_qfl->qf_nonevalid;
+ to_qfl->qf_has_user_data = from_qfl->qf_has_user_data;
to_qfl->qf_count = 0;
to_qfl->qf_index = 0;
to_qfl->qf_start = NULL;
@@ -2018,7 +2082,7 @@ static int copy_loclist(qf_list_T *from_qfl, qf_list_T *to_qfl)
// Assign a new ID for the location list
to_qfl->qf_id = ++last_qf_id;
- to_qfl->qf_changedtick = 0L;
+ to_qfl->qf_changedtick = 0;
// When no valid entries are present in the list, qf_ptr points to
// the first item in the list
@@ -2107,7 +2171,7 @@ static int qf_get_fnum(qf_list_T *qfl, char *directory, char *fname)
xfree(ptr);
} else {
xfree(qf_last_bufname);
- buf = buflist_new(bufname, NULL, (linenr_T)0, BLN_NOOPT);
+ buf = buflist_new(bufname, NULL, 0, BLN_NOOPT);
qf_last_bufname = (bufname == ptr) ? bufname : xstrdup(bufname);
set_bufref(&qf_last_bufref, buf);
}
@@ -2259,7 +2323,7 @@ static char *qf_guess_filepath(qf_list_T *qfl, char *filename)
}
/// Returns true, if a quickfix/location list with the given identifier exists.
-static bool qflist_valid(win_T *wp, unsigned int qf_id)
+static bool qflist_valid(win_T *wp, unsigned qf_id)
{
qf_info_T *qi = &ql_info;
@@ -2353,7 +2417,7 @@ static qfline_T *get_nth_valid_entry(qf_list_T *qfl, int errornr, int dir, int *
{
qfline_T *qf_ptr = qfl->qf_ptr;
int qf_idx = qfl->qf_index;
- char *err = e_no_more_items;
+ const char *err = e_no_more_items;
while (errornr--) {
qfline_T *prev_qf_ptr = qf_ptr;
@@ -2549,7 +2613,7 @@ static int qf_open_new_file_win(qf_info_T *ll_ref)
if (win_split(0, flags) == FAIL) {
return FAIL; // not enough room for window
}
- p_swb = empty_option; // don't split again
+ p_swb = empty_string_option; // don't split again
swb_flags = 0;
RESET_BINDING(curwin);
if (ll_ref != NULL) {
@@ -2609,7 +2673,7 @@ static void qf_goto_win_with_qfl_file(int qf_fnum)
{
win_T *win = curwin;
win_T *altwin = NULL;
- for (;;) {
+ while (true) {
if (win->w_buffer->b_fnum == qf_fnum) {
break;
}
@@ -2709,7 +2773,7 @@ static int qf_jump_edit_buffer(qf_info_T *qi, qfline_T *qf_ptr, int forceit, int
int *opened_window)
{
qf_list_T *qfl = qf_get_curlist(qi);
- long old_changetick = qfl->qf_changedtick;
+ int old_changetick = qfl->qf_changedtick;
int old_qf_curlist = qi->qf_curlist;
qfltype_T qfl_type = qfl->qfl_type;
int retval = OK;
@@ -2722,11 +2786,11 @@ static int qf_jump_edit_buffer(qf_info_T *qi, qfline_T *qf_ptr, int forceit, int
no_write_message();
return FAIL;
}
- retval = do_ecmd(qf_ptr->qf_fnum, NULL, NULL, NULL, (linenr_T)1,
+ retval = do_ecmd(qf_ptr->qf_fnum, NULL, NULL, NULL, 1,
ECMD_HIDE + ECMD_SET_HELP,
prev_winid == curwin->handle ? curwin : NULL);
} else {
- retval = buflist_getfile(qf_ptr->qf_fnum, (linenr_T)1,
+ retval = buflist_getfile(qf_ptr->qf_fnum, 1,
GETF_SETMARK | GETF_SWITCH, forceit);
}
// If a location list, check whether the associated window is still
@@ -2746,8 +2810,8 @@ static int qf_jump_edit_buffer(qf_info_T *qi, qfline_T *qf_ptr, int forceit, int
return QF_ABORT;
}
- if (old_qf_curlist != qi->qf_curlist // -V560
- || old_changetick != qfl->qf_changedtick // -V560
+ if (old_qf_curlist != qi->qf_curlist
+ || old_changetick != qfl->qf_changedtick
|| !is_qf_entry_present(qfl, qf_ptr)) {
if (qfl_type == QFLT_QUICKFIX) {
emsg(_(e_current_quickfix_list_was_changed));
@@ -2789,7 +2853,7 @@ static void qf_jump_goto_line(linenr_T qf_lnum, int qf_col, char qf_viscol, char
// Move the cursor to the first line in the buffer
pos_T save_cursor = curwin->w_cursor;
curwin->w_cursor.lnum = 0;
- if (!do_search(NULL, '/', '/', qf_pattern, (long)1, SEARCH_KEEP, NULL)) {
+ if (!do_search(NULL, '/', '/', qf_pattern, 1, SEARCH_KEEP, NULL)) {
curwin->w_cursor = save_cursor;
}
}
@@ -2799,6 +2863,8 @@ static void qf_jump_goto_line(linenr_T qf_lnum, int qf_col, char qf_viscol, char
static void qf_jump_print_msg(qf_info_T *qi, int qf_index, qfline_T *qf_ptr, buf_T *old_curbuf,
linenr_T old_lnum)
{
+ garray_T *const gap = qfga_get();
+
// Update the screen before showing the message, unless the screen
// scrolled up.
if (!msg_scrolled) {
@@ -2807,13 +2873,14 @@ static void qf_jump_print_msg(qf_info_T *qi, int qf_index, qfline_T *qf_ptr, buf
update_screen();
}
}
- snprintf(IObuff, IOSIZE, _("(%d of %d)%s%s: "), qf_index,
- qf_get_curlist(qi)->qf_count,
- qf_ptr->qf_cleared ? _(" (line deleted)") : "",
- qf_types(qf_ptr->qf_type, qf_ptr->qf_nr));
+ vim_snprintf(IObuff, IOSIZE, _("(%d of %d)%s%s: "), qf_index,
+ qf_get_curlist(qi)->qf_count,
+ qf_ptr->qf_cleared ? _(" (line deleted)") : "",
+ qf_types(qf_ptr->qf_type, qf_ptr->qf_nr));
// Add the message, skipping leading whitespace and newlines.
- int len = (int)strlen(IObuff);
- qf_fmt_text(skipwhite(qf_ptr->qf_text), IObuff + len, IOSIZE - len);
+ ga_concat(gap, IObuff);
+ qf_fmt_text(gap, skipwhite(qf_ptr->qf_text));
+ ga_append(gap, NUL);
// Output the message. Overwrite to avoid scrolling when the 'O'
// flag is present in 'shortmess'; But when not jumping, print the
@@ -2825,8 +2892,10 @@ static void qf_jump_print_msg(qf_info_T *qi, int qf_index, qfline_T *qf_ptr, buf
msg_scroll = false;
}
msg_ext_set_kind("quickfix");
- msg_attr_keep(IObuff, 0, true, false);
+ msg_attr_keep(gap->ga_data, 0, true, false);
msg_scroll = (int)i;
+
+ qfga_clear();
}
/// Find a usable window for opening a file from the quickfix/location list. If
@@ -2839,7 +2908,7 @@ static void qf_jump_print_msg(qf_info_T *qi, int qf_index, qfline_T *qf_ptr, buf
static int qf_jump_open_window(qf_info_T *qi, qfline_T *qf_ptr, bool newwin, int *opened_window)
{
qf_list_T *qfl = qf_get_curlist(qi);
- long old_changetick = qfl->qf_changedtick;
+ int old_changetick = qfl->qf_changedtick;
int old_qf_curlist = qi->qf_curlist;
qfltype_T qfl_type = qfl->qfl_type;
@@ -2850,7 +2919,7 @@ static int qf_jump_open_window(qf_info_T *qi, qfline_T *qf_ptr, bool newwin, int
}
}
if (old_qf_curlist != qi->qf_curlist
- || old_changetick != qfl->qf_changedtick // -V560
+ || old_changetick != qfl->qf_changedtick
|| !is_qf_entry_present(qfl, qf_ptr)) {
if (qfl_type == QFLT_QUICKFIX) {
emsg(_(e_current_quickfix_list_was_changed));
@@ -3021,7 +3090,7 @@ theend:
qfl->qf_ptr = qf_ptr;
qfl->qf_index = qf_index;
}
- if (p_swb != old_swb && p_swb == empty_option) {
+ if (p_swb != old_swb && p_swb == empty_string_option) {
// Restore old 'switchbuf' value, but not when an autocommand or
// modeline has changed the value.
p_swb = old_swb;
@@ -3081,46 +3150,35 @@ static void qf_list_entry(qfline_T *qfp, int qf_idx, bool cursel)
}
msg_putchar('\n');
- msg_outtrans_attr(IObuff, cursel ? HL_ATTR(HLF_QFL) : qfFileAttr);
+ msg_outtrans(IObuff, cursel ? HL_ATTR(HLF_QFL) : qfFileAttr);
if (qfp->qf_lnum != 0) {
msg_puts_attr(":", qfSepAttr);
}
- if (qfp->qf_lnum == 0) {
- IObuff[0] = NUL;
- } else {
- qf_range_text(qfp, IObuff, IOSIZE);
+ garray_T *gap = qfga_get();
+ if (qfp->qf_lnum != 0) {
+ qf_range_text(gap, qfp);
}
- vim_snprintf(IObuff + strlen(IObuff), IOSIZE, "%s", qf_types(qfp->qf_type, qfp->qf_nr));
- msg_puts_attr((const char *)IObuff, qfLineAttr);
+ ga_concat(gap, qf_types(qfp->qf_type, qfp->qf_nr));
+ ga_append(gap, NUL);
+ msg_puts_attr(gap->ga_data, qfLineAttr);
msg_puts_attr(":", qfSepAttr);
if (qfp->qf_pattern != NULL) {
- qf_fmt_text(qfp->qf_pattern, IObuff, IOSIZE);
- msg_puts((const char *)IObuff);
+ gap = qfga_get();
+ qf_fmt_text(gap, qfp->qf_pattern);
+ ga_append(gap, NUL);
+ msg_puts(gap->ga_data);
msg_puts_attr(":", qfSepAttr);
}
msg_puts(" ");
- char *tbuf = IObuff;
- size_t tbuflen = IOSIZE;
- size_t len = strlen(qfp->qf_text) + 3;
-
- if (len > IOSIZE) {
- tbuf = xmalloc(len);
- tbuflen = len;
- }
-
// Remove newlines and leading whitespace from the text. For an
// unrecognized line keep the indent, the compiler may mark a word
// with ^^^^.
- qf_fmt_text((fname != NULL || qfp->qf_lnum != 0)
- ? skipwhite(qfp->qf_text) : qfp->qf_text,
- tbuf, (int)tbuflen);
- msg_prt_line(tbuf, false);
-
- if (tbuf != IObuff) {
- xfree(tbuf);
- }
+ gap = qfga_get();
+ qf_fmt_text(gap, (fname != NULL || qfp->qf_lnum != 0) ? skipwhite(qfp->qf_text) : qfp->qf_text);
+ ga_append(gap, NUL);
+ msg_prt_line(gap->ga_data, false);
}
// ":clist": list all errors
@@ -3195,51 +3253,53 @@ void qf_list(exarg_T *eap)
}
os_breakcheck();
}
+ qfga_clear();
}
-// Remove newlines and leading whitespace from an error message.
-// Put the result in "buf[bufsize]".
-static void qf_fmt_text(const char *restrict text, char *restrict buf, int bufsize)
+/// Remove newlines and leading whitespace from an error message.
+/// Add the result to the grow array "gap".
+static void qf_fmt_text(garray_T *gap, const char *restrict text)
FUNC_ATTR_NONNULL_ALL
{
- int i;
- const char *p = (char *)text;
-
- for (i = 0; *p != NUL && i < bufsize - 1; i++) {
+ const char *p = text;
+ while (*p != NUL) {
if (*p == '\n') {
- buf[i] = ' ';
+ ga_append(gap, ' ');
while (*++p != NUL) {
if (!ascii_iswhite(*p) && *p != '\n') {
break;
}
}
} else {
- buf[i] = *p++;
+ ga_append(gap, (uint8_t)(*p++));
}
}
- buf[i] = NUL;
}
-// Range information from lnum, col, end_lnum, and end_col.
-// Put the result in "buf[bufsize]".
-static void qf_range_text(const qfline_T *qfp, char *buf, int bufsize)
+/// Add the range information from the lnum, col, end_lnum, and end_col values
+/// of a quickfix entry to the grow array "gap".
+static void qf_range_text(garray_T *gap, const qfline_T *qfp)
{
- vim_snprintf(buf, (size_t)bufsize, "%" PRIdLINENR, qfp->qf_lnum);
- int len = (int)strlen(buf);
+ char *const buf = IObuff;
+ const size_t bufsize = IOSIZE;
+
+ vim_snprintf(buf, bufsize, "%" PRIdLINENR, qfp->qf_lnum);
+ size_t len = strlen(buf);
if (qfp->qf_end_lnum > 0 && qfp->qf_lnum != qfp->qf_end_lnum) {
- vim_snprintf(buf + len, (size_t)(bufsize - len), "-%" PRIdLINENR, qfp->qf_end_lnum);
- len += (int)strlen(buf + len);
+ vim_snprintf(buf + len, bufsize - len, "-%" PRIdLINENR, qfp->qf_end_lnum);
+ len += strlen(buf + len);
}
if (qfp->qf_col > 0) {
- vim_snprintf(buf + len, (size_t)(bufsize - len), " col %d", qfp->qf_col);
- len += (int)strlen(buf + len);
+ vim_snprintf(buf + len, bufsize - len, " col %d", qfp->qf_col);
+ len += strlen(buf + len);
if (qfp->qf_end_col > 0 && qfp->qf_col != qfp->qf_end_col) {
- vim_snprintf(buf + len, (size_t)(bufsize - len), "-%d", qfp->qf_end_col);
- len += (int)strlen(buf + len);
+ vim_snprintf(buf + len, bufsize - len, "-%d", qfp->qf_end_col);
+ len += strlen(buf + len);
}
}
- buf[len] = NUL;
+
+ ga_concat_len(gap, buf, len);
}
/// Display information (list number, list size and the title) about a
@@ -3250,7 +3310,7 @@ static void qf_msg(qf_info_T *qi, int which, char *lead)
int count = qi->qf_lists[which].qf_count;
char buf[IOSIZE];
- vim_snprintf((char *)buf, IOSIZE, _("%serror list %d of %d; %d errors "),
+ vim_snprintf(buf, IOSIZE, _("%serror list %d of %d; %d errors "),
lead,
which + 1,
qi->qf_listcount,
@@ -3266,7 +3326,7 @@ static void qf_msg(qf_info_T *qi, int which, char *lead)
xstrlcat(buf, title, IOSIZE);
}
trunc_string(buf, buf, Columns - 1, IOSIZE);
- msg(buf);
+ msg(buf, 0);
}
/// ":colder [count]": Up in the quickfix stack.
@@ -3325,7 +3385,7 @@ void qf_history(exarg_T *eap)
}
if (qf_stack_empty(qi)) {
- msg(_("No entries"));
+ msg(_("No entries"), 0);
} else {
for (int i = 0; i < qi->qf_listcount; i++) {
qf_msg(qi, i, i == qi->qf_curlist ? "> " : " ");
@@ -3346,6 +3406,7 @@ static void qf_free_items(qf_list_T *qfl)
xfree(qfp->qf_module);
xfree(qfp->qf_text);
xfree(qfp->qf_pattern);
+ tv_clear(&qfp->qf_user_data);
stop = (qfp == qfpnext);
xfree(qfp);
if (stop) {
@@ -3353,9 +3414,10 @@ static void qf_free_items(qf_list_T *qfl)
// to avoid crashing when it's wrong.
// TODO(vim): Avoid qf_count being incorrect.
qfl->qf_count = 1;
+ } else {
+ qfl->qf_start = qfpnext;
}
}
- qfl->qf_start = qfpnext;
qfl->qf_count--;
}
@@ -3387,17 +3449,20 @@ static void qf_free(qf_list_T *qfl)
qfl->qf_ctx = NULL;
callback_free(&qfl->qf_qftf_cb);
qfl->qf_id = 0;
- qfl->qf_changedtick = 0L;
+ qfl->qf_changedtick = 0;
}
-// qf_mark_adjust: adjust marks
-bool qf_mark_adjust(win_T *wp, linenr_T line1, linenr_T line2, linenr_T amount,
+/// Adjust error list entries for changed line numbers
+///
+/// Note: `buf` is the changed buffer, but `wp` is a potential location list
+/// into that buffer, or NULL to check the quickfix list.
+bool qf_mark_adjust(buf_T *buf, win_T *wp, linenr_T line1, linenr_T line2, linenr_T amount,
linenr_T amount_after)
{
qf_info_T *qi = &ql_info;
int buf_has_flag = wp == NULL ? BUF_HAS_QF_ENTRY : BUF_HAS_LL_ENTRY;
- if (!(curbuf->b_has_qf_entry & buf_has_flag)) {
+ if (!(buf->b_has_qf_entry & buf_has_flag)) {
return false;
}
if (wp != NULL) {
@@ -3414,7 +3479,7 @@ bool qf_mark_adjust(win_T *wp, linenr_T line1, linenr_T line2, linenr_T amount,
qf_list_T *qfl = qf_get_list(qi, idx);
if (!qf_list_empty(qfl)) {
FOR_ALL_QFL_ITEMS(qfl, qfp, i) {
- if (qfp->qf_fnum == curbuf->b_fnum) {
+ if (qfp->qf_fnum == buf->b_fnum) {
found_one = true;
if (qfp->qf_lnum >= line1 && qfp->qf_lnum <= line2) {
if (amount == MAXLNUM) {
@@ -3475,7 +3540,7 @@ static char *qf_types(int c, int nr)
}
static char buf[20];
- snprintf((char *)buf, sizeof(buf), "%s %3d", p, nr);
+ snprintf(buf, sizeof(buf), "%s %3d", p, nr);
return buf;
}
@@ -3581,12 +3646,12 @@ static int qf_goto_cwindow(const qf_info_T *qi, bool resize, int sz, bool vertsp
static void qf_set_cwindow_options(void)
{
// switch off 'swapfile'
- set_option_value_give_err("swf", 0L, NULL, OPT_LOCAL);
- set_option_value_give_err("bt", 0L, "quickfix", OPT_LOCAL);
- set_option_value_give_err("bh", 0L, "hide", OPT_LOCAL);
+ set_option_value_give_err("swf", BOOLEAN_OPTVAL(false), OPT_LOCAL);
+ set_option_value_give_err("bt", STATIC_CSTR_AS_OPTVAL("quickfix"), OPT_LOCAL);
+ set_option_value_give_err("bh", STATIC_CSTR_AS_OPTVAL("hide"), OPT_LOCAL);
RESET_BINDING(curwin);
curwin->w_p_diff = false;
- set_option_value_give_err("fdm", 0L, "manual", OPT_LOCAL);
+ set_option_value_give_err("fdm", STATIC_CSTR_AS_OPTVAL("manual"), OPT_LOCAL);
}
// Open a new quickfix or location list window, load the quickfix buffer and
@@ -3800,13 +3865,11 @@ static bool qf_win_pos_update(qf_info_T *qi, int old_qf_index)
static int is_qf_win(const win_T *win, const qf_info_T *qi)
FUNC_ATTR_NONNULL_ARG(2) FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
{
- //
// A window displaying the quickfix buffer will have the w_llist_ref field
// set to NULL.
// A window displaying a location list buffer will have the w_llist_ref
// pointing to the location list.
- //
- if (bt_quickfix(win->w_buffer)) {
+ if (buf_valid(win->w_buffer) && bt_quickfix(win->w_buffer)) {
if ((IS_QF_STACK(qi) && win->w_llist_ref == NULL)
|| (IS_LL_STACK(qi) && win->w_llist_ref == qi)) {
return true;
@@ -3854,11 +3917,12 @@ static buf_T *qf_find_buf(qf_info_T *qi)
}
/// Process the 'quickfixtextfunc' option value.
-void qf_process_qftf_option(char **errmsg)
+const char *did_set_quickfixtextfunc(optset_T *args FUNC_ATTR_UNUSED)
{
if (option_set_callback_func(p_qftf, &qftf_cb) == FAIL) {
- *errmsg = e_invarg;
+ return e_invarg;
}
+ return NULL;
}
/// Update the w:quickfix_title variable in the quickfix/location list window in
@@ -3945,21 +4009,21 @@ static int qf_buf_add_line(qf_list_T *qfl, buf_T *buf, linenr_T lnum, const qfli
char *dirname, char *qftf_str, bool first_bufline)
FUNC_ATTR_NONNULL_ARG(1, 2, 4, 5)
{
+ garray_T *gap = qfga_get();
+
// If the 'quickfixtextfunc' function returned a non-empty custom string
// for this entry, then use it.
if (qftf_str != NULL && *qftf_str != NUL) {
- xstrlcpy(IObuff, qftf_str, IOSIZE);
+ ga_concat(gap, qftf_str);
} else {
buf_T *errbuf;
- int len;
if (qfp->qf_module != NULL) {
- xstrlcpy(IObuff, qfp->qf_module, IOSIZE);
- len = (int)strlen(IObuff);
+ ga_concat(gap, qfp->qf_module);
} else if (qfp->qf_fnum != 0
&& (errbuf = buflist_findnr(qfp->qf_fnum)) != NULL
&& errbuf->b_fname != NULL) {
if (qfp->qf_type == 1) { // :helpgrep
- xstrlcpy(IObuff, path_tail(errbuf->b_fname), IOSIZE);
+ ga_concat(gap, path_tail(errbuf->b_fname));
} else {
// Shorten the file name if not done already.
// For optimization, do this only for the first entry in a
@@ -3972,48 +4036,38 @@ static int qf_buf_add_line(qf_list_T *qfl, buf_T *buf, linenr_T lnum, const qfli
}
shorten_buf_fname(errbuf, dirname, false);
}
- xstrlcpy(IObuff, errbuf->b_fname, IOSIZE);
+ ga_concat(gap, errbuf->b_fname);
}
- len = (int)strlen(IObuff);
- } else {
- len = 0;
}
- if (len < IOSIZE - 1) {
- IObuff[len++] = '|';
- }
- if (qfp->qf_lnum > 0) {
- qf_range_text(qfp, IObuff + len, IOSIZE - len);
- len += (int)strlen(IObuff + len);
- snprintf(IObuff + len, (size_t)(IOSIZE - len), "%s", qf_types(qfp->qf_type,
- qfp->qf_nr));
- len += (int)strlen(IObuff + len);
+ ga_append(gap, '|');
+
+ if (qfp->qf_lnum > 0) {
+ qf_range_text(gap, qfp);
+ ga_concat(gap, qf_types(qfp->qf_type, qfp->qf_nr));
} else if (qfp->qf_pattern != NULL) {
- qf_fmt_text(qfp->qf_pattern, IObuff + len, IOSIZE - len);
- len += (int)strlen(IObuff + len);
- }
- if (len < IOSIZE - 2) {
- IObuff[len++] = '|';
- IObuff[len++] = ' ';
+ qf_fmt_text(gap, qfp->qf_pattern);
}
+ ga_append(gap, '|');
+ ga_append(gap, ' ');
// Remove newlines and leading whitespace from the text.
// For an unrecognized line keep the indent, the compiler may
// mark a word with ^^^^.
- qf_fmt_text(len > 3 ? skipwhite(qfp->qf_text) : qfp->qf_text,
- IObuff + len, IOSIZE - len);
+ qf_fmt_text(gap, gap->ga_len > 3 ? skipwhite(qfp->qf_text) : qfp->qf_text);
}
- if (ml_append_buf(buf, lnum, IObuff,
- (colnr_T)strlen(IObuff) + 1, false) == FAIL) {
+ ga_append(gap, NUL);
+ if (ml_append_buf(buf, lnum, gap->ga_data, gap->ga_len, false) == FAIL) {
return FAIL;
}
+
return OK;
}
// Call the 'quickfixtextfunc' function to get the list of lines to display in
// the quickfix window for the entries 'start_idx' to 'end_idx'.
-static list_T *call_qftf_func(qf_list_T *qfl, int qf_winid, long start_idx, long end_idx)
+static list_T *call_qftf_func(qf_list_T *qfl, int qf_winid, int start_idx, int end_idx)
{
Callback *cb = &qftf_cb;
list_T *qftf_list = NULL;
@@ -4078,7 +4132,12 @@ static void qf_fill_buffer(qf_list_T *qfl, buf_T *buf, qfline_T *old_last, int q
// delete all existing lines
while ((curbuf->b_ml.ml_flags & ML_EMPTY) == 0) {
- (void)ml_delete((linenr_T)1, false);
+ // If deletion fails, this loop may run forever, so
+ // signal error and return.
+ if (ml_delete(1, false) == FAIL) {
+ internal_error("qf_fill_buffer()");
+ return;
+ }
}
}
@@ -4104,7 +4163,7 @@ static void qf_fill_buffer(qf_list_T *qfl, buf_T *buf, qfline_T *old_last, int q
lnum = buf->b_ml.ml_line_count;
}
- list_T *qftf_list = call_qftf_func(qfl, qf_winid, lnum + 1, (long)qfl->qf_count);
+ list_T *qftf_list = call_qftf_func(qfl, qf_winid, lnum + 1, qfl->qf_count);
listitem_T *qftf_li = tv_list_first(qftf_list);
int prev_bufnr = -1;
@@ -4142,6 +4201,8 @@ static void qf_fill_buffer(qf_list_T *qfl, buf_T *buf, qfline_T *old_last, int q
// Delete the empty line which is now at the end
(void)ml_delete(lnum + 1, false);
}
+
+ qfga_clear();
}
// Correct cursor position.
@@ -4152,7 +4213,7 @@ static void qf_fill_buffer(qf_list_T *qfl, buf_T *buf, qfline_T *old_last, int q
// resembles reading a file into a buffer, it's more logical when using
// autocommands.
curbuf->b_ro_locked++;
- set_option_value_give_err("ft", 0L, "qf", OPT_LOCAL);
+ set_option_value_give_err("ft", STATIC_CSTR_AS_OPTVAL("qf"), OPT_LOCAL);
curbuf->b_p_ma = false;
keep_filetype = true; // don't detect 'filetype'
@@ -4263,11 +4324,11 @@ static char *make_get_fullcmd(const char *makecmd, const char *fname)
len += strlen(p_sp) + strlen(fname) + 3;
}
char *const cmd = xmalloc(len);
- snprintf(cmd, len, "%s%s%s", p_shq, (char *)makecmd, p_shq);
+ snprintf(cmd, len, "%s%s%s", p_shq, makecmd, p_shq);
// If 'shellpipe' empty: don't redirect to 'errorfile'.
if (*p_sp != NUL) {
- append_redir(cmd, len, p_sp, (char *)fname);
+ append_redir(cmd, len, p_sp, fname);
}
// Display the fully formed command. Output a newline if there's something
@@ -4278,7 +4339,7 @@ static char *make_get_fullcmd(const char *makecmd, const char *fname)
}
msg_start();
msg_puts(":!");
- msg_outtrans(cmd); // show what we are doing
+ msg_outtrans(cmd, 0); // show what we are doing
return cmd;
}
@@ -4391,7 +4452,7 @@ static char *get_mef_name(void)
}
// Keep trying until the name doesn't exist yet.
- for (;;) {
+ while (true) {
if (start == -1) {
start = (int)os_get_pid();
} else {
@@ -5129,9 +5190,9 @@ static void vgr_display_fname(char *fname)
msg_start();
char *p = msg_strtrunc(fname, true);
if (p == NULL) {
- msg_outtrans(fname);
+ msg_outtrans(fname, 0);
} else {
- msg_outtrans(p);
+ msg_outtrans(p, 0);
xfree(p);
}
msg_clr_eos();
@@ -5148,7 +5209,7 @@ static buf_T *vgr_load_dummy_buf(char *fname, char *dirname_start, char *dirname
// indent scripts, a great speed improvement.
char *save_ei = au_event_disable(",Filetype");
- long save_mls = p_mls;
+ OptInt save_mls = p_mls;
p_mls = 0;
// Load file into a buffer, so that 'fileencoding' is detected,
@@ -5187,11 +5248,14 @@ static bool vgr_qflist_valid(win_T *wp, qf_info_T *qi, unsigned qfid, char *titl
/// Search for a pattern in all the lines in a buffer and add the matching lines
/// to a quickfix list.
static bool vgr_match_buflines(qf_list_T *qfl, char *fname, buf_T *buf, char *spat,
- regmmatch_T *regmatch, long *tomatch, int duplicate_name, int flags)
+ regmmatch_T *regmatch, int *tomatch, int duplicate_name, int flags)
FUNC_ATTR_NONNULL_ARG(1, 3, 4, 5, 6)
{
bool found_match = false;
- const size_t pat_len = strlen(spat);
+ size_t pat_len = strlen(spat);
+ if (pat_len > MAX_FUZZY_MATCHES) {
+ pat_len = MAX_FUZZY_MATCHES;
+ }
for (linenr_T lnum = 1; lnum <= buf->b_ml.ml_line_count && *tomatch > 0; lnum++) {
colnr_T col = 0;
@@ -5206,7 +5270,7 @@ static bool vgr_match_buflines(qf_list_T *qfl, char *fname, buf_T *buf, char *sp
fname,
NULL,
duplicate_name ? 0 : buf->b_fnum,
- ml_get_buf(buf, regmatch->startpos[0].lnum + lnum, false),
+ ml_get_buf(buf, regmatch->startpos[0].lnum + lnum),
regmatch->startpos[0].lnum + lnum,
regmatch->endpos[0].lnum + lnum,
regmatch->startpos[0].col + 1,
@@ -5215,6 +5279,7 @@ static bool vgr_match_buflines(qf_list_T *qfl, char *fname, buf_T *buf, char *sp
NULL, // search pattern
0, // nr
0, // type
+ NULL, // user_data
true) // valid
== QF_FAIL) {
got_int = true;
@@ -5228,17 +5293,18 @@ static bool vgr_match_buflines(qf_list_T *qfl, char *fname, buf_T *buf, char *sp
break;
}
col = regmatch->endpos[0].col + (col == regmatch->endpos[0].col);
- if (col > (colnr_T)strlen(ml_get_buf(buf, lnum, false))) {
+ if (col > (colnr_T)strlen(ml_get_buf(buf, lnum))) {
break;
}
}
} else {
- char *const str = ml_get_buf(buf, lnum, false);
+ char *const str = ml_get_buf(buf, lnum);
int score;
uint32_t matches[MAX_FUZZY_MATCHES];
const size_t sz = sizeof(matches) / sizeof(matches[0]);
// Fuzzy string match
+ CLEAR_FIELD(matches);
while (fuzzy_match(str + col, spat, false, &score, matches, (int)sz) > 0) {
// Pass the buffer number so that it gets used even for a
// dummy buffer, unless duplicate_name is set, then the
@@ -5257,6 +5323,7 @@ static bool vgr_match_buflines(qf_list_T *qfl, char *fname, buf_T *buf, char *sp
NULL, // search pattern
0, // nr
0, // type
+ NULL, // user_data
true) // valid
== QF_FAIL) {
got_int = true;
@@ -5380,7 +5447,7 @@ static int vgr_process_files(win_T *wp, qf_info_T *qi, vgr_args_T *cmd_args, boo
// ":lcd %:p:h" changes the meaning of short path names.
os_dirname(dirname_start, MAXPATHL);
- time_t seconds = (time_t)0;
+ time_t seconds = 0;
for (int fi = 0; fi < cmd_args->fcount && !got_int && cmd_args->tomatch > 0; fi++) {
char *fname = path_try_shorten_fname(cmd_args->fnames[fi]);
if (time(NULL) > seconds) {
@@ -5413,7 +5480,7 @@ static int vgr_process_files(win_T *wp, qf_info_T *qi, vgr_args_T *cmd_args, boo
if (buf == NULL) {
if (!got_int) {
- smsg(_("Cannot open file \"%s\""), fname);
+ smsg(0, _("Cannot open file \"%s\""), fname);
}
} else {
// Try for a match in all lines of the buffer.
@@ -5618,7 +5685,7 @@ static void restore_start_dir(char *dirname_start)
static buf_T *load_dummy_buffer(char *fname, char *dirname_start, char *resulting_dir)
{
// Allocate a buffer without putting it in the buffer list.
- buf_T *newbuf = buflist_new(NULL, NULL, (linenr_T)1, BLN_DUMMY);
+ buf_T *newbuf = buflist_new(NULL, NULL, 1, BLN_DUMMY);
if (newbuf == NULL) {
return NULL;
}
@@ -5650,7 +5717,7 @@ static buf_T *load_dummy_buffer(char *fname, char *dirname_start, char *resultin
bufref_T newbuf_to_wipe;
newbuf_to_wipe.br_buf = NULL;
- int readfile_result = readfile(fname, NULL, (linenr_T)0, (linenr_T)0,
+ int readfile_result = readfile(fname, NULL, 0, 0,
(linenr_T)MAXLNUM, NULL,
READ_NEW | READ_DUMMY, false);
newbuf->b_locked--;
@@ -5772,28 +5839,21 @@ static int get_qfline_items(qfline_T *qfp, list_T *list)
buf[0] = qfp->qf_type;
buf[1] = NUL;
if (tv_dict_add_nr(dict, S_LEN("bufnr"), (varnumber_T)bufnum) == FAIL
- || (tv_dict_add_nr(dict, S_LEN("lnum"), (varnumber_T)qfp->qf_lnum)
- == FAIL)
- || (tv_dict_add_nr(dict, S_LEN("end_lnum"), (varnumber_T)qfp->qf_end_lnum)
- == FAIL)
+ || (tv_dict_add_nr(dict, S_LEN("lnum"), (varnumber_T)qfp->qf_lnum) == FAIL)
+ || (tv_dict_add_nr(dict, S_LEN("end_lnum"), (varnumber_T)qfp->qf_end_lnum) == FAIL)
|| (tv_dict_add_nr(dict, S_LEN("col"), (varnumber_T)qfp->qf_col) == FAIL)
- || (tv_dict_add_nr(dict, S_LEN("end_col"), (varnumber_T)qfp->qf_end_col)
- == FAIL)
- || (tv_dict_add_nr(dict, S_LEN("vcol"), (varnumber_T)qfp->qf_viscol)
- == FAIL)
+ || (tv_dict_add_nr(dict, S_LEN("end_col"), (varnumber_T)qfp->qf_end_col) == FAIL)
+ || (tv_dict_add_nr(dict, S_LEN("vcol"), (varnumber_T)qfp->qf_viscol) == FAIL)
|| (tv_dict_add_nr(dict, S_LEN("nr"), (varnumber_T)qfp->qf_nr) == FAIL)
- || (tv_dict_add_str(dict, S_LEN("module"),
- (qfp->qf_module == NULL ? "" : (const char *)qfp->qf_module))
- == FAIL)
- || (tv_dict_add_str(dict, S_LEN("pattern"),
- (qfp->qf_pattern == NULL ? "" : (const char *)qfp->qf_pattern))
+ || (tv_dict_add_str(dict, S_LEN("module"), (qfp->qf_module == NULL ? "" : qfp->qf_module))
== FAIL)
- || (tv_dict_add_str(dict, S_LEN("text"),
- (qfp->qf_text == NULL ? "" : (const char *)qfp->qf_text))
+ || (tv_dict_add_str(dict, S_LEN("pattern"), (qfp->qf_pattern == NULL ? "" : qfp->qf_pattern))
== FAIL)
- || (tv_dict_add_str(dict, S_LEN("type"), (const char *)buf) == FAIL)
- || (tv_dict_add_nr(dict, S_LEN("valid"), (varnumber_T)qfp->qf_valid)
- == FAIL)) {
+ || (tv_dict_add_str(dict, S_LEN("text"), (qfp->qf_text == NULL ? "" : qfp->qf_text)) == FAIL)
+ || (tv_dict_add_str(dict, S_LEN("type"), buf) == FAIL)
+ || (qfp->qf_user_data.v_type != VAR_UNKNOWN
+ && tv_dict_add_tv(dict, S_LEN("user_data"), &qfp->qf_user_data) == FAIL)
+ || (tv_dict_add_nr(dict, S_LEN("valid"), (varnumber_T)qfp->qf_valid) == FAIL)) {
// tv_dict_add* fail only if key already exist, but this is a newly
// allocated dictionary which is thus guaranteed to have no existing keys.
abort();
@@ -5897,7 +5957,7 @@ static int qf_get_list_from_lines(dict_T *what, dictitem_T *di, dict_T *retdict)
qf_info_T *const qi = qf_alloc_stack(QFLT_INTERNAL);
if (qf_init_ext(qi, 0, NULL, NULL, &di->di_tv, errorformat,
- true, (linenr_T)0, (linenr_T)0, NULL, NULL) > 0) {
+ true, 0, 0, NULL, NULL) > 0) {
(void)get_errorlist(qi, NULL, 0, 0, l);
qf_free(&qi->qf_lists[0]);
}
@@ -6016,8 +6076,7 @@ static int qf_getprop_qfidx(qf_info_T *qi, dict_T *what)
qf_idx = INVALID_QFIDX;
}
}
- } else if (di->di_tv.v_type == VAR_STRING
- && strequal((const char *)di->di_tv.vval.v_string, "$")) {
+ } else if (di->di_tv.v_type == VAR_STRING && strequal(di->di_tv.vval.v_string, "$")) {
// Get the last quickfix list number
qf_idx = qi->qf_listcount - 1;
} else {
@@ -6046,7 +6105,7 @@ static int qf_getprop_defaults(qf_info_T *qi, int flags, int locstack, dict_T *r
int status = OK;
if (flags & QF_GETLIST_TITLE) {
- status = tv_dict_add_str(retdict, S_LEN("title"), (const char *)"");
+ status = tv_dict_add_str(retdict, S_LEN("title"), "");
}
if ((status == OK) && (flags & QF_GETLIST_ITEMS)) {
list_T *l = tv_list_alloc(kListLenMayKnow);
@@ -6059,7 +6118,7 @@ static int qf_getprop_defaults(qf_info_T *qi, int flags, int locstack, dict_T *r
status = tv_dict_add_nr(retdict, S_LEN("winid"), qf_winid(qi));
}
if ((status == OK) && (flags & QF_GETLIST_CONTEXT)) {
- status = tv_dict_add_str(retdict, S_LEN("context"), (const char *)"");
+ status = tv_dict_add_str(retdict, S_LEN("context"), "");
}
if ((status == OK) && (flags & QF_GETLIST_ID)) {
status = tv_dict_add_nr(retdict, S_LEN("id"), 0);
@@ -6089,8 +6148,7 @@ static int qf_getprop_defaults(qf_info_T *qi, int flags, int locstack, dict_T *r
/// Return the quickfix list title as 'title' in retdict
static int qf_getprop_title(qf_list_T *qfl, dict_T *retdict)
{
- return tv_dict_add_str(retdict, S_LEN("title"),
- (const char *)qfl->qf_title);
+ return tv_dict_add_str(retdict, S_LEN("title"), qfl->qf_title);
}
// Returns the identifier of the window used to display files from a location
@@ -6274,8 +6332,7 @@ static int qf_setprop_qftf(qf_list_T *qfl, dictitem_T *di)
/// Add a new quickfix entry to list at 'qf_idx' in the stack 'qi' from the
/// items in the dict 'd'. If it is a valid error entry, then set 'valid_entry'
/// to true.
-static int qf_add_entry_from_dict(qf_list_T *qfl, const dict_T *d, bool first_entry,
- bool *valid_entry)
+static int qf_add_entry_from_dict(qf_list_T *qfl, dict_T *d, bool first_entry, bool *valid_entry)
FUNC_ATTR_NONNULL_ALL
{
static bool did_bufnr_emsg;
@@ -6299,6 +6356,9 @@ static int qf_add_entry_from_dict(qf_list_T *qfl, const dict_T *d, bool first_en
if (text == NULL) {
text = xcalloc(1, 1);
}
+ typval_T user_data = { .v_type = VAR_UNKNOWN };
+ tv_dict_get_tv(d, "user_data", &user_data);
+
bool valid = true;
if ((filename == NULL && bufnum == 0)
|| (lnum == 0 && pattern == NULL)) {
@@ -6335,12 +6395,14 @@ static int qf_add_entry_from_dict(qf_list_T *qfl, const dict_T *d, bool first_en
pattern, // search pattern
nr,
type == NULL ? NUL : *type,
+ &user_data,
valid);
xfree(filename);
xfree(module);
xfree(pattern);
xfree(text);
+ tv_clear(&user_data);
if (valid) {
*valid_entry = true;
@@ -6376,13 +6438,12 @@ static int qf_add_entries(qf_info_T *qi, int qf_idx, list_T *list, char *title,
continue; // Skip non-dict items.
}
- const dict_T *const d = TV_LIST_ITEM_TV(li)->vval.v_dict;
+ dict_T *const d = TV_LIST_ITEM_TV(li)->vval.v_dict;
if (d == NULL) {
continue;
}
- retval = qf_add_entry_from_dict(qfl, d, li == tv_list_first(list),
- &valid_entry);
+ retval = qf_add_entry_from_dict(qfl, d, li == tv_list_first(list), &valid_entry);
if (retval == QF_FAIL) {
break;
}
@@ -6439,8 +6500,7 @@ static int qf_setprop_get_qfidx(const qf_info_T *qi, const dict_T *what, int act
} else if (action != ' ') {
*newlist = false; // use the specified list
}
- } else if (di->di_tv.v_type == VAR_STRING
- && strequal((const char *)di->di_tv.vval.v_string, "$")) {
+ } else if (di->di_tv.v_type == VAR_STRING && strequal(di->di_tv.vval.v_string, "$")) {
if (!qf_stack_empty(qi)) {
qf_idx = qi->qf_listcount - 1;
} else if (*newlist) {
@@ -6525,7 +6585,7 @@ static int qf_setprop_items_from_lines(qf_info_T *qi, int qf_idx, const dict_T *
qf_free_items(&qi->qf_lists[qf_idx]);
}
if (qf_init_ext(qi, qf_idx, NULL, NULL, &di->di_tv, errorformat,
- false, (linenr_T)0, (linenr_T)0, NULL, NULL) >= 0) {
+ false, 0, 0, NULL, NULL) >= 0) {
retval = OK;
}
@@ -6721,6 +6781,27 @@ int set_errorlist(win_T *wp, list_T *list, int action, char *title, dict_T *what
return retval;
}
+static bool mark_quickfix_user_data(qf_info_T *qi, int copyID)
+{
+ bool abort = false;
+ for (int i = 0; i < LISTCOUNT && !abort; i++) {
+ qf_list_T *qfl = &qi->qf_lists[i];
+ if (!qfl->qf_has_user_data) {
+ continue;
+ }
+ qfline_T *qfp;
+ int j;
+ FOR_ALL_QFL_ITEMS(qfl, qfp, j) {
+ typval_T *user_data = &qfp->qf_user_data;
+ if (user_data != NULL && user_data->v_type != VAR_NUMBER
+ && user_data->v_type != VAR_STRING && user_data->v_type != VAR_FLOAT) {
+ abort = abort || set_ref_in_item(user_data, copyID, NULL, NULL);
+ }
+ }
+ }
+ return abort;
+}
+
/// Mark the quickfix context and callback function as in use for all the lists
/// in a quickfix stack.
static bool mark_quickfix_ctx(qf_info_T *qi, int copyID)
@@ -6750,6 +6831,11 @@ bool set_ref_in_quickfix(int copyID)
return abort;
}
+ abort = mark_quickfix_user_data(&ql_info, copyID);
+ if (abort) {
+ return abort;
+ }
+
abort = set_ref_in_callback(&qftf_cb, copyID, NULL, NULL);
if (abort) {
return abort;
@@ -6761,6 +6847,11 @@ bool set_ref_in_quickfix(int copyID)
if (abort) {
return abort;
}
+
+ abort = mark_quickfix_user_data(win->w_llist, copyID);
+ if (abort) {
+ return abort;
+ }
}
if (IS_LL_WINDOW(win) && (win->w_llist_ref->qf_refcount == 1)) {
@@ -6946,18 +7037,18 @@ void ex_cexpr(exarg_T *eap)
// Evaluate the expression. When the result is a string or a list we can
// use it to fill the errorlist.
- typval_T tv;
- if (eval0(eap->arg, &tv, &eap->nextcmd, true) == FAIL) {
+ typval_T *tv = eval_expr(eap->arg, eap);
+ if (tv == NULL) {
return;
}
- if ((tv.v_type == VAR_STRING && tv.vval.v_string != NULL)
- || tv.v_type == VAR_LIST) {
+ if ((tv->v_type == VAR_STRING && tv->vval.v_string != NULL)
+ || tv->v_type == VAR_LIST) {
incr_quickfix_busy();
- int res = qf_init_ext(qi, qi->qf_curlist, NULL, NULL, &tv, p_efm,
+ int res = qf_init_ext(qi, qi->qf_curlist, NULL, NULL, tv, p_efm,
(eap->cmdidx != CMD_caddexpr
&& eap->cmdidx != CMD_laddexpr),
- (linenr_T)0, (linenr_T)0,
+ 0, 0,
qf_cmdtitle(*eap->cmdlinep), NULL);
if (qf_stack_empty(qi)) {
decr_quickfix_busy();
@@ -6985,7 +7076,7 @@ void ex_cexpr(exarg_T *eap)
emsg(_("E777: String or List expected"));
}
cleanup:
- tv_clear(&tv);
+ tv_free(tv);
}
// Get the location list for ":lhelpgrep"
@@ -7018,7 +7109,7 @@ static void hgr_search_file(qf_list_T *qfl, char *fname, regmatch_T *p_regmatch)
while (!vim_fgets(IObuff, IOSIZE, fd) && !got_int) {
char *line = IObuff;
- if (vim_regexec(p_regmatch, line, (colnr_T)0)) {
+ if (vim_regexec(p_regmatch, line, 0)) {
int l = (int)strlen(line);
// remove trailing CR, LF, spaces, etc.
@@ -7041,7 +7132,8 @@ static void hgr_search_file(qf_list_T *qfl, char *fname, regmatch_T *p_regmatch)
NULL, // search pattern
0, // nr
1, // type
- true) // valid
+ NULL, // user_data
+ true) // valid
== QF_FAIL) {
got_int = true;
if (line != IObuff) {
@@ -7101,7 +7193,7 @@ static void hgr_search_in_rtp(qf_list_T *qfl, regmatch_T *p_regmatch, const char
while (*p != NUL && !got_int) {
copy_option_part(&p, NameBuff, MAXPATHL, ",");
- hgr_search_files_in_dir(qfl, NameBuff, p_regmatch, (char *)lang);
+ hgr_search_files_in_dir(qfl, NameBuff, p_regmatch, lang);
}
}
@@ -7130,7 +7222,7 @@ void ex_helpgrep(exarg_T *eap)
// Make 'cpoptions' empty, the 'l' flag should not be used here.
char *const save_cpo = p_cpo;
const bool save_cpo_allocated = is_option_allocated("cpo");
- p_cpo = empty_option;
+ p_cpo = empty_string_option;
bool new_qi = false;
if (is_loclist_cmd(eap->cmdidx)) {
@@ -7161,13 +7253,13 @@ void ex_helpgrep(exarg_T *eap)
updated = true;
}
- if (p_cpo == empty_option) {
+ if (p_cpo == empty_string_option) {
p_cpo = save_cpo;
} else {
// Darn, some plugin changed the value. If it's still empty it was
// changed and restored, need to restore in the complicated way.
if (*p_cpo == NUL) {
- set_option_value_give_err("cpo", 0L, save_cpo, 0);
+ set_option_value_give_err("cpo", CSTR_AS_OPTVAL(save_cpo), 0);
}
if (save_cpo_allocated) {
free_string_option(save_cpo);
@@ -7214,6 +7306,19 @@ void ex_helpgrep(exarg_T *eap)
}
}
+#if defined(EXITFREE)
+void free_quickfix(void)
+{
+ qf_free_all(NULL);
+ // Free all location lists
+ FOR_ALL_TAB_WINDOWS(tab, win) {
+ qf_free_all(win);
+ }
+
+ ga_clear(&qfga);
+}
+#endif
+
static void get_qf_loc_list(int is_qf, win_T *wp, typval_T *what_arg, typval_T *rettv)
{
if (what_arg->v_type == VAR_UNKNOWN) {
@@ -7250,7 +7355,7 @@ void f_getqflist(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
get_qf_loc_list(true, NULL, &argvars[0], rettv);
}
-/// Create quickfix/location list from VimL values
+/// Create quickfix/location list from Vimscript values
///
/// Used by `setqflist()` and `setloclist()` functions. Accepts invalid
/// args argument in which case errors out, including VAR_UNKNOWN parameters.
@@ -7268,7 +7373,7 @@ void f_getqflist(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
static void set_qf_ll_list(win_T *wp, typval_T *args, typval_T *rettv)
FUNC_ATTR_NONNULL_ARG(2, 3)
{
- static char *e_invact = N_("E927: Invalid action: '%s'");
+ static const char *e_invact = N_("E927: Invalid action: '%s'");
const char *title = NULL;
char action = ' ';
static int recursive = 0;