diff --git a/src/completion.c b/src/completion.c index 48cd08fc..d90ed17f 100644 --- a/src/completion.c +++ b/src/completion.c @@ -161,7 +161,12 @@ gboolean completion_create(GtkTreeModel *model, CompletionSelectFunc selfunc, return true; } -void completion_next(gboolean back) +/** + * Moves the selection to the next/previous tree item. + * If the end/beginning is reached return false and start on the opposite end + * on the next call. + */ +gboolean completion_next(gboolean back) { int rows; GtkTreePath *path; @@ -171,12 +176,22 @@ void completion_next(gboolean back) if (back) { /* step back */ if (--comp.active < 0) { - comp.active = rows - 1; + if (comp.active == -1) { + gtk_tree_selection_unselect_all(gtk_tree_view_get_selection(GTK_TREE_VIEW(comp.tree))); + return false; + } else { + comp.active = rows - 1; + } } } else { /* step forward */ if (++comp.active >= rows) { - comp.active = 0; + if (comp.active == rows) { + gtk_tree_selection_unselect_all(gtk_tree_view_get_selection(GTK_TREE_VIEW(comp.tree))); + return false; + } else { + comp.active = 0; + } } } @@ -184,6 +199,8 @@ void completion_next(gboolean back) path = gtk_tree_path_new_from_indices(comp.active, -1); gtk_tree_view_set_cursor(tree, path, NULL, false); gtk_tree_path_free(path); + + return true; } void completion_clean(void) diff --git a/src/completion.h b/src/completion.h index 4ef496e5..26b057df 100644 --- a/src/completion.h +++ b/src/completion.h @@ -35,6 +35,6 @@ typedef void (*CompletionSelectFunc) (char *match); gboolean completion_create(GtkTreeModel *model, CompletionSelectFunc selfunc, gboolean back); void completion_clean(void); -void completion_next(gboolean back); +gboolean completion_next(gboolean back); #endif /* end of include guard: _COMPLETION_H */ diff --git a/src/ex.c b/src/ex.c index 56634f25..e3e42816 100644 --- a/src/ex.c +++ b/src/ex.c @@ -208,6 +208,7 @@ static struct { guint count; char *prefix; /* completion prefix like :, ? and / */ char *current; /* holds the current written input box content */ + char *token; /* initial filter content */ } excomp; static struct { @@ -1102,8 +1103,11 @@ static gboolean complete(short direction) /* if completion was already started move to the next/prev item */ if (vb.mode->flags & FLAG_COMPLETION) { if (excomp.current && !strcmp(input, excomp.current)) { - /* step through the next/prev completion item */ - completion_next(direction < 0); + /* Step through the next/prev completion item. */ + if (!completion_next(direction < 0)) { + /* If we stepped over the last/first item - put the initial content in */ + completion_select(excomp.token); + } g_free(input); return true; @@ -1135,7 +1139,6 @@ static gboolean complete(short direction) * there is a space after the command and the optional '!' bang. */ if (parse_command_name(&in, arg) && parse_bang(&in, arg) && VB_IS_SPACE(*in)) { const char *token; - /* Get only the last word of input string for the completion for * bookmark tag completion. */ if (arg->code == EX_BMA) { @@ -1155,6 +1158,7 @@ static gboolean complete(short direction) * the ':open ' if ':open something' is completed. This means that * the completion will only the none prefix part of the input */ OVERWRITE_NSTRING(excomp.prefix, input, token - input + 1); + OVERWRITE_STRING(excomp.token, token + 1); /* the token points to a space, skip this */ skip_whitespace(&token); @@ -1212,6 +1216,7 @@ static gboolean complete(short direction) } else { /* complete command names */ /* restore the 'in' pointer after try to parse command name */ in = before_cmdname; + OVERWRITE_STRING(excomp.token, in); /* Backup the parsed data so we can access them in * completion_select function. */ @@ -1225,6 +1230,7 @@ static gboolean complete(short direction) free_cmdarg(arg); } else if (*in == '/' || *in == '?') { if (history_fill_completion(store, HISTORY_SEARCH, in + 1)) { + OVERWRITE_STRING(excomp.token, in + 1); OVERWRITE_NSTRING(excomp.prefix, in, 1); sort = true; found = true;