aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPřemysl Janouch <p.janouch@gmail.com>2015-05-07 06:37:50 +0200
committerPřemysl Janouch <p.janouch@gmail.com>2015-05-07 06:37:50 +0200
commit1d7903ae033eae21a5b2a6b13d247f0c56d25a18 (patch)
tree93a3e170e74fea143829d02f17d8124c669318de
parent4ecf8d90dae5ce512aca6787289d5b4a19565c22 (diff)
downloadxK-1d7903ae033eae21a5b2a6b13d247f0c56d25a18.tar.gz
xK-1d7903ae033eae21a5b2a6b13d247f0c56d25a18.tar.xz
xK-1d7903ae033eae21a5b2a6b13d247f0c56d25a18.zip
degesch: implement some autocompletion
-rw-r--r--degesch.c114
1 files 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;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -