To: vim_dev@googlegroups.com Subject: Patch 8.2.0959 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 8.2.0959 Problem: Using 'quickfixtextfunc' is a bit slow. Solution: Process a list of entries. (Yegappan Lakshmanan, closes #6234) Files: runtime/doc/quickfix.txt, src/quickfix.c, src/testdir/test_quickfix.vim *** ../vim-8.2.0958/runtime/doc/quickfix.txt 2020-06-08 19:20:21.703831100 +0200 --- runtime/doc/quickfix.txt 2020-06-11 19:33:26.097919533 +0200 *************** *** 1948,1956 **** 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. --- 1947,1955 ---- 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 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. *************** *** 1958,1969 **** 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 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 --- 1957,1970 ---- 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 ! 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 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 *************** *** 1978,1988 **** 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 < --- 1979,1992 ---- call setqflist([], ' ', {'lines' : v:oldfiles, 'efm' : '%f', \ 'quickfixtextfunc' : 'QfOldFiles'}) func QfOldFiles(info) ! " 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 < *** ../vim-8.2.0958/src/quickfix.c 2020-06-08 19:35:55.781319897 +0200 --- src/quickfix.c 2020-06-11 19:33:26.097919533 +0200 *************** *** 4415,4463 **** */ static int 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 qf_winid) { 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 the 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, "winid", (long)qf_winid); ! 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; ! ! 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_module != NULL) --- 4415,4431 ---- */ static int qf_buf_add_line( buf_T *buf, // quickfix window buffer linenr_T lnum, qfline_T *qfp, char_u *dirname, ! char_u *qftf_str) { int len; buf_T *errbuf; ! if (qftf_str != NULL) ! vim_strncpy(IObuff, qftf_str, IOSIZE - 1); else { if (qfp->qf_module != NULL) *************** *** 4533,4538 **** --- 4501,4541 ---- 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]; + dict_T *d; + + // create the dict argument + if ((d = dict_alloc_lock(VAR_FIXED)) == NULL) + return NULL; + dict_add_number(d, "quickfix", (long)IS_QF_LIST(qfl)); + dict_add_number(d, "winid", (long)qf_winid); + dict_add_number(d, "id", (long)qfl->qf_id); + dict_add_number(d, "start_idx", start_idx); + dict_add_number(d, "end_idx", end_idx); + ++d->dv_refcount; + args[0].v_type = VAR_DICT; + args[0].vval.v_dict = d; + + qftf_list = call_func_retlist(qftf, 1, args); + --d->dv_refcount; + } + + return qftf_list; + } + /* * Fill current buffer with quickfix errors, replacing any previous contents. * curbuf must be the quickfix buffer! *************** *** 4546,4551 **** --- 4549,4556 ---- linenr_T lnum; qfline_T *qfp; int old_KeyTyped = KeyTyped; + list_T *qftf_list = NULL; + listitem_T *qftf_li = NULL; if (old_last == NULL) { *************** *** 4578,4592 **** qfp = old_last->qf_next; lnum = buf->b_ml.ml_line_count; } while (lnum < qfl->qf_count) { ! if (qf_buf_add_line(qfl, buf, lnum, qfp, dirname, qf_winid) == FAIL) break; ++lnum; qfp = qfp->qf_next; if (qfp == NULL) break; } if (old_last == NULL) --- 4583,4612 ---- qfp = old_last->qf_next; lnum = buf->b_ml.ml_line_count; } + + qftf_list = call_qftf_func(qfl, qf_winid, (long)(lnum + 1), + (long)qfl->qf_count); + if (qftf_list != NULL) + qftf_li = qftf_list->lv_first; + 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 = tv_get_string_chk(&qftf_li->li_tv); ! ! if (qf_buf_add_line(buf, lnum, qfp, dirname, qftf_str) == FAIL) break; ++lnum; qfp = qfp->qf_next; if (qfp == NULL) break; + + if (qftf_li != NULL) + qftf_li = qftf_li->li_next; } if (old_last == NULL) *** ../vim-8.2.0958/src/testdir/test_quickfix.vim 2020-06-09 15:57:32.929019414 +0200 --- src/testdir/test_quickfix.vim 2020-06-11 19:33:26.101919513 +0200 *************** *** 4818,4841 **** " 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(a:info.winid, {'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) --- 4818,4843 ---- " Test for the 'quickfixtextfunc' setting func Tqfexpr(info) if a:info.quickfix ! let qfl = getqflist({'id' : a:info.id, 'items' : 1}).items else ! let qfl = getloclist(a:info.winid, {'id' : a:info.id, 'items' : 1}).items endif ! 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) *************** *** 4859,4874 **** " 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(a:info.winid, {'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"}) --- 4861,4878 ---- " Test for per list 'quickfixtextfunc' setting func PerQfText(info) if a:info.quickfix ! let qfl = getqflist({'id' : a:info.id, 'items' : 1}).items else ! let qfl = getloclist(a:info.winid, {'id' : a:info.id, 'items' : 1}).items endif if empty(qfl) ! return [] endif ! 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"}) *************** *** 4908,4915 **** --- 4912,4932 ---- call assert_fails("Xexpr ['F1:10:2:green', 'F1:20:4:blue']", 'E119:') 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:') + 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() *** ../vim-8.2.0958/src/version.c 2020-06-11 19:22:40.144625523 +0200 --- src/version.c 2020-06-11 19:34:46.625583935 +0200 *************** *** 756,757 **** --- 756,759 ---- { /* Add new patch number below this line */ + /**/ + 959, /**/ -- GUARD #2: It could be carried by an African swallow! GUARD #1: Oh, yeah, an African swallow maybe, but not a European swallow, that's my point. GUARD #2: Oh, yeah, I agree with that... The Quest for the Holy Grail (Monty Python) /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\ \\\ an exciting new programming language -- http://www.Zimbu.org /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///