2006-07-13 14:30:44 +00:00
|
|
|
/*
|
2006-08-20 11:54:33 +00:00
|
|
|
* search.c - this file is part of Geany, a fast and lightweight IDE
|
2006-07-13 14:30:44 +00:00
|
|
|
*
|
2006-08-20 11:54:33 +00:00
|
|
|
* Copyright 2006 Enrico Troeger <enrico.troeger@uvena.de>
|
2006-07-13 14:30:44 +00:00
|
|
|
* Copyright 2006 Nick Treleaven <nick.treleaven@btinternet.com>
|
|
|
|
*
|
|
|
|
* 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, write to the Free Software
|
|
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
|
|
*
|
|
|
|
* $Id$
|
|
|
|
*/
|
|
|
|
|
2006-09-02 23:28:34 +00:00
|
|
|
#include <gdk/gdkkeysyms.h>
|
|
|
|
|
2006-07-13 14:30:44 +00:00
|
|
|
#include "geany.h"
|
|
|
|
#include "search.h"
|
|
|
|
#include "support.h"
|
|
|
|
#include "utils.h"
|
|
|
|
#include "msgwindow.h"
|
2006-08-11 21:12:49 +00:00
|
|
|
#include "document.h"
|
|
|
|
#include "sciwrappers.h"
|
2006-10-22 14:56:05 +00:00
|
|
|
#include "ui_utils.h"
|
2006-10-22 16:52:42 +00:00
|
|
|
#include "sci_cb.h"
|
2006-07-13 14:30:44 +00:00
|
|
|
|
|
|
|
#include <unistd.h>
|
2006-08-11 21:12:49 +00:00
|
|
|
#include <string.h>
|
2006-07-13 14:30:44 +00:00
|
|
|
|
|
|
|
#ifdef G_OS_UNIX
|
|
|
|
# include <sys/types.h>
|
|
|
|
# include <sys/wait.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
2006-08-11 21:12:49 +00:00
|
|
|
enum {
|
2006-11-01 15:26:41 +00:00
|
|
|
GEANY_RESPONSE_FIND = 1,
|
|
|
|
GEANY_RESPONSE_FIND_PREVIOUS,
|
|
|
|
GEANY_RESPONSE_FIND_IN_FILE,
|
|
|
|
GEANY_RESPONSE_FIND_IN_SESSION,
|
|
|
|
GEANY_RESPONSE_MARK,
|
|
|
|
GEANY_RESPONSE_REPLACE,
|
2006-10-22 14:56:05 +00:00
|
|
|
GEANY_RESPONSE_REPLACE_AND_FIND,
|
|
|
|
GEANY_RESPONSE_REPLACE_IN_SESSION,
|
|
|
|
GEANY_RESPONSE_REPLACE_IN_FILE,
|
|
|
|
GEANY_RESPONSE_REPLACE_IN_SEL
|
2006-08-11 21:12:49 +00:00
|
|
|
};
|
|
|
|
|
2006-09-20 11:03:33 +00:00
|
|
|
|
|
|
|
typedef enum
|
|
|
|
{
|
|
|
|
FIF_CASE_SENSITIVE = 1 << 0,
|
|
|
|
FIF_WHOLE_WORD = 1 << 1,
|
|
|
|
FIF_INVERT_MATCH = 1 << 2
|
|
|
|
} fif_options;
|
|
|
|
|
|
|
|
typedef enum
|
|
|
|
{
|
|
|
|
FIF_FGREP,
|
|
|
|
FIF_GREP,
|
|
|
|
FIF_EGREP
|
|
|
|
} fif_match_type;
|
|
|
|
|
|
|
|
|
2006-08-11 21:12:49 +00:00
|
|
|
GeanySearchData search_data;
|
|
|
|
|
|
|
|
static struct
|
|
|
|
{
|
|
|
|
GtkWidget *find_dialog;
|
|
|
|
GtkWidget *replace_dialog;
|
|
|
|
GtkWidget *find_in_files_dialog;
|
|
|
|
} widgets;
|
|
|
|
|
|
|
|
|
2006-07-13 14:30:44 +00:00
|
|
|
static gboolean search_read_io (GIOChannel *source,
|
|
|
|
GIOCondition condition,
|
|
|
|
gpointer data);
|
|
|
|
|
|
|
|
static void search_close_pid(GPid child_pid, gint status, gpointer user_data);
|
|
|
|
|
|
|
|
static gchar **search_get_argv(const gchar **argv_prefix, const gchar *dir);
|
|
|
|
|
2006-08-15 12:26:15 +00:00
|
|
|
static GSList *search_get_file_list(const gchar *path, guint *length);
|
2006-07-13 14:30:44 +00:00
|
|
|
|
|
|
|
|
2006-08-11 21:12:49 +00:00
|
|
|
static void
|
|
|
|
on_find_replace_checkbutton_toggled(GtkToggleButton *togglebutton, gpointer user_data);
|
|
|
|
|
|
|
|
static void
|
|
|
|
on_find_dialog_response(GtkDialog *dialog, gint response, gpointer user_data);
|
|
|
|
|
|
|
|
static void
|
|
|
|
on_find_entry_activate(GtkEntry *entry, gpointer user_data);
|
|
|
|
|
|
|
|
static void
|
|
|
|
on_replace_dialog_response(GtkDialog *dialog, gint response, gpointer user_data);
|
|
|
|
|
|
|
|
static void
|
|
|
|
on_replace_entry_activate(GtkEntry *entry, gpointer user_data);
|
|
|
|
|
2006-09-02 23:28:34 +00:00
|
|
|
static gboolean
|
|
|
|
on_combo_entry_key_pressed(GtkWidget *widget, GdkEventKey *event, gpointer user_data);
|
|
|
|
|
2006-08-11 21:12:49 +00:00
|
|
|
static void
|
|
|
|
on_find_in_files_dialog_response(GtkDialog *dialog, gint response, gpointer user_data);
|
|
|
|
|
2006-09-20 11:03:33 +00:00
|
|
|
static gboolean
|
|
|
|
search_find_in_files(const gchar *search_text, const gchar *dir, fif_match_type regex_opt,
|
|
|
|
fif_options opts);
|
|
|
|
|
2006-08-12 21:38:36 +00:00
|
|
|
static void on_open_dir_dialog_clicked(GtkButton *button, gpointer user_data);
|
|
|
|
|
2006-08-11 21:12:49 +00:00
|
|
|
|
|
|
|
void search_init()
|
|
|
|
{
|
|
|
|
widgets.find_dialog = NULL;
|
|
|
|
widgets.replace_dialog = NULL;
|
|
|
|
widgets.find_in_files_dialog = NULL;
|
|
|
|
search_data.text = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#define FREE_WIDGET(wid) \
|
|
|
|
if (wid && GTK_IS_WIDGET(wid)) gtk_widget_destroy(wid);
|
|
|
|
|
2006-08-14 15:02:52 +00:00
|
|
|
void search_finalize()
|
2006-08-11 21:12:49 +00:00
|
|
|
{
|
|
|
|
FREE_WIDGET(widgets.find_dialog);
|
|
|
|
FREE_WIDGET(widgets.replace_dialog);
|
|
|
|
FREE_WIDGET(widgets.find_in_files_dialog);
|
|
|
|
g_free(search_data.text);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2006-10-22 14:56:05 +00:00
|
|
|
static GtkWidget *add_find_checkboxes(GtkDialog *dialog)
|
2006-08-11 21:12:49 +00:00
|
|
|
{
|
2006-11-01 15:26:41 +00:00
|
|
|
GtkWidget *checkbox1, *checkbox2, *check_regexp, *check_back, *checkbox5,
|
2006-08-12 12:04:14 +00:00
|
|
|
*checkbox7, *hbox, *fbox, *mbox;
|
2006-08-11 21:12:49 +00:00
|
|
|
GtkTooltips *tooltips = GTK_TOOLTIPS(lookup_widget(app->window, "tooltips"));
|
|
|
|
|
|
|
|
check_regexp = gtk_check_button_new_with_mnemonic(_("_Use regular expressions"));
|
|
|
|
g_object_set_data_full(G_OBJECT(dialog), "check_regexp",
|
|
|
|
gtk_widget_ref(check_regexp), (GDestroyNotify)gtk_widget_unref);
|
|
|
|
gtk_button_set_focus_on_click(GTK_BUTTON(check_regexp), FALSE);
|
|
|
|
gtk_tooltips_set_tip(tooltips, check_regexp, _("Use POSIX-like regular expressions. "
|
|
|
|
"For detailed information about using regular expressions, please read the documentation."), NULL);
|
|
|
|
g_signal_connect(G_OBJECT(check_regexp), "toggled",
|
|
|
|
G_CALLBACK(on_find_replace_checkbutton_toggled), GTK_WIDGET(dialog));
|
|
|
|
|
2006-11-01 15:26:41 +00:00
|
|
|
if (dialog != GTK_DIALOG(widgets.find_dialog))
|
|
|
|
{
|
|
|
|
check_back = gtk_check_button_new_with_mnemonic(_("_Search backwards"));
|
|
|
|
g_object_set_data_full(G_OBJECT(dialog), "check_back",
|
|
|
|
gtk_widget_ref(check_back), (GDestroyNotify)gtk_widget_unref);
|
|
|
|
gtk_button_set_focus_on_click(GTK_BUTTON(check_back), FALSE);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{ // align the two checkboxes at the top of the hbox
|
|
|
|
GtkSizeGroup *label_size;
|
|
|
|
check_back = gtk_label_new(NULL);
|
|
|
|
label_size = gtk_size_group_new(GTK_SIZE_GROUP_VERTICAL);
|
|
|
|
gtk_size_group_add_widget(GTK_SIZE_GROUP(label_size), check_back);
|
|
|
|
gtk_size_group_add_widget(GTK_SIZE_GROUP(label_size), check_regexp);
|
|
|
|
g_object_unref(label_size);
|
|
|
|
}
|
2006-08-12 12:04:14 +00:00
|
|
|
checkbox7 = gtk_check_button_new_with_mnemonic(_("Use _escape sequences"));
|
2006-08-11 21:12:49 +00:00
|
|
|
g_object_set_data_full(G_OBJECT(dialog), "check_escape",
|
|
|
|
gtk_widget_ref(checkbox7), (GDestroyNotify)gtk_widget_unref);
|
|
|
|
gtk_button_set_focus_on_click(GTK_BUTTON(checkbox7), FALSE);
|
|
|
|
gtk_tooltips_set_tip(tooltips, checkbox7,
|
|
|
|
_("Replace \\\\, \\t, \\n, \\r and \\uXXXX (Unicode chararacters) with the "
|
|
|
|
"corresponding control characters."), NULL);
|
|
|
|
|
2006-08-12 12:04:14 +00:00
|
|
|
// Search features
|
|
|
|
fbox = gtk_vbox_new(FALSE, 0);
|
|
|
|
gtk_container_add(GTK_CONTAINER(fbox), check_regexp);
|
|
|
|
gtk_container_add(GTK_CONTAINER(fbox), checkbox7);
|
2006-11-01 15:26:41 +00:00
|
|
|
gtk_container_add(GTK_CONTAINER(fbox), check_back);
|
2006-08-12 12:04:14 +00:00
|
|
|
|
|
|
|
checkbox1 = gtk_check_button_new_with_mnemonic(_("_Case sensitive"));
|
|
|
|
g_object_set_data_full(G_OBJECT(dialog), "check_case",
|
|
|
|
gtk_widget_ref(checkbox1), (GDestroyNotify)gtk_widget_unref);
|
|
|
|
gtk_button_set_focus_on_click(GTK_BUTTON(checkbox1), FALSE);
|
|
|
|
|
|
|
|
checkbox2 = gtk_check_button_new_with_mnemonic(_("Match only a _whole word"));
|
|
|
|
g_object_set_data_full(G_OBJECT(dialog), "check_word",
|
|
|
|
gtk_widget_ref(checkbox2), (GDestroyNotify)gtk_widget_unref);
|
|
|
|
gtk_button_set_focus_on_click(GTK_BUTTON(checkbox2), FALSE);
|
|
|
|
|
|
|
|
checkbox5 = gtk_check_button_new_with_mnemonic(_("Match only word s_tart"));
|
|
|
|
g_object_set_data_full(G_OBJECT(dialog), "check_wordstart",
|
|
|
|
gtk_widget_ref(checkbox5), (GDestroyNotify)gtk_widget_unref);
|
|
|
|
gtk_button_set_focus_on_click(GTK_BUTTON(checkbox5), FALSE);
|
|
|
|
|
|
|
|
// Matching options
|
|
|
|
mbox = gtk_vbox_new(FALSE, 0);
|
|
|
|
gtk_container_add(GTK_CONTAINER(mbox), checkbox1);
|
|
|
|
gtk_container_add(GTK_CONTAINER(mbox), checkbox2);
|
|
|
|
gtk_container_add(GTK_CONTAINER(mbox), checkbox5);
|
2006-08-11 21:12:49 +00:00
|
|
|
|
2006-08-27 17:49:10 +00:00
|
|
|
hbox = gtk_hbox_new(TRUE, 6);
|
2006-08-12 12:04:14 +00:00
|
|
|
gtk_container_add(GTK_CONTAINER(hbox), fbox);
|
|
|
|
gtk_container_add(GTK_CONTAINER(hbox), mbox);
|
2006-10-22 14:56:05 +00:00
|
|
|
return hbox;
|
2006-08-11 21:12:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2006-10-22 14:56:05 +00:00
|
|
|
static void send_find_dialog_response(GtkButton *button, gpointer user_data)
|
|
|
|
{
|
|
|
|
gtk_dialog_response(GTK_DIALOG(widgets.find_dialog), GPOINTER_TO_INT(user_data));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2006-10-22 16:52:42 +00:00
|
|
|
static gchar *get_default_text(gint idx)
|
|
|
|
{
|
|
|
|
gchar *s = NULL;
|
|
|
|
|
|
|
|
if (sci_get_lines_selected(doc_list[idx].sci) == 1)
|
|
|
|
{
|
|
|
|
s = g_malloc(sci_get_selected_text_length(doc_list[idx].sci));
|
|
|
|
sci_get_selected_text(doc_list[idx].sci, s);
|
|
|
|
}
|
|
|
|
else if (sci_get_lines_selected(doc_list[idx].sci) == 0)
|
|
|
|
{ // use the word at current cursor position
|
|
|
|
static gchar word[GEANY_MAX_WORD_LENGTH];
|
|
|
|
sci_cb_find_current_word(doc_list[idx].sci, -1, word, sizeof(word));
|
|
|
|
if (word[0] != '\0') s = g_strdup(word);
|
|
|
|
}
|
|
|
|
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2006-08-11 21:12:49 +00:00
|
|
|
void search_show_find_dialog()
|
|
|
|
{
|
|
|
|
gint idx = document_get_cur_idx();
|
|
|
|
gchar *sel = NULL;
|
|
|
|
|
|
|
|
if (idx == -1 || ! doc_list[idx].is_valid) return;
|
|
|
|
|
2006-10-22 16:52:42 +00:00
|
|
|
sel = get_default_text(idx);
|
2006-08-11 21:12:49 +00:00
|
|
|
|
|
|
|
if (widgets.find_dialog == NULL)
|
|
|
|
{
|
2006-10-22 14:56:05 +00:00
|
|
|
GtkWidget *label, *entry, *sbox, *vbox;
|
2006-11-01 15:26:41 +00:00
|
|
|
GtkWidget *exp, *bbox, *button, *check_close;
|
|
|
|
GtkTooltips *tooltips = GTK_TOOLTIPS(lookup_widget(app->window, "tooltips"));
|
2006-08-11 21:12:49 +00:00
|
|
|
|
|
|
|
widgets.find_dialog = gtk_dialog_new_with_buttons(_("Find"),
|
|
|
|
GTK_WINDOW(app->window), GTK_DIALOG_DESTROY_WITH_PARENT,
|
2006-11-01 15:26:41 +00:00
|
|
|
GTK_STOCK_CLOSE, GTK_RESPONSE_CANCEL, NULL);
|
2006-10-22 14:56:05 +00:00
|
|
|
vbox = ui_dialog_vbox_new(GTK_DIALOG(widgets.find_dialog));
|
|
|
|
gtk_box_set_spacing(GTK_BOX(vbox), 9);
|
2006-08-11 21:12:49 +00:00
|
|
|
|
2006-11-01 15:26:41 +00:00
|
|
|
button = gtk_button_new_with_mnemonic(_("Find _Previous"));
|
|
|
|
gtk_dialog_add_action_widget(GTK_DIALOG(widgets.find_dialog), button,
|
|
|
|
GEANY_RESPONSE_FIND_PREVIOUS);
|
|
|
|
g_object_set_data_full(G_OBJECT(widgets.find_dialog), "btn_previous",
|
|
|
|
gtk_widget_ref(button), (GDestroyNotify)gtk_widget_unref);
|
|
|
|
|
|
|
|
button = ui_button_new_with_image(GTK_STOCK_FIND, _("Find _Next"));
|
|
|
|
gtk_dialog_add_action_widget(GTK_DIALOG(widgets.find_dialog), button,
|
|
|
|
GEANY_RESPONSE_FIND);
|
|
|
|
|
2006-08-12 12:04:14 +00:00
|
|
|
label = gtk_label_new(_("Search for:"));
|
2006-08-12 13:07:58 +00:00
|
|
|
gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
|
2006-08-11 21:12:49 +00:00
|
|
|
|
|
|
|
entry = gtk_combo_box_entry_new_text();
|
|
|
|
gtk_entry_set_max_length(GTK_ENTRY(gtk_bin_get_child(GTK_BIN(entry))), 248);
|
|
|
|
gtk_entry_set_width_chars(GTK_ENTRY(gtk_bin_get_child(GTK_BIN(entry))), 50);
|
|
|
|
if (sel) gtk_entry_set_text(GTK_ENTRY(GTK_BIN(entry)->child), sel);
|
|
|
|
g_object_set_data_full(G_OBJECT(widgets.find_dialog), "entry",
|
|
|
|
gtk_widget_ref(entry), (GDestroyNotify)gtk_widget_unref);
|
|
|
|
|
|
|
|
g_signal_connect((gpointer) gtk_bin_get_child(GTK_BIN(entry)), "activate",
|
|
|
|
G_CALLBACK(on_find_entry_activate), NULL);
|
|
|
|
g_signal_connect((gpointer) widgets.find_dialog, "response",
|
|
|
|
G_CALLBACK(on_find_dialog_response), entry);
|
|
|
|
g_signal_connect((gpointer) widgets.find_dialog, "delete_event",
|
|
|
|
G_CALLBACK(gtk_widget_hide), NULL);
|
|
|
|
|
2006-08-12 13:07:58 +00:00
|
|
|
sbox = gtk_hbox_new(FALSE, 6);
|
2006-08-12 13:30:52 +00:00
|
|
|
gtk_box_pack_start(GTK_BOX(sbox), label, FALSE, FALSE, 0);
|
|
|
|
gtk_box_pack_start(GTK_BOX(sbox), entry, TRUE, TRUE, 0);
|
2006-11-01 15:26:41 +00:00
|
|
|
gtk_box_pack_start(GTK_BOX(vbox), sbox, TRUE, FALSE, 0);
|
2006-08-11 21:12:49 +00:00
|
|
|
|
2006-10-22 14:56:05 +00:00
|
|
|
gtk_container_add(GTK_CONTAINER(vbox),
|
|
|
|
add_find_checkboxes(GTK_DIALOG(widgets.find_dialog)));
|
2006-08-11 21:12:49 +00:00
|
|
|
|
2006-11-01 15:26:41 +00:00
|
|
|
// Now add the multiple match options
|
|
|
|
exp = gtk_expander_new(_("Find All"));
|
|
|
|
bbox = gtk_hbutton_box_new();
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
button = gtk_button_new_with_mnemonic(_("_Mark"));
|
|
|
|
gtk_container_add(GTK_CONTAINER(bbox), button);
|
|
|
|
g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(send_find_dialog_response),
|
|
|
|
GINT_TO_POINTER(GEANY_RESPONSE_MARK));
|
|
|
|
#endif // not implemented yet
|
|
|
|
|
|
|
|
button = gtk_button_new_with_mnemonic(_("In Sessi_on"));
|
|
|
|
gtk_container_add(GTK_CONTAINER(bbox), button);
|
|
|
|
g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(send_find_dialog_response),
|
|
|
|
GINT_TO_POINTER(GEANY_RESPONSE_FIND_IN_SESSION));
|
|
|
|
|
|
|
|
button = gtk_button_new_with_mnemonic(_("In F_ile"));
|
|
|
|
gtk_container_add(GTK_CONTAINER(bbox), button);
|
|
|
|
g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(send_find_dialog_response),
|
|
|
|
GINT_TO_POINTER(GEANY_RESPONSE_FIND_IN_FILE));
|
|
|
|
|
|
|
|
// close window checkbox
|
|
|
|
check_close = gtk_check_button_new_with_mnemonic(_("Close _dialog"));
|
|
|
|
g_object_set_data_full(G_OBJECT(widgets.find_dialog), "check_close",
|
|
|
|
gtk_widget_ref(check_close), (GDestroyNotify) gtk_widget_unref);
|
|
|
|
gtk_button_set_focus_on_click(GTK_BUTTON(check_close), FALSE);
|
|
|
|
gtk_tooltips_set_tip(tooltips, check_close,
|
|
|
|
_("The dialog window won't be closed when you start the operation."), NULL);
|
|
|
|
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check_close), TRUE);
|
|
|
|
gtk_container_add(GTK_CONTAINER(bbox), check_close);
|
|
|
|
gtk_button_box_set_child_secondary(GTK_BUTTON_BOX(bbox), check_close, TRUE);
|
|
|
|
|
|
|
|
ui_hbutton_box_copy_layout(
|
|
|
|
GTK_BUTTON_BOX(GTK_DIALOG(widgets.find_dialog)->action_area),
|
|
|
|
GTK_BUTTON_BOX(bbox));
|
|
|
|
gtk_container_add(GTK_CONTAINER(exp), bbox);
|
|
|
|
gtk_container_add(GTK_CONTAINER(vbox), exp);
|
|
|
|
|
2006-08-11 21:12:49 +00:00
|
|
|
gtk_widget_show_all(widgets.find_dialog);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (sel) gtk_entry_set_text(GTK_ENTRY(GTK_BIN(
|
|
|
|
lookup_widget(widgets.find_dialog, "entry"))->child), sel);
|
|
|
|
gtk_widget_grab_focus(GTK_WIDGET(GTK_BIN(lookup_widget(widgets.find_dialog, "entry"))->child));
|
|
|
|
gtk_widget_show(widgets.find_dialog);
|
|
|
|
}
|
|
|
|
g_free(sel);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2006-10-22 14:56:05 +00:00
|
|
|
static void send_replace_dialog_response(GtkButton *button, gpointer user_data)
|
|
|
|
{
|
|
|
|
gtk_dialog_response(GTK_DIALOG(widgets.replace_dialog), GPOINTER_TO_INT(user_data));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2006-08-11 21:12:49 +00:00
|
|
|
void search_show_replace_dialog()
|
|
|
|
{
|
|
|
|
gint idx = document_get_cur_idx();
|
|
|
|
gchar *sel = NULL;
|
|
|
|
|
|
|
|
if (idx == -1 || ! doc_list[idx].is_valid) return;
|
|
|
|
|
2006-10-22 16:52:42 +00:00
|
|
|
sel = get_default_text(idx);
|
2006-08-11 21:12:49 +00:00
|
|
|
|
|
|
|
if (widgets.replace_dialog == NULL)
|
|
|
|
{
|
|
|
|
GtkWidget *label_find, *label_replace, *entry_find, *entry_replace,
|
2006-10-22 14:56:05 +00:00
|
|
|
*check_close, *button, *rbox, *fbox, *vbox, *exp, *bbox;
|
2006-11-01 15:26:41 +00:00
|
|
|
GtkSizeGroup *label_size;
|
2006-08-11 21:12:49 +00:00
|
|
|
GtkTooltips *tooltips = GTK_TOOLTIPS(lookup_widget(app->window, "tooltips"));
|
|
|
|
|
|
|
|
widgets.replace_dialog = gtk_dialog_new_with_buttons(_("Replace"),
|
|
|
|
GTK_WINDOW(app->window), GTK_DIALOG_DESTROY_WITH_PARENT,
|
|
|
|
GTK_STOCK_CLOSE, GTK_RESPONSE_CANCEL, NULL);
|
2006-10-22 14:56:05 +00:00
|
|
|
vbox = ui_dialog_vbox_new(GTK_DIALOG(widgets.replace_dialog));
|
|
|
|
gtk_box_set_spacing(GTK_BOX(vbox), 9);
|
2006-08-11 21:12:49 +00:00
|
|
|
|
|
|
|
button = gtk_button_new_from_stock(GTK_STOCK_FIND);
|
|
|
|
gtk_dialog_add_action_widget(GTK_DIALOG(widgets.replace_dialog), button,
|
|
|
|
GEANY_RESPONSE_FIND);
|
|
|
|
button = gtk_button_new_with_mnemonic(_("_Replace"));
|
|
|
|
gtk_dialog_add_action_widget(GTK_DIALOG(widgets.replace_dialog), button,
|
|
|
|
GEANY_RESPONSE_REPLACE);
|
2006-10-22 14:56:05 +00:00
|
|
|
button = gtk_button_new_with_mnemonic(_("Re_place & Find"));
|
|
|
|
gtk_dialog_add_action_widget(GTK_DIALOG(widgets.replace_dialog), button,
|
|
|
|
GEANY_RESPONSE_REPLACE_AND_FIND);
|
|
|
|
|
2006-08-12 12:04:14 +00:00
|
|
|
label_find = gtk_label_new(_("Search for:"));
|
2006-08-11 21:12:49 +00:00
|
|
|
gtk_misc_set_alignment(GTK_MISC(label_find), 0, 0.5);
|
|
|
|
|
2006-08-12 12:04:14 +00:00
|
|
|
label_replace = gtk_label_new(_("Replace with:"));
|
2006-08-11 21:12:49 +00:00
|
|
|
gtk_misc_set_alignment(GTK_MISC(label_replace), 0, 0.5);
|
|
|
|
|
|
|
|
entry_find = gtk_combo_box_entry_new_text();
|
|
|
|
gtk_entry_set_max_length(GTK_ENTRY(gtk_bin_get_child(GTK_BIN(entry_find))), 248);
|
|
|
|
gtk_entry_set_width_chars(GTK_ENTRY(gtk_bin_get_child(GTK_BIN(entry_find))), 50);
|
|
|
|
if (sel) gtk_entry_set_text(GTK_ENTRY(GTK_BIN(entry_find)->child), sel);
|
|
|
|
g_object_set_data_full(G_OBJECT(widgets.replace_dialog), "entry_find",
|
|
|
|
gtk_widget_ref(entry_find), (GDestroyNotify)gtk_widget_unref);
|
|
|
|
|
|
|
|
entry_replace = gtk_combo_box_entry_new_text();
|
|
|
|
gtk_entry_set_max_length(GTK_ENTRY(gtk_bin_get_child(GTK_BIN(entry_replace))), 248);
|
|
|
|
gtk_entry_set_width_chars(GTK_ENTRY(gtk_bin_get_child(GTK_BIN(entry_replace))), 50);
|
|
|
|
g_object_set_data_full(G_OBJECT(widgets.replace_dialog), "entry_replace",
|
|
|
|
gtk_widget_ref(entry_replace), (GDestroyNotify)gtk_widget_unref);
|
|
|
|
|
2006-09-02 23:28:34 +00:00
|
|
|
g_signal_connect((gpointer) gtk_bin_get_child(GTK_BIN(entry_find)), "key-press-event",
|
|
|
|
G_CALLBACK(on_combo_entry_key_pressed), gtk_bin_get_child(GTK_BIN(entry_replace)));
|
2006-08-11 21:12:49 +00:00
|
|
|
g_signal_connect((gpointer) gtk_bin_get_child(GTK_BIN(entry_replace)), "activate",
|
|
|
|
G_CALLBACK(on_replace_entry_activate), NULL);
|
|
|
|
g_signal_connect((gpointer) widgets.replace_dialog, "response",
|
|
|
|
G_CALLBACK(on_replace_dialog_response), entry_replace);
|
|
|
|
g_signal_connect((gpointer) widgets.replace_dialog, "delete_event",
|
|
|
|
G_CALLBACK(gtk_widget_hide), NULL);
|
|
|
|
|
|
|
|
fbox = gtk_hbox_new(FALSE, 6);
|
2006-08-12 12:04:14 +00:00
|
|
|
gtk_box_pack_start(GTK_BOX(fbox), label_find, FALSE, FALSE, 0);
|
|
|
|
gtk_box_pack_start(GTK_BOX(fbox), entry_find, TRUE, TRUE, 0);
|
2006-08-11 21:12:49 +00:00
|
|
|
|
|
|
|
rbox = gtk_hbox_new(FALSE, 6);
|
2006-08-12 12:04:14 +00:00
|
|
|
gtk_box_pack_start(GTK_BOX(rbox), label_replace, FALSE, FALSE, 0);
|
|
|
|
gtk_box_pack_start(GTK_BOX(rbox), entry_replace, TRUE, TRUE, 0);
|
2006-08-11 21:12:49 +00:00
|
|
|
|
2006-10-22 14:56:05 +00:00
|
|
|
label_size = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
|
|
|
|
gtk_size_group_add_widget(label_size, label_find);
|
|
|
|
gtk_size_group_add_widget(label_size, label_replace);
|
|
|
|
g_object_unref(G_OBJECT(label_size)); // auto destroy the size group
|
|
|
|
|
|
|
|
gtk_box_pack_start(GTK_BOX(vbox), fbox, TRUE, FALSE, 0);
|
|
|
|
gtk_box_pack_start(GTK_BOX(vbox), rbox, TRUE, FALSE, 0);
|
|
|
|
gtk_container_add(GTK_CONTAINER(vbox),
|
|
|
|
add_find_checkboxes(GTK_DIALOG(widgets.replace_dialog)));
|
|
|
|
|
|
|
|
// Now add the multiple replace options
|
|
|
|
exp = gtk_expander_new(_("Replace All"));
|
|
|
|
bbox = gtk_hbutton_box_new();
|
|
|
|
|
|
|
|
button = gtk_button_new_with_mnemonic(_("In Se_lection"));
|
|
|
|
gtk_tooltips_set_tip(tooltips, button,
|
|
|
|
_("Replace all matches found in the currently selected text"), NULL);
|
|
|
|
gtk_container_add(GTK_CONTAINER(bbox), button);
|
|
|
|
g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(send_replace_dialog_response),
|
|
|
|
GINT_TO_POINTER(GEANY_RESPONSE_REPLACE_IN_SEL));
|
2006-08-11 21:12:49 +00:00
|
|
|
|
2006-10-24 16:15:29 +00:00
|
|
|
button = gtk_button_new_with_mnemonic(_("In Sessi_on"));
|
2006-10-22 14:56:05 +00:00
|
|
|
gtk_container_add(GTK_CONTAINER(bbox), button);
|
|
|
|
g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(send_replace_dialog_response),
|
2006-10-24 16:15:29 +00:00
|
|
|
GINT_TO_POINTER(GEANY_RESPONSE_REPLACE_IN_SESSION));
|
2006-08-11 21:12:49 +00:00
|
|
|
|
2006-10-24 16:15:29 +00:00
|
|
|
button = gtk_button_new_with_mnemonic(_("In F_ile"));
|
2006-10-22 14:56:05 +00:00
|
|
|
gtk_container_add(GTK_CONTAINER(bbox), button);
|
|
|
|
g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(send_replace_dialog_response),
|
2006-10-24 16:15:29 +00:00
|
|
|
GINT_TO_POINTER(GEANY_RESPONSE_REPLACE_IN_FILE));
|
2006-10-22 14:56:05 +00:00
|
|
|
|
2006-11-01 15:26:41 +00:00
|
|
|
// close window checkbox
|
2006-10-22 14:56:05 +00:00
|
|
|
check_close = gtk_check_button_new_with_mnemonic(_("Close _dialog"));
|
|
|
|
g_object_set_data_full(G_OBJECT(widgets.replace_dialog), "check_close",
|
|
|
|
gtk_widget_ref(check_close), (GDestroyNotify) gtk_widget_unref);
|
|
|
|
gtk_button_set_focus_on_click(GTK_BUTTON(check_close), FALSE);
|
|
|
|
gtk_tooltips_set_tip(tooltips, check_close,
|
2006-08-27 17:49:10 +00:00
|
|
|
_("The dialog window won't be closed when you start the operation."), NULL);
|
2006-10-22 14:56:05 +00:00
|
|
|
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check_close), TRUE);
|
|
|
|
gtk_container_add(GTK_CONTAINER(bbox), check_close);
|
|
|
|
gtk_button_box_set_child_secondary(GTK_BUTTON_BOX(bbox), check_close, TRUE);
|
2006-08-27 17:49:10 +00:00
|
|
|
|
2006-11-01 15:26:41 +00:00
|
|
|
ui_hbutton_box_copy_layout(
|
|
|
|
GTK_BUTTON_BOX(GTK_DIALOG(widgets.replace_dialog)->action_area),
|
|
|
|
GTK_BUTTON_BOX(bbox));
|
2006-10-22 14:56:05 +00:00
|
|
|
gtk_container_add(GTK_CONTAINER(exp), bbox);
|
|
|
|
gtk_container_add(GTK_CONTAINER(vbox), exp);
|
2006-08-11 21:12:49 +00:00
|
|
|
|
|
|
|
gtk_widget_show_all(widgets.replace_dialog);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (sel) gtk_entry_set_text(GTK_ENTRY(GTK_BIN(
|
|
|
|
lookup_widget(widgets.replace_dialog, "entry_find"))->child), sel);
|
|
|
|
gtk_widget_grab_focus(GTK_WIDGET(GTK_BIN(lookup_widget(widgets.replace_dialog, "entry_find"))->child));
|
|
|
|
gtk_widget_show(widgets.replace_dialog);
|
|
|
|
}
|
|
|
|
g_free(sel);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void search_show_find_in_files_dialog()
|
|
|
|
{
|
|
|
|
static GtkWidget *combo = NULL;
|
|
|
|
static GtkWidget *entry1;
|
|
|
|
GtkWidget *entry2; // the child GtkEntry of combo
|
2006-08-12 21:38:36 +00:00
|
|
|
GtkWidget *dirbtn, *openimg;
|
2006-08-11 21:12:49 +00:00
|
|
|
gint idx = document_get_cur_idx();
|
|
|
|
gchar *sel = NULL;
|
|
|
|
gchar *cur_dir;
|
|
|
|
|
|
|
|
if (idx == -1 || ! doc_list[idx].is_valid) return;
|
|
|
|
|
|
|
|
cur_dir = utils_get_current_file_dir();
|
|
|
|
|
|
|
|
if (widgets.find_in_files_dialog == NULL)
|
|
|
|
{
|
2006-09-20 11:03:33 +00:00
|
|
|
GtkWidget *label, *label1, *checkbox1, *checkbox2, *check_wholeword;
|
2006-10-22 14:56:05 +00:00
|
|
|
GtkWidget *dbox, *sbox, *cbox, *rbox, *rbtn, *hbox, *vbox;
|
2006-08-12 12:51:56 +00:00
|
|
|
GtkSizeGroup *size_group;
|
2006-08-11 21:12:49 +00:00
|
|
|
GtkTooltips *tooltips = GTK_TOOLTIPS(lookup_widget(app->window, "tooltips"));
|
|
|
|
|
|
|
|
widgets.find_in_files_dialog = gtk_dialog_new_with_buttons(
|
|
|
|
_("Find in files"), GTK_WINDOW(app->window), GTK_DIALOG_DESTROY_WITH_PARENT,
|
|
|
|
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, NULL);
|
2006-10-22 14:56:05 +00:00
|
|
|
vbox = ui_dialog_vbox_new(GTK_DIALOG(widgets.find_in_files_dialog));
|
|
|
|
gtk_box_set_spacing(GTK_BOX(vbox), 9);
|
2006-08-11 21:12:49 +00:00
|
|
|
|
|
|
|
gtk_dialog_add_button(GTK_DIALOG(widgets.find_in_files_dialog), "gtk-find", GTK_RESPONSE_ACCEPT);
|
|
|
|
gtk_dialog_set_default_response(GTK_DIALOG(widgets.find_in_files_dialog),
|
|
|
|
GTK_RESPONSE_ACCEPT);
|
|
|
|
|
2006-08-15 19:38:07 +00:00
|
|
|
label1 = gtk_label_new(_("Directory:"));
|
2006-08-12 12:51:56 +00:00
|
|
|
gtk_misc_set_alignment(GTK_MISC(label1), 0, 0.5);
|
2006-08-11 21:12:49 +00:00
|
|
|
|
|
|
|
entry1 = gtk_entry_new();
|
|
|
|
gtk_entry_set_max_length(GTK_ENTRY(entry1), 248);
|
|
|
|
gtk_entry_set_width_chars(GTK_ENTRY(entry1), 50);
|
|
|
|
g_object_set_data_full(G_OBJECT(widgets.find_in_files_dialog), "entry_dir",
|
|
|
|
gtk_widget_ref(entry1), (GDestroyNotify)gtk_widget_unref);
|
|
|
|
|
2006-08-12 21:38:36 +00:00
|
|
|
dirbtn = gtk_button_new();
|
|
|
|
openimg = gtk_image_new_from_stock(GTK_STOCK_OPEN, GTK_ICON_SIZE_BUTTON);
|
|
|
|
gtk_container_add(GTK_CONTAINER(dirbtn), openimg);
|
|
|
|
g_signal_connect(G_OBJECT(dirbtn), "clicked", G_CALLBACK(on_open_dir_dialog_clicked),
|
|
|
|
NULL);
|
|
|
|
|
2006-08-12 12:51:56 +00:00
|
|
|
dbox = gtk_hbox_new(FALSE, 6);
|
|
|
|
gtk_box_pack_start(GTK_BOX(dbox), label1, FALSE, FALSE, 0);
|
|
|
|
gtk_box_pack_start(GTK_BOX(dbox), entry1, TRUE, TRUE, 0);
|
2006-08-12 21:38:36 +00:00
|
|
|
gtk_box_pack_start(GTK_BOX(dbox), dirbtn, FALSE, FALSE, 0);
|
2006-08-11 21:12:49 +00:00
|
|
|
|
2006-08-12 12:04:14 +00:00
|
|
|
label = gtk_label_new(_("Search for:"));
|
2006-08-12 12:51:56 +00:00
|
|
|
gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
|
2006-08-11 21:12:49 +00:00
|
|
|
|
|
|
|
combo = gtk_combo_box_entry_new_text();
|
|
|
|
entry2 = gtk_bin_get_child(GTK_BIN(combo));
|
|
|
|
gtk_entry_set_max_length(GTK_ENTRY(entry2), 248);
|
|
|
|
gtk_entry_set_width_chars(GTK_ENTRY(entry2), 50);
|
|
|
|
gtk_entry_set_activates_default(GTK_ENTRY(entry2), TRUE);
|
|
|
|
|
2006-08-12 12:51:56 +00:00
|
|
|
sbox = gtk_hbox_new(FALSE, 6);
|
|
|
|
gtk_box_pack_start(GTK_BOX(sbox), label, FALSE, FALSE, 0);
|
|
|
|
gtk_box_pack_start(GTK_BOX(sbox), combo, TRUE, TRUE, 0);
|
|
|
|
|
|
|
|
size_group = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
|
|
|
|
gtk_size_group_add_widget(size_group, label1);
|
|
|
|
gtk_size_group_add_widget(size_group, label);
|
|
|
|
g_object_unref(G_OBJECT(size_group)); // auto destroy the size group
|
|
|
|
|
2006-09-20 11:03:33 +00:00
|
|
|
rbox = gtk_vbox_new(FALSE, 0);
|
|
|
|
rbtn = gtk_radio_button_new_with_mnemonic(NULL, _("_Fixed strings"));
|
|
|
|
// Make fixed strings the default to speed up searching all files in directory.
|
|
|
|
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(rbtn), TRUE);
|
|
|
|
g_object_set_data_full(G_OBJECT(widgets.find_in_files_dialog), "radio_fgrep",
|
|
|
|
gtk_widget_ref(rbtn), (GDestroyNotify)gtk_widget_unref);
|
|
|
|
gtk_button_set_focus_on_click(GTK_BUTTON(rbtn), FALSE);
|
|
|
|
gtk_container_add(GTK_CONTAINER(rbox), rbtn);
|
|
|
|
|
|
|
|
rbtn = gtk_radio_button_new_with_mnemonic_from_widget(GTK_RADIO_BUTTON(rbtn),
|
|
|
|
_("_Grep regular expressions"));
|
|
|
|
g_object_set_data_full(G_OBJECT(widgets.find_in_files_dialog), "radio_grep",
|
|
|
|
gtk_widget_ref(rbtn), (GDestroyNotify)gtk_widget_unref);
|
|
|
|
gtk_tooltips_set_tip(tooltips, rbtn,
|
|
|
|
_("See grep's manual page for more information."), NULL);
|
|
|
|
gtk_button_set_focus_on_click(GTK_BUTTON(rbtn), FALSE);
|
|
|
|
gtk_container_add(GTK_CONTAINER(rbox), rbtn);
|
|
|
|
|
|
|
|
rbtn = gtk_radio_button_new_with_mnemonic_from_widget(GTK_RADIO_BUTTON(rbtn),
|
|
|
|
_("_Extended regular expressions"));
|
|
|
|
gtk_tooltips_set_tip(tooltips, rbtn,
|
|
|
|
_("See grep's manual page for more information."), NULL);
|
|
|
|
gtk_button_set_focus_on_click(GTK_BUTTON(rbtn), FALSE);
|
|
|
|
gtk_container_add(GTK_CONTAINER(rbox), rbtn);
|
|
|
|
|
2006-08-11 21:12:49 +00:00
|
|
|
checkbox1 = gtk_check_button_new_with_mnemonic(_("_Case sensitive"));
|
|
|
|
g_object_set_data_full(G_OBJECT(widgets.find_in_files_dialog), "check_case",
|
|
|
|
gtk_widget_ref(checkbox1), (GDestroyNotify)gtk_widget_unref);
|
|
|
|
gtk_button_set_focus_on_click(GTK_BUTTON(checkbox1), FALSE);
|
2006-09-20 11:03:33 +00:00
|
|
|
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(checkbox1), TRUE);
|
|
|
|
|
|
|
|
check_wholeword = gtk_check_button_new_with_mnemonic(_("Match only a _whole word"));
|
|
|
|
g_object_set_data_full(G_OBJECT(widgets.find_in_files_dialog), "check_wholeword",
|
|
|
|
gtk_widget_ref(check_wholeword), (GDestroyNotify)gtk_widget_unref);
|
|
|
|
gtk_button_set_focus_on_click(GTK_BUTTON(check_wholeword), FALSE);
|
2006-08-11 21:12:49 +00:00
|
|
|
|
2006-08-12 12:04:14 +00:00
|
|
|
checkbox2 = gtk_check_button_new_with_mnemonic(_("_Invert search results"));
|
2006-08-11 21:12:49 +00:00
|
|
|
g_object_set_data_full(G_OBJECT(widgets.find_in_files_dialog), "check_invert",
|
|
|
|
gtk_widget_ref(checkbox2), (GDestroyNotify)gtk_widget_unref);
|
|
|
|
gtk_button_set_focus_on_click(GTK_BUTTON(checkbox2), FALSE);
|
|
|
|
gtk_tooltips_set_tip(tooltips, checkbox2,
|
|
|
|
_("Invert the sense of matching, to select non-matching lines."), NULL);
|
|
|
|
|
2006-08-12 12:51:56 +00:00
|
|
|
cbox = gtk_vbox_new(FALSE, 0);
|
|
|
|
gtk_container_add(GTK_CONTAINER(cbox), checkbox1);
|
2006-09-20 11:03:33 +00:00
|
|
|
gtk_container_add(GTK_CONTAINER(cbox), check_wholeword);
|
2006-08-12 12:51:56 +00:00
|
|
|
gtk_container_add(GTK_CONTAINER(cbox), checkbox2);
|
2006-08-11 21:12:49 +00:00
|
|
|
|
2006-09-20 11:03:33 +00:00
|
|
|
hbox = gtk_hbox_new(FALSE, 6);
|
|
|
|
gtk_container_add(GTK_CONTAINER(hbox), rbox);
|
|
|
|
gtk_container_add(GTK_CONTAINER(hbox), cbox);
|
2006-08-11 21:12:49 +00:00
|
|
|
|
2006-10-22 14:56:05 +00:00
|
|
|
gtk_container_add(GTK_CONTAINER(vbox), dbox);
|
|
|
|
gtk_container_add(GTK_CONTAINER(vbox), sbox);
|
|
|
|
gtk_container_add(GTK_CONTAINER(vbox), hbox);
|
2006-08-11 21:12:49 +00:00
|
|
|
|
2006-09-20 11:03:33 +00:00
|
|
|
g_signal_connect((gpointer) entry1, "key-press-event",
|
|
|
|
G_CALLBACK(on_combo_entry_key_pressed), gtk_bin_get_child(GTK_BIN(combo)));
|
|
|
|
g_signal_connect((gpointer) widgets.find_in_files_dialog, "response",
|
|
|
|
G_CALLBACK(on_find_in_files_dialog_response), combo);
|
|
|
|
g_signal_connect((gpointer) widgets.find_in_files_dialog, "delete_event",
|
|
|
|
G_CALLBACK(gtk_widget_hide), NULL);
|
|
|
|
|
2006-08-11 21:12:49 +00:00
|
|
|
gtk_widget_show_all(widgets.find_in_files_dialog);
|
|
|
|
}
|
|
|
|
|
2006-10-22 16:52:42 +00:00
|
|
|
sel = get_default_text(idx);
|
2006-08-11 21:12:49 +00:00
|
|
|
|
|
|
|
entry2 = GTK_BIN(combo)->child;
|
|
|
|
if (sel) gtk_entry_set_text(GTK_ENTRY(entry2), sel);
|
|
|
|
g_free(sel);
|
|
|
|
|
|
|
|
if (cur_dir) gtk_entry_set_text(GTK_ENTRY(entry1), cur_dir);
|
|
|
|
g_free(cur_dir);
|
|
|
|
|
|
|
|
// put the focus to the directory entry if it is empty
|
|
|
|
if (utils_strcmp(gtk_entry_get_text(GTK_ENTRY(entry1)), ""))
|
|
|
|
gtk_widget_grab_focus(entry1);
|
|
|
|
else
|
|
|
|
gtk_widget_grab_focus(entry2);
|
|
|
|
|
|
|
|
gtk_widget_show(widgets.find_in_files_dialog);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2006-08-12 21:38:36 +00:00
|
|
|
static void on_open_dir_dialog_clicked(GtkButton *button, gpointer user_data)
|
|
|
|
{
|
|
|
|
GtkWidget *dialog = gtk_file_chooser_dialog_new(_("Select folder"),
|
|
|
|
GTK_WINDOW(app->window), GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER,
|
|
|
|
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
|
|
|
|
GTK_STOCK_OPEN, GTK_RESPONSE_OK, NULL);
|
|
|
|
GtkWidget *entry_dir = lookup_widget(widgets.find_in_files_dialog, "entry_dir");
|
|
|
|
gchar *dir_locale;
|
|
|
|
const gchar *entry_text;
|
|
|
|
|
|
|
|
entry_text = gtk_entry_get_text(GTK_ENTRY(entry_dir));
|
|
|
|
dir_locale = utils_get_locale_from_utf8(entry_text);
|
|
|
|
if (g_file_test(dir_locale, G_FILE_TEST_IS_DIR))
|
|
|
|
gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog), dir_locale);
|
|
|
|
g_free(dir_locale);
|
|
|
|
|
|
|
|
if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_OK)
|
|
|
|
{
|
|
|
|
gchar *dir_utf8;
|
|
|
|
dir_locale = gtk_file_chooser_get_current_folder(GTK_FILE_CHOOSER(dialog));
|
|
|
|
dir_utf8 = utils_get_utf8_from_locale(dir_locale);
|
|
|
|
g_free(dir_locale);
|
|
|
|
gtk_entry_set_text(GTK_ENTRY(entry_dir), dir_utf8);
|
|
|
|
g_free(dir_utf8);
|
|
|
|
}
|
|
|
|
gtk_widget_destroy(dialog);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2006-08-11 21:12:49 +00:00
|
|
|
static void
|
|
|
|
on_find_replace_checkbutton_toggled(GtkToggleButton *togglebutton, gpointer user_data)
|
|
|
|
{
|
|
|
|
GtkWidget *dialog = GTK_WIDGET(user_data);
|
|
|
|
GtkToggleButton *chk_regexp = GTK_TOGGLE_BUTTON(
|
|
|
|
lookup_widget(dialog, "check_regexp"));
|
|
|
|
|
|
|
|
if (togglebutton == chk_regexp)
|
|
|
|
{
|
|
|
|
gboolean regex_set = gtk_toggle_button_get_active(chk_regexp);
|
|
|
|
GtkWidget *check_word = lookup_widget(dialog, "check_word");
|
|
|
|
GtkWidget *check_wordstart = lookup_widget(dialog, "check_wordstart");
|
2006-08-12 12:04:14 +00:00
|
|
|
GtkToggleButton *check_case = GTK_TOGGLE_BUTTON(
|
|
|
|
lookup_widget(dialog, "check_case"));
|
|
|
|
static gboolean case_state = FALSE; // state before regex enabled
|
2006-08-11 21:12:49 +00:00
|
|
|
|
2006-08-12 12:04:14 +00:00
|
|
|
// hide options that don't apply to regex searches
|
2006-11-01 15:26:41 +00:00
|
|
|
if (dialog == widgets.find_dialog)
|
|
|
|
gtk_widget_set_sensitive(lookup_widget(dialog, "btn_previous"), ! regex_set);
|
|
|
|
else
|
|
|
|
gtk_widget_set_sensitive(lookup_widget(dialog, "check_back"), ! regex_set);
|
|
|
|
|
2006-08-11 21:12:49 +00:00
|
|
|
gtk_widget_set_sensitive(check_word, ! regex_set);
|
|
|
|
gtk_widget_set_sensitive(check_wordstart, ! regex_set);
|
2006-08-12 12:04:14 +00:00
|
|
|
|
|
|
|
if (regex_set) // regex enabled
|
|
|
|
{
|
|
|
|
// Enable case sensitive but remember original case toggle state
|
|
|
|
case_state = gtk_toggle_button_get_active(check_case);
|
|
|
|
gtk_toggle_button_set_active(check_case, TRUE);
|
|
|
|
}
|
|
|
|
else // regex disabled
|
|
|
|
{
|
|
|
|
// If case sensitive is still enabled, revert to what it was before we enabled it
|
|
|
|
if (gtk_toggle_button_get_active(check_case) == TRUE)
|
|
|
|
gtk_toggle_button_set_active(check_case, case_state);
|
|
|
|
}
|
2006-08-11 21:12:49 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
on_find_dialog_response(GtkDialog *dialog, gint response, gpointer user_data)
|
|
|
|
{
|
2006-11-01 15:26:41 +00:00
|
|
|
if (response == GTK_RESPONSE_CANCEL)
|
|
|
|
gtk_widget_hide(widgets.find_dialog);
|
|
|
|
else
|
2006-08-11 21:12:49 +00:00
|
|
|
{
|
|
|
|
gint idx = document_get_cur_idx();
|
|
|
|
gboolean search_replace_escape;
|
|
|
|
gboolean
|
|
|
|
fl1 = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(
|
|
|
|
lookup_widget(GTK_WIDGET(widgets.find_dialog), "check_case"))),
|
|
|
|
fl2 = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(
|
|
|
|
lookup_widget(GTK_WIDGET(widgets.find_dialog), "check_word"))),
|
|
|
|
fl3 = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(
|
|
|
|
lookup_widget(GTK_WIDGET(widgets.find_dialog), "check_regexp"))),
|
|
|
|
fl4 = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(
|
2006-11-01 15:26:41 +00:00
|
|
|
lookup_widget(GTK_WIDGET(widgets.find_dialog), "check_wordstart"))),
|
|
|
|
check_close = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(
|
|
|
|
lookup_widget(GTK_WIDGET(widgets.find_dialog), "check_close")));
|
2006-08-11 21:12:49 +00:00
|
|
|
search_replace_escape = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(
|
|
|
|
lookup_widget(GTK_WIDGET(widgets.find_dialog), "check_escape")));
|
2006-11-01 15:26:41 +00:00
|
|
|
search_data.backwards = FALSE;
|
|
|
|
|
|
|
|
if (! DOC_IDX_VALID(idx)) return;
|
2006-08-11 21:12:49 +00:00
|
|
|
|
|
|
|
g_free(search_data.text);
|
|
|
|
search_data.text = g_strdup(gtk_entry_get_text(GTK_ENTRY(gtk_bin_get_child(GTK_BIN(user_data)))));
|
|
|
|
if (strlen(search_data.text) == 0 ||
|
|
|
|
(search_replace_escape && ! utils_str_replace_escape(search_data.text)))
|
|
|
|
{
|
|
|
|
utils_beep();
|
|
|
|
gtk_widget_grab_focus(GTK_WIDGET(GTK_BIN(lookup_widget(widgets.find_dialog, "entry"))->child));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
gtk_combo_box_prepend_text(GTK_COMBO_BOX(user_data), search_data.text);
|
|
|
|
search_data.flags = (fl1 ? SCFIND_MATCHCASE : 0) |
|
|
|
|
(fl2 ? SCFIND_WHOLEWORD : 0) |
|
|
|
|
(fl3 ? SCFIND_REGEXP | SCFIND_POSIX: 0) |
|
|
|
|
(fl4 ? SCFIND_WORDSTART : 0);
|
2006-11-01 15:26:41 +00:00
|
|
|
|
|
|
|
switch (response)
|
|
|
|
{
|
|
|
|
case GEANY_RESPONSE_FIND:
|
|
|
|
case GEANY_RESPONSE_FIND_PREVIOUS:
|
|
|
|
document_find_text(idx, search_data.text, search_data.flags,
|
|
|
|
(response == GEANY_RESPONSE_FIND_PREVIOUS));
|
|
|
|
check_close = FALSE;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case GEANY_RESPONSE_FIND_IN_FILE:
|
|
|
|
search_find_usage(search_data.text, search_data.flags, FALSE);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case GEANY_RESPONSE_FIND_IN_SESSION:
|
|
|
|
search_find_usage(search_data.text, search_data.flags, TRUE);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case GEANY_RESPONSE_MARK:
|
|
|
|
// TODO
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (check_close)
|
|
|
|
gtk_widget_hide(widgets.find_dialog);
|
2006-08-11 21:12:49 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
on_find_entry_activate(GtkEntry *entry, gpointer user_data)
|
|
|
|
{
|
|
|
|
on_find_dialog_response(NULL, GTK_RESPONSE_ACCEPT,
|
|
|
|
lookup_widget(GTK_WIDGET(entry), "entry"));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
on_replace_dialog_response(GtkDialog *dialog, gint response, gpointer user_data)
|
|
|
|
{
|
|
|
|
gint idx = document_get_cur_idx();
|
|
|
|
GtkWidget *entry_find = lookup_widget(GTK_WIDGET(widgets.replace_dialog), "entry_find");
|
|
|
|
GtkWidget *entry_replace = lookup_widget(GTK_WIDGET(widgets.replace_dialog), "entry_replace");
|
|
|
|
gint search_flags_re;
|
2006-10-22 14:56:05 +00:00
|
|
|
gboolean search_backwards_re, search_replace_escape_re;
|
2006-08-11 21:12:49 +00:00
|
|
|
gboolean fl1, fl2, fl3, fl4;
|
2006-08-27 17:49:10 +00:00
|
|
|
gboolean close_window;
|
2006-08-11 21:12:49 +00:00
|
|
|
gchar *find, *replace;
|
|
|
|
|
|
|
|
if (response == GTK_RESPONSE_CANCEL)
|
|
|
|
{
|
|
|
|
gtk_widget_hide(widgets.replace_dialog);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
fl1 = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(
|
|
|
|
lookup_widget(GTK_WIDGET(widgets.replace_dialog), "check_case")));
|
|
|
|
fl2 = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(
|
|
|
|
lookup_widget(GTK_WIDGET(widgets.replace_dialog), "check_word")));
|
|
|
|
fl3 = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(
|
|
|
|
lookup_widget(GTK_WIDGET(widgets.replace_dialog), "check_regexp")));
|
|
|
|
fl4 = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(
|
|
|
|
lookup_widget(GTK_WIDGET(widgets.replace_dialog), "check_wordstart")));
|
2006-10-22 14:56:05 +00:00
|
|
|
close_window = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(
|
|
|
|
lookup_widget(GTK_WIDGET(widgets.replace_dialog), "check_close")));
|
2006-08-11 21:12:49 +00:00
|
|
|
search_backwards_re = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(
|
|
|
|
lookup_widget(GTK_WIDGET(widgets.replace_dialog), "check_back")));
|
|
|
|
search_replace_escape_re = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(
|
|
|
|
lookup_widget(GTK_WIDGET(widgets.replace_dialog), "check_escape")));
|
|
|
|
find = g_strdup(gtk_entry_get_text(GTK_ENTRY(gtk_bin_get_child(GTK_BIN(entry_find)))));
|
|
|
|
replace = g_strdup(gtk_entry_get_text(GTK_ENTRY(gtk_bin_get_child(GTK_BIN(entry_replace)))));
|
|
|
|
|
|
|
|
if ((response != GEANY_RESPONSE_FIND) && (! fl1) && (strcasecmp(find, replace) == 0))
|
|
|
|
{
|
|
|
|
utils_beep();
|
|
|
|
gtk_widget_grab_focus(GTK_WIDGET(GTK_BIN(lookup_widget(widgets.replace_dialog, "entry_find"))->child));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
gtk_combo_box_prepend_text(GTK_COMBO_BOX(entry_find), find);
|
|
|
|
gtk_combo_box_prepend_text(GTK_COMBO_BOX(entry_replace), replace);
|
|
|
|
|
|
|
|
if (search_replace_escape_re &&
|
|
|
|
(! utils_str_replace_escape(find) || ! utils_str_replace_escape(replace)))
|
|
|
|
{
|
|
|
|
utils_beep();
|
|
|
|
gtk_widget_grab_focus(GTK_WIDGET(GTK_BIN(lookup_widget(widgets.replace_dialog, "entry_find"))->child));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
search_flags_re = (fl1 ? SCFIND_MATCHCASE : 0) |
|
|
|
|
(fl2 ? SCFIND_WHOLEWORD : 0) |
|
|
|
|
(fl3 ? SCFIND_REGEXP | SCFIND_POSIX : 0) |
|
|
|
|
(fl4 ? SCFIND_WORDSTART : 0);
|
|
|
|
|
2006-10-22 14:56:05 +00:00
|
|
|
switch (response)
|
2006-08-11 21:12:49 +00:00
|
|
|
{
|
2006-10-22 14:56:05 +00:00
|
|
|
case GEANY_RESPONSE_REPLACE_AND_FIND:
|
2006-08-11 21:12:49 +00:00
|
|
|
{
|
2006-10-22 14:56:05 +00:00
|
|
|
gint rep = document_replace_text(idx, find, replace, search_flags_re,
|
|
|
|
search_backwards_re);
|
|
|
|
if (rep != -1)
|
|
|
|
document_find_text(idx, find, search_flags_re, search_backwards_re);
|
|
|
|
break;
|
2006-08-11 21:12:49 +00:00
|
|
|
}
|
2006-10-22 14:56:05 +00:00
|
|
|
case GEANY_RESPONSE_REPLACE:
|
2006-08-11 21:12:49 +00:00
|
|
|
{
|
2006-10-22 14:56:05 +00:00
|
|
|
document_replace_text(idx, find, replace, search_flags_re,
|
|
|
|
search_backwards_re);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case GEANY_RESPONSE_FIND:
|
|
|
|
{
|
|
|
|
document_find_text(idx, find, search_flags_re, search_backwards_re);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case GEANY_RESPONSE_REPLACE_IN_FILE:
|
|
|
|
{
|
|
|
|
document_replace_all(idx, find, replace, search_flags_re, search_replace_escape_re);
|
|
|
|
if (close_window) gtk_widget_hide(widgets.replace_dialog);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case GEANY_RESPONSE_REPLACE_IN_SESSION:
|
|
|
|
{
|
|
|
|
guint i;
|
|
|
|
for (i = 0; i < doc_array->len; i++)
|
2006-08-11 21:12:49 +00:00
|
|
|
{
|
2006-10-22 14:56:05 +00:00
|
|
|
if (! doc_list[i].is_valid) continue;
|
|
|
|
|
|
|
|
document_replace_all(i, find, replace, search_flags_re, search_replace_escape_re);
|
2006-08-11 21:12:49 +00:00
|
|
|
}
|
2006-10-22 14:56:05 +00:00
|
|
|
if (close_window) gtk_widget_hide(widgets.replace_dialog);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case GEANY_RESPONSE_REPLACE_IN_SEL:
|
|
|
|
{
|
|
|
|
document_replace_sel(idx, find, replace, search_flags_re, search_replace_escape_re);
|
|
|
|
if (close_window) gtk_widget_hide(widgets.replace_dialog);
|
|
|
|
break;
|
2006-08-11 21:12:49 +00:00
|
|
|
}
|
2006-10-22 14:56:05 +00:00
|
|
|
default:
|
|
|
|
geany_debug("Missing reponse in %s.", G_GNUC_FUNCTION);
|
2006-08-11 21:12:49 +00:00
|
|
|
}
|
|
|
|
g_free(find);
|
|
|
|
g_free(replace);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
on_replace_entry_activate(GtkEntry *entry, gpointer user_data)
|
|
|
|
{
|
|
|
|
on_replace_dialog_response(NULL, GEANY_RESPONSE_REPLACE, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2006-09-02 23:28:34 +00:00
|
|
|
static gboolean
|
|
|
|
on_combo_entry_key_pressed(GtkWidget *widget, GdkEventKey *event, gpointer user_data)
|
|
|
|
{
|
|
|
|
// catch tabulator key to set the focus in the replace entry instead of
|
|
|
|
// setting it to the combo box
|
|
|
|
if (event->keyval == GDK_Tab)
|
|
|
|
{
|
|
|
|
gtk_widget_grab_focus(GTK_WIDGET(user_data));
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2006-08-11 21:12:49 +00:00
|
|
|
static void
|
|
|
|
on_find_in_files_dialog_response(GtkDialog *dialog, gint response, gpointer user_data)
|
|
|
|
{
|
|
|
|
if (response == GTK_RESPONSE_ACCEPT)
|
|
|
|
{
|
|
|
|
const gchar *search_text =
|
|
|
|
gtk_entry_get_text(GTK_ENTRY(gtk_bin_get_child(GTK_BIN(user_data))));
|
|
|
|
const gchar *utf8_dir =
|
|
|
|
gtk_entry_get_text(GTK_ENTRY(lookup_widget(widgets.find_in_files_dialog, "entry_dir")));
|
|
|
|
|
|
|
|
if (utf8_dir == NULL || utils_strcmp(utf8_dir, ""))
|
|
|
|
msgwin_status_add(_("Invalid directory for find in files."));
|
|
|
|
else if (search_text && *search_text)
|
|
|
|
{
|
|
|
|
gchar *locale_dir;
|
|
|
|
gboolean invert = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(
|
|
|
|
lookup_widget(widgets.find_in_files_dialog, "check_invert")));
|
|
|
|
gboolean case_sens = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(
|
|
|
|
lookup_widget(widgets.find_in_files_dialog, "check_case")));
|
2006-09-20 11:03:33 +00:00
|
|
|
gboolean whole_word = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(
|
|
|
|
lookup_widget(widgets.find_in_files_dialog, "check_wholeword")));
|
|
|
|
gint opts = (invert ? FIF_INVERT_MATCH : 0) |
|
|
|
|
(case_sens ? FIF_CASE_SENSITIVE : 0) |
|
|
|
|
(whole_word ? FIF_WHOLE_WORD : 0);
|
|
|
|
gboolean fgrep = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(
|
|
|
|
lookup_widget(widgets.find_in_files_dialog, "radio_fgrep")));
|
|
|
|
gboolean grep = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(
|
|
|
|
lookup_widget(widgets.find_in_files_dialog, "radio_grep")));
|
|
|
|
gint regex_opt = fgrep ? FIF_FGREP : (grep ? FIF_GREP : FIF_EGREP);
|
2006-08-11 21:12:49 +00:00
|
|
|
|
2006-08-13 09:07:10 +00:00
|
|
|
locale_dir = utils_get_locale_from_utf8(utf8_dir);
|
2006-08-11 21:12:49 +00:00
|
|
|
|
2006-09-20 11:03:33 +00:00
|
|
|
if (search_find_in_files(search_text, locale_dir, regex_opt, opts))
|
2006-08-11 21:12:49 +00:00
|
|
|
{
|
|
|
|
gtk_combo_box_prepend_text(GTK_COMBO_BOX(user_data), search_text);
|
|
|
|
gtk_widget_hide(widgets.find_in_files_dialog);
|
|
|
|
}
|
|
|
|
g_free(locale_dir);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
msgwin_status_add(_("No text to find."));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
gtk_widget_hide(widgets.find_in_files_dialog);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2006-09-20 11:03:33 +00:00
|
|
|
static gboolean
|
|
|
|
search_find_in_files(const gchar *search_text, const gchar *dir, fif_match_type regex_opt,
|
|
|
|
fif_options opts)
|
2006-07-13 14:30:44 +00:00
|
|
|
{
|
2006-07-28 18:37:32 +00:00
|
|
|
gchar **argv_prefix;
|
|
|
|
gchar **grep_cmd_argv;
|
2006-07-13 14:30:44 +00:00
|
|
|
gchar **argv;
|
2006-09-20 11:03:33 +00:00
|
|
|
gchar grep_opts[] = "-nHI ";
|
2006-07-13 14:30:44 +00:00
|
|
|
GPid child_pid;
|
2006-07-28 18:37:32 +00:00
|
|
|
gint stdout_fd, stdin_fd, grep_cmd_argv_len, i, grep_opts_len = 4;
|
2006-07-13 14:30:44 +00:00
|
|
|
GError *error = NULL;
|
|
|
|
gboolean ret = FALSE;
|
|
|
|
|
|
|
|
if (! search_text || ! *search_text || ! dir) return TRUE;
|
2006-07-28 18:37:32 +00:00
|
|
|
|
|
|
|
// first process the grep command (need to split it in a argv because it can be "grep -I")
|
|
|
|
grep_cmd_argv = g_strsplit(app->tools_grep_cmd, " ", -1);
|
|
|
|
grep_cmd_argv_len = g_strv_length(grep_cmd_argv);
|
|
|
|
|
|
|
|
if (! g_file_test(grep_cmd_argv[0], G_FILE_TEST_IS_EXECUTABLE))
|
2006-07-13 14:30:44 +00:00
|
|
|
{
|
|
|
|
msgwin_status_add(_("Cannot execute grep tool '%s';"
|
2006-07-28 18:37:32 +00:00
|
|
|
" check the path setting in Preferences."), app->tools_grep_cmd);
|
2006-07-13 14:30:44 +00:00
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
gtk_list_store_clear(msgwindow.store_msg);
|
|
|
|
gtk_notebook_set_current_page(GTK_NOTEBOOK(msgwindow.notebook), MSG_MESSAGE);
|
|
|
|
|
2006-09-20 11:03:33 +00:00
|
|
|
switch (regex_opt)
|
|
|
|
{
|
|
|
|
default:
|
|
|
|
case FIF_FGREP: grep_opts[grep_opts_len++] = 'F'; break;
|
|
|
|
case FIF_GREP: break;
|
|
|
|
case FIF_EGREP: grep_opts[grep_opts_len++] = 'E'; break;
|
|
|
|
}
|
|
|
|
|
2006-07-28 18:37:32 +00:00
|
|
|
if (! (opts & FIF_CASE_SENSITIVE))
|
|
|
|
grep_opts[grep_opts_len++] = 'i';
|
2006-09-20 11:03:33 +00:00
|
|
|
if (opts & FIF_WHOLE_WORD)
|
|
|
|
grep_opts[grep_opts_len++] = 'w';
|
2006-07-28 18:37:32 +00:00
|
|
|
if (opts & FIF_INVERT_MATCH)
|
|
|
|
grep_opts[grep_opts_len++] = 'v';
|
|
|
|
grep_opts[grep_opts_len] = '\0';
|
|
|
|
|
|
|
|
// set grep command and options
|
|
|
|
argv_prefix = g_new0(gchar*, grep_cmd_argv_len + 4);
|
|
|
|
for (i = 0; i < grep_cmd_argv_len; i++)
|
|
|
|
{
|
|
|
|
argv_prefix[i] = g_strdup(grep_cmd_argv[i]);
|
|
|
|
}
|
2006-09-20 11:03:33 +00:00
|
|
|
argv_prefix[grep_cmd_argv_len] = g_strdup(grep_opts);
|
2006-07-28 18:37:32 +00:00
|
|
|
argv_prefix[grep_cmd_argv_len + 1] = g_strdup("--");
|
|
|
|
argv_prefix[grep_cmd_argv_len + 2] = g_strdup(search_text);
|
|
|
|
argv_prefix[grep_cmd_argv_len + 3] = NULL;
|
|
|
|
g_strfreev(grep_cmd_argv);
|
|
|
|
|
|
|
|
// finally add the arguments(files to be searched)
|
|
|
|
argv = search_get_argv((const gchar**)argv_prefix, dir);
|
|
|
|
g_strfreev(argv_prefix);
|
2006-09-20 11:03:33 +00:00
|
|
|
|
2006-07-13 14:30:44 +00:00
|
|
|
if (argv == NULL) return FALSE;
|
|
|
|
|
|
|
|
if (! g_spawn_async_with_pipes(dir, (gchar**)argv, NULL,
|
|
|
|
G_SPAWN_STDERR_TO_DEV_NULL | G_SPAWN_DO_NOT_REAP_CHILD,
|
|
|
|
NULL, NULL, &child_pid,
|
|
|
|
&stdin_fd, &stdout_fd, NULL, &error))
|
|
|
|
{
|
|
|
|
geany_debug("%s: g_spawn_async_with_pipes() failed: %s", __func__, error->message);
|
|
|
|
msgwin_status_add(_("Process failed (%s)"), error->message);
|
|
|
|
g_error_free(error);
|
|
|
|
ret = FALSE;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2006-08-14 15:02:52 +00:00
|
|
|
g_free(msgwindow.find_in_files_dir);
|
|
|
|
msgwindow.find_in_files_dir = g_strdup(dir);
|
2006-07-13 14:30:44 +00:00
|
|
|
utils_set_up_io_channel(stdout_fd, G_IO_IN|G_IO_PRI|G_IO_ERR|G_IO_HUP|G_IO_NVAL,
|
|
|
|
search_read_io, NULL);
|
2006-07-28 18:37:32 +00:00
|
|
|
g_child_watch_add(child_pid, search_close_pid, NULL);
|
2006-07-13 14:30:44 +00:00
|
|
|
ret = TRUE;
|
|
|
|
}
|
|
|
|
g_strfreev(argv);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Creates an argument vector of strings, copying argv_prefix[] values for
|
|
|
|
* the first arguments, then followed by filenames found in dir.
|
|
|
|
* Returns NULL if no files were found, otherwise returned vector should be fully freed. */
|
|
|
|
static gchar **search_get_argv(const gchar **argv_prefix, const gchar *dir)
|
|
|
|
{
|
|
|
|
guint prefix_len, list_len, i, j;
|
|
|
|
gchar **argv;
|
|
|
|
GSList *list, *item;
|
2006-09-20 11:03:33 +00:00
|
|
|
|
2006-07-13 14:30:44 +00:00
|
|
|
g_return_val_if_fail(dir != NULL, NULL);
|
|
|
|
|
|
|
|
prefix_len = g_strv_length((gchar**)argv_prefix);
|
|
|
|
list = search_get_file_list(dir, &list_len);
|
|
|
|
if (list == NULL) return NULL;
|
|
|
|
|
|
|
|
argv = g_new(gchar*, prefix_len + list_len + 1);
|
|
|
|
|
|
|
|
for (i = 0; i < prefix_len; i++)
|
|
|
|
argv[i] = g_strdup(argv_prefix[i]);
|
|
|
|
|
|
|
|
item = list;
|
|
|
|
for (j = 0; j < list_len; j++)
|
|
|
|
{
|
|
|
|
argv[i++] = item->data;
|
|
|
|
item = g_slist_next(item);
|
|
|
|
}
|
|
|
|
argv[i] = NULL;
|
|
|
|
|
|
|
|
g_slist_free(list);
|
|
|
|
return argv;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2006-09-20 11:03:33 +00:00
|
|
|
/* Gets a sorted list of files in the current directory.
|
2006-07-13 14:30:44 +00:00
|
|
|
* The list and the data in the list should be freed after use.
|
2006-09-20 11:03:33 +00:00
|
|
|
* Returns: The list or NULL if no files found.
|
2006-07-13 14:30:44 +00:00
|
|
|
* *length is set to the number of non-NULL data items in the list. */
|
2006-08-15 12:26:15 +00:00
|
|
|
static GSList *search_get_file_list(const gchar *path, guint *length)
|
2006-07-13 14:30:44 +00:00
|
|
|
{
|
|
|
|
GError *error = NULL;
|
|
|
|
GSList *list = NULL;
|
2006-08-15 12:26:15 +00:00
|
|
|
guint len = 0;
|
2006-07-13 14:30:44 +00:00
|
|
|
GDir *dir;
|
2006-09-20 11:03:33 +00:00
|
|
|
|
2006-07-13 14:30:44 +00:00
|
|
|
g_return_val_if_fail(path != NULL, NULL);
|
|
|
|
|
|
|
|
dir = g_dir_open(path, 0, &error);
|
|
|
|
if (error)
|
|
|
|
{
|
2006-07-29 12:06:00 +00:00
|
|
|
msgwin_status_add(_("Could not open directory (%s)"), error->message);
|
2006-07-13 14:30:44 +00:00
|
|
|
g_error_free(error);
|
|
|
|
*length = 0;
|
|
|
|
return NULL;
|
|
|
|
}
|
2006-09-20 11:03:33 +00:00
|
|
|
|
|
|
|
while (1)
|
2006-07-13 14:30:44 +00:00
|
|
|
{
|
2006-09-20 11:03:33 +00:00
|
|
|
const gchar *filename = g_dir_read_name(dir);
|
|
|
|
if (filename == NULL) break;
|
2006-07-13 14:30:44 +00:00
|
|
|
|
2006-09-20 11:03:33 +00:00
|
|
|
list = g_slist_insert_sorted(list, g_strdup(filename), (GCompareFunc) strcmp);
|
|
|
|
len++;
|
|
|
|
}
|
2006-07-13 14:30:44 +00:00
|
|
|
g_dir_close(dir);
|
2006-09-20 11:03:33 +00:00
|
|
|
|
2006-07-13 14:30:44 +00:00
|
|
|
*length = len;
|
|
|
|
return list;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static gboolean search_read_io (GIOChannel *source,
|
|
|
|
GIOCondition condition,
|
|
|
|
gpointer data)
|
|
|
|
{
|
|
|
|
if (condition & (G_IO_IN | G_IO_PRI))
|
|
|
|
{
|
|
|
|
gchar *msg;
|
|
|
|
|
|
|
|
while (g_io_channel_read_line(source, &msg, NULL, NULL, NULL) && msg)
|
|
|
|
{
|
|
|
|
msgwin_msg_add(-1, -1, g_strstrip(msg));
|
|
|
|
g_free(msg);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (condition & (G_IO_ERR | G_IO_HUP | G_IO_NVAL))
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void search_close_pid(GPid child_pid, gint status, gpointer user_data)
|
|
|
|
{
|
|
|
|
#ifdef G_OS_UNIX
|
2006-07-14 15:50:29 +00:00
|
|
|
gchar *msg = _("Search failed.");
|
2006-07-13 14:30:44 +00:00
|
|
|
|
|
|
|
if (WIFEXITED(status))
|
|
|
|
{
|
2006-07-14 15:50:29 +00:00
|
|
|
switch (WEXITSTATUS(status))
|
|
|
|
{
|
|
|
|
case 0: msg = _("Search completed."); break;
|
|
|
|
case 1: msg = _("No matches found."); break;
|
|
|
|
default: break;
|
|
|
|
}
|
2006-07-13 14:30:44 +00:00
|
|
|
}
|
|
|
|
|
2006-07-14 15:50:29 +00:00
|
|
|
msgwin_msg_add(-1, -1, msg);
|
2006-07-13 14:30:44 +00:00
|
|
|
#endif
|
|
|
|
utils_beep();
|
|
|
|
g_spawn_close_pid(child_pid);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2006-11-01 15:26:41 +00:00
|
|
|
static gint find_document_usage(gint idx, const gchar *search_text, gint flags)
|
|
|
|
{
|
|
|
|
gchar *buffer, *short_file_name, *string;
|
|
|
|
gint pos, line, count = 0;
|
|
|
|
struct TextToFind ttf;
|
|
|
|
|
|
|
|
g_return_val_if_fail(DOC_IDX_VALID(idx), 0);
|
|
|
|
|
|
|
|
ttf.chrg.cpMin = 0;
|
|
|
|
ttf.chrg.cpMax = sci_get_length(doc_list[idx].sci);
|
|
|
|
ttf.lpstrText = (gchar *)search_text;
|
|
|
|
while (1)
|
|
|
|
{
|
|
|
|
pos = sci_find_text(doc_list[idx].sci, flags, &ttf);
|
|
|
|
if (pos == -1) break;
|
|
|
|
|
|
|
|
line = sci_get_line_from_position(doc_list[idx].sci, pos);
|
|
|
|
buffer = sci_get_line(doc_list[idx].sci, line);
|
|
|
|
|
|
|
|
if (doc_list[idx].file_name == NULL)
|
|
|
|
short_file_name = g_strdup(GEANY_STRING_UNTITLED);
|
|
|
|
else
|
|
|
|
short_file_name = g_path_get_basename(doc_list[idx].file_name);
|
|
|
|
string = g_strdup_printf("%s:%d : %s", short_file_name, line + 1, g_strstrip(buffer));
|
|
|
|
msgwin_msg_add(line + 1, idx, string);
|
|
|
|
|
|
|
|
g_free(buffer);
|
|
|
|
g_free(short_file_name);
|
|
|
|
g_free(string);
|
|
|
|
ttf.chrg.cpMin = ttf.chrgText.cpMax + 1;
|
|
|
|
count++;
|
|
|
|
}
|
|
|
|
return count;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void search_find_usage(const gchar *search_text, gint flags, gboolean in_session)
|
|
|
|
{
|
|
|
|
gint idx;
|
|
|
|
gboolean found = FALSE;
|
|
|
|
|
|
|
|
idx = document_get_cur_idx();
|
|
|
|
g_return_if_fail(DOC_IDX_VALID(idx));
|
|
|
|
|
|
|
|
gtk_notebook_set_current_page(GTK_NOTEBOOK(msgwindow.notebook), MSG_MESSAGE);
|
|
|
|
gtk_list_store_clear(msgwindow.store_msg);
|
|
|
|
|
|
|
|
if (! in_session)
|
|
|
|
{ // use current document
|
|
|
|
found = (find_document_usage(idx, search_text, flags) > 0);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
guint i;
|
|
|
|
for(i = 0; i < doc_array->len; i++)
|
|
|
|
{
|
|
|
|
if (doc_list[i].is_valid)
|
|
|
|
if (find_document_usage(i, search_text, flags) > 0) found = TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (! found) // no matches were found
|
|
|
|
{
|
|
|
|
gchar *text = g_strdup_printf(_("No matches found for '%s'."), search_text);
|
|
|
|
ui_set_statusbar(text, FALSE);
|
|
|
|
msgwin_msg_add(-1, -1, text);
|
|
|
|
g_free(text);
|
|
|
|
}
|
|
|
|
}
|