]> git.lyx.org Git - lyx.git/blob - src/HunspellChecker.cpp
fix warning
[lyx.git] / src / HunspellChecker.cpp
1 /**
2  * \file HunspellChecker.cpp
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author Abdelrazak Younes
7  *
8  * Full author contact details are available in file CREDITS.
9  */
10
11 #include <config.h>
12
13 #include "HunspellChecker.h"
14
15 #include "LyXRC.h"
16 #include "WordLangTuple.h"
17
18 #include "frontends/alert.h"
19
20 #include "support/debug.h"
21 #include "support/docstring_list.h"
22 #include "support/FileName.h"
23 #include "support/gettext.h"
24 #include "support/lassert.h"
25 #include "support/lstrings.h"
26 #include "support/os.h"
27
28 #include <hunspell/hunspell.hxx>
29
30 #include <map>
31 #include <string>
32
33 using namespace std;
34 using namespace lyx::support;
35 using namespace lyx::support::os;
36
37 namespace lyx {
38
39 namespace {
40
41 typedef map<std::string, Hunspell *> Spellers;
42
43 } // anon namespace
44
45 struct HunspellChecker::Private
46 {
47         Private() {}
48
49         ~Private();
50
51         Hunspell * addSpeller(string const & lang);
52         Hunspell * speller(string const & lang);
53
54         /// the spellers
55         Spellers spellers_;
56 };
57
58
59 HunspellChecker::Private::~Private()
60 {
61         Spellers::iterator it = spellers_.begin();
62         Spellers::iterator end = spellers_.end();
63
64         for (; it != end; ++it) {
65                 delete it->second;
66         }
67 }
68
69
70 namespace {
71 bool haveLanguageFiles(string const & hpath)
72 {
73         FileName const affix(hpath + ".aff");
74         FileName const dict(hpath + ".dic");
75         if (!affix.isReadableFile()) {
76                 // FIXME: We should indicate somehow that this language is not
77                 // supported.
78                 LYXERR(Debug::FILES, "Hunspell affix file " << affix << " does not exist");
79                 return false;
80         }
81         if (!dict.isReadableFile()) {
82                 LYXERR(Debug::FILES, "Hunspell dictionary file " << dict << " does not exist");
83                 return false;
84         }
85         return true;
86 }
87 }
88
89
90 Hunspell * HunspellChecker::Private::addSpeller(string const & lang)
91 {
92         string hunspell_path = external_path(lyxrc.hunspelldir_path);
93         LYXERR(Debug::FILES, "hunspell path: " << hunspell_path);
94         if (hunspell_path.empty()) {
95                 static bool warned = false;
96                 if (!warned) {
97                         frontend::Alert::error(_("Hunspell Path Not Found"), 
98                                         _("You must set the Hunspell dictionary path in Tools>Preferences>Paths."));
99                         warned = true;
100                 }
101                 return false;
102         }
103
104         hunspell_path += "/" + lang;
105         if (!haveLanguageFiles(hunspell_path)) {
106                 // try with '_' replaced by '-'
107                 hunspell_path = subst(hunspell_path, '_', '-');
108                 if (!haveLanguageFiles(hunspell_path)) {
109                         // FIXME: We should indicate somehow that this language is not
110                         // supported, probably by popping a warning. But we'll need to
111                         // remember which warnings we've issued.
112                         return 0;
113                 }
114         }
115         FileName const affix(hunspell_path + ".aff");
116         FileName const dict(hunspell_path + ".dic");
117         Hunspell * h = new Hunspell(affix.absFilename().c_str(), dict.absFilename().c_str());
118         spellers_[lang] = h;
119         return h;
120 }
121
122
123 Hunspell * HunspellChecker::Private::speller(string const & lang)
124 {
125         Spellers::iterator it = spellers_.find(lang);
126         if (it != spellers_.end())
127                 return it->second;
128         
129         return addSpeller(lang);
130 }
131
132
133 HunspellChecker::HunspellChecker(): d(new Private)
134 {
135 }
136
137
138 HunspellChecker::~HunspellChecker()
139 {
140         delete d;
141 }
142
143
144 SpellChecker::Result HunspellChecker::check(WordLangTuple const & wl)
145 {
146         string const word_to_check = to_utf8(wl.word());
147         Hunspell * h = d->speller(wl.lang_code());
148         if (!h)
149                 return OK;
150         int info;
151         if (h->spell(word_to_check.c_str(), &info))
152                 return OK;
153
154         if (info & SPELL_COMPOUND) {
155                 // FIXME: What to do with that?
156                 LYXERR(Debug::FILES, "Hunspell compound word found " << word_to_check);
157         }
158         if (info & SPELL_FORBIDDEN) {
159                 // FIXME: What to do with that?
160                 LYXERR(Debug::FILES, "Hunspell explicit forbidden word found " << word_to_check);
161         }
162
163         return UNKNOWN_WORD;
164 }
165
166
167 void HunspellChecker::insert(WordLangTuple const & wl)
168 {
169         string const word_to_check = to_utf8(wl.word());
170         Hunspell * h = d->speller(wl.lang_code());
171         if (!h)
172                 return;
173         h->add(word_to_check.c_str());
174 }
175
176
177 void HunspellChecker::accept(WordLangTuple const &)
178 {
179         // FIXME: not implemented!
180 }
181
182
183 void HunspellChecker::suggest(WordLangTuple const & wl,
184         docstring_list & suggestions)
185 {
186         suggestions.clear();
187         string const word_to_check = to_utf8(wl.word());
188         Hunspell * h = d->speller(wl.lang_code());
189         if (!h)
190                 return;
191         char ** suggestion_list;
192         int const suggestion_number = h->suggest(&suggestion_list, word_to_check.c_str());
193         if (suggestion_number <= 0)
194                 return;
195         for (int i = 0; i != suggestion_number; ++i)
196                 suggestions.push_back(from_utf8(suggestion_list[i]));
197         h->free_list(&suggestion_list, suggestion_number);
198 }
199
200
201 docstring const HunspellChecker::error()
202 {
203         return docstring();
204 }
205
206
207 } // namespace lyx