From 7e667a802811fc0e7ea25d7a3432d2ecf60956c5 Mon Sep 17 00:00:00 2001 From: Jfreegman Date: Fri, 18 Jul 2014 12:42:53 -0400 Subject: [PATCH] print multiple matches for all tab-complete operations, fix bug when tab-completing at end of line --- src/autocomplete.c | 55 ++++++++++++++++++++++++---------------------- src/autocomplete.h | 12 +++++----- src/chat.c | 8 ++++--- src/groupchat.c | 10 ++++----- src/prompt.c | 8 +++---- 5 files changed, 47 insertions(+), 46 deletions(-) diff --git a/src/autocomplete.c b/src/autocomplete.c index 51e7476..e986e97 100644 --- a/src/autocomplete.c +++ b/src/autocomplete.c @@ -36,9 +36,23 @@ #include "line_info.h" #include "execute.h" +static void print_matches(ToxWindow *self, Tox *m, const void *list, int n_items, int size) +{ + if (m) + execute(self->chatwin->history, self, m, "/clear", GLOBAL_COMMAND_MODE); + + const char *L = (char *) list; + int i; + + for (i = 0; i < n_items; ++i) + line_info_add(self, NULL, NULL, NULL, &L[i * size], SYS_MSG, 0, 0); + + line_info_add(self, NULL, NULL, NULL, "", SYS_MSG, 0, 0); /* formatting */ +} + /* puts match in match buffer. if more than one match, add first n chars that are identical. e.g. if matches contains: [foo, foobar, foe] we put fo in matches. */ -static void get_str_match(char *match, char (*matches)[MAX_STR_SIZE], int n) +static void get_str_match(ToxWindow *self, char *match, char (*matches)[MAX_STR_SIZE], int n) { if (n == 1) { strcpy(match, matches[0]); @@ -46,16 +60,8 @@ static void get_str_match(char *match, char (*matches)[MAX_STR_SIZE], int n) } int i; - int shortest = MAX_STR_SIZE; - for (i = 0; i < n; ++i) { - int m_len = strlen(matches[i]); - - if (m_len < shortest) - shortest = m_len; - } - - for (i = 0; i < shortest; ++i) { + for (i = 0; i < MAX_STR_SIZE; ++i) { char ch = matches[0][i]; int j; @@ -71,21 +77,22 @@ static void get_str_match(char *match, char (*matches)[MAX_STR_SIZE], int n) strcpy(match, matches[0]); } -/* looks for the first instance in list that begins with the last entered word in line according to pos, +/* looks for all instances in list that begin with the last entered word in line according to pos, then fills line with the complete word. e.g. "Hello jo" would complete the line - with "Hello john". Works slightly differently for directory paths with the same results. + with "Hello john". If multiple matches, prints out all the matches and semi-completes line. list is a pointer to the list of strings being compared, n_items is the number of items in the list, and size is the size of each item in the list. Returns the difference between the old len and new len of line on success, -1 if error */ -int complete_line(ChatContext *ctx, const void *list, int n_items, int size) +int complete_line(ToxWindow *self, const void *list, int n_items, int size) { + ChatContext *ctx = self->chatwin; + if (ctx->pos <= 0 || ctx->len <= 0 || ctx->len >= MAX_STR_SIZE || size > MAX_STR_SIZE) return -1; const char *L = (char *) list; - const char *endchrs = " "; char ubuf[MAX_STR_SIZE]; @@ -147,8 +154,11 @@ int complete_line(ChatContext *ctx, const void *list, int n_items, int size) if (!n_matches) return -1; - char match[size]; - get_str_match(match, matches, n_matches); + if (!dir_search && n_matches > 1) + print_matches(self, NULL, matches, n_matches, MAX_STR_SIZE); + + char match[MAX_STR_SIZE]; + get_str_match(self, match, matches, n_matches); if (dir_search) { if (n_matches == 1) @@ -191,7 +201,6 @@ int complete_line(ChatContext *ctx, const void *list, int n_items, int size) /* matches /sendfile "" line to matching directories. if only one match, auto-complete line. - if > 1 match, print out all the matches and partially complete line return diff between old len and new len of ctx->line, or -1 if no matches */ #define MAX_DIRS 256 @@ -237,14 +246,8 @@ int dir_match(ToxWindow *self, Tox *m, const wchar_t *line) if (dircount == 0) return -1; - if (dircount > 1) { - execute(self->chatwin->history, self, m, "/clear", GLOBAL_COMMAND_MODE); + if (dircount > 1) + print_matches(self, m, dirnames, dircount, NAME_MAX); - int i; - - for (i = 0; i < dircount; ++i) - line_info_add(self, NULL, NULL, NULL, dirnames[i], SYS_MSG, 0, 0); - } - - return complete_line(self->chatwin, dirnames, dircount, NAME_MAX); + return complete_line(self, dirnames, dircount, NAME_MAX); } diff --git a/src/autocomplete.h b/src/autocomplete.h index b97d8dc..a9f6f18 100644 --- a/src/autocomplete.h +++ b/src/autocomplete.h @@ -23,21 +23,21 @@ #ifndef _autocomplete_h #define _autocomplete_h -/* looks for the first instance in list that begins with the last entered word in line according to pos, +/* looks for all instances in list that begin with the last entered word in line according to pos, then fills line with the complete word. e.g. "Hello jo" would complete the line - with "Hello john". Works slightly differently for directory paths with the same results. + with "Hello john". If multiple matches, prints out all the matches and semi-completes line. list is a pointer to the list of strings being compared, n_items is the number of items in the list, and size is the size of each item in the list. Returns the difference between the old len and new len of line on success, -1 if error */ -int complete_line(ChatContext *ctx, const void *list, int n_items, int size); +int complete_line(ToxWindow *self, const void *list, int n_items, int size); /* matches /sendfile "" line to matching directories. - if only one match, auto-complete line and return diff between old len and new len. - return 0 if > 1 match and print out all the matches - return -1 if no matches */ + if only one match, auto-complete line. + return diff between old len and new len of ctx->line, or -1 if no matches +*/ int dir_match(ToxWindow *self, Tox *m, const wchar_t *line); #endif /* #define _autocomplete_h */ \ No newline at end of file diff --git a/src/chat.c b/src/chat.c index b85971d..2e981c2 100644 --- a/src/chat.c +++ b/src/chat.c @@ -693,12 +693,14 @@ static void chat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr) if (wcsncmp(ctx->line, L"/sendfile \"", sf_len) == 0) { diff = dir_match(self, m, &ctx->line[sf_len]); } else { - diff = complete_line(ctx, chat_cmd_list, AC_NUM_CHAT_COMMANDS, MAX_CMDNAME_SIZE); + diff = complete_line(self, chat_cmd_list, AC_NUM_CHAT_COMMANDS, MAX_CMDNAME_SIZE); } if (diff != -1) { - if (x + diff > x2 - 1) - ctx->start += diff; + if (x + diff > x2 - 1) { + int wlen = wcswidth(ctx->line, sizeof(ctx->line)); + ctx->start = wlen < x2 ? 0 : wlen - x2 + 1; + } } else { beep(); } diff --git a/src/groupchat.c b/src/groupchat.c index c501f3d..5fc8f6b 100644 --- a/src/groupchat.c +++ b/src/groupchat.c @@ -366,17 +366,15 @@ static void groupchat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr) int diff; if ((ctx->line[0] != '/') || (ctx->line[1] == 'm' && ctx->line[2] == 'e')) - diff = complete_line(ctx, groupchats[self->num].peer_names, + diff = complete_line(self, groupchats[self->num].peer_names, groupchats[self->num].num_peers, TOX_MAX_NAME_LENGTH); else - diff = complete_line(ctx, glob_cmd_list, AC_NUM_GLOB_COMMANDS, MAX_CMDNAME_SIZE); + diff = complete_line(self, glob_cmd_list, AC_NUM_GLOB_COMMANDS, MAX_CMDNAME_SIZE); if (diff != -1) { if (x + diff > x2 - 1) { - wmove(self->window, y, x + diff); - ctx->start += diff; - } else { - wmove(self->window, y, x + diff); + int wlen = wcswidth(ctx->line, sizeof(ctx->line)); + ctx->start = wlen < x2 ? 0 : wlen - x2 + 1; } } else { beep(); diff --git a/src/prompt.c b/src/prompt.c index 0989152..e986052 100644 --- a/src/prompt.c +++ b/src/prompt.c @@ -177,14 +177,12 @@ static void prompt_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr) if (key == '\t') { /* TAB key: auto-completes command */ if (ctx->len > 1 && ctx->line[0] == '/') { - int diff = complete_line(ctx, glob_cmd_list, AC_NUM_GLOB_COMMANDS, MAX_CMDNAME_SIZE); + int diff = complete_line(self, glob_cmd_list, AC_NUM_GLOB_COMMANDS, MAX_CMDNAME_SIZE); if (diff != -1) { if (x + diff > x2 - 1) { - wmove(self->window, y, x + diff); - ctx->start += diff; - } else { - wmove(self->window, y, x + diff); + int wlen = wcswidth(ctx->line, sizeof(ctx->line)); + ctx->start = wlen < x2 ? 0 : wlen - x2 + 1; } } else { beep();