[gtksourceview/wip/chergert/vim] start on some basic history recording.



commit 02e4f3816dc41d1193d985e9bf9ebbb5667c7ef2
Author: Christian Hergert <chergert redhat com>
Date:   Wed Oct 27 21:14:05 2021 -0700

    start on some basic history recording.

 gtksourceview/vim/gtk-source-vim-insert.c       |  91 +++++++++++++++++----
 gtksourceview/vim/gtk-source-vim-normal.c       |  22 ++++--
 gtksourceview/vim/gtk-source-vim-state.c        |  10 +--
 gtksourceview/vim/gtk-source-vim-text-history.c | 100 ++++++++++++++++++++++++
 gtksourceview/vim/gtk-source-vim-text-history.h |  37 +++++++++
 gtksourceview/vim/meson.build                   |   1 +
 6 files changed, 236 insertions(+), 25 deletions(-)
---
diff --git a/gtksourceview/vim/gtk-source-vim-insert.c b/gtksourceview/vim/gtk-source-vim-insert.c
index 52e2b4b7..7df69a71 100644
--- a/gtksourceview/vim/gtk-source-vim-insert.c
+++ b/gtksourceview/vim/gtk-source-vim-insert.c
@@ -29,13 +29,16 @@
 #include "gtk-source-vim-insert.h"
 #include "gtk-source-vim-insert-literal.h"
 #include "gtk-source-vim-replace.h"
+#include "gtk-source-vim-text-history.h"
 
 struct _GtkSourceVimInsert
 {
-       GtkSourceVimState parent_instance;
-       char *prefix;
-       char *suffix;
-       guint indent : 1;
+       GtkSourceVimState        parent_instance;
+       GtkSourceVimTextHistory *history;
+       char                    *prefix;
+       char                    *suffix;
+       guint                    indent : 1;
+       guint                    finished : 1;
 };
 
 G_DEFINE_TYPE (GtkSourceVimInsert, gtk_source_vim_insert, GTK_SOURCE_TYPE_VIM_STATE)
@@ -97,8 +100,6 @@ gtk_source_vim_insert_handle_event (GtkSourceVimState *state,
        g_assert (GTK_SOURCE_IS_VIM_INSERT (self));
        g_assert (event != NULL);
 
-       /* TODO: Eventually we'll need to stash these events for replay */
-
        if (!(view = gtk_source_vim_state_get_view (state)))
                return FALSE;
 
@@ -106,6 +107,11 @@ gtk_source_vim_insert_handle_event (GtkSourceVimState *state,
        mods = gdk_event_get_modifier_state (event)
             & gtk_accelerator_get_default_mod_mask ();
 
+       if (!gtk_source_vim_state_is_escape (keyval, mods))
+       {
+               gtk_source_vim_text_history_record (self->history, event);
+       }
+
        /* Allow input methods to complete */
        if (gtk_text_view_im_context_filter_keypress (GTK_TEXT_VIEW (view), event))
                return TRUE;
@@ -177,19 +183,16 @@ gtk_source_vim_insert_resume (GtkSourceVimState *state,
 }
 
 static void
-gtk_source_vim_insert_enter (GtkSourceVimState *state)
+gtk_source_vim_insert_prepare (GtkSourceVimInsert *self)
 {
-       GtkSourceVimInsert *self = (GtkSourceVimInsert *)state;
        GtkSourceBuffer *buffer;
        GtkSourceView *view;
        GtkTextIter iter;
 
        g_assert (GTK_SOURCE_IS_VIM_INSERT (self));
 
-       gtk_source_vim_state_set_overwrite (state, FALSE);
-
-       view = gtk_source_vim_state_get_view (state);
-       buffer = gtk_source_vim_state_get_buffer (state, &iter, NULL);
+       view = gtk_source_vim_state_get_view (GTK_SOURCE_VIM_STATE (self));
+       buffer = gtk_source_vim_state_get_buffer (GTK_SOURCE_VIM_STATE (self), &iter, NULL);
 
        if (self->suffix)
        {
@@ -199,14 +202,14 @@ gtk_source_vim_insert_enter (GtkSourceVimState *state)
                {
                        gtk_text_buffer_insert (GTK_TEXT_BUFFER (buffer), &iter, self->suffix, -1);
                        gtk_text_iter_backward_chars (&iter, len);
-                       gtk_source_vim_state_select (state, &iter, &iter);
+                       gtk_source_vim_state_select (GTK_SOURCE_VIM_STATE (self), &iter, &iter);
                }
        }
 
        if (self->prefix)
        {
                gtk_text_buffer_insert (GTK_TEXT_BUFFER (buffer), &iter, self->prefix, -1);
-               gtk_source_vim_state_select (state, &iter, &iter);
+               gtk_source_vim_state_select (GTK_SOURCE_VIM_STATE (self), &iter, &iter);
        }
 
        if (self->indent)
@@ -220,6 +223,63 @@ gtk_source_vim_insert_enter (GtkSourceVimState *state)
        }
 }
 
+static void
+gtk_source_vim_insert_enter (GtkSourceVimState *state)
+{
+       GtkSourceVimInsert *self = (GtkSourceVimInsert *)state;
+
+       g_assert (GTK_SOURCE_IS_VIM_INSERT (self));
+
+       gtk_source_vim_state_set_overwrite (state, FALSE);
+
+       g_clear_object (&self->history);
+       self->history = g_object_new (GTK_SOURCE_TYPE_VIM_TEXT_HISTORY, NULL);
+
+       gtk_source_vim_insert_prepare (self);
+}
+
+static void
+gtk_source_vim_insert_leave (GtkSourceVimState *state)
+{
+       GtkSourceVimInsert *self = (GtkSourceVimInsert *)state;
+       GtkSourceVimState *history;
+       int count;
+
+       g_assert (GTK_SOURCE_IS_VIM_INSERT (self));
+
+       count = gtk_source_vim_state_get_count (state);
+       history = GTK_SOURCE_VIM_STATE (self->history);
+
+       gtk_source_vim_state_push (state, g_object_ref (history));
+       while (--count > 0)
+       {
+               gtk_source_vim_insert_prepare (self);
+               gtk_source_vim_text_history_replay (self->history);
+       }
+       gtk_source_vim_state_pop (history);
+}
+
+static void
+gtk_source_vim_insert_repeat (GtkSourceVimState *state)
+{
+       GtkSourceVimInsert *self = (GtkSourceVimInsert *)state;
+       GtkSourceVimState *history;
+       int count;
+
+       g_assert (GTK_SOURCE_IS_VIM_INSERT (self));
+
+       count = gtk_source_vim_state_get_count (state);
+       history = GTK_SOURCE_VIM_STATE (self->history);
+
+       gtk_source_vim_state_push (state, g_object_ref (history));
+       for (int i = 0; i < count; i++)
+       {
+               gtk_source_vim_insert_prepare (self);
+               gtk_source_vim_text_history_replay (self->history);
+       }
+       gtk_source_vim_state_pop (history);
+}
+
 static void
 gtk_source_vim_insert_append_command (GtkSourceVimState *state,
                                       GString           *string)
@@ -288,6 +348,7 @@ gtk_source_vim_insert_dispose (GObject *object)
        GtkSourceVimInsert *self = (GtkSourceVimInsert *)object;
 
        g_clear_pointer (&self->prefix, g_free);
+       g_clear_object (&self->history);
 
        G_OBJECT_CLASS (gtk_source_vim_insert_parent_class)->dispose (object);
 }
@@ -307,6 +368,8 @@ gtk_source_vim_insert_class_init (GtkSourceVimInsertClass *klass)
        state_class->handle_event = gtk_source_vim_insert_handle_event;
        state_class->resume = gtk_source_vim_insert_resume;
        state_class->enter = gtk_source_vim_insert_enter;
+       state_class->leave = gtk_source_vim_insert_leave;
+       state_class->repeat = gtk_source_vim_insert_repeat;
 
        properties [PROP_INDENT] =
                g_param_spec_boolean ("indent",
diff --git a/gtksourceview/vim/gtk-source-vim-normal.c b/gtksourceview/vim/gtk-source-vim-normal.c
index d8b4ad36..c3227167 100644
--- a/gtksourceview/vim/gtk-source-vim-normal.c
+++ b/gtksourceview/vim/gtk-source-vim-normal.c
@@ -183,7 +183,9 @@ gtk_source_vim_normal_begin_delete (GtkSourceVimNormal *self,
 
        del = gtk_source_vim_delete_new (GTK_SOURCE_VIM_MOTION (motion));
 
+       gtk_source_vim_state_set_count (del, self->count);
        gtk_source_vim_state_push (GTK_SOURCE_VIM_STATE (self), del);
+
        if (motion != NULL)
                gtk_source_vim_state_pop (del);
 }
@@ -199,11 +201,13 @@ gtk_source_vim_normal_begin_change (GtkSourceVimNormal *self,
        const char *first_property_name;
        GtkTextIter iter, selection;
        va_list args;
+       int count;
 
        g_assert (GTK_SOURCE_IS_VIM_NORMAL (self));
        g_assert (!motion || GTK_SOURCE_IS_VIM_MOTION (motion));
 
        buffer = gtk_source_vim_state_get_buffer (GTK_SOURCE_VIM_STATE (self), &iter, &selection);
+       count = self->count;
 
        gtk_text_buffer_begin_user_action (GTK_TEXT_BUFFER (buffer));
 
@@ -225,6 +229,7 @@ gtk_source_vim_normal_begin_change (GtkSourceVimNormal *self,
        ret = GTK_SOURCE_VIM_STATE (g_object_new_valist (GTK_SOURCE_TYPE_VIM_INSERT, first_property_name, 
args));
        va_end (args);
 
+       gtk_source_vim_state_set_count (ret, count);
        gtk_source_vim_state_push (GTK_SOURCE_VIM_STATE (self), ret);
 
        gtk_text_buffer_end_user_action (GTK_TEXT_BUFFER (buffer));
@@ -250,10 +255,13 @@ gtk_source_vim_normal_begin_insert (GtkSourceVimNormal *self,
        GtkSourceVimState *ret;
        const char *first_property_name;
        va_list args;
+       int count;
 
        g_assert (GTK_SOURCE_IS_VIM_NORMAL (self));
        g_assert (!motion || GTK_SOURCE_IS_VIM_MOTION (motion));
 
+       count = self->count;
+
        if (motion != NULL)
        {
                gtk_source_vim_state_push (GTK_SOURCE_VIM_STATE (self), motion);
@@ -282,6 +290,7 @@ gtk_source_vim_normal_begin_insert (GtkSourceVimNormal *self,
        ret = GTK_SOURCE_VIM_STATE (g_object_new_valist (GTK_SOURCE_TYPE_VIM_INSERT, first_property_name, 
args));
        va_end (args);
 
+       gtk_source_vim_state_set_count (ret, count);
        gtk_source_vim_state_push (GTK_SOURCE_VIM_STATE (self), ret);
 
        return ret;
@@ -294,12 +303,16 @@ key_handler_command (GtkSourceVimNormal *self,
                      GdkModifierType     mods,
                      const char         *string)
 {
+       GtkSourceVimState *new_state;
+
        g_assert (GTK_SOURCE_IS_VIM_NORMAL (self));
 
        switch (keyval)
        {
                case GDK_KEY_R:
-                       gtk_source_vim_state_push (GTK_SOURCE_VIM_STATE (self), gtk_source_vim_replace_new 
());
+                       new_state = gtk_source_vim_replace_new ();
+                       gtk_source_vim_state_set_count (new_state, self->count);
+                       gtk_source_vim_state_push (GTK_SOURCE_VIM_STATE (self), new_state);
                        return TRUE;
 
                case GDK_KEY_i:
@@ -617,6 +630,7 @@ key_handler_g (GtkSourceVimNormal *self,
                case GDK_KEY_e:
                case GDK_KEY_E:
                        new_state = gtk_source_vim_motion_new ();
+                       gtk_source_vim_state_set_count (new_state, self->count);
                        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);
@@ -639,6 +653,7 @@ key_handler_motion (GtkSourceVimNormal *self,
        g_assert (GTK_SOURCE_IS_VIM_NORMAL (self));
 
        new_state = gtk_source_vim_motion_new ();
+       gtk_source_vim_state_set_count (new_state, self->count);
        gtk_source_vim_state_push (GTK_SOURCE_VIM_STATE (self), new_state);
        gtk_source_vim_state_synthesize (new_state, keyval, mods);
 
@@ -899,11 +914,6 @@ gtk_source_vim_normal_suspend (GtkSourceVimState *state,
        g_assert (GTK_SOURCE_IS_VIM_NORMAL (self));
        g_assert (GTK_SOURCE_IS_VIM_STATE (to));
 
-       if (self->count)
-       {
-               gtk_source_vim_state_set_count (to, self->count);
-       }
-
        buffer = gtk_source_vim_state_get_buffer (state, NULL, NULL);
        gtk_text_buffer_begin_user_action (GTK_TEXT_BUFFER (buffer));
 }
diff --git a/gtksourceview/vim/gtk-source-vim-state.c b/gtksourceview/vim/gtk-source-vim-state.c
index ba03fd96..9228d698 100644
--- a/gtksourceview/vim/gtk-source-vim-state.c
+++ b/gtksourceview/vim/gtk-source-vim-state.c
@@ -444,11 +444,6 @@ gtk_source_vim_state_pop (GtkSourceVimState *self)
                GTK_SOURCE_VIM_STATE_GET_CLASS (self)->leave (self);
        }
 
-       if (GTK_SOURCE_VIM_STATE_GET_CLASS (parent)->resume)
-       {
-               GTK_SOURCE_VIM_STATE_GET_CLASS (parent)->resume (parent, self);
-       }
-
        /* Clear the parent's child pointer, since we are no longer the
         * active event delivery child. However, the parent can still keep
         * a reference around elsewhere if they like for replaying things.
@@ -458,6 +453,11 @@ gtk_source_vim_state_pop (GtkSourceVimState *self)
                parent_priv->child = NULL;
        }
 
+       if (GTK_SOURCE_VIM_STATE_GET_CLASS (parent)->resume)
+       {
+               GTK_SOURCE_VIM_STATE_GET_CLASS (parent)->resume (parent, self);
+       }
+
        g_clear_object (&parent);
        g_object_unref (self);
 }
diff --git a/gtksourceview/vim/gtk-source-vim-text-history.c b/gtksourceview/vim/gtk-source-vim-text-history.c
new file mode 100644
index 00000000..fa0f1738
--- /dev/null
+++ b/gtksourceview/vim/gtk-source-vim-text-history.c
@@ -0,0 +1,100 @@
+/*
+ * This file is part of GtkSourceView
+ *
+ * Copyright 2021 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
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * GtkSourceView is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#include "config.h"
+
+#include "gtk-source-vim-text-history.h"
+
+struct _GtkSourceVimTextHistory
+{
+       GObject      parent_instance;
+       GPtrArray   *events;
+};
+
+G_DEFINE_TYPE (GtkSourceVimTextHistory, gtk_source_vim_text_history, GTK_SOURCE_TYPE_VIM_STATE)
+
+GtkSourceVimState *
+gtk_source_vim_text_history_new (void)
+{
+       return g_object_new (GTK_SOURCE_TYPE_VIM_TEXT_HISTORY, NULL);
+}
+
+static void
+gtk_source_vim_text_history_dispose (GObject *object)
+{
+       GtkSourceVimTextHistory *self = (GtkSourceVimTextHistory *)object;
+
+       g_clear_pointer (&self->events, g_ptr_array_unref);
+
+       G_OBJECT_CLASS (gtk_source_vim_text_history_parent_class)->dispose (object);
+}
+
+static void
+gtk_source_vim_text_history_class_init (GtkSourceVimTextHistoryClass *klass)
+{
+       GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+       object_class->dispose = gtk_source_vim_text_history_dispose;
+}
+
+static void
+gtk_source_vim_text_history_init (GtkSourceVimTextHistory *self)
+{
+       self->events = g_ptr_array_new_with_free_func ((GDestroyNotify)gdk_event_unref);
+}
+
+void
+gtk_source_vim_text_history_record (GtkSourceVimTextHistory *self,
+                                    GdkEvent                *event)
+{
+       g_return_if_fail (GTK_SOURCE_IS_VIM_TEXT_HISTORY (self));
+       g_return_if_fail (event != NULL);
+
+       g_ptr_array_add (self->events, gdk_event_ref (event));
+}
+
+void
+gtk_source_vim_text_history_replay (GtkSourceVimTextHistory *self)
+{
+       static guint signal_id;
+       GtkSourceView *view;
+       GdkSurface *surface;
+       GtkNative *native;
+
+       g_return_if_fail (GTK_SOURCE_IS_VIM_TEXT_HISTORY (self));
+
+       if (signal_id == 0)
+       {
+               signal_id = g_signal_lookup ("event", GDK_TYPE_SURFACE);
+       }
+
+       view = gtk_source_vim_state_get_view (GTK_SOURCE_VIM_STATE (self));
+       native = gtk_widget_get_native (GTK_WIDGET (view));
+       surface = gtk_native_get_surface (native);
+
+       for (guint i = 0; i < self->events->len; i++)
+       {
+               GdkEvent *event = g_ptr_array_index (self->events, i);
+               gboolean ret;
+
+               g_signal_emit (surface, signal_id, 0, event, &ret);
+       }
+}
diff --git a/gtksourceview/vim/gtk-source-vim-text-history.h b/gtksourceview/vim/gtk-source-vim-text-history.h
new file mode 100644
index 00000000..de56daec
--- /dev/null
+++ b/gtksourceview/vim/gtk-source-vim-text-history.h
@@ -0,0 +1,37 @@
+/*
+ * This file is part of GtkSourceView
+ *
+ * Copyright 2021 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
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * GtkSourceView is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#pragma once
+
+#include "gtk-source-vim-state.h"
+
+G_BEGIN_DECLS
+
+#define GTK_SOURCE_TYPE_VIM_TEXT_HISTORY (gtk_source_vim_text_history_get_type())
+
+G_DECLARE_FINAL_TYPE (GtkSourceVimTextHistory, gtk_source_vim_text_history, GTK_SOURCE, VIM_TEXT_HISTORY, 
GtkSourceVimState)
+
+GtkSourceVimState *gtk_source_vim_text_history_new    (void);
+void               gtk_source_vim_text_history_replay (GtkSourceVimTextHistory *self);
+void               gtk_source_vim_text_history_record (GtkSourceVimTextHistory *self,
+                                                       GdkEvent                *event);
+
+G_END_DECLS
diff --git a/gtksourceview/vim/meson.build b/gtksourceview/vim/meson.build
index a9985840..b164ce2a 100644
--- a/gtksourceview/vim/meson.build
+++ b/gtksourceview/vim/meson.build
@@ -8,4 +8,5 @@ vim_sources = files([
   'gtk-source-vim-insert-literal.c',
   'gtk-source-vim-replace.c',
   'gtk-source-vim-state.c',
+  'gtk-source-vim-text-history.c',
 ])


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