summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--runtime/doc/eval.txt14
-rw-r--r--src/quickfix.c23
-rw-r--r--src/testdir/test_quickfix.vim136
-rw-r--r--src/version.c2
4 files changed, 166 insertions, 9 deletions
diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt
index 0289b9fcb..2705f2a5b 100644
--- a/runtime/doc/eval.txt
+++ b/runtime/doc/eval.txt
@@ -6973,10 +6973,12 @@ setpos({expr}, {list})
|winrestview()|.
setqflist({list} [, {action}[, {what}]]) *setqflist()*
- Create or replace or add to the quickfix list using the items
- in {list}. Each item in {list} is a dictionary.
- Non-dictionary items in {list} are ignored. Each dictionary
- item can contain the following entries:
+ Create or replace or add to the quickfix list.
+
+ When {what} is not present, use the items in {list}. Each
+ item must be a dictionary. Non-dictionary items in {list} are
+ ignored. Each dictionary item can contain the following
+ entries:
bufnr buffer number; must be the number of a valid
buffer
@@ -7028,6 +7030,10 @@ setqflist({list} [, {action}[, {what}]]) *setqflist()*
argument is ignored. The following items can be specified in
{what}:
context any Vim type can be stored as a context
+ text use 'errorformat' to extract items from the
+ text and add the resulting entries to the
+ quickfix list {nr}. The value can be a string
+ with one line or a list with multiple lines.
items list of quickfix entries. Same as the {list}
argument.
nr list number in the quickfix stack; zero
diff --git a/src/quickfix.c b/src/quickfix.c
index 79cb4168d..75b58af3b 100644
--- a/src/quickfix.c
+++ b/src/quickfix.c
@@ -4885,7 +4885,7 @@ qf_add_entries(
}
static int
-qf_set_properties(qf_info_T *qi, dict_T *what, int action)
+qf_set_properties(qf_info_T *qi, dict_T *what, int action, char_u *title)
{
dictitem_T *di;
int retval = FAIL;
@@ -4929,7 +4929,7 @@ qf_set_properties(qf_info_T *qi, dict_T *what, int action)
if (newlist)
{
- qf_new_list(qi, NULL);
+ qf_new_list(qi, title);
qf_idx = qi->qf_curlist;
}
@@ -4957,6 +4957,23 @@ qf_set_properties(qf_info_T *qi, dict_T *what, int action)
}
}
+ if ((di = dict_find(what, (char_u *)"text", -1)) != NULL)
+ {
+ /* Only string and list values are supported */
+ if ((di->di_tv.v_type == VAR_STRING && di->di_tv.vval.v_string != NULL)
+ || (di->di_tv.v_type == VAR_LIST
+ && di->di_tv.vval.v_list != NULL))
+ {
+ if (action == 'r')
+ qf_free_items(qi, qf_idx);
+ if (qf_init_ext(qi, qf_idx, NULL, NULL, &di->di_tv, p_efm,
+ FALSE, (linenr_T)0, (linenr_T)0, NULL, NULL) > 0)
+ retval = OK;
+ }
+ else
+ return FAIL;
+ }
+
if ((di = dict_find(what, (char_u *)"context", -1)) != NULL)
{
typval_T *ctx;
@@ -5070,7 +5087,7 @@ set_errorlist(
qf_free_stack(wp, qi);
}
else if (what != NULL)
- retval = qf_set_properties(qi, what, action);
+ retval = qf_set_properties(qi, what, action, title);
else
retval = qf_add_entries(qi, qi->qf_curlist, list, title, action);
diff --git a/src/testdir/test_quickfix.vim b/src/testdir/test_quickfix.vim
index 41e502154..3acbd12df 100644
--- a/src/testdir/test_quickfix.vim
+++ b/src/testdir/test_quickfix.vim
@@ -1862,6 +1862,11 @@ func Xproperty_tests(cchar)
let l = g:Xgetlist({'items':1})
call assert_equal(0, len(l.items))
+ " The following used to crash Vim with address sanitizer
+ call g:Xsetlist([], 'f')
+ call g:Xsetlist([], 'a', {'items' : [{'filename':'F1', 'lnum':10}]})
+ call assert_equal(10, g:Xgetlist({'items':1}).items[0].lnum)
+
" Save and restore the quickfix stack
call g:Xsetlist([], 'f')
call assert_equal(0, g:Xgetlist({'nr':'$'}).nr)
@@ -2284,8 +2289,135 @@ func Xchangedtick_tests(cchar)
endfunc
func Test_changedtick()
- call Xchangedtick_tests('c')
- call Xchangedtick_tests('l')
+ call Xchangedtick_tests('c')
+ call Xchangedtick_tests('l')
+endfunc
+
+" Tests for parsing an expression using setqflist()
+func Xsetexpr_tests(cchar)
+ call s:setup_commands(a:cchar)
+
+ let t = ["File1:10:Line10", "File1:20:Line20"]
+ call g:Xsetlist([], ' ', {'text' : t})
+ call g:Xsetlist([], 'a', {'text' : "File1:30:Line30"})
+
+ let l = g:Xgetlist()
+ call assert_equal(3, len(l))
+ call assert_equal(20, l[1].lnum)
+ call assert_equal('Line30', l[2].text)
+ call g:Xsetlist([], 'r', {'text' : "File2:5:Line5"})
+ let l = g:Xgetlist()
+ call assert_equal(1, len(l))
+ call assert_equal('Line5', l[0].text)
+ call assert_equal(-1, g:Xsetlist([], 'a', {'text' : 10}))
+
+ call g:Xsetlist([], 'f')
+ " Add entries to multiple lists
+ call g:Xsetlist([], 'a', {'nr' : 1, 'text' : ["File1:10:Line10"]})
+ call g:Xsetlist([], 'a', {'nr' : 2, 'text' : ["File2:20:Line20"]})
+ call g:Xsetlist([], 'a', {'nr' : 1, 'text' : ["File1:15:Line15"]})
+ call g:Xsetlist([], 'a', {'nr' : 2, 'text' : ["File2:25:Line25"]})
+ call assert_equal('Line15', g:Xgetlist({'nr':1, 'items':1}).items[1].text)
+ call assert_equal('Line25', g:Xgetlist({'nr':2, 'items':1}).items[1].text)
+endfunc
+
+func Test_setexpr()
+ call Xsetexpr_tests('c')
+ call Xsetexpr_tests('l')
+endfunc
+
+" Tests for per quickfix/location list directory stack
+func Xmultidirstack_tests(cchar)
+ call s:setup_commands(a:cchar)
+
+ call g:Xsetlist([], 'f')
+ Xexpr "" | Xexpr ""
+
+ call g:Xsetlist([], 'a', {'nr' : 1, 'text' : "Entering dir 'Xone/a'"})
+ call g:Xsetlist([], 'a', {'nr' : 2, 'text' : "Entering dir 'Xtwo/a'"})
+ call g:Xsetlist([], 'a', {'nr' : 1, 'text' : "one.txt:3:one one one"})
+ call g:Xsetlist([], 'a', {'nr' : 2, 'text' : "two.txt:5:two two two"})
+
+ let l1 = g:Xgetlist({'nr':1, 'items':1})
+ let l2 = g:Xgetlist({'nr':2, 'items':1})
+ call assert_equal('Xone/a/one.txt', bufname(l1.items[1].bufnr))
+ call assert_equal(3, l1.items[1].lnum)
+ call assert_equal('Xtwo/a/two.txt', bufname(l2.items[1].bufnr))
+ call assert_equal(5, l2.items[1].lnum)
+endfunc
+
+func Test_multidirstack()
+ call mkdir('Xone/a', 'p')
+ call mkdir('Xtwo/a', 'p')
+ let lines = ['1', '2', 'one one one', '4', 'two two two', '6', '7']
+ call writefile(lines, 'Xone/a/one.txt')
+ call writefile(lines, 'Xtwo/a/two.txt')
+ let save_efm = &efm
+ set efm=%DEntering\ dir\ '%f',%f:%l:%m,%XLeaving\ dir\ '%f'
+
+ call Xmultidirstack_tests('c')
+ call Xmultidirstack_tests('l')
+
+ let &efm = save_efm
+ call delete('Xone', 'rf')
+ call delete('Xtwo', 'rf')
+endfunc
+
+" Tests for per quickfix/location list file stack
+func Xmultifilestack_tests(cchar)
+ call s:setup_commands(a:cchar)
+
+ call g:Xsetlist([], 'f')
+ Xexpr "" | Xexpr ""
+
+ call g:Xsetlist([], 'a', {'nr' : 1, 'text' : "[one.txt]"})
+ call g:Xsetlist([], 'a', {'nr' : 2, 'text' : "[two.txt]"})
+ call g:Xsetlist([], 'a', {'nr' : 1, 'text' : "(3,5) one one one"})
+ call g:Xsetlist([], 'a', {'nr' : 2, 'text' : "(5,9) two two two"})
+
+ let l1 = g:Xgetlist({'nr':1, 'items':1})
+ let l2 = g:Xgetlist({'nr':2, 'items':1})
+ call assert_equal('one.txt', bufname(l1.items[1].bufnr))
+ call assert_equal(3, l1.items[1].lnum)
+ call assert_equal('two.txt', bufname(l2.items[1].bufnr))
+ call assert_equal(5, l2.items[1].lnum)
+endfunc
+
+func Test_multifilestack()
+ let lines = ['1', '2', 'one one one', '4', 'two two two', '6', '7']
+ call writefile(lines, 'one.txt')
+ call writefile(lines, 'two.txt')
+ let save_efm = &efm
+ set efm=%+P[%f],(%l\\,%c)\ %m,%-Q
+
+ call Xmultifilestack_tests('c')
+ call Xmultifilestack_tests('l')
+
+ let &efm = save_efm
+ call delete('one.txt')
+ call delete('two.txt')
+endfunc
+
+" Tests for per buffer 'efm' setting
+func Test_perbuf_efm()
+ call writefile(["File1-10-Line10"], 'one.txt')
+ call writefile(["File2#20#Line20"], 'two.txt')
+ set efm=%f#%l#%m
+ new | only
+ new
+ setlocal efm=%f-%l-%m
+ cfile one.txt
+ wincmd w
+ caddfile two.txt
+
+ let l = getqflist()
+ call assert_equal(10, l[0].lnum)
+ call assert_equal('Line20', l[1].text)
+
+ set efm&
+ new | only
+ call delete('one.txt')
+ call delete('two.txt')
endfunc
" Open multiple help windows using ":lhelpgrep
diff --git a/src/version.c b/src/version.c
index 3f8e89077..f0e7062f7 100644
--- a/src/version.c
+++ b/src/version.c
@@ -770,6 +770,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 904,
+/**/
903,
/**/
902,