To: vim_dev@googlegroups.com Subject: Patch 8.2.3665 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ 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() or funcref() 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 -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// \\\ \\\ sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///