From 6ffb747421de2a97cdeeb29961f0f8f1062ab834 Mon Sep 17 00:00:00 2001 From: Konstantinos Sideris Date: Sun, 29 Jul 2018 21:58:18 +0300 Subject: [PATCH] Add tab-completion for usernames fixes #394 --- src/TextInputWidget.cpp | 45 +++++++++++++++++++++++++++++++---------- src/TextInputWidget.h | 15 ++++++++++++++ 2 files changed, 49 insertions(+), 11 deletions(-) diff --git a/src/TextInputWidget.cpp b/src/TextInputWidget.cpp index 897e2a76..f3b0f4be 100644 --- a/src/TextInputWidget.cpp +++ b/src/TextInputWidget.cpp @@ -107,7 +107,7 @@ FilteredTextEdit::showResults(const QVector &results) { QPoint pos; - if (atTriggerPosition_ != -1) { + if (isAnchorValid()) { auto cursor = textCursor(); cursor.setPosition(atTriggerPosition_); pos = viewport()->mapToGlobal(cursorRect(cursor).topLeft()); @@ -134,7 +134,7 @@ FilteredTextEdit::keyPressEvent(QKeyEvent *event) } // calculate the new query - if (textCursor().position() < atTriggerPosition_ || atTriggerPosition_ == -1) { + if (textCursor().position() < atTriggerPosition_ || !isAnchorValid()) { resetAnchor(); closeSuggestions(); } @@ -165,9 +165,31 @@ FilteredTextEdit::keyPressEvent(QKeyEvent *event) switch (event->key()) { case Qt::Key_At: atTriggerPosition_ = textCursor().position(); + anchorType_ = AnchorType::Sigil; QTextEdit::keyPressEvent(event); break; + case Qt::Key_Tab: { + auto cursor = textCursor(); + const int initialPos = cursor.position(); + + cursor.movePosition(QTextCursor::StartOfWord, QTextCursor::KeepAnchor); + auto word = cursor.selectedText(); + + const int startOfWord = cursor.position(); + + // There is a word to complete. + if (initialPos != startOfWord) { + atTriggerPosition_ = startOfWord; + anchorType_ = AnchorType::Tab; + + emit showSuggestions(word); + } else { + QTextEdit::keyPressEvent(event); + } + + break; + } case Qt::Key_Return: case Qt::Key_Enter: if (!(event->modifiers() & Qt::ShiftModifier)) { @@ -213,26 +235,27 @@ FilteredTextEdit::keyPressEvent(QKeyEvent *event) default: QTextEdit::keyPressEvent(event); - // Check if the current word should be autocompleted. - auto cursor = textCursor(); - cursor.movePosition(QTextCursor::StartOfWord, QTextCursor::KeepAnchor); - auto word = cursor.selectedText(); + if (isModifier) + return; - if (cursor.position() == 0) { + if (textCursor().position() == 0) { resetAnchor(); closeSuggestions(); return; } - if (cursor.position() == atTriggerPosition_ + 1) { - const auto q = query(); + // Check if the current word should be autocompleted. + auto cursor = textCursor(); + cursor.movePosition(QTextCursor::StartOfWord, QTextCursor::KeepAnchor); + auto word = cursor.selectedText(); - if (q.isEmpty()) { + if (hasAnchor(cursor.position(), anchorType_) && isAnchorValid()) { + if (word.isEmpty()) { closeSuggestions(); return; } - emit showSuggestions(query()); + emit showSuggestions(word); } else { resetAnchor(); closeSuggestions(); diff --git a/src/TextInputWidget.h b/src/TextInputWidget.h index e7d5f948..37d73fbb 100644 --- a/src/TextInputWidget.h +++ b/src/TextInputWidget.h @@ -94,8 +94,23 @@ private: SuggestionsPopup popup_; + enum class AnchorType + { + Tab = 0, + Sigil = 1, + }; + + AnchorType anchorType_ = AnchorType::Sigil; + + int anchorWidth(AnchorType anchor) { return static_cast(anchor); } + void closeSuggestions() { popup_.hide(); } void resetAnchor() { atTriggerPosition_ = -1; } + bool isAnchorValid() { return atTriggerPosition_ != -1; } + bool hasAnchor(int pos, AnchorType anchor) + { + return pos == atTriggerPosition_ + anchorWidth(anchor); + } QString query() {