string toAspellWord(docstring const & word) const;
SpellChecker::Result check(AspellSpeller * m,
- WordLangTuple const & word) const;
+ WordLangTuple const & word);
void initSessionDictionary(Speller const & speller, PersonalWordList * pd);
void addToSession(AspellCanHaveError * speller, docstring const & word);
void insert(WordLangTuple const & word);
void remove(WordLangTuple const & word);
- bool learned(WordLangTuple const & word);
void accept(Speller & speller, WordLangTuple const & word);
{
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();
+ docstring_list::const_iterator it = pd->includes_begin();
+ docstring_list::const_iterator et = pd->includes_end();
for (; it != et; ++it) {
addToSession(speller.e_speller, *it);
}
SpellChecker::Result AspellChecker::Private::check(
AspellSpeller * m, WordLangTuple const & word)
- const
{
+ PersonalWordList * pd = personal_[word.lang()->lang()];
SpellChecker::Result result = WORD_OK;
docstring w1;
LYXERR(Debug::GUI, "spellCheck: \"" <<
int const word_ok = aspell_speller_check(m, word_str.c_str(), -1);
LASSERT(word_ok != -1, return UNKNOWN_WORD);
result = (word_ok) ? WORD_OK : UNKNOWN_WORD;
+ if (result == WORD_OK && pd && pd->excluded(w1)) {
+ result = UNKNOWN_WORD;
+ }
if (rest.empty())
break;
rest = split(rest, w1, '-');
string const word_str = toAspellWord(word.word());
int const word_ok = aspell_speller_check(m, word_str.c_str(), -1);
LASSERT(word_ok != -1, return UNKNOWN_WORD);
- return (word_ok) ? WORD_OK : UNKNOWN_WORD;
+ result = (word_ok) ? WORD_OK : UNKNOWN_WORD;
+ if (result == WORD_OK && pd && pd->excluded(word.word())) {
+ result = UNKNOWN_WORD;
+ }
+ return result;
}
void AspellChecker::Private::accept(Speller & speller, WordLangTuple const & word)
}
}
-bool AspellChecker::Private::learned(WordLangTuple const & word)
-{
- PersonalWordList * pd = personal_[word.lang()->lang()];
- if (!pd)
- return false;
- return pd->exists(word.word());
-}
-
AspellChecker::AspellChecker()
: d(new Private)
if (it->word() == word.word())
return DOCUMENT_LEARNED_WORD;
}
- SpellChecker::Result rc = d->check(m, word);
- return (rc == WORD_OK && d->learned(word)) ? LEARNED_WORD : rc;
+ return d->check(m, word);
}
/// personal word list interface
void remove(WordLangTuple const & wl);
void insert(WordLangTuple const & wl);
- bool learned(WordLangTuple const & wl);
/// the spellers
Spellers spellers_;
///
PersonalWordList * pd = new PersonalWordList(lang->lang());
pd->load();
personal_[lang->lang()] = pd;
- docstring_list::const_iterator it = pd->begin();
- docstring_list::const_iterator et = pd->end();
+ docstring_list::const_iterator it = pd->includes_begin();
+ docstring_list::const_iterator et = pd->includes_end();
for (; it != et; ++it) {
string const word_to_add = to_iconv_encoding(*it, encoding);
h->add(word_to_add.c_str());
}
+ it = pd->excludes_begin();
+ et = pd->excludes_end();
+ for (; it != et; ++it) {
+ string const word_to_add = to_iconv_encoding(*it, encoding);
+ h->remove(word_to_add.c_str());
+ }
}
return h;
}
}
-bool HunspellChecker::Private::learned(WordLangTuple const & wl)
-{
- PersonalWordList * pd = personal_[wl.lang()->lang()];
- if (!pd)
- return false;
- return pd->exists(wl.word());
-}
-
-
HunspellChecker::HunspellChecker()
: d(new Private)
{}
#else
if (h->spell(word_to_check.c_str(), &info))
#endif
- return d->learned(wl) ? LEARNED_WORD : WORD_OK;
+ return WORD_OK;
if (info & SPELL_COMPOUND) {
// FIXME: What to do with that?
namespace lyx {
-FileName PersonalWordList::dictfile() const
+FileName PersonalWordListPart::dictfile() const
{
- string fname = "pwl_" + lang_ + ".dict";
+ string fext = is_includes_ ? ".dict" : ".excl";
+ string fname = "pwl_" + lang_ + fext;
return FileName(addName(package().user_support().absFileName(),fname));
}
-docstring_list::const_iterator PersonalWordList::begin() const
+docstring_list::const_iterator PersonalWordListPart::begin() const
{
return words_.begin();
}
-docstring_list::const_iterator PersonalWordList::end() const
+docstring_list::const_iterator PersonalWordListPart::end() const
{
return words_.end();
}
-void PersonalWordList::load()
+void PersonalWordListPart::load()
{
FileName fn = dictfile();
LYXERR(Debug::FILES, "load personal dictionary from: " << fn);
}
-void PersonalWordList::save()
+void PersonalWordListPart::save()
{
if (!isDirty())
return;
}
-bool PersonalWordList::equalwords(docstring const & w1, docstring const & w2) const
+bool PersonalWordListPart::equalwords(docstring const & w1, docstring const & w2) const
{
return w1 == w2;
}
-bool PersonalWordList::exists(docstring const & word) const
+bool PersonalWordListPart::exists(docstring const & word) const
{
docstring_list::const_iterator it = words_.begin();
docstring_list::const_iterator et = words_.end();
}
-void PersonalWordList::insert(docstring const & word)
+void PersonalWordListPart::insert(docstring const & word)
{
if (exists(word))
return;
}
-void PersonalWordList::remove(docstring const & word)
+void PersonalWordListPart::remove(docstring const & word)
{
docstring_list::iterator it = words_.begin();
docstring_list::const_iterator et = words_.end();
namespace lyx {
-/// A PersonalWordList holds a word list with persistent state
-class PersonalWordList {
-public:
- /// the word list has an associated language
- PersonalWordList(std::string const & lang) : lang_(lang), dirty_(false) {}
+/// A PersonalWordListPart holds a part of the word list with persistent state
+struct PersonalWordListPart {
+ /// the word list has an associated language, and a flag indicating whether it is an includes or excludes list
+ PersonalWordListPart(std::string lang, bool is_includes) : lang_(lang), is_includes_(is_includes), dirty_(false) {}
/// the location of the file to hold to word list
lyx::support::FileName dictfile() const;
/// (re)load the word list from file
///
std::string lang_;
///
+ bool is_includes_;
+ ///
bool dirty_;
///
bool equalwords(docstring const & w1, docstring const & w2) const;
///
- std::string header() const { return "# personal word list"; }
+ std::string header() const { return is_includes_ ? "# personal word list" : "# personal world list (exclusions)"; }
///
void dirty(bool flag) { dirty_ = flag; }
};
+/// A PersonalWordState holds a list of words to include (i.e. marked as spelt correctly), and a list of words to exclude (i.e. marked as spelled incorrectly)
+class PersonalWordList {
+public:
+ /// the word list has an associated language
+ PersonalWordList(std::string lang) : includes_(lang, true), excludes_(lang, false) {}
+
+ /// first item in includes word list
+ docstring_list::const_iterator includes_begin() const { return includes_.begin(); }
+ /// end of includes word list
+ docstring_list::const_iterator includes_end() const { return includes_.end(); }
+ /// first item in excludes word list
+ docstring_list::const_iterator excludes_begin() const { return excludes_.begin(); }
+ /// end of excludes word list
+ docstring_list::const_iterator excludes_end() const { return excludes_.end(); }
+ /// (re)load both word lists from file
+ void load() { includes_.load(); excludes_.load(); }
+ /// save both word lists to file
+ void save() { includes_.save(); excludes_.save(); }
+ /// is the given word excluded? (i.e. we previously called remove)
+ bool excluded(docstring const & word) const { return excludes_.exists(word); }
+ /// is the given word included? (i.e. we previously called insert)
+ bool included(docstring const & word) const { return includes_.exists(word); }
+ /// insert a given word to the set of valid words
+ void insert(docstring const & word) { excludes_.remove(word); includes_.insert(word); }
+ /// remove given word from the set of valid words
+ void remove(docstring const & word) { includes_.remove(word); excludes_.insert(word); }
+
+private:
+ /// The list of words to include
+ PersonalWordListPart includes_;
+ /// The list of words to exclude
+ PersonalWordListPart excludes_;
+};
+
} // namespace lyx
#endif // PERSONAL_WORD_LIST_H
enum Result {
/// word is correct
WORD_OK = 1,
- /// root of given word was found
- ROOT_FOUND,
- /// word found through compound formation
- COMPOUND_WORD,
/// word not found
UNKNOWN_WORD,
- /// number of other ignored "word"
- IGNORED_WORD,
- /// number of personal dictionary "word"
- LEARNED_WORD,
/// number of document dictionary "word"
DOCUMENT_LEARNED_WORD,
/// missing dictionary for language
/// does the spell check failed
static bool misspelled(Result res) {
return res != WORD_OK
- && res != IGNORED_WORD
&& res != NO_DICTIONARY
- && res != LEARNED_WORD
&& res != DOCUMENT_LEARNED_WORD; }
/// check the given word of the given lang code and return the result
}
}
break;
- case SpellChecker::LEARNED_WORD: {
- LYXERR(Debug::GUI, "Learned Word.");
+ case SpellChecker::WORD_OK: {
+ LYXERR(Debug::GUI, "Valid Word.");
docstring const arg = wl.word() + " " + from_ascii(wl.lang()->lang());
add(MenuItem(MenuItem::Command, qt_("Remove from personal dictionary|r"),
FuncRequest(LFUN_SPELLING_REMOVE, arg)));
case SpellChecker::NO_DICTIONARY:
LYXERR(Debug::GUI, "No dictionary for language " + from_ascii(wl.lang()->lang()));
// FALLTHROUGH
- case SpellChecker::WORD_OK:
- case SpellChecker::COMPOUND_WORD:
- case SpellChecker::ROOT_FOUND:
- case SpellChecker::IGNORED_WORD:
- break;
}
}