]> granicus.if.org Git - vim/commitdiff
patch 8.2.1255: cannot use a lambda with quickfix functions v8.2.1255
authorBram Moolenaar <Bram@vim.org>
Mon, 20 Jul 2020 19:31:32 +0000 (21:31 +0200)
committerBram Moolenaar <Bram@vim.org>
Mon, 20 Jul 2020 19:31:32 +0000 (21:31 +0200)
Problem:    Cannot use a lambda with quickfix functions.
Solution:   Add support for lambda. (Yegappan Lakshmanan, closes #6499)

runtime/doc/eval.txt
runtime/doc/options.txt
runtime/doc/quickfix.txt
src/channel.c
src/evalvars.c
src/optionstr.c
src/proto/evalvars.pro
src/proto/quickfix.pro
src/quickfix.c
src/testdir/test_quickfix.vim
src/version.c

index 5be18bd796e6a21b95b16a640e1f9d7bc001f6e0..ed4f8aab0ee01ef849d85a0eb8d0a65332da3a1e 100644 (file)
@@ -1,4 +1,4 @@
-*eval.txt*     For Vim version 8.2.  Last change: 2020 Jul 09
+*eval.txt*     For Vim version 8.2.  Last change: 2020 Jul 19
 
 
                  VIM REFERENCE MANUAL    by Bram Moolenaar
@@ -94,8 +94,9 @@ the Number.  Examples:
        Number 0        -->     String "0" ~
        Number -1       -->     String "-1" ~
                                                        *octal*
-Conversion from a String to a Number is done by converting the first digits to
-a number.  Hexadecimal "0xf9", Octal "017" or "0o17", and Binary "0b10"
+Conversion from a String to a Number only happens in legacy Vim script, not in
+Vim9 script.  It is done by converting the first digits to a number.
+Hexadecimal "0xf9", Octal "017" or "0o17", and Binary "0b10"
 numbers are recognized (NOTE: when using |scriptversion-4| octal with a
 leading "0" is not recognized).  If the String doesn't start with digits, the
 result is zero.
@@ -2831,7 +2832,7 @@ stridx({haystack}, {needle} [, {start}])
 string({expr})                 String  String representation of {expr} value
 strlen({expr})                 Number  length of the String {expr}
 strpart({str}, {start} [, {len}])
-                               String  {len} characters of {str} at {start}
+                               String  {len} bytes of {str} at byte {start}
 strptime({format}, {timestring})
                                Number  Convert {timestring} to unix timestamp
 strridx({haystack}, {needle} [, {start}])
@@ -9183,7 +9184,8 @@ setqflist({list} [, {action} [, {what}]])         *setqflist()*
                                the last quickfix list.
                    quickfixtextfunc
                                function to get the text to display in the
-                               quickfix window.  Refer to
+                               quickfix window.  The value can be the name of
+                               a function or a funcref or a lambda.  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|
index 71ee94b4e5ad385eb565e8fa99647c9a77cc2973..6a9e2ed0e88aa1051f67d70aea5564a71577ee2b 100644 (file)
@@ -5913,7 +5913,8 @@ A jump table for the options with a short description can be found at |Q_op|.
        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.
+       function and an example. The value can be the name of a function or a
+       lambda.
 
        This option cannot be set from a |modeline| or in the |sandbox|, for
        security reasons.
index 293014b2407ae5ebae1c6d2d7946e374c799431a..48776487309232bbcd1fce652a0c82d3e707e124 100644 (file)
@@ -1964,7 +1964,10 @@ The function should return a single line of text to display in the quickfix
 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.
+can be used with the 'winid' argument. If an empty list is returned, then the
+default format is used to display all the entries. If an item in the returned
+list is an empty string, then the default format is used to display the
+corresponding entry.
 
 If a quickfix or location list specific customization is needed, then the
 'quickfixtextfunc' attribute of the list can be set using the |setqflist()| or
index 740329f1098680be19e6a1e80ddaf4cecb580d69..f20a4d851da353b7eeeb40d116d1d711a6cfe620 100644 (file)
@@ -1101,27 +1101,6 @@ channel_open(
     return channel;
 }
 
-/*
- * Copy callback from "src" to "dest", incrementing the refcounts.
- */
-    static void
-copy_callback(callback_T *dest, callback_T *src)
-{
-    dest->cb_partial = src->cb_partial;
-    if (dest->cb_partial != NULL)
-    {
-       dest->cb_name = src->cb_name;
-       dest->cb_free_name = FALSE;
-       ++dest->cb_partial->pt_refcount;
-    }
-    else
-    {
-       dest->cb_name = vim_strsave(src->cb_name);
-       dest->cb_free_name = TRUE;
-       func_ref(src->cb_name);
-    }
-}
-
     static void
 free_set_callback(callback_T *cbp, callback_T *callback)
 {
index 197a19dd1d99f50119d6351a6519294cda2efb39..e2469b0e8242641100dfd3cb1c081d5c3144ead8 100644 (file)
@@ -3848,6 +3848,27 @@ set_callback(callback_T *dest, callback_T *src)
     dest->cb_partial = src->cb_partial;
 }
 
+/*
+ * Copy callback from "src" to "dest", incrementing the refcounts.
+ */
+    void
+copy_callback(callback_T *dest, callback_T *src)
+{
+    dest->cb_partial = src->cb_partial;
+    if (dest->cb_partial != NULL)
+    {
+       dest->cb_name = src->cb_name;
+       dest->cb_free_name = FALSE;
+       ++dest->cb_partial->pt_refcount;
+    }
+    else
+    {
+       dest->cb_name = vim_strsave(src->cb_name);
+       dest->cb_free_name = TRUE;
+       func_ref(src->cb_name);
+    }
+}
+
 /*
  * Unref/free "callback" returned by get_callback() or set_callback().
  */
index bfc2e3b9557e92e4765a21e1986ec5950e7fc58d..177ce859fdd12768a21d63aca8e6af0adcf9a832 100644 (file)
@@ -2255,6 +2255,14 @@ did_set_string_option(
 # endif
 #endif
 
+#ifdef FEAT_QUICKFIX
+    else if (varp == &p_qftf)
+    {
+       if (qf_process_qftf_option() == FALSE)
+           errmsg = e_invarg;
+    }
+#endif
+
     // Options that are a list of flags.
     else
     {
index a1083100dcb52a9701af74bc31b23ad51712f6f1..43c25287cae97693245b20d85b4e166e2f86ebc6 100644 (file)
@@ -88,5 +88,6 @@ void f_setbufvar(typval_T *argvars, typval_T *rettv);
 callback_T get_callback(typval_T *arg);
 void put_callback(callback_T *cb, typval_T *tv);
 void set_callback(callback_T *dest, callback_T *src);
+void copy_callback(callback_T *dest, callback_T *src);
 void free_callback(callback_T *callback);
 /* vim: set ft=c : */
index 0d84112a6f70a68accd735e0b92247405bb101f5..abe5b390c97ad96cf5af77d2626648897fe3e5e2 100644 (file)
@@ -15,6 +15,7 @@ void ex_cclose(exarg_T *eap);
 void ex_copen(exarg_T *eap);
 void ex_cbottom(exarg_T *eap);
 linenr_T qf_current_entry(win_T *wp);
+int qf_process_qftf_option(void);
 int grep_internal(cmdidx_T cmdidx);
 void ex_make(exarg_T *eap);
 int qf_get_size(exarg_T *eap);
index a7d211822a24ad62f6cb2b485a47209b64836603..4957f7d527acca3c468c767faa662c8287b91eab 100644 (file)
@@ -82,7 +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
+    callback_T  qftf_cb;       // 'quickfixtextfunc' callback function
 
     struct dir_stack_T *qf_dir_stack;
     char_u             *qf_directory;
@@ -161,6 +161,9 @@ static int  quickfix_busy = 0;
 
 static efm_T   *fmt_start = NULL; // cached across qf_parse_line() calls
 
+// callback function for 'quickfixtextfunc'
+static callback_T qftf_cb;
+
 static void    qf_new_list(qf_info_T *qi, char_u *qf_title);
 static int     qf_add_entry(qf_list_T *qfl, char_u *dir, char_u *fname, char_u *module, int bufnum, char_u *mesg, long lnum, int col, int vis_col, char_u *pattern, int nr, int type, int valid);
 static void    qf_free(qf_list_T *qfl);
@@ -2279,10 +2282,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);
+    if (from_qfl->qftf_cb.cb_name != NULL)
+       copy_callback(&to_qfl->qftf_cb, &from_qfl->qftf_cb);
     else
-       to_qfl->qf_qftf = NULL;
+       to_qfl->qftf_cb.cb_name = NULL;
 
     if (from_qfl->qf_count)
        if (copy_loclist_entries(from_qfl, to_qfl) == FAIL)
@@ -3818,7 +3821,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);
+    free_callback(&qfl->qftf_cb);
     qfl->qf_id = 0;
     qfl->qf_changedtick = 0L;
 }
@@ -4348,6 +4351,49 @@ qf_find_buf(qf_info_T *qi)
     return NULL;
 }
 
+/*
+ * Process the 'quickfixtextfunc' option value.
+ */
+    int
+qf_process_qftf_option(void)
+{
+    typval_T   *tv;
+    callback_T cb;
+
+    if (p_qftf == NULL || *p_qftf == NUL)
+    {
+       free_callback(&qftf_cb);
+       return TRUE;
+    }
+
+    if (*p_qftf == '{')
+    {
+       // Lambda expression
+       tv = eval_expr(p_qftf, NULL);
+       if (tv == NULL)
+           return FALSE;
+    }
+    else
+    {
+       // treat everything else as a function name string
+       tv = alloc_string_tv(vim_strsave(p_qftf));
+       if (tv == NULL)
+           return FALSE;
+    }
+
+    cb = get_callback(tv);
+    if (cb.cb_name == NULL)
+    {
+       free_tv(tv);
+       return FALSE;
+    }
+
+    free_callback(&qftf_cb);
+    set_callback(&qftf_cb, &cb);
+    free_tv(tv);
+    return TRUE;
+}
+
 /*
  * Update the w:quickfix_title variable in the quickfix/location list window
  */
@@ -4424,7 +4470,9 @@ qf_buf_add_line(
     int                len;
     buf_T      *errbuf;
 
-    if (qftf_str != NULL)
+    // If the 'quickfixtextfunc' function returned an non-empty custom string
+    // for this entry, then use it.
+    if (qftf_str != NULL && *qftf_str != NUL)
        vim_strncpy(IObuff, qftf_str, IOSIZE - 1);
     else
     {
@@ -4501,21 +4549,26 @@ qf_buf_add_line(
     return OK;
 }
 
+/*
+ * Call the 'quickfixtextfunc' function to get the list of lines to display in
+ * the quickfix window for the entries 'start_idx' to 'end_idx'.
+ */
     static list_T *
 call_qftf_func(qf_list_T *qfl, int qf_winid, long start_idx, long end_idx)
 {
-    char_u     *qftf = p_qftf;
+    callback_T *cb = &qftf_cb;
     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)
+    if (qfl->qftf_cb.cb_name != NULL)
+       cb = &qfl->qftf_cb;
+    if (cb != NULL && cb->cb_name != NULL)
     {
        typval_T        args[1];
        dict_T          *d;
+       typval_T        rettv;
 
        // create the dict argument
        if ((d = dict_alloc_lock(VAR_FIXED)) == NULL)
@@ -4529,8 +4582,17 @@ call_qftf_func(qf_list_T *qfl, int qf_winid, long start_idx, long end_idx)
        args[0].v_type = VAR_DICT;
        args[0].vval.v_dict = d;
 
-       qftf_list = call_func_retlist(qftf, 1, args);
-       --d->dv_refcount;
+       qftf_list = NULL;
+       if (call_callback(cb, 0, &rettv, 1, args) != FAIL)
+       {
+           if (rettv.v_type == VAR_LIST)
+           {
+               qftf_list = rettv.vval.v_list;
+               qftf_list->lv_refcount++;
+           }
+           clear_tv(&rettv);
+       }
+       dict_unref(d);
     }
 
     return qftf_list;
@@ -4569,6 +4631,7 @@ qf_fill_buffer(qf_list_T *qfl, buf_T *buf, qfline_T *old_last, int qf_winid)
     if (qfl != NULL)
     {
        char_u          dirname[MAXPATHL];
+       int             invalid_val = FALSE;
 
        *dirname = NUL;
 
@@ -4593,9 +4656,15 @@ qf_fill_buffer(qf_list_T *qfl, buf_T *buf, qfline_T *old_last, int qf_winid)
        {
            char_u      *qftf_str = NULL;
 
-           if (qftf_li != NULL)
-               // Use the text supplied by the user defined function
+           // Use the text supplied by the user defined function (if any).
+           // If the returned value is not string, then ignore the rest
+           // of the returned values and use the default.
+           if (qftf_li != NULL && !invalid_val)
+           {
                qftf_str = tv_get_string_chk(&qftf_li->li_tv);
+               if (qftf_str == NULL)
+                   invalid_val = TRUE;
+           }
 
            if (qf_buf_add_line(buf, lnum, qfp, dirname, qftf_str) == FAIL)
                break;
@@ -6515,7 +6584,8 @@ enum {
     QF_GETLIST_TICK    = 0x100,
     QF_GETLIST_FILEWINID       = 0x200,
     QF_GETLIST_QFBUFNR = 0x400,
-    QF_GETLIST_ALL     = 0x7FF,
+    QF_GETLIST_QFTF    = 0x800,
+    QF_GETLIST_ALL     = 0xFFF,
 };
 
 /*
@@ -6644,6 +6714,9 @@ qf_getprop_keys2flags(dict_T *what, int loclist)
     if (dict_find(what, (char_u *)"qfbufnr", -1) != NULL)
        flags |= QF_GETLIST_QFBUFNR;
 
+    if (dict_find(what, (char_u *)"quickfixtextfunc", -1) != NULL)
+       flags |= QF_GETLIST_QFTF;
+
     return flags;
 }
 
@@ -6738,6 +6811,8 @@ qf_getprop_defaults(qf_info_T *qi, int flags, int locstack, dict_T *retdict)
        status = dict_add_number(retdict, "filewinid", 0);
     if ((status == OK) && (flags & QF_GETLIST_QFBUFNR))
        status = qf_getprop_qfbufnr(qi, retdict);
+    if ((status == OK) && (flags & QF_GETLIST_QFTF))
+       status = dict_add_string(retdict, "quickfixtextfunc", (char_u *)"");
 
     return status;
 }
@@ -6836,6 +6911,28 @@ qf_getprop_idx(qf_list_T *qfl, int eidx, dict_T *retdict)
     return dict_add_number(retdict, "idx", eidx);
 }
 
+/*
+ * Return the 'quickfixtextfunc' function of a quickfix/location list
+ */
+    static int
+qf_getprop_qftf(qf_list_T *qfl, dict_T *retdict)
+{
+    int                status;
+
+    if (qfl->qftf_cb.cb_name != NULL)
+    {
+       typval_T        tv;
+
+       put_callback(&qfl->qftf_cb, &tv);
+       status = dict_add_tv(retdict, "quickfixtextfunc", &tv);
+       clear_tv(&tv);
+    }
+    else
+       status = dict_add_string(retdict, "quickfixtextfunc", (char_u *)"");
+
+    return status;
+}
+
 /*
  * Return quickfix/location list details (title) as a
  * dictionary. 'what' contains the details to return. If 'list_idx' is -1,
@@ -6899,6 +6996,8 @@ qf_get_properties(win_T *wp, dict_T *what, dict_T *retdict)
        status = qf_getprop_filewinid(wp, qi, retdict);
     if ((status == OK) && (flags & QF_GETLIST_QFBUFNR))
        status = qf_getprop_qfbufnr(qi, retdict);
+    if ((status == OK) && (flags & QF_GETLIST_QFTF))
+       status = qf_getprop_qftf(qfl, retdict);
 
     return status;
 }
@@ -7260,10 +7359,12 @@ qf_setprop_curidx(qf_info_T *qi, qf_list_T *qfl, dictitem_T *di)
     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);
+    callback_T cb;
+
+    free_callback(&qfl->qftf_cb);
+    cb = get_callback(&di->di_tv);
+    if (cb.cb_name != NULL && *cb.cb_name != NUL)
+       set_callback(&qfl->qftf_cb, &cb);
 
     return OK;
 }
index 6005b8d201956d33870164de6f06f47f1466d0eb..8ca55785d1e257a3425450bf75cf49a27bbb04a3 100644 (file)
@@ -3490,13 +3490,13 @@ func Xgetlist_empty_tests(cchar)
   if a:cchar == 'c'
     call assert_equal({'context' : '', 'id' : 0, 'idx' : 0,
                  \ 'items' : [], 'nr' : 0, 'size' : 0, 'qfbufnr' : 0,
-                 \ 'title' : '', 'winid' : 0, 'changedtick': 0},
-                 \ g:Xgetlist({'all' : 0}))
+                 \ 'title' : '', 'winid' : 0, 'changedtick': 0,
+                  \ 'quickfixtextfunc' : ''}, g:Xgetlist({'all' : 0}))
   else
     call assert_equal({'context' : '', 'id' : 0, 'idx' : 0,
                \ 'items' : [], 'nr' : 0, 'size' : 0, 'title' : '',
                \ 'winid' : 0, 'changedtick': 0, 'filewinid' : 0,
-               \ 'qfbufnr' : 0},
+               \ 'qfbufnr' : 0, 'quickfixtextfunc' : ''},
                \ g:Xgetlist({'all' : 0}))
   endif
 
@@ -3535,12 +3535,13 @@ func Xgetlist_empty_tests(cchar)
   if a:cchar == 'c'
     call assert_equal({'context' : '', 'id' : 0, 'idx' : 0, 'items' : [],
                \ 'nr' : 0, 'size' : 0, 'title' : '', 'winid' : 0,
-               \ 'qfbufnr' : qfbufnr,
+               \ 'qfbufnr' : qfbufnr, 'quickfixtextfunc' : '',
                \ 'changedtick' : 0}, g:Xgetlist({'id' : qfid, 'all' : 0}))
   else
     call assert_equal({'context' : '', 'id' : 0, 'idx' : 0, 'items' : [],
                \ 'nr' : 0, 'size' : 0, 'title' : '', 'winid' : 0,
-               \ 'changedtick' : 0, 'filewinid' : 0, 'qfbufnr' : 0},
+               \ 'changedtick' : 0, 'filewinid' : 0, 'qfbufnr' : 0,
+                \ 'quickfixtextfunc' : ''},
                \ g:Xgetlist({'id' : qfid, 'all' : 0}))
   endif
 
@@ -3557,13 +3558,13 @@ func Xgetlist_empty_tests(cchar)
   if a:cchar == 'c'
     call assert_equal({'context' : '', 'id' : 0, 'idx' : 0, 'items' : [],
                \ 'nr' : 0, 'size' : 0, 'title' : '', 'winid' : 0,
-               \ 'changedtick' : 0, 'qfbufnr' : qfbufnr},
-               \ g:Xgetlist({'nr' : 5, 'all' : 0}))
+               \ 'changedtick' : 0, 'qfbufnr' : qfbufnr,
+                \ 'quickfixtextfunc' : ''}, g:Xgetlist({'nr' : 5, 'all' : 0}))
   else
     call assert_equal({'context' : '', 'id' : 0, 'idx' : 0, 'items' : [],
                \ 'nr' : 0, 'size' : 0, 'title' : '', 'winid' : 0,
-               \ 'changedtick' : 0, 'filewinid' : 0, 'qfbufnr' : 0},
-               \ g:Xgetlist({'nr' : 5, 'all' : 0}))
+               \ 'changedtick' : 0, 'filewinid' : 0, 'qfbufnr' : 0,
+                \ 'quickfixtextfunc' : ''}, g:Xgetlist({'nr' : 5, 'all' : 0}))
   endif
 endfunc
 
@@ -4865,6 +4866,9 @@ func Xtest_qftextfunc(cchar)
 
   set efm=%f:%l:%c:%m
   set quickfixtextfunc=Tqfexpr
+  call assert_equal('Tqfexpr', &quickfixtextfunc)
+  call assert_equal('',
+        \ g:Xgetlist({'quickfixtextfunc' : 1}).quickfixtextfunc)
   Xexpr ['F1:10:2:green', 'F1:20:4:blue']
   Xwindow
   call assert_equal('F1-L10C2-green', getline(1))
@@ -4901,12 +4905,15 @@ func Xtest_qftextfunc(cchar)
   call assert_equal('Line 10, Col 2', getline(1))
   call assert_equal('Line 20, Col 4', getline(2))
   Xclose
+  call assert_equal(function('PerQfText'),
+        \ g:Xgetlist({'quickfixtextfunc' : 1}).quickfixtextfunc)
   " Add entries to the list when the quickfix buffer is hidden
   Xaddexpr ['F1:30:6:red']
   Xwindow
   call assert_equal('Line 30, Col 6', getline(3))
   Xclose
   call g:Xsetlist([], 'r', {'quickfixtextfunc' : ''})
+  call assert_equal('', g:Xgetlist({'quickfixtextfunc' : 1}).quickfixtextfunc)
   set quickfixtextfunc&
   delfunc PerQfText
 
@@ -4941,12 +4948,53 @@ func Xtest_qftextfunc(cchar)
   call assert_fails("Xexpr ['F1:10:2:green', 'F1:20:4:blue', 'F1:30:6:red']",
                                                                   \ 'E730:')
   call assert_fails('Xwindow', 'E730:')
-  call assert_equal(['one', 'F1|20 col 4| blue', 'two'], getline(1, '$'))
+  call assert_equal(['one', 'F1|20 col 4| blue', 'F1|30 col 6| red'],
+        \ getline(1, '$'))
   Xclose
 
   set quickfixtextfunc&
   delfunc Xqftext
   delfunc Xqftext2
+
+  " set the global option to a lambda function
+  set quickfixtextfunc={d\ ->\ map(g:Xgetlist({'id'\ :\ d.id,\ 'items'\ :\ 1}).items[d.start_idx-1:d.end_idx-1],\ 'v:val.text')}
+  Xexpr ['F1:10:2:green', 'F1:20:4:blue']
+  Xwindow
+  call assert_equal(['green', 'blue'], getline(1, '$'))
+  Xclose
+  call assert_equal("{d -> map(g:Xgetlist({'id' : d.id, 'items' : 1}).items[d.start_idx-1:d.end_idx-1], 'v:val.text')}", &quickfixtextfunc)
+  set quickfixtextfunc&
+
+  " use a lambda function that returns an empty list
+  set quickfixtextfunc={d\ ->\ []}
+  Xexpr ['F1:10:2:green', 'F1:20:4:blue']
+  Xwindow
+  call assert_equal(['F1|10 col 2| green', 'F1|20 col 4| blue'],
+        \ getline(1, '$'))
+  Xclose
+  set quickfixtextfunc&
+
+  " use a lambda function that returns a list with empty strings
+  set quickfixtextfunc={d\ ->\ ['',\ '']}
+  Xexpr ['F1:10:2:green', 'F1:20:4:blue']
+  Xwindow
+  call assert_equal(['F1|10 col 2| green', 'F1|20 col 4| blue'],
+        \ getline(1, '$'))
+  Xclose
+  set quickfixtextfunc&
+
+  " set the per-quickfix list text function to a lambda function
+  call g:Xsetlist([], ' ',
+        \ {'quickfixtextfunc' :
+        \   {d -> map(g:Xgetlist({'id' : d.id, 'items' : 1}).items[d.start_idx-1:d.end_idx-1],
+        \ "'Line ' .. v:val.lnum .. ', Col ' .. v:val.col")}})
+  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 assert_match("function('<lambda>\\d\\+')", string(g:Xgetlist({'quickfixtextfunc' : 1}).quickfixtextfunc))
+  call g:Xsetlist([], 'f')
 endfunc
 
 func Test_qftextfunc()
index 8cedb1cb9973a5071224e7cdccbae74c5c26d050..71c164a428832f8aca7b4a9edddcb1aca7339428 100644 (file)
@@ -754,6 +754,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    1255,
 /**/
     1254,
 /**/