Commit d4e7368a authored by Gaël Bonithon's avatar Gaël Bonithon Committed by Matthew Brush

Add regex search

Closes #1, #9
parent d5b5f9ab
...@@ -35,7 +35,6 @@ enum { ...@@ -35,7 +35,6 @@ enum {
MOUSEPAD_RESPONSE_REVERT, MOUSEPAD_RESPONSE_REVERT,
MOUSEPAD_RESPONSE_SAVE, MOUSEPAD_RESPONSE_SAVE,
MOUSEPAD_RESPONSE_SAVE_AS, MOUSEPAD_RESPONSE_SAVE_AS,
MOUSEPAD_RESPONSE_CHECK_ENTRY
}; };
......
...@@ -182,8 +182,10 @@ mousepad_document_init (MousepadDocument *document) ...@@ -182,8 +182,10 @@ mousepad_document_init (MousepadDocument *document)
gtk_scrolled_window_set_hadjustment (GTK_SCROLLED_WINDOW (document), NULL); gtk_scrolled_window_set_hadjustment (GTK_SCROLLED_WINDOW (document), NULL);
gtk_scrolled_window_set_vadjustment (GTK_SCROLLED_WINDOW (document), NULL); gtk_scrolled_window_set_vadjustment (GTK_SCROLLED_WINDOW (document), NULL);
/* create a textbuffer */ /* create a textbuffer and associated search context */
document->buffer = GTK_TEXT_BUFFER (gtk_source_buffer_new (NULL)); document->buffer = GTK_TEXT_BUFFER (gtk_source_buffer_new (NULL));
document->search_context = gtk_source_search_context_new (GTK_SOURCE_BUFFER (document->buffer), NULL);
gtk_source_search_context_set_highlight (document->search_context, FALSE);
/* initialize the file */ /* initialize the file */
document->file = mousepad_file_new (document->buffer); document->file = mousepad_file_new (document->buffer);
......
...@@ -46,8 +46,9 @@ struct _MousepadDocument ...@@ -46,8 +46,9 @@ struct _MousepadDocument
/* file */ /* file */
MousepadFile *file; MousepadFile *file;
/* text buffer */ /* text buffer and associated search context */
GtkTextBuffer *buffer; GtkTextBuffer *buffer;
GtkSourceSearchContext *search_context;
/* text view */ /* text view */
MousepadView *textview; MousepadView *textview;
......
...@@ -226,6 +226,13 @@ mousepad_replace_dialog_init (MousepadReplaceDialog *dialog) ...@@ -226,6 +226,13 @@ mousepad_replace_dialog_init (MousepadReplaceDialog *dialog)
mousepad_replace_dialog_bind_setting (dialog, MOUSEPAD_SETTING_SEARCH_MATCH_CASE, check, "active"); mousepad_replace_dialog_bind_setting (dialog, MOUSEPAD_SETTING_SEARCH_MATCH_CASE, check, "active");
/* enable regex search */
check = gtk_check_button_new_with_mnemonic (_("_Enable Regex"));
gtk_box_pack_start (GTK_BOX (vbox), check, FALSE, FALSE, 0);
gtk_widget_show (check);
mousepad_replace_dialog_bind_setting (dialog, MOUSEPAD_SETTING_SEARCH_ENABLE_REGEX, check, "active");
/* match whole word */ /* match whole word */
check = gtk_check_button_new_with_mnemonic (_("_Match whole word")); check = gtk_check_button_new_with_mnemonic (_("_Match whole word"));
gtk_box_pack_start (GTK_BOX (vbox), check, FALSE, FALSE, 0); gtk_box_pack_start (GTK_BOX (vbox), check, FALSE, FALSE, 0);
...@@ -304,21 +311,25 @@ mousepad_replace_dialog_response (GtkWidget *widget, ...@@ -304,21 +311,25 @@ mousepad_replace_dialog_response (GtkWidget *widget,
const gchar *search_str, *replace_str; const gchar *search_str, *replace_str;
gchar *message; gchar *message;
gint search_direction, replace_all_location; gint search_direction, replace_all_location;
gboolean match_case, match_whole_word, replace_all; gboolean match_case, enable_regex, match_whole_word, replace_all;
/* close dialog */
if (response_id == MOUSEPAD_RESPONSE_CLOSE || response_id < 0)
{
gtk_widget_destroy (widget);
return;
}
/* read the search settings */ /* read the search settings */
search_direction = MOUSEPAD_SETTING_GET_INT (SEARCH_DIRECTION); search_direction = MOUSEPAD_SETTING_GET_INT (SEARCH_DIRECTION);
replace_all_location = MOUSEPAD_SETTING_GET_INT (SEARCH_REPLACE_ALL_LOCATION); replace_all_location = MOUSEPAD_SETTING_GET_INT (SEARCH_REPLACE_ALL_LOCATION);
match_case = MOUSEPAD_SETTING_GET_BOOLEAN (SEARCH_MATCH_CASE); match_case = MOUSEPAD_SETTING_GET_BOOLEAN (SEARCH_MATCH_CASE);
enable_regex = MOUSEPAD_SETTING_GET_BOOLEAN (SEARCH_ENABLE_REGEX);
match_whole_word = MOUSEPAD_SETTING_GET_BOOLEAN (SEARCH_MATCH_WHOLE_WORD); match_whole_word = MOUSEPAD_SETTING_GET_BOOLEAN (SEARCH_MATCH_WHOLE_WORD);
replace_all = MOUSEPAD_SETTING_GET_BOOLEAN (SEARCH_REPLACE_ALL); replace_all = MOUSEPAD_SETTING_GET_BOOLEAN (SEARCH_REPLACE_ALL);
/* close dialog */
if (response_id == MOUSEPAD_RESPONSE_CLOSE)
goto destroy_dialog;
/* search direction */ /* search direction */
if (search_direction == DIRECTION_UP && ! replace_all) if (search_direction == DIRECTION_UP)
flags = MOUSEPAD_SEARCH_FLAGS_DIR_BACKWARD; flags = MOUSEPAD_SEARCH_FLAGS_DIR_BACKWARD;
else else
flags = MOUSEPAD_SEARCH_FLAGS_DIR_FORWARD; flags = MOUSEPAD_SEARCH_FLAGS_DIR_FORWARD;
...@@ -327,38 +338,34 @@ mousepad_replace_dialog_response (GtkWidget *widget, ...@@ -327,38 +338,34 @@ mousepad_replace_dialog_response (GtkWidget *widget,
if (match_case) if (match_case)
flags |= MOUSEPAD_SEARCH_FLAGS_MATCH_CASE; flags |= MOUSEPAD_SEARCH_FLAGS_MATCH_CASE;
/* enable regex search */
if (enable_regex)
flags |= MOUSEPAD_SEARCH_FLAGS_ENABLE_REGEX;
/* only match whole words */ /* only match whole words */
if (match_whole_word) if (match_whole_word)
flags |= MOUSEPAD_SEARCH_FLAGS_WHOLE_WORD; flags |= MOUSEPAD_SEARCH_FLAGS_WHOLE_WORD;
/* wrap around */ /* wrap around */
if (search_direction == DIRECTION_BOTH && ! replace_all) if (search_direction == DIRECTION_BOTH)
flags |= MOUSEPAD_SEARCH_FLAGS_WRAP_AROUND; flags |= MOUSEPAD_SEARCH_FLAGS_WRAP_AROUND;
/* search area */ /* search area */
if (replace_all && replace_all_location == IN_SELECTION) if (replace_all)
flags |= MOUSEPAD_SEARCH_FLAGS_AREA_SELECTION;
else
flags |= MOUSEPAD_SEARCH_FLAGS_AREA_DOCUMENT;
/* start position */
if (response_id == MOUSEPAD_RESPONSE_CHECK_ENTRY)
{ {
/* no visible actions */ flags |= MOUSEPAD_SEARCH_FLAGS_ENTIRE_AREA;
flags |= MOUSEPAD_SEARCH_FLAGS_ACTION_NONE; if (replace_all_location == IN_ALL_DOCUMENTS)
flags |= MOUSEPAD_SEARCH_FLAGS_AREA_ALL_DOCUMENTS;
if (replace_all) else if (replace_all_location == IN_SELECTION)
goto replace_flags; flags |= MOUSEPAD_SEARCH_FLAGS_AREA_SELECTION;
else
goto search_flags;
} }
else if (response_id == MOUSEPAD_RESPONSE_FIND)
/* start position */
if (response_id == MOUSEPAD_RESPONSE_FIND)
{ {
/* select the first match */ /* select the first match */
flags |= MOUSEPAD_SEARCH_FLAGS_ACTION_SELECT; flags |= MOUSEPAD_SEARCH_FLAGS_ACTION_SELECT;
search_flags:
/* start at the 'end' of the selection */ /* start at the 'end' of the selection */
if (flags & MOUSEPAD_SEARCH_FLAGS_DIR_BACKWARD) if (flags & MOUSEPAD_SEARCH_FLAGS_DIR_BACKWARD)
flags |= MOUSEPAD_SEARCH_FLAGS_ITER_SEL_START; flags |= MOUSEPAD_SEARCH_FLAGS_ITER_SEL_START;
...@@ -370,36 +377,11 @@ mousepad_replace_dialog_response (GtkWidget *widget, ...@@ -370,36 +377,11 @@ mousepad_replace_dialog_response (GtkWidget *widget,
/* replace matches */ /* replace matches */
flags |= MOUSEPAD_SEARCH_FLAGS_ACTION_REPLACE; flags |= MOUSEPAD_SEARCH_FLAGS_ACTION_REPLACE;
if (replace_all) /* start at the 'beginning' of the selection */
{ if (flags & MOUSEPAD_SEARCH_FLAGS_DIR_BACKWARD)
replace_flags: flags |= MOUSEPAD_SEARCH_FLAGS_ITER_SEL_END;
/* replace all from the beginning of the document */
flags |= MOUSEPAD_SEARCH_FLAGS_ITER_AREA_START
| MOUSEPAD_SEARCH_FLAGS_ENTIRE_AREA;
/* search all opened documents (flag used in mousepad-window.c) */
if (replace_all_location == IN_ALL_DOCUMENTS)
flags |= MOUSEPAD_SEARCH_FLAGS_ALL_DOCUMENTS;
}
else else
{ flags |= MOUSEPAD_SEARCH_FLAGS_ITER_SEL_START;
/* start at the 'beginning' of the selection */
if (flags & MOUSEPAD_SEARCH_FLAGS_DIR_BACKWARD)
flags |= MOUSEPAD_SEARCH_FLAGS_ITER_SEL_END;
else
flags |= MOUSEPAD_SEARCH_FLAGS_ITER_SEL_START;
}
}
else
{
destroy_dialog:
/* destroy the window */
gtk_widget_destroy (widget);
/* leave */
return;
} }
/* get strings */ /* get strings */
...@@ -448,7 +430,7 @@ mousepad_replace_dialog_changed (MousepadReplaceDialog *dialog) ...@@ -448,7 +430,7 @@ mousepad_replace_dialog_changed (MousepadReplaceDialog *dialog)
if (text != NULL && *text != '\0') if (text != NULL && *text != '\0')
{ {
/* do an invisible search to give the user some visible feedback */ /* do an invisible search to give the user some visible feedback */
gtk_dialog_response (GTK_DIALOG (dialog), MOUSEPAD_RESPONSE_CHECK_ENTRY); gtk_dialog_response (GTK_DIALOG (dialog), MOUSEPAD_RESPONSE_FIND);
/* buttons are sensitive */ /* buttons are sensitive */
sensitive = TRUE; sensitive = TRUE;
......
...@@ -28,7 +28,6 @@ ...@@ -28,7 +28,6 @@
#define TOOL_BAR_ICON_SIZE GTK_ICON_SIZE_MENU #define TOOL_BAR_ICON_SIZE GTK_ICON_SIZE_MENU
#define HIGHTLIGHT_TIMEOUT 225
...@@ -46,9 +45,8 @@ static void mousepad_search_bar_highlight_toggled (GtkWidget ...@@ -46,9 +45,8 @@ static void mousepad_search_bar_highlight_toggled (GtkWidget
MousepadSearchBar *bar); MousepadSearchBar *bar);
static void mousepad_search_bar_match_case_toggled (GtkWidget *button, static void mousepad_search_bar_match_case_toggled (GtkWidget *button,
MousepadSearchBar *bar); MousepadSearchBar *bar);
static void mousepad_search_bar_highlight_schedule (MousepadSearchBar *bar); static void mousepad_search_bar_enable_regex_toggled (GtkWidget *button,
static gboolean mousepad_search_bar_highlight_timeout (gpointer user_data); MousepadSearchBar *bar);
static void mousepad_search_bar_highlight_timeout_destroy (gpointer user_data);
...@@ -73,13 +71,12 @@ struct _MousepadSearchBar ...@@ -73,13 +71,12 @@ struct _MousepadSearchBar
/* menu entries */ /* menu entries */
GtkWidget *match_case_entry; GtkWidget *match_case_entry;
GtkWidget *enable_regex_entry;
/* flags */ /* flags */
guint highlight_all : 1; guint highlight_all : 1;
guint match_case : 1; guint match_case : 1;
guint enable_regex : 1;
/* highlight id */
guint highlight_id;
}; };
...@@ -185,14 +182,15 @@ mousepad_search_bar_init (MousepadSearchBar *bar) ...@@ -185,14 +182,15 @@ mousepad_search_bar_init (MousepadSearchBar *bar)
{ {
GtkWidget *label, *image, *check, *menuitem; GtkWidget *label, *image, *check, *menuitem;
GtkToolItem *item; GtkToolItem *item;
gboolean match_case; gboolean match_case, enable_regex;
/* load some saved state */ /* load some saved state */
match_case = MOUSEPAD_SETTING_GET_BOOLEAN (SEARCH_MATCH_CASE); match_case = MOUSEPAD_SETTING_GET_BOOLEAN (SEARCH_MATCH_CASE);
enable_regex = MOUSEPAD_SETTING_GET_BOOLEAN (SEARCH_ENABLE_REGEX);
/* init variables */ /* init variables */
bar->highlight_id = 0;
bar->match_case = match_case; bar->match_case = match_case;
bar->enable_regex = enable_regex;
/* the close button */ /* the close button */
item = gtk_tool_button_new_from_stock (GTK_STOCK_CLOSE); item = gtk_tool_button_new_from_stock (GTK_STOCK_CLOSE);
...@@ -279,6 +277,29 @@ mousepad_search_bar_init (MousepadSearchBar *bar) ...@@ -279,6 +277,29 @@ mousepad_search_bar_init (MousepadSearchBar *bar)
/* Keep toolbar check button and overflow proxy menu item in sync */ /* Keep toolbar check button and overflow proxy menu item in sync */
g_object_bind_property (check, "active", menuitem, "active", G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE); g_object_bind_property (check, "active", menuitem, "active", G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE);
gtk_widget_show (menuitem); gtk_widget_show (menuitem);
/* check button for enabling regex, including the proxy menu item */
item = gtk_tool_item_new ();
g_signal_connect_object (G_OBJECT (bar), "destroy", G_CALLBACK (gtk_widget_destroy), item, G_CONNECT_SWAPPED);
gtk_toolbar_insert (GTK_TOOLBAR (bar), item, -1);
gtk_widget_show (GTK_WIDGET (item));
check = gtk_check_button_new_with_mnemonic (_("_Enable Regex"));
g_signal_connect_object (G_OBJECT (bar), "destroy", G_CALLBACK (gtk_widget_destroy), item, G_CONNECT_SWAPPED);
gtk_container_add (GTK_CONTAINER (item), check);
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (check), enable_regex);
g_signal_connect (G_OBJECT (check), "toggled", G_CALLBACK (mousepad_search_bar_enable_regex_toggled), bar);
gtk_widget_show (check);
/* keep the widgets in sync with the GSettings */
MOUSEPAD_SETTING_BIND (SEARCH_ENABLE_REGEX, check, "active", G_SETTINGS_BIND_DEFAULT);
bar->enable_regex_entry = menuitem = gtk_check_menu_item_new_with_mnemonic (_("_Enable Regex"));
g_signal_connect_object (G_OBJECT (bar), "destroy", G_CALLBACK (gtk_widget_destroy), item, G_CONNECT_SWAPPED);
gtk_tool_item_set_proxy_menu_item (item, "enable-regex", menuitem);
/* Keep toolbar check button and overflow proxy menu item in sync */
g_object_bind_property (check, "active", menuitem, "active", G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE);
gtk_widget_show (menuitem);
} }
...@@ -286,12 +307,6 @@ mousepad_search_bar_init (MousepadSearchBar *bar) ...@@ -286,12 +307,6 @@ mousepad_search_bar_init (MousepadSearchBar *bar)
static void static void
mousepad_search_bar_finalize (GObject *object) mousepad_search_bar_finalize (GObject *object)
{ {
MousepadSearchBar *bar = MOUSEPAD_SEARCH_BAR (object);
/* stop a running highlight timeout */
if (bar->highlight_id != 0)
g_source_remove (bar->highlight_id);
(*G_OBJECT_CLASS (mousepad_search_bar_parent_class)->finalize) (object); (*G_OBJECT_CLASS (mousepad_search_bar_parent_class)->finalize) (object);
} }
...@@ -304,11 +319,8 @@ mousepad_search_bar_find_string (MousepadSearchBar *bar, ...@@ -304,11 +319,8 @@ mousepad_search_bar_find_string (MousepadSearchBar *bar,
const gchar *string; const gchar *string;
gint nmatches; gint nmatches;
/* search the entire document */
flags |= MOUSEPAD_SEARCH_FLAGS_AREA_DOCUMENT;
/* if we don't hightlight, we select with wrapping */ /* if we don't hightlight, we select with wrapping */
if ((flags & MOUSEPAD_SEARCH_FLAGS_ACTION_HIGHTLIGHT) == 0) if (! (flags & MOUSEPAD_SEARCH_FLAGS_ACTION_HIGHLIGHT_ON))
flags |= MOUSEPAD_SEARCH_FLAGS_ACTION_SELECT flags |= MOUSEPAD_SEARCH_FLAGS_ACTION_SELECT
| MOUSEPAD_SEARCH_FLAGS_WRAP_AROUND; | MOUSEPAD_SEARCH_FLAGS_WRAP_AROUND;
...@@ -316,6 +328,10 @@ mousepad_search_bar_find_string (MousepadSearchBar *bar, ...@@ -316,6 +328,10 @@ mousepad_search_bar_find_string (MousepadSearchBar *bar,
if (bar->match_case) if (bar->match_case)
flags |= MOUSEPAD_SEARCH_FLAGS_MATCH_CASE; flags |= MOUSEPAD_SEARCH_FLAGS_MATCH_CASE;
/* append the regex flags when needed */
if (bar->enable_regex)
flags |= MOUSEPAD_SEARCH_FLAGS_ENABLE_REGEX;
/* get the entry string */ /* get the entry string */
string = gtk_entry_get_text (GTK_ENTRY (bar->entry)); string = gtk_entry_get_text (GTK_ENTRY (bar->entry));
...@@ -323,7 +339,7 @@ mousepad_search_bar_find_string (MousepadSearchBar *bar, ...@@ -323,7 +339,7 @@ mousepad_search_bar_find_string (MousepadSearchBar *bar,
g_signal_emit (G_OBJECT (bar), search_bar_signals[SEARCH], 0, flags, string, NULL, &nmatches); g_signal_emit (G_OBJECT (bar), search_bar_signals[SEARCH], 0, flags, string, NULL, &nmatches);
/* do nothing with the error entry when highlight when trigged with highlight */ /* do nothing with the error entry when highlight when trigged with highlight */
if ((flags & MOUSEPAD_SEARCH_FLAGS_ACTION_HIGHTLIGHT) == 0) if (! (flags & MOUSEPAD_SEARCH_FLAGS_ACTION_HIGHLIGHT_ON))
{ {
/* make sure the search entry is not red when no text was typed */ /* make sure the search entry is not red when no text was typed */
if (string == NULL || *string == '\0') if (string == NULL || *string == '\0')
...@@ -377,9 +393,6 @@ mousepad_search_bar_entry_changed (GtkWidget *entry, ...@@ -377,9 +393,6 @@ mousepad_search_bar_entry_changed (GtkWidget *entry,
/* find */ /* find */
mousepad_search_bar_find_string (bar, flags); mousepad_search_bar_find_string (bar, flags);
/* schedule a new highlight */
mousepad_search_bar_highlight_schedule (bar);
} }
...@@ -392,27 +405,15 @@ mousepad_search_bar_highlight_toggled (GtkWidget *button, ...@@ -392,27 +405,15 @@ mousepad_search_bar_highlight_toggled (GtkWidget *button,
g_return_if_fail (MOUSEPAD_IS_SEARCH_BAR (bar)); g_return_if_fail (MOUSEPAD_IS_SEARCH_BAR (bar));
/* set the new state */ /* set the new state and search flags */
bar->highlight_all = gtk_toggle_tool_button_get_active (GTK_TOGGLE_TOOL_BUTTON (button)); bar->highlight_all = gtk_toggle_tool_button_get_active (GTK_TOGGLE_TOOL_BUTTON (button));
if (bar->highlight_all) if (bar->highlight_all)
{ flags = MOUSEPAD_SEARCH_FLAGS_ACTION_HIGHLIGHT_ON;
/* reschedule the highlight */
mousepad_search_bar_highlight_schedule (bar);
}
else else
{ flags = MOUSEPAD_SEARCH_FLAGS_ACTION_HIGHLIGHT_OFF;
/* stop timeout */
if (bar->highlight_id != 0)
g_source_remove (bar->highlight_id);
/* set search flags */ /* emit signal to set the highlight */
flags = MOUSEPAD_SEARCH_FLAGS_ACTION_HIGHTLIGHT mousepad_search_bar_find_string (bar, flags);
| MOUSEPAD_SEARCH_FLAGS_ACTION_CLEANUP;
/* emit signal to cleanup the highlight */
mousepad_search_bar_find_string (bar, flags);
}
} }
...@@ -433,56 +434,26 @@ mousepad_search_bar_match_case_toggled (GtkWidget *button, ...@@ -433,56 +434,26 @@ mousepad_search_bar_match_case_toggled (GtkWidget *button,
/* search ahead with this new flags */ /* search ahead with this new flags */
mousepad_search_bar_entry_changed (NULL, bar); mousepad_search_bar_entry_changed (NULL, bar);
/* schedule a new hightlight */
mousepad_search_bar_highlight_schedule (bar);
}
static void
mousepad_search_bar_highlight_schedule (MousepadSearchBar *bar)
{
g_return_if_fail (MOUSEPAD_IS_SEARCH_BAR (bar));
/* stop a pending timeout */
if (bar->highlight_id != 0)
g_source_remove (bar->highlight_id);
/* schedule a new timeout */
if (bar->highlight_all)
{
bar->highlight_id = g_timeout_add_full (G_PRIORITY_LOW, HIGHTLIGHT_TIMEOUT, mousepad_search_bar_highlight_timeout,
bar, mousepad_search_bar_highlight_timeout_destroy);
}
} }
static void static void
mousepad_search_bar_highlight_timeout_destroy (gpointer user_data) mousepad_search_bar_enable_regex_toggled (GtkWidget *button,
MousepadSearchBar *bar)
{ {
MOUSEPAD_SEARCH_BAR (user_data)->highlight_id = 0; gboolean active;
}
static gboolean g_return_if_fail (MOUSEPAD_IS_SEARCH_BAR (bar));
mousepad_search_bar_highlight_timeout (gpointer user_data)
{
MousepadSearchBar *bar = MOUSEPAD_SEARCH_BAR (user_data);
MousepadSearchFlags flags;
/* set search flags */ /* get the state of the toggle button */
flags = MOUSEPAD_SEARCH_FLAGS_DIR_FORWARD active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button));
| MOUSEPAD_SEARCH_FLAGS_ITER_AREA_START
| MOUSEPAD_SEARCH_FLAGS_ACTION_HIGHTLIGHT;
/* emit signal */ /* save the state */
mousepad_search_bar_find_string (bar, flags); bar->enable_regex = active;
/* stop the timeout */ /* search ahead with this new flags */
return FALSE; mousepad_search_bar_entry_changed (NULL, bar);
} }
...@@ -501,16 +472,22 @@ mousepad_search_bar_entry (MousepadSearchBar *bar) ...@@ -501,16 +472,22 @@ mousepad_search_bar_entry (MousepadSearchBar *bar)
void void
mousepad_search_bar_focus (MousepadSearchBar *bar) mousepad_search_bar_focus (MousepadSearchBar *bar)
{ {
MousepadSearchFlags flags;
g_return_if_fail (MOUSEPAD_IS_SEARCH_BAR (bar)); g_return_if_fail (MOUSEPAD_IS_SEARCH_BAR (bar));
/* focus the entry field */ /* focus the entry field */
gtk_widget_grab_focus (bar->entry); gtk_widget_grab_focus (bar->entry);
/* update the highlight */
mousepad_search_bar_highlight_schedule (bar);
/* select the entire entry */ /* select the entire entry */
gtk_editable_select_region (GTK_EDITABLE (bar->entry), 0, -1); gtk_editable_select_region (GTK_EDITABLE (bar->entry), 0, -1);
/* highlighting has been disabled by hiding the search bar */
if (bar->highlight_all)
{
flags = MOUSEPAD_SEARCH_FLAGS_ACTION_HIGHLIGHT_ON;
mousepad_search_bar_find_string (bar, flags);
}
} }
......
...@@ -60,6 +60,7 @@ G_BEGIN_DECLS ...@@ -60,6 +60,7 @@ G_BEGIN_DECLS
/* State setting names */ /* State setting names */
#define MOUSEPAD_SETTING_SEARCH_DIRECTION "/state/search/direction" #define MOUSEPAD_SETTING_SEARCH_DIRECTION "/state/search/direction"
#define MOUSEPAD_SETTING_SEARCH_MATCH_CASE "/state/search/match-case" #define MOUSEPAD_SETTING_SEARCH_MATCH_CASE "/state/search/match-case"
#define MOUSEPAD_SETTING_SEARCH_ENABLE_REGEX "/state/search/enable-regex"
#define MOUSEPAD_SETTING_SEARCH_MATCH_WHOLE_WORD "/state/search/match-whole-word" #define MOUSEPAD_SETTING_SEARCH_MATCH_WHOLE_WORD "/state/search/match-whole-word"
#define MOUSEPAD_SETTING_SEARCH_REPLACE_ALL "/state/search/replace-all" #define MOUSEPAD_SETTING_SEARCH_REPLACE_ALL "/state/search/replace-all"
#define MOUSEPAD_SETTING_SEARCH_REPLACE_ALL_LOCATION "/state/search/replace-all-location" #define MOUSEPAD_SETTING_SEARCH_REPLACE_ALL_LOCATION "/state/search/replace-all-location"
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include <mousepad/mousepad-private.h> #include <mousepad/mousepad-private.h>
#include <mousepad/mousepad-gtkcompat.h> #include <mousepad/mousepad-gtkcompat.h>
#include <mousepad/mousepad-util.h> #include <mousepad/mousepad-util.h>
#include <gtksourceview/gtksource.h>
...@@ -626,430 +627,128 @@ mousepad_util_search_flags_get_type (void) ...@@ -626,430 +627,128 @@ mousepad_util_search_flags_get_type (void)
static gboolean gint
mousepad_util_search_iter (const GtkTextIter *start, mousepad_util_search (GtkSourceSearchContext *search_context,
const gchar *string, const gchar *string,
MousepadSearchFlags flags, const gchar *replace,
GtkTextIter *match_start, MousepadSearchFlags flags)
GtkTextIter *match_end,
const GtkTextIter *limit)
{
GtkTextIter iter, begin;
gunichar iter_char, str_char;
gboolean succeed = FALSE;
const gchar *needle = string;
gboolean match_case, search_backwards, whole_word;
guint needle_offset = 0;
g_return_val_if_fail (start != NULL, FALSE);
g_return_val_if_fail (string != NULL, FALSE);
g_return_val_if_fail (limit != NULL, FALSE);
/* search properties */
match_case = (flags & MOUSEPAD_SEARCH_FLAGS_MATCH_CASE) != 0;
search_backwards = (flags & MOUSEPAD_SEARCH_FLAGS_DIR_BACKWARD) != 0;
whole_word = (flags & MOUSEPAD_SEARCH_FLAGS_WHOLE_WORD) != 0;
/* set the start iter */
iter = *start;
/* walk from the start to the end iter */
for (;;)
{
/* break when we reach the limit iter, for backwards searching it's
* it has to be less than the limit which is 0 so that we can match
* at the very start of the buffer. for forwards searching the limit
* is the index after the last char so break when we are at or past
* the limit. */
if ((search_backwards && gtk_text_iter_compare (&iter, limit) < 0) ||
(!search_backwards && gtk_text_iter_compare (&iter, limit) >= 0))
{
break;
}
/* get the unichar characters */
iter_char = gtk_text_iter_get_char (&iter);
str_char = g_utf8_get_char (needle);
/* skip unknown characters */
if (G_UNLIKELY (iter_char == 0xFFFC))
goto continue_searching;
/* lower case searching */
if (!match_case)
{
/* convert the characters to lower case */
iter_char = g_unichar_tolower (iter_char);
str_char = g_unichar_tolower (str_char);
}
/* compare the two characters */
if (iter_char == str_char)
{
/* first character matched, set the begin iter */
if (needle_offset == 0)
begin = iter;
/* get the next character and increase the offset counter */
needle = g_utf8_next_char (needle);
needle_offset++;
/* we hit the end of the search string, so we had a full match */
if (G_UNLIKELY (*needle == '\0'))
{
if (G_LIKELY (!search_backwards))
{
/* set the end iter after the character (for selection) */
gtk_text_iter_forward_char (&iter);
/* check if we match a whole word */
if (whole_word && !(mousepad_util_iter_starts_word (&begin) && mousepad_util_iter_ends_word (&iter)))
goto reset_and_continue_searching;