[gtksourceview/wip/marks-sequence] Implement private class GtkSourceMarksSequence
- From: Sébastien Wilmet <swilmet src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtksourceview/wip/marks-sequence] Implement private class GtkSourceMarksSequence
- Date: Mon, 9 Sep 2013 17:06:39 +0000 (UTC)
commit 3963e3f2df09da4ce693b1a40910d5ed7c55793c
Author: Sébastien Wilmet <swilmet gnome org>
Date: Sun Sep 8 15:25:55 2013 +0200
Implement private class GtkSourceMarksSequence
And use it for GtkSourceMarks. It will be useful for the code folding
too.
More unit tests are needed.
docs/reference/Makefile.am | 1 +
gtksourceview/Makefile.am | 2 +
gtksourceview/gtksourcebuffer.c | 490 +++++++---------------------
gtksourceview/gtksourcemark.c | 24 +-
gtksourceview/gtksourcemarkssequence.c | 563 ++++++++++++++++++++++++++++++++
gtksourceview/gtksourcemarkssequence.h | 96 ++++++
gtksourceview/gtksourcetypes-private.h | 1 +
tests/Makefile.am | 7 +
tests/test-marks-sequence.c | 72 ++++
9 files changed, 882 insertions(+), 374 deletions(-)
---
diff --git a/docs/reference/Makefile.am b/docs/reference/Makefile.am
index 8acf0b3..1987d7f 100644
--- a/docs/reference/Makefile.am
+++ b/docs/reference/Makefile.am
@@ -36,6 +36,7 @@ IGNORE_HFILES = \
gtksourcegutterrenderermarks.h \
gtksourcegutterrenderer-private.h \
gtksourcelanguage-private.h \
+ gtksourcemarkssequence.h \
gtksourcepixbufhelper.h \
gtksourceregex.h \
gtksourcestyle-private.h \
diff --git a/gtksourceview/Makefile.am b/gtksourceview/Makefile.am
index 735bfb6..e27d220 100644
--- a/gtksourceview/Makefile.am
+++ b/gtksourceview/Makefile.am
@@ -61,6 +61,7 @@ libgtksourceview_private_headers = \
gtksourcegutterrenderermarks.h \
gtksourcegutterrenderer-private.h \
gtksourcelanguage-private.h \
+ gtksourcemarkssequence.h \
gtksourcepixbufhelper.h \
gtksourceregex.h \
gtksourcestyle-private.h \
@@ -79,6 +80,7 @@ libgtksourceview_private_c_files = \
gtksourcegutterrenderermarks.c \
gtksourcelanguage-parser-1.c \
gtksourcelanguage-parser-2.c \
+ gtksourcemarkssequence.c \
gtksourcepixbufhelper.c \
gtksourceregex.c \
gtksourceundomanager.c \
diff --git a/gtksourceview/gtksourcebuffer.c b/gtksourceview/gtksourcebuffer.c
index 78b2919..089beb9 100644
--- a/gtksourceview/gtksourcebuffer.c
+++ b/gtksourceview/gtksourcebuffer.c
@@ -32,18 +32,19 @@
#include "gtksourcebuffer.h"
#include "gtksourcebuffer-private.h"
-#include "gtksourceview-i18n.h"
#include "gtksourcelanguage.h"
#include "gtksourcelanguage-private.h"
#include "gtksourceundomanager.h"
-#include "gtksourceview-marshal.h"
+#include "gtksourceundomanagerdefault.h"
#include "gtksourcestylescheme.h"
#include "gtksourcestyleschememanager.h"
#include "gtksourcestyle-private.h"
-#include "gtksourceundomanagerdefault.h"
-#include "gtksourceview-typebuiltins.h"
#include "gtksourcemark.h"
+#include "gtksourcemarkssequence.h"
#include "gtksourcesearchcontext.h"
+#include "gtksourceview-i18n.h"
+#include "gtksourceview-marshal.h"
+#include "gtksourceview-typebuiltins.h"
/**
* SECTION:buffer
@@ -169,7 +170,9 @@ struct _GtkSourceBufferPrivate
GtkTextMark *bracket_mark_match;
GtkSourceBracketMatchType bracket_match;
- GArray *source_marks;
+ /* Hash table: category -> MarksSequence */
+ GHashTable *source_marks;
+ GtkSourceMarksSequence *all_source_marks;
GtkSourceLanguage *language;
@@ -191,7 +194,6 @@ G_DEFINE_TYPE_WITH_PRIVATE (GtkSourceBuffer, gtk_source_buffer, GTK_TYPE_TEXT_BU
static guint buffer_signals[LAST_SIGNAL];
-static void gtk_source_buffer_finalize (GObject *object);
static void gtk_source_buffer_dispose (GObject *object);
static void gtk_source_buffer_set_property (GObject *object,
guint prop_id,
@@ -265,7 +267,6 @@ gtk_source_buffer_class_init (GtkSourceBufferClass *klass)
tb_class = GTK_TEXT_BUFFER_CLASS (klass);
object_class->constructed = gtk_source_buffer_constructed;
- object_class->finalize = gtk_source_buffer_finalize;
object_class->dispose = gtk_source_buffer_dispose;
object_class->get_property = gtk_source_buffer_get_property;
object_class->set_property = gtk_source_buffer_set_property;
@@ -515,7 +516,13 @@ gtk_source_buffer_init (GtkSourceBuffer *buffer)
priv->bracket_mark_match = NULL;
priv->bracket_match = GTK_SOURCE_BRACKET_MATCH_NONE;
- priv->source_marks = g_array_new (FALSE, FALSE, sizeof (GtkSourceMark *));
+ priv->source_marks = g_hash_table_new_full (g_str_hash,
+ g_str_equal,
+ (GDestroyNotify)g_free,
+ (GDestroyNotify)g_object_unref);
+
+ priv->all_source_marks = _gtk_source_marks_sequence_new (GTK_TEXT_BUFFER (buffer));
+
priv->style_scheme = _gtk_source_style_scheme_get_default ();
if (priv->style_scheme != NULL)
@@ -525,23 +532,6 @@ gtk_source_buffer_init (GtkSourceBuffer *buffer)
}
static void
-gtk_source_buffer_finalize (GObject *object)
-{
- GtkSourceBuffer *buffer;
-
- g_return_if_fail (object != NULL);
- g_return_if_fail (GTK_SOURCE_IS_BUFFER (object));
-
- buffer = GTK_SOURCE_BUFFER (object);
- g_return_if_fail (buffer->priv != NULL);
-
- if (buffer->priv->source_marks)
- g_array_free (buffer->priv->source_marks, TRUE);
-
- G_OBJECT_CLASS (gtk_source_buffer_parent_class)->finalize (object);
-}
-
-static void
gtk_source_buffer_dispose (GObject *object)
{
GtkSourceBuffer *buffer;
@@ -578,6 +568,14 @@ gtk_source_buffer_dispose (GObject *object)
g_list_free (buffer->priv->search_contexts);
buffer->priv->search_contexts = NULL;
+ g_clear_object (&buffer->priv->all_source_marks);
+
+ if (buffer->priv->source_marks != NULL)
+ {
+ g_hash_table_destroy (buffer->priv->source_marks);
+ buffer->priv->source_marks = NULL;
+ }
+
G_OBJECT_CLASS (gtk_source_buffer_parent_class)->dispose (object);
}
@@ -1688,168 +1686,6 @@ gtk_source_buffer_get_style_scheme (GtkSourceBuffer *buffer)
return buffer->priv->style_scheme;
}
-/* Source Marks functionality */
-
-/* At the moment this is pretty dumb (O(N)), if it is a performance
- * problem we should change data struct.
- * Since it's used from mark_set when the mark was moved, we cannot bsearch.
- * Returns TRUE if the mark was found and removed */
-static gboolean
-source_mark_remove (GtkSourceBuffer *buffer, GtkSourceMark *mark)
-{
- guint i;
-
- for (i = 0; i < buffer->priv->source_marks->len; ++i)
- {
- GtkSourceMark *m;
-
- m = g_array_index (buffer->priv->source_marks, GtkSourceMark *, i);
- if (mark == m)
- {
- g_array_remove_index (buffer->priv->source_marks, i);
- g_object_unref (m);
-
- return TRUE;
- }
- }
-
- return FALSE;
-}
-
-/* Performs a binary search among the source marks in @buffer for the
- * position of the @iter. Returns the index of the mark at the specified
- * position or nearest before or after depending on @before.
- *
- * Return value: an index in the source marks array or -1 if the array is
- * empty or if there is no mark before/after the specified position
- */
-static gint
-source_mark_bsearch (GtkSourceBuffer *buffer, GtkTextIter *iter, gboolean before)
-{
- GArray *marks = buffer->priv->source_marks;
- GtkSourceMark *check;
- GtkTextIter check_iter, found_iter;
- gint cmp, i, min, max;
-
- if (marks->len == 0)
- return -1;
-
- i = min = 0;
- max = marks->len - 1;
- while (max >= min)
- {
- i = (min + max) >> 1;
- check = g_array_index (marks, GtkSourceMark *, i);
- gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (buffer),
- &check_iter,
- GTK_TEXT_MARK (check));
- cmp = gtk_text_iter_compare (iter, &check_iter);
- if (cmp < 0)
- {
- max = i - 1;
- }
- else if (cmp > 0)
- {
- min = i + 1;
- }
- else
- break;
- }
-
- if (before)
- {
- /* if the binary search match is after the specified iter, go back */
- while (cmp < 0 && i >= 0)
- {
- if (i == 0)
- return -1;
-
- i--;
- check = g_array_index (marks, GtkSourceMark *, i);
- gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (buffer),
- &check_iter,
- GTK_TEXT_MARK (check));
- cmp = gtk_text_iter_compare (iter, &check_iter);
- }
-
- /* if there are many marks at the given iter, return the last */
- found_iter = check_iter;
- while (i < marks->len - 1)
- {
- check = g_array_index (marks, GtkSourceMark *, i + 1);
- gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (buffer),
- &check_iter,
- GTK_TEXT_MARK (check));
- cmp = gtk_text_iter_compare (&found_iter, &check_iter);
- if (cmp != 0)
- {
- break;
- }
- i++;
- }
- }
- else
- {
- /* if the binary search match is before the specified iter, go forward */
- while (cmp > 0 && i < marks->len)
- {
- if (i == marks->len - 1)
- return -1;
-
- i++;
- check = g_array_index (marks, GtkSourceMark *, i);
- gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (buffer),
- &check_iter,
- GTK_TEXT_MARK (check));
- cmp = gtk_text_iter_compare (iter, &check_iter);
- }
-
- /* if there are many marks at the given iter, return the first */
- found_iter = check_iter;
- while (i > 0)
- {
- check = g_array_index (marks, GtkSourceMark *, i - 1);
- gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (buffer),
- &check_iter,
- GTK_TEXT_MARK (check));
- cmp = gtk_text_iter_compare (&found_iter, &check_iter);
- if (cmp != 0)
- {
- break;
- }
- i--;
- }
- }
-
- return i;
-}
-
-static void
-source_mark_insert (GtkSourceBuffer *buffer, GtkSourceMark *mark)
-{
- GtkTextIter iter;
- gint idx;
-
- gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (buffer),
- &iter,
- GTK_TEXT_MARK (mark));
-
- idx = source_mark_bsearch (buffer, &iter, TRUE);
- if (idx >= 0)
- {
- /* if the mark we found is at same iter or before
- * put our mark after that */
- idx++;
- }
- else
- {
- idx = 0;
- }
-
- g_object_ref (mark);
- g_array_insert_val (buffer->priv->source_marks, idx, mark);
-}
-
static void
gtk_source_buffer_real_apply_tag (GtkTextBuffer *buffer,
GtkTextTag *tag,
@@ -1872,18 +1708,39 @@ gtk_source_buffer_real_apply_tag (GtkTextBuffer *buffer,
}
static void
+add_source_mark (GtkSourceBuffer *buffer,
+ GtkSourceMark *mark)
+{
+ const gchar *category;
+ GtkSourceMarksSequence *seq;
+
+ _gtk_source_marks_sequence_add (buffer->priv->all_source_marks,
+ GTK_TEXT_MARK (mark));
+
+ category = gtk_source_mark_get_category (mark);
+ seq = g_hash_table_lookup (buffer->priv->source_marks, category);
+
+ if (seq == NULL)
+ {
+ seq = _gtk_source_marks_sequence_new (GTK_TEXT_BUFFER (buffer));
+
+ g_hash_table_insert (buffer->priv->source_marks,
+ g_strdup (category),
+ seq);
+ }
+
+ _gtk_source_marks_sequence_add (seq, GTK_TEXT_MARK (mark));
+}
+
+static void
gtk_source_buffer_real_mark_set (GtkTextBuffer *buffer,
const GtkTextIter *location,
GtkTextMark *mark)
{
if (GTK_SOURCE_IS_MARK (mark))
{
- /* for now we simply remove and reinsert at
- * the right place every time */
- source_mark_remove (GTK_SOURCE_BUFFER (buffer),
- GTK_SOURCE_MARK (mark));
- source_mark_insert (GTK_SOURCE_BUFFER (buffer),
- GTK_SOURCE_MARK (mark));
+ add_source_mark (GTK_SOURCE_BUFFER (buffer),
+ GTK_SOURCE_MARK (mark));
g_signal_emit_by_name (buffer, "source_mark_updated", mark);
}
@@ -1899,18 +1756,29 @@ gtk_source_buffer_real_mark_set (GtkTextBuffer *buffer,
static void
gtk_source_buffer_real_mark_deleted (GtkTextBuffer *buffer,
- GtkTextMark *mark)
+ GtkTextMark *mark)
{
if (GTK_SOURCE_IS_MARK (mark))
{
- source_mark_remove (GTK_SOURCE_BUFFER (buffer),
- GTK_SOURCE_MARK (mark));
+ GtkSourceBuffer *source_buffer = GTK_SOURCE_BUFFER (buffer);
+ const gchar *category;
+ GtkSourceMarksSequence *seq;
+
+ category = gtk_source_mark_get_category (GTK_SOURCE_MARK (mark));
+ seq = g_hash_table_lookup (source_buffer->priv->source_marks, category);
+
+ if (_gtk_source_marks_sequence_is_empty (seq))
+ {
+ g_hash_table_remove (source_buffer->priv->source_marks, category);
+ }
g_signal_emit_by_name (buffer, "source_mark_updated", mark);
}
if (GTK_TEXT_BUFFER_CLASS (gtk_source_buffer_parent_class)->mark_deleted != NULL)
+ {
GTK_TEXT_BUFFER_CLASS (gtk_source_buffer_parent_class)->mark_deleted (buffer, mark);
+ }
}
static void
@@ -1974,32 +1842,13 @@ gtk_source_buffer_create_source_mark (GtkSourceBuffer *buffer,
return mark;
}
-static gint
-get_mark_index (GtkSourceBuffer *buffer,
- GtkSourceMark *mark)
+static GtkSourceMarksSequence *
+get_marks_sequence (GtkSourceBuffer *buffer,
+ const gchar *category)
{
- GtkTextIter iter;
- gint idx;
-
- /* TODO: we could speed this up by caching the current
- * position in the mark and invalidating the cache when
- * the marks array changes. For now we always lookup. */
- gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (buffer),
- &iter,
- GTK_TEXT_MARK (mark));
-
- idx = source_mark_bsearch (buffer, &iter, FALSE);
-
- /* the array should already contain @mark */
- g_assert (idx >= 0);
-
- /* move up to our mark among the ones at this position */
- while (mark != g_array_index (buffer->priv->source_marks, GtkSourceMark *, idx))
- {
- ++idx;
- }
-
- return idx;
+ return category == NULL ?
+ buffer->priv->all_source_marks :
+ g_hash_table_lookup (buffer->priv->source_marks, category);
}
GtkSourceMark *
@@ -2007,25 +1856,21 @@ _gtk_source_buffer_source_mark_next (GtkSourceBuffer *buffer,
GtkSourceMark *mark,
const gchar *category)
{
- gint idx;
+ GtkSourceMarksSequence *seq;
+ GtkTextMark *next_mark;
g_return_val_if_fail (GTK_SOURCE_IS_BUFFER (buffer), NULL);
- idx = get_mark_index (buffer, mark);
+ seq = get_marks_sequence (buffer, category);
- while ((guint) ++idx < buffer->priv->source_marks->len)
+ if (seq == NULL)
{
- GtkSourceMark *ret;
-
- ret = g_array_index (buffer->priv->source_marks, GtkSourceMark *, idx);
- if (category == NULL ||
- 0 == strcmp (category, gtk_source_mark_get_category (ret)))
- {
- return ret;
- }
+ return NULL;
}
- return NULL;
+ next_mark = _gtk_source_marks_sequence_next (seq, GTK_TEXT_MARK (mark));
+
+ return next_mark == NULL ? NULL : GTK_SOURCE_MARK (next_mark);
}
GtkSourceMark *
@@ -2033,25 +1878,21 @@ _gtk_source_buffer_source_mark_prev (GtkSourceBuffer *buffer,
GtkSourceMark *mark,
const gchar *category)
{
- gint idx;
+ GtkSourceMarksSequence *seq;
+ GtkTextMark *prev_mark;
g_return_val_if_fail (GTK_SOURCE_IS_BUFFER (buffer), NULL);
- idx = get_mark_index (buffer, mark);
+ seq = get_marks_sequence (buffer, category);
- while (--idx >= 0)
+ if (seq == NULL)
{
- GtkSourceMark *ret;
-
- ret = g_array_index (buffer->priv->source_marks, GtkSourceMark *, idx);
- if (category == NULL ||
- 0 == strcmp (category, gtk_source_mark_get_category (ret)))
- {
- return ret;
- }
+ return NULL;
}
- return NULL;
+ prev_mark = _gtk_source_marks_sequence_prev (seq, GTK_TEXT_MARK (mark));
+
+ return prev_mark == NULL ? NULL : GTK_SOURCE_MARK (prev_mark);
}
/**
@@ -2073,39 +1914,19 @@ gtk_source_buffer_forward_iter_to_source_mark (GtkSourceBuffer *buffer,
GtkTextIter *iter,
const gchar *category)
{
- GtkTextIter i;
- gint idx;
+ GtkSourceMarksSequence *seq;
g_return_val_if_fail (GTK_SOURCE_IS_BUFFER (buffer), FALSE);
g_return_val_if_fail (iter != NULL, FALSE);
- i = *iter;
-
- idx = source_mark_bsearch (buffer, &i, FALSE);
- if (idx < 0)
- return FALSE;
+ seq = get_marks_sequence (buffer, category);
- while ((guint) idx < buffer->priv->source_marks->len)
+ if (seq == NULL)
{
- GtkSourceMark *mark;
-
- mark = g_array_index (buffer->priv->source_marks, GtkSourceMark *, idx);
- if (category == NULL ||
- 0 == strcmp (category, gtk_source_mark_get_category (mark)))
- {
- /* update the iter */
- gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (buffer), &i, GTK_TEXT_MARK (mark));
- if (gtk_text_iter_compare (&i, iter) > 0)
- {
- *iter = i;
- return TRUE;
- }
- }
-
- ++idx;
+ return FALSE;
}
- return FALSE;
+ return _gtk_source_marks_sequence_forward_iter (seq, iter);
}
/**
@@ -2127,39 +1948,19 @@ gtk_source_buffer_backward_iter_to_source_mark (GtkSourceBuffer *buffer,
GtkTextIter *iter,
const gchar *category)
{
- GtkTextIter i;
- gint idx;
+ GtkSourceMarksSequence *seq;
g_return_val_if_fail (GTK_SOURCE_IS_BUFFER (buffer), FALSE);
g_return_val_if_fail (iter != NULL, FALSE);
- i = *iter;
-
- idx = source_mark_bsearch (buffer, &i, TRUE);
- if (idx < 0)
- return FALSE;
+ seq = get_marks_sequence (buffer, category);
- while (idx >= 0)
+ if (seq == NULL)
{
- GtkSourceMark *mark;
-
- mark = g_array_index (buffer->priv->source_marks, GtkSourceMark *, idx);
- if (category == NULL ||
- 0 == strcmp (category, gtk_source_mark_get_category (mark)))
- {
- /* update the iter */
- gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (buffer), &i, GTK_TEXT_MARK (mark));
- if (gtk_text_iter_compare (&i, iter) < 0)
- {
- *iter = i;
- return TRUE;
- }
- }
-
- --idx;
+ return FALSE;
}
- return FALSE;
+ return _gtk_source_marks_sequence_backward_iter (seq, iter);
}
/**
@@ -2181,34 +1982,19 @@ gtk_source_buffer_get_source_marks_at_iter (GtkSourceBuffer *buffer,
GtkTextIter *iter,
const gchar *category)
{
- GSList *marks, *l, *res;
+ GtkSourceMarksSequence *seq;
+ g_return_val_if_fail (GTK_SOURCE_IS_BUFFER (buffer), NULL);
g_return_val_if_fail (iter != NULL, NULL);
- if (buffer->priv->source_marks->len == 0)
- return NULL;
-
- res = NULL;
- marks = gtk_text_iter_get_marks (iter);
+ seq = get_marks_sequence (buffer, category);
- for (l = marks; l != NULL; l = l->next)
+ if (seq == NULL)
{
- GtkSourceMark *mark;
-
- if (!GTK_SOURCE_IS_MARK (l->data))
- continue;
-
- mark = GTK_SOURCE_MARK (l->data);
- if (category == NULL ||
- 0 == strcmp (category, gtk_source_mark_get_category (mark)))
- {
- res = g_slist_prepend (res, l->data);
- }
+ return NULL;
}
- g_slist_free (marks);
-
- return g_slist_reverse (res);
+ return _gtk_source_marks_sequence_get_marks_at_iter (seq, iter);
}
/**
@@ -2230,42 +2016,31 @@ gtk_source_buffer_get_source_marks_at_line (GtkSourceBuffer *buffer,
gint line,
const gchar *category)
{
- GtkTextIter iter;
- GSList *res;
+ GtkSourceMarksSequence *seq;
+ GtkTextIter start;
+ GtkTextIter end;
+
+ g_return_val_if_fail (GTK_SOURCE_IS_BUFFER (buffer), NULL);
- g_return_val_if_fail (GTK_SOURCE_IS_BUFFER (buffer), NULL);
+ seq = get_marks_sequence (buffer, category);
- if (buffer->priv->source_marks->len == 0)
+ if (seq == NULL)
+ {
return NULL;
+ }
gtk_text_buffer_get_iter_at_line (GTK_TEXT_BUFFER (buffer),
- &iter, line);
+ &start,
+ line);
- res = gtk_source_buffer_get_source_marks_at_iter (buffer,
- &iter,
- category);
+ end = start;
- while (gtk_source_buffer_forward_iter_to_source_mark (buffer,
- &iter,
- category))
+ if (!gtk_text_iter_ends_line (&end))
{
- if (gtk_text_iter_get_line (&iter) == line)
- {
- GSList *l;
-
- l = gtk_source_buffer_get_source_marks_at_iter (buffer,
- &iter,
- category);
-
- res = g_slist_concat (res, l);
- }
- else
- {
- break;
- }
+ gtk_text_iter_forward_to_line_end (&end);
}
- return res;
+ return _gtk_source_marks_sequence_get_marks_in_range (seq, &start, &end);
}
/**
@@ -2286,7 +2061,7 @@ gtk_source_buffer_remove_source_marks (GtkSourceBuffer *buffer,
const GtkTextIter *end,
const gchar *category)
{
- GtkTextIter iter;
+ GtkSourceMarksSequence *seq;
GSList *list;
GSList *l;
@@ -2294,40 +2069,23 @@ gtk_source_buffer_remove_source_marks (GtkSourceBuffer *buffer,
g_return_if_fail (start != NULL);
g_return_if_fail (end != NULL);
- iter = *start;
+ seq = get_marks_sequence (buffer, category);
- list = gtk_source_buffer_get_source_marks_at_iter (buffer,
- &iter,
- category);
-
- while (gtk_source_buffer_forward_iter_to_source_mark (buffer,
- &iter,
- category))
+ if (seq == NULL)
{
- if (gtk_text_iter_compare (&iter, end) <= 0)
- {
- l = gtk_source_buffer_get_source_marks_at_iter (buffer,
- &iter,
- category);
-
- list = g_slist_concat (list, l);
- }
- else
- {
- break;
- }
+ return;
}
+ list = _gtk_source_marks_sequence_get_marks_in_range (seq, start, end);
+
for (l = list; l != NULL; l = l->next)
{
- gtk_text_buffer_delete_mark (GTK_TEXT_BUFFER (buffer),
- GTK_TEXT_MARK (l->data));
+ gtk_text_buffer_delete_mark (GTK_TEXT_BUFFER (buffer), l->data);
}
g_slist_free (list);
}
-
/**
* gtk_source_buffer_iter_has_context_class:
* @buffer: a #GtkSourceBuffer.
diff --git a/gtksourceview/gtksourcemark.c b/gtksourceview/gtksourcemark.c
index 85a7a2f..061f9eb 100644
--- a/gtksourceview/gtksourcemark.c
+++ b/gtksourceview/gtksourcemark.c
@@ -221,11 +221,15 @@ gtk_source_mark_next (GtkSourceMark *mark,
g_return_val_if_fail (GTK_SOURCE_IS_MARK (mark), NULL);
buffer = gtk_text_mark_get_buffer (GTK_TEXT_MARK (mark));
- if (buffer != NULL)
- return _gtk_source_buffer_source_mark_next (GTK_SOURCE_BUFFER (buffer),
- mark, category);
- else
+
+ if (buffer == NULL)
+ {
return NULL;
+ }
+
+ return _gtk_source_buffer_source_mark_next (GTK_SOURCE_BUFFER (buffer),
+ mark,
+ category);
}
/**
@@ -251,10 +255,14 @@ gtk_source_mark_prev (GtkSourceMark *mark,
g_return_val_if_fail (GTK_SOURCE_IS_MARK (mark), NULL);
buffer = gtk_text_mark_get_buffer (GTK_TEXT_MARK (mark));
- if (buffer != NULL)
- return _gtk_source_buffer_source_mark_prev (GTK_SOURCE_BUFFER (buffer),
- mark, category);
- else
+
+ if (buffer == NULL)
+ {
return NULL;
+ }
+
+ return _gtk_source_buffer_source_mark_prev (GTK_SOURCE_BUFFER (buffer),
+ mark,
+ category);
}
diff --git a/gtksourceview/gtksourcemarkssequence.c b/gtksourceview/gtksourcemarkssequence.c
new file mode 100644
index 0000000..29a7b97
--- /dev/null
+++ b/gtksourceview/gtksourcemarkssequence.c
@@ -0,0 +1,563 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; coding: utf-8 -*- */
+/* gtksourcemarkssequence.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 "gtksourcemarkssequence.h"
+
+/* An object for storing GtkTextMarks. The text marks are sorted internally with
+ * a GSequence. Going to the previous or next text mark has a O(1) complexity.
+ * Finding a text mark in the neighborhood of a text iter has a O(log n)
+ * complexity, with 'n' the number of marks in the sequence.
+ *
+ * The GSequenceIter associated to a text mark is inserted into the text mark,
+ * with g_object_set_qdata(). So the text mark knows its position in the
+ * GSequence. This allows to use normal GtkTextMarks in the API, instead of
+ * using a subclass or a custom iter.
+ *
+ * The MarksSequence has a weak reference to the text buffer.
+ */
+
+enum
+{
+ PROP_0,
+ PROP_BUFFER,
+};
+
+struct _GtkSourceMarksSequencePrivate
+{
+ GtkTextBuffer *buffer;
+ GSequence *seq;
+
+ /* The quark used for storing the GSequenceIter into the text mark, with
+ * g_object_set_qdata().
+ */
+ GQuark quark;
+};
+
+G_DEFINE_TYPE_WITH_PRIVATE (GtkSourceMarksSequence, _gtk_source_marks_sequence, G_TYPE_OBJECT)
+
+static void
+remove_qdata (GtkTextMark *mark,
+ GtkSourceMarksSequence *seq)
+{
+ g_object_set_qdata (G_OBJECT (mark),
+ seq->priv->quark,
+ NULL);
+}
+
+static void
+free_sequence (GtkSourceMarksSequence *seq)
+{
+ if (seq->priv->seq != NULL)
+ {
+ g_sequence_foreach (seq->priv->seq,
+ (GFunc)remove_qdata,
+ seq);
+
+ g_sequence_free (seq->priv->seq);
+ seq->priv->seq = NULL;
+ }
+}
+
+static gint
+compare_marks (GtkTextMark *mark1,
+ GtkTextMark *mark2)
+{
+ GtkTextBuffer *buffer;
+ GtkTextIter iter1;
+ GtkTextIter iter2;
+
+ g_assert (GTK_IS_TEXT_MARK (mark1));
+ g_assert (GTK_IS_TEXT_MARK (mark2));
+
+ buffer = gtk_text_mark_get_buffer (mark1);
+
+ g_assert (buffer == gtk_text_mark_get_buffer (mark2));
+
+ gtk_text_buffer_get_iter_at_mark (buffer, &iter1, mark1);
+ gtk_text_buffer_get_iter_at_mark (buffer, &iter2, mark2);
+
+ return gtk_text_iter_compare (&iter1, &iter2);
+}
+
+static void
+mark_set_cb (GtkTextBuffer *buffer,
+ GtkTextIter *location,
+ GtkTextMark *mark,
+ GtkSourceMarksSequence *seq)
+{
+ GSequenceIter *seq_iter;
+
+ seq_iter = g_object_get_qdata (G_OBJECT (mark), seq->priv->quark);
+
+ if (seq_iter != NULL)
+ {
+ g_sequence_sort_changed (seq_iter,
+ (GCompareDataFunc)compare_marks,
+ NULL);
+ }
+}
+
+static void
+mark_deleted_cb (GtkTextBuffer *buffer,
+ GtkTextMark *mark,
+ GtkSourceMarksSequence *seq)
+{
+ _gtk_source_marks_sequence_remove (seq, mark);
+}
+
+static void
+set_buffer (GtkSourceMarksSequence *seq,
+ GtkTextBuffer *buffer)
+{
+ g_assert (seq->priv->buffer == NULL);
+
+ seq->priv->buffer = buffer;
+
+ g_object_add_weak_pointer (G_OBJECT (buffer),
+ (gpointer *)&seq->priv->buffer);
+
+ g_signal_connect_object (buffer,
+ "mark-set",
+ G_CALLBACK (mark_set_cb),
+ seq,
+ 0);
+
+ g_signal_connect_object (buffer,
+ "mark-deleted",
+ G_CALLBACK (mark_deleted_cb),
+ seq,
+ 0);
+}
+
+static void
+_gtk_source_marks_sequence_dispose (GObject *object)
+{
+ GtkSourceMarksSequence *seq = GTK_SOURCE_MARKS_SEQUENCE (object);
+
+ seq->priv->buffer = NULL;
+
+ free_sequence (seq);
+
+ G_OBJECT_CLASS (_gtk_source_marks_sequence_parent_class)->dispose (object);
+}
+
+static void
+_gtk_source_marks_sequence_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GtkSourceMarksSequence *seq;
+
+ g_return_if_fail (GTK_SOURCE_IS_MARKS_SEQUENCE (object));
+
+ seq = GTK_SOURCE_MARKS_SEQUENCE (object);
+
+ switch (prop_id)
+ {
+ case PROP_BUFFER:
+ g_value_set_object (value, seq->priv->buffer);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+_gtk_source_marks_sequence_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GtkSourceMarksSequence *seq;
+
+ g_return_if_fail (GTK_SOURCE_IS_MARKS_SEQUENCE (object));
+
+ seq = GTK_SOURCE_MARKS_SEQUENCE (object);
+
+ switch (prop_id)
+ {
+ case PROP_BUFFER:
+ set_buffer (seq, g_value_get_object (value));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+_gtk_source_marks_sequence_class_init (GtkSourceMarksSequenceClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->dispose = _gtk_source_marks_sequence_dispose;
+ object_class->get_property = _gtk_source_marks_sequence_get_property;
+ object_class->set_property = _gtk_source_marks_sequence_set_property;
+
+ g_object_class_install_property (object_class,
+ PROP_BUFFER,
+ g_param_spec_object ("buffer",
+ "Buffer",
+ "The text buffer",
+ GTK_TYPE_TEXT_BUFFER,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+}
+
+static void
+_gtk_source_marks_sequence_init (GtkSourceMarksSequence *seq)
+{
+ gchar *unique_str;
+
+ seq->priv = _gtk_source_marks_sequence_get_instance_private (seq);
+
+ seq->priv->seq = g_sequence_new ((GDestroyNotify)g_object_unref);
+
+ unique_str = g_strdup_printf ("gtk-source-marks-sequence-%p", seq);
+ seq->priv->quark = g_quark_from_string (unique_str);
+ g_free (unique_str);
+}
+
+GtkSourceMarksSequence *
+_gtk_source_marks_sequence_new (GtkTextBuffer *buffer)
+{
+ g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), NULL);
+
+ return g_object_new (GTK_SOURCE_TYPE_MARKS_SEQUENCE,
+ "buffer", buffer,
+ NULL);
+}
+
+gboolean
+_gtk_source_marks_sequence_is_empty (GtkSourceMarksSequence *seq)
+{
+ g_return_val_if_fail (GTK_SOURCE_IS_MARKS_SEQUENCE (seq), TRUE);
+
+ return g_sequence_get_length (seq->priv->seq) == 0;
+}
+
+void
+_gtk_source_marks_sequence_add (GtkSourceMarksSequence *seq,
+ GtkTextMark *mark)
+{
+ GSequenceIter *seq_iter;
+
+ g_return_if_fail (GTK_SOURCE_IS_MARKS_SEQUENCE (seq));
+ g_return_if_fail (GTK_IS_TEXT_MARK (mark));
+ g_return_if_fail (gtk_text_mark_get_buffer (mark) == seq->priv->buffer);
+
+ seq_iter = g_object_get_qdata (G_OBJECT (mark), seq->priv->quark);
+
+ if (seq_iter != NULL)
+ {
+ /* The mark is already added. */
+ return;
+ }
+
+ seq_iter = g_sequence_insert_sorted (seq->priv->seq,
+ mark,
+ (GCompareDataFunc)compare_marks,
+ NULL);
+
+ g_object_ref (mark);
+ g_object_set_qdata (G_OBJECT (mark),
+ seq->priv->quark,
+ seq_iter);
+}
+
+void
+_gtk_source_marks_sequence_remove (GtkSourceMarksSequence *seq,
+ GtkTextMark *mark)
+{
+ GSequenceIter *seq_iter;
+
+ g_return_if_fail (GTK_SOURCE_IS_MARKS_SEQUENCE (seq));
+ g_return_if_fail (GTK_IS_TEXT_MARK (mark));
+
+ seq_iter = g_object_get_qdata (G_OBJECT (mark), seq->priv->quark);
+
+ if (seq_iter != NULL)
+ {
+ g_object_set_qdata (G_OBJECT (mark), seq->priv->quark, NULL);
+ g_sequence_remove (seq_iter);
+ }
+}
+
+GtkTextMark *
+_gtk_source_marks_sequence_next (GtkSourceMarksSequence *seq,
+ GtkTextMark *mark)
+{
+ GSequenceIter *seq_iter;
+
+ g_return_val_if_fail (GTK_SOURCE_IS_MARKS_SEQUENCE (seq), NULL);
+ g_return_val_if_fail (GTK_IS_TEXT_MARK (mark), NULL);
+ g_return_val_if_fail (gtk_text_mark_get_buffer (mark) == seq->priv->buffer, NULL);
+
+ seq_iter = g_object_get_qdata (G_OBJECT (mark), seq->priv->quark);
+
+ g_return_val_if_fail (seq_iter != NULL, NULL);
+
+ seq_iter = g_sequence_iter_next (seq_iter);
+
+ return g_sequence_iter_is_end (seq_iter) ? NULL : g_sequence_get (seq_iter);
+}
+
+GtkTextMark *
+_gtk_source_marks_sequence_prev (GtkSourceMarksSequence *seq,
+ GtkTextMark *mark)
+{
+ GSequenceIter *seq_iter;
+
+ g_return_val_if_fail (GTK_SOURCE_IS_MARKS_SEQUENCE (seq), NULL);
+ g_return_val_if_fail (GTK_IS_TEXT_MARK (mark), NULL);
+ g_return_val_if_fail (gtk_text_mark_get_buffer (mark) == seq->priv->buffer, NULL);
+
+ seq_iter = g_object_get_qdata (G_OBJECT (mark), seq->priv->quark);
+
+ g_return_val_if_fail (seq_iter != NULL, NULL);
+
+ if (g_sequence_iter_is_begin (seq_iter))
+ {
+ return NULL;
+ }
+
+ seq_iter = g_sequence_iter_prev (seq_iter);
+
+ return g_sequence_get (seq_iter);
+}
+
+/* Moves @iter forward to the next position where there is at least one mark.
+ * Returns %TRUE if @iter was moved.
+ */
+gboolean
+_gtk_source_marks_sequence_forward_iter (GtkSourceMarksSequence *seq,
+ GtkTextIter *iter)
+{
+ GtkTextMark *mark;
+ GSequenceIter *seq_iter;
+
+ g_return_val_if_fail (GTK_SOURCE_IS_MARKS_SEQUENCE (seq), FALSE);
+ g_return_val_if_fail (iter != NULL, FALSE);
+ g_return_val_if_fail (gtk_text_iter_get_buffer (iter) == seq->priv->buffer, FALSE);
+
+ mark = gtk_text_buffer_create_mark (seq->priv->buffer,
+ NULL,
+ iter,
+ TRUE);
+
+ seq_iter = g_sequence_search (seq->priv->seq,
+ mark,
+ (GCompareDataFunc)compare_marks,
+ NULL);
+
+ gtk_text_buffer_delete_mark (seq->priv->buffer, mark);
+
+ while (!g_sequence_iter_is_end (seq_iter))
+ {
+ GtkTextMark *cur_mark = g_sequence_get (seq_iter);
+ GtkTextIter cur_iter;
+
+ gtk_text_buffer_get_iter_at_mark (seq->priv->buffer, &cur_iter, cur_mark);
+
+ if (gtk_text_iter_compare (iter, &cur_iter) < 0)
+ {
+ *iter = cur_iter;
+ return TRUE;
+ }
+
+ seq_iter = g_sequence_iter_next (seq_iter);
+ }
+
+ return FALSE;
+}
+
+/* Moves @iter backward to the previous position where there is at least one
+ * mark. Returns %TRUE if @iter was moved.
+ */
+gboolean
+_gtk_source_marks_sequence_backward_iter (GtkSourceMarksSequence *seq,
+ GtkTextIter *iter)
+{
+ GtkTextMark *mark;
+ GSequenceIter *seq_iter;
+
+ g_return_val_if_fail (GTK_SOURCE_IS_MARKS_SEQUENCE (seq), FALSE);
+ g_return_val_if_fail (iter != NULL, FALSE);
+ g_return_val_if_fail (gtk_text_iter_get_buffer (iter) == seq->priv->buffer, FALSE);
+
+ mark = gtk_text_buffer_create_mark (seq->priv->buffer,
+ NULL,
+ iter,
+ TRUE);
+
+ seq_iter = g_sequence_search (seq->priv->seq,
+ mark,
+ (GCompareDataFunc)compare_marks,
+ NULL);
+
+ gtk_text_buffer_delete_mark (seq->priv->buffer, mark);
+
+ if (g_sequence_iter_is_end (seq_iter))
+ {
+ seq_iter = g_sequence_iter_prev (seq_iter);
+ }
+
+ if (g_sequence_iter_is_end (seq_iter))
+ {
+ /* The sequence is empty. */
+ return FALSE;
+ }
+
+ while (TRUE)
+ {
+ GtkTextMark *cur_mark;
+ GtkTextIter cur_iter;
+
+ cur_mark = g_sequence_get (seq_iter);
+
+ gtk_text_buffer_get_iter_at_mark (seq->priv->buffer, &cur_iter, cur_mark);
+
+ if (gtk_text_iter_compare (&cur_iter, iter) < 0)
+ {
+ *iter = cur_iter;
+ return TRUE;
+ }
+
+ if (g_sequence_iter_is_begin (seq_iter))
+ {
+ break;
+ }
+
+ seq_iter = g_sequence_iter_prev (seq_iter);
+ }
+
+ return FALSE;
+}
+
+GSList *
+_gtk_source_marks_sequence_get_marks_in_range (GtkSourceMarksSequence *seq,
+ const GtkTextIter *iter1,
+ const GtkTextIter *iter2)
+{
+ GtkTextIter start;
+ GtkTextIter end;
+ GtkTextMark *mark_start;
+ GSequenceIter *seq_iter;
+ GSequenceIter *first_seq_iter = NULL;
+ GSList *ret = NULL;
+
+ g_return_val_if_fail (GTK_SOURCE_IS_MARKS_SEQUENCE (seq), NULL);
+ g_return_val_if_fail (iter1 != NULL, NULL);
+ g_return_val_if_fail (iter2 != NULL, NULL);
+ g_return_val_if_fail (gtk_text_iter_get_buffer (iter1) == seq->priv->buffer, NULL);
+ g_return_val_if_fail (gtk_text_iter_get_buffer (iter2) == seq->priv->buffer, NULL);
+
+ start = *iter1;
+ end = *iter2;
+
+ gtk_text_iter_order (&start, &end);
+
+ mark_start = gtk_text_buffer_create_mark (seq->priv->buffer,
+ NULL,
+ &start,
+ TRUE);
+
+ seq_iter = g_sequence_search (seq->priv->seq,
+ mark_start,
+ (GCompareDataFunc)compare_marks,
+ NULL);
+
+ gtk_text_buffer_delete_mark (seq->priv->buffer, mark_start);
+
+ if (g_sequence_iter_is_end (seq_iter))
+ {
+ seq_iter = g_sequence_iter_prev (seq_iter);
+ }
+
+ if (g_sequence_iter_is_end (seq_iter))
+ {
+ /* The sequence is empty. */
+ return NULL;
+ }
+
+ /* Find the first mark */
+
+ while (TRUE)
+ {
+ GtkTextMark *cur_mark;
+ GtkTextIter cur_iter;
+
+ cur_mark = g_sequence_get (seq_iter);
+ gtk_text_buffer_get_iter_at_mark (seq->priv->buffer, &cur_iter, cur_mark);
+
+ if (gtk_text_iter_compare (&cur_iter, &start) < 0)
+ {
+ break;
+ }
+
+ first_seq_iter = seq_iter;
+
+ if (g_sequence_iter_is_begin (seq_iter))
+ {
+ break;
+ }
+
+ seq_iter = g_sequence_iter_prev (seq_iter);
+ }
+
+ if (first_seq_iter == NULL)
+ {
+ /* The last mark in the sequence is before @start. */
+ return NULL;
+ }
+
+ /* Go forward until @end to fill the list of marks */
+
+ for (seq_iter = first_seq_iter;
+ !g_sequence_iter_is_end (seq_iter);
+ seq_iter = g_sequence_iter_next (seq_iter))
+ {
+ GtkTextMark *cur_mark;
+ GtkTextIter cur_iter;
+
+ cur_mark = g_sequence_get (seq_iter);
+ gtk_text_buffer_get_iter_at_mark (seq->priv->buffer, &cur_iter, cur_mark);
+
+ if (gtk_text_iter_compare (&end, &cur_iter) < 0)
+ {
+ break;
+ }
+
+ ret = g_slist_prepend (ret, cur_mark);
+ }
+
+ return ret;
+}
+
+GSList *
+_gtk_source_marks_sequence_get_marks_at_iter (GtkSourceMarksSequence *seq,
+ const GtkTextIter *iter)
+{
+ return _gtk_source_marks_sequence_get_marks_in_range (seq, iter, iter);
+}
diff --git a/gtksourceview/gtksourcemarkssequence.h b/gtksourceview/gtksourcemarkssequence.h
new file mode 100644
index 0000000..40cfb70
--- /dev/null
+++ b/gtksourceview/gtksourcemarkssequence.h
@@ -0,0 +1,96 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; coding: utf-8 -*- */
+/* gtksourcemarkssequence.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_MARKS_SEQUENCE_H__
+#define __GTK_SOURCE_MARKS_SEQUENCE_H__
+
+#include <gtk/gtk.h>
+#include "gtksourcetypes-private.h"
+
+G_BEGIN_DECLS
+
+#define GTK_SOURCE_TYPE_MARKS_SEQUENCE (_gtk_source_marks_sequence_get_type ())
+#define GTK_SOURCE_MARKS_SEQUENCE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj),
GTK_SOURCE_TYPE_MARKS_SEQUENCE, GtkSourceMarksSequence))
+#define GTK_SOURCE_MARKS_SEQUENCE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass),
GTK_SOURCE_TYPE_MARKS_SEQUENCE, GtkSourceMarksSequenceClass))
+#define GTK_SOURCE_IS_MARKS_SEQUENCE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj),
GTK_SOURCE_TYPE_MARKS_SEQUENCE))
+#define GTK_SOURCE_IS_MARKS_SEQUENCE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass),
GTK_SOURCE_TYPE_MARKS_SEQUENCE))
+#define GTK_SOURCE_MARKS_SEQUENCE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj),
GTK_SOURCE_TYPE_MARKS_SEQUENCE, GtkSourceMarksSequenceClass))
+
+typedef struct _GtkSourceMarksSequenceClass GtkSourceMarksSequenceClass;
+typedef struct _GtkSourceMarksSequencePrivate GtkSourceMarksSequencePrivate;
+
+struct _GtkSourceMarksSequence
+{
+ GObject parent;
+
+ GtkSourceMarksSequencePrivate *priv;
+};
+
+struct _GtkSourceMarksSequenceClass
+{
+ GObjectClass parent_class;
+};
+
+G_GNUC_INTERNAL
+GType _gtk_source_marks_sequence_get_type (void) G_GNUC_CONST;
+
+G_GNUC_INTERNAL
+GtkSourceMarksSequence *_gtk_source_marks_sequence_new (GtkTextBuffer *buffer);
+
+G_GNUC_INTERNAL
+gboolean _gtk_source_marks_sequence_is_empty (GtkSourceMarksSequence *seq);
+
+G_GNUC_INTERNAL
+void _gtk_source_marks_sequence_add (GtkSourceMarksSequence *seq,
+ GtkTextMark *mark);
+
+G_GNUC_INTERNAL
+void _gtk_source_marks_sequence_remove (GtkSourceMarksSequence *seq,
+ GtkTextMark *mark);
+
+G_GNUC_INTERNAL
+GtkTextMark *_gtk_source_marks_sequence_next (GtkSourceMarksSequence *seq,
+ GtkTextMark *mark);
+
+G_GNUC_INTERNAL
+GtkTextMark *_gtk_source_marks_sequence_prev (GtkSourceMarksSequence *seq,
+ GtkTextMark *mark);
+
+G_GNUC_INTERNAL
+gboolean _gtk_source_marks_sequence_forward_iter (GtkSourceMarksSequence *seq,
+ GtkTextIter *iter);
+
+G_GNUC_INTERNAL
+gboolean _gtk_source_marks_sequence_backward_iter (GtkSourceMarksSequence *seq,
+ GtkTextIter *iter);
+
+G_GNUC_INTERNAL
+GSList *_gtk_source_marks_sequence_get_marks_at_iter (GtkSourceMarksSequence *seq,
+ const GtkTextIter *iter);
+
+G_GNUC_INTERNAL
+GSList *_gtk_source_marks_sequence_get_marks_in_range (GtkSourceMarksSequence *seq,
+ const GtkTextIter *iter1,
+ const GtkTextIter *iter2);
+
+G_END_DECLS
+
+#endif /* __GTK_SOURCE_MARKS_SEQUENCE_H__ */
diff --git a/gtksourceview/gtksourcetypes-private.h b/gtksourceview/gtksourcetypes-private.h
index 6b88c2c..afb1c8a 100644
--- a/gtksourceview/gtksourcetypes-private.h
+++ b/gtksourceview/gtksourcetypes-private.h
@@ -32,6 +32,7 @@ typedef struct _GtkSourceContextEngine GtkSourceContextEngine;
typedef struct _GtkSourceEngine GtkSourceEngine;
typedef struct _GtkSourceGutterRendererLines GtkSourceGutterRendererLines;
typedef struct _GtkSourceGutterRendererMarks GtkSourceGutterRendererMarks;
+typedef struct _GtkSourceMarksSequence GtkSourceMarksSequence;
typedef struct _GtkSourcePixbufHelper GtkSourcePixbufHelper;
typedef struct _GtkSourceRegex GtkSourceRegex;
typedef struct _GtkSourceUndoManagerDefault GtkSourceUndoManagerDefault;
diff --git a/tests/Makefile.am b/tests/Makefile.am
index b5e6827..0dbcc93 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -102,6 +102,13 @@ test_mark_LDADD = \
$(DEP_LIBS) \
$(TESTS_LIBS)
+UNIT_TEST_PROGS += test-marks-sequence
+test_marks_sequence_SOURCES = test-marks-sequence.c
+test_marks_sequence_LDADD = \
+ $(top_builddir)/gtksourceview/libgtksourceview-private.la \
+ $(DEP_LIBS) \
+ $(TESTS_LIBS)
+
UNIT_TEST_PROGS += test-printcompositor
test_printcompositor_SOURCES = \
test-printcompositor.c
diff --git a/tests/test-marks-sequence.c b/tests/test-marks-sequence.c
new file mode 100644
index 0000000..de27d6d
--- /dev/null
+++ b/tests/test-marks-sequence.c
@@ -0,0 +1,72 @@
+/*
+ * test-marks-sequence.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 <gtk/gtk.h>
+#include "gtksourceview/gtksourcemarkssequence.h"
+
+static void
+test_simple (void)
+{
+ GtkTextBuffer *buffer = gtk_text_buffer_new (NULL);
+ GtkSourceMarksSequence *seq = _gtk_source_marks_sequence_new (buffer);
+ GtkTextIter iter;
+ GtkTextMark *mark1;
+ GtkTextMark *mark2;
+ GtkTextMark *mark;
+
+ gtk_text_buffer_set_text (buffer, "text", -1);
+
+ gtk_text_buffer_get_start_iter (buffer, &iter);
+ mark1 = gtk_text_buffer_create_mark (buffer, NULL, &iter, TRUE);
+
+ gtk_text_buffer_get_end_iter (buffer, &iter);
+ mark2 = gtk_text_buffer_create_mark (buffer, NULL, &iter, TRUE);
+
+ _gtk_source_marks_sequence_add (seq, mark1);
+ _gtk_source_marks_sequence_add (seq, mark2);
+
+ mark = _gtk_source_marks_sequence_next (seq, mark1);
+ g_assert (mark == mark2);
+
+ mark = _gtk_source_marks_sequence_next (seq, mark2);
+ g_assert (mark == NULL);
+
+ mark = _gtk_source_marks_sequence_prev (seq, mark2);
+ g_assert (mark == mark1);
+
+ mark = _gtk_source_marks_sequence_prev (seq, mark1);
+ g_assert (mark == NULL);
+
+ _gtk_source_marks_sequence_remove (seq, mark2);
+
+ g_object_unref (buffer);
+ g_object_unref (seq);
+}
+
+int
+main (int argc, char **argv)
+{
+ gtk_test_init (&argc, &argv);
+
+ g_test_add_func ("/MarksSequence/simple", test_simple);
+
+ return g_test_run ();
+}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]