mirror of
https://github.com/vim/vim.git
synced 2025-09-25 03:54:15 -04:00
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 #9204)
This commit is contained in:
committed by
Bram Moolenaar
parent
e413ea04b7
commit
19916a8c89
@@ -377,9 +377,9 @@ Some options ('completefunc', 'imactivatefunc', 'imstatusfunc', 'omnifunc',
|
|||||||
or a function reference or a lambda function. Examples:
|
or a function reference or a lambda function. Examples:
|
||||||
>
|
>
|
||||||
set opfunc=MyOpFunc
|
set opfunc=MyOpFunc
|
||||||
set opfunc=function("MyOpFunc")
|
set opfunc=function('MyOpFunc')
|
||||||
set opfunc=funcref("MyOpFunc")
|
set opfunc=funcref('MyOpFunc')
|
||||||
set opfunc={t\ ->\ MyOpFunc(t)}
|
let &opfunc = "{t -> MyOpFunc(t)}"
|
||||||
<
|
<
|
||||||
|
|
||||||
Setting the filetype
|
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.
|
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
|
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
|
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'*
|
||||||
'taglength' 'tl' number (default 0)
|
'taglength' 'tl' number (default 0)
|
||||||
|
@@ -2344,6 +2344,7 @@ free_buf_options(
|
|||||||
clear_string_option(&buf->b_p_tc);
|
clear_string_option(&buf->b_p_tc);
|
||||||
#ifdef FEAT_EVAL
|
#ifdef FEAT_EVAL
|
||||||
clear_string_option(&buf->b_p_tfu);
|
clear_string_option(&buf->b_p_tfu);
|
||||||
|
free_callback(&buf->b_tfu_cb);
|
||||||
#endif
|
#endif
|
||||||
clear_string_option(&buf->b_p_dict);
|
clear_string_option(&buf->b_p_dict);
|
||||||
clear_string_option(&buf->b_p_tsr);
|
clear_string_option(&buf->b_p_tsr);
|
||||||
|
@@ -810,6 +810,7 @@ free_all_options(void)
|
|||||||
clear_string_option((char_u **)options[i].var);
|
clear_string_option((char_u **)options[i].var);
|
||||||
}
|
}
|
||||||
free_operatorfunc_option();
|
free_operatorfunc_option();
|
||||||
|
free_tagfunc_option();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -5956,6 +5957,7 @@ buf_copy_options(buf_T *buf, int flags)
|
|||||||
#ifdef FEAT_EVAL
|
#ifdef FEAT_EVAL
|
||||||
buf->b_p_tfu = vim_strsave(p_tfu);
|
buf->b_p_tfu = vim_strsave(p_tfu);
|
||||||
COPY_OPT_SCTX(buf, BV_TFU);
|
COPY_OPT_SCTX(buf, BV_TFU);
|
||||||
|
buf_set_tfu_callback(buf);
|
||||||
#endif
|
#endif
|
||||||
buf->b_p_sts = p_sts;
|
buf->b_p_sts = p_sts;
|
||||||
COPY_OPT_SCTX(buf, BV_STS);
|
COPY_OPT_SCTX(buf, BV_STS);
|
||||||
|
@@ -2333,6 +2333,15 @@ ambw_end:
|
|||||||
}
|
}
|
||||||
#endif
|
#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.
|
// Options that are a list of flags.
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@@ -1,4 +1,7 @@
|
|||||||
/* tag.c */
|
/* 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);
|
int do_tag(char_u *tag, int type, int count, int forceit, int verbose);
|
||||||
void tag_freematch(void);
|
void tag_freematch(void);
|
||||||
void do_tags(exarg_T *eap);
|
void do_tags(exarg_T *eap);
|
||||||
|
@@ -2878,7 +2878,8 @@ struct file_buffer
|
|||||||
char_u *b_p_ofu; // 'omnifunc'
|
char_u *b_p_ofu; // 'omnifunc'
|
||||||
#endif
|
#endif
|
||||||
#ifdef FEAT_EVAL
|
#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
|
#endif
|
||||||
int b_p_eol; // 'endofline'
|
int b_p_eol; // 'endofline'
|
||||||
int b_p_fixeol; // 'fixendofline'
|
int b_p_fixeol; // 'fixendofline'
|
||||||
|
51
src/tag.c
51
src/tag.c
@@ -103,11 +103,60 @@ static taggy_T ptag_entry = {NULL, {{0, 0, 0}, 0}, 0, 0, NULL};
|
|||||||
|
|
||||||
#ifdef FEAT_EVAL
|
#ifdef FEAT_EVAL
|
||||||
static int tfu_in_use = FALSE; // disallow recursive call of tagfunc
|
static int tfu_in_use = FALSE; // disallow recursive call of tagfunc
|
||||||
|
static callback_T tfu_cb; // 'tagfunc' callback function
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Used instead of NUL to separate tag fields in the growarrays.
|
// Used instead of NUL to separate tag fields in the growarrays.
|
||||||
#define TAG_SEP 0x02
|
#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
|
* Jump to tag; handling of tag commands and tag stack
|
||||||
*
|
*
|
||||||
@@ -1341,7 +1390,7 @@ find_tagfunc_tags(
|
|||||||
flags & TAG_REGEXP ? "r": "");
|
flags & TAG_REGEXP ? "r": "");
|
||||||
|
|
||||||
save_pos = curwin->w_cursor;
|
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
|
curwin->w_cursor = save_pos; // restore the cursor position
|
||||||
--d->dv_refcount;
|
--d->dv_refcount;
|
||||||
|
|
||||||
|
@@ -117,4 +117,54 @@ func Test_tagfunc_settagstack()
|
|||||||
delfunc Mytagfunc2
|
delfunc Mytagfunc2
|
||||||
endfunc
|
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: shiftwidth=2 sts=2 expandtab
|
||||||
|
@@ -757,6 +757,8 @@ static char *(features[]) =
|
|||||||
|
|
||||||
static int included_patches[] =
|
static int included_patches[] =
|
||||||
{ /* Add new patch number below this line */
|
{ /* Add new patch number below this line */
|
||||||
|
/**/
|
||||||
|
3665,
|
||||||
/**/
|
/**/
|
||||||
3664,
|
3664,
|
||||||
/**/
|
/**/
|
||||||
|
Reference in New Issue
Block a user