From e8618df7f826d2ca4d524f12fc712d7c52ea158c Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sat, 20 Aug 2022 06:12:02 +0800 Subject: vim-patch:8.2.3619: cannot use a lambda for 'operatorfunc' (#19846) Problem: Cannot use a lambda for 'operatorfunc'. Solution: Support using a lambda or partial. (Yegappan Lakshmanan, closes vim/vim#8775) https://github.com/vim/vim/commit/777175b0df8c5ec3cd30d19a2e887e661ac209c8 Omit duplicate docs. It's removed in patch 8.2.3623. Nvim doesn't seem to need callback_set() as it was omitted when patch 8.1.1437 was first ported. --- src/nvim/option.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 46 insertions(+), 2 deletions(-) (limited to 'src/nvim/option.c') diff --git a/src/nvim/option.c b/src/nvim/option.c index 09793cbdcf..e85a0d9ee4 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -66,6 +66,7 @@ #include "nvim/mouse.h" #include "nvim/move.h" #include "nvim/normal.h" +#include "nvim/ops.h" #include "nvim/option.h" #include "nvim/os/os.h" #include "nvim/os_unix.h" @@ -782,6 +783,7 @@ void free_all_options(void) clear_string_option((char_u **)options[i].var); } } + free_operatorfunc_option(); } #endif @@ -3264,8 +3266,12 @@ static char *did_set_string_option(int opt_idx, char_u **varp, char_u *oldval, c } } } - } else if (varp == &p_qftf) { - if (!qf_process_qftf_option()) { + } else if (varp == &p_opfunc) { // 'operatorfunc' + if (set_operatorfunc_option() == FAIL) { + errmsg = e_invarg; + } + } else if (varp == &p_qftf) { // 'quickfixtextfunc' + if (qf_process_qftf_option() == FAIL) { errmsg = e_invarg; } } else { @@ -6917,6 +6923,44 @@ static int fill_culopt_flags(char_u *val, win_T *wp) return OK; } +/// Set the callback function value for an option that accepts a function name, +/// lambda, et al. (e.g. 'operatorfunc', 'tagfunc', etc.) +/// @return OK if the option is successfully set to a function, otherwise FAIL +int option_set_callback_func(char_u *optval, Callback *optcb) +{ + if (optval == NULL || *optval == NUL) { + callback_free(optcb); + return OK; + } + + typval_T *tv; + if (*optval == '{' + || (STRNCMP(optval, "function(", 9) == 0) + || (STRNCMP(optval, "funcref(", 8) == 0)) { + // Lambda expression or a funcref + tv = eval_expr((char *)optval); + if (tv == NULL) { + return FAIL; + } + } else { + // treat everything else as a function name string + tv = xcalloc(1, sizeof(*tv)); + tv->v_type = VAR_STRING; + tv->vval.v_string = (char *)vim_strsave(optval); + } + + Callback cb; + if (!callback_from_typval(&cb, tv)) { + tv_free(tv); + return FAIL; + } + + callback_free(optcb); + *optcb = cb; + tv_free(tv); + return OK; +} + /// Check an option that can be a range of string values. /// /// @param list when true: accept a list of values -- cgit