Sonnet

hunspelldict.cpp
1 /*
2  * kspell_hunspelldict.cpp
3  *
4  * SPDX-FileCopyrightText: 2009 Montel Laurent <[email protected]>
5  *
6  * SPDX-License-Identifier: LGPL-2.1-or-later
7  */
8 
9 #include "hunspelldict.h"
10 
11 #include "config-hunspell.h"
12 #include "hunspelldebug.h"
13 
14 #include <QDir>
15 #include <QFile>
16 #include <QFileInfo>
17 #include <QStandardPaths>
18 #include <QTextStream>
19 
20 using namespace Sonnet;
21 
22 HunspellDict::HunspellDict(const QString &lang, const std::shared_ptr<Hunspell> &speller)
23  : SpellerPlugin(lang)
24 {
25  if (!speller) {
26  qCWarning(SONNET_HUNSPELL) << "Can't create a client without a speller";
27  return;
28  }
29  m_decoder = QStringDecoder(speller->get_dic_encoding());
30  if (!m_decoder.isValid()) {
31  qCWarning(SONNET_HUNSPELL) << "Failed to find a text codec for name" << speller->get_dic_encoding() << "defaulting to locale text codec";
32  m_decoder = QStringDecoder(QStringDecoder::System);
33  Q_ASSERT(m_decoder.isValid());
34  }
35  m_encoder = QStringEncoder(speller->get_dic_encoding());
36  if (!m_encoder.isValid()) {
37  qCWarning(SONNET_HUNSPELL) << "Failed to find a text codec for name" << speller->get_dic_encoding() << "defaulting to locale text codec";
38  m_encoder = QStringEncoder(QStringEncoder::System);
39  Q_ASSERT(m_encoder.isValid());
40  }
41  m_speller = speller;
42 
43  const QString userDic = QDir::home().filePath(QLatin1String(".hunspell_") % lang);
44  QFile userDicFile(userDic);
45  if (userDicFile.open(QIODevice::ReadOnly | QIODevice::Text)) {
46  qCDebug(SONNET_HUNSPELL) << "Load a user dictionary" << userDic;
47  QTextStream userDicIn(&userDicFile);
48  while (!userDicIn.atEnd()) {
49  const QString word = userDicIn.readLine();
50  if (word.isEmpty()) {
51  continue;
52  }
53 
54  if (word.contains(QLatin1Char('/'))) {
55  QStringList wordParts = word.split(QLatin1Char('/'));
56  speller->add_with_affix(toDictEncoding(wordParts.at(0)).constData(), toDictEncoding(wordParts.at(1)).constData());
57  }
58  if (word.at(0) == QLatin1Char('*')) {
59  speller->remove(toDictEncoding(word.mid(1)).constData());
60  } else {
61  speller->add(toDictEncoding(word).constData());
62  }
63  }
64  userDicFile.close();
65  }
66 }
67 
68 std::shared_ptr<Hunspell> HunspellDict::createHunspell(const QString &lang, QString path)
69 {
70  qCDebug(SONNET_HUNSPELL) << "Loading dictionary for" << lang << "from" << path;
71 
72  if (!path.endsWith(QLatin1Char('/'))) {
73  path += QLatin1Char('/');
74  }
75  path += lang;
76  QString dictionary = path + QStringLiteral(".dic");
77  QString aff = path + QStringLiteral(".aff");
78 
79  if (!QFileInfo::exists(dictionary) || !QFileInfo::exists(aff)) {
80  qCWarning(SONNET_HUNSPELL) << "Unable to find dictionary for" << lang << "in path" << path;
81  return nullptr;
82  }
83 
84  std::shared_ptr<Hunspell> speller = std::make_shared<Hunspell>(aff.toLocal8Bit().constData(), dictionary.toLocal8Bit().constData());
85  qCDebug(SONNET_HUNSPELL) << "Created " << speller.get();
86 
87  return speller;
88 }
89 
90 HunspellDict::~HunspellDict()
91 {
92 }
93 
94 QByteArray HunspellDict::toDictEncoding(const QString &word) const
95 {
96  if (m_encoder.isValid()) {
97  return m_encoder.encode(word);
98  }
99  return {};
100 }
101 
102 bool HunspellDict::isCorrect(const QString &word) const
103 {
104  qCDebug(SONNET_HUNSPELL) << " isCorrect :" << word;
105  if (!m_speller) {
106  return false;
107  }
108 
109 #if USE_OLD_HUNSPELL_API
110  int result = m_speller->spell(toDictEncoding(word).constData());
111  qCDebug(SONNET_HUNSPELL) << " result :" << result;
112  return result != 0;
113 #else
114  bool result = m_speller->spell(toDictEncoding(word).toStdString());
115  qCDebug(SONNET_HUNSPELL) << " result :" << result;
116  return result;
117 #endif
118 }
119 
120 QStringList HunspellDict::suggest(const QString &word) const
121 {
122  if (!m_speller) {
123  return QStringList();
124  }
125 
126  QStringList lst;
127 #if USE_OLD_HUNSPELL_API
128  char **selection;
129  int nbWord = m_speller->suggest(&selection, toDictEncoding(word).constData());
130  for (int i = 0; i < nbWord; ++i) {
131  lst << m_decoder.decode(selection[i]);
132  }
133  m_speller->free_list(&selection, nbWord);
134 #else
135  const auto suggestions = m_speller->suggest(toDictEncoding(word).toStdString());
136  for_each(suggestions.begin(), suggestions.end(), [this, &lst](const std::string &suggestion) {
137  lst << m_decoder.decode(suggestion.c_str());
138  });
139 #endif
140 
141  return lst;
142 }
143 
144 bool HunspellDict::storeReplacement(const QString &bad, const QString &good)
145 {
146  Q_UNUSED(bad);
147  Q_UNUSED(good);
148  if (!m_speller) {
149  return false;
150  }
151  qCDebug(SONNET_HUNSPELL) << "HunspellDict::storeReplacement not implemented";
152  return false;
153 }
154 
155 bool HunspellDict::addToPersonal(const QString &word)
156 {
157  if (!m_speller) {
158  return false;
159  }
160  m_speller->add(toDictEncoding(word).constData());
161  const QString userDic = QDir::home().filePath(QLatin1String(".hunspell_") % language());
162  QFile userDicFile(userDic);
163  if (userDicFile.open(QIODevice::Append | QIODevice::Text)) {
164  QTextStream out(&userDicFile);
165  out << word << '\n';
166  userDicFile.close();
167  return true;
168  }
169 
170  return false;
171 }
172 
173 bool HunspellDict::addToSession(const QString &word)
174 {
175  if (!m_speller) {
176  return false;
177  }
178  int r = m_speller->add(toDictEncoding(word).constData());
179  return r == 0;
180 }
bool endsWith(const QString &s, Qt::CaseSensitivity cs) const const
QStringList split(const QString &sep, QString::SplitBehavior behavior, Qt::CaseSensitivity cs) const const
bool exists() const const
QDir home()
bool isEmpty() const const
const T & at(int i) const const
The sonnet namespace.
const char * constData() const const
QString path(const QString &relativePath)
QString filePath(const QString &fileName) const const
const QChar at(int position) const const
QByteArray toLocal8Bit() const const
bool contains(QChar ch, Qt::CaseSensitivity cs) const const
QString mid(int position, int n) const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Sun Jun 4 2023 04:04:12 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.