[gtksourceview/wip/chergert/vim: 167/363] start on some motion work for visual-char mode




commit d18fc2388ca6c1aba7107fee68c03515fafeef06
Author: Christian Hergert <chergert redhat com>
Date:   Sat Oct 30 14:35:29 2021 -0700

    start on some motion work for visual-char mode

 gtksourceview/vim/gtk-source-vim-visual.c | 173 ++++++++++++++++++++++++++----
 1 file changed, 152 insertions(+), 21 deletions(-)
---
diff --git a/gtksourceview/vim/gtk-source-vim-visual.c b/gtksourceview/vim/gtk-source-vim-visual.c
index 02a829e2..0f673303 100644
--- a/gtksourceview/vim/gtk-source-vim-visual.c
+++ b/gtksourceview/vim/gtk-source-vim-visual.c
@@ -23,12 +23,17 @@
 
 #include <glib/gi18n.h>
 
+#include "gtk-source-vim-motion.h"
 #include "gtk-source-vim-visual.h"
 
 struct _GtkSourceVimVisual
 {
        GtkSourceVimState parent_class;
+
        GtkSourceVimVisualMode mode;
+
+       GtkTextMark *started_at;
+       GtkTextMark *cursor;
 };
 
 G_DEFINE_TYPE (GtkSourceVimVisual, gtk_source_vim_visual, GTK_SOURCE_TYPE_VIM_STATE)
@@ -58,45 +63,91 @@ extend_lines (GtkTextIter *a,
 }
 
 static void
-gtk_source_vim_visual_extend_selection (GtkSourceVimVisual *self)
+gtk_source_vim_visual_track_char (GtkSourceVimVisual *self)
 {
        GtkSourceBuffer *buffer;
-       GtkTextIter iter;
-       GtkTextIter selection;
+       GtkTextIter cursor;
+       GtkTextIter started_at;
+
+       g_assert (GTK_SOURCE_IS_VIM_VISUAL (self));
+
+       buffer = gtk_source_vim_state_get_buffer (GTK_SOURCE_VIM_STATE (self), NULL, NULL);
+       gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (buffer), &cursor, self->cursor);
+       gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (buffer), &started_at, self->started_at);
+
+       if (gtk_text_iter_equal (&cursor, &started_at))
+       {
+               if (gtk_text_iter_starts_line (&cursor) && gtk_text_iter_ends_line (&cursor))
+               {
+                       /* Leave the selection empty, since we don't really
+                        * have a character to select (other than the newline
+                        * which isn't what VIM does.
+                        */
+               }
+               else if (gtk_text_iter_ends_line (&cursor))
+               {
+                       /* Some how ended up on the \n when we shouldn't. Maybe
+                        * a stray button press or something. Adjust now.
+                        */
+                       gtk_text_iter_backward_char (&started_at);
+               }
+               else
+               {
+                       gtk_text_iter_forward_char (&cursor);
+               }
+
+               gtk_source_vim_state_select (GTK_SOURCE_VIM_STATE (self), &cursor, &started_at);
+       }
+       else if (gtk_text_iter_compare (&started_at, &cursor) < 0)
+       {
+               /* Include the the character under the cursor */
+               if (!gtk_text_iter_ends_line (&cursor))
+               {
+                       gtk_text_iter_forward_char (&cursor);
+               }
+
+               gtk_source_vim_state_select (GTK_SOURCE_VIM_STATE (self), &cursor, &started_at);
+       }
+       else
+       {
+               /* We need to swap the started at so that it is one character
+                * above so that the starting character is still selected.
+                */
+               if (!gtk_text_iter_ends_line (&started_at))
+               {
+                       gtk_text_iter_forward_char (&started_at);
+               }
+
+               gtk_source_vim_state_select (GTK_SOURCE_VIM_STATE (self), &cursor, &started_at);
+       }
+}
 
+static void
+gtk_source_vim_visual_track_line (GtkSourceVimVisual *self)
+{
        g_assert (GTK_SOURCE_IS_VIM_VISUAL (self));
 
-       buffer = gtk_source_vim_state_get_buffer (GTK_SOURCE_VIM_STATE (self), &iter, &selection);
+}
+
+static void
+gtk_source_vim_visual_track_motion (GtkSourceVimVisual *self)
+{
+       g_assert (GTK_SOURCE_IS_VIM_VISUAL (self));
 
        switch (self->mode)
        {
                case GTK_SOURCE_VIM_VISUAL_LINE:
-                       extend_lines (&iter, &selection);
+                       gtk_source_vim_visual_track_line (self);
                        break;
 
                case GTK_SOURCE_VIM_VISUAL_CHAR:
-                       if (gtk_text_iter_equal (&iter, &selection))
-                       {
-                               gtk_text_iter_forward_char (&iter);
-                       }
+                       gtk_source_vim_visual_track_char (self);
                        break;
 
                case GTK_SOURCE_VIM_VISUAL_BLOCK:
                default:
                        break;
        }
-
-       gtk_source_vim_state_select (GTK_SOURCE_VIM_STATE (self), &iter, &selection);
-}
-
-static void
-gtk_source_vim_visual_enter (GtkSourceVimState *state)
-{
-       GtkSourceVimVisual *self = (GtkSourceVimVisual *)state;
-
-       g_assert (GTK_SOURCE_IS_VIM_VISUAL (self));
-
-       gtk_source_vim_visual_extend_selection (self);
 }
 
 static const char *
@@ -123,6 +174,74 @@ gtk_source_vim_visual_get_command_bar_text (GtkSourceVimState *state)
        }
 }
 
+static void
+gtk_source_vim_visual_enter (GtkSourceVimState *state)
+{
+       GtkSourceVimVisual *self = (GtkSourceVimVisual *)state;
+       GtkSourceBuffer *buffer;
+       GtkTextIter iter, selection;
+
+       g_assert (GTK_SOURCE_IS_VIM_VISUAL (self));
+
+       buffer = gtk_source_vim_state_get_buffer (state, &iter, &selection);
+
+       self->started_at = gtk_text_buffer_create_mark (GTK_TEXT_BUFFER (buffer), NULL, &iter, TRUE);
+       self->cursor = gtk_text_buffer_create_mark (GTK_TEXT_BUFFER (buffer), NULL, &iter, FALSE);
+       gtk_text_mark_set_visible (self->cursor, self->mode != GTK_SOURCE_VIM_VISUAL_CHAR);
+
+       gtk_source_vim_visual_track_motion (self);
+}
+
+static void
+gtk_source_vim_visual_leave (GtkSourceVimState *state)
+{
+       GtkSourceVimVisual *self = (GtkSourceVimVisual *)state;
+       GtkSourceBuffer *buffer;
+       GtkSourceView *view;
+       GtkTextIter iter;
+       GtkTextIter selection;
+
+       g_assert (GTK_SOURCE_IS_VIM_VISUAL (self));
+
+       buffer = gtk_source_vim_state_get_buffer (state, &iter, &selection);
+       view = gtk_source_vim_state_get_view (state);
+
+       gtk_text_view_set_overwrite (GTK_TEXT_VIEW (view), TRUE);
+
+       if (self->cursor)
+       {
+               gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (buffer), &iter, self->cursor);
+               gtk_text_buffer_delete_mark (GTK_TEXT_BUFFER (buffer), self->cursor);
+               self->cursor = NULL;
+       }
+
+       if (self->started_at)
+       {
+               gtk_text_buffer_delete_mark (GTK_TEXT_BUFFER (buffer), self->started_at);
+               self->started_at = NULL;
+       }
+
+       if (gtk_text_iter_ends_line (&iter) && !gtk_text_iter_starts_line (&iter))
+               gtk_text_iter_backward_char (&iter);
+
+       gtk_source_vim_state_select (state, &iter, &iter);
+}
+
+static void
+gtk_source_vim_visual_resume (GtkSourceVimState *state,
+                              GtkSourceVimState *from)
+{
+       GtkSourceVimVisual *self = (GtkSourceVimVisual *)state;
+
+       g_assert (GTK_SOURCE_IS_VIM_VISUAL (self));
+       g_assert (GTK_SOURCE_IS_VIM_STATE (from));
+
+       if (GTK_SOURCE_IS_VIM_MOTION (from))
+       {
+               gtk_source_vim_visual_track_motion (self);
+       }
+}
+
 static gboolean
 gtk_source_vim_visual_handle_keypress (GtkSourceVimState *state,
                                        guint              keyval,
@@ -131,6 +250,7 @@ gtk_source_vim_visual_handle_keypress (GtkSourceVimState *state,
                                        const char        *string)
 {
        GtkSourceVimVisual *self = (GtkSourceVimVisual *)state;
+       GtkSourceVimState *motion;
 
        g_assert (GTK_SOURCE_IS_VIM_VISUAL (state));
 
@@ -141,12 +261,21 @@ gtk_source_vim_visual_handle_keypress (GtkSourceVimState *state,
                return TRUE;
        }
 
+       /* Try to apply a motion to our cursor */
+       motion = gtk_source_vim_motion_new ();
+       gtk_source_vim_motion_set_mark (GTK_SOURCE_VIM_MOTION (motion), self->cursor);
+       gtk_source_vim_state_push (state, motion);
+       gtk_source_vim_state_synthesize (motion, keyval, mods);
+
        return TRUE;
 }
 
 static void
 gtk_source_vim_visual_dispose (GObject *object)
 {
+       g_assert (GTK_SOURCE_VIM_VISUAL (object)->started_at == NULL);
+       g_assert (GTK_SOURCE_VIM_VISUAL (object)->cursor == NULL);
+
        G_OBJECT_CLASS (gtk_source_vim_visual_parent_class)->dispose (object);
 }
 
@@ -161,6 +290,8 @@ gtk_source_vim_visual_class_init (GtkSourceVimVisualClass *klass)
        state_class->get_command_bar_text = gtk_source_vim_visual_get_command_bar_text;
        state_class->handle_keypress = gtk_source_vim_visual_handle_keypress;
        state_class->enter = gtk_source_vim_visual_enter;
+       state_class->leave = gtk_source_vim_visual_leave;
+       state_class->resume = gtk_source_vim_visual_resume;
 }
 
 static void


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