diff options
author | zeertzjq <zeertzjq@outlook.com> | 2022-08-20 08:27:10 +0800 |
---|---|---|
committer | zeertzjq <zeertzjq@outlook.com> | 2022-11-07 08:24:48 +0800 |
commit | 900dd2bdab85b25237cec638265d44c2174154ed (patch) | |
tree | 44fc0d39cdd01d31143679545c0a407a366337ee /src | |
parent | 9b9f84bc62a01ed76b9f53119781816bd3375267 (diff) | |
download | rneovim-900dd2bdab85b25237cec638265d44c2174154ed.tar.gz rneovim-900dd2bdab85b25237cec638265d44c2174154ed.tar.bz2 rneovim-900dd2bdab85b25237cec638265d44c2174154ed.zip |
vim-patch:8.2.3665: cannot use a lambda for 'tagfunc'
Problem: Cannot use a lambda for 'tagfunc'.
Solution: Use 'tagfunc' like 'opfunc'. (Yegappan Lakshmanan, closes vim/vim#9204)
https://github.com/vim/vim/commit/19916a8c8920b6a1fd737ffa6d4e363fc7a96319
Co-authored-by: Yegappan Lakshmanan <yegappan@yahoo.com>
Diffstat (limited to 'src')
-rw-r--r-- | src/nvim/buffer.c | 1 | ||||
-rw-r--r-- | src/nvim/buffer_defs.h | 1 | ||||
-rw-r--r-- | src/nvim/option.c | 3 | ||||
-rw-r--r-- | src/nvim/optionstr.c | 5 | ||||
-rw-r--r-- | src/nvim/tag.c | 41 | ||||
-rw-r--r-- | src/nvim/testdir/test_tagfunc.vim | 50 |
6 files changed, 100 insertions, 1 deletions
diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c index ade5c35450..4c8faccaa7 100644 --- a/src/nvim/buffer.c +++ b/src/nvim/buffer.c @@ -1981,6 +1981,7 @@ void free_buf_options(buf_T *buf, int free_p_ff) clear_string_option(&buf->b_p_tags); clear_string_option(&buf->b_p_tc); clear_string_option(&buf->b_p_tfu); + callback_free(&buf->b_tfu_cb); clear_string_option(&buf->b_p_dict); clear_string_option(&buf->b_p_tsr); clear_string_option(&buf->b_p_qe); diff --git a/src/nvim/buffer_defs.h b/src/nvim/buffer_defs.h index 2b42289858..d8e86a75cf 100644 --- a/src/nvim/buffer_defs.h +++ b/src/nvim/buffer_defs.h @@ -677,6 +677,7 @@ struct file_buffer { char *b_p_cfu; ///< 'completefunc' char *b_p_ofu; ///< 'omnifunc' char *b_p_tfu; ///< 'tagfunc' + Callback b_tfu_cb; ///< 'tagfunc' callback int b_p_eof; ///< 'endoffile' int b_p_eol; ///< 'endofline' int b_p_fixeol; ///< 'fixendofline' diff --git a/src/nvim/option.c b/src/nvim/option.c index 523ae13e52..1eabe8c540 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -78,6 +78,7 @@ #include "nvim/spellsuggest.h" #include "nvim/strings.h" #include "nvim/syntax.h" +#include "nvim/tag.h" #include "nvim/ui.h" #include "nvim/ui_compositor.h" #include "nvim/undo.h" @@ -577,6 +578,7 @@ void free_all_options(void) } } free_operatorfunc_option(); + free_tagfunc_option(); } #endif @@ -4383,6 +4385,7 @@ void buf_copy_options(buf_T *buf, int flags) COPY_OPT_SCTX(buf, BV_OFU); buf->b_p_tfu = xstrdup(p_tfu); COPY_OPT_SCTX(buf, BV_TFU); + buf_set_tfu_callback(buf); buf->b_p_sts = p_sts; COPY_OPT_SCTX(buf, BV_STS); buf->b_p_sts_nopaste = p_sts_nopaste; diff --git a/src/nvim/optionstr.c b/src/nvim/optionstr.c index 65bc9f60df..abae338daa 100644 --- a/src/nvim/optionstr.c +++ b/src/nvim/optionstr.c @@ -38,6 +38,7 @@ #include "nvim/spellfile.h" #include "nvim/spellsuggest.h" #include "nvim/strings.h" +#include "nvim/tag.h" #include "nvim/ui.h" #include "nvim/vim.h" #include "nvim/window.h" @@ -1480,6 +1481,10 @@ char *did_set_string_option(int opt_idx, char **varp, char *oldval, char *errbuf if (qf_process_qftf_option() == FAIL) { errmsg = e_invarg; } + } else if (gvarp == &p_tfu) { // 'tagfunc' + if (set_tagfunc_option() == FAIL) { + errmsg = e_invarg; + } } else { // Options that are a list of flags. p = NULL; diff --git a/src/nvim/tag.c b/src/nvim/tag.c index 264f961b43..e38fbb7da9 100644 --- a/src/nvim/tag.c +++ b/src/nvim/tag.c @@ -114,10 +114,49 @@ static char *tagmatchname = NULL; // name of last used tag static taggy_T ptag_entry = { NULL, INIT_FMARK, 0, 0, NULL }; static int tfu_in_use = false; // disallow recursive call of tagfunc +static Callback tfu_cb; // 'tagfunc' callback function // 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(void) +{ + callback_free(&tfu_cb); + callback_free(&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; + } + + callback_copy(&curbuf->b_tfu_cb, &tfu_cb); + + return OK; +} + +#if defined(EXITFREE) +void free_tagfunc_option(void) +{ + callback_free(&tfu_cb); +} +#endif + +/// Copy the global 'tagfunc' callback function to the buffer-local 'tagfunc' +/// callback for 'buf'. +void buf_set_tfu_callback(buf_T *buf) +{ + callback_free(&buf->b_tfu_cb); + if (tfu_cb.data.funcref != NULL && *tfu_cb.data.funcref != NUL) { + callback_copy(&buf->b_tfu_cb, &tfu_cb); + } +} + /// Jump to tag; handling of tag commands and tag stack /// /// *tag != NUL: ":tag {tag}", jump to new tag, add to tag stack @@ -1129,7 +1168,7 @@ static int find_tagfunc_tags(char_u *pat, garray_T *ga, int *match_count, int fl flags & TAG_REGEXP ? "r": ""); save_pos = curwin->w_cursor; - result = call_vim_function(curbuf->b_p_tfu, 3, args, &rettv); + result = callback_call(&curbuf->b_tfu_cb, 3, args, &rettv); curwin->w_cursor = save_pos; // restore the cursor position d->dv_refcount--; diff --git a/src/nvim/testdir/test_tagfunc.vim b/src/nvim/testdir/test_tagfunc.vim index bdf5afa5b2..92c2f2d6a1 100644 --- a/src/nvim/testdir/test_tagfunc.vim +++ b/src/nvim/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 |