degesch: implement some autocompletion
This commit is contained in:
parent
4ecf8d90da
commit
1d7903ae03
114
degesch.c
114
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;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
|
Loading…
Reference in New Issue