#include <config.h>
#include "AspellChecker.h"
+#include "PersonalWordList.h"
+
#include "LyXRC.h"
#include "WordLangTuple.h"
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
~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);
-
- /// create a unique ID from lang code and variety
- string const spellerID(string const & lang,
- string const & variety);
+ AspellSpeller * speller(Language const * lang);
bool isValidDictionary(AspellConfig * config,
string const & lang, string const & variety);
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"; }
+ const string dictDirectory(void) { return "dicts"; }
/// there the dat+cmap files lookup will happen
const string dataDirectory(void) { return "data"; }
/// os package directory constants
}
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;
+ }
}
}
-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.
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_[lang->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(lang->lang());
if (it != spellers_.end())
return to_aspell_speller(it->second.e_speller);
- return addSpeller(lang, variety);
+ return addSpeller(lang);
+}
+
+
+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)
+{
+ 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(word.lang()->lang());
+ if (it != spellers_.end()) {
+ initSessionDictionary(it->second, pd);
+ }
+}
+
+
+void AspellChecker::Private::insert(WordLangTuple const & word)
+{
+ Spellers::iterator it = spellers_.find(word.lang()->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());
+ }
+}
-string const AspellChecker::Private::spellerID(string const & lang,
- string const & variety)
+bool AspellChecker::Private::learned(WordLangTuple const & word)
{
- if (variety.empty())
- return lang;
- return lang + "-" + variety;
+ PersonalWordList * pd = personal_[word.lang()->lang()];
+ if (!pd)
+ return false;
+ return pd->exists(word.word());
}
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 WORD_OK;
return WORD_OK;
string const word_str = to_utf8(word.word());
- int const word_ok = aspell_speller_check(m, word_str.c_str(), -1);
- LASSERT(word_ok != -1, /**/);
+ SpellChecker::Result rc = d->check(m, word_str);
+ return (rc == WORD_OK && d->learned(word)) ? LEARNED_WORD : rc;
+}
- return (word_ok) ? WORD_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(word.lang()->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();
}
}
docstring_list & suggestions)
{
suggestions.clear();
- AspellSpeller * m =
- d->speller(wl.lang()->code(), wl.lang()->variety());
+ AspellSpeller * m = d->speller(wl.lang());
if (!m)
return;
delete_aspell_string_enumeration(els);
}
+void AspellChecker::remove(WordLangTuple const & word)
+{
+ d->remove(word);
+ advanceChangeNumber();
+}
bool AspellChecker::hasDictionary(Language const * lang) const
{