]> git.lyx.org Git - lyx.git/blobdiff - src/AspellChecker.cpp
Added possibility to retrieve internal buffers (by their tmp file-name) from the...
[lyx.git] / src / AspellChecker.cpp
index 097ec6916595bcbe8c732af56f3046c55ca253c4..642f804977c77d37ab6298a206701a855451fe73 100644 (file)
@@ -12,6 +12,8 @@
 #include <config.h>
 
 #include "AspellChecker.h"
+#include "PersonalWordList.h"
+
 #include "LyXRC.h"
 #include "WordLangTuple.h"
 
@@ -39,9 +41,11 @@ namespace {
 struct Speller {
        AspellConfig * config;
        AspellCanHaveError * e_speller;
+       docstring_list ignored_words_;
 };
 
 typedef std::map<std::string, Speller> Spellers;
+typedef map<std::string, PersonalWordList *> LangPersonalWordList;
 
 } // anon namespace
 
@@ -52,16 +56,13 @@ struct AspellChecker::Private
        ~Private();
 
        /// add a speller of the given language and variety
-       AspellSpeller * addSpeller(string const & lang,
-                                  string const & variety = string());
+       AspellSpeller * addSpeller(Language const * lang);
 
        ///
-       AspellSpeller * speller(string const & lang,
-                               string const & variety);
+       AspellSpeller * speller(Language const * lang);
 
        /// create a unique ID from lang code and variety
-       string const spellerID(string const & lang,
-                              string const & variety);
+       string const spellerID(Language const * lang);
 
        bool isValidDictionary(AspellConfig * config,
                        string const & lang, string const & variety);
@@ -70,9 +71,21 @@ struct AspellChecker::Private
                string const & lang, string const & variety);
        AspellConfig * getConfig(string const & lang, string const & variety);
 
+       SpellChecker::Result check(AspellSpeller * m,
+               string const & word) const;
+
+       void initSessionDictionary(Speller const & speller, PersonalWordList * pd);
+       void insert(WordLangTuple const & word);
+       void remove(WordLangTuple const & word);
+       bool learned(WordLangTuple const & word);
+
+       void accept(Speller & speller, WordLangTuple const & word);
+
        /// the spellers
        Spellers spellers_;
 
+       LangPersonalWordList personal_;
+
        /// the location below system/user directory
        /// there the rws files lookup will happen
        const string dictDirectory(void) { return "dict"; }
@@ -113,6 +126,17 @@ AspellChecker::Private::~Private()
                }
                delete_aspell_config(it->second.config);
        }
+
+       LangPersonalWordList::const_iterator pdit = personal_.begin();
+       LangPersonalWordList::const_iterator pdet = personal_.end();
+       
+       for (; pdit != pdet; ++pdit) {
+               if ( 0 == pdit->second)
+                       continue;
+               PersonalWordList * pd = pdit->second;
+               pd->save();
+               delete pd;
+       }
 }
 
 
@@ -186,16 +210,37 @@ AspellConfig * AspellChecker::Private::getConfig(string const & lang, string con
 }
 
 
-AspellSpeller * AspellChecker::Private::addSpeller(string const & lang,
-                                                  string const & variety)
+void AspellChecker::Private::initSessionDictionary(
+       Speller const & speller,
+       PersonalWordList * pd)
 {
-       Speller m;
+       AspellSpeller * aspell = to_aspell_speller(speller.e_speller);
+       aspell_speller_clear_session(aspell);
+       docstring_list::const_iterator it = pd->begin();
+       docstring_list::const_iterator et = pd->end();
+       for (; it != et; ++it) {
+               string const word_to_add = to_utf8(*it);
+               aspell_speller_add_to_session(aspell, word_to_add.c_str(), -1);
+       }
+       it = speller.ignored_words_.begin();
+       et = speller.ignored_words_.end();
+       for (; it != et; ++it) {
+               string const word_to_add = to_utf8(*it);
+               aspell_speller_add_to_session(aspell, word_to_add.c_str(), -1);
+       }
+}
+
 
-       m.config = getConfig(lang, variety);
+AspellSpeller * AspellChecker::Private::addSpeller(Language const * lang)
+{
+       Speller m;
+       string const code = lang->code();
+       string const variety = lang->variety();
+       m.config = getConfig(code, variety);
        // Aspell supports both languages and varieties (such as German
        // old vs. new spelling). The respective naming convention is
        // lang_REGION-variety (e.g. de_DE-alt).
-       aspell_config_replace(m.config, "lang", lang.c_str());
+       aspell_config_replace(m.config, "lang", code.c_str());
        if (!variety.empty())
                aspell_config_replace(m.config, "variety", variety.c_str());
        // Set the encoding to utf-8.
@@ -221,30 +266,82 @@ AspellSpeller * AspellChecker::Private::addSpeller(string const & lang,
                delete_aspell_config(m.config);
                m.config = 0;
                m.e_speller = 0;
+       } else {
+               PersonalWordList * pd = new PersonalWordList(lang->lang());
+               pd->load();
+               personal_[lang->lang()] = pd;
+               initSessionDictionary(m, pd);
        }
-
-       spellers_[spellerID(lang, variety)] = m;
+       
+       spellers_[spellerID(lang)] = m;
        return m.e_speller ? to_aspell_speller(m.e_speller) : 0;
 }
 
 
-AspellSpeller * AspellChecker::Private::speller(string const & lang,
-                                               string const & variety)
+AspellSpeller * AspellChecker::Private::speller(Language const * lang)
 {
-       Spellers::iterator it = spellers_.find(spellerID(lang, variety));
+       Spellers::iterator it = spellers_.find(spellerID(lang));
        if (it != spellers_.end())
                return to_aspell_speller(it->second.e_speller);
        
-       return addSpeller(lang, variety);
+       return addSpeller(lang);
+}
+
+
+string const AspellChecker::Private::spellerID(Language const * lang)
+{
+       return lang->code() + "-" + lang->variety();
 }
 
 
-string const AspellChecker::Private::spellerID(string const & lang,
-                                       string const & variety)
+SpellChecker::Result AspellChecker::Private::check(
+       AspellSpeller * m, string const & word) 
+       const
+{
+       int const word_ok = aspell_speller_check(m, word.c_str(), -1);
+       LASSERT(word_ok != -1, /**/);
+       return (word_ok) ? WORD_OK : UNKNOWN_WORD;
+}
+
+void AspellChecker::Private::accept(Speller & speller, WordLangTuple const & word)
 {
-       if (variety.empty())
-               return lang;
-       return lang + "-" + variety;
+       speller.ignored_words_.push_back(word.word());
+}
+
+
+/// personal word list interface
+void AspellChecker::Private::remove(WordLangTuple const & word)
+{
+       PersonalWordList * pd = personal_[word.lang()->lang()];
+       if (!pd)
+               return;
+       pd->remove(word.word());
+       Spellers::iterator it = spellers_.find(spellerID(word.lang()));
+       if (it != spellers_.end()) {
+               initSessionDictionary(it->second, pd);
+       }
+}
+
+               
+void AspellChecker::Private::insert(WordLangTuple const & word)
+{
+       Spellers::iterator it = spellers_.find(spellerID(word.lang()));
+       if (it != spellers_.end()) {
+               AspellSpeller * speller = to_aspell_speller(it->second.e_speller);
+               aspell_speller_add_to_session(speller, to_utf8(word.word()).c_str(), -1);
+               PersonalWordList * pd = personal_[word.lang()->lang()];
+               if (!pd)
+                       return;
+               pd->insert(word.word());
+       }
+}
+
+bool AspellChecker::Private::learned(WordLangTuple const & word)
+{
+       PersonalWordList * pd = personal_[word.lang()->lang()];
+       if (!pd)
+               return false;
+       return pd->exists(word.word());
 }
 
 
@@ -262,42 +359,42 @@ AspellChecker::~AspellChecker()
 SpellChecker::Result AspellChecker::check(WordLangTuple const & word)
 {
   
-       AspellSpeller * m =
-               d->speller(word.lang()->code(), word.lang()->variety());
+       AspellSpeller * m = d->speller(word.lang());
 
        if (!m)
-               return OK;
+               return WORD_OK;
 
        if (word.word().empty())
                // MSVC compiled Aspell doesn't like it.
-               return OK;
+               return WORD_OK;
+
+       string const word_str = to_utf8(word.word());
+       SpellChecker::Result rc = d->check(m, word_str);
+       return (rc == WORD_OK && d->learned(word)) ? LEARNED_WORD : rc;
+}
 
-       const char * word_str = to_utf8(word.word()).c_str();
-       int const word_ok = aspell_speller_check(m, word_str, -1);
-       LASSERT(word_ok != -1, /**/);
 
-       return (word_ok) ? OK : UNKNOWN_WORD;
+void AspellChecker::advanceChangeNumber()
+{
+       nextChangeNumber();
 }
 
 
 void AspellChecker::insert(WordLangTuple const & word)
 {
-       Spellers::iterator it = d->spellers_.find(
-               d->spellerID(word.lang()->code(), word.lang()->variety()));
-       if (it != d->spellers_.end()) {
-               AspellSpeller * speller = to_aspell_speller(it->second.e_speller);
-               aspell_speller_add_to_personal(speller, to_utf8(word.word()).c_str(), -1);
-       }
+       d->insert(word);
+       advanceChangeNumber();
 }
 
 
 void AspellChecker::accept(WordLangTuple const & word)
 {
-       Spellers::iterator it = d->spellers_.find(
-               d->spellerID(word.lang()->code(), word.lang()->variety()));
+       Spellers::iterator it = d->spellers_.find(d->spellerID(word.lang()));
        if (it != d->spellers_.end()) {
                AspellSpeller * speller = to_aspell_speller(it->second.e_speller);
                aspell_speller_add_to_session(speller, to_utf8(word.word()).c_str(), -1);
+               d->accept(it->second, word);
+               advanceChangeNumber();
        }
 }
 
@@ -306,8 +403,7 @@ void AspellChecker::suggest(WordLangTuple const & wl,
        docstring_list & suggestions)
 {
        suggestions.clear();
-       AspellSpeller * m =
-               d->speller(wl.lang()->code(), wl.lang()->variety());
+       AspellSpeller * m = d->speller(wl.lang());
 
        if (!m)
                return;
@@ -329,6 +425,11 @@ void AspellChecker::suggest(WordLangTuple const & wl,
        delete_aspell_string_enumeration(els);
 }
 
+void AspellChecker::remove(WordLangTuple const & word)
+{
+       d->remove(word);
+       advanceChangeNumber();
+}
 
 bool AspellChecker::hasDictionary(Language const * lang) const
 {