From ba092aa29bc6d2f0aff9dac880d59337b75a317e Mon Sep 17 00:00:00 2001 From: Rasmus Karlsson Date: Tue, 1 Aug 2017 00:10:02 +0200 Subject: [PATCH] Add emojis to autocomplete Improve autocomplete: - Add space after autocompleted item - Emotes starting with `:` can now be autocompleted properly (i.e. emojis) --- src/completionmanager.cpp | 21 ++++++++++---- src/completionmanager.hpp | 2 ++ src/emotemanager.cpp | 1 + src/emotemanager.hpp | 2 ++ src/widgets/resizingtextedit.cpp | 49 ++++++++++++++++++++++++++++---- src/widgets/resizingtextedit.hpp | 5 +++- 6 files changed, 69 insertions(+), 11 deletions(-) diff --git a/src/completionmanager.cpp b/src/completionmanager.cpp index e040adad..393739da 100644 --- a/src/completionmanager.cpp +++ b/src/completionmanager.cpp @@ -4,6 +4,12 @@ namespace chatterino { +void CompletionModel::addString(const std::string &str) +{ + // Always add a space at the end of completions + this->emotes.push_back(qS(str) + " "); +} + CompletionManager::CompletionManager(EmoteManager &_emoteManager) : emoteManager(_emoteManager) { @@ -40,30 +46,35 @@ void CompletionManager::updateModel(CompletionModel *model, const std::string &c for (const auto &m : this->emoteManager.twitchAccountEmotes) { for (const auto &emoteName : m.second.emoteCodes) { - model->emotes.push_back(qS(emoteName)); + model->addString(emoteName); } } std::vector &bttvGlobalEmoteCodes = this->emoteManager.bttvGlobalEmoteCodes; for (const auto &m : bttvGlobalEmoteCodes) { - model->emotes.push_back(qS(m)); + model->addString(m); } std::vector &ffzGlobalEmoteCodes = this->emoteManager.ffzGlobalEmoteCodes; for (const auto &m : ffzGlobalEmoteCodes) { - model->emotes.push_back(qS(m)); + model->addString(m); } std::vector &bttvChannelEmoteCodes = this->emoteManager.bttvChannelEmoteCodes[channelName]; for (const auto &m : bttvChannelEmoteCodes) { - model->emotes.push_back(qS(m)); + model->addString(m); } std::vector &ffzChannelEmoteCodes = this->emoteManager.ffzChannelEmoteCodes[channelName]; for (const auto &m : ffzChannelEmoteCodes) { - model->emotes.push_back(qS(m)); + model->addString(m); + } + + const auto &emojiShortCodes = this->emoteManager.emojiShortCodes; + for (const auto &m : emojiShortCodes) { + model->addString(":" + m + ":"); } } diff --git a/src/completionmanager.hpp b/src/completionmanager.hpp index 29980ac0..3d70be8b 100644 --- a/src/completionmanager.hpp +++ b/src/completionmanager.hpp @@ -28,6 +28,8 @@ public: return this->emotes.size(); } + void addString(const std::string &str); + QVector emotes; }; diff --git a/src/emotemanager.cpp b/src/emotemanager.cpp index 87190955..12eebf6c 100644 --- a/src/emotemanager.cpp +++ b/src/emotemanager.cpp @@ -199,6 +199,7 @@ void EmoteManager::loadEmojis() }; this->emojiShortCodeToEmoji.insert(shortCode, emojiData); + this->emojiShortCodes.push_back(shortCode.toStdString()); this->emojiFirstByte[emojiData.value.at(0)].append(emojiData); diff --git a/src/emotemanager.hpp b/src/emotemanager.hpp index 768fec22..0d276a44 100644 --- a/src/emotemanager.hpp +++ b/src/emotemanager.hpp @@ -94,6 +94,8 @@ public: QString replaceShortCodes(const QString &text); + std::vector emojiShortCodes; + /// Twitch emotes void refreshTwitchEmotes(const std::string &roomID); diff --git a/src/widgets/resizingtextedit.cpp b/src/widgets/resizingtextedit.cpp index dfb253fc..779e9eca 100644 --- a/src/widgets/resizingtextedit.cpp +++ b/src/widgets/resizingtextedit.cpp @@ -29,11 +29,41 @@ int ResizingTextEdit::heightForWidth(int) const return margins.top() + document()->size().height() + margins.bottom() + 5; } -QString ResizingTextEdit::textUnderCursor() const +QString ResizingTextEdit::textUnderCursor(bool *hadSpace) const { - QTextCursor tc = textCursor(); - tc.select(QTextCursor::WordUnderCursor); - return tc.selectedText(); + auto currentText = this->toPlainText(); + + QTextCursor tc = this->textCursor(); + + auto textUpToCursor = currentText.left(tc.selectionStart()); + + auto words = textUpToCursor.splitRef(' '); + if (words.size() == 0) { + return QString(); + } + + bool first = true; + QString lastWord; + for (auto it = words.crbegin(); it != words.crend(); ++it) { + auto word = *it; + + if (first && word.isEmpty()) { + first = false; + if (hadSpace != nullptr) { + *hadSpace = true; + } + continue; + } + + lastWord = word.toString(); + break; + } + + if (lastWord.isEmpty()) { + return QString(); + } + + return lastWord; } void ResizingTextEdit::keyPressEvent(QKeyEvent *event) @@ -105,8 +135,17 @@ void ResizingTextEdit::insertCompletion(const QString &completion) return; } + bool hadSpace = false; + auto prefix = this->textUnderCursor(&hadSpace); + + int prefixSize = prefix.size(); + + if (hadSpace) { + ++prefixSize; + } + QTextCursor tc = this->textCursor(); - tc.select(QTextCursor::SelectionType::WordUnderCursor); + tc.movePosition(QTextCursor::PreviousCharacter, QTextCursor::KeepAnchor, prefixSize); tc.insertText(completion); this->setTextCursor(tc); } diff --git a/src/widgets/resizingtextedit.hpp b/src/widgets/resizingtextedit.hpp index a786a356..ba76092d 100644 --- a/src/widgets/resizingtextedit.hpp +++ b/src/widgets/resizingtextedit.hpp @@ -25,7 +25,10 @@ protected: private: QCompleter *completer = nullptr; - QString textUnderCursor() const; + + // hadSpace is set to true in case the "textUnderCursor" word was after a space + QString textUnderCursor(bool *hadSpace = nullptr) const; + bool nextCompletion = false; private slots: