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



commit fd8001defe913ede8cf3ec8da4b43de700adac25
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 |   31 ++++++++++++++++++++++++++++++
 libide/editor/ide-editor-frame-private.h |    1 +
 libide/editor/ide-editor-frame.c         |   27 ++++++++++++++++++++++++++
 plugins/command-bar/gb-vim.c             |   21 ++++++++++++++++++++
 4 files changed, 80 insertions(+), 0 deletions(-)
---
diff --git a/libide/editor/ide-editor-frame-actions.c b/libide/editor/ide-editor-frame-actions.c
index 42935ea..bd5b9df 100644
--- a/libide/editor/ide-editor-frame-actions.c
+++ b/libide/editor/ide-editor-frame-actions.c
@@ -358,10 +358,41 @@ ide_editor_frame_actions_replace_all (GSimpleAction *action,
     }
 }
 
+static void
+ide_editor_frame_actions_replace_confirm (GSimpleAction *action,
+                                          GVariant      *state,
+                                          gpointer       user_data)
+{
+  IdeEditorFrame *self = user_data;
+  g_autofree const gchar **strv;
+
+  g_assert (IDE_IS_EDITOR_FRAME (self));
+
+  strv = g_variant_get_strv (state, NULL);
+
+  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..e5725af 100644
--- a/libide/editor/ide-editor-frame-private.h
+++ b/libide/editor/ide-editor-frame-private.h
@@ -57,6 +57,7 @@ struct _IdeEditorFrame
 
   guint                auto_hide_map : 1;
   guint                show_ruler : 1;
+  guint                pending_replace_confirm;
 };
 
 G_END_DECLS
diff --git a/libide/editor/ide-editor-frame.c b/libide/editor/ide-editor-frame.c
index 84e89b7..f604273 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 48701f1..69fccd4 100644
--- a/plugins/command-bar/gb-vim.c
+++ b/plugins/command-bar/gb-vim.c
@@ -1001,6 +1001,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"));
@@ -1070,6 +1071,9 @@ gb_vim_command_search (GtkWidget      *active_widget,
         {
           switch (*command)
             {
+            case 'c':
+              confirm_replace = TRUE;
+              break;
             case 'g':
               break;
 
@@ -1083,6 +1087,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;
+
+    builder = g_variant_builder_new (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]