lyx_mirror/src/EnchantChecker.cpp
Jean-Marc Lasgouttes b3cca8086d Add support for enchant 2.x
As of enchant 2.x, it is required to create a Broker instance instead
of relying on a static one provided by the library.

Add autoconf and cmake (courtesy of Kornel) tests that check whether
one can indeed instantiate a Broker object, and act on the result in a
new broker() helper function.

Fixes bug #10986.

(cherry picked from commit 63a4e82874)
2018-03-19 17:33:17 +01:00

216 lines
3.7 KiB
C++

/**
* \file EnchantChecker.cpp
* This file is part of LyX, the document processor.
* Licence details can be found in the file COPYING.
*
* \author Caolán McNamara
* \author Jürgen Spitzmüller
*
* Full author contact details are available in file CREDITS.
*/
#include <config.h>
#include <enchant++.h>
#include "EnchantChecker.h"
#include "LyXRC.h"
#include "WordLangTuple.h"
#include "support/lassert.h"
#include "support/debug.h"
#include "support/docstring_list.h"
#include <map>
#include <string>
using namespace std;
namespace lyx {
namespace {
enchant::Broker & broker()
{
#ifdef HAVE_ENCHANT2
static enchant::Broker thebroker;
return thebroker;
#else
return *enchant::Broker::instance();
#endif
}
struct Speller {
enchant::Dict * speller;
};
typedef map<string, Speller> Spellers;
} // namespace
struct EnchantChecker::Private
{
Private()
{}
~Private();
/// add a speller of the given language
enchant::Dict * addSpeller(string const & lang);
///
enchant::Dict * speller(string const & lang);
/// the spellers
Spellers spellers_;
};
EnchantChecker::Private::~Private()
{
Spellers::iterator it = spellers_.begin();
Spellers::iterator end = spellers_.end();
for (; it != end; ++it)
delete it->second.speller;
}
enchant::Dict * EnchantChecker::Private::addSpeller(string const & lang)
{
Speller m;
try {
LYXERR(Debug::FILES, "request enchant speller for language " << lang);
m.speller = broker().request_dict(lang);
}
catch (enchant::Exception & e) {
// FIXME error handling?
const char * what = e.what();
LYXERR(Debug::FILES, "cannot add enchant speller: " <<
((what && *what) ? what : "unspecified enchant exception in request_dict()"));
m.speller = 0;
}
spellers_[lang] = m;
return m.speller;
}
enchant::Dict * EnchantChecker::Private::speller(string const & lang)
{
Spellers::iterator it = spellers_.find(lang);
if (it != spellers_.end())
return it->second.speller;
return addSpeller(lang);
}
EnchantChecker::EnchantChecker()
: d(new Private)
{}
EnchantChecker::~EnchantChecker()
{
delete d;
}
SpellChecker::Result EnchantChecker::check(WordLangTuple const & word)
{
enchant::Dict * m = d->speller(word.lang()->code());
if (!m)
return NO_DICTIONARY;
if (word.word().empty())
return WORD_OK;
string utf8word = to_utf8(word.word());
if (m->check(utf8word))
return WORD_OK;
return UNKNOWN_WORD;
}
void EnchantChecker::advanceChangeNumber()
{
nextChangeNumber();
}
void EnchantChecker::insert(WordLangTuple const & word)
{
enchant::Dict * m = d->speller(word.lang()->code());
if (m) {
m->add(to_utf8(word.word()));
advanceChangeNumber();
}
}
void EnchantChecker::remove(WordLangTuple const & word)
{
enchant::Dict * m = d->speller(word.lang()->code());
if (m) {
m->remove(to_utf8(word.word()));
advanceChangeNumber();
}
}
void EnchantChecker::accept(WordLangTuple const & word)
{
enchant::Dict * m = d->speller(word.lang()->code());
if (m) {
m->add_to_session(to_utf8(word.word()));
advanceChangeNumber();
}
}
void EnchantChecker::suggest(WordLangTuple const & wl,
docstring_list & suggestions)
{
suggestions.clear();
enchant::Dict * m = d->speller(wl.lang()->code());
if (!m)
return;
string utf8word = to_utf8(wl.word());
vector<string> suggs = m->suggest(utf8word);
vector<string>::const_iterator it = suggs.begin();
for (; it != suggs.end(); ++it)
suggestions.push_back(from_utf8(*it));
}
bool EnchantChecker::hasDictionary(Language const * lang) const
{
if (!lang)
return false;
return broker().dict_exists(lang->code());
}
int EnchantChecker::numDictionaries() const
{
return d->spellers_.size();
}
docstring const EnchantChecker::error()
{
return docstring();
}
} // namespace lyx