changeset 2170:282531385f34

Multilanguage spell checking
author Dmitry Potapov <potapov.d@gmail.com>
date Sun, 15 Feb 2015 16:23:30 +0100
parents 4889f429fdd0
children 46d1182d45be
files mcabber/mcabber/screen.c mcabber/mcabberrc.example
diffstat 2 files changed, 92 insertions(+), 71 deletions(-) [+]
line wrap: on
line diff
--- a/mcabber/mcabber/screen.c	Sun Feb 15 12:12:22 2015 +0100
+++ b/mcabber/mcabber/screen.c	Sun Feb 15 16:23:30 2015 +0100
@@ -186,14 +186,19 @@
 
 #define SPELLBADCHAR 5
 
+#if defined(WITH_ENCHANT) || defined(WITH_ASPELL)
+typedef struct {
 #ifdef WITH_ENCHANT
-EnchantBroker *spell_broker;
-EnchantDict *spell_checker;
+  EnchantBroker *broker;
+  EnchantDict *checker;
 #endif
-
 #ifdef WITH_ASPELL
-AspellConfig *spell_config;
-AspellSpeller *spell_checker;
+  AspellConfig *config;
+  AspellSpeller *checker;
+#endif
+} spell_checker;
+
+GSList* spell_checkers = NULL;
 #endif
 
 typedef struct {
@@ -4480,35 +4485,65 @@
 }
 
 #if defined(WITH_ENCHANT) || defined(WITH_ASPELL)
+static void spell_checker_free(gpointer data)
+{
+  spell_checker* sc = data;
+#ifdef WITH_ENCHANT
+  enchant_broker_free_dict(sc->broker, sc->checker);
+  enchant_broker_free(sc->broker);
+#endif
+#ifdef WITH_ASPELL
+  delete_aspell_speller(sc->checker);
+  delete_aspell_config(sc->config);
+#endif
+  g_free(sc);
+}
+
+static spell_checker* new_spell_checker(const char* spell_lang)
+{
+  spell_checker* sc = g_new(spell_checker, 1);
+#ifdef WITH_ASPELL
+  const char *spell_encoding = settings_opt_get("spell_encoding");
+  AspellCanHaveError *possible_err;
+  sc->config = new_aspell_config();
+  if (spell_encoding)
+    aspell_config_replace(sc->config, "encoding", spell_encoding);
+  aspell_config_replace(sc->config, "lang", spell_lang);
+  possible_err = new_aspell_speller(sc->config);
+
+  if (aspell_error_number(possible_err) != 0) {
+    delete_aspell_config(sc->config);
+    g_free(sc);
+    sc = NULL;
+  } else {
+    sc->checker = to_aspell_speller(possible_err);
+  }
+#endif
+#ifdef WITH_ENCHANT
+  sc->broker = enchant_broker_init();
+  sc->checker = enchant_broker_request_dict(sc->broker, spell_lang);
+  if (!sc->checker) {
+    enchant_broker_free(sc->broker);
+    g_free(sc);
+    sc = NULL;
+  }
+#endif
+  return sc;
+}
+
 // initialization
 void spellcheck_init(void)
 {
   int spell_enable            = settings_opt_get_int("spell_enable");
   const char *spell_lang     = settings_opt_get("spell_lang");
-#ifdef WITH_ASPELL
-  const char *spell_encoding = settings_opt_get("spell_encoding");
-  AspellCanHaveError *possible_err;
-#endif
+  gchar** langs;
+  gchar** lang_iter;
+  spell_checker* sc;
 
   if (!spell_enable)
     return;
 
-#ifdef WITH_ENCHANT
-  if (spell_checker) {
-     enchant_broker_free_dict(spell_broker, spell_checker);
-     enchant_broker_free(spell_broker);
-     spell_checker = NULL;
-     spell_broker = NULL;
-  }
-#endif
-#ifdef WITH_ASPELL
-  if (spell_checker) {
-    delete_aspell_speller(spell_checker);
-    delete_aspell_config(spell_config);
-    spell_checker = NULL;
-    spell_config = NULL;
-  }
-#endif
+  spellcheck_deinit();
 
   if (!spell_lang) { // Cannot initialize: language not specified
     scr_LogPrint(LPRINT_LOGNORM, "Error: Cannot initialize spell checker, language not specified.");
@@ -4516,53 +4551,43 @@
     return;
   }
 
-#ifdef WITH_ENCHANT
-  spell_broker = enchant_broker_init();
-  spell_checker = enchant_broker_request_dict(spell_broker, spell_lang);
-#endif
-
-#ifdef WITH_ASPELL
-  spell_config = new_aspell_config();
-  if (spell_encoding)
-    aspell_config_replace(spell_config, "encoding", spell_encoding);
-  aspell_config_replace(spell_config, "lang", spell_lang);
-  possible_err = new_aspell_speller(spell_config);
-
-  if (aspell_error_number(possible_err) != 0) {
-    spell_checker = NULL;
-    delete_aspell_config(spell_config);
-    spell_config = NULL;
-  } else {
-    spell_checker = to_aspell_speller(possible_err);
+  langs = g_strsplit(spell_lang, " ", -1);
+  for (lang_iter = langs; *lang_iter; ++lang_iter) {
+    if (**lang_iter) { // Skip empty strings
+      sc = new_spell_checker(*lang_iter);
+      if (sc) {
+        spell_checkers = g_slist_append(spell_checkers, sc);
+      }
+    }
   }
-#endif
+  g_strfreev(langs);
 }
 
 // Deinitialization of spellchecker
 void spellcheck_deinit(void)
 {
-  if (spell_checker) {
+  g_slist_free_full(spell_checkers, spell_checker_free);
+  spell_checkers = NULL;
+}
+
+typedef struct {
+  const char* str;
+  int len;
+} spell_substring;
+
+static int spellcheckword(gconstpointer sc_ptr, gconstpointer substr_ptr)
+{
+  spell_checker* sc = (spell_checker*) sc_ptr;
+  spell_substring* substr = (spell_substring*) substr_ptr;
 #ifdef WITH_ENCHANT
-    enchant_broker_free_dict(spell_broker, spell_checker);
+  // enchant_dict_check will return 0 on good word
+  return enchant_dict_check(sc->checker, substr->str, substr->len);
 #endif
 #ifdef WITH_ASPELL
-    delete_aspell_speller(spell_checker);
+  // aspell_speller_check will return 1 on good word, so we need to make it 0
+  return aspell_speller_check(sc->checker, substr->str, substr->len) - 1;
 #endif
-    spell_checker = NULL;
-  }
-
-#ifdef WITH_ENCHANT
-  if (spell_broker) {
-    enchant_broker_free(spell_broker);
-    spell_broker = NULL;
-  }
-#endif
-#ifdef WITH_ASPELL
-  if (spell_config) {
-    delete_aspell_config(spell_config);
-    spell_config = NULL;
-  }
-#endif
+  return 0; // Keep compiler happy
 }
 
 #define spell_isalpha(c) (utf8_mode ? iswalpha(get_char(c)) : isalpha(*c))
@@ -4571,6 +4596,7 @@
 static void spellcheck(char *line, char *checked)
 {
   const char *start, *line_start;
+  spell_substring substr;
 
   if (inputLine[0] == 0 || inputLine[0] == COMMAND_CHAR)
     return;
@@ -4607,14 +4633,9 @@
     while (spell_isalpha(line))
       line = next_char(line);
 
-    if (spell_checker &&
-#ifdef WITH_ENCHANT
-        enchant_dict_check(spell_checker, start, line - start) != 0
-#endif
-#ifdef WITH_ASPELL
-        aspell_speller_check(spell_checker, start, line - start) == 0
-#endif
-    )
+    substr.str = start;
+    substr.len = line - start;
+    if (!g_slist_find_custom(spell_checkers, &substr, spellcheckword))
       memset(&checked[start - line_start], SPELLBADCHAR, line - start);
   }
 }
--- a/mcabber/mcabberrc.example	Sun Feb 15 12:12:22 2015 +0100
+++ b/mcabber/mcabberrc.example	Sun Feb 15 16:23:30 2015 +0100
@@ -110,7 +110,7 @@
 # checking with the following options (you can't change them once mcabber is
 # running).
 #set spell_enable = 1
-#set spell_lang = en_US
+#set spell_lang = en_US ru_RU
 #set spell_encoding = iso8859-1
 #set spell_encoding = UTF-8