diff --git a/src/plugins/texteditor/codeassist/codeassistant.cpp b/src/plugins/texteditor/codeassist/codeassistant.cpp index a21cf7c46c64b8f99228a6a62226f742347f94ba..8af30428e0749be0fb64ec115978c160dd878e94 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 325b758028222ff876cd7486581c5e80eeb0515d..8bdcbded9599696167892178fabdaa71612653b0 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 5dfb172eb27acdd9128e0d1d3e70d418379065b5..0b466718f97c45bcfe4ea965b035113588089a74 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 b505eb656613935740506edd635e745008a41c17..fce419b422d959f0c271ddae3aa3970ab254a520 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 d91caeda947ca9cc593901482174e7cd65f0f341..23e61d22be41184e5e1429759078e71f49a2fafa 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 f2cb276008ccc649987af41bced863b7d169de5c..d5f50ec4b8a0fcdf41e81a54a9b731d8d895cb07 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 ce896250e1c5f5eac7e0d9f0a7b0dc92df976842..87182f18cf311a69e377af15e7071997db95f248 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();