Skip to content

Commit

Permalink
patch 8.2.3725: cannot use a lambda for 'completefunc' and 'omnifunc'
Browse files Browse the repository at this point in the history
Problem:    Cannot use a lambda for 'completefunc' and 'omnifunc'.
Solution:   Implement lambda support. (Yegappan Lakshmanan, closes #9257)
  • Loading branch information
yegappan authored and brammool committed Dec 3, 2021
1 parent 021ef35 commit 8658c75
Show file tree
Hide file tree
Showing 14 changed files with 740 additions and 17 deletions.
14 changes: 10 additions & 4 deletions runtime/doc/options.txt
Original file line number Diff line number Diff line change
Expand Up @@ -373,8 +373,8 @@ Note: In the future more global options can be made global-local. Using

*option-value-function*
Some options ('completefunc', 'imactivatefunc', 'imstatusfunc', 'omnifunc',
'operatorfunc', 'quickfixtextfunc' and 'tagfunc') are set to a function name
or a function reference or a lambda function. Examples:
'operatorfunc', 'quickfixtextfunc', 'tagfunc' and 'thesaurusfunc') are set to
a function name or a function reference or a lambda function. Examples:
>
set opfunc=MyOpFunc
set opfunc=function('MyOpFunc')
Expand Down Expand Up @@ -1939,7 +1939,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 for Insert mode completion
with CTRL-X CTRL-U. |i_CTRL-X_CTRL-U|
See |complete-functions| for an explanation of how the function is
invoked and what it should return.
invoked and what it should return. The value can be the name of a
function, a |lambda| or a |Funcref|. See |option-value-function| for
more information.
This option cannot be set from a |modeline| or in the |sandbox|, for
security reasons.

Expand Down Expand Up @@ -5616,7 +5618,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 for Insert mode omni
completion with CTRL-X CTRL-O. |i_CTRL-X_CTRL-O|
See |complete-functions| for an explanation of how the function is
invoked and what it should return.
invoked and what it should return. The value can be the name of a
function, a |lambda| or a |Funcref|. See |option-value-function| for
more information.
This option is usually set by a filetype plugin:
|:filetype-plugin-on|
This option cannot be set from a |modeline| or in the |sandbox|, for
Expand Down Expand Up @@ -8075,6 +8079,8 @@ A jump table for the options with a short description can be found at |Q_op|.
feature}
This option specifies a function to be used for thesaurus completion
with CTRL-X CTRL-T. |i_CTRL-X_CTRL-T| See |compl-thesaurusfunc|.
The value can be the name of a function, a |lambda| or a |Funcref|.
See |option-value-function| for more information.

This option cannot be set from a |modeline| or in the |sandbox|, for
security reasons.
Expand Down
3 changes: 3 additions & 0 deletions src/buffer.c
Original file line number Diff line number Diff line change
Expand Up @@ -2326,8 +2326,11 @@ free_buf_options(
clear_string_option(&buf->b_p_cpt);
#ifdef FEAT_COMPL_FUNC
clear_string_option(&buf->b_p_cfu);
free_callback(&buf->b_cfu_cb);
clear_string_option(&buf->b_p_ofu);
free_callback(&buf->b_ofu_cb);
clear_string_option(&buf->b_p_tsrfu);
free_callback(&buf->b_tsrfu_cb);
#endif
#ifdef FEAT_QUICKFIX
clear_string_option(&buf->b_p_gp);
Expand Down
137 changes: 135 additions & 2 deletions src/insexpand.c
Original file line number Diff line number Diff line change
Expand Up @@ -2237,6 +2237,113 @@ ins_compl_next_buf(buf_T *buf, int flag)
}

#ifdef FEAT_COMPL_FUNC

# ifdef FEAT_EVAL
static callback_T cfu_cb; // 'completefunc' callback function
static callback_T ofu_cb; // 'omnifunc' callback function
static callback_T tsrfu_cb; // 'thesaurusfunc' callback function
# endif

/*
* Copy a global callback function to a buffer local callback.
*/
static void
copy_global_to_buflocal_cb(callback_T *globcb, callback_T *bufcb)
{
free_callback(bufcb);
if (globcb->cb_name != NULL && *globcb->cb_name != NUL)
copy_callback(bufcb, globcb);
}

/*
* Parse the 'completefunc' option value and set the callback function.
* Invoked when the 'completefunc' option is set. The option value can be a
* name of a function (string), or function(<name>) or funcref(<name>) or a
* lambda expression.
*/
int
set_completefunc_option(void)
{
int retval;

retval = option_set_callback_func(curbuf->b_p_cfu, &cfu_cb);
if (retval == OK)
set_buflocal_cfu_callback(curbuf);

return retval;
}

/*
* Copy the global 'completefunc' callback function to the buffer-local
* 'completefunc' callback for 'buf'.
*/
void
set_buflocal_cfu_callback(buf_T *buf UNUSED)
{
# ifdef FEAT_EVAL
copy_global_to_buflocal_cb(&cfu_cb, &buf->b_cfu_cb);
# endif
}

/*
* Parse the 'omnifunc' option value and set the callback function.
* Invoked when the 'omnifunc' option is set. The option value can be a
* name of a function (string), or function(<name>) or funcref(<name>) or a
* lambda expression.
*/
int
set_omnifunc_option(void)
{
int retval;

retval = option_set_callback_func(curbuf->b_p_ofu, &ofu_cb);
if (retval == OK)
set_buflocal_ofu_callback(curbuf);

return retval;
}

/*
* Copy the global 'omnifunc' callback function to the buffer-local 'omnifunc'
* callback for 'buf'.
*/
void
set_buflocal_ofu_callback(buf_T *buf UNUSED)
{
# ifdef FEAT_EVAL
copy_global_to_buflocal_cb(&ofu_cb, &buf->b_ofu_cb);
# endif
}

/*
* Parse the 'thesaurusfunc' option value and set the callback function.
* Invoked when the 'thesaurusfunc' option is set. The option value can be a
* name of a function (string), or function(<name>) or funcref(<name>) or a
* lambda expression.
*/
int
set_thesaurusfunc_option(void)
{
int retval;

if (*curbuf->b_p_tsrfu != NUL)
{
// buffer-local option set
free_callback(&curbuf->b_tsrfu_cb);
retval = option_set_callback_func(curbuf->b_p_tsrfu,
&curbuf->b_tsrfu_cb);
}
else
{
// global option set
free_callback(&tsrfu_cb);
retval = option_set_callback_func(p_tsrfu, &tsrfu_cb);
}

return retval;
}


/*
* Get the user-defined completion function name for completion 'type'
*/
Expand All @@ -2256,6 +2363,20 @@ get_complete_funcname(int type)
}
}

/*
* Get the callback to use for insert mode completion.
*/
callback_T *
get_insert_callback(int type)
{
if (type == CTRL_X_FUNCTION)
return &curbuf->b_cfu_cb;
if (type == CTRL_X_OMNI)
return &curbuf->b_ofu_cb;
// CTRL_X_THESAURUS
return (*curbuf->b_p_tsrfu != NUL) ? &curbuf->b_tsrfu_cb : &tsrfu_cb;
}

/*
* Execute user defined complete function 'completefunc', 'omnifunc' or
* 'thesaurusfunc', and get matches in "matches".
Expand All @@ -2269,8 +2390,10 @@ expand_by_function(int type, char_u *base)
typval_T args[3];
char_u *funcname;
pos_T pos;
callback_T *cb;
typval_T rettv;
int save_State = State;
int retval;

funcname = get_complete_funcname(type);
if (*funcname == NUL)
Expand All @@ -2289,8 +2412,11 @@ expand_by_function(int type, char_u *base)
// Insert mode in another buffer.
++textwinlock;

cb = get_insert_callback(type);
retval = call_callback(cb, 0, &rettv, 2, args);

// Call a function, which returns a list or dict.
if (call_vim_function(funcname, 2, args, &rettv) == OK)
if (retval == OK)
{
switch (rettv.v_type)
{
Expand Down Expand Up @@ -3971,6 +4097,7 @@ ins_complete(int c, int enable_pum)
char_u *funcname;
pos_T pos;
int save_State = State;
callback_T *cb;

// Call 'completefunc' or 'omnifunc' and get pattern length as a
// string
Expand All @@ -3991,7 +4118,8 @@ ins_complete(int c, int enable_pum)
args[2].v_type = VAR_UNKNOWN;
pos = curwin->w_cursor;
++textwinlock;
col = call_func_retnr(funcname, 2, args);
cb = get_insert_callback(ctrl_x_mode);
col = call_callback_retnr(cb, 2, args);
--textwinlock;

State = save_State;
Expand Down Expand Up @@ -4339,6 +4467,11 @@ quote_meta(char_u *dest, char_u *src, int len)
free_insexpand_stuff(void)
{
VIM_CLEAR(compl_orig_text);
# ifdef FEAT_EVAL
free_callback(&cfu_cb);
free_callback(&ofu_cb);
free_callback(&tsrfu_cb);
# endif
}
#endif

Expand Down
4 changes: 3 additions & 1 deletion src/option.c
Original file line number Diff line number Diff line change
Expand Up @@ -5927,13 +5927,15 @@ buf_copy_options(buf_T *buf, int flags)
#ifdef FEAT_COMPL_FUNC
buf->b_p_cfu = vim_strsave(p_cfu);
COPY_OPT_SCTX(buf, BV_CFU);
set_buflocal_cfu_callback(buf);
buf->b_p_ofu = vim_strsave(p_ofu);
COPY_OPT_SCTX(buf, BV_OFU);
set_buflocal_ofu_callback(buf);
#endif
#ifdef FEAT_EVAL
buf->b_p_tfu = vim_strsave(p_tfu);
COPY_OPT_SCTX(buf, BV_TFU);
buf_set_tfu_callback(buf);
set_buflocal_tfu_callback(buf);
#endif
buf->b_p_sts = p_sts;
COPY_OPT_SCTX(buf, BV_STS);
Expand Down
23 changes: 23 additions & 0 deletions src/optionstr.c
Original file line number Diff line number Diff line change
Expand Up @@ -2307,6 +2307,29 @@ did_set_string_option(
# endif
#endif

#ifdef FEAT_COMPL_FUNC
// 'completefunc'
else if (gvarp == &p_cfu)
{
if (set_completefunc_option() == FAIL)
errmsg = e_invarg;
}

// 'omnifunc'
else if (gvarp == &p_ofu)
{
if (set_omnifunc_option() == FAIL)
errmsg = e_invarg;
}

// 'thesaurusfunc'
else if (gvarp == &p_tsrfu)
{
if (set_thesaurusfunc_option() == FAIL)
errmsg = e_invarg;
}
#endif

// 'operatorfunc'
else if (varp == &p_opfunc)
{
Expand Down
6 changes: 6 additions & 0 deletions src/proto/insexpand.pro
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,12 @@ int ins_compl_bs(void);
void ins_compl_addleader(int c);
void ins_compl_addfrommatch(void);
int ins_compl_prep(int c);
int set_completefunc_option(void);
void set_buflocal_cfu_callback(buf_T *buf);
int set_omnifunc_option(void);
void set_buflocal_ofu_callback(buf_T *buf);
int set_thesaurusfunc_option(void);
callback_T *get_insert_callback(int type);
void f_complete(typval_T *argvars, typval_T *rettv);
void f_complete_add(typval_T *argvars, typval_T *rettv);
void f_complete_check(typval_T *argvars, typval_T *rettv);
Expand Down
2 changes: 1 addition & 1 deletion src/proto/tag.pro
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/* tag.c */
int set_tagfunc_option(void);
void free_tagfunc_option(void);
void buf_set_tfu_callback(buf_T *buf);
void set_buflocal_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);
Expand Down
1 change: 1 addition & 0 deletions src/proto/userfunc.pro
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ int builtin_function(char_u *name, int len);
int func_call(char_u *name, typval_T *args, partial_T *partial, dict_T *selfdict, typval_T *rettv);
int get_callback_depth(void);
int call_callback(callback_T *callback, int len, typval_T *rettv, int argcount, typval_T *argvars);
varnumber_T call_callback_retnr(callback_T *callback, int argcount, typval_T *argvars);
void user_func_error(int error, char_u *name);
int call_func(char_u *funcname, int len, typval_T *rettv, int argcount_in, typval_T *argvars_in, funcexe_T *funcexe);
char_u *printable_func_name(ufunc_T *fp);
Expand Down
3 changes: 3 additions & 0 deletions src/structs.h
Original file line number Diff line number Diff line change
Expand Up @@ -2876,7 +2876,9 @@ struct file_buffer
#endif
#ifdef FEAT_COMPL_FUNC
char_u *b_p_cfu; // 'completefunc'
callback_T b_cfu_cb; // 'completefunc' callback
char_u *b_p_ofu; // 'omnifunc'
callback_T b_ofu_cb; // 'omnifunc' callback
#endif
#ifdef FEAT_EVAL
char_u *b_p_tfu; // 'tagfunc' option value
Expand Down Expand Up @@ -2982,6 +2984,7 @@ struct file_buffer
char_u *b_p_tsr; // 'thesaurus' local value
#ifdef FEAT_COMPL_FUNC
char_u *b_p_tsrfu; // 'thesaurusfunc' local value
callback_T b_tsrfu_cb; // 'thesaurusfunc' callback
#endif
long b_p_ul; // 'undolevels' local value
#ifdef FEAT_PERSISTENT_UNDO
Expand Down
4 changes: 2 additions & 2 deletions src/tag.c
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ static callback_T tfu_cb; // 'tagfunc' callback function
* a function (string), or function(<name>) or funcref(<name>) or a lambda.
*/
int
set_tagfunc_option()
set_tagfunc_option(void)
{
#ifdef FEAT_EVAL
free_callback(&tfu_cb);
Expand Down Expand Up @@ -148,7 +148,7 @@ free_tagfunc_option(void)
* callback for 'buf'.
*/
void
buf_set_tfu_callback(buf_T *buf UNUSED)
set_buflocal_tfu_callback(buf_T *buf UNUSED)
{
#ifdef FEAT_EVAL
free_callback(&buf->b_tfu_cb);
Expand Down
Loading

0 comments on commit 8658c75

Please sign in to comment.