/** * \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 #include #include "EnchantChecker.h" #include "LyXRC.h" #include "WordLangTuple.h" #include "support/lassert.h" #include "support/debug.h" #include "support/docstring_list.h" #include #include 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 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 = nullptr; } 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, std::vector const & docdict) { 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; vector::const_iterator it = docdict.begin(); for (; it != docdict.end(); ++it) { if (it->lang()->code() != word.lang()->code()) continue; if (it->word() == word.word()) return DOCUMENT_LEARNED_WORD; } 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 suggs = m->suggest(utf8word); vector::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