static void update_empty_search (GeditDocument *doc) { GeditDocumentPrivate *priv; gboolean new_value; priv = gedit_document_get_instance_private (doc); if (priv->search_context == NULL) { new_value = TRUE; } else { GtkSourceSearchSettings *search_settings; search_settings = gtk_source_search_context_get_settings (priv->search_context); new_value = gtk_source_search_settings_get_search_text (search_settings) == NULL; } if (priv->empty_search != new_value) { priv->empty_search = new_value; g_object_notify (G_OBJECT (doc), "empty-search"); } }
static void check_replace_text (IdeEditorFrame *self) { GtkSourceSearchContext *search_context; GtkSourceSearchSettings *search_settings; g_autoptr(GError) error = NULL; PangoAttrList *attrs; g_assert (IDE_IS_EDITOR_FRAME (self)); search_context = ide_source_view_get_search_context (self->source_view); search_settings = gtk_source_search_context_get_settings (search_context); attrs = pango_attr_list_new (); /* * If the replace expression is invalid, add a white squiggly underline; * otherwise remove it. */ if (gtk_source_search_settings_get_regex_enabled (search_settings)) { const gchar *replace_text; replace_text = gtk_entry_get_text (GTK_ENTRY (self->replace_entry)); if (!g_regex_check_replacement (replace_text, NULL, &error)) { pango_attr_list_insert (attrs, pango_attr_underline_new (PANGO_UNDERLINE_ERROR)); pango_attr_list_insert (attrs, pango_attr_underline_color_new (65535, 65535, 65535)); } } gtk_entry_set_attributes (GTK_ENTRY (self->replace_entry), attrs); pango_attr_list_unref (attrs); }
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_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) { /* Temporarily disable updating the search position label to prevent flickering */ g_signal_handler_block (buffer, self->cursor_moved_handler); gtk_source_search_context_replace2 (search_context, &start, &end, unescaped_replace_text, -1, &error); /* Re-enable updating the search position label. The next-search-result action * below will cause it to update. */ g_signal_handler_unblock (buffer, self->cursor_moved_handler); 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 update_replace_actions_sensitivity (IdeEditorFrame *self) { GtkSourceSearchContext *search_context; GtkSourceSearchSettings *search_settings; GtkTextBuffer *buffer; GtkTextIter start; GtkTextIter end; const gchar *search_text; const gchar *replace_text; gint pos; gint count; gboolean enable_replace; gboolean enable_replace_all; gboolean replace_regex_valid; g_autoptr(GError) regex_error = NULL; g_autoptr(GError) replace_regex_error = NULL; GActionGroup *group; GAction *replace_action; GAction *replace_all_action; g_assert (IDE_IS_EDITOR_FRAME (self)); search_context = ide_source_view_get_search_context (self->source_view); search_settings = gtk_source_search_context_get_settings (search_context); buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (self->source_view)); gtk_text_buffer_get_selection_bounds (GTK_TEXT_BUFFER (buffer), &start, &end); replace_text = gtk_entry_get_text (GTK_ENTRY (self->replace_entry)); /* Gather enough info to determine if Replace or Replace All would make sense */ search_text = gtk_entry_get_text (GTK_ENTRY (self->search_entry)); pos = gtk_source_search_context_get_occurrence_position (search_context, &start, &end); count = gtk_source_search_context_get_occurrences_count (search_context); regex_error = gtk_source_search_context_get_regex_error (search_context); replace_regex_valid = gtk_source_search_settings_get_regex_enabled (search_settings) ? g_regex_check_replacement (replace_text, NULL, &replace_regex_error) : TRUE; enable_replace = (!ide_str_empty0 (search_text) && regex_error == NULL && replace_regex_valid && pos > 0); enable_replace_all = (!ide_str_empty0 (search_text) && regex_error == NULL && replace_regex_valid && count > 0); group = gtk_widget_get_action_group (GTK_WIDGET (self->search_frame), "search-entry"); replace_action = g_action_map_lookup_action (G_ACTION_MAP (group), "replace"); replace_all_action = g_action_map_lookup_action (G_ACTION_MAP (group), "replace-all"); g_simple_action_set_enabled (G_SIMPLE_ACTION (replace_action), enable_replace); g_simple_action_set_enabled (G_SIMPLE_ACTION (replace_all_action), enable_replace_all); }
static void connect_search_settings (GeditDocument *doc) { GtkSourceSearchSettings *search_settings; search_settings = gtk_source_search_context_get_settings (doc->priv->search_context); /* Note: the signal handler is never disconnected. If the search context * changes its search settings, the old search settings will most * probably be destroyed, anyway. So it shouldn't cause performance * problems. */ g_signal_connect_object (search_settings, "notify::search-text", G_CALLBACK (update_empty_search), doc, G_CONNECT_SWAPPED); }
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 gboolean search_text_transform_to (GBinding *binding, const GValue *from_value, GValue *to_value, gpointer user_data) { IdeEditorFrame *self = user_data; g_assert (IDE_IS_EDITOR_FRAME (self)); g_assert (from_value != NULL); g_assert (to_value != NULL); if (g_value_get_string (from_value) == NULL) { g_value_set_string (to_value, ""); } else { const gchar *entry_text = g_value_get_string (from_value); GtkSourceSearchContext *search_context; GtkSourceSearchSettings *search_settings; search_context = ide_source_view_get_search_context (self->source_view); search_settings = gtk_source_search_context_get_settings (search_context); if (gtk_source_search_settings_get_regex_enabled (search_settings)) { g_value_set_string (to_value, entry_text); } else { gchar *unescaped_entry_text; unescaped_entry_text = gtk_source_utils_unescape_search_text (entry_text); g_value_set_string (to_value, unescaped_entry_text); g_free (unescaped_entry_text); } } return TRUE; }
static void ide_editor_frame_actions_find (GSimpleAction *action, GVariant *variant, gpointer user_data) { IdeEditorFrame *self = user_data; GtkTextBuffer *buffer; GtkDirectionType search_direction; g_assert (IDE_IS_EDITOR_FRAME (self)); gtk_widget_set_visible (GTK_WIDGET (self->replace_entry), FALSE); gtk_widget_set_visible (GTK_WIDGET (self->replace_button), FALSE); gtk_widget_set_visible (GTK_WIDGET (self->replace_all_button), FALSE); search_direction = (GtkDirectionType) g_variant_get_int32 (variant); ide_source_view_set_search_direction (self->source_view, search_direction); buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (self->source_view)); /* * If the buffer currently has a selection, we prime the search entry with the * selected text. If not, we use our previous search text in the case that it was * cleared by the IdeSourceView internal state. */ if (gtk_text_buffer_get_has_selection (buffer)) { GtkTextIter start_sel; GtkTextIter end_sel; g_autofree gchar *selected_text = NULL; g_autofree gchar *escaped_selected_text = NULL; GtkSourceSearchContext *search_context; GtkSourceSearchSettings *search_settings; gtk_text_buffer_get_selection_bounds (buffer, &start_sel, &end_sel); selected_text = gtk_text_buffer_get_text (buffer, &start_sel, &end_sel, FALSE); search_context = ide_source_view_get_search_context (self->source_view); search_settings = gtk_source_search_context_get_settings (search_context); if (gtk_source_search_settings_get_regex_enabled (search_settings)) escaped_selected_text = g_regex_escape_string (selected_text, -1); else escaped_selected_text = gtk_source_utils_escape_search_text (selected_text); gtk_entry_set_text (GTK_ENTRY (self->search_entry), escaped_selected_text); } else { GtkSourceSearchContext *search_context; GtkSourceSearchSettings *search_settings; const gchar *search_text; search_context = ide_source_view_get_search_context (self->source_view); search_settings = gtk_source_search_context_get_settings (search_context); search_text = gtk_source_search_settings_get_search_text (search_settings); if ((search_text != NULL) && (search_text [0] != '\0')) gtk_entry_set_text (GTK_ENTRY (self->search_entry), search_text); else if (self->previous_search_string != NULL) gtk_entry_set_text (GTK_ENTRY (self->search_entry), self->previous_search_string); } gtk_revealer_set_reveal_child (self->search_revealer, TRUE); gtk_widget_grab_focus (GTK_WIDGET (self->search_entry)); }
void ide_editor_frame_set_document (IdeEditorFrame *self, IdeBuffer *buffer) { GtkSourceSearchContext *search_context; GtkSourceSearchSettings *search_settings; GtkTextMark *mark; GtkTextIter iter; GActionGroup *group; g_return_if_fail (IDE_IS_EDITOR_FRAME (self)); g_return_if_fail (IDE_IS_BUFFER (buffer)); gtk_text_view_set_buffer (GTK_TEXT_VIEW (self->source_view), GTK_TEXT_BUFFER (buffer)); g_signal_connect_object (buffer, "notify::busy", G_CALLBACK (ide_editor_frame_update_ruler), self, G_CONNECT_SWAPPED); self->cursor_moved_handler = g_signal_connect (buffer, "cursor-moved", G_CALLBACK (on_cursor_moved), self); mark = gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (buffer)); gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (buffer), &iter, mark); on_cursor_moved (buffer, &iter, self); /* * Sync search entry with the search settings. */ search_context = ide_source_view_get_search_context (self->source_view); search_settings = gtk_source_search_context_get_settings (search_context); g_object_bind_property_full (self->search_entry, "text", search_settings, "search-text", (G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL), search_text_transform_to, search_text_transform_from, self, NULL); g_signal_connect_object (search_context, "notify::occurrences-count", G_CALLBACK (ide_editor_frame_on_search_occurrences_notify), self, G_CONNECT_SWAPPED); g_signal_connect_object (search_context, "notify::regex-error", G_CALLBACK (on_regex_error_changed), 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); g_signal_connect_object (search_settings, "notify::search-text", G_CALLBACK (on_search_text_changed), self, G_CONNECT_SWAPPED); g_signal_connect_object (search_settings, "notify::regex-enabled", G_CALLBACK (on_regex_enabled_changed), self, G_CONNECT_SWAPPED); g_signal_connect_object (self->replace_entry, "notify::text", G_CALLBACK (on_replace_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); }