diff options
Diffstat (limited to 'src/nvim/quickfix.c')
-rw-r--r-- | src/nvim/quickfix.c | 569 |
1 files changed, 319 insertions, 250 deletions
diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c index f9d139c466..5518fdfa51 100644 --- a/src/nvim/quickfix.c +++ b/src/nvim/quickfix.c @@ -4,30 +4,44 @@ // quickfix.c: functions for quickfix mode, using a file with error messages #include <assert.h> +#include <errno.h> #include <inttypes.h> +#include <limits.h> #include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> #include <string.h> +#include <time.h> -#include "nvim/api/private/helpers.h" #include "nvim/arglist.h" #include "nvim/ascii.h" +#include "nvim/autocmd.h" #include "nvim/buffer.h" #include "nvim/charset.h" #include "nvim/cursor.h" #include "nvim/drawscreen.h" #include "nvim/edit.h" #include "nvim/eval.h" +#include "nvim/eval/typval.h" +#include "nvim/eval/typval_defs.h" +#include "nvim/eval/window.h" #include "nvim/ex_cmds.h" #include "nvim/ex_cmds2.h" +#include "nvim/ex_cmds_defs.h" #include "nvim/ex_docmd.h" #include "nvim/ex_eval.h" #include "nvim/ex_getln.h" #include "nvim/fileio.h" #include "nvim/fold.h" +#include "nvim/gettext.h" +#include "nvim/globals.h" #include "nvim/help.h" +#include "nvim/highlight_defs.h" #include "nvim/highlight_group.h" +#include "nvim/macros.h" #include "nvim/mark.h" #include "nvim/mbyte.h" +#include "nvim/memfile_defs.h" #include "nvim/memline.h" #include "nvim/memory.h" #include "nvim/message.h" @@ -35,14 +49,16 @@ #include "nvim/normal.h" #include "nvim/option.h" #include "nvim/optionstr.h" +#include "nvim/os/fs_defs.h" #include "nvim/os/input.h" #include "nvim/os/os.h" -#include "nvim/os_unix.h" #include "nvim/path.h" +#include "nvim/pos.h" #include "nvim/quickfix.h" #include "nvim/regexp.h" #include "nvim/search.h" #include "nvim/strings.h" +#include "nvim/types.h" #include "nvim/ui.h" #include "nvim/vim.h" #include "nvim/window.h" @@ -176,6 +192,7 @@ enum { QF_NOMEM = 3, QF_IGNORE_LINE = 4, QF_MULTISCAN = 5, + QF_ABORT = 6, }; /// State information used to parse lines and add entries to a quickfix/location @@ -336,8 +353,7 @@ static const size_t LINE_MAXLEN = 4096; static struct fmtpattern { char convchar; char *pattern; -} fmt_pat[FMT_PATTERNS] = -{ +} fmt_pat[FMT_PATTERNS] = { { 'f', ".\\+" }, // only used when at end { 'n', "\\d\\+" }, // 1 { 'l', "\\d\\+" }, // 2 @@ -368,9 +384,9 @@ static char *efmpat_to_regpat(const char *efmpat, char *regpat, efm_T *efminfo, return NULL; } if ((idx && idx < FMT_PATTERN_R - && vim_strchr("DXOPQ", efminfo->prefix) != NULL) + && vim_strchr("DXOPQ", (uint8_t)efminfo->prefix) != NULL) || (idx == FMT_PATTERN_R - && vim_strchr("OPQ", efminfo->prefix) == NULL)) { + && vim_strchr("OPQ", (uint8_t)efminfo->prefix) == NULL)) { semsg(_("E373: Unexpected %%%c in format string"), *efmpat); return NULL; } @@ -452,10 +468,10 @@ static char *scanf_fmt_to_regpat(const char **pefmp, const char *efm, int len, c static const char *efm_analyze_prefix(const char *efmp, efm_T *efminfo) FUNC_ATTR_NONNULL_ALL { - if (vim_strchr("+-", *efmp) != NULL) { + if (vim_strchr("+-", (uint8_t)(*efmp)) != NULL) { efminfo->flags = *efmp++; } - if (vim_strchr("DXAEWINCZGOPQ", *efmp) != NULL) { + if (vim_strchr("DXAEWINCZGOPQ", (uint8_t)(*efmp)) != NULL) { efminfo->prefix = *efmp; } else { semsg(_("E376: Invalid %%%c in format string prefix"), *efmp); @@ -494,7 +510,7 @@ static int efm_to_regpat(const char *efm, int len, efm_T *fmt_ptr, char *regpat) if (ptr == NULL) { return FAIL; } - } else if (vim_strchr("%\\.^$~[", *efmp) != NULL) { + } else if (vim_strchr("%\\.^$~[", (uint8_t)(*efmp)) != NULL) { *ptr++ = *efmp; // regexp magic characters } else if (*efmp == '#') { *ptr++ = '*'; @@ -514,7 +530,7 @@ static int efm_to_regpat(const char *efm, int len, efm_T *fmt_ptr, char *regpat) } else { // copy normal character if (*efmp == '\\' && efmp + 1 < efm + len) { efmp++; - } else if (vim_strchr(".*^$~[", *efmp) != NULL) { + } else if (vim_strchr(".*^$~[", (uint8_t)(*efmp)) != NULL) { *ptr++ = '\\'; // escape regexp atoms } if (*efmp) { @@ -562,7 +578,7 @@ static size_t efm_regpat_bufsz(char *efm) } /// Return the length of a 'errorformat' option part (separated by ","). -static int efm_option_part_len(char *efm) +static int efm_option_part_len(const char *efm) { int len; @@ -657,7 +673,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 = (char *)IObuff; + state->linebuf = IObuff; state->linelen = len; } memcpy(state->linebuf, p_str, state->linelen); @@ -692,12 +708,12 @@ static int qf_get_next_list_line(qfstate_T *state) if (len > IOSIZE - 2) { state->linebuf = qf_grow_linebuf(state, len); } else { - state->linebuf = (char *)IObuff; + state->linebuf = IObuff; state->linelen = len; } - STRLCPY(state->linebuf, TV_LIST_ITEM_TV(p_li)->vval.v_string, - state->linelen + 1); + xstrlcpy(state->linebuf, TV_LIST_ITEM_TV(p_li)->vval.v_string, + state->linelen + 1); state->p_li = TV_LIST_ITEM_NEXT(state->p_list, p_li); return QF_OK; @@ -717,10 +733,10 @@ static int qf_get_next_buf_line(qfstate_T *state) if (len > IOSIZE - 2) { state->linebuf = qf_grow_linebuf(state, len); } else { - state->linebuf = (char *)IObuff; + state->linebuf = IObuff; state->linelen = len; } - STRLCPY(state->linebuf, p_buf, state->linelen + 1); + xstrlcpy(state->linebuf, p_buf, state->linelen + 1); return QF_OK; } @@ -730,7 +746,7 @@ static int qf_get_next_file_line(qfstate_T *state) { retry: errno = 0; - if (fgets((char *)IObuff, IOSIZE, state->fd) == NULL) { + if (fgets(IObuff, IOSIZE, state->fd) == NULL) { if (errno == EINTR) { goto retry; } @@ -780,7 +796,7 @@ retry: // The current line is longer than LINE_MAXLEN, continue reading but // discard everything until EOL or EOF is reached. errno = 0; - if (fgets((char *)IObuff, IOSIZE, state->fd) == NULL) { + if (fgets(IObuff, IOSIZE, state->fd) == NULL) { if (errno == EINTR) { continue; } @@ -794,15 +810,15 @@ retry: state->linebuf = state->growbuf; state->linelen = growbuflen; } else { - state->linebuf = (char *)IObuff; + state->linebuf = IObuff; } // Convert a line if it contains a non-ASCII character - if (state->vc.vc_type != CONV_NONE && has_non_ascii((char_u *)state->linebuf)) { + if (state->vc.vc_type != CONV_NONE && has_non_ascii(state->linebuf)) { char *line = string_convert(&state->vc, state->linebuf, &state->linelen); if (line != NULL) { if (state->linelen < IOSIZE) { - STRLCPY(state->linebuf, line, state->linelen + 1); + xstrlcpy(state->linebuf, line, state->linelen + 1); xfree(line); } else { xfree(state->growbuf); @@ -852,7 +868,7 @@ static int qf_get_nextline(qfstate_T *state) #endif } - remove_bom((char_u *)state->linebuf); + remove_bom(state->linebuf); return QF_OK; } @@ -909,7 +925,7 @@ restofline: // match or no match. fields->valid = true; for (; fmt_ptr != NULL; fmt_ptr = fmt_ptr->next) { - idx = (char_u)fmt_ptr->prefix; + idx = (uint8_t)fmt_ptr->prefix; status = qf_parse_get_fields(linebuf, linelen, fmt_ptr, fields, qfl->qf_multiline, qfl->qf_multiscan, &tail); @@ -1058,6 +1074,7 @@ static int qf_init_ext(qf_info_T *qi, int qf_idx, const char *restrict efile, bu { qfstate_T state = { 0 }; qffields_T fields = { 0 }; + qfline_T *old_last = NULL; static efm_T *fmt_first = NULL; static char *last_efm = NULL; int retval = -1; // default: return error flag @@ -1071,7 +1088,6 @@ static int qf_init_ext(qf_info_T *qi, int qf_idx, const char *restrict efile, bu } qf_list_T *qfl; - qfline_T *old_last = NULL; bool adding = false; if (newlist || qf_idx == qi->qf_listcount) { // make place for a new list @@ -1174,13 +1190,15 @@ static void qf_store_title(qf_list_T *qfl, const char *title) { XFREE_CLEAR(qfl->qf_title); - if (title != NULL) { - size_t len = strlen(title) + 1; - char *p = xmallocz(len); - - qfl->qf_title = p; - STRLCPY(p, title, len + 1); + if (title == NULL) { + return; } + + size_t len = strlen(title) + 1; + char *p = xmallocz(len); + + qfl->qf_title = p; + xstrlcpy(p, title, len + 1); } /// The title of a quickfix/location list is set, by default, to the command @@ -1323,9 +1341,9 @@ static int qf_parse_fmt_t(regmatch_T *rmp, int midx, qffields_T *fields) 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 *linebuf, size_t linelen, qffields_T *fields) +/// Copy a non-error line into the error string. Return the matched line in +/// "fields->errmsg". +static int copy_nonerror_line(const char *linebuf, size_t linelen, qffields_T *fields) FUNC_ATTR_NONNULL_ALL { if (linelen >= fields->errmsglen) { @@ -1333,7 +1351,10 @@ static void qf_parse_fmt_plus(const char *linebuf, size_t linelen, qffields_T *f fields->errmsg = xrealloc(fields->errmsg, linelen + 1); fields->errmsglen = linelen + 1; } - STRLCPY(fields->errmsg, linebuf, linelen + 1); + // copy whole line to error message + xstrlcpy(fields->errmsg, linebuf, linelen + 1); + + return QF_OK; } /// Parse the match for error message ('%m') pattern in regmatch. @@ -1349,7 +1370,7 @@ static int qf_parse_fmt_m(regmatch_T *rmp, int midx, qffields_T *fields) fields->errmsg = xrealloc(fields->errmsg, len + 1); fields->errmsglen = len + 1; } - STRLCPY(fields->errmsg, rmp->startp[midx], len + 1); + xstrlcpy(fields->errmsg, rmp->startp[midx], len + 1); return QF_OK; } @@ -1464,7 +1485,7 @@ static int qf_parse_match(char *linebuf, size_t linelen, efm_T *fmt_ptr, regmatc if ((idx == 'C' || idx == 'Z') && !qf_multiline) { return QF_FAIL; } - if (vim_strchr("EWIN", idx) != NULL) { + if (vim_strchr("EWIN", (uint8_t)idx) != NULL) { fields->type = idx; } else { fields->type = 0; @@ -1480,7 +1501,7 @@ static int qf_parse_match(char *linebuf, size_t linelen, efm_T *fmt_ptr, regmatc status = qf_parse_fmt_f(regmatch, midx, fields, idx); } else if (i == FMT_PATTERN_M) { if (fmt_ptr->flags == '+' && !qf_multiscan) { // %+ - qf_parse_fmt_plus(linebuf, linelen, fields); + status = copy_nonerror_line(linebuf, linelen, fields); } else if (midx > 0) { // %m status = qf_parse_fmt_m(regmatch, midx, fields); } @@ -1505,7 +1526,7 @@ static int qf_parse_match(char *linebuf, size_t linelen, efm_T *fmt_ptr, regmatc 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) { - if (qf_multiscan && vim_strchr("OPQ", fmt_ptr->prefix) == NULL) { + if (qf_multiscan && vim_strchr("OPQ", (uint8_t)fmt_ptr->prefix) == NULL) { return QF_FAIL; } @@ -1588,15 +1609,8 @@ static int qf_parse_line_nomatch(char *linebuf, size_t linelen, qffields_T *fiel fields->namebuf[0] = NUL; // no match found, remove file name fields->lnum = 0; // don't jump to this line fields->valid = false; - if (linelen >= fields->errmsglen) { - // linelen + null terminator - fields->errmsg = xrealloc(fields->errmsg, linelen + 1); - fields->errmsglen = linelen + 1; - } - // copy whole line to error message - STRLCPY(fields->errmsg, linebuf, linelen + 1); - return QF_OK; + return copy_nonerror_line(linebuf, linelen, fields); } /// Parse multi-line error format prefixes (%C and %Z) @@ -1672,14 +1686,16 @@ int qf_stack_get_bufnr(void) 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; - } + if (qi->qf_bufnr == INVALID_QFBUFNR) { + return; + } + + 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; } } @@ -1790,7 +1806,7 @@ void check_quickfix_busy(void) /// @param type type character /// @param valid valid entry /// -/// @returns QF_OK or QF_FAIL. +/// @return QF_OK on success or QF_FAIL on failure. static int qf_add_entry(qf_list_T *qfl, char *dir, char *fname, char *module, int bufnum, char *mesg, linenr_T lnum, linenr_T end_lnum, int col, int end_col, char vis_col, char *pattern, int nr, char type, char valid) @@ -2063,7 +2079,7 @@ static int qf_get_fnum(qf_list_T *qfl, char *directory, char *fname) } slash_adjust(fname); #endif - if (directory != NULL && !vim_isAbsName((char_u *)fname)) { + if (directory != NULL && !vim_isAbsName(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 @@ -2116,7 +2132,7 @@ static char *qf_push_dir(char *dirbuf, struct dir_stack_T **stackptr, bool is_fi *stackptr = ds_new; // store directory on the stack - if (vim_isAbsName((char_u *)dirbuf) + if (vim_isAbsName(dirbuf) || (*stackptr)->next == NULL || is_file_stack) { (*stackptr)->dirname = xstrdup(dirbuf); @@ -2153,12 +2169,11 @@ static char *qf_push_dir(char *dirbuf, struct dir_stack_T **stackptr, bool is_fi if ((*stackptr)->dirname != NULL) { return (*stackptr)->dirname; - } else { - ds_ptr = *stackptr; - *stackptr = (*stackptr)->next; - xfree(ds_ptr); - return NULL; } + ds_ptr = *stackptr; + *stackptr = (*stackptr)->next; + xfree(ds_ptr); + return NULL; } // pop dirbuf from the directory stack and return previous directory or NULL if @@ -2686,6 +2701,10 @@ static int qf_jump_to_usable_window(int qf_fnum, bool newwin, int *opened_window } /// Edit the selected file or help file. +/// @return OK if successfully edited the file. +/// FAIL on failing to open the buffer. +/// QF_ABORT if the quickfix/location list was freed by an autocmd +/// when opening the buffer. static int qf_jump_edit_buffer(qf_info_T *qi, qfline_T *qf_ptr, int forceit, int prev_winid, int *opened_window) { @@ -2702,11 +2721,10 @@ static int qf_jump_edit_buffer(qf_info_T *qi, qfline_T *qf_ptr, int forceit, int if (!can_abandon(curbuf, forceit)) { no_write_message(); return FAIL; - } else { - retval = do_ecmd(qf_ptr->qf_fnum, NULL, NULL, NULL, (linenr_T)1, - ECMD_HIDE + ECMD_SET_HELP, - prev_winid == curwin->handle ? curwin : NULL); } + retval = do_ecmd(qf_ptr->qf_fnum, NULL, NULL, NULL, (linenr_T)1, + ECMD_HIDE + ECMD_SET_HELP, + prev_winid == curwin->handle ? curwin : NULL); } else { retval = buflist_getfile(qf_ptr->qf_fnum, (linenr_T)1, GETF_SETMARK | GETF_SWITCH, forceit); @@ -2719,13 +2737,13 @@ static int qf_jump_edit_buffer(qf_info_T *qi, qfline_T *qf_ptr, int forceit, int if (wp == NULL && curwin->w_llist != qi) { emsg(_("E924: Current window was closed")); *opened_window = false; - return NOTDONE; + return QF_ABORT; } } if (qfl_type == QFLT_QUICKFIX && !qflist_valid(NULL, save_qfid)) { emsg(_(e_current_quickfix_list_was_changed)); - return NOTDONE; + return QF_ABORT; } if (old_qf_curlist != qi->qf_curlist // -V560 @@ -2736,7 +2754,7 @@ static int qf_jump_edit_buffer(qf_info_T *qi, qfline_T *qf_ptr, int forceit, int } else { emsg(_(e_current_location_list_was_changed)); } - return NOTDONE; + return QF_ABORT; } return retval; @@ -2771,7 +2789,7 @@ static void qf_jump_goto_line(linenr_T qf_lnum, int qf_col, char qf_viscol, char // Move the cursor to the first line in the buffer pos_T save_cursor = curwin->w_cursor; curwin->w_cursor.lnum = 0; - if (!do_search(NULL, '/', '/', (char_u *)qf_pattern, (long)1, SEARCH_KEEP, NULL)) { + if (!do_search(NULL, '/', '/', qf_pattern, (long)1, SEARCH_KEEP, NULL)) { curwin->w_cursor = save_cursor; } } @@ -2789,13 +2807,13 @@ static void qf_jump_print_msg(qf_info_T *qi, int qf_index, qfline_T *qf_ptr, buf update_screen(); } } - snprintf((char *)IObuff, IOSIZE, _("(%d of %d)%s%s: "), qf_index, + snprintf(IObuff, IOSIZE, _("(%d of %d)%s%s: "), qf_index, qf_get_curlist(qi)->qf_count, qf_ptr->qf_cleared ? _(" (line deleted)") : "", qf_types(qf_ptr->qf_type, qf_ptr->qf_nr)); // Add the message, skipping leading whitespace and newlines. int len = (int)strlen(IObuff); - qf_fmt_text(skipwhite(qf_ptr->qf_text), (char *)IObuff + len, IOSIZE - len); + qf_fmt_text(skipwhite(qf_ptr->qf_text), 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 @@ -2807,16 +2825,17 @@ static void qf_jump_print_msg(qf_info_T *qi, int qf_index, qfline_T *qf_ptr, buf msg_scroll = false; } msg_ext_set_kind("quickfix"); - msg_attr_keep((char *)IObuff, 0, true, false); + msg_attr_keep(IObuff, 0, true, false); msg_scroll = (int)i; } /// Find a usable window for opening a file from the quickfix/location list. If /// a window is not found then open a new window. If 'newwin' is true, then open /// a new window. -/// Returns OK if successfully jumped or opened a window. Returns FAIL if not -/// able to jump/open a window. Returns NOTDONE if a file is not associated -/// with the entry. +/// @return OK if successfully jumped or opened a window. +/// FAIL if not able to jump/open a window. +/// NOTDONE if a file is not associated with the entry. +/// QF_ABORT if the quickfix/location list was modified by an autocmd. static int qf_jump_open_window(qf_info_T *qi, qfline_T *qf_ptr, bool newwin, int *opened_window) { qf_list_T *qfl = qf_get_curlist(qi); @@ -2838,7 +2857,7 @@ static int qf_jump_open_window(qf_info_T *qi, qfline_T *qf_ptr, bool newwin, int } else { emsg(_(e_current_location_list_was_changed)); } - return FAIL; + return QF_ABORT; } // If currently in the quickfix window, find another window to show the @@ -2863,7 +2882,7 @@ static int qf_jump_open_window(qf_info_T *qi, qfline_T *qf_ptr, bool newwin, int } else { emsg(_(e_current_location_list_was_changed)); } - return FAIL; + return QF_ABORT; } return OK; @@ -2872,9 +2891,9 @@ static int qf_jump_open_window(qf_info_T *qi, qfline_T *qf_ptr, bool newwin, int /// Edit a selected file from the quickfix/location list and jump to a /// particular line/column, adjust the folds and display a message about the /// jump. -/// Returns OK on success and FAIL on failing to open the file/buffer. Returns -/// NOTDONE if the quickfix/location list is freed by an autocmd when opening -/// the file. +/// @return OK on success and FAIL on failing to open the file/buffer. +/// QF_ABORT 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, int prev_winid, int *opened_window, int openfold, int print_message) { @@ -2968,14 +2987,19 @@ static void qf_jump_newwin(qf_info_T *qi, int dir, int errornr, int forceit, boo if (retval == FAIL) { goto failed; } + if (retval == QF_ABORT) { + qi = NULL; + qf_ptr = NULL; + goto theend; + } if (retval == NOTDONE) { goto theend; } 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 + if (retval == QF_ABORT) { + // Quickfix/location list was modified by an autocmd qi = NULL; qf_ptr = NULL; } @@ -3019,7 +3043,7 @@ static void qf_list_entry(qfline_T *qfp, int qf_idx, bool cursel) { char *fname = NULL; if (qfp->qf_module != NULL && *qfp->qf_module != NUL) { - vim_snprintf((char *)IObuff, IOSIZE, "%2d %s", qf_idx, qfp->qf_module); + vim_snprintf(IObuff, IOSIZE, "%2d %s", qf_idx, qfp->qf_module); } else { buf_T *buf; if (qfp->qf_fnum != 0 @@ -3030,9 +3054,9 @@ static void qf_list_entry(qfline_T *qfp, int qf_idx, bool cursel) } } if (fname == NULL) { - snprintf((char *)IObuff, IOSIZE, "%2d", qf_idx); + snprintf(IObuff, IOSIZE, "%2d", qf_idx); } else { - vim_snprintf((char *)IObuff, IOSIZE, "%2d %s", qf_idx, fname); + vim_snprintf(IObuff, IOSIZE, "%2d %s", qf_idx, fname); } } @@ -3057,7 +3081,7 @@ static void qf_list_entry(qfline_T *qfp, int qf_idx, bool cursel) } msg_putchar('\n'); - msg_outtrans_attr((char *)IObuff, cursel ? HL_ATTR(HLF_QFL) : qfFileAttr); + msg_outtrans_attr(IObuff, cursel ? HL_ATTR(HLF_QFL) : qfFileAttr); if (qfp->qf_lnum != 0) { msg_puts_attr(":", qfSepAttr); @@ -3065,13 +3089,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, (char *)IObuff, IOSIZE); + qf_range_text(qfp, IObuff, IOSIZE); } - vim_snprintf((char *)IObuff + strlen(IObuff), IOSIZE, "%s", qf_types(qfp->qf_type, qfp->qf_nr)); + vim_snprintf(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, (char *)IObuff, IOSIZE); + qf_fmt_text(qfp->qf_pattern, IObuff, IOSIZE); msg_puts((const char *)IObuff); msg_puts_attr(":", qfSepAttr); } @@ -3148,15 +3172,15 @@ void qf_list(exarg_T *eap) // Get the attributes for the different quickfix highlight items. Note // that this depends on syntax items defined in the qf.vim syntax file - qfFileAttr = syn_name2attr((char_u *)"qfFileName"); + qfFileAttr = syn_name2attr("qfFileName"); if (qfFileAttr == 0) { qfFileAttr = HL_ATTR(HLF_D); } - qfSepAttr = syn_name2attr((char_u *)"qfSeparator"); + qfSepAttr = syn_name2attr("qfSeparator"); if (qfSepAttr == 0) { qfSepAttr = HL_ATTR(HLF_D); } - qfLineAttr = syn_name2attr((char_u *)"qfLineNr"); + qfLineAttr = syn_name2attr("qfLineNr"); if (qfLineAttr == 0) { qfLineAttr = HL_ATTR(HLF_N); } @@ -3461,12 +3485,10 @@ void qf_view_result(bool split) { qf_info_T *qi = &ql_info; - if (!bt_quickfix(curbuf)) { - return; - } if (IS_LL_WINDOW(curwin)) { qi = GET_LOC_LIST(curwin); } + if (qf_list_empty(qf_get_curlist(qi))) { emsg(_(e_no_errors)); return; @@ -3832,10 +3854,11 @@ static buf_T *qf_find_buf(qf_info_T *qi) } /// Process the 'quickfixtextfunc' option value. -/// @return OK or FAIL -int qf_process_qftf_option(void) +void qf_process_qftf_option(char **errmsg) { - return option_set_callback_func(p_qftf, &qftf_cb); + if (option_set_callback_func(p_qftf, &qftf_cb) == FAIL) { + *errmsg = e_invarg; + } } /// Update the w:quickfix_title variable in the quickfix/location list window in @@ -3860,48 +3883,61 @@ static void qf_update_buffer(qf_info_T *qi, qfline_T *old_last) { // Check if a buffer for the quickfix list exists. Update it. buf_T *buf = qf_find_buf(qi); - if (buf != NULL) { - linenr_T old_line_count = buf->b_ml.ml_line_count; - int qf_winid = 0; - - win_T *win; - if (IS_LL_STACK(qi)) { - if (curwin->w_llist == qi) { - win = curwin; - } else { - win = qf_find_win_with_loclist(qi); - if (win == NULL) { - return; - } + if (buf == NULL) { + return; + } + + linenr_T old_line_count = buf->b_ml.ml_line_count; + int qf_winid = 0; + + win_T *win; + if (IS_LL_STACK(qi)) { + if (curwin->w_llist == qi) { + win = curwin; + } else { + // Find the file window (non-quickfix) with this location list + win = qf_find_win_with_loclist(qi); + if (win == NULL) { + // File window is not found. Find the location list window. + win = qf_find_win(qi); + } + if (win == NULL) { + return; } - qf_winid = (int)win->handle; } + qf_winid = (int)win->handle; + } - aco_save_T aco; + // autocommands may cause trouble + incr_quickfix_busy(); - if (old_last == NULL) { - // set curwin/curbuf to buf and save a few things - aucmd_prepbuf(&aco, buf); - } + aco_save_T aco; - qf_update_win_titlevar(qi); + if (old_last == NULL) { + // set curwin/curbuf to buf and save a few things + aucmd_prepbuf(&aco, buf); + } - qf_fill_buffer(qf_get_curlist(qi), buf, old_last, qf_winid); - buf_inc_changedtick(buf); + qf_update_win_titlevar(qi); - if (old_last == NULL) { - (void)qf_win_pos_update(qi, 0); + qf_fill_buffer(qf_get_curlist(qi), buf, old_last, qf_winid); + buf_inc_changedtick(buf); - // restore curwin/curbuf and a few other things - aucmd_restbuf(&aco); - } + if (old_last == NULL) { + (void)qf_win_pos_update(qi, 0); - // Only redraw when added lines are visible. This avoids flickering when - // the added lines are not visible. - if ((win = qf_find_win(qi)) != NULL && old_line_count < win->w_botline) { - redraw_buf_later(buf, UPD_NOT_VALID); - } + // restore curwin/curbuf and a few other things + aucmd_restbuf(&aco); + } + + // Only redraw when added lines are visible. This avoids flickering when + // the added lines are not visible. + if ((win = qf_find_win(qi)) != NULL && old_line_count < win->w_botline) { + redraw_buf_later(buf, UPD_NOT_VALID); } + + // always called after incr_quickfix_busy() + decr_quickfix_busy(); } // Add an error line to the quickfix buffer. @@ -3912,31 +3948,31 @@ static int qf_buf_add_line(qf_list_T *qfl, buf_T *buf, linenr_T lnum, const qfli // If the 'quickfixtextfunc' function returned a non-empty custom string // for this entry, then use it. if (qftf_str != NULL && *qftf_str != NUL) { - STRLCPY(IObuff, qftf_str, IOSIZE); + xstrlcpy(IObuff, qftf_str, IOSIZE); } else { buf_T *errbuf; int len; if (qfp->qf_module != NULL) { - STRLCPY(IObuff, qfp->qf_module, IOSIZE); + xstrlcpy(IObuff, qfp->qf_module, IOSIZE); len = (int)strlen(IObuff); } else if (qfp->qf_fnum != 0 && (errbuf = buflist_findnr(qfp->qf_fnum)) != NULL && errbuf->b_fname != NULL) { if (qfp->qf_type == 1) { // :helpgrep - STRLCPY(IObuff, path_tail(errbuf->b_fname), IOSIZE); + xstrlcpy(IObuff, path_tail(errbuf->b_fname), IOSIZE); } else { // Shorten the file name if not done already. // For optimization, do this only for the first entry in a // buffer. if (first_bufline && (errbuf->b_sfname == NULL - || path_is_absolute((char_u *)errbuf->b_sfname))) { + || path_is_absolute(errbuf->b_sfname))) { if (*dirname == NUL) { - os_dirname((char_u *)dirname, MAXPATHL); + os_dirname(dirname, MAXPATHL); } - shorten_buf_fname(errbuf, (char_u *)dirname, false); + shorten_buf_fname(errbuf, dirname, false); } - STRLCPY(IObuff, errbuf->b_fname, IOSIZE); + xstrlcpy(IObuff, errbuf->b_fname, IOSIZE); } len = (int)strlen(IObuff); } else { @@ -3946,14 +3982,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, (char *)IObuff + len, IOSIZE - len); + qf_range_text(qfp, IObuff + len, IOSIZE - len); len += (int)strlen(IObuff + len); - snprintf((char *)IObuff + len, (size_t)(IOSIZE - len), "%s", qf_types(qfp->qf_type, - qfp->qf_nr)); + snprintf(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, (char *)IObuff + len, IOSIZE - len); + qf_fmt_text(qfp->qf_pattern, IObuff + len, IOSIZE - len); len += (int)strlen(IObuff + len); } if (len < IOSIZE - 2) { @@ -3965,11 +4001,11 @@ 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, - (char *)IObuff + len, IOSIZE - len); + IObuff + len, IOSIZE - len); } - if (ml_append_buf(buf, lnum, (char_u *)IObuff, - (colnr_T)STRLEN(IObuff) + 1, false) == FAIL) { + if (ml_append_buf(buf, lnum, IObuff, + (colnr_T)strlen(IObuff) + 1, false) == FAIL) { return FAIL; } return OK; @@ -3981,6 +4017,12 @@ static list_T *call_qftf_func(qf_list_T *qfl, int qf_winid, long start_idx, long { Callback *cb = &qftf_cb; list_T *qftf_list = NULL; + static bool recursive = false; + + if (recursive) { + return NULL; // this doesn't work properly recursively + } + recursive = true; // 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 @@ -4014,6 +4056,7 @@ static list_T *call_qftf_func(qf_list_T *qfl, int qf_winid, long start_idx, long tv_dict_unref(dict); } + recursive = false; return qftf_list; } @@ -4040,7 +4083,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) { + if (qfl != NULL && qfl->qf_start != NULL) { char dirname[MAXPATHL]; *dirname = NUL; @@ -4152,14 +4195,16 @@ static int qf_id2nr(const qf_info_T *const qi, const unsigned qfid) static int qf_restore_list(qf_info_T *qi, unsigned save_qfid) FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT { - if (qf_get_curlist(qi)->qf_id != save_qfid) { - const int curlist = qf_id2nr(qi, save_qfid); - if (curlist < 0) { - // list is not present - return FAIL; - } - qi->qf_curlist = curlist; + if (qf_get_curlist(qi)->qf_id == save_qfid) { + return OK; + } + + const int curlist = qf_id2nr(qi, save_qfid); + if (curlist < 0) { + // list is not present + return FAIL; } + qi->qf_curlist = curlist; return OK; } @@ -4213,12 +4258,12 @@ static char *make_get_auname(cmdidx_T cmdidx) 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; + size_t len = strlen(p_shq) * 2 + strlen(makecmd) + 1; if (*p_sp != NUL) { len += strlen(p_sp) + strlen(fname) + 3; } char *const cmd = xmalloc(len); - snprintf(cmd, len, "%s%s%s", (char *)p_shq, (char *)makecmd, (char *)p_shq); + snprintf(cmd, len, "%s%s%s", p_shq, (char *)makecmd, p_shq); // If 'shellpipe' empty: don't redirect to 'errorfile'. if (*p_sp != NUL) { @@ -4275,10 +4320,17 @@ void ex_make(exarg_T *eap) incr_quickfix_busy(); - int res = qf_init(wp, fname, (eap->cmdidx != CMD_make - && eap->cmdidx != CMD_lmake) ? p_gefm : p_efm, - (eap->cmdidx != CMD_grepadd && eap->cmdidx != CMD_lgrepadd), - qf_cmdtitle(*eap->cmdlinep), enc); + char *errorformat = p_efm; + bool newlist = true; + + if (eap->cmdidx != CMD_make && eap->cmdidx != CMD_lmake) { + errorformat = p_gefm; + } + if (eap->cmdidx == CMD_grepadd || eap->cmdidx == CMD_lgrepadd) { + newlist = false; + } + + int res = qf_init(wp, fname, errorformat, newlist, qf_cmdtitle(*eap->cmdlinep), enc); qf_info_T *qi = &ql_info; if (wp != NULL) { @@ -4997,8 +5049,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, (char *)p_ef, p_efm, (eap->cmdidx != CMD_caddfile - && eap->cmdidx != CMD_laddfile), + int res = qf_init(wp, 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); @@ -5062,7 +5114,7 @@ static void vgr_init_regmatch(regmmatch_T *regmatch, char *s) emsg(_(e_noprevre)); return; } - regmatch->regprog = vim_regcomp((char *)last_search_pat(), RE_MAGIC); + regmatch->regprog = vim_regcomp(last_search_pat(), RE_MAGIC); } else { regmatch->regprog = vim_regcomp(s, RE_MAGIC); } @@ -5120,11 +5172,10 @@ static bool vgr_qflist_valid(win_T *wp, qf_info_T *qi, unsigned qfid, char *titl // An autocmd has freed the location list emsg(_(e_current_location_list_was_changed)); return false; - } else { - // Quickfix list is not found, create a new one. - qf_new_list(qi, title); - return true; } + // Quickfix list is not found, create a new one. + qf_new_list(qi, title); + return true; } if (qf_restore_list(qi, qfid) == FAIL) { return false; @@ -5188,8 +5239,7 @@ static bool vgr_match_buflines(qf_list_T *qfl, char *fname, buf_T *buf, char *sp 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) { + while (fuzzy_match(str + col, spat, false, &score, matches, (int)sz) > 0) { // Pass the buffer number so that it gets used even for a // dummy buffer, unless duplicate_name is set, then the // buffer will be wiped out below. @@ -5236,7 +5286,7 @@ static bool vgr_match_buflines(qf_list_T *qfl, char *fname, buf_T *buf, char *sp /// Jump to the first match and update the directory. 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 *first_match_buf, char *target_dir) // NOLINT(readability-non-const-parameter) { buf_T *buf = curbuf; qf_jump(qi, 0, 0, forceit); @@ -5263,7 +5313,7 @@ static bool existing_swapfile(const buf_T *buf) { if (buf->b_ml.ml_mfp != NULL && buf->b_ml.ml_mfp->mf_fname != NULL) { const char *const fname = buf->b_ml.ml_mfp->mf_fname; - const size_t len = STRLEN(fname); + const size_t len = strlen(fname); return fname[len - 1] != 'p' || fname[len - 2] != 'w'; } @@ -5305,10 +5355,8 @@ static int vgr_process_args(exarg_T *eap, vgr_args_T *args) } // Parse the list of arguments, wildcards have already been expanded. - if (get_arglist_exp(p, &args->fcount, &args->fnames, true) == FAIL) { - return FAIL; - } - if (args->fcount == 0) { + if (get_arglist_exp(p, &args->fcount, &args->fnames, true) == FAIL + || args->fcount == 0) { emsg(_(e_nomatch)); return FAIL; } @@ -5330,11 +5378,11 @@ static int vgr_process_files(win_T *wp, qf_info_T *qi, vgr_args_T *cmd_args, boo // 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); + os_dirname(dirname_start, MAXPATHL); 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]); + char *fname = path_try_shorten_fname(cmd_args->fnames[fi]); if (time(NULL) > seconds) { // Display the file name every second or so, show the user we are // working on it. @@ -5541,7 +5589,7 @@ static void restore_start_dir(char *dirname_start) { char *dirname_now = xmalloc(MAXPATHL); - os_dirname((char_u *)dirname_now, MAXPATHL); + os_dirname(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. @@ -5622,6 +5670,7 @@ static buf_T *load_dummy_buffer(char *fname, char *dirname_start, char *resultin // Restore curwin/curbuf and a few other things. aucmd_restbuf(&aco); + if (newbuf_to_wipe.br_buf != NULL && bufref_valid(&newbuf_to_wipe)) { wipe_buffer(newbuf_to_wipe.br_buf, false); } @@ -5634,7 +5683,7 @@ static buf_T *load_dummy_buffer(char *fname, char *dirname_start, char *resultin // 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((char_u *)resulting_dir, MAXPATHL); + os_dirname(resulting_dir, MAXPATHL); restore_start_dir(dirname_start); if (!bufref_valid(&newbufref)) { @@ -5696,12 +5745,14 @@ static void wipe_dummy_buffer(buf_T *buf, char *dirname_start) // 'autochdir' option have changed it. static void unload_dummy_buffer(buf_T *buf, char *dirname_start) { - if (curbuf != buf) { // safety check - close_buffer(NULL, buf, DOBUF_UNLOAD, false, true); - - // When autocommands/'autochdir' option changed directory: go back. - restore_start_dir(dirname_start); + if (curbuf == buf) { // safety check + return; } + + close_buffer(NULL, buf, DOBUF_UNLOAD, false, true); + + // When autocommands/'autochdir' option changed directory: go back. + restore_start_dir(dirname_start); } /// Copy the specified quickfix entry items into a new dict and append the dict @@ -5826,32 +5877,34 @@ static int qf_get_list_from_lines(dict_T *what, dictitem_T *di, dict_T *retdict) int status = FAIL; // Only a List value is supported - if (di->di_tv.v_type == VAR_LIST && di->di_tv.vval.v_list != NULL) { - char *errorformat = p_efm; - dictitem_T *efm_di; - // If errorformat is supplied then use it, otherwise use the 'efm' - // option setting - if ((efm_di = tv_dict_find(what, S_LEN("efm"))) != NULL) { - if (efm_di->di_tv.v_type != VAR_STRING - || efm_di->di_tv.vval.v_string == NULL) { - return FAIL; - } - errorformat = efm_di->di_tv.vval.v_string; - } - - list_T *l = tv_list_alloc(kListLenMayKnow); - qf_info_T *const qi = qf_alloc_stack(QFLT_INTERNAL); + if (di->di_tv.v_type != VAR_LIST || di->di_tv.vval.v_list == NULL) { + return FAIL; + } - if (qf_init_ext(qi, 0, NULL, NULL, &di->di_tv, errorformat, - true, (linenr_T)0, (linenr_T)0, NULL, NULL) > 0) { - (void)get_errorlist(qi, NULL, 0, 0, l); - qf_free(&qi->qf_lists[0]); + char *errorformat = p_efm; + dictitem_T *efm_di; + // If errorformat is supplied then use it, otherwise use the 'efm' + // option setting + if ((efm_di = tv_dict_find(what, S_LEN("efm"))) != NULL) { + if (efm_di->di_tv.v_type != VAR_STRING + || efm_di->di_tv.vval.v_string == NULL) { + return FAIL; } - xfree(qi); + errorformat = efm_di->di_tv.vval.v_string; + } + + list_T *l = tv_list_alloc(kListLenMayKnow); + qf_info_T *const qi = qf_alloc_stack(QFLT_INTERNAL); - tv_dict_add_list(retdict, S_LEN("items"), l); - status = OK; + if (qf_init_ext(qi, 0, NULL, NULL, &di->di_tv, errorformat, + true, (linenr_T)0, (linenr_T)0, NULL, NULL) > 0) { + (void)get_errorlist(qi, NULL, 0, 0, l); + qf_free(&qi->qf_lists[0]); } + xfree(qi); + + tv_dict_add_list(retdict, S_LEN("items"), l); + status = OK; return status; } @@ -6668,7 +6721,8 @@ int set_errorlist(win_T *wp, list_T *list, int action, char *title, dict_T *what return retval; } -/// Mark the context as in use for all the lists in a quickfix stack. +/// Mark the quickfix context and callback function as in use for all the lists +/// in a quickfix stack. static bool mark_quickfix_ctx(qf_info_T *qi, int copyID) { bool abort = false; @@ -6679,6 +6733,9 @@ static bool mark_quickfix_ctx(qf_info_T *qi, int copyID) && ctx->v_type != VAR_STRING && ctx->v_type != VAR_FLOAT) { abort = set_ref_in_item(ctx, copyID, NULL, NULL); } + + Callback *cb = &qi->qf_lists[i].qf_qftf_cb; + abort = abort || set_ref_in_callback(cb, copyID, NULL, NULL); } return abort; @@ -6693,6 +6750,11 @@ bool set_ref_in_quickfix(int copyID) return abort; } + abort = set_ref_in_callback(&qftf_cb, copyID, NULL, NULL); + if (abort) { + return abort; + } + FOR_ALL_TAB_WINDOWS(tp, win) { if (win->w_llist != NULL) { abort = mark_quickfix_ctx(win->w_llist, copyID); @@ -6806,8 +6868,8 @@ void ex_cbuffer(exarg_T *eap) char *qf_title = qf_cmdtitle(*eap->cmdlinep); if (buf->b_sfname) { - vim_snprintf((char *)IObuff, IOSIZE, "%s (%s)", qf_title, buf->b_sfname); - qf_title = (char *)IObuff; + vim_snprintf(IObuff, IOSIZE, "%s (%s)", qf_title, buf->b_sfname); + qf_title = IObuff; } incr_quickfix_busy(); @@ -6885,43 +6947,45 @@ void ex_cexpr(exarg_T *eap) // Evaluate the expression. When the result is a string or a list we can // use it to fill the errorlist. typval_T tv; - if (eval0(eap->arg, &tv, &eap->nextcmd, true) != FAIL) { - if ((tv.v_type == VAR_STRING && tv.vval.v_string != NULL) - || tv.v_type == VAR_LIST) { - incr_quickfix_busy(); - int res = qf_init_ext(qi, qi->qf_curlist, NULL, NULL, &tv, p_efm, - (eap->cmdidx != CMD_caddexpr - && eap->cmdidx != CMD_laddexpr), - (linenr_T)0, (linenr_T)0, - qf_cmdtitle(*eap->cmdlinep), NULL); - if (qf_stack_empty(qi)) { - decr_quickfix_busy(); - goto cleanup; - } - if (res >= 0) { - qf_list_changed(qf_get_curlist(qi)); - } - // 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); - } - // Jump to the first error for a new list and if autocmds didn't - // free the list. - if (res > 0 - && (eap->cmdidx == CMD_cexpr || eap->cmdidx == CMD_lexpr) - && qflist_valid(wp, save_qfid)) { - // display the first error - qf_jump_first(qi, save_qfid, eap->forceit); - } + if (eval0(eap->arg, &tv, &eap->nextcmd, true) == FAIL) { + return; + } + + if ((tv.v_type == VAR_STRING && tv.vval.v_string != NULL) + || tv.v_type == VAR_LIST) { + incr_quickfix_busy(); + int res = qf_init_ext(qi, qi->qf_curlist, NULL, NULL, &tv, p_efm, + (eap->cmdidx != CMD_caddexpr + && eap->cmdidx != CMD_laddexpr), + (linenr_T)0, (linenr_T)0, + qf_cmdtitle(*eap->cmdlinep), NULL); + if (qf_stack_empty(qi)) { decr_quickfix_busy(); - } else { - emsg(_("E777: String or List expected")); + goto cleanup; } -cleanup: - tv_clear(&tv); + if (res >= 0) { + qf_list_changed(qf_get_curlist(qi)); + } + // 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); + } + // Jump to the first error for a new list and if autocmds didn't + // free the list. + if (res > 0 + && (eap->cmdidx == CMD_cexpr || eap->cmdidx == CMD_lexpr) + && qflist_valid(wp, save_qfid)) { + // display the first error + qf_jump_first(qi, save_qfid, eap->forceit); + } + decr_quickfix_busy(); + } else { + emsg(_("E777: String or List expected")); } +cleanup: + tv_clear(&tv); } // Get the location list for ":lhelpgrep" @@ -6951,8 +7015,8 @@ static void hgr_search_file(qf_list_T *qfl, char *fname, regmatch_T *p_regmatch) } linenr_T lnum = 1; - while (!vim_fgets((char_u *)IObuff, IOSIZE, fd) && !got_int) { - char *line = (char *)IObuff; + while (!vim_fgets(IObuff, IOSIZE, fd) && !got_int) { + char *line = IObuff; if (vim_regexec(p_regmatch, line, (colnr_T)0)) { int l = (int)strlen(line); @@ -7035,9 +7099,9 @@ static void hgr_search_in_rtp(qf_list_T *qfl, regmatch_T *p_regmatch, const char // Go through all directories in 'runtimepath' char *p = p_rtp; while (*p != NUL && !got_int) { - copy_option_part(&p, (char *)NameBuff, MAXPATHL, ","); + copy_option_part(&p, NameBuff, MAXPATHL, ","); - hgr_search_files_in_dir(qfl, (char *)NameBuff, p_regmatch, (char *)lang); + hgr_search_files_in_dir(qfl, NameBuff, p_regmatch, (char *)lang); } } @@ -7045,7 +7109,7 @@ static void hgr_search_in_rtp(qf_list_T *qfl, regmatch_T *p_regmatch, const char void ex_helpgrep(exarg_T *eap) { qf_info_T *qi = &ql_info; - char *au_name = NULL; + char *au_name = NULL; switch (eap->cmdidx) { case CMD_helpgrep: @@ -7065,6 +7129,7 @@ void ex_helpgrep(exarg_T *eap) bool updated = false; // Make 'cpoptions' empty, the 'l' flag should not be used here. char *const save_cpo = p_cpo; + const bool save_cpo_allocated = is_option_allocated("cpo"); p_cpo = empty_option; bool new_qi = false; @@ -7104,7 +7169,9 @@ void ex_helpgrep(exarg_T *eap) if (*p_cpo == NUL) { set_option_value_give_err("cpo", 0L, save_cpo, 0); } - free_string_option(save_cpo); + if (save_cpo_allocated) { + free_string_option(save_cpo); + } } if (updated) { @@ -7139,7 +7206,9 @@ void ex_helpgrep(exarg_T *eap) if (new_qi) { ll_free_all(&qi); } - } else if (curwin->w_llist == NULL) { + } else if (curwin->w_llist == NULL && new_qi) { + // current window didn't have a location list associated with it + // before. Associate the new location list now. curwin->w_llist = qi; } } |