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/lassert.h"
|
||||||
#include "support/debug.h"
|
#include "support/debug.h"
|
||||||
|
#include "support/docstring_list.h"
|
||||||
|
|
||||||
#include <aspell.h>
|
#include <aspell.h>
|
||||||
|
|
||||||
@ -40,18 +41,19 @@ typedef std::map<std::string, Speller> Spellers;
|
|||||||
|
|
||||||
struct AspellChecker::Private
|
struct AspellChecker::Private
|
||||||
{
|
{
|
||||||
Private(): els(0), spell_error_object(0) {}
|
Private(): spell_error_object(0) {}
|
||||||
|
|
||||||
~Private();
|
~Private();
|
||||||
|
|
||||||
/// add a speller of the given language
|
/// 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
|
/// the spellers
|
||||||
Spellers spellers_;
|
Spellers spellers_;
|
||||||
|
|
||||||
/// FIXME
|
|
||||||
AspellStringEnumeration * els;
|
|
||||||
/// FIXME
|
/// FIXME
|
||||||
AspellCanHaveError * spell_error_object;
|
AspellCanHaveError * spell_error_object;
|
||||||
};
|
};
|
||||||
@ -64,9 +66,6 @@ AspellChecker::Private::~Private()
|
|||||||
spell_error_object = 0;
|
spell_error_object = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (els)
|
|
||||||
delete_aspell_string_enumeration(els);
|
|
||||||
|
|
||||||
Spellers::iterator it = spellers_.begin();
|
Spellers::iterator it = spellers_.begin();
|
||||||
Spellers::iterator end = spellers_.end();
|
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();
|
AspellConfig * config = new_aspell_config();
|
||||||
// FIXME The aspell documentation says to use "lang"
|
// 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);
|
delete_aspell_can_have_error(spell_error_object);
|
||||||
spell_error_object = 0;
|
spell_error_object = 0;
|
||||||
|
|
||||||
if (aspell_error_number(err) == 0) {
|
if (aspell_error_number(err) != 0) {
|
||||||
Speller m;
|
// FIXME: We should we indicate somehow that this language is not
|
||||||
m.speller = to_aspell_speller(err);
|
// supported.
|
||||||
m.config = config;
|
|
||||||
spellers_[lang] = m;
|
|
||||||
} else {
|
|
||||||
spell_error_object = err;
|
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)
|
SpellChecker::Result AspellChecker::check(WordLangTuple const & word)
|
||||||
{
|
{
|
||||||
Result res = UNKNOWN_WORD;
|
AspellSpeller * m = d->speller(word.lang_code());
|
||||||
|
if (!m)
|
||||||
Spellers::iterator it = d->spellers_.find(word.lang_code());
|
return OK;
|
||||||
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;
|
|
||||||
|
|
||||||
if (word.word().empty())
|
if (word.word().empty())
|
||||||
// MSVC compiled Aspell doesn't like it.
|
// 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);
|
int const word_ok = aspell_speller_check(m, to_utf8(word.word()).c_str(), -1);
|
||||||
LASSERT(word_ok != -1, /**/);
|
LASSERT(word_ok != -1, /**/);
|
||||||
|
|
||||||
if (word_ok)
|
return (word_ok) ? OK : UNKNOWN_WORD;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -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)
|
AspellWordList const * sugs =
|
||||||
str = aspell_string_enumeration_next(d->els);
|
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();
|
||||||
~AspellChecker();
|
~AspellChecker();
|
||||||
|
|
||||||
/// check the given word and return the result
|
/// SpellChecker inherited methods.
|
||||||
|
///@{
|
||||||
enum Result check(WordLangTuple const &);
|
enum Result check(WordLangTuple const &);
|
||||||
|
void suggest(WordLangTuple const &, docstring_list &);
|
||||||
/// insert the given word into the personal dictionary
|
|
||||||
void insert(WordLangTuple const &);
|
void insert(WordLangTuple const &);
|
||||||
|
|
||||||
/// accept the given word temporarily
|
|
||||||
void accept(WordLangTuple const &);
|
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();
|
docstring const error();
|
||||||
|
///@}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct Private;
|
struct Private;
|
||||||
|
@ -17,12 +17,17 @@
|
|||||||
|
|
||||||
#include "support/lassert.h"
|
#include "support/lassert.h"
|
||||||
#include "support/debug.h"
|
#include "support/debug.h"
|
||||||
|
#include "support/docstring_list.h"
|
||||||
|
|
||||||
#include <hunspell/hunspell.hxx>
|
#include <hunspell/hunspell.hxx>
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <string>
|
#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;
|
using namespace std;
|
||||||
|
|
||||||
namespace lyx {
|
namespace lyx {
|
||||||
@ -35,11 +40,51 @@ typedef map<std::string, Hunspell *> Spellers;
|
|||||||
|
|
||||||
struct HunspellChecker::Private
|
struct HunspellChecker::Private
|
||||||
{
|
{
|
||||||
|
Private() {}
|
||||||
|
|
||||||
|
~Private();
|
||||||
|
|
||||||
|
Hunspell * addSpeller(string const & lang);
|
||||||
|
Hunspell * speller(string const & lang);
|
||||||
|
|
||||||
/// the spellers
|
/// the spellers
|
||||||
Spellers 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)
|
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;
|
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)
|
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();
|
||||||
~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 insert(WordLangTuple const &);
|
||||||
void accept(WordLangTuple const &);
|
void accept(WordLangTuple const &);
|
||||||
docstring const nextMiss();
|
|
||||||
docstring const error();
|
docstring const error();
|
||||||
|
///@}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct Private;
|
struct Private;
|
||||||
|
@ -3088,10 +3088,11 @@ bool Paragraph::spellCheck(pos_type & from, pos_type & to, WordLangTuple & wl,
|
|||||||
if (lyxrc.spellcheck_continuously)
|
if (lyxrc.spellcheck_continuously)
|
||||||
d->fontlist_.setMisspelled(from, to, misspelled);
|
d->fontlist_.setMisspelled(from, to, misspelled);
|
||||||
|
|
||||||
if (misspelled) {
|
if (misspelled)
|
||||||
while (!(word = speller->nextMiss()).empty())
|
speller->suggest(wl, suggestions);
|
||||||
suggestions.push_back(word);
|
else
|
||||||
}
|
suggestions.clear();
|
||||||
|
|
||||||
return misspelled;
|
return misspelled;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,6 +20,7 @@ namespace lyx {
|
|||||||
|
|
||||||
class BufferParams;
|
class BufferParams;
|
||||||
class WordLangTuple;
|
class WordLangTuple;
|
||||||
|
class docstring_list;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Pure virtual base class of all spellchecker implementations.
|
* Pure virtual base class of all spellchecker implementations.
|
||||||
@ -37,8 +38,6 @@ public:
|
|||||||
COMPOUND_WORD,
|
COMPOUND_WORD,
|
||||||
/// word not found
|
/// word not found
|
||||||
UNKNOWN_WORD,
|
UNKNOWN_WORD,
|
||||||
/// not found, with suggestions
|
|
||||||
SUGGESTED_WORDS,
|
|
||||||
/// number of other ignored "word"
|
/// number of other ignored "word"
|
||||||
IGNORED_WORD
|
IGNORED_WORD
|
||||||
};
|
};
|
||||||
@ -47,7 +46,9 @@ public:
|
|||||||
|
|
||||||
/// check the given word of the given lang code and return the result
|
/// check the given word of the given lang code and return the result
|
||||||
virtual enum Result check(WordLangTuple const &) = 0;
|
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
|
/// insert the given word into the personal dictionary
|
||||||
virtual void insert(WordLangTuple const &) = 0;
|
virtual void insert(WordLangTuple const &) = 0;
|
||||||
@ -55,9 +56,6 @@ public:
|
|||||||
/// accept the given word temporarily
|
/// accept the given word temporarily
|
||||||
virtual void accept(WordLangTuple const &) = 0;
|
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
|
/// give an error message on messy exit
|
||||||
virtual docstring const error() = 0;
|
virtual docstring const error() = 0;
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user