[gtksourceview/wip/chergert/vim] start on some repeatable visual+commands
- From: Christian Hergert <chergert src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtksourceview/wip/chergert/vim] start on some repeatable visual+commands
- Date: Sun, 31 Oct 2021 19:45:31 +0000 (UTC)
commit 3753ff6917f7288e16723dccfcf4f145db175cf4
Author: Christian Hergert <chergert redhat com>
Date: Sun Oct 31 12:45:24 2021 -0700
start on some repeatable visual+commands
gtksourceview/vim/gtk-source-vim-delete.c | 31 ++++-----
gtksourceview/vim/gtk-source-vim-delete.h | 4 +-
gtksourceview/vim/gtk-source-vim-visual.c | 106 ++++++++++++++++++++++++++----
3 files changed, 111 insertions(+), 30 deletions(-)
---
diff --git a/gtksourceview/vim/gtk-source-vim-delete.c b/gtksourceview/vim/gtk-source-vim-delete.c
index c9f1fde7..08aa3c10 100644
--- a/gtksourceview/vim/gtk-source-vim-delete.c
+++ b/gtksourceview/vim/gtk-source-vim-delete.c
@@ -54,19 +54,20 @@ gtk_source_vim_delete_new (GtkSourceVimMotion *motion)
NULL);
}
-static void
+void
gtk_source_vim_delete_set_motion (GtkSourceVimDelete *self,
GtkSourceVimMotion *motion)
{
- g_assert (GTK_SOURCE_IS_VIM_DELETE (self));
- g_assert (!motion || GTK_SOURCE_IS_VIM_MOTION (motion));
+ g_return_if_fail (GTK_SOURCE_IS_VIM_DELETE (self));
+ g_return_if_fail (!motion || GTK_SOURCE_IS_VIM_MOTION (motion));
if (g_set_object (&self->motion, motion))
{
if (motion != NULL)
{
gtk_source_vim_motion_set_apply_on_leave (motion, FALSE);
- g_object_set (motion, "parent", self, NULL);
+ gtk_source_vim_state_set_parent (GTK_SOURCE_VIM_STATE (motion),
+ GTK_SOURCE_VIM_STATE (self));
}
}
}
@@ -129,31 +130,31 @@ static void
gtk_source_vim_delete_repeat (GtkSourceVimState *state)
{
GtkSourceVimDelete *self = (GtkSourceVimDelete *)state;
+ GtkSourceBuffer *buffer;
+ GtkTextIter insert, selection;
g_assert (GTK_SOURCE_IS_VIM_DELETE (self));
+ buffer = gtk_source_vim_state_get_buffer (state, &insert, &selection);
+
if (self->motion != NULL)
{
- GtkSourceBuffer *buffer;
- GtkTextIter insert, selection;
int count = gtk_source_vim_state_get_count (state);
- buffer = gtk_source_vim_state_get_buffer (state, &insert, &selection);
-
do
{
if (!gtk_source_vim_motion_apply (self->motion, &insert, TRUE))
break;
} while (--count > 0);
+ }
- gtk_text_buffer_delete (GTK_TEXT_BUFFER (buffer), &insert, &selection);
+ gtk_text_buffer_delete (GTK_TEXT_BUFFER (buffer), &insert, &selection);
- if (gtk_text_iter_ends_line (&insert) &&
- !gtk_text_iter_starts_line (&insert))
- {
- gtk_text_iter_backward_char (&insert);
- gtk_source_vim_state_select (state, &insert, &insert);
- }
+ if (gtk_text_iter_ends_line (&insert) &&
+ !gtk_text_iter_starts_line (&insert))
+ {
+ gtk_text_iter_backward_char (&insert);
+ gtk_source_vim_state_select (state, &insert, &insert);
}
}
diff --git a/gtksourceview/vim/gtk-source-vim-delete.h b/gtksourceview/vim/gtk-source-vim-delete.h
index 613905ec..c3ebf144 100644
--- a/gtksourceview/vim/gtk-source-vim-delete.h
+++ b/gtksourceview/vim/gtk-source-vim-delete.h
@@ -30,6 +30,8 @@ G_BEGIN_DECLS
G_DECLARE_FINAL_TYPE (GtkSourceVimDelete, gtk_source_vim_delete, GTK_SOURCE, VIM_DELETE, GtkSourceVimState)
-GtkSourceVimState *gtk_source_vim_delete_new (GtkSourceVimMotion *motion);
+GtkSourceVimState *gtk_source_vim_delete_new (GtkSourceVimMotion *motion);
+void gtk_source_vim_delete_set_motion (GtkSourceVimDelete *self,
+ GtkSourceVimMotion *motion);
G_END_DECLS
diff --git a/gtksourceview/vim/gtk-source-vim-visual.c b/gtksourceview/vim/gtk-source-vim-visual.c
index 89c22ebf..43dce89f 100644
--- a/gtksourceview/vim/gtk-source-vim-visual.c
+++ b/gtksourceview/vim/gtk-source-vim-visual.c
@@ -23,6 +23,7 @@
#include <glib/gi18n.h>
+#include "gtk-source-vim-delete.h"
#include "gtk-source-vim-motion.h"
#include "gtk-source-vim-visual.h"
@@ -38,6 +39,14 @@ struct _GtkSourceVimVisual
GtkSourceVimVisualMode mode;
+ /* A recording of motions so that we can replay commands
+ * such as delete and get a similar result to VIM. Replaying
+ * our motion's visual selection is not enough as after a
+ * delete it would be empty.
+ */
+ GtkSourceVimMotion *motion;
+ GtkSourceVimState *command;
+
KeyHandler handler;
GtkTextMark *started_at;
@@ -45,30 +54,46 @@ struct _GtkSourceVimVisual
};
static gboolean gtk_source_vim_visual_bail (GtkSourceVimVisual *self);
+static gboolean key_handler_initial (GtkSourceVimVisual *self,
+ guint keyval,
+ guint keycode,
+ GdkModifierType mods,
+ const char *string);
G_DEFINE_TYPE (GtkSourceVimVisual, gtk_source_vim_visual, GTK_SOURCE_TYPE_VIM_STATE)
+static void
+gtk_source_vim_visual_clear (GtkSourceVimVisual *self)
+{
+ self->handler = key_handler_initial;
+}
+
+static gboolean
+gtk_source_vim_visual_bail (GtkSourceVimVisual *self)
+{
+ gtk_source_vim_visual_clear (self);
+ return TRUE;
+}
+
static void
extend_lines (GtkTextIter *a,
GtkTextIter *b)
{
- if (gtk_text_iter_equal (a, b))
- {
- gtk_text_iter_set_line_offset (a, 0);
- if (!gtk_text_iter_ends_line (b))
- gtk_text_iter_forward_to_line_end (b);
- }
- else if (gtk_text_iter_compare (a, b) < 0)
+ if (gtk_text_iter_compare (a, b) <= 0)
{
gtk_text_iter_set_line_offset (a, 0);
if (!gtk_text_iter_ends_line (b))
gtk_text_iter_forward_to_line_end (b);
+ if (gtk_text_iter_ends_line (b) && !gtk_text_iter_is_end (b))
+ gtk_text_iter_forward_char (b);
}
else
{
gtk_text_iter_set_line_offset (b, 0);
if (!gtk_text_iter_ends_line (a))
gtk_text_iter_forward_to_line_end (a);
+ if (gtk_text_iter_ends_line (a) && !gtk_text_iter_is_end (a))
+ gtk_text_iter_forward_char (a);
}
}
@@ -227,6 +252,23 @@ key_handler_z (GtkSourceVimVisual *self,
}
}
+static void
+gtk_source_vim_visual_delete (GtkSourceVimVisual *self)
+{
+ g_assert (GTK_SOURCE_IS_VIM_VISUAL (self));
+
+ gtk_source_vim_visual_clear (self);
+ g_clear_object (&self->command);
+
+ gtk_source_vim_state_set_can_repeat (GTK_SOURCE_VIM_STATE (self), TRUE);
+
+ self->command = gtk_source_vim_delete_new (NULL);
+ gtk_source_vim_state_set_parent (self->command, GTK_SOURCE_VIM_STATE (self));
+ gtk_source_vim_state_repeat (self->command);
+
+ gtk_source_vim_state_pop (GTK_SOURCE_VIM_STATE (self));
+}
+
static gboolean
key_handler_initial (GtkSourceVimVisual *self,
guint keyval,
@@ -236,12 +278,18 @@ key_handler_initial (GtkSourceVimVisual *self,
{
GtkSourceVimState *motion;
+ g_assert (GTK_SOURCE_IS_VIM_VISUAL (self));
+
switch (keyval)
{
case GDK_KEY_z:
self->handler = key_handler_z;
return TRUE;
+ case GDK_KEY_x:
+ gtk_source_vim_visual_delete (self);
+ return TRUE;
+
default:
break;
}
@@ -255,13 +303,6 @@ key_handler_initial (GtkSourceVimVisual *self,
return TRUE;
}
-static gboolean
-gtk_source_vim_visual_bail (GtkSourceVimVisual *self)
-{
- self->handler = key_handler_initial;
- return TRUE;
-}
-
static void
gtk_source_vim_visual_enter (GtkSourceVimState *state)
{
@@ -328,12 +369,45 @@ gtk_source_vim_visual_resume (GtkSourceVimState *state,
if (GTK_SOURCE_IS_VIM_MOTION (from))
{
+ GtkSourceVimState *chained;
+
+ /* Update our selection to match the motion. If we're in
+ * linewise, that needs to be updated to contain the whole line.
+ */
gtk_source_vim_visual_track_motion (self);
+
+ /* Keep the motion around too so we can potentially replay it
+ * for commands like delete, etc.
+ */
+ chained = gtk_source_vim_motion_chain (self->motion, GTK_SOURCE_VIM_MOTION (from));
+ gtk_source_vim_state_set_parent (chained, GTK_SOURCE_VIM_STATE (self));
+ g_set_object (&self->motion, GTK_SOURCE_VIM_MOTION (chained));
+ g_object_unref (chained);
}
self->handler = key_handler_initial;
}
+static void
+gtk_source_vim_visual_repeat (GtkSourceVimState *state)
+{
+ GtkSourceVimVisual *self = (GtkSourceVimVisual *)state;
+ int count;
+
+ g_assert (GTK_SOURCE_IS_VIM_STATE (self));
+
+ count = gtk_source_vim_state_get_count (state);
+
+ do
+ {
+ if (self->motion != NULL)
+ gtk_source_vim_state_repeat (GTK_SOURCE_VIM_STATE (self->motion));
+
+ if (self->command != NULL)
+ gtk_source_vim_state_repeat (self->command);
+ } while (--count > 0);
+}
+
static gboolean
gtk_source_vim_visual_handle_keypress (GtkSourceVimState *state,
guint keyval,
@@ -378,6 +452,9 @@ gtk_source_vim_visual_dispose (GObject *object)
gtk_text_buffer_delete_mark (GTK_TEXT_BUFFER (buffer), mark);
}
+ g_clear_object (&self->motion);
+ g_clear_object (&self->command);
+
G_OBJECT_CLASS (gtk_source_vim_visual_parent_class)->dispose (object);
}
@@ -394,6 +471,7 @@ gtk_source_vim_visual_class_init (GtkSourceVimVisualClass *klass)
state_class->enter = gtk_source_vim_visual_enter;
state_class->leave = gtk_source_vim_visual_leave;
state_class->resume = gtk_source_vim_visual_resume;
+ state_class->repeat = gtk_source_vim_visual_repeat;
}
static void
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]