diff options
author | Přemysl Janouch <p.janouch@gmail.com> | 2015-05-07 06:37:50 +0200 |
---|---|---|
committer | Přemysl Janouch <p.janouch@gmail.com> | 2015-05-07 06:37:50 +0200 |
commit | 1d7903ae033eae21a5b2a6b13d247f0c56d25a18 (patch) | |
tree | 93a3e170e74fea143829d02f17d8124c669318de | |
parent | 4ecf8d90dae5ce512aca6787289d5b4a19565c22 (diff) | |
download | xK-1d7903ae033eae21a5b2a6b13d247f0c56d25a18.tar.gz xK-1d7903ae033eae21a5b2a6b13d247f0c56d25a18.tar.xz xK-1d7903ae033eae21a5b2a6b13d247f0c56d25a18.zip |
degesch: implement some autocompletion
-rw-r--r-- | degesch.c | 114 |
1 files changed, 107 insertions, 7 deletions
@@ -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; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |