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.
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
every entry in a quickfix or a location list. The dict argument will have the
following fields:
to a Vim function. This function will be called with a dict argument and
should return a List of strings to be displayed in the quickfix or location
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
a location list.
@ -1919,12 +1919,14 @@ following fields:
location list. For a quickfix list, set to 0. Can be used in
getloclist() to get the location list entry.
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
window for the entry identified by idx. The function can obtain information
about the current entry using the |getqflist()| function and specifying the
quickfix list identifier "id" and the entry index "idx".
window for each entry from start_idx to end_idx. The function can obtain
information about the entries using the |getqflist()| function and specifying
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
'quickfixtextfunc' attribute of the list can be set using the |setqflist()| or
@ -1939,11 +1941,14 @@ Example: >
call setqflist([], ' ', {'lines' : v:oldfiles, 'efm' : '%f',
\ 'quickfixtextfunc' : 'QfOldFiles'})
func QfOldFiles(info)
" get information about the specific quickfix entry
let e = getqflist({'id' : a:info.id, 'idx' : a:info.idx,
\ 'items' : 1}).items[0]
" return the simplified file name
return fnamemodify(bufname(e.bufnr), ':p:.')
" get information about a range of quickfix entries
let items = getqflist({'id' : a:info.id, 'items' : 1}).items
let l = []
for idx in range(a:info.start_idx - 1, a:info.end_idx - 1)
" use the simplified file name
call add(l, fnamemodify(bufname(items[idx].bufnr), ':p:.'))
endfor
return l
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.
static int qf_buf_add_line(qf_list_T *qfl, buf_T *buf, linenr_T lnum,
const qfline_T *qfp,
char_u *dirname, int qf_winid, bool first_bufline)
FUNC_ATTR_NONNULL_ALL
const qfline_T *qfp, char_u *dirname,
char_u *qftf_str, bool first_bufline)
FUNC_ATTR_NONNULL_ARG(1, 2, 4, 5)
{
int len;
buf_T *errbuf;
char_u *qftf;
// If 'quickfixtextfunc' is set, then use the user-supplied function to get
// the text to display
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);
if (qftf_str != NULL) {
STRLCPY(IObuff, qftf_str, IOSIZE - 1);
} else {
if (qfp->qf_module != NULL) {
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;
}
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.
/// curbuf must be the quickfix buffer!
/// 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;
qfline_T *qfp;
const bool old_KeyTyped = KeyTyped;
list_T *qftf_list = NULL;
listitem_T *qftf_li = NULL;
if (old_last == NULL) {
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;
}
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) {
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) {
break;
}
@ -4084,6 +4104,10 @@ static void qf_fill_buffer(qf_list_T *qfl, buf_T *buf, qfline_T *old_last,
if (qfp == NULL) {
break;
}
if (qftf_li != NULL) {
qftf_li = TV_LIST_ITEM_NEXT(qftf_list, qftf_li);
}
}
if (old_last == NULL) {
// Delete the empty line which is now at the end

View File

@ -4809,24 +4809,27 @@ endfunc
" Test for the 'quickfixtextfunc' setting
func Tqfexpr(info)
if a:info.quickfix
let qfl = getqflist({'id' : a:info.id, 'idx' : a:info.idx,
\ 'items' : 1}).items
let qfl = getqflist({'id' : a:info.id, 'items' : 1}).items
else
let qfl = getloclist(a:info.winid, {'id' : a:info.id, 'idx' : a:info.idx,
\ 'items' : 1}).items
let qfl = getloclist(a:info.winid, {'id' : a:info.id, 'items' : 1}).items
endif
let e = qfl[0]
let s = ''
if e.bufnr != 0
let bname = bufname(e.bufnr)
let s ..= fnamemodify(bname, ':.')
endif
let s ..= '-'
let s ..= 'L' .. string(e.lnum) .. 'C' .. string(e.col) .. '-'
let s ..= e.text
return s
let l = []
for idx in range(a:info.start_idx - 1, a:info.end_idx - 1)
let e = qfl[idx]
let s = ''
if e.bufnr != 0
let bname = bufname(e.bufnr)
let s ..= fnamemodify(bname, ':.')
endif
let s ..= '-'
let s ..= 'L' .. string(e.lnum) .. 'C' .. string(e.col) .. '-'
let s ..= e.text
call add(l, s)
endfor
return l
endfunc
func Xtest_qftextfunc(cchar)
@ -4850,16 +4853,18 @@ func Xtest_qftextfunc(cchar)
" Test for per list 'quickfixtextfunc' setting
func PerQfText(info)
if a:info.quickfix
let qfl = getqflist({'id' : a:info.id, 'idx' : a:info.idx,
\ 'items' : 1}).items
let qfl = getqflist({'id' : a:info.id, 'items' : 1}).items
else
let qfl = getloclist(a:info.winid, {'id' : a:info.id, 'idx' : a:info.idx,
\ 'items' : 1}).items
let qfl = getloclist(a:info.winid, {'id' : a:info.id, 'items' : 1}).items
endif
if empty(qfl)
return ''
return []
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
set quickfixtextfunc=Tqfexpr
call g:Xsetlist([], ' ', {'quickfixtextfunc' : "PerQfText"})
@ -4902,8 +4907,22 @@ func Xtest_qftextfunc(cchar)
Xexpr ['F1:10:2:green', 'F1:20:4:blue']"
call assert_fails("Xwindow", 'E119:')
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&
delfunc Xqftext
delfunc Xqftext2
endfunc
func Test_qftextfunc()