[gtk/wip/chergert/spellcheck: 27/40] spellcheck: stub out spellcheck API
- From: Christian Hergert <chergert src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk/wip/chergert/spellcheck: 27/40] spellcheck: stub out spellcheck API
- Date: Tue, 30 Mar 2021 20:08:06 +0000 (UTC)
commit 15abded486f05ecf3f90bd34b6a5e898b1358362
Author: Christian Hergert <chergert redhat com>
Date: Thu Mar 11 15:29:36 2021 -0800
spellcheck: stub out spellcheck API
config.h.meson | 3 +
gdk/gdkkeys.c | 2 +-
gdk/wayland/gdkkeys-wayland.c | 2 +
gtk/gtk.h | 1 +
gtk/gtkspellcheck.c | 463 ++++++++++++++++++++++++++++++++++++++++++
gtk/gtkspellcheck.h | 69 +++++++
gtk/gtkspellcheckprivate.h | 93 +++++++++
gtk/meson.build | 3 +
meson.build | 12 ++
meson_options.txt | 7 +
tests/meson.build | 1 +
tests/testspelling.c | 68 +++++++
12 files changed, 723 insertions(+), 1 deletion(-)
---
diff --git a/config.h.meson b/config.h.meson
index 549a677379..c490d4e25c 100644
--- a/config.h.meson
+++ b/config.h.meson
@@ -30,6 +30,9 @@
/* Define to 1 if you have the <dlfcn.h> header file. */
#mesondefine HAVE_DLFCN_H
+#
+/* define if we have enchant */
+#mesondefine HAVE_ENCHANT
/* Have the ffmpeg library */
#mesondefine HAVE_FFMPEG
diff --git a/gdk/gdkkeys.c b/gdk/gdkkeys.c
index 90f42c5472..7c86715089 100644
--- a/gdk/gdkkeys.c
+++ b/gdk/gdkkeys.c
@@ -587,7 +587,7 @@ gdk_keymap_lookup_key (GdkKeymap *keymap,
* (state & ~consumed & ALL_ACCELS_MASK) == GDK_CONTROL_MASK)
* // Control was pressed
* ]|
- *
+ *
* An older interpretation @consumed_modifiers was that it contained
* all modifiers that might affect the translation of the key;
* this allowed accelerators to be stored with irrelevant consumed
diff --git a/gdk/wayland/gdkkeys-wayland.c b/gdk/wayland/gdkkeys-wayland.c
index 38f346c75d..ac8e133756 100644
--- a/gdk/wayland/gdkkeys-wayland.c
+++ b/gdk/wayland/gdkkeys-wayland.c
@@ -53,6 +53,8 @@ struct _GdkWaylandKeymap
PangoDirection *direction;
gboolean bidi;
+
+ char **languages;
};
struct _GdkWaylandKeymapClass
diff --git a/gtk/gtk.h b/gtk/gtk.h
index d5f50a86b3..ddd63a7a23 100644
--- a/gtk/gtk.h
+++ b/gtk/gtk.h
@@ -236,6 +236,7 @@
#include <gtk/gtkstacksidebar.h>
#include <gtk/gtksizegroup.h>
#include <gtk/gtksizerequest.h>
+#include <gtk/gtkspellcheck.h>
#include <gtk/gtkspinbutton.h>
#include <gtk/gtkspinner.h>
#include <gtk/gtkstack.h>
diff --git a/gtk/gtkspellcheck.c b/gtk/gtkspellcheck.c
new file mode 100644
index 0000000000..deb39d4fc6
--- /dev/null
+++ b/gtk/gtkspellcheck.c
@@ -0,0 +1,463 @@
+/*
+ * Copyright 2021 Christian Hergert <chergert redhat com>
+ *
+ * This library 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 of the
+ * licence or (at your option) any later version.
+ *
+ * This library 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, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#include "config.h"
+
+#ifdef HAVE_ENCHANT
+# include <enchant.h>
+#endif
+
+#include "gtkflattenlistmodel.h"
+#include "gtkspellcheckprivate.h"
+#include "gtkstringlist.h"
+
+#ifdef HAVE_ENCHANT
+static char **gtk_enchant_list_languages (void);
+static gboolean gtk_enchant_supports (const char *code);
+static gboolean gtk_enchant_contains_word (GtkSpellLanguage *language,
+ const char *word,
+ gssize word_length);
+static void gtk_enchant_init_language (GtkSpellLanguage *language);
+static void gtk_enchant_fini_language (GtkSpellLanguage *language);
+static GListModel *gtk_enchant_list_corrections (GtkSpellLanguage *language,
+ const char *word,
+ gssize word_length);
+#endif
+
+G_DEFINE_TYPE (GtkSpellChecker, gtk_spell_checker, G_TYPE_OBJECT)
+
+enum {
+ PROP_0,
+ PROP_LANGUAGES,
+ N_PROPS
+};
+
+static GParamSpec *properties [N_PROPS];
+static const GtkSpellProvider providers[] = {
+#ifdef HAVE_ENCHANT
+ {
+ .name = "enchant",
+ .supports = gtk_enchant_supports,
+ .contains_word = gtk_enchant_contains_word,
+ .list_languages = gtk_enchant_list_languages,
+ .init_language = gtk_enchant_init_language,
+ .fini_language = gtk_enchant_fini_language,
+ .list_corrections = gtk_enchant_list_corrections,
+ },
+#endif
+};
+
+static gboolean
+gtk_spell_provider_supports (const GtkSpellProvider *provider,
+ const char *code)
+{
+ char **codes;
+ gboolean ret = FALSE;
+
+ if (provider->supports != NULL)
+ return provider->supports (code);
+
+ /* Fallback based on listing languages */
+ if ((codes = provider->list_languages ()))
+ {
+ for (guint i = 0; codes[i]; i++)
+ {
+ if (g_strcmp0 (codes[i], code) == 0)
+ {
+ ret = TRUE;
+ break;
+ }
+ }
+ }
+
+ g_strfreev (codes);
+
+ return ret;
+}
+
+static void
+_gtk_source_language_free (GtkSpellLanguage *language)
+{
+ if (language->provider->fini_language)
+ language->provider->fini_language (language);
+
+ g_clear_pointer (&language->code, g_free);
+
+ language->provider = NULL;
+ language->native = NULL;
+
+ g_free (language);
+}
+
+static GtkSpellLanguage *
+_gtk_spell_language_new (const GtkSpellProvider *provider,
+ const char *code)
+{
+ GtkSpellLanguage *language;
+
+ g_assert (provider != NULL);
+ g_assert (code != NULL);
+
+ language = g_new0 (GtkSpellLanguage, 1);
+ language->provider = provider;
+ language->code = g_strdup (code);
+
+ if (provider->init_language != NULL)
+ provider->init_language (language);
+
+ return language;
+}
+
+static char **
+gtk_spell_checker_get_languages (GtkSpellChecker *self)
+{
+ GArray *ar = g_array_new (TRUE, FALSE, sizeof (char *));
+
+ for (guint i = 0; i < self->languages->len; i++)
+ {
+ GtkSpellLanguage *language = g_ptr_array_index (self->languages, i);
+ char *code = g_strdup (language->code);
+ g_array_append_val (ar, code);
+ }
+
+ return (char **)(gpointer)g_array_free (ar, FALSE);
+}
+
+static void
+gtk_spell_checker_set_languages (GtkSpellChecker *self,
+ const char * const *languages)
+{
+ for (guint i = 0; languages[i]; i++)
+ {
+ const char *code = languages[i];
+
+ for (guint j = 0; j < G_N_ELEMENTS (providers); j++)
+ {
+ const GtkSpellProvider *provider = &providers[j];
+
+ if (gtk_spell_provider_supports (provider, code))
+ {
+ g_ptr_array_add (self->languages, _gtk_spell_language_new (provider, code));
+ break;
+ }
+ }
+ }
+}
+
+static void
+gtk_spell_checker_finalize (GObject *object)
+{
+ GtkSpellChecker *self = (GtkSpellChecker *)object;
+
+ g_clear_pointer (&self->languages, g_ptr_array_unref);
+
+ G_OBJECT_CLASS (gtk_spell_checker_parent_class)->finalize (object);
+}
+
+static void
+gtk_spell_checker_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GtkSpellChecker *self = GTK_SPELL_CHECKER (object);
+
+ switch (prop_id)
+ {
+ case PROP_LANGUAGES:
+ g_value_take_boxed (value, gtk_spell_checker_get_languages (self));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+gtk_spell_checker_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GtkSpellChecker *self = GTK_SPELL_CHECKER (object);
+
+ switch (prop_id)
+ {
+ case PROP_LANGUAGES:
+ gtk_spell_checker_set_languages (self, g_value_get_boxed (value));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+gtk_spell_checker_class_init (GtkSpellCheckerClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->finalize = gtk_spell_checker_finalize;
+ object_class->get_property = gtk_spell_checker_get_property;
+ object_class->set_property = gtk_spell_checker_set_property;
+
+ properties [PROP_LANGUAGES] =
+ g_param_spec_boxed ("languages",
+ "Languages",
+ "The language codes to support",
+ G_TYPE_STRV,
+ (G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_properties (object_class, N_PROPS, properties);
+}
+
+static void
+gtk_spell_checker_init (GtkSpellChecker *self)
+{
+ self->languages = g_ptr_array_new_with_free_func ((GDestroyNotify)_gtk_source_language_free);
+}
+
+/**
+ * gtk_spell_checker_new_for_language:
+ * @language: (nullable): the language to support
+ *
+ * Creates a new #GtkSpellChecker which uses a dictionary available based
+ * on @language.
+ *
+ * Returns: (transfer full): a #GtkSpellChecker
+ *
+ * Since: 4.2
+ */
+GtkSpellChecker *
+gtk_spell_checker_new_for_language (const char *language)
+{
+ const char *languages[] = { language, NULL };
+
+ return g_object_new (GTK_TYPE_SPELL_CHECKER,
+ "languages", languages,
+ NULL);
+}
+
+/**
+ * gtk_spell_checker_new_for_languages:
+ * @languages: (nullable) (element-type utf8): the language codes to support
+ *
+ * Creates a new #GtkSpellChecker which uses dictionaries available based
+ * on @languages.
+ *
+ * Returns: (transfer full): a #GtkSpellChecker
+ *
+ * Since: 4.2
+ */
+GtkSpellChecker *
+gtk_spell_checker_new_for_languages (const char * const * languages)
+{
+ return g_object_new (GTK_TYPE_SPELL_CHECKER,
+ "languages", languages,
+ NULL);
+}
+
+const char * const *
+gtk_spell_checker_list_languages (void)
+{
+ static char **languages;
+
+ if (languages == NULL)
+ {
+ GHashTable *seen = g_hash_table_new (g_str_hash, g_str_equal);
+ GArray *ar = g_array_new (TRUE, FALSE, sizeof (char *));
+
+ for (guint i = 0; i < G_N_ELEMENTS (providers); i++)
+ {
+ const GtkSpellProvider *provider = &providers[i];
+ char **found = provider->list_languages ();
+
+ if (found == NULL)
+ continue;
+
+ for (guint j = 0; found[j]; j++)
+ {
+ if (!g_hash_table_contains (seen, found[j]))
+ {
+ char *copy = g_strdup (found[j]);
+ g_array_append_val (ar, copy);
+ g_hash_table_add (seen, copy);
+ }
+ }
+
+ g_strfreev (found);
+ }
+
+ languages = (char **)(gpointer)g_array_free (ar, FALSE);
+ g_hash_table_unref (seen);
+ }
+
+ return (const char * const *)languages;
+}
+
+gboolean
+gtk_spell_checker_contains_word (GtkSpellChecker *self,
+ const char *word,
+ gssize word_length)
+{
+ g_return_val_if_fail (GTK_IS_SPELL_CHECKER (self), FALSE);
+
+ return _gtk_spell_checker_contains_word (self, word, word_length);
+}
+
+GListModel *
+gtk_spell_checker_list_corrections (GtkSpellChecker *self,
+ const char *word,
+ gssize word_length)
+{
+ GtkFlattenListModel *ret;
+ GListStore *store;
+
+ g_return_val_if_fail (GTK_IS_SPELL_CHECKER (self), NULL);
+ g_return_val_if_fail (word != NULL, NULL);
+
+ if (word_length < 0)
+ word_length = strlen (word);
+
+ if (self->languages->len == 0)
+ return G_LIST_MODEL (gtk_string_list_new (NULL));
+
+ store = g_list_store_new (G_TYPE_LIST_MODEL);
+
+ if (self->languages->len == 1)
+ {
+ GtkSpellLanguage *language = g_ptr_array_index (self->languages, 0);
+ return language->provider->list_corrections (language, word, word_length);
+ }
+
+ for (guint i = 0; i < self->languages->len; i++)
+ {
+ GtkSpellLanguage *language = g_ptr_array_index (self->languages, i);
+ GListModel *model = language->provider->list_corrections (language, word, word_length);
+
+ if (model != NULL)
+ {
+ g_list_store_append (store, model);
+ g_object_unref (model);
+ }
+ }
+
+ ret = gtk_flatten_list_model_new (G_LIST_MODEL (store));
+
+ g_object_unref (store);
+
+ return G_LIST_MODEL (ret);
+}
+
+GtkSpellChecker *
+gtk_spell_checker_get_default (void)
+{
+ static GtkSpellChecker *instance;
+
+ if (instance == NULL)
+ {
+ instance = gtk_spell_checker_new_for_language ("en_US");
+ g_object_add_weak_pointer (G_OBJECT (instance), (gpointer *)&instance);
+ }
+
+ return instance;
+}
+
+#ifdef HAVE_ENCHANT
+static EnchantBroker *
+gtk_enchant_get_broker (void)
+{
+ static EnchantBroker *broker;
+
+ if (broker == NULL)
+ broker = enchant_broker_init ();
+
+ return broker;
+}
+
+static gboolean
+gtk_enchant_supports (const char *code)
+{
+ return enchant_broker_dict_exists (gtk_enchant_get_broker (), code);
+}
+
+static void
+gtk_enchant_list_languages_cb (const char * const lang_tag,
+ const char * const provider_name,
+ const char * const provider_desc,
+ const char * const provider_file,
+ void *user_data)
+{
+ GArray *ar = user_data;
+ char *code = g_strdup (lang_tag);
+ g_array_append_val (ar, code);
+}
+
+static char **
+gtk_enchant_list_languages (void)
+{
+ EnchantBroker *broker = gtk_enchant_get_broker ();
+ GArray *ar = g_array_new (TRUE, FALSE, sizeof (char *));
+
+ enchant_broker_list_dicts (broker,
+ gtk_enchant_list_languages_cb,
+ ar);
+
+ return (char **)(gpointer)g_array_free (ar, FALSE);
+}
+
+static gboolean
+gtk_enchant_contains_word (GtkSpellLanguage *language,
+ const char *word,
+ gssize word_length)
+{
+ return enchant_dict_check (language->native, word, word_length) == 0;
+}
+
+static GListModel *
+gtk_enchant_list_corrections (GtkSpellLanguage *language,
+ const char *word,
+ gssize word_length)
+{
+ size_t count = 0;
+ char **ret = enchant_dict_suggest (language->native, word, word_length, &count);
+ GtkStringList *model = gtk_string_list_new ((const char * const *)ret);
+ enchant_dict_free_string_list (language->native, ret);
+ return G_LIST_MODEL (model);
+}
+
+static void
+gtk_enchant_init_language (GtkSpellLanguage *language)
+{
+ EnchantBroker *broker = gtk_enchant_get_broker ();
+ language->native = enchant_broker_request_dict (broker, language->code);
+}
+
+static void
+gtk_enchant_fini_language (GtkSpellLanguage *language)
+{
+ if (language->native != NULL)
+ {
+ enchant_broker_free_dict (gtk_enchant_get_broker (), language->native);
+ language->native = NULL;
+ }
+}
+#endif
diff --git a/gtk/gtkspellcheck.h b/gtk/gtkspellcheck.h
new file mode 100644
index 0000000000..5bfffcda47
--- /dev/null
+++ b/gtk/gtkspellcheck.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2021 Christian Hergert <chergert redhat com>
+ *
+ * This library 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 of the
+ * licence or (at your option) any later version.
+ *
+ * This library 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, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#ifndef __GTK_SPELL_CHECK_H__
+#define __GTK_SPELL_CHECK_H__
+
+#include <gdk/gdk.h>
+
+G_BEGIN_DECLS
+
+#define GTK_TYPE_SPELL_CHECKER (gtk_spell_checker_get_type())
+
+typedef enum _GtkSpellDictionary
+{
+ GTK_SPELL_DICTIONARY_SESSION,
+ GTK_SPELL_DICTIONARY_PERSONAL,
+} GtkSpellDictionary;
+
+GDK_AVAILABLE_IN_4_2
+G_DECLARE_FINAL_TYPE (GtkSpellChecker, gtk_spell_checker, GTK, SPELL_CHECKER, GObject)
+
+GDK_AVAILABLE_IN_4_2
+GtkSpellChecker *gtk_spell_checker_get_default (void);
+GDK_AVAILABLE_IN_4_2
+GtkSpellChecker *gtk_spell_checker_new_for_language (const char *language);
+GDK_AVAILABLE_IN_4_2
+GtkSpellChecker *gtk_spell_checker_new_for_languages (const char * const *languages);
+GDK_AVAILABLE_IN_4_2
+const char * const *gtk_spell_checker_list_languages (void);
+GDK_AVAILABLE_IN_4_2
+gboolean gtk_spell_checker_contains_word (GtkSpellChecker *self,
+ const char *word,
+ gssize word_length);
+GDK_AVAILABLE_IN_4_2
+GListModel *gtk_spell_checker_list_corrections (GtkSpellChecker *self,
+ const char *word,
+ gssize word_length);
+GDK_AVAILABLE_IN_4_2
+void gtk_spell_checker_add_word (GtkSpellChecker *self,
+ GtkSpellDictionary dictionary,
+ const char *word,
+ gssize word_length);
+GDK_AVAILABLE_IN_4_2
+void gtk_spell_checker_set_correction (GtkSpellChecker *self,
+ GtkSpellDictionary dictionary,
+ const char *word,
+ gssize word_length,
+ const char *correction,
+ gssize correction_length);
+
+G_END_DECLS
+
+#endif /* __GTK_SPELL_CHECK_H__ */
diff --git a/gtk/gtkspellcheckprivate.h b/gtk/gtkspellcheckprivate.h
new file mode 100644
index 0000000000..71e4806e13
--- /dev/null
+++ b/gtk/gtkspellcheckprivate.h
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2021 Christian Hergert <chergert redhat com>
+ *
+ * This library 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 of the
+ * licence or (at your option) any later version.
+ *
+ * This library 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, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#ifndef __GTK_SPELL_CHECK_PRIVATE_H__
+#define __GTK_SPELL_CHECK_PRIVATE_H__
+
+#include "gtkspellcheck.h"
+
+G_BEGIN_DECLS
+
+typedef struct _GtkSpellProvider GtkSpellProvider;
+typedef struct _GtkSpellLanguage GtkSpellLanguage;
+
+struct _GtkSpellProvider
+{
+ const char *name;
+ gboolean (*supports) (const char *code);
+ char **(*list_languages) (void);
+ GListModel *(*list_corrections) (GtkSpellLanguage *language,
+ const char *word,
+ gssize word_length);
+ void (*init_language) (GtkSpellLanguage *language);
+ void (*fini_language) (GtkSpellLanguage *language);
+ gboolean (*contains_word) (GtkSpellLanguage *language,
+ const char *word,
+ gssize word_length);
+};
+
+struct _GtkSpellLanguage
+{
+ const GtkSpellProvider *provider;
+ char *code;
+ gpointer native;
+};
+
+struct _GtkSpellChecker
+{
+ GObject parent_instance;
+ GPtrArray *languages;
+};
+
+struct _GtkSpellCorrection
+{
+ GObject parent_instance;
+ char *text;
+};
+
+static inline gboolean
+_gtk_spell_language_contains_word (GtkSpellLanguage *language,
+ const char *word,
+ gssize word_length)
+{
+ return language->provider->contains_word (language, word, word_length);
+}
+
+static inline gboolean
+_gtk_spell_checker_contains_word (GtkSpellChecker *checker,
+ const char *word,
+ gssize word_length)
+{
+ if (word_length < 0)
+ word_length = strlen (word);
+
+ for (guint i = 0; i < checker->languages->len; i++)
+ {
+ GtkSpellLanguage *language = g_ptr_array_index (checker->languages, i);
+
+ if (_gtk_spell_language_contains_word (language, word, word_length))
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+G_END_DECLS
+
+#endif /* __GTK_SPELL_CHECKER_PRIVATE_H__ */
diff --git a/gtk/meson.build b/gtk/meson.build
index fe0ec456d9..4cf4c253a6 100644
--- a/gtk/meson.build
+++ b/gtk/meson.build
@@ -377,6 +377,7 @@ gtk_public_sources = files([
'gtksnapshot.c',
'gtksorter.c',
'gtksortlistmodel.c',
+ 'gtkspellcheck.c',
'gtkspinbutton.c',
'gtkspinner.c',
'gtkstack.c',
@@ -648,6 +649,7 @@ gtk_public_headers = files([
'gtksnapshot.h',
'gtksorter.h',
'gtksortlistmodel.h',
+ 'gtkspellcheck.h',
'gtkspinbutton.h',
'gtkspinner.h',
'gtkstack.h',
@@ -1001,6 +1003,7 @@ gtk_deps = [
epoxy_dep,
libm,
graphene_dep,
+ libenchant_dep,
]
if harfbuzz_dep.found() and pangoft_dep.found()
diff --git a/meson.build b/meson.build
index 38d23ed61c..e54b9af809 100644
--- a/meson.build
+++ b/meson.build
@@ -23,6 +23,7 @@ epoxy_req = '>= 1.4'
cloudproviders_req = '>= 0.3.1'
xkbcommon_req = '>= 0.2.0'
sysprof_req = '>= 3.38.0'
+enchant_req = '>= 2.2.12'
gnome = import('gnome')
pkg_config = import('pkgconfig')
@@ -667,6 +668,16 @@ else
profiler_enabled = false
endif
+# enchant spellcheck support
+spellcheck_backends = []
+if not get_option('spell-enchant').disabled()
+ libenchant_dep = dependency('enchant-2', version: enchant_req, required: get_option('spell-enchant'))
+ if libenchant_dep.found()
+ spellcheck_backends += ['enchant']
+ cdata.set10('HAVE_ENCHANT', true)
+ endif
+endif
+
graphene_dep_type = graphene_dep.type_name()
if graphene_dep_type == 'pkgconfig'
graphene_has_sse2 = graphene_dep.get_pkgconfig_variable('graphene_has_sse2') == '1'
@@ -834,6 +845,7 @@ endif
summary('Display backends', display_backends)
summary('Print backends', print_backends)
summary('Media backends', media_backends)
+summary('Spell backends', spellcheck_backends)
summary('Vulkan support', vulkan_dep.found(), section: 'Features')
summary('Cloud support', cloudproviders_dep.found(), section: 'Features')
diff --git a/meson_options.txt b/meson_options.txt
index 16a1cbd9fe..c749529be1 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -49,6 +49,13 @@ option('print-cloudprint',
value: 'auto',
description : 'Build the cloudprint print backend')
+# Spell Check Providers
+
+option('spell-enchant',
+ type: 'feature',
+ value: 'auto',
+ description : 'Build the enchant spellcheck backend')
+
# Optional features
option('vulkan',
diff --git a/tests/meson.build b/tests/meson.build
index c0e5f836b0..dbe4d62e19 100644
--- a/tests/meson.build
+++ b/tests/meson.build
@@ -68,6 +68,7 @@ gtk_tests = [
['testscale'],
['testselectionmode'],
['testsounds'],
+ ['testspelling'],
['testspinbutton'],
['testtreechanging'],
['testtreednd'],
diff --git a/tests/testspelling.c b/tests/testspelling.c
new file mode 100644
index 0000000000..4159e5ddec
--- /dev/null
+++ b/tests/testspelling.c
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2021 Christian Hergert <chergert redhat com>
+ *
+ * This library 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 of the
+ * licence or (at your option) any later version.
+ *
+ * This library 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, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#include <gtk/gtk.h>
+
+int
+main (int argc, char *argv[])
+{
+ GtkSpellChecker *checker;
+
+ gtk_init ();
+
+ checker = gtk_spell_checker_get_default ();
+
+ for (guint i = 1; i < argc; i++)
+ {
+ const char *word = argv[i];
+ GListModel *corrections;
+ guint n_items = 0;
+
+ if (gtk_spell_checker_contains_word (checker, word, -1))
+ {
+ g_print ("Dictionary contains the word “%s”\n", word);
+ continue;
+ }
+
+ if ((corrections = gtk_spell_checker_list_corrections (checker, word, -1)))
+ {
+ n_items = g_list_model_get_n_items (G_LIST_MODEL (corrections));
+
+ if (n_items > 0)
+ g_print ("Corrections for “%s”:\n", word);
+
+ for (guint j = 0; j < n_items; j++)
+ {
+ GtkStringObject *correction = g_list_model_get_item (corrections, j);
+ const char *text = gtk_string_object_get_string (correction);
+
+ g_print (" %s\n", text);
+ }
+
+ g_object_unref (corrections);
+ }
+
+ if (n_items == 0)
+ g_print ("No corrections for “%s” were found.\n", word);
+ }
+
+ g_assert_finalize_object (checker);
+
+ return 0;
+}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]