summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2020-05-31 23:11:59 +0200
committerBram Moolenaar <Bram@vim.org>2020-05-31 23:11:59 +0200
commit858ba06d5f577b187da0367b231f7fa9461cb32d (patch)
tree89e7da14ddfacad9663c1289d8c71d57d81206f9
parent2245ae18e3480057f98fc0e5d9f18091f32a5de0 (diff)
downloadvim-git-858ba06d5f577b187da0367b231f7fa9461cb32d.tar.gz
patch 8.2.0869: it is not possible to customize the quickfix window contentsv8.2.0869
Problem: It is not possible to customize the quickfix window contents. Solution: Add 'quickfixtextfunc'. (Yegappan Lakshmanan, closes #5465)
-rw-r--r--runtime/doc/eval.txt12
-rw-r--r--runtime/doc/options.txt15
-rw-r--r--runtime/doc/quickfix.txt56
-rw-r--r--src/option.h1
-rw-r--r--src/optiondefs.h9
-rw-r--r--src/quickfix.c226
-rw-r--r--src/testdir/test_quickfix.vim117
-rw-r--r--src/version.c2
8 files changed, 367 insertions, 71 deletions
diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt
index b753aae62..fb0b2a789 100644
--- a/runtime/doc/eval.txt
+++ b/runtime/doc/eval.txt
@@ -5508,8 +5508,9 @@ getqflist([{what}]) *getqflist()*
id get information for the quickfix list with
|quickfix-ID|; zero means the id for the
current list or the list specified by "nr"
- idx index of the current entry in the quickfix
- list specified by 'id' or 'nr'.
+ idx get information for the quickfix entry at this
+ index in the list specified by 'id' or 'nr'.
+ If set to zero, then uses the current entry.
See |quickfix-index|
items quickfix list entries
lines parse a list of lines using 'efm' and return
@@ -5545,7 +5546,7 @@ getqflist([{what}]) *getqflist()*
If not present, set to "".
id quickfix list ID |quickfix-ID|. If not
present, set to 0.
- idx index of the current entry in the list. If not
+ idx index of the quickfix entry in the list. If not
present, set to 0.
items quickfix list entries. If not present, set to
an empty list.
@@ -8841,6 +8842,11 @@ setqflist({list} [, {action} [, {what}]]) *setqflist()*
nr list number in the quickfix stack; zero
means the current quickfix list and "$" means
the last quickfix list.
+ quickfixtextfunc
+ function to get the text to display in the
+ quickfix window. Refer to
+ |quickfix-window-function| for an explanation
+ of how to write the function and an example.
title quickfix list title text. See |quickfix-title|
Unsupported keys in {what} are ignored.
If the "nr" item is not present, then the current quickfix list
diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt
index d4d87872c..82b91a610 100644
--- a/runtime/doc/options.txt
+++ b/runtime/doc/options.txt
@@ -5901,6 +5901,21 @@ A jump table for the options with a short description can be found at |Q_op|.
This option cannot be set from a |modeline| or in the |sandbox|, for
security reasons.
+ *'quickfixtextfunc'* *'qftf'*
+'quickfixtextfunc' 'qftf' string (default "")
+ global
+ {only available when compiled with the |+quickfix|
+ feature}
+ This option specifies a function to be used to get the text to display
+ in the quickfix and location list windows. This can be used to
+ customize the information displayed in the quickfix or location window
+ for each entry in the corresponding quickfix or location list. See
+ |quickfix-window-function| for an explanation of how to write the
+ function and an example.
+
+ This option cannot be set from a |modeline| or in the |sandbox|, for
+ security reasons.
+
*'quoteescape'* *'qe'*
'quoteescape' 'qe' string (default "\")
local to buffer
diff --git a/runtime/doc/quickfix.txt b/runtime/doc/quickfix.txt
index 7f7f10fac..d4ebf5c48 100644
--- a/runtime/doc/quickfix.txt
+++ b/runtime/doc/quickfix.txt
@@ -15,6 +15,7 @@ This subject is introduced in section |30.1| of the user manual.
7. The error format |error-file-format|
8. The directory stack |quickfix-directory-stack|
9. Specific error file formats |errorformats|
+10. Customizing the quickfix window |quickfix-window-function|
The quickfix commands are not available when the |+quickfix| feature was
disabled at compile time.
@@ -1921,6 +1922,59 @@ error messages into a format that quickfix mode will understand. See the
start of the file about how to use it. (This script is deprecated, see
|compiler-perl|.)
-
+=============================================================================
+10. Customizing the quickfix window *quickfix-window-function*
+
+The default format for the lines displayed in the quickfix window and location
+list window is:
+
+ <filename>|<lnum> col <col>|<text>
+
+The values displayed in each line correspond to the "bufnr", "lnum", "col" and
+"text" fields returned by the |getqflist()| function.
+
+For some quickfix/location lists, the displayed text need to be customized.
+For example, if only the filename is present for a quickfix entry, then the
+two "|" field separator characters after the filename are not needed. Another
+use case is to customize the path displayed for a filename. By default, the
+complete path (which may be too long) is displayed for files which are not
+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:
+
+ quickfix set to 1 when called for a quickfix list and 0 when called for
+ a location list.
+ id quickfix or location list identifier
+ idx index of the entry in the quickfix or location list
+
+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".
+
+If a quickfix or location list specific customization is needed, then the
+'quickfixtextfunc' attribute of the list can be set using the |setqflist()| or
+|setloclist()| function. This overrides the global 'quickfixtextfunc' option.
+
+The example below displays the list of old files (|v:oldfiles|) in a quickfix
+window. As there is no line, column number and error text information
+associated with each entry, the 'quickfixtextfunc' function returns only the
+filename.
+Example: >
+ " create a quickfix list from v:oldfiles
+ 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:.')
+ endfunc
+<
vim:tw=78:ts=8:noet:ft=help:norl:
diff --git a/src/option.h b/src/option.h
index bead4c5bb..718553a90 100644
--- a/src/option.h
+++ b/src/option.h
@@ -820,6 +820,7 @@ EXTERN int p_ru; // 'ruler'
EXTERN char_u *p_ruf; // 'rulerformat'
#endif
EXTERN char_u *p_pp; // 'packpath'
+EXTERN char_u *p_qftf; // 'quickfixtextfunc'
EXTERN char_u *p_rtp; // 'runtimepath'
EXTERN long p_sj; // 'scrolljump'
#if defined(MSWIN) && defined(FEAT_GUI)
diff --git a/src/optiondefs.h b/src/optiondefs.h
index 5ed9be9bc..571a3af5e 100644
--- a/src/optiondefs.h
+++ b/src/optiondefs.h
@@ -2045,6 +2045,15 @@ static struct vimoption options[] =
#endif
{(char_u *)DEFAULT_PYTHON_VER, (char_u *)0L}
SCTX_INIT},
+ {"quickfixtextfunc", "qftf", P_STRING|P_ALLOCED|P_VI_DEF|P_VIM|P_SECURE,
+#if defined(FEAT_QUICKFIX) && defined(FEAT_EVAL)
+ (char_u *)&p_qftf, PV_NONE,
+ {(char_u *)"", (char_u *)0L}
+#else
+ (char_u *)NULL, PV_NONE,
+ {(char_u *)NULL, (char_u *)NULL}
+#endif
+ SCTX_INIT},
{"quoteescape", "qe", P_STRING|P_ALLOCED|P_VI_DEF,
#ifdef FEAT_TEXTOBJ
(char_u *)&p_qe, PV_QE,
diff --git a/src/quickfix.c b/src/quickfix.c
index f3ad4cde2..acd28a143 100644
--- a/src/quickfix.c
+++ b/src/quickfix.c
@@ -82,6 +82,7 @@ typedef struct qf_list_S
char_u *qf_title; // title derived from the command that created
// the error list or set by setqflist
typval_T *qf_ctx; // context set by setqflist/setloclist
+ char_u *qf_qftf; // 'quickfixtextfunc' setting for this list
struct dir_stack_T *qf_dir_stack;
char_u *qf_directory;
@@ -2277,6 +2278,10 @@ copy_loclist(qf_list_T *from_qfl, qf_list_T *to_qfl)
}
else
to_qfl->qf_ctx = NULL;
+ if (from_qfl->qf_qftf != NULL)
+ to_qfl->qf_qftf = vim_strsave(from_qfl->qf_qftf);
+ else
+ to_qfl->qf_qftf = NULL;
if (from_qfl->qf_count)
if (copy_loclist_entries(from_qfl, to_qfl) == FAIL)
@@ -3812,6 +3817,7 @@ qf_free(qf_list_T *qfl)
VIM_CLEAR(qfl->qf_title);
free_tv(qfl->qf_ctx);
qfl->qf_ctx = NULL;
+ VIM_CLEAR(qfl->qf_qftf);
qfl->qf_id = 0;
qfl->qf_changedtick = 0L;
}
@@ -4399,75 +4405,116 @@ 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(buf_T *buf, linenr_T lnum, qfline_T *qfp, char_u *dirname)
+qf_buf_add_line(
+ qf_list_T *qfl, // quickfix list
+ buf_T *buf, // quickfix window buffer
+ linenr_T lnum,
+ qfline_T *qfp,
+ char_u *dirname)
{
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];
+ dict_T *d;
+
+ // create 'info' dict argument
+ if ((d = dict_alloc_lock(VAR_FIXED)) == NULL)
+ return FAIL;
+ dict_add_number(d, "quickfix", (long)IS_QF_LIST(qfl));
+ dict_add_number(d, "id", (long)qfl->qf_id);
+ dict_add_number(d, "idx", (long)(lnum + 1));
+ ++d->dv_refcount;
+ args[0].v_type = VAR_DICT;
+ args[0].vval.v_dict = d;
- if (qfp->qf_module != NULL)
- {
- vim_strncpy(IObuff, qfp->qf_module, IOSIZE - 1);
- len = (int)STRLEN(IObuff);
+ qfbuf_text = call_func_retstr(qftf, 1, args);
+ --d->dv_refcount;
+
+ if (qfbuf_text == NULL)
+ return FAIL;
+
+ vim_strncpy(IObuff, qfbuf_text, IOSIZE - 1);
+ vim_free(qfbuf_text);
}
- else if (qfp->qf_fnum != 0
- && (errbuf = buflist_findnr(qfp->qf_fnum)) != NULL
- && errbuf->b_fname != NULL)
+ else
{
- if (qfp->qf_type == 1) // :helpgrep
- vim_strncpy(IObuff, gettail(errbuf->b_fname), IOSIZE - 1);
- else
+ if (qfp->qf_module != NULL)
+ {
+ vim_strncpy(IObuff, qfp->qf_module, IOSIZE - 1);
+ len = (int)STRLEN(IObuff);
+ }
+ else if (qfp->qf_fnum != 0
+ && (errbuf = buflist_findnr(qfp->qf_fnum)) != NULL
+ && errbuf->b_fname != NULL)
{
- // shorten the file name if not done already
- if (errbuf->b_sfname == NULL
- || mch_isFullName(errbuf->b_sfname))
+ if (qfp->qf_type == 1) // :helpgrep
+ vim_strncpy(IObuff, gettail(errbuf->b_fname), IOSIZE - 1);
+ else
{
- if (*dirname == NUL)
- mch_dirname(dirname, MAXPATHL);
- shorten_buf_fname(errbuf, dirname, FALSE);
+ // shorten the file name if not done already
+ if (errbuf->b_sfname == NULL
+ || mch_isFullName(errbuf->b_sfname))
+ {
+ if (*dirname == NUL)
+ mch_dirname(dirname, MAXPATHL);
+ shorten_buf_fname(errbuf, dirname, FALSE);
+ }
+ vim_strncpy(IObuff, errbuf->b_fname, IOSIZE - 1);
}
- vim_strncpy(IObuff, errbuf->b_fname, IOSIZE - 1);
+ len = (int)STRLEN(IObuff);
}
- len = (int)STRLEN(IObuff);
- }
- else
- len = 0;
+ else
+ len = 0;
- if (len < IOSIZE - 1)
- IObuff[len++] = '|';
+ if (len < IOSIZE - 1)
+ IObuff[len++] = '|';
- if (qfp->qf_lnum > 0)
- {
- vim_snprintf((char *)IObuff + len, IOSIZE - len, "%ld", qfp->qf_lnum);
- len += (int)STRLEN(IObuff + len);
+ if (qfp->qf_lnum > 0)
+ {
+ vim_snprintf((char *)IObuff + len, IOSIZE - len, "%ld",
+ qfp->qf_lnum);
+ len += (int)STRLEN(IObuff + len);
+
+ if (qfp->qf_col > 0)
+ {
+ vim_snprintf((char *)IObuff + len, IOSIZE - len,
+ " col %d", qfp->qf_col);
+ len += (int)STRLEN(IObuff + len);
+ }
- if (qfp->qf_col > 0)
+ vim_snprintf((char *)IObuff + len, IOSIZE - len, "%s",
+ (char *)qf_types(qfp->qf_type, qfp->qf_nr));
+ len += (int)STRLEN(IObuff + len);
+ }
+ else if (qfp->qf_pattern != NULL)
{
- vim_snprintf((char *)IObuff + len, IOSIZE - len,
- " col %d", qfp->qf_col);
+ qf_fmt_text(qfp->qf_pattern, IObuff + len, IOSIZE - len);
len += (int)STRLEN(IObuff + len);
}
+ if (len < IOSIZE - 2)
+ {
+ IObuff[len++] = '|';
+ IObuff[len++] = ' ';
+ }
- vim_snprintf((char *)IObuff + len, IOSIZE - len, "%s",
- (char *)qf_types(qfp->qf_type, qfp->qf_nr));
- len += (int)STRLEN(IObuff + len);
- }
- else if (qfp->qf_pattern != NULL)
- {
- qf_fmt_text(qfp->qf_pattern, IObuff + len, IOSIZE - len);
- len += (int)STRLEN(IObuff + len);
- }
- if (len < IOSIZE - 2)
- {
- IObuff[len++] = '|';
- IObuff[len++] = ' ';
+ // Remove newlines and leading whitespace from the text.
+ // For an unrecognized line keep the indent, the compiler may
+ // mark a word with ^^^^.
+ qf_fmt_text(len > 3 ? skipwhite(qfp->qf_text) : qfp->qf_text,
+ IObuff + len, IOSIZE - len);
}
- // Remove newlines and leading whitespace from the text.
- // For an unrecognized line keep the indent, the compiler may
- // mark a word with ^^^^.
- qf_fmt_text(len > 3 ? skipwhite(qfp->qf_text) : qfp->qf_text,
- IObuff + len, IOSIZE - len);
-
if (ml_append_buf(buf, lnum, IObuff,
(colnr_T)STRLEN(IObuff) + 1, FALSE) == FAIL)
return FAIL;
@@ -4522,7 +4569,7 @@ qf_fill_buffer(qf_list_T *qfl, buf_T *buf, qfline_T *old_last)
}
while (lnum < qfl->qf_count)
{
- if (qf_buf_add_line(buf, lnum, qfp, dirname) == FAIL)
+ if (qf_buf_add_line(qfl, buf, lnum, qfp, dirname) == FAIL)
break;
++lnum;
@@ -6369,9 +6416,16 @@ get_qfline_items(qfline_T *qfp, list_T *list)
/*
* Add each quickfix error to list "list" as a dictionary.
* If qf_idx is -1, use the current list. Otherwise, use the specified list.
+ * If eidx is not 0, then return only the specified entry. Otherwise return
+ * all the entries.
*/
static int
-get_errorlist(qf_info_T *qi_arg, win_T *wp, int qf_idx, list_T *list)
+get_errorlist(
+ qf_info_T *qi_arg,
+ win_T *wp,
+ int qf_idx,
+ int eidx,
+ list_T *list)
{
qf_info_T *qi = qi_arg;
qf_list_T *qfl;
@@ -6389,6 +6443,9 @@ get_errorlist(qf_info_T *qi_arg, win_T *wp, int qf_idx, list_T *list)
}
}
+ if (eidx < 0)
+ return OK;
+
if (qf_idx == INVALID_QFIDX)
qf_idx = qi->qf_curlist;
@@ -6401,7 +6458,12 @@ get_errorlist(qf_info_T *qi_arg, win_T *wp, int qf_idx, list_T *list)
FOR_ALL_QFL_ITEMS(qfl, qfp, i)
{
- if (get_qfline_items(qfp, list) == FAIL)
+ if (eidx > 0)
+ {
+ if (eidx == i)
+ return get_qfline_items(qfp, list);
+ }
+ else if (get_qfline_items(qfp, list) == FAIL)
return FAIL;
}
@@ -6461,7 +6523,7 @@ qf_get_list_from_lines(dict_T *what, dictitem_T *di, dict_T *retdict)
if (qf_init_ext(qi, 0, NULL, NULL, &di->di_tv, errorformat,
TRUE, (linenr_T)0, (linenr_T)0, NULL, NULL) > 0)
{
- (void)get_errorlist(qi, NULL, 0, l);
+ (void)get_errorlist(qi, NULL, 0, 0, l);
qf_free(&qi->qf_lists[0]);
}
free(qi);
@@ -6679,16 +6741,17 @@ qf_getprop_filewinid(win_T *wp, qf_info_T *qi, dict_T *retdict)
}
/*
- * Return the quickfix list items/entries as 'items' in retdict
+ * Return the quickfix list items/entries as 'items' in retdict.
+ * If eidx is not 0, then return the item at the specified index.
*/
static int
-qf_getprop_items(qf_info_T *qi, int qf_idx, dict_T *retdict)
+qf_getprop_items(qf_info_T *qi, int qf_idx, int eidx, dict_T *retdict)
{
int status = OK;
list_T *l = list_alloc();
if (l != NULL)
{
- (void)get_errorlist(qi, NULL, qf_idx, l);
+ (void)get_errorlist(qi, NULL, qf_idx, eidx, l);
dict_add_list(retdict, "items", l);
}
else
@@ -6726,16 +6789,20 @@ qf_getprop_ctx(qf_list_T *qfl, dict_T *retdict)
}
/*
- * Return the current quickfix list index as 'idx' in retdict
+ * Return the current quickfix list index as 'idx' in retdict.
+ * If a specific entry index (eidx) is supplied, then use that.
*/
static int
-qf_getprop_idx(qf_list_T *qfl, dict_T *retdict)
+qf_getprop_idx(qf_list_T *qfl, int eidx, dict_T *retdict)
{
- int curidx = qfl->qf_index;
- if (qf_list_empty(qfl))
- // For empty lists, current index is set to 0
- curidx = 0;
- return dict_add_number(retdict, "idx", curidx);
+ if (eidx == 0)
+ {
+ eidx = qfl->qf_index;
+ if (qf_list_empty(qfl))
+ // For empty lists, current index is set to 0
+ eidx = 0;
+ }
+ return dict_add_number(retdict, "idx", eidx);
}
/*
@@ -6750,6 +6817,7 @@ qf_get_properties(win_T *wp, dict_T *what, dict_T *retdict)
qf_list_T *qfl;
int status = OK;
int qf_idx = INVALID_QFIDX;
+ int eidx = 0;
dictitem_T *di;
int flags = QF_GETLIST_NONE;
@@ -6770,6 +6838,14 @@ qf_get_properties(win_T *wp, dict_T *what, dict_T *retdict)
qfl = qf_get_list(qi, qf_idx);
+ // If an entry index is specified, use that
+ if ((di = dict_find(what, (char_u *)"idx", -1)) != NULL)
+ {
+ if (di->di_tv.v_type != VAR_NUMBER)
+ return FAIL;
+ eidx = di->di_tv.vval.v_number;
+ }
+
if (flags & QF_GETLIST_TITLE)
status = qf_getprop_title(qfl, retdict);
if ((status == OK) && (flags & QF_GETLIST_NR))
@@ -6777,13 +6853,13 @@ qf_get_properties(win_T *wp, dict_T *what, dict_T *retdict)
if ((status == OK) && (flags & QF_GETLIST_WINID))
status = dict_add_number(retdict, "winid", qf_winid(qi));
if ((status == OK) && (flags & QF_GETLIST_ITEMS))
- status = qf_getprop_items(qi, qf_idx, retdict);
+ status = qf_getprop_items(qi, qf_idx, eidx, retdict);
if ((status == OK) && (flags & QF_GETLIST_CONTEXT))
status = qf_getprop_ctx(qfl, retdict);
if ((status == OK) && (flags & QF_GETLIST_ID))
status = dict_add_number(retdict, "id", qfl->qf_id);
if ((status == OK) && (flags & QF_GETLIST_IDX))
- status = qf_getprop_idx(qfl, retdict);
+ status = qf_getprop_idx(qfl, eidx, retdict);
if ((status == OK) && (flags & QF_GETLIST_SIZE))
status = dict_add_number(retdict, "size", qfl->qf_count);
if ((status == OK) && (flags & QF_GETLIST_TICK))
@@ -7148,6 +7224,20 @@ qf_setprop_curidx(qf_info_T *qi, qf_list_T *qfl, dictitem_T *di)
}
/*
+ * Set the current index in the specified quickfix list
+ */
+ static int
+qf_setprop_qftf(qf_info_T *qi UNUSED, qf_list_T *qfl, dictitem_T *di)
+{
+ VIM_CLEAR(qfl->qf_qftf);
+ if (di->di_tv.v_type == VAR_STRING
+ && di->di_tv.vval.v_string != NULL)
+ qfl->qf_qftf = vim_strsave(di->di_tv.vval.v_string);
+
+ return OK;
+}
+
+/*
* Set quickfix/location list properties (title, items, context).
* Also used to add items from parsing a list of lines.
* Used by the setqflist() and setloclist() Vim script functions.
@@ -7186,6 +7276,8 @@ qf_set_properties(qf_info_T *qi, dict_T *what, int action, char_u *title)
retval = qf_setprop_context(qfl, di);
if ((di = dict_find(what, (char_u *)"idx", -1)) != NULL)
retval = qf_setprop_curidx(qi, qfl, di);
+ if ((di = dict_find(what, (char_u *)"quickfixtextfunc", -1)) != NULL)
+ retval = qf_setprop_qftf(qi, qfl, di);
if (retval == OK)
qf_list_changed(qfl);
@@ -7900,7 +7992,7 @@ get_qf_loc_list(int is_qf, win_T *wp, typval_T *what_arg, typval_T *rettv)
{
if (rettv_list_alloc(rettv) == OK)
if (is_qf || wp != NULL)
- (void)get_errorlist(NULL, wp, -1, rettv->vval.v_list);
+ (void)get_errorlist(NULL, wp, -1, 0, rettv->vval.v_list);
}
else
{
diff --git a/src/testdir/test_quickfix.vim b/src/testdir/test_quickfix.vim
index 11bdfbefa..fb4e07c6f 100644
--- a/src/testdir/test_quickfix.vim
+++ b/src/testdir/test_quickfix.vim
@@ -4766,4 +4766,121 @@ func Test_cquit()
call assert_fails('-3cquit', 'E16:')
endfunc
+" Test for getting a specific item from a quickfix list
+func Xtest_getqflist_by_idx(cchar)
+ call s:setup_commands(a:cchar)
+ " Empty list
+ call assert_equal([], g:Xgetlist({'idx' : 1, 'items' : 0}).items)
+ Xexpr ['F1:10:L10', 'F1:20:L20']
+ let l = g:Xgetlist({'idx' : 2, 'items' : 0}).items
+ call assert_equal(bufnr('F1'), l[0].bufnr)
+ call assert_equal(20, l[0].lnum)
+ call assert_equal('L20', l[0].text)
+ call assert_equal([], g:Xgetlist({'idx' : -1, 'items' : 0}).items)
+ call assert_equal([], g:Xgetlist({'idx' : 3, 'items' : 0}).items)
+ %bwipe!
+endfunc
+
+func Test_getqflist_by_idx()
+ call Xtest_getqflist_by_idx('c')
+ call Xtest_getqflist_by_idx('l')
+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
+ else
+ let qfl = getloclist(0, {'id' : a:info.id, 'idx' : a:info.idx,
+ \ '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
+endfunc
+
+func Xtest_qftextfunc(cchar)
+ call s:setup_commands(a:cchar)
+
+ set efm=%f:%l:%c:%m
+ set quickfixtextfunc=Tqfexpr
+ Xexpr ['F1:10:2:green', 'F1:20:4:blue']
+ Xwindow
+ call assert_equal('F1-L10C2-green', getline(1))
+ call assert_equal('F1-L20C4-blue', getline(2))
+ Xclose
+ set quickfixtextfunc&vim
+ Xwindow
+ call assert_equal('F1|10 col 2| green', getline(1))
+ call assert_equal('F1|20 col 4| blue', getline(2))
+ Xclose
+ set efm&
+ set quickfixtextfunc&
+
+ " 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
+ else
+ let qfl = getloclist(0, {'id' : a:info.id, 'idx' : a:info.idx,
+ \ 'items' : 1}).items
+ endif
+ if empty(qfl)
+ return ''
+ endif
+ return 'Line ' .. qfl[0].lnum .. ', Col ' .. qfl[0].col
+ endfunc
+ set quickfixtextfunc=Tqfexpr
+ call g:Xsetlist([], ' ', {'quickfixtextfunc' : "PerQfText"})
+ Xaddexpr ['F1:10:2:green', 'F1:20:4:blue']
+ Xwindow
+ call assert_equal('Line 10, Col 2', getline(1))
+ call assert_equal('Line 20, Col 4', getline(2))
+ Xclose
+ call g:Xsetlist([], 'r', {'quickfixtextfunc' : ''})
+ set quickfixtextfunc&
+ delfunc PerQfText
+
+ " Non-existing function
+ set quickfixtextfunc=Tabc
+ call assert_fails("Xexpr ['F1:10:2:green', 'F1:20:4:blue']", 'E117:')
+ call assert_fails("Xwindow", 'E117:')
+ Xclose
+ set quickfixtextfunc&
+
+ " set option to a non-function
+ set quickfixtextfunc=[10,\ 20]
+ call assert_fails("Xexpr ['F1:10:2:green', 'F1:20:4:blue']", 'E117:')
+ call assert_fails("Xwindow", 'E117:')
+ Xclose
+ set quickfixtextfunc&
+
+ " set option to a function with different set of arguments
+ func Xqftext(a, b, c)
+ return a:a .. a:b .. a:c
+ endfunc
+ set quickfixtextfunc=Xqftext
+ call assert_fails("Xexpr ['F1:10:2:green', 'F1:20:4:blue']", 'E119:')
+ call assert_fails("Xwindow", 'E119:')
+ Xclose
+ set quickfixtextfunc&
+ delfunc Xqftext
+endfunc
+
+func Test_qftextfunc()
+ call Xtest_qftextfunc('c')
+ call Xtest_qftextfunc('l')
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/version.c b/src/version.c
index c75283f9f..d211e8cd0 100644
--- a/src/version.c
+++ b/src/version.c
@@ -747,6 +747,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 869,
+/**/
868,
/**/
867,