vim-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 vim/vim#6234)
00e260bb6c
This commit is contained in:
kevinhwang91 2021-05-04 13:57:00 +08:00
parent 00246d7be5
commit 19d4926f5a
3 changed files with 115 additions and 67 deletions

View File

@ -1909,9 +1909,9 @@ under the current directory tree. The file path may need to be simplified to a
common parent directory. common parent directory.
The displayed text can be customized by setting the 'quickfixtextfunc' option The displayed text can be customized by setting the 'quickfixtextfunc' option
to a Vim function. This function will be called with a dict argument for to a Vim function. This function will be called with a dict argument and
every entry in a quickfix or a location list. The dict argument will have the should return a List of strings to be displayed in the quickfix or location
following fields: list window. The dict argument will have the following fields:
quickfix set to 1 when called for a quickfix list and 0 when called for quickfix set to 1 when called for a quickfix list and 0 when called for
a location list. a location list.
@ -1919,12 +1919,14 @@ following fields:
location list. For a quickfix list, set to 0. Can be used in location list. For a quickfix list, set to 0. Can be used in
getloclist() to get the location list entry. getloclist() to get the location list entry.
id quickfix or location list identifier id quickfix or location list identifier
idx index of the entry in the quickfix or location list start_idx index of the first entry for which text should be returned
end_idx index of the last entry for which text should be returned
The function should return a single line of text to display in the quickfix The function should return a single line of text to display in the quickfix
window for the entry identified by idx. The function can obtain information window for each entry from start_idx to end_idx. The function can obtain
about the current entry using the |getqflist()| function and specifying the information about the entries using the |getqflist()| function and specifying
quickfix list identifier "id" and the entry index "idx". the quickfix list identifier "id". For a location list, getloclist() function
can be used with the 'winid' argument.
If a quickfix or location list specific customization is needed, then the If a quickfix or location list specific customization is needed, then the
'quickfixtextfunc' attribute of the list can be set using the |setqflist()| or 'quickfixtextfunc' attribute of the list can be set using the |setqflist()| or
@ -1939,11 +1941,14 @@ Example: >
call setqflist([], ' ', {'lines' : v:oldfiles, 'efm' : '%f', call setqflist([], ' ', {'lines' : v:oldfiles, 'efm' : '%f',
\ 'quickfixtextfunc' : 'QfOldFiles'}) \ 'quickfixtextfunc' : 'QfOldFiles'})
func QfOldFiles(info) func QfOldFiles(info)
" get information about the specific quickfix entry " get information about a range of quickfix entries
let e = getqflist({'id' : a:info.id, 'idx' : a:info.idx, let items = getqflist({'id' : a:info.id, 'items' : 1}).items
\ 'items' : 1}).items[0] let l = []
" return the simplified file name for idx in range(a:info.start_idx - 1, a:info.end_idx - 1)
return fnamemodify(bufname(e.bufnr), ':p:.') " use the simplified file name
call add(l, fnamemodify(bufname(items[idx].bufnr), ':p:.'))
endfor
return l
endfunc endfunc
< <

View File

@ -3924,44 +3924,15 @@ static void qf_update_buffer(qf_info_T *qi, qfline_T *old_last)
// Add an error line to the quickfix buffer. // Add an error line to the quickfix buffer.
static int qf_buf_add_line(qf_list_T *qfl, buf_T *buf, linenr_T lnum, static int qf_buf_add_line(qf_list_T *qfl, buf_T *buf, linenr_T lnum,
const qfline_T *qfp, const qfline_T *qfp, char_u *dirname,
char_u *dirname, int qf_winid, bool first_bufline) char_u *qftf_str, bool first_bufline)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_NONNULL_ARG(1, 2, 4, 5)
{ {
int len; int len;
buf_T *errbuf; buf_T *errbuf;
char_u *qftf;
// If 'quickfixtextfunc' is set, then use the user-supplied function to get if (qftf_str != NULL) {
// the text to display STRLCPY(IObuff, qftf_str, IOSIZE - 1);
qftf = p_qftf;
// Use the local value of 'quickfixtextfunc' if it is set.
if (qfl->qf_qftf != NULL) {
qftf = qfl->qf_qftf;
}
if (qftf != NULL && *qftf != NUL) {
char_u *qfbuf_text;
typval_T args[1];
// create the dict argument
dict_T *const dict = tv_dict_alloc_lock(VAR_FIXED);
tv_dict_add_nr(dict, S_LEN("quickfix"), IS_QF_LIST(qfl));
tv_dict_add_nr(dict, S_LEN("winid"), qf_winid);
tv_dict_add_nr(dict, S_LEN("id"), qfl->qf_id);
tv_dict_add_nr(dict, S_LEN("idx"), lnum + 1);
dict->dv_refcount++;
args[0].v_type = VAR_DICT;
args[0].vval.v_dict = dict;
qfbuf_text = (char_u *)call_func_retstr((const char *const)qftf, 1, args);
dict->dv_refcount--;
if (qfbuf_text == NULL) {
return FAIL;
}
STRLCPY(IObuff, qfbuf_text, IOSIZE - 1);
xfree(qfbuf_text);
} else { } else {
if (qfp->qf_module != NULL) { if (qfp->qf_module != NULL) {
STRLCPY(IObuff, qfp->qf_module, IOSIZE - 1); STRLCPY(IObuff, qfp->qf_module, IOSIZE - 1);
@ -4029,6 +4000,42 @@ static int qf_buf_add_line(qf_list_T *qfl, buf_T *buf, linenr_T lnum,
return OK; return OK;
} }
static list_T *call_qftf_func(qf_list_T *qfl,
int qf_winid,
long start_idx,
long end_idx)
{
char_u *qftf = p_qftf;
list_T *qftf_list = NULL;
// If 'quickfixtextfunc' is set, then use the user-supplied function to get
// the text to display. Use the local value of 'quickfixtextfunc' if it is
// set.
if (qfl->qf_qftf != NULL) {
qftf = qfl->qf_qftf;
}
if (qftf != NULL && *qftf != NUL) {
typval_T args[1];
// create the dict argument
dict_T *const dict = tv_dict_alloc_lock(VAR_FIXED);
tv_dict_add_nr(dict, S_LEN("quickfix"), IS_QF_LIST(qfl));
tv_dict_add_nr(dict, S_LEN("winid"), qf_winid);
tv_dict_add_nr(dict, S_LEN("id"), qfl->qf_id);
tv_dict_add_nr(dict, S_LEN("start_idx"), start_idx);
tv_dict_add_nr(dict, S_LEN("end_idx"), end_idx);
dict->dv_refcount++;
args[0].v_type = VAR_DICT;
args[0].vval.v_dict = dict;
qftf_list = call_func_retlist(qftf, 1, args);
dict->dv_refcount--;
}
return qftf_list;
}
/// Fill current buffer with quickfix errors, replacing any previous contents. /// Fill current buffer with quickfix errors, replacing any previous contents.
/// curbuf must be the quickfix buffer! /// curbuf must be the quickfix buffer!
/// If "old_last" is not NULL append the items after this one. /// If "old_last" is not NULL append the items after this one.
@ -4041,6 +4048,8 @@ static void qf_fill_buffer(qf_list_T *qfl, buf_T *buf, qfline_T *old_last,
linenr_T lnum; linenr_T lnum;
qfline_T *qfp; qfline_T *qfp;
const bool old_KeyTyped = KeyTyped; const bool old_KeyTyped = KeyTyped;
list_T *qftf_list = NULL;
listitem_T *qftf_li = NULL;
if (old_last == NULL) { if (old_last == NULL) {
if (buf != curbuf) { if (buf != curbuf) {
@ -4073,8 +4082,19 @@ static void qf_fill_buffer(qf_list_T *qfl, buf_T *buf, qfline_T *old_last,
} }
lnum = buf->b_ml.ml_line_count; lnum = buf->b_ml.ml_line_count;
} }
qftf_list = call_qftf_func(qfl, qf_winid, lnum + 1, (long)qfl->qf_count);
qftf_li = tv_list_first(qftf_list);
while (lnum < qfl->qf_count) { while (lnum < qfl->qf_count) {
if (qf_buf_add_line(qfl, buf, lnum, qfp, dirname, qf_winid, char_u *qftf_str = NULL;
if (qftf_li != NULL) {
// Use the text supplied by the user defined function
qftf_str = (char_u *)tv_get_string_chk(TV_LIST_ITEM_TV(qftf_li));
}
if (qf_buf_add_line(qfl, buf, lnum, qfp, dirname, qftf_str,
prev_bufnr != qfp->qf_fnum) == FAIL) { prev_bufnr != qfp->qf_fnum) == FAIL) {
break; break;
} }
@ -4084,6 +4104,10 @@ static void qf_fill_buffer(qf_list_T *qfl, buf_T *buf, qfline_T *old_last,
if (qfp == NULL) { if (qfp == NULL) {
break; break;
} }
if (qftf_li != NULL) {
qftf_li = TV_LIST_ITEM_NEXT(qftf_list, qftf_li);
}
} }
if (old_last == NULL) { if (old_last == NULL) {
// Delete the empty line which is now at the end // Delete the empty line which is now at the end

View File

@ -4809,14 +4809,15 @@ endfunc
" Test for the 'quickfixtextfunc' setting " Test for the 'quickfixtextfunc' setting
func Tqfexpr(info) func Tqfexpr(info)
if a:info.quickfix if a:info.quickfix
let qfl = getqflist({'id' : a:info.id, 'idx' : a:info.idx, let qfl = getqflist({'id' : a:info.id, 'items' : 1}).items
\ 'items' : 1}).items
else else
let qfl = getloclist(a:info.winid, {'id' : a:info.id, 'idx' : a:info.idx, let qfl = getloclist(a:info.winid, {'id' : a:info.id, 'items' : 1}).items
\ 'items' : 1}).items
endif endif
let e = qfl[0]
let l = []
for idx in range(a:info.start_idx - 1, a:info.end_idx - 1)
let e = qfl[idx]
let s = '' let s = ''
if e.bufnr != 0 if e.bufnr != 0
let bname = bufname(e.bufnr) let bname = bufname(e.bufnr)
@ -4825,8 +4826,10 @@ func Tqfexpr(info)
let s ..= '-' let s ..= '-'
let s ..= 'L' .. string(e.lnum) .. 'C' .. string(e.col) .. '-' let s ..= 'L' .. string(e.lnum) .. 'C' .. string(e.col) .. '-'
let s ..= e.text let s ..= e.text
call add(l, s)
endfor
return s return l
endfunc endfunc
func Xtest_qftextfunc(cchar) func Xtest_qftextfunc(cchar)
@ -4850,16 +4853,18 @@ func Xtest_qftextfunc(cchar)
" Test for per list 'quickfixtextfunc' setting " Test for per list 'quickfixtextfunc' setting
func PerQfText(info) func PerQfText(info)
if a:info.quickfix if a:info.quickfix
let qfl = getqflist({'id' : a:info.id, 'idx' : a:info.idx, let qfl = getqflist({'id' : a:info.id, 'items' : 1}).items
\ 'items' : 1}).items
else else
let qfl = getloclist(a:info.winid, {'id' : a:info.id, 'idx' : a:info.idx, let qfl = getloclist(a:info.winid, {'id' : a:info.id, 'items' : 1}).items
\ 'items' : 1}).items
endif endif
if empty(qfl) if empty(qfl)
return '' return []
endif endif
return 'Line ' .. qfl[0].lnum .. ', Col ' .. qfl[0].col let l = []
for idx in range(a:info.start_idx - 1, a:info.end_idx - 1)
call add(l, 'Line ' .. qfl[idx].lnum .. ', Col ' .. qfl[idx].col)
endfor
return l
endfunc endfunc
set quickfixtextfunc=Tqfexpr set quickfixtextfunc=Tqfexpr
call g:Xsetlist([], ' ', {'quickfixtextfunc' : "PerQfText"}) call g:Xsetlist([], ' ', {'quickfixtextfunc' : "PerQfText"})
@ -4902,8 +4907,22 @@ func Xtest_qftextfunc(cchar)
Xexpr ['F1:10:2:green', 'F1:20:4:blue']" Xexpr ['F1:10:2:green', 'F1:20:4:blue']"
call assert_fails("Xwindow", 'E119:') call assert_fails("Xwindow", 'E119:')
Xclose Xclose
" set option to a function that returns a list with non-strings
func Xqftext2(d)
return ['one', [], 'two']
endfunc
set quickfixtextfunc=Xqftext2
" call assert_fails("Xexpr ['F1:10:2:green', 'F1:20:4:blue', 'F1:30:6:red']",
" \ 'E730:')
Xexpr ['F1:10:2:green', 'F1:20:4:blue', 'F1:30:6:red']
call assert_fails('Xwindow', 'E730:')
call assert_equal(['one', 'F1|20 col 4| blue', 'two'], getline(1, '$'))
Xclose
set quickfixtextfunc& set quickfixtextfunc&
delfunc Xqftext delfunc Xqftext
delfunc Xqftext2
endfunc endfunc
func Test_qftextfunc() func Test_qftextfunc()