From cac24cb06ddcad0cfb3a9379c3bdd0e8706602f9 Mon Sep 17 00:00:00 2001 From: Thiago de Arruda Date: Tue, 9 Sep 2014 09:36:14 -0300 Subject: api/msgpack-rpc: Refactor msgpack_rpc_helpers.{c,h} - Move helpers that are specific to API types to api/private/helpers.{c,h} - Include headers with generated declarations - Delete unused macros --- src/nvim/os/provider.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'src/nvim/os/provider.c') diff --git a/src/nvim/os/provider.c b/src/nvim/os/provider.c index 07e757fe0e..57c2e57a3c 100644 --- a/src/nvim/os/provider.c +++ b/src/nvim/os/provider.c @@ -14,7 +14,6 @@ #include "nvim/log.h" #include "nvim/map.h" #include "nvim/message.h" -#include "nvim/os/msgpack_rpc_helpers.h" #define FEATURE_COUNT (sizeof(features) / sizeof(features[0])) @@ -109,7 +108,7 @@ Object provider_call(char *method, Array args) "Provider for \"%s\" is not available", method); report_error(buf); - msgpack_rpc_free_array(args); + api_free_array(args); return NIL; } @@ -119,7 +118,7 @@ Object provider_call(char *method, Array args) if (error) { report_error(result.data.string.data); - msgpack_rpc_free_object(result); + api_free_object(result); return NIL; } -- cgit From a1ce3a3acc9f5e617e9d7e9542d58953d2e9546f Mon Sep 17 00:00:00 2001 From: Thiago de Arruda Date: Wed, 10 Sep 2014 10:11:45 -0300 Subject: provider: Major refactor - Providers for features are now registered as a unit. For example, instead of calling `register_provider("clipboard_get")` and `register_provider("clipboard_set")`, clients call `register_provider("clipboard")` and nvim will assume it implements all methods of the "clipboard" feature - Bootstrapping code was removed. With the `api_spawn` function exposed to vimscript, it's no longer necessary and will be handled by plugins distributed with nvim. - Now the `has` function will return true if there's a live channel that has registered as a provider for the feature. - 'initpython'/'initclipboard' options were removed - A new API function was exposed: `vim_discover_features` which returns an object with information about pluggable features such as 'python' or 'clipboard' --- src/nvim/os/provider.c | 166 ++++++++++++++++--------------------------------- 1 file changed, 54 insertions(+), 112 deletions(-) (limited to 'src/nvim/os/provider.c') diff --git a/src/nvim/os/provider.c b/src/nvim/os/provider.c index 57c2e57a3c..e56e33aa1a 100644 --- a/src/nvim/os/provider.c +++ b/src/nvim/os/provider.c @@ -17,33 +17,31 @@ #define FEATURE_COUNT (sizeof(features) / sizeof(features[0])) -#define FEATURE(feature_name, provider_bootstrap_command, ...) { \ +#define FEATURE(feature_name, ...) { \ .name = feature_name, \ - .bootstrap_command = provider_bootstrap_command, \ - .argv = NULL, \ .channel_id = 0, \ .methods = (char *[]){__VA_ARGS__, NULL} \ } -static struct feature { - char *name, **bootstrap_command, **argv, **methods; +typedef struct { + char *name, **methods; size_t name_length; uint64_t channel_id; -} features[] = { +} Feature; + +static Feature features[] = { FEATURE("python", - &p_ipy, "python_execute", "python_execute_file", "python_do_range", "python_eval"), FEATURE("clipboard", - &p_icpb, "clipboard_get", "clipboard_set") }; -static Map(cstr_t, uint64_t) *registered_providers = NULL; +static PMap(cstr_t) *registered_providers = NULL; #ifdef INCLUDE_GENERATED_DECLARATIONS # include "os/provider.c.generated.h" @@ -52,60 +50,57 @@ static Map(cstr_t, uint64_t) *registered_providers = NULL; void provider_init(void) { - registered_providers = map_new(cstr_t, uint64_t)(); + registered_providers = pmap_new(cstr_t)(); } bool provider_has_feature(char *name) { - for (size_t i = 0; i < FEATURE_COUNT; i++) { - struct feature *f = &features[i]; - if (!STRICMP(name, f->name)) { - return f->channel_id || can_execute(f); - } - } - - return false; + Feature *f = find_feature(name); + return f != NULL && channel_exists(f->channel_id); } -bool provider_available(char *method) +bool provider_register(char *name, uint64_t channel_id) { - return map_has(cstr_t, uint64_t)(registered_providers, method); -} + Feature *f = find_feature(name); -bool provider_register(char *method, uint64_t channel_id) -{ - if (map_has(cstr_t, uint64_t)(registered_providers, method)) { + if (!f) { return false; } - // First check if this method is part of a feature, and if so, update - // the feature structure with the channel id - struct feature *f = get_feature_for(method); - if (f) { - DLOG("Registering provider for \"%s\" " - "which is part of the \"%s\" feature", - method, - f->name); - f->channel_id = channel_id; + 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); } - map_put(cstr_t, uint64_t)(registered_providers, xstrdup(method), channel_id); - ILOG("Registered channel %" PRIu64 " as the provider for \"%s\"", + ILOG("Registered channel %" PRIu64 " as the provider for the \"%s\" feature", channel_id, - method); + name); return true; } Object provider_call(char *method, Array args) { - uint64_t channel_id = get_provider_for(method); + Feature *f = pmap_get(cstr_t)(registered_providers, method); - if (!channel_id) { + if (!f || !channel_exists(f->channel_id)) { char buf[256]; snprintf(buf, sizeof(buf), - "Provider for \"%s\" is not available", + "Provider for method \"%s\" is not available", method); report_error(buf); api_free_array(args); @@ -114,7 +109,7 @@ Object provider_call(char *method, Array args) bool error = false; Object result = NIL; - channel_send_call(channel_id, method, args, &result, &error); + channel_send_call(f->channel_id, method, args, &result, &error); if (error) { report_error(result.data.string.data); @@ -125,62 +120,36 @@ Object provider_call(char *method, Array args) return result; } -static uint64_t get_provider_for(char *method) +Dictionary provider_get_all(void) { - uint64_t channel_id = map_get(cstr_t, uint64_t)(registered_providers, method); - - if (channel_id) { - return channel_id; - } - - // Try to bootstrap if the method is part of a feature - struct feature *f = get_feature_for(method); - - if (!f || !can_execute(f)) { - ELOG("Cannot bootstrap provider for \"%s\"", method); - goto err; - } + Dictionary rv = ARRAY_DICT_INIT; - if (f->channel_id) { - ELOG("Already bootstrapped provider for \"%s\"", f->name); - goto err; - } + for (size_t i = 0; i < FEATURE_COUNT; i++) { + Array methods = ARRAY_DICT_INIT; + Feature *f = &features[i]; - f->channel_id = channel_from_job(f->argv); + size_t j; + char *method; + for (method = f->methods[j = 0]; method; method = f->methods[++j]) { + ADD(methods, STRING_OBJ(cstr_to_string(method))); + } - if (!f->channel_id) { - ELOG("The provider for \"%s\" failed to bootstrap", f->name); - goto err; + PUT(rv, f->name, ARRAY_OBJ(methods)); } - return f->channel_id; - -err: - // Ensure we won't try to restart the provider - if (f) { - f->bootstrap_command = NULL; - f->channel_id = 0; - } - return 0; + return rv; } -static bool can_execute(struct feature *f) +static Feature * find_feature(char *name) { - if (!f->bootstrap_command) { - return false; - } - - char *cmd = *f->bootstrap_command; - - if (!cmd || !strlen(cmd)) { - return false; - } - - if (!f->argv) { - f->argv = shell_build_argv((uint8_t *)cmd, NULL); + for (size_t i = 0; i < FEATURE_COUNT; i++) { + Feature *f = &features[i]; + if (!STRICMP(name, f->name)) { + return f; + } } - return os_can_exe((uint8_t *)f->argv[0]); + return NULL; } static void report_error(char *str) @@ -188,30 +157,3 @@ static void report_error(char *str) vim_err_write((String) {.data = str, .size = strlen(str)}); vim_err_write((String) {.data = "\n", .size = 1}); } - -static bool feature_has_method(struct feature *f, char *method) -{ - size_t i; - char *m; - - for (m = f->methods[i = 0]; m; m = f->methods[++i]) { - if (!STRCMP(method, m)) { - return true; - } - } - - return false; -} - - -static struct feature *get_feature_for(char *method) -{ - for (size_t i = 0; i < FEATURE_COUNT; i++) { - struct feature *f = &features[i]; - if (feature_has_method(f, method)) { - return f; - } - } - - return NULL; -} -- cgit From 15ca58d79f8cc8565c1a2b2581029cf7901b5fbd Mon Sep 17 00:00:00 2001 From: Thiago de Arruda Date: Thu, 11 Sep 2014 10:35:52 -0300 Subject: api: Implement `vim_report_error` function This function is used to report errors caused by remote functions called by channel_send_call --- src/nvim/os/provider.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) (limited to 'src/nvim/os/provider.c') diff --git a/src/nvim/os/provider.c b/src/nvim/os/provider.c index e56e33aa1a..9d8f6f297c 100644 --- a/src/nvim/os/provider.c +++ b/src/nvim/os/provider.c @@ -102,7 +102,7 @@ Object provider_call(char *method, Array args) sizeof(buf), "Provider for method \"%s\" is not available", method); - report_error(buf); + vim_report_error(cstr_as_string(buf)); api_free_array(args); return NIL; } @@ -112,7 +112,7 @@ Object provider_call(char *method, Array args) channel_send_call(f->channel_id, method, args, &result, &error); if (error) { - report_error(result.data.string.data); + vim_report_error(result.data.string); api_free_object(result); return NIL; } @@ -151,9 +151,3 @@ static Feature * find_feature(char *name) return NULL; } - -static void report_error(char *str) -{ - vim_err_write((String) {.data = str, .size = strlen(str)}); - vim_err_write((String) {.data = "\n", .size = 1}); -} -- cgit From cd2e46c0785d40b9ea15f6d722a3fad54c007b9b Mon Sep 17 00:00:00 2001 From: Thiago de Arruda Date: Thu, 11 Sep 2014 21:56:52 -0300 Subject: api/msgpack-rpc: Refactor metadata object construction Instead of building all metadata from msgpack-gen.lua, we now merge the generated part with manual information(such as types and features). The metadata is accessible through the api method `vim_get_api_info`. This was done to simplify the generator while also increasing flexibility(by being able to add more metadata) --- src/nvim/os/provider.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src/nvim/os/provider.c') diff --git a/src/nvim/os/provider.c b/src/nvim/os/provider.c index 9d8f6f297c..2e7a677793 100644 --- a/src/nvim/os/provider.c +++ b/src/nvim/os/provider.c @@ -120,9 +120,9 @@ Object provider_call(char *method, Array args) return result; } -Dictionary provider_get_all(void) +void provider_init_feature_metadata(Dictionary *metadata) { - Dictionary rv = ARRAY_DICT_INIT; + Dictionary md = ARRAY_DICT_INIT; for (size_t i = 0; i < FEATURE_COUNT; i++) { Array methods = ARRAY_DICT_INIT; @@ -134,10 +134,10 @@ Dictionary provider_get_all(void) ADD(methods, STRING_OBJ(cstr_to_string(method))); } - PUT(rv, f->name, ARRAY_OBJ(methods)); + PUT(md, f->name, ARRAY_OBJ(methods)); } - return rv; + PUT(*metadata, "features", DICTIONARY_OBJ(md)); } static Feature * find_feature(char *name) -- cgit