mirror of
https://github.com/profanity-im/profanity.git
synced 2024-11-03 19:37:16 -05:00
parent
d485588a07
commit
dcc2123ec4
@ -93,6 +93,13 @@ Remove all values from autocompletion for a command, or command argument.
|
||||
*/
|
||||
void prof_completer_clear(const char *key);
|
||||
|
||||
/**
|
||||
Add filepath autocompletion for a command, or command argument.
|
||||
|
||||
@param prefix the prefix from which filepath autocompletion will be triggered
|
||||
*/
|
||||
void prof_filepath_completer_add(const char *prefix);
|
||||
|
||||
/**
|
||||
Send a desktop notification.
|
||||
@param message the message to display in the notification
|
||||
|
@ -182,6 +182,20 @@ def completer_clear(key):
|
||||
pass
|
||||
|
||||
|
||||
def filepath_completer_add(prefix):
|
||||
"""Add filepath autocompletion for a command, or command argument.
|
||||
|
||||
:param prefix: the prefix from which filepath autocompletion will be triggered
|
||||
|
||||
Examples:
|
||||
::
|
||||
prof.filepath_completer_add("/filecmd")
|
||||
|
||||
prof.filepath_completer_add("/mycommand open")
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
def send_line(line):
|
||||
"""Send a line of input to Profanity to execute.
|
||||
|
||||
|
@ -57,8 +57,6 @@
|
||||
#include "pgp/gpg.h"
|
||||
#endif
|
||||
|
||||
static char* _complete_filepath(const char *const input, char *const startstr);
|
||||
|
||||
static char* _sub_autocomplete(ProfWin *window, const char *const input);
|
||||
static char* _notify_autocomplete(ProfWin *window, const char *const input);
|
||||
static char* _theme_autocomplete(ProfWin *window, const char *const input);
|
||||
@ -1140,6 +1138,113 @@ cmd_ac_uninit(void)
|
||||
autocomplete_free(winpos_ac);
|
||||
}
|
||||
|
||||
char*
|
||||
cmd_ac_complete_filepath(const char *const input, char *const startstr)
|
||||
{
|
||||
static char* last_directory = NULL;
|
||||
|
||||
unsigned int output_off = 0;
|
||||
|
||||
char *result = NULL;
|
||||
char *tmp;
|
||||
|
||||
// strip command
|
||||
char *inpcp = (char*)input + strlen(startstr);
|
||||
while (*inpcp == ' ') {
|
||||
inpcp++;
|
||||
}
|
||||
|
||||
inpcp = strdup(inpcp);
|
||||
|
||||
// strip quotes
|
||||
if (*inpcp == '"') {
|
||||
tmp = strchr(inpcp+1, '"');
|
||||
if (tmp) {
|
||||
*tmp = '\0';
|
||||
}
|
||||
tmp = strdup(inpcp+1);
|
||||
free(inpcp);
|
||||
inpcp = tmp;
|
||||
}
|
||||
|
||||
// expand ~ to $HOME
|
||||
if (inpcp[0] == '~' && inpcp[1] == '/') {
|
||||
if (asprintf(&tmp, "%s/%sfoo", getenv("HOME"), inpcp+2) == -1) {
|
||||
return NULL;
|
||||
}
|
||||
output_off = strlen(getenv("HOME"))+1;
|
||||
} else {
|
||||
if (asprintf(&tmp, "%sfoo", inpcp) == -1) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
free(inpcp);
|
||||
inpcp = tmp;
|
||||
|
||||
char* inpcp2 = strdup(inpcp);
|
||||
char* foofile = strdup(basename(inpcp2));
|
||||
char* directory = strdup(dirname(inpcp));
|
||||
free(inpcp);
|
||||
free(inpcp2);
|
||||
|
||||
if (!last_directory || strcmp(last_directory, directory) != 0) {
|
||||
free(last_directory);
|
||||
last_directory = directory;
|
||||
autocomplete_reset(filepath_ac);
|
||||
|
||||
struct dirent *dir;
|
||||
|
||||
DIR *d = opendir(directory);
|
||||
if (d) {
|
||||
while ((dir = readdir(d)) != NULL) {
|
||||
if (strcmp(dir->d_name, ".") == 0) {
|
||||
continue;
|
||||
} else if (strcmp(dir->d_name, "..") == 0) {
|
||||
continue;
|
||||
} else if (*(dir->d_name) == '.' && *foofile != '.') {
|
||||
// only show hidden files on explicit request
|
||||
continue;
|
||||
}
|
||||
char * acstring;
|
||||
if (output_off) {
|
||||
if (asprintf(&tmp, "%s/%s", directory, dir->d_name) == -1) {
|
||||
free(foofile);
|
||||
return NULL;
|
||||
}
|
||||
if (asprintf(&acstring, "~/%s", tmp+output_off) == -1) {
|
||||
free(foofile);
|
||||
return NULL;
|
||||
}
|
||||
free(tmp);
|
||||
} else if (strcmp(directory, "/") == 0) {
|
||||
if (asprintf(&acstring, "/%s", dir->d_name) == -1) {
|
||||
free(foofile);
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
if (asprintf(&acstring, "%s/%s", directory, dir->d_name) == -1) {
|
||||
free(foofile);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
autocomplete_add(filepath_ac, acstring);
|
||||
free(acstring);
|
||||
}
|
||||
closedir(d);
|
||||
}
|
||||
} else {
|
||||
free(directory);
|
||||
}
|
||||
free(foofile);
|
||||
|
||||
result = autocomplete_param_with_ac(input, startstr, filepath_ac, TRUE);
|
||||
if (result) {
|
||||
return result;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static char*
|
||||
_cmd_ac_complete_params(ProfWin *window, const char *const input)
|
||||
{
|
||||
@ -1918,7 +2023,7 @@ _plugins_autocomplete(ProfWin *window, const char *const input)
|
||||
char *result = NULL;
|
||||
|
||||
if (strncmp(input, "/plugins install ", 17) == 0) {
|
||||
return _complete_filepath(input, "/plugins install");
|
||||
return cmd_ac_complete_filepath(input, "/plugins install");
|
||||
}
|
||||
|
||||
if (strncmp(input, "/plugins load ", 14) == 0) {
|
||||
@ -2736,7 +2841,7 @@ _close_autocomplete(ProfWin *window, const char *const input)
|
||||
static char*
|
||||
_sendfile_autocomplete(ProfWin *window, const char *const input)
|
||||
{
|
||||
return _complete_filepath(input, "/sendfile");
|
||||
return cmd_ac_complete_filepath(input, "/sendfile");
|
||||
}
|
||||
|
||||
static char*
|
||||
@ -2945,109 +3050,3 @@ _presence_autocomplete(ProfWin *window, const char *const input)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static char*
|
||||
_complete_filepath(const char *const input, char *const startstr)
|
||||
{
|
||||
static char* last_directory = NULL;
|
||||
|
||||
unsigned int output_off = 0;
|
||||
|
||||
char *result = NULL;
|
||||
char *tmp;
|
||||
|
||||
// strip command
|
||||
char *inpcp = (char*)input + strlen(startstr);
|
||||
while (*inpcp == ' ') {
|
||||
inpcp++;
|
||||
}
|
||||
|
||||
inpcp = strdup(inpcp);
|
||||
|
||||
// strip quotes
|
||||
if (*inpcp == '"') {
|
||||
tmp = strchr(inpcp+1, '"');
|
||||
if (tmp) {
|
||||
*tmp = '\0';
|
||||
}
|
||||
tmp = strdup(inpcp+1);
|
||||
free(inpcp);
|
||||
inpcp = tmp;
|
||||
}
|
||||
|
||||
// expand ~ to $HOME
|
||||
if (inpcp[0] == '~' && inpcp[1] == '/') {
|
||||
if (asprintf(&tmp, "%s/%sfoo", getenv("HOME"), inpcp+2) == -1) {
|
||||
return NULL;
|
||||
}
|
||||
output_off = strlen(getenv("HOME"))+1;
|
||||
} else {
|
||||
if (asprintf(&tmp, "%sfoo", inpcp) == -1) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
free(inpcp);
|
||||
inpcp = tmp;
|
||||
|
||||
char* inpcp2 = strdup(inpcp);
|
||||
char* foofile = strdup(basename(inpcp2));
|
||||
char* directory = strdup(dirname(inpcp));
|
||||
free(inpcp);
|
||||
free(inpcp2);
|
||||
|
||||
if (!last_directory || strcmp(last_directory, directory) != 0) {
|
||||
free(last_directory);
|
||||
last_directory = directory;
|
||||
autocomplete_reset(filepath_ac);
|
||||
|
||||
struct dirent *dir;
|
||||
|
||||
DIR *d = opendir(directory);
|
||||
if (d) {
|
||||
while ((dir = readdir(d)) != NULL) {
|
||||
if (strcmp(dir->d_name, ".") == 0) {
|
||||
continue;
|
||||
} else if (strcmp(dir->d_name, "..") == 0) {
|
||||
continue;
|
||||
} else if (*(dir->d_name) == '.' && *foofile != '.') {
|
||||
// only show hidden files on explicit request
|
||||
continue;
|
||||
}
|
||||
char * acstring;
|
||||
if (output_off) {
|
||||
if (asprintf(&tmp, "%s/%s", directory, dir->d_name) == -1) {
|
||||
free(foofile);
|
||||
return NULL;
|
||||
}
|
||||
if (asprintf(&acstring, "~/%s", tmp+output_off) == -1) {
|
||||
free(foofile);
|
||||
return NULL;
|
||||
}
|
||||
free(tmp);
|
||||
} else if (strcmp(directory, "/") == 0) {
|
||||
if (asprintf(&acstring, "/%s", dir->d_name) == -1) {
|
||||
free(foofile);
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
if (asprintf(&acstring, "%s/%s", directory, dir->d_name) == -1) {
|
||||
free(foofile);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
autocomplete_add(filepath_ac, acstring);
|
||||
free(acstring);
|
||||
}
|
||||
closedir(d);
|
||||
}
|
||||
} else {
|
||||
free(directory);
|
||||
}
|
||||
free(foofile);
|
||||
|
||||
result = autocomplete_param_with_ac(input, startstr, filepath_ac, TRUE);
|
||||
if (result) {
|
||||
return result;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
@ -57,4 +57,6 @@ void cmd_ac_remove_alias_value(char *value);
|
||||
void cmd_ac_add_form_fields(DataForm *form);
|
||||
void cmd_ac_remove_form_fields(DataForm *form);
|
||||
|
||||
char* cmd_ac_complete_filepath(const char *const input, char *const startstr);
|
||||
|
||||
#endif
|
||||
|
@ -178,6 +178,12 @@ api_completer_clear(const char *const plugin_name, const char *key)
|
||||
autocompleters_clear(plugin_name, key);
|
||||
}
|
||||
|
||||
void
|
||||
api_filepath_completer_add(const char *const plugin_name, const char *prefix)
|
||||
{
|
||||
autocompleters_filepath_add(plugin_name, prefix);
|
||||
}
|
||||
|
||||
void
|
||||
api_notify(const char *message, const char *category, int timeout_ms)
|
||||
{
|
||||
|
@ -59,6 +59,7 @@ void api_register_timed(const char *const plugin_name, void *callback, int inter
|
||||
void api_completer_add(const char *const plugin_name, const char *key, char **items);
|
||||
void api_completer_remove(const char *const plugin_name, const char *key, char **items);
|
||||
void api_completer_clear(const char *const plugin_name, const char *key);
|
||||
void api_filepath_completer_add(const char *const plugin_name, const char *prefix);
|
||||
|
||||
void api_log_debug(const char *message);
|
||||
void api_log_info(const char *message);
|
||||
|
@ -37,8 +37,10 @@
|
||||
#include <glib.h>
|
||||
|
||||
#include "tools/autocomplete.h"
|
||||
#include "command/cmd_ac.h"
|
||||
|
||||
static GHashTable *plugin_to_acs;
|
||||
static GHashTable *plugin_to_filepath_acs;
|
||||
|
||||
static void
|
||||
_free_autocompleters(GHashTable *key_to_ac)
|
||||
@ -46,10 +48,17 @@ _free_autocompleters(GHashTable *key_to_ac)
|
||||
g_hash_table_destroy(key_to_ac);
|
||||
}
|
||||
|
||||
static void
|
||||
_free_filepath_autocompleters(GHashTable *prefixes)
|
||||
{
|
||||
g_hash_table_destroy(prefixes);
|
||||
}
|
||||
|
||||
void
|
||||
autocompleters_init(void)
|
||||
{
|
||||
plugin_to_acs = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, (GDestroyNotify)_free_autocompleters);
|
||||
plugin_to_filepath_acs = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, (GDestroyNotify)_free_filepath_autocompleters);
|
||||
}
|
||||
|
||||
void
|
||||
@ -106,7 +115,20 @@ autocompleters_clear(const char *const plugin_name, const char *key)
|
||||
autocomplete_clear(ac);
|
||||
}
|
||||
|
||||
char *
|
||||
void
|
||||
autocompleters_filepath_add(const char *const plugin_name, const char *prefix)
|
||||
{
|
||||
GHashTable *prefixes = g_hash_table_lookup(plugin_to_filepath_acs, plugin_name);
|
||||
if (prefixes) {
|
||||
g_hash_table_add(prefixes, strdup(prefix));
|
||||
} else {
|
||||
prefixes = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);
|
||||
g_hash_table_add(prefixes, strdup(prefix));
|
||||
g_hash_table_insert(plugin_to_filepath_acs, strdup(plugin_name), prefixes);
|
||||
}
|
||||
}
|
||||
|
||||
char*
|
||||
autocompleters_complete(const char * const input)
|
||||
{
|
||||
char *result = NULL;
|
||||
@ -121,6 +143,7 @@ autocompleters_complete(const char * const input)
|
||||
while (curr) {
|
||||
result = autocomplete_param_with_ac(input, curr->data, g_hash_table_lookup(key_to_ac, curr->data), TRUE);
|
||||
if (result) {
|
||||
g_list_free(ac_hashes);
|
||||
g_list_free(keys);
|
||||
return result;
|
||||
}
|
||||
@ -132,6 +155,31 @@ autocompleters_complete(const char * const input)
|
||||
}
|
||||
g_list_free(ac_hashes);
|
||||
|
||||
GList *filepath_hashes = g_hash_table_get_values(plugin_to_filepath_acs);
|
||||
curr_hash = filepath_hashes;
|
||||
while (curr_hash) {
|
||||
GHashTable *prefixes_hash = curr_hash->data;
|
||||
GList *prefixes = g_hash_table_get_keys(prefixes_hash);
|
||||
GList *curr_prefix = prefixes;
|
||||
while (curr_prefix) {
|
||||
char *prefix = curr_prefix->data;
|
||||
if (g_str_has_prefix(input, prefix)) {
|
||||
result = cmd_ac_complete_filepath(input, prefix);
|
||||
if (result) {
|
||||
g_list_free(filepath_hashes);
|
||||
g_list_free(prefixes);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
curr_prefix = g_list_next(curr_prefix);
|
||||
}
|
||||
g_list_free(prefixes);
|
||||
|
||||
curr_hash = g_list_next(curr_hash);
|
||||
}
|
||||
g_list_free(filepath_hashes);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -41,6 +41,7 @@ void autocompleters_init(void);
|
||||
void autocompleters_add(const char *const plugin_name, const char *key, char **items);
|
||||
void autocompleters_remove(const char *const plugin_name, const char *key, char **items);
|
||||
void autocompleters_clear(const char *const plugin_name, const char *key);
|
||||
void autocompleters_filepath_add(const char *const plugin_name, const char *prefix);
|
||||
char* autocompleters_complete(const char * const input);
|
||||
void autocompleters_reset(void);
|
||||
void autocompleters_destroy(void);
|
||||
|
@ -142,6 +142,17 @@ c_api_completer_clear(const char *filename, const char *key)
|
||||
free(plugin_name);
|
||||
}
|
||||
|
||||
static void
|
||||
c_api_filepath_completer_add(const char *filename, const char *prefix)
|
||||
{
|
||||
char *plugin_name = _c_plugin_name(filename);
|
||||
log_debug("Filepath autocomplete added '%s' for %s", prefix, plugin_name);
|
||||
|
||||
api_filepath_completer_add(plugin_name, prefix);
|
||||
|
||||
free(plugin_name);
|
||||
}
|
||||
|
||||
static void
|
||||
c_api_notify(const char *message, int timeout_ms, const char *category)
|
||||
{
|
||||
@ -360,6 +371,7 @@ c_api_init(void)
|
||||
_prof_completer_add = c_api_completer_add;
|
||||
_prof_completer_remove = c_api_completer_remove;
|
||||
_prof_completer_clear = c_api_completer_clear;
|
||||
_prof_filepath_completer_add = c_api_filepath_completer_add;
|
||||
_prof_win_create = c_api_win_create;
|
||||
prof_notify = c_api_notify;
|
||||
prof_send_line = c_api_send_line;
|
||||
|
@ -51,6 +51,7 @@ void (*_prof_register_timed)(const char *filename, TIMED_CB callback, int interv
|
||||
void (*_prof_completer_add)(const char *filename, const char *key, char **items) = NULL;
|
||||
void (*_prof_completer_remove)(const char *filename, const char *key, char **items) = NULL;
|
||||
void (*_prof_completer_clear)(const char *filename, const char *key) = NULL;
|
||||
void (*_prof_filepath_completer_add)(const char *filename, const char *prefix) = NULL;
|
||||
|
||||
void (*prof_notify)(const char *message, int timeout_ms, const char *category) = NULL;
|
||||
|
||||
|
@ -40,6 +40,7 @@
|
||||
#define prof_completer_add(key, items) _prof_completer_add(__FILE__, key, items)
|
||||
#define prof_completer_remove(key, items) _prof_completer_remove(__FILE__, key, items)
|
||||
#define prof_completer_clear(key) _prof_completer_clear(__FILE__, key)
|
||||
#define prof_filepath_completer_add(prefix) _prof_filepath_completer_add(__FILE__, prefix)
|
||||
#define prof_win_create(win, input_handler) _prof_win_create(__FILE__, win, input_handler)
|
||||
#define prof_disco_add_feature(feature) _prof_disco_add_feature(__FILE__, feature)
|
||||
|
||||
@ -62,6 +63,7 @@ void (*_prof_register_timed)(const char *filename, TIMED_CB callback, int interv
|
||||
void (*_prof_completer_add)(const char *filename, const char *key, char **items);
|
||||
void (*_prof_completer_remove)(const char *filename, const char *key, char **items);
|
||||
void (*_prof_completer_clear)(const char *filename, const char *key);
|
||||
void (*_prof_filepath_completer_add)(const char *filename, const char *prefix);
|
||||
|
||||
void (*prof_notify)(const char *message, int timeout_ms, const char *category);
|
||||
|
||||
|
@ -339,6 +339,30 @@ python_api_completer_clear(PyObject *self, PyObject *args)
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
static PyObject*
|
||||
python_api_filepath_completer_add(PyObject *self, PyObject *args)
|
||||
{
|
||||
PyObject *prefix = NULL;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "O", &prefix)) {
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
char *prefix_str = python_str_or_unicode_to_string(prefix);
|
||||
|
||||
char *plugin_name = _python_plugin_name();
|
||||
log_debug("Filepath autocomplete added '%s' for %s", prefix_str, plugin_name);
|
||||
|
||||
allow_python_threads();
|
||||
api_filepath_completer_add(plugin_name, prefix_str);
|
||||
free(prefix_str);
|
||||
disable_python_threads();
|
||||
|
||||
free(plugin_name);
|
||||
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
static PyObject*
|
||||
python_api_notify(PyObject *self, PyObject *args)
|
||||
{
|
||||
@ -1063,6 +1087,7 @@ static PyMethodDef apiMethods[] = {
|
||||
{ "completer_add", python_api_completer_add, METH_VARARGS, "Add items to an autocompleter." },
|
||||
{ "completer_remove", python_api_completer_remove, METH_VARARGS, "Remove items from an autocompleter." },
|
||||
{ "completer_clear", python_api_completer_clear, METH_VARARGS, "Remove all items from an autocompleter." },
|
||||
{ "filepath_completer_add", python_api_filepath_completer_add, METH_VARARGS, "Add filepath autocompleter" },
|
||||
{ "send_line", python_api_send_line, METH_VARARGS, "Send a line of input." },
|
||||
{ "notify", python_api_notify, METH_VARARGS, "Send desktop notification." },
|
||||
{ "get_current_recipient", python_api_get_current_recipient, METH_VARARGS, "Return the jid of the recipient of the current window." },
|
||||
|
Loading…
Reference in New Issue
Block a user