[gtksourceview/gtksourcecompletion] Added general purpose words completion provider
- From: Jesse van den Kieboom <jessevdk src gnome org>
- To: svn-commits-list gnome org
- Cc:
- Subject: [gtksourceview/gtksourcecompletion] Added general purpose words completion provider
- Date: Mon, 21 Sep 2009 10:23:57 +0000 (UTC)
commit 571cecdd915b0154abaa84a4b40cdb304c4a4dfb
Author: Jesse van den Kieboom <jessevdk gnome org>
Date: Mon Sep 21 12:23:47 2009 +0200
Added general purpose words completion provider
This is basicly a rewrite of the words provider from the test case.
You can register multiple buffers with the provider to monitor and words
will be completed from all buffers through a shared words library.
configure.ac | 10 +
gtksourceview/Makefile.am | 9 +-
gtksourceview/completion-providers/Makefile.am | 1 +
.../completion-providers/words/Makefile.am | 33 +
.../words/gtksourcecompletionwords.c | 506 ++++++++
.../words/gtksourcecompletionwords.h | 67 ++
.../words/gtksourcecompletionwordsbuffer.c | 701 +++++++++++
.../words/gtksourcecompletionwordsbuffer.h | 66 ++
.../words/gtksourcecompletionwordslibrary.c | 352 ++++++
.../words/gtksourcecompletionwordslibrary.h | 86 ++
.../words/gtksourcecompletionwordsproposal.c | 141 +++
.../words/gtksourcecompletionwordsproposal.h | 65 ++
tests/Makefile.am | 4 +-
tests/completion-simple.c | 33 +-
tests/gsc-provider-words.c | 1217 --------------------
tests/gsc-provider-words.h | 36 -
16 files changed, 2043 insertions(+), 1284 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index 157e3a5..b2868e7 100644
--- a/configure.ac
+++ b/configure.ac
@@ -88,6 +88,14 @@ fi
AM_CONDITIONAL(USE_DEVHELP, test "x$have_devhelp" = "xyes")
+dnl Check to enable completion providers
+AC_ARG_ENABLE(providers,
+ AC_HELP_STRING([--enable-completion-providers],
+ [Enable building completion providers (words)]),,
+ enable_providers=yes)
+
+AM_CONDITIONAL(ENABLE_PROVIDERS, test "x$enable_providers" = "xyes")
+
# i18N stuff
GETTEXT_PACKAGE=gtksourceview-2.0
AC_SUBST(GETTEXT_PACKAGE)
@@ -107,6 +115,8 @@ Makefile
gtksourceview-zip
po/Makefile.in
gtksourceview/Makefile
+gtksourceview/completion-providers/Makefile
+gtksourceview/completion-providers/words/Makefile
gtksourceview/language-specs/Makefile
docs/Makefile
docs/reference/Makefile
diff --git a/gtksourceview/Makefile.am b/gtksourceview/Makefile.am
index 76f4c7d..0a02ec4 100644
--- a/gtksourceview/Makefile.am
+++ b/gtksourceview/Makefile.am
@@ -1,5 +1,9 @@
SUBDIRS = language-specs
+if ENABLE_PROVIDERS
+SUBDIRS += completion-providers
+endif
+
INCLUDES = \
-DDATADIR=\""$(datadir)"\" \
-DG_LOG_DOMAIN=\"GtkSourceView\"\
@@ -85,7 +89,10 @@ libgtksourceview_2_0_la_SOURCES = \
nodist_libgtksourceview_2_0_la_SOURCES =\
$(BUILT_SOURCES)
-libgtksourceview_2_0_la_LIBADD = $(DEP_LIBS)
+completion_providers = \
+ completion-providers/words/libgtksourcecompletionwords.la
+
+libgtksourceview_2_0_la_LIBADD = $(DEP_LIBS) $(completion_providers)
libgtksourceview_2_0_la_LDFLAGS = -no-undefined -export-symbols-regex "^gtk_source_.*"
libgtksourceview_2_0_includedir = $(includedir)/gtksourceview-2.0/gtksourceview
diff --git a/gtksourceview/completion-providers/Makefile.am b/gtksourceview/completion-providers/Makefile.am
new file mode 100644
index 0000000..de2a31a
--- /dev/null
+++ b/gtksourceview/completion-providers/Makefile.am
@@ -0,0 +1 @@
+SUBDIRS = words
diff --git a/gtksourceview/completion-providers/words/Makefile.am b/gtksourceview/completion-providers/words/Makefile.am
new file mode 100644
index 0000000..bd4b286
--- /dev/null
+++ b/gtksourceview/completion-providers/words/Makefile.am
@@ -0,0 +1,33 @@
+INCLUDES = \
+ -DDATADIR=\""$(datadir)"\" \
+ -DG_LOG_DOMAIN=\"GtkSourceView\"\
+ -I$(top_srcdir) -I$(srcdir) \
+ $(DISABLE_DEPRECATED_CFLAGS) \
+ $(WARN_CFLAGS) \
+ $(DEP_CFLAGS)
+
+noinst_LTLIBRARIES = libgtksourcecompletionwords.la
+
+NOINST_H_FILES = \
+ gtksourcecompletionwordslibrary.h \
+ gtksourcecompletionwordsproposal.h \
+ gtksourcecompletionwordsbuffer.h
+
+libgtksourcecompletionwords_headers = \
+ gtksourcecompletionwords.h
+
+libgtksourcecompletionwords_la_SOURCES = \
+ gtksourcecompletionwords.c \
+ gtksourcecompletionwordslibrary.c \
+ gtksourcecompletionwordsproposal.c \
+ gtksourcecompletionwordsbuffer.c \
+ $(libgtksourcecompletionwords_headers) \
+ $(NOINST_H_FILES)
+
+libgtksourcecompletionwords_includedir = \
+ $(includedir)/gtksourceview-2.0/gtksourceview/completion-providers/words
+
+libgtksourcecompletionwords_include_HEADERS = \
+ $(libgtksourcecompletionwords_headers)
+
+-include $(top_srcdir)/git.mk
diff --git a/gtksourceview/completion-providers/words/gtksourcecompletionwords.c b/gtksourceview/completion-providers/words/gtksourcecompletionwords.c
new file mode 100644
index 0000000..9f16ee1
--- /dev/null
+++ b/gtksourceview/completion-providers/words/gtksourcecompletionwords.c
@@ -0,0 +1,506 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; coding: utf-8 -*-
+ * gtksourcecompletionproviderwords.c
+ * This file is part of gtksourceview
+ *
+ * Copyright (C) 2009 - Jesse van den Kieboom
+ *
+ * gtksourceview is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with gtksourceview; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ */
+
+#include "gtksourcecompletionwords.h"
+#include "gtksourcecompletionwordslibrary.h"
+#include "gtksourcecompletionwordsbuffer.h"
+
+#include <gtksourceview/gtksourcecompletion.h>
+#include <gtksourceview/gtksourceview-i18n.h>
+#include <string.h>
+
+#define GTK_SOURCE_COMPLETION_WORDS_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE((object), GSC_TYPE_PROVIDER_WORDS, GtkSourceCompletionWordsPrivate))
+
+#define BUFFER_KEY "GtkSourceCompletionWordsBufferKey"
+
+enum
+{
+ PROP_0,
+
+ PROP_NAME,
+ PROP_ICON,
+ PROP_PROPOSALS_BATCH_SIZE,
+ PROP_SCAN_BATCH_SIZE
+};
+
+struct _GtkSourceCompletionWordsPrivate
+{
+ gchar *name;
+ GdkPixbuf *icon;
+
+ gchar *word;
+ gint word_len;
+ guint idle_id;
+
+ GtkSourceCompletionContext *context;
+ GSequenceIter *populate_iter;
+
+ guint cancel_id;
+
+ guint proposals_batch_size;
+ guint scan_batch_size;
+
+ GtkSourceCompletionWordsLibrary *library;
+ GList *buffers;
+};
+
+typedef struct
+{
+ GObjectClass parent_class;
+} GscProposalWordsClass;
+
+static void gtk_source_completion_words_iface_init (GtkSourceCompletionProviderIface *iface);
+
+GType gsc_proposal_words_get_type (void);
+
+G_DEFINE_TYPE_WITH_CODE (GtkSourceCompletionWords,
+ gtk_source_completion_words,
+ G_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE (GTK_TYPE_SOURCE_COMPLETION_PROVIDER,
+ gtk_source_completion_words_iface_init))
+
+static const gchar *
+gtk_source_completion_words_get_name (GtkSourceCompletionProvider *self)
+{
+ return GTK_SOURCE_COMPLETION_WORDS (self)->priv->name;
+}
+
+static GdkPixbuf *
+gtk_source_completion_words_get_icon (GtkSourceCompletionProvider *self)
+{
+ return GTK_SOURCE_COMPLETION_WORDS (self)->priv->icon;
+}
+
+static gboolean
+gtk_source_completion_words_match (GtkSourceCompletionProvider *provider,
+ GtkSourceCompletionContext *context)
+{
+ return TRUE;
+}
+
+static gboolean
+is_word_char (gunichar ch)
+{
+ return g_unichar_isprint (ch) &&
+ (g_unichar_isalnum (ch) || ch == g_utf8_get_char ("_"));
+}
+
+static void
+population_finished (GtkSourceCompletionWords *words)
+{
+ if (words->priv->idle_id != 0)
+ {
+ g_source_remove (words->priv->idle_id);
+ words->priv->idle_id = 0;
+ }
+
+ g_free (words->priv->word);
+ words->priv->word = NULL;
+
+ if (words->priv->context != NULL)
+ {
+ if (words->priv->cancel_id)
+ {
+ g_signal_handler_disconnect (words->priv->context,
+ words->priv->cancel_id);
+ words->priv->cancel_id = 0;
+ }
+
+ g_object_unref (words->priv->context);
+ words->priv->context = NULL;
+ }
+}
+
+static gchar *
+get_word_at_iter (GtkSourceCompletionWords *words,
+ GtkTextIter *iter)
+{
+ GtkTextIter start = *iter;
+ gint line = gtk_text_iter_get_line (iter);
+ gboolean went_back = TRUE;
+
+ if (!gtk_text_iter_backward_char (&start))
+ {
+ return NULL;
+ }
+
+ while (went_back &&
+ line == gtk_text_iter_get_line (&start) &&
+ is_word_char (gtk_text_iter_get_char (&start)))
+ {
+ went_back = gtk_text_iter_backward_char (&start);
+ }
+
+ if (went_back)
+ {
+ gtk_text_iter_forward_char (&start);
+ }
+
+ if (gtk_text_iter_equal (iter, &start))
+ {
+ return NULL;
+ }
+
+ return gtk_text_iter_get_text (&start, iter);
+}
+
+static gboolean
+add_in_idle (GtkSourceCompletionWords *words)
+{
+ guint idx = 0;
+ GList *ret = NULL;
+ gboolean finished;
+
+ /* Don't complete empty string (when word == NULL) */
+ if (words->priv->word == NULL)
+ {
+ gtk_source_completion_context_add_proposals (words->priv->context,
+ GTK_SOURCE_COMPLETION_PROVIDER (words),
+ NULL,
+ TRUE);
+ population_finished (words);
+ return FALSE;
+ }
+
+ if (words->priv->populate_iter == NULL)
+ {
+ words->priv->populate_iter =
+ gtk_source_completion_words_library_find_first (words->priv->library,
+ words->priv->word,
+ words->priv->word_len);
+ }
+
+ while (idx < words->priv->proposals_batch_size &&
+ words->priv->populate_iter)
+ {
+ GtkSourceCompletionWordsProposal *proposal =
+ gtk_source_completion_words_library_get_proposal (words->priv->populate_iter);
+
+ /* Only add non-exact matches */
+ if (strcmp (gtk_source_completion_words_proposal_get_word (proposal),
+ words->priv->word) != 0)
+ {
+ ret = g_list_prepend (ret, proposal);
+ }
+
+ words->priv->populate_iter =
+ gtk_source_completion_words_library_find_next (words->priv->populate_iter,
+ words->priv->word,
+ words->priv->word_len);
+ ++idx;
+ }
+
+ ret = g_list_reverse (ret);
+ finished = words->priv->populate_iter == NULL;
+
+ gtk_source_completion_context_add_proposals (words->priv->context,
+ GTK_SOURCE_COMPLETION_PROVIDER (words),
+ ret,
+ finished);
+
+ if (finished)
+ {
+ gtk_source_completion_words_library_unlock (words->priv->library);
+ population_finished (words);
+ }
+
+ return !finished;
+}
+
+static void
+gtk_source_completion_words_populate (GtkSourceCompletionProvider *provider,
+ GtkSourceCompletionContext *context)
+{
+ GtkSourceCompletionWords *words = GTK_SOURCE_COMPLETION_WORDS (provider);
+ GtkTextIter iter;
+ gchar *word;
+
+ gtk_source_completion_context_get_iter (context, &iter);
+
+ g_free (words->priv->word);
+ word = get_word_at_iter (words, &iter);
+
+ if (word == NULL)
+ {
+ gtk_source_completion_context_add_proposals (context,
+ provider,
+ NULL,
+ TRUE);
+ return;
+ }
+
+ words->priv->cancel_id =
+ g_signal_connect_swapped (context,
+ "cancelled",
+ G_CALLBACK (population_finished),
+ provider);
+
+ words->priv->context = g_object_ref (context);
+
+ words->priv->word = word;
+ words->priv->word_len = strlen (word);
+
+ /* Do first right now */
+ if (add_in_idle (words))
+ {
+ gtk_source_completion_words_library_lock (words->priv->library);
+ words->priv->idle_id = g_idle_add ((GSourceFunc)add_in_idle,
+ words);
+ }
+}
+
+static void
+remove_buffer (GtkSourceCompletionWordsBuffer *buffer)
+{
+ g_object_set_data (G_OBJECT (gtk_source_completion_words_buffer_get_buffer (buffer)),
+ BUFFER_KEY,
+ NULL);
+
+ g_object_unref (buffer);
+}
+
+static void
+gtk_source_completion_words_dispose (GObject *object)
+{
+ GtkSourceCompletionWords *provider = GTK_SOURCE_COMPLETION_WORDS (object);
+ population_finished (provider);
+
+ g_list_foreach (provider->priv->buffers, (GFunc)remove_buffer, NULL);
+ g_list_free (provider->priv->buffers);
+
+ g_free (provider->priv->name);
+ provider->priv->name = NULL;
+
+ if (provider->priv->icon)
+ {
+ g_object_unref (provider->priv->icon);
+ provider->priv->icon = NULL;
+ }
+
+ if (provider->priv->library)
+ {
+ g_object_unref (provider->priv->library);
+ provider->priv->library = NULL;
+ }
+
+ G_OBJECT_CLASS (gtk_source_completion_words_parent_class)->dispose (object);
+}
+
+static void
+gtk_source_completion_words_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GtkSourceCompletionWords *self = GTK_SOURCE_COMPLETION_WORDS (object);
+
+ switch (prop_id)
+ {
+ case PROP_NAME:
+ g_free (self->priv->name);
+ self->priv->name = g_value_dup_string (value);
+
+ if (self->priv->name == NULL)
+ {
+ self->priv->name = g_strdup (_("Document Words"));
+ }
+ break;
+ case PROP_ICON:
+ if (self->priv->icon)
+ {
+ g_object_unref (self->priv->icon);
+ }
+
+ self->priv->icon = g_value_dup_object (value);
+ break;
+ case PROP_PROPOSALS_BATCH_SIZE:
+ self->priv->proposals_batch_size = g_value_get_uint (value);
+ break;
+ case PROP_SCAN_BATCH_SIZE:
+ self->priv->scan_batch_size = g_value_get_uint (value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gtk_source_completion_words_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GtkSourceCompletionWords *self = GTK_SOURCE_COMPLETION_WORDS (object);
+
+ switch (prop_id)
+ {
+ case PROP_NAME:
+ g_value_set_string (value, self->priv->name);
+ break;
+ case PROP_ICON:
+ g_value_set_object (value, self->priv->icon);
+ break;
+ case PROP_PROPOSALS_BATCH_SIZE:
+ g_value_set_uint (value, self->priv->proposals_batch_size);
+ break;
+ case PROP_SCAN_BATCH_SIZE:
+ g_value_set_uint (value, self->priv->scan_batch_size);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gtk_source_completion_words_class_init (GtkSourceCompletionWordsClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->dispose = gtk_source_completion_words_dispose;
+
+ object_class->set_property = gtk_source_completion_words_set_property;
+ object_class->get_property = gtk_source_completion_words_get_property;
+
+ g_object_class_install_property (object_class,
+ PROP_NAME,
+ g_param_spec_string ("name",
+ _("Name"),
+ _("The provider name"),
+ NULL,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+
+ g_object_class_install_property (object_class,
+ PROP_ICON,
+ g_param_spec_object ("icon",
+ _("Icon"),
+ _("The provider icon"),
+ GDK_TYPE_PIXBUF,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+
+ g_object_class_install_property (object_class,
+ PROP_PROPOSALS_BATCH_SIZE,
+ g_param_spec_uint ("proposals-batch-size",
+ _("Proposals Batch Size"),
+ _("Number of proposals added in one batch"),
+ 1,
+ G_MAXUINT,
+ 300,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+
+ g_object_class_install_property (object_class,
+ PROP_SCAN_BATCH_SIZE,
+ g_param_spec_uint ("scan-batch-size",
+ _("Scan Batch Size"),
+ _("Number of lines scanned in one batch"),
+ 1,
+ G_MAXUINT,
+ 20,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+
+ g_type_class_add_private (object_class, sizeof(GtkSourceCompletionWordsPrivate));
+}
+
+static gboolean
+gtk_source_completion_words_get_start_iter (GtkSourceCompletionProvider *provider,
+ GtkSourceCompletionProposal *proposal,
+ GtkTextIter *iter)
+{
+ //GtkSourceCompletionWords *words = GTK_SOURCE_COMPLETION_WORDS (provider);
+
+ /* TODO: implement */
+ return FALSE;
+}
+
+static void
+gtk_source_completion_words_iface_init (GtkSourceCompletionProviderIface *iface)
+{
+ iface->get_name = gtk_source_completion_words_get_name;
+ iface->get_icon = gtk_source_completion_words_get_icon;
+
+ iface->populate = gtk_source_completion_words_populate;
+ iface->match = gtk_source_completion_words_match;
+
+ iface->get_start_iter = gtk_source_completion_words_get_start_iter;
+}
+
+static void
+gtk_source_completion_words_init (GtkSourceCompletionWords *self)
+{
+ self->priv = GTK_SOURCE_COMPLETION_WORDS_GET_PRIVATE (self);
+
+ self->priv->library = gtk_source_completion_words_library_new ();
+}
+
+GtkSourceCompletionWords *
+gtk_source_completion_words_new (gchar const *name,
+ GdkPixbuf *icon)
+{
+ return g_object_new (GSC_TYPE_PROVIDER_WORDS,
+ "name", name,
+ "icon", icon,
+ NULL);
+}
+
+void
+gtk_source_completion_words_register (GtkSourceCompletionWords *words,
+ GtkTextBuffer *buffer)
+{
+ GtkSourceCompletionWordsBuffer *buf;
+
+ g_return_if_fail (GTK_IS_SOURCE_COMPLETION_WORDS (words));
+ g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
+
+ buf = g_object_get_data (G_OBJECT (buffer), BUFFER_KEY);
+
+ if (buf != NULL)
+ {
+ return;
+ }
+
+ buf = gtk_source_completion_words_buffer_new (words->priv->library,
+ buffer,
+ words->priv->scan_batch_size);
+
+ g_object_set_data (G_OBJECT (buf), BUFFER_KEY, buffer);
+ words->priv->buffers = g_list_prepend (words->priv->buffers, buf);
+}
+
+void
+gtk_source_completion_words_unregister (GtkSourceCompletionWords *words,
+ GtkTextBuffer *buffer)
+{
+ GtkSourceCompletionWordsBuffer *buf;
+
+ g_return_if_fail (GTK_IS_SOURCE_COMPLETION_WORDS (words));
+ g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
+
+ buf = g_object_get_data (G_OBJECT (buffer), BUFFER_KEY);
+
+ if (buf != NULL)
+ {
+ remove_buffer (buf);
+ words->priv->buffers = g_list_remove (words->priv->buffers, buf);
+ }
+}
+
diff --git a/gtksourceview/completion-providers/words/gtksourcecompletionwords.h b/gtksourceview/completion-providers/words/gtksourcecompletionwords.h
new file mode 100644
index 0000000..02de97a
--- /dev/null
+++ b/gtksourceview/completion-providers/words/gtksourcecompletionwords.h
@@ -0,0 +1,67 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; coding: utf-8 -*-
+ * gtksourcecompletionproviderwords.h
+ * This file is part of gtksourceview
+ *
+ * Copyright (C) 2009 - Jesse van den Kieboom
+ *
+ * gtksourceview is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with gtksourceview; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ */
+
+#ifndef __GTK_SOURCE_COMPLETION_WORDS_H__
+#define __GTK_SOURCE_COMPLETION_WORDS_H__
+
+#include <gtksourceview/gtksourcecompletionprovider.h>
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+#define GSC_TYPE_PROVIDER_WORDS (gtk_source_completion_words_get_type ())
+#define GTK_SOURCE_COMPLETION_WORDS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GSC_TYPE_PROVIDER_WORDS, GtkSourceCompletionWords))
+#define GTK_SOURCE_COMPLETION_WORDS_CONST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GSC_TYPE_PROVIDER_WORDS, GtkSourceCompletionWords const))
+#define GTK_SOURCE_COMPLETION_WORDS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GSC_TYPE_PROVIDER_WORDS, GtkSourceCompletionWordsClass))
+#define GTK_IS_SOURCE_COMPLETION_WORDS(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GSC_TYPE_PROVIDER_WORDS))
+#define GTK_IS_SOURCE_COMPLETION_WORDS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GSC_TYPE_PROVIDER_WORDS))
+#define GTK_SOURCE_COMPLETION_WORDS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GSC_TYPE_PROVIDER_WORDS, GtkSourceCompletionWordsClass))
+
+typedef struct _GtkSourceCompletionWords GtkSourceCompletionWords;
+typedef struct _GtkSourceCompletionWordsClass GtkSourceCompletionWordsClass;
+typedef struct _GtkSourceCompletionWordsPrivate GtkSourceCompletionWordsPrivate;
+
+struct _GtkSourceCompletionWords {
+ GObject parent;
+
+ GtkSourceCompletionWordsPrivate *priv;
+};
+
+struct _GtkSourceCompletionWordsClass {
+ GObjectClass parent_class;
+};
+
+GType gtk_source_completion_words_get_type (void) G_GNUC_CONST;
+
+GtkSourceCompletionWords *
+ gtk_source_completion_words_new (gchar const *name,
+ GdkPixbuf *icon);
+
+void gtk_source_completion_words_register (GtkSourceCompletionWords *words,
+ GtkTextBuffer *buffer);
+
+void gtk_source_completion_words_unregister (GtkSourceCompletionWords *words,
+ GtkTextBuffer *buffer);
+
+G_END_DECLS
+
+#endif /* __GTK_SOURCE_COMPLETION_WORDS_H__ */
diff --git a/gtksourceview/completion-providers/words/gtksourcecompletionwordsbuffer.c b/gtksourceview/completion-providers/words/gtksourcecompletionwordsbuffer.c
new file mode 100644
index 0000000..17ba908
--- /dev/null
+++ b/gtksourceview/completion-providers/words/gtksourcecompletionwordsbuffer.c
@@ -0,0 +1,701 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; coding: utf-8 -*-
+ * gtksourcecompletionwordsbuffer.c
+ * This file is part of gtksourceview
+ *
+ * Copyright (C) 2009 - Jesse van den Kieboom
+ *
+ * gtksourceview is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with gtksourceview; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ */
+
+#include "gtksourcecompletionwordsbuffer.h"
+
+#define GTK_SOURCE_COMPLETION_WORDS_BUFFER_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE((object), GTK_TYPE_SOURCE_COMPLETION_WORDS_BUFFER, GtkSourceCompletionWordsBufferPrivate))
+
+#define REGION_FROM_LIST(list) ((ScanRegion *)list->data)
+
+typedef struct
+{
+ guint start;
+ guint end;
+} ScanRegion;
+
+enum
+{
+ EXT_INSERT_TEXT,
+ EXT_INSERT_TEXT_AFTER,
+ EXT_DELETE_RANGE,
+ EXT_DELETE_RANGE_AFTER,
+ NUM_EXT_SIGNALS
+};
+
+struct _GtkSourceCompletionWordsBufferPrivate
+{
+ GtkSourceCompletionWordsLibrary *library;
+ GtkTextBuffer *buffer;
+
+ GList *lines;
+ gint current_insert_line;
+
+ GList *scan_regions;
+ guint idle_scan_id;
+
+ guint ext_signal_handlers[NUM_EXT_SIGNALS];
+ guint scan_batch_size;
+
+ guint lock_handler_id;
+ guint unlock_handler_id;
+};
+
+G_DEFINE_TYPE (GtkSourceCompletionWordsBuffer, gtk_source_completion_words_buffer, G_TYPE_OBJECT)
+
+static ScanRegion *
+scan_region_new (gint start,
+ gint end)
+{
+ ScanRegion *region = (ScanRegion *)g_slice_new (ScanRegion);
+
+ region->start = start;
+ region->end = end;
+
+ return region;
+}
+
+static void
+scan_region_free (ScanRegion *region)
+{
+ g_slice_free (ScanRegion, region);
+}
+
+static void
+remove_proposal (GtkSourceCompletionWordsProposal *proposal,
+ GtkSourceCompletionWordsBuffer *buffer)
+{
+ gtk_source_completion_words_library_remove_word (buffer->priv->library,
+ proposal);
+}
+
+static void
+remove_line (GList *line,
+ GtkSourceCompletionWordsBuffer *buffer)
+{
+ g_list_foreach (line, (GFunc)remove_proposal, buffer);
+ g_list_free (line);
+}
+
+static void
+gtk_source_completion_words_buffer_dispose (GObject *object)
+{
+ GtkSourceCompletionWordsBuffer *buffer =
+ GTK_SOURCE_COMPLETION_WORDS_BUFFER (object);
+
+ if (buffer->priv->library)
+ {
+ g_signal_handler_disconnect (buffer->priv->library,
+ buffer->priv->lock_handler_id);
+ g_signal_handler_disconnect (buffer->priv->library,
+ buffer->priv->unlock_handler_id);
+
+ g_object_unref (buffer->priv->library);
+ buffer->priv->library = NULL;
+ }
+
+ if (buffer->priv->buffer)
+ {
+ gint i;
+
+ for (i = 0; i < NUM_EXT_SIGNALS; ++i)
+ {
+ g_signal_handler_disconnect (buffer->priv->buffer,
+ buffer->priv->ext_signal_handlers[i]);
+ }
+
+ g_object_unref (buffer->priv->buffer);
+ buffer->priv->buffer = NULL;
+ }
+
+ if (buffer->priv->idle_scan_id)
+ {
+ g_source_remove (buffer->priv->idle_scan_id);
+ buffer->priv->idle_scan_id = 0;
+ }
+
+ g_list_foreach (buffer->priv->scan_regions, (GFunc)scan_region_free, NULL);
+ g_list_free (buffer->priv->scan_regions);
+
+ buffer->priv->scan_regions = NULL;
+
+ g_list_foreach (buffer->priv->lines, (GFunc)remove_line, buffer);
+ g_list_free (buffer->priv->lines);
+
+ buffer->priv->lines = NULL;
+
+ G_OBJECT_CLASS (gtk_source_completion_words_buffer_parent_class)->dispose (object);
+}
+
+static void
+gtk_source_completion_words_buffer_class_init (GtkSourceCompletionWordsBufferClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->dispose = gtk_source_completion_words_buffer_dispose;
+
+ g_type_class_add_private (object_class, sizeof(GtkSourceCompletionWordsBufferPrivate));
+}
+
+static void
+gtk_source_completion_words_buffer_init (GtkSourceCompletionWordsBuffer *self)
+{
+ self->priv = GTK_SOURCE_COMPLETION_WORDS_BUFFER_GET_PRIVATE (self);
+}
+
+static void
+on_insert_text_cb (GtkTextBuffer *textbuffer,
+ GtkTextIter *location,
+ gchar const *text,
+ gint len,
+ GtkSourceCompletionWordsBuffer *buffer)
+{
+ buffer->priv->current_insert_line = gtk_text_iter_get_line (location);
+}
+
+static gboolean
+is_word_char (gunichar ch)
+{
+ return g_unichar_isprint (ch) &&
+ (g_unichar_isalnum (ch) || ch == g_utf8_get_char ("_"));
+}
+
+static gboolean
+iter_at_word_start (GtkTextIter *iter)
+{
+ GtkTextIter prev = *iter;
+
+ if (!gtk_text_iter_starts_word (iter) ||
+ g_unichar_isdigit (gtk_text_iter_get_char (iter)))
+ {
+ return FALSE;
+ }
+
+ if (!gtk_text_iter_is_start (&prev) &&
+ !gtk_text_iter_starts_line (&prev))
+ {
+ gtk_text_iter_backward_char (&prev);
+
+ return !is_word_char (gtk_text_iter_get_char (&prev));
+ }
+ else
+ {
+ return TRUE;
+ }
+}
+
+static gboolean
+iter_at_word_end (GtkTextIter *iter)
+{
+ if (!gtk_text_iter_ends_word (iter) ||
+ g_unichar_isdigit (gtk_text_iter_get_char (iter)))
+ {
+ return FALSE;
+ }
+
+ if (!gtk_text_iter_is_end (iter) &&
+ !gtk_text_iter_ends_line (iter))
+ {
+ return !is_word_char (gtk_text_iter_get_char (iter));
+ }
+ else
+ {
+ return TRUE;
+ }
+}
+
+static GList *
+scan_line (GtkSourceCompletionWordsBuffer *buffer,
+ gint line)
+{
+ GtkTextIter start;
+ GtkTextIter end;
+ GList *ret = NULL;
+
+ gtk_text_buffer_get_iter_at_line (buffer->priv->buffer, &start, line);
+
+ while (gtk_text_iter_get_line (&start) == line)
+ {
+ gchar *word;
+
+ /* Forward start to next word start */
+ while (!iter_at_word_start (&start) &&
+ !gtk_text_iter_ends_line (&start))
+ {
+ if (!gtk_text_iter_forward_char (&start))
+ {
+ break;
+ }
+ }
+
+ if (gtk_text_iter_ends_line (&start))
+ {
+ break;
+ }
+
+ end = start;
+
+ if (!gtk_text_iter_forward_char (&end))
+ {
+ break;
+ }
+
+ /* Forward end to next word end */
+ while (!iter_at_word_end (&end))
+ {
+ if (!gtk_text_iter_forward_char (&end))
+ {
+ break;
+ }
+ }
+
+ if (gtk_text_iter_get_offset (&end) - gtk_text_iter_get_offset (&start) > 2)
+ {
+ GtkSourceCompletionWordsProposal *proposal;
+
+ word = gtk_text_iter_get_text (&start, &end);
+ proposal = gtk_source_completion_words_library_add_word (buffer->priv->library,
+ word);
+
+ if (proposal != NULL)
+ {
+ ret = g_list_prepend (ret, proposal);
+ g_free (word);
+ }
+ }
+
+ start = end;
+
+ if (!gtk_text_iter_forward_char (&start))
+ {
+ break;
+ }
+ }
+
+ return g_list_reverse (ret);
+}
+
+static gboolean
+idle_scan_regions (GtkSourceCompletionWordsBuffer *buffer)
+{
+ guint num = 0;
+ GList *ptr = buffer->priv->lines;
+ guint prev = 0;
+ gboolean finished;
+
+ /* Scan a few lines */
+ while (buffer->priv->scan_regions)
+ {
+ ScanRegion *region = REGION_FROM_LIST (buffer->priv->scan_regions);
+
+ gint span = (region->end - region->start) + 1;
+ gint doscan = MIN(buffer->priv->scan_batch_size - num, span);
+ gint i;
+
+ ptr = g_list_nth (ptr, region->start - prev);
+
+ for (i = 0; i < doscan; ++i)
+ {
+ /* First remove this line */
+ remove_line ((GList *)ptr->data, buffer);
+
+ /* Then scan it which adds words */
+ ptr->data = scan_line (buffer, region->start + i);
+
+ ptr = g_list_next (ptr);
+ }
+
+ prev = region->start + doscan;
+
+ if (doscan == span)
+ {
+ /* Simply remove the region */
+ scan_region_free (region);
+
+ buffer->priv->scan_regions =
+ g_list_delete_link (buffer->priv->scan_regions,
+ buffer->priv->scan_regions);
+ }
+ else
+ {
+ /* Update the region and break */
+ region->start = region->start + doscan;
+ break;
+ }
+
+ num += doscan;
+ }
+
+ finished = buffer->priv->scan_regions == NULL;
+
+ if (finished)
+ {
+ buffer->priv->idle_scan_id = 0;
+ }
+
+ return !finished;
+}
+
+static void
+remove_scan_regions (GtkSourceCompletionWordsBuffer *buffer,
+ gint start,
+ gint end)
+{
+ GList *item;
+ gint span = end - start + 1;
+
+ for (item = buffer->priv->scan_regions; item; item = g_list_next (item))
+ {
+ ScanRegion *region = REGION_FROM_LIST (item);
+
+ if (region->start >= start && region->end <= end)
+ {
+ GList *remove = item;
+ scan_region_free (region);
+
+ item = g_list_previous (item);
+
+ /* Remove whole thing */
+ buffer->priv->scan_regions =
+ g_list_delete_link (buffer->priv->scan_regions,
+ remove);
+ }
+ else if (region->start >= start)
+ {
+ /* Start in region */
+ region->end = start;
+ }
+ else if (region->end <= end)
+ {
+ /* End in region */
+ region->start = start;
+ region->end -= span;
+ }
+ else if (region->start > start)
+ {
+ region->start -= span;
+ region->end -= span;
+ }
+ }
+}
+
+static void
+remove_range (GtkSourceCompletionWordsBuffer *buffer,
+ gint start,
+ gint end)
+{
+ if (start > end)
+ {
+ return;
+ }
+
+ remove_scan_regions (buffer, start, end);
+
+ GList *line = g_list_nth (buffer->priv->lines, start);
+
+ while (start <= end && line)
+ {
+ GList *cur = line;
+
+ /* Remove proposals */
+ remove_line ((GList *)line->data, buffer);
+ line = g_list_next (cur);
+
+ buffer->priv->lines = g_list_delete_link (buffer->priv->lines,
+ cur);
+ ++start;
+ }
+}
+
+static void
+add_scan_region (GtkSourceCompletionWordsBuffer *buffer,
+ gint start,
+ gint end)
+{
+ GList *item;
+ GList *merge_start = NULL;
+ gint line_count = gtk_text_buffer_get_line_count (buffer->priv->buffer);
+
+ if (end >= line_count)
+ {
+ end = line_count - 1;
+ }
+
+ if (start > end)
+ {
+ return;
+ }
+
+ for (item = buffer->priv->scan_regions; item; item = g_list_next (item))
+ {
+ ScanRegion *region = (ScanRegion *)item->data;
+
+ if (merge_start != NULL)
+ {
+ if (end < region->start)
+ {
+ break;
+ }
+ }
+ else if (start >= region->start)
+ {
+ merge_start = item;
+ }
+ }
+
+ if (merge_start == NULL)
+ {
+ /* Simply prepend */
+ buffer->priv->scan_regions =
+ g_list_prepend (buffer->priv->scan_regions,
+ scan_region_new (start, end));
+ }
+ else
+ {
+ GList *insert_at;
+
+ if (end < REGION_FROM_LIST (merge_start)->start)
+ {
+ /* In this case, merge from next(merge_start) to item */
+ merge_start = g_list_next (merge_start);
+ }
+
+ insert_at = g_list_previous (merge_start);
+
+ start = MIN(start, REGION_FROM_LIST (merge_start)->start);
+
+ if (item)
+ {
+ end = MIN(end, REGION_FROM_LIST (item)->end);
+ }
+
+ while (merge_start != item)
+ {
+ GList *tmp = merge_start;
+
+ merge_start = g_list_next (merge_start);
+ scan_region_free (REGION_FROM_LIST (tmp));
+
+ buffer->priv->scan_regions =
+ g_list_delete_link (buffer->priv->scan_regions,
+ tmp);
+ }
+
+ /* Insert new region */
+ insert_at = g_list_next (insert_at);
+
+ if (insert_at != NULL)
+ {
+ buffer->priv->scan_regions =
+ g_list_insert_before (buffer->priv->scan_regions,
+ insert_at,
+ scan_region_new (start, end));
+ }
+ else
+ {
+ buffer->priv->scan_regions =
+ g_list_append (buffer->priv->scan_regions,
+ scan_region_new (start, end));
+ }
+ }
+
+ if (buffer->priv->idle_scan_id == 0 &&
+ !gtk_source_completion_words_library_is_locked (buffer->priv->library))
+ {
+ buffer->priv->idle_scan_id =
+ g_idle_add ((GSourceFunc)idle_scan_regions,
+ buffer);
+ }
+}
+
+static void
+handle_text_inserted (GtkSourceCompletionWordsBuffer *buffer,
+ gint start,
+ gint end)
+{
+ gint pos = start;
+ GList *ptr = NULL;
+
+ if (start > end)
+ {
+ ptr = g_list_nth (buffer->priv->lines,
+ start + 1);
+ }
+
+ while (pos < end)
+ {
+ /* Insert new empty lines */
+ if (ptr == NULL)
+ {
+ buffer->priv->lines =
+ g_list_append (buffer->priv->lines,
+ NULL);
+ }
+ else
+ {
+ buffer->priv->lines =
+ g_list_insert_before (buffer->priv->lines,
+ ptr,
+ NULL);
+ }
+
+ ++pos;
+ }
+
+ /* Invalidate new region */
+ add_scan_region (buffer,
+ start,
+ end);
+}
+
+static void
+on_insert_text_after_cb (GtkTextBuffer *text_buffer,
+ GtkTextIter *location,
+ gchar const *text,
+ gint len,
+ GtkSourceCompletionWordsBuffer *buffer)
+{
+ handle_text_inserted (buffer,
+ buffer->priv->current_insert_line,
+ gtk_text_iter_get_line (location));
+}
+
+static void
+on_delete_range_cb (GtkTextBuffer *text_buffer,
+ GtkTextIter *start,
+ GtkTextIter *end,
+ GtkSourceCompletionWordsBuffer *buffer)
+{
+ gint start_line = gtk_text_iter_get_line (start);
+ gint end_line = gtk_text_iter_get_line (end);
+
+ /* Simply remove everything from lines start + 1 to end */
+ remove_range (buffer, start_line + 1, end_line);
+}
+
+static void
+on_delete_range_after_cb (GtkTextBuffer *text_buffer,
+ GtkTextIter *start,
+ GtkTextIter *end,
+ GtkSourceCompletionWordsBuffer *buffer)
+{
+ gint start_line = gtk_text_iter_get_line (start);
+
+ /* Add start line to scan regions */
+ add_scan_region (buffer, start_line, start_line);
+}
+
+static void
+connect_buffer (GtkSourceCompletionWordsBuffer *buffer)
+{
+ buffer->priv->ext_signal_handlers[EXT_INSERT_TEXT] =
+ g_signal_connect (buffer->priv->buffer,
+ "insert-text",
+ G_CALLBACK (on_insert_text_cb),
+ buffer);
+
+ buffer->priv->ext_signal_handlers[EXT_INSERT_TEXT_AFTER] =
+ g_signal_connect_after (buffer->priv->buffer,
+ "insert-text",
+ G_CALLBACK (on_insert_text_after_cb),
+ buffer);
+
+ buffer->priv->ext_signal_handlers[EXT_DELETE_RANGE] =
+ g_signal_connect (buffer->priv->buffer,
+ "delete-range",
+ G_CALLBACK (on_delete_range_cb),
+ buffer);
+
+ buffer->priv->ext_signal_handlers[EXT_DELETE_RANGE_AFTER] =
+ g_signal_connect_after (buffer->priv->buffer,
+ "delete-range",
+ G_CALLBACK (on_delete_range_after_cb),
+ buffer);
+
+ /* Start initial scan */
+ handle_text_inserted (buffer,
+ 0,
+ gtk_text_buffer_get_line_count (buffer->priv->buffer));
+}
+
+static void
+on_library_lock (GtkSourceCompletionWordsBuffer *buffer)
+{
+ if (buffer->priv->idle_scan_id != 0)
+ {
+ g_source_remove (buffer->priv->idle_scan_id);
+ buffer->priv->idle_scan_id = 0;
+ }
+}
+
+static void
+on_library_unlock (GtkSourceCompletionWordsBuffer *buffer)
+{
+ if (buffer->priv->idle_scan_id == 0 &&
+ buffer->priv->scan_regions != NULL)
+ {
+ buffer->priv->idle_scan_id =
+ g_idle_add ((GSourceFunc)idle_scan_regions,
+ buffer);
+ }
+}
+
+GtkSourceCompletionWordsBuffer *
+gtk_source_completion_words_buffer_new (GtkSourceCompletionWordsLibrary *library,
+ GtkTextBuffer *buffer,
+ guint scan_batch_size)
+{
+ GtkSourceCompletionWordsBuffer *ret;
+
+ g_return_val_if_fail (GTK_IS_SOURCE_COMPLETION_WORDS_LIBRARY (library), NULL);
+ g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), NULL);
+ g_return_val_if_fail (scan_batch_size > 0, NULL);
+
+ ret = g_object_new (GTK_TYPE_SOURCE_COMPLETION_WORDS_BUFFER, NULL);
+
+ ret->priv->library = g_object_ref (library);
+ ret->priv->buffer = g_object_ref (buffer);
+ ret->priv->scan_batch_size = scan_batch_size;
+
+ ret->priv->lock_handler_id =
+ g_signal_connect_swapped (ret->priv->library,
+ "lock",
+ G_CALLBACK (on_library_lock),
+ ret);
+
+ ret->priv->unlock_handler_id =
+ g_signal_connect_swapped (ret->priv->library,
+ "unlock",
+ G_CALLBACK (on_library_unlock),
+ ret);
+
+ connect_buffer (ret);
+
+ return ret;
+}
+
+GtkTextBuffer *
+gtk_source_completion_words_buffer_get_buffer (GtkSourceCompletionWordsBuffer *buffer)
+{
+ g_return_val_if_fail (GTK_IS_SOURCE_COMPLETION_WORDS_BUFFER (buffer), NULL);
+
+ return buffer->priv->buffer;
+}
diff --git a/gtksourceview/completion-providers/words/gtksourcecompletionwordsbuffer.h b/gtksourceview/completion-providers/words/gtksourcecompletionwordsbuffer.h
new file mode 100644
index 0000000..775fd0b
--- /dev/null
+++ b/gtksourceview/completion-providers/words/gtksourcecompletionwordsbuffer.h
@@ -0,0 +1,66 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; coding: utf-8 -*-
+ * gtksourcecompletionwordsbuffer.h
+ * This file is part of gtksourceview
+ *
+ * Copyright (C) 2009 - Jesse van den Kieboom
+ *
+ * gtksourceview is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with gtksourceview; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ */
+
+#ifndef __GTK_SOURCE_COMPLETION_WORDS_BUFFER_H__
+#define __GTK_SOURCE_COMPLETION_WORDS_BUFFER_H__
+
+#include <glib-object.h>
+#include <gtk/gtk.h>
+
+#include "gtksourcecompletionwordslibrary.h"
+
+G_BEGIN_DECLS
+
+#define GTK_TYPE_SOURCE_COMPLETION_WORDS_BUFFER (gtk_source_completion_words_buffer_get_type ())
+#define GTK_SOURCE_COMPLETION_WORDS_BUFFER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_SOURCE_COMPLETION_WORDS_BUFFER, GtkSourceCompletionWordsBuffer))
+#define GTK_SOURCE_COMPLETION_WORDS_BUFFER_CONST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_SOURCE_COMPLETION_WORDS_BUFFER, GtkSourceCompletionWordsBuffer const))
+#define GTK_SOURCE_COMPLETION_WORDS_BUFFER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_SOURCE_COMPLETION_WORDS_BUFFER, GtkSourceCompletionWordsBufferClass))
+#define GTK_IS_SOURCE_COMPLETION_WORDS_BUFFER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_SOURCE_COMPLETION_WORDS_BUFFER))
+#define GTK_IS_SOURCE_COMPLETION_WORDS_BUFFER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_SOURCE_COMPLETION_WORDS_BUFFER))
+#define GTK_SOURCE_COMPLETION_WORDS_BUFFER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_SOURCE_COMPLETION_WORDS_BUFFER, GtkSourceCompletionWordsBufferClass))
+
+typedef struct _GtkSourceCompletionWordsBuffer GtkSourceCompletionWordsBuffer;
+typedef struct _GtkSourceCompletionWordsBufferClass GtkSourceCompletionWordsBufferClass;
+typedef struct _GtkSourceCompletionWordsBufferPrivate GtkSourceCompletionWordsBufferPrivate;
+
+struct _GtkSourceCompletionWordsBuffer {
+ GObject parent;
+
+ GtkSourceCompletionWordsBufferPrivate *priv;
+};
+
+struct _GtkSourceCompletionWordsBufferClass {
+ GObjectClass parent_class;
+};
+
+GType gtk_source_completion_words_buffer_get_type (void) G_GNUC_CONST;
+
+GtkSourceCompletionWordsBuffer *
+ gtk_source_completion_words_buffer_new (GtkSourceCompletionWordsLibrary *library,
+ GtkTextBuffer *buffer,
+ guint process_batch);
+
+GtkTextBuffer *gtk_source_completion_words_buffer_get_buffer (GtkSourceCompletionWordsBuffer *buffer);
+
+G_END_DECLS
+
+#endif /* __GTK_SOURCE_COMPLETION_WORDS_BUFFER_H__ */
diff --git a/gtksourceview/completion-providers/words/gtksourcecompletionwordslibrary.c b/gtksourceview/completion-providers/words/gtksourcecompletionwordslibrary.c
new file mode 100644
index 0000000..458c04e
--- /dev/null
+++ b/gtksourceview/completion-providers/words/gtksourcecompletionwordslibrary.c
@@ -0,0 +1,352 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; coding: utf-8 -*-
+ * gtksourcecompletionwordslibrary.c
+ * This file is part of gtksourceview
+ *
+ * Copyright (C) 2009 - Jesse van den Kieboom
+ *
+ * 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 "gtksourcecompletionwordslibrary.h"
+
+#include <string.h>
+
+#define GTK_SOURCE_COMPLETION_WORDS_LIBRARY_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE((object), GTK_TYPE_SOURCE_COMPLETION_WORDS_LIBRARY, GtkSourceCompletionWordsLibraryPrivate))
+
+enum
+{
+ LOCK,
+ UNLOCK,
+ NUM_SIGNALS
+};
+
+struct _GtkSourceCompletionWordsLibraryPrivate
+{
+ GSequence *store;
+ gboolean locked;
+};
+
+static guint signals[NUM_SIGNALS] = {0,};
+
+G_DEFINE_TYPE (GtkSourceCompletionWordsLibrary, gtk_source_completion_words_library, G_TYPE_OBJECT)
+
+static void
+gtk_source_completion_words_library_finalize (GObject *object)
+{
+ G_OBJECT_CLASS (gtk_source_completion_words_library_parent_class)->finalize (object);
+}
+
+static void
+gtk_source_completion_words_library_class_init (GtkSourceCompletionWordsLibraryClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->finalize = gtk_source_completion_words_library_finalize;
+
+ signals[LOCK] =
+ g_signal_new ("lock",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ 0,
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE,
+ 0);
+
+ signals[UNLOCK] =
+ g_signal_new ("unlock",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ 0,
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE,
+ 0);
+
+ g_type_class_add_private (object_class, sizeof(GtkSourceCompletionWordsLibraryPrivate));
+}
+
+static void
+gtk_source_completion_words_library_init (GtkSourceCompletionWordsLibrary *self)
+{
+ self->priv = GTK_SOURCE_COMPLETION_WORDS_LIBRARY_GET_PRIVATE (self);
+
+ self->priv->store = g_sequence_new ((GDestroyNotify)g_object_unref);
+}
+
+GtkSourceCompletionWordsLibrary *
+gtk_source_completion_words_library_new (void)
+{
+ return g_object_new (GTK_TYPE_SOURCE_COMPLETION_WORDS_LIBRARY, NULL);
+}
+
+static gint
+compare_two_items (GtkSourceCompletionWordsProposal *a,
+ GtkSourceCompletionWordsProposal *b,
+ gpointer data)
+{
+ return strcmp (gtk_source_completion_words_proposal_get_word (a),
+ gtk_source_completion_words_proposal_get_word (b));
+}
+
+static gint
+compare_items (GtkSourceCompletionWordsProposal *a,
+ GtkSourceCompletionWordsProposal *b,
+ gchar const *word)
+{
+ gchar const *m1 =
+ gtk_source_completion_words_proposal_get_word (a == NULL ? b : a);
+
+ return strcmp (m1, word);
+}
+
+static gboolean
+iter_match_prefix (GSequenceIter *iter,
+ gchar const *word,
+ gint len)
+{
+ GtkSourceCompletionWordsProposal *item;
+
+ item = gtk_source_completion_words_library_get_proposal (iter);
+
+ return strncmp (gtk_source_completion_words_proposal_get_word (item),
+ word,
+ len != -1 ? len : strlen (word)) == 0;
+}
+
+GtkSourceCompletionWordsProposal *
+gtk_source_completion_words_library_get_proposal (GSequenceIter *iter)
+{
+ if (iter == NULL)
+ {
+ return NULL;
+ }
+
+ return GTK_SOURCE_COMPLETION_WORDS_PROPOSAL (g_sequence_get (iter));
+}
+
+GSequenceIter *
+gtk_source_completion_words_library_find_first (GtkSourceCompletionWordsLibrary *library,
+ gchar const *word,
+ gint len)
+{
+ GSequenceIter *iter;
+ GSequenceIter *prev;
+
+ g_return_val_if_fail (GTK_IS_SOURCE_COMPLETION_WORDS_LIBRARY (library), NULL);
+ g_return_val_if_fail (word != NULL, NULL);
+
+ iter = g_sequence_search (library->priv->store,
+ NULL,
+ (GCompareDataFunc)compare_items,
+ (gpointer)word);
+
+ if (iter == NULL)
+ {
+ return NULL;
+ }
+
+ if (len == -1)
+ {
+ len = strlen (word);
+ }
+
+ /* Test if this position might be after the last match */
+ if (!g_sequence_iter_is_begin (iter) &&
+ (g_sequence_iter_is_end (iter) ||
+ !iter_match_prefix (iter, word, len)))
+ {
+ iter = g_sequence_iter_prev (iter);
+
+ /* Maybe there is actually nothing in the sequence */
+ if (g_sequence_iter_is_end (iter) ||
+ !iter_match_prefix (iter, word, len))
+ {
+ return NULL;
+ }
+ }
+
+ if (g_sequence_iter_is_end (iter))
+ {
+ return NULL;
+ }
+
+ /* Go back while it matches */
+ while (iter &&
+ (prev = g_sequence_iter_prev (iter)) &&
+ iter_match_prefix (prev, word, len))
+ {
+ iter = prev;
+
+ if (g_sequence_iter_is_begin (iter))
+ {
+ break;
+ }
+ }
+
+ return iter;
+}
+
+GSequenceIter *
+gtk_source_completion_words_library_find_next (GSequenceIter *iter,
+ gchar const *word,
+ gint len)
+{
+ g_return_val_if_fail (iter != NULL, NULL);
+ g_return_val_if_fail (word != NULL, NULL);
+
+ iter = g_sequence_iter_next (iter);
+
+ if (!iter || g_sequence_iter_is_end (iter))
+ {
+ return NULL;
+ }
+
+ return iter_match_prefix (iter, word, len) ? iter : NULL;
+}
+
+GSequenceIter *
+gtk_source_completion_words_library_find (GtkSourceCompletionWordsLibrary *library,
+ GtkSourceCompletionWordsProposal *proposal)
+{
+ GSequenceIter *iter;
+ GtkSourceCompletionWordsProposal *other;
+ gchar const *word = gtk_source_completion_words_proposal_get_word (proposal);
+ gint len = strlen (word);
+
+ g_return_val_if_fail (GTK_IS_SOURCE_COMPLETION_WORDS_LIBRARY (library), NULL);
+ g_return_val_if_fail (GTK_IS_SOURCE_COMPLETION_WORDS_PROPOSAL (proposal), NULL);
+
+ iter = gtk_source_completion_words_library_find_first (library, word, len);
+
+ if (!iter)
+ {
+ return NULL;
+ }
+
+ do
+ {
+ other = gtk_source_completion_words_library_get_proposal (iter);
+
+ if (proposal == other)
+ {
+ return iter;
+ }
+
+ iter = g_sequence_iter_next (iter);
+ } while (!g_sequence_iter_is_end (iter) &&
+ strcmp (gtk_source_completion_words_proposal_get_word (other),
+ word) == 0);
+
+ return NULL;
+}
+
+static void
+on_proposal_unused (GtkSourceCompletionWordsProposal *proposal,
+ GtkSourceCompletionWordsLibrary *library)
+{
+ GSequenceIter *iter = gtk_source_completion_words_library_find (library,
+ proposal);
+
+ if (iter != NULL)
+ {
+ g_sequence_remove (iter);
+ }
+}
+
+GtkSourceCompletionWordsProposal *
+gtk_source_completion_words_library_add_word (GtkSourceCompletionWordsLibrary *library,
+ gchar const *word)
+{
+ GtkSourceCompletionWordsProposal *proposal;
+ GSequenceIter *iter;
+
+ g_return_val_if_fail (GTK_IS_SOURCE_COMPLETION_WORDS_LIBRARY (library), NULL);
+ g_return_val_if_fail (word != NULL, NULL);
+
+ /* Check if word already exists */
+ iter = gtk_source_completion_words_library_find_first (library, word, -1);
+
+ if (iter)
+ {
+ proposal = gtk_source_completion_words_library_get_proposal (iter);
+
+ if (strcmp (gtk_source_completion_words_proposal_get_word (proposal),
+ word) == 0)
+ {
+ /* Already exists, increase the use count */
+ gtk_source_completion_words_proposal_use (proposal);
+ return proposal;
+ }
+ }
+
+ if (library->priv->locked)
+ {
+ return NULL;
+ }
+
+ proposal = gtk_source_completion_words_proposal_new (word);
+
+ g_signal_connect (proposal,
+ "unused",
+ G_CALLBACK (on_proposal_unused),
+ library);
+
+ /* Insert proposal into binary tree of words */
+ g_sequence_insert_sorted (library->priv->store,
+ proposal,
+ (GCompareDataFunc)compare_two_items,
+ NULL);
+
+ return proposal;
+}
+
+void
+gtk_source_completion_words_library_remove_word (GtkSourceCompletionWordsLibrary *library,
+ GtkSourceCompletionWordsProposal *proposal)
+{
+ g_return_if_fail (GTK_IS_SOURCE_COMPLETION_WORDS_LIBRARY (library));
+ g_return_if_fail (GTK_IS_SOURCE_COMPLETION_WORDS_PROPOSAL (proposal));
+
+ gtk_source_completion_words_proposal_unuse (proposal);
+}
+
+void
+gtk_source_completion_words_library_lock (GtkSourceCompletionWordsLibrary *library)
+{
+ g_return_if_fail (GTK_IS_SOURCE_COMPLETION_WORDS_LIBRARY (library));
+
+ library->priv->locked = TRUE;
+ g_signal_emit (library, signals[LOCK], 0);
+}
+
+void
+gtk_source_completion_words_library_unlock (GtkSourceCompletionWordsLibrary *library)
+{
+ g_return_if_fail (GTK_IS_SOURCE_COMPLETION_WORDS_LIBRARY (library));
+
+ library->priv->locked = FALSE;
+ g_signal_emit (library, signals[UNLOCK], 0);
+}
+
+gboolean
+gtk_source_completion_words_library_is_locked (GtkSourceCompletionWordsLibrary *library)
+{
+ g_return_val_if_fail (GTK_IS_SOURCE_COMPLETION_WORDS_LIBRARY (library), TRUE);
+
+ return library->priv->locked;
+}
diff --git a/gtksourceview/completion-providers/words/gtksourcecompletionwordslibrary.h b/gtksourceview/completion-providers/words/gtksourcecompletionwordslibrary.h
new file mode 100644
index 0000000..544f377
--- /dev/null
+++ b/gtksourceview/completion-providers/words/gtksourcecompletionwordslibrary.h
@@ -0,0 +1,86 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; coding: utf-8 -*-
+ * gtksourcecompletionwordslibrary.h
+ * This file is part of gtksourceview
+ *
+ * Copyright (C) 2009 - Jesse van den Kieboom
+ *
+ * gtksourceview is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with gtksourceview; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ */
+
+#ifndef __GTK_SOURCE_COMPLETION_WORDS_LIBRARY_H__
+#define __GTK_SOURCE_COMPLETION_WORDS_LIBRARY_H__
+
+#include <glib-object.h>
+#include "gtksourcecompletionwordsproposal.h"
+
+G_BEGIN_DECLS
+
+#define GTK_TYPE_SOURCE_COMPLETION_WORDS_LIBRARY (gtk_source_completion_words_library_get_type ())
+#define GTK_SOURCE_COMPLETION_WORDS_LIBRARY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_SOURCE_COMPLETION_PROVIDER_WORDS_LIBRARY, GtkSourceCompletionWordsLibrary))
+#define GTK_SOURCE_COMPLETION_WORDS_LIBRARY_CONST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_SOURCE_COMPLETION_WORDS_LIBRARY, GtkSourceCompletionWordsLibrary const))
+#define GTK_SOURCE_COMPLETION_WORDS_LIBRARY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_SOURCE_COMPLETION_WORDS_LIBRARY, GtkSourceCompletionWordsLibraryClass))
+#define GTK_IS_SOURCE_COMPLETION_WORDS_LIBRARY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_SOURCE_COMPLETION_WORDS_LIBRARY))
+#define GTK_IS_SOURCE_COMPLETION_WORDS_LIBRARY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_SOURCE_COMPLETION_WORDS_LIBRARY))
+#define GTK_SOURCE_COMPLETION_WORDS_LIBRARY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_SOURCE_COMPLETION_WORDS_LIBRARY, GtkSourceCompletionWordsLibraryClass))
+
+typedef struct _GtkSourceCompletionWordsLibrary GtkSourceCompletionWordsLibrary;
+typedef struct _GtkSourceCompletionWordsLibraryClass GtkSourceCompletionWordsLibraryClass;
+typedef struct _GtkSourceCompletionWordsLibraryPrivate GtkSourceCompletionWordsLibraryPrivate;
+
+struct _GtkSourceCompletionWordsLibrary {
+ GObject parent;
+
+ GtkSourceCompletionWordsLibraryPrivate *priv;
+};
+
+struct _GtkSourceCompletionWordsLibraryClass {
+ GObjectClass parent_class;
+};
+
+GType gtk_source_completion_words_library_get_type (void) G_GNUC_CONST;
+
+GtkSourceCompletionWordsLibrary *
+ gtk_source_completion_words_library_new (void);
+
+/* Finding */
+GSequenceIter *gtk_source_completion_words_library_find (GtkSourceCompletionWordsLibrary *library,
+ GtkSourceCompletionWordsProposal *proposal);
+GSequenceIter *gtk_source_completion_words_library_find_first (GtkSourceCompletionWordsLibrary *library,
+ gchar const *word,
+ gint len);
+
+GSequenceIter *gtk_source_completion_words_library_find_next (GSequenceIter *iter,
+ gchar const *word,
+ gint len);
+
+/* Getting */
+GtkSourceCompletionWordsProposal *
+ gtk_source_completion_words_library_get_proposal (GSequenceIter *iter);
+
+/* Adding/removing */
+GtkSourceCompletionWordsProposal *
+ gtk_source_completion_words_library_add_word (GtkSourceCompletionWordsLibrary *library,
+ gchar const *word);
+void gtk_source_completion_words_library_remove_word (GtkSourceCompletionWordsLibrary *library,
+ GtkSourceCompletionWordsProposal *proposal);
+
+gboolean gtk_source_completion_words_library_is_locked (GtkSourceCompletionWordsLibrary *library);
+void gtk_source_completion_words_library_lock (GtkSourceCompletionWordsLibrary *library);
+void gtk_source_completion_words_library_unlock (GtkSourceCompletionWordsLibrary *library);
+
+G_END_DECLS
+
+#endif /* __GTK_SOURCE_COMPLETION_WORDS_LIBRARY_H__ */
diff --git a/gtksourceview/completion-providers/words/gtksourcecompletionwordsproposal.c b/gtksourceview/completion-providers/words/gtksourcecompletionwordsproposal.c
new file mode 100644
index 0000000..b2a2295
--- /dev/null
+++ b/gtksourceview/completion-providers/words/gtksourcecompletionwordsproposal.c
@@ -0,0 +1,141 @@
+/*
+ * gtksourcecompletionwordsproposal.c
+ * This file is part of gtksourceview
+ *
+ * Copyright (C) 2009 - Jesse van den Kieboom
+ *
+ * gtksourceview is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with gtksourceview; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ */
+
+#include "gtksourcecompletionwordsproposal.h"
+
+#define GTK_SOURCE_COMPLETION_WORDS_PROPOSAL_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE((object), GTK_TYPE_SOURCE_COMPLETION_WORDS_PROPOSAL, GtkSourceCompletionWordsProposalPrivate))
+
+struct _GtkSourceCompletionWordsProposalPrivate
+{
+ gchar *word;
+ gint use_count;
+};
+
+enum
+{
+ UNUSED,
+ NUM_SIGNALS
+};
+
+static guint signals[NUM_SIGNALS] = {0,};
+
+static void gtk_source_completion_proposal_iface_init (gpointer g_iface, gpointer iface_data);
+
+G_DEFINE_TYPE_WITH_CODE (GtkSourceCompletionWordsProposal,
+ gtk_source_completion_words_proposal,
+ G_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE (GTK_TYPE_SOURCE_COMPLETION_PROPOSAL,
+ gtk_source_completion_proposal_iface_init))
+
+static const gchar *
+gtk_source_completion_words_proposal_get_text (GtkSourceCompletionProposal *proposal)
+{
+ return GTK_SOURCE_COMPLETION_WORDS_PROPOSAL(proposal)->priv->word;
+}
+
+static void
+gtk_source_completion_proposal_iface_init (gpointer g_iface,
+ gpointer iface_data)
+{
+ GtkSourceCompletionProposalIface *iface = (GtkSourceCompletionProposalIface *)g_iface;
+
+ /* Interface data getter implementations */
+ iface->get_label = gtk_source_completion_words_proposal_get_text;
+ iface->get_text = gtk_source_completion_words_proposal_get_text;
+}
+
+static void
+gtk_source_completion_words_proposal_finalize (GObject *object)
+{
+ GtkSourceCompletionWordsProposal *proposal;
+
+ proposal = GTK_SOURCE_COMPLETION_WORDS_PROPOSAL (object);
+ g_free (proposal->priv->word);
+
+ G_OBJECT_CLASS (gtk_source_completion_words_proposal_parent_class)->finalize (object);
+}
+
+static void
+gtk_source_completion_words_proposal_class_init (GtkSourceCompletionWordsProposalClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->finalize = gtk_source_completion_words_proposal_finalize;
+
+ signals[UNUSED] =
+ g_signal_new ("unused",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ 0,
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE,
+ 0);
+
+ g_type_class_add_private (object_class, sizeof(GtkSourceCompletionWordsProposalPrivate));
+}
+
+static void
+gtk_source_completion_words_proposal_init (GtkSourceCompletionWordsProposal *self)
+{
+ self->priv = GTK_SOURCE_COMPLETION_WORDS_PROPOSAL_GET_PRIVATE (self);
+
+ self->priv->use_count = 1;
+}
+
+GtkSourceCompletionWordsProposal *
+gtk_source_completion_words_proposal_new (gchar const *word)
+{
+ GtkSourceCompletionWordsProposal *proposal =
+ g_object_new (GTK_TYPE_SOURCE_COMPLETION_WORDS_PROPOSAL, NULL);
+
+ proposal->priv->word = g_strdup (word);
+ return proposal;
+}
+
+void
+gtk_source_completion_words_proposal_use (GtkSourceCompletionWordsProposal *proposal)
+{
+ g_return_if_fail (GTK_IS_SOURCE_COMPLETION_WORDS_PROPOSAL (proposal));
+
+ g_atomic_int_inc (&proposal->priv->use_count);
+}
+
+void
+gtk_source_completion_words_proposal_unuse (GtkSourceCompletionWordsProposal *proposal)
+{
+ g_return_if_fail (GTK_IS_SOURCE_COMPLETION_WORDS_PROPOSAL (proposal));
+
+ if (g_atomic_int_dec_and_test (&proposal->priv->use_count))
+ {
+ g_signal_emit (proposal, signals[UNUSED], 0);
+ }
+}
+
+gchar const *
+gtk_source_completion_words_proposal_get_word (GtkSourceCompletionWordsProposal *proposal)
+{
+ g_return_val_if_fail (GTK_IS_SOURCE_COMPLETION_WORDS_PROPOSAL (proposal), NULL);
+ return proposal->priv->word;
+}
+
diff --git a/gtksourceview/completion-providers/words/gtksourcecompletionwordsproposal.h b/gtksourceview/completion-providers/words/gtksourcecompletionwordsproposal.h
new file mode 100644
index 0000000..807af09
--- /dev/null
+++ b/gtksourceview/completion-providers/words/gtksourcecompletionwordsproposal.h
@@ -0,0 +1,65 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; coding: utf-8 -*-
+ * gtksourcecompletionwordsproposal.h
+ * This file is part of gtksourceview
+ *
+ * Copyright (C) 2009 - Jesse van den Kieboom
+ *
+ * gtksourceview is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with gtksourceview; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ */
+
+#ifndef __GTK_SOURCE_COMPLETION_WORDS_PROPOSAL_H__
+#define __GTK_SOURCE_COMPLETION_WORDS_PROPOSAL_H__
+
+#include <glib-object.h>
+#include <gtksourceview/gtksourcecompletionproposal.h>
+
+G_BEGIN_DECLS
+
+#define GTK_TYPE_SOURCE_COMPLETION_WORDS_PROPOSAL (gtk_source_completion_words_proposal_get_type ())
+#define GTK_SOURCE_COMPLETION_WORDS_PROPOSAL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_SOURCE_COMPLETION_WORDS_PROPOSAL, GtkSourceCompletionWordsProposal))
+#define GTK_SOURCE_COMPLETION_WORDS_PROPOSAL_CONST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_SOURCE_COMPLETION_WORDS_PROPOSAL, GtkSourceCompletionWordsProposal const))
+#define GTK_SOURCE_COMPLETION_WORDS_PROPOSAL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_SOURCE_COMPLETION_WORDS_PROPOSAL, GtkSourceCompletionWordsProposalClass))
+#define GTK_IS_SOURCE_COMPLETION_WORDS_PROPOSAL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_SOURCE_COMPLETION_WORDS_PROPOSAL))
+#define GTK_IS_SOURCE_COMPLETION_WORDS_PROPOSAL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_SOURCE_COMPLETION_WORDS_PROPOSAL))
+#define GTK_SOURCE_COMPLETION_WORDS_PROPOSAL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_SOURCE_COMPLETION_WORDS_PROPOSAL, GtkSourceCompletionWordsProposalClass))
+
+typedef struct _GtkSourceCompletionWordsProposal GtkSourceCompletionWordsProposal;
+typedef struct _GtkSourceCompletionWordsProposalClass GtkSourceCompletionWordsProposalClass;
+typedef struct _GtkSourceCompletionWordsProposalPrivate GtkSourceCompletionWordsProposalPrivate;
+
+struct _GtkSourceCompletionWordsProposal {
+ GObject parent;
+
+ GtkSourceCompletionWordsProposalPrivate *priv;
+};
+
+struct _GtkSourceCompletionWordsProposalClass {
+ GObjectClass parent_class;
+};
+
+GType gtk_source_completion_words_proposal_get_type (void) G_GNUC_CONST;
+
+GtkSourceCompletionWordsProposal *
+ gtk_source_completion_words_proposal_new (gchar const *word);
+
+gchar const *gtk_source_completion_words_proposal_get_word (GtkSourceCompletionWordsProposal *proposal);
+
+void gtk_source_completion_words_proposal_use (GtkSourceCompletionWordsProposal *proposal);
+void gtk_source_completion_words_proposal_unuse (GtkSourceCompletionWordsProposal *proposal);
+
+G_END_DECLS
+
+#endif /* __GTK_SOURCE_COMPLETION_WORDS_PROPOSAL_H__ */
diff --git a/tests/Makefile.am b/tests/Makefile.am
index b688e53..63910bb 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -22,9 +22,7 @@ test_widget_LDADD = \
$(TESTS_LIBS)
test_completion_SOURCES = \
- completion-simple.c \
- gsc-provider-words.c \
- gsc-provider-words.h
+ completion-simple.c
test_completion_LDADD = \
$(top_builddir)/gtksourceview/libgtksourceview-2.0.la \
diff --git a/tests/completion-simple.c b/tests/completion-simple.c
index 2bc9826..46ab656 100644
--- a/tests/completion-simple.c
+++ b/tests/completion-simple.c
@@ -29,8 +29,7 @@
#include <gtksourceview/gtksourcecompletion.h>
#include <gtksourceview/gtksourcecompletioninfo.h>
#include <gtksourceview/gtksourcelanguagemanager.h>
-
-#include "gsc-provider-words.h"
+#include <gtksourceview/completion-providers/words/gtksourcecompletionwords.h>
#ifdef HAVE_DEVHELP
#include <devhelp/dh-base.h>
@@ -84,26 +83,6 @@ show_headers_toggled_cb (GtkToggleButton *button,
NULL);
}
-static gboolean
-key_press (GtkWidget *widget,
- GdkEventKey *event,
- gpointer user_data)
-{
- if (event->keyval == GDK_F8)
- {
- GtkSourceCompletionInfo *gsc_info;
-
- gsc_info = gtk_source_completion_get_info_window (comp);
-
- if (GTK_WIDGET_VISIBLE (GTK_WIDGET (gsc_info)))
- gtk_widget_hide (GTK_WIDGET (gsc_info));
- else
- gtk_widget_show (GTK_WIDGET (gsc_info));
- }
-
- return FALSE;
-}
-
static void
toggle_active_property (gpointer source,
gpointer dest,
@@ -155,9 +134,6 @@ create_window (void)
gtk_container_add (GTK_CONTAINER (window), vbox);
- g_signal_connect (view, "key-release-event",
- G_CALLBACK (key_press),
- NULL);
g_signal_connect (window, "destroy",
G_CALLBACK (destroy_cb),
NULL);
@@ -177,10 +153,13 @@ create_window (void)
static void
create_completion(void)
{
- GscProviderWords *prov_words;
+ GtkSourceCompletionWords *prov_words;
comp = gtk_source_view_get_completion (GTK_SOURCE_VIEW (view));
- prov_words = gsc_provider_words_new (GTK_SOURCE_VIEW (view));
+ prov_words = gtk_source_completion_words_new (NULL, NULL);
+
+ gtk_source_completion_words_register (prov_words,
+ gtk_text_view_get_buffer (GTK_TEXT_VIEW (view)));
gtk_source_completion_add_provider (comp,
GTK_SOURCE_COMPLETION_PROVIDER (prov_words),
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]