[gtksourceview/wip/search] Asynchronous backward search
- From: Sébastien Wilmet <swilmet src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtksourceview/wip/search] Asynchronous backward search
- Date: Wed, 26 Jun 2013 16:09:40 +0000 (UTC)
commit 5daa675ae6465a91ab0a4585d450102a7dca08ad
Author: Sébastien Wilmet <swilmet gnome org>
Date: Wed Jun 26 18:05:17 2013 +0200
Asynchronous backward search
gtksourceview/gtksourcebuffer.c | 32 +++++
gtksourceview/gtksourcebuffer.h | 13 ++
gtksourceview/gtksourcesearch.c | 238 +++++++++++++++++++++++++++++++++++++-
gtksourceview/gtksourcesearch.h | 14 +++
tests/test-search-ui.c | 32 ++++--
5 files changed, 313 insertions(+), 16 deletions(-)
---
diff --git a/gtksourceview/gtksourcebuffer.c b/gtksourceview/gtksourcebuffer.c
index fb24cbc..462aff6 100644
--- a/gtksourceview/gtksourcebuffer.c
+++ b/gtksourceview/gtksourcebuffer.c
@@ -2761,3 +2761,35 @@ gtk_source_buffer_backward_search (GtkSourceBuffer *buffer,
match_start,
match_end);
}
+
+void
+gtk_source_buffer_backward_search_async (GtkSourceBuffer *buffer,
+ const GtkTextIter *iter,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ g_return_if_fail (GTK_SOURCE_IS_BUFFER (buffer));
+
+ _gtk_source_search_backward_async (buffer->priv->search,
+ iter,
+ cancellable,
+ callback,
+ user_data);
+}
+
+gboolean
+gtk_source_buffer_backward_search_finish (GtkSourceBuffer *buffer,
+ GAsyncResult *result,
+ GtkTextIter *match_start,
+ GtkTextIter *match_end,
+ GError **error)
+{
+ g_return_val_if_fail (GTK_SOURCE_IS_BUFFER (buffer), FALSE);
+
+ return _gtk_source_search_backward_finish (buffer->priv->search,
+ result,
+ match_start,
+ match_end,
+ error);
+}
diff --git a/gtksourceview/gtksourcebuffer.h b/gtksourceview/gtksourcebuffer.h
index 15e7f0e..3cba252 100644
--- a/gtksourceview/gtksourcebuffer.h
+++ b/gtksourceview/gtksourcebuffer.h
@@ -227,6 +227,19 @@ gboolean gtk_source_buffer_backward_search (GtkSourceBuffer
*buffer,
GtkTextIter *match_start,
GtkTextIter *match_end);
+void gtk_source_buffer_backward_search_async(GtkSourceBuffer *buffer,
+ const GtkTextIter *iter,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+
+gboolean gtk_source_buffer_backward_search_finish
+ (GtkSourceBuffer *buffer,
+ GAsyncResult *result,
+ GtkTextIter *match_start,
+ GtkTextIter *match_end,
+ GError **error);
+
/* private */
void _gtk_source_buffer_update_highlight (GtkSourceBuffer *buffer,
const GtkTextIter *start,
diff --git a/gtksourceview/gtksourcesearch.c b/gtksourceview/gtksourcesearch.c
index a2023b1..74d49da 100644
--- a/gtksourceview/gtksourcesearch.c
+++ b/gtksourceview/gtksourcesearch.c
@@ -151,6 +151,9 @@ typedef struct
GtkTextIter match_start;
GtkTextIter match_end;
guint found : 1;
+
+ /* forward or backward */
+ guint is_forward : 1;
} ForwardBackwardData;
G_DEFINE_TYPE_WITH_PRIVATE (GtkSourceSearch, _gtk_source_search, G_TYPE_OBJECT);
@@ -288,6 +291,46 @@ get_first_subregion (GtkTextRegion *region,
return FALSE;
}
+/* Sets @start and @end to the last non-empty subregion.
+ * Returns FALSE if the region is empty.
+ */
+static gboolean
+get_last_subregion (GtkTextRegion *region,
+ GtkTextIter *start,
+ GtkTextIter *end)
+{
+ GtkTextRegionIterator region_iter;
+ gboolean found = FALSE;
+
+ if (region == NULL)
+ {
+ return FALSE;
+ }
+
+ gtk_text_region_get_iterator (region, ®ion_iter, 0);
+
+ while (!gtk_text_region_iterator_is_end (®ion_iter))
+ {
+ GtkTextIter start_subregion;
+ GtkTextIter end_subregion;
+
+ gtk_text_region_iterator_get_subregion (®ion_iter,
+ &start_subregion,
+ &end_subregion);
+
+ if (!gtk_text_iter_equal (&start_subregion, &end_subregion))
+ {
+ found = TRUE;
+ *start = start_subregion;
+ *end = end_subregion;
+ }
+
+ gtk_text_region_iterator_next (®ion_iter);
+ }
+
+ return found;
+}
+
static void
clear_task (GtkSourceSearch *search)
{
@@ -415,7 +458,7 @@ forward_backward_data_free (ForwardBackwardData *data)
}
static void
-begin_smart_forward_search (GtkSourceSearch *search,
+smart_forward_search_async (GtkSourceSearch *search,
const GtkTextIter *start_at,
GTask *task)
{
@@ -429,6 +472,7 @@ begin_smart_forward_search (GtkSourceSearch *search,
{
task_data = g_slice_new0 (ForwardBackwardData);
task_data->found = FALSE;
+ task_data->is_forward = TRUE;
g_task_return_pointer (task,
task_data,
@@ -476,6 +520,102 @@ begin_smart_forward_search (GtkSourceSearch *search,
task_data->found = TRUE;
task_data->match_start = match_start;
task_data->match_end = match_end;
+ task_data->is_forward = TRUE;
+
+ g_task_return_pointer (task,
+ task_data,
+ (GDestroyNotify)forward_backward_data_free);
+
+ g_object_unref (task);
+ return;
+ }
+
+ smart_forward_search_async (search, &limit, task);
+ return;
+ }
+
+ task_data = g_slice_new0 (ForwardBackwardData);
+ task_data->is_forward = TRUE;
+ task_data->start_at = gtk_text_buffer_create_mark (search->priv->buffer,
+ NULL,
+ start_at,
+ TRUE);
+
+ g_task_set_task_data (task,
+ task_data,
+ (GDestroyNotify)forward_backward_data_free);
+
+ clear_task (search);
+ search->priv->task = g_object_ref (task);
+ search->priv->task_region = region;
+
+ install_idle_scan (search);
+}
+
+static void
+smart_backward_search_async (GtkSourceSearch *search,
+ const GtkTextIter *start_at,
+ GTask *task)
+{
+ GtkTextIter iter = *start_at;
+ GtkTextIter limit;
+ GtkTextRegion *region = NULL;
+ ForwardBackwardData *task_data;
+
+ if (gtk_text_iter_is_start (start_at) ||
+ search->priv->text == NULL)
+ {
+ task_data = g_slice_new0 (ForwardBackwardData);
+ task_data->found = FALSE;
+ task_data->is_forward = FALSE;
+
+ g_task_return_pointer (task,
+ task_data,
+ (GDestroyNotify)forward_backward_data_free);
+
+ g_object_unref (task);
+ return;
+ }
+
+ 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, start_at, &limit);
+ }
+
+ if (is_text_region_empty (region))
+ {
+ GtkTextIter match_start;
+ GtkTextIter match_end;
+ gboolean found;
+
+ found = basic_backward_search (search, &iter, &match_start, &match_end, &limit);
+
+ if (region != NULL)
+ {
+ gtk_text_region_destroy (region, TRUE);
+ }
+
+ if (found)
+ {
+ task_data = g_slice_new0 (ForwardBackwardData);
+ task_data->found = TRUE;
+ task_data->match_start = match_start;
+ task_data->match_end = match_end;
+ task_data->is_forward = FALSE;
g_task_return_pointer (task,
task_data,
@@ -485,11 +625,12 @@ begin_smart_forward_search (GtkSourceSearch *search,
return;
}
- begin_smart_forward_search (search, &limit, task);
+ smart_forward_search_async (search, &limit, task);
return;
}
task_data = g_slice_new0 (ForwardBackwardData);
+ task_data->is_forward = FALSE;
task_data->start_at = gtk_text_buffer_create_mark (search->priv->buffer,
NULL,
start_at,
@@ -873,6 +1014,38 @@ scan_region_forward (GtkSourceSearch *search,
}
}
+/* Same as scan_region_forward(), but begins the scan at the end of the region. */
+static void
+scan_region_backward (GtkSourceSearch *search,
+ GtkTextRegion *region)
+{
+ gint nb_remaining_lines = SCAN_BATCH_SIZE;
+ GtkTextIter start;
+ GtkTextIter end;
+
+ while (nb_remaining_lines > 0 &&
+ get_last_subregion (region, &start, &end))
+ {
+ GtkTextIter limit = end;
+ gint limit_line;
+ gint end_line;
+
+ gtk_text_iter_backward_lines (&limit, nb_remaining_lines);
+
+ if (gtk_text_iter_compare (&limit, &start) < 0)
+ {
+ limit = start;
+ }
+
+ scan_subregion (search, &limit, &end);
+
+ limit_line = gtk_text_iter_get_line (&limit);
+ end_line = gtk_text_iter_get_line (&end);
+
+ nb_remaining_lines -= end_line - limit_line;
+ }
+}
+
static void
scan_task_region (GtkSourceSearch *search)
{
@@ -880,7 +1053,14 @@ scan_task_region (GtkSourceSearch *search)
ForwardBackwardData *task_data = g_task_get_task_data (task);
GtkTextIter start_at;
- scan_region_forward (search, search->priv->task_region);
+ if (task_data->is_forward)
+ {
+ scan_region_forward (search, search->priv->task_region);
+ }
+ else
+ {
+ scan_region_backward (search, search->priv->task_region);
+ }
if (search->priv->task_region != NULL)
{
@@ -894,7 +1074,14 @@ scan_task_region (GtkSourceSearch *search)
&start_at,
task_data->start_at);
- begin_smart_forward_search (search, &start_at, task);
+ if (task_data->is_forward)
+ {
+ smart_forward_search_async (search, &start_at, task);
+ }
+ else
+ {
+ smart_backward_search_async (search, &start_at, task);
+ }
}
static gboolean
@@ -1471,7 +1658,7 @@ _gtk_source_search_forward_async (GtkSourceSearch *search,
task = g_task_new (search->priv->buffer, cancellable, callback, user_data);
- begin_smart_forward_search (search, iter, task);
+ smart_forward_search_async (search, iter, task);
}
gboolean
@@ -1498,8 +1685,15 @@ _gtk_source_search_forward_finish (GtkSourceSearch *search,
if (found)
{
- *match_start = data->match_start;
- *match_end = data->match_end;
+ if (match_start != NULL)
+ {
+ *match_start = data->match_start;
+ }
+
+ if (match_end != NULL)
+ {
+ *match_end = data->match_end;
+ }
}
forward_backward_data_free (data);
@@ -1516,3 +1710,33 @@ _gtk_source_search_backward (GtkSourceSearch *search,
return smart_backward_search (search, iter, match_start, match_end);
}
+
+void
+_gtk_source_search_backward_async (GtkSourceSearch *search,
+ const GtkTextIter *iter,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GTask *task;
+
+ g_return_if_fail (GTK_SOURCE_IS_SEARCH (search));
+
+ task = g_task_new (search->priv->buffer, cancellable, callback, user_data);
+
+ smart_backward_search_async (search, iter, task);
+}
+
+gboolean
+_gtk_source_search_backward_finish (GtkSourceSearch *search,
+ GAsyncResult *result,
+ GtkTextIter *match_start,
+ GtkTextIter *match_end,
+ GError **error)
+{
+ return _gtk_source_search_forward_finish (search,
+ result,
+ match_start,
+ match_end,
+ error);
+}
diff --git a/gtksourceview/gtksourcesearch.h b/gtksourceview/gtksourcesearch.h
index 34d5d04..f55a3e6 100644
--- a/gtksourceview/gtksourcesearch.h
+++ b/gtksourceview/gtksourcesearch.h
@@ -106,6 +106,20 @@ gboolean _gtk_source_search_backward (GtkSourceSearch
*search,
GtkTextIter *match_start,
GtkTextIter *match_end);
+G_GNUC_INTERNAL
+void _gtk_source_search_backward_async (GtkSourceSearch *search,
+ const GtkTextIter *iter,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+
+G_GNUC_INTERNAL
+gboolean _gtk_source_search_backward_finish (GtkSourceSearch *search,
+ GAsyncResult *result,
+ GtkTextIter *match_start,
+ GtkTextIter *match_end,
+ GError **error);
+
G_END_DECLS
#endif /* __GTK_SOURCE_SEARCH_H__ */
diff --git a/tests/test-search-ui.c b/tests/test-search-ui.c
index da251ca..ad4c200 100644
--- a/tests/test-search-ui.c
+++ b/tests/test-search-ui.c
@@ -123,23 +123,37 @@ select_search_occurrence (GtkTextView *view,
}
static void
+backward_search_finished (GtkSourceBuffer *buffer,
+ GAsyncResult *result,
+ GtkTextView *view)
+{
+ GtkTextIter match_start;
+ GtkTextIter match_end;
+
+ if (gtk_source_buffer_backward_search_finish (buffer,
+ result,
+ &match_start,
+ &match_end,
+ NULL))
+ {
+ select_search_occurrence (view, &match_start, &match_end);
+ }
+}
+
+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, &match_start, &match_end);
- }
+ gtk_source_buffer_backward_search_async (GTK_SOURCE_BUFFER (buffer),
+ &iter,
+ NULL,
+ (GAsyncReadyCallback)backward_search_finished,
+ view);
}
static void
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]