aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThiago de Arruda <tpadilha84@gmail.com>2014-09-10 10:11:45 -0300
committerThiago de Arruda <tpadilha84@gmail.com>2014-09-12 13:25:29 -0300
commita1ce3a3acc9f5e617e9d7e9542d58953d2e9546f (patch)
tree75868da04d3253dac4e759f0cf0a480d63d25516
parent50609029301d0baac36d7500c2d80da9efb41861 (diff)
downloadrneovim-a1ce3a3acc9f5e617e9d7e9542d58953d2e9546f.tar.gz
rneovim-a1ce3a3acc9f5e617e9d7e9542d58953d2e9546f.tar.bz2
rneovim-a1ce3a3acc9f5e617e9d7e9542d58953d2e9546f.zip
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'
-rw-r--r--src/nvim/api/vim.c18
-rw-r--r--src/nvim/option.c6
-rw-r--r--src/nvim/option_defs.h2
-rw-r--r--src/nvim/os/provider.c166
4 files changed, 66 insertions, 126 deletions
diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c
index b1d5a067b4..e14c427dc1 100644
--- a/src/nvim/api/vim.c
+++ b/src/nvim/api/vim.c
@@ -502,22 +502,28 @@ void vim_unsubscribe(uint64_t channel_id, String event)
channel_unsubscribe(channel_id, e);
}
-/// Registers the channel as the provider for `method`. This fails if
-/// a provider for `method` is already registered.
+/// 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 method The method name
+/// @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 method, Error *err)
+void vim_register_provider(uint64_t channel_id, String feature, Error *err)
{
char buf[METHOD_MAXLEN];
- xstrlcpy(buf, method.data, sizeof(buf));
+ xstrlcpy(buf, feature.data, sizeof(buf));
if (!provider_register(buf, channel_id)) {
- set_api_error("Provider already registered", err);
+ set_api_error("Feature doesn't exist", err);
}
}
+/// Returns a feature->method list dictionary for all pluggable features
+Dictionary vim_discover_features(void)
+{
+ return provider_get_all();
+}
+
/// Writes a message to vim output or error buffer. The string is split
/// and flushed after each newline. Incomplete lines are kept for writing
/// later.
diff --git a/src/nvim/option.c b/src/nvim/option.c
index b9becebbf4..b26b6ed4cc 100644
--- a/src/nvim/option.c
+++ b/src/nvim/option.c
@@ -974,12 +974,6 @@ static struct vimoption
{"infercase", "inf", P_BOOL|P_VI_DEF,
(char_u *)&p_inf, PV_INF,
{(char_u *)FALSE, (char_u *)0L} SCRIPTID_INIT},
- {"initclipboard","icpb",P_STRING|P_VI_DEF|P_SECURE,
- (char_u *)&p_icpb, PV_NONE,
- {(char_u *)"", (char_u *)0L} SCRIPTID_INIT},
- {"initpython","ipy",P_STRING|P_VI_DEF|P_SECURE,
- (char_u *)&p_ipy, PV_NONE,
- {(char_u *)"", (char_u *)0L} SCRIPTID_INIT},
{"insertmode", "im", P_BOOL|P_VI_DEF|P_VIM,
(char_u *)&p_im, PV_NONE,
{(char_u *)FALSE, (char_u *)0L} SCRIPTID_INIT},
diff --git a/src/nvim/option_defs.h b/src/nvim/option_defs.h
index 555e9166d6..cd61b6427c 100644
--- a/src/nvim/option_defs.h
+++ b/src/nvim/option_defs.h
@@ -631,8 +631,6 @@ EXTERN int p_write; /* 'write' */
EXTERN int p_wa; /* 'writeany' */
EXTERN int p_wb; /* 'writebackup' */
EXTERN long p_wd; /* 'writedelay' */
-EXTERN char *p_ipy; // 'initpython'
-EXTERN char *p_icpb; // 'initclipboard'
/*
* "indir" values for buffer-local opions.
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;
-}