[gtksourceview/wip/chergert/vim: 14/293] start on idea for classes for state




commit 294b89d0e5312d3a7219a52244c8941b60d128b9
Author: Christian Hergert <chergert redhat com>
Date:   Tue Oct 19 17:24:59 2021 -0700

    start on idea for classes for state
    
    the main thing is that we want a better way to handle repeat as well as
    moving in/out of states (suspend/restore).

 gtksourceview/gtksourcevimstate.c | 347 ++++++++++++++++++++++++++++++++++++++
 gtksourceview/gtksourcevimstate.h |  70 ++++++++
 gtksourceview/meson.build         |   1 +
 3 files changed, 418 insertions(+)
---
diff --git a/gtksourceview/gtksourcevimstate.c b/gtksourceview/gtksourcevimstate.c
new file mode 100644
index 00000000..ab6218b2
--- /dev/null
+++ b/gtksourceview/gtksourcevimstate.c
@@ -0,0 +1,347 @@
+/*
+ * 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 "gtksourceview.h"
+#include "gtksourcevimstate.h"
+
+typedef struct
+{
+  GtkSourceVimState *parent;
+  GtkSourceView     *view;
+} GtkSourceVimStatePrivate;
+
+struct _GtkSourceVimNormal
+{
+  GtkSourceVimState parent_instance;
+};
+
+struct _GtkSourceVimInsert
+{
+  GtkSourceVimState parent_instance;
+};
+
+G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (GtkSourceVimState, gtk_source_vim_state, G_TYPE_OBJECT)
+G_DEFINE_TYPE (GtkSourceVimNormal, gtk_source_vim_normal, GTK_SOURCE_TYPE_VIM_STATE)
+G_DEFINE_TYPE (GtkSourceVimInsert, gtk_source_vim_insert, GTK_SOURCE_TYPE_VIM_STATE)
+
+enum {
+  STATE_PROP_0,
+  STATE_PROP_PARENT,
+  STATE_PROP_VIEW,
+  STATE_N_PROPS
+};
+
+static GParamSpec *state_properties [STATE_N_PROPS];
+
+static void
+gtk_source_vim_state_dispose (GObject *object)
+{
+  GtkSourceVimState *self = (GtkSourceVimState *)object;
+  GtkSourceVimStatePrivate *priv = gtk_source_vim_state_get_instance_private (self);
+
+  g_clear_object (&priv->parent);
+
+  G_OBJECT_CLASS (gtk_source_vim_state_parent_class)->dispose (object);
+}
+
+static void
+gtk_source_vim_state_get_property (GObject    *object,
+                                   guint       prop_id,
+                                   GValue     *value,
+                                   GParamSpec *pspec)
+{
+  GtkSourceVimState *self = GTK_SOURCE_VIM_STATE (object);
+
+  switch (prop_id)
+    {
+    case STATE_PROP_PARENT:
+      g_value_set_object (value, gtk_source_vim_state_get_parent (self));
+      break;
+
+    case STATE_PROP_VIEW:
+      g_value_set_object (value, gtk_source_vim_state_get_view (self));
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+    }
+}
+
+static void
+gtk_source_vim_state_set_property (GObject      *object,
+                                   guint         prop_id,
+                                   const GValue *value,
+                                   GParamSpec   *pspec)
+{
+  GtkSourceVimState *self = GTK_SOURCE_VIM_STATE (object);
+  GtkSourceVimStatePrivate *priv = gtk_source_vim_state_get_instance_private (self);
+
+  switch (prop_id)
+    {
+    case STATE_PROP_PARENT:
+      priv->parent = g_value_dup_object (value);
+      break;
+
+    case STATE_PROP_VIEW:
+      priv->view = g_value_dup_object (value);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+    }
+}
+
+static void
+gtk_source_vim_state_class_init (GtkSourceVimStateClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  object_class->dispose = gtk_source_vim_state_dispose;
+  object_class->get_property = gtk_source_vim_state_get_property;
+  object_class->set_property = gtk_source_vim_state_set_property;
+
+  state_properties [STATE_PROP_PARENT] =
+    g_param_spec_object ("parent",
+                         "Parent",
+                         "The parent state",
+                         GTK_SOURCE_TYPE_VIM_STATE,
+                         (G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
+
+  state_properties [STATE_PROP_VIEW] =
+    g_param_spec_object ("view",
+                         "View",
+                         "The source view",
+                         GTK_SOURCE_TYPE_VIEW,
+                         (G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_properties (object_class, STATE_N_PROPS, state_properties);
+}
+
+static void
+gtk_source_vim_state_init (GtkSourceVimState *self)
+{
+}
+
+void
+gtk_source_vim_state_get_iter (GtkSourceVimState *self,
+                               GtkTextIter       *iter)
+{
+  GtkSourceVimStatePrivate *priv = gtk_source_vim_state_get_instance_private (self);
+  GtkTextBuffer *buffer;
+  GtkTextMark *mark;
+
+  g_return_if_fail (GTK_SOURCE_IS_VIM_STATE (self));
+  g_return_if_fail (iter != NULL);
+
+  buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->view));
+  mark = gtk_text_buffer_get_insert (buffer);
+  gtk_text_buffer_get_iter_at_mark (buffer, iter, mark);
+}
+
+void
+gtk_source_vim_state_move_to (GtkSourceVimState *self,
+                              const GtkTextIter *iter)
+{
+  g_return_if_fail (GTK_SOURCE_IS_VIM_STATE (self));
+  g_return_if_fail (iter != NULL);
+
+  gtk_text_buffer_select_range (gtk_text_iter_get_buffer (iter), iter, iter);
+}
+
+/**
+ * gtk_source_vim_state_get_parent:
+ *
+ * Returns: (transfer none) (nullable): a #GtkSourceVimState or %NULL
+ */
+GtkSourceVimState *
+gtk_source_vim_state_get_parent (GtkSourceVimState *self)
+{
+  GtkSourceVimStatePrivate *priv = gtk_source_vim_state_get_instance_private (self);
+
+  g_return_val_if_fail (GTK_SOURCE_IS_VIM_STATE (self), NULL);
+
+  return priv->parent;
+}
+
+/**
+ * gtk_source_vim_state_get_view:
+ *
+ * Returns: (transfer none): a #GtkSourceView
+ */
+GtkSourceView *
+gtk_source_vim_state_get_view (GtkSourceVimState *self)
+{
+  GtkSourceVimStatePrivate *priv = gtk_source_vim_state_get_instance_private (self);
+
+  g_return_val_if_fail (GTK_SOURCE_IS_VIM_STATE (self), NULL);
+
+  return priv->view;
+}
+
+/**
+ * gtk_source_vim_state_enter:
+ *
+ * Called when a new state has been placed on the stack
+ * so that the state can finish initial setup.
+ */
+void
+gtk_source_vim_state_enter (GtkSourceVimState *self)
+{
+  g_return_if_fail (GTK_SOURCE_IS_VIM_STATE (self));
+
+  if (GTK_SOURCE_VIM_STATE_GET_CLASS (self)->enter)
+    GTK_SOURCE_VIM_STATE_GET_CLASS (self)->enter (self);
+}
+
+/**
+ * gtk_source_vim_state_leave:
+ *
+ * Called when a state is being removed from the stack
+ * (such as when it has completed).
+ */
+void
+gtk_source_vim_state_leave (GtkSourceVimState *self)
+{
+  g_return_if_fail (GTK_SOURCE_IS_VIM_STATE (self));
+
+  if (GTK_SOURCE_VIM_STATE_GET_CLASS (self)->leave)
+    GTK_SOURCE_VIM_STATE_GET_CLASS (self)->leave (self);
+}
+
+/**
+ * gtk_source_vim_state_suspend:
+ *
+ * Called when a state is being suspended because another
+ * state has been pushed onto the stack.
+ */
+void
+gtk_source_vim_state_suspend (GtkSourceVimState *self,
+                              GtkSourceVimState *to)
+{
+  g_return_if_fail (GTK_SOURCE_IS_VIM_STATE (self));
+  g_return_if_fail (GTK_SOURCE_IS_VIM_STATE (to));
+
+  if (GTK_SOURCE_VIM_STATE_GET_CLASS (self)->suspend)
+    GTK_SOURCE_VIM_STATE_GET_CLASS (self)->suspend (self, to);
+}
+
+/**
+ * gtk_source_vim_state_restore:
+ *
+ * Called when a state is being restored because another
+ * state has been popped off the stack and @self is now the
+ * current state.
+ */
+void
+gtk_source_vim_state_restore (GtkSourceVimState *self,
+                              GtkSourceVimState *from)
+{
+  g_return_if_fail (GTK_SOURCE_IS_VIM_STATE (self));
+  g_return_if_fail (GTK_SOURCE_IS_VIM_STATE (from));
+
+  if (GTK_SOURCE_VIM_STATE_GET_CLASS (self)->restore)
+    GTK_SOURCE_VIM_STATE_GET_CLASS (self)->restore (self, from);
+}
+
+/**
+ * gtk_source_vim_state_handle:
+ *
+ * Handle an incoming key press or release event.
+ */
+gboolean
+gtk_source_vim_state_handle (GtkSourceVimState *self,
+                             GdkEvent          *event)
+{
+  g_return_val_if_fail (GTK_SOURCE_IS_VIM_STATE (self), FALSE);
+  g_return_val_if_fail (event != NULL, FALSE);
+
+  if (GTK_SOURCE_VIM_STATE_GET_CLASS (self)->handle)
+    return GTK_SOURCE_VIM_STATE_GET_CLASS (self)->handle (self, event);
+
+  return FALSE;
+}
+
+static gboolean
+gtk_source_vim_normal_handle (GtkSourceVimState *state,
+                              GdkEvent          *event)
+{
+  GtkSourceVimNormal *self = (GtkSourceVimNormal *)state;
+
+  g_assert (GTK_SOURCE_IS_VIM_NORMAL (self));
+  g_assert (event != NULL);
+
+  return FALSE;
+}
+
+static void
+gtk_source_vim_normal_restore (GtkSourceVimState *state,
+                               GtkSourceVimState *from)
+{
+  GtkSourceVimNormal *self = (GtkSourceVimNormal *)state;
+
+  g_assert (GTK_SOURCE_IS_VIM_NORMAL (self));
+
+  /* If we have a count to repeat, then we should perform that now. */
+
+  /* If we are restoring from an insert, then we need to move
+   * the cursor back one character so the block cursor appears
+   * on the right character.
+   */
+  if (GTK_SOURCE_IS_VIM_INSERT (from))
+    {
+      GtkTextIter iter;
+
+      gtk_source_vim_state_get_iter (state, &iter);
+
+      if (!gtk_text_iter_starts_line (&iter))
+        {
+          gtk_text_iter_backward_char (&iter);
+          gtk_source_vim_state_move_to (state, &iter);
+        }
+    }
+}
+
+static void
+gtk_source_vim_normal_class_init (GtkSourceVimNormalClass *klass)
+{
+  GtkSourceVimStateClass *state_class = GTK_SOURCE_VIM_STATE_CLASS (klass);
+
+  state_class->handle = gtk_source_vim_normal_handle;
+  state_class->restore = gtk_source_vim_normal_restore;
+}
+
+static void
+gtk_source_vim_normal_init (GtkSourceVimNormal *self)
+{
+}
+
+static void
+gtk_source_vim_insert_class_init (GtkSourceVimInsertClass *klass)
+{
+  GtkSourceVimStateClass *state_class = GTK_SOURCE_VIM_STATE_CLASS (klass);
+}
+
+static void
+gtk_source_vim_insert_init (GtkSourceVimInsert *self)
+{
+}
diff --git a/gtksourceview/gtksourcevimstate.h b/gtksourceview/gtksourcevimstate.h
new file mode 100644
index 00000000..c00a5553
--- /dev/null
+++ b/gtksourceview/gtksourcevimstate.h
@@ -0,0 +1,70 @@
+/*
+ * 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 <gdk/gdk.h>
+
+#include "gtksourcetypes.h"
+#include "gtksourcetypes-private.h"
+
+G_BEGIN_DECLS
+
+#define GTK_SOURCE_TYPE_VIM_STATE (gtk_source_vim_state_get_type())
+
+G_DECLARE_DERIVABLE_TYPE (GtkSourceVimState, gtk_source_vim_state, GTK_SOURCE, VIM_STATE, GObject)
+
+struct _GtkSourceVimStateClass
+{
+  GObject parent_class;
+
+  void     (*enter)   (GtkSourceVimState *state);
+  void     (*leave)   (GtkSourceVimState *state);
+  void     (*suspend) (GtkSourceVimState *state,
+                       GtkSourceVimState *to);
+  void     (*restore) (GtkSourceVimState *state,
+                       GtkSourceVimState *from);
+  gboolean (*handle)  (GtkSourceVimState *state,
+                       GdkEvent          *event);
+};
+
+GtkSourceVimState *gtk_source_vim_state_get_parent (GtkSourceVimState *self);
+GtkSourceView     *gtk_source_vim_state_get_view   (GtkSourceVimState *self);
+void               gtk_source_vim_state_enter      (GtkSourceVimState *self);
+void               gtk_source_vim_state_leave      (GtkSourceVimState *self);
+void               gtk_source_vim_state_suspend    (GtkSourceVimState *self,
+                                                    GtkSourceVimState *to);
+void               gtk_source_vim_state_restore    (GtkSourceVimState *self,
+                                                    GtkSourceVimState *from);
+gboolean           gtk_source_vim_state_handle     (GtkSourceVimState *self,
+                                                    GdkEvent          *event);
+void               gtk_source_vim_state_get_iter   (GtkSourceVimState *self,
+                                                    GtkTextIter       *iter);
+void               gtk_source_vim_state_move_to    (GtkSourceVimState *self,
+                                                    const GtkTextIter *iter);
+
+#define GTK_SOURCE_TYPE_VIM_NORMAL (gtk_source_vim_normal_get_type())
+G_DECLARE_FINAL_TYPE (GtkSourceVimNormal, gtk_source_vim_normal, GTK_SOURCE, VIM_NORMAL, GtkSourceVimState)
+
+#define GTK_SOURCE_TYPE_VIM_INSERT (gtk_source_vim_insert_get_type())
+G_DECLARE_FINAL_TYPE (GtkSourceVimInsert, gtk_source_vim_insert, GTK_SOURCE, VIM_INSERT, GtkSourceVimState)
+
+G_END_DECLS
diff --git a/gtksourceview/meson.build b/gtksourceview/meson.build
index 4ef73c35..b4f55ccb 100644
--- a/gtksourceview/meson.build
+++ b/gtksourceview/meson.build
@@ -136,6 +136,7 @@ core_private_c = files([
   'gtksourcesnippetbundle-parser.c',
   'gtksourceview-snippets.c',
   'gtksourcevim.c',
+  'gtksourcevimstate.c',
   'implregex.c',
 ])
 


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