diff options
author | Bram Moolenaar <Bram@vim.org> | 2020-05-31 23:11:59 +0200 |
---|---|---|
committer | Bram Moolenaar <Bram@vim.org> | 2020-05-31 23:11:59 +0200 |
commit | 858ba06d5f577b187da0367b231f7fa9461cb32d (patch) | |
tree | 89e7da14ddfacad9663c1289d8c71d57d81206f9 /src | |
parent | 2245ae18e3480057f98fc0e5d9f18091f32a5de0 (diff) |
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)
Diffstat (limited to 'src')
-rw-r--r-- | src/option.h | 1 | ||||
-rw-r--r-- | src/optiondefs.h | 9 | ||||
-rw-r--r-- | src/quickfix.c | 226 | ||||
-rw-r--r-- | src/testdir/test_quickfix.vim | 117 | ||||
-rw-r--r-- | src/version.c | 2 |
5 files changed, 288 insertions, 67 deletions
diff --git a/src/option.h b/src/option.h index bead4c5bb6..718553a908 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 5ed9be9bc6..571a3af5e2 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 f3ad4cde20..acd28a1435 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 11bdfbefa3..fb4e07c6f7 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 c75283f9f1..d211e8cd0a 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, |