diff --git a/src/AspellChecker.cpp b/src/AspellChecker.cpp index 802b541a57..98506b88c4 100644 --- a/src/AspellChecker.cpp +++ b/src/AspellChecker.cpp @@ -17,6 +17,7 @@ #include "support/lassert.h" #include "support/debug.h" +#include "support/docstring_list.h" #include @@ -40,18 +41,19 @@ typedef std::map Spellers; struct AspellChecker::Private { - Private(): els(0), spell_error_object(0) {} + Private(): spell_error_object(0) {} ~Private(); /// add a speller of the given language - void addSpeller(std::string const & lang); + AspellSpeller * addSpeller(string const & lang); + + /// + AspellSpeller * speller(string const & lang); /// the spellers Spellers spellers_; - /// FIXME - AspellStringEnumeration * els; /// FIXME AspellCanHaveError * spell_error_object; }; @@ -64,9 +66,6 @@ AspellChecker::Private::~Private() spell_error_object = 0; } - if (els) - delete_aspell_string_enumeration(els); - Spellers::iterator it = spellers_.begin(); Spellers::iterator end = spellers_.end(); @@ -78,7 +77,7 @@ AspellChecker::Private::~Private() } -void AspellChecker::Private::addSpeller(string const & lang) +AspellSpeller * AspellChecker::Private::addSpeller(string const & lang) { AspellConfig * config = new_aspell_config(); // FIXME The aspell documentation says to use "lang" @@ -102,14 +101,27 @@ void AspellChecker::Private::addSpeller(string const & lang) delete_aspell_can_have_error(spell_error_object); spell_error_object = 0; - if (aspell_error_number(err) == 0) { - Speller m; - m.speller = to_aspell_speller(err); - m.config = config; - spellers_[lang] = m; - } else { + if (aspell_error_number(err) != 0) { + // FIXME: We should we indicate somehow that this language is not + // supported. spell_error_object = err; + return 0; } + Speller m; + m.speller = to_aspell_speller(err); + m.config = config; + spellers_[lang] = m; + return m.speller; +} + + +AspellSpeller * AspellChecker::Private::speller(string const & lang) +{ + Spellers::iterator it = spellers_.find(lang); + if (it != spellers_.end()) + return it->second.speller; + + return addSpeller(lang); } @@ -126,18 +138,9 @@ AspellChecker::~AspellChecker() SpellChecker::Result AspellChecker::check(WordLangTuple const & word) { - Result res = UNKNOWN_WORD; - - Spellers::iterator it = d->spellers_.find(word.lang_code()); - if (it == d->spellers_.end()) { - d->addSpeller(word.lang_code()); - it = d->spellers_.find(word.lang_code()); - // FIXME - if (it == d->spellers_.end()) - return res; - } - - AspellSpeller * m = it->second.speller; + AspellSpeller * m = d->speller(word.lang_code()); + if (!m) + return OK; if (word.word().empty()) // MSVC compiled Aspell doesn't like it. @@ -146,19 +149,7 @@ SpellChecker::Result AspellChecker::check(WordLangTuple const & word) int const word_ok = aspell_speller_check(m, to_utf8(word.word()).c_str(), -1); LASSERT(word_ok != -1, /**/); - if (word_ok) - return OK; - - AspellWordList const * sugs = - aspell_speller_suggest(m, to_utf8(word.word()).c_str(), -1); - LASSERT(sugs != 0, /**/); - d->els = aspell_word_list_elements(sugs); - if (aspell_word_list_empty(sugs)) - res = UNKNOWN_WORD; - else - res = SUGGESTED_WORDS; - - return res; + return (word_ok) ? OK : UNKNOWN_WORD; } @@ -178,14 +169,29 @@ void AspellChecker::accept(WordLangTuple const & word) } -docstring const AspellChecker::nextMiss() +void AspellChecker::suggest(WordLangTuple const & wl, + docstring_list & suggestions) { - char const * str = 0; + suggestions.clear(); + AspellSpeller * m = d->speller(wl.lang_code()); + if (!m) + return; - if (d->els) - str = aspell_string_enumeration_next(d->els); + AspellWordList const * sugs = + aspell_speller_suggest(m, to_utf8(wl.word()).c_str(), -1); + LASSERT(sugs != 0, /**/); + AspellStringEnumeration * els = aspell_word_list_elements(sugs); + if (!els || aspell_word_list_empty(sugs)) + return; - return (str ? from_utf8(str) : docstring()); + for (;;) { + char const * str = aspell_string_enumeration_next(els); + if (!str) + break; + suggestions.push_back(from_utf8(str)); + } + + delete_aspell_string_enumeration(els); } diff --git a/src/AspellChecker.h b/src/AspellChecker.h index 4477d31241..61e904c316 100644 --- a/src/AspellChecker.h +++ b/src/AspellChecker.h @@ -23,20 +23,14 @@ public: AspellChecker(); ~AspellChecker(); - /// check the given word and return the result + /// SpellChecker inherited methods. + ///@{ enum Result check(WordLangTuple const &); - - /// insert the given word into the personal dictionary + void suggest(WordLangTuple const &, docstring_list &); void insert(WordLangTuple const &); - - /// accept the given word temporarily void accept(WordLangTuple const &); - - /// return the next near miss after a SUGGESTED_WORDS result - docstring const nextMiss(); - - /// give an error message on messy exit docstring const error(); + ///@} private: struct Private; diff --git a/src/HunspellChecker.cpp b/src/HunspellChecker.cpp index fc6e0e5b37..c51c0001a6 100644 --- a/src/HunspellChecker.cpp +++ b/src/HunspellChecker.cpp @@ -17,12 +17,17 @@ #include "support/lassert.h" #include "support/debug.h" +#include "support/docstring_list.h" #include #include #include +// FIXME (Abdel): I still got linking problems but if anybody wants +// to try, defines this to 1. +#define TRY_HUNSPELL 0 + using namespace std; namespace lyx { @@ -35,11 +40,51 @@ typedef map Spellers; struct HunspellChecker::Private { + Private() {} + + ~Private(); + + Hunspell * addSpeller(string const & lang); + Hunspell * speller(string const & lang); + /// the spellers Spellers spellers_; }; +HunspellChecker::Private::~Private() +{ +#if TRY_HUNSPELL + Spellers::iterator it = spellers_.begin(); + Spellers::iterator end = spellers_.end(); + + for (; it != end; ++it) { + delete it->second; + } +#endif +} + + +Hunspell * HunspellChecker::Private::addSpeller(string const & lang) +{ + // FIXME: not implemented! + + // FIXME: We should we indicate somehow that this language is not + // supported. + return 0; +} + + +Hunspell * HunspellChecker::Private::speller(string const & lang) +{ + Spellers::iterator it = spellers_.find(lang); + if (it != spellers_.end()) + return it->second; + + return addSpeller(lang); +} + + HunspellChecker::HunspellChecker(): d(new Private) { } @@ -51,25 +96,56 @@ HunspellChecker::~HunspellChecker() } -SpellChecker::Result HunspellChecker::check(WordLangTuple const & word) +SpellChecker::Result HunspellChecker::check(WordLangTuple const & wl) { + string const word_to_check = to_utf8(wl.word()); +#if TRY_HUNSPELL + Hunspell * h = d->speller(wl.lang_code()); + int info; + if (h->spell(word_to_check.c_str(), &info)) + return OK; + // FIXME: What to do with that? + switch (info) { + case SPELL_COMPOUND: + case SPELL_FORBIDDEN: + default: + return UNKNOWN_WORD; + } + return UNKNOWN_WORD; +#endif return OK; } -void HunspellChecker::insert(WordLangTuple const & word) +void HunspellChecker::insert(WordLangTuple const & wl) { + string const word_to_check = to_utf8(wl.word()); +#if TRY_HUNSPELL + Hunspell * h = d->speller(wl.lang_code()); + h->add(word_to_check.c_str()); +#endif } void HunspellChecker::accept(WordLangTuple const & word) { + // FIXME: not implemented! } -docstring const HunspellChecker::nextMiss() +void HunspellChecker::suggest(WordLangTuple const & wl, + docstring_list & suggestions) { - return docstring(); + suggestions.clear(); + string const word_to_check = to_utf8(wl.word()); +#if TRY_HUNSPELL + Hunspell * h = d->speller(wl.lang_code()); + char *** suggestion_list = 0; + int const suggestion_number = h->suggest(suggestion_list, word_to_check.c_str()); + if (suggestion_number == 0) + return; + h->free_list(suggestion_list, suggestion_number); +#endif } diff --git a/src/HunspellChecker.h b/src/HunspellChecker.h index 8defa22e41..8eb470a22b 100644 --- a/src/HunspellChecker.h +++ b/src/HunspellChecker.h @@ -23,11 +23,14 @@ public: HunspellChecker(); ~HunspellChecker(); - SpellChecker::Result check(WordLangTuple const &); + /// SpellChecker inherited methods. + ///@{ + enum Result check(WordLangTuple const &); + void suggest(WordLangTuple const &, docstring_list &); void insert(WordLangTuple const &); void accept(WordLangTuple const &); - docstring const nextMiss(); docstring const error(); + ///@} private: struct Private; diff --git a/src/Paragraph.cpp b/src/Paragraph.cpp index 1b8924a1e9..5f23849553 100644 --- a/src/Paragraph.cpp +++ b/src/Paragraph.cpp @@ -3088,10 +3088,11 @@ bool Paragraph::spellCheck(pos_type & from, pos_type & to, WordLangTuple & wl, if (lyxrc.spellcheck_continuously) d->fontlist_.setMisspelled(from, to, misspelled); - if (misspelled) { - while (!(word = speller->nextMiss()).empty()) - suggestions.push_back(word); - } + if (misspelled) + speller->suggest(wl, suggestions); + else + suggestions.clear(); + return misspelled; } diff --git a/src/SpellChecker.h b/src/SpellChecker.h index b46b97400a..c6e3748c84 100644 --- a/src/SpellChecker.h +++ b/src/SpellChecker.h @@ -20,6 +20,7 @@ namespace lyx { class BufferParams; class WordLangTuple; +class docstring_list; /** * Pure virtual base class of all spellchecker implementations. @@ -37,8 +38,6 @@ public: COMPOUND_WORD, /// word not found UNKNOWN_WORD, - /// not found, with suggestions - SUGGESTED_WORDS, /// number of other ignored "word" IGNORED_WORD }; @@ -47,7 +46,9 @@ public: /// check the given word of the given lang code and return the result virtual enum Result check(WordLangTuple const &) = 0; - + + /// Gives suggestions. + virtual void suggest(WordLangTuple const &, docstring_list & suggestions) = 0; /// insert the given word into the personal dictionary virtual void insert(WordLangTuple const &) = 0; @@ -55,9 +56,6 @@ public: /// accept the given word temporarily virtual void accept(WordLangTuple const &) = 0; - /// return the next near miss after a SUGGESTED_WORDS result - virtual docstring const nextMiss() = 0; - /// give an error message on messy exit virtual docstring const error() = 0; };