aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--runtime/doc/quickfix.txt29
-rw-r--r--src/nvim/quickfix.c94
-rw-r--r--src/nvim/testdir/test_quickfix.vim59
3 files changed, 115 insertions, 67 deletions
diff --git a/runtime/doc/quickfix.txt b/runtime/doc/quickfix.txt
index 1198c097fe..c67e52bd42 100644
--- a/runtime/doc/quickfix.txt
+++ b/runtime/doc/quickfix.txt
@@ -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
<
diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c
index 9ed1f0e256..0aff3218d3 100644
--- a/src/nvim/quickfix.c
+++ b/src/nvim/quickfix.c
@@ -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
diff --git a/src/nvim/testdir/test_quickfix.vim b/src/nvim/testdir/test_quickfix.vim
index ed83a96906..06a0fd5001 100644
--- a/src/nvim/testdir/test_quickfix.vim
+++ b/src/nvim/testdir/test_quickfix.vim
@@ -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()