aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/quickfix.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nvim/quickfix.c')
-rw-r--r--src/nvim/quickfix.c225
1 files changed, 163 insertions, 62 deletions
diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c
index fc2e1a4295..1cd7879dc0 100644
--- a/src/nvim/quickfix.c
+++ b/src/nvim/quickfix.c
@@ -1092,6 +1092,7 @@ qf_init_ext(
)
FUNC_ATTR_NONNULL_ARG(1)
{
+ qf_list_T *qfl;
qfstate_T state = { 0 };
qffields_T fields = { 0 };
qfline_T *old_last = NULL;
@@ -1115,15 +1116,16 @@ qf_init_ext(
// make place for a new list
qf_new_list(qi, qf_title);
qf_idx = qi->qf_curlist;
+ qfl = qf_get_list(qi, qf_idx);
} else {
// Adding to existing list, use last entry.
adding = true;
- if (!qf_list_empty(qf_get_list(qi, qf_idx) )) {
- old_last = qi->qf_lists[qf_idx].qf_last;
+ qfl = qf_get_list(qi, qf_idx);
+ if (!qf_list_empty(qfl)) {
+ old_last = qfl->qf_last;
}
}
- qf_list_T *qfl = qf_get_list(qi, qf_idx);
// Use the local value of 'errorformat' if it's set.
if (errorformat == p_efm && tv == NULL && buf && *buf->b_p_efm != NUL) {
@@ -1665,8 +1667,8 @@ static int qf_parse_multiline_pfx(int idx, qf_list_T *qfl, qffields_T *fields)
}
if (!qfprev->qf_col) {
qfprev->qf_col = fields->col;
+ qfprev->qf_viscol = fields->use_viscol;
}
- qfprev->qf_viscol = fields->use_viscol;
if (!qfprev->qf_fnum) {
qfprev->qf_fnum = qf_get_fnum(qfl, qfl->qf_directory,
*fields->namebuf || qfl->qf_directory
@@ -1775,7 +1777,7 @@ static void decr_quickfix_busy(void)
void check_quickfix_busy(void)
{
if (quickfix_busy != 0) {
- EMSGN("quickfix_busy not zero on exit: %ld", (long)quickfix_busy);
+ EMSGN("quickfix_busy not zero on exit: %" PRId64, (int64_t)quickfix_busy);
# ifdef ABORT_ON_INTERNAL_ERROR
abort();
# endif
@@ -2453,12 +2455,13 @@ static void win_set_loclist(win_T *wp, qf_info_T *qi)
qi->qf_refcount++;
}
-/// Find a help window or open one.
-static int jump_to_help_window(qf_info_T *qi, int *opened_window)
+/// Find a help window or open one. If 'newwin' is true, then open a new help
+/// window.
+static int jump_to_help_window(qf_info_T *qi, bool newwin, int *opened_window)
{
win_T *wp = NULL;
- if (cmdmod.tab != 0) {
+ if (cmdmod.tab != 0 || newwin) {
wp = NULL;
} else {
wp = qf_find_help_win();
@@ -2476,8 +2479,10 @@ static int jump_to_help_window(qf_info_T *qi, int *opened_window)
flags |= WSP_TOP;
}
- if (IS_LL_STACK(qi)) {
- flags |= WSP_NEWLOC; // don't copy the location list
+ // If the user asks to open a new window, then copy the location list.
+ // Otherwise, don't copy the location list.
+ if (IS_LL_STACK(qi) && !newwin) {
+ flags |= WSP_NEWLOC;
}
if (win_split(0, flags) == FAIL) {
@@ -2490,8 +2495,10 @@ static int jump_to_help_window(qf_info_T *qi, int *opened_window)
win_setheight((int)p_hh);
}
- if (IS_LL_STACK(qi)) { // not a quickfix list
- // The new window should use the supplied location list
+ // When using location list, the new window should use the supplied
+ // location list. If the user asks to open a new window, then the new
+ // window will get a copy of the location list.
+ if (IS_LL_STACK(qi) && !newwin) {
win_set_loclist(curwin, qi);
}
}
@@ -2652,14 +2659,19 @@ static void qf_goto_win_with_qfl_file(int qf_fnum)
// Find a suitable window for opening a file (qf_fnum) from the
// quickfix/location list and jump to it. If the file is already opened in a
-// window, jump to it. Otherwise open a new window to display the file. This is
-// called from either a quickfix or a location list window.
-static int qf_jump_to_usable_window(int qf_fnum, int *opened_window)
+// window, jump to it. Otherwise open a new window to display the file. If
+// 'newwin' is true, then always open a new window. This is called from either
+// a quickfix or a location list window.
+static int qf_jump_to_usable_window(int qf_fnum, bool newwin,
+ int *opened_window)
{
win_T *usable_win_ptr = NULL;
bool usable_win = false;
- qf_info_T *ll_ref = curwin->w_llist_ref;
+ // If opening a new window, then don't use the location list referred by
+ // the current window. Otherwise two windows will refer to the same
+ // location list.
+ qf_info_T *ll_ref = newwin ? NULL : curwin->w_llist_ref;
if (ll_ref != NULL) {
// Find a non-quickfix window with this location list
usable_win_ptr = qf_find_win_with_loclist(ll_ref);
@@ -2684,7 +2696,7 @@ static int qf_jump_to_usable_window(int qf_fnum, int *opened_window)
// If there is only one window and it is the quickfix window, create a
// new one above the quickfix window.
- if ((ONE_WINDOW && bt_quickfix(curbuf)) || !usable_win) {
+ if ((ONE_WINDOW && bt_quickfix(curbuf)) || !usable_win || newwin) {
if (qf_open_new_file_win(ll_ref) != OK) {
return FAIL;
}
@@ -2823,11 +2835,12 @@ static void qf_jump_print_msg(qf_info_T *qi, int qf_index, qfline_T *qf_ptr,
}
/// Find a usable window for opening a file from the quickfix/location list. If
-/// a window is not found then open a new window.
+/// 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.
-static int qf_jump_open_window(qf_info_T *qi, qfline_T *qf_ptr,
+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);
@@ -2837,7 +2850,7 @@ static int qf_jump_open_window(qf_info_T *qi, qfline_T *qf_ptr,
// For ":helpgrep" find a help window or open one.
if (qf_ptr->qf_type == 1 && (!bt_help(curwin->w_buffer) || cmdmod.tab != 0)) {
- if (jump_to_help_window(qi, opened_window) == FAIL) {
+ if (jump_to_help_window(qi, newwin, opened_window) == FAIL) {
return FAIL;
}
}
@@ -2861,7 +2874,8 @@ static int qf_jump_open_window(qf_info_T *qi, qfline_T *qf_ptr,
return NOTDONE;
}
- if (qf_jump_to_usable_window(qf_ptr->qf_fnum, opened_window) == FAIL) {
+ if (qf_jump_to_usable_window(qf_ptr->qf_fnum, newwin, opened_window)
+ == FAIL) {
return FAIL;
}
}
@@ -2924,15 +2938,24 @@ static int qf_jump_to_buffer(qf_info_T *qi, int qf_index, qfline_T *qf_ptr,
return retval;
}
-/// jump to a quickfix ltne
-/// if dir == FORWARD go "errornr" valid entries forward
-/// if dir == BACKWARD go "errornr" valid entries backward
-/// if dir == FORWARD_FILE go "errornr" valid entries files backward
-/// if dir == BACKWARD_FILE go "errornr" valid entries files backward
-/// else if "errornr" is zero, redisplay the same line
-/// else go to entry "errornr"
+/// Jump to a quickfix line and try to use an existing window.
void qf_jump(qf_info_T *qi, int dir, int errornr, int forceit)
{
+ qf_jump_newwin(qi, dir, errornr, forceit, false);
+}
+
+// Jump to a quickfix line.
+// If dir == 0 go to entry "errornr".
+// If dir == FORWARD go "errornr" valid entries forward.
+// If dir == BACKWARD go "errornr" valid entries backward.
+// If dir == FORWARD_FILE go "errornr" valid entries files backward.
+// If dir == BACKWARD_FILE go "errornr" valid entries files backward
+// else if "errornr" is zero, redisplay the same line
+// If 'forceit' is true, then can discard changes to the current buffer.
+// If 'newwin' is true, then open the file in a new window.
+static void qf_jump_newwin(qf_info_T *qi, int dir, int errornr, int forceit,
+ bool newwin)
+{
qf_list_T *qfl;
qfline_T *qf_ptr;
qfline_T *old_qf_ptr;
@@ -2975,7 +2998,7 @@ void qf_jump(qf_info_T *qi, int dir, int errornr, int forceit)
print_message = false;
}
- retval = qf_jump_open_window(qi, qf_ptr, &opened_window);
+ retval = qf_jump_open_window(qi, qf_ptr, newwin, &opened_window);
if (retval == FAIL) {
goto failed;
}
@@ -3277,7 +3300,7 @@ void qf_history(exarg_T *eap)
qf_info_T *qi = qf_cmd_get_stack(eap, false);
int i;
- if (qf_stack_empty(qi) || qf_list_empty(qf_get_curlist(qi))) {
+ if (qf_stack_empty(qi)) {
MSG(_("No entries"));
} else {
for (i = 0; i < qi->qf_listcount; i++) {
@@ -3445,14 +3468,9 @@ void qf_view_result(bool split)
}
if (split) {
- char cmd[32];
-
- snprintf(cmd, sizeof(cmd), "split +%" PRId64 "%s",
- (int64_t)curwin->w_cursor.lnum,
- IS_LL_WINDOW(curwin) ? "ll" : "cc");
- if (do_cmdline_cmd(cmd) == OK) {
- do_cmdline_cmd("clearjumps");
- }
+ // Open the selected entry in a new window
+ qf_jump_newwin(qi, 0, (int)curwin->w_cursor.lnum, false, true);
+ do_cmdline_cmd("clearjumps");
return;
}
@@ -3483,7 +3501,7 @@ void ex_cwindow(exarg_T *eap)
// it if we have errors; otherwise, leave it closed.
if (qf_stack_empty(qi)
|| qfl->qf_nonevalid
- || qf_list_empty(qf_get_curlist(qi))) {
+ || qf_list_empty(qfl)) {
if (win != NULL) {
ex_cclose(eap);
}
@@ -3536,10 +3554,23 @@ static int qf_goto_cwindow(const qf_info_T *qi, bool resize, int sz,
return OK;
}
+// Set options for the buffer in the quickfix or location list window.
+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);
+ RESET_BINDING(curwin);
+ curwin->w_p_diff = false;
+ set_option_value("fdm", 0L, "manual", OPT_LOCAL);
+}
+
// Open a new quickfix or location list window, load the quickfix buffer and
// set the appropriate options for the window.
// Returns FAIL if the window could not be opened.
-static int qf_open_new_cwindow(const qf_info_T *qi, int height)
+static int qf_open_new_cwindow(qf_info_T *qi, int height)
+ FUNC_ATTR_NONNULL_ALL
{
win_T *oldwin = curwin;
const tabpage_T *const prevtab = curtab;
@@ -3582,14 +3613,13 @@ static int qf_open_new_cwindow(const qf_info_T *qi, int height)
} else {
// Create a new quickfix buffer
(void)do_ecmd(0, NULL, NULL, NULL, ECMD_ONE, ECMD_HIDE, oldwin);
+ }
- // 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);
- RESET_BINDING(curwin);
- curwin->w_p_diff = false;
- set_option_value("fdm", 0L, "manual", OPT_LOCAL);
+ // Set the options for the quickfix buffer/window (if not already done)
+ // Do this even if the quickfix buffer was already present, as an autocmd
+ // might have previously deleted (:bdelete) the quickfix buffer.
+ if (curbuf->b_p_bt[0] != 'q') {
+ qf_set_cwindow_options();
}
// Only set the height when still in the same tab page and there is no
@@ -3778,8 +3808,8 @@ static win_T *qf_find_win(const qf_info_T *qi)
// Find a quickfix buffer.
// Searches in windows opened in all the tabs.
-static buf_T *qf_find_buf(const qf_info_T *qi)
- FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
+static buf_T *qf_find_buf(qf_info_T *qi)
+ FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
{
FOR_ALL_TAB_WINDOWS(tp, win) {
if (is_qf_win(win, qi)) {
@@ -4922,7 +4952,7 @@ static bool vgr_qflist_valid(win_T *wp, qf_info_T *qi, unsigned qfid,
/// 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_info_T *qi, char_u *fname, buf_T *buf,
+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)
@@ -4936,7 +4966,7 @@ static bool vgr_match_buflines(qf_info_T *qi, char_u *fname, buf_T *buf,
// 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(qf_get_curlist(qi),
+ if (qf_add_entry(qfl,
NULL, // dir
fname,
NULL,
@@ -4997,6 +5027,20 @@ static void vgr_jump_to_match(qf_info_T *qi, int forceit, int *redraw_for_dummy,
}
}
+// Return true if "buf" had an existing swap file, the current swap file does
+// not end in ".swp".
+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 size_t len = STRLEN(fname);
+
+ return fname[len - 1] != 'p' || fname[len - 2] != 'w';
+ }
+ return false;
+}
+
// ":vimgrep {pattern} file(s)"
// ":vimgrepadd {pattern} file(s)"
// ":lvimgrep {pattern} file(s)"
@@ -5129,7 +5173,8 @@ 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(qi, fname, buf, &regmatch, &tomatch,
+ found_match = vgr_match_buflines(qf_get_curlist(qi),
+ fname, buf, &regmatch, &tomatch,
duplicate_name, flags);
if (using_dummy) {
@@ -5153,7 +5198,9 @@ 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
+ || (flags & VGR_NOJUMP)
+ || existing_swapfile(buf)) {
unload_dummy_buffer(buf, dirname_start);
// Keeping the buffer, remove the dummy flag.
buf->b_flags &= ~BF_DUMMY;
@@ -6119,6 +6166,49 @@ static int qf_setprop_context(qf_list_T *qfl, dictitem_T *di)
return OK;
}
+// Set the current index in the specified quickfix list
+static int qf_setprop_curidx(qf_info_T *qi, qf_list_T *qfl,
+ const dictitem_T *di)
+ FUNC_ATTR_NONNULL_ALL
+{
+ int newidx;
+
+ // If the specified index is '$', then use the last entry
+ if (di->di_tv.v_type == VAR_STRING
+ && di->di_tv.vval.v_string != NULL
+ && STRCMP(di->di_tv.vval.v_string, "$") == 0) {
+ newidx = qfl->qf_count;
+ } else {
+ // Otherwise use the specified index
+ bool denote = false;
+ newidx = (int)tv_get_number_chk(&di->di_tv, &denote);
+ if (denote) {
+ return FAIL;
+ }
+ }
+
+ if (newidx < 1) { // sanity check
+ return FAIL;
+ }
+ if (newidx > qfl->qf_count) {
+ newidx = qfl->qf_count;
+ }
+ const int old_qfidx = qfl->qf_index;
+ qfline_T *const qf_ptr = get_nth_entry(qfl, newidx, &newidx);
+ if (qf_ptr == NULL) {
+ return FAIL;
+ }
+ qfl->qf_ptr = qf_ptr;
+ qfl->qf_index = newidx;
+
+ // If the current list is modified and it is displayed in the quickfix
+ // window, then Update it.
+ if (qi->qf_lists[qi->qf_curlist].qf_id == qfl->qf_id) {
+ qf_win_pos_update(qi, old_qfidx);
+ }
+ return OK;
+}
+
/// 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.
@@ -6154,6 +6244,9 @@ static int qf_set_properties(qf_info_T *qi, const dict_T *what, int action,
if ((di = tv_dict_find(what, S_LEN("context"))) != NULL) {
retval = qf_setprop_context(qfl, di);
}
+ if ((di = tv_dict_find(what, S_LEN("idx"))) != NULL) {
+ retval = qf_setprop_curidx(qi, qfl, di);
+ }
if (retval == OK) {
qf_list_changed(qfl);
@@ -6164,7 +6257,8 @@ static int qf_set_properties(qf_info_T *qi, const dict_T *what, int action,
/// Find the non-location list window with the specified location list stack in
/// the current tabpage.
-static win_T * find_win_with_ll(qf_info_T *qi)
+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)) {
@@ -6223,6 +6317,7 @@ static void qf_free_stack(win_T *wp, qf_info_T *qi)
// Populate the quickfix list with the items supplied in the list
// 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)
{
@@ -6239,6 +6334,12 @@ int set_errorlist(win_T *wp, list_T *list, int action, char_u *title,
return OK;
}
+ // A dict argument cannot be specified with a non-empty list argument
+ if (list != NULL && tv_list_len(list) != 0 && what != NULL) {
+ EMSG2(_(e_invarg2), _("cannot have both a list and a \"what\" argument"));
+ return FAIL;
+ }
+
incr_quickfix_busy();
if (what != NULL) {
@@ -6538,7 +6639,7 @@ static qf_info_T *hgr_get_ll(bool *new_ll)
// Search for a pattern in a help file.
static void hgr_search_file(
- qf_info_T *qi,
+ qf_list_T *qfl,
char_u *fname,
regmatch_T *p_regmatch)
FUNC_ATTR_NONNULL_ARG(1, 3)
@@ -6560,7 +6661,7 @@ static void hgr_search_file(
line[--l] = NUL;
}
- if (qf_add_entry(qf_get_curlist(qi),
+ if (qf_add_entry(qfl,
NULL, // dir
fname,
NULL,
@@ -6593,7 +6694,7 @@ static void hgr_search_file(
// 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_info_T *qi,
+ qf_list_T *qfl,
char_u *dirname,
regmatch_T *p_regmatch,
const char_u *lang)
@@ -6618,7 +6719,7 @@ static void hgr_search_files_in_dir(
continue;
}
- hgr_search_file(qi, fnames[fi], p_regmatch);
+ hgr_search_file(qfl, fnames[fi], p_regmatch);
}
FreeWild(fcount, fnames);
}
@@ -6628,7 +6729,7 @@ static void hgr_search_files_in_dir(
// and add the matches to a quickfix list.
// 'lang' is the language specifier. If supplied, then only matches in the
// specified language are found.
-static void hgr_search_in_rtp(qf_info_T *qi, regmatch_T *p_regmatch,
+static void hgr_search_in_rtp(qf_list_T *qfl, regmatch_T *p_regmatch,
const char_u *lang)
FUNC_ATTR_NONNULL_ARG(1, 2)
{
@@ -6637,7 +6738,7 @@ static void hgr_search_in_rtp(qf_info_T *qi, regmatch_T *p_regmatch,
while (*p != NUL && !got_int) {
copy_option_part(&p, NameBuff, MAXPATHL, ",");
- hgr_search_files_in_dir(qi, NameBuff, p_regmatch, lang);
+ hgr_search_files_in_dir(qfl, NameBuff, p_regmatch, lang);
}
}
@@ -6679,12 +6780,12 @@ void ex_helpgrep(exarg_T *eap)
if (regmatch.regprog != NULL) {
// Create a new quickfix list.
qf_new_list(qi, qf_cmdtitle(*eap->cmdlinep));
+ qf_list_T *const qfl = qf_get_curlist(qi);
- hgr_search_in_rtp(qi, &regmatch, lang);
+ hgr_search_in_rtp(qfl, &regmatch, lang);
vim_regfree(regmatch.regprog);
- qf_list_T *qfl = qf_get_curlist(qi);
qfl->qf_nonevalid = false;
qfl->qf_ptr = qfl->qf_start;
qfl->qf_index = 1;