aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPřemysl Eric Janouch <p@janouch.name>2020-10-31 23:06:43 +0100
committerPřemysl Eric Janouch <p@janouch.name>2020-10-31 23:18:31 +0100
commit821ce04915fa7f42fee77f626685ab983387073b (patch)
tree281807136e2e0f407fc035414438a3f30b06f134
parent2fe3b95ecd21cdd1991d3d5ab3aa989531be2cf2 (diff)
downloadxK-821ce04915fa7f42fee77f626685ab983387073b.tar.gz
xK-821ce04915fa7f42fee77f626685ab983387073b.tar.xz
xK-821ce04915fa7f42fee77f626685ab983387073b.zip
degesch: implement autocompletion for /set
It was super annoying to just slightly modify strings and string arrays, now you can have existing values filled in. complete_word() looks a bit cleaner now as well.
-rw-r--r--degesch.c110
1 files changed, 82 insertions, 28 deletions
diff --git a/degesch.c b/degesch.c
index 4eeea23..8c035c6 100644
--- a/degesch.c
+++ b/degesch.c
@@ -12358,15 +12358,12 @@ completion_locate (struct completion *self, size_t offset)
self->location = i - 1;
}
-static bool
-completion_matches (struct completion *self, int word, const char *pattern)
+static char *
+completion_word (struct completion *self, int word)
{
hard_assert (word >= 0 && word < (int) self->words_len);
- char *text = xstrndup (self->line + self->words[word].start,
+ return 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;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@@ -12462,6 +12459,66 @@ complete_option (struct app_context *ctx, struct completion *data,
}
static void
+complete_set_value (struct config_item *item, const char *word,
+ struct strv *output)
+{
+ struct str serialized = str_make ();
+ config_item_write (item, false, &serialized);
+ if (!strncmp (serialized.str, word, strlen (word)))
+ strv_append_owned (output, str_steal (&serialized));
+ else
+ str_free (&serialized);
+}
+
+static void
+complete_set_value_array (struct config_item *item, const char *word,
+ struct strv *output)
+{
+ if (!item->schema || item->schema->type != CONFIG_ITEM_STRING_ARRAY)
+ return;
+
+ struct strv items = strv_make ();
+ cstr_split (item->value.string.str, ",", false, &items);
+ for (size_t i = 0; i < items.len; i++)
+ {
+ struct str wrapped = str_make (), serialized = str_make ();
+ str_append (&wrapped, items.vector[i]);
+ config_item_write_string (&serialized, &wrapped);
+ str_free (&wrapped);
+
+ if (!strncmp (serialized.str, word, strlen (word)))
+ strv_append_owned (output, str_steal (&serialized));
+ else
+ str_free (&serialized);
+ }
+ strv_free (&items);
+}
+
+static void
+complete_set (struct app_context *ctx, struct completion *data,
+ const char *word, struct strv *output)
+{
+ if (data->location == 1)
+ {
+ complete_option (ctx, data, word, output);
+ return;
+ }
+ if (data->location != 3)
+ return;
+
+ char *key = completion_word (data, 1);
+ struct config_item *item = config_item_get (ctx->config.root, key, NULL);
+ if (item)
+ {
+ char *op = completion_word (data, 2);
+ if (!strcmp (op, "-=")) complete_set_value_array (item, word, output);
+ if (!strcmp (op, "=")) complete_set_value (item, word, output);
+ free (op);
+ }
+ free (key);
+}
+
+static void
complete_topic (struct app_context *ctx, struct completion *data,
const char *word, struct strv *output)
{
@@ -12514,33 +12571,30 @@ static char **
complete_word (struct app_context *ctx, struct completion *data,
const char *word)
{
- // First figure out what exactly we need to complete
- bool try_commands = false;
- bool try_options = false;
- bool try_topic = 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 if (data->location == 1 && completion_matches (data, 0, "/topic"))
- try_topic = try_nicknames = true;
- else
- try_nicknames = true;
+ char *initial = completion_word (data, 0);
+ // Start with a placeholder for the longest common prefix
struct strv words = strv_make ();
-
- // Add placeholder
strv_append_owned (&words, NULL);
- if (try_commands) complete_command (ctx, data, word, &words);
- if (try_options) complete_option (ctx, data, word, &words);
- if (try_topic) complete_topic (ctx, data, word, &words);
- if (try_nicknames) complete_nicknames (ctx, data, word, &words);
+ if (data->location == 0 && *initial == '/')
+ complete_command (ctx, data, word, &words);
+ else if (data->location >= 1 && !strcmp (initial, "/set"))
+ complete_set (ctx, data, word, &words);
+ else if (data->location == 1 && !strcmp (initial, "/help"))
+ {
+ complete_command (ctx, data, word, &words);
+ complete_option (ctx, data, word, &words);
+ }
+ else if (data->location == 1 && !strcmp (initial, "/topic"))
+ {
+ complete_topic (ctx, data, word, &words);
+ complete_nicknames (ctx, data, word, &words);
+ }
+ else
+ complete_nicknames (ctx, data, word, &words);
+ cstr_set (&initial, NULL);
LIST_FOR_EACH (struct hook, iter, ctx->completion_hooks)
{
struct completion_hook *hook = (struct completion_hook *) iter;