aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/nvim/eval.c119
-rw-r--r--src/nvim/globals.h10
2 files changed, 128 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;
+}
diff --git a/src/nvim/globals.h b/src/nvim/globals.h
index 2a4d6da8dc..cd9f7a648f 100644
--- a/src/nvim/globals.h
+++ b/src/nvim/globals.h
@@ -360,6 +360,16 @@ EXTERN int garbage_collect_at_exit INIT(= FALSE);
/* ID of script being sourced or was sourced to define the current function. */
EXTERN scid_T current_SID INIT(= 0);
+// Scope information for the code that indirectly triggered the current
+// provider function call
+EXTERN struct caller_scope {
+ scid_T SID;
+ uint8_t *sourcing_name, *autocmd_fname, *autocmd_match;
+ linenr_T sourcing_lnum;
+ int autocmd_fname_full, autocmd_bufnr;
+ void *funccalp;
+} provider_caller_scope;
+EXTERN int provider_call_nesting INIT(= 0);
/* Magic number used for hashitem "hi_key" value indicating a deleted item.
* Only the address is used. */