diff options
author | TJ DeVries <devries.timothyj@gmail.com> | 2020-07-11 17:40:31 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-07-11 17:40:31 -0400 |
commit | 1ca67a73c0ba680eb8328e68bea31f839855dd29 (patch) | |
tree | 6f770f564307cb8a31f6ead427114267fcba3953 /src/nvim/eval | |
parent | a695da7d3fac19624d458e3f2980b4c0e55f50a4 (diff) | |
parent | 6360cf7ce87407bd8a519b9a17f45b2148291904 (diff) | |
download | rneovim-1ca67a73c0ba680eb8328e68bea31f839855dd29.tar.gz rneovim-1ca67a73c0ba680eb8328e68bea31f839855dd29.tar.bz2 rneovim-1ca67a73c0ba680eb8328e68bea31f839855dd29.zip |
Merge pull request #12507 from tjdevries/tjdevries/viml_lua_callbacks
[RFC] Allow passing lua functions and closures into vim functions.
Diffstat (limited to 'src/nvim/eval')
-rw-r--r-- | src/nvim/eval/funcs.c | 3 | ||||
-rw-r--r-- | src/nvim/eval/typval.c | 3 | ||||
-rw-r--r-- | src/nvim/eval/typval.h | 14 | ||||
-rw-r--r-- | src/nvim/eval/userfunc.c | 51 |
4 files changed, 67 insertions, 4 deletions
diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index 1071e75c06..99014d1a09 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -824,9 +824,12 @@ static void f_call(typval_T *argvars, typval_T *rettv, FunPtr fptr) } else if (argvars[0].v_type == VAR_PARTIAL) { partial = argvars[0].vval.v_partial; func = partial_name(partial); + } else if (nlua_is_table_from_lua(&argvars[0])) { + func = nlua_register_table_as_callable(&argvars[0]); } else { func = (char_u *)tv_get_string(&argvars[0]); } + if (*func == NUL) { return; // type error or empty name } diff --git a/src/nvim/eval/typval.c b/src/nvim/eval/typval.c index 0daaf6c878..89ca2db59b 100644 --- a/src/nvim/eval/typval.c +++ b/src/nvim/eval/typval.c @@ -16,6 +16,7 @@ #include "nvim/eval/typval_encode.h" #include "nvim/eval.h" #include "nvim/eval/userfunc.h" +#include "nvim/lua/executor.h" #include "nvim/types.h" #include "nvim/assert.h" #include "nvim/memory.h" @@ -301,6 +302,7 @@ void tv_list_free_list(list_T *const l) } list_log(l, NULL, NULL, "freelist"); + nlua_free_typval_list(l); xfree(l); } @@ -1374,6 +1376,7 @@ void tv_dict_free_dict(dict_T *const d) d->dv_used_next->dv_used_prev = d->dv_used_prev; } + nlua_free_typval_dict(d); xfree(d); } diff --git a/src/nvim/eval/typval.h b/src/nvim/eval/typval.h index 343dd205ff..503a32a81e 100644 --- a/src/nvim/eval/typval.h +++ b/src/nvim/eval/typval.h @@ -180,6 +180,8 @@ struct listvar_S { int lv_idx; ///< Index of a cached item, used for optimising repeated l[idx]. int lv_copyID; ///< ID used by deepcopy(). VarLockStatus lv_lock; ///< Zero, VAR_LOCKED, VAR_FIXED. + + LuaRef lua_table_ref; }; // Static list with 10 items. Use tv_list_init_static10() to initialize. @@ -245,6 +247,8 @@ struct dictvar_S { dict_T *dv_used_next; ///< Next dictionary in used dictionaries list. dict_T *dv_used_prev; ///< Previous dictionary in used dictionaries list. QUEUE watchers; ///< Dictionary key watchers set by user code. + + LuaRef lua_table_ref; }; /// Type used for script ID @@ -271,6 +275,12 @@ typedef struct { /// Number of fixed variables used for arguments #define FIXVAR_CNT 12 +/// Callback interface for C function reference> +/// Used for managing functions that were registered with |register_cfunc| +typedef int (*cfunc_T)(int argcount, typval_T *argvars, typval_T *rettv, void *state); // NOLINT +/// Callback to clear cfunc_T and any associated state. +typedef void (*cfunc_free_T)(void *state); + // Structure to hold info for a function that is currently being executed. typedef struct funccall_S funccall_T; @@ -307,6 +317,10 @@ struct ufunc { garray_T uf_lines; ///< function lines int uf_profiling; ///< true when func is being profiled int uf_prof_initialized; + // Managing cfuncs + cfunc_T uf_cb; ///< C function extension callback + cfunc_free_T uf_cb_free; ///< C function extesion free callback + void *uf_cb_state; ///< State of C function extension. // Profiling the function as a whole. int uf_tm_count; ///< nr of calls proftime_T uf_tm_total; ///< time spent in function + children diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c index 4d658498c1..229f0e8dde 100644 --- a/src/nvim/eval/userfunc.c +++ b/src/nvim/eval/userfunc.c @@ -32,6 +32,7 @@ #define FC_DELETED 0x10 // :delfunction used while uf_refcount > 0 #define FC_REMOVED 0x20 // function redefined while uf_refcount > 0 #define FC_SANDBOX 0x40 // function defined in the sandbox +#define FC_CFUNC 0x80 // C function extension #ifdef INCLUDE_GENERATED_DECLARATIONS #include "eval/userfunc.c.generated.h" @@ -162,6 +163,17 @@ static void register_closure(ufunc_T *fp) [current_funccal->fc_funcs.ga_len++] = fp; } + +/// Get a name for a lambda. Returned in static memory. +char_u * get_lambda_name(void) +{ + static char_u name[30]; + static int lambda_no = 0; + + snprintf((char *)name, sizeof(name), "<lambda>%d", ++lambda_no); + return name; +} + /// Parse a lambda expression and get a Funcref from "*arg". /// /// @return OK or FAIL. Returns NOTDONE for dict or {expr}. @@ -175,7 +187,6 @@ int get_lambda_tv(char_u **arg, typval_T *rettv, bool evaluate) int ret; char_u *start = skipwhite(*arg + 1); char_u *s, *e; - static int lambda_no = 0; bool *old_eval_lavars = eval_lavars_used; bool eval_lavars = false; @@ -219,11 +230,9 @@ int get_lambda_tv(char_u **arg, typval_T *rettv, bool evaluate) if (evaluate) { int len, flags = 0; char_u *p; - char_u name[20]; garray_T newlines; - lambda_no++; - snprintf((char *)name, sizeof(name), "<lambda>%d", lambda_no); + char_u *name = get_lambda_name(); fp = xcalloc(1, offsetof(ufunc_T, uf_name) + STRLEN(name) + 1); pt = xcalloc(1, sizeof(partial_T)); @@ -700,6 +709,11 @@ static void func_clear_items(ufunc_T *fp) ga_clear_strings(&(fp->uf_args)); ga_clear_strings(&(fp->uf_lines)); + if (fp->uf_cb_free != NULL) { + fp->uf_cb_free(fp->uf_cb_state); + fp->uf_cb_free = NULL; + } + XFREE_CLEAR(fp->uf_tml_count); XFREE_CLEAR(fp->uf_tml_total); XFREE_CLEAR(fp->uf_tml_self); @@ -1408,6 +1422,9 @@ call_func( if (fp != NULL && (fp->uf_flags & FC_DELETED)) { error = ERROR_DELETED; + } else if (fp != NULL && (fp->uf_flags & FC_CFUNC)) { + cfunc_T cb = fp->uf_cb; + error = (*cb)(argcount, argvars, rettv, fp->uf_cb_state); } else if (fp != NULL) { if (argv_func != NULL) { // postponed filling in the arguments, do it now @@ -3435,3 +3452,29 @@ bool set_ref_in_func(char_u *name, ufunc_T *fp_in, int copyID) xfree(tofree); return abort; } + +/// Registers a C extension user function. +char_u *register_cfunc(cfunc_T cb, cfunc_free_T cb_free, void *state) +{ + char_u *name = get_lambda_name(); + ufunc_T *fp = NULL; + + fp = xcalloc(1, offsetof(ufunc_T, uf_name) + STRLEN(name) + 1); + if (fp == NULL) { + return NULL; + } + + fp->uf_refcount = 1; + fp->uf_varargs = true; + fp->uf_flags = FC_CFUNC; + fp->uf_calls = 0; + fp->uf_script_ctx = current_sctx; + fp->uf_cb = cb; + fp->uf_cb_free = cb_free; + fp->uf_cb_state = state; + + STRCPY(fp->uf_name, name); + hash_add(&func_hashtab, UF2HIKEY(fp)); + + return fp->uf_name; +} |