From 9bacb3e33e46b3a15ab3c803eb014e85d91c97b9 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Wed, 1 Jun 2016 10:19:59 +0200 Subject: [PATCH] Editor: Highlight automatically inserted text Keep the highlight as long as the cursor is directly behind the closing character and the editor is the focus widget. Change-Id: Ic1d4bac263e9d2f395791dad7ecdceb9d69635c5 Reviewed-by: Alessandro Portale --- .../texteditor/codeassist/codeassistant.cpp | 2 + src/plugins/texteditor/completionsettings.cpp | 5 ++ src/plugins/texteditor/completionsettings.h | 1 + .../texteditor/completionsettingspage.cpp | 2 + .../texteditor/completionsettingspage.ui | 10 ++- src/plugins/texteditor/texteditor.cpp | 71 +++++++++++++++---- src/plugins/texteditor/texteditor.h | 4 ++ 7 files changed, 79 insertions(+), 16 deletions(-) diff --git a/src/plugins/texteditor/codeassist/codeassistant.cpp b/src/plugins/texteditor/codeassist/codeassistant.cpp index a21cf7c46c..8af30428e0 100644 --- a/src/plugins/texteditor/codeassist/codeassistant.cpp +++ b/src/plugins/texteditor/codeassist/codeassistant.cpp @@ -307,6 +307,7 @@ void CodeAssistantPrivate::displayProposal(IAssistProposal *newProposal, AssistR if (m_proposal->isCorrective()) m_proposal->makeCorrection(m_editorWidget); + m_editorWidget->keepAutoCompletionHighlight(true); basePosition = m_proposal->basePosition(); m_proposalWidget = m_proposal->createWidget(); connect(m_proposalWidget, &QObject::destroyed, @@ -421,6 +422,7 @@ void CodeAssistantPrivate::destroyContext() if (isWaitingForProposal()) { cancelCurrentRequest(); } else if (isDisplayingProposal()) { + m_editorWidget->keepAutoCompletionHighlight(false); m_proposalWidget->closeProposal(); disconnect(m_proposalWidget, &QObject::destroyed, this, &CodeAssistantPrivate::finalizeProposal); diff --git a/src/plugins/texteditor/completionsettings.cpp b/src/plugins/texteditor/completionsettings.cpp index 325b758028..8bdcbded95 100644 --- a/src/plugins/texteditor/completionsettings.cpp +++ b/src/plugins/texteditor/completionsettings.cpp @@ -39,6 +39,7 @@ static const char partiallyCompleteKey[] = "PartiallyComplete"; static const char spaceAfterFunctionNameKey[] = "SpaceAfterFunctionName"; static const char autoSplitStringsKey[] = "AutoSplitStrings"; static const char animateAutoCompleteKey[] = "AnimateAutoComplete"; +static const char highlightAutoCompleteKey[] = "HighlightAutoComplete"; using namespace TextEditor; @@ -56,6 +57,7 @@ void CompletionSettings::toSettings(QSettings *s) const s->setValue(spaceAfterFunctionNameKey, m_spaceAfterFunctionName); s->setValue(autoSplitStringsKey, m_autoSplitStrings); s->setValue(animateAutoCompleteKey, m_animateAutoComplete); + s->setValue(highlightAutoCompleteKey, m_highlightAutoComplete); s->endGroup(); } @@ -86,6 +88,8 @@ void CompletionSettings::fromSettings(QSettings *s) s->value(autoSplitStringsKey, m_autoSplitStrings).toBool(); m_animateAutoComplete = s->value(animateAutoCompleteKey, m_animateAutoComplete).toBool(); + m_highlightAutoComplete = + s->value(highlightAutoCompleteKey, m_highlightAutoComplete).toBool(); s->endGroup(); } @@ -102,5 +106,6 @@ bool CompletionSettings::equals(const CompletionSettings &cs) const && m_spaceAfterFunctionName == cs.m_spaceAfterFunctionName && m_autoSplitStrings == cs.m_autoSplitStrings && m_animateAutoComplete == cs.m_animateAutoComplete + && m_highlightAutoComplete == cs.m_highlightAutoComplete ; } diff --git a/src/plugins/texteditor/completionsettings.h b/src/plugins/texteditor/completionsettings.h index 5dfb172eb2..0b466718f9 100644 --- a/src/plugins/texteditor/completionsettings.h +++ b/src/plugins/texteditor/completionsettings.h @@ -67,6 +67,7 @@ public: bool m_spaceAfterFunctionName = false; bool m_autoSplitStrings = true; bool m_animateAutoComplete = true; + bool m_highlightAutoComplete = false; }; inline bool operator==(const CompletionSettings &t1, const CompletionSettings &t2) { return t1.equals(t2); } diff --git a/src/plugins/texteditor/completionsettingspage.cpp b/src/plugins/texteditor/completionsettingspage.cpp index b505eb6566..fce419b422 100644 --- a/src/plugins/texteditor/completionsettingspage.cpp +++ b/src/plugins/texteditor/completionsettingspage.cpp @@ -103,6 +103,7 @@ QWidget *CompletionSettingsPage::widget() m_page->spaceAfterFunctionName->setChecked(m_completionSettings.m_spaceAfterFunctionName); m_page->autoSplitStrings->setChecked(m_completionSettings.m_autoSplitStrings); m_page->animateAutoComplete->setChecked(m_completionSettings.m_animateAutoComplete); + m_page->highlightAutoComplete->setChecked(m_completionSettings.m_highlightAutoComplete); m_page->enableDoxygenCheckBox->setChecked(m_commentsSettings.m_enableDoxygen); m_page->generateBriefCheckBox->setChecked(m_commentsSettings.m_generateBrief); @@ -177,6 +178,7 @@ void CompletionSettingsPage::settingsFromUi(CompletionSettings &completion, Comm completion.m_spaceAfterFunctionName = m_page->spaceAfterFunctionName->isChecked(); completion.m_autoSplitStrings = m_page->autoSplitStrings->isChecked(); completion.m_animateAutoComplete = m_page->animateAutoComplete->isChecked(); + completion.m_highlightAutoComplete = m_page->highlightAutoComplete->isChecked(); comment.m_enableDoxygen = m_page->enableDoxygenCheckBox->isChecked(); comment.m_generateBrief = m_page->generateBriefCheckBox->isChecked(); diff --git a/src/plugins/texteditor/completionsettingspage.ui b/src/plugins/texteditor/completionsettingspage.ui index d91caeda94..23e61d22be 100644 --- a/src/plugins/texteditor/completionsettingspage.ui +++ b/src/plugins/texteditor/completionsettingspage.ui @@ -7,7 +7,7 @@ 0 0 511 - 420 + 437 @@ -227,6 +227,13 @@ In addition, Shift+Enter inserts an escape character at the cursor position and + + + + Highlight automatically inserted text + + + @@ -316,6 +323,7 @@ In addition, Shift+Enter inserts an escape character at the cursor position and surroundQuotes spaceAfterFunctionName animateAutoComplete + highlightAutoComplete enableDoxygenCheckBox generateBriefCheckBox leadingAsterisksCheckBox diff --git a/src/plugins/texteditor/texteditor.cpp b/src/plugins/texteditor/texteditor.cpp index f2cb276008..d5f50ec4b8 100644 --- a/src/plugins/texteditor/texteditor.cpp +++ b/src/plugins/texteditor/texteditor.cpp @@ -329,7 +329,7 @@ public: // parentheses matcher void _q_matchParentheses(); void _q_highlightBlocks(); - void _q_autocompleterHighlight(const QTextCursor &cursor = QTextCursor()); + void autocompleterHighlight(const QTextCursor &cursor = QTextCursor()); void updateAnimator(QPointer animator, QPainter &painter); void cancelCurrentAnimations(); void slotSelectionChanged(); @@ -452,8 +452,14 @@ public: QList m_hoverHandlers; // Not owned QPointer m_bracketsAnimator; + + // Animation and highlighting of auto completed text QPointer m_autocompleteAnimator; bool m_animateAutoComplete = true; + bool m_highlightAutoComplete = true; + bool m_keepAutoCompletionHighlight = false; + QTextCursor m_autoCompleteHighlightPos; + int m_cursorBlockNumber; int m_blockCount; @@ -629,6 +635,7 @@ static const char kTextBlockMimeType[] = "application/vnd.qtcreator.blocktext"; Id TextEditorWidget::SnippetPlaceholderSelection("TextEdit.SnippetPlaceHolderSelection"); Id TextEditorWidget::CurrentLineSelection("TextEdit.CurrentLineSelection"); Id TextEditorWidget::ParenthesesMatchingSelection("TextEdit.ParenthesesMatchingSelection"); +Id TextEditorWidget::AutoCompleteSelection("TextEdit.AutoCompleteSelection"); Id TextEditorWidget::CodeWarningsSelection("TextEdit.CodeWarningsSelection"); Id TextEditorWidget::CodeSemanticsSelection("TextEdit.CodeSemanticsSelection"); Id TextEditorWidget::UndefinedSymbolSelection("TextEdit.UndefinedSymbolSelection"); @@ -2156,12 +2163,12 @@ void TextEditorWidget::keyPressEvent(QKeyEvent *e) d->m_document->autoIndent(ensureVisible); else if (!previousIndentationString.isEmpty()) ensureVisible.insertText(previousIndentationString); - if (d->m_animateAutoComplete) { + if (d->m_animateAutoComplete || d->m_highlightAutoComplete) { QTextCursor tc = ensureVisible; tc.movePosition(QTextCursor::EndOfBlock); tc.movePosition(QTextCursor::StartOfBlock, QTextCursor::KeepAnchor); tc.movePosition(QTextCursor::NextWord, QTextCursor::KeepAnchor); - d->_q_autocompleterHighlight(tc); + d->autocompleterHighlight(tc); } } setTextCursor(ensureVisible); @@ -2422,9 +2429,10 @@ void TextEditorWidget::keyPressEvent(QKeyEvent *e) if (!autoText.isEmpty()) { int pos = cursor.position(); cursor.insertText(autoText); + cursor.movePosition(QTextCursor::PreviousCharacter, QTextCursor::KeepAnchor); + d->autocompleterHighlight(cursor); //Select the inserted text, to be able to re-indent the inserted text cursor.setPosition(pos, QTextCursor::KeepAnchor); - d->_q_autocompleterHighlight(cursor); } if (!electricChar.isNull() && d->m_autoCompleter->contextAllowsElectricCharacters(cursor)) d->m_document->autoIndent(cursor, electricChar); @@ -4705,6 +4713,17 @@ void TextEditorWidgetPrivate::updateHighlights() } } + if (m_highlightAutoComplete && !m_autoCompleteHighlightPos.isNull()) { + QTimer::singleShot(0, this, [this](){ + if ((!m_keepAutoCompletionHighlight && !q->hasFocus()) + || m_autoCompleteHighlightPos != q->textCursor()) { + q->setExtraSelections(TextEditorWidget::AutoCompleteSelection, + QList()); // clear + m_autoCompleteHighlightPos = QTextCursor(); + } + }); + } + updateCurrentLineHighlight(); if (m_displaySettings.m_highlightBlocks) { @@ -6026,23 +6045,38 @@ void TextEditorWidgetPrivate::_q_highlightBlocks() } } -void TextEditorWidgetPrivate::_q_autocompleterHighlight(const QTextCursor &cursor) +void TextEditorWidgetPrivate::autocompleterHighlight(const QTextCursor &cursor) { - if (!m_animateAutoComplete || q->isReadOnly() || !cursor.hasSelection()) + QList extraSelections; + if ((!m_animateAutoComplete && !m_highlightAutoComplete) + || q->isReadOnly() || !cursor.hasSelection()) { + q->setExtraSelections(TextEditorWidget::AutoCompleteSelection, extraSelections); // clear return; + } const QTextCharFormat &matchFormat = q->textDocument()->fontSettings().toTextCharFormat(C_AUTOCOMPLETE); - cancelCurrentAnimations();// one animation is enough - m_autocompleteAnimator = new TextEditorAnimator(this); - m_autocompleteAnimator->setPosition(cursor.selectionStart()); - QPalette pal; - pal.setBrush(QPalette::Text, matchFormat.foreground()); - pal.setBrush(QPalette::Base, matchFormat.background()); - m_autocompleteAnimator->setData(q->font(), pal, cursor.selectedText()); - connect(m_autocompleteAnimator.data(), &TextEditorAnimator::updateRequest, - this, &TextEditorWidgetPrivate::_q_animateUpdate); + if (m_highlightAutoComplete) { + QTextEdit::ExtraSelection sel; + sel.cursor = cursor; + sel.format.setBackground(matchFormat.background()); + extraSelections.append(sel); + m_autoCompleteHighlightPos = cursor; + m_autoCompleteHighlightPos.movePosition(QTextCursor::PreviousCharacter); + } + if (m_animateAutoComplete) { + cancelCurrentAnimations();// one animation is enough + m_autocompleteAnimator = new TextEditorAnimator(this); + m_autocompleteAnimator->setPosition(cursor.selectionStart()); + QPalette pal; + pal.setBrush(QPalette::Text, matchFormat.foreground()); + pal.setBrush(QPalette::Base, matchFormat.background()); + m_autocompleteAnimator->setData(q->font(), pal, cursor.selectedText()); + connect(m_autocompleteAnimator.data(), &TextEditorAnimator::updateRequest, + this, &TextEditorWidgetPrivate::_q_animateUpdate); + } + q->setExtraSelections(TextEditorWidget::AutoCompleteSelection, extraSelections); } void TextEditorWidgetPrivate::updateAnimator(QPointer animator, @@ -6089,6 +6123,7 @@ void TextEditorWidget::focusOutEvent(QFocusEvent *e) QPlainTextEdit::focusOutEvent(e); if (viewport()->cursor().shape() == Qt::BlankCursor) viewport()->setCursor(Qt::IBeamCursor); + d->updateHighlights(); } @@ -6542,6 +6577,7 @@ void TextEditorWidget::setCompletionSettings(const CompletionSettings &completio d->m_autoCompleter->setAutoInsertQuotesEnabled(completionSettings.m_autoInsertQuotes); d->m_autoCompleter->setSurroundWithQuotesEnabled(completionSettings.m_surroundingAutoQuotes); d->m_animateAutoComplete = completionSettings.m_animateAutoComplete; + d->m_highlightAutoComplete = completionSettings.m_highlightAutoComplete; } void TextEditorWidget::setExtraEncodingSettings(const ExtraEncodingSettings &extraEncodingSettings) @@ -7003,6 +7039,11 @@ void TextEditorWidget::insertExtraToolBarWidget(TextEditorWidget::Side side, d->m_toolBar->insertWidget(d->m_toolBar->actions().first(), widget); } +void TextEditorWidget::keepAutoCompletionHighlight(bool keepHighlight) +{ + d->m_keepAutoCompletionHighlight = keepHighlight; +} + int BaseTextEditor::currentLine() const { return editorWidget()->textCursor().blockNumber() + 1; diff --git a/src/plugins/texteditor/texteditor.h b/src/plugins/texteditor/texteditor.h index ce896250e1..87182f18cf 100644 --- a/src/plugins/texteditor/texteditor.h +++ b/src/plugins/texteditor/texteditor.h @@ -301,6 +301,7 @@ public: static Core::Id SnippetPlaceholderSelection; static Core::Id CurrentLineSelection; static Core::Id ParenthesesMatchingSelection; + static Core::Id AutoCompleteSelection; static Core::Id CodeWarningsSelection; static Core::Id CodeSemanticsSelection; static Core::Id UndefinedSymbolSelection; @@ -323,6 +324,9 @@ public: enum Side { Left, Right }; void insertExtraToolBarWidget(Side side, QWidget *widget); + // keep the auto completion even if the focus is lost + void keepAutoCompletionHighlight(bool keepHighlight); + virtual void copy(); virtual void paste(); virtual void cut(); -- GitLab