[gtksourceview/wip/chergert/vim: 51/73] handle gg ge and gE commands




commit d177d872e1c2ebae4bba38dd8bd372b7f463bb53
Author: Christian Hergert <chergert redhat com>
Date:   Sat Oct 23 12:23:40 2021 -0700

    handle gg ge and gE commands

 gtksourceview/vim/gtk-source-vim-motion.c | 84 +++++++++++++++++++++++++++++--
 gtksourceview/vim/gtk-source-vim-normal.c | 22 ++++++--
 gtksourceview/vim/gtk-source-vim-state.c  | 13 +++++
 gtksourceview/vim/gtk-source-vim-state.h  |  3 ++
 4 files changed, 114 insertions(+), 8 deletions(-)
---
diff --git a/gtksourceview/vim/gtk-source-vim-motion.c b/gtksourceview/vim/gtk-source-vim-motion.c
index 31040eff..ab5a33ce 100644
--- a/gtksourceview/vim/gtk-source-vim-motion.c
+++ b/gtksourceview/vim/gtk-source-vim-motion.c
@@ -31,10 +31,24 @@ typedef gboolean (*Motion) (GtkTextIter   *iter,
 struct _GtkSourceVimMotion
 {
        GtkSourceVimState parent_instance;
-       Motion            motion;
-       int               number;
-       guint             apply_on_leave : 1;
-       guint             failed : 1;
+
+       /* A function to apply the motion */
+       Motion motion;
+
+       /* A number for the motion like `3e`. */
+       int number;
+
+       /* Apply the motion when leaving the state. This is useful
+        * so that you can either capture a motion for future use
+        * or simply apply it immediately.
+        */
+       guint apply_on_leave : 1;
+
+       /* If the command starts with `g` such as `ge` or `gE`. */
+       guint g_command : 1;
+
+       /* If we called gtk_source_vim_motion_bail(). */
+       guint failed : 1;
 };
 
 G_DEFINE_TYPE (GtkSourceVimMotion, gtk_source_vim_motion, GTK_SOURCE_TYPE_VIM_STATE)
@@ -560,6 +574,37 @@ motion_backward_WORD_end (GtkTextIter   *iter,
        return backward_classified_end (iter, classify_WORD);
 }
 
+static gboolean
+motion_buffer_start (GtkTextIter   *iter,
+                     GtkSourceView *view)
+{
+       if (!gtk_text_iter_is_start (iter))
+       {
+               gtk_text_iter_set_offset (iter, 0);
+               return TRUE;
+       }
+
+       return FALSE;
+}
+
+static gboolean
+motion_buffer_start_first_char (GtkTextIter   *iter,
+                               GtkSourceView *view)
+{
+       GtkTextIter before = *iter;
+
+       motion_buffer_start (iter, view);
+
+       while (!gtk_text_iter_ends_line (iter) &&
+              g_unichar_isspace (gtk_text_iter_get_char (iter)))
+       {
+               if (!gtk_text_iter_forward_char (iter))
+                       break;
+       }
+
+       return !gtk_text_iter_equal (&before, iter);
+}
+
 GtkSourceVimState *
 gtk_source_vim_motion_new (void)
 {
@@ -599,6 +644,26 @@ gtk_source_vim_motion_handle_keypress (GtkSourceVimState *state,
 
        g_assert (GTK_SOURCE_IS_VIM_MOTION (self));
 
+       if (self->g_command)
+       {
+               switch (keyval)
+               {
+                       case GDK_KEY_g:
+                               return gtk_source_vim_motion_complete (self, motion_buffer_start_first_char);
+
+                       case GDK_KEY_e:
+                               return gtk_source_vim_motion_complete (self, motion_backward_word_end);
+
+                       case GDK_KEY_E:
+                               return gtk_source_vim_motion_complete (self, motion_backward_WORD_end);
+
+                       default:
+                               return gtk_source_vim_motion_bail (self);
+               }
+
+               g_assert_not_reached ();
+       }
+
        if (self->number != 0)
        {
                if (keyval >= GDK_KEY_0 && keyval <= GDK_KEY_9)
@@ -669,6 +734,10 @@ gtk_source_vim_motion_handle_keypress (GtkSourceVimState *state,
                case GDK_KEY_G:
                        return gtk_source_vim_motion_complete (self, motion_last_line_first_char);
 
+               case GDK_KEY_g:
+                       self->g_command = TRUE;
+                       return TRUE;
+
                case GDK_KEY_H:
                        return gtk_source_vim_motion_complete (self, motion_screen_top);
 
@@ -724,6 +793,11 @@ gtk_source_vim_motion_repeat (GtkSourceVimState *state,
 
        g_assert (GTK_SOURCE_IS_VIM_MOTION (self));
 
+       if (self->failed)
+       {
+               return;
+       }
+
        buffer = gtk_source_vim_state_get_buffer (state, &insert, &selection);
        has_selection = !gtk_text_iter_equal (&insert, &selection);
 
@@ -751,7 +825,9 @@ gtk_source_vim_motion_leave (GtkSourceVimState *state)
        g_assert (GTK_SOURCE_IS_VIM_MOTION (self));
 
        if (self->apply_on_leave)
+       {
                gtk_source_vim_motion_repeat (state, 1);
+       }
 }
 
 static void
diff --git a/gtksourceview/vim/gtk-source-vim-normal.c b/gtksourceview/vim/gtk-source-vim-normal.c
index 97bb0740..c9362283 100644
--- a/gtksourceview/vim/gtk-source-vim-normal.c
+++ b/gtksourceview/vim/gtk-source-vim-normal.c
@@ -289,9 +289,24 @@ key_handler_g (GtkSourceVimNormal *self,
                GdkModifierType     mods,
                const char         *string)
 {
+       GtkSourceVimState *new_state;
+
        g_assert (GTK_SOURCE_IS_VIM_NORMAL (self));
 
-       return TRUE;
+       switch (keyval)
+       {
+               case GDK_KEY_g:
+               case GDK_KEY_e:
+               case GDK_KEY_E:
+                       new_state = gtk_source_vim_motion_new ();
+                       gtk_source_vim_state_push (GTK_SOURCE_VIM_STATE (self), new_state);
+                       gtk_source_vim_state_synthesize (new_state, GDK_KEY_g, 0);
+                       gtk_source_vim_state_synthesize (new_state, keyval, mods);
+                       return TRUE;
+
+               default:
+                       return gtk_source_vim_normal_bail (self);
+       }
 }
 
 static gboolean
@@ -306,9 +321,8 @@ key_handler_motion (GtkSourceVimNormal *self,
        g_assert (GTK_SOURCE_IS_VIM_NORMAL (self));
 
        new_state = gtk_source_vim_motion_new ();
-       gtk_source_vim_motion_set_apply_on_leave (GTK_SOURCE_VIM_MOTION (new_state), TRUE);
        gtk_source_vim_state_push (GTK_SOURCE_VIM_STATE (self), new_state);
-       GTK_SOURCE_VIM_STATE_GET_CLASS (new_state)->handle_keypress (new_state, keyval, keycode, mods, 
string);
+       gtk_source_vim_state_synthesize (new_state, keyval, mods);
 
        return TRUE;
 }
@@ -471,7 +485,7 @@ key_handler_initial (GtkSourceVimNormal *self,
 
                        case GDK_KEY_g:
                                self->handler = key_handler_g;
-                               break;
+                               return TRUE;
 
                        case GDK_KEY_z:
                                self->handler = key_handler_viewport;
diff --git a/gtksourceview/vim/gtk-source-vim-state.c b/gtksourceview/vim/gtk-source-vim-state.c
index 96db0d16..c4a122d9 100644
--- a/gtksourceview/vim/gtk-source-vim-state.c
+++ b/gtksourceview/vim/gtk-source-vim-state.c
@@ -459,3 +459,16 @@ gtk_source_vim_state_set_overwrite (GtkSourceVimState *self,
                gtk_text_view_set_overwrite (GTK_TEXT_VIEW (priv->view), overwrite);
        }
 }
+
+gboolean
+gtk_source_vim_state_synthesize (GtkSourceVimState *self,
+                                 guint              keyval,
+                                 GdkModifierType    mods)
+{
+       char string[16];
+
+       g_return_val_if_fail (GTK_SOURCE_IS_VIM_STATE (self), FALSE);
+
+       keyval_to_string (keyval, mods, string);
+       return GTK_SOURCE_VIM_STATE_GET_CLASS (self)->handle_keypress (self, keyval, 0, mods, string);
+}
diff --git a/gtksourceview/vim/gtk-source-vim-state.h b/gtksourceview/vim/gtk-source-vim-state.h
index 206cf303..1d12802b 100644
--- a/gtksourceview/vim/gtk-source-vim-state.h
+++ b/gtksourceview/vim/gtk-source-vim-state.h
@@ -71,6 +71,9 @@ gboolean           gtk_source_vim_state_handle_event   (GtkSourceVimState *self,
 void               gtk_source_vim_state_set_overwrite  (GtkSourceVimState *self,
                                                         gboolean           overwrite);
 gboolean           gtk_source_vim_state_get_can_repeat (GtkSourceVimState *self);
+gboolean           gtk_source_vim_state_synthesize     (GtkSourceVimState *self,
+                                                        guint              keyval,
+                                                        GdkModifierType    mods);
 void               gtk_source_vim_state_repeat         (GtkSourceVimState *self,
                                                         int                repeat);
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]