forked from qt-creator/qt-creator
TextEditor: highlight selected text
Change-Id: Ib46908decef51d478f6954a116108c48e4a07ed3 Reviewed-by: Marcus Tillmanns <marcus.tillmanns@qt.io>
This commit is contained in:
@@ -432,6 +432,7 @@ VcsBase_FileUnmerged_TextColor=ffff4040
|
|||||||
Bookmarks_TextMarkColor=ff8080ff
|
Bookmarks_TextMarkColor=ff8080ff
|
||||||
|
|
||||||
TextEditor_SearchResult_ScrollBarColor=ff00c000
|
TextEditor_SearchResult_ScrollBarColor=ff00c000
|
||||||
|
TextEditor_Selection_ScrollBarColor=ff888888
|
||||||
TextEditor_CurrentLine_ScrollBarColor=ffffffff
|
TextEditor_CurrentLine_ScrollBarColor=ffffffff
|
||||||
|
|
||||||
ProjectExplorer_TaskError_TextMarkColor=error
|
ProjectExplorer_TaskError_TextMarkColor=error
|
||||||
|
|||||||
@@ -424,6 +424,7 @@ VcsBase_FileUnmerged_TextColor=ffee0000
|
|||||||
Bookmarks_TextMarkColor=ffa0a0ff
|
Bookmarks_TextMarkColor=ffa0a0ff
|
||||||
|
|
||||||
TextEditor_SearchResult_ScrollBarColor=ff00c000
|
TextEditor_SearchResult_ScrollBarColor=ff00c000
|
||||||
|
TextEditor_Selection_ScrollBarColor=ffcccccc
|
||||||
TextEditor_CurrentLine_ScrollBarColor=ff404040
|
TextEditor_CurrentLine_ScrollBarColor=ff404040
|
||||||
|
|
||||||
ProjectExplorer_TaskError_TextMarkColor=error
|
ProjectExplorer_TaskError_TextMarkColor=error
|
||||||
|
|||||||
@@ -437,6 +437,7 @@ VcsBase_FileUnmerged_TextColor=ffee0000
|
|||||||
Bookmarks_TextMarkColor=ffa0a0ff
|
Bookmarks_TextMarkColor=ffa0a0ff
|
||||||
|
|
||||||
TextEditor_SearchResult_ScrollBarColor=ff00c000
|
TextEditor_SearchResult_ScrollBarColor=ff00c000
|
||||||
|
TextEditor_Selection_ScrollBarColor=ffcccccc
|
||||||
TextEditor_CurrentLine_ScrollBarColor=ff404040
|
TextEditor_CurrentLine_ScrollBarColor=ff404040
|
||||||
|
|
||||||
ProjectExplorer_TaskError_TextMarkColor=error
|
ProjectExplorer_TaskError_TextMarkColor=error
|
||||||
|
|||||||
@@ -440,6 +440,7 @@ VcsBase_FileUnmerged_TextColor=ffff4040
|
|||||||
Bookmarks_TextMarkColor=ff8080ff
|
Bookmarks_TextMarkColor=ff8080ff
|
||||||
|
|
||||||
TextEditor_SearchResult_ScrollBarColor=ff00c000
|
TextEditor_SearchResult_ScrollBarColor=ff00c000
|
||||||
|
TextEditor_Selection_ScrollBarColor=ff888888
|
||||||
TextEditor_CurrentLine_ScrollBarColor=ffffffff
|
TextEditor_CurrentLine_ScrollBarColor=ffffffff
|
||||||
|
|
||||||
ProjectExplorer_TaskError_TextMarkColor=error
|
ProjectExplorer_TaskError_TextMarkColor=error
|
||||||
|
|||||||
@@ -436,6 +436,7 @@ VcsBase_FileUnmerged_TextColor=ffff4040
|
|||||||
Bookmarks_TextMarkColor=ff8080ff
|
Bookmarks_TextMarkColor=ff8080ff
|
||||||
|
|
||||||
TextEditor_SearchResult_ScrollBarColor=ff00c000
|
TextEditor_SearchResult_ScrollBarColor=ff00c000
|
||||||
|
TextEditor_Selection_ScrollBarColor=ff888888
|
||||||
TextEditor_CurrentLine_ScrollBarColor=ffffffff
|
TextEditor_CurrentLine_ScrollBarColor=ffffffff
|
||||||
|
|
||||||
ProjectExplorer_TaskError_TextMarkColor=error
|
ProjectExplorer_TaskError_TextMarkColor=error
|
||||||
|
|||||||
@@ -433,6 +433,7 @@ VcsBase_FileUnmerged_TextColor=ffee0000
|
|||||||
Bookmarks_TextMarkColor=ffa0a0ff
|
Bookmarks_TextMarkColor=ffa0a0ff
|
||||||
|
|
||||||
TextEditor_SearchResult_ScrollBarColor=ff00c000
|
TextEditor_SearchResult_ScrollBarColor=ff00c000
|
||||||
|
TextEditor_Selection_ScrollBarColor=ffcccccc
|
||||||
TextEditor_CurrentLine_ScrollBarColor=ff404040
|
TextEditor_CurrentLine_ScrollBarColor=ff404040
|
||||||
|
|
||||||
ProjectExplorer_TaskError_TextMarkColor=error
|
ProjectExplorer_TaskError_TextMarkColor=error
|
||||||
|
|||||||
@@ -431,6 +431,7 @@ VcsBase_FileUnmerged_TextColor=ffee0000
|
|||||||
Bookmarks_TextMarkColor=ffa0a0ff
|
Bookmarks_TextMarkColor=ffa0a0ff
|
||||||
|
|
||||||
TextEditor_SearchResult_ScrollBarColor=ff00c000
|
TextEditor_SearchResult_ScrollBarColor=ff00c000
|
||||||
|
TextEditor_Selection_ScrollBarColor=ffcccccc
|
||||||
TextEditor_CurrentLine_ScrollBarColor=ff404040
|
TextEditor_CurrentLine_ScrollBarColor=ff404040
|
||||||
|
|
||||||
ProjectExplorer_TaskError_TextMarkColor=error
|
ProjectExplorer_TaskError_TextMarkColor=error
|
||||||
|
|||||||
@@ -15,6 +15,17 @@ bool Position::operator==(const Position &other) const
|
|||||||
return line == other.line && column == other.column;
|
return line == other.line && column == other.column;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int Position::positionInDocument(QTextDocument *doc) const
|
||||||
|
{
|
||||||
|
if (!isValid())
|
||||||
|
return -1;
|
||||||
|
QTC_ASSERT(doc, return -1);
|
||||||
|
QTextBlock block = doc->findBlockByNumber(line - 1);
|
||||||
|
if (!block.isValid())
|
||||||
|
return -1;
|
||||||
|
return block.position() + column;
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Returns the text position of a \a fileName and sets the \a postfixPos if
|
Returns the text position of a \a fileName and sets the \a postfixPos if
|
||||||
it can find a positional postfix.
|
it can find a positional postfix.
|
||||||
@@ -107,6 +118,14 @@ bool Range::operator==(const Range &other) const
|
|||||||
return begin == other.begin && end == other.end;
|
return begin == other.begin && end == other.end;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QTextCursor Range::toTextCursor(QTextDocument *doc) const
|
||||||
|
{
|
||||||
|
QTextCursor cursor(doc);
|
||||||
|
cursor.setPosition(begin.positionInDocument(doc));
|
||||||
|
cursor.setPosition(end.positionInDocument(doc), QTextCursor::KeepAnchor);
|
||||||
|
return cursor;
|
||||||
|
}
|
||||||
|
|
||||||
bool convertPosition(const QTextDocument *document, int pos, int *line, int *column)
|
bool convertPosition(const QTextDocument *document, int pos, int *line, int *column)
|
||||||
{
|
{
|
||||||
QTextBlock block = document->findBlock(pos);
|
QTextBlock block = document->findBlock(pos);
|
||||||
|
|||||||
@@ -30,6 +30,8 @@ public:
|
|||||||
|
|
||||||
bool isValid() const { return line > 0 && column >= 0; }
|
bool isValid() const { return line > 0 && column >= 0; }
|
||||||
|
|
||||||
|
int positionInDocument(QTextDocument *doc) const;
|
||||||
|
|
||||||
static Position fromFileName(QStringView fileName, int &postfixPos);
|
static Position fromFileName(QStringView fileName, int &postfixPos);
|
||||||
static Position fromPositionInDocument(const QTextDocument *document, int pos);
|
static Position fromPositionInDocument(const QTextDocument *document, int pos);
|
||||||
static Position fromCursor(const QTextCursor &cursor);
|
static Position fromCursor(const QTextCursor &cursor);
|
||||||
@@ -49,6 +51,8 @@ public:
|
|||||||
bool operator==(const Range &other) const;
|
bool operator==(const Range &other) const;
|
||||||
|
|
||||||
bool operator!=(const Range &other) const { return !(operator==(other)); }
|
bool operator!=(const Range &other) const { return !(operator==(other)); }
|
||||||
|
|
||||||
|
QTextCursor toTextCursor(QTextDocument *doc) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
// line is 1-based, column is 0-based
|
// line is 1-based, column is 0-based
|
||||||
|
|||||||
@@ -259,6 +259,7 @@ public:
|
|||||||
|
|
||||||
/* TextEditor Plugin */
|
/* TextEditor Plugin */
|
||||||
TextEditor_SearchResult_ScrollBarColor,
|
TextEditor_SearchResult_ScrollBarColor,
|
||||||
|
TextEditor_Selection_ScrollBarColor,
|
||||||
TextEditor_CurrentLine_ScrollBarColor,
|
TextEditor_CurrentLine_ScrollBarColor,
|
||||||
|
|
||||||
/* Debugger Plugin */
|
/* Debugger Plugin */
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
#include "highlightscrollbarcontroller.h"
|
#include "highlightscrollbarcontroller.h"
|
||||||
|
|
||||||
#include <QAbstractScrollArea>
|
#include <QAbstractScrollArea>
|
||||||
|
#include <QLoggingCategory>
|
||||||
#include <QPainter>
|
#include <QPainter>
|
||||||
#include <QResizeEvent>
|
#include <QResizeEvent>
|
||||||
#include <QScrollBar>
|
#include <QScrollBar>
|
||||||
@@ -12,6 +13,8 @@
|
|||||||
|
|
||||||
using namespace Utils;
|
using namespace Utils;
|
||||||
|
|
||||||
|
static Q_LOGGING_CATEGORY(LOG, "qtc.utils.highlightscrollbar", QtWarningMsg)
|
||||||
|
|
||||||
namespace Core {
|
namespace Core {
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -403,6 +406,7 @@ void HighlightScrollBarController::addHighlight(Highlight highlight)
|
|||||||
if (!m_overlay)
|
if (!m_overlay)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
qCDebug(LOG) << "addHighlight" << highlight.category.toString() << highlight.position;
|
||||||
m_highlights[highlight.category] << highlight;
|
m_highlights[highlight.category] << highlight;
|
||||||
m_overlay->scheduleUpdate();
|
m_overlay->scheduleUpdate();
|
||||||
}
|
}
|
||||||
@@ -412,6 +416,7 @@ void HighlightScrollBarController::removeHighlights(Id category)
|
|||||||
if (!m_overlay)
|
if (!m_overlay)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
qCDebug(LOG) << "removeHighlights" << category.toString();
|
||||||
m_highlights.remove(category);
|
m_highlights.remove(category);
|
||||||
m_overlay->scheduleUpdate();
|
m_overlay->scheduleUpdate();
|
||||||
}
|
}
|
||||||
@@ -421,6 +426,7 @@ void HighlightScrollBarController::removeAllHighlights()
|
|||||||
if (!m_overlay)
|
if (!m_overlay)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
qCDebug(LOG) << "removeAllHighlights";
|
||||||
m_highlights.clear();
|
m_highlights.clear();
|
||||||
m_overlay->scheduleUpdate();
|
m_overlay->scheduleUpdate();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ const char animateWithinFileTimeMaxKey[] = "AnimateWithinFileTimeMax";
|
|||||||
const char displayAnnotationsKey[] = "DisplayAnnotations";
|
const char displayAnnotationsKey[] = "DisplayAnnotations";
|
||||||
const char annotationAlignmentKey[] = "AnnotationAlignment";
|
const char annotationAlignmentKey[] = "AnnotationAlignment";
|
||||||
const char minimalAnnotationContentKey[] = "MinimalAnnotationContent";
|
const char minimalAnnotationContentKey[] = "MinimalAnnotationContent";
|
||||||
|
const char highlightSelectionKey[] = "HighlightSelection";
|
||||||
const char groupPostfix[] = "textDisplaySettings";
|
const char groupPostfix[] = "textDisplaySettings";
|
||||||
|
|
||||||
void DisplaySettings::toSettings(QtcSettings *s) const
|
void DisplaySettings::toSettings(QtcSettings *s) const
|
||||||
@@ -61,6 +62,7 @@ void DisplaySettings::toSettings(QtcSettings *s) const
|
|||||||
s->setValue(animateNavigationWithinFileKey, m_animateNavigationWithinFile);
|
s->setValue(animateNavigationWithinFileKey, m_animateNavigationWithinFile);
|
||||||
s->setValue(displayAnnotationsKey, m_displayAnnotations);
|
s->setValue(displayAnnotationsKey, m_displayAnnotations);
|
||||||
s->setValue(annotationAlignmentKey, static_cast<int>(m_annotationAlignment));
|
s->setValue(annotationAlignmentKey, static_cast<int>(m_annotationAlignment));
|
||||||
|
s->setValue(highlightSelectionKey, m_highlightSelection);
|
||||||
s->endGroup();
|
s->endGroup();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -92,6 +94,7 @@ void DisplaySettings::fromSettings(QtcSettings *s)
|
|||||||
s->value(annotationAlignmentKey,
|
s->value(annotationAlignmentKey,
|
||||||
static_cast<int>(m_annotationAlignment)).toInt());
|
static_cast<int>(m_annotationAlignment)).toInt());
|
||||||
m_minimalAnnotationContent = s->value(minimalAnnotationContentKey, m_minimalAnnotationContent).toInt();
|
m_minimalAnnotationContent = s->value(minimalAnnotationContentKey, m_minimalAnnotationContent).toInt();
|
||||||
|
m_highlightSelection = s->value(highlightSelectionKey, m_highlightSelection).toBool();
|
||||||
s->endGroup();
|
s->endGroup();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -119,6 +122,7 @@ bool DisplaySettings::equals(const DisplaySettings &ds) const
|
|||||||
&& m_displayAnnotations == ds.m_displayAnnotations
|
&& m_displayAnnotations == ds.m_displayAnnotations
|
||||||
&& m_annotationAlignment == ds.m_annotationAlignment
|
&& m_annotationAlignment == ds.m_annotationAlignment
|
||||||
&& m_minimalAnnotationContent == ds.m_minimalAnnotationContent
|
&& m_minimalAnnotationContent == ds.m_minimalAnnotationContent
|
||||||
|
&& m_highlightSelection == ds.m_highlightSelection
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -52,6 +52,7 @@ public:
|
|||||||
bool m_displayFileLineEnding = true;
|
bool m_displayFileLineEnding = true;
|
||||||
bool m_scrollBarHighlights = true;
|
bool m_scrollBarHighlights = true;
|
||||||
bool m_animateNavigationWithinFile = false;
|
bool m_animateNavigationWithinFile = false;
|
||||||
|
bool m_highlightSelection = true;
|
||||||
int m_animateWithinFileTimeMax = 333; // read only setting
|
int m_animateWithinFileTimeMax = 333; // read only setting
|
||||||
bool m_displayAnnotations = true;
|
bool m_displayAnnotations = true;
|
||||||
AnnotationAlignment m_annotationAlignment = AnnotationAlignment::RightSide;
|
AnnotationAlignment m_annotationAlignment = AnnotationAlignment::RightSide;
|
||||||
|
|||||||
@@ -98,6 +98,10 @@ public:
|
|||||||
visualizeWhitespace = new QCheckBox(Tr::tr("&Visualize whitespace"));
|
visualizeWhitespace = new QCheckBox(Tr::tr("&Visualize whitespace"));
|
||||||
visualizeWhitespace->setToolTip(Tr::tr("Shows tabs and spaces."));
|
visualizeWhitespace->setToolTip(Tr::tr("Shows tabs and spaces."));
|
||||||
|
|
||||||
|
highlightSelection = new QCheckBox(Tr::tr("&Highlight Selection"));
|
||||||
|
highlightSelection->setToolTip(Tr::tr("Adds a colored background and a marker to the "
|
||||||
|
"scrollbar to occurrences of the selected text."));
|
||||||
|
|
||||||
leftAligned = new QRadioButton(Tr::tr("Next to editor content"));
|
leftAligned = new QRadioButton(Tr::tr("Next to editor content"));
|
||||||
atMargin = new QRadioButton(Tr::tr("Next to right margin"));
|
atMargin = new QRadioButton(Tr::tr("Next to right margin"));
|
||||||
rightAligned = new QRadioButton(Tr::tr("Aligned at right side"));
|
rightAligned = new QRadioButton(Tr::tr("Aligned at right side"));
|
||||||
@@ -143,6 +147,7 @@ public:
|
|||||||
autoFoldFirstComment,
|
autoFoldFirstComment,
|
||||||
scrollBarHighlights,
|
scrollBarHighlights,
|
||||||
animateNavigationWithinFile,
|
animateNavigationWithinFile,
|
||||||
|
highlightSelection,
|
||||||
},
|
},
|
||||||
Column {
|
Column {
|
||||||
highlightCurrentLine,
|
highlightCurrentLine,
|
||||||
@@ -195,6 +200,7 @@ public:
|
|||||||
QCheckBox *openLinksInNextSplit;
|
QCheckBox *openLinksInNextSplit;
|
||||||
QCheckBox *highlightMatchingParentheses;
|
QCheckBox *highlightMatchingParentheses;
|
||||||
QCheckBox *visualizeWhitespace;
|
QCheckBox *visualizeWhitespace;
|
||||||
|
QCheckBox *highlightSelection;
|
||||||
QGroupBox *displayAnnotations;
|
QGroupBox *displayAnnotations;
|
||||||
QRadioButton *leftAligned;
|
QRadioButton *leftAligned;
|
||||||
QRadioButton *atMargin;
|
QRadioButton *atMargin;
|
||||||
@@ -238,6 +244,7 @@ void DisplaySettingsWidget::settingsFromUI(DisplaySettings &displaySettings,
|
|||||||
displaySettings.m_scrollBarHighlights = scrollBarHighlights->isChecked();
|
displaySettings.m_scrollBarHighlights = scrollBarHighlights->isChecked();
|
||||||
displaySettings.m_animateNavigationWithinFile = animateNavigationWithinFile->isChecked();
|
displaySettings.m_animateNavigationWithinFile = animateNavigationWithinFile->isChecked();
|
||||||
displaySettings.m_displayAnnotations = displayAnnotations->isChecked();
|
displaySettings.m_displayAnnotations = displayAnnotations->isChecked();
|
||||||
|
displaySettings.m_highlightSelection = highlightSelection->isChecked();
|
||||||
if (leftAligned->isChecked())
|
if (leftAligned->isChecked())
|
||||||
displaySettings.m_annotationAlignment = AnnotationAlignment::NextToContent;
|
displaySettings.m_annotationAlignment = AnnotationAlignment::NextToContent;
|
||||||
else if (atMargin->isChecked())
|
else if (atMargin->isChecked())
|
||||||
@@ -276,6 +283,7 @@ void DisplaySettingsWidget::settingsToUI()
|
|||||||
scrollBarHighlights->setChecked(displaySettings.m_scrollBarHighlights);
|
scrollBarHighlights->setChecked(displaySettings.m_scrollBarHighlights);
|
||||||
animateNavigationWithinFile->setChecked(displaySettings.m_animateNavigationWithinFile);
|
animateNavigationWithinFile->setChecked(displaySettings.m_animateNavigationWithinFile);
|
||||||
displayAnnotations->setChecked(displaySettings.m_displayAnnotations);
|
displayAnnotations->setChecked(displaySettings.m_displayAnnotations);
|
||||||
|
highlightSelection->setChecked(displaySettings.m_highlightSelection);
|
||||||
switch (displaySettings.m_annotationAlignment) {
|
switch (displaySettings.m_annotationAlignment) {
|
||||||
case AnnotationAlignment::NextToContent: leftAligned->setChecked(true); break;
|
case AnnotationAlignment::NextToContent: leftAligned->setChecked(true); break;
|
||||||
case AnnotationAlignment::NextToMargin: atMargin->setChecked(true); break;
|
case AnnotationAlignment::NextToMargin: atMargin->setChecked(true); break;
|
||||||
|
|||||||
@@ -79,6 +79,13 @@ public:
|
|||||||
IAssistProvider *m_quickFixProvider = nullptr;
|
IAssistProvider *m_quickFixProvider = nullptr;
|
||||||
QScopedPointer<Indenter> m_indenter;
|
QScopedPointer<Indenter> m_indenter;
|
||||||
QScopedPointer<Formatter> m_formatter;
|
QScopedPointer<Formatter> m_formatter;
|
||||||
|
struct PlainTextCache
|
||||||
|
{
|
||||||
|
int revision = -1;
|
||||||
|
QString plainText;
|
||||||
|
};
|
||||||
|
|
||||||
|
PlainTextCache m_plainTextCache;
|
||||||
|
|
||||||
int m_autoSaveRevision = -1;
|
int m_autoSaveRevision = -1;
|
||||||
bool m_silentReload = false;
|
bool m_silentReload = false;
|
||||||
@@ -305,7 +312,11 @@ QString TextDocument::convertToPlainText(const QString &rawText)
|
|||||||
|
|
||||||
QString TextDocument::plainText() const
|
QString TextDocument::plainText() const
|
||||||
{
|
{
|
||||||
return convertToPlainText(d->m_document.toRawText());
|
if (d->m_plainTextCache.revision != d->m_document.revision()) {
|
||||||
|
d->m_plainTextCache.plainText = convertToPlainText(d->m_document.toRawText());
|
||||||
|
d->m_plainTextCache.revision = d->m_document.revision();
|
||||||
|
}
|
||||||
|
return d->m_plainTextCache.plainText;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString TextDocument::textAt(int pos, int length) const
|
QString TextDocument::textAt(int pos, int length) const
|
||||||
|
|||||||
@@ -605,6 +605,7 @@ public:
|
|||||||
void paintRightMarginLine(const PaintEventData &data, QPainter &painter) const;
|
void paintRightMarginLine(const PaintEventData &data, QPainter &painter) const;
|
||||||
void paintBlockHighlight(const PaintEventData &data, QPainter &painter) const;
|
void paintBlockHighlight(const PaintEventData &data, QPainter &painter) const;
|
||||||
void paintSearchResultOverlay(const PaintEventData &data, QPainter &painter) const;
|
void paintSearchResultOverlay(const PaintEventData &data, QPainter &painter) const;
|
||||||
|
void paintSelectionOverlay(const PaintEventData &data, QPainter &painter) const;
|
||||||
void paintIfDefedOutBlocks(const PaintEventData &data, QPainter &painter) const;
|
void paintIfDefedOutBlocks(const PaintEventData &data, QPainter &painter) const;
|
||||||
void paintFindScope(const PaintEventData &data, QPainter &painter) const;
|
void paintFindScope(const PaintEventData &data, QPainter &painter) const;
|
||||||
void paintCurrentLineHighlight(const PaintEventData &data, QPainter &painter) const;
|
void paintCurrentLineHighlight(const PaintEventData &data, QPainter &painter) const;
|
||||||
@@ -690,6 +691,7 @@ public:
|
|||||||
int length;
|
int length;
|
||||||
};
|
};
|
||||||
void addSearchResultsToScrollBar(const QVector<SearchResult> &results);
|
void addSearchResultsToScrollBar(const QVector<SearchResult> &results);
|
||||||
|
void addSelectionHighlightToScrollBar(const QVector<SearchResult> &selections);
|
||||||
void adjustScrollBarRanges();
|
void adjustScrollBarRanges();
|
||||||
|
|
||||||
void setFindScope(const MultiTextCursor &scope);
|
void setFindScope(const MultiTextCursor &scope);
|
||||||
@@ -766,6 +768,7 @@ public:
|
|||||||
TextEditorOverlay *m_overlay = nullptr;
|
TextEditorOverlay *m_overlay = nullptr;
|
||||||
SnippetOverlay *m_snippetOverlay = nullptr;
|
SnippetOverlay *m_snippetOverlay = nullptr;
|
||||||
TextEditorOverlay *m_searchResultOverlay = nullptr;
|
TextEditorOverlay *m_searchResultOverlay = nullptr;
|
||||||
|
TextEditorOverlay *m_selectionHighlightOverlay = nullptr;
|
||||||
bool snippetCheckCursor(const QTextCursor &cursor);
|
bool snippetCheckCursor(const QTextCursor &cursor);
|
||||||
void snippetTabOrBacktab(bool forward);
|
void snippetTabOrBacktab(bool forward);
|
||||||
|
|
||||||
@@ -811,6 +814,7 @@ public:
|
|||||||
QString m_findText;
|
QString m_findText;
|
||||||
FindFlags m_findFlags;
|
FindFlags m_findFlags;
|
||||||
void highlightSearchResults(const QTextBlock &block, const PaintEventData &data) const;
|
void highlightSearchResults(const QTextBlock &block, const PaintEventData &data) const;
|
||||||
|
void highlightSelection(const QTextBlock &block) const;
|
||||||
QTimer m_delayedUpdateTimer;
|
QTimer m_delayedUpdateTimer;
|
||||||
|
|
||||||
void setExtraSelections(Utils::Id kind, const QList<QTextEdit::ExtraSelection> &selections);
|
void setExtraSelections(Utils::Id kind, const QList<QTextEdit::ExtraSelection> &selections);
|
||||||
@@ -871,7 +875,9 @@ public:
|
|||||||
CommentDefinition m_commentDefinition;
|
CommentDefinition m_commentDefinition;
|
||||||
|
|
||||||
QFuture<SearchResultItems> m_searchFuture;
|
QFuture<SearchResultItems> m_searchFuture;
|
||||||
|
QFuture<SearchResultItems> m_selectionHighlightFuture;
|
||||||
QVector<SearchResult> m_searchResults;
|
QVector<SearchResult> m_searchResults;
|
||||||
|
QVector<SearchResult> m_selectionResults;
|
||||||
QTimer m_scrollBarUpdateTimer;
|
QTimer m_scrollBarUpdateTimer;
|
||||||
HighlightScrollBarController *m_highlightScrollBarController = nullptr;
|
HighlightScrollBarController *m_highlightScrollBarController = nullptr;
|
||||||
bool m_scrollBarUpdateScheduled = false;
|
bool m_scrollBarUpdateScheduled = false;
|
||||||
@@ -995,6 +1001,7 @@ TextEditorWidgetPrivate::TextEditorWidgetPrivate(TextEditorWidget *parent)
|
|||||||
, m_overlay(new TextEditorOverlay(q))
|
, m_overlay(new TextEditorOverlay(q))
|
||||||
, m_snippetOverlay(new SnippetOverlay(q))
|
, m_snippetOverlay(new SnippetOverlay(q))
|
||||||
, m_searchResultOverlay(new TextEditorOverlay(q))
|
, m_searchResultOverlay(new TextEditorOverlay(q))
|
||||||
|
, m_selectionHighlightOverlay(new TextEditorOverlay(q))
|
||||||
, m_refactorOverlay(new RefactorOverlay(q))
|
, m_refactorOverlay(new RefactorOverlay(q))
|
||||||
, m_marksVisible(false)
|
, m_marksVisible(false)
|
||||||
, m_codeFoldingVisible(false)
|
, m_codeFoldingVisible(false)
|
||||||
@@ -1010,6 +1017,7 @@ TextEditorWidgetPrivate::TextEditorWidgetPrivate(TextEditorWidget *parent)
|
|||||||
, m_clipboardAssistProvider(new ClipboardAssistProvider)
|
, m_clipboardAssistProvider(new ClipboardAssistProvider)
|
||||||
, m_autoCompleter(new AutoCompleter)
|
, m_autoCompleter(new AutoCompleter)
|
||||||
{
|
{
|
||||||
|
m_selectionHighlightOverlay->show();
|
||||||
auto aggregate = new Aggregation::Aggregate;
|
auto aggregate = new Aggregation::Aggregate;
|
||||||
m_find = new TextEditorWidgetFind(q);
|
m_find = new TextEditorWidgetFind(q);
|
||||||
connect(m_find, &BaseTextFind::highlightAllRequested,
|
connect(m_find, &BaseTextFind::highlightAllRequested,
|
||||||
@@ -1139,6 +1147,8 @@ TextEditorWidgetPrivate::~TextEditorWidgetPrivate()
|
|||||||
delete m_highlightScrollBarController;
|
delete m_highlightScrollBarController;
|
||||||
if (m_searchFuture.isRunning())
|
if (m_searchFuture.isRunning())
|
||||||
m_searchFuture.cancel();
|
m_searchFuture.cancel();
|
||||||
|
if (m_selectionHighlightFuture.isRunning())
|
||||||
|
m_selectionHighlightFuture.cancel();
|
||||||
}
|
}
|
||||||
|
|
||||||
static QFrame *createSeparator(const QString &styleSheet)
|
static QFrame *createSeparator(const QString &styleSheet)
|
||||||
@@ -3346,10 +3356,12 @@ void TextEditorWidgetPrivate::documentAboutToBeReloaded()
|
|||||||
m_overlay->clear();
|
m_overlay->clear();
|
||||||
m_snippetOverlay->clear();
|
m_snippetOverlay->clear();
|
||||||
m_searchResultOverlay->clear();
|
m_searchResultOverlay->clear();
|
||||||
|
m_selectionHighlightOverlay->clear();
|
||||||
m_refactorOverlay->clear();
|
m_refactorOverlay->clear();
|
||||||
|
|
||||||
// clear search results
|
// clear search results
|
||||||
m_searchResults.clear();
|
m_searchResults.clear();
|
||||||
|
m_selectionResults.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void TextEditorWidgetPrivate::documentReloadFinished(bool success)
|
void TextEditorWidgetPrivate::documentReloadFinished(bool success)
|
||||||
@@ -4070,6 +4082,35 @@ void TextEditorWidgetPrivate::highlightSearchResults(const QTextBlock &block, co
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TextEditorWidgetPrivate::highlightSelection(const QTextBlock &block) const
|
||||||
|
{
|
||||||
|
if (!m_displaySettings.m_highlightSelection || m_cursors.hasMultipleCursors())
|
||||||
|
return;
|
||||||
|
const QString selection = m_cursors.selectedText();
|
||||||
|
if (selection.trimmed().isEmpty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
const int blockPosition = block.position();
|
||||||
|
|
||||||
|
QString text = block.text();
|
||||||
|
text.replace(QChar::Nbsp, QLatin1Char(' '));
|
||||||
|
const int l = selection.length();
|
||||||
|
|
||||||
|
for (int idx = text.indexOf(selection, 0, Qt::CaseInsensitive);
|
||||||
|
idx >= 0;
|
||||||
|
idx = text.indexOf(selection, idx + 1, Qt::CaseInsensitive)) {
|
||||||
|
const int start = blockPosition + idx;
|
||||||
|
const int end = start + l;
|
||||||
|
if (!Utils::contains(m_selectionHighlightOverlay->selections(),
|
||||||
|
[&](const OverlaySelection &selection) {
|
||||||
|
return selection.m_cursor_begin.position() == start
|
||||||
|
&& selection.m_cursor_end.position() == end;
|
||||||
|
})) {
|
||||||
|
m_selectionHighlightOverlay->addOverlaySelection(start, end, {}, {});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void TextEditorWidgetPrivate::startCursorFlashTimer()
|
void TextEditorWidgetPrivate::startCursorFlashTimer()
|
||||||
{
|
{
|
||||||
const int flashTime = QApplication::cursorFlashTime();
|
const int flashTime = QApplication::cursorFlashTime();
|
||||||
@@ -4108,6 +4149,44 @@ void TextEditorWidgetPrivate::updateCursorSelections()
|
|||||||
selections << QTextEdit::ExtraSelection{cursor, selectionFormat};
|
selections << QTextEdit::ExtraSelection{cursor, selectionFormat};
|
||||||
}
|
}
|
||||||
q->setExtraSelections(TextEditorWidget::CursorSelection, selections);
|
q->setExtraSelections(TextEditorWidget::CursorSelection, selections);
|
||||||
|
|
||||||
|
m_selectionHighlightOverlay->clear();
|
||||||
|
|
||||||
|
if (m_selectionHighlightFuture.isRunning())
|
||||||
|
m_selectionHighlightFuture.cancel();
|
||||||
|
|
||||||
|
m_selectionResults.clear();
|
||||||
|
if (!m_highlightScrollBarController)
|
||||||
|
return;
|
||||||
|
m_highlightScrollBarController->removeHighlights(Constants::SCROLL_BAR_SELECTION);
|
||||||
|
|
||||||
|
if (!m_displaySettings.m_highlightSelection || m_cursors.hasMultipleCursors())
|
||||||
|
return;
|
||||||
|
|
||||||
|
const QString txt = m_cursors.selectedText();
|
||||||
|
if (txt.trimmed().isEmpty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_selectionHighlightFuture = Utils::asyncRun(Utils::searchInContents,
|
||||||
|
txt,
|
||||||
|
FindFlags{},
|
||||||
|
m_document->filePath(),
|
||||||
|
m_document->plainText());
|
||||||
|
|
||||||
|
Utils::onResultReady(m_selectionHighlightFuture,
|
||||||
|
this,
|
||||||
|
[this](const SearchResultItems &resultList) {
|
||||||
|
QList<SearchResult> results;
|
||||||
|
for (const SearchResultItem &item : resultList) {
|
||||||
|
int start = item.mainRange().begin.positionInDocument(
|
||||||
|
m_document->document());
|
||||||
|
int end = item.mainRange().end.positionInDocument(
|
||||||
|
m_document->document());
|
||||||
|
results << SearchResult{start, end - start};
|
||||||
|
}
|
||||||
|
m_selectionResults = results;
|
||||||
|
addSelectionHighlightToScrollBar(results);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void TextEditorWidgetPrivate::moveCursor(QTextCursor::MoveOperation operation,
|
void TextEditorWidgetPrivate::moveCursor(QTextCursor::MoveOperation operation,
|
||||||
@@ -4489,6 +4568,40 @@ void TextEditorWidgetPrivate::paintSearchResultOverlay(const PaintEventData &dat
|
|||||||
data.eventRect);
|
data.eventRect);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TextEditorWidgetPrivate::paintSelectionOverlay(const PaintEventData &data,
|
||||||
|
QPainter &painter) const
|
||||||
|
{
|
||||||
|
if (m_cursors.hasMultipleCursors())
|
||||||
|
return;
|
||||||
|
const QString expr = m_cursors.selectedText();
|
||||||
|
if (expr.isEmpty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
const int margin = 5;
|
||||||
|
QTextBlock block = data.block;
|
||||||
|
QPointF offset = data.offset;
|
||||||
|
while (block.isValid()) {
|
||||||
|
QRectF blockBoundingRect = q->blockBoundingRect(block).translated(offset);
|
||||||
|
|
||||||
|
if (blockBoundingRect.bottom() >= data.eventRect.top() - margin
|
||||||
|
&& blockBoundingRect.top() <= data.eventRect.bottom() + margin) {
|
||||||
|
highlightSelection(block);
|
||||||
|
}
|
||||||
|
offset.ry() += blockBoundingRect.height();
|
||||||
|
|
||||||
|
if (offset.y() > data.viewportRect.height() + margin)
|
||||||
|
break;
|
||||||
|
|
||||||
|
block = TextEditor::nextVisibleBlock(block, data.doc);
|
||||||
|
}
|
||||||
|
|
||||||
|
QColor selection = m_document->fontSettings().toTextCharFormat(C_SELECTION).background().color();
|
||||||
|
const QColor text = m_document->fontSettings().toTextCharFormat(C_TEXT).background().color();
|
||||||
|
selection.setAlphaF(StyleHelper::luminance(text) > 0.5 ? 0.25 : 0.5);
|
||||||
|
|
||||||
|
m_selectionHighlightOverlay->fill(&painter, selection, data.eventRect);
|
||||||
|
}
|
||||||
|
|
||||||
void TextEditorWidgetPrivate::paintIfDefedOutBlocks(const PaintEventData &data,
|
void TextEditorWidgetPrivate::paintIfDefedOutBlocks(const PaintEventData &data,
|
||||||
QPainter &painter) const
|
QPainter &painter) const
|
||||||
{
|
{
|
||||||
@@ -5076,6 +5189,8 @@ void TextEditorWidget::paintEvent(QPaintEvent *e)
|
|||||||
d->paintFindScope(data, painter);
|
d->paintFindScope(data, painter);
|
||||||
// paint search results on top of the find scope
|
// paint search results on top of the find scope
|
||||||
d->paintSearchResultOverlay(data, painter);
|
d->paintSearchResultOverlay(data, painter);
|
||||||
|
// paint selection highlights
|
||||||
|
d->paintSelectionOverlay(data, painter);
|
||||||
}
|
}
|
||||||
|
|
||||||
while (data.block.isValid()) {
|
while (data.block.isValid()) {
|
||||||
@@ -6947,6 +7062,33 @@ void TextEditorWidgetPrivate::addSearchResultsToScrollBar(const QVector<SearchRe
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TextEditorWidgetPrivate::addSelectionHighlightToScrollBar(
|
||||||
|
const QVector<SearchResult> &selections)
|
||||||
|
{
|
||||||
|
if (!m_highlightScrollBarController)
|
||||||
|
return;
|
||||||
|
for (const SearchResult &result : selections) {
|
||||||
|
const QTextBlock &block = q->document()->findBlock(result.start);
|
||||||
|
if (block.isValid() && block.isVisible()) {
|
||||||
|
if (q->lineWrapMode() == QPlainTextEdit::WidgetWidth) {
|
||||||
|
const int firstLine = block.layout()->lineForTextPosition(result.start - block.position()).lineNumber();
|
||||||
|
const int lastLine = block.layout()->lineForTextPosition(result.start - block.position() + result.length).lineNumber();
|
||||||
|
for (int line = firstLine; line <= lastLine; ++line) {
|
||||||
|
m_highlightScrollBarController->addHighlight(
|
||||||
|
{Constants::SCROLL_BAR_SELECTION, block.firstLineNumber() + line,
|
||||||
|
Theme::TextEditor_Selection_ScrollBarColor, Highlight::NormalPriority});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
m_highlightScrollBarController->addHighlight(
|
||||||
|
{Constants::SCROLL_BAR_SELECTION,
|
||||||
|
block.blockNumber(),
|
||||||
|
Theme::TextEditor_Selection_ScrollBarColor,
|
||||||
|
Highlight::NormalPriority});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Highlight markToHighlight(TextMark *mark, int lineNumber)
|
Highlight markToHighlight(TextMark *mark, int lineNumber)
|
||||||
{
|
{
|
||||||
return Highlight(mark->category().id,
|
return Highlight(mark->category().id,
|
||||||
@@ -6968,6 +7110,9 @@ void TextEditorWidgetPrivate::updateHighlightScrollBarNow()
|
|||||||
// update search results
|
// update search results
|
||||||
addSearchResultsToScrollBar(m_searchResults);
|
addSearchResultsToScrollBar(m_searchResults);
|
||||||
|
|
||||||
|
// update search selection
|
||||||
|
addSelectionHighlightToScrollBar(m_selectionResults);
|
||||||
|
|
||||||
// update text marks
|
// update text marks
|
||||||
const TextMarks marks = m_document->marks();
|
const TextMarks marks = m_document->marks();
|
||||||
for (TextMark *mark : marks) {
|
for (TextMark *mark : marks) {
|
||||||
@@ -7900,6 +8045,7 @@ void TextEditorWidget::setDisplaySettings(const DisplaySettings &ds)
|
|||||||
d->updateFileLineEndingVisible();
|
d->updateFileLineEndingVisible();
|
||||||
d->updateHighlights();
|
d->updateHighlights();
|
||||||
d->setupScrollBar();
|
d->setupScrollBar();
|
||||||
|
d->updateCursorSelections();
|
||||||
viewport()->update();
|
viewport()->update();
|
||||||
extraArea()->update();
|
extraArea()->update();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -216,6 +216,7 @@ const char JUMP_TO_FILE_UNDER_CURSOR[] = "TextEditor.JumpToFileUnderCursor";
|
|||||||
const char JUMP_TO_FILE_UNDER_CURSOR_IN_NEXT_SPLIT[] = "TextEditor.JumpToFileUnderCursorInNextSplit";
|
const char JUMP_TO_FILE_UNDER_CURSOR_IN_NEXT_SPLIT[] = "TextEditor.JumpToFileUnderCursorInNextSplit";
|
||||||
|
|
||||||
const char SCROLL_BAR_SEARCH_RESULT[] = "TextEditor.ScrollBarSearchResult";
|
const char SCROLL_BAR_SEARCH_RESULT[] = "TextEditor.ScrollBarSearchResult";
|
||||||
|
const char SCROLL_BAR_SELECTION[] = "TextEditor.ScrollBarSelection";
|
||||||
const char SCROLL_BAR_CURRENT_LINE[] = "TextEditor.ScrollBarCurrentLine";
|
const char SCROLL_BAR_CURRENT_LINE[] = "TextEditor.ScrollBarCurrentLine";
|
||||||
|
|
||||||
const TEXTEDITOR_EXPORT char *nameForStyle(TextStyle style);
|
const TEXTEDITOR_EXPORT char *nameForStyle(TextStyle style);
|
||||||
|
|||||||
@@ -82,10 +82,13 @@ void TextEditorOverlay::addOverlaySelection(int begin, int end,
|
|||||||
|
|
||||||
if (m_selections.isEmpty())
|
if (m_selections.isEmpty())
|
||||||
m_firstSelectionOriginalBegin = begin;
|
m_firstSelectionOriginalBegin = begin;
|
||||||
else if (begin < m_firstSelectionOriginalBegin)
|
|
||||||
qWarning() << "overlay selections not in order";
|
|
||||||
|
|
||||||
m_selections.append(selection);
|
const auto it = std::find_if(m_selections.cbegin(),
|
||||||
|
m_selections.cend(),
|
||||||
|
[&](const OverlaySelection &selection) {
|
||||||
|
return begin > selection.m_cursor_begin.position();
|
||||||
|
});
|
||||||
|
m_selections.insert(it, selection);
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user