Skip to content

Commit 00e260b

Browse files
committed
patch 8.2.0959: using 'quickfixtextfunc' is a bit slow
Problem: Using 'quickfixtextfunc' is a bit slow. Solution: Process a list of entries. (Yegappan Lakshmanan, closes #6234)
1 parent 1de5f7c commit 00e260b

File tree

4 files changed

+112
-68
lines changed

4 files changed

+112
-68
lines changed

runtime/doc/quickfix.txt

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1947,22 +1947,24 @@ under the current directory tree. The file path may need to be simplified to a
19471947
common parent directory.
19481948

19491949
The displayed text can be customized by setting the 'quickfixtextfunc' option
1950-
to a Vim function. This function will be called with a dict argument for
1951-
every entry in a quickfix or a location list. The dict argument will have the
1952-
following fields:
1950+
to a Vim function. This function will be called with a dict argument and
1951+
should return a List of strings to be displayed in the quickfix or location
1952+
list window. The dict argument will have the following fields:
19531953

19541954
quickfix set to 1 when called for a quickfix list and 0 when called for
19551955
a location list.
19561956
winid for a location list, set to the id of the window with the
19571957
location list. For a quickfix list, set to 0. Can be used in
19581958
getloclist() to get the location list entry.
19591959
id quickfix or location list identifier
1960-
idx index of the entry in the quickfix or location list
1960+
start_idx index of the first entry for which text should be returned
1961+
end_idx index of the last entry for which text should be returned
19611962

19621963
The function should return a single line of text to display in the quickfix
1963-
window for the entry identified by idx. The function can obtain information
1964-
about the current entry using the |getqflist()| function and specifying the
1965-
quickfix list identifier "id" and the entry index "idx".
1964+
window for each entry from start_idx to end_idx. The function can obtain
1965+
information about the entries using the |getqflist()| function and specifying
1966+
the quickfix list identifier "id". For a location list, getloclist() function
1967+
can be used with the 'winid' argument.
19661968

19671969
If a quickfix or location list specific customization is needed, then the
19681970
'quickfixtextfunc' attribute of the list can be set using the |setqflist()| or
@@ -1977,11 +1979,14 @@ Example: >
19771979
call setqflist([], ' ', {'lines' : v:oldfiles, 'efm' : '%f',
19781980
\ 'quickfixtextfunc' : 'QfOldFiles'})
19791981
func QfOldFiles(info)
1980-
" get information about the specific quickfix entry
1981-
let e = getqflist({'id' : a:info.id, 'idx' : a:info.idx,
1982-
\ 'items' : 1}).items[0]
1983-
" return the simplified file name
1984-
return fnamemodify(bufname(e.bufnr), ':p:.')
1982+
" get information about a range of quickfix entries
1983+
let items = getqflist({'id' : a:info.id, 'items' : 1}).items
1984+
let l = []
1985+
for idx in range(a:info.start_idx - 1, a:info.end_idx - 1)
1986+
" use the simplified file name
1987+
call add(l, fnamemodify(bufname(items[idx].bufnr), ':p:.'))
1988+
endfor
1989+
return l
19851990
endfunc
19861991
<
19871992

src/quickfix.c

Lines changed: 56 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -4415,49 +4415,17 @@ qf_update_buffer(qf_info_T *qi, qfline_T *old_last)
44154415
*/
44164416
static int
44174417
qf_buf_add_line(
4418-
qf_list_T *qfl, // quickfix list
44194418
buf_T *buf, // quickfix window buffer
44204419
linenr_T lnum,
44214420
qfline_T *qfp,
44224421
char_u *dirname,
4423-
int qf_winid)
4422+
char_u *qftf_str)
44244423
{
44254424
int len;
44264425
buf_T *errbuf;
4427-
char_u *qftf;
44284426

4429-
// If 'quickfixtextfunc' is set, then use the user-supplied function to get
4430-
// the text to display
4431-
qftf = p_qftf;
4432-
// Use the local value of 'quickfixtextfunc' if it is set.
4433-
if (qfl->qf_qftf != NULL)
4434-
qftf = qfl->qf_qftf;
4435-
if (qftf != NULL && *qftf != NUL)
4436-
{
4437-
char_u *qfbuf_text;
4438-
typval_T args[1];
4439-
dict_T *d;
4440-
4441-
// create the dict argument
4442-
if ((d = dict_alloc_lock(VAR_FIXED)) == NULL)
4443-
return FAIL;
4444-
dict_add_number(d, "quickfix", (long)IS_QF_LIST(qfl));
4445-
dict_add_number(d, "winid", (long)qf_winid);
4446-
dict_add_number(d, "id", (long)qfl->qf_id);
4447-
dict_add_number(d, "idx", (long)(lnum + 1));
4448-
++d->dv_refcount;
4449-
args[0].v_type = VAR_DICT;
4450-
args[0].vval.v_dict = d;
4451-
4452-
qfbuf_text = call_func_retstr(qftf, 1, args);
4453-
--d->dv_refcount;
4454-
4455-
if (qfbuf_text == NULL)
4456-
return FAIL;
4457-
4458-
vim_strncpy(IObuff, qfbuf_text, IOSIZE - 1);
4459-
vim_free(qfbuf_text);
4460-
}
4427+
if (qftf_str != NULL)
4428+
vim_strncpy(IObuff, qftf_str, IOSIZE - 1);
44614429
else
44624430
{
44634431
if (qfp->qf_module != NULL)
@@ -4533,6 +4501,41 @@ qf_buf_add_line(
45334501
return OK;
45344502
}
45354503

4504+
static list_T *
4505+
call_qftf_func(qf_list_T *qfl, int qf_winid, long start_idx, long end_idx)
4506+
{
4507+
char_u *qftf = p_qftf;
4508+
list_T *qftf_list = NULL;
4509+
4510+
// If 'quickfixtextfunc' is set, then use the user-supplied function to get
4511+
// the text to display. Use the local value of 'quickfixtextfunc' if it is
4512+
// set.
4513+
if (qfl->qf_qftf != NULL)
4514+
qftf = qfl->qf_qftf;
4515+
if (qftf != NULL && *qftf != NUL)
4516+
{
4517+
typval_T args[1];
4518+
dict_T *d;
4519+
4520+
// create the dict argument
4521+
if ((d = dict_alloc_lock(VAR_FIXED)) == NULL)
4522+
return NULL;
4523+
dict_add_number(d, "quickfix", (long)IS_QF_LIST(qfl));
4524+
dict_add_number(d, "winid", (long)qf_winid);
4525+
dict_add_number(d, "id", (long)qfl->qf_id);
4526+
dict_add_number(d, "start_idx", start_idx);
4527+
dict_add_number(d, "end_idx", end_idx);
4528+
++d->dv_refcount;
4529+
args[0].v_type = VAR_DICT;
4530+
args[0].vval.v_dict = d;
4531+
4532+
qftf_list = call_func_retlist(qftf, 1, args);
4533+
--d->dv_refcount;
4534+
}
4535+
4536+
return qftf_list;
4537+
}
4538+
45364539
/*
45374540
* Fill current buffer with quickfix errors, replacing any previous contents.
45384541
* curbuf must be the quickfix buffer!
@@ -4546,6 +4549,8 @@ qf_fill_buffer(qf_list_T *qfl, buf_T *buf, qfline_T *old_last, int qf_winid)
45464549
linenr_T lnum;
45474550
qfline_T *qfp;
45484551
int old_KeyTyped = KeyTyped;
4552+
list_T *qftf_list = NULL;
4553+
listitem_T *qftf_li = NULL;
45494554

45504555
if (old_last == NULL)
45514556
{
@@ -4578,15 +4583,30 @@ qf_fill_buffer(qf_list_T *qfl, buf_T *buf, qfline_T *old_last, int qf_winid)
45784583
qfp = old_last->qf_next;
45794584
lnum = buf->b_ml.ml_line_count;
45804585
}
4586+
4587+
qftf_list = call_qftf_func(qfl, qf_winid, (long)(lnum + 1),
4588+
(long)qfl->qf_count);
4589+
if (qftf_list != NULL)
4590+
qftf_li = qftf_list->lv_first;
4591+
45814592
while (lnum < qfl->qf_count)
45824593
{
4583-
if (qf_buf_add_line(qfl, buf, lnum, qfp, dirname, qf_winid) == FAIL)
4594+
char_u *qftf_str = NULL;
4595+
4596+
if (qftf_li != NULL)
4597+
// Use the text supplied by the user defined function
4598+
qftf_str = tv_get_string_chk(&qftf_li->li_tv);
4599+
4600+
if (qf_buf_add_line(buf, lnum, qfp, dirname, qftf_str) == FAIL)
45844601
break;
45854602

45864603
++lnum;
45874604
qfp = qfp->qf_next;
45884605
if (qfp == NULL)
45894606
break;
4607+
4608+
if (qftf_li != NULL)
4609+
qftf_li = qftf_li->li_next;
45904610
}
45914611

45924612
if (old_last == NULL)

src/testdir/test_quickfix.vim

Lines changed: 37 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -4818,24 +4818,26 @@ endfunc
48184818
" Test for the 'quickfixtextfunc' setting
48194819
func Tqfexpr(info)
48204820
if a:info.quickfix
4821-
let qfl = getqflist({'id' : a:info.id, 'idx' : a:info.idx,
4822-
\ 'items' : 1}).items
4821+
let qfl = getqflist({'id' : a:info.id, 'items' : 1}).items
48234822
else
4824-
let qfl = getloclist(a:info.winid, {'id' : a:info.id, 'idx' : a:info.idx,
4825-
\ 'items' : 1}).items
4823+
let qfl = getloclist(a:info.winid, {'id' : a:info.id, 'items' : 1}).items
48264824
endif
48274825

4828-
let e = qfl[0]
4829-
let s = ''
4830-
if e.bufnr != 0
4831-
let bname = bufname(e.bufnr)
4832-
let s ..= fnamemodify(bname, ':.')
4833-
endif
4834-
let s ..= '-'
4835-
let s ..= 'L' .. string(e.lnum) .. 'C' .. string(e.col) .. '-'
4836-
let s ..= e.text
4826+
let l = []
4827+
for idx in range(a:info.start_idx - 1, a:info.end_idx - 1)
4828+
let e = qfl[idx]
4829+
let s = ''
4830+
if e.bufnr != 0
4831+
let bname = bufname(e.bufnr)
4832+
let s ..= fnamemodify(bname, ':.')
4833+
endif
4834+
let s ..= '-'
4835+
let s ..= 'L' .. string(e.lnum) .. 'C' .. string(e.col) .. '-'
4836+
let s ..= e.text
4837+
call add(l, s)
4838+
endfor
48374839

4838-
return s
4840+
return l
48394841
endfunc
48404842

48414843
func Xtest_qftextfunc(cchar)
@@ -4859,16 +4861,18 @@ func Xtest_qftextfunc(cchar)
48594861
" Test for per list 'quickfixtextfunc' setting
48604862
func PerQfText(info)
48614863
if a:info.quickfix
4862-
let qfl = getqflist({'id' : a:info.id, 'idx' : a:info.idx,
4863-
\ 'items' : 1}).items
4864+
let qfl = getqflist({'id' : a:info.id, 'items' : 1}).items
48644865
else
4865-
let qfl = getloclist(a:info.winid, {'id' : a:info.id, 'idx' : a:info.idx,
4866-
\ 'items' : 1}).items
4866+
let qfl = getloclist(a:info.winid, {'id' : a:info.id, 'items' : 1}).items
48674867
endif
48684868
if empty(qfl)
4869-
return ''
4869+
return []
48704870
endif
4871-
return 'Line ' .. qfl[0].lnum .. ', Col ' .. qfl[0].col
4871+
let l = []
4872+
for idx in range(a:info.start_idx - 1, a:info.end_idx - 1)
4873+
call add(l, 'Line ' .. qfl[idx].lnum .. ', Col ' .. qfl[idx].col)
4874+
endfor
4875+
return l
48724876
endfunc
48734877
set quickfixtextfunc=Tqfexpr
48744878
call g:Xsetlist([], ' ', {'quickfixtextfunc' : "PerQfText"})
@@ -4908,8 +4912,21 @@ func Xtest_qftextfunc(cchar)
49084912
call assert_fails("Xexpr ['F1:10:2:green', 'F1:20:4:blue']", 'E119:')
49094913
call assert_fails("Xwindow", 'E119:')
49104914
Xclose
4915+
4916+
" set option to a function that returns a list with non-strings
4917+
func Xqftext2(d)
4918+
return ['one', [], 'two']
4919+
endfunc
4920+
set quickfixtextfunc=Xqftext2
4921+
call assert_fails("Xexpr ['F1:10:2:green', 'F1:20:4:blue', 'F1:30:6:red']",
4922+
\ 'E730:')
4923+
call assert_fails('Xwindow', 'E730:')
4924+
call assert_equal(['one', 'F1|20 col 4| blue', 'two'], getline(1, '$'))
4925+
Xclose
4926+
49114927
set quickfixtextfunc&
49124928
delfunc Xqftext
4929+
delfunc Xqftext2
49134930
endfunc
49144931

49154932
func Test_qftextfunc()

src/version.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -754,6 +754,8 @@ static char *(features[]) =
754754

755755
static int included_patches[] =
756756
{ /* Add new patch number below this line */
757+
/**/
758+
959,
757759
/**/
758760
958,
759761
/**/

0 commit comments

Comments
 (0)