diff options
-rw-r--r-- | runtime/doc/options.txt | 10 | ||||
-rw-r--r-- | src/buffer.c | 1 | ||||
-rw-r--r-- | src/option.c | 2 | ||||
-rw-r--r-- | src/optionstr.c | 9 | ||||
-rw-r--r-- | src/proto/tag.pro | 3 | ||||
-rw-r--r-- | src/structs.h | 3 | ||||
-rw-r--r-- | src/tag.c | 51 | ||||
-rw-r--r-- | src/testdir/test_tagfunc.vim | 50 | ||||
-rw-r--r-- | src/version.c | 2 |
9 files changed, 125 insertions, 6 deletions
diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt index 8fa4cebb4..f5f570ba3 100644 --- a/runtime/doc/options.txt +++ b/runtime/doc/options.txt @@ -377,9 +377,9 @@ Some options ('completefunc', 'imactivatefunc', 'imstatusfunc', 'omnifunc', 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)} + set opfunc=function('MyOpFunc') + set opfunc=funcref('MyOpFunc') + let &opfunc = "{t -> MyOpFunc(t)}" < Setting the filetype @@ -7792,7 +7792,9 @@ A jump table for the options with a short description can be found at |Q_op|. 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. + 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) diff --git a/src/buffer.c b/src/buffer.c index 2983ca9fe..e2732de7a 100644 --- a/src/buffer.c +++ b/src/buffer.c @@ -2344,6 +2344,7 @@ free_buf_options( 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); diff --git a/src/option.c b/src/option.c index b807b9b6c..4422634e2 100644 --- a/src/option.c +++ b/src/option.c @@ -810,6 +810,7 @@ free_all_options(void) clear_string_option((char_u **)options[i].var); } free_operatorfunc_option(); + free_tagfunc_option(); } #endif @@ -5956,6 +5957,7 @@ buf_copy_options(buf_T *buf, int flags) #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); diff --git a/src/optionstr.c b/src/optionstr.c index 705e86089..8948830c8 100644 --- a/src/optionstr.c +++ b/src/optionstr.c @@ -2333,6 +2333,15 @@ ambw_end: } #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 { diff --git a/src/proto/tag.pro b/src/proto/tag.pro index 3046406a3..e9827ea7e 100644 --- a/src/proto/tag.pro +++ b/src/proto/tag.pro @@ -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); diff --git a/src/structs.h b/src/structs.h index d9d3e30c3..bef7062df 100644 --- a/src/structs.h +++ b/src/structs.h @@ -2878,7 +2878,8 @@ struct file_buffer char_u *b_p_ofu; // 'omnifunc' #endif #ifdef FEAT_EVAL - char_u *b_p_tfu; // 'tagfunc' + 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' @@ -103,12 +103,61 @@ static taggy_T ptag_entry = {NULL, {{0, 0, 0}, 0}, 0, 0, NULL}; #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,7 +1390,7 @@ find_tagfunc_tags( flags & TAG_REGEXP ? "r": ""); save_pos = curwin->w_cursor; - result = call_vim_function(curbuf->b_p_tfu, 3, args, &rettv); + result = call_callback(&curbuf->b_tfu_cb, 0, &rettv, 3, args); curwin->w_cursor = save_pos; // restore the cursor position --d->dv_refcount; diff --git a/src/testdir/test_tagfunc.vim b/src/testdir/test_tagfunc.vim index 3eb390440..a972016c9 100644 --- a/src/testdir/test_tagfunc.vim +++ b/src/testdir/test_tagfunc.vim @@ -117,4 +117,54 @@ func Test_tagfunc_settagstack() 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 diff --git a/src/version.c b/src/version.c index 4356be14e..7a29e4e0d 100644 --- a/src/version.c +++ b/src/version.c @@ -758,6 +758,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 3665, +/**/ 3664, /**/ 3663, |