From 1d7903ae033eae21a5b2a6b13d247f0c56d25a18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C5=99emysl=20Janouch?= Date: Thu, 7 May 2015 06:37:50 +0200 Subject: [PATCH] degesch: implement some autocompletion --- degesch.c | 114 ++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 107 insertions(+), 7 deletions(-) diff --git a/degesch.c b/degesch.c index 1e82ee3..54f523e 100644 --- a/degesch.c +++ b/degesch.c @@ -5065,7 +5065,7 @@ completion_add_word (struct completion *self, size_t start, size_t end) self->words = xcalloc ((self->words_alloc = 4), sizeof *self->words); if (self->words_len == self->words_alloc) self->words = xrealloc (self->words, (self->words_alloc <<= 1)); - self->words[self->words_len] = (struct completion_word) { start, end }; + self->words[self->words_len++] = (struct completion_word) { start, end }; } static void @@ -5098,6 +5098,17 @@ completion_locate (struct completion *self, size_t offset) self->location = i - 1; } +static bool +completion_matches (struct completion *self, int word, const char *pattern) +{ + hard_assert (word >= 0 && word < (int) self->words_len); + char *text = xstrndup (self->line + self->words[word].start, + self->words[word].end - self->words[word].start); + bool result = !fnmatch (pattern, text, 0); + free (text); + return result; +} + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - struct utf8_iter @@ -5168,16 +5179,105 @@ utf8_common_prefix (const char **vector, size_t len) return prefix; } +static void +complete_command (struct app_context *ctx, struct completion *data, + const char *word, struct str_vector *output) +{ + (void) ctx; + (void) data; + + const char *prefix = ""; + if (*word == '/') + { + word++; + prefix = "/"; + } + + for (size_t i = 0; i < N_ELEMENTS (g_command_handlers); i++) + { + struct command_handler *handler = &g_command_handlers[i]; + // FIXME: we want an ASCII version + if (!strncasecmp (word, handler->name, strlen (word))) + str_vector_add_owned (output, + xstrdup_printf ("%s%s", prefix, handler->name)); + } +} + +static void +complete_option (struct app_context *ctx, struct completion *data, + const char *word, struct str_vector *output) +{ + (void) data; + + struct str_vector options; + str_vector_init (&options); + + // Wildcard expansion is an interesting side-effect + char *x = xstrdup_printf ("%s*", word); + dump_matching_options (ctx, x, &options); + free (x); + + str_vector_add_vector (output, options.vector); + str_vector_free (&options); +} + +static void +complete_nicknames (struct app_context *ctx, struct completion *data, + const char *word, struct str_vector *output) +{ + // TODO; if (data->location == 0) --> add colons to nicknames +} + static char ** complete_word (struct app_context *ctx, struct completion *data, const char *word) { - // TODO: return a list of matches with the longest common part - // (or a copy of "word" if none) as the first entry - // TODO: if there's only one match, don't bother computing the common part - char **result = xcalloc (2, sizeof *result); - result[0] = xstrdup_printf ("%shue", word); - return result; + // First figure out what exactly do we need to complete + bool try_commands = false; + bool try_options = false; + bool try_nicknames = false; + + if (data->location == 0 && completion_matches (data, 0, "/*")) + try_commands = true; + else if (data->location == 1 && completion_matches (data, 0, "/set")) + try_options = true; + else if (data->location == 1 && completion_matches (data, 0, "/help")) + try_commands = try_options = true; + else + try_nicknames = true; + + struct str_vector words; + str_vector_init (&words); + + // Add placeholder + str_vector_add_owned (&words, NULL); + + if (try_commands) complete_command (ctx, data, word, &words); + if (try_options) complete_option (ctx, data, word, &words); + if (try_nicknames) complete_nicknames (ctx, data, word, &words); + + if (words.len == 1) + { + // Nothing matched + str_vector_free (&words); + return NULL; + } + + if (words.len == 2) + { + words.vector[0] = words.vector[1]; + words.vector[1] = NULL; + } + else + { + size_t prefix = utf8_common_prefix + ((const char **) words.vector + 1, words.len - 1); + if (!prefix) + words.vector[0] = xstrdup (word); + else + words.vector[0] = xstrndup (words.vector[1], prefix); + } + return words.vector; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -