[gnome-text-editor] spellchecker: connect plumbing to check words



commit 16d82887d736677f1dab713fdeb0f736c2e15342
Author: Christian Hergert <chergert redhat com>
Date:   Fri Jun 25 17:53:43 2021 -0700

    spellchecker: connect plumbing to check words
    
    We still need to ignore words that are not in contexts we care about.

 src/editor-spell-checker.c             | 32 +++++++++++--
 src/editor-spell-checker.h             |  3 ++
 src/editor-spell-language.c            |  3 ++
 src/editor-spell-provider.c            | 32 +++++++++++++
 src/editor-spell-provider.h            |  2 +
 src/editor-text-buffer-spell-adapter.c | 85 +++++++++++++++++++++++++++++++++-
 6 files changed, 151 insertions(+), 6 deletions(-)
---
diff --git a/src/editor-spell-checker.c b/src/editor-spell-checker.c
index ee5e491..cd9c07b 100644
--- a/src/editor-spell-checker.c
+++ b/src/editor-spell-checker.c
@@ -21,13 +21,14 @@
 #include "config.h"
 
 #include "editor-spell-checker.h"
+#include "editor-spell-language.h"
 #include "editor-spell-provider.h"
 
 struct _EditorSpellChecker
 {
   GObject              parent_instance;
   EditorSpellProvider *provider;
-  const char          *language;
+  EditorSpellLanguage *language;
 };
 
 G_DEFINE_TYPE (EditorSpellChecker, editor_spell_checker, G_TYPE_OBJECT)
@@ -54,6 +55,12 @@ editor_spell_checker_new (EditorSpellProvider *provider,
 {
   g_return_val_if_fail (EDITOR_IS_SPELL_PROVIDER (provider) || !provider, NULL);
 
+  if (provider == NULL)
+    provider = editor_spell_provider_get_default ();
+
+  if (language == NULL)
+    language = editor_spell_provider_get_default_code (provider);
+
   return g_object_new (EDITOR_TYPE_SPELL_CHECKER,
                        "provider", provider,
                        "language", language,
@@ -79,6 +86,7 @@ editor_spell_checker_finalize (GObject *object)
   EditorSpellChecker *self = (EditorSpellChecker *)object;
 
   g_clear_object (&self->provider);
+  g_clear_object (&self->language);
 
   G_OBJECT_CLASS (editor_spell_checker_parent_class)->finalize (object);
 }
@@ -189,7 +197,7 @@ editor_spell_checker_get_language (EditorSpellChecker *self)
 {
   g_return_val_if_fail (EDITOR_IS_SPELL_CHECKER (self), NULL);
 
-  return self->language;
+  return self->language ? editor_spell_language_get_code (self->language) : NULL;
 }
 
 /**
@@ -206,9 +214,9 @@ editor_spell_checker_set_language (EditorSpellChecker *self,
 {
   g_return_if_fail (EDITOR_IS_SPELL_CHECKER (self));
 
-  if (g_strcmp0 (language, self->language) != 0)
+  if (g_strcmp0 (language, editor_spell_checker_get_language (self)) != 0)
     {
-      self->language = g_intern_string (language);
+      self->language = editor_spell_provider_get_language (self->provider, language);
       g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_LANGUAGE]);
     }
 }
@@ -229,3 +237,19 @@ editor_spell_checker_get_provider (EditorSpellChecker *self)
 
   return self->provider;
 }
+
+gboolean
+editor_spell_checker_check_word (EditorSpellChecker *self,
+                                 const char         *word,
+                                 gssize              word_len)
+{
+  g_return_val_if_fail (EDITOR_IS_SPELL_CHECKER (self), FALSE);
+
+  if (word == NULL || word_len == 0)
+    return FALSE;
+
+  if (self->language == NULL)
+    return TRUE;
+
+  return editor_spell_language_contains_word (self->language, word, word_len);
+}
diff --git a/src/editor-spell-checker.h b/src/editor-spell-checker.h
index f29b5fe..dc53c42 100644
--- a/src/editor-spell-checker.h
+++ b/src/editor-spell-checker.h
@@ -34,5 +34,8 @@ EditorSpellProvider *editor_spell_checker_get_provider (EditorSpellChecker  *sel
 const char          *editor_spell_checker_get_language (EditorSpellChecker  *self);
 void                 editor_spell_checker_set_language (EditorSpellChecker  *self,
                                                         const char          *language);
+gboolean             editor_spell_checker_check_word   (EditorSpellChecker  *self,
+                                                        const char          *word,
+                                                        gssize               word_len);
 
 G_END_DECLS
diff --git a/src/editor-spell-language.c b/src/editor-spell-language.c
index 23c5b02..33344f1 100644
--- a/src/editor-spell-language.c
+++ b/src/editor-spell-language.c
@@ -119,6 +119,9 @@ editor_spell_language_contains_word (EditorSpellLanguage *self,
   g_return_val_if_fail (EDITOR_IS_SPELL_LANGUAGE (self), FALSE);
   g_return_val_if_fail (word != NULL, FALSE);
 
+  if (word_len < 0)
+    word_len = strlen (word);
+
   return EDITOR_SPELL_LANGUAGE_GET_CLASS (self)->contains_word (self, word, word_len);
 }
 
diff --git a/src/editor-spell-provider.c b/src/editor-spell-provider.c
index 053d568..60bd112 100644
--- a/src/editor-spell-provider.c
+++ b/src/editor-spell-provider.c
@@ -199,3 +199,35 @@ editor_spell_provider_get_language (EditorSpellProvider *self,
 
   return EDITOR_SPELL_PROVIDER_GET_CLASS (self)->get_language (self, language);
 }
+
+const char *
+editor_spell_provider_get_default_code (EditorSpellProvider *self)
+{
+  const char * const *langs;
+  const char *ret;
+
+  g_return_val_if_fail (EDITOR_IS_SPELL_PROVIDER (self), NULL);
+
+  if (EDITOR_SPELL_PROVIDER_GET_CLASS (self)->get_default_code &&
+      (ret = EDITOR_SPELL_PROVIDER_GET_CLASS (self)->get_default_code (self)))
+    return ret;
+
+  langs = g_get_language_names ();
+
+  if (langs != NULL)
+    {
+      for (guint i = 0; langs[i]; i++)
+        {
+          if (editor_spell_provider_supports_language (self, langs[i]))
+            return langs[i];
+        }
+    }
+
+  if (editor_spell_provider_supports_language (self, "en_US"))
+    return "en_US";
+
+  if (editor_spell_provider_supports_language (self, "C"))
+    return "C";
+
+  return NULL;
+}
diff --git a/src/editor-spell-provider.h b/src/editor-spell-provider.h
index 293e4b1..40f9144 100644
--- a/src/editor-spell-provider.h
+++ b/src/editor-spell-provider.h
@@ -37,12 +37,14 @@ struct _EditorSpellProviderClass
                                               const char          *language);
   EditorSpellLanguage  *(*get_language)      (EditorSpellProvider *self,
                                               const char          *language);
+  const char           *(*get_default_code)  (EditorSpellProvider *self);
 
   /*< private >*/
   gpointer _reserved[8];
 };
 
 EditorSpellProvider  *editor_spell_provider_get_default       (void);
+const char           *editor_spell_provider_get_default_code  (EditorSpellProvider *self);
 const char           *editor_spell_provider_get_display_name  (EditorSpellProvider *self);
 gboolean              editor_spell_provider_supports_language (EditorSpellProvider *self,
                                                                const char          *language);
diff --git a/src/editor-text-buffer-spell-adapter.c b/src/editor-text-buffer-spell-adapter.c
index ffe69c3..e412eb6 100644
--- a/src/editor-text-buffer-spell-adapter.c
+++ b/src/editor-text-buffer-spell-adapter.c
@@ -29,6 +29,18 @@
 #define CHECKED            GSIZE_TO_POINTER(1)
 #define UPDATE_DELAY_MSECS 200
 
+typedef struct
+{
+  gint64   deadline;
+  guint    has_unchecked : 1;
+} Update;
+
+typedef struct
+{
+  gsize offset;
+  guint found : 1;
+} ScanForUnchecked;
+
 struct _EditorTextBufferSpellAdapter
 {
   GObject             parent_instance;
@@ -67,14 +79,83 @@ editor_text_buffer_spell_adapter_new (GtkTextBuffer      *buffer,
                        NULL);
 }
 
+static gboolean
+scan_for_next_unchecked_cb (gsize                   offset,
+                            const CjhTextRegionRun *run,
+                            gpointer                user_data)
+{
+  ScanForUnchecked *state = user_data;
+
+  if (run->data == UNCHECKED)
+    {
+      state->offset = offset;
+      state->found = TRUE;
+      return TRUE;
+    }
+
+  return FALSE;
+}
+
+static gboolean
+scan_for_next_unchecked (CjhTextRegion *region,
+                         gsize          begin,
+                         gsize          end,
+                         gsize         *position)
+{
+  ScanForUnchecked state = {0};
+  _cjh_text_region_foreach_in_range (region, begin, end, scan_for_next_unchecked_cb, &state);
+  *position = state.offset;
+  return state.found;
+}
+
 static gboolean
 editor_text_buffer_spell_adapter_update_range (EditorTextBufferSpellAdapter *self,
-                                               gsize                         begin,
-                                               gsize                         end,
+                                               gsize                         begin_offset,
+                                               gsize                         end_offset,
                                                gint64                        deadline)
 {
+  GtkTextIter iter, begin, end;
+  gsize position;
+
   g_assert (EDITOR_IS_TEXT_BUFFER_SPELL_ADAPTER (self));
 
+  if (begin_offset == end_offset)
+    return FALSE;
+
+  if (!scan_for_next_unchecked (self->region, begin_offset, end_offset, &position))
+    return FALSE;
+
+  gtk_text_buffer_get_iter_at_offset (self->buffer, &begin, position);
+  gtk_text_buffer_get_iter_at_offset (self->buffer, &end, end_offset);
+  iter = begin;
+
+  if (!gtk_text_iter_starts_word (&iter))
+    gtk_text_iter_backward_word_start (&iter);
+
+  while (gtk_text_iter_compare (&iter, &end) < 0)
+    {
+      GtkTextIter word_end = iter;
+      char *word;
+
+      if (!gtk_text_iter_forward_word_end (&word_end))
+        break;
+
+      word = gtk_text_iter_get_slice (&iter, &word_end);
+      if (!editor_spell_checker_check_word (self->checker, word, -1))
+        gtk_text_buffer_apply_tag (self->buffer, self->tag, &iter, &word_end);
+      g_free (word);
+
+      if (!gtk_text_iter_forward_word_end (&word_end))
+        break;
+
+      iter = word_end;
+
+      if (!gtk_text_iter_backward_word_start (&iter))
+        break;
+    }
+
+  _cjh_text_region_replace (self->region, begin_offset, end_offset - begin_offset, CHECKED);
+
   return FALSE;
 }
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]