[gtksourceview/wip/search] Asynchronous backward search



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, &region_iter, 0);
+
+       while (!gtk_text_region_iterator_is_end (&region_iter))
+       {
+               GtkTextIter start_subregion;
+               GtkTextIter end_subregion;
+
+               gtk_text_region_iterator_get_subregion (&region_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 (&region_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]