[gtksourceview/wip/search: 5/36] Synchronous forward and backward search
- From: Sébastien Wilmet <swilmet src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtksourceview/wip/search: 5/36] Synchronous forward and backward search
- Date: Sat, 6 Jul 2013 15:57:09 +0000 (UTC)
commit b4136a0fa4af8959c8a7407623a96a3a8cae88c1
Author: Sébastien Wilmet <swilmet gnome org>
Date: Tue Jun 25 14:58:04 2013 +0200
Synchronous forward and backward search
gtksourceview/gtksourcebuffer.c | 50 +++++++++++
gtksourceview/gtksourcebuffer.h | 10 ++
gtksourceview/gtksourcesearch.c | 185 +++++++++++++++++++++++++++++++++++++--
gtksourceview/gtksourcesearch.h | 13 +++
tests/test-search-ui.c | 66 ++++++++++++++
tests/test-search-ui.ui | 40 +++++++++
6 files changed, 357 insertions(+), 7 deletions(-)
---
diff --git a/gtksourceview/gtksourcebuffer.c b/gtksourceview/gtksourcebuffer.c
index 8b2532b..2037c69 100644
--- a/gtksourceview/gtksourcebuffer.c
+++ b/gtksourceview/gtksourcebuffer.c
@@ -2679,3 +2679,53 @@ gtk_source_buffer_get_search_occurrences_count (GtkSourceBuffer *buffer)
return _gtk_source_search_get_occurrences_count (buffer->priv->search);
}
+
+/**
+ * gtk_source_buffer_forward_search:
+ * @buffer: a #GtkSourceBuffer.
+ * @iter: start of search.
+ * @match_start: return location for start of match, or %NULL.
+ * @match_end: return location for end of match, or %NULL.
+ *
+ * Synchronous forward search.
+ *
+ * Returns: whether a match was found.
+ */
+gboolean
+gtk_source_buffer_forward_search (GtkSourceBuffer *buffer,
+ const GtkTextIter *iter,
+ GtkTextIter *match_start,
+ GtkTextIter *match_end)
+{
+ g_return_val_if_fail (GTK_SOURCE_IS_BUFFER (buffer), FALSE);
+
+ return _gtk_source_search_forward (buffer->priv->search,
+ iter,
+ match_start,
+ match_end);
+}
+
+/**
+ * gtk_source_buffer_backward_search:
+ * @buffer: a #GtkSourceBuffer.
+ * @iter: start of search.
+ * @match_start: return location for start of match, or %NULL.
+ * @match_end: return location for end of match, or %NULL.
+ *
+ * Synchronous backward search.
+ *
+ * Returns: whether a match was found.
+ */
+gboolean
+gtk_source_buffer_backward_search (GtkSourceBuffer *buffer,
+ const GtkTextIter *iter,
+ GtkTextIter *match_start,
+ GtkTextIter *match_end)
+{
+ g_return_val_if_fail (GTK_SOURCE_IS_BUFFER (buffer), FALSE);
+
+ return _gtk_source_search_backward (buffer->priv->search,
+ iter,
+ match_start,
+ match_end);
+}
diff --git a/gtksourceview/gtksourcebuffer.h b/gtksourceview/gtksourcebuffer.h
index fab8416..ea079ad 100644
--- a/gtksourceview/gtksourcebuffer.h
+++ b/gtksourceview/gtksourcebuffer.h
@@ -205,6 +205,16 @@ GtkSourceSearchFlags gtk_source_buffer_get_search_flags (GtkSourceBuffer
*buffe
guint gtk_source_buffer_get_search_occurrences_count
(GtkSourceBuffer *buffer);
+gboolean gtk_source_buffer_forward_search (GtkSourceBuffer *buffer,
+ const GtkTextIter *iter,
+ GtkTextIter *match_start,
+ GtkTextIter *match_end);
+
+gboolean gtk_source_buffer_backward_search (GtkSourceBuffer *buffer,
+ const GtkTextIter *iter,
+ GtkTextIter *match_start,
+ GtkTextIter *match_end);
+
/* private */
void _gtk_source_buffer_update_highlight (GtkSourceBuffer *buffer,
const GtkTextIter *start,
diff --git a/gtksourceview/gtksourcesearch.c b/gtksourceview/gtksourcesearch.c
index 8130250..a5696f7 100644
--- a/gtksourceview/gtksourcesearch.c
+++ b/gtksourceview/gtksourcesearch.c
@@ -148,11 +148,11 @@ dispose_has_run (GtkSourceSearch *search)
}
static gboolean
-forward_search (GtkSourceSearch *search,
- const GtkTextIter *iter,
- GtkTextIter *match_start,
- GtkTextIter *match_end,
- const GtkTextIter *limit)
+basic_forward_search (GtkSourceSearch *search,
+ const GtkTextIter *iter,
+ GtkTextIter *match_start,
+ GtkTextIter *match_end,
+ const GtkTextIter *limit)
{
GtkTextIter begin_search = *iter;
@@ -180,6 +180,39 @@ forward_search (GtkSourceSearch *search,
}
}
+static gboolean
+basic_backward_search (GtkSourceSearch *search,
+ const GtkTextIter *iter,
+ GtkTextIter *match_start,
+ GtkTextIter *match_end,
+ const GtkTextIter *limit)
+{
+ GtkTextIter begin_search = *iter;
+
+ while (TRUE)
+ {
+ gboolean found = gtk_text_iter_backward_search (&begin_search,
+ search->priv->text,
+ search->priv->flags,
+ match_start,
+ match_end,
+ limit);
+
+ if (!found || !search->priv->at_word_boundaries)
+ {
+ return found;
+ }
+
+ if (gtk_text_iter_starts_word (match_start) &&
+ gtk_text_iter_ends_word (match_end))
+ {
+ return TRUE;
+ }
+
+ begin_search = *match_start;
+ }
+}
+
static void
sync_found_tag (GtkSourceSearch *search)
{
@@ -523,7 +556,7 @@ remove_occurrences_in_range (GtkSourceSearch *search,
iter = *start;
/* TODO optimization: search with forward_to_tag_toggle() */
- while (forward_search (search, &iter, &match_start, &match_end, end))
+ while (basic_forward_search (search, &iter, &match_start, &match_end, end))
{
if (search->priv->scan_region == NULL)
{
@@ -611,7 +644,7 @@ scan_subregion (GtkSourceSearch *search,
GtkTextIter match_start;
GtkTextIter match_end;
- found = forward_search (search, &iter, &match_start, &match_end, limit);
+ found = basic_forward_search (search, &iter, &match_start, &match_end, limit);
if (found)
{
@@ -737,6 +770,122 @@ install_idle_scan (GtkSourceSearch *search)
}
}
+static gboolean
+smart_forward_search (GtkSourceSearch *search,
+ const GtkTextIter *start_at,
+ GtkTextIter *match_start,
+ GtkTextIter *match_end)
+{
+ GtkTextIter iter = *start_at;
+ GtkTextIter limit;
+ GtkTextRegion *region = NULL;
+
+ if (gtk_text_iter_is_end (start_at) ||
+ search->priv->text == NULL)
+ {
+ return FALSE;
+ }
+
+ if (search->priv->found_tag == NULL)
+ {
+ init_found_tag (search);
+ }
+
+ if (!gtk_text_iter_has_tag (&iter, search->priv->found_tag) ||
+ gtk_text_iter_ends_tag (&iter, search->priv->found_tag))
+ {
+ gtk_text_iter_forward_to_tag_toggle (&iter, search->priv->found_tag);
+ }
+
+ limit = iter;
+ gtk_text_iter_forward_to_tag_toggle (&limit, search->priv->found_tag);
+
+ if (search->priv->scan_region != NULL)
+ {
+ region = gtk_text_region_intersect (search->priv->scan_region, start_at, &limit);
+ }
+
+ if (is_text_region_empty (region))
+ {
+ gboolean found = basic_forward_search (search, &iter, match_start, match_end, &limit);
+
+ if (region != NULL)
+ {
+ gtk_text_region_destroy (region, TRUE);
+ }
+
+ if (found)
+ {
+ return TRUE;
+ }
+
+ return smart_forward_search (search, &limit, match_start, match_end);
+ }
+
+ scan_all_region (search, region);
+ gtk_text_region_destroy (region, TRUE);
+
+ return smart_forward_search (search, start_at, match_start, match_end);
+}
+
+static gboolean
+smart_backward_search (GtkSourceSearch *search,
+ const GtkTextIter *start_at,
+ GtkTextIter *match_start,
+ GtkTextIter *match_end)
+{
+ GtkTextIter iter = *start_at;
+ GtkTextIter limit;
+ GtkTextRegion *region = NULL;
+
+ if (gtk_text_iter_is_start (start_at) ||
+ search->priv->text == NULL)
+ {
+ return FALSE;
+ }
+
+ if (search->priv->found_tag == NULL)
+ {
+ init_found_tag (search);
+ }
+
+ if (!gtk_text_iter_has_tag (&iter, search->priv->found_tag) ||
+ gtk_text_iter_begins_tag (&iter, search->priv->found_tag))
+ {
+ gtk_text_iter_backward_to_tag_toggle (&iter, search->priv->found_tag);
+ }
+
+ limit = iter;
+ gtk_text_iter_backward_to_tag_toggle (&limit, search->priv->found_tag);
+
+ if (search->priv->scan_region != NULL)
+ {
+ region = gtk_text_region_intersect (search->priv->scan_region, &limit, start_at);
+ }
+
+ if (is_text_region_empty (region))
+ {
+ gboolean found = basic_backward_search (search, &iter, match_start, match_end, &limit);
+
+ if (region != NULL)
+ {
+ gtk_text_region_destroy (region, TRUE);
+ }
+
+ if (found)
+ {
+ return TRUE;
+ }
+
+ return smart_backward_search (search, &limit, match_start, match_end);
+ }
+
+ scan_all_region (search, region);
+ gtk_text_region_destroy (region, TRUE);
+
+ return smart_backward_search (search, start_at, match_start, match_end);
+}
+
static void
add_subregion_to_scan (GtkSourceSearch *search,
const GtkTextIter *subregion_start,
@@ -1115,3 +1264,25 @@ _gtk_source_search_get_occurrences_count (GtkSourceSearch *search)
return search->priv->occurrences_count;
}
+
+gboolean
+_gtk_source_search_forward (GtkSourceSearch *search,
+ const GtkTextIter *iter,
+ GtkTextIter *match_start,
+ GtkTextIter *match_end)
+{
+ g_return_val_if_fail (GTK_SOURCE_IS_SEARCH (search), FALSE);
+
+ return smart_forward_search (search, iter, match_start, match_end);
+}
+
+gboolean
+_gtk_source_search_backward (GtkSourceSearch *search,
+ const GtkTextIter *iter,
+ GtkTextIter *match_start,
+ GtkTextIter *match_end)
+{
+ g_return_val_if_fail (GTK_SOURCE_IS_SEARCH (search), FALSE);
+
+ return smart_backward_search (search, iter, match_start, match_end);
+}
diff --git a/gtksourceview/gtksourcesearch.h b/gtksourceview/gtksourcesearch.h
index 6fe023b..ce9a143 100644
--- a/gtksourceview/gtksourcesearch.h
+++ b/gtksourceview/gtksourcesearch.h
@@ -77,8 +77,21 @@ void _gtk_source_search_update_highlight (GtkSourceSearch
*search,
const GtkTextIter *end,
gboolean synchronous);
+G_GNUC_INTERNAL
guint _gtk_source_search_get_occurrences_count (GtkSourceSearch *search);
+G_GNUC_INTERNAL
+gboolean _gtk_source_search_forward (GtkSourceSearch *search,
+ const GtkTextIter *iter,
+ GtkTextIter *match_start,
+ GtkTextIter *match_end);
+
+G_GNUC_INTERNAL
+gboolean _gtk_source_search_backward (GtkSourceSearch *search,
+ const GtkTextIter *iter,
+ GtkTextIter *match_start,
+ GtkTextIter *match_end);
+
G_END_DECLS
#endif /* __GTK_SOURCE_SEARCH_H__ */
diff --git a/tests/test-search-ui.c b/tests/test-search-ui.c
index b907e84..8a4e7b0 100644
--- a/tests/test-search-ui.c
+++ b/tests/test-search-ui.c
@@ -106,6 +106,58 @@ on_at_word_boundaries_toggled_cb (GtkToggleButton *button,
}
static void
+select_search_occurrence (GtkTextView *view,
+ GtkTextBuffer *buffer,
+ const GtkTextIter *match_start,
+ const GtkTextIter *match_end)
+{
+ gtk_text_buffer_select_range (buffer, match_start, match_end);
+
+ gtk_text_view_scroll_mark_onscreen (view, gtk_text_buffer_get_insert (buffer));
+}
+
+static void
+on_button_previous_clicked_cb (GtkButton *button,
+ GtkTextView *view)
+{
+ GtkTextBuffer *buffer = gtk_text_view_get_buffer (view);
+ GtkTextIter iter;
+ GtkTextIter match_start;
+ GtkTextIter match_end;
+
+ gtk_text_buffer_get_selection_bounds (buffer, &iter, NULL);
+
+ if (gtk_source_buffer_backward_search (GTK_SOURCE_BUFFER (buffer),
+ &iter,
+ &match_start,
+ &match_end))
+ {
+ select_search_occurrence (view, buffer, &match_start, &match_end);
+ }
+}
+
+static void
+on_button_next_clicked_cb (GtkButton *button,
+ GtkTextView *view)
+{
+ GtkTextBuffer *buffer = gtk_text_view_get_buffer (view);
+ GtkTextIter iter;
+ GtkTextIter match_start;
+ GtkTextIter match_end;
+
+ gtk_text_buffer_get_selection_bounds (buffer, NULL, &iter);
+
+ if (gtk_source_buffer_forward_search (GTK_SOURCE_BUFFER (buffer),
+ &iter,
+ &match_start,
+ &match_end))
+ {
+ select_search_occurrence (view, buffer, &match_start, &match_end);
+ }
+}
+
+
+static void
create_window (void)
{
GtkBuilder *builder;
@@ -117,6 +169,8 @@ create_window (void)
GtkLabel *label_occurrences_count;
GtkCheckButton *match_case;
GtkCheckButton *at_word_boundaries;
+ GtkButton *button_previous;
+ GtkButton *button_next;
PangoFontDescription *font;
builder = gtk_builder_new ();
@@ -136,6 +190,8 @@ create_window (void)
label_occurrences_count = GTK_LABEL (gtk_builder_get_object (builder, "label_occurrences_count"));
match_case = GTK_CHECK_BUTTON (gtk_builder_get_object (builder, "checkbutton_match_case"));
at_word_boundaries = GTK_CHECK_BUTTON (gtk_builder_get_object (builder,
"checkbutton_at_word_boundaries"));
+ button_previous = GTK_BUTTON (gtk_builder_get_object (builder, "button_previous"));
+ button_next = GTK_BUTTON (gtk_builder_get_object (builder, "button_next"));
font = pango_font_description_from_string ("Monospace 10");
gtk_widget_override_font (GTK_WIDGET (source_view), font);
@@ -179,6 +235,16 @@ create_window (void)
G_CALLBACK (on_at_word_boundaries_toggled_cb),
source_buffer);
+ g_signal_connect (button_previous,
+ "clicked",
+ G_CALLBACK (on_button_previous_clicked_cb),
+ source_view);
+
+ g_signal_connect (button_next,
+ "clicked",
+ G_CALLBACK (on_button_next_clicked_cb),
+ source_view);
+
g_object_unref (builder);
}
diff --git a/tests/test-search-ui.ui b/tests/test-search-ui.ui
index 8bf9f72..5de2949 100644
--- a/tests/test-search-ui.ui
+++ b/tests/test-search-ui.ui
@@ -2,6 +2,18 @@
<interface>
<!-- interface-requires gtk+ 3.6 -->
<!-- interface-requires gtksourceview 3.0 -->
+ <object class="GtkImage" id="image1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="stock">gtk-go-up</property>
+ <property name="icon_size">1</property>
+ </object>
+ <object class="GtkImage" id="image2">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="stock">gtk-go-down</property>
+ <property name="icon_size">1</property>
+ </object>
<object class="GtkWindow" id="window">
<property name="visible">True</property>
<property name="can_focus">False</property>
@@ -84,12 +96,40 @@
<property name="label">0 occurrences</property>
</object>
<packing>
+ <property name="left_attach">4</property>
+ <property name="top_attach">0</property>
+ <property name="width">1</property>
+ <property name="height">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="button_previous">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="image">image1</property>
+ </object>
+ <packing>
<property name="left_attach">2</property>
<property name="top_attach">0</property>
<property name="width">1</property>
<property name="height">1</property>
</packing>
</child>
+ <child>
+ <object class="GtkButton" id="button_next">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="image">image2</property>
+ </object>
+ <packing>
+ <property name="left_attach">3</property>
+ <property name="top_attach">0</property>
+ <property name="width">1</property>
+ <property name="height">1</property>
+ </packing>
+ </child>
</object>
<packing>
<property name="left_attach">0</property>
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]