diff options
author | Jan Edmund Lazo <jan.lazo@mail.utoronto.ca> | 2021-06-22 22:02:59 -0400 |
---|---|---|
committer | Jan Edmund Lazo <jan.lazo@mail.utoronto.ca> | 2021-06-23 23:16:20 -0400 |
commit | 4cb0bf09421e88adb812bb716b56af22bd51353e (patch) | |
tree | ed9c686270a620545f39a39cae5e8a00f1fe4ff2 | |
parent | d5329c0331a4e899ea88277b745df8d1bf3a99fa (diff) | |
download | rneovim-4cb0bf09421e88adb812bb716b56af22bd51353e.tar.gz rneovim-4cb0bf09421e88adb812bb716b56af22bd51353e.tar.bz2 rneovim-4cb0bf09421e88adb812bb716b56af22bd51353e.zip |
vim-patch:8.2.1255: cannot use a lambda with quickfix functions
Problem: Cannot use a lambda with quickfix functions.
Solution: Add support for lambda. (Yegappan Lakshmanan, closes vim/vim#6499)
https://github.com/vim/vim/commit/d43906d2e5969288f239df851f5ad7b1dc2c7251
-rw-r--r-- | runtime/doc/eval.txt | 3 | ||||
-rw-r--r-- | runtime/doc/options.txt | 3 | ||||
-rw-r--r-- | runtime/doc/quickfix.txt | 5 | ||||
-rw-r--r-- | src/nvim/eval.c | 13 | ||||
-rw-r--r-- | src/nvim/eval/typval.c | 44 | ||||
-rw-r--r-- | src/nvim/eval/typval.h | 2 | ||||
-rw-r--r-- | src/nvim/option.c | 5 | ||||
-rw-r--r-- | src/nvim/quickfix.c | 141 | ||||
-rw-r--r-- | src/nvim/testdir/test_quickfix.vim | 67 |
9 files changed, 232 insertions, 51 deletions
diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt index 9f44c016f0..bf7f2b21de 100644 --- a/runtime/doc/eval.txt +++ b/runtime/doc/eval.txt @@ -7879,7 +7879,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| diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt index cc9696e536..af65241bbf 100644 --- a/runtime/doc/options.txt +++ b/runtime/doc/options.txt @@ -4607,7 +4607,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. diff --git a/runtime/doc/quickfix.txt b/runtime/doc/quickfix.txt index ebc7e2a1b4..563fb0c962 100644 --- a/runtime/doc/quickfix.txt +++ b/runtime/doc/quickfix.txt @@ -1919,7 +1919,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 diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 7e462e568b..1b78147ec2 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -7200,12 +7200,15 @@ bool callback_from_typval(Callback *const callback, typval_T *const arg) r = FAIL; } else if (arg->v_type == VAR_FUNC || arg->v_type == VAR_STRING) { char_u *name = arg->vval.v_string; - if (name != NULL) { + if (name == NULL) { + r = FAIL; + } else if (*name == NUL) { + callback->type = kCallbackNone; + callback->data.funcref = NULL; + } else { func_ref(name); callback->data.funcref = vim_strsave(name); callback->type = kCallbackFuncref; - } else { - r = FAIL; } } else if (nlua_is_table_from_lua(arg)) { char_u *name = nlua_register_table_as_callable(arg); @@ -7216,8 +7219,10 @@ bool callback_from_typval(Callback *const callback, typval_T *const arg) } else { r = FAIL; } - } else if (arg->v_type == VAR_NUMBER && arg->vval.v_number == 0) { + } else if (arg->v_type == VAR_SPECIAL + || (arg->v_type == VAR_NUMBER && arg->vval.v_number == 0)) { callback->type = kCallbackNone; + callback->data.funcref = NULL; } else { r = FAIL; } diff --git a/src/nvim/eval/typval.c b/src/nvim/eval/typval.c index 4118ec407c..4275ff7c61 100644 --- a/src/nvim/eval/typval.c +++ b/src/nvim/eval/typval.c @@ -1162,20 +1162,48 @@ void callback_free(Callback *callback) } } callback->type = kCallbackNone; + callback->data.funcref = NULL; } /// Copy a callback into a typval_T. void callback_put(Callback *cb, typval_T *tv) FUNC_ATTR_NONNULL_ALL { - if (cb->type == kCallbackPartial) { - tv->v_type = VAR_PARTIAL; - tv->vval.v_partial = cb->data.partial; - cb->data.partial->pt_refcount++; - } else if (cb->type == kCallbackFuncref) { - tv->v_type = VAR_FUNC; - tv->vval.v_string = vim_strsave(cb->data.funcref); - func_ref(cb->data.funcref); + switch (cb->type) { + case kCallbackPartial: + tv->v_type = VAR_PARTIAL; + tv->vval.v_partial = cb->data.partial; + cb->data.partial->pt_refcount++; + break; + case kCallbackFuncref: + tv->v_type = VAR_FUNC; + tv->vval.v_string = vim_strsave(cb->data.funcref); + func_ref(cb->data.funcref); + break; + default: + tv->v_type = VAR_SPECIAL; + tv->vval.v_special = kSpecialVarNull; + break; + } +} + +// Copy callback from "src" to "dest", incrementing the refcounts. +void callback_copy(Callback *dest, Callback *src) + FUNC_ATTR_NONNULL_ALL +{ + dest->type = src->type; + switch (src->type) { + case kCallbackPartial: + dest->data.partial = src->data.partial; + dest->data.partial->pt_refcount++; + break; + case kCallbackFuncref: + dest->data.funcref = vim_strsave(src->data.funcref); + func_ref(src->data.funcref); + break; + default: + dest->data.funcref = NULL; + break; } } diff --git a/src/nvim/eval/typval.h b/src/nvim/eval/typval.h index 2b4612016b..050b84efec 100644 --- a/src/nvim/eval/typval.h +++ b/src/nvim/eval/typval.h @@ -120,7 +120,7 @@ typedef enum { VAR_DICT, ///< Dictionary, .v_dict is used. VAR_FLOAT, ///< Floating-point value, .v_float is used. VAR_BOOL, ///< true, false - VAR_SPECIAL, ///< Special value (true, false, null), .v_special + VAR_SPECIAL, ///< Special value (null), .v_special ///< is used. VAR_PARTIAL, ///< Partial, .v_partial is used. } VarType; diff --git a/src/nvim/option.c b/src/nvim/option.c index 57b8fe1a2e..f57abe89cc 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -85,6 +85,7 @@ #include "nvim/api/private/helpers.h" #include "nvim/os/input.h" #include "nvim/os/lang.h" +#include "nvim/quickfix.h" /* * The options that are local to a window or buffer have "indir" set to one of @@ -3182,6 +3183,10 @@ ambw_end: } } } + } else if (varp == &p_qftf) { + if (!qf_process_qftf_option()) { + errmsg = e_invarg; + } } else { // Options that are a list of flags. p = NULL; diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c index 1a9bbe26f0..508257d5b1 100644 --- a/src/nvim/quickfix.c +++ b/src/nvim/quickfix.c @@ -100,7 +100,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 qftf_cb; ///< 'quickfixtextfunc' callback function struct dir_stack_T *qf_dir_stack; char_u *qf_directory; @@ -541,6 +541,9 @@ static int efm_to_regpat(const char_u *efm, int len, efm_T *fmt_ptr, static efm_T *fmt_start = NULL; // cached across qf_parse_line() calls +// callback function for 'quickfixtextfunc' +static Callback qftf_cb; + static void free_efm_list(efm_T **efm_first) { for (efm_T *efm_ptr = *efm_first; efm_ptr != NULL; efm_ptr = *efm_first) { @@ -1978,7 +1981,7 @@ static int copy_loclist_entries(const qf_list_T *from_qfl, qf_list_T *to_qfl) } /// Copy the specified location list 'from_qfl' to 'to_qfl'. -static int copy_loclist(const qf_list_T *from_qfl, qf_list_T *to_qfl) +static int copy_loclist(qf_list_T *from_qfl, qf_list_T *to_qfl) FUNC_ATTR_NONNULL_ALL { // Some of the fields are populated by qf_add_entry() @@ -2000,11 +2003,7 @@ static int copy_loclist(const 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; - } + callback_copy(&to_qfl->qftf_cb, &from_qfl->qftf_cb); if (from_qfl->qf_count) { if (copy_loclist_entries(from_qfl, to_qfl) == FAIL) { @@ -3385,7 +3384,7 @@ static void qf_free(qf_list_T *qfl) XFREE_CLEAR(qfl->qf_title); tv_free(qfl->qf_ctx); qfl->qf_ctx = NULL; - XFREE_CLEAR(qfl->qf_qftf); + callback_free(&qfl->qftf_cb); qfl->qf_id = 0; qfl->qf_changedtick = 0L; } @@ -3860,6 +3859,41 @@ static buf_T *qf_find_buf(qf_info_T *qi) return NULL; } +// Process the 'quickfixtextfunc' option value. +bool qf_process_qftf_option(void) +{ + typval_T *tv; + Callback cb; + + if (p_qftf == NULL || *p_qftf == NUL) { + callback_free(&qftf_cb); + return true; + } + + if (*p_qftf == '{') { + // Lambda expression + tv = eval_expr(p_qftf); + if (tv == NULL) { + return false; + } + } else { + // treat everything else as a function name string + tv = xcalloc(1, sizeof(*tv)); + tv->v_type = VAR_STRING; + tv->vval.v_string = vim_strsave(p_qftf); + } + + if (!callback_from_typval(&cb, tv)) { + tv_free(tv); + return false; + } + + callback_free(&qftf_cb); + qftf_cb = cb; + tv_free(tv); + return true; +} + /// Update the w:quickfix_title variable in the quickfix/location list window in /// all the tab pages. static void qf_update_win_titlevar(qf_info_T *qi) @@ -3928,7 +3962,9 @@ static int qf_buf_add_line(qf_list_T *qfl, buf_T *buf, linenr_T lnum, 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) { STRLCPY(IObuff, qftf_str, IOSIZE); } else { if (qfp->qf_module != NULL) { @@ -3997,22 +4033,25 @@ static int qf_buf_add_line(qf_list_T *qfl, buf_T *buf, linenr_T lnum, 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 *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 (qfl->qftf_cb.type != kCallbackNone) { + cb = &qfl->qftf_cb; } - if (qftf != NULL && *qftf != NUL) { + if (cb != NULL && cb->type != kCallbackNone) { typval_T args[1]; + typval_T rettv; // create the dict argument dict_T *const dict = tv_dict_alloc_lock(VAR_FIXED); @@ -4026,8 +4065,16 @@ static list_T *call_qftf_func(qf_list_T *qfl, args[0].v_type = VAR_DICT; args[0].vval.v_dict = dict; - qftf_list = call_func_retlist(qftf, 1, args); - dict->dv_refcount--; + qftf_list = NULL; + + if (callback_call(cb, 1, args, &rettv)) { + if (rettv.v_type == VAR_LIST) { + qftf_list = rettv.vval.v_list; + tv_list_ref(qftf_list); + } + tv_clear(&rettv); + } + tv_dict_unref(dict); } return qftf_list; @@ -4064,6 +4111,7 @@ static void qf_fill_buffer(qf_list_T *qfl, buf_T *buf, qfline_T *old_last, if (qfl != NULL) { char_u dirname[MAXPATHL]; int prev_bufnr = -1; + bool invalid_val = false; *dirname = NUL; @@ -4086,10 +4134,15 @@ static void qf_fill_buffer(qf_list_T *qfl, buf_T *buf, qfline_T *old_last, while (lnum < qfl->qf_count) { 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)); + // 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 = (char_u *)tv_get_string_chk(TV_LIST_ITEM_TV(qftf_li)); + if (qftf_str == NULL) { + invalid_val = true; } + } if (qf_buf_add_line(qfl, buf, lnum, qfp, dirname, qftf_str, prev_bufnr != qfp->qf_fnum) == FAIL) { @@ -5796,7 +5849,9 @@ enum { QF_GETLIST_SIZE = 0x80, QF_GETLIST_TICK = 0x100, QF_GETLIST_FILEWINID = 0x200, - QF_GETLIST_ALL = 0x3FF, + QF_GETLIST_QFBUFNR = 0x400, + QF_GETLIST_QFTF = 0x800, + QF_GETLIST_ALL = 0xFFF, }; /// Parse text from 'di' and return the quickfix list items. @@ -5894,6 +5949,9 @@ static int qf_getprop_keys2flags(const dict_T *what, bool loclist) if (loclist && tv_dict_find(what, S_LEN("filewinid")) != NULL) { flags |= QF_GETLIST_FILEWINID; } + if (tv_dict_find(what, S_LEN("quickfixtextfunc")) != NULL) { + flags |= QF_GETLIST_QFTF; + } return flags; } @@ -5985,6 +6043,9 @@ static int qf_getprop_defaults(qf_info_T *qi, if ((status == OK) && locstack && (flags & QF_GETLIST_FILEWINID)) { status = tv_dict_add_nr(retdict, S_LEN("filewinid"), 0); } + if ((status == OK) && (flags & QF_GETLIST_QFTF)) { + status = tv_dict_add_str(retdict, S_LEN("quickfixtextfunc"), ""); + } return status; } @@ -6060,6 +6121,26 @@ static int qf_getprop_idx(qf_list_T *qfl, int eidx, dict_T *retdict) return tv_dict_add_nr(retdict, S_LEN("idx"), eidx); } +/// Return the 'quickfixtextfunc' function of a quickfix/location list +/// @return OK or FAIL +static int qf_getprop_qftf(qf_list_T *qfl, dict_T *retdict) + FUNC_ATTR_NONNULL_ALL +{ + int status; + + if (qfl->qftf_cb.type != kCallbackNone) { + typval_T tv; + + callback_put(&qfl->qftf_cb, &tv); + status = tv_dict_add_tv(retdict, S_LEN("quickfixtextfunc"), &tv); + tv_clear(&tv); + } else { + status = tv_dict_add_str(retdict, S_LEN("quickfixtextfunc"), ""); + } + + return status; +} + /// Return quickfix/location list details (title) as a dictionary. /// 'what' contains the details to return. If 'list_idx' is -1, /// then current list is used. Otherwise the specified list is used. @@ -6133,19 +6214,25 @@ int qf_get_properties(win_T *wp, dict_T *what, dict_T *retdict) if ((status == OK) && (wp != NULL) && (flags & QF_GETLIST_FILEWINID)) { status = qf_getprop_filewinid(wp, qi, retdict); } + if ((status == OK) && (flags & QF_GETLIST_QFTF)) { + status = qf_getprop_qftf(qfl, retdict); + } return status; } /// Set the current index in the specified quickfix list -static int qf_setprop_qftf(qf_info_T *qi, qf_list_T *qfl, - dictitem_T *di) +/// @return OK +static int qf_setprop_qftf(qf_list_T *qfl, dictitem_T *di) + FUNC_ATTR_NONNULL_ALL { - XFREE_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; + Callback cb; + + callback_free(&qfl->qftf_cb); + if (callback_from_typval(&cb, &di->di_tv)) { + qfl->qftf_cb = cb; + } + return OK; } /// Add a new quickfix entry to list at 'qf_idx' in the stack 'qi' from the @@ -6514,7 +6601,7 @@ static int qf_set_properties(qf_info_T *qi, const dict_T *what, int action, retval = qf_setprop_curidx(qi, qfl, di); } if ((di = tv_dict_find(what, S_LEN("quickfixtextfunc"))) != NULL) { - retval = qf_setprop_qftf(qi, qfl, di); + retval = qf_setprop_qftf(qfl, di); } if (newlist || retval == OK) { diff --git a/src/nvim/testdir/test_quickfix.vim b/src/nvim/testdir/test_quickfix.vim index 14240f0d5f..c63613ab1b 100644 --- a/src/nvim/testdir/test_quickfix.vim +++ b/src/nvim/testdir/test_quickfix.vim @@ -3483,12 +3483,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}, - \ 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}, + \ 'winid' : 0, 'changedtick': 0, 'filewinid' : 0, + \ 'quickfixtextfunc' : ''}, \ g:Xgetlist({'all' : 0})) endif @@ -3526,11 +3527,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, + \ '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}, + \ 'changedtick' : 0, 'filewinid' : 0, + \ 'quickfixtextfunc' : ''}, \ g:Xgetlist({'id' : qfid, 'all' : 0})) endif @@ -3547,12 +3550,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}, g:Xgetlist({'nr' : 5, 'all' : 0})) + \ 'changedtick' : 0, + \ '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}, - \ g:Xgetlist({'nr' : 5, 'all' : 0})) + \ 'changedtick' : 0, 'filewinid' : 0, + \ 'quickfixtextfunc' : ''}, g:Xgetlist({'nr' : 5, 'all' : 0})) endif endfunc @@ -4994,6 +4998,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)) @@ -5030,12 +5037,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 @@ -5074,12 +5084,53 @@ func Xtest_qftextfunc(cchar) " \ '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, '$')) + 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() |