2 * \file HunspellChecker.cpp
3 * This file is part of LyX, the document processor.
4 * Licence details can be found in the file COPYING.
6 * \author Abdelrazak Younes
8 * Full author contact details are available in file CREDITS.
13 #include "HunspellChecker.h"
16 #include "WordLangTuple.h"
18 #include "support/debug.h"
19 #include "support/docstring_list.h"
20 #include "support/FileName.h"
21 #include "support/gettext.h"
22 #include "support/lassert.h"
23 #include "support/os.h"
25 #include <hunspell/hunspell.hxx>
31 using namespace lyx::support;
32 using namespace lyx::support::os;
38 typedef map<std::string, Hunspell *> Spellers;
42 struct HunspellChecker::Private
48 Hunspell * addSpeller(string const & lang);
49 Hunspell * speller(string const & lang);
56 HunspellChecker::Private::~Private()
58 Spellers::iterator it = spellers_.begin();
59 Spellers::iterator end = spellers_.end();
61 for (; it != end; ++it) {
67 Hunspell * HunspellChecker::Private::addSpeller(string const & lang)
69 string hunspell_path = external_path(lyxrc.hunspelldir_path);
70 LYXERR(Debug::FILES, "hunspell path: " << hunspell_path);
71 if (hunspell_path.empty())
74 hunspell_path += "/" + lang;
75 // replace '_' with '-' as this is the convention used by hunspell.
76 hunspell_path[hunspell_path.size() - 3] = '-';
77 FileName const affix(hunspell_path + ".aff");
78 FileName const dict(hunspell_path + ".dic");
79 if (!affix.isReadableFile()) {
80 // FIXME: We should indicate somehow that this language is not
82 LYXERR(Debug::FILES, "Hunspell affix file " << affix << " does not exist");
85 if (!dict.isReadableFile()) {
86 LYXERR(Debug::FILES, "Hunspell dictionary file " << dict << " does not exist");
89 Hunspell * h = new Hunspell(affix.absFilename().c_str(), dict.absFilename().c_str());
95 Hunspell * HunspellChecker::Private::speller(string const & lang)
97 Spellers::iterator it = spellers_.find(lang);
98 if (it != spellers_.end())
101 return addSpeller(lang);
105 HunspellChecker::HunspellChecker(): d(new Private)
110 HunspellChecker::~HunspellChecker()
116 SpellChecker::Result HunspellChecker::check(WordLangTuple const & wl)
118 string const word_to_check = to_utf8(wl.word());
119 Hunspell * h = d->speller(wl.lang_code());
123 if (h->spell(word_to_check.c_str(), &info))
126 if (info & SPELL_COMPOUND) {
127 // FIXME: What to do with that?
128 LYXERR(Debug::FILES, "Hunspell compound word found " << word_to_check);
130 if (info & SPELL_FORBIDDEN) {
131 // FIXME: What to do with that?
132 LYXERR(Debug::FILES, "Hunspell explicit forbidden word found " << word_to_check);
139 void HunspellChecker::insert(WordLangTuple const & wl)
141 string const word_to_check = to_utf8(wl.word());
142 Hunspell * h = d->speller(wl.lang_code());
145 h->add(word_to_check.c_str());
149 void HunspellChecker::accept(WordLangTuple const & word)
151 // FIXME: not implemented!
155 void HunspellChecker::suggest(WordLangTuple const & wl,
156 docstring_list & suggestions)
159 string const word_to_check = to_utf8(wl.word());
160 Hunspell * h = d->speller(wl.lang_code());
163 char ** suggestion_list;
164 int const suggestion_number = h->suggest(&suggestion_list, word_to_check.c_str());
165 if (suggestion_number <= 0)
167 for (int i = 0; i != suggestion_number; ++i)
168 suggestions.push_back(from_utf8(suggestion_list[i]));
169 h->free_list(&suggestion_list, suggestion_number);
173 docstring const HunspellChecker::error()