]> git.ipfire.org Git - thirdparty/vim.git/commitdiff
patch 8.2.0959: using 'quickfixtextfunc' is a bit slow v8.2.0959
authorBram Moolenaar <Bram@vim.org>
Thu, 11 Jun 2020 17:35:52 +0000 (19:35 +0200)
committerBram Moolenaar <Bram@vim.org>
Thu, 11 Jun 2020 17:35:52 +0000 (19:35 +0200)
Problem:    Using 'quickfixtextfunc' is a bit slow.
Solution:   Process a list of entries. (Yegappan Lakshmanan, closes #6234)

runtime/doc/quickfix.txt
src/quickfix.c
src/testdir/test_quickfix.vim
src/version.c

index 982044c5bf074cd0cd561774ad30253c56da1bfe..293014b2407ae5ebae1c6d2d7946e374c799431a 100644 (file)
@@ -1947,9 +1947,9 @@ 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:
+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.
@@ -1957,12 +1957,14 @@ following fields:
                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
+    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 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".
+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
@@ -1977,11 +1979,14 @@ Example: >
     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:.')
+       " 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
 <
 
index 35a66dc93cad720cda0247972fd9f735c85cb4fe..ba54fab9c736c2595cd5b7be42a39ce7fdbfa107 100644 (file)
@@ -4415,49 +4415,17 @@ qf_update_buffer(qf_info_T *qi, qfline_T *old_last)
  */
     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)
+       char_u          *qftf_str)
 {
     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);
-    }
+    if (qftf_str != NULL)
+       vim_strncpy(IObuff, qftf_str, IOSIZE - 1);
     else
     {
        if (qfp->qf_module != NULL)
@@ -4533,6 +4501,41 @@ qf_buf_add_line(
     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,6 +4549,8 @@ qf_fill_buffer(qf_list_T *qfl, buf_T *buf, qfline_T *old_last, int qf_winid)
     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,15 +4583,30 @@ qf_fill_buffer(qf_list_T *qfl, buf_T *buf, qfline_T *old_last, int qf_winid)
            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)
        {
-           if (qf_buf_add_line(qfl, buf, lnum, qfp, dirname, qf_winid) == FAIL)
+           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)
index 474b087ae46aff1b6a1263ae96df37ff2844a115..d3b9127fa37a7f66171e2af051e88ca51a43ff88 100644 (file)
@@ -4818,24 +4818,26 @@ 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
+    let qfl = getqflist({'id' : a:info.id, 'items' : 1}).items
   else
-    let qfl = getloclist(a:info.winid, {'id' : a:info.id, 'idx' : a:info.idx,
-          \ 'items' : 1}).items
+    let qfl = getloclist(a:info.winid, {'id' : a:info.id, '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
+  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 s
+  return l
 endfunc
 
 func Xtest_qftextfunc(cchar)
@@ -4859,16 +4861,18 @@ func Xtest_qftextfunc(cchar)
   " 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
+      let qfl = getqflist({'id' : a:info.id, 'items' : 1}).items
     else
-      let qfl = getloclist(a:info.winid, {'id' : a:info.id, 'idx' : a:info.idx,
-            \ 'items' : 1}).items
+      let qfl = getloclist(a:info.winid, {'id' : a:info.id, 'items' : 1}).items
     endif
     if empty(qfl)
-      return ''
+      return []
     endif
-    return 'Line ' .. qfl[0].lnum .. ', Col ' .. qfl[0].col
+    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,8 +4912,21 @@ func Xtest_qftextfunc(cchar)
   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()
index 8b08d077767a75dc56cfbee06ffe3dae9601fa88..1479c2ab60eacdaf6236c9f549b9b002d6c775e5 100644 (file)
@@ -754,6 +754,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    959,
 /**/
     958,
 /**/