[gtksourceview/wip/chergert/vim: 20/293] more work on layered state in vim/




commit f058870e87df2239ab3150d82517f54984f19c17
Author: Christian Hergert <chergert redhat com>
Date:   Thu Oct 21 15:26:09 2021 -0700

    more work on layered state in vim/

 gtksourceview/gtksourcetypes-private.h         |   2 -
 gtksourceview/gtksourcetypes.h                 |   1 +
 gtksourceview/gtksourcevim-private.h           |  71 ----
 gtksourceview/gtksourcevim.c                   | 435 ------------------------
 gtksourceview/gtksourcevimimcontext.c          | 230 +++----------
 gtksourceview/gtksourcevimimcontext.h          |  12 +-
 gtksourceview/gtksourcevimstate.c              | 438 -------------------------
 gtksourceview/gtksourcevimstate.h              |  75 -----
 gtksourceview/meson.build                      |   5 +-
 gtksourceview/vim/gtk-source-vim-command-bar.c |  56 ++++
 gtksourceview/vim/gtk-source-vim-command-bar.h |  34 ++
 gtksourceview/vim/gtk-source-vim-insert.h      |   8 +-
 gtksourceview/vim/gtk-source-vim-normal.c      |  22 +-
 gtksourceview/vim/gtk-source-vim-normal.h      |   7 +-
 gtksourceview/vim/gtk-source-vim-replace.h     |   6 +-
 gtksourceview/vim/gtk-source-vim-state.c       |  46 ++-
 gtksourceview/vim/gtk-source-vim-state.h       |   7 +-
 gtksourceview/vim/gtk-source-vim-visual.h      |   7 +-
 gtksourceview/vim/gtk-source-vim.c             | 243 ++++++++++++++
 gtksourceview/vim/gtk-source-vim.h             |  20 +-
 gtksourceview/vim/meson.build                  |   6 +
 21 files changed, 479 insertions(+), 1252 deletions(-)
---
diff --git a/gtksourceview/gtksourcetypes-private.h b/gtksourceview/gtksourcetypes-private.h
index 669bbc0a..cde07715 100644
--- a/gtksourceview/gtksourcetypes-private.h
+++ b/gtksourceview/gtksourcetypes-private.h
@@ -39,8 +39,6 @@ typedef struct _GtkSourceMarksSequence          GtkSourceMarksSequence;
 typedef struct _GtkSourcePixbufHelper           GtkSourcePixbufHelper;
 typedef struct _GtkSourceRegex                  GtkSourceRegex;
 typedef struct _GtkSourceSnippetBundle          GtkSourceSnippetBundle;
-typedef struct _GtkSourceVim                    GtkSourceVim;
-typedef struct _GtkSourceVimCallbacks           GtkSourceVimCallbacks;
 
 #ifdef _MSC_VER
 /* For Visual Studio, we need to export the symbols used by the unit tests */
diff --git a/gtksourceview/gtksourcetypes.h b/gtksourceview/gtksourcetypes.h
index a6a8da02..61859e31 100644
--- a/gtksourceview/gtksourcetypes.h
+++ b/gtksourceview/gtksourcetypes.h
@@ -54,6 +54,7 @@ typedef struct _GtkSourceHover                     GtkSourceHover;
 typedef struct _GtkSourceHoverContext              GtkSourceHoverContext;
 typedef struct _GtkSourceHoverDisplay              GtkSourceHoverDisplay;
 typedef struct _GtkSourceHoverProvider             GtkSourceHoverProvider;
+typedef struct _GtkSourceVimIMContext              GtkSourceVimIMContext;
 typedef struct _GtkSourceIndenter                  GtkSourceIndenter;
 typedef struct _GtkSourceLanguage                  GtkSourceLanguage;
 typedef struct _GtkSourceLanguageManager           GtkSourceLanguageManager;
diff --git a/gtksourceview/gtksourcevimimcontext.c b/gtksourceview/gtksourcevimimcontext.c
index 0e7a6c6a..c61aec94 100644
--- a/gtksourceview/gtksourcevimimcontext.c
+++ b/gtksourceview/gtksourcevimimcontext.c
@@ -23,18 +23,14 @@
 
 #include "gtksourceview.h"
 #include "gtksourcevimimcontext.h"
-#include "gtksourcevim-private.h"
-
 #include "gtksource-enumtypes.h"
 
+#include "vim/gtk-source-vim.h"
+
 struct _GtkSourceVimIMContext
 {
-       GtkIMContext      parent_instance;
-       GtkSourceView    *view;
-       GtkSourceVim     *vim;
-       char             *command_bar_text;
-       char             *command_text;
-       GtkSourceVimMode  mode;
+       GtkIMContext  parent_instance;
+       GtkSourceVim *vim;
 };
 
 G_DEFINE_TYPE (GtkSourceVimIMContext, gtk_source_vim_im_context, GTK_TYPE_IM_CONTEXT)
@@ -43,12 +39,10 @@ enum {
        PROP_0,
        PROP_COMMAND_BAR_TEXT,
        PROP_COMMAND_TEXT,
-       PROP_MODE,
-       PROP_VIEW,
        N_PROPS
 };
 
-static GParamSpec *properties [N_PROPS];
+static GParamSpec *properties[N_PROPS];
 
 GtkIMContext *
 gtk_source_vim_im_context_new (void)
@@ -64,10 +58,19 @@ gtk_source_vim_im_context_set_client_widget (GtkIMContext *context,
 
        g_return_if_fail (GTK_SOURCE_IS_VIM_IM_CONTEXT (self));
 
-       if (g_set_weak_pointer (&self->view, GTK_SOURCE_VIEW (widget)))
+       if (!GTK_SOURCE_IS_VIEW (widget))
+               return;
+
+       if (self->vim != NULL)
        {
-               gtk_source_vim_set_view (self->vim, self->view);
+               g_object_run_dispose (G_OBJECT (self->vim));
+               g_clear_object (&self->vim);
        }
+
+       self->vim = gtk_source_vim_new (GTK_SOURCE_VIEW (widget));
+
+       g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_COMMAND_TEXT]);
+       g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_COMMAND_BAR_TEXT]);
 }
 
 static void
@@ -84,92 +87,44 @@ static void
 gtk_source_vim_im_context_focus_in (GtkIMContext *context)
 {
        GtkSourceVimIMContext *self = (GtkSourceVimIMContext *)context;
+       GtkSourceView *view;
 
        g_return_if_fail (GTK_SOURCE_IS_VIM_IM_CONTEXT (self));
 
-       gtk_text_view_set_overwrite (GTK_TEXT_VIEW (self->view), TRUE);
-       gtk_text_view_set_cursor_visible (GTK_TEXT_VIEW (self->view), TRUE);
-
-       g_print ("Focus in %p\n", self->view);
-}
-
-static void
-gtk_source_vim_im_context_focus_out (GtkIMContext *context)
-{
-       GtkSourceVimIMContext *self = (GtkSourceVimIMContext *)context;
-
-       g_return_if_fail (GTK_SOURCE_IS_VIM_IM_CONTEXT (self));
-
-       gtk_text_view_set_overwrite (GTK_TEXT_VIEW (self->view), FALSE);
-       gtk_text_view_set_cursor_visible (GTK_TEXT_VIEW (self->view), FALSE);
+       if (self->vim == NULL)
+               return;
 
-       g_print ("Focus out\n");
-}
-
-static void
-gtk_source_vim_im_context_beep (gpointer user_data)
-{
-       GtkSourceVimIMContext *self = user_data;
-       GdkDisplay *display;
-
-       g_assert (GTK_SOURCE_IS_VIM_IM_CONTEXT (self));
+       view = gtk_source_vim_state_get_view (GTK_SOURCE_VIM_STATE (self->vim));
 
-       if (self->view != NULL &&
-           (display = gtk_widget_get_display (GTK_WIDGET (self->view))))
+       if (view != NULL)
        {
-               gdk_display_beep (display);
+               gtk_text_view_set_overwrite (GTK_TEXT_VIEW (view), TRUE);
+               gtk_text_view_set_cursor_visible (GTK_TEXT_VIEW (view), TRUE);
        }
-}
-
-static void
-gtk_source_vim_im_context_set_mode (GtkSourceVimMode mode,
-                                    gpointer         user_data)
-{
-       GtkSourceVimIMContext *self = user_data;
-
-       g_assert (GTK_SOURCE_IS_VIM_IM_CONTEXT (self));
 
-       self->mode = mode;
-       g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_MODE]);
+       g_print ("Focus in %p\n", view);
 }
 
 static void
-gtk_source_vim_im_context_set_label (GtkSourceVimLabel  label,
-                                     const char        *text,
-                                     gpointer           user_data)
+gtk_source_vim_im_context_focus_out (GtkIMContext *context)
 {
-       GtkSourceVimIMContext *self = user_data;
+       GtkSourceVimIMContext *self = (GtkSourceVimIMContext *)context;
+       GtkSourceView *view;
 
-       g_assert (GTK_SOURCE_IS_VIM_IM_CONTEXT (self));
+       g_return_if_fail (GTK_SOURCE_IS_VIM_IM_CONTEXT (self));
 
-       if (label == GTK_SOURCE_VIM_LABEL_COMMAND_BAR)
-       {
-               g_free (self->command_bar_text);
-               self->command_bar_text = g_strdup (text);
-               g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_COMMAND_BAR_TEXT]);
-       }
-       else if (label == GTK_SOURCE_VIM_LABEL_COMMAND)
-       {
-               g_free (self->command_text);
-               self->command_text = g_strdup (text);
-               g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_COMMAND_TEXT]);
-       }
-}
+       g_print ("Focus out\n");
 
-static gboolean
-gtk_source_vim_im_context_propagate_keypress (GdkEvent *event,
-                                              gpointer  user_data)
-{
-       GtkSourceVimIMContext *self = user_data;
+       if (self->vim == NULL)
+               return;
 
-       g_assert (GTK_SOURCE_IS_VIM_IM_CONTEXT (self));
+       view = gtk_source_vim_state_get_view (GTK_SOURCE_VIM_STATE (self->vim));
 
-       if (self->view == NULL)
+       if (view != NULL)
        {
-               return FALSE;
+               gtk_text_view_set_overwrite (GTK_TEXT_VIEW (view), FALSE);
+               gtk_text_view_set_cursor_visible (GTK_TEXT_VIEW (view), FALSE);
        }
-
-       return gtk_text_view_im_context_filter_keypress (GTK_TEXT_VIEW (self->view), event);
 }
 
 static gboolean
@@ -177,28 +132,27 @@ gtk_source_vim_im_context_filter_keypress (GtkIMContext *context,
                                            GdkEvent     *event)
 {
        GtkSourceVimIMContext *self = (GtkSourceVimIMContext *)context;
-       GdkModifierType state;
-       gboolean ret = FALSE;
-       guint keyval;
 
        g_assert (GTK_SOURCE_IS_VIM_IM_CONTEXT (self));
        g_assert (gdk_event_get_event_type (event) == GDK_KEY_PRESS ||
                  gdk_event_get_event_type (event) == GDK_KEY_RELEASE);
 
-       return gtk_source_vim_deliver (self->vim, event);
+       if (self->vim == NULL)
+       {
+               return FALSE;
+       }
+
+       return gtk_source_vim_state_handle_event (GTK_SOURCE_VIM_STATE (self->vim), event);
 }
 
 static void
-gtk_source_vim_im_context_finalize (GObject *object)
+gtk_source_vim_im_context_dispose (GObject *object)
 {
        GtkSourceVimIMContext *self = (GtkSourceVimIMContext *)object;
 
-       g_clear_weak_pointer (&self->view);
-       g_clear_pointer (&self->vim, gtk_source_vim_free);
-       g_clear_pointer (&self->command_text, g_free);
-       g_clear_pointer (&self->command_bar_text, g_free);
+       g_clear_object (&self->vim);
 
-       G_OBJECT_CLASS (gtk_source_vim_im_context_parent_class)->finalize (object);
+       G_OBJECT_CLASS (gtk_source_vim_im_context_parent_class)->dispose (object);
 }
 
 static void
@@ -219,27 +173,6 @@ gtk_source_vim_im_context_get_property (GObject    *object,
                g_value_set_string (value, gtk_source_vim_im_context_get_command_bar_text (self));
                break;
 
-       case PROP_VIEW:
-               g_value_set_object (value, gtk_source_vim_im_context_get_view (self));
-               break;
-
-       case PROP_MODE:
-               g_value_set_static_string (value, gtk_source_vim_im_context_get_mode (self));
-               break;
-
-       default:
-               G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-       }
-}
-
-static void
-gtk_source_vim_im_context_set_property (GObject      *object,
-                                        guint         prop_id,
-                                        const GValue *value,
-                                        GParamSpec   *pspec)
-{
-       switch (prop_id)
-       {
        default:
                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
        }
@@ -251,9 +184,8 @@ gtk_source_vim_im_context_class_init (GtkSourceVimIMContextClass *klass)
        GObjectClass *object_class = G_OBJECT_CLASS (klass);
        GtkIMContextClass *im_context_class = GTK_IM_CONTEXT_CLASS (klass);
 
-       object_class->finalize = gtk_source_vim_im_context_finalize;
+       object_class->dispose = gtk_source_vim_im_context_dispose;
        object_class->get_property = gtk_source_vim_im_context_get_property;
-       object_class->set_property = gtk_source_vim_im_context_set_property;
 
        im_context_class->set_client_widget = gtk_source_vim_im_context_set_client_widget;
        im_context_class->reset = gtk_source_vim_im_context_reset;
@@ -261,13 +193,6 @@ gtk_source_vim_im_context_class_init (GtkSourceVimIMContextClass *klass)
        im_context_class->focus_out = gtk_source_vim_im_context_focus_out;
        im_context_class->filter_keypress = gtk_source_vim_im_context_filter_keypress;
 
-       properties [PROP_VIEW] =
-               g_param_spec_object ("view",
-                                    "View",
-                                    "The view the IM context is attached to",
-                                    GTK_SOURCE_TYPE_VIEW,
-                                    (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
-
        properties [PROP_COMMAND_TEXT] =
                g_param_spec_string ("command-text",
                                     "Command Text",
@@ -282,45 +207,12 @@ gtk_source_vim_im_context_class_init (GtkSourceVimIMContextClass *klass)
                                     NULL,
                                     (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
 
-       properties [PROP_MODE] =
-               g_param_spec_string ("mode",
-                                    "Mode",
-                                    "The VIM mode for the context",
-                                    "NORMAL",
-                                    (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
-
        g_object_class_install_properties (object_class, N_PROPS, properties);
 }
 
 static void
 gtk_source_vim_im_context_init (GtkSourceVimIMContext *self)
 {
-       static const GtkSourceVimCallbacks callbacks = {
-               .beep = gtk_source_vim_im_context_beep,
-               .set_mode = gtk_source_vim_im_context_set_mode,
-               .set_label = gtk_source_vim_im_context_set_label,
-               .filter_keypress = gtk_source_vim_im_context_propagate_keypress,
-       };
-
-       self->vim = gtk_source_vim_new (&callbacks, self);
-}
-
-/**
- * gtk_source_vim_im_context_get_view:
- * @self: a #GtkSourceVimIMContext
- *
- * Gets the #GtkSourceView that @self is attached to.
- *
- * Returns: (transfer none) (nullable): a #GtkSourceView or %NULL
- *
- * Since: 5.4
- */
-GtkSourceView *
-gtk_source_vim_im_context_get_view (GtkSourceVimIMContext *self)
-{
-       g_return_val_if_fail (GTK_SOURCE_IS_VIM_IM_CONTEXT (self), NULL);
-
-       return self->view;
 }
 
 /**
@@ -338,7 +230,10 @@ gtk_source_vim_im_context_get_command_text (GtkSourceVimIMContext *self)
 {
        g_return_val_if_fail (GTK_SOURCE_IS_VIM_IM_CONTEXT (self), NULL);
 
-       return self->command_text;
+       if (self->vim == NULL)
+               return NULL;
+
+       return gtk_source_vim_get_command_text (self->vim);
 }
 
 /**
@@ -356,29 +251,8 @@ gtk_source_vim_im_context_get_command_bar_text (GtkSourceVimIMContext *self)
 {
        g_return_val_if_fail (GTK_SOURCE_IS_VIM_IM_CONTEXT (self), NULL);
 
-       return self->command_bar_text;
-}
-
-const char *
-gtk_source_vim_im_context_get_mode (GtkSourceVimIMContext *self)
-{
-       g_return_val_if_fail (GTK_SOURCE_IS_VIM_IM_CONTEXT (self), 0);
-
-       switch ((int)self->mode)
-       {
-       case GTK_SOURCE_VIM_INSERT:
-               return "INSERT";
-       case GTK_SOURCE_VIM_REPLACE:
-               return "REPLACE";
-       case GTK_SOURCE_VIM_VIRTUAL_REPLACE:
-               return "VREPLACE";
-       case GTK_SOURCE_VIM_VISUAL:
-               return "VISUAL";
-       case GTK_SOURCE_VIM_VISUAL_LINE:
-               return "VISUAL LINE";
-       case GTK_SOURCE_VIM_VISUAL_BLOCK:
-               return "VISUAL BLOCK";
-       default:
+       if (self->vim == NULL)
                return NULL;
-       }
+
+       return gtk_source_vim_get_command_bar_text (self->vim);
 }
diff --git a/gtksourceview/gtksourcevimimcontext.h b/gtksourceview/gtksourcevimimcontext.h
index e3e10470..6c08f540 100644
--- a/gtksourceview/gtksourcevimimcontext.h
+++ b/gtksourceview/gtksourcevimimcontext.h
@@ -33,18 +33,14 @@ G_BEGIN_DECLS
 
 #define GTK_SOURCE_TYPE_VIM_IM_CONTEXT (gtk_source_vim_im_context_get_type())
 
-GTK_SOURCE_AVAILABLE_IN_5_4
+GTK_SOURCE_AVAILABLE_IN_ALL
 G_DECLARE_FINAL_TYPE (GtkSourceVimIMContext, gtk_source_vim_im_context, GTK_SOURCE, VIM_IM_CONTEXT, 
GtkIMContext)
 
-GTK_SOURCE_AVAILABLE_IN_5_4
+GTK_SOURCE_AVAILABLE_IN_ALL
 GtkIMContext     *gtk_source_vim_im_context_new                  (void);
-GTK_SOURCE_AVAILABLE_IN_5_4
-GtkSourceView    *gtk_source_vim_im_context_get_view             (GtkSourceVimIMContext *self);
-GTK_SOURCE_AVAILABLE_IN_5_4
+GTK_SOURCE_AVAILABLE_IN_ALL
 const char       *gtk_source_vim_im_context_get_command_text     (GtkSourceVimIMContext *self);
-GTK_SOURCE_AVAILABLE_IN_5_4
+GTK_SOURCE_AVAILABLE_IN_ALL
 const char       *gtk_source_vim_im_context_get_command_bar_text (GtkSourceVimIMContext *self);
-GTK_SOURCE_AVAILABLE_IN_5_4
-const char       *gtk_source_vim_im_context_get_mode             (GtkSourceVimIMContext *self);
 
 G_END_DECLS
diff --git a/gtksourceview/meson.build b/gtksourceview/meson.build
index b4f55ccb..ee9efebe 100644
--- a/gtksourceview/meson.build
+++ b/gtksourceview/meson.build
@@ -5,6 +5,8 @@ core_marshallers = gnome.genmarshal('gtksource-marshal',
   valist_marshallers: true,
 )
 
+subdir('vim')
+
 core_public_h = files([
   'gtksource.h',
   'gtksourcebuffer.h',
@@ -135,8 +137,6 @@ core_private_c = files([
   'gtksourcesnippetbundle.c',
   'gtksourcesnippetbundle-parser.c',
   'gtksourceview-snippets.c',
-  'gtksourcevim.c',
-  'gtksourcevimstate.c',
   'implregex.c',
 ])
 
@@ -225,6 +225,7 @@ core_sources = [
   gtksourceversion_h,
   core_marshallers,
   gtksource_res,
+  vim_sources,
 ]
 
 install_headers(
diff --git a/gtksourceview/vim/gtk-source-vim-command-bar.c b/gtksourceview/vim/gtk-source-vim-command-bar.c
new file mode 100644
index 00000000..cbb2385f
--- /dev/null
+++ b/gtksourceview/vim/gtk-source-vim-command-bar.c
@@ -0,0 +1,56 @@
+/*
+ * 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-command-bar.h"
+
+struct _GtkSourceVimCommandBar
+{
+       GtkSourceVimState parent_instance;
+};
+
+G_DEFINE_TYPE (GtkSourceVimCommandBar, gtk_source_vim_command_bar, GTK_SOURCE_TYPE_VIM_STATE)
+
+GtkSourceVimCommandBar *
+gtk_source_vim_command_bar_new (void)
+{
+       return g_object_new (GTK_SOURCE_TYPE_VIM_COMMAND_BAR, NULL);
+}
+
+static void
+gtk_source_vim_command_bar_dispose (GObject *object)
+{
+       G_OBJECT_CLASS (gtk_source_vim_command_bar_parent_class)->dispose (object);
+}
+
+static void
+gtk_source_vim_command_bar_class_init (GtkSourceVimCommandBarClass *klass)
+{
+       GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+       object_class->dispose = gtk_source_vim_command_bar_dispose;
+}
+
+static void
+gtk_source_vim_command_bar_init (GtkSourceVimCommandBar *self)
+{
+}
diff --git a/gtksourceview/vim/gtk-source-vim-command-bar.h b/gtksourceview/vim/gtk-source-vim-command-bar.h
new file mode 100644
index 00000000..bf212128
--- /dev/null
+++ b/gtksourceview/vim/gtk-source-vim-command-bar.h
@@ -0,0 +1,34 @@
+/*
+ * 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_COMMAND_BAR (gtk_source_vim_command_bar_get_type())
+
+G_DECLARE_FINAL_TYPE (GtkSourceVimCommandBar, gtk_source_vim_command_bar, GTK_SOURCE, VIM_COMMAND_BAR, 
GtkSourceVimState)
+
+GtkSourceVimCommandBar *gtk_source_vim_command_bar_new (void);
+
+G_END_DECLS
diff --git a/gtksourceview/vim/gtk-source-vim-insert.h b/gtksourceview/vim/gtk-source-vim-insert.h
index 0d1b3d10..49ed3459 100644
--- a/gtksourceview/vim/gtk-source-vim-insert.h
+++ b/gtksourceview/vim/gtk-source-vim-insert.h
@@ -21,14 +21,14 @@
 
 #pragma once
 
-#include "gtksourcevimstate.h"
+#include "gtk-source-vim-state.h"
 
 G_BEGIN_DECLS
 
-#define GTK_TYPE_SOURCE_VIM_INSERT (gtk_source_vim_insert_get_type())
+#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, GObject)
+G_DECLARE_FINAL_TYPE (GtkSourceVimInsert, gtk_source_vim_insert, GTK_SOURCE, VIM_INSERT, GtkSourceVimState)
 
-GtkSourceVimInsert *gtk_source_vim_insert_new (GtkSourceVimState *parent);
+GtkSourceVimInsert *gtk_source_vim_insert_new (void);
 
 G_END_DECLS
diff --git a/gtksourceview/vim/gtk-source-vim-normal.c b/gtksourceview/vim/gtk-source-vim-normal.c
index b2e495aa..7f149042 100644
--- a/gtksourceview/vim/gtk-source-vim-normal.c
+++ b/gtksourceview/vim/gtk-source-vim-normal.c
@@ -21,7 +21,7 @@
 
 #include "config.h"
 
-#include "gtksourcevimnormal.h"
+#include "gtk-source-vim-normal.h"
 
 typedef enum
 {
@@ -62,7 +62,7 @@ is_escape (guint           keyval,
           GdkModifierType mods)
 {
        return keyval == GDK_KEY_Escape ||
-               (keyval == GDK_KEY_bracketleft && (state & GDK_CONTROL_MASK) != 0);
+               (keyval == GDK_KEY_bracketleft && (mods & GDK_CONTROL_MASK) != 0);
 }
 
 static void
@@ -91,6 +91,7 @@ gtk_source_vim_normal_handle_keypress (GtkSourceVimState *state,
                return TRUE;
        }
 
+#if 0
        if (keyval >= GDK_KEY_0 && keyval <= GDK_KEY_9)
        {
        }
@@ -138,6 +139,7 @@ gtk_source_vim_normal_handle_keypress (GtkSourceVimState *state,
        case GDK_KEY_9:
                break;
        }
+#endif
 
        return FALSE;
 }
@@ -176,11 +178,17 @@ gtk_source_vim_normal_init (GtkSourceVimNormal *self)
 }
 
 GtkSourceVimNormal *
-gtk_source_vim_normal_new (GtkSourceVimState *parent)
+gtk_source_vim_normal_new (void)
 {
-       g_return_val_if_fail (GTK_SOURCE_IS_VIM_STATE (parent), NULL);
+       return g_object_new (GTK_SOURCE_TYPE_VIM_STATE, NULL);
+}
+
+void
+gtk_source_vim_normal_clear (GtkSourceVimNormal *self)
+{
+       g_return_if_fail (GTK_SOURCE_IS_VIM_NORMAL (self));
 
-       return g_object_new (GTK_SOURCE_TYPE_VIM_STATE,
-                            "parent", parent,
-                            NULL);
+       /* TODO: clear any state other than repeat, registers, marks, etc
+        * so that input from the user feels fresh.
+        */
 }
diff --git a/gtksourceview/vim/gtk-source-vim-normal.h b/gtksourceview/vim/gtk-source-vim-normal.h
index a09a5d40..7ff91c18 100644
--- a/gtksourceview/vim/gtk-source-vim-normal.h
+++ b/gtksourceview/vim/gtk-source-vim-normal.h
@@ -21,14 +21,15 @@
 
 #pragma once
 
-#include "gtksourcevimstate.h"
+#include "gtk-source-vim-state.h"
 
 G_BEGIN_DECLS
 
-#define GTK_TYPE_SOURCE_VIM_NORMAL (gtk_source_vim_normal_get_type())
+#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)
 
-GtkSourceVimNormal *gtk_source_vim_normal_new (GtkSourceVimState *parent);
+GtkSourceVimNormal *gtk_source_vim_normal_new   (void);
+void                gtk_source_vim_normal_clear (GtkSourceVimNormal *self);
 
 G_END_DECLS
diff --git a/gtksourceview/vim/gtk-source-vim-replace.h b/gtksourceview/vim/gtk-source-vim-replace.h
index 2b297a5a..35282995 100644
--- a/gtksourceview/vim/gtk-source-vim-replace.h
+++ b/gtksourceview/vim/gtk-source-vim-replace.h
@@ -21,14 +21,14 @@
 
 #pragma once
 
-#include "gtksourcevimstate.h"
+#include "gtk-source-vim-state.h"
 
 G_BEGIN_DECLS
 
-#define GTK_TYPE_SOURCE_VIM_REPLACE (gtk_source_vim_replace_get_type())
+#define GTK_SOURCE_TYPE_VIM_REPLACE (gtk_source_vim_replace_get_type())
 
 G_DECLARE_FINAL_TYPE (GtkSourceVimReplace, gtk_source_vim_replace, GTK_SOURCE, VIM_REPLACE, 
GtkSourceVimState)
 
-GtkSourceVimReplace *gtk_source_vim_replace_new (GtkSourceVimState *parent);
+GtkSourceVimReplace *gtk_source_vim_replace_new (void);
 
 G_END_DECLS
diff --git a/gtksourceview/vim/gtk-source-vim-state.c b/gtksourceview/vim/gtk-source-vim-state.c
index 31fb2843..378988cc 100644
--- a/gtksourceview/vim/gtk-source-vim-state.c
+++ b/gtksourceview/vim/gtk-source-vim-state.c
@@ -21,6 +21,9 @@
 
 #include "config.h"
 
+#include "gtksourcebuffer.h"
+#include "gtksourceview.h"
+
 #include "gtk-source-vim-state.h"
 
 typedef struct
@@ -42,9 +45,9 @@ enum {
 static GParamSpec *properties [N_PROPS];
 
 static inline void
-get_key_string (guint           keyval,
-                GdkModifierType mods,
-                char            str[16])
+keyval_to_string (guint           keyval,
+                  GdkModifierType mods,
+                  char            str[16])
 {
        int pos = 0;
 
@@ -286,6 +289,29 @@ gtk_source_vim_state_beep (GtkSourceVimState *self)
        }
 }
 
+GtkSourceVimState *
+gtk_source_vim_state_get_child (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->child;
+}
+
+GtkSourceVimState *
+gtk_source_vim_state_get_current (GtkSourceVimState *self)
+{
+       GtkSourceVimStatePrivate *priv = gtk_source_vim_state_get_instance_private (self);
+
+       g_return_val_if_fail (GTK_SOURCE_IS_VIM_STATE (self), NULL);
+
+       if (priv->child == NULL)
+               return self;
+
+       return gtk_source_vim_state_get_current (priv->child);
+}
+
 GtkSourceVimState *
 gtk_source_vim_state_get_parent (GtkSourceVimState *self)
 {
@@ -315,20 +341,20 @@ gtk_source_vim_state_repeat (GtkSourceVimState *self,
 {
        g_return_if_fail (GTK_SOURCE_IS_VIM_STATE (self));
 
-       if (GTK_SOURCE_VIM_GET_CLASS (self)->repeat)
+       if (GTK_SOURCE_VIM_STATE_GET_CLASS (self)->repeat)
        {
-               GTK_SOURCE_VIM_GET_CLASS (self)->repeat (self, repeat);
+               GTK_SOURCE_VIM_STATE_GET_CLASS (self)->repeat (self, repeat);
        }
 }
 
 gboolean
-gtk_source_vim_get_can_repeat (GtkSourceVimState *self)
+gtk_source_vim_state_get_can_repeat (GtkSourceVimState *self)
 {
        g_return_val_if_fail (GTK_SOURCE_IS_VIM_STATE (self), FALSE);
 
-       if (GTK_SOURCE_VIM_GET_CLASS (self)->get_can_repeat)
+       if (GTK_SOURCE_VIM_STATE_GET_CLASS (self)->get_can_repeat)
        {
-               return GTK_SOURCE_VIM_GET_CLASS (self)->get_can_repeat (self);
+               return GTK_SOURCE_VIM_STATE_GET_CLASS (self)->get_can_repeat (self);
        }
 
        return FALSE;
@@ -341,9 +367,9 @@ gtk_source_vim_state_handle_event (GtkSourceVimState *self,
        g_return_val_if_fail (GTK_SOURCE_IS_VIM_STATE (self), FALSE);
        g_return_val_if_fail (event != NULL, FALSE);
 
-       if (GTK_SOURCE_VIM_GET_CLASS (self)->handle_event)
+       if (GTK_SOURCE_VIM_STATE_GET_CLASS (self)->handle_event)
        {
-               return GTK_SOURCE_VIM_GET_CLASS (self)->handle_event (self, event);
+               return GTK_SOURCE_VIM_STATE_GET_CLASS (self)->handle_event (self, event);
        }
 
        return FALSE;
diff --git a/gtksourceview/vim/gtk-source-vim-state.h b/gtksourceview/vim/gtk-source-vim-state.h
index 89a61c7f..84f8efeb 100644
--- a/gtksourceview/vim/gtk-source-vim-state.h
+++ b/gtksourceview/vim/gtk-source-vim-state.h
@@ -24,11 +24,10 @@
 #include <gtk/gtk.h>
 
 #include "gtksourcetypes.h"
-#include "gtksourcetypes-private.h"
 
 G_BEGIN_DECLS
 
-#define GTK_TYPE_SOURCE_VIM_STATE (gtk_source_vim_state_get_type())
+#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)
 
@@ -58,6 +57,8 @@ void               gtk_source_vim_state_push           (GtkSourceVimState *self,
                                                         GtkSourceVimState *new_state);
 void               gtk_source_vim_state_pop            (GtkSourceVimState *self);
 void               gtk_source_vim_state_beep           (GtkSourceVimState *self);
+GtkSourceVimState *gtk_source_vim_state_get_child      (GtkSourceVimState *self);
+GtkSourceVimState *gtk_source_vim_state_get_current    (GtkSourceVimState *self);
 GtkSourceView     *gtk_source_vim_state_get_view       (GtkSourceVimState *self);
 GtkSourceBuffer   *gtk_source_vim_state_get_buffer     (GtkSourceVimState *self,
                                                         GtkTextIter       *insert,
@@ -66,7 +67,7 @@ GtkSourceVimState *gtk_source_vim_state_get_root       (GtkSourceVimState *self)
 GtkSourceVimState *gtk_source_vim_state_get_parent     (GtkSourceVimState *self);
 gboolean           gtk_source_vim_state_handle_event   (GtkSourceVimState *self,
                                                         GdkEvent          *event);
-gboolean           gtk_source_vim_state_get_can_repeat (GtkSourceVimState *self,
+gboolean           gtk_source_vim_state_get_can_repeat (GtkSourceVimState *self);
 void               gtk_source_vim_state_repeat         (GtkSourceVimState *self,
                                                         int                repeat);
 
diff --git a/gtksourceview/vim/gtk-source-vim-visual.h b/gtksourceview/vim/gtk-source-vim-visual.h
index 411444fa..9ebed71a 100644
--- a/gtksourceview/vim/gtk-source-vim-visual.h
+++ b/gtksourceview/vim/gtk-source-vim-visual.h
@@ -21,7 +21,7 @@
 
 #pragma once
 
-#include "gtksourcevimstate.h"
+#include "gtk-source-vim-state.h"
 
 G_BEGIN_DECLS
 
@@ -32,11 +32,10 @@ typedef enum
        GTK_SOURCE_VIM_VISUAL_BLOCK,
 } GtkSourceVimVisualMode;
 
-#define GTK_TYPE_SOURCE_VIM_VISUAL (gtk_source_vim_visual_get_type())
+#define GTK_SOURCE_TYPE_VIM_VISUAL (gtk_source_vim_visual_get_type())
 
 G_DECLARE_FINAL_TYPE (GtkSourceVimVisual, gtk_source_vim_visual, GTK_SOURCE, VIM_VISUAL, GObject)
 
-GtkSourceVimVisual *gtk_source_vim_visual_new (GtkSourceVimState      *parent,
-                                               GtkSourceVimVisualMode  mode);
+GtkSourceVimVisual *gtk_source_vim_visual_new (GtkSourceVimVisualMode mode);
 
 G_END_DECLS
diff --git a/gtksourceview/vim/gtk-source-vim.c b/gtksourceview/vim/gtk-source-vim.c
new file mode 100644
index 00000000..fff5d177
--- /dev/null
+++ b/gtksourceview/vim/gtk-source-vim.c
@@ -0,0 +1,243 @@
+/*
+ * 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.h"
+#include "gtk-source-vim-command-bar.h"
+#include "gtk-source-vim-normal.h"
+
+struct _GtkSourceVim
+{
+       GtkSourceVimState parent_instance;
+};
+
+G_DEFINE_TYPE (GtkSourceVim, gtk_source_vim, GTK_SOURCE_TYPE_VIM_STATE)
+
+enum {
+       PROP_0,
+       PROP_COMMAND_TEXT,
+       PROP_COMMAND_BAR_TEXT,
+       N_PROPS
+};
+
+enum {
+       SPLIT,
+       N_SIGNALS
+};
+
+static GParamSpec *properties[N_PROPS];
+static guint signals[N_SIGNALS];
+
+GtkSourceVim *
+gtk_source_vim_new (GtkSourceView *view)
+{
+       return g_object_new (GTK_SOURCE_TYPE_VIM,
+                            "view", view,
+                            NULL);
+}
+
+static gboolean
+gtk_source_vim_handle_event (GtkSourceVimState *state,
+                             GdkEvent          *event)
+{
+       GtkSourceVimState *current;
+
+       g_assert (GTK_SOURCE_IS_VIM (state));
+       g_assert (event != NULL);
+
+       current = gtk_source_vim_state_get_current (state);
+
+       if (current == state)
+       {
+               return FALSE;
+       }
+
+       return gtk_source_vim_state_handle_event (current, event);
+}
+
+static void
+gtk_source_vim_constructed (GObject *object)
+{
+       GtkSourceVim *self = (GtkSourceVim *)object;
+       g_autoptr(GtkSourceVimNormal) normal = NULL;
+
+       G_OBJECT_CLASS (gtk_source_vim_parent_class)->constructed (object);
+
+       normal = gtk_source_vim_normal_new ();
+       gtk_source_vim_state_push (GTK_SOURCE_VIM_STATE (self),
+                                  GTK_SOURCE_VIM_STATE (normal));
+}
+
+static void
+gtk_source_vim_get_property (GObject    *object,
+                             guint       prop_id,
+                             GValue     *value,
+                             GParamSpec *pspec)
+{
+       GtkSourceVim *self = GTK_SOURCE_VIM (object);
+
+       switch (prop_id)
+       {
+               case PROP_COMMAND_TEXT:
+                       g_value_set_string (value, gtk_source_vim_get_command_text (self));
+                       break;
+
+               case PROP_COMMAND_BAR_TEXT:
+                       g_value_set_string (value, gtk_source_vim_get_command_bar_text (self));
+                       break;
+
+               default:
+                       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+       }
+}
+
+static void
+gtk_source_vim_class_init (GtkSourceVimClass *klass)
+{
+       GObjectClass *object_class = G_OBJECT_CLASS (klass);
+       GtkSourceVimStateClass *state_class = GTK_SOURCE_VIM_STATE_CLASS (klass);
+
+       object_class->constructed = gtk_source_vim_constructed;
+       object_class->get_property = gtk_source_vim_get_property;
+
+       state_class->handle_event = gtk_source_vim_handle_event;
+
+       properties [PROP_COMMAND_TEXT] =
+               g_param_spec_string ("command-text",
+                                    "Command Text",
+                                    "Command Text",
+                                    NULL,
+                                    (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+
+       properties [PROP_COMMAND_BAR_TEXT] =
+               g_param_spec_string ("command-bar-text",
+                                    "Command Bar Text",
+                                    "Command Bar Text",
+                                    NULL,
+                                    (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+
+       g_object_class_install_properties (object_class, N_PROPS, properties);
+
+       /**
+        * GtkSourceVim::split:
+        * @self: a #GtkSourceVim
+        * @orientation: a #GtkOrientation for vertical or horizontal
+        * @new_document: %TRUE if a new document should be created
+        * @focus_split: %TRUE if the new document should be focused
+        * @numeric: a numeric value provided with the command such as
+        *   the number of columns for the split
+        */
+       signals[SPLIT] =
+               g_signal_new ("split",
+                             G_TYPE_FROM_CLASS (klass),
+                             G_SIGNAL_RUN_LAST,
+                             0,
+                             NULL, NULL,
+                             NULL,
+                             G_TYPE_NONE,
+                             3,
+                             GTK_TYPE_ORIENTATION,
+                             G_TYPE_BOOLEAN,
+                             G_TYPE_BOOLEAN,
+                             G_TYPE_INT);
+}
+
+static void
+gtk_source_vim_init (GtkSourceVim *self)
+{
+}
+
+const char *
+gtk_source_vim_get_command_text (GtkSourceVim *self)
+{
+       GtkSourceVimState *current;
+
+       g_return_val_if_fail (GTK_SOURCE_IS_VIM (self), NULL);
+
+       current = gtk_source_vim_state_get_current (GTK_SOURCE_VIM_STATE (self));
+
+       if (GTK_SOURCE_IS_VIM_NORMAL (current))
+       {
+               /* TODO */
+       }
+
+       return NULL;
+}
+
+const char *
+gtk_source_vim_get_command_bar_text (GtkSourceVim *self)
+{
+       GtkSourceVimState *child;
+
+       g_return_val_if_fail (GTK_SOURCE_IS_VIM (self), NULL);
+
+       child = gtk_source_vim_state_get_child (GTK_SOURCE_VIM_STATE (self));
+
+       if (GTK_SOURCE_IS_VIM_COMMAND_BAR (child))
+       {
+               /* TODO */
+       }
+
+       return NULL;
+}
+
+void
+gtk_source_vim_emit_split (GtkSourceVim   *self,
+                           GtkOrientation  orientation,
+                           gboolean        new_document,
+                           gboolean        focus_split,
+                           int             numeric)
+{
+       g_return_if_fail (GTK_SOURCE_IS_VIM (self));
+
+       g_signal_emit (self, signals[SPLIT], 0,
+                      orientation, new_document, focus_split, numeric);
+}
+
+void
+gtk_source_vim_reset (GtkSourceVim *self)
+{
+       GtkSourceVimState *current;
+
+       g_return_if_fail (GTK_SOURCE_IS_VIM (self));
+
+       /* Clear everything up to the top-most Normal mode */
+       while ((current = gtk_source_vim_state_get_current (GTK_SOURCE_VIM_STATE (self))))
+       {
+               GtkSourceVimState *parent = gtk_source_vim_state_get_parent (current);
+
+               if (parent == NULL || parent == GTK_SOURCE_VIM_STATE (self))
+                       break;
+
+               gtk_source_vim_state_pop (current);
+       }
+
+       current = gtk_source_vim_state_get_current (GTK_SOURCE_VIM_STATE (self));
+
+       /* If we found the normal mode (should always happen), then
+        * also tell it to clear anything in progress.
+        */
+       if (GTK_SOURCE_IS_VIM_NORMAL (current))
+       {
+               gtk_source_vim_normal_clear (GTK_SOURCE_VIM_NORMAL (current));
+       }
+}
diff --git a/gtksourceview/vim/gtk-source-vim.h b/gtksourceview/vim/gtk-source-vim.h
index 9a7e6f87..b867b6cf 100644
--- a/gtksourceview/vim/gtk-source-vim.h
+++ b/gtksourceview/vim/gtk-source-vim.h
@@ -21,20 +21,22 @@
 
 #pragma once
 
-#include "gtksourcevim.h"
+#include "gtk-source-vim-state.h"
 
 G_BEGIN_DECLS
 
-#define GTK_TYPE_SOURCE_VIM (gtk_source_vim_get_type())
+#define GTK_SOURCE_TYPE_VIM (gtk_source_vim_get_type())
 
 G_DECLARE_FINAL_TYPE (GtkSourceVim, gtk_source_vim, GTK_SOURCE, VIM, GtkSourceVimState)
 
-GtkSourceVim *gtk_source_vim_new             (GtkSourceView  *view);
-const char   *gtk_source_vim_get_command     (GtkSourceVim   *self);
-const char   *gtk_source_vim_get_command_bar (GtkSourceVim   *self);
-void          gtk_source_vim_emit_split      (GtkSourceVim   *self,
-                                              GtkOrientation  orientation,
-                                              gboolean        new_document,
-                                              gboolean        focus_split);
+GtkSourceVim *gtk_source_vim_new                  (GtkSourceView  *view);
+void          gtk_source_vim_reset                (GtkSourceVim   *self);
+const char   *gtk_source_vim_get_command_text     (GtkSourceVim   *self);
+const char   *gtk_source_vim_get_command_bar_text (GtkSourceVim   *self);
+void          gtk_source_vim_emit_split           (GtkSourceVim   *self,
+                                                   GtkOrientation  orientation,
+                                                   gboolean        new_document,
+                                                   gboolean        focus_split,
+                                                   int             numeric);
 
 G_END_DECLS
diff --git a/gtksourceview/vim/meson.build b/gtksourceview/vim/meson.build
new file mode 100644
index 00000000..a0eb2858
--- /dev/null
+++ b/gtksourceview/vim/meson.build
@@ -0,0 +1,6 @@
+vim_sources = files([
+  'gtk-source-vim.c',
+  'gtk-source-vim-command-bar.c',
+  'gtk-source-vim-normal.c',
+  'gtk-source-vim-state.c',
+])


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