mirror of
https://github.com/neovim/neovim.git
synced 2025-09-05 19:08:15 +00:00
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)
19916a8c89
Co-authored-by: Yegappan Lakshmanan <yegappan@yahoo.com>
This commit is contained in:
@@ -318,9 +318,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
|
||||
@@ -6443,7 +6443,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)
|
||||
|
@@ -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);
|
||||
|
@@ -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'
|
||||
|
@@ -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;
|
||||
|
@@ -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;
|
||||
|
@@ -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--;
|
||||
|
||||
|
@@ -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
|
||||
|
Reference in New Issue
Block a user