[gtksourceview/gnome-3-16] SearchContext: fix bug look-ahead regex
- From: Sébastien Wilmet <swilmet src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtksourceview/gnome-3-16] SearchContext: fix bug look-ahead regex
- Date: Sun, 23 Aug 2015 19:33:39 +0000 (UTC)
commit 63ebe6f2c6fe2989ae99c52664befec3e5deef10
Author: Sébastien Wilmet <swilmet gnome org>
Date: Thu Aug 20 14:34:32 2015 +0200
SearchContext: fix bug look-ahead regex
- Write unit tests.
- Adapt basic_forward_regex_search() to support partial matches.
The gedit code calls gtk_source_search_context_get_occurrence_position()
to know if the selected text matches. get_occerrence_position()
traverses the occurrences by first going to tag toggles, and then inside
the tagged text, find the exact matches with basic_forward_search().
Finding the exact matches is needed because when contiguous matches are
found, when applying the tag the previous match boundary is lost.
https://bugzilla.gnome.org/show_bug.cgi?id=752719
gtksourceview/gtksourcesearchcontext.c | 112 ++++++++++++++++++++++---------
tests/test-search-context.c | 89 ++++++++++++++++++++++++-
2 files changed, 165 insertions(+), 36 deletions(-)
---
diff --git a/gtksourceview/gtksourcesearchcontext.c b/gtksourceview/gtksourcesearchcontext.c
index 5f1a4fb..a6144a8 100644
--- a/gtksourceview/gtksourcesearchcontext.c
+++ b/gtksourceview/gtksourcesearchcontext.c
@@ -715,13 +715,8 @@ basic_forward_regex_search (GtkSourceSearchContext *search,
GtkTextIter real_start;
GtkTextIter end;
gint start_pos;
- gchar *subject;
- gssize subject_length;
- GRegexMatchFlags match_options;
- GMatchInfo *match_info;
- GtkTextIter iter;
- gint iter_byte_pos;
- gboolean found;
+ gboolean found = FALSE;
+ gint nb_lines = 1;
if (search->priv->regex == NULL ||
search->priv->regex_error != NULL)
@@ -740,38 +735,89 @@ basic_forward_regex_search (GtkSourceSearchContext *search,
end = *limit;
}
- match_options = regex_search_get_match_options (&real_start, &end);
+ while (TRUE)
+ {
+ GRegexMatchFlags match_options;
+ gchar *subject;
+ gssize subject_length;
+ GMatchInfo *match_info;
+ GtkTextIter iter;
+ gint iter_byte_pos;
+ GtkTextIter m_start;
+ GtkTextIter m_end;
- subject = gtk_text_iter_get_visible_text (&real_start, &end);
- subject_length = strlen (subject);
+ match_options = regex_search_get_match_options (&real_start, &end);
- g_regex_match_full (search->priv->regex,
- subject,
- subject_length,
- start_pos,
- match_options,
- &match_info,
- &search->priv->regex_error);
+ if (!gtk_text_iter_is_end (&end))
+ {
+ match_options |= G_REGEX_MATCH_PARTIAL_HARD;
+ }
- iter = real_start;
- iter_byte_pos = 0;
+ subject = gtk_text_iter_get_visible_text (&real_start, &end);
+ subject_length = strlen (subject);
+
+ g_regex_match_full (search->priv->regex,
+ subject,
+ subject_length,
+ start_pos,
+ match_options,
+ &match_info,
+ &search->priv->regex_error);
+
+ iter = real_start;
+ iter_byte_pos = 0;
+
+ found = regex_search_fetch_match (match_info,
+ subject,
+ subject_length,
+ &iter,
+ &iter_byte_pos,
+ &m_start,
+ &m_end);
+
+ if (!found && g_match_info_is_partial_match (match_info))
+ {
+ gtk_text_iter_forward_lines (&end, nb_lines);
+ nb_lines <<= 1;
- found = regex_search_fetch_match (match_info,
- subject,
- subject_length,
- &iter,
- &iter_byte_pos,
- match_start,
- match_end);
+ g_free (subject);
+ g_match_info_free (match_info);
+ continue;
+ }
- if (search->priv->regex_error != NULL)
- {
- g_object_notify (G_OBJECT (search), "regex-error");
- found = FALSE;
- }
+ /* Check that the match is not beyond the limit. This can happen
+ * if a partial match is found on the first iteration. Then the
+ * partial match was actually not a good match, but a second
+ * good match is found.
+ */
+ if (found && limit != NULL && gtk_text_iter_compare (limit, &m_end) < 0)
+ {
+ found = FALSE;
+ }
- g_free (subject);
- g_match_info_free (match_info);
+ if (search->priv->regex_error != NULL)
+ {
+ g_object_notify (G_OBJECT (search), "regex-error");
+ found = FALSE;
+ }
+
+ if (found)
+ {
+ if (match_start != NULL)
+ {
+ *match_start = m_start;
+ }
+
+ if (match_end != NULL)
+ {
+ *match_end = m_end;
+ }
+ }
+
+ g_free (subject);
+ g_match_info_free (match_info);
+ break;
+ }
return found;
}
diff --git a/tests/test-search-context.c b/tests/test-search-context.c
index 8a2cafe..7f03334 100644
--- a/tests/test-search-context.c
+++ b/tests/test-search-context.c
@@ -921,7 +921,7 @@ test_replace_all (void)
}
static void
-test_regex (void)
+test_regex_basics (void)
{
GtkSourceBuffer *source_buffer = gtk_source_buffer_new (NULL);
GtkTextBuffer *text_buffer = GTK_TEXT_BUFFER (source_buffer);
@@ -1060,6 +1060,87 @@ test_regex_at_word_boundaries (void)
}
static void
+test_regex_look_behind (void)
+{
+ GtkSourceBuffer *source_buffer = gtk_source_buffer_new (NULL);
+ GtkTextBuffer *text_buffer = GTK_TEXT_BUFFER (source_buffer);
+ GtkSourceSearchSettings *settings = gtk_source_search_settings_new ();
+ GtkSourceSearchContext *context = gtk_source_search_context_new (source_buffer, settings);
+ GtkTextIter iter;
+ GtkTextIter match_start;
+ GtkTextIter match_end;
+ gint count;
+ gint pos;
+ gint offset;
+ gboolean found;
+
+ gtk_text_buffer_set_text (text_buffer, "12\n23\n123\n23\n12", -1);
+
+ gtk_source_search_settings_set_regex_enabled (settings, TRUE);
+ gtk_source_search_settings_set_search_text (settings, "(?<=1)23");
+ flush_queue ();
+
+ count = gtk_source_search_context_get_occurrences_count (context);
+ g_assert_cmpint (count, ==, 1);
+
+ gtk_text_buffer_get_start_iter (text_buffer, &iter);
+ found = gtk_source_search_context_forward (context, &iter, &match_start, &match_end);
+ g_assert (found);
+
+ offset = gtk_text_iter_get_offset (&match_start);
+ g_assert_cmpint (offset, ==, 7);
+ offset = gtk_text_iter_get_offset (&match_end);
+ g_assert_cmpint (offset, ==, 9);
+
+ pos = gtk_source_search_context_get_occurrence_position (context, &match_start, &match_end);
+ g_assert_cmpint (pos, ==, 1);
+
+ g_object_unref (source_buffer);
+ g_object_unref (settings);
+ g_object_unref (context);
+}
+
+static void
+test_regex_look_ahead (void)
+{
+ GtkSourceBuffer *source_buffer = gtk_source_buffer_new (NULL);
+ GtkTextBuffer *text_buffer = GTK_TEXT_BUFFER (source_buffer);
+ GtkSourceSearchSettings *settings = gtk_source_search_settings_new ();
+ GtkSourceSearchContext *context = gtk_source_search_context_new (source_buffer, settings);
+ GtkTextIter iter;
+ GtkTextIter match_start;
+ GtkTextIter match_end;
+ gint count;
+ gint pos;
+ gint offset;
+ gboolean found;
+
+ gtk_text_buffer_set_text (text_buffer, "12\n23\n123\n23\n12", -1);
+
+ gtk_source_search_settings_set_regex_enabled (settings, TRUE);
+ gtk_source_search_settings_set_search_text (settings, "12(?=3)");
+ flush_queue ();
+ count = gtk_source_search_context_get_occurrences_count (context);
+ g_assert_cmpint (count, ==, 1);
+
+ gtk_text_buffer_get_start_iter (text_buffer, &iter);
+ found = gtk_source_search_context_forward (context, &iter, &match_start, &match_end);
+ g_assert (found);
+
+ offset = gtk_text_iter_get_offset (&match_start);
+ g_assert_cmpint (offset, ==, 6);
+ offset = gtk_text_iter_get_offset (&match_end);
+ g_assert_cmpint (offset, ==, 8);
+
+ pos = gtk_source_search_context_get_occurrence_position (context, &match_start, &match_end);
+ g_assert_cmpint (pos, ==, 1);
+
+ g_object_unref (source_buffer);
+ g_object_unref (settings);
+ g_object_unref (context);
+}
+
+static void
test_destroy_buffer_during_search (void)
{
GtkSourceBuffer *source_buffer = gtk_source_buffer_new (NULL);
@@ -1106,8 +1187,10 @@ main (int argc, char **argv)
g_test_add_func ("/Search/occurrence-position", test_occurrence_position);
g_test_add_func ("/Search/replace", test_replace);
g_test_add_func ("/Search/replace", test_replace_all);
- g_test_add_func ("/Search/regex", test_regex);
- g_test_add_func ("/Search/regex-at-word-boundaries", test_regex_at_word_boundaries);
+ g_test_add_func ("/Search/regex/basics", test_regex_basics);
+ g_test_add_func ("/Search/regex/at-word-boundaries", test_regex_at_word_boundaries);
+ g_test_add_func ("/Search/regex/look-behind", test_regex_look_behind);
+ g_test_add_func ("/Search/regex/look-ahead", test_regex_look_ahead);
g_test_add_func ("/Search/destroy-buffer-during-search", test_destroy_buffer_during_search);
return g_test_run ();
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]