diff --git a/src/command/cmd_ac.c b/src/command/cmd_ac.c index 56baafc8..544719d4 100644 --- a/src/command/cmd_ac.c +++ b/src/command/cmd_ac.c @@ -184,6 +184,7 @@ static Autocomplete console_ac; static Autocomplete console_msg_ac; static Autocomplete autoping_ac; static Autocomplete plugins_ac; +static Autocomplete plugins_sourcepath_ac; static Autocomplete plugins_load_ac; static Autocomplete plugins_unload_ac; static Autocomplete plugins_reload_ac; @@ -714,6 +715,11 @@ cmd_ac_init(void) autocomplete_add(plugins_ac, "unload"); autocomplete_add(plugins_ac, "reload"); autocomplete_add(plugins_ac, "python_version"); + autocomplete_add(plugins_ac, "sourcepath"); + + plugins_sourcepath_ac = autocomplete_new(); + autocomplete_add(plugins_sourcepath_ac, "set"); + autocomplete_add(plugins_sourcepath_ac, "clear"); filepath_ac = autocomplete_new(); @@ -1011,6 +1017,7 @@ cmd_ac_reset(ProfWin *window) autocomplete_reset(console_msg_ac); autocomplete_reset(autoping_ac); autocomplete_reset(plugins_ac); + autocomplete_reset(plugins_sourcepath_ac); autocomplete_reset(blocked_ac); autocomplete_reset(tray_ac); autocomplete_reset(presence_ac); @@ -2025,10 +2032,21 @@ _plugins_autocomplete(ProfWin *window, const char *const input) { char *result = NULL; + if (strncmp(input, "/plugins sourcepath set ", 24) == 0) { + return cmd_ac_complete_filepath(input, "/plugins sourcepath set"); + } + if (strncmp(input, "/plugins install ", 17) == 0) { return cmd_ac_complete_filepath(input, "/plugins install"); } + if (strncmp(input, "/plugins sourcepath ", 20) == 0) { + result = autocomplete_param_with_ac(input, "/plugins sourcepath", plugins_sourcepath_ac, TRUE); + if (result) { + return result; + } + } + if (strncmp(input, "/plugins load ", 14) == 0) { if (plugins_load_ac == NULL) { plugins_load_ac = autocomplete_new(); diff --git a/src/command/cmd_defs.c b/src/command/cmd_defs.c index 2ca3b967..8f8ced09 100644 --- a/src/command/cmd_defs.c +++ b/src/command/cmd_defs.c @@ -2046,8 +2046,9 @@ static struct cmd_t command_defs[] = }, { "/plugins", - parse_args, 0, 2, NULL, + parse_args, 0, 3, NULL, CMD_SUBFUNCS( + { "sourcepath", cmd_plugins_sourcepath }, { "install", cmd_plugins_install }, { "load", cmd_plugins_load }, { "unload", cmd_plugins_unload }, @@ -2057,7 +2058,9 @@ static struct cmd_t command_defs[] = CMD_NOTAGS CMD_SYN( "/plugins", - "/plugins install ", + "/plugins sourcepath set ", + "/plugins sourcepath clear", + "/plugins install []", "/plugins unload []", "/plugins load []", "/plugins reload []", @@ -2065,12 +2068,16 @@ static struct cmd_t command_defs[] = CMD_DESC( "Manage plugins. Passing no arguments lists currently loaded plugins.") CMD_ARGS( - { "install ", "Install file to plugins directory, and load or reload the plugin." }, - { "load []", "Load a plugin that already exists in the plugin directory, passing no argument loads all found plugins." }, - { "unload []", "Unload a loaded plugin, passing no argument will unload all plugins." }, - { "reload []", "Reload a plugin, passing no argument will reload all plugins." }, - { "python_version", "Show the Python interpreter version." }) + { "sourcepath set ", "Set the default path to install plugins from, will be used if no arg is passed to /plugins install." }, + { "sourcepath clear", "Clear the default plugins source path." }, + { "install []", "Install a plugin, or all plugins found in a directory (recursive). Passing no argument will use the sourcepath if one is set." }, + { "load []", "Load a plugin that already exists in the plugin directory, passing no argument loads all found plugins." }, + { "unload []", "Unload a loaded plugin, passing no argument will unload all plugins." }, + { "reload []", "Reload a plugin, passing no argument will reload all plugins." }, + { "python_version", "Show the Python interpreter version." }) CMD_EXAMPLES( + "/plugins sourcepath set /home/meee/projects/profanity-plugins", + "/plugins install", "/plugins install /home/steveharris/Downloads/metal.py", "/plugins load browser.py", "/plugins unload say.py", diff --git a/src/command/cmd_funcs.c b/src/command/cmd_funcs.c index d26ff43f..3df17079 100644 --- a/src/command/cmd_funcs.c +++ b/src/command/cmd_funcs.c @@ -6211,17 +6211,70 @@ cmd_xa(ProfWin *window, const char *const command, gchar **args) return TRUE; } +gboolean +cmd_plugins_sourcepath(ProfWin *window, const char *const command, gchar **args) +{ + if (args[1] == NULL) { + char *sourcepath = prefs_get_string(PREF_PLUGINS_SOURCEPATH); + if (sourcepath) { + cons_show("Current plugins sourcepath: %s", sourcepath); + prefs_free_string(sourcepath); + } else { + cons_show("Plugins sourcepath not currently set."); + } + return TRUE; + } + + if (g_strcmp0(args[1], "clear") == 0) { + prefs_set_string(PREF_PLUGINS_SOURCEPATH, NULL); + cons_show("Plugins sourcepath cleared."); + return TRUE; + } + + if (g_strcmp0(args[1], "set") == 0) { + char *path = args[2]; + if (path == NULL) { + cons_bad_cmd_usage(command); + return TRUE; + } + + // expand ~ to $HOME + if (path[0] == '~' && path[1] == '/') { + if (asprintf(&path, "%s/%s", getenv("HOME"), path+2) == -1) { + return TRUE; + } + } else { + path = strdup(path); + } + + if (!is_dir(path)) { + cons_show("Plugins sourcepath must be a directory."); + return TRUE; + } + + cons_show("Setting plugins sourcepath: %s", path); + prefs_set_string(PREF_PLUGINS_SOURCEPATH, path); + return TRUE; + } + + cons_bad_cmd_usage(command); + return TRUE; +} + gboolean cmd_plugins_install(ProfWin *window, const char *const command, gchar **args) { char *path = args[1]; if (path == NULL) { - cons_bad_cmd_usage(command); - return TRUE; - } - - // expand ~ to $HOME - if (path[0] == '~' && path[1] == '/') { + char* sourcepath = prefs_get_string(PREF_PLUGINS_SOURCEPATH); + if (sourcepath) { + path = strdup(sourcepath); + prefs_free_string(sourcepath); + } else { + cons_show("Either a path must be provided or the sourcepath property must be set, see /help plugins"); + return TRUE; + } + } else if (path[0] == '~' && path[1] == '/') { if (asprintf(&path, "%s/%s", getenv("HOME"), path+2) == -1) { return TRUE; } diff --git a/src/command/cmd_funcs.h b/src/command/cmd_funcs.h index c7a89e43..2f0e0bac 100644 --- a/src/command/cmd_funcs.h +++ b/src/command/cmd_funcs.h @@ -160,6 +160,7 @@ gboolean cmd_charset(ProfWin *window, const char *const command, gchar **args); gboolean cmd_console(ProfWin *window, const char *const command, gchar **args); gboolean cmd_plugins(ProfWin *window, const char *const command, gchar **args); +gboolean cmd_plugins_sourcepath(ProfWin *window, const char *const command, gchar **args); gboolean cmd_plugins_install(ProfWin *window, const char *const command, gchar **args); gboolean cmd_plugins_load(ProfWin *window, const char *const command, gchar **args); gboolean cmd_plugins_unload(ProfWin *window, const char *const command, gchar **args); diff --git a/src/config/preferences.c b/src/config/preferences.c index f759da35..6dc8ef32 100644 --- a/src/config/preferences.c +++ b/src/config/preferences.c @@ -59,6 +59,7 @@ #define PREF_GROUP_OTR "otr" #define PREF_GROUP_PGP "pgp" #define PREF_GROUP_MUC "muc" +#define PREF_GROUP_PLUGINS "plugins" #define INPBLOCK_DEFAULT 1000 @@ -665,27 +666,27 @@ prefs_get_tray_timer(void) gchar** prefs_get_plugins(void) { - if (!g_key_file_has_group(prefs, "plugins")) { + if (!g_key_file_has_group(prefs, PREF_GROUP_PLUGINS)) { return NULL; } - if (!g_key_file_has_key(prefs, "plugins", "load", NULL)) { + if (!g_key_file_has_key(prefs, PREF_GROUP_PLUGINS, "load", NULL)) { return NULL; } - return g_key_file_get_string_list(prefs, "plugins", "load", NULL, NULL); + return g_key_file_get_string_list(prefs, PREF_GROUP_PLUGINS, "load", NULL, NULL); } void prefs_add_plugin(const char *const name) { - conf_string_list_add(prefs, "plugins", "load", name); + conf_string_list_add(prefs, PREF_GROUP_PLUGINS, "load", name); _save_prefs(); } void prefs_remove_plugin(const char *const name) { - conf_string_list_remove(prefs, "plugins", "load", name); + conf_string_list_remove(prefs, PREF_GROUP_PLUGINS, "load", name); _save_prefs(); } @@ -1614,6 +1615,8 @@ _get_group(preference_t pref) return PREF_GROUP_PGP; case PREF_BOOKMARK_INVITE: return PREF_GROUP_MUC; + case PREF_PLUGINS_SOURCEPATH: + return PREF_GROUP_PLUGINS; default: return NULL; } @@ -1814,6 +1817,8 @@ _get_key(preference_t pref) return "console.chat"; case PREF_BOOKMARK_INVITE: return "bookmark.invite"; + case PREF_PLUGINS_SOURCEPATH: + return "sourcepath"; default: return NULL; } diff --git a/src/config/preferences.h b/src/config/preferences.h index dbc74148..cc605c79 100644 --- a/src/config/preferences.h +++ b/src/config/preferences.h @@ -141,6 +141,7 @@ typedef enum { PREF_CONSOLE_PRIVATE, PREF_CONSOLE_CHAT, PREF_BOOKMARK_INVITE, + PREF_PLUGINS_SOURCEPATH, } preference_t; typedef struct prof_alias_t {