[gtksourceview/wip/chergert/vim] special case line movement to avoid empty line issues



commit 59d0553e2f1d8c53cc84290299bb6294dd750e9e
Author: Christian Hergert <chergert redhat com>
Date:   Thu Oct 28 17:08:35 2021 -0700

    special case line movement to avoid empty line issues

 gtksourceview/vim/gtk-source-vim-motion.c | 43 +++++++++++++++++++++++++++----
 1 file changed, 38 insertions(+), 5 deletions(-)
---
diff --git a/gtksourceview/vim/gtk-source-vim-motion.c b/gtksourceview/vim/gtk-source-vim-motion.c
index 899c50fb..cc8ed105 100644
--- a/gtksourceview/vim/gtk-source-vim-motion.c
+++ b/gtksourceview/vim/gtk-source-vim-motion.c
@@ -46,6 +46,11 @@ struct _GtkSourceVimMotion
        /* character for f or F */
        gunichar f_char;
 
+       /* Where are we applying the :count, useful when you need
+        * to deal with empty lines and forward_to_line_end().
+        */
+       int apply_count;
+
        /* Apply the motion when leaving the state. This is useful
         * so that you can either capture a motion for future use
         * or simply apply it immediately.
@@ -1275,9 +1280,7 @@ gtk_source_vim_motion_repeat (GtkSourceVimState *state)
        do
        {
                if (!gtk_source_vim_motion_apply (self, &iter, FALSE))
-               {
                        break;
-               }
        } while (--count > 0);
 
        gtk_source_vim_state_select (state, &iter, &iter);
@@ -1366,15 +1369,16 @@ gtk_source_vim_motion_apply (GtkSourceVimMotion *self,
 
        do
        {
+               self->apply_count++;
                if (!self->motion (iter, self))
-               {
                        goto do_inclusive;
-               }
        } while (--count > 0);
 
        ret = TRUE;
 
 do_inclusive:
+       self->apply_count = 0;
+
        if (apply_inclusive)
        {
                guint end_offset = gtk_text_iter_get_offset (iter);
@@ -1465,7 +1469,36 @@ static gboolean
 motion_line_end_with_nl (GtkTextIter        *iter,
                          GtkSourceVimMotion *self)
 {
-       return gtk_text_iter_forward_to_line_end (iter);
+       int count;
+
+       /* This function has to take into account newlines so that we
+        * can move and delete whole lines. It is extra complicated
+        * because we can't actually move when we have an empty line.
+        * So we know our :count to apply and can do it in one pass
+        * and rely on subsequent calls to be idempotent. When applying
+        * we get the same result and need not worry about the impedance
+        * mismatch with VIM character movements.
+        */
+
+       if (self->apply_count != 1)
+               return FALSE;
+
+       count = gtk_source_vim_state_get_count (GTK_SOURCE_VIM_STATE (self));
+
+       if (count == 1)
+       {
+               if (gtk_text_iter_ends_line (iter))
+                       return TRUE;
+
+               return gtk_text_iter_forward_to_line_end (iter);
+       }
+
+       gtk_text_iter_set_line (iter, gtk_text_iter_get_line (iter) + count - 1);
+
+       if (!gtk_text_iter_ends_line (iter))
+               gtk_text_iter_forward_to_line_end (iter);
+
+       return TRUE;
 }
 
 GtkSourceVimState *


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