SpellChecker work:

* Move suggestion searching out of check() and onto suggest().
* Cleanup a bit AspellChecker
* Begin Hunspell support (not tested and does not link yet)


git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@30824 a592a061-630c-0410-9148-cb99ea01b6c8
This commit is contained in:
Abdelrazak Younes 2009-08-02 09:17:32 +00:00
parent 17e6ab45b0
commit 1f53de6592
6 changed files with 148 additions and 70 deletions

View File

@ -17,6 +17,7 @@
#include "support/lassert.h"
#include "support/debug.h"
#include "support/docstring_list.h"
#include <aspell.h>
@ -40,18 +41,19 @@ typedef std::map<std::string, Speller> 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);
}

View File

@ -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;

View File

@ -17,12 +17,17 @@
#include "support/lassert.h"
#include "support/debug.h"
#include "support/docstring_list.h"
#include <hunspell/hunspell.hxx>
#include <map>
#include <string>
// 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<std::string, Hunspell *> 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
}

View File

@ -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;

View File

@ -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;
}

View File

@ -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
};
@ -48,6 +47,8 @@ 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;
};