[gnome-builder/wip/mwleeds/replace: 30/30] command-bar: Implement the 'c' option for vim substitute commands



commit 50f6f7b5491cc9e1989662d001ae6e33b7efdafb
Author: Matthew Leeds <mleeds redhat com>
Date:   Fri Jul 1 12:01:29 2016 -0400

    command-bar: Implement the 'c' option for vim substitute commands
    
    In vim, if the 'c' option is specified at the end of a substitute
    command (like :%s/this/that/gc), the user is prompted to confirm or deny
    replacement on each occurrence of the search term. This commit makes
    Builder recognize that option and respond by opening the replace UI with
    the search entry and replace entry fields filled in.
    
    Because the search_revealer animation doesn't happen immediately (it
    waits for the frame clock to increment), we can't directly trigger the
    "next-search-result" action in ide_editor_frame_actions_replace_confirm.
    The selection would be cleared once the search_entry widget is mapped.
    So instead we setup a callback on the buffer's has-selection property,
    and use that to trigger next-search-result if there's a pending
    replace-confirm action.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=765635

 libide/editor/ide-editor-frame-actions.c |   35 ++++++++++++++++++++++++++++++
 libide/editor/ide-editor-frame-private.h |    1 +
 libide/editor/ide-editor-frame.c         |   27 +++++++++++++++++++++++
 plugins/command-bar/gb-vim.c             |   22 ++++++++++++++++++
 4 files changed, 85 insertions(+), 0 deletions(-)
---
diff --git a/libide/editor/ide-editor-frame-actions.c b/libide/editor/ide-editor-frame-actions.c
index f99a3b5..2103ae8 100644
--- a/libide/editor/ide-editor-frame-actions.c
+++ b/libide/editor/ide-editor-frame-actions.c
@@ -357,10 +357,45 @@ ide_editor_frame_actions_replace_all (GSimpleAction *action,
   g_free (unescaped_replace_text);
 }
 
+static void
+ide_editor_frame_actions_replace_confirm (GSimpleAction *action,
+                                          GVariant      *state,
+                                          gpointer       user_data)
+{
+  IdeEditorFrame *self = user_data;
+  g_autofree const gchar **strv = NULL;
+  gsize array_length;
+
+  g_assert (IDE_IS_EDITOR_FRAME (self));
+  g_assert (state != NULL);
+  g_assert (g_variant_is_of_type (state, G_VARIANT_TYPE_STRING_ARRAY));
+
+  strv = g_variant_get_strv (state, &array_length);
+  g_assert (array_length >= 2);
+
+  gtk_entry_set_text (GTK_ENTRY (self->search_entry), strv[0]);
+  gtk_entry_set_text (GTK_ENTRY (self->replace_entry), strv[1]);
+
+  gtk_widget_show (GTK_WIDGET (self->replace_entry));
+  gtk_widget_show (GTK_WIDGET (self->replace_button));
+  gtk_widget_show (GTK_WIDGET (self->replace_all_button));
+
+  /* increment pending_replace_confirm so that search_revealer_on_child_revealed_changed
+   * will know to go to the next search result (the occurrence only stays selected after
+   * search_entry has been mapped).
+   */
+  self->pending_replace_confirm++;
+
+  gtk_revealer_set_reveal_child (self->search_revealer, TRUE);
+
+  gtk_widget_grab_focus (GTK_WIDGET (self->search_entry));
+}
+
 static const GActionEntry IdeEditorFrameActions[] = {
   { "find", ide_editor_frame_actions_find, "i" },
   { "next-search-result", ide_editor_frame_actions_next_search_result },
   { "previous-search-result", ide_editor_frame_actions_previous_search_result },
+  { "replace-confirm", ide_editor_frame_actions_replace_confirm, "as" },
 };
 
 static const GActionEntry IdeEditorFrameSearchActions[] = {
diff --git a/libide/editor/ide-editor-frame-private.h b/libide/editor/ide-editor-frame-private.h
index c266cd7..134eb2f 100644
--- a/libide/editor/ide-editor-frame-private.h
+++ b/libide/editor/ide-editor-frame-private.h
@@ -55,6 +55,7 @@ struct _IdeEditorFrame
 
   gulong               cursor_moved_handler;
 
+  guint                pending_replace_confirm;
   guint                auto_hide_map : 1;
   guint                show_ruler : 1;
 };
diff --git a/libide/editor/ide-editor-frame.c b/libide/editor/ide-editor-frame.c
index 0fb2951..ae60f26 100644
--- a/libide/editor/ide-editor-frame.c
+++ b/libide/editor/ide-editor-frame.c
@@ -448,6 +448,25 @@ on_search_text_changed (IdeEditorFrame          *self,
                                ide_str_empty0 (search_text) ? FALSE : TRUE);
 }
 
+static void
+search_revealer_on_child_revealed_changed (IdeEditorFrame *self,
+                                           GParamSpec     *pspec,
+                                           GtkRevealer    *search_revealer)
+{
+  g_assert (IDE_IS_EDITOR_FRAME (self));
+  g_assert (GTK_IS_REVEALER (search_revealer));
+
+  if (self->pending_replace_confirm == 0 ||
+      !gtk_revealer_get_child_revealed (search_revealer))
+    return;
+
+  ide_widget_action (GTK_WIDGET (self), "frame", "next-search-result", NULL);
+
+  self->pending_replace_confirm--;
+
+  gtk_widget_grab_focus (GTK_WIDGET (self->replace_button));
+}
+
 void
 ide_editor_frame_set_document (IdeEditorFrame *self,
                                IdeBuffer      *buffer)
@@ -510,6 +529,14 @@ ide_editor_frame_set_document (IdeEditorFrame *self,
                            G_CALLBACK (on_search_text_changed),
                            self,
                            G_CONNECT_SWAPPED);
+
+  /* Setup a callback so the replace-confirm action can work properly. */
+  self->pending_replace_confirm = 0;
+  g_signal_connect_object (self->search_revealer,
+                           "notify::child-revealed",
+                           G_CALLBACK (search_revealer_on_child_revealed_changed),
+                           self,
+                           G_CONNECT_SWAPPED);
 }
 
 static gboolean
diff --git a/plugins/command-bar/gb-vim.c b/plugins/command-bar/gb-vim.c
index c2bcade..4a05bde 100644
--- a/plugins/command-bar/gb-vim.c
+++ b/plugins/command-bar/gb-vim.c
@@ -1021,6 +1021,7 @@ gb_vim_command_search (GtkWidget      *active_widget,
   gchar *search_text = NULL;
   gchar *replace_text = NULL;
   gunichar separator;
+  gboolean confirm_replace = FALSE;
 
   g_assert (GTK_IS_WIDGET (active_widget));
   g_assert (g_str_has_prefix (command, "%s") || g_str_has_prefix (command, "s"));
@@ -1090,6 +1091,10 @@ gb_vim_command_search (GtkWidget      *active_widget,
         {
           switch (*command)
             {
+            case 'c':
+              confirm_replace = TRUE;
+              break;
+
             case 'g':
               break;
 
@@ -1103,6 +1108,23 @@ gb_vim_command_search (GtkWidget      *active_widget,
   search_text = g_strndup (search_begin, search_end - search_begin);
   replace_text = g_strndup (replace_begin, replace_end - replace_begin);
 
+  if (confirm_replace)
+    {
+      GVariant *variant;
+      GVariantBuilder builder;
+
+      g_variant_builder_init (&builder, G_VARIANT_TYPE_STRING_ARRAY);
+      g_variant_builder_add (&builder, "s", search_text);
+      g_variant_builder_add (&builder, "s", replace_text);
+      variant = g_variant_builder_end (&builder);
+
+      ide_widget_action (GTK_WIDGET (IDE_EDITOR_VIEW (active_widget)->frame1),
+                         "frame",
+                         "replace-confirm",
+                         variant);
+      return TRUE;
+    }
+
   buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (source_view));
 
   if (gtk_text_buffer_get_has_selection (buffer))


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