From ba429d344132c088177e853cce8ff7181570b221 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Wed, 10 Apr 2024 19:42:51 +0200 Subject: Adding upstream version 44.2. Signed-off-by: Daniel Baumann --- gedit/gedit-commands-search.c | 696 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 696 insertions(+) create mode 100644 gedit/gedit-commands-search.c (limited to 'gedit/gedit-commands-search.c') diff --git a/gedit/gedit-commands-search.c b/gedit/gedit-commands-search.c new file mode 100644 index 0000000..1054859 --- /dev/null +++ b/gedit/gedit-commands-search.c @@ -0,0 +1,696 @@ +/* + * gedit-commands-search.c + * This file is part of gedit + * + * Copyright (C) 1998, 1999 Alex Roberts, Evan Lawrence + * Copyright (C) 2000, 2001 Chema Celorio, Paolo Maggi + * Copyright (C) 2002-2006 Paolo Maggi + * Copyright (C) 2013 Sébastien Wilmet + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#include "config.h" + +#include "gedit-commands.h" +#include "gedit-commands-private.h" + +#include +#include +#include +#include + +#include "gedit-debug.h" +#include "gedit-statusbar.h" +#include "gedit-tab.h" +#include "gedit-tab-private.h" +#include "gedit-view-frame.h" +#include "gedit-window.h" +#include "gedit-utils.h" +#include "gedit-replace-dialog.h" + +#define GEDIT_REPLACE_DIALOG_KEY "gedit-replace-dialog-key" +#define GEDIT_LAST_SEARCH_DATA_KEY "gedit-last-search-data-key" + +typedef struct _LastSearchData LastSearchData; +struct _LastSearchData +{ + gint x; + gint y; +}; + +static void +last_search_data_free (LastSearchData *data) +{ + g_slice_free (LastSearchData, data); +} + +static void +last_search_data_restore_position (GeditReplaceDialog *dlg) +{ + LastSearchData *data; + + data = g_object_get_data (G_OBJECT (dlg), GEDIT_LAST_SEARCH_DATA_KEY); + + if (data != NULL) + { + gtk_window_move (GTK_WINDOW (dlg), + data->x, + data->y); + } +} + +static void +last_search_data_store_position (GeditReplaceDialog *dlg) +{ + LastSearchData *data; + + data = g_object_get_data (G_OBJECT (dlg), GEDIT_LAST_SEARCH_DATA_KEY); + + if (data == NULL) + { + data = g_slice_new (LastSearchData); + + g_object_set_data_full (G_OBJECT (dlg), + GEDIT_LAST_SEARCH_DATA_KEY, + data, + (GDestroyNotify) last_search_data_free); + } + + gtk_window_get_position (GTK_WINDOW (dlg), + &data->x, + &data->y); +} + +/* Use occurences only for Replace All */ +static void +text_found (GeditWindow *window, + gint occurrences) +{ + GeditStatusbar *statusbar = GEDIT_STATUSBAR (gedit_window_get_statusbar (window)); + + if (occurrences > 1) + { + _gedit_statusbar_flash_generic_message (statusbar, + ngettext("Found and replaced %d occurrence", + "Found and replaced %d occurrences", + occurrences), + occurrences); + } + else if (occurrences == 1) + { + _gedit_statusbar_flash_generic_message (statusbar, + _("Found and replaced one occurrence")); + } + else + { + _gedit_statusbar_flash_generic_message (statusbar, " "); + } +} + +#define MAX_MSG_LENGTH 40 + +static void +text_not_found (GeditWindow *window, + GeditReplaceDialog *replace_dialog) +{ + const gchar *search_text; + gchar *truncated_text; + GeditStatusbar *statusbar; + + search_text = gedit_replace_dialog_get_search_text (replace_dialog); + truncated_text = tepl_utils_str_end_truncate (search_text, MAX_MSG_LENGTH); + + statusbar = GEDIT_STATUSBAR (gedit_window_get_statusbar (window)); + + _gedit_statusbar_flash_generic_message (statusbar, + /* Translators: %s is replaced by the text entered + * by the user in the search box. + */ + _("“%s” not found"), truncated_text); + + g_free (truncated_text); +} + +static void +finish_search_from_dialog (GeditWindow *window, + gboolean found) +{ + GeditReplaceDialog *replace_dialog; + + replace_dialog = g_object_get_data (G_OBJECT (window), GEDIT_REPLACE_DIALOG_KEY); + + g_return_if_fail (replace_dialog != NULL); + + if (found) + { + text_found (window, 0); + } + else + { + text_not_found (window, replace_dialog); + } +} + +static gboolean +forward_search_finished (GtkSourceSearchContext *search_context, + GAsyncResult *result, + GeditView *view) +{ + gboolean found; + GtkSourceBuffer *buffer; + GtkTextIter match_start; + GtkTextIter match_end; + + found = gtk_source_search_context_forward_finish (search_context, + result, + &match_start, + &match_end, + NULL, + NULL); + + buffer = gtk_source_search_context_get_buffer (search_context); + + if (found) + { + gtk_text_buffer_select_range (GTK_TEXT_BUFFER (buffer), + &match_start, + &match_end); + + tepl_view_scroll_to_cursor (TEPL_VIEW (view)); + } + else + { + GtkTextIter end_selection; + + gtk_text_buffer_get_selection_bounds (GTK_TEXT_BUFFER (buffer), + NULL, + &end_selection); + + gtk_text_buffer_select_range (GTK_TEXT_BUFFER (buffer), + &end_selection, + &end_selection); + } + + return found; +} + +static void +forward_search_from_dialog_finished (GtkSourceSearchContext *search_context, + GAsyncResult *result, + GeditWindow *window) +{ + GeditView *view = gedit_window_get_active_view (window); + gboolean found; + + if (view == NULL) + { + return; + } + + found = forward_search_finished (search_context, result, view); + + finish_search_from_dialog (window, found); +} + +static void +run_forward_search (GeditWindow *window, + gboolean from_dialog) +{ + GeditView *view; + GtkTextBuffer *buffer; + GtkTextIter start_at; + GtkSourceSearchContext *search_context; + + view = gedit_window_get_active_view (window); + + if (view == NULL) + { + return; + } + + buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view)); + + search_context = gedit_document_get_search_context (GEDIT_DOCUMENT (buffer)); + + if (search_context == NULL) + { + return; + } + + gtk_text_buffer_get_selection_bounds (buffer, NULL, &start_at); + + if (from_dialog) + { + gtk_source_search_context_forward_async (search_context, + &start_at, + NULL, + (GAsyncReadyCallback)forward_search_from_dialog_finished, + window); + } + else + { + gtk_source_search_context_forward_async (search_context, + &start_at, + NULL, + (GAsyncReadyCallback)forward_search_finished, + view); + } +} + +static gboolean +backward_search_finished (GtkSourceSearchContext *search_context, + GAsyncResult *result, + GeditView *view) +{ + gboolean found; + GtkTextIter match_start; + GtkTextIter match_end; + GtkSourceBuffer *buffer; + + found = gtk_source_search_context_backward_finish (search_context, + result, + &match_start, + &match_end, + NULL, + NULL); + + buffer = gtk_source_search_context_get_buffer (search_context); + + if (found) + { + gtk_text_buffer_select_range (GTK_TEXT_BUFFER (buffer), + &match_start, + &match_end); + + tepl_view_scroll_to_cursor (TEPL_VIEW (view)); + } + else + { + GtkTextIter start_selection; + + gtk_text_buffer_get_selection_bounds (GTK_TEXT_BUFFER (buffer), + &start_selection, + NULL); + + gtk_text_buffer_select_range (GTK_TEXT_BUFFER (buffer), + &start_selection, + &start_selection); + } + + return found; +} + +static void +backward_search_from_dialog_finished (GtkSourceSearchContext *search_context, + GAsyncResult *result, + GeditWindow *window) +{ + GeditView *view = gedit_window_get_active_view (window); + gboolean found; + + if (view == NULL) + { + return; + } + + found = backward_search_finished (search_context, result, view); + + finish_search_from_dialog (window, found); +} + +static void +run_backward_search (GeditWindow *window, + gboolean from_dialog) +{ + GeditView *view; + GtkTextBuffer *buffer; + GtkTextIter start_at; + GtkSourceSearchContext *search_context; + + view = gedit_window_get_active_view (window); + + if (view == NULL) + { + return; + } + + buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view)); + + search_context = gedit_document_get_search_context (GEDIT_DOCUMENT (buffer)); + + if (search_context == NULL) + { + return; + } + + gtk_text_buffer_get_selection_bounds (buffer, &start_at, NULL); + + if (from_dialog) + { + gtk_source_search_context_backward_async (search_context, + &start_at, + NULL, + (GAsyncReadyCallback)backward_search_from_dialog_finished, + window); + } + else + { + gtk_source_search_context_backward_async (search_context, + &start_at, + NULL, + (GAsyncReadyCallback)backward_search_finished, + view); + } +} + +static void +do_find (GeditReplaceDialog *dialog, + GeditWindow *window) +{ + if (gedit_replace_dialog_get_backwards (dialog)) + { + run_backward_search (window, TRUE); + } + else + { + run_forward_search (window, TRUE); + } +} + +static void +do_replace (GeditReplaceDialog *dialog, + GeditWindow *window) +{ + GeditDocument *doc; + GtkSourceSearchContext *search_context; + const gchar *replace_entry_text; + gchar *unescaped_replace_text; + GtkTextIter start; + GtkTextIter end; + GError *error = NULL; + + doc = gedit_window_get_active_document (window); + + if (doc == NULL) + { + return; + } + + search_context = gedit_document_get_search_context (doc); + + if (search_context == NULL) + { + return; + } + + /* replace text may be "", we just delete */ + replace_entry_text = gedit_replace_dialog_get_replace_text (dialog); + g_return_if_fail (replace_entry_text != NULL); + + unescaped_replace_text = gtk_source_utils_unescape_search_text (replace_entry_text); + + gtk_text_buffer_get_selection_bounds (GTK_TEXT_BUFFER (doc), &start, &end); + + gtk_source_search_context_replace (search_context, + &start, + &end, + unescaped_replace_text, + -1, + &error); + + g_free (unescaped_replace_text); + + if (error != NULL) + { + gedit_replace_dialog_set_replace_error (dialog, error->message); + g_error_free (error); + } + + do_find (dialog, window); +} + +static void +do_replace_all (GeditReplaceDialog *dialog, + GeditWindow *window) +{ + GeditView *view; + GtkSourceSearchContext *search_context; + GtkTextBuffer *buffer; + GtkSourceCompletion *completion; + const gchar *replace_entry_text; + gchar *unescaped_replace_text; + gint count; + GError *error = NULL; + + view = gedit_window_get_active_view (window); + + if (view == NULL) + { + return; + } + + buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view)); + + search_context = gedit_document_get_search_context (GEDIT_DOCUMENT (buffer)); + + if (search_context == NULL) + { + return; + } + + /* FIXME: this should really be done automatically in gtksoureview, but + * it is an important performance fix, so let's do it here for now. + */ + completion = gtk_source_view_get_completion (GTK_SOURCE_VIEW (view)); + gtk_source_completion_block_interactive (completion); + + /* replace text may be "", we just delete all occurrences */ + replace_entry_text = gedit_replace_dialog_get_replace_text (dialog); + g_return_if_fail (replace_entry_text != NULL); + + unescaped_replace_text = gtk_source_utils_unescape_search_text (replace_entry_text); + + count = gtk_source_search_context_replace_all (search_context, + unescaped_replace_text, + -1, + &error); + + g_free (unescaped_replace_text); + + gtk_source_completion_unblock_interactive (completion); + + if (count > 0) + { + text_found (window, count); + } + else if (error == NULL) + { + text_not_found (window, dialog); + } + + if (error != NULL) + { + gedit_replace_dialog_set_replace_error (dialog, error->message); + g_error_free (error); + } +} + +static void +replace_dialog_response_cb (GeditReplaceDialog *dialog, + gint response_id, + GeditWindow *window) +{ + gedit_debug (DEBUG_COMMANDS); + + switch (response_id) + { + case GEDIT_REPLACE_DIALOG_FIND_RESPONSE: + do_find (dialog, window); + break; + + case GEDIT_REPLACE_DIALOG_REPLACE_RESPONSE: + do_replace (dialog, window); + break; + + case GEDIT_REPLACE_DIALOG_REPLACE_ALL_RESPONSE: + do_replace_all (dialog, window); + break; + + default: + last_search_data_store_position (dialog); + gtk_widget_hide (GTK_WIDGET (dialog)); + } +} + +static void +replace_dialog_destroyed (GeditWindow *window, + GeditReplaceDialog *dialog) +{ + gedit_debug (DEBUG_COMMANDS); + + g_object_set_data (G_OBJECT (window), + GEDIT_REPLACE_DIALOG_KEY, + NULL); + g_object_set_data (G_OBJECT (dialog), + GEDIT_LAST_SEARCH_DATA_KEY, + NULL); +} + +static GtkWidget * +create_dialog (GeditWindow *window) +{ + GtkWidget *dialog = gedit_replace_dialog_new (window); + + g_signal_connect (dialog, + "response", + G_CALLBACK (replace_dialog_response_cb), + window); + + g_object_set_data (G_OBJECT (window), + GEDIT_REPLACE_DIALOG_KEY, + dialog); + + g_object_weak_ref (G_OBJECT (dialog), + (GWeakNotify) replace_dialog_destroyed, + window); + + return dialog; +} + +void +_gedit_cmd_search_find (GSimpleAction *action, + GVariant *parameter, + gpointer user_data) +{ + GeditWindow *window = GEDIT_WINDOW (user_data); + GeditTab *active_tab; + GeditViewFrame *frame; + + gedit_debug (DEBUG_COMMANDS); + + active_tab = gedit_window_get_active_tab (window); + + if (active_tab == NULL) + { + return; + } + + frame = _gedit_tab_get_view_frame (active_tab); + gedit_view_frame_popup_search (frame); +} + +void +_gedit_cmd_search_replace (GSimpleAction *action, + GVariant *parameter, + gpointer user_data) +{ + GeditWindow *window = GEDIT_WINDOW (user_data); + gpointer data; + GtkWidget *replace_dialog; + + gedit_debug (DEBUG_COMMANDS); + + data = g_object_get_data (G_OBJECT (window), GEDIT_REPLACE_DIALOG_KEY); + + if (data == NULL) + { + replace_dialog = create_dialog (window); + } + else + { + g_return_if_fail (GEDIT_IS_REPLACE_DIALOG (data)); + + replace_dialog = GTK_WIDGET (data); + } + + gtk_widget_show (replace_dialog); + last_search_data_restore_position (GEDIT_REPLACE_DIALOG (replace_dialog)); + gedit_replace_dialog_present_with_time (GEDIT_REPLACE_DIALOG (replace_dialog), + GDK_CURRENT_TIME); +} + +void +_gedit_cmd_search_find_next (GSimpleAction *action, + GVariant *parameter, + gpointer user_data) +{ + GeditWindow *window = GEDIT_WINDOW (user_data); + + gedit_debug (DEBUG_COMMANDS); + + run_forward_search (window, FALSE); +} + +void +_gedit_cmd_search_find_prev (GSimpleAction *action, + GVariant *parameter, + gpointer user_data) +{ + GeditWindow *window = GEDIT_WINDOW (user_data); + + gedit_debug (DEBUG_COMMANDS); + + run_backward_search (window, FALSE); +} + +void +_gedit_cmd_search_clear_highlight (GSimpleAction *action, + GVariant *parameter, + gpointer user_data) +{ + GeditWindow *window = GEDIT_WINDOW (user_data); + GeditTab *active_tab; + GeditViewFrame *frame; + GeditDocument *doc; + + gedit_debug (DEBUG_COMMANDS); + + active_tab = gedit_window_get_active_tab (window); + + if (active_tab == NULL) + { + return; + } + + frame = _gedit_tab_get_view_frame (active_tab); + gedit_view_frame_clear_search (frame); + + doc = gedit_tab_get_document (active_tab); + gedit_document_set_search_context (doc, NULL); +} + +void +_gedit_cmd_search_goto_line (GSimpleAction *action, + GVariant *parameter, + gpointer user_data) +{ + GeditWindow *window = GEDIT_WINDOW (user_data); + GeditTab *active_tab; + GeditViewFrame *frame; + + gedit_debug (DEBUG_COMMANDS); + + active_tab = gedit_window_get_active_tab (window); + + if (active_tab == NULL) + { + return; + } + + frame = _gedit_tab_get_view_frame (active_tab); + gedit_view_frame_popup_goto_line (frame); +} + +/* ex:set ts=8 noet: */ -- cgit v1.2.3