diff options
author | Christian Hergert <chergert@redhat.com> | 2022-10-05 13:43:04 -0700 |
---|---|---|
committer | Christian Hergert <chergert@redhat.com> | 2022-10-05 13:43:04 -0700 |
commit | 559032fbe2d88973bde1caea4a87b1ef0efbb474 (patch) | |
tree | 11c50a64982424b5a8b99e5895e990682565c732 | |
parent | bf978b825c224df144af03d86b34e52d604056f8 (diff) | |
download | gtksourceview-559032fbe2d88973bde1caea4a87b1ef0efbb474.tar.gz |
vim: implement rudimentary search through previous commands
This allows using arrow keys to find other commands in the history which
match the currently typed prefix.
-rw-r--r-- | gtksourceview/vim/gtksourcevimcommandbar.c | 57 |
1 files changed, 45 insertions, 12 deletions
diff --git a/gtksourceview/vim/gtksourcevimcommandbar.c b/gtksourceview/vim/gtksourcevimcommandbar.c index f558a702..32d24eaa 100644 --- a/gtksourceview/vim/gtksourcevimcommandbar.c +++ b/gtksourceview/vim/gtksourcevimcommandbar.c @@ -1,7 +1,7 @@ /* * This file is part of GtkSourceView * - * Copyright 2021 Christian Hergert <chergert@redhat.com> + * Copyright 2021-2022 Christian Hergert <chergert@redhat.com> * * GtkSourceView is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -32,6 +32,7 @@ struct _GtkSourceVimCommandBar GtkSourceVimState parent_instance; GtkSourceVimCommand *command; GString *buffer; + char *typed; int history_pos; }; @@ -58,6 +59,8 @@ gtk_source_vim_command_bar_dispose (GObject *object) { GtkSourceVimCommandBar *self = (GtkSourceVimCommandBar *)object; + g_clear_pointer (&self->typed, g_free); + if (self->buffer == NULL) { g_string_free (self->buffer, TRUE); @@ -86,23 +89,45 @@ static void move_history (GtkSourceVimCommandBar *self, int direction) { + int position; + g_assert (GTK_SOURCE_IS_VIM_COMMAND_BAR (self)); if (history->len == 0) + { return; + } + + if (self->typed == NULL && self->buffer->len > 0) + { + self->typed = g_strdup (self->buffer->str); + } - if (direction < 0) - self->history_pos--; - else - self->history_pos++; + direction = direction < 0 ? -1 : 1; + position = self->history_pos + direction; - if (self->history_pos < 0) - self->history_pos = history->len - 1; - else if (self->history_pos >= history->len) - self->history_pos = 0; + while (position >= 0 && position < history->len) + { + const char *item = g_ptr_array_index (history, position); - g_string_truncate (self->buffer, 0); - g_string_append (self->buffer, g_ptr_array_index (history, self->history_pos)); + if (self->typed == NULL || g_str_has_prefix (item, self->typed)) + { + self->history_pos = position; + g_string_truncate (self->buffer, 0); + g_string_append (self->buffer, item); + return; + } + + position += direction; + } + + /* Reset to typed text if we exhausted the tail of history */ + if (position >= history->len && self->typed != NULL) + { + self->history_pos = history->len; + g_string_truncate (self->buffer, 0); + g_string_append (self->buffer, self->typed); + } } static void @@ -191,6 +216,8 @@ gtk_source_vim_command_bar_handle_keypress (GtkSourceVimState *state, { gsize len = g_utf8_strlen (self->buffer->str, -1); + g_clear_pointer (&self->typed, g_free); + if (len > 1) { char *s = g_utf8_offset_to_pointer (self->buffer->str, len-1); @@ -219,6 +246,7 @@ gtk_source_vim_command_bar_handle_keypress (GtkSourceVimState *state, case GDK_KEY_Return: case GDK_KEY_KP_Enter: case GDK_KEY_ISO_Enter: + g_clear_pointer (&self->typed, g_free); do_execute (self, self->buffer->str); g_string_truncate (self->buffer, 0); do_notify (self); @@ -228,6 +256,7 @@ gtk_source_vim_command_bar_handle_keypress (GtkSourceVimState *state, case GDK_KEY_u: if (mods & GDK_CONTROL_MASK) { + g_clear_pointer (&self->typed, g_free); g_string_truncate (self->buffer, 1); do_notify (self); return TRUE; @@ -242,6 +271,7 @@ gtk_source_vim_command_bar_handle_keypress (GtkSourceVimState *state, if (str[0]) { g_string_append (self->buffer, str); + g_clear_pointer (&self->typed, g_free); do_notify (self); } @@ -256,7 +286,7 @@ gtk_source_vim_command_bar_enter (GtkSourceVimState *state) g_assert (GTK_SOURCE_VIM_STATE (self)); - self->history_pos = 0; + self->history_pos = history->len; if (self->buffer->len == 0) { @@ -276,6 +306,9 @@ gtk_source_vim_command_bar_leave (GtkSourceVimState *state) g_assert (GTK_SOURCE_VIM_STATE (self)); + self->history_pos = 0; + + g_clear_pointer (&self->typed, g_free); g_string_truncate (self->buffer, 0); do_notify (self); |