[gnome-builder/wip/libide] libide: add begin-macro, end-macro, and reply-macro signals



commit 4b4b7de36b4864c7e55b446f7ca4dd54f39a5534
Author: Christian Hergert <christian hergert me>
Date:   Thu Mar 12 01:37:04 2015 -0700

    libide: add begin-macro, end-macro, and reply-macro signals
    
    These signals can be used to capture a series of changes to the
    IdeSourceView for which they can be replayed multiple times later.

 libide/ide-source-view.c |  158 ++++++++++++++++++++++++++++++++++++++++++++-
 libide/ide-source-view.h |    3 +
 2 files changed, 157 insertions(+), 4 deletions(-)
---
diff --git a/libide/ide-source-view.c b/libide/ide-source-view.c
index 185fbe0..9d31f8d 100644
--- a/libide/ide-source-view.c
+++ b/libide/ide-source-view.c
@@ -49,6 +49,7 @@
 #include "ide-source-snippets-manager.h"
 #include "ide-source-location.h"
 #include "ide-source-view.h"
+#include "ide-source-view-capture.h"
 #include "ide-source-view-mode.h"
 #include "ide-source-view-movements.h"
 
@@ -91,6 +92,7 @@ typedef struct
   IdeIndenter                 *indenter;
   GtkSourceGutterRenderer     *line_change_renderer;
   GtkSourceGutterRenderer     *line_diagnostics_renderer;
+  IdeSourceViewCapture        *capture;
   IdeSourceViewMode           *mode;
   GQueue                      *selections;
   GQueue                      *snippets;
@@ -123,8 +125,10 @@ typedef struct
   guint                        auto_indent : 1;
   guint                        completion_visible : 1;
   guint                        enable_word_completion : 1;
+  guint                        in_replay_macro : 1;
   guint                        insert_matching_brace : 1;
   guint                        overwrite_braces : 1;
+  guint                        recording_macro : 1;
   guint                        show_grid_lines : 1;
   guint                        show_line_changes : 1;
   guint                        snippet_completion : 1;
@@ -153,6 +157,7 @@ enum {
   ACTION,
   APPEND_TO_COUNT,
   AUTO_INDENT,
+  BEGIN_MACRO,
   CAPTURE_MODIFIER,
   CLEAR_COUNT,
   CLEAR_MODIFIER,
@@ -160,6 +165,7 @@ enum {
   CLEAR_SNIPPETS,
   CYCLE_COMPLETION,
   DELETE_SELECTION,
+  END_MACRO,
   INDENT_SELECTION,
   INSERT_AT_CURSOR_AND_INDENT,
   INSERT_MODIFIER,
@@ -167,9 +173,10 @@ enum {
   MOVEMENT,
   PASTE_CLIPBOARD_EXTENDED,
   POP_SELECTION,
+  POP_SNIPPET,
   PUSH_SELECTION,
   PUSH_SNIPPET,
-  POP_SNIPPET,
+  REPLAY_MACRO,
   RESTORE_INSERT_MARK,
   SAVE_INSERT_MARK,
   SELECTION_THEATRIC,
@@ -207,6 +214,9 @@ _ide_source_view_set_modifier (IdeSourceView *self,
   g_return_if_fail (IDE_IS_SOURCE_VIEW (self));
 
   priv->modifier = modifier;
+
+  if (priv->recording_macro && !priv->in_replay_macro)
+    ide_source_view_capture_record_modifier (priv->capture, modifier);
 }
 
 static void
@@ -1690,15 +1700,25 @@ ide_source_view_key_press_event (GtkWidget   *widget,
 
   g_assert (IDE_IS_SOURCE_VIEW (self));
 
+  buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (self));
+  insert = gtk_text_buffer_get_insert (buffer);
+
+  /*
+   * If we are waiting for input for a modifier key, dispatch it now.
+   */
   if (priv->waiting_for_capture)
     {
       if (!is_modifier_key (event))
-        priv->modifier = gdk_keyval_to_unicode (event->keyval);
+        _ide_source_view_set_modifier (self, gdk_keyval_to_unicode (event->keyval));
       return TRUE;
     }
 
-  buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (self));
-  insert = gtk_text_buffer_get_insert (buffer);
+  /*
+   * Are we currently recording a macro? If so lets stash the event for later.
+   */
+  if (priv->recording_macro)
+    ide_source_view_capture_record_event (priv->capture, (GdkEvent *)event,
+                                          priv->count, priv->modifier);
 
   /*
    * Check our current change sequence. If the buffer has changed during the
@@ -3244,6 +3264,77 @@ ide_source_view_real_draw_layer (GtkTextView      *text_view,
 }
 
 static void
+ide_source_view_real_begin_macro (IdeSourceView *self)
+{
+  IdeSourceViewPrivate *priv = ide_source_view_get_instance_private (self);
+  IdeSourceViewModeType mode_type;
+  GdkEvent *event;
+  const gchar *mode_name;
+  gunichar modifier;
+  guint count;
+
+  g_assert (IDE_IS_SOURCE_VIEW (self));
+
+  if (priv->in_replay_macro)
+    return;
+
+  priv->recording_macro = TRUE;
+
+  mode_type = ide_source_view_mode_get_mode_type (priv->mode);
+  mode_name = ide_source_view_mode_get_name (priv->mode);
+  modifier = priv->modifier;
+  count = priv->count;
+  event = gtk_get_current_event ();
+
+  g_clear_object (&priv->capture);
+
+  priv->capture = ide_source_view_capture_new (self, mode_name, mode_type, count, modifier);
+  ide_source_view_capture_record_event (priv->capture, event, count, modifier);
+  gdk_event_free (event);
+}
+
+static void
+ide_source_view_real_end_macro (IdeSourceView *self)
+{
+  IdeSourceViewPrivate *priv = ide_source_view_get_instance_private (self);
+
+  g_assert (IDE_IS_SOURCE_VIEW (self));
+
+  if (priv->in_replay_macro)
+    return;
+
+  priv->recording_macro = FALSE;
+}
+
+static void
+ide_source_view_real_replay_macro (IdeSourceView *self)
+{
+  IdeSourceViewPrivate *priv = ide_source_view_get_instance_private (self);
+  IdeSourceViewCapture *capture;
+
+  g_assert (IDE_IS_SOURCE_VIEW (self));
+
+  if (priv->recording_macro)
+    {
+      g_warning ("Cannot playback macro while recording.");
+      return;
+    }
+
+  if (priv->in_replay_macro)
+    {
+      g_warning ("Cannot playback macro while playing back macro.");
+      return;
+    }
+
+  priv->in_replay_macro = TRUE;
+  capture = priv->capture, priv->capture = NULL;
+  ide_source_view_capture_replay (capture);
+  g_clear_object (&priv->capture);
+  priv->capture = capture, capture = NULL;
+  priv->in_replay_macro = FALSE;
+}
+
+static void
 ide_source_view_dispose (GObject *object)
 {
   IdeSourceView *self = (IdeSourceView *)object;
@@ -3251,6 +3342,7 @@ ide_source_view_dispose (GObject *object)
 
   ide_source_view_clear_snippets (self);
 
+  g_clear_object (&priv->capture);
   g_clear_object (&priv->indenter);
   g_clear_object (&priv->line_change_renderer);
   g_clear_object (&priv->line_diagnostics_renderer);
@@ -3416,6 +3508,7 @@ ide_source_view_class_init (IdeSourceViewClass *klass)
   klass->action = ide_source_view_real_action;
   klass->append_to_count = ide_source_view_real_append_to_count;
   klass->auto_indent = ide_source_view_real_auto_indent;
+  klass->begin_macro = ide_source_view_real_begin_macro;
   klass->capture_modifier = ide_source_view_real_capture_modifier;
   klass->clear_count = ide_source_view_real_clear_count;
   klass->clear_modifier = ide_source_view_real_clear_modifier;
@@ -3423,6 +3516,7 @@ ide_source_view_class_init (IdeSourceViewClass *klass)
   klass->clear_selection = ide_source_view_real_clear_selection;
   klass->cycle_completion = ide_source_view_real_cycle_completion;
   klass->delete_selection = ide_source_view_real_delete_selection;
+  klass->end_macro = ide_source_view_real_end_macro;
   klass->indent_selection = ide_source_view_real_indent_selection;
   klass->insert_at_cursor_and_indent = ide_source_view_real_insert_at_cursor_and_indent;
   klass->insert_modifier = ide_source_view_real_insert_modifier;
@@ -3432,6 +3526,7 @@ ide_source_view_class_init (IdeSourceViewClass *klass)
   klass->pop_selection = ide_source_view_real_pop_selection;
   klass->push_selection = ide_source_view_real_push_selection;
   klass->push_snippet = ide_source_view_real_push_snippet;
+  klass->replay_macro = ide_source_view_real_replay_macro;
   klass->restore_insert_mark = ide_source_view_real_restore_insert_mark;
   klass->save_insert_mark = ide_source_view_real_save_insert_mark;
   klass->selection_theatric = ide_source_view_real_selection_theatric;
@@ -3569,6 +3664,25 @@ ide_source_view_class_init (IdeSourceViewClass *klass)
                   0);
 
   /**
+   * IdeSourceView::begin-macro:
+   *
+   * This signal will begin recording input to the #IdeSourceView. This includes the current
+   * #IdeSourceViewMode, #IdeSourceView:count and #IdeSourceView:modifier which will be used
+   * to replay the sequence starting from the correct state.
+   *
+   * Pair this with an emission of #IdeSourceView::end-macro to complete the sequence.
+   */
+  gSignals [BEGIN_MACRO] =
+    g_signal_new ("begin-macro",
+                  G_TYPE_FROM_CLASS (klass),
+                  G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+                  G_STRUCT_OFFSET (IdeSourceViewClass, begin_macro),
+                  NULL, NULL,
+                  g_cclosure_marshal_VOID__VOID,
+                  G_TYPE_NONE,
+                  0);
+
+  /**
    * IdeSourceView::capture-modifier:
    *
    * This signal will block the main loop in a similar fashion to how
@@ -3654,6 +3768,25 @@ ide_source_view_class_init (IdeSourceViewClass *klass)
                   G_TYPE_NONE,
                   0);
 
+  /**
+   * IdeSourceView::end-macro:
+   *
+   * You should call #IdeSourceView::begin-macro before emitting this signal.
+   *
+   * Complete a macro recording sequence. This may be called more times than is necessary,
+   * since #IdeSourceView will only keep the most recent macro recording. This can be
+   * helpful when implementing recording sequences such as in Vim.
+   */
+  gSignals [END_MACRO] =
+    g_signal_new ("end-macro",
+                  G_TYPE_FROM_CLASS (klass),
+                  G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+                  G_STRUCT_OFFSET (IdeSourceViewClass, end_macro),
+                  NULL, NULL,
+                  g_cclosure_marshal_VOID__VOID,
+                  G_TYPE_NONE,
+                  0);
+
   gSignals [INDENT_SELECTION] =
     g_signal_new ("indent-selection",
                   G_TYPE_FROM_CLASS (klass),
@@ -3794,6 +3927,23 @@ ide_source_view_class_init (IdeSourceViewClass *klass)
                   IDE_TYPE_SOURCE_SNIPPET_CONTEXT,
                   GTK_TYPE_TEXT_ITER);
 
+  /**
+   * IdeSourceView:replay-macro:
+   * @self: an #IdeSourceView.
+   *
+   * Replays the last series of captured events that were captured between calls
+   * to #IdeSourceView::begin-macro and #IdeSourceView::end-macro.
+   */
+  gSignals [REPLAY_MACRO] =
+    g_signal_new ("replay-macro",
+                  G_TYPE_FROM_CLASS (klass),
+                  G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+                  G_STRUCT_OFFSET (IdeSourceViewClass, replay_macro),
+                  NULL, NULL,
+                  g_cclosure_marshal_VOID__VOID,
+                  G_TYPE_NONE,
+                  0);
+
   gSignals [RESTORE_INSERT_MARK] =
     g_signal_new ("restore-insert-mark",
                   G_TYPE_FROM_CLASS (klass),
diff --git a/libide/ide-source-view.h b/libide/ide-source-view.h
index 22d6fd0..13da534 100644
--- a/libide/ide-source-view.h
+++ b/libide/ide-source-view.h
@@ -209,6 +209,7 @@ struct _IdeSourceViewClass
   void (*append_to_count)             (IdeSourceView           *self,
                                        gint                     digit);
   void (*auto_indent)                 (IdeSourceView           *self);
+  void (*begin_macro)                 (IdeSourceView           *self);
   void (*capture_modifier)            (IdeSourceView           *self);
   void (*clear_count)                 (IdeSourceView           *self);
   void (*clear_modifier)              (IdeSourceView           *self);
@@ -217,6 +218,7 @@ struct _IdeSourceViewClass
   void (*cycle_completion)            (IdeSourceView           *self,
                                        GtkDirectionType         direction);
   void (*delete_selection)            (IdeSourceView           *self);
+  void (*end_macro)                   (IdeSourceView           *self);
   void (*indent_selection)            (IdeSourceView           *self,
                                        gint                     level);
   void (*insert_at_cursor_and_indent) (IdeSourceView           *self,
@@ -242,6 +244,7 @@ struct _IdeSourceViewClass
                                        IdeSourceSnippet        *snippet,
                                        IdeSourceSnippetContext *context,
                                        const GtkTextIter       *location);
+  void (*replay_macro)                (IdeSourceView           *self);
   void (*restore_insert_mark)         (IdeSourceView           *self);
   void (*save_insert_mark)            (IdeSourceView           *self);
   void (*selection_theatric)          (IdeSourceView           *self,


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