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