summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorSebastien Helleu <flashcode@flashtux.org>2007-12-07 15:01:37 +0100
committerSebastien Helleu <flashcode@flashtux.org>2007-12-07 15:01:37 +0100
commit72a694ed4c78df15b68ef4698b16f7072919f3ee (patch)
tree499e976612d6fe1d92675149707350c38b74758b /src
parent495e6bd5df9163148676821d610c9ef863326f70 (diff)
downloadweechat-72a694ed4c78df15b68ef4698b16f7072919f3ee.zip
Added completion hook, to let plugins add custom completions for commands
Diffstat (limited to 'src')
-rw-r--r--src/core/wee-command.c20
-rw-r--r--src/core/wee-hook.c86
-rw-r--r--src/core/wee-hook.h13
-rw-r--r--src/gui/gui-completion.c79
-rw-r--r--src/plugins/alias/alias.c29
-rw-r--r--src/plugins/plugin-api.c15
-rw-r--r--src/plugins/plugin-api.h4
-rw-r--r--src/plugins/plugin.c1
-rw-r--r--src/plugins/weechat-plugin.h6
9 files changed, 230 insertions, 23 deletions
diff --git a/src/core/wee-command.c b/src/core/wee-command.c
index 487527656..72405bc9a 100644
--- a/src/core/wee-command.c
+++ b/src/core/wee-command.c
@@ -1020,7 +1020,7 @@ command_plugin_list (char *name, int full)
{
if (!hook_found)
gui_chat_printf (NULL,
- _(" configuration otions "
+ _(" configuration options "
"hooked:"));
hook_found = 1;
gui_chat_printf (NULL,
@@ -1031,6 +1031,24 @@ command_plugin_list (char *name, int full)
HOOK_CONFIG(ptr_hook, option) : "*");
}
}
+
+ /* completion hooked */
+ hook_found = 0;
+ for (ptr_hook = weechat_hooks; ptr_hook;
+ ptr_hook = ptr_hook->next_hook)
+ {
+ if ((ptr_hook->plugin == ptr_plugin)
+ && (ptr_hook->type == HOOK_TYPE_COMPLETION))
+ {
+ if (!hook_found)
+ gui_chat_printf (NULL,
+ _(" completion hooked:"));
+ hook_found = 1;
+ gui_chat_printf (NULL,
+ " %s",
+ HOOK_COMPLETION(ptr_hook, completion));
+ }
+ }
}
}
}
diff --git a/src/core/wee-hook.c b/src/core/wee-hook.c
index a1db2b586..ebe656c39 100644
--- a/src/core/wee-hook.c
+++ b/src/core/wee-hook.c
@@ -827,6 +827,80 @@ hook_config_exec (char *type, char *option, char *value)
}
/*
+ * hook_completion: hook a completion
+ */
+
+struct t_hook *
+hook_completion (void *plugin, char *completion,
+ t_hook_callback_completion *callback, void *callback_data)
+{
+ struct t_hook *new_hook;
+ struct t_hook_completion *new_hook_completion;
+
+ if (!completion || !completion[0] || strchr (completion, ' '))
+ return NULL;
+
+ new_hook = (struct t_hook *)malloc (sizeof (struct t_hook));
+ if (!new_hook)
+ return NULL;
+ new_hook_completion = (struct t_hook_completion *)malloc (sizeof (struct t_hook_completion));
+ if (!new_hook_completion)
+ {
+ free (new_hook);
+ return NULL;
+ }
+
+ hook_init (new_hook, plugin, HOOK_TYPE_COMPLETION, callback_data);
+
+ new_hook->hook_data = new_hook_completion;
+ new_hook_completion->callback = callback;
+ new_hook_completion->completion = strdup (completion);
+
+ hook_add_to_list (new_hook);
+
+ return new_hook;
+}
+
+/*
+ * hook_completion_exec: execute completion hook
+ */
+
+void
+hook_completion_exec (void *plugin, char *completion, void *list)
+{
+ struct t_hook *ptr_hook, *next_hook;
+
+ hook_exec_recursion++;
+
+ ptr_hook = weechat_hooks;
+ while (ptr_hook)
+ {
+ next_hook = ptr_hook->next_hook;
+
+ if ((ptr_hook->type == HOOK_TYPE_COMPLETION)
+ && (!ptr_hook->running)
+ && (ptr_hook->plugin == plugin)
+ && (string_strcasecmp (HOOK_COMPLETION(ptr_hook, completion),
+ completion) == 0))
+ {
+ ptr_hook->running = 1;
+ (void) (HOOK_COMPLETION(ptr_hook, callback))
+ (ptr_hook->callback_data, completion, list);
+ if (ptr_hook->type == HOOK_TYPE_COMPLETION)
+ ptr_hook->running = 0;
+ }
+
+ ptr_hook = next_hook;
+ }
+
+ if (hook_exec_recursion > 0)
+ hook_exec_recursion--;
+
+ if (hook_exec_recursion == 0)
+ hook_remove_deleted ();
+}
+
+/*
* unhook: unhook something
*/
@@ -894,6 +968,11 @@ unhook (struct t_hook *hook)
free (HOOK_CONFIG(hook, option));
free ((struct t_hook_config *)hook->hook_data);
break;
+ case HOOK_TYPE_COMPLETION:
+ if (HOOK_COMPLETION(hook, completion))
+ free (HOOK_COMPLETION(hook, completion));
+ free ((struct t_hook_completion *)hook->hook_data);
+ break;
}
hook->hook_data = NULL;
}
@@ -1021,6 +1100,13 @@ hook_print_log ()
log_printf (" type . . . . . . . . : '%s'", HOOK_CONFIG(ptr_hook, type));
log_printf (" option . . . . . . . : '%s'", HOOK_CONFIG(ptr_hook, option));
break;
+ case HOOK_TYPE_COMPLETION:
+ log_printf (" type . . . . . . . . . : %d (completion)", ptr_hook->type);
+ log_printf (" callback_data. . . . . : 0x%X", ptr_hook->callback_data);
+ log_printf (" completion data:");
+ log_printf (" callback . . . . . . : 0x%X", HOOK_COMPLETION(ptr_hook, callback));
+ log_printf (" completion . . . . . : '%s'", HOOK_COMPLETION(ptr_hook, completion));
+ break;
}
log_printf (" running. . . . . . . . : %d", ptr_hook->running);
log_printf (" prev_hook. . . . . . . : 0x%X", ptr_hook->prev_hook);
diff --git a/src/core/wee-hook.h b/src/core/wee-hook.h
index 7bf23300b..ceb49998a 100644
--- a/src/core/wee-hook.h
+++ b/src/core/wee-hook.h
@@ -31,6 +31,7 @@ enum t_hook_type
HOOK_TYPE_PRINT, /* printed message */
HOOK_TYPE_EVENT, /* event */
HOOK_TYPE_CONFIG, /* config option */
+ HOOK_TYPE_COMPLETION, /* custom completions */
};
#define HOOK_FD_FLAG_READ 1
@@ -43,6 +44,7 @@ enum t_hook_type
#define HOOK_PRINT(hook, var) (((struct t_hook_print *)hook->hook_data)->var)
#define HOOK_EVENT(hook, var) (((struct t_hook_event *)hook->hook_data)->var)
#define HOOK_CONFIG(hook, var) (((struct t_hook_config *)hook->hook_data)->var)
+#define HOOK_COMPLETION(hook, var) (((struct t_hook_completion *)hook->hook_data)->var)
struct t_hook
{
@@ -121,6 +123,14 @@ struct t_hook_config
/* (NULL = hook for all options) */
};
+typedef int (t_hook_callback_completion)(void *, char *, void *);
+
+struct t_hook_completion
+{
+ t_hook_callback_completion *callback; /* completion callback */
+ char *completion; /* name of completion */
+};
+
/* hook variables */
extern struct t_hook *weechat_hooks;
@@ -149,6 +159,9 @@ extern void hook_event_exec (char *, void *);
extern struct t_hook *hook_config (void *, char *, char *,
t_hook_callback_config *, void *);
extern void hook_config_exec (char *, char *, char *);
+extern struct t_hook *hook_completion (void *, char *,
+ t_hook_callback_completion *, void *);
+extern void hook_completion_exec (void *, char *, void *);
extern void unhook (struct t_hook *);
extern void unhook_all_plugin (void *);
diff --git a/src/gui/gui-completion.c b/src/gui/gui-completion.c
index 6598d8c3d..555404648 100644
--- a/src/gui/gui-completion.c
+++ b/src/gui/gui-completion.c
@@ -127,18 +127,14 @@ gui_completion_stop (struct t_gui_completion *completion)
}
/*
- * gui_completion_get_command_infos: return completion template and max arg
- * for command
+ * gui_completion_search_command: search command hook
*/
-void
-gui_completion_get_command_infos (struct t_gui_completion *completion,
- char **template)
+struct t_hook *
+gui_completion_search_command (struct t_gui_completion *completion)
{
struct t_hook *ptr_hook;
- *template = NULL;
-
for (ptr_hook = weechat_hooks; ptr_hook;
ptr_hook = ptr_hook->next_hook)
{
@@ -148,11 +144,11 @@ gui_completion_get_command_infos (struct t_gui_completion *completion,
&& (HOOK_COMMAND(ptr_hook, level) == 0)
&& (string_strcasecmp (HOOK_COMMAND(ptr_hook, command),
completion->base_command) == 0))
- {
- *template = HOOK_COMMAND(ptr_hook, completion);
- return;
- }
+ return ptr_hook;
}
+
+ /* command not found */
+ return NULL;
}
/*
@@ -862,13 +858,29 @@ gui_completion_list_add_weechat_cmd (struct t_gui_completion *completion)
}
/*
+ * gui_completion_custom: custom completion by a plugin
+ */
+
+void
+gui_completion_custom (struct t_gui_completion *completion,
+ char *custom_completion,
+ struct t_weechat_plugin *plugin)
+{
+ hook_completion_exec (plugin,
+ custom_completion,
+ completion->completion_list);
+}
+
+/*
* gui_completion_build_list_template: build data list according to a template
*/
void
-gui_completion_build_list_template (struct t_gui_completion *completion, char *template)
+gui_completion_build_list_template (struct t_gui_completion *completion,
+ char *template,
+ struct t_weechat_plugin *plugin)
{
- char *word, *pos;
+ char *word, *pos, *pos_end, *custom_completion;
int word_offset;
word = strdup (template);
@@ -963,6 +975,25 @@ gui_completion_build_list_template (struct t_gui_completion *completion, char *t
case 'w': /* WeeChat commands */
gui_completion_list_add_weechat_cmd (completion);
break;
+ case '(': /* custom completion by a plugin */
+ pos++;
+ pos_end = strchr (pos, ')');
+ if (pos_end)
+ {
+ if (pos_end > pos)
+ {
+ custom_completion = strndup (pos,
+ pos_end - pos);
+ if (custom_completion)
+ {
+ gui_completion_custom (completion,
+ custom_completion,
+ plugin);
+ free (custom_completion);
+ }
+ }
+ pos = pos_end + 1;
+ }
}
}
break;
@@ -985,33 +1016,37 @@ gui_completion_build_list_template (struct t_gui_completion *completion, char *t
void
gui_completion_build_list (struct t_gui_completion *completion)
{
+ struct t_hook *ptr_hook;
char *template, *pos_template, *pos_space;
int repeat_last, i, length;
repeat_last = 0;
- gui_completion_get_command_infos (completion, &template);
- if (!template || (strcmp (template, "-") == 0))
+ ptr_hook = gui_completion_search_command (completion);
+ if (!ptr_hook || !HOOK_COMMAND(ptr_hook, completion)
+ || (strcmp (HOOK_COMMAND(ptr_hook, completion), "-") == 0))
{
gui_completion_stop (completion);
return;
}
-
- length = strlen (template);
+
+ length = strlen (HOOK_COMMAND(ptr_hook, completion));
if (length >= 2)
{
- if (strcmp (template + length - 2, "%*") == 0)
+ if (strcmp (HOOK_COMMAND(ptr_hook, completion) + length - 2,
+ "%*") == 0)
repeat_last = 1;
}
i = 1;
- pos_template = template;
+ pos_template = HOOK_COMMAND(ptr_hook, completion);
while (pos_template && pos_template[0])
{
pos_space = strchr (pos_template, ' ');
if (i == completion->base_command_arg)
{
- gui_completion_build_list_template (completion, pos_template);
+ gui_completion_build_list_template (completion, pos_template,
+ ptr_hook->plugin);
return;
}
if (pos_space)
@@ -1028,7 +1063,9 @@ gui_completion_build_list (struct t_gui_completion *completion)
{
pos_space = rindex (template, ' ');
gui_completion_build_list_template (completion,
- (pos_space) ? pos_space + 1 : template);
+ (pos_space) ?
+ pos_space + 1 : template,
+ ptr_hook->plugin);
}
}
diff --git a/src/plugins/alias/alias.c b/src/plugins/alias/alias.c
index cee9e7b22..b7a74be8e 100644
--- a/src/plugins/alias/alias.c
+++ b/src/plugins/alias/alias.c
@@ -43,6 +43,7 @@ struct t_alias *last_alias = NULL;
struct t_hook *alias_command = NULL;
struct t_hook *unalias_command = NULL;
struct t_hook *config_reload = NULL;
+struct t_hook *completion = NULL;
/*
@@ -691,6 +692,28 @@ unalias_command_cb (void *data, void *buffer, int argc, char **argv,
}
/*
+ * alias_completion_cb: callback for completion
+ */
+
+int
+alias_completion_cb (void *data, char *completion, void *list)
+{
+ struct t_alias *ptr_alias;
+
+ /* make C compiler happy */
+ (void) data;
+ (void) completion;
+
+ for (ptr_alias = alias_list; ptr_alias;
+ ptr_alias = ptr_alias->next_alias)
+ {
+ weechat_list_add (list, ptr_alias->name, "sort");
+ }
+
+ return PLUGIN_RC_SUCCESS;
+}
+
+/*
* weechat_plugin_init: initialize alias plugin
*/
@@ -734,12 +757,15 @@ weechat_plugin_init (struct t_weechat_plugin *plugin)
N_("alias_name"),
N_("alias_name: name of alias to "
"remove"),
- "%h",
+ "%(alias)",
unalias_command_cb, NULL);
config_reload = weechat_hook_event ("config_reload",
alias_config_reload_event_cb, NULL);
+ completion = weechat_hook_completion ("alias",
+ alias_completion_cb, NULL);
+
return PLUGIN_RC_SUCCESS;
}
@@ -756,6 +782,7 @@ weechat_plugin_end ()
weechat_unhook (alias_command);
weechat_unhook (unalias_command);
weechat_unhook (config_reload);
+ weechat_unhook (completion);
return PLUGIN_RC_SUCCESS;
}
diff --git a/src/plugins/plugin-api.c b/src/plugins/plugin-api.c
index 88b712983..d16e4e520 100644
--- a/src/plugins/plugin-api.c
+++ b/src/plugins/plugin-api.c
@@ -1186,6 +1186,21 @@ plugin_api_hook_config (struct t_weechat_plugin *plugin, char *config_type,
}
/*
+ * plugin_api_hook_completion: hook a completion
+ */
+
+struct t_hook *
+plugin_api_hook_completion (struct t_weechat_plugin *plugin, char *completion,
+ int (*callback)(void *, char *, void *),
+ void *data)
+{
+ if (plugin && callback)
+ return hook_completion (plugin, completion, callback, data);
+
+ return NULL;
+}
+
+/*
* plugin_api_unhook: unhook something
*/
diff --git a/src/plugins/plugin-api.h b/src/plugins/plugin-api.h
index d1ceda88d..7b0b83ae3 100644
--- a/src/plugins/plugin-api.h
+++ b/src/plugins/plugin-api.h
@@ -146,6 +146,10 @@ extern struct t_hook *plugin_api_hook_config (struct t_weechat_plugin *,
char *, char *,
int (*)(void *, char *, char *, char *),
void *);
+extern struct t_hook *plugin_api_hook_completion (struct t_weechat_plugin *,
+ char *,
+ int (*)(void *, char *, void *),
+ void *);
extern void plugin_api_unhook (struct t_weechat_plugin *, void *);
extern void plugin_api_unhook_all (struct t_weechat_plugin *);
diff --git a/src/plugins/plugin.c b/src/plugins/plugin.c
index 09b481734..f1057c3cf 100644
--- a/src/plugins/plugin.c
+++ b/src/plugins/plugin.c
@@ -289,6 +289,7 @@ plugin_load (char *filename)
new_plugin->hook_print = &plugin_api_hook_print;
new_plugin->hook_event = &plugin_api_hook_event;
new_plugin->hook_config = &plugin_api_hook_config;
+ new_plugin->hook_completion = &plugin_api_hook_completion;
new_plugin->unhook = &plugin_api_unhook;
new_plugin->unhook_all = &plugin_api_unhook_all;
diff --git a/src/plugins/weechat-plugin.h b/src/plugins/weechat-plugin.h
index 115c9f032..3bdbc2b39 100644
--- a/src/plugins/weechat-plugin.h
+++ b/src/plugins/weechat-plugin.h
@@ -155,6 +155,9 @@ struct t_weechat_plugin
struct t_hook *(*hook_config) (struct t_weechat_plugin *, char *, char *,
int (*)(void *, char *, char *, char *),
void *);
+ struct t_hook *(*hook_completion) (struct t_weechat_plugin *, char *,
+ int (*)(void *, char *, void *),
+ void *);
void (*unhook) (struct t_weechat_plugin *, void *);
void (*unhook_all) (struct t_weechat_plugin *);
@@ -364,6 +367,9 @@ struct t_weechat_plugin
#define weechat_hook_config(__type, __option, __callback, __data) \
weechat_plugin->hook_config(weechat_plugin, __type, __option, \
__callback, __data)
+#define weechat_hook_completion(__completion, __callback, __data) \
+ weechat_plugin->hook_completion(weechat_plugin, __completion, \
+ __callback, __data)
#define weechat_unhook(__hook) \
weechat_plugin->unhook(weechat_plugin, __hook)
#define weechat_unhook_all() \