diff options
| -rw-r--r-- | runtime/doc/eval.txt | 19 | ||||
| -rw-r--r-- | src/nvim/eval.c | 3 | ||||
| -rw-r--r-- | src/nvim/quickfix.c | 63 | ||||
| -rw-r--r-- | src/nvim/testdir/test_quickfix.vim | 109 | 
4 files changed, 178 insertions, 16 deletions
| diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt index e337c5d6d5..efc8775d0a 100644 --- a/runtime/doc/eval.txt +++ b/runtime/doc/eval.txt @@ -6855,16 +6855,19 @@ setqflist({list} [, {action}[, {what}]])		*setqflist()*  		Note that the list is not exactly the same as what  		|getqflist()| returns. -							*E927* -		If {action} is set to 'a', then the items from {list} are -		added to the existing quickfix list. If there is no existing -		list, then a new list is created. +		{action} values:				*E927* +		'a'	The items from {list} are added to the existing +			quickfix list. If there is no existing list, then a +			new list is created. -		If {action} is set to 'r', then the items from the current -		quickfix list are replaced with the items from {list}.  This -		can also be used to clear the list: > -			:call setqflist([], 'r') +		'r'	The items from the current quickfix list are replaced +			with the items from {list}.  This can also be used to +			clear the list: > +				:call setqflist([], 'r')  <	 +		'f'	All the quickfix lists in the quickfix stack are +			freed. +  		If {action} is not present or is set to ' ', then a new list  		is created. diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 7fa9f7563e..1461ddb8f9 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -14594,7 +14594,8 @@ static void set_qf_ll_list(win_T *wp, typval_T *args, typval_T *rettv)      return;    }    const char *const act = tv_get_string_chk(action_arg); -  if ((*act == 'a' || *act == 'r' || *act == ' ') && act[1] == NUL) { +  if ((*act == 'a' || *act == 'r' || *act == ' ' || *act == 'f') +      && act[1] == NUL) {      action = *act;    } else {      EMSG2(_(e_invact), act); diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c index 6d59d15515..73ad14ab22 100644 --- a/src/nvim/quickfix.c +++ b/src/nvim/quickfix.c @@ -4267,6 +4267,64 @@ static int qf_set_properties(qf_info_T *qi, dict_T *what, int action)    return retval;  } +// Find the non-location list window with the specified location list. +static win_T * find_win_with_ll(qf_info_T *qi) +{ +  FOR_ALL_WINDOWS_IN_TAB(wp, curtab) { +    if ((wp->w_llist == qi) && !bt_quickfix(wp->w_buffer)) { +      return wp; +    } +  } + +  return NULL; +} + +// Free the entire quickfix/location list stack. +// If the quickfix/location list window is open, then clear it. +static void qf_free_stack(win_T *wp, qf_info_T *qi) +{ +  win_T *qfwin = qf_find_win(qi); + +  if (qfwin != NULL) { +    // If the quickfix/location list window is open, then clear it +    if (qi->qf_curlist < qi->qf_listcount) { +      qf_free(qi, qi->qf_curlist); +    } +    qf_update_buffer(qi, NULL); +  } + +  win_T *llwin = NULL; +  win_T *orig_wp = wp; +  if (wp != NULL && IS_LL_WINDOW(wp)) { +    // If in the location list window, then use the non-location list +    // window with this location list (if present) +    llwin = find_win_with_ll(qi); +    if (llwin != NULL) { +      wp = llwin; +    } +  } + +  qf_free_all(wp); +  if (wp == NULL) { +    // quickfix list +    qi->qf_curlist = 0; +    qi->qf_listcount = 0; +  } else if (IS_LL_WINDOW(orig_wp)) { +    // If the location list window is open, then create a new empty location +    // list +    qf_info_T *new_ll = ll_new_list(); + +    // first free the list reference in the location list window +    ll_free_all(&orig_wp->w_llist_ref); + +    orig_wp->w_llist_ref = new_ll; +    if (llwin != NULL) { +      llwin->w_llist = new_ll; +      new_ll->qf_refcount++; +    } +  } +} +  // 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. @@ -4280,7 +4338,10 @@ int set_errorlist(win_T *wp, list_T *list, int action, char_u *title,      qi = ll_get_or_alloc_list(wp);    } -  if (what != NULL) { +  if (action == 'f') { +    // Free the entire quickfix or location list stack +    qf_free_stack(wp, qi); +  } else if (what != NULL) {      retval = qf_set_properties(qi, what, action);    } else {      retval = qf_add_entries(qi, list, title, action); diff --git a/src/nvim/testdir/test_quickfix.vim b/src/nvim/testdir/test_quickfix.vim index 3d8d18cf88..40ad387dee 100644 --- a/src/nvim/testdir/test_quickfix.vim +++ b/src/nvim/testdir/test_quickfix.vim @@ -38,6 +38,7 @@ func s:setup_commands(cchar)      command! -nargs=* Xhelpgrep helpgrep <args>      let g:Xgetlist = function('getqflist')      let g:Xsetlist = function('setqflist') +    call setqflist([], 'f')    else      command! -nargs=* -bang Xlist <mods>llist<bang> <args>      command! -nargs=* Xgetexpr <mods>lgetexpr <args> @@ -69,6 +70,7 @@ func s:setup_commands(cchar)      command! -nargs=* Xhelpgrep lhelpgrep <args>      let g:Xgetlist = function('getloclist', [0])      let g:Xsetlist = function('setloclist', [0]) +    call setloclist(0, [], 'f')    endif  endfunc @@ -76,6 +78,9 @@ endfunc  func XlistTests(cchar)    call s:setup_commands(a:cchar) +  if a:cchar == 'l' +      call assert_fails('llist', 'E776:') +  endif    " With an empty list, command should return error    Xgetexpr []    silent! Xlist @@ -146,6 +151,9 @@ endfunc  func XageTests(cchar)    call s:setup_commands(a:cchar) +  let list = [{'bufnr': 1, 'lnum': 1}] +  call g:Xsetlist(list) +    " Jumping to a non existent list should return error    silent! Xolder 99    call assert_true(v:errmsg ==# 'E380: At bottom of quickfix stack') @@ -179,11 +187,7 @@ func XageTests(cchar)  endfunc  func Test_cage() -  let list = [{'bufnr': 1, 'lnum': 1}] -  call setqflist(list)    call XageTests('c') - -  call setloclist(0, list)    call XageTests('l')  endfunc @@ -192,6 +196,11 @@ endfunc  func XwindowTests(cchar)    call s:setup_commands(a:cchar) +  " Opening the location list window without any errors should fail +  if a:cchar == 'l' +      call assert_fails('lopen', 'E776:') +  endif +    " Create a list with no valid entries    Xgetexpr ['non-error 1', 'non-error 2', 'non-error 3'] @@ -232,6 +241,19 @@ func XwindowTests(cchar)    " Calling cwindow should close the quickfix window with no valid errors    Xwindow    call assert_true(winnr('$') == 1) + +  if a:cchar == 'c' +      " Opening the quickfix window in multiple tab pages should reuse the +      " quickfix buffer +      Xgetexpr ['Xtestfile1:1:3:Line1', 'Xtestfile2:2:2:Line2', +		  \ 'Xtestfile3:3:1:Line3'] +      Xopen +      let qfbufnum = bufnr('%') +      tabnew +      Xopen +      call assert_equal(qfbufnum, bufnr('%')) +      new | only | tabonly +  endif  endfunc  func Test_cwindow() @@ -360,6 +382,13 @@ endfunc  func Xtest_browse(cchar)    call s:setup_commands(a:cchar) +  " Jumping to first or next location list entry without any error should +  " result in failure +  if a:cchar == 'l' +      call assert_fails('lfirst', 'E776:') +      call assert_fails('lnext', 'E776:') +  endif +    call s:create_test_file('Xqftestfile1')    call s:create_test_file('Xqftestfile2') @@ -1532,6 +1561,11 @@ endfunc  func XbottomTests(cchar)    call s:setup_commands(a:cchar) +  " Calling lbottom without any errors should fail +  if a:cchar == 'l' +      call assert_fails('lbottom', 'E776:') +  endif +    call g:Xsetlist([{'filename': 'foo', 'lnum': 42}])     Xopen    let wid = win_getid() @@ -1553,10 +1587,9 @@ endfunc  func HistoryTest(cchar)    call s:setup_commands(a:cchar) -  call assert_fails(a:cchar . 'older 99', 'E380:')    " clear all lists after the first one, then replace the first one.    call g:Xsetlist([]) -  Xolder +  call assert_fails('Xolder 99', 'E380:')    let entry = {'filename': 'foo', 'lnum': 42}    call g:Xsetlist([entry], 'r')    call g:Xsetlist([entry, entry]) @@ -1599,6 +1632,7 @@ func Xproperty_tests(cchar)      call assert_fails('call g:Xsetlist([], "a", [])', 'E715:')      " Set and get the title +    call g:Xsetlist([])      Xopen      wincmd p      call g:Xsetlist([{'filename':'foo', 'lnum':27}]) @@ -1860,3 +1894,66 @@ func Test_vimgrep()    call XvimgrepTests('c')    call XvimgrepTests('l')  endfunc + +func XfreeTests(cchar) +  call s:setup_commands(a:cchar) + +  enew | only + +  " Deleting the quickfix stack should work even When the current list is +  " somewhere in the middle of the stack +  Xexpr ['Xfile1:10:10:Line 10', 'Xfile1:15:15:Line 15'] +  Xexpr ['Xfile2:20:20:Line 20', 'Xfile2:25:25:Line 25'] +  Xexpr ['Xfile3:30:30:Line 30', 'Xfile3:35:35:Line 35'] +  Xolder +  call g:Xsetlist([], 'f') +  call assert_equal(0, len(g:Xgetlist())) + +  " After deleting the stack, adding a new list should create a stack with a +  " single list. +  Xexpr ['Xfile1:10:10:Line 10', 'Xfile1:15:15:Line 15'] +  call assert_equal(1, g:Xgetlist({'all':1}).nr) + +  " Deleting the stack from a quickfix window should update/clear the +  " quickfix/location list window. +  Xexpr ['Xfile1:10:10:Line 10', 'Xfile1:15:15:Line 15'] +  Xexpr ['Xfile2:20:20:Line 20', 'Xfile2:25:25:Line 25'] +  Xexpr ['Xfile3:30:30:Line 30', 'Xfile3:35:35:Line 35'] +  Xolder +  Xwindow +  call g:Xsetlist([], 'f') +  call assert_equal(2, winnr('$')) +  call assert_equal(1, line('$')) +  Xclose + +  " Deleting the stack from a non-quickfix window should update/clear the +  " quickfix/location list window. +  Xexpr ['Xfile1:10:10:Line 10', 'Xfile1:15:15:Line 15'] +  Xexpr ['Xfile2:20:20:Line 20', 'Xfile2:25:25:Line 25'] +  Xexpr ['Xfile3:30:30:Line 30', 'Xfile3:35:35:Line 35'] +  Xolder +  Xwindow +  wincmd p +  call g:Xsetlist([], 'f') +  call assert_equal(0, len(g:Xgetlist())) +  wincmd p +  call assert_equal(2, winnr('$')) +  call assert_equal(1, line('$')) + +  " After deleting the location list stack, if the location list window is +  " opened, then a new location list should be created. So opening the +  " location list window again should not create a new window. +  if a:cchar == 'l' +      lexpr ['Xfile1:10:10:Line 10', 'Xfile1:15:15:Line 15'] +      wincmd p +      lopen +      call assert_equal(2, winnr('$')) +  endif +  Xclose +endfunc + +" Tests for the quickifx free functionality +func Test_qf_free() +  call XfreeTests('c') +  call XfreeTests('l') +endfunc | 
