diff options
-rw-r--r-- | runtime/doc/quickfix.txt | 4 | ||||
-rw-r--r-- | src/nvim/quickfix.c | 43 | ||||
-rw-r--r-- | src/nvim/version.c | 2 | ||||
-rw-r--r-- | test/functional/legacy/quickfix_spec.lua | 46 |
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() |