diff options
Diffstat (limited to 'src/nvim/quickfix.c')
-rw-r--r-- | src/nvim/quickfix.c | 484 |
1 files changed, 303 insertions, 181 deletions
diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c index a19e98725a..ba2f2ba969 100644 --- a/src/nvim/quickfix.c +++ b/src/nvim/quickfix.c @@ -82,6 +82,7 @@ struct qfline_S { /// created using setqflist()/setloclist() with a title and/or user context /// information and entries can be added later using setqflist()/setloclist(). typedef struct qf_list_S { + unsigned qf_id; ///< Unique identifier for this list qfline_T *qf_start; ///< pointer to the first error qfline_T *qf_last; ///< pointer to the last error qfline_T *qf_ptr; ///< pointer to the current error @@ -91,6 +92,14 @@ typedef struct qf_list_S { char_u *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 + + struct dir_stack_T *qf_dir_stack; + char_u *qf_directory; + struct dir_stack_T *qf_file_stack; + char_u *qf_currfile; + bool qf_multiline; + bool qf_multiignore; + bool qf_multiscan; } qf_list_T; /// Quickfix/Location list stack definition @@ -106,18 +115,10 @@ struct qf_info_S { int qf_listcount; /* current number of lists */ int qf_curlist; /* current error list */ qf_list_T qf_lists[LISTCOUNT]; - - int qf_dir_curlist; ///< error list for qf_dir_stack - struct dir_stack_T *qf_dir_stack; - char_u *qf_directory; - struct dir_stack_T *qf_file_stack; - char_u *qf_currfile; - bool qf_multiline; - bool qf_multiignore; - bool qf_multiscan; }; -static qf_info_T ql_info; /* global quickfix list */ +static qf_info_T ql_info; // global quickfix list +static unsigned last_qf_id = 0; // Last Used quickfix list id #define FMT_PATTERNS 10 /* maximum number of % recognized */ @@ -223,9 +224,8 @@ int qf_init(win_T *wp, char_u *efile, char_u *errorformat, int newlist, qi = ll_get_or_alloc_list(wp); } - return qf_init_ext(qi, efile, curbuf, NULL, errorformat, newlist, - (linenr_T)0, (linenr_T)0, - qf_title, enc); + return qf_init_ext(qi, qi->qf_curlist, efile, curbuf, NULL, errorformat, + newlist, (linenr_T)0, (linenr_T)0, qf_title, enc); } // Maximum number of bytes allowed per line while reading an errorfile. @@ -712,8 +712,8 @@ static int qf_get_nextline(qfstate_T *state) /// Parse a line and get the quickfix fields. /// Return the QF_ status. -static int qf_parse_line(qf_info_T *qi, char_u *linebuf, size_t linelen, - efm_T *fmt_first, qffields_T *fields) +static int qf_parse_line(qf_info_T *qi, int qf_idx, char_u *linebuf, + size_t linelen, efm_T *fmt_first, qffields_T *fields) { efm_T *fmt_ptr; size_t len; @@ -721,7 +721,7 @@ static int qf_parse_line(qf_info_T *qi, char_u *linebuf, size_t linelen, int idx = 0; char_u *tail = NULL; regmatch_T regmatch; - + qf_list_T *qfl = &qi->qf_lists[qf_idx]; // Always ignore case when looking for a matching error. regmatch.rm_ic = true; @@ -740,12 +740,12 @@ static int qf_parse_line(qf_info_T *qi, char_u *linebuf, size_t linelen, restofline: for (; fmt_ptr != NULL; fmt_ptr = fmt_ptr->next) { idx = fmt_ptr->prefix; - if (qi->qf_multiscan && vim_strchr((char_u *)"OPQ", idx) == NULL) { + if (qfl->qf_multiscan && vim_strchr((char_u *)"OPQ", idx) == NULL) { continue; } fields->namebuf[0] = NUL; fields->pattern[0] = NUL; - if (!qi->qf_multiscan) { + if (!qfl->qf_multiscan) { fields->errmsg[0] = NUL; } fields->lnum = 0; @@ -759,7 +759,7 @@ restofline: int r = vim_regexec(®match, linebuf, (colnr_T)0); fmt_ptr->prog = regmatch.regprog; if (r) { - if ((idx == 'C' || idx == 'Z') && !qi->qf_multiline) { + if ((idx == 'C' || idx == 'Z') && !qfl->qf_multiline) { continue; } if (vim_strchr((char_u *)"EWI", idx) != NULL) { @@ -809,7 +809,7 @@ restofline: } fields->type = *regmatch.startp[i]; } - if (fmt_ptr->flags == '+' && !qi->qf_multiscan) { // %+ + if (fmt_ptr->flags == '+' && !qfl->qf_multiscan) { // %+ if (linelen >= fields->errmsglen) { // linelen + null terminator fields->errmsg = xrealloc(fields->errmsg, linelen + 1); @@ -877,7 +877,7 @@ restofline: break; } } - qi->qf_multiscan = false; + qfl->qf_multiscan = false; if (fmt_ptr == NULL || idx == 'D' || idx == 'X') { if (fmt_ptr != NULL) { @@ -886,13 +886,13 @@ restofline: EMSG(_("E379: Missing or empty directory name")); return QF_FAIL; } - qi->qf_directory = qf_push_dir(fields->namebuf, &qi->qf_dir_stack, - false); - if (qi->qf_directory == NULL) { + qfl->qf_directory = qf_push_dir(fields->namebuf, &qfl->qf_dir_stack, + false); + if (qfl->qf_directory == NULL) { return QF_FAIL; } } else if (idx == 'X') { // leave directory - qi->qf_directory = qf_pop_dir(&qi->qf_dir_stack); + qfl->qf_directory = qf_pop_dir(&qfl->qf_dir_stack); } } fields->namebuf[0] = NUL; // no match found, remove file name @@ -906,7 +906,7 @@ restofline: // copy whole line to error message STRLCPY(fields->errmsg, linebuf, linelen + 1); if (fmt_ptr == NULL) { - qi->qf_multiline = qi->qf_multiignore = false; + qfl->qf_multiline = qfl->qf_multiignore = false; } } else { // honor %> item @@ -915,12 +915,12 @@ restofline: } if (vim_strchr((char_u *)"AEWI", idx) != NULL) { - qi->qf_multiline = true; // start of a multi-line message - qi->qf_multiignore = false; // reset continuation + 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) { // continuation of multi-line msg - if (!qi->qf_multiignore) { - qfline_T *qfprev = qi->qf_lists[qi->qf_curlist].qf_last; + if (!qfl->qf_multiignore) { + qfline_T *qfprev = qfl->qf_last; if (qfprev == NULL) { return QF_FAIL; } @@ -945,15 +945,15 @@ restofline: } qfprev->qf_viscol = fields->use_viscol; if (!qfprev->qf_fnum) { - qfprev->qf_fnum = qf_get_fnum(qi, qi->qf_directory, - *fields->namebuf || qi->qf_directory + qfprev->qf_fnum = qf_get_fnum(qi, qf_idx, qfl->qf_directory, + *fields->namebuf || qfl->qf_directory ? fields->namebuf - : qi->qf_currfile && fields->valid - ? qi->qf_currfile : 0); + : qfl->qf_currfile && fields->valid + ? qfl->qf_currfile : 0); } } if (idx == 'Z') { - qi->qf_multiline = qi->qf_multiignore = false; + qfl->qf_multiline = qfl->qf_multiignore = false; } line_breakcheck(); @@ -963,23 +963,23 @@ restofline: fields->valid = false; if (*fields->namebuf == NUL || os_path_exists(fields->namebuf)) { if (*fields->namebuf && idx == 'P') { - qi->qf_currfile = qf_push_dir(fields->namebuf, &qi->qf_file_stack, - true); + qfl->qf_currfile = qf_push_dir(fields->namebuf, &qfl->qf_file_stack, + true); } else if (idx == 'Q') { - qi->qf_currfile = qf_pop_dir(&qi->qf_file_stack); + qfl->qf_currfile = qf_pop_dir(&qfl->qf_file_stack); } *fields->namebuf = NUL; if (tail && *tail) { STRMOVE(IObuff, skipwhite(tail)); - qi->qf_multiscan = true; + qfl->qf_multiscan = true; goto restofline; } } } if (fmt_ptr->flags == '-') { // generally exclude this line - if (qi->qf_multiline) { + if (qfl->qf_multiline) { // also exclude continuation lines - qi->qf_multiignore = true; + qfl->qf_multiignore = true; } return QF_IGNORE_LINE; } @@ -999,6 +999,7 @@ restofline: static int qf_init_ext( qf_info_T *qi, + int qf_idx, char_u *efile, buf_T *buf, typval_T *tv, @@ -1041,17 +1042,20 @@ qf_init_ext( goto qf_init_end; } - if (newlist || qi->qf_curlist == qi->qf_listcount) { + if (newlist || qf_idx == qi->qf_listcount) { // make place for a new list qf_new_list(qi, qf_title); + qf_idx = qi->qf_curlist; } else { // Adding to existing list, use last entry. adding = true; - if (qi->qf_lists[qi->qf_curlist].qf_count > 0) { - old_last = qi->qf_lists[qi->qf_curlist].qf_last; + if (qi->qf_lists[qf_idx].qf_count > 0) { + old_last = qi->qf_lists[qf_idx].qf_last; } } + qf_list_T *qfl = &qi->qf_lists[qf_idx]; + // 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; @@ -1059,18 +1063,6 @@ qf_init_ext( efm = errorformat; } - // If we are not adding or adding to another list: clear the state. - if (newlist || qi->qf_curlist != qi->qf_dir_curlist) { - qi->qf_dir_curlist = qi->qf_curlist; - qf_clean_dir_stack(&qi->qf_dir_stack); - qi->qf_directory = NULL; - qf_clean_dir_stack(&qi->qf_file_stack); - qi->qf_currfile = NULL; - qi->qf_multiline = false; - qi->qf_multiignore = false; - qi->qf_multiscan = false; - } - // If the errorformat didn't change between calls, then reuse the previously // parsed values. if (last_efm == NULL || (STRCMP(last_efm, efm) != 0)) { @@ -1120,8 +1112,8 @@ qf_init_ext( break; } - status = qf_parse_line(qi, state.linebuf, state.linelen, fmt_first, - &fields); + status = qf_parse_line(qi, qf_idx, state.linebuf, state.linelen, + fmt_first, &fields); if (status == QF_FAIL) { goto error2; } @@ -1130,11 +1122,11 @@ qf_init_ext( } if (qf_add_entry(qi, - qi->qf_curlist, - qi->qf_directory, - (*fields.namebuf || qi->qf_directory) - ? fields.namebuf : ((qi->qf_currfile && fields.valid) - ? qi->qf_currfile : (char_u *)NULL), + qf_idx, + qfl->qf_directory, + (*fields.namebuf || qfl->qf_directory) + ? fields.namebuf : ((qfl->qf_currfile && fields.valid) + ? qfl->qf_currfile : (char_u *)NULL), 0, fields.errmsg, fields.lnum, @@ -1149,25 +1141,25 @@ qf_init_ext( line_breakcheck(); } if (state.fd == NULL || !ferror(state.fd)) { - if (qi->qf_lists[qi->qf_curlist].qf_index == 0) { - /* no valid entry found */ - qi->qf_lists[qi->qf_curlist].qf_ptr = - qi->qf_lists[qi->qf_curlist].qf_start; - qi->qf_lists[qi->qf_curlist].qf_index = 1; - qi->qf_lists[qi->qf_curlist].qf_nonevalid = TRUE; + if (qfl->qf_index == 0) { + // no valid entry found + qfl->qf_ptr = qfl->qf_start; + qfl->qf_index = 1; + qfl->qf_nonevalid = true; } else { - qi->qf_lists[qi->qf_curlist].qf_nonevalid = FALSE; - if (qi->qf_lists[qi->qf_curlist].qf_ptr == NULL) - qi->qf_lists[qi->qf_curlist].qf_ptr = - qi->qf_lists[qi->qf_curlist].qf_start; + qfl->qf_nonevalid = false; + if (qfl->qf_ptr == NULL) { + qfl->qf_ptr = qfl->qf_start; + } } - /* return number of matches */ - retval = qi->qf_lists[qi->qf_curlist].qf_count; + // return number of matches + retval = qfl->qf_count; goto qf_init_end; } EMSG(_(e_readerrf)); error2: if (!adding) { + // Error when creating a new list. Free the new list qf_free(qi, qi->qf_curlist); qi->qf_listcount--; if (qi->qf_curlist > 0) { @@ -1183,7 +1175,9 @@ qf_init_end: xfree(fields.pattern); xfree(state.growbuf); - qf_update_buffer(qi, old_last); + if (qf_idx == qi->qf_curlist) { + qf_update_buffer(qi, old_last); + } if (state.vc.vc_type != CONV_NONE) { convert_setup(&state.vc, NULL, NULL); @@ -1206,9 +1200,9 @@ static void qf_store_title(qf_info_T *qi, int qf_idx, char_u *title) } } -/* - * Prepare for adding a new quickfix list. - */ +// 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, char_u *qf_title) { int i; @@ -1232,6 +1226,7 @@ static void qf_new_list(qf_info_T *qi, char_u *qf_title) qi->qf_curlist = qi->qf_listcount++; memset(&qi->qf_lists[qi->qf_curlist], 0, (size_t)(sizeof(qf_list_T))); qf_store_title(qi, qi->qf_curlist, qf_title); + qi->qf_lists[qi->qf_curlist].qf_id = ++last_qf_id; } /* @@ -1305,7 +1300,7 @@ static int qf_add_entry(qf_info_T *qi, int qf_idx, char_u *dir, char_u *fname, (qi == &ql_info) ? BUF_HAS_QF_ENTRY : BUF_HAS_LL_ENTRY; } } else { - qfp->qf_fnum = qf_get_fnum(qi, dir, fname); + qfp->qf_fnum = qf_get_fnum(qi, qf_idx, dir, fname); } qfp->qf_text = vim_strsave(mesg); qfp->qf_lnum = lnum; @@ -1475,6 +1470,9 @@ void copy_loclist(win_T *from, win_T *to) to_qfl->qf_index = from_qfl->qf_index; /* current index in the list */ + // Assign a new ID for the location list + to_qfl->qf_id = ++last_qf_id; + /* When no valid entries are present in the list, qf_ptr points to * the first item in the list */ if (to_qfl->qf_nonevalid) { @@ -1488,7 +1486,8 @@ void copy_loclist(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_info_T *qi, char_u *directory, char_u *fname) +static int qf_get_fnum(qf_info_T *qi, int qf_idx, char_u *directory, + char_u *fname) { char_u *ptr = NULL; char_u *bufname; @@ -1511,7 +1510,7 @@ static int qf_get_fnum(qf_info_T *qi, char_u *directory, char_u *fname) // directory change. if (!os_path_exists(ptr)) { xfree(ptr); - directory = qf_guess_filepath(qi, fname); + directory = qf_guess_filepath(qi, qf_idx, fname); if (directory) { ptr = (char_u *)concat_fnames((char *)directory, (char *)fname, true); } else { @@ -1661,18 +1660,19 @@ static void qf_clean_dir_stack(struct dir_stack_T **stackptr) * 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_info_T *qi, char_u *filename) +static char_u *qf_guess_filepath(qf_info_T *qi, int qf_idx, char_u *filename) { struct dir_stack_T *ds_ptr; struct dir_stack_T *ds_tmp; char_u *fullname; + qf_list_T *qfl = &qi->qf_lists[qf_idx]; // no dirs on the stack - there's nothing we can do - if (qi->qf_dir_stack == NULL) { + if (qfl->qf_dir_stack == NULL) { return NULL; } - ds_ptr = qi->qf_dir_stack->next; + ds_ptr = qfl->qf_dir_stack->next; fullname = NULL; while (ds_ptr) { xfree(fullname); @@ -1688,9 +1688,9 @@ static char_u *qf_guess_filepath(qf_info_T *qi, char_u *filename) xfree(fullname); // clean up all dirs we already left - while (qi->qf_dir_stack->next != ds_ptr) { - ds_tmp = qi->qf_dir_stack->next; - qi->qf_dir_stack->next = qi->qf_dir_stack->next->next; + while (qfl->qf_dir_stack->next != ds_ptr) { + ds_tmp = qfl->qf_dir_stack->next; + qfl->qf_dir_stack->next = qfl->qf_dir_stack->next->next; xfree(ds_tmp->dirname); xfree(ds_tmp); } @@ -1845,12 +1845,12 @@ void qf_jump(qf_info_T *qi, int dir, int errornr, int forceit) /* * For ":helpgrep" find a help window or open one. */ - if (qf_ptr->qf_type == 1 && (!curwin->w_buffer->b_help || cmdmod.tab != 0)) { + if (qf_ptr->qf_type == 1 && (!bt_help(curwin->w_buffer) || cmdmod.tab != 0)) { win_T *wp = NULL; if (cmdmod.tab == 0) { FOR_ALL_WINDOWS_IN_TAB(wp2, curtab) { - if (wp2->w_buffer != NULL && wp2->w_buffer->b_help) { + if (bt_help(wp2->w_buffer)) { wp = wp2; break; } @@ -2415,11 +2415,12 @@ static void qf_free_items(qf_info_T *qi, int idx) qfline_T *qfp; qfline_T *qfpnext; bool stop = false; + qf_list_T *qfl = &qi->qf_lists[idx]; - while (qi->qf_lists[idx].qf_count && qi->qf_lists[idx].qf_start != NULL) { - qfp = qi->qf_lists[idx].qf_start; + while (qfl->qf_count && qfl->qf_start != NULL) { + qfp = qfl->qf_start; qfpnext = qfp->qf_next; - if (qi->qf_lists[idx].qf_title != NULL && !stop) { + if (!stop) { xfree(qfp->qf_text); stop = (qfp == qfpnext); xfree(qfp->qf_pattern); @@ -2428,40 +2429,42 @@ static void qf_free_items(qf_info_T *qi, int idx) // Somehow qf_count may have an incorrect value, set it to 1 // to avoid crashing when it's wrong. // TODO(vim): Avoid qf_count being incorrect. - qi->qf_lists[idx].qf_count = 1; + qfl->qf_count = 1; } } - qi->qf_lists[idx].qf_start = qfpnext; - qi->qf_lists[idx].qf_count--; - } - - qi->qf_lists[idx].qf_start = NULL; - qi->qf_lists[idx].qf_ptr = NULL; - qi->qf_lists[idx].qf_index = 0; - qi->qf_lists[idx].qf_start = NULL; - qi->qf_lists[idx].qf_last = NULL; - qi->qf_lists[idx].qf_ptr = NULL; - qi->qf_lists[idx].qf_nonevalid = true; - - qf_clean_dir_stack(&qi->qf_dir_stack); - qi->qf_directory = NULL; - qf_clean_dir_stack(&qi->qf_file_stack); - qi->qf_currfile = NULL; - qi->qf_multiline = false; - qi->qf_multiignore = false; - qi->qf_multiscan = false; + qfl->qf_start = qfpnext; + qfl->qf_count--; + } + + qfl->qf_start = NULL; + qfl->qf_ptr = NULL; + qfl->qf_index = 0; + qfl->qf_start = NULL; + qfl->qf_last = NULL; + qfl->qf_ptr = NULL; + qfl->qf_nonevalid = true; + + qf_clean_dir_stack(&qfl->qf_dir_stack); + qfl->qf_directory = NULL; + qf_clean_dir_stack(&qfl->qf_file_stack); + qfl->qf_currfile = NULL; + qfl->qf_multiline = false; + qfl->qf_multiignore = false; + qfl->qf_multiscan = false; } /// Free error list "idx". Frees all the entries in the quickfix list, /// associated context information and the title. static void qf_free(qf_info_T *qi, int idx) { + qf_list_T *qfl = &qi->qf_lists[idx]; qf_free_items(qi, idx); - xfree(qi->qf_lists[idx].qf_title); - qi->qf_lists[idx].qf_title = NULL; - tv_free(qi->qf_lists[idx].qf_ctx); - qi->qf_lists[idx].qf_ctx = NULL; + xfree(qfl->qf_title); + qfl->qf_title = NULL; + tv_free(qfl->qf_ctx); + qfl->qf_ctx = NULL; + qfl->qf_id = 0; } /* @@ -2601,8 +2604,9 @@ 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); + if (win != NULL) { + win_close(win, false); + } } /* @@ -4034,18 +4038,22 @@ static void unload_dummy_buffer(buf_T *buf, char_u *dirname_start) /// Add each quickfix error to list "list" as a dictionary. /// If qf_idx is -1, use the current list. Otherwise, use the specified list. -int get_errorlist(win_T *wp, int qf_idx, list_T *list) +int get_errorlist(const qf_info_T *qi_arg, win_T *wp, int qf_idx, list_T *list) { - qf_info_T *qi = &ql_info; + const qf_info_T *qi = qi_arg; char_u buf[2]; qfline_T *qfp; int i; int bufnum; - if (wp != NULL) { - qi = GET_LOC_LIST(wp); - if (qi == NULL) - return FAIL; + if (qi == NULL) { + qi = &ql_info; + if (wp != NULL) { + qi = GET_LOC_LIST(wp); + if (qi == NULL) { + return FAIL; + } + } } if (qf_idx == -1) { @@ -4109,9 +4117,48 @@ enum { QF_GETLIST_NR = 0x4, QF_GETLIST_WINID = 0x8, QF_GETLIST_CONTEXT = 0x10, + QF_GETLIST_ID = 0x20, QF_GETLIST_ALL = 0xFF }; +// Parse text from 'di' and return the quickfix list items +static int qf_get_list_from_lines(dict_T *what, dictitem_T *di, dict_T *retdict) +{ + int status = FAIL; + char_u *errorformat = p_efm; + dictitem_T *efm_di; + + // Only a List value is supported + if (di->di_tv.v_type == VAR_LIST && di->di_tv.vval.v_list != NULL) { + // 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 *qi = xmalloc(sizeof(*qi)); + memset(qi, 0, sizeof(*qi)); + qi->qf_refcount++; + + 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, l); + qf_free(qi, 0); + } + xfree(qi); + + tv_dict_add_list(retdict, S_LEN("items"), l); + status = OK; + } + + return status; +} + /// Return quickfix/location list details (title) as a /// dictionary. 'what' contains the details to return. If 'list_idx' is -1, /// then current list is used. Otherwise the specified list is used. @@ -4120,17 +4167,22 @@ int get_errorlist_properties(win_T *wp, dict_T *what, dict_T *retdict) qf_info_T *qi = &ql_info; dictitem_T *di; + if ((di = tv_dict_find(what, S_LEN("lines"))) != NULL) { + return qf_get_list_from_lines(what, di, retdict); + } + if (wp != NULL) { qi = GET_LOC_LIST(wp); - if (qi == NULL) { - // If querying for the size of the location list, return 0 - if (((di = tv_dict_find(what, S_LEN("nr"))) != NULL) - && (di->di_tv.v_type == VAR_STRING) - && strequal((const char *)di->di_tv.vval.v_string, "$")) { - return tv_dict_add_nr(retdict, S_LEN("nr"), 0); - } - return FAIL; + } + // List is not present or is empty + if (qi == NULL || qi->qf_listcount == 0) { + // If querying for the size of the list, return 0 + if (((di = tv_dict_find(what, S_LEN("nr"))) != NULL) + && (di->di_tv.v_type == VAR_STRING) + && (STRCMP(di->di_tv.vval.v_string, "$") == 0)) { + return tv_dict_add_nr(retdict, S_LEN("nr"), 0); } + return FAIL; } int status = OK; @@ -4146,44 +4198,51 @@ int get_errorlist_properties(win_T *wp, dict_T *what, dict_T *retdict) if (qf_idx < 0 || qf_idx >= qi->qf_listcount) { return FAIL; } - } else if (qi->qf_listcount == 0) { // stack is empty - return FAIL; } - flags |= QF_GETLIST_NR; } else if (di->di_tv.v_type == VAR_STRING && strequal((const char *)di->di_tv.vval.v_string, "$")) { // Get the last quickfix list number - if (qi->qf_listcount > 0) { - qf_idx = qi->qf_listcount - 1; - } else { - qf_idx = -1; // Quickfix stack is empty - } - flags |= QF_GETLIST_NR; + qf_idx = qi->qf_listcount - 1; } else { return FAIL; } + flags |= QF_GETLIST_NR; } - if (qf_idx != -1) { - if (tv_dict_find(what, S_LEN("all")) != NULL) { - flags |= QF_GETLIST_ALL; - } - - if (tv_dict_find(what, S_LEN("title")) != NULL) { - flags |= QF_GETLIST_TITLE; - } - - if (tv_dict_find(what, S_LEN("winid")) != NULL) { - flags |= QF_GETLIST_WINID; - } - - if (tv_dict_find(what, S_LEN("context")) != NULL) { - flags |= QF_GETLIST_CONTEXT; + if ((di = tv_dict_find(what, S_LEN("id"))) != NULL) { + // Look for a list with the specified id + if (di->di_tv.v_type == VAR_NUMBER) { + // For zero, use the current list or the list specifed by 'nr' + if (di->di_tv.vval.v_number != 0) { + for (qf_idx = 0; qf_idx < qi->qf_listcount; qf_idx++) { + if (qi->qf_lists[qf_idx].qf_id == di->di_tv.vval.v_number) { + break; + } + } + if (qf_idx == qi->qf_listcount) { + return FAIL; // List not found + } + } + flags |= QF_GETLIST_ID; + } else { + return FAIL; } + } - if (tv_dict_find(what, S_LEN("items")) != NULL) { - flags |= QF_GETLIST_ITEMS; - } + if (tv_dict_find(what, S_LEN("all")) != NULL) { + flags |= QF_GETLIST_ALL; + } + if (tv_dict_find(what, S_LEN("title")) != NULL) { + flags |= QF_GETLIST_TITLE; + } + if (tv_dict_find(what, S_LEN("winid")) != NULL) { + flags |= QF_GETLIST_WINID; + } + if (tv_dict_find(what, S_LEN("context")) != NULL) { + flags |= QF_GETLIST_CONTEXT; + } + if (tv_dict_find(what, S_LEN("items")) != NULL) { + flags |= QF_GETLIST_ITEMS; } if (flags & QF_GETLIST_TITLE) { @@ -4204,7 +4263,7 @@ int get_errorlist_properties(win_T *wp, dict_T *what, dict_T *retdict) } if ((status == OK) && (flags & QF_GETLIST_ITEMS)) { list_T *l = tv_list_alloc(kListLenMayKnow); - (void)get_errorlist(wp, qf_idx, l); + (void)get_errorlist(qi, NULL, qf_idx, l); tv_dict_add_list(retdict, S_LEN("items"), l); } @@ -4221,6 +4280,10 @@ int get_errorlist_properties(win_T *wp, dict_T *what, dict_T *retdict) } } + if ((status == OK) && (flags & QF_GETLIST_ID)) { + status = tv_dict_add_nr(retdict, S_LEN("id"), qi->qf_lists[qf_idx].qf_id); + } + return status; } @@ -4333,11 +4396,13 @@ static int qf_add_entries(qf_info_T *qi, int qf_idx, list_T *list, return retval; } -static int qf_set_properties(qf_info_T *qi, dict_T *what, int action) +static int qf_set_properties(qf_info_T *qi, dict_T *what, int action, + char_u *title) { dictitem_T *di; int retval = FAIL; int newlist = false; + char_u *errorformat = p_efm; if (action == ' ' || qi->qf_curlist == qi->qf_listcount) { newlist = true; @@ -4353,25 +4418,48 @@ static int qf_set_properties(qf_info_T *qi, dict_T *what, int action) if ((action == ' ' || action == 'a') && qf_idx == qi->qf_listcount) { // When creating a new list, accept qf_idx pointing to the next - // non-available list + // non-available list and add the new list at the end of the + // stack. newlist = true; + qf_idx = qi->qf_listcount - 1; } else if (qf_idx < 0 || qf_idx >= qi->qf_listcount) { return FAIL; - } else { + } else if (action != ' ') { newlist = false; // use the specified list } } else if (di->di_tv.v_type == VAR_STRING - && strequal((const char *)di->di_tv.vval.v_string, "$") - && qi->qf_listcount > 0) { - qf_idx = qi->qf_listcount - 1; - newlist = false; + && strequal((const char *)di->di_tv.vval.v_string, "$")) { + if (qi->qf_listcount > 0) { + qf_idx = qi->qf_listcount - 1; + } else if (newlist) { + qf_idx = 0; + } else { + return FAIL; + } + } else { + return FAIL; + } + } + + if (!newlist && (di = tv_dict_find(what, S_LEN("id"))) != NULL) { + // Use the quickfix/location list with the specified id + if (di->di_tv.v_type == VAR_NUMBER) { + for (qf_idx = 0; qf_idx < qi->qf_listcount; qf_idx++) { + if (qi->qf_lists[qf_idx].qf_id == di->di_tv.vval.v_number) { + break; + } + } + if (qf_idx == qi->qf_listcount) { + return FAIL; // List not found + } } else { return FAIL; } } if (newlist) { - qf_new_list(qi, NULL); + qi->qf_curlist = qf_idx; + qf_new_list(qi, title); qf_idx = qi->qf_curlist; } @@ -4396,6 +4484,28 @@ static int qf_set_properties(qf_info_T *qi, dict_T *what, int action) } } + if ((di = tv_dict_find(what, S_LEN("efm"))) != NULL) { + if (di->di_tv.v_type != VAR_STRING || di->di_tv.vval.v_string == NULL) { + return FAIL; + } + errorformat = di->di_tv.vval.v_string; + } + + if ((di = tv_dict_find(what, S_LEN("lines"))) != NULL) { + // Only a List value is supported + if (di->di_tv.v_type == VAR_LIST && di->di_tv.vval.v_list != NULL) { + if (action == 'r') { + qf_free_items(qi, qf_idx); + } + if (qf_init_ext(qi, qf_idx, NULL, NULL, &di->di_tv, errorformat, + false, (linenr_T)0, (linenr_T)0, NULL, NULL) > 0) { + retval = OK; + } + } else { + return FAIL; + } + } + if ((di = tv_dict_find(what, S_LEN("context"))) != NULL) { tv_free(qi->qf_lists[qf_idx].qf_ctx); @@ -4483,7 +4593,7 @@ int set_errorlist(win_T *wp, list_T *list, int action, char_u *title, // Free the entire quickfix or location list stack qf_free_stack(wp, qi); } else if (what != NULL) { - retval = qf_set_properties(qi, what, action); + retval = qf_set_properties(qi, what, action, title); } else { retval = qf_add_entries(qi, qi->qf_curlist, list, title, action); } @@ -4603,7 +4713,7 @@ void ex_cbuffer(exarg_T *eap) qf_title = IObuff; } - if (qf_init_ext(qi, NULL, buf, NULL, p_efm, + if (qf_init_ext(qi, qi->qf_curlist, NULL, buf, NULL, p_efm, (eap->cmdidx != CMD_caddbuffer && eap->cmdidx != CMD_laddbuffer), eap->line1, eap->line2, qf_title, NULL) > 0) { @@ -4668,7 +4778,7 @@ void ex_cexpr(exarg_T *eap) if (eval0(eap->arg, &tv, NULL, true) != FAIL) { if ((tv.v_type == VAR_STRING && tv.vval.v_string != NULL) || tv.v_type == VAR_LIST) { - if (qf_init_ext(qi, NULL, NULL, &tv, p_efm, + if (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, *eap->cmdlinep, NULL) > 0) { @@ -4725,16 +4835,26 @@ void ex_helpgrep(exarg_T *eap) p_cpo = empty_option; if (eap->cmdidx == CMD_lhelpgrep) { - qi = NULL; + win_T *wp = NULL; - /* Find an existing help window */ - FOR_ALL_WINDOWS_IN_TAB(wp, curtab) { - if (wp->w_buffer != NULL && wp->w_buffer->b_help) { - qi = wp->w_llist; + // If the current window is a help window, then use it + if (bt_help(curwin->w_buffer)) { + wp = curwin; + } else { + // Find an existing help window + FOR_ALL_WINDOWS_IN_TAB(wp2, curtab) { + if (bt_help(wp2->w_buffer)) { + wp = wp2; + break; + } } } - /* Help window not found */ + if (wp == NULL) { // Help window not found + qi = NULL; + } else { + qi = wp->w_llist; + } if (qi == NULL) { /* Allocate a new location list for help text matches */ qi = ll_new_list(); @@ -4855,11 +4975,13 @@ void ex_helpgrep(exarg_T *eap) if (eap->cmdidx == CMD_lhelpgrep) { /* If the help window is not opened or if it already points to the * correct location list, then free the new location list. */ - if (!curwin->w_buffer->b_help || curwin->w_llist == qi) { - if (new_qi) + if (!bt_help(curwin->w_buffer) || curwin->w_llist == qi) { + if (new_qi) { ll_free_all(&qi); - } else if (curwin->w_llist == NULL) + } + } else if (curwin->w_llist == NULL) { curwin->w_llist = qi; + } } } |