[gtksourceview/wip/chergert/vim: 178/363] add helper to chain motions




commit 21df53de18a0dfbdfa36987686e522fe2599ed3e
Author: Christian Hergert <chergert redhat com>
Date:   Sun Oct 31 12:04:16 2021 -0700

    add helper to chain motions

 gtksourceview/vim/gtk-source-vim-motion.c | 88 +++++++++++++++++++++++++++++--
 gtksourceview/vim/gtk-source-vim-motion.h |  2 +
 2 files changed, 87 insertions(+), 3 deletions(-)
---
diff --git a/gtksourceview/vim/gtk-source-vim-motion.c b/gtksourceview/vim/gtk-source-vim-motion.c
index 77536075..bcc5230b 100644
--- a/gtksourceview/vim/gtk-source-vim-motion.c
+++ b/gtksourceview/vim/gtk-source-vim-motion.c
@@ -46,6 +46,11 @@ struct _GtkSourceVimMotion
        /* A function to apply the motion */
        Motion motion;
 
+       /* An array of motions if this is a motion chain (such as those
+        * used by delete to replay Visual state motions.
+        */
+       GPtrArray *chained;
+
        /* character for f or F */
        gunichar f_char;
 
@@ -71,6 +76,9 @@ struct _GtkSourceVimMotion
 
        /* If the motion is exclusive (does not include char) */
        guint inclusivity : 1;
+
+       /* If we're to apply inclusivity (used by chained motions) */
+       guint applying_inclusive : 1;
 };
 
 G_DEFINE_TYPE (GtkSourceVimMotion, gtk_source_vim_motion, GTK_SOURCE_TYPE_VIM_STATE)
@@ -1489,15 +1497,17 @@ gtk_source_vim_motion_append_command (GtkSourceVimState *state,
 }
 
 static void
-gtk_source_vim_motion_finalize (GObject *object)
+gtk_source_vim_motion_dispose (GObject *object)
 {
        GtkSourceVimMotion *self = (GtkSourceVimMotion *)object;
 
+       g_clear_pointer (&self->chained, g_ptr_array_unref);
+
        g_clear_object (&self->mark);
        g_string_free (self->command_text, TRUE);
        self->command_text = NULL;
 
-       G_OBJECT_CLASS (gtk_source_vim_motion_parent_class)->finalize (object);
+       G_OBJECT_CLASS (gtk_source_vim_motion_parent_class)->dispose (object);
 }
 
 static void
@@ -1506,7 +1516,7 @@ gtk_source_vim_motion_class_init (GtkSourceVimMotionClass *klass)
        GObjectClass *object_class = G_OBJECT_CLASS (klass);
        GtkSourceVimStateClass *state_class = GTK_SOURCE_VIM_STATE_CLASS (klass);
 
-       object_class->finalize = gtk_source_vim_motion_finalize;
+       object_class->dispose = gtk_source_vim_motion_dispose;
 
        state_class->append_command = gtk_source_vim_motion_append_command;
        state_class->handle_keypress = gtk_source_vim_motion_handle_keypress;
@@ -1537,6 +1547,8 @@ gtk_source_vim_motion_apply (GtkSourceVimMotion *self,
                return FALSE;
        }
 
+       self->applying_inclusive = !!apply_inclusive;
+
        begin_offset = gtk_text_iter_get_offset (iter);
        count = gtk_source_vim_state_get_count (GTK_SOURCE_VIM_STATE (self));
 
@@ -1567,6 +1579,8 @@ do_inclusive:
                        gtk_text_iter_forward_char (iter);
        }
 
+       self->applying_inclusive = FALSE;
+
        return ret;
 }
 
@@ -1731,3 +1745,71 @@ gtk_source_vim_motion_new_none (void)
 
        return GTK_SOURCE_VIM_STATE (self);
 }
+
+static gboolean
+motion_chained (GtkTextIter        *iter,
+                GtkSourceVimMotion *self)
+{
+       GtkTextIter before = *iter;
+
+       for (guint i = 0; i < self->chained->len; i++)
+       {
+               GtkSourceVimMotion *motion = g_ptr_array_index (self->chained, i);
+
+               gtk_source_vim_motion_apply (motion, iter, self->applying_inclusive);
+       }
+
+       return !gtk_text_iter_equal (&before, iter);
+}
+
+GtkSourceVimState *
+gtk_source_vim_motion_chain (GtkSourceVimMotion *self,
+                             GtkSourceVimMotion *other)
+{
+       GtkSourceVimMotion *chained;
+
+       g_return_val_if_fail (!self || GTK_SOURCE_IS_VIM_MOTION (self), NULL);
+       g_return_val_if_fail (!other || GTK_SOURCE_IS_VIM_MOTION (other), NULL);
+
+       if (!self && other)
+               return g_object_ref (GTK_SOURCE_VIM_STATE (other));
+
+       if (!other && self)
+               return g_object_ref (GTK_SOURCE_VIM_STATE (other));
+
+       g_assert (self != NULL);
+       g_assert (other != NULL);
+
+       if (self->motion == motion_chained)
+       {
+               g_assert (self->chained != NULL);
+               g_assert (self->chained->len > 0);
+
+               g_ptr_array_add (self->chained, g_object_ref (other));
+
+               return g_object_ref (GTK_SOURCE_VIM_STATE (self));
+       }
+
+       if (self->motion == other->motion &&
+           self->inclusivity == other->inclusivity &&
+           self->f_char == other->f_char)
+       {
+               int count = gtk_source_vim_state_get_count (GTK_SOURCE_VIM_STATE (self))
+                         + gtk_source_vim_state_get_count (GTK_SOURCE_VIM_STATE (other));
+
+               gtk_source_vim_state_set_count (GTK_SOURCE_VIM_STATE (self), count);
+
+               return g_object_ref (GTK_SOURCE_VIM_STATE (self));
+       }
+
+
+       chained = GTK_SOURCE_VIM_MOTION (gtk_source_vim_motion_new ());
+       chained->motion = motion_chained;
+       chained->inclusivity = INCLUSIVE;
+       chained->chained = g_ptr_array_new_with_free_func (g_object_unref);
+
+       g_ptr_array_add (chained->chained, g_object_ref (self));
+       g_ptr_array_add (chained->chained, g_object_ref (other));
+
+       return GTK_SOURCE_VIM_STATE (chained);
+}
diff --git a/gtksourceview/vim/gtk-source-vim-motion.h b/gtksourceview/vim/gtk-source-vim-motion.h
index ae2f7632..ec10ec22 100644
--- a/gtksourceview/vim/gtk-source-vim-motion.h
+++ b/gtksourceview/vim/gtk-source-vim-motion.h
@@ -32,6 +32,8 @@ G_BEGIN_DECLS
 G_DECLARE_FINAL_TYPE (GtkSourceVimMotion, gtk_source_vim_motion, GTK_SOURCE, VIM_MOTION, GtkSourceVimState)
 
 GtkSourceVimState *gtk_source_vim_motion_new                       (void);
+GtkSourceVimState *gtk_source_vim_motion_chain                     (GtkSourceVimMotion *self,
+                                                                    GtkSourceVimMotion *other);
 GtkSourceVimState *gtk_source_vim_motion_new_none                  (void);
 GtkSourceVimState *gtk_source_vim_motion_new_first_char            (void);
 GtkSourceVimState *gtk_source_vim_motion_new_line_end              (void);


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