mirror of
https://git.lyx.org/repos/lyx.git
synced 2024-11-09 18:31:04 +00:00
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:
parent
17e6ab45b0
commit
1f53de6592
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user