X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2FAspellChecker.cpp;h=642f804977c77d37ab6298a206701a855451fe73;hb=edc94a578f3e43c036842f91f25cf2eea42eb6cf;hp=263e379c23b8e406d44b8b8e2936abf0685dbaea;hpb=f6071af49d12683a52753f280626d6e7dadcc172;p=lyx.git diff --git a/src/AspellChecker.cpp b/src/AspellChecker.cpp index 263e379c23..642f804977 100644 --- a/src/AspellChecker.cpp +++ b/src/AspellChecker.cpp @@ -12,6 +12,8 @@ #include #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 Spellers; +typedef map 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. @@ -217,30 +262,86 @@ AspellSpeller * AspellChecker::Private::addSpeller(string const & lang, if (aspell_error_number(m.e_speller) != 0) { // FIXME: We should indicate somehow that this language is not supported. LYXERR(Debug::FILES, "aspell error: " << aspell_error_message(m.e_speller)); + delete_aspell_can_have_error(m.e_speller); + 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; - return to_aspell_speller(m.e_speller); + + 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()); } @@ -258,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(); } } @@ -302,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; @@ -325,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 { @@ -334,7 +439,7 @@ bool AspellChecker::hasDictionary(Language const * lang) const if (lang) { for (; it != end && !have; ++it) { - have = d->isValidDictionary(it->second.config, lang->code(), lang->variety()); + have = it->second.config && d->isValidDictionary(it->second.config, lang->code(), lang->variety()); } if (!have) { AspellConfig * config = d->getConfig(lang->code(), lang->variety());