summaryrefslogtreecommitdiff
path: root/src/fe-common/core/completion.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/fe-common/core/completion.c')
-rw-r--r--src/fe-common/core/completion.c90
1 files changed, 63 insertions, 27 deletions
diff --git a/src/fe-common/core/completion.c b/src/fe-common/core/completion.c
index 31d62e10..914ba80b 100644
--- a/src/fe-common/core/completion.c
+++ b/src/fe-common/core/completion.c
@@ -37,8 +37,11 @@ static int last_want_space, last_line_pos;
#define isseparator_notspace(c) \
((c) == ',')
+#define isseparator_space(c) \
+ ((c) == ' ')
+
#define isseparator(c) \
- ((c) == ' ' || isseparator_notspace(c))
+ (isseparator_space(c) || isseparator_notspace(c))
void chat_completion_init(void);
void chat_completion_deinit(void);
@@ -51,7 +54,7 @@ static const char *completion_find(const char *key, int automatic)
if (node == NULL || node->type != NODE_TYPE_BLOCK)
return NULL;
- node = config_node_section(node, key, -1);
+ node = iconfig_node_section(node, key, -1);
if (node == NULL)
return NULL;
@@ -141,7 +144,7 @@ char *word_complete(WINDOW_REC *window, const char *line, int *pos, int erase, i
g_return_val_if_fail(pos != NULL, NULL);
continue_complete = complist != NULL && *pos == last_line_pos &&
- strcmp(line, last_line) == 0;
+ g_strcmp0(line, last_line) == 0;
if (erase && !continue_complete)
return NULL;
@@ -153,20 +156,23 @@ char *word_complete(WINDOW_REC *window, const char *line, int *pos, int erase, i
word = NULL;
linestart = NULL;
} else {
+ char* old_wordstart;
+
/* get the word we want to complete */
word = get_word_at(line, *pos, &wordstart);
+ old_wordstart = wordstart;
+
startpos = (int) (wordstart-line);
wordlen = strlen(word);
- /* get the start of line until the word we're completing */
- if (isseparator(*line)) {
- /* empty space at the start of line */
- if (wordstart == line)
- wordstart += strlen(wordstart);
- } else {
- while (wordstart > line && isseparator(wordstart[-1]))
- wordstart--;
- }
+ /* remove trailing spaces from linestart */
+ while (wordstart > line && isseparator_space(wordstart[-1]))
+ wordstart--;
+
+ /* unless everything was spaces */
+ if (old_wordstart > line && wordstart == line)
+ wordstart = old_wordstart - 1;
+
linestart = g_strndup(line, (int) (wordstart-line));
/* completions usually add space after the word, that makes
@@ -175,19 +181,24 @@ char *word_complete(WINDOW_REC *window, const char *line, int *pos, int erase, i
BUT if we start completion with "/msg "<tab>, we don't
want to complete the /msg word, but instead complete empty
word with /msg being in linestart. */
- if (!erase && *pos > 0 && line[*pos-1] == ' ' &&
- (*linestart == '\0' || wordstart[-1] != ' ')) {
+ if (!erase && *pos > 0 && isseparator_space(line[*pos-1]) &&
+ (*linestart == '\0' || !isseparator_space(wordstart[-1]))) {
char *old;
- old = linestart;
+ old = linestart;
linestart = *linestart == '\0' ?
g_strdup(word) :
- g_strconcat(linestart, " ", word, NULL);
+ g_strdup_printf("%s%c%s",
+ /* do not accidentally duplicate the word separator */
+ line == wordstart - 1 ? "" : linestart,
+ old_wordstart[-1], word);
g_free(old);
g_free(word);
word = g_strdup("");
- startpos = strlen(linestart)+1;
+
+ startpos = *linestart == '\0' ? 0 :
+ strlen(linestart)+1;
wordlen = 0;
}
@@ -217,6 +228,11 @@ char *word_complete(WINDOW_REC *window, const char *line, int *pos, int erase, i
want_space = TRUE;
signal_emit("complete word", 5, &complist, window, word, linestart, &want_space);
last_want_space = want_space;
+
+ if (complist != NULL) {
+ /* Remove all nulls (from the signal) before doing further processing */
+ complist = g_list_remove_all(g_list_first(complist), NULL);
+ }
}
g_free(linestart);
@@ -329,7 +345,9 @@ GList *filename_complete(const char *path, const char *default_path)
(dp->d_name[1] == '.' && dp->d_name[2] == '\0'))
continue; /* skip . and .. */
- if (basename[0] != '.')
+ /* Skip the dotfiles unless the user explicitly asked us
+ * to do so. Basename might be './', beware of that */
+ if (basename[0] != '.' || basename[1] == '\0')
continue;
}
@@ -362,8 +380,7 @@ static GList *completion_get_settings(const char *key, SettingType type)
for (tmp = sets; tmp != NULL; tmp = tmp->next) {
SETTINGS_REC *rec = tmp->data;
- if ((type == -1 || rec->type == type) &&
- g_ascii_strncasecmp(rec->key, key, len) == 0)
+ if ((type == SETTING_TYPE_ANY || rec->type == type) && g_ascii_strncasecmp(rec->key, key, len) == 0)
complist = g_list_insert_sorted(complist, g_strdup(rec->key), (GCompareFunc) g_istr_cmp);
}
g_slist_free(sets);
@@ -393,7 +410,8 @@ static GList *completion_get_aliases(const char *alias, char cmdchar)
continue;
if (g_ascii_strncasecmp(node->key, alias, len) == 0) {
- word = g_strdup_printf("%c%s", cmdchar, node->key);
+ word = cmdchar == '\0' ? g_strdup(node->key) :
+ g_strdup_printf("%c%s", cmdchar, node->key);
/* add matching alias to completion list, aliases will
be appended after command completions and kept in
uppercase to show it's an alias */
@@ -585,13 +603,19 @@ static void sig_complete_word(GList **list, WINDOW_REC *window,
/* command completion? */
cmdchars = settings_get_str("cmdchars");
- if (*word != '\0' && *linestart == '\0' && strchr(cmdchars, *word)) {
+ if (*word != '\0' && ((*linestart == '\0' && strchr(cmdchars, *word)) ||
+ (*linestart != '\0' && linestart[1] == '\0' &&
+ strchr(cmdchars, *linestart)))) {
+ gboolean skip = *linestart == '\0' ? TRUE : FALSE;
+
/* complete /command */
- *list = completion_get_commands(word+1, *word);
+ *list = completion_get_commands(word + (skip ? 1 : 0),
+ skip ? *word : '\0');
/* complete aliases, too */
*list = g_list_concat(*list,
- completion_get_aliases(word+1, *word));
+ completion_get_aliases(word + (skip ? 1 : 0),
+ skip ? *word : '\0'));
if (*list != NULL) signal_stop();
return;
@@ -681,14 +705,26 @@ static void sig_complete_set(GList **list, WINDOW_REC *window,
g_return_if_fail(line != NULL);
if (*line == '\0' ||
- !strcmp("-clear", line) || !strcmp("-default", line))
- *list = completion_get_settings(word, -1);
+ !g_strcmp0("-clear", line) || !g_strcmp0("-default", line))
+ *list = completion_get_settings(word, SETTING_TYPE_ANY);
else if (*line != '\0' && *word == '\0') {
SETTINGS_REC *rec = settings_get_record(line);
if (rec != NULL) {
char *value = settings_get_print(rec);
+
+ /* show the current option first */
if (value != NULL)
*list = g_list_append(*list, value);
+
+ /* show the whole list of valid options */
+ if (rec->type == SETTING_TYPE_CHOICE) {
+ char **tmp;
+
+ for (tmp = rec->choices; *tmp; tmp++) {
+ if (g_ascii_strcasecmp(*tmp, value) != 0)
+ *list = g_list_append(*list, g_strdup(*tmp));
+ }
+ }
}
}
@@ -785,7 +821,7 @@ static void cmd_completion(const char *data)
} else if (*key != '\0' && *value != '\0') {
int automatic = g_hash_table_lookup(optlist, "auto") != NULL;
- node = config_node_section(node, key, NODE_TYPE_BLOCK);
+ node = iconfig_node_section(node, key, NODE_TYPE_BLOCK);
iconfig_node_set_str(node, "value", value);
if (automatic)
iconfig_node_set_bool(node, "auto", TRUE);