diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/nvim/api/private/helpers.c | 2 | ||||
-rw-r--r-- | src/nvim/api/vim.c | 17 | ||||
-rw-r--r-- | src/nvim/eval.c | 144 | ||||
-rw-r--r-- | src/nvim/ex_cmds2.c | 60 | ||||
-rw-r--r-- | src/nvim/globals.h | 10 | ||||
-rw-r--r-- | src/nvim/msgpack_rpc/channel.c | 11 | ||||
-rw-r--r-- | src/nvim/ops.c | 44 | ||||
-rw-r--r-- | src/nvim/os/event.c | 3 | ||||
-rw-r--r-- | src/nvim/os/provider.c | 152 | ||||
-rw-r--r-- | src/nvim/os/provider.h | 11 |
10 files changed, 193 insertions, 261 deletions
diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c index a7b48f3b7e..750b151d10 100644 --- a/src/nvim/api/private/helpers.c +++ b/src/nvim/api/private/helpers.c @@ -7,7 +7,6 @@ #include "nvim/api/private/helpers.h" #include "nvim/api/private/defs.h" #include "nvim/api/private/handle.h" -#include "nvim/os/provider.h" #include "nvim/ascii.h" #include "nvim/vim.h" #include "nvim/buffer.h" @@ -548,7 +547,6 @@ Dictionary api_metadata(void) msgpack_rpc_init_function_metadata(&metadata); init_error_type_metadata(&metadata); init_type_metadata(&metadata); - provider_init_feature_metadata(&metadata); } return copy_object(DICTIONARY_OBJ(metadata)).data.dictionary; diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index b6bac1588a..addcbf62e9 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -11,7 +11,6 @@ #include "nvim/api/private/defs.h" #include "nvim/api/buffer.h" #include "nvim/msgpack_rpc/channel.h" -#include "nvim/os/provider.h" #include "nvim/vim.h" #include "nvim/buffer.h" #include "nvim/window.h" @@ -538,22 +537,6 @@ void vim_unsubscribe(uint64_t channel_id, String event) channel_unsubscribe(channel_id, e); } -/// Registers the channel as the provider for `feature`. This fails if -/// a provider for `feature` is already provided by another channel. -/// -/// @param channel_id The channel id -/// @param feature The feature name -/// @param[out] err Details of an error that may have occurred -void vim_register_provider(uint64_t channel_id, String feature, Error *err) -{ - char buf[METHOD_MAXLEN]; - xstrlcpy(buf, feature.data, sizeof(buf)); - - if (!provider_register(buf, channel_id)) { - api_set_error(err, Validation, _("Feature doesn't exist")); - } -} - Array vim_get_api_info(uint64_t channel_id) { Array rv = ARRAY_DICT_INIT; diff --git a/src/nvim/eval.c b/src/nvim/eval.c index a0e6f84259..498795dc38 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -89,7 +89,6 @@ #include "nvim/api/private/helpers.h" #include "nvim/api/vim.h" #include "nvim/os/dl.h" -#include "nvim/os/provider.h" #include "nvim/os/event.h" #define DICT_MAXNEST 100 /* maximum nesting of lists and dicts */ @@ -457,7 +456,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. @@ -5152,7 +5151,7 @@ void list_append_string(list_T *l, char_u *str, int len) /* * Append "n" to list "l". */ -static void list_append_number(list_T *l, varnumber_T n) +void list_append_number(list_T *l, varnumber_T n) { listitem_T *li = listitem_alloc(); li->li_tv.v_type = VAR_NUMBER; @@ -9987,7 +9986,7 @@ static void f_has(typval_T *argvars, typval_T *rettv) } } - if (n == FALSE && provider_has_feature((char *)name)) { + if (n == FALSE && eval_has_provider((char *)name)) { n = TRUE; } @@ -11695,7 +11694,7 @@ static void f_pumvisible(typval_T *argvars, typval_T *rettv) */ static void f_pyeval(typval_T *argvars, typval_T *rettv) { - script_host_eval("python_eval", argvars, rettv); + script_host_eval("python", argvars, rettv); } /* @@ -12540,11 +12539,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; @@ -19671,22 +19711,94 @@ static void apply_job_autocmds(int id, char *name, char *type, } } -static void script_host_eval(char *method, typval_T *argvars, typval_T *rettv) +static void script_host_eval(char *name, typval_T *argvars, typval_T *rettv) { - Array args = ARRAY_DICT_INIT; - ADD(args, vim_to_object(argvars)); - Object result = provider_call(method, args); - - if (result.type == kObjectTypeNil) { + if (check_restricted() || check_secure()) { return; } - Error err = ERROR_INIT; - - if (!object_to_vim(result, rettv, &err)){ - EMSG("Error converting value back to vim"); + if (argvars[0].v_type != VAR_STRING) { + EMSG(_(e_invarg)); } - api_free_object(result); + list_T *args = list_alloc(); + list_append_string(args, argvars[0].vval.v_string, -1); + *rettv = eval_call_provider(name, "eval", args); } +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/ex_cmds2.c b/src/nvim/ex_cmds2.c index 1636d62c74..96410897df 100644 --- a/src/nvim/ex_cmds2.c +++ b/src/nvim/ex_cmds2.c @@ -55,7 +55,6 @@ #include "nvim/os/os.h" #include "nvim/os/shell.h" #include "nvim/os/fs_defs.h" -#include "nvim/os/provider.h" #include "nvim/api/private/helpers.h" #include "nvim/api/private/defs.h" @@ -791,17 +790,17 @@ void ex_profile(exarg_T *eap) void ex_python(exarg_T *eap) { - script_host_execute("python_execute", eap); + script_host_execute("python", eap); } void ex_pyfile(exarg_T *eap) { - script_host_execute_file("python_execute_file", eap); + script_host_execute_file("python", eap); } void ex_pydo(exarg_T *eap) { - script_host_do_range("python_do_range", eap); + script_host_do_range("python", eap); } @@ -3254,46 +3253,43 @@ char_u *get_locales(expand_T *xp, int idx) #endif -static void script_host_execute(char *method, exarg_T *eap) +static void script_host_execute(char *name, exarg_T *eap) { - char *script = (char *)script_get(eap, eap->arg); + uint8_t *script = script_get(eap, eap->arg); if (!eap->skip) { - Array args = ARRAY_DICT_INIT; - ADD(args, STRING_OBJ(cstr_to_string(script ? script : (char *)eap->arg))); - // add current range - ADD(args, INTEGER_OBJ(eap->line1)); - ADD(args, INTEGER_OBJ(eap->line2)); - Object result = provider_call(method, args); - // We don't care about the result, so free it just in case a bad provider - // returned something - api_free_object(result); + list_T *args = list_alloc(); + // script + list_append_string(args, script ? script : eap->arg, -1); + // current range + list_append_number(args, eap->line1); + list_append_number(args, eap->line2); + (void)eval_call_provider(name, "execute", args); } free(script); } -static void script_host_execute_file(char *method, exarg_T *eap) +static void script_host_execute_file(char *name, exarg_T *eap) { - char buffer[MAXPATHL]; - vim_FullName(eap->arg, (uint8_t *)buffer, sizeof(buffer), false); + uint8_t buffer[MAXPATHL]; + vim_FullName(eap->arg, buffer, sizeof(buffer), false); - Array args = ARRAY_DICT_INIT; - ADD(args, STRING_OBJ(cstr_to_string(buffer))); - // add current range - ADD(args, INTEGER_OBJ(eap->line1)); - ADD(args, INTEGER_OBJ(eap->line2)); - Object result = provider_call(method, args); - api_free_object(result); + list_T *args = list_alloc(); + // filename + list_append_string(args, buffer, -1); + // current range + list_append_number(args, eap->line1); + list_append_number(args, eap->line2); + (void)eval_call_provider(name, "execute_file", args); } -static void script_host_do_range(char *method, exarg_T *eap) +static void script_host_do_range(char *name, exarg_T *eap) { - Array args = ARRAY_DICT_INIT; - ADD(args, INTEGER_OBJ(eap->line1)); - ADD(args, INTEGER_OBJ(eap->line2)); - ADD(args, STRING_OBJ(cstr_to_string((char *)eap->arg))); - Object result = provider_call(method, args); - api_free_object(result); + list_T *args = list_alloc(); + list_append_number(args, eap->line1); + list_append_number(args, eap->line2); + list_append_string(args, eap->arg, -1); + (void)eval_call_provider(name, "do_range", args); } 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. */ diff --git a/src/nvim/msgpack_rpc/channel.c b/src/nvim/msgpack_rpc/channel.c index da1dc8d1b5..0c04a7b23e 100644 --- a/src/nvim/msgpack_rpc/channel.c +++ b/src/nvim/msgpack_rpc/channel.c @@ -137,7 +137,6 @@ uint64_t channel_from_job(char **argv) &status); if (status <= 0) { - free_channel(channel); return 0; } @@ -381,7 +380,7 @@ static void parse_msgpack(RStream *rstream, void *data, bool eof) bool is_response = is_rpc_response(&unpacked.data); log_client_msg(channel->id, !is_response, unpacked.data); - if (kv_size(channel->call_stack) && is_response) { + if (is_response) { if (is_valid_rpc_response(&unpacked.data, channel)) { complete_call(&unpacked.data, channel); } else { @@ -389,8 +388,8 @@ static void parse_msgpack(RStream *rstream, void *data, bool eof) snprintf(buf, sizeof(buf), "Channel %" PRIu64 " returned a response that doesn't have " - " a matching id for the current RPC call. Ensure the client " - " is properly synchronized", + "a matching request id. Ensure the client is properly " + "synchronized", channel->id); call_set_error(channel, buf); } @@ -685,8 +684,8 @@ static bool is_valid_rpc_response(msgpack_object *obj, Channel *channel) { uint64_t response_id = obj->via.array.ptr[1].via.u64; // Must be equal to the frame at the stack's bottom - return response_id == kv_A(channel->call_stack, - kv_size(channel->call_stack) - 1)->request_id; + return kv_size(channel->call_stack) && response_id + == kv_A(channel->call_stack, kv_size(channel->call_stack) - 1)->request_id; } static void complete_call(msgpack_object *obj, Channel *channel) diff --git a/src/nvim/ops.c b/src/nvim/ops.c index 2523e21c42..5ef605bb3b 100644 --- a/src/nvim/ops.c +++ b/src/nvim/ops.c @@ -48,7 +48,6 @@ #include "nvim/ui.h" #include "nvim/undo.h" #include "nvim/window.h" -#include "nvim/os/provider.h" #include "nvim/api/private/helpers.h" /* @@ -1308,7 +1307,7 @@ bool adjust_clipboard_register(int *rp) { // If no reg. specified and 'unnamedclip' is set, use the // clipboard register. - if (*rp == 0 && p_unc && provider_has_feature("clipboard")) { + if (*rp == 0 && p_unc && eval_has_provider("clipboard")) { *rp = '+'; return true; } @@ -5240,28 +5239,29 @@ static void copy_register(struct yankreg *dest, struct yankreg *src) static void get_clipboard(int name) { if (!(name == '*' || name == '+' - || (p_unc && !name && provider_has_feature("clipboard")))) { + || (p_unc && !name && eval_has_provider("clipboard")))) { return; } struct yankreg *reg = &y_regs[CLIP_REGISTER]; free_register(reg); - Array args = ARRAY_DICT_INIT; - Object result = provider_call("clipboard_get", args); + list_T *args = list_alloc(); + typval_T result = eval_call_provider("clipboard", "get", args); - if (result.type != kObjectTypeArray) { + if (result.v_type != VAR_LIST) { goto err; } - Array lines = result.data.array; - reg->y_array = xcalloc(lines.size, sizeof(uint8_t *)); - reg->y_size = lines.size; + list_T *lines = result.vval.v_list; + reg->y_array = xcalloc(lines->lv_len, sizeof(uint8_t *)); + reg->y_size = lines->lv_len; - for (size_t i = 0; i < lines.size; i++) { - if (lines.items[i].type != kObjectTypeString) { + int i = 0; + for (listitem_T *li = lines->lv_first; li != NULL; li = li->li_next) { + if (li->li_tv.v_type != VAR_STRING) { goto err; } - reg->y_array[i] = (uint8_t *)lines.items[i].data.string.data; + reg->y_array[i++] = (uint8_t *)xstrdup((char *)li->li_tv.vval.v_string); } if (!name && p_unc) { @@ -5272,8 +5272,12 @@ static void get_clipboard(int name) return; err: - api_free_object(result); - free(reg->y_array); + if (reg->y_array) { + for (int i = 0; i < reg->y_size; i++) { + free(reg->y_array[i]); + } + free(reg->y_array); + } reg->y_array = NULL; reg->y_size = 0; EMSG("Clipboard provider returned invalid data"); @@ -5282,7 +5286,7 @@ err: static void set_clipboard(int name) { if (!(name == '*' || name == '+' - || (p_unc && !name && provider_has_feature("clipboard")))) { + || (p_unc && !name && eval_has_provider("clipboard")))) { return; } @@ -5293,15 +5297,11 @@ static void set_clipboard(int name) copy_register(reg, &y_regs[0]); } - Array lines = ARRAY_DICT_INIT; + list_T *lines = list_alloc(); for (int i = 0; i < reg->y_size; i++) { - ADD(lines, STRING_OBJ(cstr_to_string((char *)reg->y_array[i]))); + list_append_string(lines, reg->y_array[i], -1); } - Array args = ARRAY_DICT_INIT; - ADD(args, ARRAY_OBJ(lines)); - - Object result = provider_call("clipboard_set", args); - api_free_object(result); + (void)eval_call_provider("clipboard", "set", lines); } diff --git a/src/nvim/os/event.c b/src/nvim/os/event.c index 5a5da5cd63..1477072f4f 100644 --- a/src/nvim/os/event.c +++ b/src/nvim/os/event.c @@ -11,7 +11,6 @@ #include "nvim/msgpack_rpc/channel.h" #include "nvim/msgpack_rpc/server.h" #include "nvim/msgpack_rpc/helpers.h" -#include "nvim/os/provider.h" #include "nvim/os/signal.h" #include "nvim/os/rstream.h" #include "nvim/os/wstream.h" @@ -62,8 +61,6 @@ void event_init(void) // finish mspgack-rpc initialization channel_init(); server_init(); - // Providers - provider_init(); } void event_teardown(void) diff --git a/src/nvim/os/provider.c b/src/nvim/os/provider.c deleted file mode 100644 index 414c8841fa..0000000000 --- a/src/nvim/os/provider.c +++ /dev/null @@ -1,152 +0,0 @@ -#include <stdint.h> -#include <inttypes.h> -#include <stdbool.h> -#include <assert.h> - -#include "nvim/os/provider.h" -#include "nvim/memory.h" -#include "nvim/api/vim.h" -#include "nvim/api/private/helpers.h" -#include "nvim/api/private/defs.h" -#include "nvim/msgpack_rpc/channel.h" -#include "nvim/os/shell.h" -#include "nvim/os/os.h" -#include "nvim/log.h" -#include "nvim/map.h" -#include "nvim/message.h" - -#define FEATURE_COUNT (sizeof(features) / sizeof(features[0])) - -#define FEATURE(feature_name, ...) { \ - .name = feature_name, \ - .channel_id = 0, \ - .methods = (char *[]){__VA_ARGS__, NULL} \ -} - -typedef struct { - char *name, **methods; - size_t name_length; - uint64_t channel_id; -} Feature; - -static Feature features[] = { - FEATURE("python", - "python_execute", - "python_execute_file", - "python_do_range", - "python_eval"), - - FEATURE("clipboard", - "clipboard_get", - "clipboard_set") -}; - -static PMap(cstr_t) *registered_providers = NULL; - -#ifdef INCLUDE_GENERATED_DECLARATIONS -# include "os/provider.c.generated.h" -#endif - - -void provider_init(void) -{ - registered_providers = pmap_new(cstr_t)(); -} - -bool provider_has_feature(char *name) -{ - Feature *f = find_feature(name); - return f != NULL && channel_exists(f->channel_id); -} - -bool provider_register(char *name, uint64_t channel_id) -{ - Feature *f = find_feature(name); - - if (!f) { - return false; - } - - if (f->channel_id && channel_exists(f->channel_id)) { - ILOG("Feature \"%s\" is already provided by another channel" - "(will be replaced)", name); - } - - DLOG("Registering provider for \"%s\"", name); - f->channel_id = channel_id; - - // Associate all method names with the feature struct - size_t i; - char *method; - for (method = f->methods[i = 0]; method; method = f->methods[++i]) { - pmap_put(cstr_t)(registered_providers, method, f); - DLOG("Channel \"%" PRIu64 "\" will be sent requests for \"%s\"", - channel_id, - method); - } - - ILOG("Registered channel %" PRIu64 " as the provider for the \"%s\" feature", - channel_id, - name); - - return true; -} - -Object provider_call(char *method, Array args) -{ - Feature *f = pmap_get(cstr_t)(registered_providers, method); - - if (!f || !channel_exists(f->channel_id)) { - char buf[256]; - snprintf(buf, - sizeof(buf), - "Provider for method \"%s\" is not available", - method); - vim_report_error(cstr_as_string(buf)); - api_free_array(args); - return NIL; - } - - Error err = ERROR_INIT; - Object result = NIL = channel_send_call(f->channel_id, method, args, &err); - - if (err.set) { - vim_report_error(cstr_as_string(err.msg)); - api_free_object(result); - return NIL; - } - - return result; -} - -void provider_init_feature_metadata(Dictionary *metadata) -{ - Dictionary md = ARRAY_DICT_INIT; - - for (size_t i = 0; i < FEATURE_COUNT; i++) { - Array methods = ARRAY_DICT_INIT; - Feature *f = &features[i]; - - size_t j; - char *method; - for (method = f->methods[j = 0]; method; method = f->methods[++j]) { - ADD(methods, STRING_OBJ(cstr_to_string(method))); - } - - PUT(md, f->name, ARRAY_OBJ(methods)); - } - - PUT(*metadata, "features", DICTIONARY_OBJ(md)); -} - -static Feature * find_feature(char *name) -{ - for (size_t i = 0; i < FEATURE_COUNT; i++) { - Feature *f = &features[i]; - if (!STRICMP(name, f->name)) { - return f; - } - } - - return NULL; -} diff --git a/src/nvim/os/provider.h b/src/nvim/os/provider.h deleted file mode 100644 index c6f12e02dd..0000000000 --- a/src/nvim/os/provider.h +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef NVIM_OS_PROVIDER_H -#define NVIM_OS_PROVIDER_H - -#include "nvim/api/private/defs.h" - -#ifdef INCLUDE_GENERATED_DECLARATIONS -# include "os/provider.h.generated.h" -#endif - -#endif // NVIM_OS_PROVIDER_H - |