Patch 8.2.3665
Problem:    Cannot use a lambda for 'tagfunc'.
Solution:   Use 'tagfunc' like 'opfunc'. (Yegappan Lakshmanan, closes #9204)
Files:      runtime/doc/options.txt, src/buffer.c, src/option.c,
            src/optionstr.c, src/proto/tag.pro, src/structs.h, src/tag.c,
            src/testdir/test_tagfunc.vim


*** ../vim-8.2.3664/runtime/doc/options.txt     2021-11-18 22:08:52.007682711 
+0000
--- runtime/doc/options.txt     2021-11-24 16:27:46.892748472 +0000
***************
*** 370,378 ****
  or a function reference or a lambda function.  Examples:
  >
        set opfunc=MyOpFunc
!       set opfunc=function("MyOpFunc")
!       set opfunc=funcref("MyOpFunc")
!       set opfunc={t\ ->\ MyOpFunc(t)}
  <
  
  Setting the filetype
--- 377,385 ----
  or a function reference or a lambda function.  Examples:
  >
        set opfunc=MyOpFunc
!       set opfunc=function('MyOpFunc')
!       set opfunc=funcref('MyOpFunc')
!       let &opfunc = "{t -> MyOpFunc(t)}"
  <
  
  Setting the filetype
***************
*** 7770,7776 ****
        This option specifies a function to be used to perform tag searches.
        The function gets the tag pattern and should return a List of matching
        tags.  See |tag-function| for an explanation of how to write the
!       function and an example.
  
                                                *'taglength'* *'tl'*
  'taglength' 'tl'      number  (default 0)
--- 7792,7800 ----
        This option specifies a function to be used to perform tag searches.
        The function gets the tag pattern and should return a List of matching
        tags.  See |tag-function| for an explanation of how to write the
!       function and an example.  The value can be the name of a function, a
!       |lambda| or a |Funcref|. See |option-value-function| for more
!       information.
  
                                                *'taglength'* *'tl'*
  'taglength' 'tl'      number  (default 0)
*** ../vim-8.2.3664/src/buffer.c        2021-11-19 17:01:05.555037778 +0000
--- src/buffer.c        2021-11-24 16:26:17.400826784 +0000
***************
*** 2344,2349 ****
--- 2344,2350 ----
      clear_string_option(&buf->b_p_tc);
  #ifdef FEAT_EVAL
      clear_string_option(&buf->b_p_tfu);
+     free_callback(&buf->b_tfu_cb);
  #endif
      clear_string_option(&buf->b_p_dict);
      clear_string_option(&buf->b_p_tsr);
*** ../vim-8.2.3664/src/option.c        2021-11-20 13:45:37.806729612 +0000
--- src/option.c        2021-11-24 16:26:17.400826784 +0000
***************
*** 810,815 ****
--- 810,816 ----
            clear_string_option((char_u **)options[i].var);
      }
      free_operatorfunc_option();
+     free_tagfunc_option();
  }
  #endif
  
***************
*** 5956,5961 ****
--- 5957,5963 ----
  #ifdef FEAT_EVAL
            buf->b_p_tfu = vim_strsave(p_tfu);
            COPY_OPT_SCTX(buf, BV_TFU);
+           buf_set_tfu_callback(buf);
  #endif
            buf->b_p_sts = p_sts;
            COPY_OPT_SCTX(buf, BV_STS);
*** ../vim-8.2.3664/src/optionstr.c     2021-11-20 13:45:37.806729612 +0000
--- src/optionstr.c     2021-11-24 16:26:17.400826784 +0000
***************
*** 2333,2338 ****
--- 2333,2347 ----
      }
  #endif
  
+ #ifdef FEAT_EVAL
+     // 'tagfunc'
+     else if (gvarp == &p_tfu)
+     {
+       if (set_tagfunc_option() == FAIL)
+           errmsg = e_invarg;
+     }
+ #endif
+ 
      // Options that are a list of flags.
      else
      {
*** ../vim-8.2.3664/src/proto/tag.pro   2019-12-12 11:55:34.000000000 +0000
--- src/proto/tag.pro   2021-11-24 16:30:12.228602387 +0000
***************
*** 1,4 ****
--- 1,7 ----
  /* tag.c */
+ int set_tagfunc_option(void);
+ void free_tagfunc_option(void);
+ void buf_set_tfu_callback(buf_T *buf);
  int do_tag(char_u *tag, int type, int count, int forceit, int verbose);
  void tag_freematch(void);
  void do_tags(exarg_T *eap);
*** ../vim-8.2.3664/src/structs.h       2021-11-24 16:19:41.389010087 +0000
--- src/structs.h       2021-11-24 16:26:17.400826784 +0000
***************
*** 2878,2884 ****
      char_u    *b_p_ofu;       // 'omnifunc'
  #endif
  #ifdef FEAT_EVAL
!     char_u    *b_p_tfu;       // 'tagfunc'
  #endif
      int               b_p_eol;        // 'endofline'
      int               b_p_fixeol;     // 'fixendofline'
--- 2878,2885 ----
      char_u    *b_p_ofu;       // 'omnifunc'
  #endif
  #ifdef FEAT_EVAL
!     char_u    *b_p_tfu;       // 'tagfunc' option value
!     callback_T        b_tfu_cb;       // 'tagfunc' callback
  #endif
      int               b_p_eol;        // 'endofline'
      int               b_p_fixeol;     // 'fixendofline'
*** ../vim-8.2.3664/src/tag.c   2021-10-02 11:23:01.566500862 +0100
--- src/tag.c   2021-11-24 16:26:17.404826781 +0000
***************
*** 103,114 ****
--- 103,163 ----
  
  #ifdef FEAT_EVAL
  static int  tfu_in_use = FALSE;           // disallow recursive call of 
tagfunc
+ static callback_T tfu_cb;         // 'tagfunc' callback function
  #endif
  
  // Used instead of NUL to separate tag fields in the growarrays.
  #define TAG_SEP 0x02
  
  /*
+  * Reads the 'tagfunc' option value and convert that to a callback value.
+  * Invoked when the 'tagfunc' option is set. The option value can be a name of
+  * a function (string), or function(<name>) or funcref(<name>) or a lambda.
+  */
+     int
+ set_tagfunc_option()
+ {
+ #ifdef FEAT_EVAL
+     free_callback(&tfu_cb);
+     free_callback(&curbuf->b_tfu_cb);
+ 
+     if (*curbuf->b_p_tfu == NUL)
+       return OK;
+ 
+     if (option_set_callback_func(curbuf->b_p_tfu, &tfu_cb) == FAIL)
+       return FAIL;
+ 
+     copy_callback(&curbuf->b_tfu_cb, &tfu_cb);
+ #endif
+ 
+     return OK;
+ }
+ 
+ # if defined(EXITFREE) || defined(PROTO)
+     void
+ free_tagfunc_option(void)
+ {
+ #  ifdef FEAT_EVAL
+     free_callback(&tfu_cb);
+ #  endif
+ }
+ # endif
+ 
+ /*
+  * Copy the global 'tagfunc' callback function to the buffer-local 'tagfunc'
+  * callback for 'buf'.
+  */
+     void
+ buf_set_tfu_callback(buf_T *buf UNUSED)
+ {
+ #ifdef FEAT_EVAL
+     free_callback(&buf->b_tfu_cb);
+     if (tfu_cb.cb_name != NULL && *tfu_cb.cb_name != NUL)
+       copy_callback(&buf->b_tfu_cb, &tfu_cb);
+ #endif
+ }
+ 
+ /*
   * Jump to tag; handling of tag commands and tag stack
   *
   * *tag != NUL: ":tag {tag}", jump to new tag, add to tag stack
***************
*** 1341,1347 ****
                 flags & TAG_REGEXP   ? "r": "");
  
      save_pos = curwin->w_cursor;
!     result = call_vim_function(curbuf->b_p_tfu, 3, args, &rettv);
      curwin->w_cursor = save_pos;      // restore the cursor position
      --d->dv_refcount;
  
--- 1390,1396 ----
                 flags & TAG_REGEXP   ? "r": "");
  
      save_pos = curwin->w_cursor;
!     result = call_callback(&curbuf->b_tfu_cb, 0, &rettv, 3, args);
      curwin->w_cursor = save_pos;      // restore the cursor position
      --d->dv_refcount;
  
*** ../vim-8.2.3664/src/testdir/test_tagfunc.vim        2021-03-21 
13:49:53.453675479 +0000
--- src/testdir/test_tagfunc.vim        2021-11-24 16:26:17.404826781 +0000
***************
*** 117,120 ****
--- 117,170 ----
    delfunc Mytagfunc2
  endfunc
  
+ " Test for different ways of setting the 'tagfunc' option
+ func Test_tagfunc_callback()
+   " Test for using a function()
+   func MytagFunc1(pat, flags, info)
+     let g:MytagFunc1_args = [a:pat, a:flags, a:info]
+     return v:null
+   endfunc
+   let g:MytagFunc1_args = []
+   set tagfunc=function('MytagFunc1')
+   call assert_fails('tag abc', 'E433:')
+   call assert_equal(['abc', '', {}], g:MytagFunc1_args)
+ 
+   " Test for using a funcref()
+   new
+   func MytagFunc2(pat, flags, info)
+     let g:MytagFunc2_args = [a:pat, a:flags, a:info]
+     return v:null
+   endfunc
+   let g:MytagFunc2_args = []
+   set tagfunc=funcref('MytagFunc2')
+   call assert_fails('tag def', 'E433:')
+   call assert_equal(['def', '', {}], g:MytagFunc2_args)
+ 
+   " Test for using a lambda function
+   new
+   func MytagFunc3(pat, flags, info)
+     let g:MytagFunc3_args = [a:pat, a:flags, a:info]
+     return v:null
+   endfunc
+   let g:MytagFunc3_args = []
+   let &tagfunc= '{a, b, c -> MytagFunc3(a, b, c)}'
+   call assert_fails('tag ghi', 'E433:')
+   call assert_equal(['ghi', '', {}], g:MytagFunc3_args)
+ 
+   " Test for clearing the 'tagfunc' option
+   set tagfunc=''
+   set tagfunc&
+ 
+   call assert_fails("set tagfunc=function('abc')", "E700:")
+   call assert_fails("set tagfunc=funcref('abc')", "E700:")
+   let &tagfunc = "{a -> 'abc'}"
+   call assert_fails("echo taglist('a')", "E987:")
+ 
+   " cleanup
+   delfunc MytagFunc1
+   delfunc MytagFunc2
+   delfunc MytagFunc3
+   %bw!
+ endfunc
+ 
  " vim: shiftwidth=2 sts=2 expandtab
*** ../vim-8.2.3664/src/version.c       2021-11-24 16:19:41.393010087 +0000
--- src/version.c       2021-11-24 16:29:04.868672714 +0000
***************
*** 759,760 ****
--- 759,762 ----
  {   /* Add new patch number below this line */
+ /**/
+     3665,
  /**/

-- 
A programmer's wife asks him: "Please run to the store and pick up a loaf of
bread.  If they have eggs, get a dozen".  The programmer comes home with 12
loafs of bread.

 /// Bram Moolenaar -- [email protected] -- http://www.Moolenaar.net   \\\
///                                                                      \\\
\\\        sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ ///
 \\\            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/20211124163325.6365A1C0745%40moolenaar.net.

Raspunde prin e-mail lui