aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--runtime/doc/quickfix.txt4
-rw-r--r--src/nvim/quickfix.c43
-rw-r--r--src/nvim/version.c2
-rw-r--r--test/functional/legacy/quickfix_spec.lua46
4 files changed, 92 insertions, 3 deletions
diff --git a/runtime/doc/quickfix.txt b/runtime/doc/quickfix.txt
index 44d68c7b38..7c1fc30eba 100644
--- a/runtime/doc/quickfix.txt
+++ b/runtime/doc/quickfix.txt
@@ -53,6 +53,10 @@ command with 'l'.
If the current window was closed by an |autocommand| while processing a
location list command, it will be aborted.
+ *E925* *E926*
+If the current quickfix or location list was changed by an |autocommand| while
+processing a quickfix or location list command, it will be aborted.
+
*:cc*
:cc[!] [nr] Display error [nr]. If [nr] is omitted, the same
error is displayed again. Without [!] this doesn't
diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c
index d6697902ef..71fcb5e60f 100644
--- a/src/nvim/quickfix.c
+++ b/src/nvim/quickfix.c
@@ -1254,6 +1254,32 @@ static char_u *qf_guess_filepath(char_u *filename)
}
+/// When loading a file from the quickfix, the auto commands may modify it.
+/// This may invalidate the current quickfix entry. This function checks
+/// whether a entry is still present in the quickfix.
+/// Similar to location list.
+static bool is_qf_entry_present(qf_info_T *qi, qfline_T *qf_ptr)
+{
+ qf_list_T *qfl;
+ qfline_T *qfp;
+ int i;
+
+ qfl = &qi->qf_lists[qi->qf_curlist];
+
+ // Search for the entry in the current list
+ for (i = 0, qfp = qfl->qf_start; i < qfl->qf_count; i++, qfp = qfp->qf_next) {
+ if (qfp == qf_ptr) {
+ break;
+ }
+ }
+
+ if (i == qfl->qf_count) { // Entry is not found
+ return false;
+ }
+
+ return true;
+}
+
/*
* jump to a quickfix line
* if dir == FORWARD go "errornr" valid entries forward
@@ -1585,14 +1611,29 @@ win_found:
oldwin == curwin ? curwin : NULL);
}
} else {
+ int old_qf_curlist = qi->qf_curlist;
+ bool is_abort = false;
+
ok = buflist_getfile(qf_ptr->qf_fnum, (linenr_T)1,
GETF_SETMARK | GETF_SWITCH, forceit);
if (qi != &ql_info && !win_valid(oldwin)) {
EMSG(_("E924: Current window was closed"));
+ is_abort = true;
+ opened_window = false;
+ } else if (old_qf_curlist != qi->qf_curlist
+ || !is_qf_entry_present(qi, qf_ptr)) {
+ if (qi == &ql_info) {
+ EMSG(_("E925: Current quickfix was changed"));
+ } else {
+ EMSG(_("E926: Current location list was changed"));
+ }
+ is_abort = true;
+ }
+
+ if (is_abort) {
ok = false;
qi = NULL;
qf_ptr = NULL;
- opened_window = false;
}
}
}
diff --git a/src/nvim/version.c b/src/nvim/version.c
index 7721e9dc8c..69438c50d0 100644
--- a/src/nvim/version.c
+++ b/src/nvim/version.c
@@ -804,7 +804,7 @@ static int included_patches[] = {
1643,
1642,
1641,
- // 1640,
+ 1640,
// 1639,
// 1638,
// 1637 NA
diff --git a/test/functional/legacy/quickfix_spec.lua b/test/functional/legacy/quickfix_spec.lua
index b5a8e10a97..480e046f55 100644
--- a/test/functional/legacy/quickfix_spec.lua
+++ b/test/functional/legacy/quickfix_spec.lua
@@ -265,7 +265,7 @@ describe('helpgrep', function()
autocmd BufReadCmd t call R(expand("<amatch>"))
augroup END
- function R(n)
+ function! R(n)
quit
endfunc
@@ -406,6 +406,43 @@ describe('helpgrep', function()
augroup END
augroup! QfBufWinEnter
endfunc
+
+ function XquickfixChangedByAutocmd(cchar)
+ let Xolder = a:cchar . 'older'
+ let Xgetexpr = a:cchar . 'getexpr'
+ let Xrewind = a:cchar . 'rewind'
+ if a:cchar == 'c'
+ let Xsetlist = 'setqflist('
+ let ErrorNr = 'E925'
+ function! ReadFunc()
+ colder
+ cgetexpr []
+ endfunc
+ else
+ let Xsetlist = 'setloclist(0,'
+ let ErrorNr = 'E926'
+ function! ReadFunc()
+ lolder
+ lgetexpr []
+ endfunc
+ endif
+
+ augroup testgroup
+ au!
+ autocmd BufReadCmd t call ReadFunc()
+ augroup END
+
+ bwipe!
+ let words = [ "a", "b" ]
+ let qflist = []
+ for word in words
+ call add(qflist, {'filename': 't'})
+ exec "call " . Xsetlist . "qflist, '')"
+ endfor
+ exec "call assert_fails('" . Xrewind . "', '" . ErrorNr . ":')"
+
+ augroup! testgroup
+ endfunc
]])
end)
@@ -478,6 +515,13 @@ describe('helpgrep', function()
call('Test_locationlist')
expected_empty()
end)
+
+ it('is changed by autocmd', function()
+ call('XquickfixChangedByAutocmd', 'c')
+ expected_empty()
+ call('XquickfixChangedByAutocmd', 'l')
+ expected_empty()
+ end)
end)
describe('errorformat', function()