[gnome-builder/wip/mwleeds/replace: 27/30] editor-frame: Add actions to make search-and-replace work
- From: Matthew Leeds <mwleeds src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-builder/wip/mwleeds/replace: 27/30] editor-frame: Add actions to make search-and-replace work
- Date: Thu, 7 Jul 2016 02:54:31 +0000 (UTC)
commit 8d870b6e693df9d2aca94e92d684af9884d94cfc
Author: Matthew Leeds <mleeds redhat com>
Date: Fri Jul 1 11:54:27 2016 -0400
editor-frame: Add actions to make search-and-replace work
This commit adds actions so the "Replace" and "Replace All" buttons
work, using the GtkSourceView API. It also adds actions to show or hide
the Replace widgets, to show or hide the search options, and to exit the
search, which are all buttons in the search box.
https://bugzilla.gnome.org/show_bug.cgi?id=765635
libide/editor/ide-editor-frame-actions.c | 165 +++++++++++++++++++++++++++++-
libide/editor/ide-editor-frame-private.h | 5 +
libide/editor/ide-editor-frame.c | 98 ++++++++----------
3 files changed, 213 insertions(+), 55 deletions(-)
---
diff --git a/libide/editor/ide-editor-frame-actions.c b/libide/editor/ide-editor-frame-actions.c
index 028c53b..5c5e2b8 100644
--- a/libide/editor/ide-editor-frame-actions.c
+++ b/libide/editor/ide-editor-frame-actions.c
@@ -20,6 +20,7 @@
#include "ide-editor-frame-actions.h"
#include "ide-editor-frame-private.h"
+#include "util/ide-gtk.h"
static void
ide_editor_frame_actions_find (GSimpleAction *action,
@@ -176,6 +177,162 @@ ide_editor_frame_actions_select_all (GSimpleAction *action,
gtk_editable_select_region (GTK_EDITABLE (self->search_entry), 0, -1);
}
+static void
+ide_editor_frame_actions_toggle_search_replace (GSimpleAction *action,
+ GVariant *state,
+ gpointer user_data)
+{
+ IdeEditorFrame *self = user_data;
+ gboolean visible;
+
+ g_assert (IDE_IS_EDITOR_FRAME (self));
+
+ visible = !gtk_widget_get_visible (GTK_WIDGET (self->replace_entry));
+
+ gtk_widget_set_visible (GTK_WIDGET (self->replace_entry), visible);
+ gtk_widget_set_visible (GTK_WIDGET (self->replace_button), visible);
+ gtk_widget_set_visible (GTK_WIDGET (self->replace_all_button), visible);
+}
+
+static void
+ide_editor_frame_actions_toggle_search_options (GSimpleAction *action,
+ GVariant *state,
+ gpointer user_data)
+{
+ IdeEditorFrame *self = user_data;
+ gboolean visible;
+
+ g_assert (IDE_IS_EDITOR_FRAME (self));
+
+ visible = !gtk_widget_get_visible (GTK_WIDGET (self->search_options));
+
+ gtk_widget_set_visible (GTK_WIDGET (self->search_options), visible);
+}
+
+static void
+ide_editor_frame_actions_exit_search (GSimpleAction *action,
+ GVariant *state,
+ gpointer user_data)
+{
+ IdeEditorFrame *self = user_data;
+ GtkTextBuffer *buffer;
+
+ g_assert (IDE_IS_EDITOR_FRAME (self));
+
+ /* stash the search string for later */
+ g_free (self->previous_search_string);
+ g_object_get (self->search_entry, "text", &self->previous_search_string, NULL);
+
+ /* clear the highlights in the source view */
+ ide_source_view_clear_search (self->source_view);
+
+ /* disable rubberbanding and ensure insert mark is on screen */
+ buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (self->source_view));
+ ide_source_view_set_rubberband_search (self->source_view, FALSE);
+ ide_source_view_scroll_mark_onscreen (self->source_view,
+ gtk_text_buffer_get_insert (buffer),
+ TRUE,
+ 0.5,
+ 0.5);
+
+ /* finally we can focus the source view */
+ gtk_widget_grab_focus (GTK_WIDGET (self->source_view));
+}
+
+static void
+ide_editor_frame_actions_replace (GSimpleAction *action,
+ GVariant *state,
+ gpointer user_data)
+{
+ IdeEditorFrame *self = user_data;
+ GtkSourceSearchContext *search_context;
+ GtkSourceSearchSettings *search_settings;
+ const gchar *replace_text;
+ gchar *unescaped_replace_text;
+ const gchar *search_text;
+ GError *error = NULL;
+ GtkTextIter start;
+ GtkTextIter end;
+ GtkTextBuffer *buffer;
+ gint occurrence_position;
+
+ g_assert (IDE_IS_EDITOR_FRAME (self));
+
+ search_context = ide_source_view_get_search_context (self->source_view);
+ g_assert (search_context != NULL);
+ search_settings = gtk_source_search_context_get_settings (search_context);
+ search_text = gtk_source_search_settings_get_search_text (search_settings);
+ replace_text = gtk_entry_get_text (GTK_ENTRY (self->replace_entry));
+
+ if (ide_str_empty0 (search_text) || replace_text == NULL)
+ return;
+
+ unescaped_replace_text = gtk_source_utils_unescape_search_text (replace_text);
+
+ buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (self->source_view));
+ gtk_text_buffer_get_selection_bounds (buffer, &start, &end);
+ occurrence_position = gtk_source_search_context_get_occurrence_position (search_context, &start, &end);
+
+ if (occurrence_position > 0)
+ {
+ gtk_source_search_context_replace2 (search_context, &start, &end, unescaped_replace_text, -1, &error);
+
+ if (error != NULL)
+ {
+ g_warning ("%s", error->message);
+ g_clear_error (&error);
+ }
+
+ ide_widget_action (GTK_WIDGET (self), "frame", "next-search-result", NULL);
+ }
+
+ g_free (unescaped_replace_text);
+}
+
+static void
+ide_editor_frame_actions_replace_all (GSimpleAction *action,
+ GVariant *state,
+ gpointer user_data)
+{
+ IdeEditorFrame *self = user_data;
+ GtkSourceSearchContext *search_context;
+ GtkSourceSearchSettings *search_settings;
+ const gchar *replace_text;
+ gchar *unescaped_replace_text;
+ const gchar *search_text;
+ GError *error = NULL;
+ GtkSourceCompletion *completion;
+
+ g_assert (IDE_IS_EDITOR_FRAME (self));
+
+ search_context = ide_source_view_get_search_context (self->source_view);
+ g_assert (search_context != NULL);
+ search_settings = gtk_source_search_context_get_settings (search_context);
+ search_text = gtk_source_search_settings_get_search_text (search_settings);
+ replace_text = gtk_entry_get_text (GTK_ENTRY (self->replace_entry));
+
+ if (ide_str_empty0 (search_text) || replace_text == NULL)
+ return;
+
+ /* Temporarily disabling auto completion makes replace more efficient. */
+ completion = gtk_source_view_get_completion (GTK_SOURCE_VIEW (self->source_view));
+ gtk_source_completion_block_interactive (completion);
+
+ unescaped_replace_text = gtk_source_utils_unescape_search_text (replace_text);
+
+ gtk_source_search_context_replace_all (search_context, unescaped_replace_text, -1, &error);
+
+ gtk_source_completion_unblock_interactive (completion);
+
+ if (error != NULL)
+ {
+ g_warning ("%s", error->message);
+ g_clear_error (&error);
+ }
+
+ g_free (unescaped_replace_text);
+}
+
static const GActionEntry IdeEditorFrameActions[] = {
{ "find", ide_editor_frame_actions_find, "i" },
{ "next-search-result", ide_editor_frame_actions_next_search_result },
@@ -188,6 +345,11 @@ static const GActionEntry IdeEditorFrameSearchActions[] = {
{ "paste-clipboard", ide_editor_frame_actions_paste_clipboard, },
{ "delete-selection", ide_editor_frame_actions_delete_selection, },
{ "select-all", ide_editor_frame_actions_select_all },
+ { "toggle-search-replace", NULL, "b", "false", ide_editor_frame_actions_toggle_search_replace },
+ { "toggle-search-options", NULL, "b", "false", ide_editor_frame_actions_toggle_search_options },
+ { "exit-search", ide_editor_frame_actions_exit_search },
+ { "replace", ide_editor_frame_actions_replace },
+ { "replace-all", ide_editor_frame_actions_replace_all },
};
void
@@ -206,6 +368,7 @@ ide_editor_frame_actions_init (IdeEditorFrame *self)
group = g_simple_action_group_new ();
g_action_map_add_action_entries (G_ACTION_MAP (group), IdeEditorFrameSearchActions,
G_N_ELEMENTS (IdeEditorFrameSearchActions), self);
- gtk_widget_insert_action_group (GTK_WIDGET (self->search_entry), "search-entry", G_ACTION_GROUP (group));
+ gtk_widget_insert_action_group (GTK_WIDGET (self->search_frame), "search-entry", G_ACTION_GROUP (group));
+
g_object_unref (group);
}
diff --git a/libide/editor/ide-editor-frame-private.h b/libide/editor/ide-editor-frame-private.h
index 165e296..c266cd7 100644
--- a/libide/editor/ide-editor-frame-private.h
+++ b/libide/editor/ide-editor-frame-private.h
@@ -41,7 +41,12 @@ struct _IdeEditorFrame
GtkLabel *overwrite_label;
GtkScrolledWindow *scrolled_window;
GtkRevealer *search_revealer;
+ GtkFrame *search_frame;
GdTaggedEntry *search_entry;
+ GtkSearchEntry *replace_entry;
+ GtkButton *replace_button;
+ GtkButton *replace_all_button;
+ GtkGrid *search_options;
GdTaggedEntryTag *search_entry_tag;
IdeSourceView *source_view;
IdeEditorMapBin *source_map_container;
diff --git a/libide/editor/ide-editor-frame.c b/libide/editor/ide-editor-frame.c
index 59cbb09..c452239 100644
--- a/libide/editor/ide-editor-frame.c
+++ b/libide/editor/ide-editor-frame.c
@@ -373,6 +373,37 @@ search_text_transform_from (GBinding *binding,
return TRUE;
}
+static void
+ide_editor_frame_add_search_actions (IdeEditorFrame *self,
+ GActionGroup *group)
+{
+ GPropertyAction *prop_action;
+ GtkSourceSearchContext *search_context;
+ GtkSourceSearchSettings *search_settings;
+
+ g_assert (IDE_IS_EDITOR_FRAME (self));
+ g_assert (G_IS_ACTION_GROUP (group));
+
+ search_context = ide_source_view_get_search_context (self->source_view);
+ search_settings = gtk_source_search_context_get_settings (search_context);
+
+ prop_action = g_property_action_new ("change-case-sensitive", search_settings, "case-sensitive");
+ g_action_map_add_action (G_ACTION_MAP (group), G_ACTION (prop_action));
+ g_object_unref (prop_action);
+
+ prop_action = g_property_action_new ("change-word-boundaries", search_settings, "at-word-boundaries");
+ g_action_map_add_action (G_ACTION_MAP (group), G_ACTION (prop_action));
+ g_object_unref (prop_action);
+
+ prop_action = g_property_action_new ("change-regex-enabled", search_settings, "regex-enabled");
+ g_action_map_add_action (G_ACTION_MAP (group), G_ACTION (prop_action));
+ g_object_unref (prop_action);
+
+ prop_action = g_property_action_new ("change-wrap-around", search_settings, "wrap-around");
+ g_action_map_add_action (G_ACTION_MAP (group), G_ACTION (prop_action));
+ g_object_unref (prop_action);
+}
+
void
ide_editor_frame_set_document (IdeEditorFrame *self,
IdeBuffer *buffer)
@@ -416,6 +447,12 @@ ide_editor_frame_set_document (IdeEditorFrame *self,
G_CALLBACK (ide_editor_frame_on_search_occurrences_notify),
self,
G_CONNECT_SWAPPED);
+
+ /*
+ * Add search option property actions
+ */
+ group = gtk_widget_get_action_group (GTK_WIDGET (self->search_frame), "search-entry");
+ ide_editor_frame_add_search_actions (self, group);
}
static gboolean
@@ -504,33 +541,13 @@ ide_editor_frame__search_key_press_event (IdeEditorFrame *self,
GdkEventKey *event,
GdTaggedEntry *entry)
{
- GtkTextBuffer *buffer;
-
g_assert (IDE_IS_EDITOR_FRAME (self));
g_assert (GD_IS_TAGGED_ENTRY (entry));
switch (event->keyval)
{
case GDK_KEY_Escape:
- /* stash the search string for later */
- g_free (self->previous_search_string);
- g_object_get (self->search_entry, "text", &self->previous_search_string, NULL);
-
- /* clear the highlights in the source view */
- ide_source_view_clear_search (self->source_view);
-
- /* disable rubberbanding and ensure insert mark is on screen */
- buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (self->source_view));
- ide_source_view_set_rubberband_search (self->source_view, FALSE);
- ide_source_view_scroll_mark_onscreen (self->source_view,
- gtk_text_buffer_get_insert (buffer),
- TRUE,
- 0.5,
- 0.5);
-
- /* finally we can focus the source view */
- gtk_widget_grab_focus (GTK_WIDGET (self->source_view));
-
+ ide_widget_action (GTK_WIDGET (self->search_frame), "search-entry", "exit-search", NULL);
return GDK_EVENT_STOP;
case GDK_KEY_KP_Enter:
@@ -697,37 +714,6 @@ ide_editor_frame__source_view_populate_popup (IdeEditorFrame *self,
}
static void
-ide_editor_frame_add_search_actions (IdeEditorFrame *self,
- GActionGroup *group)
-{
- GPropertyAction *prop_action;
- GtkSourceSearchContext *search_context;
- GtkSourceSearchSettings *search_settings;
-
- g_assert (IDE_IS_EDITOR_FRAME (self));
- g_assert (G_IS_ACTION_GROUP (group));
-
- search_context = ide_source_view_get_search_context (self->source_view);
- search_settings = gtk_source_search_context_get_settings (search_context);
-
- prop_action = g_property_action_new ("change-case-sensitive", search_settings, "case-sensitive");
- g_action_map_add_action (G_ACTION_MAP (group), G_ACTION (prop_action));
- g_object_unref (prop_action);
-
- prop_action = g_property_action_new ("change-word-boundaries", search_settings, "at-word-boundaries");
- g_action_map_add_action (G_ACTION_MAP (group), G_ACTION (prop_action));
- g_object_unref (prop_action);
-
- prop_action = g_property_action_new ("change-regex-enabled", search_settings, "regex-enabled");
- g_action_map_add_action (G_ACTION_MAP (group), G_ACTION (prop_action));
- g_object_unref (prop_action);
-
- prop_action = g_property_action_new ("change-wrap-around", search_settings, "wrap-around");
- g_action_map_add_action (G_ACTION_MAP (group), G_ACTION (prop_action));
- g_object_unref (prop_action);
-}
-
-static void
ide_editor_frame__search_populate_popup (IdeEditorFrame *self,
GtkWidget *popup,
GdTaggedEntry *entry)
@@ -746,8 +732,7 @@ ide_editor_frame__search_populate_popup (IdeEditorFrame *self,
gboolean clipboard_contains_text;
gboolean entry_has_selection;
- group = gtk_widget_get_action_group (GTK_WIDGET (entry), "search-entry");
- ide_editor_frame_add_search_actions (self, group);
+ group = gtk_widget_get_action_group (GTK_WIDGET (self->search_frame), "search-entry");
menu = ide_application_get_menu_by_id (IDE_APPLICATION_DEFAULT, "ide-editor-frame-search-menu");
gtk_menu_shell_bind_model (GTK_MENU_SHELL (popup), G_MENU_MODEL (menu), NULL, TRUE);
@@ -983,7 +968,12 @@ ide_editor_frame_class_init (IdeEditorFrameClass *klass)
gtk_widget_class_bind_template_child (widget_class, IdeEditorFrame, mode_name_label);
gtk_widget_class_bind_template_child (widget_class, IdeEditorFrame, overwrite_label);
gtk_widget_class_bind_template_child (widget_class, IdeEditorFrame, scrolled_window);
+ gtk_widget_class_bind_template_child (widget_class, IdeEditorFrame, search_frame);
gtk_widget_class_bind_template_child (widget_class, IdeEditorFrame, search_entry);
+ gtk_widget_class_bind_template_child (widget_class, IdeEditorFrame, replace_entry);
+ gtk_widget_class_bind_template_child (widget_class, IdeEditorFrame, replace_button);
+ gtk_widget_class_bind_template_child (widget_class, IdeEditorFrame, replace_all_button);
+ gtk_widget_class_bind_template_child (widget_class, IdeEditorFrame, search_options);
gtk_widget_class_bind_template_child (widget_class, IdeEditorFrame, search_revealer);
gtk_widget_class_bind_template_child (widget_class, IdeEditorFrame, source_map_container);
gtk_widget_class_bind_template_child (widget_class, IdeEditorFrame, source_overlay);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]