diff options
author | Thiago de Arruda <tpadilha84@gmail.com> | 2014-11-11 09:54:27 -0300 |
---|---|---|
committer | Thiago de Arruda <tpadilha84@gmail.com> | 2014-11-18 07:56:58 -0300 |
commit | 268b2eff4a5b69329e21ea8d1019984983a04f78 (patch) | |
tree | 88ae83966cda941ed3652d6dcbe709b56cb0984d /src/nvim/eval.c | |
parent | a67fd6f21378bc01b41e5349abff2eb214f6c288 (diff) | |
download | rneovim-268b2eff4a5b69329e21ea8d1019984983a04f78.tar.gz rneovim-268b2eff4a5b69329e21ea8d1019984983a04f78.tar.bz2 rneovim-268b2eff4a5b69329e21ea8d1019984983a04f78.zip |
eval: Add eval_call_provider/eval_has_provider functions
These use autoloaded vimscript to replace the provider_call/provider_has
functions, moving the implementation of providers to pure vimscript(we lose
nothing since vimscript can also call msgpack-rpc functions).
When calling the rpcrequest function from a provider, temporarily switch to the
caller scope. This is required for compatibility with legacy plugins, because
they may depend on scope information that changes when "leaving" the C stack to
enter the vimscript stack.
Diffstat (limited to 'src/nvim/eval.c')
-rw-r--r-- | src/nvim/eval.c | 119 |
1 files changed, 118 insertions, 1 deletions
diff --git a/src/nvim/eval.c b/src/nvim/eval.c index a0e6f84259..f4d117c391 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -457,7 +457,7 @@ typedef struct { } JobEvent; #define JobEventFreer(x) KMEMPOOL_INIT(JobEventPool, JobEvent, JobEventFreer) -kmempool_t(JobEventPool) *job_event_pool = NULL; +static kmempool_t(JobEventPool) *job_event_pool = NULL; /* * Initialize the global and v: variables. @@ -12540,11 +12540,52 @@ static void f_rpcrequest(typval_T *argvars, typval_T *rettv) ADD(args, vim_to_object(tv)); } + scid_T save_current_SID; + uint8_t *save_sourcing_name, *save_autocmd_fname, *save_autocmd_match; + linenr_T save_sourcing_lnum; + int save_autocmd_fname_full, save_autocmd_bufnr; + void *save_funccalp; + + if (provider_call_nesting) { + // If this is called from a provider function, restore the scope + // information of the caller. + save_current_SID = current_SID; + save_sourcing_name = sourcing_name; + save_sourcing_lnum = sourcing_lnum; + save_autocmd_fname = autocmd_fname; + save_autocmd_match = autocmd_match; + save_autocmd_fname_full = autocmd_fname_full; + save_autocmd_bufnr = autocmd_bufnr; + save_funccalp = save_funccal(); + // + current_SID = provider_caller_scope.SID; + sourcing_name = provider_caller_scope.sourcing_name; + sourcing_lnum = provider_caller_scope.sourcing_lnum; + autocmd_fname = provider_caller_scope.autocmd_fname; + autocmd_match = provider_caller_scope.autocmd_match; + autocmd_fname_full = provider_caller_scope.autocmd_fname_full; + autocmd_bufnr = provider_caller_scope.autocmd_bufnr; + restore_funccal(provider_caller_scope.funccalp); + } + + Error err = ERROR_INIT; Object result = channel_send_call((uint64_t)argvars[0].vval.v_number, (char *)argvars[1].vval.v_string, args, &err); + + if (provider_call_nesting) { + current_SID = save_current_SID; + sourcing_name = save_sourcing_name; + sourcing_lnum = save_sourcing_lnum; + autocmd_fname = save_autocmd_fname; + autocmd_match = save_autocmd_match; + autocmd_fname_full = save_autocmd_fname_full; + autocmd_bufnr = save_autocmd_bufnr; + restore_funccal(save_funccalp); + } + if (err.set) { vim_report_error(cstr_as_string(err.msg)); goto end; @@ -19690,3 +19731,79 @@ static void script_host_eval(char *method, typval_T *argvars, typval_T *rettv) api_free_object(result); } +typval_T eval_call_provider(char *provider, char *method, list_T *arguments) +{ + char func[256]; + int name_len = snprintf(func, sizeof(func), "provider#%s#Call", provider); + + // Save caller scope information + struct caller_scope saved_provider_caller_scope = provider_caller_scope; + provider_caller_scope = (struct caller_scope) { + .SID = current_SID, + .sourcing_name = sourcing_name, + .sourcing_lnum = sourcing_lnum, + .autocmd_fname = autocmd_fname, + .autocmd_match = autocmd_match, + .autocmd_fname_full = autocmd_fname_full, + .autocmd_bufnr = autocmd_bufnr, + .funccalp = save_funccal() + }; + provider_call_nesting++; + + typval_T argvars[3] = { + {.v_type = VAR_STRING, .vval.v_string = (uint8_t *)method, .v_lock = 0}, + {.v_type = VAR_LIST, .vval.v_list = arguments, .v_lock = 0}, + {.v_type = VAR_UNKNOWN} + }; + typval_T rettv = {.v_type = VAR_UNKNOWN, .v_lock = 0}; + arguments->lv_refcount++; + + int dummy; + (void)call_func((uint8_t *)func, + name_len, + &rettv, + 2, + argvars, + curwin->w_cursor.lnum, + curwin->w_cursor.lnum, + &dummy, + true, + NULL); + + arguments->lv_refcount--; + // Restore caller scope information + restore_funccal(provider_caller_scope.funccalp); + provider_caller_scope = saved_provider_caller_scope; + provider_call_nesting--; + + return rettv; +} + +bool eval_has_provider(char *name) +{ +#define source_provider(name) \ + do_source((uint8_t *)"$VIMRUNTIME/autoload/provider/" name ".vim", \ + false, \ + false) + +#define check_provider(name) \ + if (has_##name == -1) { \ + has_##name = !!find_func((uint8_t *)"provider#" #name "#Call"); \ + if (!has_##name) { \ + source_provider(#name); \ + has_##name = !!find_func((uint8_t *)"provider#" #name "#Call"); \ + } \ + } + + static int has_clipboard = -1, has_python = -1; + + if (!strcmp(name, "clipboard")) { + check_provider(clipboard); + return has_clipboard; + } else if (!strcmp(name, "python")) { + check_provider(python); + return has_python; + } + + return false; +} |