]> git.tuebingen.mpg.de Git - paraslash.git/commitdiff
i9e: Introduce i9e_cword_is_option_arg().
authorAndre Noll <maan@tuebingen.mpg.de>
Sun, 6 Apr 2025 20:14:43 +0000 (22:14 +0200)
committerAndre Noll <maan@tuebingen.mpg.de>
Sun, 18 May 2025 17:19:02 +0000 (19:19 +0200)
Call the new function to complete --admissible, --sort and --listing-mode of
the ls subcommand and teach the touch completer to prevent filename completion
if a numerical argument is expected. The grab subcommand of para_audiod
also benefits from the new helper: para_audioc learned to complete the three
different grab modes.

Since --admissible expects a mood or playlist argument, factor out the code
from the select completer which returns the list of all moods and playlists
so that it can be called by the ls completer as well.

audioc.c
client.c
interactive.c
interactive.h

index 45b5e12c6eacfbea51803867db0b2ceece23c252..6b98de4f275ce9ba6e76b594a67771710ea192b1 100644 (file)
--- a/audioc.c
+++ b/audioc.c
@@ -138,6 +138,19 @@ static void grab_completer(struct i9e_completion_info *ci,
                struct i9e_completion_result *cr)
 {
        char * const opts[] = {LSG_AUDIOD_CMD_GRAB_OPTS, NULL};
+       int num = i9e_cword_is_option_arg(opts, ci);
+
+       if (num >= 0) {
+               const char *opt = opts[num];
+               if (!strcmp(opt, "-m=") || !strcmp(opt, "--mode=")) {
+                       cr->matches = arr_alloc(4, sizeof(char *));
+                       cr->matches[0] = make_message("%ss", opt);
+                       cr->matches[1] = make_message("%sp", opt);
+                       cr->matches[2] = make_message("%sa", opt);
+                       cr->matches[3] = NULL;
+                       return;
+               }
+       }
        i9e_complete_option(opts, ci, cr);
 }
 
index a0def4aee25f2b043caab59e4a26cb0c8ec5f001..00902e3d6e5963dd29ff3f24febc723dfa4593ce 100644 (file)
--- a/client.c
+++ b/client.c
@@ -318,10 +318,79 @@ static void add_completer(struct i9e_completion_info *ci,
        cr->filename_completion_desired = true;
 }
 
+static void complete_mops(const char *word, const char *pfx, char ***matches)
+{
+       char *mood_buf, *pl_buf, **moods, **playlists;
+       char **mops;
+       int num_moods, num_pl, i, n, ret;
+
+       ret = execute_client_command("lsmood", &mood_buf);
+       if (ret < 0)
+               return;
+       ret = execute_client_command("lspl", &pl_buf);
+       if (ret < 0)
+               goto free_mood_buf;
+       ret = create_argv(mood_buf, "\n", &moods);
+       if (ret < 0)
+               goto free_pl_buf;
+       num_moods = ret;
+       ret = create_argv(pl_buf, "\n", &playlists);
+       if (ret < 0)
+               goto free_moods;
+       num_pl = ret;
+       n = num_moods + num_pl;
+       mops = arr_alloc(n + 1, sizeof(char *));
+       for (i = 0; i < num_moods; i++)
+               mops[i] = make_message("%sm/%s", pfx, moods[i]);
+       for (i = 0; i < num_pl; i++)
+               mops[num_moods + i] = make_message("%sp/%s", pfx, playlists[i]);
+       mops[n] = NULL;
+       i9e_extract_completions(word, mops, matches);
+       free_argv(mops);
+       free_argv(playlists);
+free_moods:
+       free_argv(moods);
+free_pl_buf:
+       free(pl_buf);
+free_mood_buf:
+       free(mood_buf);
+}
+
 static void ls_completer(struct i9e_completion_info *ci,
                struct i9e_completion_result *cr)
 {
        char * const opts[] = {LSG_SERVER_CMD_LS_OPTS, NULL};
+       int num = i9e_cword_is_option_arg(opts, ci);
+
+       if (num >= 0) {
+               const char *opt = opts[num];
+               if (!strcmp(opt, "-a=") || !strcmp(opt, "--admissible="))
+                       return complete_mops(ci->word, opt, &cr->matches);
+               if (!strcmp(opt, "-l=") || !strcmp(opt, "--listing-mode=")) {
+                       cr->matches = arr_alloc(5, sizeof(char *));
+                       cr->matches[0] = make_message("%ss", opt);
+                       cr->matches[1] = make_message("%sl", opt);
+                       cr->matches[2] = make_message("%sv", opt);
+                       cr->matches[3] = make_message("%sp", opt);
+                       cr->matches[4] = NULL;
+                       return;
+               }
+               if (!strcmp(opt, "-s=") || !strcmp(opt, "--sort=")) {
+                       cr->matches = arr_alloc(11, sizeof(char *));
+                       cr->matches[0] = make_message("%sl", opt);
+                       cr->matches[1] = make_message("%sn", opt);
+                       cr->matches[2] = make_message("%sf", opt);
+                       cr->matches[3] = make_message("%sc", opt);
+                       cr->matches[4] = make_message("%si", opt);
+                       cr->matches[5] = make_message("%sy", opt);
+                       cr->matches[6] = make_message("%sb", opt);
+                       cr->matches[7] = make_message("%sd", opt);
+                       cr->matches[8] = make_message("%sa", opt);
+                       cr->matches[9] = make_message("%sh", opt);
+                       cr->matches[10] = NULL;
+                       return;
+               }
+       }
        if (ci->word[0] == '-')
                i9e_complete_option(opts, ci, cr);
        cr->filename_completion_desired = true;
@@ -404,8 +473,10 @@ static void touch_completer(struct i9e_completion_info *ci,
 {
        char * const opts[] = {LSG_SERVER_CMD_TOUCH_OPTS, NULL};
 
+       if (i9e_cword_is_option_arg(opts, ci) >= 0)
+               return;
        if (ci->word[0] == '-')
-               i9e_complete_option(opts, ci, cr);
+               return i9e_complete_option(opts, ci, cr);
        cr->filename_completion_desired = true;
 }
 
@@ -423,42 +494,10 @@ static void select_completer(struct i9e_completion_info *ci,
                struct i9e_completion_result *cr)
 {
        char * const opts[] = {LSG_SERVER_CMD_SELECT_OPTS, NULL};
-       char *mood_buf, *pl_buf, **moods, **playlists, **mops;
-       int num_moods, num_pl, i, n, ret;
 
        if (ci->word[0] == '-')
                return i9e_complete_option(opts, ci, cr);
-       ret = execute_client_command("lsmood", &mood_buf);
-       if (ret < 0)
-               return;
-       ret = execute_client_command("lspl", &pl_buf);
-       if (ret < 0)
-               goto free_mood_buf;
-
-       ret = create_argv(mood_buf, "\n", &moods);
-       if (ret < 0)
-               goto free_pl_buf;
-       num_moods = ret;
-       ret = create_argv(pl_buf, "\n", &playlists);
-       if (ret < 0)
-               goto free_moods;
-       num_pl = ret;
-       n = num_moods + num_pl;
-       mops = arr_alloc(n + 1, sizeof(char *));
-       for (i = 0; i < num_moods; i++)
-               mops[i] = make_message("m/%s", moods[i]);
-       for (i = 0; i < num_pl; i++)
-               mops[num_moods + i] = make_message("p/%s", playlists[i]);
-       mops[n] = NULL;
-       i9e_extract_completions(ci->word, mops, &cr->matches);
-       free_argv(mops);
-       free_argv(playlists);
-free_moods:
-       free_argv(moods);
-free_pl_buf:
-       free(pl_buf);
-free_mood_buf:
-       free(mood_buf);
+       complete_mops(ci->word, "", &cr->matches);
 }
 
 #define DEFINE_BLOB_COMPLETER(cmd, blob_type) \
index 77f3fc609f6cef06db76b48568de14489c569553..0b1a978fe2d187daeefef641a320755f5025f05c 100644 (file)
@@ -720,6 +720,44 @@ void i9e_complete_option(char * const *opts,
        }
 }
 
+/**
+ * Find out whether the current word is an argument to an option.
+ *
+ * This handles both the --opt=arg and --opt arg syntax to specify option
+ * arguments.
+ *
+ * \param opts NULL-terminated array of short and long options.
+ * \param ci Provided by i9e in completion context.
+ *
+ * \return If the current word is an option argument, the function returns
+ * the index into the option array which corresponds to the matching option.
+ * Otherwise, -1 is returned.
+ */
+int i9e_cword_is_option_arg(char * const *opts, struct i9e_completion_info *ci)
+{
+       const char *prev;
+
+       /* Return -1 if cursor is at first word or if we've seen "--". */
+       if (ci->word_num == 0)
+               return -1;
+       for (unsigned n = 0; n < ci->word_num; n++)
+               if (!strcmp(ci->argv[n], "--"))
+                       return -1;
+       prev = ci->argv[ci->word_num - 1];
+       for (unsigned n = 0; opts[n]; n++) {
+               const char *opt = opts[n];
+               size_t len = strlen(opt);
+               assert(len > 0);
+               if (opt[len - 1] != '=')
+                       continue;
+               if (!strncmp(opt, ci->word, len))
+                       return n; /* --opt=arg */
+               if (!strncmp(opt, prev, len - 1) && prev[len - 1] == '\0')
+                       return n; /* --opt arg */
+       }
+       return -1;
+}
+
 /**
  * Print possible completions to stdout.
  *
index 7ab9778f89cab55bcf6eea16423d9d1ee6191ad2..6d84d226016441e371b8dc9334769bbfe303d3e6 100644 (file)
@@ -90,6 +90,7 @@ int i9e_extract_completions(const char *word, char * const *string_list,
 char **i9e_complete_commands(const char *word, struct i9e_completer *completers);
 void i9e_complete_option(char * const *opts,
                struct i9e_completion_info *ci, struct i9e_completion_result *cr);
+int i9e_cword_is_option_arg(char * const *opts, struct i9e_completion_info *ci);
 int i9e_print_completions(struct i9e_completer *completers);
 int i9e_get_error(void);
 void i9e_ll_completer(struct i9e_completion_info *ci,