diff options
Diffstat (limited to 'src/nvim/quickfix.c')
-rw-r--r-- | src/nvim/quickfix.c | 1424 |
1 files changed, 777 insertions, 647 deletions
diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c index 0196e05455..2138437b29 100644 --- a/src/nvim/quickfix.c +++ b/src/nvim/quickfix.c @@ -22,6 +22,7 @@ #include "nvim/ex_getln.h" #include "nvim/fileio.h" #include "nvim/fold.h" +#include "nvim/highlight_group.h" #include "nvim/mark.h" #include "nvim/mbyte.h" #include "nvim/memline.h" @@ -39,15 +40,13 @@ #include "nvim/screen.h" #include "nvim/search.h" #include "nvim/strings.h" -#include "nvim/syntax.h" #include "nvim/ui.h" #include "nvim/vim.h" #include "nvim/window.h" - struct dir_stack_T { struct dir_stack_T *next; - char_u *dirname; + char *dirname; }; // For each error the next struct is allocated and linked in a list. @@ -62,23 +61,23 @@ 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_u *qf_module; ///< module name for this error - char_u *qf_pattern; ///< search pattern for the error - char_u *qf_text; ///< description of the error - char_u qf_viscol; ///< set to TRUE if qf_col and qf_end_col is + 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_u qf_cleared; ///< set to TRUE if line has been deleted - char_u qf_type; ///< type of the error (mostly 'E'); 1 for :helpgrep - char_u qf_valid; ///< valid error message detected + 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 }; // There is a stack of error lists. #define LISTCOUNT 10 #define INVALID_QFIDX (-1) +#define INVALID_QFBUFNR (0) /// Quickfix list type. -typedef enum -{ +typedef enum { QFLT_QUICKFIX, ///< Quickfix list - global list QFLT_LOCATION, ///< Location list - per window list QFLT_INTERNAL, ///< Internal - Temporary list used by @@ -99,15 +98,15 @@ typedef struct qf_list_S { 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_u *qf_title; ///< title derived from the command that created - ///< the error list or set by setqflist + 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 qftf_cb; ///< 'quickfixtextfunc' callback function + Callback qf_qftf_cb; ///< 'quickfixtextfunc' callback function struct dir_stack_T *qf_dir_stack; - char_u *qf_directory; + char *qf_directory; struct dir_stack_T *qf_file_stack; - char_u *qf_currfile; + char *qf_currfile; bool qf_multiline; bool qf_multiignore; bool qf_multiscan; @@ -126,36 +125,37 @@ struct qf_info_S { int qf_curlist; // current error list qf_list_T qf_lists[LISTCOUNT]; qfltype_T qfl_type; // type of list + int qf_bufnr; // quickfix window buffer number }; static qf_info_T ql_info; // global quickfix list static unsigned last_qf_id = 0; // Last Used quickfix list id -#define FMT_PATTERNS 11 // maximum number of % recognized +#define FMT_PATTERNS 13 // maximum number of % recognized // Structure used to hold the info of one part of 'errorformat' typedef struct efm_S efm_T; struct efm_S { regprog_T *prog; // pre-formatted part of 'errorformat' efm_T *next; // pointer to next (NULL if last) - char_u addr[FMT_PATTERNS]; // indices of used % patterns - char_u prefix; // prefix of this format line: - // 'D' enter directory - // 'X' leave directory - // 'A' start of multi-line message - // 'E' error message - // 'W' warning message - // 'I' informational message - // 'N' note message - // 'C' continuation line - // 'Z' end of multi-line message - // 'G' general, unspecific message - // 'P' push file (partial) message - // 'Q' pop/quit file (partial) message - // 'O' overread (partial) message - char_u flags; // additional flags given in prefix - // '-' do not include this line - // '+' include whole line in message + char addr[FMT_PATTERNS]; // indices of used % patterns + char prefix; // prefix of this format line: + // 'D' enter directory + // 'X' leave directory + // 'A' start of multi-line message + // 'E' error message + // 'W' warning message + // 'I' informational message + // 'N' note message + // 'C' continuation line + // 'Z' end of multi-line message + // 'G' general, unspecific message + // 'P' push file (partial) message + // 'Q' pop/quit file (partial) message + // 'O' overread (partial) message + char flags; // additional flags given in prefix + // '-' do not include this line + // '+' include whole line in message int conthere; // %> used }; @@ -178,13 +178,13 @@ enum { /// State information used to parse lines and add entries to a quickfix/location /// list. typedef struct { - char_u *linebuf; + char *linebuf; size_t linelen; - char_u *growbuf; + char *growbuf; size_t growbufsiz; FILE *fd; typval_T *tv; - char_u *p_str; + char *p_str; list_T *p_list; listitem_T *p_li; buf_T *buf; @@ -194,55 +194,65 @@ typedef struct { } qfstate_T; typedef struct { - char_u *namebuf; - char_u *module; - char_u *errmsg; + char *namebuf; + char *module; + char *errmsg; size_t errmsglen; - long lnum; - long end_lnum; + linenr_T lnum; + linenr_T end_lnum; int col; int end_col; bool use_viscol; - char_u *pattern; + char *pattern; int enr; - char_u type; + char type; bool valid; } qffields_T; +/// :vimgrep command arguments +typedef struct vgr_args_S { + long tomatch; ///< maximum number of matches to find + char *spat; ///< search pattern + int flags; ///< search modifier + char **fnames; ///< list of files to search + int fcount; ///< number of files + regmmatch_T regmatch; ///< compiled search pattern + char *qf_title; ///< quickfix list title +} vgr_args_T; + #ifdef INCLUDE_GENERATED_DECLARATIONS # include "quickfix.c.generated.h" #endif -static char_u *e_no_more_items = (char_u *)N_("E553: No more items"); +static char *e_no_more_items = N_("E553: No more items"); // Quickfix window check helper macro -#define IS_QF_WINDOW(wp) (bt_quickfix(wp->w_buffer) && wp->w_llist_ref == NULL) +#define IS_QF_WINDOW(wp) (bt_quickfix((wp)->w_buffer) && (wp)->w_llist_ref == NULL) // Location list window check helper macro -#define IS_LL_WINDOW(wp) (bt_quickfix(wp->w_buffer) && wp->w_llist_ref != NULL) +#define IS_LL_WINDOW(wp) (bt_quickfix((wp)->w_buffer) && (wp)->w_llist_ref != NULL) // Quickfix and location list stack check helper macros -#define IS_QF_STACK(qi) (qi->qfl_type == QFLT_QUICKFIX) -#define IS_LL_STACK(qi) (qi->qfl_type == QFLT_LOCATION) -#define IS_QF_LIST(qfl) (qfl->qfl_type == QFLT_QUICKFIX) -#define IS_LL_LIST(qfl) (qfl->qfl_type == QFLT_LOCATION) +#define IS_QF_STACK(qi) ((qi)->qfl_type == QFLT_QUICKFIX) +#define IS_LL_STACK(qi) ((qi)->qfl_type == QFLT_LOCATION) +#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) +#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 // Quickfix item index starts from 1, so i below starts at 1 #define FOR_ALL_QFL_ITEMS(qfl, qfp, i) \ - for (i = 1, qfp = qfl->qf_start; /* NOLINT(readability/braces) */ \ - !got_int && i <= qfl->qf_count && qfp != NULL; \ - i++, qfp = qfp->qf_next) - + for ((i) = 1, (qfp) = (qfl)->qf_start; /* NOLINT(readability/braces) */ \ + !got_int && (i) <= (qfl)->qf_count && (qfp) != NULL; \ + (i)++, (qfp) = (qfp)->qf_next) // Looking up a buffer can be slow if there are many. Remember the last one // to make this a lot faster if there are multiple matches in the same file. -static char_u *qf_last_bufname = NULL; +static char *qf_last_bufname = NULL; static bufref_T qf_last_bufref = { NULL, 0, 0 }; static char *e_current_quickfix_list_was_changed = @@ -279,7 +289,7 @@ static int qf_init_process_nextline(qf_list_T *qfl, efm_T *fmt_first, qfstate_T (*fields->namebuf || qfl->qf_directory != NULL) ? fields->namebuf : ((qfl->qf_currfile != NULL && fields->valid) - ? qfl->qf_currfile : (char_u *)NULL), + ? qfl->qf_currfile : NULL), fields->module, 0, fields->errmsg, @@ -305,8 +315,8 @@ static int qf_init_process_nextline(qf_list_T *qfl, efm_T *fmt_first, qfstate_T /// @params enc If non-NULL, encoding used to parse errors /// /// @returns -1 for error, number of errors for success. -int qf_init(win_T *wp, const char_u *restrict efile, char_u *restrict errorformat, int newlist, - const char_u *restrict qf_title, char_u *restrict enc) +int qf_init(win_T *wp, const char *restrict efile, char *restrict errorformat, int newlist, + const char *restrict qf_title, char *restrict enc) { qf_info_T *qi = &ql_info; @@ -314,37 +324,41 @@ int qf_init(win_T *wp, const char_u *restrict efile, char_u *restrict errorforma qi = ll_get_or_alloc_list(wp); } - return qf_init_ext(qi, qi->qf_curlist, efile, curbuf, NULL, errorformat, - newlist, (linenr_T)0, (linenr_T)0, qf_title, enc); + return qf_init_ext(qi, qi->qf_curlist, (char *)efile, curbuf, NULL, errorformat, + newlist, (linenr_T)0, (linenr_T)0, (char *)qf_title, enc); } // Maximum number of bytes allowed per line while reading an errorfile. static const size_t LINE_MAXLEN = 4096; +/// Patterns used. Keep in sync with qf_parse_fmt[]. static struct fmtpattern { - char_u convchar; + char convchar; char *pattern; } fmt_pat[FMT_PATTERNS] = { - { 'f', ".\\+" }, // only used when at end - { 'n', "\\d\\+" }, - { 'l', "\\d\\+" }, - { 'c', "\\d\\+" }, - { 't', "." }, - { 'm', ".\\+" }, - { 'r', ".*" }, - { 'p', "[- .]*"}, // NOLINT(whitespace/tab) - { 'v', "\\d\\+" }, - { 's', ".\\+" }, - { 'o', ".\\+" } + { '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 }; /// Convert an errorformat pattern to a regular expression pattern. /// See fmt_pat definition above for the list of supported patterns. The /// pattern specifier is supplied in "efmpat". The converted pattern is stored /// in "regpat". Returns a pointer to the location after the pattern. -static char_u *efmpat_to_regpat(const char_u *efmpat, char_u *regpat, efm_T *efminfo, int idx, - int round) +static char *efmpat_to_regpat(const char *efmpat, char *regpat, efm_T *efminfo, int idx, int round) FUNC_ATTR_NONNULL_ALL { if (efminfo->addr[idx]) { @@ -352,14 +366,14 @@ static char_u *efmpat_to_regpat(const char_u *efmpat, char_u *regpat, efm_T *efm semsg(_("E372: Too many %%%c in format string"), *efmpat); return NULL; } - if ((idx && idx < 6 - && vim_strchr((char_u *)"DXOPQ", efminfo->prefix) != NULL) - || (idx == 6 - && vim_strchr((char_u *)"OPQ", efminfo->prefix) == NULL)) { + if ((idx && idx < FMT_PATTERN_R + && vim_strchr("DXOPQ", efminfo->prefix) != NULL) + || (idx == FMT_PATTERN_R + && vim_strchr("OPQ", efminfo->prefix) == NULL)) { semsg(_("E373: Unexpected %%%c in format string"), *efmpat); return NULL; } - efminfo->addr[idx] = (char_u)++ round; + efminfo->addr[idx] = (char)++round; *regpat++ = '\\'; *regpat++ = '('; #ifdef BACKSLASH_IN_FILENAME @@ -387,7 +401,7 @@ static char_u *efmpat_to_regpat(const char_u *efmpat, char_u *regpat, efm_T *efm regpat += 4; } } else { - char_u *srcptr = (char_u *)fmt_pat[idx].pattern; + char *srcptr = fmt_pat[idx].pattern; while ((*regpat = *srcptr++) != NUL) { regpat++; } @@ -400,10 +414,10 @@ static char_u *efmpat_to_regpat(const char_u *efmpat, char_u *regpat, efm_T *efm /// Convert a scanf like format in 'errorformat' to a regular expression. /// Returns a pointer to the location after the pattern. -static char_u *scanf_fmt_to_regpat(const char_u **pefmp, const char_u *efm, int len, char_u *regpat) +static char *scanf_fmt_to_regpat(const char **pefmp, const char *efm, int len, char *regpat) FUNC_ATTR_NONNULL_ALL { - const char_u *efmp = *pefmp; + const char *efmp = *pefmp; if (*efmp == '[' || *efmp == '\\') { if ((*regpat++ = *efmp) == '[') { // %*[^a-z0-9] etc. @@ -412,8 +426,7 @@ static char_u *scanf_fmt_to_regpat(const char_u **pefmp, const char_u *efm, int } if (efmp < efm + len) { *regpat++ = *++efmp; // could be ']' - while (efmp < efm + len && (*regpat++ = *++efmp) != ']') { - } + while (efmp < efm + len && (*regpat++ = *++efmp) != ']') {} if (efmp == efm + len) { emsg(_("E374: Missing ] in format string")); return NULL; @@ -435,13 +448,13 @@ static char_u *scanf_fmt_to_regpat(const char_u **pefmp, const char_u *efm, int } /// Analyze/parse an errorformat prefix. -static const char_u *efm_analyze_prefix(const char_u *efmp, efm_T *efminfo) +static const char *efm_analyze_prefix(const char *efmp, efm_T *efminfo) FUNC_ATTR_NONNULL_ALL { - if (vim_strchr((char_u *)"+-", *efmp) != NULL) { + if (vim_strchr("+-", *efmp) != NULL) { efminfo->flags = *efmp++; } - if (vim_strchr((char_u *)"DXAEWINCZGOPQ", *efmp) != NULL) { + if (vim_strchr("DXAEWINCZGOPQ", *efmp) != NULL) { efminfo->prefix = *efmp; } else { semsg(_("E376: Invalid %%%c in format string prefix"), *efmp); @@ -451,16 +464,15 @@ static const char_u *efm_analyze_prefix(const char_u *efmp, efm_T *efminfo) return efmp; } - // Converts a 'errorformat' string to regular expression pattern -static int efm_to_regpat(const char_u *efm, int len, efm_T *fmt_ptr, char_u *regpat) +static int efm_to_regpat(const char *efm, int len, efm_T *fmt_ptr, char *regpat) FUNC_ATTR_NONNULL_ALL { // Build regexp pattern from current 'errorformat' option - char_u *ptr = regpat; + char *ptr = regpat; *ptr++ = '^'; int round = 0; - for (const char_u *efmp = efm; efmp < efm + len; efmp++) { + for (const char *efmp = efm; efmp < efm + len; efmp++) { if (*efmp == '%') { efmp++; int idx; @@ -470,7 +482,7 @@ static int efm_to_regpat(const char_u *efm, int len, efm_T *fmt_ptr, char_u *reg } } if (idx < FMT_PATTERNS) { - ptr = efmpat_to_regpat(efmp, ptr, fmt_ptr, idx, round); + ptr = efmpat_to_regpat((char *)efmp, ptr, fmt_ptr, idx, round); if (ptr == NULL) { return FAIL; } @@ -481,7 +493,7 @@ static int efm_to_regpat(const char_u *efm, int len, efm_T *fmt_ptr, char_u *reg if (ptr == NULL) { return FAIL; } - } else if (vim_strchr((char_u *)"%\\.^$~[", *efmp) != NULL) { + } else if (vim_strchr("%\\.^$~[", *efmp) != NULL) { *ptr++ = *efmp; // regexp magic characters } else if (*efmp == '#') { *ptr++ = '*'; @@ -501,7 +513,7 @@ static int efm_to_regpat(const char_u *efm, int len, efm_T *fmt_ptr, char_u *reg } else { // copy normal character if (*efmp == '\\' && efmp + 1 < efm + len) { efmp++; - } else if (vim_strchr((char_u *)".*^$~[", *efmp) != NULL) { + } else if (vim_strchr(".*^$~[", *efmp) != NULL) { *ptr++ = '\\'; // escape regexp atoms } if (*efmp) { @@ -533,7 +545,7 @@ static void free_efm_list(efm_T **efm_first) /// Compute the size of the buffer used to convert a 'errorformat' pattern into /// a regular expression pattern. -static size_t efm_regpat_bufsz(char_u *efm) +static size_t efm_regpat_bufsz(char *efm) { size_t sz; @@ -551,7 +563,7 @@ static size_t efm_regpat_bufsz(char_u *efm) } /// Return the length of a 'errorformat' option part (separated by ","). -static int efm_option_part_len(char_u *efm) +static int efm_option_part_len(char *efm) { int len; @@ -567,7 +579,7 @@ static int efm_option_part_len(char_u *efm) /// Parse the 'errorformat' option. Multiple parts in the 'errorformat' option /// are parsed and converted to regular expressions. Returns information about /// the parsed 'errorformat' option. -static efm_T *parse_efm_option(char_u *efm) +static efm_T *parse_efm_option(char *efm) { efm_T *fmt_ptr = NULL; efm_T *fmt_first = NULL; @@ -576,7 +588,7 @@ static efm_T *parse_efm_option(char_u *efm) // Get some space to modify the format string into. size_t sz = efm_regpat_bufsz(efm); - char_u *fmtstr = xmalloc(sz); + char *fmtstr = xmalloc(sz); while (efm[0] != NUL) { // Allocate a new eformat structure and put it at the end of the list @@ -598,7 +610,7 @@ static efm_T *parse_efm_option(char_u *efm) goto parse_efm_error; } // Advance to next part - efm = skip_to_option_part(efm + len); // skip comma and spaces + efm = (char *)skip_to_option_part((char_u *)efm + len); // skip comma and spaces } if (fmt_first == NULL) { // nothing found @@ -617,7 +629,7 @@ parse_efm_end: } /// Allocate more memory for the line buffer used for parsing lines. -static char_u *qf_grow_linebuf(qfstate_T *state, size_t newsz) +static char *qf_grow_linebuf(qfstate_T *state, size_t newsz) { // If the line exceeds LINE_MAXLEN exclude the last // byte since it's not a NL character. @@ -636,8 +648,8 @@ static char_u *qf_grow_linebuf(qfstate_T *state, size_t newsz) static int qf_get_next_str_line(qfstate_T *state) { // Get the next line from the supplied string - char_u *p_str = state->p_str; - char_u *p; + char *p_str = state->p_str; + char *p; size_t len; if (*p_str == NUL) { // Reached the end of the string @@ -654,7 +666,7 @@ static int qf_get_next_str_line(qfstate_T *state) if (len > IOSIZE - 2) { state->linebuf = qf_grow_linebuf(state, len); } else { - state->linebuf = IObuff; + state->linebuf = (char *)IObuff; state->linelen = len; } memcpy(state->linebuf, p_str, state->linelen); @@ -690,7 +702,7 @@ static int qf_get_next_list_line(qfstate_T *state) if (len > IOSIZE - 2) { state->linebuf = qf_grow_linebuf(state, len); } else { - state->linebuf = IObuff; + state->linebuf = (char *)IObuff; state->linelen = len; } @@ -704,21 +716,21 @@ static int qf_get_next_list_line(qfstate_T *state) /// Get the next string from state->buf. static int qf_get_next_buf_line(qfstate_T *state) { - char_u *p_buf = NULL; + char *p_buf = NULL; size_t len; // Get the next line from the supplied buffer if (state->buflnum > state->lnumlast) { return QF_END_OF_INPUT; } - p_buf = ml_get_buf(state->buf, state->buflnum, false); + p_buf = (char *)ml_get_buf(state->buf, state->buflnum, false); state->buflnum += 1; len = STRLEN(p_buf); if (len > IOSIZE - 2) { state->linebuf = qf_grow_linebuf(state, len); } else { - state->linebuf = IObuff; + state->linebuf = (char *)IObuff; state->linelen = len; } STRLCPY(state->linebuf, p_buf, state->linelen + 1); @@ -757,7 +769,7 @@ retry: for (;;) { errno = 0; - if (fgets((char *)state->growbuf + growbuflen, + if (fgets(state->growbuf + growbuflen, (int)(state->growbufsiz - growbuflen), state->fd) == NULL) { if (errno == EINTR) { continue; @@ -797,19 +809,20 @@ retry: state->linebuf = state->growbuf; state->linelen = growbuflen; } else { - state->linebuf = IObuff; + state->linebuf = (char *)IObuff; } // Convert a line if it contains a non-ASCII character - if (state->vc.vc_type != CONV_NONE && has_non_ascii(state->linebuf)) { - char_u *line = string_convert(&state->vc, state->linebuf, &state->linelen); + if (state->vc.vc_type != CONV_NONE && has_non_ascii((char_u *)state->linebuf)) { + char *line = (char *)string_convert(&state->vc, (char_u *)state->linebuf, &state->linelen); if (line != NULL) { if (state->linelen < IOSIZE) { STRLCPY(state->linebuf, line, state->linelen + 1); xfree(line); } else { xfree(state->growbuf); - state->linebuf = state->growbuf = line; + state->linebuf = line; + state->growbuf = line; state->growbufsiz = state->linelen < LINE_MAXLEN ? state->linelen : LINE_MAXLEN; } @@ -854,7 +867,7 @@ static int qf_get_nextline(qfstate_T *state) #endif } - remove_bom(state->linebuf); + remove_bom((char_u *)state->linebuf); return QF_OK; } @@ -889,12 +902,12 @@ static qf_list_T *qf_get_list(qf_info_T *qi, int idx) /// Parse a line and get the quickfix fields. /// Return the QF_ status. -static int qf_parse_line(qf_list_T *qfl, char_u *linebuf, size_t linelen, efm_T *fmt_first, +static int qf_parse_line(qf_list_T *qfl, char *linebuf, size_t linelen, efm_T *fmt_first, qffields_T *fields) { efm_T *fmt_ptr; int idx = 0; - char_u *tail = NULL; + char *tail = NULL; int status; restofline: @@ -911,7 +924,7 @@ restofline: // match or no match. fields->valid = true; for (; fmt_ptr != NULL; fmt_ptr = fmt_ptr->next) { - idx = fmt_ptr->prefix; + idx = (char_u)fmt_ptr->prefix; status = qf_parse_get_fields(linebuf, linelen, fmt_ptr, fields, qfl->qf_multiline, qfl->qf_multiscan, &tail); @@ -945,16 +958,16 @@ restofline: fmt_start = fmt_ptr; } - if (vim_strchr((char_u *)"AEWIN", idx) != NULL) { + if (vim_strchr("AEWIN", idx) != NULL) { qfl->qf_multiline = true; // start of a multi-line message qfl->qf_multiignore = false; // reset continuation - } else if (vim_strchr((char_u *)"CZ", idx) != NULL) { + } else if (vim_strchr("CZ", idx) != NULL) { // continuation of multi-line msg status = qf_parse_multiline_pfx(idx, qfl, fields); if (status != QF_OK) { return status; } - } else if (vim_strchr((char_u *)"OPQ", idx) != NULL) { + } else if (vim_strchr("OPQ", idx) != NULL) { // global file names status = qf_parse_file_pfx(idx, fields, qfl, tail); if (status == QF_MULTISCAN) { @@ -996,17 +1009,17 @@ static void qf_free_fields(qffields_T *pfields) // Setup the state information used for parsing lines and populating a // quickfix list. -static int qf_setup_state(qfstate_T *pstate, char_u *restrict enc, const char_u *restrict efile, +static int qf_setup_state(qfstate_T *pstate, char *restrict enc, const char *restrict efile, typval_T *tv, buf_T *buf, linenr_T lnumfirst, linenr_T lnumlast) FUNC_ATTR_NONNULL_ARG(1) { pstate->vc.vc_type = CONV_NONE; if (enc != NULL && *enc != NUL) { - convert_setup(&pstate->vc, enc, p_enc); + convert_setup(&pstate->vc, (char_u *)enc, p_enc); } if (efile != NULL - && (pstate->fd = os_fopen((const char *)efile, "r")) == NULL) { + && (pstate->fd = os_fopen(efile, "r")) == NULL) { semsg(_(e_openerrf), efile); return FAIL; } @@ -1053,9 +1066,9 @@ static void qf_cleanup_state(qfstate_T *pstate) /// @param lnumlast last line number to use /// /// @return -1 for error, number of errors for success. -static int qf_init_ext(qf_info_T *qi, int qf_idx, const char_u *restrict efile, buf_T *buf, - typval_T *tv, char_u *restrict errorformat, bool newlist, linenr_T lnumfirst, - linenr_T lnumlast, const char_u *restrict qf_title, char_u *restrict enc) +static int qf_init_ext(qf_info_T *qi, int qf_idx, const char *restrict efile, buf_T *buf, + typval_T *tv, char *restrict errorformat, bool newlist, linenr_T lnumfirst, + linenr_T lnumlast, const char *restrict qf_title, char *restrict enc) FUNC_ATTR_NONNULL_ARG(1) { qf_list_T *qfl; @@ -1064,8 +1077,8 @@ static int qf_init_ext(qf_info_T *qi, int qf_idx, const char_u *restrict efile, qfline_T *old_last = NULL; bool adding = false; static efm_T *fmt_first = NULL; - char_u *efm; - static char_u *last_efm = NULL; + char *efm; + static char *last_efm = NULL; int retval = -1; // default: return error flag int status; @@ -1073,8 +1086,7 @@ static int qf_init_ext(qf_info_T *qi, int qf_idx, const char_u *restrict efile, XFREE_CLEAR(qf_last_bufname); qf_alloc_fields(&fields); - if (qf_setup_state(&state, enc, efile, tv, buf, - lnumfirst, lnumlast) == FAIL) { + if (qf_setup_state(&state, enc, efile, tv, buf, lnumfirst, lnumlast) == FAIL) { goto qf_init_end; } @@ -1092,10 +1104,9 @@ static int qf_init_ext(qf_info_T *qi, int qf_idx, const char_u *restrict efile, } } - // Use the local value of 'errorformat' if it's set. if (errorformat == p_efm && tv == NULL && buf && *buf->b_p_efm != NUL) { - efm = buf->b_p_efm; + efm = (char *)buf->b_p_efm; } else { efm = errorformat; } @@ -1110,7 +1121,7 @@ static int qf_init_ext(qf_info_T *qi, int qf_idx, const char_u *restrict efile, // parse the current 'efm' fmt_first = parse_efm_option(efm); if (fmt_first != NULL) { - last_efm = vim_strsave(efm); + last_efm = xstrdup(efm); } } @@ -1173,14 +1184,14 @@ qf_init_end: /// Set the title of the specified quickfix list. Frees the previous title. /// Prepends ':' to the title. -static void qf_store_title(qf_list_T *qfl, const char_u *title) +static void qf_store_title(qf_list_T *qfl, const char *title) FUNC_ATTR_NONNULL_ARG(1) { XFREE_CLEAR(qfl->qf_title); if (title != NULL) { size_t len = STRLEN(title) + 1; - char_u *p = xmallocz(len); + char *p = xmallocz(len); qfl->qf_title = p; STRLCPY(p, title, len + 1); @@ -1191,11 +1202,11 @@ static void qf_store_title(qf_list_T *qfl, const char_u *title) /// that created the quickfix list with the ":" prefix. /// Create a quickfix list title string by prepending ":" to a user command. /// Returns a pointer to a static buffer with the title. -static char_u *qf_cmdtitle(char_u *cmd) +static char *qf_cmdtitle(char *cmd) { - static char_u qftitle_str[IOSIZE]; + static char qftitle_str[IOSIZE]; - snprintf((char *)qftitle_str, IOSIZE, ":%s", (char *)cmd); + snprintf((char *)qftitle_str, IOSIZE, ":%s", cmd); return qftitle_str; } @@ -1210,7 +1221,7 @@ static qf_list_T *qf_get_curlist(qf_info_T *qi) /// Prepare for adding a new quickfix list. If the current list is in the /// middle of the stack, then all the following lists are freed and then /// the new list is added. -static void qf_new_list(qf_info_T *qi, const char_u *qf_title) +static void qf_new_list(qf_info_T *qi, const char *qf_title) { int i; qf_list_T *qfl; @@ -1244,22 +1255,22 @@ static void qf_new_list(qf_info_T *qi, const char_u *qf_title) /// Return the matched value in "fields->namebuf". static int qf_parse_fmt_f(regmatch_T *rmp, int midx, qffields_T *fields, int prefix) { - char_u c; + char c; if (rmp->startp[midx] == NULL || rmp->endp[midx] == NULL) { return QF_FAIL; } // Expand ~/file and $HOME/file to full path. - c = *rmp->endp[midx]; + c = (char)(*rmp->endp[midx]); *rmp->endp[midx] = NUL; - expand_env(rmp->startp[midx], fields->namebuf, CMDBUFFSIZE); - *rmp->endp[midx] = c; + expand_env(rmp->startp[midx], (char_u *)fields->namebuf, CMDBUFFSIZE); + *rmp->endp[midx] = (char_u)c; // For separate filename patterns (%O, %P and %Q), the specified file // should exist. - if (vim_strchr((char_u *)"OPQ", prefix) != NULL - && !os_path_exists(fields->namebuf)) { + if (vim_strchr("OPQ", prefix) != NULL + && !os_path_exists((char_u *)fields->namebuf)) { return QF_FAIL; } @@ -1277,14 +1288,25 @@ static int qf_parse_fmt_n(regmatch_T *rmp, int midx, qffields_T *fields) return QF_OK; } -/// Parse the match for line number (%l') pattern in regmatch. +/// Parse the match for line number ('%l') pattern in regmatch. /// Return the matched value in "fields->lnum". static int qf_parse_fmt_l(regmatch_T *rmp, int midx, qffields_T *fields) { if (rmp->startp[midx] == NULL) { return QF_FAIL; } - fields->lnum = atol((char *)rmp->startp[midx]); + fields->lnum = (linenr_T)atol((char *)rmp->startp[midx]); + return QF_OK; +} + +/// Parse the match for end line number ('%e') pattern in regmatch. +/// Return the matched value in "fields->end_lnum". +static int qf_parse_fmt_e(regmatch_T *rmp, int midx, qffields_T *fields) +{ + if (rmp->startp[midx] == NULL) { + return QF_FAIL; + } + fields->end_lnum = (linenr_T)atol((char *)rmp->startp[midx]); return QF_OK; } @@ -1299,6 +1321,17 @@ static int qf_parse_fmt_c(regmatch_T *rmp, int midx, qffields_T *fields) return QF_OK; } +/// Parse the match for end line number ('%e') pattern in regmatch. +/// Return the matched value in "fields->end_lnum". +static int qf_parse_fmt_k(regmatch_T *rmp, int midx, qffields_T *fields) +{ + if (rmp->startp[midx] == NULL) { + return QF_FAIL; + } + fields->end_col = (int)atol((char *)rmp->startp[midx]); + return QF_OK; +} + /// Parse the match for error type ('%t') pattern in regmatch. /// Return the matched value in "fields->type". static int qf_parse_fmt_t(regmatch_T *rmp, int midx, qffields_T *fields) @@ -1306,13 +1339,13 @@ static int qf_parse_fmt_t(regmatch_T *rmp, int midx, qffields_T *fields) if (rmp->startp[midx] == NULL) { return QF_FAIL; } - fields->type = *rmp->startp[midx]; + fields->type = (char)(*rmp->startp[midx]); return QF_OK; } /// Parse the match for '%+' format pattern. The whole matching line is included /// in the error string. Return the matched line in "fields->errmsg". -static void qf_parse_fmt_plus(const char_u *linebuf, size_t linelen, qffields_T *fields) +static void qf_parse_fmt_plus(const char *linebuf, size_t linelen, qffields_T *fields) FUNC_ATTR_NONNULL_ALL { if (linelen >= fields->errmsglen) { @@ -1344,12 +1377,12 @@ static int qf_parse_fmt_m(regmatch_T *rmp, int midx, qffields_T *fields) /// Parse the match for rest of a single-line file message ('%r') pattern. /// Return the matched value in "tail". -static int qf_parse_fmt_r(regmatch_T *rmp, int midx, char_u **tail) +static int qf_parse_fmt_r(regmatch_T *rmp, int midx, char **tail) { if (rmp->startp[midx] == NULL) { return QF_FAIL; } - *tail = rmp->startp[midx]; + *tail = (char *)rmp->startp[midx]; return QF_OK; } @@ -1357,13 +1390,13 @@ static int qf_parse_fmt_r(regmatch_T *rmp, int midx, char_u **tail) /// Return the matched value in "fields->col". static int qf_parse_fmt_p(regmatch_T *rmp, int midx, qffields_T *fields) { - char_u *match_ptr; + char *match_ptr; if (rmp->startp[midx] == NULL || rmp->endp[midx] == NULL) { return QF_FAIL; } fields->col = 0; - for (match_ptr = rmp->startp[midx]; match_ptr != rmp->endp[midx]; + for (match_ptr = (char *)rmp->startp[midx]; (char_u *)match_ptr != rmp->endp[midx]; match_ptr++) { fields->col++; if (*match_ptr == TAB) { @@ -1431,14 +1464,17 @@ static int qf_parse_fmt_o(regmatch_T *rmp, int midx, qffields_T *fields) /// 'errorformat' format pattern parser functions. /// The '%f' and '%r' formats are parsed differently from other formats. /// See qf_parse_match() for details. +/// Keep in sync with fmt_pat[]. static int (*qf_parse_fmt[FMT_PATTERNS])(regmatch_T *, int, qffields_T *) = { - NULL, + NULL, // %f qf_parse_fmt_n, qf_parse_fmt_l, + qf_parse_fmt_e, qf_parse_fmt_c, + qf_parse_fmt_k, qf_parse_fmt_t, qf_parse_fmt_m, - NULL, + NULL, // %r qf_parse_fmt_p, qf_parse_fmt_v, qf_parse_fmt_s, @@ -1449,10 +1485,10 @@ static int (*qf_parse_fmt[FMT_PATTERNS])(regmatch_T *, int, qffields_T *) = { /// fmt_ptr contains the 'efm' format specifiers/prefixes that have a match. /// Returns QF_OK if all the matches are successfully parsed. On failure, /// returns QF_FAIL or QF_NOMEM. -static int qf_parse_match(char_u *linebuf, size_t linelen, efm_T *fmt_ptr, regmatch_T *regmatch, - qffields_T *fields, int qf_multiline, int qf_multiscan, char_u **tail) +static int qf_parse_match(char *linebuf, size_t linelen, efm_T *fmt_ptr, regmatch_T *regmatch, + qffields_T *fields, int qf_multiline, int qf_multiscan, char **tail) { - char_u idx = fmt_ptr->prefix; + char idx = fmt_ptr->prefix; int i; int midx; int status; @@ -1460,7 +1496,7 @@ static int qf_parse_match(char_u *linebuf, size_t linelen, efm_T *fmt_ptr, regma if ((idx == 'C' || idx == 'Z') && !qf_multiline) { return QF_FAIL; } - if (vim_strchr((char_u *)"EWIN", idx) != NULL) { + if (vim_strchr("EWIN", idx) != NULL) { fields->type = idx; } else { fields->type = 0; @@ -1474,13 +1510,13 @@ static int qf_parse_match(char_u *linebuf, size_t linelen, efm_T *fmt_ptr, regma midx = (int)fmt_ptr->addr[i]; if (i == 0 && midx > 0) { // %f status = qf_parse_fmt_f(regmatch, midx, fields, idx); - } else if (i == 5) { + } else if (i == FMT_PATTERN_M) { if (fmt_ptr->flags == '+' && !qf_multiscan) { // %+ qf_parse_fmt_plus(linebuf, linelen, fields); } else if (midx > 0) { // %m status = qf_parse_fmt_m(regmatch, midx, fields); } - } else if (i == 6 && midx > 0) { // %r + } else if (i == FMT_PATTERN_R && midx > 0) { // %r status = qf_parse_fmt_r(regmatch, midx, tail); } else if (midx > 0) { // others status = (qf_parse_fmt[i])(regmatch, midx, fields); @@ -1498,14 +1534,14 @@ static int qf_parse_match(char_u *linebuf, size_t linelen, efm_T *fmt_ptr, regma /// 'fmt_ptr->prog' and return the matching values in 'fields'. /// Returns QF_OK if the efm format matches completely and the fields are /// successfully copied. Otherwise returns QF_FAIL or QF_NOMEM. -static int qf_parse_get_fields(char_u *linebuf, size_t linelen, efm_T *fmt_ptr, qffields_T *fields, - int qf_multiline, int qf_multiscan, char_u **tail) +static int qf_parse_get_fields(char *linebuf, size_t linelen, efm_T *fmt_ptr, qffields_T *fields, + int qf_multiline, int qf_multiscan, char **tail) { regmatch_T regmatch; int status = QF_FAIL; int r; - if (qf_multiscan && vim_strchr((char_u *)"OPQ", fmt_ptr->prefix) == NULL) { + if (qf_multiscan && vim_strchr("OPQ", fmt_ptr->prefix) == NULL) { return QF_FAIL; } @@ -1559,13 +1595,12 @@ static int qf_parse_dir_pfx(int idx, qffields_T *fields, qf_list_T *qfl) } /// Parse global file name error format prefixes (%O, %P and %Q). -static int qf_parse_file_pfx(int idx, qffields_T *fields, qf_list_T *qfl, char_u *tail) +static int qf_parse_file_pfx(int idx, qffields_T *fields, qf_list_T *qfl, char *tail) { fields->valid = false; - if (*fields->namebuf == NUL || os_path_exists(fields->namebuf)) { + if (*fields->namebuf == NUL || os_path_exists((char_u *)fields->namebuf)) { if (*fields->namebuf && idx == 'P') { - qfl->qf_currfile = qf_push_dir(fields->namebuf, &qfl->qf_file_stack, - true); + qfl->qf_currfile = qf_push_dir(fields->namebuf, &qfl->qf_file_stack, true); } else if (idx == 'Q') { qfl->qf_currfile = qf_pop_dir(&qfl->qf_file_stack); } @@ -1582,7 +1617,7 @@ static int qf_parse_file_pfx(int idx, qffields_T *fields, qf_list_T *qfl, char_u /// Parse a non-error line (a line which doesn't match any of the error /// format in 'efm'). -static int qf_parse_line_nomatch(char_u *linebuf, size_t linelen, qffields_T *fields) +static int qf_parse_line_nomatch(char *linebuf, size_t linelen, qffields_T *fields) { fields->namebuf[0] = NUL; // no match found, remove file name fields->lnum = 0; // don't jump to this line @@ -1625,10 +1660,16 @@ static int qf_parse_multiline_pfx(int idx, qf_list_T *qfl, qffields_T *fields) if (!qfprev->qf_lnum) { qfprev->qf_lnum = fields->lnum; } + if (!qfprev->qf_end_lnum) { + qfprev->qf_end_lnum = fields->end_lnum; + } if (!qfprev->qf_col) { qfprev->qf_col = fields->col; qfprev->qf_viscol = fields->use_viscol; } + if (!qfprev->qf_end_col) { + qfprev->qf_end_col = fields->end_col; + } if (!qfprev->qf_fnum) { qfprev->qf_fnum = qf_get_fnum(qfl, qfl->qf_directory, *fields->namebuf || qfl->qf_directory @@ -1656,6 +1697,28 @@ static void locstack_queue_delreq(qf_info_T *qi) qf_delq_head = q; } +/// Return the global quickfix stack window buffer number. +int qf_stack_get_bufnr(void) +{ + return ql_info.qf_bufnr; +} + +/// Wipe the quickfix window buffer (if present) for the specified +/// quickfix/location list. +static void wipe_qf_buffer(qf_info_T *qi) + FUNC_ATTR_NONNULL_ALL +{ + if (qi->qf_bufnr != INVALID_QFBUFNR) { + buf_T *const qfbuf = buflist_findnr(qi->qf_bufnr); + if (qfbuf != NULL && qfbuf->b_nwindows == 0) { + // If the quickfix buffer is not loaded in any window, then + // wipe the buffer. + close_buffer(NULL, qfbuf, DOBUF_WIPE, false, false); + qi->qf_bufnr = INVALID_QFBUFNR; + } + } +} + /// Free a location list stack static void ll_free_all(qf_info_T **pqi) { @@ -1668,19 +1731,23 @@ static void ll_free_all(qf_info_T **pqi) } *pqi = NULL; // Remove reference to this list + // If the location list is still in use, then queue the delete request + // to be processed later. + if (quickfix_busy > 0) { + locstack_queue_delreq(qi); + return; + } + qi->qf_refcount--; if (qi->qf_refcount < 1) { // No references to this location list. - // If the location list is still in use, then queue the delete request - // to be processed later. - if (quickfix_busy > 0) { - locstack_queue_delreq(qi); - } else { - for (i = 0; i < qi->qf_listcount; i++) { - qf_free(qf_get_list(qi, i)); - } - xfree(qi); + // If the quickfix window buffer is loaded, then wipe it + wipe_qf_buffer(qi); + + for (i = 0; i < qi->qf_listcount; i++) { + qf_free(qf_get_list(qi, i)); } + xfree(qi); } } @@ -1765,9 +1832,9 @@ void check_quickfix_busy(void) /// @param valid valid entry /// /// @returns QF_OK or QF_FAIL. -static int qf_add_entry(qf_list_T *qfl, char_u *dir, char_u *fname, char_u *module, int bufnum, - char_u *mesg, long lnum, long end_lnum, int col, int end_col, - char_u vis_col, char_u *pattern, int nr, char_u type, char_u valid) +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) { qfline_T *qfp = xmalloc(sizeof(qfline_T)); qfline_T **lastp; // pointer to qf_last or NULL @@ -1783,7 +1850,7 @@ static int qf_add_entry(qf_list_T *qfl, char_u *dir, char_u *fname, char_u *modu } else { qfp->qf_fnum = qf_get_fnum(qfl, dir, fname); } - qfp->qf_text = vim_strsave(mesg); + qfp->qf_text = xstrdup(mesg); qfp->qf_lnum = lnum; qfp->qf_end_lnum = end_lnum; qfp->qf_col = col; @@ -1792,12 +1859,12 @@ static int qf_add_entry(qf_list_T *qfl, char_u *dir, char_u *fname, char_u *modu if (pattern == NULL || *pattern == NUL) { qfp->qf_pattern = NULL; } else { - qfp->qf_pattern = vim_strsave(pattern); + qfp->qf_pattern = xstrdup(pattern); } if (module == NULL || *module == NUL) { qfp->qf_module = NULL; } else { - qfp->qf_module = vim_strsave(module); + qfp->qf_module = xstrdup(module); } qfp->qf_nr = nr; if (type != 1 && !vim_isprintc(type)) { // only printable chars allowed @@ -1838,6 +1905,7 @@ static qf_info_T *qf_alloc_stack(qfltype_T qfltype) qf_info_T *qi = xcalloc(1, sizeof(qf_info_T)); qi->qf_refcount++; qi->qfl_type = qfltype; + qi->qf_bufnr = INVALID_QFBUFNR; return qi; } @@ -1954,7 +2022,7 @@ static int copy_loclist(qf_list_T *from_qfl, qf_list_T *to_qfl) to_qfl->qf_last = NULL; to_qfl->qf_ptr = NULL; if (from_qfl->qf_title != NULL) { - to_qfl->qf_title = vim_strsave(from_qfl->qf_title); + to_qfl->qf_title = xstrdup(from_qfl->qf_title); } else { to_qfl->qf_title = NULL; } @@ -1964,7 +2032,7 @@ static int copy_loclist(qf_list_T *from_qfl, qf_list_T *to_qfl) } else { to_qfl->qf_ctx = NULL; } - callback_copy(&to_qfl->qftf_cb, &from_qfl->qftf_cb); + callback_copy(&to_qfl->qf_qftf_cb, &from_qfl->qf_qftf_cb); if (from_qfl->qf_count) { if (copy_loclist_entries(from_qfl, to_qfl) == FAIL) { @@ -2028,10 +2096,10 @@ void copy_loclist_stack(win_T *from, win_T *to) /// Get buffer number for file "directory/fname". /// Also sets the b_has_qf_entry flag. -static int qf_get_fnum(qf_list_T *qfl, char_u *directory, char_u *fname) +static int qf_get_fnum(qf_list_T *qfl, char *directory, char *fname) { - char_u *ptr = NULL; - char_u *bufname; + char *ptr = NULL; + char *bufname; buf_T *buf; if (fname == NULL || *fname == NUL) { // no file name return 0; @@ -2043,19 +2111,19 @@ static int qf_get_fnum(qf_list_T *qfl, char_u *directory, char_u *fname) } slash_adjust(fname); #endif - if (directory != NULL && !vim_isAbsName(fname)) { - ptr = (char_u *)concat_fnames((char *)directory, (char *)fname, true); + if (directory != NULL && !vim_isAbsName((char_u *)fname)) { + ptr = concat_fnames(directory, fname, true); // Here we check if the file really exists. // This should normally be true, but if make works without // "leaving directory"-messages we might have missed a // directory change. - if (!os_path_exists(ptr)) { + if (!os_path_exists((char_u *)ptr)) { xfree(ptr); directory = qf_guess_filepath(qfl, fname); if (directory) { - ptr = (char_u *)concat_fnames((char *)directory, (char *)fname, true); + ptr = concat_fnames(directory, fname, true); } else { - ptr = vim_strsave(fname); + ptr = xstrdup(fname); } } // Use concatenated directory name and file name. @@ -2072,7 +2140,7 @@ static int qf_get_fnum(qf_list_T *qfl, char_u *directory, char_u *fname) } else { xfree(qf_last_bufname); buf = buflist_new(bufname, NULL, (linenr_T)0, BLN_NOOPT); - qf_last_bufname = (bufname == ptr) ? bufname : vim_strsave(bufname); + qf_last_bufname = (bufname == ptr) ? bufname : xstrdup(bufname); set_bufref(&qf_last_bufref, buf); } if (buf == NULL) { @@ -2085,7 +2153,7 @@ static int qf_get_fnum(qf_list_T *qfl, char_u *directory, char_u *fname) // Push dirbuf onto the directory stack and return pointer to actual dir or // NULL on error. -static char_u *qf_push_dir(char_u *dirbuf, struct dir_stack_T **stackptr, bool is_file_stack) +static char *qf_push_dir(char *dirbuf, struct dir_stack_T **stackptr, bool is_file_stack) { struct dir_stack_T *ds_ptr; @@ -2096,10 +2164,10 @@ static char_u *qf_push_dir(char_u *dirbuf, struct dir_stack_T **stackptr, bool i *stackptr = ds_new; // store directory on the stack - if (vim_isAbsName(dirbuf) + if (vim_isAbsName((char_u *)dirbuf) || (*stackptr)->next == NULL - || (*stackptr && is_file_stack)) { - (*stackptr)->dirname = vim_strsave(dirbuf); + || is_file_stack) { + (*stackptr)->dirname = xstrdup(dirbuf); } else { // Okay we don't have an absolute path. // dirbuf must be a subdir of one of the directories on the stack. @@ -2108,9 +2176,8 @@ static char_u *qf_push_dir(char_u *dirbuf, struct dir_stack_T **stackptr, bool i (*stackptr)->dirname = NULL; while (ds_new) { xfree((*stackptr)->dirname); - (*stackptr)->dirname = (char_u *)concat_fnames((char *)ds_new->dirname, - (char *)dirbuf, TRUE); - if (os_isdir((*stackptr)->dirname)) { + (*stackptr)->dirname = concat_fnames(ds_new->dirname, dirbuf, true); + if (os_isdir((char_u *)(*stackptr)->dirname)) { break; } @@ -2128,7 +2195,7 @@ static char_u *qf_push_dir(char_u *dirbuf, struct dir_stack_T **stackptr, bool i // Nothing found -> it must be on top level if (ds_new == NULL) { xfree((*stackptr)->dirname); - (*stackptr)->dirname = vim_strsave(dirbuf); + (*stackptr)->dirname = xstrdup(dirbuf); } } @@ -2142,10 +2209,9 @@ static char_u *qf_push_dir(char_u *dirbuf, struct dir_stack_T **stackptr, bool i } } - // pop dirbuf from the directory stack and return previous directory or NULL if // stack is empty -static char_u *qf_pop_dir(struct dir_stack_T **stackptr) +static char *qf_pop_dir(struct dir_stack_T **stackptr) { struct dir_stack_T *ds_ptr; @@ -2194,11 +2260,11 @@ static void qf_clean_dir_stack(struct dir_stack_T **stackptr) /// x.c:9: Error /// Then qf_push_dir thinks we are in ./aa/bb, but we are in ./bb. /// qf_guess_filepath will return NULL. -static char_u *qf_guess_filepath(qf_list_T *qfl, char_u *filename) +static char *qf_guess_filepath(qf_list_T *qfl, char *filename) { struct dir_stack_T *ds_ptr; struct dir_stack_T *ds_tmp; - char_u *fullname; + char *fullname; // no dirs on the stack - there's nothing we can do if (qfl->qf_dir_stack == NULL) { @@ -2209,9 +2275,9 @@ static char_u *qf_guess_filepath(qf_list_T *qfl, char_u *filename) fullname = NULL; while (ds_ptr) { xfree(fullname); - fullname = (char_u *)concat_fnames((char *)ds_ptr->dirname, (char *)filename, TRUE); + fullname = concat_fnames(ds_ptr->dirname, filename, true); - if (os_path_exists(fullname)) { + if (os_path_exists((char_u *)fullname)) { break; } @@ -2237,7 +2303,10 @@ static bool qflist_valid(win_T *wp, unsigned int qf_id) qf_info_T *qi = &ql_info; if (wp) { - qi = GET_LOC_LIST(wp); + if (!win_valid(wp)) { + return false; + } + qi = GET_LOC_LIST(wp); // Location list if (!qi) { return false; } @@ -2325,7 +2394,7 @@ static qfline_T *get_nth_valid_entry(qf_list_T *qfl, int errornr, int dir, int * int qf_idx = qfl->qf_index; qfline_T *prev_qf_ptr; int prev_index; - char_u *err = e_no_more_items; + char *err = e_no_more_items; while (errornr--) { prev_qf_ptr = qf_ptr; @@ -2399,7 +2468,7 @@ static qfline_T *qf_get_entry(qf_list_T *qfl, int errornr, int dir, int *new_qfi return qf_ptr; } -// Find a window displaying a Vim help file. +// Find a window displaying a Vim help file in the current tab page. static win_T *qf_find_help_win(void) FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT { @@ -2424,7 +2493,7 @@ static int jump_to_help_window(qf_info_T *qi, bool newwin, int *opened_window) { win_T *wp = NULL; - if (cmdmod.tab != 0 || newwin) { + if (cmdmod.cmod_tab != 0 || newwin) { wp = NULL; } else { wp = qf_find_help_win(); @@ -2436,7 +2505,7 @@ static int jump_to_help_window(qf_info_T *qi, bool newwin, int *opened_window) // Split off help window; put it at far top if no position // specified, the current window is vertically split and narrow. int flags = WSP_HELP; - if (cmdmod.split == 0 + if (cmdmod.cmod_split == 0 && curwin->w_width != Columns && curwin->w_width < 80) { flags |= WSP_TOP; @@ -2466,15 +2535,14 @@ static int jump_to_help_window(qf_info_T *qi, bool newwin, int *opened_window) } } - if (!p_im) { - restart_edit = 0; // don't want insert mode in help file - } + restart_edit = 0; // don't want insert mode in help file return OK; } -// Find a non-quickfix window using the given location list. -// Returns NULL if a matching window is not found. +/// Find a non-quickfix window using the given location list stack in the +/// current tabpage. +/// Returns NULL if a matching window is not found. static win_T *qf_find_win_with_loclist(const qf_info_T *ll) FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT { @@ -2486,7 +2554,7 @@ static win_T *qf_find_win_with_loclist(const qf_info_T *ll) return NULL; } -// Find a window containing a normal buffer +/// Find a window containing a normal buffer in the current tab page. static win_T *qf_find_win_with_normal_buf(void) FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT { @@ -2542,7 +2610,7 @@ static void qf_goto_win_with_ll_file(win_T *use_win, int qf_fnum, qf_info_T *ll_ win_T *win = use_win; if (win == NULL) { - // Find the window showing the selected file + // Find the window showing the selected file in the current tab page. FOR_ALL_WINDOWS_IN_TAB(win2, curtab) { if (win2->w_buffer->b_fnum == qf_fnum) { win = win2; @@ -2674,7 +2742,7 @@ static int qf_jump_to_usable_window(int qf_fnum, bool newwin, int *opened_window } /// Edit the selected file or help file. -static int qf_jump_edit_buffer(qf_info_T *qi, qfline_T *qf_ptr, int forceit, win_T *oldwin, +static int qf_jump_edit_buffer(qf_info_T *qi, qfline_T *qf_ptr, int forceit, int prev_winid, int *opened_window) { qf_list_T *qfl = qf_get_curlist(qi); @@ -2693,7 +2761,7 @@ static int qf_jump_edit_buffer(qf_info_T *qi, qfline_T *qf_ptr, int forceit, win } else { retval = do_ecmd(qf_ptr->qf_fnum, NULL, NULL, NULL, (linenr_T)1, ECMD_HIDE + ECMD_SET_HELP, - oldwin == curwin ? curwin : NULL); + prev_winid == curwin->handle ? curwin : NULL); } } else { retval = buflist_getfile(qf_ptr->qf_fnum, (linenr_T)1, @@ -2701,10 +2769,14 @@ static int qf_jump_edit_buffer(qf_info_T *qi, qfline_T *qf_ptr, int forceit, win } // If a location list, check whether the associated window is still // present. - if (qfl_type == QFLT_LOCATION && !win_valid_any_tab(oldwin)) { - emsg(_("E924: Current window was closed")); - *opened_window = false; - return NOTDONE; + if (qfl_type == QFLT_LOCATION) { + win_T *wp = win_id2wp(prev_winid); + + if (wp == NULL && curwin->w_llist != qi) { + emsg(_("E924: Current window was closed")); + *opened_window = false; + return NOTDONE; + } } if (qfl_type == QFLT_QUICKFIX && !qflist_valid(NULL, save_qfid)) { @@ -2712,8 +2784,8 @@ static int qf_jump_edit_buffer(qf_info_T *qi, qfline_T *qf_ptr, int forceit, win return NOTDONE; } - if (old_qf_curlist != qi->qf_curlist - || old_changetick != qfl->qf_changedtick + if (old_qf_curlist != qi->qf_curlist // -V560 + || old_changetick != qfl->qf_changedtick // -V560 || !is_qf_entry_present(qfl, qf_ptr)) { if (qfl_type == QFLT_QUICKFIX) { emsg(_(e_current_quickfix_list_was_changed)); @@ -2728,7 +2800,7 @@ static int qf_jump_edit_buffer(qf_info_T *qi, qfline_T *qf_ptr, int forceit, win /// Go to the error line in the current file using either line/column number or /// a search pattern. -static void qf_jump_goto_line(linenr_T qf_lnum, int qf_col, char_u qf_viscol, char_u *qf_pattern) +static void qf_jump_goto_line(linenr_T qf_lnum, int qf_col, char qf_viscol, char *qf_pattern) { linenr_T i; @@ -2757,7 +2829,7 @@ static void qf_jump_goto_line(linenr_T qf_lnum, int qf_col, char_u qf_viscol, ch // 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, '/', '/', (char_u *)qf_pattern, (long)1, SEARCH_KEEP, NULL)) { curwin->w_cursor = save_cursor; } } @@ -2775,10 +2847,10 @@ static void qf_jump_print_msg(qf_info_T *qi, int qf_index, qfline_T *qf_ptr, buf snprintf((char *)IObuff, IOSIZE, _("(%d of %d)%s%s: "), qf_index, qf_get_curlist(qi)->qf_count, qf_ptr->qf_cleared ? _(" (line deleted)") : "", - (char *)qf_types(qf_ptr->qf_type, qf_ptr->qf_nr)); + 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); + qf_fmt_text(skipwhite(qf_ptr->qf_text), (char *)IObuff + len, IOSIZE - len); // Output the message. Overwrite to avoid scrolling when the 'O' // flag is present in 'shortmess'; But when not jumping, print the @@ -2808,13 +2880,13 @@ static int qf_jump_open_window(qf_info_T *qi, qfline_T *qf_ptr, bool newwin, int qfltype_T qfl_type = qfl->qfl_type; // For ":helpgrep" find a help window or open one. - if (qf_ptr->qf_type == 1 && (!bt_help(curwin->w_buffer) || cmdmod.tab != 0)) { + if (qf_ptr->qf_type == 1 && (!bt_help(curwin->w_buffer) || cmdmod.cmod_tab != 0)) { if (jump_to_help_window(qi, newwin, opened_window) == FAIL) { return FAIL; } } if (old_qf_curlist != qi->qf_curlist - || old_changetick != qfl->qf_changedtick + || old_changetick != qfl->qf_changedtick // -V560 || !is_qf_entry_present(qfl, qf_ptr)) { if (qfl_type == QFLT_QUICKFIX) { emsg(_(e_current_quickfix_list_was_changed)); @@ -2859,7 +2931,7 @@ static int qf_jump_open_window(qf_info_T *qi, qfline_T *qf_ptr, bool newwin, int /// NOTDONE if the quickfix/location list is freed by an autocmd when opening /// the file. static int qf_jump_to_buffer(qf_info_T *qi, int qf_index, qfline_T *qf_ptr, int forceit, - win_T *oldwin, int *opened_window, int openfold, int print_message) + int prev_winid, int *opened_window, int openfold, int print_message) { buf_T *old_curbuf; linenr_T old_lnum; @@ -2871,7 +2943,7 @@ static int qf_jump_to_buffer(qf_info_T *qi, int qf_index, qfline_T *qf_ptr, int old_lnum = curwin->w_cursor.lnum; if (qf_ptr->qf_fnum != 0) { - retval = qf_jump_edit_buffer(qi, qf_ptr, forceit, oldwin, + retval = qf_jump_edit_buffer(qi, qf_ptr, forceit, prev_winid, opened_window); if (retval != OK) { return retval; @@ -2883,8 +2955,7 @@ static int qf_jump_to_buffer(qf_info_T *qi, int qf_index, qfline_T *qf_ptr, int setpcmark(); } - qf_jump_goto_line(qf_ptr->qf_lnum, qf_ptr->qf_col, qf_ptr->qf_viscol, - qf_ptr->qf_pattern); + qf_jump_goto_line(qf_ptr->qf_lnum, qf_ptr->qf_col, qf_ptr->qf_viscol, qf_ptr->qf_pattern); if ((fdo_flags & FDO_QUICKFIX) && openfold) { foldOpenCursor(); @@ -2918,10 +2989,10 @@ static void qf_jump_newwin(qf_info_T *qi, int dir, int errornr, int forceit, boo qfline_T *old_qf_ptr; int qf_index; int old_qf_index; - char_u *old_swb = p_swb; + char *old_swb = (char *)p_swb; unsigned old_swb_flags = swb_flags; + int prev_winid; int opened_window = false; - win_T *oldwin = curwin; int print_message = true; const bool old_KeyTyped = KeyTyped; // getting file may reset it int retval = OK; @@ -2935,6 +3006,8 @@ static void qf_jump_newwin(qf_info_T *qi, int dir, int errornr, int forceit, boo return; } + incr_quickfix_busy(); + qfl = qf_get_curlist(qi); qf_ptr = qfl->qf_ptr; @@ -2957,6 +3030,8 @@ static void qf_jump_newwin(qf_info_T *qi, int dir, int errornr, int forceit, boo print_message = false; } + prev_winid = curwin->handle; + retval = qf_jump_open_window(qi, qf_ptr, newwin, &opened_window); if (retval == FAIL) { goto failed; @@ -2965,7 +3040,7 @@ static void qf_jump_newwin(qf_info_T *qi, int dir, int errornr, int forceit, boo goto theend; } - retval = qf_jump_to_buffer(qi, qf_index, qf_ptr, forceit, oldwin, + retval = qf_jump_to_buffer(qi, qf_index, qf_ptr, forceit, prev_winid, &opened_window, old_KeyTyped, print_message); if (retval == NOTDONE) { // Quickfix/location list is freed by an autocmd @@ -2975,7 +3050,7 @@ static void qf_jump_newwin(qf_info_T *qi, int dir, int errornr, int forceit, boo if (retval != OK) { if (opened_window) { - win_close(curwin, true); // Close opened window + win_close(curwin, true, false); // Close opened window } if (qf_ptr != NULL && qf_ptr->qf_fnum != 0) { // Couldn't open file, so put index back where it was. This could @@ -2990,15 +3065,15 @@ theend: qfl->qf_ptr = qf_ptr; qfl->qf_index = qf_index; } - if (p_swb != old_swb && p_swb == empty_option && opened_window) { + if (p_swb != (char_u *)old_swb && p_swb == empty_option) { // Restore old 'switchbuf' value, but not when an autocommand or // modeline has changed the value. - p_swb = old_swb; + p_swb = (char_u *)old_swb; swb_flags = old_swb_flags; } + decr_quickfix_busy(); } - // Highlight attributes used for displaying entries from the quickfix list. static int qfFileAttr; static int qfSepAttr; @@ -3010,13 +3085,12 @@ static int qfLineAttr; /// quickfix list. static void qf_list_entry(qfline_T *qfp, int qf_idx, bool cursel) { - char_u *fname; + char *fname; buf_T *buf; fname = NULL; if (qfp->qf_module != NULL && *qfp->qf_module != NUL) { - vim_snprintf((char *)IObuff, IOSIZE, "%2d %s", qf_idx, - (char *)qfp->qf_module); + vim_snprintf((char *)IObuff, IOSIZE, "%2d %s", qf_idx, qfp->qf_module); } else { if (qfp->qf_fnum != 0 && (buf = buflist_findnr(qfp->qf_fnum)) != NULL) { @@ -3028,8 +3102,7 @@ static void qf_list_entry(qfline_T *qfp, int qf_idx, bool cursel) if (fname == NULL) { snprintf((char *)IObuff, IOSIZE, "%2d", qf_idx); } else { - vim_snprintf((char *)IObuff, IOSIZE, "%2d %s", - qf_idx, (char *)fname); + vim_snprintf((char *)IObuff, IOSIZE, "%2d %s", qf_idx, fname); } } @@ -3038,16 +3111,16 @@ static void qf_list_entry(qfline_T *qfp, int qf_idx, bool cursel) // text of the entry. bool filter_entry = true; if (qfp->qf_module != NULL && *qfp->qf_module != NUL) { - filter_entry &= message_filtered(qfp->qf_module); + filter_entry &= message_filtered((char_u *)qfp->qf_module); } if (filter_entry && fname != NULL) { - filter_entry &= message_filtered(fname); + filter_entry &= message_filtered((char_u *)fname); } if (filter_entry && qfp->qf_pattern != NULL) { - filter_entry &= message_filtered(qfp->qf_pattern); + filter_entry &= message_filtered((char_u *)qfp->qf_pattern); } if (filter_entry) { - filter_entry &= message_filtered(qfp->qf_text); + filter_entry &= message_filtered((char_u *)qfp->qf_text); } if (filter_entry) { return; @@ -3062,14 +3135,13 @@ static void qf_list_entry(qfline_T *qfp, int qf_idx, bool cursel) if (qfp->qf_lnum == 0) { IObuff[0] = NUL; } else { - qf_range_text(qfp, IObuff, IOSIZE); + qf_range_text(qfp, (char *)IObuff, IOSIZE); } - vim_snprintf((char *)IObuff + STRLEN(IObuff), IOSIZE, "%s", - (char *)qf_types(qfp->qf_type, qfp->qf_nr)); + vim_snprintf((char *)IObuff + STRLEN(IObuff), IOSIZE, "%s", qf_types(qfp->qf_type, qfp->qf_nr)); msg_puts_attr((const char *)IObuff, qfLineAttr); msg_puts_attr(":", qfSepAttr); if (qfp->qf_pattern != NULL) { - qf_fmt_text(qfp->qf_pattern, IObuff, IOSIZE); + qf_fmt_text(qfp->qf_pattern, (char *)IObuff, IOSIZE); msg_puts((const char *)IObuff); msg_puts_attr(":", qfSepAttr); } @@ -3080,7 +3152,7 @@ static void qf_list_entry(qfline_T *qfp, int qf_idx, bool cursel) // with ^^^^. */ qf_fmt_text((fname != NULL || qfp->qf_lnum != 0) ? skipwhite(qfp->qf_text) : qfp->qf_text, - IObuff, IOSIZE); + (char *)IObuff, IOSIZE); msg_prt_line(IObuff, false); ui_flush(); // show one line at a time } @@ -3094,7 +3166,7 @@ void qf_list(exarg_T *eap) int i; int idx1 = 1; int idx2 = -1; - char_u *arg = eap->arg; + char *arg = eap->arg; int all = eap->forceit; // if not :cl!, only show // recognised errors qf_info_T *qi; @@ -3113,7 +3185,7 @@ void qf_list(exarg_T *eap) arg++; plus = true; } - if (!get_list_range(&arg, &idx1, &idx2) || *arg != NUL) { + if (!get_list_range((char_u **)&arg, &idx1, &idx2) || *arg != NUL) { emsg(_(e_trailing)); return; } @@ -3163,11 +3235,11 @@ void qf_list(exarg_T *eap) // Remove newlines and leading whitespace from an error message. // Put the result in "buf[bufsize]". -static void qf_fmt_text(const char_u *restrict text, char_u *restrict buf, int bufsize) +static void qf_fmt_text(const char *restrict text, char *restrict buf, int bufsize) FUNC_ATTR_NONNULL_ALL { int i; - const char_u *p = text; + const char *p = (char *)text; for (i = 0; *p != NUL && i < bufsize - 1; ++i) { if (*p == '\n') { @@ -3186,37 +3258,33 @@ static void qf_fmt_text(const char_u *restrict text, char_u *restrict buf, int b // 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_u *buf, int bufsize) +static void qf_range_text(const qfline_T *qfp, char *buf, int bufsize) { - vim_snprintf((char *)buf, (size_t)bufsize, "%" PRIdLINENR, qfp->qf_lnum); + vim_snprintf(buf, (size_t)bufsize, "%" PRIdLINENR, qfp->qf_lnum); int len = (int)STRLEN(buf); if (qfp->qf_end_lnum > 0 && qfp->qf_lnum != qfp->qf_end_lnum) { - vim_snprintf((char *)buf + len, (size_t)(bufsize - len), - "-%" PRIdLINENR, qfp->qf_end_lnum); + vim_snprintf(buf + len, (size_t)(bufsize - len), "-%" PRIdLINENR, qfp->qf_end_lnum); len += (int)STRLEN(buf + len); } if (qfp->qf_col > 0) { - vim_snprintf((char *)buf + len, (size_t)(bufsize - len), - " col %d", qfp->qf_col); + vim_snprintf(buf + len, (size_t)(bufsize - len), " col %d", qfp->qf_col); len += (int)STRLEN(buf + len); if (qfp->qf_end_col > 0 && qfp->qf_col != qfp->qf_end_col) { - vim_snprintf((char *)buf + len, (size_t)(bufsize - len), - "-%d", qfp->qf_end_col); + vim_snprintf(buf + len, (size_t)(bufsize - len), "-%d", qfp->qf_end_col); len += (int)STRLEN(buf + len); } } buf[len] = NUL; } - /// Display information (list number, list size and the title) about a /// quickfix/location list. static void qf_msg(qf_info_T *qi, int which, char *lead) { - char *title = (char *)qi->qf_lists[which].qf_title; + char *title = qi->qf_lists[which].qf_title; int count = qi->qf_lists[which].qf_count; - char_u buf[IOSIZE]; + char buf[IOSIZE]; vim_snprintf((char *)buf, IOSIZE, _("%serror list %d of %d; %d errors "), lead, @@ -3234,7 +3302,7 @@ static void qf_msg(qf_info_T *qi, int which, char *lead) STRLCAT(buf, title, IOSIZE); } trunc_string(buf, buf, Columns - 1, IOSIZE); - msg((char *)buf); + msg(buf); } /// ":colder [count]": Up in the quickfix stack. @@ -3251,7 +3319,6 @@ void qf_age(exarg_T *eap) } if (eap->addr_count != 0) { - assert(eap->line2 <= INT_MAX); count = (int)eap->line2; } else { count = 1; @@ -3289,7 +3356,7 @@ void qf_history(exarg_T *eap) // Jump to the specified quickfix list if (eap->line2 > 0 && eap->line2 <= qi->qf_listcount) { - qi->qf_curlist = (int)(eap->line2 - 1); + qi->qf_curlist = eap->line2 - 1; qf_msg(qi, qi->qf_curlist, ""); qf_update_buffer(qi, NULL); } else { @@ -3362,13 +3429,14 @@ static void qf_free(qf_list_T *qfl) XFREE_CLEAR(qfl->qf_title); tv_free(qfl->qf_ctx); qfl->qf_ctx = NULL; - callback_free(&qfl->qftf_cb); + callback_free(&qfl->qf_qftf_cb); qfl->qf_id = 0; qfl->qf_changedtick = 0L; } // qf_mark_adjust: adjust marks -bool qf_mark_adjust(win_T *wp, linenr_T line1, linenr_T line2, long amount, long amount_after) +bool qf_mark_adjust(win_T *wp, linenr_T line1, linenr_T line2, linenr_T amount, + linenr_T amount_after) { int i; qfline_T *qfp; @@ -3425,25 +3493,25 @@ bool qf_mark_adjust(win_T *wp, linenr_T line1, linenr_T line2, long amount, long // 0 n " error n" // other n " c n" // 1 x "" :helpgrep -static char_u *qf_types(int c, int nr) +static char *qf_types(int c, int nr) { - static char_u buf[20]; - static char_u cc[3]; - char_u *p; + static char buf[20]; + static char cc[3]; + char *p; if (c == 'W' || c == 'w') { - p = (char_u *)" warning"; + p = " warning"; } else if (c == 'I' || c == 'i') { - p = (char_u *)" info"; + p = " info"; } else if (c == 'N' || c == 'n') { - p = (char_u *)" note"; + p = " note"; } else if (c == 'E' || c == 'e' || (c == 0 && nr > 0)) { - p = (char_u *)" error"; + p = " error"; } else if (c == 0 || c == 1) { - p = (char_u *)""; + p = ""; } else { cc[0] = ' '; - cc[1] = (char_u)c; + cc[1] = (char)c; cc[2] = NUL; p = cc; } @@ -3452,7 +3520,7 @@ static char_u *qf_types(int c, int nr) return p; } - sprintf((char *)buf, "%s %3d", (char *)p, nr); + snprintf((char *)buf, sizeof(buf), "%s %3d", p, nr); return buf; } @@ -3530,7 +3598,7 @@ void ex_cclose(exarg_T *eap) // Find existing quickfix window and close it. win = qf_find_win(qi); if (win != NULL) { - win_close(win, false); + win_close(win, false, false); } } @@ -3550,7 +3618,7 @@ static int qf_goto_cwindow(const qf_info_T *qi, bool resize, int sz, bool vertsp win_setwidth(sz); } } else if (sz != win->w_height - && (win->w_height + win->w_status_height + tabline_height() + && (win->w_height + win->w_hsep_height + win->w_status_height + tabline_height() < cmdline_row)) { win_setheight(sz); } @@ -3565,7 +3633,7 @@ static void qf_set_cwindow_options(void) // switch off 'swapfile' set_option_value("swf", 0L, NULL, OPT_LOCAL); set_option_value("bt", 0L, "quickfix", OPT_LOCAL); - set_option_value("bh", 0L, "wipe", OPT_LOCAL); + set_option_value("bh", 0L, "hide", OPT_LOCAL); RESET_BINDING(curwin); curwin->w_p_diff = false; set_option_value("fdm", 0L, "manual", OPT_LOCAL); @@ -3586,35 +3654,26 @@ static int qf_open_new_cwindow(qf_info_T *qi, int height) // The current window becomes the previous window afterwards. win_T *const win = curwin; - if (IS_QF_STACK(qi) && cmdmod.split == 0) { + if (IS_QF_STACK(qi) && cmdmod.cmod_split == 0) { // Create the new quickfix window at the very bottom, except when // :belowright or :aboveleft is used. win_goto(lastwin); } // Default is to open the window below the current window - if (cmdmod.split == 0) { + if (cmdmod.cmod_split == 0) { flags = WSP_BELOW; } flags |= WSP_NEWLOC; if (win_split(height, flags) == FAIL) { return FAIL; // not enough room for window } - - // User autocommands may have invalidated the previous window after calling - // win_split, so add a check to ensure that the win is still here - if (IS_LL_STACK(qi) && !win_valid(win)) { - // close the window that was supposed to be for the loclist - win_close(curwin, false); - return FAIL; - } - RESET_BINDING(curwin); if (IS_LL_STACK(qi)) { // For the location list window, create a reference to the - // location list from the window 'win'. - curwin->w_llist_ref = win->w_llist; - win->w_llist->qf_refcount++; + // location list stack from the window 'win'. + curwin->w_llist_ref = qi; + qi->qf_refcount++; } if (oldwin != curwin) { @@ -3631,6 +3690,8 @@ static int qf_open_new_cwindow(qf_info_T *qi, int height) if (do_ecmd(0, NULL, NULL, NULL, ECMD_ONE, ECMD_HIDE + ECMD_NOWINENTER, oldwin) == FAIL) { return FAIL; } + // save the number of the new buffer + qi->qf_bufnr = curbuf->b_fnum; } // Set the options for the quickfix buffer/window (if not already done) @@ -3677,7 +3738,6 @@ void ex_copen(exarg_T *eap) incr_quickfix_busy(); if (eap->addr_count != 0) { - assert(eap->line2 <= INT_MAX); height = (int)eap->line2; } else { height = QF_WINHEIGHT; @@ -3685,9 +3745,9 @@ void ex_copen(exarg_T *eap) reset_VIsual_and_resel(); // stop Visual mode // Find an existing quickfix window, or open a new one. - if (cmdmod.tab == 0) { + if (cmdmod.cmod_tab == 0) { status = qf_goto_cwindow(qi, eap->addr_count != 0, height, - cmdmod.split & WSP_VERT); + cmdmod.cmod_split & WSP_VERT); } if (status == FAIL) { if (qf_open_new_cwindow(qi, height) == FAIL) { @@ -3809,8 +3869,8 @@ static int is_qf_win(const win_T *win, const qf_info_T *qi) return false; } -/// Find a window displaying the quickfix/location stack 'qi' -/// Only searches in the current tabpage. +/// Find a window displaying the quickfix/location stack 'qi' in the current tab +/// page. static win_T *qf_find_win(const qf_info_T *qi) FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT { @@ -3823,11 +3883,20 @@ static win_T *qf_find_win(const qf_info_T *qi) return NULL; } -// Find a quickfix buffer. -// Searches in windows opened in all the tabs. +/// Find a quickfix buffer. +/// Searches in windows opened in all the tab pages. static buf_T *qf_find_buf(qf_info_T *qi) FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT { + if (qi->qf_bufnr != INVALID_QFBUFNR) { + buf_T *const qfbuf = buflist_findnr(qi->qf_bufnr); + if (qfbuf != NULL) { + return qfbuf; + } + // buffer is no longer present + qi->qf_bufnr = INVALID_QFBUFNR; + } + FOR_ALL_TAB_WINDOWS(tp, win) { if (is_qf_win(win, qi)) { return win->w_buffer; @@ -3850,7 +3919,7 @@ bool qf_process_qftf_option(void) if (*p_qftf == '{') { // Lambda expression - tv = eval_expr(p_qftf); + tv = eval_expr((char *)p_qftf); if (tv == NULL) { return false; } @@ -3858,7 +3927,7 @@ bool qf_process_qftf_option(void) // treat everything else as a function name string tv = xcalloc(1, sizeof(*tv)); tv->v_type = VAR_STRING; - tv->vval.v_string = vim_strsave(p_qftf); + tv->vval.v_string = (char *)vim_strsave(p_qftf); } if (!callback_from_typval(&cb, tv)) { @@ -3941,7 +4010,7 @@ static void qf_update_buffer(qf_info_T *qi, qfline_T *old_last) // Add an error line to the quickfix buffer. static int qf_buf_add_line(qf_list_T *qfl, buf_T *buf, linenr_T lnum, const qfline_T *qfp, - char_u *dirname, char_u *qftf_str, bool first_bufline) + char *dirname, char *qftf_str, bool first_bufline) FUNC_ATTR_NONNULL_ARG(1, 2, 4, 5) { int len; @@ -3966,11 +4035,11 @@ static int qf_buf_add_line(qf_list_T *qfl, buf_T *buf, linenr_T lnum, const qfli // buffer. if (first_bufline && (errbuf->b_sfname == NULL - || path_is_absolute(errbuf->b_sfname))) { + || path_is_absolute((char_u *)errbuf->b_sfname))) { if (*dirname == NUL) { - os_dirname(dirname, MAXPATHL); + os_dirname((char_u *)dirname, MAXPATHL); } - shorten_buf_fname(errbuf, dirname, false); + shorten_buf_fname(errbuf, (char_u *)dirname, false); } STRLCPY(IObuff, errbuf->b_fname, IOSIZE); } @@ -3982,14 +4051,14 @@ static int qf_buf_add_line(qf_list_T *qfl, buf_T *buf, linenr_T lnum, const qfli IObuff[len++] = '|'; } if (qfp->qf_lnum > 0) { - qf_range_text(qfp, IObuff + len, IOSIZE - len); + qf_range_text(qfp, (char *)IObuff + len, IOSIZE - len); len += (int)STRLEN(IObuff + len); - snprintf((char *)IObuff + len, (size_t)(IOSIZE - len), "%s", - (char *)qf_types(qfp->qf_type, qfp->qf_nr)); + snprintf((char *)IObuff + len, (size_t)(IOSIZE - len), "%s", qf_types(qfp->qf_type, + qfp->qf_nr)); len += (int)STRLEN(IObuff + len); } else if (qfp->qf_pattern != NULL) { - qf_fmt_text(qfp->qf_pattern, IObuff + len, IOSIZE - len); + qf_fmt_text(qfp->qf_pattern, (char *)IObuff + len, IOSIZE - len); len += (int)STRLEN(IObuff + len); } if (len < IOSIZE - 2) { @@ -4001,7 +4070,7 @@ static int qf_buf_add_line(qf_list_T *qfl, buf_T *buf, linenr_T lnum, const qfli // 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); + (char *)IObuff + len, IOSIZE - len); } if (ml_append_buf(buf, lnum, IObuff, @@ -4021,10 +4090,10 @@ static list_T *call_qftf_func(qf_list_T *qfl, int qf_winid, long start_idx, long // If 'quickfixtextfunc' is set, then use the user-supplied function to get // the text to display. Use the local value of 'quickfixtextfunc' if it is // set. - if (qfl->qftf_cb.type != kCallbackNone) { - cb = &qfl->qftf_cb; + if (qfl->qf_qftf_cb.type != kCallbackNone) { + cb = &qfl->qf_qftf_cb; } - if (cb != NULL && cb->type != kCallbackNone) { + if (cb->type != kCallbackNone) { typval_T args[1]; typval_T rettv; @@ -4083,7 +4152,7 @@ static void qf_fill_buffer(qf_list_T *qfl, buf_T *buf, qfline_T *old_last, int q // Check if there is anything to display if (qfl != NULL) { - char_u dirname[MAXPATHL]; + char dirname[MAXPATHL]; int prev_bufnr = -1; bool invalid_val = false; @@ -4106,13 +4175,13 @@ static void qf_fill_buffer(qf_list_T *qfl, buf_T *buf, qfline_T *old_last, int q qftf_li = tv_list_first(qftf_list); while (lnum < qfl->qf_count) { - char_u *qftf_str = NULL; + char *qftf_str = NULL; // Use the text supplied by the user defined function (if any). // If the returned value is not string, then ignore the rest // of the returned values and use the default. if (qftf_li != NULL && !invalid_val) { - qftf_str = (char_u *)tv_get_string_chk(TV_LIST_ITEM_TV(qftf_li)); + qftf_str = (char *)tv_get_string_chk(TV_LIST_ITEM_TV(qftf_li)); if (qftf_str == NULL) { invalid_val = true; } @@ -4151,10 +4220,8 @@ static void qf_fill_buffer(qf_list_T *qfl, buf_T *buf, qfline_T *old_last, int q curbuf->b_p_ma = false; keep_filetype = true; // don't detect 'filetype' - apply_autocmds(EVENT_BUFREADPOST, (char_u *)"quickfix", NULL, - false, curbuf); - apply_autocmds(EVENT_BUFWINENTER, (char_u *)"quickfix", NULL, - false, curbuf); + apply_autocmds(EVENT_BUFREADPOST, "quickfix", NULL, false, curbuf); + apply_autocmds(EVENT_BUFWINENTER, "quickfix", NULL, false, curbuf); keep_filetype = false; curbuf->b_ro_locked--; @@ -4228,22 +4295,22 @@ int grep_internal(cmdidx_T cmdidx) } // Return the make/grep autocmd name. -static char_u *make_get_auname(cmdidx_T cmdidx) +static char *make_get_auname(cmdidx_T cmdidx) FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT { switch (cmdidx) { case CMD_make: - return (char_u *)"make"; + return "make"; case CMD_lmake: - return (char_u *)"lmake"; + return "lmake"; case CMD_grep: - return (char_u *)"grep"; + return "grep"; case CMD_lgrep: - return (char_u *)"lgrep"; + return "lgrep"; case CMD_grepadd: - return (char_u *)"grepadd"; + return "grepadd"; case CMD_lgrepadd: - return (char_u *)"lgrepadd"; + return "lgrepadd"; default: return NULL; } @@ -4251,7 +4318,7 @@ static char_u *make_get_auname(cmdidx_T cmdidx) // Form the complete command line to invoke 'make'/'grep'. Quote the command // using 'shellquote' and append 'shellpipe'. Echo the fully formed command. -static char *make_get_fullcmd(const char_u *makecmd, const char_u *fname) +static char *make_get_fullcmd(const char *makecmd, const char *fname) FUNC_ATTR_NONNULL_ALL FUNC_ATTR_NONNULL_RET { size_t len = STRLEN(p_shq) * 2 + STRLEN(makecmd) + 1; @@ -4274,7 +4341,7 @@ static char *make_get_fullcmd(const char_u *makecmd, const char_u *fname) } msg_start(); msg_puts(":!"); - msg_outtrans((char_u *)cmd); // show what we are doing + msg_outtrans(cmd); // show what we are doing return cmd; } @@ -4282,11 +4349,11 @@ static char *make_get_fullcmd(const char_u *makecmd, const char_u *fname) // Used for ":make", ":lmake", ":grep", ":lgrep", ":grepadd", and ":lgrepadd" void ex_make(exarg_T *eap) { - char_u *fname; + char *fname; win_T *wp = NULL; qf_info_T *qi = &ql_info; int res; - char_u *enc = (*curbuf->b_p_menc != NUL) ? curbuf->b_p_menc : p_menc; + char *enc = (*curbuf->b_p_menc != NUL) ? (char *)curbuf->b_p_menc : (char *)p_menc; // Redirect ":grep" to ":vimgrep" if 'grepprg' is "internal". if (grep_internal(eap->cmdidx)) { @@ -4294,7 +4361,7 @@ void ex_make(exarg_T *eap) return; } - char_u *const au_name = make_get_auname(eap->cmdidx); + char *const au_name = make_get_auname(eap->cmdidx); if (au_name != NULL && apply_autocmds(EVENT_QUICKFIXCMDPRE, au_name, curbuf->b_fname, true, curbuf)) { if (aborting()) { @@ -4311,11 +4378,11 @@ void ex_make(exarg_T *eap) if (fname == NULL) { return; } - os_remove((char *)fname); // in case it's not unique + os_remove(fname); // in case it's not unique char *const cmd = make_get_fullcmd(eap->arg, fname); - do_shell((char_u *)cmd, 0); + do_shell(cmd, 0); incr_quickfix_busy(); @@ -4346,7 +4413,7 @@ void ex_make(exarg_T *eap) cleanup: decr_quickfix_busy(); - os_remove((char *)fname); + os_remove(fname); xfree(fname); xfree(cmd); } @@ -4354,15 +4421,15 @@ cleanup: // Return the name for the errorfile, in allocated memory. // Find a new unique name when 'makeef' contains "##". // Returns NULL for error. -static char_u *get_mef_name(void) +static char *get_mef_name(void) { - char_u *p; - char_u *name; + char *p; + char *name; static int start = -1; static int off = 0; if (*p_mef == NUL) { - name = vim_tempname(); + name = (char *)vim_tempname(); if (name == NULL) { emsg(_(e_notmp)); } @@ -4376,7 +4443,7 @@ static char_u *get_mef_name(void) } if (*p == NUL) { - return vim_strsave(p_mef); + return xstrdup(p_mef); } // Keep trying until the name doesn't exist yet. @@ -4388,11 +4455,11 @@ static char_u *get_mef_name(void) } name = xmalloc(STRLEN(p_mef) + 30); STRCPY(name, p_mef); - sprintf((char *)name + (p - p_mef), "%d%d", start, off); + snprintf(name + (p - p_mef), STRLEN(name), "%d%d", start, off); STRCAT(name, p + 2); // Don't accept a symbolic link, it's a security risk. FileInfo file_info; - bool file_or_link_found = os_fileinfo_link((char *)name, &file_info); + bool file_or_link_found = os_fileinfo_link(name, &file_info); if (!file_or_link_found) { break; } @@ -4849,11 +4916,12 @@ static qfline_T *qf_find_closest_entry(qf_list_T *qfl, int bnr, const pos_T *pos /// Get the nth quickfix entry below the specified entry. Searches forward in /// the list. If linewise is true, then treat multiple entries on a single line /// as one. -static void qf_get_nth_below_entry(qfline_T *entry, linenr_T n, bool linewise, int *errornr) +static void qf_get_nth_below_entry(qfline_T *entry_arg, linenr_T n, bool linewise, int *errornr) FUNC_ATTR_NONNULL_ALL { + qfline_T *entry = entry_arg; + while (n-- > 0 && !got_int) { - // qfline_T *first_entry = entry; int first_errornr = *errornr; if (linewise) { @@ -4864,9 +4932,6 @@ static void qf_get_nth_below_entry(qfline_T *entry, linenr_T n, bool linewise, i if (entry->qf_next == NULL || entry->qf_next->qf_fnum != entry->qf_fnum) { if (linewise) { - // If multiple entries are on the same line, then use the first - // entry - // entry = first_entry; *errornr = first_errornr; } break; @@ -4996,36 +5061,34 @@ void ex_cbelow(exarg_T *eap) } } - /// Return the autocmd name for the :cfile Ex commands -static char_u *cfile_get_auname(cmdidx_T cmdidx) +static char *cfile_get_auname(cmdidx_T cmdidx) { switch (cmdidx) { case CMD_cfile: - return (char_u *)"cfile"; + return "cfile"; case CMD_cgetfile: - return (char_u *)"cgetfile"; + return "cgetfile"; case CMD_caddfile: - return (char_u *)"caddfile"; + return "caddfile"; case CMD_lfile: - return (char_u *)"lfile"; + return "lfile"; case CMD_lgetfile: - return (char_u *)"lgetfile"; + return "lgetfile"; case CMD_laddfile: - return (char_u *)"laddfile"; + return "laddfile"; default: return NULL; } } - // ":cfile"/":cgetfile"/":caddfile" commands. // ":lfile"/":lgetfile"/":laddfile" commands. void ex_cfile(exarg_T *eap) { win_T *wp = NULL; qf_info_T *qi = &ql_info; - char_u *au_name = NULL; + char *au_name = NULL; au_name = cfile_get_auname(eap->cmdidx); if (au_name != NULL @@ -5038,7 +5101,7 @@ void ex_cfile(exarg_T *eap) set_string_option_direct("ef", -1, eap->arg, OPT_FREE, 0); } - char_u *enc = (*curbuf->b_p_menc != NUL) ? curbuf->b_p_menc : p_menc; + char *enc = (*curbuf->b_p_menc != NUL) ? (char *)curbuf->b_p_menc : (char *)p_menc; if (is_loclist_cmd(eap->cmdidx)) { wp = curwin; @@ -5054,8 +5117,8 @@ void ex_cfile(exarg_T *eap) // first error. // :caddfile adds to an existing quickfix list. If there is no // quickfix list then a new list is created. - int res = qf_init(wp, p_ef, p_efm, (eap->cmdidx != CMD_caddfile - && eap->cmdidx != CMD_laddfile), + int res = qf_init(wp, (char *)p_ef, p_efm, (eap->cmdidx != CMD_caddfile + && eap->cmdidx != CMD_laddfile), qf_cmdtitle(*eap->cmdlinep), enc); if (wp != NULL) { qi = GET_LOC_LIST(wp); @@ -5083,32 +5146,32 @@ void ex_cfile(exarg_T *eap) } /// Return the vimgrep autocmd name. -static char_u *vgr_get_auname(cmdidx_T cmdidx) +static char *vgr_get_auname(cmdidx_T cmdidx) { switch (cmdidx) { case CMD_vimgrep: - return (char_u *)"vimgrep"; + return "vimgrep"; case CMD_lvimgrep: - return (char_u *)"lvimgrep"; + return "lvimgrep"; case CMD_vimgrepadd: - return (char_u *)"vimgrepadd"; + return "vimgrepadd"; case CMD_lvimgrepadd: - return (char_u *)"lvimgrepadd"; + return "lvimgrepadd"; case CMD_grep: - return (char_u *)"grep"; + return "grep"; case CMD_lgrep: - return (char_u *)"lgrep"; + return "lgrep"; case CMD_grepadd: - return (char_u *)"grepadd"; + return "grepadd"; case CMD_lgrepadd: - return (char_u *)"lgrepadd"; + return "lgrepadd"; default: return NULL; } } /// Initialize the regmatch used by vimgrep for pattern "s". -static void vgr_init_regmatch(regmmatch_T *regmatch, char_u *s) +static void vgr_init_regmatch(regmmatch_T *regmatch, char *s) { // Get the search pattern: either white-separated or enclosed in //. regmatch->regprog = NULL; @@ -5119,7 +5182,7 @@ static void vgr_init_regmatch(regmmatch_T *regmatch, char_u *s) emsg(_(e_noprevre)); return; } - regmatch->regprog = vim_regcomp(last_search_pat(), RE_MAGIC); + regmatch->regprog = vim_regcomp((char *)last_search_pat(), RE_MAGIC); } else { regmatch->regprog = vim_regcomp(s, RE_MAGIC); } @@ -5128,12 +5191,11 @@ static void vgr_init_regmatch(regmmatch_T *regmatch, char_u *s) regmatch->rmm_maxcol = 0; } - /// Display a file name when vimgrep is running. -static void vgr_display_fname(char_u *fname) +static void vgr_display_fname(char *fname) { msg_start(); - char_u *p = msg_strtrunc(fname, true); + char *p = (char *)msg_strtrunc((char_u *)fname, true); if (p == NULL) { msg_outtrans(fname); } else { @@ -5148,11 +5210,11 @@ static void vgr_display_fname(char_u *fname) } /// Load a dummy buffer to search for a pattern using vimgrep. -static buf_T *vgr_load_dummy_buf(char_u *fname, char_u *dirname_start, char_u *dirname_now) +static buf_T *vgr_load_dummy_buf(char *fname, char *dirname_start, char *dirname_now) { // Don't do Filetype autocommands to avoid loading syntax and // indent scripts, a great speed improvement. - char_u *save_ei = au_event_disable(",Filetype"); + char *save_ei = au_event_disable(",Filetype"); long save_mls = p_mls; p_mls = 0; @@ -5170,7 +5232,7 @@ static buf_T *vgr_load_dummy_buf(char_u *fname, char_u *dirname_start, char_u *d /// Check whether a quickfix/location list is valid. Autocmds may remove or /// change a quickfix list when vimgrep is running. If the list is not found, /// create a new list. -static bool vgr_qflist_valid(win_T *wp, qf_info_T *qi, unsigned qfid, char_u *title) +static bool vgr_qflist_valid(win_T *wp, qf_info_T *qi, unsigned qfid, char *title) { // Verify that the quickfix/location list was not freed by an autocmd if (!qflist_valid(wp, qfid)) { @@ -5191,52 +5253,96 @@ static bool vgr_qflist_valid(win_T *wp, qf_info_T *qi, unsigned qfid, char_u *ti return true; } - /// 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_u *fname, buf_T *buf, regmmatch_T *regmatch, - long *tomatch, int duplicate_name, int flags) - FUNC_ATTR_NONNULL_ARG(1, 3, 4, 5) +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) + FUNC_ATTR_NONNULL_ARG(1, 3, 4, 5, 6) { bool found_match = false; - for (long lnum = 1; lnum <= buf->b_ml.ml_line_count && *tomatch > 0; lnum++) { + for (linenr_T lnum = 1; lnum <= buf->b_ml.ml_line_count && *tomatch > 0; lnum++) { colnr_T col = 0; - while (vim_regexec_multi(regmatch, curwin, buf, lnum, col, NULL, - NULL) > 0) { - // Pass the buffer number so that it gets used even for a - // dummy buffer, unless duplicate_name is set, then the - // buffer will be wiped out below. - if (qf_add_entry(qfl, - NULL, // dir - fname, - NULL, - duplicate_name ? 0 : buf->b_fnum, - ml_get_buf(buf, regmatch->startpos[0].lnum + lnum, - false), - regmatch->startpos[0].lnum + lnum, - regmatch->endpos[0].lnum + lnum, - regmatch->startpos[0].col + 1, - regmatch->endpos[0].col + 1, - false, // vis_col - NULL, // search pattern - 0, // nr - 0, // type - true) // valid - == QF_FAIL) { - got_int = true; - break; - } - found_match = true; - if (--*tomatch == 0) { - break; - } - if ((flags & VGR_GLOBAL) == 0 || regmatch->endpos[0].lnum > 0) { - break; + if (!(flags & VGR_FUZZY)) { + // Regular expression match + while (vim_regexec_multi(regmatch, curwin, buf, lnum, col, NULL, NULL) > 0) { + // Pass the buffer number so that it gets used even for a + // dummy buffer, unless duplicate_name is set, then the + // buffer will be wiped out below. + if (qf_add_entry(qfl, + NULL, // dir + fname, + NULL, + duplicate_name ? 0 : buf->b_fnum, + (char *)ml_get_buf(buf, regmatch->startpos[0].lnum + lnum, false), + regmatch->startpos[0].lnum + lnum, + regmatch->endpos[0].lnum + lnum, + regmatch->startpos[0].col + 1, + regmatch->endpos[0].col + 1, + false, // vis_col + NULL, // search pattern + 0, // nr + 0, // type + true) // valid + == QF_FAIL) { + got_int = true; + break; + } + found_match = true; + if (--*tomatch == 0) { + break; + } + if ((flags & VGR_GLOBAL) == 0 || regmatch->endpos[0].lnum > 0) { + break; + } + col = regmatch->endpos[0].col + (col == regmatch->endpos[0].col); + if (col > (colnr_T)STRLEN(ml_get_buf(buf, lnum, false))) { + break; + } } - col = regmatch->endpos[0].col + (col == regmatch->endpos[0].col); - if (col > (colnr_T)STRLEN(ml_get_buf(buf, lnum, false))) { - break; + } else { + const size_t pat_len = STRLEN(spat); + char *const str = (char *)ml_get_buf(buf, lnum, false); + int score; + uint32_t matches[MAX_FUZZY_MATCHES]; + const size_t sz = sizeof(matches) / sizeof(matches[0]); + + // Fuzzy string match + while (fuzzy_match((char_u *)str + col, (char_u *)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 + // buffer will be wiped out below. + if (qf_add_entry(qfl, + NULL, // dir + fname, + NULL, + duplicate_name ? 0 : buf->b_fnum, + str, + lnum, + 0, + (colnr_T)matches[0] + col + 1, + 0, + false, // vis_col + NULL, // search pattern + 0, // nr + 0, // type + true) // valid + == QF_FAIL) { + got_int = true; + break; + } + found_match = true; + if (--*tomatch == 0) { + break; + } + if ((flags & VGR_GLOBAL) == 0) { + break; + } + col = (colnr_T)matches[pat_len - 1] + col + 1; + if (col > (colnr_T)STRLEN(str)) { + break; + } } } line_breakcheck(); @@ -5249,8 +5355,8 @@ static bool vgr_match_buflines(qf_list_T *qfl, char_u *fname, buf_T *buf, regmma } /// Jump to the first match and update the directory. -static void vgr_jump_to_match(qf_info_T *qi, int forceit, int *redraw_for_dummy, - buf_T *first_match_buf, char_u *target_dir) +static void vgr_jump_to_match(qf_info_T *qi, int forceit, bool *redraw_for_dummy, + buf_T *first_match_buf, char *target_dir) { buf_T *buf = curbuf; qf_jump(qi, 0, 0, forceit); @@ -5276,7 +5382,7 @@ static bool existing_swapfile(const buf_T *buf) FUNC_ATTR_NONNULL_ALL FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT { if (buf->b_ml.ml_mfp != NULL && buf->b_ml.ml_mfp->mf_fname != NULL) { - const char_u *const fname = buf->b_ml.ml_mfp->mf_fname; + const char *const fname = (char *)buf->b_ml.ml_mfp->mf_fname; const size_t len = STRLEN(fname); return fname[len - 1] != 'p' || fname[len - 2] != 'w'; @@ -5284,104 +5390,71 @@ static bool existing_swapfile(const buf_T *buf) return false; } -// ":vimgrep {pattern} file(s)" -// ":vimgrepadd {pattern} file(s)" -// ":lvimgrep {pattern} file(s)" -// ":lvimgrepadd {pattern} file(s)" -void ex_vimgrep(exarg_T *eap) +/// Process :vimgrep command arguments. The command syntax is: +/// +/// :{count}vimgrep /{pattern}/[g][j] {file} ... +static int vgr_process_args(exarg_T *eap, vgr_args_T *args) { - regmmatch_T regmatch; - int fcount; - char_u **fnames; - char_u *fname; - char_u *s; - char_u *p; - int fi; - qf_list_T *qfl; - win_T *wp = NULL; - buf_T *buf; - int duplicate_name = FALSE; - int using_dummy; - int redraw_for_dummy = FALSE; - int found_match; - buf_T *first_match_buf = NULL; - time_t seconds = 0; - aco_save_T aco; - int flags = 0; - long tomatch; - char_u *dirname_start = NULL; - char_u *dirname_now = NULL; - char_u *target_dir = NULL; - char_u *au_name = NULL; - - au_name = vgr_get_auname(eap->cmdidx); - if (au_name != NULL && apply_autocmds(EVENT_QUICKFIXCMDPRE, au_name, - curbuf->b_fname, true, curbuf)) { - if (aborting()) { - return; - } - } + memset(args, 0, sizeof(*args)); - qf_info_T *qi = qf_cmd_get_or_alloc_stack(eap, &wp); + args->regmatch.regprog = NULL; + args->qf_title = xstrdup(qf_cmdtitle(*eap->cmdlinep)); if (eap->addr_count > 0) { - tomatch = eap->line2; + args->tomatch = eap->line2; } else { - tomatch = MAXLNUM; + args->tomatch = MAXLNUM; } // Get the search pattern: either white-separated or enclosed in // - regmatch.regprog = NULL; - char_u *title = vim_strsave(qf_cmdtitle(*eap->cmdlinep)); - p = skip_vimgrep_pat(eap->arg, &s, &flags); + char *p = skip_vimgrep_pat(eap->arg, &args->spat, &args->flags); if (p == NULL) { emsg(_(e_invalpat)); - goto theend; + return FAIL; } - vgr_init_regmatch(®match, s); - if (regmatch.regprog == NULL) { - goto theend; + vgr_init_regmatch(&args->regmatch, args->spat); + if (args->regmatch.regprog == NULL) { + return FAIL; } p = skipwhite(p); if (*p == NUL) { emsg(_("E683: File name missing or invalid pattern")); - goto theend; - } - - if ((eap->cmdidx != CMD_grepadd && eap->cmdidx != CMD_lgrepadd - && eap->cmdidx != CMD_vimgrepadd && eap->cmdidx != CMD_lvimgrepadd) - || qf_stack_empty(qi)) { - // make place for a new list - qf_new_list(qi, title); + return FAIL; } // Parse the list of arguments, wildcards have already been expanded. - if (get_arglist_exp(p, &fcount, &fnames, true) == FAIL) { - goto theend; + if (get_arglist_exp((char_u *)p, &args->fcount, (char_u ***)&args->fnames, true) == FAIL) { + return FAIL; } - if (fcount == 0) { + if (args->fcount == 0) { emsg(_(e_nomatch)); - goto theend; + return FAIL; } - dirname_start = xmalloc(MAXPATHL); - dirname_now = xmalloc(MAXPATHL); + return OK; +} - // Remember the current directory, because a BufRead autocommand that does - // ":lcd %:p:h" changes the meaning of short path names. - os_dirname(dirname_start, MAXPATHL); +/// Search for a pattern in a list of files and populate the quickfix list with +/// the matches. +static int vgr_process_files(win_T *wp, qf_info_T *qi, vgr_args_T *cmd_args, bool *redraw_for_dummy, + buf_T **first_match_buf, char **target_dir) +{ + int status = FAIL; + unsigned save_qfid = qf_get_curlist(qi)->qf_id; + bool duplicate_name = false; - incr_quickfix_busy(); + char *dirname_start = xmalloc(MAXPATHL); + char *dirname_now = xmalloc(MAXPATHL); - // Remember the current quickfix list identifier, so that we can check for - // autocommands changing the current quickfix list. - unsigned save_qfid = qf_get_curlist(qi)->qf_id; + // Remember the current directory, because a BufRead autocommand that does + // ":lcd %:p:h" changes the meaning of short path names. + os_dirname((char_u *)dirname_start, MAXPATHL); - seconds = (time_t)0; - for (fi = 0; fi < fcount && !got_int && tomatch > 0; fi++) { - fname = path_try_shorten_fname(fnames[fi]); + time_t seconds = (time_t)0; + for (int fi = 0; fi < cmd_args->fcount && !got_int && cmd_args->tomatch > 0; fi++) { + char *fname = (char *)path_try_shorten_fname((char_u *)cmd_args->fnames[fi]); if (time(NULL) > seconds) { // Display the file name every second or so, show the user we are // working on it. @@ -5389,13 +5462,13 @@ void ex_vimgrep(exarg_T *eap) vgr_display_fname(fname); } - buf = buflist_findname_exp(fnames[fi]); + buf_T *buf = buflist_findname_exp(cmd_args->fnames[fi]); + bool using_dummy; if (buf == NULL || buf->b_ml.ml_mfp == NULL) { // Remember that a buffer with this name already exists. duplicate_name = (buf != NULL); - using_dummy = TRUE; - redraw_for_dummy = TRUE; - + using_dummy = true; + *redraw_for_dummy = true; buf = vgr_load_dummy_buf(fname, dirname_start, dirname_now); } else { // Use existing, loaded buffer. @@ -5404,11 +5477,10 @@ void ex_vimgrep(exarg_T *eap) // Check whether the quickfix list is still valid. When loading a // buffer above, autocommands might have changed the quickfix list. - if (!vgr_qflist_valid(wp, qi, save_qfid, *eap->cmdlinep)) { - FreeWild(fcount, fnames); - decr_quickfix_busy(); + if (!vgr_qflist_valid(wp, qi, save_qfid, cmd_args->qf_title)) { goto theend; } + save_qfid = qf_get_curlist(qi)->qf_id; if (buf == NULL) { @@ -5418,20 +5490,25 @@ void ex_vimgrep(exarg_T *eap) } else { // Try for a match in all lines of the buffer. // For ":1vimgrep" look for first match only. - found_match = vgr_match_buflines(qf_get_curlist(qi), - fname, buf, ®match, &tomatch, - duplicate_name, flags); + bool found_match = vgr_match_buflines(qf_get_curlist(qi), + fname, + buf, + cmd_args->spat, + &cmd_args->regmatch, + &cmd_args->tomatch, + duplicate_name, + cmd_args->flags); if (using_dummy) { - if (found_match && first_match_buf == NULL) { - first_match_buf = buf; + if (found_match && *first_match_buf == NULL) { + *first_match_buf = buf; } if (duplicate_name) { // Never keep a dummy buffer if there is another buffer // with the same name. wipe_dummy_buffer(buf, dirname_start); buf = NULL; - } else if (!cmdmod.hide + } else if ((cmdmod.cmod_flags & CMOD_HIDE) == 0 || buf->b_p_bh[0] == 'u' // "unload" || buf->b_p_bh[0] == 'w' // "wipe" || buf->b_p_bh[0] == 'd') { // "delete" @@ -5444,8 +5521,8 @@ void ex_vimgrep(exarg_T *eap) if (!found_match) { wipe_dummy_buffer(buf, dirname_start); buf = NULL; - } else if (buf != first_match_buf - || (flags & VGR_NOJUMP) + } else if (buf != *first_match_buf + || (cmd_args->flags & VGR_NOJUMP) || existing_swapfile(buf)) { unload_dummy_buffer(buf, dirname_start); // Keeping the buffer, remove the dummy flag. @@ -5460,18 +5537,19 @@ void ex_vimgrep(exarg_T *eap) // If the buffer is still loaded we need to use the // directory we jumped to below. - if (buf == first_match_buf - && target_dir == NULL + if (buf == *first_match_buf + && *target_dir == NULL && STRCMP(dirname_start, dirname_now) != 0) { - target_dir = vim_strsave(dirname_now); + *target_dir = xstrdup(dirname_now); } // The buffer is still loaded, the Filetype autocommands // need to be done now, in that buffer. And the modelines // need to be done (again). But not the window-local // options! + aco_save_T aco; aucmd_prepbuf(&aco, buf); - apply_autocmds(EVENT_FILETYPE, buf->b_p_ft, buf->b_fname, true, buf); + apply_autocmds(EVENT_FILETYPE, (char *)buf->b_p_ft, buf->b_fname, true, buf); do_modelines(OPT_NOWIN); aucmd_restbuf(&aco); } @@ -5479,9 +5557,58 @@ void ex_vimgrep(exarg_T *eap) } } - FreeWild(fcount, fnames); + status = OK; - qfl = qf_get_curlist(qi); +theend: + xfree(dirname_now); + xfree(dirname_start); + return status; +} + +/// ":vimgrep {pattern} file(s)" +/// ":vimgrepadd {pattern} file(s)" +/// ":lvimgrep {pattern} file(s)" +/// ":lvimgrepadd {pattern} file(s)" +void ex_vimgrep(exarg_T *eap) +{ + char *au_name = vgr_get_auname(eap->cmdidx); + if (au_name != NULL && apply_autocmds(EVENT_QUICKFIXCMDPRE, au_name, + curbuf->b_fname, true, curbuf)) { + if (aborting()) { + return; + } + } + + win_T *wp = NULL; + qf_info_T *qi = qf_cmd_get_or_alloc_stack(eap, &wp); + char *target_dir = NULL; + vgr_args_T args; + if (vgr_process_args(eap, &args) == FAIL) { + goto theend; + } + + if ((eap->cmdidx != CMD_grepadd && eap->cmdidx != CMD_lgrepadd + && eap->cmdidx != CMD_vimgrepadd && eap->cmdidx != CMD_lvimgrepadd) + || qf_stack_empty(qi)) { + // make place for a new list + qf_new_list(qi, args.qf_title); + } + + incr_quickfix_busy(); + + bool redraw_for_dummy = false; + buf_T *first_match_buf = NULL; + int status = vgr_process_files(wp, qi, &args, &redraw_for_dummy, &first_match_buf, &target_dir); + + if (status != OK) { + FreeWild(args.fcount, (char_u **)args.fnames); + decr_quickfix_busy(); + goto theend; + } + + FreeWild(args.fcount, (char_u **)args.fnames); + + qf_list_T *qfl = qf_get_curlist(qi); qfl->qf_nonevalid = false; qfl->qf_ptr = qfl->qf_start; qfl->qf_index = 1; @@ -5489,26 +5616,28 @@ void ex_vimgrep(exarg_T *eap) qf_update_buffer(qi, NULL); + // Remember the current quickfix list identifier, so that we can check for + // autocommands changing the current quickfix list. + unsigned save_qfid = qf_get_curlist(qi)->qf_id; + if (au_name != NULL) { apply_autocmds(EVENT_QUICKFIXCMDPOST, au_name, curbuf->b_fname, true, curbuf); } // The QuickFixCmdPost autocmd may free the quickfix list. Check the list // is still valid. - if (!qflist_valid(wp, save_qfid) - || qf_restore_list(qi, save_qfid) == FAIL) { + if (!qflist_valid(wp, save_qfid) || qf_restore_list(qi, save_qfid) == FAIL) { decr_quickfix_busy(); goto theend; } // Jump to first match. if (!qf_list_empty(qf_get_curlist(qi))) { - if ((flags & VGR_NOJUMP) == 0) { - vgr_jump_to_match(qi, eap->forceit, &redraw_for_dummy, first_match_buf, - target_dir); + if ((args.flags & VGR_NOJUMP) == 0) { + vgr_jump_to_match(qi, eap->forceit, &redraw_for_dummy, first_match_buf, target_dir); } } else { - semsg(_(e_nomatch2), s); + semsg(_(e_nomatch2), args.spat); } decr_quickfix_busy(); @@ -5520,21 +5649,19 @@ void ex_vimgrep(exarg_T *eap) } theend: - xfree(title); - xfree(dirname_now); - xfree(dirname_start); + xfree(args.qf_title); xfree(target_dir); - vim_regfree(regmatch.regprog); + vim_regfree(args.regmatch.regprog); } // 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) +static void restore_start_dir(char *dirname_start) FUNC_ATTR_NONNULL_ALL { - char_u *dirname_now = xmalloc(MAXPATHL); + char *dirname_now = xmalloc(MAXPATHL); - os_dirname(dirname_now, MAXPATHL); + os_dirname((char_u *)dirname_now, MAXPATHL); if (STRCMP(dirname_start, dirname_now) != 0) { // If the directory has changed, change it back by building up an // appropriate ex command and executing it. @@ -5560,7 +5687,7 @@ static void restore_start_dir(char_u *dirname_start) /// @param resulting_dir out: new directory /// /// @return NULL if it fails. -static buf_T *load_dummy_buffer(char_u *fname, char_u *dirname_start, char_u *resulting_dir) +static buf_T *load_dummy_buffer(char *fname, char *dirname_start, char *resulting_dir) { buf_T *newbuf; bufref_T newbufref; @@ -5599,7 +5726,7 @@ static buf_T *load_dummy_buffer(char_u *fname, char_u *dirname_start, char_u *re newbuf_to_wipe.br_buf = NULL; readfile_result = readfile(fname, NULL, (linenr_T)0, (linenr_T)0, (linenr_T)MAXLNUM, NULL, - READ_NEW | READ_DUMMY); + READ_NEW | READ_DUMMY, false); newbuf->b_locked--; if (readfile_result == OK && !got_int @@ -5629,7 +5756,7 @@ static buf_T *load_dummy_buffer(char_u *fname, char_u *dirname_start, char_u *re // When autocommands/'autochdir' option changed directory: go back. // Let the caller know what the resulting dir was first, in case it is // important. - os_dirname(resulting_dir, MAXPATHL); + os_dirname((char_u *)resulting_dir, MAXPATHL); restore_start_dir(dirname_start); if (!bufref_valid(&newbufref)) { @@ -5645,7 +5772,7 @@ static buf_T *load_dummy_buffer(char_u *fname, char_u *dirname_start, char_u *re // Wipe out the dummy buffer that load_dummy_buffer() created. Restores // 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) +static void wipe_dummy_buffer(buf_T *buf, char *dirname_start) FUNC_ATTR_NONNULL_ALL { // If any autocommand opened a window on the dummy buffer, close that @@ -5656,7 +5783,7 @@ static void wipe_dummy_buffer(buf_T *buf, char_u *dirname_start) 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) { + if (win_close(wp, false, false) == OK) { did_one = true; } break; @@ -5689,10 +5816,10 @@ static void wipe_dummy_buffer(buf_T *buf, char_u *dirname_start) // Unload the dummy buffer that load_dummy_buffer() created. Restores // directory to "dirname_start" prior to returning, if autocmds or the // 'autochdir' option have changed it. -static void unload_dummy_buffer(buf_T *buf, char_u *dirname_start) +static void unload_dummy_buffer(buf_T *buf, char *dirname_start) { if (curbuf != buf) { // safety check - close_buffer(NULL, buf, DOBUF_UNLOAD, false); + close_buffer(NULL, buf, DOBUF_UNLOAD, false, true); // When autocommands/'autochdir' option changed directory: go back. restore_start_dir(dirname_start); @@ -5703,7 +5830,7 @@ static void unload_dummy_buffer(buf_T *buf, char_u *dirname_start) /// to 'list'. Returns OK on success. static int get_qfline_items(qfline_T *qfp, list_T *list) { - char_u buf[2]; + char buf[2]; int bufnum; // Handle entries with a non-existing buffer number. @@ -5822,7 +5949,7 @@ enum { static int qf_get_list_from_lines(dict_T *what, dictitem_T *di, dict_T *retdict) { int status = FAIL; - char_u *errorformat = p_efm; + char *errorformat = p_efm; dictitem_T *efm_di; // Only a List value is supported @@ -5869,6 +5996,21 @@ static int qf_winid(qf_info_T *qi) return 0; } +/// Returns the number of the buffer displayed in the quickfix/location list +/// window. If there is no buffer associated with the list or the buffer is +/// wiped out, then returns 0. +static int qf_getprop_qfbufnr(const qf_info_T *qi, dict_T *retdict) + FUNC_ATTR_NONNULL_ARG(2) +{ + int bufnum = 0; + + if (qi != NULL && buflist_findnr(qi->qf_bufnr) != NULL) { + bufnum = qi->qf_bufnr; + } + + return tv_dict_add_nr(retdict, S_LEN("qfbufnr"), bufnum); +} + /// Convert the keys in 'what' to quickfix list property flags. static int qf_getprop_keys2flags(const dict_T *what, bool loclist) FUNC_ATTR_NONNULL_ALL FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT @@ -5912,6 +6054,9 @@ static int qf_getprop_keys2flags(const dict_T *what, bool loclist) if (loclist && tv_dict_find(what, S_LEN("filewinid")) != NULL) { flags |= QF_GETLIST_FILEWINID; } + if (tv_dict_find(what, S_LEN("qfbufnr")) != NULL) { + flags |= QF_GETLIST_QFBUFNR; + } if (tv_dict_find(what, S_LEN("quickfixtextfunc")) != NULL) { flags |= QF_GETLIST_QFTF; } @@ -6003,6 +6148,9 @@ static int qf_getprop_defaults(qf_info_T *qi, int flags, int locstack, dict_T *r if ((status == OK) && locstack && (flags & QF_GETLIST_FILEWINID)) { status = tv_dict_add_nr(retdict, S_LEN("filewinid"), 0); } + if ((status == OK) && (flags & QF_GETLIST_QFBUFNR)) { + status = qf_getprop_qfbufnr(qi, retdict); + } if ((status == OK) && (flags & QF_GETLIST_QFTF)) { status = tv_dict_add_str(retdict, S_LEN("quickfixtextfunc"), ""); } @@ -6086,10 +6234,10 @@ static int qf_getprop_qftf(qf_list_T *qfl, dict_T *retdict) { int status; - if (qfl->qftf_cb.type != kCallbackNone) { + if (qfl->qf_qftf_cb.type != kCallbackNone) { typval_T tv; - callback_put(&qfl->qftf_cb, &tv); + callback_put(&qfl->qf_qftf_cb, &tv); status = tv_dict_add_tv(retdict, S_LEN("quickfixtextfunc"), &tv); tv_clear(&tv); } else { @@ -6172,6 +6320,9 @@ int qf_get_properties(win_T *wp, dict_T *what, dict_T *retdict) if ((status == OK) && (wp != NULL) && (flags & QF_GETLIST_FILEWINID)) { status = qf_getprop_filewinid(wp, qi, retdict); } + if ((status == OK) && (flags & QF_GETLIST_QFBUFNR)) { + status = qf_getprop_qfbufnr(qi, retdict); + } if ((status == OK) && (flags & QF_GETLIST_QFTF)) { status = qf_getprop_qftf(qfl, retdict); } @@ -6186,9 +6337,9 @@ static int qf_setprop_qftf(qf_list_T *qfl, dictitem_T *di) { Callback cb; - callback_free(&qfl->qftf_cb); + callback_free(&qfl->qf_qftf_cb); if (callback_from_typval(&cb, &di->di_tv)) { - qfl->qftf_cb = cb; + qfl->qf_qftf_cb = cb; } return OK; } @@ -6209,11 +6360,11 @@ static int qf_add_entry_from_dict(qf_list_T *qfl, const dict_T *d, bool first_en 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 long end_lnum = (long)tv_dict_get_number(d, "end_lnum"); + const linenr_T lnum = (linenr_T)tv_dict_get_number(d, "lnum"); + const linenr_T end_lnum = (linenr_T)tv_dict_get_number(d, "end_lnum"); const int col = (int)tv_dict_get_number(d, "col"); const int end_col = (int)tv_dict_get_number(d, "end_col"); - const char_u vcol = (char_u)tv_dict_get_number(d, "vcol"); + const char vcol = (char)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); @@ -6245,18 +6396,18 @@ static int qf_add_entry_from_dict(qf_list_T *qfl, const dict_T *d, bool first_en const int status = qf_add_entry(qfl, NULL, // dir - (char_u *)filename, - (char_u *)module, + filename, + module, bufnum, - (char_u *)text, + text, lnum, end_lnum, col, end_col, vcol, // vis_col - (char_u *)pattern, // search pattern + pattern, // search pattern nr, - (char_u)(type == NULL ? NUL : *type), + type == NULL ? NUL : *type, valid); xfree(filename); @@ -6273,7 +6424,7 @@ static int qf_add_entry_from_dict(qf_list_T *qfl, const dict_T *d, bool first_en /// 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) +static int qf_add_entries(qf_info_T *qi, int qf_idx, list_T *list, char *title, int action) { qf_list_T *qfl = qf_get_list(qi, qf_idx); qfline_T *old_last = NULL; @@ -6396,7 +6547,7 @@ static int qf_setprop_title(qf_info_T *qi, int qf_idx, const dict_T *what, const } xfree(qfl->qf_title); - qfl->qf_title = (char_u *)tv_dict_get_string(what, "title", true); + qfl->qf_title = tv_dict_get_string(what, "title", true); if (qf_idx == qi->qf_curlist) { qf_update_win_titlevar(qi); } @@ -6412,9 +6563,8 @@ static int qf_setprop_items(qf_info_T *qi, int qf_idx, dictitem_T *di, int actio return FAIL; } - char_u *title_save = vim_strsave(qi->qf_lists[qf_idx].qf_title); - const int retval = qf_add_entries(qi, qf_idx, di->di_tv.vval.v_list, - title_save, + char *title_save = xstrdup(qi->qf_lists[qf_idx].qf_title); + const int retval = qf_add_entries(qi, qf_idx, di->di_tv.vval.v_list, title_save, action == ' ' ? 'a' : action); xfree(title_save); @@ -6426,7 +6576,7 @@ static int qf_setprop_items_from_lines(qf_info_T *qi, int qf_idx, const dict_T * dictitem_T *di, int action) FUNC_ATTR_NONNULL_ALL { - char_u *errorformat = p_efm; + char *errorformat = p_efm; dictitem_T *efm_di; int retval = FAIL; @@ -6512,7 +6662,7 @@ static int qf_setprop_curidx(qf_info_T *qi, qf_list_T *qfl, const dictitem_T *di /// Set quickfix/location list properties (title, items, context). /// Also used to add items from parsing a list of lines. /// Used by the setqflist() and setloclist() Vim script functions. -static int qf_set_properties(qf_info_T *qi, const dict_T *what, int action, char_u *title) +static int qf_set_properties(qf_info_T *qi, const dict_T *what, int action, char *title) FUNC_ATTR_NONNULL_ALL { qf_list_T *qfl; @@ -6560,20 +6710,6 @@ static int qf_set_properties(qf_info_T *qi, const dict_T *what, int action, char return retval; } -/// Find the non-location list window with the specified location list stack in -/// the current tabpage. -static win_T *find_win_with_ll(const qf_info_T *qi) - FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT -{ - FOR_ALL_WINDOWS_IN_TAB(wp, curtab) { - if ((wp->w_llist == qi) && !bt_quickfix(wp->w_buffer)) { - return wp; - } - } - - return NULL; -} - // Free the entire quickfix/location list stack. // If the quickfix/location list window is open, then clear it. static void qf_free_stack(win_T *wp, qf_info_T *qi) @@ -6588,12 +6724,10 @@ static void qf_free_stack(win_T *wp, qf_info_T *qi) qf_update_buffer(qi, NULL); } - win_T *llwin = NULL; - win_T *orig_wp = wp; if (wp != NULL && IS_LL_WINDOW(wp)) { // If in the location list window, then use the non-location list // window with this location list (if present) - llwin = find_win_with_ll(qi); + win_T *const llwin = qf_find_win_with_loclist(qi); if (llwin != NULL) { wp = llwin; } @@ -6604,16 +6738,17 @@ static void qf_free_stack(win_T *wp, qf_info_T *qi) // quickfix list qi->qf_curlist = 0; qi->qf_listcount = 0; - } else if (IS_LL_WINDOW(orig_wp)) { + } else if (qfwin != NULL) { // If the location list window is open, then create a new empty location // list qf_info_T *new_ll = qf_alloc_stack(QFLT_LOCATION); + new_ll->qf_bufnr = qfwin->w_buffer->b_fnum; // first free the list reference in the location list window - ll_free_all(&orig_wp->w_llist_ref); + ll_free_all(&qfwin->w_llist_ref); - orig_wp->w_llist_ref = new_ll; - if (llwin != NULL) { + qfwin->w_llist_ref = new_ll; + if (wp != qfwin) { win_set_loclist(wp, new_ll); } } @@ -6623,7 +6758,7 @@ static void qf_free_stack(win_T *wp, qf_info_T *qi) // of dictionaries. "title" will be copied to w:quickfix_title // "action" is 'a' for add, 'r' for replace. Otherwise create a new list. // When "what" is not NULL then only set some properties. -int set_errorlist(win_T *wp, list_T *list, int action, char_u *title, dict_T *what) +int set_errorlist(win_T *wp, list_T *list, int action, char *title, dict_T *what) { qf_info_T *qi = &ql_info; int retval = OK; @@ -6708,21 +6843,21 @@ bool set_ref_in_quickfix(int copyID) } /// Return the autocmd name for the :cbuffer Ex commands -static char_u *cbuffer_get_auname(cmdidx_T cmdidx) +static char *cbuffer_get_auname(cmdidx_T cmdidx) { switch (cmdidx) { case CMD_cbuffer: - return (char_u *)"cbuffer"; + return "cbuffer"; case CMD_cgetbuffer: - return (char_u *)"cgetbuffer"; + return "cgetbuffer"; case CMD_caddbuffer: - return (char_u *)"caddbuffer"; + return "caddbuffer"; case CMD_lbuffer: - return (char_u *)"lbuffer"; + return "lbuffer"; case CMD_lgetbuffer: - return (char_u *)"lgetbuffer"; + return "lgetbuffer"; case CMD_laddbuffer: - return (char_u *)"laddbuffer"; + return "laddbuffer"; default: return NULL; } @@ -6737,7 +6872,7 @@ static int cbuffer_process_args(exarg_T *eap, buf_T **bufp, linenr_T *line1, lin if (*eap->arg == NUL) { buf = curbuf; } else if (*skipwhite(skipdigits(eap->arg)) == NUL) { - buf = buflist_findnr(atoi((char *)eap->arg)); + buf = buflist_findnr(atoi(eap->arg)); } if (buf == NULL) { @@ -6777,9 +6912,9 @@ static int cbuffer_process_args(exarg_T *eap, buf_T **bufp, linenr_T *line1, lin void ex_cbuffer(exarg_T *eap) { buf_T *buf = NULL; - char_u *au_name = NULL; + char *au_name = NULL; win_T *wp = NULL; - char_u *qf_title; + char *qf_title; linenr_T line1; linenr_T line2; @@ -6801,9 +6936,8 @@ void ex_cbuffer(exarg_T *eap) qf_title = qf_cmdtitle(*eap->cmdlinep); if (buf->b_sfname) { - vim_snprintf((char *)IObuff, IOSIZE, "%s (%s)", - (char *)qf_title, (char *)buf->b_sfname); - qf_title = IObuff; + vim_snprintf((char *)IObuff, IOSIZE, "%s (%s)", qf_title, buf->b_sfname); + qf_title = (char *)IObuff; } incr_quickfix_busy(); @@ -6824,8 +6958,7 @@ void ex_cbuffer(exarg_T *eap) unsigned save_qfid = qf_get_curlist(qi)->qf_id; if (au_name != NULL) { const buf_T *const curbuf_old = curbuf; - apply_autocmds(EVENT_QUICKFIXCMDPOST, au_name, - curbuf->b_fname, true, curbuf); + apply_autocmds(EVENT_QUICKFIXCMDPOST, au_name, curbuf->b_fname, true, curbuf); if (curbuf != curbuf_old) { // Autocommands changed buffer, don't jump now, "qi" may // be invalid. @@ -6844,21 +6977,21 @@ void ex_cbuffer(exarg_T *eap) } /// Return the autocmd name for the :cexpr Ex commands. -static char_u *cexpr_get_auname(cmdidx_T cmdidx) +static char *cexpr_get_auname(cmdidx_T cmdidx) { switch (cmdidx) { case CMD_cexpr: - return (char_u *)"cexpr"; + return "cexpr"; case CMD_cgetexpr: - return (char_u *)"cgetexpr"; + return "cgetexpr"; case CMD_caddexpr: - return (char_u *)"caddexpr"; + return "caddexpr"; case CMD_lexpr: - return (char_u *)"lexpr"; + return "lexpr"; case CMD_lgetexpr: - return (char_u *)"lgetexpr"; + return "lgetexpr"; case CMD_laddexpr: - return (char_u *)"laddexpr"; + return "laddexpr"; default: return NULL; } @@ -6868,7 +7001,7 @@ static char_u *cexpr_get_auname(cmdidx_T cmdidx) /// ":lexpr {expr}", ":lgetexpr {expr}", ":laddexpr {expr}" command. void ex_cexpr(exarg_T *eap) { - char_u *au_name = NULL; + char *au_name = NULL; win_T *wp = NULL; au_name = cexpr_get_auname(eap->cmdidx); @@ -6904,8 +7037,7 @@ void ex_cexpr(exarg_T *eap) // check for autocommands changing the current quickfix list. unsigned save_qfid = qf_get_curlist(qi)->qf_id; if (au_name != NULL) { - apply_autocmds(EVENT_QUICKFIXCMDPOST, au_name, - curbuf->b_fname, true, curbuf); + apply_autocmds(EVENT_QUICKFIXCMDPOST, au_name, curbuf->b_fname, true, curbuf); } // Jump to the first error for a new list and if autocmds didn't // free the list. @@ -6954,17 +7086,17 @@ static qf_info_T *hgr_get_ll(bool *new_ll) } // Search for a pattern in a help file. -static void hgr_search_file(qf_list_T *qfl, char_u *fname, regmatch_T *p_regmatch) +static void hgr_search_file(qf_list_T *qfl, char *fname, regmatch_T *p_regmatch) FUNC_ATTR_NONNULL_ARG(1, 3) { - FILE *const fd = os_fopen((char *)fname, "r"); + FILE *const fd = os_fopen(fname, "r"); if (fd == NULL) { return; } - long lnum = 1; + linenr_T lnum = 1; while (!vim_fgets(IObuff, IOSIZE, fd) && !got_int) { - char_u *line = IObuff; + char *line = (char *)IObuff; if (vim_regexec(p_regmatch, line, (colnr_T)0)) { int l = (int)STRLEN(line); @@ -6982,8 +7114,8 @@ static void hgr_search_file(qf_list_T *qfl, char_u *fname, regmatch_T *p_regmatc line, lnum, 0, - (int)(p_regmatch->startp[0] - line) + 1, // col - (int)(p_regmatch->endp[0] - line) + (int)(p_regmatch->startp[0] - (char_u *)line) + 1, // col + (int)(p_regmatch->endp[0] - (char_u *)line) + 1, // end_col false, // vis_col NULL, // search pattern @@ -6992,13 +7124,13 @@ static void hgr_search_file(qf_list_T *qfl, char_u *fname, regmatch_T *p_regmatc true) // valid == QF_FAIL) { got_int = true; - if (line != IObuff) { + if ((char_u *)line != IObuff) { xfree(line); } break; } } - if (line != IObuff) { + if ((char_u *)line != IObuff) { xfree(line); } lnum++; @@ -7009,18 +7141,18 @@ static void hgr_search_file(qf_list_T *qfl, char_u *fname, regmatch_T *p_regmatc // Search for a pattern in all the help files in the doc directory under // the given directory. -static void hgr_search_files_in_dir(qf_list_T *qfl, char_u *dirname, regmatch_T *p_regmatch, - const char_u *lang) +static void hgr_search_files_in_dir(qf_list_T *qfl, char *dirname, regmatch_T *p_regmatch, + const char *lang) FUNC_ATTR_NONNULL_ARG(1, 2, 3) { int fcount; - char_u **fnames; + char **fnames; // Find all "*.txt" and "*.??x" files in the "doc" directory. - add_pathsep((char *)dirname); + add_pathsep(dirname); STRCAT(dirname, "doc/*.\\(txt\\|??x\\)"); // NOLINT - if (gen_expand_wildcards(1, &dirname, &fcount, - &fnames, EW_FILE|EW_SILENT) == OK + if (gen_expand_wildcards(1, (char_u **)&dirname, &fcount, + (char_u ***)&fnames, EW_FILE|EW_SILENT) == OK && fcount > 0) { for (int fi = 0; fi < fcount && !got_int; fi++) { // Skip files for a different language. @@ -7034,7 +7166,7 @@ static void hgr_search_files_in_dir(qf_list_T *qfl, char_u *dirname, regmatch_T hgr_search_file(qfl, fnames[fi], p_regmatch); } - FreeWild(fcount, fnames); + FreeWild(fcount, (char_u **)fnames); } } @@ -7042,15 +7174,15 @@ static void hgr_search_files_in_dir(qf_list_T *qfl, char_u *dirname, regmatch_T // 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_list_T *qfl, regmatch_T *p_regmatch, const char_u *lang) +static void hgr_search_in_rtp(qf_list_T *qfl, regmatch_T *p_regmatch, const char *lang) FUNC_ATTR_NONNULL_ARG(1, 2) { // Go through all directories in 'runtimepath' - char_u *p = p_rtp; + char *p = (char *)p_rtp; while (*p != NUL && !got_int) { - copy_option_part(&p, NameBuff, MAXPATHL, ","); + copy_option_part(&p, (char *)NameBuff, MAXPATHL, ","); - hgr_search_files_in_dir(qfl, NameBuff, p_regmatch, lang); + hgr_search_files_in_dir(qfl, (char *)NameBuff, p_regmatch, (char *)lang); } } @@ -7059,13 +7191,13 @@ void ex_helpgrep(exarg_T *eap) { qf_info_T *qi = &ql_info; bool new_qi = false; - char_u *au_name = NULL; + char *au_name = NULL; switch (eap->cmdidx) { case CMD_helpgrep: - au_name = (char_u *)"helpgrep"; break; + au_name = "helpgrep"; break; case CMD_lhelpgrep: - au_name = (char_u *)"lhelpgrep"; break; + au_name = "lhelpgrep"; break; default: break; } @@ -7077,8 +7209,8 @@ void ex_helpgrep(exarg_T *eap) } // Make 'cpoptions' empty, the 'l' flag should not be used here. - char_u *const save_cpo = p_cpo; - p_cpo = empty_option; + char *const save_cpo = p_cpo; + p_cpo = (char *)empty_option; if (is_loclist_cmd(eap->cmdidx)) { qi = hgr_get_ll(&new_qi); @@ -7087,7 +7219,7 @@ void ex_helpgrep(exarg_T *eap) incr_quickfix_busy(); // Check for a specified language - char_u *const lang = check_help_lang(eap->arg); + char *const lang = check_help_lang(eap->arg); regmatch_T regmatch = { .regprog = vim_regcomp(eap->arg, RE_MAGIC + RE_STRING), .rm_ic = false, @@ -7108,16 +7240,15 @@ void ex_helpgrep(exarg_T *eap) qf_update_buffer(qi, NULL); } - if (p_cpo == empty_option) { + if ((char_u *)p_cpo == empty_option) { p_cpo = save_cpo; } else { // Darn, some plugin changed the value. - free_string_option(save_cpo); + free_string_option((char_u *)save_cpo); } if (au_name != NULL) { - apply_autocmds(EVENT_QUICKFIXCMDPOST, au_name, - curbuf->b_fname, true, curbuf); + apply_autocmds(EVENT_QUICKFIXCMDPOST, au_name, curbuf->b_fname, true, curbuf); // When adding a location list to an existing location list stack, // if the autocmd made the stack invalid, then just return. if (!new_qi && IS_LL_STACK(qi) && qf_find_win_with_loclist(qi) == NULL) { @@ -7147,4 +7278,3 @@ void ex_helpgrep(exarg_T *eap) } } } - |