[gnome-builder/wip/mwleeds/replace: 182/185] 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: 182/185] editor-frame: Add actions to make search-and-replace work
- Date: Fri, 1 Jul 2016 17:33:25 +0000 (UTC)
commit 10caa53f1404975f5a0e6b72ebcc6ef6851981f1
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 | 166 +++++++++++++++++++++++++++++-
libide/editor/ide-editor-frame-private.h | 5 +
libide/editor/ide-editor-frame.c | 98 ++++++++----------
3 files changed, 214 insertions(+), 55 deletions(-)
---
diff --git a/libide/editor/ide-editor-frame-actions.c b/libide/editor/ide-editor-frame-actions.c
index 028c53b..c449e23 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,163 @@ 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;
+
+ g_assert (IDE_IS_EDITOR_FRAME (self));
+
+ if (gtk_widget_get_visible (GTK_WIDGET (self->replace_entry)))
+ {
+ gtk_widget_hide (GTK_WIDGET (self->replace_entry));
+ gtk_widget_hide (GTK_WIDGET (self->replace_button));
+ gtk_widget_hide (GTK_WIDGET (self->replace_all_button));
+ }
+ else
+ {
+ 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));
+ }
+}
+
+static void
+ide_editor_frame_actions_toggle_search_options (GSimpleAction *action,
+ GVariant *state,
+ gpointer user_data)
+{
+ IdeEditorFrame *self = user_data;
+
+ g_assert (IDE_IS_EDITOR_FRAME (self));
+
+ if (gtk_widget_get_visible (GTK_WIDGET (self->search_options)))
+ gtk_widget_hide (GTK_WIDGET (self->search_options));
+ else
+ gtk_widget_show_all (GTK_WIDGET (self->search_options));
+}
+
+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_return_if_fail (search_context != NULL);
+
+ search_settings = gtk_source_search_context_get_settings (search_context);
+ search_text = gtk_source_search_settings_get_search_text (search_settings);
+ g_return_if_fail (!ide_str_empty0 (search_text));
+
+ /* replace_text can be an empty string, but can't be NULL */
+ replace_text = gtk_entry_get_text (GTK_ENTRY (self->replace_entry));
+ g_return_if_fail (replace_text != NULL);
+ 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);
+ g_return_if_fail (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);
+}
+
+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_return_if_fail (search_context != NULL);
+
+ search_settings = gtk_source_search_context_get_settings (search_context);
+ search_text = gtk_source_search_settings_get_search_text (search_settings);
+ g_return_if_fail (!ide_str_empty0 (search_text));
+
+ /* 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);
+
+ replace_text = gtk_entry_get_text (GTK_ENTRY (self->replace_entry));
+ g_return_if_fail (replace_text != NULL);
+ 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);
+ }
+}
+
static const GActionEntry IdeEditorFrameActions[] = {
{ "find", ide_editor_frame_actions_find, "i" },
{ "next-search-result", ide_editor_frame_actions_next_search_result },
@@ -188,6 +346,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 +369,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]