]> git.tuebingen.mpg.de Git - paraslash.git/commitdiff
i9e: Introduce i9e_get_nonopt_argnum().
authorAndre Noll <maan@tuebingen.mpg.de>
Mon, 28 Apr 2025 14:37:14 +0000 (16:37 +0200)
committerAndre Noll <maan@tuebingen.mpg.de>
Sun, 18 May 2025 17:19:02 +0000 (19:19 +0200)
Call the new function from various subcommand completers to attempt completion
only on the first or the first two non-option arguments.

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

index 6b98de4f275ce9ba6e76b594a67771710ea192b1..1fa2d76c947bb88d9ccd35d09d03917b6113f47b 100644 (file)
--- a/audioc.c
+++ b/audioc.c
@@ -104,7 +104,8 @@ static void help_completer(struct i9e_completion_info *ci,
                i9e_complete_option(opts, ci, cr);
                return;
        }
-       cr->matches = i9e_complete_commands(ci->word, audiod_completers);
+       if (i9e_get_nonopt_argnum(opts, ci) == 1)
+               cr->matches = i9e_complete_commands(ci->word, audiod_completers);
 }
 
 static void ll_completer(struct i9e_completion_info *ci,
index 00902e3d6e5963dd29ff3f24febc723dfa4593ce..4ae60f23c45f34a8ec7c2132d423199612c78602 100644 (file)
--- a/client.c
+++ b/client.c
@@ -227,7 +227,9 @@ static void complete_mvblob(const char *blob_type,
                struct i9e_completion_info *ci,
                struct i9e_completion_result *cr)
 {
-       generic_blob_complete(blob_type, ci, cr);
+       unsigned num = i9e_get_nonopt_argnum(NULL, ci);
+       if (num == 1 || num == 2)
+               generic_blob_complete(blob_type, ci, cr);
 }
 
 /* these don't need any completions */
@@ -261,7 +263,8 @@ static void help_completer(struct i9e_completion_info *ci,
                i9e_complete_option(opts, ci, cr);
                return;
        }
-       cr->matches = i9e_complete_commands(ci->word, completers);
+       if (i9e_get_nonopt_argnum(opts, ci) == 1) /* arg #0 is "help" */
+               cr->matches = i9e_complete_commands(ci->word, completers);
 }
 
 static void stat_completer(struct i9e_completion_info *ci,
@@ -440,7 +443,9 @@ static void lsatt_completer(struct i9e_completion_info *ci,
 static void mvatt_completer(struct i9e_completion_info *ci,
                struct i9e_completion_result *cr)
 {
-       complete_attributes(ci->word, &cr->matches);
+       unsigned num = i9e_get_nonopt_argnum(NULL, ci);
+       if (num == 1 || num == 2)
+               complete_attributes(ci->word, &cr->matches);
 }
 
 static void rmatt_completer(struct i9e_completion_info *ci,
@@ -497,7 +502,8 @@ static void select_completer(struct i9e_completion_info *ci,
 
        if (ci->word[0] == '-')
                return i9e_complete_option(opts, ci, cr);
-       complete_mops(ci->word, "", &cr->matches);
+       if (i9e_get_nonopt_argnum(opts, ci) == 1) /* arg #0 is "select" */
+               complete_mops(ci->word, "", &cr->matches);
 }
 
 #define DEFINE_BLOB_COMPLETER(cmd, blob_type) \
index 0b1a978fe2d187daeefef641a320755f5025f05c..18f9eebd08ef17a475ff32cceb24e77f231892c9 100644 (file)
@@ -720,6 +720,77 @@ void i9e_complete_option(char * const *opts,
        }
 }
 
+/**
+ * Return the number of non-option arguments encountered so far.
+ *
+ * This counts the number of arguments up to the current word which are neither
+ * options nor arguments to options.
+ *
+ * \param opts NULL terminated array of short and long options, may be NULL.
+ * \param ci Provided by i9e in completion context.
+ *
+ * For convenience, NULL can be passed as the option array pointer to
+ * indicate that the subcommand has no options. In this case the function
+ * returns the word number stored in the completion info structure.
+ *
+ * \return Zero means that the cursor is positioned at the first non-option
+ * argument.
+ */
+unsigned i9e_get_nonopt_argnum(char * const *opts,
+               struct i9e_completion_info *ci)
+{
+       bool prev_is_option_with_arg = false;
+       unsigned num_non_option_args = 0;
+
+       if (!opts)
+               return ci->word_num;
+       for (unsigned n = 0; n < ci->word_num; n++) {
+               unsigned m;
+               const char *arg = ci->argv[n];
+
+               if (prev_is_option_with_arg) {
+                       prev_is_option_with_arg = false;
+                       continue;
+               }
+               if (!strcmp(arg, "--")) {
+                       prev_is_option_with_arg = false;
+                       continue;
+               }
+               if (arg[0] != '-') {
+                       num_non_option_args++;
+                       prev_is_option_with_arg = false;
+                       continue;
+               }
+               for (m = 0; opts[m]; m++) {
+                       const char *opt = opts[m];
+                       size_t len = strlen(opt);
+                       if (opt[len - 1] != '=') {
+                               if (strcmp(opt, arg))
+                                       continue;
+                               /* opt without arg */
+                               prev_is_option_with_arg = false;
+                               break;
+                       }
+                       if (strncmp(opt, arg, len - 1))
+                               continue;
+                       if (arg[len - 1] == '\0') { /* --opt-with-arg */
+                               prev_is_option_with_arg = true;
+                               break;
+                       }
+                       if (arg[len - 1] == '=') { /* --opt-with-arg= */
+                               prev_is_option_with_arg = false;
+                               break;
+                       }
+                       /* --opt-with-arg-garbage, no match */
+               }
+               if (!opts[m]) { /* no match */
+                       num_non_option_args++;
+                       prev_is_option_with_arg = false;
+               }
+       }
+       return num_non_option_args;
+}
+
 /**
  * Find out whether the current word is an argument to an option.
  *
index 6d84d226016441e371b8dc9334769bbfe303d3e6..95d1956006e7bafe5f440cd9b928ba140c2826ea 100644 (file)
@@ -90,6 +90,8 @@ 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);
+unsigned i9e_get_nonopt_argnum(char * const *opts,
+               struct i9e_completion_info *ci);
 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);