Patch 8.2.0869
Problem:    It is not possible to customize the quickfix window contents.
Solution:   Add 'quickfixtextfunc'. (Yegappan Lakshmanan, closes #5465)
Files:      runtime/doc/eval.txt, runtime/doc/options.txt,
            runtime/doc/quickfix.txt, src/option.h, src/optiondefs.h,
            src/quickfix.c, src/testdir/test_quickfix.vim


*** ../vim-8.2.0868/runtime/doc/eval.txt        2020-05-31 22:19:52.894638049 
+0200
--- runtime/doc/eval.txt        2020-05-31 22:57:50.937143392 +0200
***************
*** 5498,5505 ****
                        id      get information for the quickfix list with
                                |quickfix-ID|; zero means the id for the
                                current list or the list specified by "nr"
!                       idx     index of the current entry in the quickfix
!                               list specified by 'id' or 'nr'.
                                See |quickfix-index|
                        items   quickfix list entries
                        lines   parse a list of lines using 'efm' and return
--- 5508,5516 ----
                        id      get information for the quickfix list with
                                |quickfix-ID|; zero means the id for the
                                current list or the list specified by "nr"
!                       idx     get information for the quickfix entry at this
!                               index in the list specified by 'id' or 'nr'.
!                               If set to zero, then uses the current entry.
                                See |quickfix-index|
                        items   quickfix list entries
                        lines   parse a list of lines using 'efm' and return
***************
*** 5535,5541 ****
                                If not present, set to "".
                        id      quickfix list ID |quickfix-ID|. If not
                                present, set to 0.
!                       idx     index of the current entry in the list. If not
                                present, set to 0.
                        items   quickfix list entries. If not present, set to
                                an empty list.
--- 5546,5552 ----
                                If not present, set to "".
                        id      quickfix list ID |quickfix-ID|. If not
                                present, set to 0.
!                       idx     index of the quickfix entry in the list. If not
                                present, set to 0.
                        items   quickfix list entries. If not present, set to
                                an empty list.
***************
*** 8745,8751 ****
  setqflist({list} [, {action} [, {what}]])             *setqflist()*
                Create or replace or add to the quickfix list.
  
!               When {what} is not present, use the items in {list}.  Each
                item must be a dictionary.  Non-dictionary items in {list} are
                ignored.  Each dictionary item can contain the following
                entries:
--- 8762,8773 ----
  setqflist({list} [, {action} [, {what}]])             *setqflist()*
                Create or replace or add to the quickfix list.
  
!               If the optional {what} dictionary argument is supplied, then
!               only the items listed in {what} are set. The first {list}
!               argument is ignored.  See below for the supported items in
!               {what}.
! 
!               When {what} is not present, the items in {list} or used.  Each
                item must be a dictionary.  Non-dictionary items in {list} are
                ignored.  Each dictionary item can contain the following
                entries:
***************
*** 8800,8809 ****
                freed. To add a new quickfix list at the end of the stack,
                set "nr" in {what} to "$".
  
!               If the optional {what} dictionary argument is supplied, then
!               only the items listed in {what} are set. The first {list}
!               argument is ignored.  The following items can be specified in
!               {what}:
                    context     quickfix list context. See |quickfix-context|
                    efm         errorformat to use when parsing text from
                                "lines". If this is not present, then the
--- 8822,8828 ----
                freed. To add a new quickfix list at the end of the stack,
                set "nr" in {what} to "$".
  
!               The following items can be specified in dictionary {what}:
                    context     quickfix list context. See |quickfix-context|
                    efm         errorformat to use when parsing text from
                                "lines". If this is not present, then the
***************
*** 8823,8828 ****
--- 8842,8852 ----
                    nr          list number in the quickfix stack; zero
                                means the current quickfix list and "$" means
                                the last quickfix list.
+                   quickfixtextfunc
+                               function to get the text to display in the
+                               quickfix window.  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|
                Unsupported keys in {what} are ignored.
                If the "nr" item is not present, then the current quickfix list
*** ../vim-8.2.0868/runtime/doc/options.txt     2020-05-31 15:08:55.118721233 
+0200
--- runtime/doc/options.txt     2020-05-31 22:59:34.412839507 +0200
***************
*** 5900,5905 ****
--- 5901,5921 ----
        This option cannot be set from a |modeline| or in the |sandbox|, for
        security reasons.
  
+                                               *'quickfixtextfunc'* *'qftf'*
+ 'quickfixtextfunc' 'qftf'     string (default "")
+                       global
+                       {only available when compiled with the |+quickfix|
+                       feature}
+       This option specifies a function to be used to get the text to display
+       in the quickfix and location list windows.  This can be used to
+       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.
+ 
+       This option cannot be set from a |modeline| or in the |sandbox|, for
+       security reasons.
+ 
                                                *'quoteescape'* *'qe'*
  'quoteescape' 'qe'    string  (default "\")
                        local to buffer
*** ../vim-8.2.0868/runtime/doc/quickfix.txt    2020-01-06 21:47:17.040023214 
+0100
--- runtime/doc/quickfix.txt    2020-05-31 23:01:47.928423150 +0200
***************
*** 15,20 ****
--- 15,21 ----
  7. The error format                   |error-file-format|
  8. The directory stack                        |quickfix-directory-stack|
  9. Specific error file formats                |errorformats|
+ 10. Customizing the quickfix window   |quickfix-window-function|
  
  The quickfix commands are not available when the |+quickfix| feature was
  disabled at compile time.
***************
*** 1922,1927 ****
--- 1922,1980 ----
  start of the file about how to use it.  (This script is deprecated, see
  |compiler-perl|.)
  
+ =============================================================================
+ 10. Customizing the quickfix window           *quickfix-window-function*
+ 
+ The default format for the lines displayed in the quickfix window and location
+ list window is:
  
+     <filename>|<lnum> col <col>|<text>
+ 
+ The values displayed in each line correspond to the "bufnr", "lnum", "col" and
+ "text" fields returned by the |getqflist()| function.
+ 
+ For some quickfix/location lists, the displayed text need to be customized.
+ For example, if only the filename is present for a quickfix entry, then the
+ two "|" field separator characters after the filename are not needed.  Another
+ use case is to customize the path displayed for a filename. By default, the
+ complete path (which may be too long) is displayed for files which are not
+ 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:
+ 
+     quickfix  set to 1 when called for a quickfix list and 0 when called for
+               a location list.
+     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
+ |setloclist()| function. This overrides the global 'quickfixtextfunc' option.
+ 
+ The example below displays the list of old files (|v:oldfiles|) in a quickfix
+ window. As there is no line, column number and error text information
+ associated with each entry, the 'quickfixtextfunc' function returns only the
+ filename.
+ Example: >
+     " create a quickfix list from v:oldfiles
+     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
+ <
  
   vim:tw=78:ts=8:noet:ft=help:norl:
*** ../vim-8.2.0868/src/option.h        2020-04-17 19:41:16.100078313 +0200
--- src/option.h        2020-05-31 22:57:50.937143392 +0200
***************
*** 820,825 ****
--- 820,826 ----
  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)
*** ../vim-8.2.0868/src/optiondefs.h    2020-05-31 16:41:04.646603340 +0200
--- src/optiondefs.h    2020-05-31 22:57:50.937143392 +0200
***************
*** 2045,2050 ****
--- 2045,2059 ----
  #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,
*** ../vim-8.2.0868/src/quickfix.c      2020-05-30 20:30:42.896816552 +0200
--- src/quickfix.c      2020-05-31 22:57:50.941143383 +0200
***************
*** 82,87 ****
--- 82,88 ----
      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,2282 ****
--- 2278,2287 ----
      }
      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,3817 ****
--- 3817,3823 ----
      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,4473 ****
   * 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)
  {
      int               len;
      buf_T     *errbuf;
  
!     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)
      {
!       if (qfp->qf_type == 1)  // :helpgrep
!           vim_strncpy(IObuff, gettail(errbuf->b_fname), IOSIZE - 1);
!       else
        {
!           // 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);
        }
!       len = (int)STRLEN(IObuff);
!     }
!     else
!       len = 0;
  
!     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_col > 0)
        {
!           vim_snprintf((char *)IObuff + len, IOSIZE - len,
!                                                      " col %d", qfp->qf_col);
            len += (int)STRLEN(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);
- 
      if (ml_append_buf(buf, lnum, IObuff,
                (colnr_T)STRLEN(IObuff) + 1, FALSE) == FAIL)
        return FAIL;
--- 4405,4520 ----
   * Add an error line to the quickfix buffer.
   */
      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               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;
! 
!       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)
        {
!           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)
!       {
!           if (qfp->qf_type == 1)      // :helpgrep
!               vim_strncpy(IObuff, gettail(errbuf->b_fname), IOSIZE - 1);
!           else
            {
!               // 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);
            }
!           len = (int)STRLEN(IObuff);
        }
!       else
!           len = 0;
  
!       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_col > 0)
!           {
!               vim_snprintf((char *)IObuff + len, IOSIZE - len,
!                       " col %d", qfp->qf_col);
!               len += (int)STRLEN(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);
      }
  
      if (ml_append_buf(buf, lnum, IObuff,
                (colnr_T)STRLEN(IObuff) + 1, FALSE) == FAIL)
        return FAIL;
***************
*** 4522,4528 ****
        }
        while (lnum < qfl->qf_count)
        {
!           if (qf_buf_add_line(buf, lnum, qfp, dirname) == FAIL)
                break;
  
            ++lnum;
--- 4569,4575 ----
        }
        while (lnum < qfl->qf_count)
        {
!           if (qf_buf_add_line(qfl, buf, lnum, qfp, dirname) == FAIL)
                break;
  
            ++lnum;
***************
*** 6369,6377 ****
  /*
   * Add each quickfix error to list "list" as a dictionary.
   * If qf_idx is -1, use the current list. Otherwise, use the specified list.
   */
      static int
! get_errorlist(qf_info_T *qi_arg, win_T *wp, int qf_idx, list_T *list)
  {
      qf_info_T *qi = qi_arg;
      qf_list_T *qfl;
--- 6416,6431 ----
  /*
   * 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,
!       int             eidx,
!       list_T          *list)
  {
      qf_info_T *qi = qi_arg;
      qf_list_T *qfl;
***************
*** 6389,6394 ****
--- 6443,6451 ----
        }
      }
  
+     if (eidx < 0)
+       return OK;
+ 
      if (qf_idx == INVALID_QFIDX)
        qf_idx = qi->qf_curlist;
  
***************
*** 6401,6407 ****
  
      FOR_ALL_QFL_ITEMS(qfl, qfp, i)
      {
!       if (get_qfline_items(qfp, list) == FAIL)
            return FAIL;
      }
  
--- 6458,6469 ----
  
      FOR_ALL_QFL_ITEMS(qfl, qfp, i)
      {
!       if (eidx > 0)
!       {
!           if (eidx == i)
!               return get_qfline_items(qfp, list);
!       }
!       else if (get_qfline_items(qfp, list) == FAIL)
            return FAIL;
      }
  
***************
*** 6461,6467 ****
            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);
                qf_free(&qi->qf_lists[0]);
            }
            free(qi);
--- 6523,6529 ----
            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, 0, l);
                qf_free(&qi->qf_lists[0]);
            }
            free(qi);
***************
*** 6679,6694 ****
  }
  
  /*
!  * Return the quickfix list items/entries as 'items' in retdict
   */
      static int
! qf_getprop_items(qf_info_T *qi, int qf_idx, dict_T *retdict)
  {
      int               status = OK;
      list_T    *l = list_alloc();
      if (l != NULL)
      {
!       (void)get_errorlist(qi, NULL, qf_idx, l);
        dict_add_list(retdict, "items", l);
      }
      else
--- 6741,6757 ----
  }
  
  /*
!  * 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, int eidx, dict_T *retdict)
  {
      int               status = OK;
      list_T    *l = list_alloc();
      if (l != NULL)
      {
!       (void)get_errorlist(qi, NULL, qf_idx, eidx, l);
        dict_add_list(retdict, "items", l);
      }
      else
***************
*** 6726,6741 ****
  }
  
  /*
!  * Return the current quickfix list index as 'idx' in retdict
   */
      static int
! qf_getprop_idx(qf_list_T *qfl, 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);
  }
  
  /*
--- 6789,6808 ----
  }
  
  /*
!  * 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, int eidx, dict_T *retdict)
  {
!     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,6755 ****
--- 6817,6823 ----
      qf_list_T *qfl;
      int               status = OK;
      int               qf_idx = INVALID_QFIDX;
+     int               eidx = 0;
      dictitem_T        *di;
      int               flags = QF_GETLIST_NONE;
  
***************
*** 6770,6775 ****
--- 6838,6851 ----
  
      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,6789 ****
      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);
      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);
      if ((status == OK) && (flags & QF_GETLIST_SIZE))
        status = dict_add_number(retdict, "size", qfl->qf_count);
      if ((status == OK) && (flags & QF_GETLIST_TICK))
--- 6853,6865 ----
      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, 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, 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,7153 ****
--- 7224,7243 ----
  }
  
  /*
+  * 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,7191 ****
--- 7276,7283 ----
        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,7906 ****
      {
        if (rettv_list_alloc(rettv) == OK)
            if (is_qf || wp != NULL)
!               (void)get_errorlist(NULL, wp, -1, rettv->vval.v_list);
      }
      else
      {
--- 7992,7998 ----
      {
        if (rettv_list_alloc(rettv) == OK)
            if (is_qf || wp != NULL)
!               (void)get_errorlist(NULL, wp, -1, 0, rettv->vval.v_list);
      }
      else
      {
*** ../vim-8.2.0868/src/testdir/test_quickfix.vim       2020-05-03 
16:29:46.891538441 +0200
--- src/testdir/test_quickfix.vim       2020-05-31 22:57:50.941143383 +0200
***************
*** 4766,4769 ****
--- 4766,4886 ----
    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
*** ../vim-8.2.0868/src/version.c       2020-05-31 22:19:52.898638027 +0200
--- src/version.c       2020-05-31 22:58:28.513035100 +0200
***************
*** 748,749 ****
--- 748,751 ----
  {   /* Add new patch number below this line */
+ /**/
+     869,
  /**/

-- 
hundred-and-one symptoms of being an internet addict:
237. You tattoo your email address on your forehead.

 /// Bram Moolenaar -- [email protected] -- 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    ///

-- 
-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- 
You received this message because you are subscribed to the Google Groups 
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/vim_dev/202005312112.04VLCjRu755735%40masaka.moolenaar.net.

Raspunde prin e-mail lui