From 8fa6ca5e61a19e65f0b35c20a332b45e7dfce1a1 Mon Sep 17 00:00:00 2001 From: Timo Sirainen Date: Sat, 17 Jun 2000 15:58:40 +0000 Subject: [PATCH] File name completion for /DCC SEND git-svn-id: http://svn.irssi.org/repos/irssi/trunk@361 dbcabf3a-b0e7-0310-adc4-f8d773084564 --- src/core/commands.c | 15 ++++ src/core/commands.h | 2 + src/fe-common/core/completion.c | 116 +++++++++++++++++++++++++++-- src/fe-common/core/completion.h | 2 + src/fe-common/irc/dcc/fe-dcc.c | 21 ++++++ src/fe-common/irc/irc-completion.c | 7 +- 6 files changed, 153 insertions(+), 10 deletions(-) diff --git a/src/core/commands.c b/src/core/commands.c index 1b17ac4b..225f8213 100644 --- a/src/core/commands.c +++ b/src/core/commands.c @@ -115,6 +115,21 @@ void command_runsub(const char *cmd, const char *data, void *p1, void *p2) g_free(subcmd); } +COMMAND_REC *command_find(const char *command) +{ + GSList *tmp; + int len; + + for (tmp = commands; tmp != NULL; tmp = tmp->next) { + COMMAND_REC *rec = tmp->data; + + if (g_strcasecmp(rec->cmd, command) == 0) + return rec; + } + + return NULL; +} + char *cmd_get_param(char **data) { char *pos; diff --git a/src/core/commands.h b/src/core/commands.h index 74f66e45..42fb20c0 100644 --- a/src/core/commands.h +++ b/src/core/commands.h @@ -34,6 +34,8 @@ void command_unbind(const char *cmd, SIGNAL_FUNC func); void command_runsub(const char *cmd, const char *data, void *p1, void *p2); +COMMAND_REC *command_find(const char *command); + /* count can have these flags: */ #define PARAM_WITHOUT_FLAGS(a) ((a) & 0x00ffffff) /* don't check for quotes - "arg1 arg2" is NOT treated as one argument */ diff --git a/src/fe-common/core/completion.c b/src/fe-common/core/completion.c index 552d8642..2c46a010 100644 --- a/src/fe-common/core/completion.c +++ b/src/fe-common/core/completion.c @@ -35,6 +35,7 @@ static GList *complist; /* list of commands we're currently completing */ static char *last_linestart; +static int last_want_space; #define isseparator_notspace(c) \ ((c) == ',') @@ -113,7 +114,7 @@ char *word_complete(WINDOW_REC *window, const char *line, int *pos) { GString *result; char *word, *wordstart, *linestart, *ret; - int startpos, wordlen; + int startpos, wordlen, want_space; g_return_val_if_fail(line != NULL, NULL); g_return_val_if_fail(pos != NULL, NULL); @@ -132,12 +133,15 @@ char *word_complete(WINDOW_REC *window, const char *line, int *pos) /* complete from old list */ complist = complist->next != NULL ? complist->next : g_list_first(complist); + want_space = last_want_space; } else { /* get new completion list */ free_completions(); last_linestart = g_strdup(linestart); - signal_emit("word complete", 4, window, word, linestart, &complist); + want_space = TRUE; + signal_emit("word complete", 5, &complist, window, word, linestart, &want_space); + last_want_space = want_space; } if (complist == NULL) @@ -152,7 +156,7 @@ char *word_complete(WINDOW_REC *window, const char *line, int *pos) g_string_erase(result, startpos, wordlen); g_string_insert(result, startpos, complist->data); - if (!isseparator(result->str[*pos-1])) + if (want_space && !isseparator(result->str[*pos-1])) g_string_insert_c(result, *pos-1, ' '); ret = result->str; @@ -164,7 +168,51 @@ char *word_complete(WINDOW_REC *window, const char *line, int *pos) return ret; } -static int is_sub_command(const char *command) +GList *list_add_file(GList *list, const char *name) +{ + struct stat statbuf; + + if (stat(name, &statbuf) != 0) + return list; + + return g_list_append(list, !S_ISDIR(statbuf.st_mode) ? g_strdup(name) : + g_strconcat(name, G_DIR_SEPARATOR_S, NULL)); +} + +GList *filename_complete(const char *path) +{ + GList *list; + DIR *dirp; + struct dirent *dp; + char *realpath, *dir, *basename, *name; + int len; + + list = NULL; + + realpath = strncmp(path, "~/", 2) != 0 ? g_strdup(path) : + g_strconcat(g_get_home_dir(), path+1, NULL); + + dir = g_dirname(realpath); + dirp = opendir(dir); + + basename = g_basename(realpath); + len = strlen(basename); + + while ((dp = readdir(dirp)) != NULL) { + if (len == 0 || strncmp(dp->d_name, basename, len) == 0) { + name = g_strdup_printf("%s"G_DIR_SEPARATOR_S"%s", dir, dp->d_name); + list = list_add_file(list, name); + g_free(name); + } + } + closedir(dirp); + + g_free(realpath); + g_free(dir); + return list; +} + +static int is_base_command(const char *command) { GSList *tmp; int len; @@ -256,12 +304,50 @@ static GList *completion_get_subcommands(const char *cmd) return complist; } -static void sig_word_complete(WINDOW_REC *window, const char *word, - const char *linestart, GList **list) +/* split the line to command and arguments */ +static char *line_get_command(const char *line, char **args) +{ + const char *ptr, *cmdargs; + char *cmd, *checkcmd; + + cmd = checkcmd = NULL; + cmdargs = NULL; ptr = line; + + do { + ptr = strchr(ptr, ' '); + if (ptr == NULL) { + checkcmd = g_strdup(line); + cmdargs = ""; + } else { + checkcmd = g_strndup(line, (int) (ptr-line)); + + while (isspace(*ptr)) ptr++; + cmdargs = ptr; + } + + if (!command_find(checkcmd)) { + /* not found, use the previous */ + g_free(checkcmd); + break; + } + + /* found, check if it has subcommands */ + g_free_not_null(cmd); + cmd = checkcmd; + *args = (char *) cmdargs; + } while (ptr != NULL); + + return cmd; +} + +static void sig_word_complete(GList **list, WINDOW_REC *window, + const char *word, const char *linestart, int *want_space) { const char *newword, *cmdchars; + g_return_if_fail(list != NULL); g_return_if_fail(word != NULL); + g_return_if_fail(linestart != NULL); /* check against "completion words" list */ newword = completion_find(word); @@ -290,8 +376,8 @@ static void sig_word_complete(WINDOW_REC *window, const char *word, return; } - if (strchr(cmdchars, *linestart) && is_sub_command(linestart+1)) { - /* complete (/command's) subcommand */ + if (strchr(cmdchars, *linestart) && is_base_command(linestart+1)) { + /* complete /command's subcommand */ char *tmp; tmp = g_strconcat(linestart+1, " ", word, NULL); @@ -301,6 +387,20 @@ static void sig_word_complete(WINDOW_REC *window, const char *word, if (*list != NULL) signal_stop(); return; } + + if (strchr(cmdchars, *linestart)) { + /* complete /command's parameters */ + char *signal, *cmd, *args; + + cmd = line_get_command(linestart+1, &args); + if (cmd != NULL) { + signal = g_strconcat("command complete ", cmd, NULL); + signal_emit(signal, 5, list, window, word, args, want_space); + + g_free(signal); + g_free(cmd); + } + } } void completion_init(void) diff --git a/src/fe-common/core/completion.h b/src/fe-common/core/completion.h index 45ac1563..ef0fe06f 100644 --- a/src/fe-common/core/completion.h +++ b/src/fe-common/core/completion.h @@ -8,6 +8,8 @@ char *auto_word_complete(const char *line, int *pos); /* manual word completion - called when TAB is pressed */ char *word_complete(WINDOW_REC *window, const char *line, int *pos); +GList *filename_complete(const char *path); + void completion_init(void); void completion_deinit(void); diff --git a/src/fe-common/irc/dcc/fe-dcc.c b/src/fe-common/irc/dcc/fe-dcc.c index 077fb5f7..a4b902af 100644 --- a/src/fe-common/irc/dcc/fe-dcc.c +++ b/src/fe-common/irc/dcc/fe-dcc.c @@ -31,6 +31,7 @@ #include "irc/dcc/dcc.h" +#include "completion.h" #include "themes.h" #include "windows.h" @@ -405,6 +406,24 @@ static void cmd_dcc_list(const char *data) printformat(NULL, NULL, MSGLEVEL_DCC, IRCTXT_DCC_LIST_FOOTER); } +static void sig_dcc_send_complete(GList **list, WINDOW_REC *window, + const char *word, const char *line, int *want_space) +{ + g_return_if_fail(list != NULL); + g_return_if_fail(word != NULL); + g_return_if_fail(line != NULL); + + if (*line == '\0' || strchr(line, ' ') != NULL) + return; + + /* completing filename parameter for /DCC SEND */ + *list = filename_complete(word); + if (*list != NULL) { + *want_space = FALSE; + signal_stop(); + } +} + void fe_irc_dcc_init(void) { signal_add("dcc connected", (SIGNAL_FUNC) dcc_connected); @@ -425,6 +444,7 @@ void fe_irc_dcc_init(void) signal_add("dcc unknown reply", (SIGNAL_FUNC) dcc_unknown_reply); signal_add("dcc destroyed", (SIGNAL_FUNC) sig_dcc_destroyed); signal_add("query destroyed", (SIGNAL_FUNC) sig_query_destroyed); + signal_add("command complete dcc send", (SIGNAL_FUNC) sig_dcc_send_complete); command_bind("msg", NULL, (SIGNAL_FUNC) cmd_msg); command_bind("me", NULL, (SIGNAL_FUNC) cmd_me); command_bind("action", NULL, (SIGNAL_FUNC) cmd_action); @@ -457,6 +477,7 @@ void fe_irc_dcc_deinit(void) signal_remove("dcc unknown reply", (SIGNAL_FUNC) dcc_unknown_reply); signal_remove("dcc destroyed", (SIGNAL_FUNC) sig_dcc_destroyed); signal_remove("query destroyed", (SIGNAL_FUNC) sig_query_destroyed); + signal_remove("command complete dcc send", (SIGNAL_FUNC) sig_dcc_send_complete); command_unbind("msg", (SIGNAL_FUNC) cmd_msg); command_unbind("me", (SIGNAL_FUNC) cmd_me); command_unbind("action", (SIGNAL_FUNC) cmd_action); diff --git a/src/fe-common/irc/irc-completion.c b/src/fe-common/irc/irc-completion.c index 8422c981..39c67387 100644 --- a/src/fe-common/irc/irc-completion.c +++ b/src/fe-common/irc/irc-completion.c @@ -300,8 +300,8 @@ static GList *completion_joinlist(GList *list1, GList *list2) return list1; } -static void sig_word_complete(WINDOW_REC *window, const char *word, - const char *linestart, GList **list) +static void sig_word_complete(GList **list, WINDOW_REC *window, + const char *word, const char *linestart) { IRC_SERVER_REC *server; CHANNEL_REC *channel; @@ -309,7 +309,10 @@ static void sig_word_complete(WINDOW_REC *window, const char *word, const char *cmdchars, *nickprefix; char *prefix; + g_return_if_fail(list != NULL); + g_return_if_fail(window != NULL); g_return_if_fail(word != NULL); + g_return_if_fail(linestart != NULL); server = window->active_server; if (server == NULL || !server->connected)