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,
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 */
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,
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,
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) \
}
}
+/**
+ * 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.
*
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);