-
Notifications
You must be signed in to change notification settings - Fork 0
/
Hunspell.diff
150 lines (144 loc) · 4.82 KB
/
Hunspell.diff
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
diff --git a/Telegram/SourceFiles/historywidget.cpp b/Telegram/SourceFiles/historywidget.cpp
index c28d64b7..316fc09e 100644
--- a/Telegram/SourceFiles/historywidget.cpp
+++ b/Telegram/SourceFiles/historywidget.cpp
@@ -61,6 +61,9 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
#include "core/qthelp_regex.h"
#include "ui/widgets/popup_menu.h"
#include "platform/platform_file_dialog.h"
+#ifdef USE_HUNSPELL
+ #include <hunspell.hxx>
+#endif
namespace {
@@ -118,6 +121,92 @@ ApiWrap::RequestMessageDataCallback replyEditMessageDataCallback() {
};
}
+#ifdef USE_HUNSPELL
+// Helper for Hunspell (spell checking)
+class HunspellHelper {
+public:
+ HunspellHelper(const QByteArray &lang) : _hunspell(nullptr), _codec(nullptr), _hunspellPath("/usr/share/hunspell/") {
+ const QByteArray affPath = _hunspellPath + lang + ".aff";
+ const QByteArray dicPath = _hunspellPath + lang + ".dic";
+ if (QFileInfo(affPath).exists() && QFileInfo(dicPath).exists()) {
+ _hunspell.reset(new Hunspell(affPath, dicPath));
+ _codec = QTextCodec::codecForName(_hunspell->get_dic_encoding());
+ if (!_codec) {
+ _hunspell.reset();
+ }
+ }
+ }
+
+ bool isOpen() const {
+ return (bool)_hunspell;
+ }
+
+ bool spell(const QStringRef &word) {
+ return _hunspell->spell(_codec->fromUnicode(word.data(), word.count()));
+ }
+
+private:
+ std_::unique_ptr<Hunspell> _hunspell;
+ QTextCodec *_codec;
+
+ const QByteArray _hunspellPath;
+};
+
+// For spell checking in QTextEdit
+class SpellHighlighter : public QSyntaxHighlighter {
+public:
+ SpellHighlighter(QTextEdit *textEdit) : QSyntaxHighlighter(textEdit->document()) {}
+
+ void setSpellCheckers(QStringList languages) {
+ _hunspells.clear();
+ languages.removeDuplicates();
+ for (const QString &lang : languages) {
+ auto hunspell = std_::unique_ptr<HunspellHelper>(new HunspellHelper(lang.toLatin1()));
+ if (hunspell->isOpen()) {
+ _hunspells.push_back(std_::move(hunspell));
+ }
+ }
+ }
+
+private:
+ void highlightBlock(const QString &text) final {
+ if (_hunspells.empty())
+ return;
+
+ QTextCharFormat underlineFmt;
+ underlineFmt.setFontUnderline(true);
+ underlineFmt.setUnderlineColor(Qt::red);
+
+ const int textLen = text.length();
+ int beginIdx = 0;
+ for (int endIdx = 0; endIdx < textLen; ++endIdx) {
+ const bool letterAtBeginIdx = text[beginIdx].isLetter();
+ const bool letterAtEndIdx = text[endIdx].isLetter();
+ const bool atEnd = letterAtEndIdx && (endIdx == textLen - 1);
+ if (letterAtBeginIdx && (!letterAtEndIdx || atEnd)) {
+ const int wordLen = endIdx + atEnd - beginIdx;
+ const QStringRef word = text.midRef(beginIdx, wordLen);
+ if (word.length() > 1) {
+ bool correctWord = false;
+ for (auto &&hunspell : _hunspells) {
+ if (hunspell->spell(word)) {
+ correctWord = true;
+ break;
+ }
+ }
+ setFormat(beginIdx, wordLen, correctWord ? QTextCharFormat() : underlineFmt);
+ }
+ }
+ if (!letterAtBeginIdx || !letterAtEndIdx) {
+ beginIdx = endIdx + 1;
+ }
+ }
+ }
+
+ std::vector<std_::unique_ptr<HunspellHelper>> _hunspells;
+};
+#endif
+
} // namespace
// flick scroll taken from http://qt-project.org/doc/qt-4.8/demos-embedded-anomaly-src-flickcharm-cpp.html
@@ -2392,6 +2481,10 @@ void HistoryInner::onParentGeometryChanged() {
MessageField::MessageField(HistoryWidget *history, const style::FlatTextarea &st, const QString &ph, const QString &val) : Ui::FlatTextarea(history, st, ph, val), history(history) {
setMinHeight(st::historySendSize.height() - 2 * st::historySendPadding);
setMaxHeight(st::historyComposeFieldMaxHeight);
+
+#ifdef USE_HUNSPELL
+ (new SpellHighlighter(this))->setSpellCheckers({QLocale::system().name(), "en_US"});
+#endif
}
bool MessageField::hasSendText() const {
diff --git a/Telegram/gyp/Telegram.gyp b/Telegram/gyp/Telegram.gyp
index 65d2e415..c2127428 100644
--- a/Telegram/gyp/Telegram.gyp
+++ b/Telegram/gyp/Telegram.gyp
@@ -84,6 +84,7 @@
'TDESKTOP_DISABLE_AUTOUPDATE',
'TDESKTOP_DISABLE_REGISTER_CUSTOM_SCHEME',
'TDESKTOP_DISABLE_UNITY_INTEGRATION',
+ 'USE_HUNSPELL',
],
'include_dirs': [
diff --git a/Telegram/gyp/telegram_linux.gypi b/Telegram/gyp/telegram_linux.gypi
index 9e2d3b76..da8ac718 100644
--- a/Telegram/gyp/telegram_linux.gypi
+++ b/Telegram/gyp/telegram_linux.gypi
@@ -53,6 +53,7 @@
'composeplatforminputcontextplugin',
'ibusplatforminputcontextplugin',
'fcitxplatforminputcontextplugin',
+ 'hunspell',
'<!(pkg-config 2> /dev/null --libs <@(pkgconfig_libs))',
],
'cflags_cc': [
@@ -60,6 +61,7 @@
'<!(pkg-config 2> /dev/null --cflags gtk+-2.0)',
'<!(pkg-config 2> /dev/null --cflags glib-2.0)',
'<!(pkg-config 2> /dev/null --cflags <@(pkgconfig_libs))',
+ '<!(pkg-config 2> /dev/null --cflags hunspell)',
],
'configurations': {
'Release': {