Commit 9bacb3e3 authored by David Schulz's avatar David Schulz Committed by David Schulz

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's avatarAlessandro Portale <alessandro.portale@qt.io>
parent 6a2e9a1f
...@@ -307,6 +307,7 @@ void CodeAssistantPrivate::displayProposal(IAssistProposal *newProposal, AssistR ...@@ -307,6 +307,7 @@ void CodeAssistantPrivate::displayProposal(IAssistProposal *newProposal, AssistR
if (m_proposal->isCorrective()) if (m_proposal->isCorrective())
m_proposal->makeCorrection(m_editorWidget); m_proposal->makeCorrection(m_editorWidget);
m_editorWidget->keepAutoCompletionHighlight(true);
basePosition = m_proposal->basePosition(); basePosition = m_proposal->basePosition();
m_proposalWidget = m_proposal->createWidget(); m_proposalWidget = m_proposal->createWidget();
connect(m_proposalWidget, &QObject::destroyed, connect(m_proposalWidget, &QObject::destroyed,
...@@ -421,6 +422,7 @@ void CodeAssistantPrivate::destroyContext() ...@@ -421,6 +422,7 @@ void CodeAssistantPrivate::destroyContext()
if (isWaitingForProposal()) { if (isWaitingForProposal()) {
cancelCurrentRequest(); cancelCurrentRequest();
} else if (isDisplayingProposal()) { } else if (isDisplayingProposal()) {
m_editorWidget->keepAutoCompletionHighlight(false);
m_proposalWidget->closeProposal(); m_proposalWidget->closeProposal();
disconnect(m_proposalWidget, &QObject::destroyed, disconnect(m_proposalWidget, &QObject::destroyed,
this, &CodeAssistantPrivate::finalizeProposal); this, &CodeAssistantPrivate::finalizeProposal);
......
...@@ -39,6 +39,7 @@ static const char partiallyCompleteKey[] = "PartiallyComplete"; ...@@ -39,6 +39,7 @@ static const char partiallyCompleteKey[] = "PartiallyComplete";
static const char spaceAfterFunctionNameKey[] = "SpaceAfterFunctionName"; static const char spaceAfterFunctionNameKey[] = "SpaceAfterFunctionName";
static const char autoSplitStringsKey[] = "AutoSplitStrings"; static const char autoSplitStringsKey[] = "AutoSplitStrings";
static const char animateAutoCompleteKey[] = "AnimateAutoComplete"; static const char animateAutoCompleteKey[] = "AnimateAutoComplete";
static const char highlightAutoCompleteKey[] = "HighlightAutoComplete";
using namespace TextEditor; using namespace TextEditor;
...@@ -56,6 +57,7 @@ void CompletionSettings::toSettings(QSettings *s) const ...@@ -56,6 +57,7 @@ void CompletionSettings::toSettings(QSettings *s) const
s->setValue(spaceAfterFunctionNameKey, m_spaceAfterFunctionName); s->setValue(spaceAfterFunctionNameKey, m_spaceAfterFunctionName);
s->setValue(autoSplitStringsKey, m_autoSplitStrings); s->setValue(autoSplitStringsKey, m_autoSplitStrings);
s->setValue(animateAutoCompleteKey, m_animateAutoComplete); s->setValue(animateAutoCompleteKey, m_animateAutoComplete);
s->setValue(highlightAutoCompleteKey, m_highlightAutoComplete);
s->endGroup(); s->endGroup();
} }
...@@ -86,6 +88,8 @@ void CompletionSettings::fromSettings(QSettings *s) ...@@ -86,6 +88,8 @@ void CompletionSettings::fromSettings(QSettings *s)
s->value(autoSplitStringsKey, m_autoSplitStrings).toBool(); s->value(autoSplitStringsKey, m_autoSplitStrings).toBool();
m_animateAutoComplete = m_animateAutoComplete =
s->value(animateAutoCompleteKey, m_animateAutoComplete).toBool(); s->value(animateAutoCompleteKey, m_animateAutoComplete).toBool();
m_highlightAutoComplete =
s->value(highlightAutoCompleteKey, m_highlightAutoComplete).toBool();
s->endGroup(); s->endGroup();
} }
...@@ -102,5 +106,6 @@ bool CompletionSettings::equals(const CompletionSettings &cs) const ...@@ -102,5 +106,6 @@ bool CompletionSettings::equals(const CompletionSettings &cs) const
&& m_spaceAfterFunctionName == cs.m_spaceAfterFunctionName && m_spaceAfterFunctionName == cs.m_spaceAfterFunctionName
&& m_autoSplitStrings == cs.m_autoSplitStrings && m_autoSplitStrings == cs.m_autoSplitStrings
&& m_animateAutoComplete == cs.m_animateAutoComplete && m_animateAutoComplete == cs.m_animateAutoComplete
&& m_highlightAutoComplete == cs.m_highlightAutoComplete
; ;
} }
...@@ -67,6 +67,7 @@ public: ...@@ -67,6 +67,7 @@ public:
bool m_spaceAfterFunctionName = false; bool m_spaceAfterFunctionName = false;
bool m_autoSplitStrings = true; bool m_autoSplitStrings = true;
bool m_animateAutoComplete = true; bool m_animateAutoComplete = true;
bool m_highlightAutoComplete = false;
}; };
inline bool operator==(const CompletionSettings &t1, const CompletionSettings &t2) { return t1.equals(t2); } inline bool operator==(const CompletionSettings &t1, const CompletionSettings &t2) { return t1.equals(t2); }
......
...@@ -103,6 +103,7 @@ QWidget *CompletionSettingsPage::widget() ...@@ -103,6 +103,7 @@ QWidget *CompletionSettingsPage::widget()
m_page->spaceAfterFunctionName->setChecked(m_completionSettings.m_spaceAfterFunctionName); m_page->spaceAfterFunctionName->setChecked(m_completionSettings.m_spaceAfterFunctionName);
m_page->autoSplitStrings->setChecked(m_completionSettings.m_autoSplitStrings); m_page->autoSplitStrings->setChecked(m_completionSettings.m_autoSplitStrings);
m_page->animateAutoComplete->setChecked(m_completionSettings.m_animateAutoComplete); 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->enableDoxygenCheckBox->setChecked(m_commentsSettings.m_enableDoxygen);
m_page->generateBriefCheckBox->setChecked(m_commentsSettings.m_generateBrief); m_page->generateBriefCheckBox->setChecked(m_commentsSettings.m_generateBrief);
...@@ -177,6 +178,7 @@ void CompletionSettingsPage::settingsFromUi(CompletionSettings &completion, Comm ...@@ -177,6 +178,7 @@ void CompletionSettingsPage::settingsFromUi(CompletionSettings &completion, Comm
completion.m_spaceAfterFunctionName = m_page->spaceAfterFunctionName->isChecked(); completion.m_spaceAfterFunctionName = m_page->spaceAfterFunctionName->isChecked();
completion.m_autoSplitStrings = m_page->autoSplitStrings->isChecked(); completion.m_autoSplitStrings = m_page->autoSplitStrings->isChecked();
completion.m_animateAutoComplete = m_page->animateAutoComplete->isChecked(); completion.m_animateAutoComplete = m_page->animateAutoComplete->isChecked();
completion.m_highlightAutoComplete = m_page->highlightAutoComplete->isChecked();
comment.m_enableDoxygen = m_page->enableDoxygenCheckBox->isChecked(); comment.m_enableDoxygen = m_page->enableDoxygenCheckBox->isChecked();
comment.m_generateBrief = m_page->generateBriefCheckBox->isChecked(); comment.m_generateBrief = m_page->generateBriefCheckBox->isChecked();
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>511</width> <width>511</width>
<height>420</height> <height>437</height>
</rect> </rect>
</property> </property>
<layout class="QVBoxLayout" name="verticalLayout_2"> <layout class="QVBoxLayout" name="verticalLayout_2">
...@@ -227,6 +227,13 @@ In addition, Shift+Enter inserts an escape character at the cursor position and ...@@ -227,6 +227,13 @@ In addition, Shift+Enter inserts an escape character at the cursor position and
</property> </property>
</widget> </widget>
</item> </item>
<item row="3" column="1">
<widget class="QCheckBox" name="highlightAutoComplete">
<property name="text">
<string>Highlight automatically inserted text</string>
</property>
</widget>
</item>
</layout> </layout>
</widget> </widget>
</item> </item>
...@@ -316,6 +323,7 @@ In addition, Shift+Enter inserts an escape character at the cursor position and ...@@ -316,6 +323,7 @@ In addition, Shift+Enter inserts an escape character at the cursor position and
<tabstop>surroundQuotes</tabstop> <tabstop>surroundQuotes</tabstop>
<tabstop>spaceAfterFunctionName</tabstop> <tabstop>spaceAfterFunctionName</tabstop>
<tabstop>animateAutoComplete</tabstop> <tabstop>animateAutoComplete</tabstop>
<tabstop>highlightAutoComplete</tabstop>
<tabstop>enableDoxygenCheckBox</tabstop> <tabstop>enableDoxygenCheckBox</tabstop>
<tabstop>generateBriefCheckBox</tabstop> <tabstop>generateBriefCheckBox</tabstop>
<tabstop>leadingAsterisksCheckBox</tabstop> <tabstop>leadingAsterisksCheckBox</tabstop>
......
...@@ -329,7 +329,7 @@ public: ...@@ -329,7 +329,7 @@ public:
// parentheses matcher // parentheses matcher
void _q_matchParentheses(); void _q_matchParentheses();
void _q_highlightBlocks(); void _q_highlightBlocks();
void _q_autocompleterHighlight(const QTextCursor &cursor = QTextCursor()); void autocompleterHighlight(const QTextCursor &cursor = QTextCursor());
void updateAnimator(QPointer<TextEditorAnimator> animator, QPainter &painter); void updateAnimator(QPointer<TextEditorAnimator> animator, QPainter &painter);
void cancelCurrentAnimations(); void cancelCurrentAnimations();
void slotSelectionChanged(); void slotSelectionChanged();
...@@ -452,8 +452,14 @@ public: ...@@ -452,8 +452,14 @@ public:
QList<BaseHoverHandler *> m_hoverHandlers; // Not owned QList<BaseHoverHandler *> m_hoverHandlers; // Not owned
QPointer<TextEditorAnimator> m_bracketsAnimator; QPointer<TextEditorAnimator> m_bracketsAnimator;
// Animation and highlighting of auto completed text
QPointer<TextEditorAnimator> m_autocompleteAnimator; QPointer<TextEditorAnimator> m_autocompleteAnimator;
bool m_animateAutoComplete = true; bool m_animateAutoComplete = true;
bool m_highlightAutoComplete = true;
bool m_keepAutoCompletionHighlight = false;
QTextCursor m_autoCompleteHighlightPos;
int m_cursorBlockNumber; int m_cursorBlockNumber;
int m_blockCount; int m_blockCount;
...@@ -629,6 +635,7 @@ static const char kTextBlockMimeType[] = "application/vnd.qtcreator.blocktext"; ...@@ -629,6 +635,7 @@ static const char kTextBlockMimeType[] = "application/vnd.qtcreator.blocktext";
Id TextEditorWidget::SnippetPlaceholderSelection("TextEdit.SnippetPlaceHolderSelection"); Id TextEditorWidget::SnippetPlaceholderSelection("TextEdit.SnippetPlaceHolderSelection");
Id TextEditorWidget::CurrentLineSelection("TextEdit.CurrentLineSelection"); Id TextEditorWidget::CurrentLineSelection("TextEdit.CurrentLineSelection");
Id TextEditorWidget::ParenthesesMatchingSelection("TextEdit.ParenthesesMatchingSelection"); Id TextEditorWidget::ParenthesesMatchingSelection("TextEdit.ParenthesesMatchingSelection");
Id TextEditorWidget::AutoCompleteSelection("TextEdit.AutoCompleteSelection");
Id TextEditorWidget::CodeWarningsSelection("TextEdit.CodeWarningsSelection"); Id TextEditorWidget::CodeWarningsSelection("TextEdit.CodeWarningsSelection");
Id TextEditorWidget::CodeSemanticsSelection("TextEdit.CodeSemanticsSelection"); Id TextEditorWidget::CodeSemanticsSelection("TextEdit.CodeSemanticsSelection");
Id TextEditorWidget::UndefinedSymbolSelection("TextEdit.UndefinedSymbolSelection"); Id TextEditorWidget::UndefinedSymbolSelection("TextEdit.UndefinedSymbolSelection");
...@@ -2156,12 +2163,12 @@ void TextEditorWidget::keyPressEvent(QKeyEvent *e) ...@@ -2156,12 +2163,12 @@ void TextEditorWidget::keyPressEvent(QKeyEvent *e)
d->m_document->autoIndent(ensureVisible); d->m_document->autoIndent(ensureVisible);
else if (!previousIndentationString.isEmpty()) else if (!previousIndentationString.isEmpty())
ensureVisible.insertText(previousIndentationString); ensureVisible.insertText(previousIndentationString);
if (d->m_animateAutoComplete) { if (d->m_animateAutoComplete || d->m_highlightAutoComplete) {
QTextCursor tc = ensureVisible; QTextCursor tc = ensureVisible;
tc.movePosition(QTextCursor::EndOfBlock); tc.movePosition(QTextCursor::EndOfBlock);
tc.movePosition(QTextCursor::StartOfBlock, QTextCursor::KeepAnchor); tc.movePosition(QTextCursor::StartOfBlock, QTextCursor::KeepAnchor);
tc.movePosition(QTextCursor::NextWord, QTextCursor::KeepAnchor); tc.movePosition(QTextCursor::NextWord, QTextCursor::KeepAnchor);
d->_q_autocompleterHighlight(tc); d->autocompleterHighlight(tc);
} }
} }
setTextCursor(ensureVisible); setTextCursor(ensureVisible);
...@@ -2422,9 +2429,10 @@ void TextEditorWidget::keyPressEvent(QKeyEvent *e) ...@@ -2422,9 +2429,10 @@ void TextEditorWidget::keyPressEvent(QKeyEvent *e)
if (!autoText.isEmpty()) { if (!autoText.isEmpty()) {
int pos = cursor.position(); int pos = cursor.position();
cursor.insertText(autoText); 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 //Select the inserted text, to be able to re-indent the inserted text
cursor.setPosition(pos, QTextCursor::KeepAnchor); cursor.setPosition(pos, QTextCursor::KeepAnchor);
d->_q_autocompleterHighlight(cursor);
} }
if (!electricChar.isNull() && d->m_autoCompleter->contextAllowsElectricCharacters(cursor)) if (!electricChar.isNull() && d->m_autoCompleter->contextAllowsElectricCharacters(cursor))
d->m_document->autoIndent(cursor, electricChar); d->m_document->autoIndent(cursor, electricChar);
...@@ -4705,6 +4713,17 @@ void TextEditorWidgetPrivate::updateHighlights() ...@@ -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<QTextEdit::ExtraSelection>()); // clear
m_autoCompleteHighlightPos = QTextCursor();
}
});
}
updateCurrentLineHighlight(); updateCurrentLineHighlight();
if (m_displaySettings.m_highlightBlocks) { if (m_displaySettings.m_highlightBlocks) {
...@@ -6026,23 +6045,38 @@ void TextEditorWidgetPrivate::_q_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<QTextEdit::ExtraSelection> extraSelections;
if ((!m_animateAutoComplete && !m_highlightAutoComplete)
|| q->isReadOnly() || !cursor.hasSelection()) {
q->setExtraSelections(TextEditorWidget::AutoCompleteSelection, extraSelections); // clear
return; return;
}
const QTextCharFormat &matchFormat const QTextCharFormat &matchFormat
= q->textDocument()->fontSettings().toTextCharFormat(C_AUTOCOMPLETE); = q->textDocument()->fontSettings().toTextCharFormat(C_AUTOCOMPLETE);
cancelCurrentAnimations();// one animation is enough if (m_highlightAutoComplete) {
m_autocompleteAnimator = new TextEditorAnimator(this); QTextEdit::ExtraSelection sel;
m_autocompleteAnimator->setPosition(cursor.selectionStart()); sel.cursor = cursor;
QPalette pal; sel.format.setBackground(matchFormat.background());
pal.setBrush(QPalette::Text, matchFormat.foreground()); extraSelections.append(sel);
pal.setBrush(QPalette::Base, matchFormat.background()); m_autoCompleteHighlightPos = cursor;
m_autocompleteAnimator->setData(q->font(), pal, cursor.selectedText()); m_autoCompleteHighlightPos.movePosition(QTextCursor::PreviousCharacter);
connect(m_autocompleteAnimator.data(), &TextEditorAnimator::updateRequest, }
this, &TextEditorWidgetPrivate::_q_animateUpdate); 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<TextEditorAnimator> animator, void TextEditorWidgetPrivate::updateAnimator(QPointer<TextEditorAnimator> animator,
...@@ -6089,6 +6123,7 @@ void TextEditorWidget::focusOutEvent(QFocusEvent *e) ...@@ -6089,6 +6123,7 @@ void TextEditorWidget::focusOutEvent(QFocusEvent *e)
QPlainTextEdit::focusOutEvent(e); QPlainTextEdit::focusOutEvent(e);
if (viewport()->cursor().shape() == Qt::BlankCursor) if (viewport()->cursor().shape() == Qt::BlankCursor)
viewport()->setCursor(Qt::IBeamCursor); viewport()->setCursor(Qt::IBeamCursor);
d->updateHighlights();
} }
...@@ -6542,6 +6577,7 @@ void TextEditorWidget::setCompletionSettings(const CompletionSettings &completio ...@@ -6542,6 +6577,7 @@ void TextEditorWidget::setCompletionSettings(const CompletionSettings &completio
d->m_autoCompleter->setAutoInsertQuotesEnabled(completionSettings.m_autoInsertQuotes); d->m_autoCompleter->setAutoInsertQuotesEnabled(completionSettings.m_autoInsertQuotes);
d->m_autoCompleter->setSurroundWithQuotesEnabled(completionSettings.m_surroundingAutoQuotes); d->m_autoCompleter->setSurroundWithQuotesEnabled(completionSettings.m_surroundingAutoQuotes);
d->m_animateAutoComplete = completionSettings.m_animateAutoComplete; d->m_animateAutoComplete = completionSettings.m_animateAutoComplete;
d->m_highlightAutoComplete = completionSettings.m_highlightAutoComplete;
} }
void TextEditorWidget::setExtraEncodingSettings(const ExtraEncodingSettings &extraEncodingSettings) void TextEditorWidget::setExtraEncodingSettings(const ExtraEncodingSettings &extraEncodingSettings)
...@@ -7003,6 +7039,11 @@ void TextEditorWidget::insertExtraToolBarWidget(TextEditorWidget::Side side, ...@@ -7003,6 +7039,11 @@ void TextEditorWidget::insertExtraToolBarWidget(TextEditorWidget::Side side,
d->m_toolBar->insertWidget(d->m_toolBar->actions().first(), widget); d->m_toolBar->insertWidget(d->m_toolBar->actions().first(), widget);
} }
void TextEditorWidget::keepAutoCompletionHighlight(bool keepHighlight)
{
d->m_keepAutoCompletionHighlight = keepHighlight;
}
int BaseTextEditor::currentLine() const int BaseTextEditor::currentLine() const
{ {
return editorWidget()->textCursor().blockNumber() + 1; return editorWidget()->textCursor().blockNumber() + 1;
......
...@@ -301,6 +301,7 @@ public: ...@@ -301,6 +301,7 @@ public:
static Core::Id SnippetPlaceholderSelection; static Core::Id SnippetPlaceholderSelection;
static Core::Id CurrentLineSelection; static Core::Id CurrentLineSelection;
static Core::Id ParenthesesMatchingSelection; static Core::Id ParenthesesMatchingSelection;
static Core::Id AutoCompleteSelection;
static Core::Id CodeWarningsSelection; static Core::Id CodeWarningsSelection;
static Core::Id CodeSemanticsSelection; static Core::Id CodeSemanticsSelection;
static Core::Id UndefinedSymbolSelection; static Core::Id UndefinedSymbolSelection;
...@@ -323,6 +324,9 @@ public: ...@@ -323,6 +324,9 @@ public:
enum Side { Left, Right }; enum Side { Left, Right };
void insertExtraToolBarWidget(Side side, QWidget *widget); 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 copy();
virtual void paste(); virtual void paste();
virtual void cut(); virtual void cut();
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment