aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/nvim/buffer.c1
-rw-r--r--src/nvim/buffer_defs.h1
-rw-r--r--src/nvim/option.c3
-rw-r--r--src/nvim/optionstr.c5
-rw-r--r--src/nvim/tag.c41
-rw-r--r--src/nvim/testdir/test_tagfunc.vim50
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