Added completion hook, to let plugins add custom completions for commands
This commit is contained in:
parent
495e6bd5df
commit
72a694ed4c
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -826,6 +826,80 @@ hook_config_exec (char *type, char *option, char *value)
|
||||
hook_remove_deleted ();
|
||||
}
|
||||
|
||||
/*
|
||||
* 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);
|
||||
|
@ -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 *);
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -861,14 +857,30 @@ 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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
||||
/*
|
||||
@ -690,6 +691,28 @@ unalias_command_cb (void *data, void *buffer, int argc, char **argv,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
|
@ -1185,6 +1185,21 @@ plugin_api_hook_config (struct t_weechat_plugin *plugin, char *config_type,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
|
@ -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 *);
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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() \
|
||||
|
Loading…
x
Reference in New Issue
Block a user