[gtksourceview/wip/chergert/vim] start on some repeatable visual+commands



commit 3753ff6917f7288e16723dccfcf4f145db175cf4
Author: Christian Hergert <chergert redhat com>
Date:   Sun Oct 31 12:45:24 2021 -0700

    start on some repeatable visual+commands

 gtksourceview/vim/gtk-source-vim-delete.c |  31 ++++-----
 gtksourceview/vim/gtk-source-vim-delete.h |   4 +-
 gtksourceview/vim/gtk-source-vim-visual.c | 106 ++++++++++++++++++++++++++----
 3 files changed, 111 insertions(+), 30 deletions(-)
---
diff --git a/gtksourceview/vim/gtk-source-vim-delete.c b/gtksourceview/vim/gtk-source-vim-delete.c
index c9f1fde7..08aa3c10 100644
--- a/gtksourceview/vim/gtk-source-vim-delete.c
+++ b/gtksourceview/vim/gtk-source-vim-delete.c
@@ -54,19 +54,20 @@ gtk_source_vim_delete_new (GtkSourceVimMotion *motion)
                             NULL);
 }
 
-static void
+void
 gtk_source_vim_delete_set_motion (GtkSourceVimDelete *self,
                                  GtkSourceVimMotion *motion)
 {
-       g_assert (GTK_SOURCE_IS_VIM_DELETE (self));
-       g_assert (!motion || GTK_SOURCE_IS_VIM_MOTION (motion));
+       g_return_if_fail (GTK_SOURCE_IS_VIM_DELETE (self));
+       g_return_if_fail (!motion || GTK_SOURCE_IS_VIM_MOTION (motion));
 
        if (g_set_object (&self->motion, motion))
        {
                if (motion != NULL)
                {
                        gtk_source_vim_motion_set_apply_on_leave (motion, FALSE);
-                       g_object_set (motion, "parent", self, NULL);
+                       gtk_source_vim_state_set_parent (GTK_SOURCE_VIM_STATE (motion),
+                                                        GTK_SOURCE_VIM_STATE (self));
                }
        }
 }
@@ -129,31 +130,31 @@ static void
 gtk_source_vim_delete_repeat (GtkSourceVimState *state)
 {
        GtkSourceVimDelete *self = (GtkSourceVimDelete *)state;
+       GtkSourceBuffer *buffer;
+       GtkTextIter insert, selection;
 
        g_assert (GTK_SOURCE_IS_VIM_DELETE (self));
 
+       buffer = gtk_source_vim_state_get_buffer (state, &insert, &selection);
+
        if (self->motion != NULL)
        {
-               GtkSourceBuffer *buffer;
-               GtkTextIter insert, selection;
                int count = gtk_source_vim_state_get_count (state);
 
-               buffer = gtk_source_vim_state_get_buffer (state, &insert, &selection);
-
                do
                {
                        if (!gtk_source_vim_motion_apply (self->motion, &insert, TRUE))
                                break;
                } while (--count > 0);
+       }
 
-               gtk_text_buffer_delete (GTK_TEXT_BUFFER (buffer), &insert, &selection);
+       gtk_text_buffer_delete (GTK_TEXT_BUFFER (buffer), &insert, &selection);
 
-               if (gtk_text_iter_ends_line (&insert) &&
-                   !gtk_text_iter_starts_line (&insert))
-               {
-                       gtk_text_iter_backward_char (&insert);
-                       gtk_source_vim_state_select (state, &insert, &insert);
-               }
+       if (gtk_text_iter_ends_line (&insert) &&
+           !gtk_text_iter_starts_line (&insert))
+       {
+               gtk_text_iter_backward_char (&insert);
+               gtk_source_vim_state_select (state, &insert, &insert);
        }
 }
 
diff --git a/gtksourceview/vim/gtk-source-vim-delete.h b/gtksourceview/vim/gtk-source-vim-delete.h
index 613905ec..c3ebf144 100644
--- a/gtksourceview/vim/gtk-source-vim-delete.h
+++ b/gtksourceview/vim/gtk-source-vim-delete.h
@@ -30,6 +30,8 @@ G_BEGIN_DECLS
 
 G_DECLARE_FINAL_TYPE (GtkSourceVimDelete, gtk_source_vim_delete, GTK_SOURCE, VIM_DELETE, GtkSourceVimState)
 
-GtkSourceVimState *gtk_source_vim_delete_new (GtkSourceVimMotion *motion);
+GtkSourceVimState *gtk_source_vim_delete_new        (GtkSourceVimMotion *motion);
+void               gtk_source_vim_delete_set_motion (GtkSourceVimDelete *self,
+                                                     GtkSourceVimMotion *motion);
 
 G_END_DECLS
diff --git a/gtksourceview/vim/gtk-source-vim-visual.c b/gtksourceview/vim/gtk-source-vim-visual.c
index 89c22ebf..43dce89f 100644
--- a/gtksourceview/vim/gtk-source-vim-visual.c
+++ b/gtksourceview/vim/gtk-source-vim-visual.c
@@ -23,6 +23,7 @@
 
 #include <glib/gi18n.h>
 
+#include "gtk-source-vim-delete.h"
 #include "gtk-source-vim-motion.h"
 #include "gtk-source-vim-visual.h"
 
@@ -38,6 +39,14 @@ struct _GtkSourceVimVisual
 
        GtkSourceVimVisualMode mode;
 
+       /* A recording of motions so that we can replay commands
+        * such as delete and get a similar result to VIM. Replaying
+        * our motion's visual selection is not enough as after a
+        * delete it would be empty.
+        */
+       GtkSourceVimMotion *motion;
+       GtkSourceVimState *command;
+
        KeyHandler handler;
 
        GtkTextMark *started_at;
@@ -45,30 +54,46 @@ struct _GtkSourceVimVisual
 };
 
 static gboolean gtk_source_vim_visual_bail (GtkSourceVimVisual *self);
+static gboolean key_handler_initial        (GtkSourceVimVisual *self,
+                                            guint               keyval,
+                                            guint               keycode,
+                                            GdkModifierType     mods,
+                                            const char         *string);
 
 G_DEFINE_TYPE (GtkSourceVimVisual, gtk_source_vim_visual, GTK_SOURCE_TYPE_VIM_STATE)
 
+static void
+gtk_source_vim_visual_clear (GtkSourceVimVisual *self)
+{
+       self->handler = key_handler_initial;
+}
+
+static gboolean
+gtk_source_vim_visual_bail (GtkSourceVimVisual *self)
+{
+       gtk_source_vim_visual_clear (self);
+       return TRUE;
+}
+
 static void
 extend_lines (GtkTextIter *a,
               GtkTextIter *b)
 {
-       if (gtk_text_iter_equal (a, b))
-       {
-               gtk_text_iter_set_line_offset (a, 0);
-               if (!gtk_text_iter_ends_line (b))
-                       gtk_text_iter_forward_to_line_end (b);
-       }
-       else if (gtk_text_iter_compare (a, b) < 0)
+       if (gtk_text_iter_compare (a, b) <= 0)
        {
                gtk_text_iter_set_line_offset (a, 0);
                if (!gtk_text_iter_ends_line (b))
                        gtk_text_iter_forward_to_line_end (b);
+               if (gtk_text_iter_ends_line (b) && !gtk_text_iter_is_end (b))
+                       gtk_text_iter_forward_char (b);
        }
        else
        {
                gtk_text_iter_set_line_offset (b, 0);
                if (!gtk_text_iter_ends_line (a))
                        gtk_text_iter_forward_to_line_end (a);
+               if (gtk_text_iter_ends_line (a) && !gtk_text_iter_is_end (a))
+                       gtk_text_iter_forward_char (a);
        }
 }
 
@@ -227,6 +252,23 @@ key_handler_z (GtkSourceVimVisual *self,
        }
 }
 
+static void
+gtk_source_vim_visual_delete (GtkSourceVimVisual *self)
+{
+       g_assert (GTK_SOURCE_IS_VIM_VISUAL (self));
+
+       gtk_source_vim_visual_clear (self);
+       g_clear_object (&self->command);
+
+       gtk_source_vim_state_set_can_repeat (GTK_SOURCE_VIM_STATE (self), TRUE);
+
+       self->command = gtk_source_vim_delete_new (NULL);
+       gtk_source_vim_state_set_parent (self->command, GTK_SOURCE_VIM_STATE (self));
+       gtk_source_vim_state_repeat (self->command);
+
+       gtk_source_vim_state_pop (GTK_SOURCE_VIM_STATE (self));
+}
+
 static gboolean
 key_handler_initial (GtkSourceVimVisual *self,
                      guint               keyval,
@@ -236,12 +278,18 @@ key_handler_initial (GtkSourceVimVisual *self,
 {
        GtkSourceVimState *motion;
 
+       g_assert (GTK_SOURCE_IS_VIM_VISUAL (self));
+
        switch (keyval)
        {
                case GDK_KEY_z:
                        self->handler = key_handler_z;
                        return TRUE;
 
+               case GDK_KEY_x:
+                       gtk_source_vim_visual_delete (self);
+                       return TRUE;
+
                default:
                        break;
        }
@@ -255,13 +303,6 @@ key_handler_initial (GtkSourceVimVisual *self,
        return TRUE;
 }
 
-static gboolean
-gtk_source_vim_visual_bail (GtkSourceVimVisual *self)
-{
-       self->handler = key_handler_initial;
-       return TRUE;
-}
-
 static void
 gtk_source_vim_visual_enter (GtkSourceVimState *state)
 {
@@ -328,12 +369,45 @@ gtk_source_vim_visual_resume (GtkSourceVimState *state,
 
        if (GTK_SOURCE_IS_VIM_MOTION (from))
        {
+               GtkSourceVimState *chained;
+
+               /* Update our selection to match the motion. If we're in
+                * linewise, that needs to be updated to contain the whole line.
+                */
                gtk_source_vim_visual_track_motion (self);
+
+               /* Keep the motion around too so we can potentially replay it
+                * for commands like delete, etc.
+                */
+               chained = gtk_source_vim_motion_chain (self->motion, GTK_SOURCE_VIM_MOTION (from));
+               gtk_source_vim_state_set_parent (chained, GTK_SOURCE_VIM_STATE (self));
+               g_set_object (&self->motion, GTK_SOURCE_VIM_MOTION (chained));
+               g_object_unref (chained);
        }
 
        self->handler = key_handler_initial;
 }
 
+static void
+gtk_source_vim_visual_repeat (GtkSourceVimState *state)
+{
+       GtkSourceVimVisual *self = (GtkSourceVimVisual *)state;
+       int count;
+
+       g_assert (GTK_SOURCE_IS_VIM_STATE (self));
+
+       count = gtk_source_vim_state_get_count (state);
+
+       do
+       {
+               if (self->motion != NULL)
+                       gtk_source_vim_state_repeat (GTK_SOURCE_VIM_STATE (self->motion));
+
+               if (self->command != NULL)
+                       gtk_source_vim_state_repeat (self->command);
+       } while (--count > 0);
+}
+
 static gboolean
 gtk_source_vim_visual_handle_keypress (GtkSourceVimState *state,
                                        guint              keyval,
@@ -378,6 +452,9 @@ gtk_source_vim_visual_dispose (GObject *object)
                gtk_text_buffer_delete_mark (GTK_TEXT_BUFFER (buffer), mark);
        }
 
+       g_clear_object (&self->motion);
+       g_clear_object (&self->command);
+
        G_OBJECT_CLASS (gtk_source_vim_visual_parent_class)->dispose (object);
 }
 
@@ -394,6 +471,7 @@ gtk_source_vim_visual_class_init (GtkSourceVimVisualClass *klass)
        state_class->enter = gtk_source_vim_visual_enter;
        state_class->leave = gtk_source_vim_visual_leave;
        state_class->resume = gtk_source_vim_visual_resume;
+       state_class->repeat = gtk_source_vim_visual_repeat;
 }
 
 static void


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