#include <config.h>
-#include "support/debug.h"
-
-#include <aspell.h>
-
#include "AspellChecker.h"
#include "LyXRC.h"
#include "WordLangTuple.h"
#include "support/lassert.h"
+#include "support/debug.h"
+#include "support/docstring_list.h"
+
+#include <aspell.h>
+
+#include <map>
+#include <string>
using namespace std;
namespace lyx {
-AspellChecker::AspellChecker(): els(0), spell_error_object(0)
+namespace {
+
+struct Speller {
+ AspellSpeller * speller;
+ AspellConfig * config;
+};
+
+typedef std::map<std::string, Speller> Spellers;
+
+} // anon namespace
+
+struct AspellChecker::Private
{
-}
+ Private(): spell_error_object(0) {}
+ ~Private();
-AspellChecker::~AspellChecker()
+ /// add a speller of the given language
+ AspellSpeller * addSpeller(string const & lang);
+
+ ///
+ AspellSpeller * speller(string const & lang);
+
+ /// the spellers
+ Spellers spellers_;
+
+ /// FIXME
+ AspellCanHaveError * spell_error_object;
+};
+
+
+AspellChecker::Private::~Private()
{
if (spell_error_object) {
delete_aspell_can_have_error(spell_error_object);
spell_error_object = 0;
}
- if (els)
- delete_aspell_string_enumeration(els);
-
Spellers::iterator it = spellers_.begin();
Spellers::iterator end = spellers_.end();
}
-void AspellChecker::addSpeller(string const & lang)
+AspellSpeller * AspellChecker::Private::addSpeller(string const & lang)
{
AspellConfig * config = new_aspell_config();
// FIXME The aspell documentation says to use "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;
}
-AspellChecker::Result AspellChecker::check(WordLangTuple const & word)
+AspellSpeller * AspellChecker::Private::speller(string const & lang)
{
- Result res = UNKNOWN_WORD;
-
- Spellers::iterator it = spellers_.find(word.lang_code());
- if (it == spellers_.end()) {
- addSpeller(word.lang_code());
- it = spellers_.find(word.lang_code());
- // FIXME
- if (it == spellers_.end())
- return res;
- }
+ Spellers::iterator it = spellers_.find(lang);
+ if (it != spellers_.end())
+ return it->second.speller;
+
+ return addSpeller(lang);
+}
- AspellSpeller * m = it->second.speller;
+
+AspellChecker::AspellChecker(): d(new Private)
+{
+}
+
+
+AspellChecker::~AspellChecker()
+{
+ delete d;
+}
+
+
+SpellChecker::Result AspellChecker::check(WordLangTuple const & word)
+{
+ AspellSpeller * m = d->speller(word.lang_code());
+ if (!m)
+ return OK;
if (word.word().empty())
// MSVC compiled Aspell doesn't like it.
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, /**/);
- 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;
}
void AspellChecker::insert(WordLangTuple const & word)
{
- Spellers::iterator it = spellers_.find(word.lang_code());
- if (it != spellers_.end())
+ Spellers::iterator it = d->spellers_.find(word.lang_code());
+ if (it != d->spellers_.end())
aspell_speller_add_to_personal(it->second.speller, to_utf8(word.word()).c_str(), -1);
}
void AspellChecker::accept(WordLangTuple const & word)
{
- Spellers::iterator it = spellers_.find(word.lang_code());
- if (it != spellers_.end())
+ Spellers::iterator it = d->spellers_.find(word.lang_code());
+ if (it != d->spellers_.end())
aspell_speller_add_to_session(it->second.speller, to_utf8(word.word()).c_str(), -1);
}
-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 (els)
- str = aspell_string_enumeration_next(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;
+
+ for (;;) {
+ char const * str = aspell_string_enumeration_next(els);
+ if (!str)
+ break;
+ suggestions.push_back(from_utf8(str));
+ }
- return (str ? from_utf8(str) : docstring());
+ delete_aspell_string_enumeration(els);
}
{
char const * err = 0;
- if (spell_error_object && aspell_error_number(spell_error_object) != 0)
- err = aspell_error_message(spell_error_object);
+ if (d->spell_error_object && aspell_error_number(d->spell_error_object) != 0)
+ err = aspell_error_message(d->spell_error_object);
// FIXME UNICODE: err is not in UTF8, but probably the locale encoding
return (err ? from_utf8(err) : docstring());