]> git.lyx.org Git - lyx.git/blob - src/HunspellChecker.cpp
56b0c26952eac0040f1acc6b50c125fc9e0c1b96
[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 "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"
24
25 #include <hunspell/hunspell.hxx>
26
27 #include <map>
28 #include <string>
29
30 using namespace std;
31 using namespace lyx::support;
32 using namespace lyx::support::os;
33
34 namespace lyx {
35
36 namespace {
37
38 typedef map<std::string, Hunspell *> Spellers;
39
40 } // anon namespace
41
42 struct HunspellChecker::Private
43 {
44         Private() {}
45
46         ~Private();
47
48         Hunspell * addSpeller(string const & lang);
49         Hunspell * speller(string const & lang);
50
51         /// the spellers
52         Spellers spellers_;
53 };
54
55
56 HunspellChecker::Private::~Private()
57 {
58         Spellers::iterator it = spellers_.begin();
59         Spellers::iterator end = spellers_.end();
60
61         for (; it != end; ++it) {
62                 delete it->second;
63         }
64 }
65
66
67 Hunspell * HunspellChecker::Private::addSpeller(string const & lang)
68 {
69         string hunspell_path = external_path(lyxrc.hunspelldir_path);
70         LYXERR(Debug::FILES, "hunspell path: " << hunspell_path);
71         if (hunspell_path.empty())
72                 return false;
73
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
81                 // supported.
82                 LYXERR(Debug::FILES, "Hunspell affix file " << affix << " does not exist");
83                 return 0;
84         }
85         if (!dict.isReadableFile()) {
86                 LYXERR(Debug::FILES, "Hunspell dictionary file " << dict << " does not exist");
87                 return 0;
88         }
89         Hunspell * h = new Hunspell(affix.absFilename().c_str(), dict.absFilename().c_str());
90         spellers_[lang] = h;
91         return h;
92 }
93
94
95 Hunspell * HunspellChecker::Private::speller(string const & lang)
96 {
97         Spellers::iterator it = spellers_.find(lang);
98         if (it != spellers_.end())
99                 return it->second;
100         
101         return addSpeller(lang);
102 }
103
104
105 HunspellChecker::HunspellChecker(): d(new Private)
106 {
107 }
108
109
110 HunspellChecker::~HunspellChecker()
111 {
112         delete d;
113 }
114
115
116 SpellChecker::Result HunspellChecker::check(WordLangTuple const & wl)
117 {
118         string const word_to_check = to_utf8(wl.word());
119         Hunspell * h = d->speller(wl.lang_code());
120         if (!h)
121                 return OK;
122         int info;
123         if (h->spell(word_to_check.c_str(), &info))
124                 return OK;
125
126         if (info & SPELL_COMPOUND) {
127                 // FIXME: What to do with that?
128                 LYXERR(Debug::FILES, "Hunspell compound word found " << word_to_check);
129         }
130         if (info & SPELL_FORBIDDEN) {
131                 // FIXME: What to do with that?
132                 LYXERR(Debug::FILES, "Hunspell explicit forbidden word found " << word_to_check);
133         }
134
135         return UNKNOWN_WORD;
136 }
137
138
139 void HunspellChecker::insert(WordLangTuple const & wl)
140 {
141         string const word_to_check = to_utf8(wl.word());
142         Hunspell * h = d->speller(wl.lang_code());
143         if (!h)
144                 return;
145         h->add(word_to_check.c_str());
146 }
147
148
149 void HunspellChecker::accept(WordLangTuple const & word)
150 {
151         // FIXME: not implemented!
152 }
153
154
155 void HunspellChecker::suggest(WordLangTuple const & wl,
156         docstring_list & suggestions)
157 {
158         suggestions.clear();
159         string const word_to_check = to_utf8(wl.word());
160         Hunspell * h = d->speller(wl.lang_code());
161         if (!h)
162                 return;
163         char ** suggestion_list;
164         int const suggestion_number = h->suggest(&suggestion_list, word_to_check.c_str());
165         if (suggestion_number <= 0)
166                 return;
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);
170 }
171
172
173 docstring const HunspellChecker::error()
174 {
175         return docstring();
176 }
177
178
179 } // namespace lyx