1
0
mirror of https://github.com/profanity-im/profanity.git synced 2024-06-16 21:35:24 +00:00

Free plugins commands on quit

This commit is contained in:
James Booth 2016-07-04 00:41:29 +01:00
parent 606a860bdc
commit 71879a3f64
15 changed files with 203 additions and 53 deletions

View File

@ -123,6 +123,7 @@ unittest_sources = \
tests/unittests/test_cmd_join.c tests/unittests/test_cmd_join.h \
tests/unittests/test_cmd_roster.c tests/unittests/test_cmd_roster.h \
tests/unittests/test_cmd_disconnect.c tests/unittests/test_cmd_disconnect.h \
tests/unittests/test_callbacks.c tests/unittests/test_callbacks.h \
tests/unittests/unittests.c
functionaltest_sources = \

View File

@ -3809,7 +3809,7 @@ cmd_form(ProfWin *window, const char *const command, gchar **args)
} else {
mucconfwin_form_help(confwin);
const gchar **help_text = NULL;
gchar **help_text = NULL;
Command *command = cmd_get("/form");
if (command) {

View File

@ -39,11 +39,11 @@
// Command help strings
typedef struct cmd_help_t {
const gchar *tags[20];
const gchar *synopsis[50];
const gchar *desc;
const gchar *args[128][2];
const gchar *examples[20];
gchar *tags[20];
gchar *synopsis[50];
gchar *desc;
gchar *args[128][2];
gchar *examples[20];
} CommandHelp;
/*

View File

@ -107,18 +107,21 @@ api_cons_bad_cmd_usage(const char *const cmd)
void
api_register_command(const char *const plugin_name, const char *command_name, int min_args, int max_args,
const char **synopsis, const char *description, const char *arguments[][2], const char **examples, void *callback,
void(*callback_exec)(PluginCommand *command, gchar **args))
const char **synopsis, const char *description, const char *arguments[][2], const char **examples,
void *callback, void(*callback_exec)(PluginCommand *command, gchar **args), void(*callback_destroy)(void *callback))
{
PluginCommand *command = malloc(sizeof(PluginCommand));
command->command_name = command_name;
command->command_name = strdup(command_name);
command->min_args = min_args;
command->max_args = max_args;
command->callback = callback;
command->callback_exec = callback_exec;
command->callback_destroy = callback_destroy;
CommandHelp *help = malloc(sizeof(CommandHelp));
help->tags[0] = NULL;
int i = 0;
for (i = 0; synopsis[i] != NULL; i++) {
help->synopsis[i] = strdup(synopsis[i]);
@ -140,16 +143,17 @@ api_register_command(const char *const plugin_name, const char *command_name, in
command->help = help;
callbacks_add_command(command);
callbacks_add_command(plugin_name, command);
}
void
api_register_timed(const char *const plugin_name, void *callback, int interval_seconds,
void (*callback_exec)(PluginTimedFunction *timed_function))
void (*callback_exec)(PluginTimedFunction *timed_function), void(*callback_destroy)(void *callback))
{
PluginTimedFunction *timed_function = malloc(sizeof(PluginTimedFunction));
timed_function->callback = callback;
timed_function->callback_exec = callback_exec;
timed_function->callback_destroy = callback_destroy;
timed_function->interval_seconds = interval_seconds;
timed_function->timer = g_timer_new();

View File

@ -52,9 +52,9 @@ char** api_get_current_occupants(void);
void api_register_command(const char *const plugin_name, const char *command_name, int min_args, int max_args,
const char **synopsis, const char *description, const char *arguments[][2], const char **examples,
void *callback, void(*callback_func)(PluginCommand *command, gchar **args));
void *callback, void(*callback_func)(PluginCommand *command, gchar **args), void(*callback_destroy)(void *callback));
void api_register_timed(const char *const plugin_name, void *callback, int interval_seconds,
void (*callback_func)(PluginTimedFunction *timed_function));
void (*callback_func)(PluginTimedFunction *timed_function), void(*callback_destroy)(void *callback));
void api_completer_add(const char *const plugin_name, const char *key, char **items);
void api_completer_remove(const char *key, char **items);
@ -70,8 +70,8 @@ void api_win_create(
const char *const plugin_name,
const char *tag,
void *callback,
void(*destroy)(void *callback),
void(*callback_func)(PluginWindowCallback *window_callback, char *tag, char *line));
void(*callback_func)(PluginWindowCallback *window_callback, char *tag, char *line),
void(*destroy)(void *callback));
int api_win_focus(const char *tag);
int api_win_show(const char *tag, const char *line);
int api_win_show_themed(const char *tag, const char *const group, const char *const key, const char *const def, const char *line);

View File

@ -90,7 +90,9 @@ c_api_register_command(const char *filename, const char *command_name, int min_a
CommandWrapper *wrapper = malloc(sizeof(CommandWrapper));
wrapper->func = callback;
api_register_command(plugin_name, command_name, min_args, max_args, synopsis,
description, arguments, examples, wrapper, c_command_callback);
description, arguments, examples, wrapper, c_command_callback, free);
free(plugin_name);
}
static void
@ -101,7 +103,9 @@ c_api_register_timed(const char *filename, void(*callback)(void), int interval_s
TimedWrapper *wrapper = malloc(sizeof(TimedWrapper));
wrapper->func = callback;
api_register_timed(plugin_name, wrapper, interval_seconds, c_timed_callback);
api_register_timed(plugin_name, wrapper, interval_seconds, c_timed_callback, free);
free(plugin_name);
}
static void
@ -111,6 +115,8 @@ c_api_completer_add(const char *filename, const char *key, char **items)
log_debug("Autocomplete add %s for %s", key, plugin_name);
api_completer_add(plugin_name, key, items);
free(plugin_name);
}
static void
@ -205,7 +211,9 @@ c_api_win_create(const char *filename, char *tag, void(*callback)(char *tag, cha
WindowWrapper *wrapper = malloc(sizeof(WindowWrapper));
wrapper->func = callback;
api_win_create(plugin_name, tag, wrapper, free, c_window_callback);
api_win_create(plugin_name, tag, wrapper, c_window_callback, free);
free(plugin_name);
}
static int

View File

@ -44,7 +44,7 @@
#include "ui/ui.h"
static GSList *p_commands = NULL;
static GHashTable *p_commands = NULL;
static GSList *p_timed_functions = NULL;
static GHashTable *p_window_callbacks = NULL;
@ -57,22 +57,88 @@ _free_window_callback(PluginWindowCallback *window_callback)
free(window_callback);
}
void
callbacks_init(void)
//typedef struct cmd_help_t {
// const gchar *tags[20];
// const gchar *synopsis[50];
// const gchar *desc;
// const gchar *args[128][2];
// const gchar *examples[20];
//} CommandHelp;
static void
_free_command_help(CommandHelp *help)
{
p_window_callbacks = g_hash_table_new_full(g_str_hash, g_str_equal, free, (GDestroyNotify)_free_window_callback);
int i = 0;
while (help->tags[i] != NULL) {
free(help->tags[i++]);
}
i = 0;
while (help->synopsis[i] != NULL) {
free(help->synopsis[i++]);
}
free(help->desc);
i = 0;
while (help->args[i] != NULL && help->args[i][0] != NULL) {
free(help->args[i][0]);
free(help->args[i][1]);
i++;
}
i = 0;
while (help->examples[i] != NULL) {
free(help->examples[i++]);
}
free(help);
}
static void
_free_command(PluginCommand *command)
{
if (command->callback_destroy) {
command->callback_destroy(command->callback);
}
free(command->command_name);
_free_command_help(command->help);
free(command);
}
static void
_free_command_hash(GHashTable *command_hash)
{
g_hash_table_destroy(command_hash);
}
void
callbacks_init(void)
{
p_commands = g_hash_table_new_full(g_str_hash, g_str_equal, free, (GDestroyNotify)_free_command_hash);
p_window_callbacks = g_hash_table_new_full(g_str_hash, g_str_equal, free, (GDestroyNotify)_free_window_callback);
}
// TODO move to plugin destroy functions
void
callbacks_close(void)
{
g_hash_table_destroy(p_commands);
g_hash_table_destroy(p_window_callbacks);
}
void
callbacks_add_command(PluginCommand *command)
callbacks_add_command(const char *const plugin_name, PluginCommand *command)
{
p_commands = g_slist_append(p_commands, command);
GHashTable *command_hash = g_hash_table_lookup(p_commands, plugin_name);
if (command_hash) {
g_hash_table_insert(command_hash, strdup(command->command_name), command);
} else {
command_hash = g_hash_table_new_full(g_str_hash, g_str_equal, free, (GDestroyNotify)_free_command);
g_hash_table_insert(command_hash, strdup(command->command_name), command);
g_hash_table_insert(p_commands, strdup(plugin_name), command_hash);
}
cmd_ac_add(command->command_name);
cmd_ac_add_help(&command->command_name[1]);
}
@ -104,25 +170,32 @@ plugins_run_command(const char * const input)
{
gchar **split = g_strsplit(input, " ", -1);
GSList *p_command = p_commands;
while (p_command) {
PluginCommand *command = p_command->data;
if (g_strcmp0(split[0], command->command_name) == 0) {
GList *command_hashes = g_hash_table_get_values(p_commands);
GList *curr_hash = command_hashes;
while (curr_hash) {
GHashTable *command_hash = curr_hash->data;
PluginCommand *command = g_hash_table_lookup(command_hash, split[0]);
if (command) {
gboolean result;
gchar **args = parse_args_with_freetext(input, command->min_args, command->max_args, &result);
if (result == FALSE) {
ui_invalid_command_usage(command->command_name, NULL);
g_strfreev(split);
g_list_free(command_hashes);
return TRUE;
} else {
command->callback_exec(command, args);
g_strfreev(split);
g_strfreev(args);
g_list_free(command_hashes);
return TRUE;
}
}
p_command = g_slist_next(p_command);
curr_hash = g_list_next(curr_hash);
}
g_strfreev(split);
return FALSE;
}
@ -130,16 +203,22 @@ plugins_run_command(const char * const input)
CommandHelp*
plugins_get_help(const char *const cmd)
{
GSList *curr = p_commands;
while (curr) {
PluginCommand *command = curr->data;
if (g_strcmp0(cmd, command->command_name) == 0) {
GList *command_hashes = g_hash_table_get_values(p_commands);
GList *curr_hash = command_hashes;
while (curr_hash) {
GHashTable *command_hash = curr_hash->data;
PluginCommand *command = g_hash_table_lookup(command_hash, cmd);
if (command) {
g_list_free(command_hashes);
return command->help;
}
curr = g_slist_next(curr);
curr_hash = g_list_next(curr_hash);
}
g_list_free(command_hashes);
return NULL;
}
@ -167,12 +246,22 @@ plugins_get_command_names(void)
{
GList *result = NULL;
GSList *curr = p_commands;
while (curr) {
PluginCommand *command = curr->data;
result = g_list_append(result, (char*)command->command_name);
curr = g_slist_next(curr);
GList *command_hashes = g_hash_table_get_values(p_commands);
GList *curr_hash = command_hashes;
while (curr_hash) {
GHashTable *command_hash = curr_hash->data;
GList *commands = g_hash_table_get_keys(command_hash);
GList *curr = commands;
while (curr) {
char *command = curr->data;
result = g_list_append(result, command);
curr = g_list_next(curr);
}
g_list_free(commands);
curr_hash = g_list_next(curr_hash);
}
g_list_free(command_hashes);
return result;
}

View File

@ -40,17 +40,19 @@
#include "command/cmd_defs.h"
typedef struct p_command {
const char *command_name;
char *command_name;
int min_args;
int max_args;
CommandHelp *help;
void *callback;
void (*callback_exec)(struct p_command *command, gchar **args);
void (*callback_destroy)(void *callback);
} PluginCommand;
typedef struct p_timed_function {
void *callback;
void (*callback_exec)(struct p_timed_function *timed_function);
void (*callback_destroy)(void *callback);
int interval_seconds;
GTimer *timer;
} PluginTimedFunction;
@ -64,7 +66,7 @@ typedef struct p_window_input_callback {
void callbacks_init(void);
void callbacks_close(void);
void callbacks_add_command(PluginCommand *command);
void callbacks_add_command(const char *const plugin, PluginCommand *command);
void callbacks_add_timed(PluginTimedFunction *timed_function);
void callbacks_add_window_handler(const char *tag, PluginWindowCallback *window_callback);
void * callbacks_get_window_handler(const char *tag);

View File

@ -166,19 +166,18 @@ python_api_register_command(PyObject *self, PyObject *args)
allow_python_threads();
api_register_command(plugin_name, command_name, min_args, max_args, c_synopsis,
description, c_arguments, c_examples, p_callback, python_command_callback);
description, c_arguments, c_examples, p_callback, python_command_callback, NULL);
disable_python_threads();
}
free(plugin_name);
return Py_BuildValue("");
}
static PyObject *
python_api_register_timed(PyObject *self, PyObject *args)
{
char *plugin_name = _python_plugin_name();
log_debug("Register timed for %s", plugin_name);
PyObject *p_callback = NULL;
int interval_seconds = 0;
@ -186,12 +185,17 @@ python_api_register_timed(PyObject *self, PyObject *args)
return Py_BuildValue("");
}
char *plugin_name = _python_plugin_name();
log_debug("Register timed for %s", plugin_name);
if (p_callback && PyCallable_Check(p_callback)) {
allow_python_threads();
api_register_timed(plugin_name, p_callback, interval_seconds, python_timed_callback);
api_register_timed(plugin_name, p_callback, interval_seconds, python_timed_callback, NULL);
disable_python_threads();
}
free(plugin_name);
return Py_BuildValue("");
}
@ -223,6 +227,8 @@ python_api_completer_add(PyObject *self, PyObject *args)
api_completer_add(plugin_name, key, c_items);
disable_python_threads();
free(plugin_name);
return Py_BuildValue("");
}
@ -456,19 +462,21 @@ python_api_win_create(PyObject *self, PyObject *args)
char *tag = NULL;
PyObject *p_callback = NULL;
char *plugin_name = _python_plugin_name();
log_debug("Win create %s for %s", tag, plugin_name);
if (!PyArg_ParseTuple(args, "sO", &tag, &p_callback)) {
return Py_BuildValue("");
}
char *plugin_name = _python_plugin_name();
log_debug("Win create %s for %s", tag, plugin_name);
if (p_callback && PyCallable_Check(p_callback)) {
allow_python_threads();
api_win_create(plugin_name, tag, p_callback, NULL, python_window_callback);
api_win_create(plugin_name, tag, p_callback, python_window_callback, NULL);
disable_python_threads();
}
free(plugin_name);
return Py_BuildValue("");
}

View File

@ -1230,7 +1230,7 @@ ui_handle_room_config_submit_result_error(const char *const roomjid, const char
}
void
ui_show_lines(ProfWin *window, const gchar** lines)
ui_show_lines(ProfWin *window, gchar** lines)
{
if (lines) {
int i;

View File

@ -110,7 +110,7 @@ void ui_goodbye_title(void);
void ui_handle_room_configuration_form_error(const char *const roomjid, const char *const message);
void ui_handle_room_config_submit_result(const char *const roomjid);
void ui_handle_room_config_submit_result_error(const char *const roomjid, const char *const message);
void ui_show_lines(ProfWin *window, const gchar** lines);
void ui_show_lines(ProfWin *window, gchar** lines);
void ui_redraw_all_room_rosters(void);
void ui_show_all_room_rosters(void);
void ui_hide_all_room_rosters(void);

View File

@ -0,0 +1,32 @@
#include <stdarg.h>
#include <stddef.h>
#include <setjmp.h>
#include <cmocka.h>
#include <stdlib.h>
#include <string.h>
#include <glib.h>
#include "plugins/callbacks.h"
#include "plugins/plugins.h"
void returns_no_commands(void **state)
{
callbacks_init();
GList *commands = plugins_get_command_names();
assert_true(commands == NULL);
}
void returns_commands(void **state)
{
callbacks_init();
PluginCommand *command = malloc(sizeof(PluginCommand));
command->command_name = strdup("something");
callbacks_add_command("Cool plugin", command);
GList *commands = plugins_get_command_names();
assert_true(g_list_length(commands) == 1);
char *name = commands->data;
assert_string_equal(name, "something");
}

View File

@ -0,0 +1,2 @@
void returns_no_commands(void **state);
void returns_commands(void **state);

View File

@ -265,7 +265,7 @@ void mucconfwin_show_form(ProfMucConfWin *confwin) {}
void mucconfwin_show_form_field(ProfMucConfWin *confwin, DataForm *form, char *tag) {}
void mucconfwin_form_help(ProfMucConfWin *confwin) {}
void mucconfwin_field_help(ProfMucConfWin *confwin, char *tag) {}
void ui_show_lines(ProfWin *window, const gchar** lines) {}
void ui_show_lines(ProfWin *window, gchar** lines) {}
void ui_redraw_all_room_rosters(void) {}
void ui_show_all_room_rosters(void) {}
void ui_hide_all_room_rosters(void) {}

View File

@ -33,6 +33,7 @@
#include "test_cmd_roster.h"
#include "test_cmd_disconnect.h"
#include "test_form.h"
#include "test_callbacks.h"
int main(int argc, char* argv[]) {
const UnitTest all_tests[] = {
@ -602,6 +603,9 @@ int main(int argc, char* argv[]) {
unit_test(prof_partial_occurrences_tests),
unit_test(prof_whole_occurrences_tests),
unit_test(returns_no_commands),
unit_test(returns_commands),
};
return run_tests(all_tests);