[gtksourceview/wip/search: 1/2] buffer: add set_search() and clear_search() API
- From: Sébastien Wilmet <swilmet src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtksourceview/wip/search: 1/2] buffer: add set_search() and clear_search() API
- Date: Mon, 17 Jun 2013 15:52:07 +0000 (UTC)
commit e29af7e6c3204b587f2a655787b40067129b5727
Author: Sébastien Wilmet <swilmet gnome org>
Date: Sat Jun 15 10:46:39 2013 +0200
buffer: add set_search() and clear_search() API
There are also properties defining the state of the search.
The implementation (that comes from gedit) is in the new private class
GtkSourceSearch, to try to keep the GtkSourceBuffer small.
docs/reference/Makefile.am | 1 +
docs/reference/gtksourceview-3.0-sections.txt | 2 +
gtksourceview/Makefile.am | 2 +
gtksourceview/gtksourcebuffer.c | 283 +++++++++++-
gtksourceview/gtksourcebuffer.h | 8 +
gtksourceview/gtksourcesearch.c | 624 +++++++++++++++++++++++++
gtksourceview/gtksourcesearch.h | 98 ++++
gtksourceview/gtksourcetypes-private.h | 1 +
po/POTFILES.in | 1 +
9 files changed, 1019 insertions(+), 1 deletions(-)
---
diff --git a/docs/reference/Makefile.am b/docs/reference/Makefile.am
index 0ee0152..58d5593 100644
--- a/docs/reference/Makefile.am
+++ b/docs/reference/Makefile.am
@@ -37,6 +37,7 @@ IGNORE_HFILES = \
gtksourcelanguage-private.h \
gtksourcepixbufhelper.h \
gtksourceregex.h \
+ gtksourcesearch.h \
gtksourcestyle-private.h \
gtksourcetypes-private.h \
gtksourceundomanagerdefault.h \
diff --git a/docs/reference/gtksourceview-3.0-sections.txt b/docs/reference/gtksourceview-3.0-sections.txt
index 1e82636..09922f0 100644
--- a/docs/reference/gtksourceview-3.0-sections.txt
+++ b/docs/reference/gtksourceview-3.0-sections.txt
@@ -36,6 +36,8 @@ gtk_source_buffer_iter_forward_to_context_class_toggle
gtk_source_buffer_iter_backward_to_context_class_toggle
gtk_source_buffer_get_undo_manager
gtk_source_buffer_set_undo_manager
+gtk_source_buffer_set_search
+gtk_source_buffer_clear_search
<SUBSECTION Standard>
GtkSourceBufferClass
GTK_SOURCE_IS_BUFFER
diff --git a/gtksourceview/Makefile.am b/gtksourceview/Makefile.am
index 53cdbef..1d3278c 100644
--- a/gtksourceview/Makefile.am
+++ b/gtksourceview/Makefile.am
@@ -58,6 +58,7 @@ libgtksourceview_private_headers = \
gtksourcelanguage-private.h \
gtksourcepixbufhelper.h \
gtksourceregex.h \
+ gtksourcesearch.h \
gtksourcestyle-private.h \
gtksourcetypes-private.h \
gtksourceundomanagerdefault.h \
@@ -74,6 +75,7 @@ libgtksourceview_private_c_files = \
gtksourcelanguage-parser-1.c \
gtksourcelanguage-parser-2.c \
gtksourceregex.c \
+ gtksourcesearch.c \
gtksourceundomanager.c \
gtksourceundomanagerdefault.c \
gtksourceview-i18n.c \
diff --git a/gtksourceview/gtksourcebuffer.c b/gtksourceview/gtksourcebuffer.c
index 4828fc5..ec11372 100644
--- a/gtksourceview/gtksourcebuffer.c
+++ b/gtksourceview/gtksourcebuffer.c
@@ -42,6 +42,7 @@
#include "gtksourceundomanagerdefault.h"
#include "gtksourceview-typebuiltins.h"
#include "gtksourcemark.h"
+#include "gtksourcesearch.h"
/**
* SECTION:buffer
@@ -120,7 +121,11 @@ enum {
PROP_MAX_UNDO_LEVELS,
PROP_LANGUAGE,
PROP_STYLE_SCHEME,
- PROP_UNDO_MANAGER
+ PROP_UNDO_MANAGER,
+ PROP_SEARCH_STRING,
+ PROP_SEARCH_FLAGS,
+ PROP_SEARCH_START,
+ PROP_SEARCH_END
};
struct _GtkSourceBufferPrivate
@@ -140,6 +145,8 @@ struct _GtkSourceBufferPrivate
GtkSourceUndoManager *undo_manager;
gint max_undo_levels;
+ GtkSourceSearch *search;
+
guint highlight_syntax : 1;
guint highlight_brackets : 1;
guint constructed : 1;
@@ -335,6 +342,67 @@ gtk_source_buffer_class_init (GtkSourceBufferClass *klass)
GTK_SOURCE_TYPE_UNDO_MANAGER,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+ /**
+ * GtkSourceBuffer:search-string:
+ *
+ * A search string, or %NULL if the search is cleared.
+ *
+ * Since: 3.10
+ */
+ g_object_class_install_property (object_class,
+ PROP_SEARCH_STRING,
+ g_param_spec_string ("search-string",
+ _("Search string"),
+ _("Search string"),
+ NULL,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+
+ /**
+ * GtkSourceBuffer:search-flags:
+ *
+ * Flags affecting how the search is done.
+ *
+ * Since: 3.10
+ */
+ g_object_class_install_property (object_class,
+ PROP_SEARCH_FLAGS,
+ g_param_spec_flags ("search-flags",
+ _("Search flags"),
+ _("Search flags"),
+ GTK_TYPE_TEXT_SEARCH_FLAGS,
+ GTK_TEXT_SEARCH_VISIBLE_ONLY |
GTK_TEXT_SEARCH_TEXT_ONLY,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+
+ /**
+ * GtkSourceBuffer:search-start:
+ *
+ * The lower bound for the search, or %NULL for the start of the buffer.
+ *
+ * Since: 3.10
+ */
+ g_object_class_install_property (object_class,
+ PROP_SEARCH_START,
+ g_param_spec_object ("search-start",
+ _("Search start"),
+ _("Lower bound for the search"),
+ GTK_TYPE_TEXT_MARK,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+
+ /**
+ * GtkSourceBuffer:search-end:
+ *
+ * The upper bound for the search, or %NULL for the end of the buffer.
+ *
+ * Since: 3.10
+ */
+ g_object_class_install_property (object_class,
+ PROP_SEARCH_END,
+ g_param_spec_object ("search-end",
+ _("Search end"),
+ _("Upper bound for the search"),
+ GTK_TYPE_TEXT_MARK,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+
param_types[0] = GTK_TYPE_TEXT_ITER | G_SIGNAL_TYPE_STATIC_SCOPE;
param_types[1] = GTK_TYPE_TEXT_ITER | G_SIGNAL_TYPE_STATIC_SCOPE;
@@ -476,6 +544,8 @@ gtk_source_buffer_init (GtkSourceBuffer *buffer)
if (priv->style_scheme != NULL)
g_object_ref (priv->style_scheme);
+
+ priv->search = _gtk_source_search_new (buffer);
}
static void
@@ -518,6 +588,7 @@ gtk_source_buffer_dispose (GObject *object)
g_clear_object (&buffer->priv->highlight_engine);
g_clear_object (&buffer->priv->language);
g_clear_object (&buffer->priv->style_scheme);
+ g_clear_object (&buffer->priv->search);
G_OBJECT_CLASS (gtk_source_buffer_parent_class)->dispose (object);
}
@@ -566,6 +637,30 @@ gtk_source_buffer_set_property (GObject *object,
g_value_get_object (value));
break;
+ case PROP_SEARCH_STRING:
+ _gtk_source_search_set_string (source_buffer->priv->search,
+ g_value_get_string (value));
+ _gtk_source_search_update (source_buffer->priv->search);
+ break;
+
+ case PROP_SEARCH_FLAGS:
+ _gtk_source_search_set_flags (source_buffer->priv->search,
+ g_value_get_flags (value));
+ _gtk_source_search_update (source_buffer->priv->search);
+ break;
+
+ case PROP_SEARCH_START:
+ _gtk_source_search_set_start (source_buffer->priv->search,
+ g_value_get_object (value));
+ _gtk_source_search_update (source_buffer->priv->search);
+ break;
+
+ case PROP_SEARCH_END:
+ _gtk_source_search_set_end (source_buffer->priv->search,
+ g_value_get_object (value));
+ _gtk_source_search_update (source_buffer->priv->search);
+ break;
+
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -621,6 +716,22 @@ gtk_source_buffer_get_property (GObject *object,
g_value_set_object (value, source_buffer->priv->undo_manager);
break;
+ case PROP_SEARCH_STRING:
+ g_value_set_string (value, _gtk_source_search_get_string
(source_buffer->priv->search));
+ break;
+
+ case PROP_SEARCH_FLAGS:
+ g_value_set_flags (value, _gtk_source_search_get_flags (source_buffer->priv->search));
+ break;
+
+ case PROP_SEARCH_START:
+ g_value_set_object (value, _gtk_source_search_get_start
(source_buffer->priv->search));
+ break;
+
+ case PROP_SEARCH_END:
+ g_value_set_object (value, _gtk_source_search_get_end (source_buffer->priv->search));
+ break;
+
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -1532,10 +1643,17 @@ _gtk_source_buffer_update_highlight (GtkSourceBuffer *buffer,
g_return_if_fail (GTK_SOURCE_IS_BUFFER (buffer));
if (buffer->priv->highlight_engine != NULL)
+ {
_gtk_source_engine_update_highlight (buffer->priv->highlight_engine,
start,
end,
synchronous);
+ }
+
+ _gtk_source_search_update_highlight (buffer->priv->search,
+ start,
+ end,
+ synchronous);
}
/**
@@ -2476,3 +2594,166 @@ gtk_source_buffer_get_undo_manager (GtkSourceBuffer *buffer)
return buffer->priv->undo_manager;
}
+
+/**
+ * gtk_source_buffer_set_search:
+ * @buffer: the #GtkSourceBuffer where the search occurs.
+ * @str: a search string.
+ * @flags: flags affecting how the search is done.
+ * @start_iter: lower bound for the search, or %NULL for the start of the buffer.
+ * @end_iter: upper bound for the search, or %NULL for the end of the buffer.
+ *
+ * Starts a new search, defined by @str and @flags, and delimited by @start and
+ * @end. To search the all @buffer, set @start and @end to %NULL.
+ *
+ * The search matches will be highlighted. When the search is finished, call
+ * gtk_source_buffer_clear_search().
+ *
+ * Since: 3.10
+ */
+void
+gtk_source_buffer_set_search (GtkSourceBuffer *buffer,
+ const gchar *str,
+ GtkTextSearchFlags flags,
+ const GtkTextIter *start_iter,
+ const GtkTextIter *end_iter)
+{
+ const gchar *cur_str;
+ GtkTextSearchFlags cur_flags;
+ GtkTextMark *cur_start_mark;
+ GtkTextMark *cur_end_mark;
+ gboolean set_start = FALSE;
+ gboolean set_end = FALSE;
+
+ g_return_if_fail (GTK_SOURCE_IS_BUFFER (buffer));
+
+ /* Update the string */
+
+ cur_str = _gtk_source_search_get_string (buffer->priv->search);
+
+ if (g_strcmp0 (cur_str, str) != 0)
+ {
+ _gtk_source_search_set_string (buffer->priv->search, str);
+ g_object_notify (G_OBJECT (buffer), "search-string");
+ }
+
+ /* Update the flags */
+
+ cur_flags = _gtk_source_search_get_flags (buffer->priv->search);
+
+ if (cur_flags != flags)
+ {
+ _gtk_source_search_set_flags (buffer->priv->search, flags);
+ g_object_notify (G_OBJECT (buffer), "search-flags");
+ }
+
+ /* Update the start */
+
+ cur_start_mark = _gtk_source_search_get_start (buffer->priv->search);
+
+ if (cur_start_mark != NULL)
+ {
+ if (start_iter == NULL)
+ {
+ _gtk_source_search_set_start (buffer->priv->search, NULL);
+ g_object_notify (G_OBJECT (buffer), "search-start");
+ }
+ else
+ {
+ GtkTextIter cur_start_iter;
+
+ gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (buffer),
+ &cur_start_iter,
+ cur_start_mark);
+
+ if (!gtk_text_iter_equal (&cur_start_iter, start_iter))
+ {
+ set_start = TRUE;
+ }
+ }
+ }
+ else if (start_iter != NULL)
+ {
+ set_start = TRUE;
+ }
+
+ if (set_start)
+ {
+ GtkTextMark *start_mark;
+
+ start_mark = gtk_text_buffer_create_mark (GTK_TEXT_BUFFER (buffer),
+ NULL,
+ start_iter,
+ TRUE);
+
+ _gtk_source_search_set_start (buffer->priv->search, start_mark);
+ g_object_notify (G_OBJECT (buffer), "search-start");
+ }
+
+ /* Update the end */
+
+ cur_end_mark = _gtk_source_search_get_end (buffer->priv->search);
+
+ if (cur_end_mark != NULL)
+ {
+ if (end_iter == NULL)
+ {
+ _gtk_source_search_set_end (buffer->priv->search, NULL);
+ g_object_notify (G_OBJECT (buffer), "search-end");
+ }
+ else
+ {
+ GtkTextIter cur_end_iter;
+
+ gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (buffer),
+ &cur_end_iter,
+ cur_end_mark);
+
+ if (!gtk_text_iter_equal (&cur_end_iter, end_iter))
+ {
+ set_end = TRUE;
+ }
+ }
+ }
+ else if (end_iter != NULL)
+ {
+ set_end = TRUE;
+ }
+
+ if (set_end)
+ {
+ GtkTextMark *end_mark;
+
+ end_mark = gtk_text_buffer_create_mark (GTK_TEXT_BUFFER (buffer),
+ NULL,
+ end_iter,
+ FALSE);
+
+ _gtk_source_search_set_end (buffer->priv->search, end_mark);
+ g_object_notify (G_OBJECT (buffer), "search-end");
+ }
+
+ /* Update the search */
+
+ _gtk_source_search_update (buffer->priv->search);
+}
+
+/**
+ * gtk_source_buffer_clear_search:
+ * @buffer: the #GtkSourceBuffer where the search occurs.
+ *
+ * Clear the search matches highlighting.
+ *
+ * Since: 3.10
+ */
+void
+gtk_source_buffer_clear_search (GtkSourceBuffer *buffer)
+{
+ GtkTextSearchFlags flags;
+
+ g_return_if_fail (GTK_SOURCE_IS_BUFFER (buffer));
+
+ flags = _gtk_source_search_get_flags (buffer->priv->search);
+
+ gtk_source_buffer_set_search (buffer, NULL, flags, NULL, NULL);
+}
diff --git a/gtksourceview/gtksourcebuffer.h b/gtksourceview/gtksourcebuffer.h
index 80b365e..a170862 100644
--- a/gtksourceview/gtksourcebuffer.h
+++ b/gtksourceview/gtksourcebuffer.h
@@ -175,6 +175,14 @@ GtkSourceUndoManager *gtk_source_buffer_get_undo_manager (GtkSourceBuffer
*buffe
void gtk_source_buffer_set_undo_manager (GtkSourceBuffer *buffer,
GtkSourceUndoManager *manager);
+void gtk_source_buffer_set_search (GtkSourceBuffer *buffer,
+ const gchar *str,
+ GtkTextSearchFlags flags,
+ const GtkTextIter *start_iter,
+ const GtkTextIter *end_iter);
+
+void gtk_source_buffer_clear_search (GtkSourceBuffer *buffer);
+
/* private */
void _gtk_source_buffer_update_highlight (GtkSourceBuffer *buffer,
const GtkTextIter *start,
diff --git a/gtksourceview/gtksourcesearch.c b/gtksourceview/gtksourcesearch.c
new file mode 100644
index 0000000..f9bf517
--- /dev/null
+++ b/gtksourceview/gtksourcesearch.c
@@ -0,0 +1,624 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; coding: utf-8 -*- */
+/* gtksourcesearch.c
+ * This file is part of GtkSourceView
+ *
+ * Copyright (C) 2013 - Sébastien Wilmet <swilmet gnome org>
+ *
+ * GtkSourceView is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * GtkSourceView is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "gtksourcesearch.h"
+#include "gtksourcebuffer.h"
+#include "gtksourcestylescheme.h"
+#include "gtktextregion.h"
+#include "gtksourcestyle-private.h"
+
+#include <string.h>
+
+struct _GtkSourceSearchPrivate
+{
+ GtkTextBuffer *buffer;
+
+ /* State of the search */
+ gchar *str;
+ gint str_nb_lines;
+ GtkTextSearchFlags flags;
+ GtkTextMark *start;
+ GtkTextMark *end;
+
+ /* Contains the remaining region to highlight */
+ GtkTextRegion *region;
+
+ GtkTextTag *found_tag;
+};
+
+#define GTK_SOURCE_SEARCH_GET_PRIVATE(object) \
+ (G_TYPE_INSTANCE_GET_PRIVATE ((object), \
+ GTK_SOURCE_TYPE_SEARCH, \
+ GtkSourceSearchPrivate))
+
+G_DEFINE_TYPE (GtkSourceSearch, _gtk_source_search, G_TYPE_OBJECT);
+
+static gboolean
+dispose_has_run (GtkSourceSearch *search)
+{
+ return search->priv->buffer == NULL;
+}
+
+static void
+sync_found_tag (GtkSourceSearch *search)
+{
+ GtkSourceStyleScheme *style_scheme;
+ GtkSourceStyle *style = NULL;
+
+ if (dispose_has_run (search))
+ {
+ return;
+ }
+
+ style_scheme = gtk_source_buffer_get_style_scheme (GTK_SOURCE_BUFFER (search->priv->buffer));
+
+ if (style_scheme != NULL)
+ {
+ style = gtk_source_style_scheme_get_style (style_scheme, "search-match");
+ }
+
+ if (style == NULL)
+ {
+ g_warning ("search-match style not available.");
+ }
+
+ _gtk_source_style_apply (style, search->priv->found_tag);
+}
+
+static void
+init_found_tag (GtkSourceSearch *search)
+{
+ if (search->priv->found_tag != NULL)
+ {
+ return;
+ }
+
+ search->priv->found_tag = gtk_text_buffer_create_tag (search->priv->buffer, NULL, NULL);
+
+ sync_found_tag (search);
+
+ g_signal_connect_object (search->priv->buffer,
+ "notify::style-scheme",
+ G_CALLBACK (sync_found_tag),
+ search,
+ G_CONNECT_SWAPPED);
+}
+
+static void
+text_tag_set_highest_priority (GtkTextTag *tag,
+ GtkTextBuffer *buffer)
+{
+ GtkTextTagTable *table;
+ gint n;
+
+ table = gtk_text_buffer_get_tag_table (buffer);
+ n = gtk_text_tag_table_get_size (table);
+ gtk_text_tag_set_priority (tag, n - 1);
+}
+
+static void
+_gtk_source_search_dispose (GObject *object)
+{
+ GtkSourceSearch *search = GTK_SOURCE_SEARCH (object);
+
+ if (search->priv->start != NULL)
+ {
+ gtk_text_buffer_delete_mark (search->priv->buffer,
+ search->priv->start);
+
+ g_clear_object (&search->priv->start);
+ }
+
+ if (search->priv->end != NULL)
+ {
+ gtk_text_buffer_delete_mark (search->priv->buffer,
+ search->priv->end);
+
+ g_clear_object (&search->priv->end);
+ }
+
+ if (search->priv->region != NULL)
+ {
+ gtk_text_region_destroy (search->priv->region, TRUE);
+ search->priv->region = NULL;
+ }
+
+ g_clear_object (&search->priv->buffer);
+
+ G_OBJECT_CLASS (_gtk_source_search_parent_class)->dispose (object);
+}
+
+static void
+_gtk_source_search_finalize (GObject *object)
+{
+ GtkSourceSearch *search = GTK_SOURCE_SEARCH (object);
+
+ g_free (search->priv->str);
+
+ G_OBJECT_CLASS (_gtk_source_search_parent_class)->finalize (object);
+}
+
+static void
+_gtk_source_search_class_init (GtkSourceSearchClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->dispose = _gtk_source_search_dispose;
+ object_class->finalize = _gtk_source_search_finalize;
+
+ g_type_class_add_private (object_class, sizeof (GtkSourceSearchPrivate));
+}
+
+static void
+_gtk_source_search_init (GtkSourceSearch *self)
+{
+ self->priv = GTK_SOURCE_SEARCH_GET_PRIVATE (self);
+
+ self->priv->flags = GTK_TEXT_SEARCH_VISIBLE_ONLY | GTK_TEXT_SEARCH_TEXT_ONLY;
+}
+
+GtkSourceSearch *
+_gtk_source_search_new (GtkSourceBuffer *buffer)
+{
+ GtkSourceSearch *search;
+
+ g_return_val_if_fail (GTK_SOURCE_IS_BUFFER (buffer), NULL);
+
+ search = g_object_new (GTK_SOURCE_TYPE_SEARCH, NULL);
+ search->priv->buffer = GTK_TEXT_BUFFER (buffer);
+ g_object_ref (buffer);
+
+ return search;
+}
+
+static gchar *
+unescape_search_text (const gchar *text)
+{
+ GString *str;
+ gint length;
+ gboolean drop_prev = FALSE;
+ const gchar *cur;
+ const gchar *end;
+ const gchar *prev;
+
+ if (text == NULL)
+ {
+ return NULL;
+ }
+
+ length = strlen (text);
+
+ str = g_string_new ("");
+
+ cur = text;
+ end = text + length;
+ prev = NULL;
+
+ while (cur != end)
+ {
+ const gchar *next;
+ next = g_utf8_next_char (cur);
+
+ if (prev != NULL && *prev == '\\')
+ {
+ switch (*cur)
+ {
+ case 'n':
+ str = g_string_append (str, "\n");
+ break;
+ case 'r':
+ str = g_string_append (str, "\r");
+ break;
+ case 't':
+ str = g_string_append (str, "\t");
+ break;
+ case '\\':
+ str = g_string_append (str, "\\");
+ drop_prev = TRUE;
+ break;
+ default:
+ str = g_string_append (str, "\\");
+ str = g_string_append_len (str, cur, next - cur);
+ break;
+ }
+ }
+ else if (*cur != '\\')
+ {
+ str = g_string_append_len (str, cur, next - cur);
+ }
+ else if (next == end && *cur == '\\')
+ {
+ str = g_string_append (str, "\\");
+ }
+
+ if (!drop_prev)
+ {
+ prev = cur;
+ }
+ else
+ {
+ prev = NULL;
+ drop_prev = FALSE;
+ }
+
+ cur = next;
+ }
+
+ return g_string_free (str, FALSE);
+}
+
+static gint
+compute_nb_of_lines (const gchar *text)
+{
+ const gchar *p;
+ gint len;
+ gint nb_of_lines = 1;
+
+ if (text == NULL)
+ {
+ return 0;
+ }
+
+ len = strlen (text);
+ p = text;
+
+ while (len > 0)
+ {
+ gint delimiter;
+ gint next_paragraph;
+
+ pango_find_paragraph_boundary (p, len, &delimiter, &next_paragraph);
+
+ if (delimiter == next_paragraph)
+ {
+ /* not found */
+ break;
+ }
+
+ p += next_paragraph;
+ len -= next_paragraph;
+ nb_of_lines++;
+ }
+
+ return nb_of_lines;
+}
+
+void
+_gtk_source_search_set_string (GtkSourceSearch *search,
+ const gchar *str)
+{
+ g_return_if_fail (GTK_SOURCE_IS_SEARCH (search));
+ g_return_if_fail (str == NULL || g_utf8_validate (str, -1, NULL));
+
+ g_free (search->priv->str);
+ search->priv->str = unescape_search_text (str);
+ search->priv->str_nb_lines = compute_nb_of_lines (search->priv->str);
+}
+
+const gchar *
+_gtk_source_search_get_string (GtkSourceSearch *search)
+{
+ g_return_val_if_fail (GTK_SOURCE_IS_SEARCH (search), NULL);
+
+ return search->priv->str;
+}
+
+void
+_gtk_source_search_set_flags (GtkSourceSearch *search,
+ GtkTextSearchFlags flags)
+{
+ g_return_if_fail (GTK_SOURCE_IS_SEARCH (search));
+
+ search->priv->flags = flags;
+}
+
+GtkTextSearchFlags
+_gtk_source_search_get_flags (GtkSourceSearch *search)
+{
+ g_return_val_if_fail (GTK_SOURCE_IS_SEARCH (search), 0);
+
+ return search->priv->flags;
+}
+
+void
+_gtk_source_search_set_start (GtkSourceSearch *search,
+ GtkTextMark *start)
+{
+ g_return_if_fail (GTK_SOURCE_IS_SEARCH (search));
+
+ if (dispose_has_run (search))
+ {
+ return;
+ }
+
+ if (start != NULL)
+ {
+ g_return_if_fail (gtk_text_mark_get_buffer (start) == search->priv->buffer);
+ }
+
+ if (search->priv->start != NULL)
+ {
+ gtk_text_buffer_delete_mark (search->priv->buffer,
+ search->priv->start);
+
+ g_object_unref (search->priv->start);
+ }
+
+ search->priv->start = start;
+
+ if (start != NULL)
+ {
+ g_object_ref (start);
+ }
+}
+
+GtkTextMark *
+_gtk_source_search_get_start (GtkSourceSearch *search)
+{
+ g_return_val_if_fail (GTK_SOURCE_IS_SEARCH (search), NULL);
+
+ return search->priv->start;
+}
+
+void
+_gtk_source_search_set_end (GtkSourceSearch *search,
+ GtkTextMark *end)
+{
+ g_return_if_fail (GTK_SOURCE_IS_SEARCH (search));
+
+ if (dispose_has_run (search))
+ {
+ return;
+ }
+
+ if (end != NULL)
+ {
+ g_return_if_fail (gtk_text_mark_get_buffer (end) == search->priv->buffer);
+ }
+
+ if (search->priv->end != NULL)
+ {
+ gtk_text_buffer_delete_mark (search->priv->buffer,
+ search->priv->end);
+
+ g_object_unref (search->priv->end);
+ }
+
+ search->priv->end = end;
+
+ if (end != NULL)
+ {
+ g_object_ref (end);
+ }
+}
+
+GtkTextMark *
+_gtk_source_search_get_end (GtkSourceSearch *search)
+{
+ g_return_val_if_fail (GTK_SOURCE_IS_SEARCH (search), NULL);
+
+ return search->priv->end;
+}
+
+static void
+clear_search (GtkSourceSearch *search)
+{
+ if (search->priv->region != NULL)
+ {
+ gtk_text_region_destroy (search->priv->region, TRUE);
+ search->priv->region = NULL;
+ }
+
+ if (search->priv->found_tag != NULL)
+ {
+ GtkTextIter start;
+ GtkTextIter end;
+
+ gtk_text_buffer_get_bounds (search->priv->buffer, &start, &end);
+
+ gtk_text_buffer_remove_tag (search->priv->buffer,
+ search->priv->found_tag,
+ &start,
+ &end);
+ }
+}
+
+/* Separate update function, so we can change several search properties at once. */
+void
+_gtk_source_search_update (GtkSourceSearch *search)
+{
+ GtkTextIter start;
+ GtkTextIter end;
+
+ g_return_if_fail (GTK_SOURCE_IS_SEARCH (search));
+
+ if (dispose_has_run (search))
+ {
+ return;
+ }
+
+ clear_search (search);
+
+ if (search->priv->str == NULL)
+ {
+ return;
+ }
+
+ search->priv->region = gtk_text_region_new (search->priv->buffer);
+
+ if (search->priv->start != NULL)
+ {
+ gtk_text_buffer_get_iter_at_mark (search->priv->buffer,
+ &start,
+ search->priv->start);
+ }
+ else
+ {
+ gtk_text_buffer_get_start_iter (search->priv->buffer, &start);
+ }
+
+ if (search->priv->end != NULL)
+ {
+ gtk_text_buffer_get_iter_at_mark (search->priv->buffer,
+ &end,
+ search->priv->end);
+ }
+ else
+ {
+ gtk_text_buffer_get_end_iter (search->priv->buffer, &end);
+ }
+
+ gtk_text_region_add (search->priv->region, &start, &end);
+}
+
+static void
+highlight_subregion (GtkSourceSearch *search,
+ GtkTextIter *start,
+ GtkTextIter *end)
+{
+ GtkTextIter iter;
+ gboolean found = TRUE;
+
+ if (search->priv->found_tag == NULL)
+ {
+ init_found_tag (search);
+ }
+
+ /* Make sure the 'found' tag has the priority over syntax highlighting
+ * tags. */
+ text_tag_set_highest_priority (search->priv->found_tag,
+ search->priv->buffer);
+
+ g_return_if_fail (search->priv->str_nb_lines > 0);
+
+ gtk_text_iter_backward_lines (start, search->priv->str_nb_lines);
+ gtk_text_iter_forward_lines (end, search->priv->str_nb_lines);
+
+ if (gtk_text_iter_has_tag (start, search->priv->found_tag) &&
+ !gtk_text_iter_begins_tag (start, search->priv->found_tag))
+ {
+ gtk_text_iter_backward_to_tag_toggle (start, search->priv->found_tag);
+ }
+
+ if (gtk_text_iter_has_tag (end, search->priv->found_tag) &&
+ !gtk_text_iter_ends_tag (end, search->priv->found_tag))
+ {
+ gtk_text_iter_forward_to_tag_toggle (end, search->priv->found_tag);
+ }
+
+ /*
+ g_print ("[%u (%u), %u (%u)]\n", gtk_text_iter_get_line (start), gtk_text_iter_get_offset (start),
+ gtk_text_iter_get_line (end), gtk_text_iter_get_offset (end));
+ */
+
+ gtk_text_buffer_remove_tag (search->priv->buffer,
+ search->priv->found_tag,
+ start,
+ end);
+
+ if (search->priv->str[0] == '\0')
+ {
+ return;
+ }
+
+ iter = *start;
+
+ do
+ {
+ GtkTextIter match_start;
+ GtkTextIter match_end;
+
+ /* FIXME normally it is not needed.
+ if ((end != NULL) && gtk_text_iter_is_end (end))
+ {
+ end = NULL;
+ }
+ */
+
+ found = gtk_text_iter_forward_search (&iter,
+ search->priv->str,
+ search->priv->flags,
+ &match_start,
+ &match_end,
+ end);
+
+ iter = match_end;
+
+ if (found)
+ {
+ gtk_text_buffer_apply_tag (search->priv->buffer,
+ search->priv->found_tag,
+ &match_start,
+ &match_end);
+ }
+
+ } while (found);
+}
+
+void
+_gtk_source_search_update_highlight (GtkSourceSearch *search,
+ const GtkTextIter *start,
+ const GtkTextIter *end,
+ gboolean synchronous)
+{
+ GtkTextRegion *region_to_highlight;
+ GtkTextIter start_search;
+ GtkTextIter end_search;
+ gint nb_subregions;
+
+ g_return_if_fail (GTK_SOURCE_IS_SEARCH (search));
+ g_return_if_fail (start != NULL);
+ g_return_if_fail (end != NULL);
+
+ if (dispose_has_run (search) || search->priv->region == NULL)
+ {
+ return;
+ }
+
+ region_to_highlight = gtk_text_region_intersect (search->priv->region,
+ start,
+ end);
+
+ if (region_to_highlight == NULL)
+ {
+ return;
+ }
+
+ nb_subregions = gtk_text_region_subregions (region_to_highlight);
+ g_assert (nb_subregions >= 1);
+
+ gtk_text_region_nth_subregion (region_to_highlight,
+ 0,
+ &start_search,
+ NULL);
+
+ gtk_text_region_nth_subregion (region_to_highlight,
+ nb_subregions - 1,
+ NULL,
+ &end_search);
+
+ gtk_text_iter_order (&start_search, &end_search);
+
+ highlight_subregion (search, &start_search, &end_search);
+
+ /* Remove the just highlighted region */
+ gtk_text_region_subtract (search->priv->region, start, end);
+}
diff --git a/gtksourceview/gtksourcesearch.h b/gtksourceview/gtksourcesearch.h
new file mode 100644
index 0000000..d50b147
--- /dev/null
+++ b/gtksourceview/gtksourcesearch.h
@@ -0,0 +1,98 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; coding: utf-8 -*-
+ * gtksourcesearch.h
+ * This file is part of GtkSourceView
+ *
+ * Copyright (C) 2013 - Sébastien Wilmet <swilmet gnome org>
+ *
+ * GtkSourceView is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * GtkSourceView is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __GTK_SOURCE_SEARCH_H__
+#define __GTK_SOURCE_SEARCH_H__
+
+#include <gtk/gtk.h>
+#include "gtksourcetypes.h"
+#include "gtksourcetypes-private.h"
+
+G_BEGIN_DECLS
+
+#define GTK_SOURCE_TYPE_SEARCH (_gtk_source_search_get_type ())
+#define GTK_SOURCE_SEARCH(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_SOURCE_TYPE_SEARCH,
GtkSourceSearch))
+#define GTK_SOURCE_SEARCH_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_SOURCE_TYPE_SEARCH,
GtkSourceSearchClass))
+#define GTK_SOURCE_IS_SEARCH(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_SOURCE_TYPE_SEARCH))
+#define GTK_SOURCE_IS_SEARCH_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_SOURCE_TYPE_SEARCH))
+#define GTK_SOURCE_SEARCH_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_SOURCE_TYPE_SEARCH,
GtkSourceSearchClass))
+
+typedef struct _GtkSourceSearchClass GtkSourceSearchClass;
+typedef struct _GtkSourceSearchPrivate GtkSourceSearchPrivate;
+
+struct _GtkSourceSearch
+{
+ GObject parent;
+
+ GtkSourceSearchPrivate *priv;
+};
+
+struct _GtkSourceSearchClass
+{
+ GObjectClass parent_class;
+};
+
+G_GNUC_INTERNAL
+GType _gtk_source_search_get_type (void) G_GNUC_CONST;
+
+G_GNUC_INTERNAL
+GtkSourceSearch * _gtk_source_search_new (GtkSourceBuffer *buffer);
+
+G_GNUC_INTERNAL
+void _gtk_source_search_set_string (GtkSourceSearch *search,
+ const gchar *str);
+
+G_GNUC_INTERNAL
+const gchar * _gtk_source_search_get_string (GtkSourceSearch *search);
+
+G_GNUC_INTERNAL
+void _gtk_source_search_set_flags (GtkSourceSearch *search,
+ GtkTextSearchFlags flags);
+
+G_GNUC_INTERNAL
+GtkTextSearchFlags _gtk_source_search_get_flags (GtkSourceSearch *search);
+
+G_GNUC_INTERNAL
+void _gtk_source_search_set_start (GtkSourceSearch *search,
+ GtkTextMark *start);
+
+G_GNUC_INTERNAL
+GtkTextMark * _gtk_source_search_get_start (GtkSourceSearch *search);
+
+G_GNUC_INTERNAL
+void _gtk_source_search_set_end (GtkSourceSearch *search,
+ GtkTextMark *end);
+
+G_GNUC_INTERNAL
+GtkTextMark * _gtk_source_search_get_end (GtkSourceSearch *search);
+
+G_GNUC_INTERNAL
+void _gtk_source_search_update (GtkSourceSearch *search);
+
+G_GNUC_INTERNAL
+void _gtk_source_search_update_highlight (GtkSourceSearch *search,
+ const GtkTextIter *start,
+ const GtkTextIter *end,
+ gboolean synchronous);
+
+G_END_DECLS
+
+#endif /* __GTK_SOURCE_SEARCH_H__ */
diff --git a/gtksourceview/gtksourcetypes-private.h b/gtksourceview/gtksourcetypes-private.h
index 6b88c2c..58ccf31 100644
--- a/gtksourceview/gtksourcetypes-private.h
+++ b/gtksourceview/gtksourcetypes-private.h
@@ -34,6 +34,7 @@ typedef struct _GtkSourceGutterRendererLines GtkSourceGutterRendererLines;
typedef struct _GtkSourceGutterRendererMarks GtkSourceGutterRendererMarks;
typedef struct _GtkSourcePixbufHelper GtkSourcePixbufHelper;
typedef struct _GtkSourceRegex GtkSourceRegex;
+typedef struct _GtkSourceSearch GtkSourceSearch;
typedef struct _GtkSourceUndoManagerDefault GtkSourceUndoManagerDefault;
G_END_DECLS
diff --git a/po/POTFILES.in b/po/POTFILES.in
index aebf5cf..32a6455 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -131,6 +131,7 @@ gtksourceview/gtksourcemarkattributes.c
gtksourceview/gtksourcemark.c
gtksourceview/gtksourceprintcompositor.c
gtksourceview/gtksourceregex.c
+gtksourceview/gtksourcesearch.c
gtksourceview/gtksourcestyle.c
gtksourceview/gtksourcestylescheme.c
gtksourceview/gtksourcestyleschememanager.c
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]