diff options
| -rw-r--r-- | runtime/doc/eval.txt | 2 | ||||
| -rw-r--r-- | runtime/doc/options.txt | 2 | ||||
| -rw-r--r-- | runtime/doc/quickfix.txt | 4 | ||||
| -rw-r--r-- | src/nvim/eval/encode.c | 4 | ||||
| -rw-r--r-- | src/nvim/quickfix.c | 59 | ||||
| -rw-r--r-- | src/nvim/undo.c | 2 | ||||
| -rw-r--r-- | src/nvim/version.c | 10 | ||||
| -rw-r--r-- | test/functional/eval/msgpack_functions_spec.lua | 20 | ||||
| -rw-r--r-- | test/functional/legacy/quickfix_spec.lua | 70 | ||||
| -rw-r--r-- | test/functional/shada/errors_spec.lua | 4 | ||||
| -rw-r--r-- | test/functional/shada/variables_spec.lua | 4 | 
11 files changed, 150 insertions, 31 deletions
diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt index eecf12c44e..64f58c5599 100644 --- a/runtime/doc/eval.txt +++ b/runtime/doc/eval.txt @@ -5069,7 +5069,7 @@ msgpackdump({list})				   {Nvim} *msgpackdump()*  		(dictionary with zero items is represented by 0x80 byte in  		messagepack). -		Limitations:				*E951* *E952* *E953* +		Limitations:				*E5004* *E5005*  		1. |Funcref|s cannot be dumped.  		2. Containers that reference themselves cannot be dumped.  		3. Dictionary keys are always dumped as STR strings. diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt index 1789f73aa9..9d8d1f84c8 100644 --- a/runtime/doc/options.txt +++ b/runtime/doc/options.txt @@ -6512,7 +6512,7 @@ A jump table for the options with a short description can be found at |Q_op|.  				     *'ttyfast'* *'tf'* *'nottyfast'* *'notf'*  'ttyfast' 'tf'		Removed. |vim-differences| {Nvim} -						*'undodir'* *'udir'* *E926* +						*'undodir'* *'udir'* *E5003*  'undodir' 'udir'	string	(default "$XDG_DATA_HOME/nvim/undo")  			global  			{only when compiled with the |+persistent_undo| feature} 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/eval/encode.c b/src/nvim/eval/encode.c index 670437ceda..f6c58d8562 100644 --- a/src/nvim/eval/encode.c +++ b/src/nvim/eval/encode.c @@ -836,7 +836,7 @@ char *encode_tv2json(typval_T *tv, size_t *len)      msgpack_pack_double(packer, (double) (flt))  #define TYPVAL_ENCODE_CONV_FUNC(fun) \ -    return conv_error(_("E951: Error while dumping %s, %s: " \ +    return conv_error(_("E5004: Error while dumping %s, %s: " \                          "attempt to dump function reference"), \                        mpstack, objname) @@ -880,7 +880,7 @@ char *encode_tv2json(typval_T *tv, size_t *len)  #define TYPVAL_ENCODE_CONV_LIST_BETWEEN_ITEMS()  #define TYPVAL_ENCODE_CONV_RECURSE(val, conv_type) \ -    return conv_error(_("E952: Unable to dump %s: " \ +    return conv_error(_("E5005: Unable to dump %s: " \                          "container references itself in %s"), \                        mpstack, objname) diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c index d6697902ef..f0d77f9e2b 100644 --- a/src/nvim/quickfix.c +++ b/src/nvim/quickfix.c @@ -482,9 +482,11 @@ qf_init_ext (            p_str += len;          } else if (tv->v_type == VAR_LIST) { -          /* Get the next line from the supplied list */ -          while (p_li && p_li->li_tv.v_type != VAR_STRING) -            p_li = p_li->li_next;               /* Skip non-string items */ +          // Get the next line from the supplied list +          while (p_li && (p_li->li_tv.v_type != VAR_STRING +                          || p_li->li_tv.vval.v_string == NULL)) { +            p_li = p_li->li_next;               // Skip non-string items +          }            if (!p_li)                            /* End of the list */              break; @@ -910,7 +912,9 @@ static int qf_add_entry(qf_info_T *qi, qfline_T **prevp, char_u *dir,    if (qi->qf_lists[qi->qf_curlist].qf_count == 0) {      /* first element in the list */      qi->qf_lists[qi->qf_curlist].qf_start = qfp; -    qfp->qf_prev = qfp;         /* first element points to itself */ +    qi->qf_lists[qi->qf_curlist].qf_ptr = qfp; +    qi->qf_lists[qi->qf_curlist].qf_index = 0; +    qfp->qf_prev = qfp;         // first element points to itself    } else {      assert(*prevp);      qfp->qf_prev = *prevp; @@ -1254,6 +1258,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 +1615,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;        }      }    } @@ -3580,7 +3625,9 @@ int set_errorlist(win_T *wp, list_T *list, int action, char_u *title)    else      qi->qf_lists[qi->qf_curlist].qf_nonevalid = FALSE;    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; +  if (qi->qf_lists[qi->qf_curlist].qf_count > 0) { +    qi->qf_lists[qi->qf_curlist].qf_index = 1; +  }    qf_update_buffer(qi); diff --git a/src/nvim/undo.c b/src/nvim/undo.c index d6428d63f7..4d56046bc1 100644 --- a/src/nvim/undo.c +++ b/src/nvim/undo.c @@ -691,7 +691,7 @@ char *u_get_undo_file_name(const char *const buf_ffname, const bool reading)          int ret;          char *failed_dir;          if ((ret = os_mkdir_recurse(dir_name, 0755, &failed_dir)) != 0) { -          EMSG3(_("E926: Unable to create directory \"%s\" for undo file: %s"), +          EMSG3(_("E5003: Unable to create directory \"%s\" for undo file: %s"),                  failed_dir, os_strerror(ret));            xfree(failed_dir);          } else { diff --git a/src/nvim/version.c b/src/nvim/version.c index 10dbf97158..8f3619f1e8 100644 --- a/src/nvim/version.c +++ b/src/nvim/version.c @@ -747,7 +747,7 @@ static int included_patches[] = {    1700,    // 1699,    // 1698 NA -  // 1697, +  1697,    // 1696,    1695,    // 1694 NA @@ -780,7 +780,7 @@ static int included_patches[] = {    // 1667 NA    // 1666 NA    // 1665 NA -  // 1664, +  1664,    1663,    // 1662 NA    // 1661 NA @@ -794,17 +794,17 @@ static int included_patches[] = {    // 1653 NA    1652,    // 1651 NA -  // 1650, +  1650,    1649,    1648, -  // 1647, +  1647,    // 1646 NA    // 1645,    // 1644,    1643,    1642,    1641, -  // 1640, +  1640,    // 1639,    // 1638,    // 1637 NA diff --git a/test/functional/eval/msgpack_functions_spec.lua b/test/functional/eval/msgpack_functions_spec.lua index f11c08de05..ebe7c5492b 100644 --- a/test/functional/eval/msgpack_functions_spec.lua +++ b/test/functional/eval/msgpack_functions_spec.lua @@ -566,27 +566,27 @@ describe('msgpackdump() function', function()    it('fails to dump a function reference', function()      execute('let Todump = function("tr")') -    eq('Vim(call):E951: Error while dumping msgpackdump() argument, index 0, itself: attempt to dump function reference', +    eq('Vim(call):E5004: Error while dumping msgpackdump() argument, index 0, itself: attempt to dump function reference',         exc_exec('call msgpackdump([Todump])'))    end)    it('fails to dump a function reference in a list', function()      execute('let todump = [function("tr")]') -    eq('Vim(call):E951: Error while dumping msgpackdump() argument, index 0, index 0: attempt to dump function reference', +    eq('Vim(call):E5004: Error while dumping msgpackdump() argument, index 0, index 0: attempt to dump function reference',         exc_exec('call msgpackdump([todump])'))    end)    it('fails to dump a recursive list', function()      execute('let todump = [[[]]]')      execute('call add(todump[0][0], todump)') -    eq('Vim(call):E952: Unable to dump msgpackdump() argument, index 0: container references itself in index 0, index 0, index 0', +    eq('Vim(call):E5005: Unable to dump msgpackdump() argument, index 0: container references itself in index 0, index 0, index 0',         exc_exec('call msgpackdump([todump])'))    end)    it('fails to dump a recursive dict', function()      execute('let todump = {"d": {"d": {}}}')      execute('call extend(todump.d.d, {"d": todump})') -    eq('Vim(call):E952: Unable to dump msgpackdump() argument, index 0: container references itself in key \'d\', key \'d\', key \'d\'', +    eq('Vim(call):E5005: Unable to dump msgpackdump() argument, index 0: container references itself in key \'d\', key \'d\', key \'d\'',         exc_exec('call msgpackdump([todump])'))    end) @@ -605,35 +605,35 @@ describe('msgpackdump() function', function()    it('fails to dump a recursive list in a special dict', function()      execute('let todump = {"_TYPE": v:msgpack_types.array, "_VAL": []}')      execute('call add(todump._VAL, todump)') -    eq('Vim(call):E952: Unable to dump msgpackdump() argument, index 0: container references itself in index 0', +    eq('Vim(call):E5005: Unable to dump msgpackdump() argument, index 0: container references itself in index 0',         exc_exec('call msgpackdump([todump])'))    end)    it('fails to dump a recursive (key) map in a special dict', function()      execute('let todump = {"_TYPE": v:msgpack_types.map, "_VAL": []}')      execute('call add(todump._VAL, [todump, 0])') -    eq('Vim(call):E952: Unable to dump msgpackdump() argument, index 0: container references itself in index 1', +    eq('Vim(call):E5005: Unable to dump msgpackdump() argument, index 0: container references itself in index 1',         exc_exec('call msgpackdump([todump])'))    end)    it('fails to dump a recursive (val) map in a special dict', function()      execute('let todump = {"_TYPE": v:msgpack_types.map, "_VAL": []}')      execute('call add(todump._VAL, [0, todump])') -    eq('Vim(call):E952: Unable to dump msgpackdump() argument, index 0: container references itself in key 0 at index 0 from special map', +    eq('Vim(call):E5005: Unable to dump msgpackdump() argument, index 0: container references itself in key 0 at index 0 from special map',         exc_exec('call msgpackdump([todump])'))    end)    it('fails to dump a recursive (key) map in a special dict, _VAL reference', function()      execute('let todump = {"_TYPE": v:msgpack_types.map, "_VAL": [[[], []]]}')      execute('call add(todump._VAL[0][0], todump._VAL)') -    eq('Vim(call):E952: Unable to dump msgpackdump() argument, index 0: container references itself in key [[[[...@0], []]]] at index 0 from special map, index 0', +    eq('Vim(call):E5005: Unable to dump msgpackdump() argument, index 0: container references itself in key [[[[...@0], []]]] at index 0 from special map, index 0',         exc_exec('call msgpackdump([todump])'))    end)    it('fails to dump a recursive (val) map in a special dict, _VAL reference', function()      execute('let todump = {"_TYPE": v:msgpack_types.map, "_VAL": [[[], []]]}')      execute('call add(todump._VAL[0][1], todump._VAL)') -    eq('Vim(call):E952: Unable to dump msgpackdump() argument, index 0: container references itself in key [] at index 0 from special map, index 0', +    eq('Vim(call):E5005: Unable to dump msgpackdump() argument, index 0: container references itself in key [] at index 0 from special map, index 0',         exc_exec('call msgpackdump([todump])'))    end) @@ -641,7 +641,7 @@ describe('msgpackdump() function', function()    function()      execute('let todump = {"_TYPE": v:msgpack_types.array, "_VAL": []}')      execute('call add(todump._VAL, [0, todump._VAL])') -    eq('Vim(call):E952: Unable to dump msgpackdump() argument, index 0: container references itself in index 0, index 1', +    eq('Vim(call):E5005: Unable to dump msgpackdump() argument, index 0: container references itself in index 0, index 1',         exc_exec('call msgpackdump([todump])'))    end) diff --git a/test/functional/legacy/quickfix_spec.lua b/test/functional/legacy/quickfix_spec.lua index b5a8e10a97..5787ff8ff3 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,56 @@ 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 + +      func Test_caddbuffer_to_empty() +        helpgr quickfix +        call setqflist([], 'r') +        cad +        try +          silent cn +        catch +          " number of matches is unknown +          call assert_true(v:exception =~ 'E553:') +        endtry +        quit! +      endfunc        ]])    end) @@ -478,6 +528,24 @@ 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) + +  it('does not crash after using caddbuffer with an empty qf list', function() +    call('Test_caddbuffer_to_empty') +    expected_empty() +  end) + +  it('cgetexpr does not crash with a NULL element in a list', function() +    execute('cgetexpr [$x]') +    -- Still alive? +    eq(2, eval('1+1')) +  end)  end)  describe('errorformat', function() diff --git a/test/functional/shada/errors_spec.lua b/test/functional/shada/errors_spec.lua index 98ead6cc3d..19f35571d7 100644 --- a/test/functional/shada/errors_spec.lua +++ b/test/functional/shada/errors_spec.lua @@ -497,7 +497,7 @@ $    it('errors when a funcref is stored in a variable', function()      nvim_command('let F = function("tr")')      nvim_command('set shada+=!') -    eq('\nE951: Error while dumping variable g:F, itself: attempt to dump function reference' +    eq('\nE5004: Error while dumping variable g:F, itself: attempt to dump function reference'         .. '\nE574: Failed to write variable F',         redir_exec('wshada'))    end) @@ -506,7 +506,7 @@ $      nvim_command('let L = []')      nvim_command('call add(L, L)')      nvim_command('set shada+=!') -    eq('\nE952: Unable to dump variable g:L: container references itself in index 0' +    eq('\nE5005: Unable to dump variable g:L: container references itself in index 0'         .. '\nE574: Failed to write variable L',         redir_exec('wshada'))    end) diff --git a/test/functional/shada/variables_spec.lua b/test/functional/shada/variables_spec.lua index 15502f0b71..a420462437 100644 --- a/test/functional/shada/variables_spec.lua +++ b/test/functional/shada/variables_spec.lua @@ -132,7 +132,7 @@ describe('ShaDa support code', function()      meths.set_var('U', '10')      nvim_command('set shada+=!')      set_additional_cmd('set shada+=!') -    eq('Vim(wshada):E951: Error while dumping variable g:F, itself: attempt to dump function reference', +    eq('Vim(wshada):E5004: Error while dumping variable g:F, itself: attempt to dump function reference',         exc_exec('wshada'))      meths.set_option('shada', '')      reset() @@ -145,7 +145,7 @@ describe('ShaDa support code', function()      nvim_command('call add(L, L)')      meths.set_var('U', '10')      nvim_command('set shada+=!') -    eq('Vim(wshada):E952: Unable to dump variable g:L: container references itself in index 0', +    eq('Vim(wshada):E5005: Unable to dump variable g:L: container references itself in index 0',         exc_exec('wshada'))      meths.set_option('shada', '')      set_additional_cmd('set shada+=!')  | 
