forked from qt-creator/qt-creator
TextEditor: speed up searching in huge documents
Avoid creating QTextCursors for checking whether a search result is inside the find scope. QTextCursor::setPosition seems to layout the block the cursor is positioned at, which is not for free and not needed to verify whether a search result is inside the find scope. Change-Id: Ia1658fbbaa89a61f862e0b97eaa5b059972e2311 Reviewed-by: Christian Stenger <christian.stenger@qt.io>
This commit is contained in:
@@ -64,6 +64,16 @@ Position Position::fromCursor(const QTextCursor &c)
|
||||
return c.isNull() ? Position{} : Position{c.blockNumber() + 1, c.positionInBlock()};
|
||||
}
|
||||
|
||||
int Position::toPositionInDocument(const QTextDocument *document) const
|
||||
{
|
||||
QTC_ASSERT(document, return -1);
|
||||
const QTextBlock block = document->findBlockByNumber(line - 1);
|
||||
if (block.isValid())
|
||||
return block.position() + qMin(column, block.length() - 1);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int Range::length(const QString &text) const
|
||||
{
|
||||
if (end.line < begin.line)
|
||||
|
@@ -33,6 +33,8 @@ public:
|
||||
static Position fromFileName(QStringView fileName, int &postfixPos);
|
||||
static Position fromPositionInDocument(const QTextDocument *document, int pos);
|
||||
static Position fromCursor(const QTextCursor &cursor);
|
||||
|
||||
int toPositionInDocument(const QTextDocument *document) const;
|
||||
};
|
||||
|
||||
class QTCREATOR_UTILS_EXPORT Range
|
||||
|
@@ -425,9 +425,17 @@ bool BaseTextFind::inScope(const QTextCursor &candidate) const
|
||||
return false;
|
||||
if (d->m_scope.isNull())
|
||||
return true;
|
||||
return Utils::anyOf(d->m_scope, [candidate](const QTextCursor &scope){
|
||||
return candidate.selectionStart() >= scope.selectionStart()
|
||||
&& candidate.selectionEnd() <= scope.selectionEnd();
|
||||
return inScope(candidate.selectionStart(), candidate.selectionEnd());
|
||||
}
|
||||
|
||||
bool BaseTextFind::inScope(int candidateStart, int candidateEnd) const
|
||||
{
|
||||
if (d->m_scope.isNull())
|
||||
return true;
|
||||
if (candidateStart > candidateEnd)
|
||||
std::swap(candidateStart, candidateEnd);
|
||||
return Utils::anyOf(d->m_scope, [&](const QTextCursor &scope) {
|
||||
return candidateStart >= scope.selectionStart() && candidateEnd <= scope.selectionEnd();
|
||||
});
|
||||
}
|
||||
|
||||
|
@@ -50,6 +50,7 @@ public:
|
||||
using CursorProvider = std::function<Utils::MultiTextCursor ()>;
|
||||
void setMultiTextCursorProvider(const CursorProvider &provider);
|
||||
bool inScope(const QTextCursor &candidate) const;
|
||||
bool inScope(int candidateStart, int candidateEnd) const;
|
||||
|
||||
static QRegularExpression regularExpression(const QString &txt, Utils::FindFlags flags);
|
||||
|
||||
|
@@ -4031,10 +4031,7 @@ void TextEditorWidgetPrivate::highlightSearchResults(const QTextBlock &block, co
|
||||
|
||||
const int start = blockPosition + idx;
|
||||
const int end = start + l;
|
||||
QTextCursor result = cursor;
|
||||
result.setPosition(start);
|
||||
result.setPosition(end, QTextCursor::KeepAnchor);
|
||||
if (!q->inFindScope(result))
|
||||
if (!m_find->inScope(start, end))
|
||||
continue;
|
||||
|
||||
// check if the result is inside the visibale area for long blocks
|
||||
@@ -6884,9 +6881,16 @@ void TextEditorWidgetPrivate::highlightSearchResultsInScrollBar()
|
||||
Utils::onResultReady(m_searchFuture, this, [this](const SearchResultItems &resultList) {
|
||||
QList<SearchResult> results;
|
||||
for (const SearchResultItem &result : resultList) {
|
||||
SearchResult searchResult;
|
||||
if (q->inFindScope(selectRange(q->document(), result.mainRange(), &searchResult)))
|
||||
results << searchResult;
|
||||
int start = result.mainRange().begin.toPositionInDocument(m_document->document());
|
||||
if (start < 0)
|
||||
continue;
|
||||
int end = result.mainRange().end.toPositionInDocument(m_document->document());
|
||||
if (end < 0)
|
||||
continue;
|
||||
if (start > end)
|
||||
std::swap(start, end);
|
||||
if (m_find->inScope(start, end))
|
||||
results << SearchResult{start, start - end};
|
||||
}
|
||||
m_searchResults << results;
|
||||
addSearchResultsToScrollBar(results);
|
||||
@@ -6924,12 +6928,20 @@ void TextEditorWidgetPrivate::addSearchResultsToScrollBar(const QVector<SearchRe
|
||||
for (const SearchResult &result : results) {
|
||||
const QTextBlock &block = q->document()->findBlock(result.start);
|
||||
if (block.isValid() && block.isVisible()) {
|
||||
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) {
|
||||
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_SEARCH_RESULT, block.firstLineNumber() + line,
|
||||
Theme::TextEditor_SearchResult_ScrollBarColor, Highlight::HighPriority});
|
||||
}
|
||||
} else {
|
||||
m_highlightScrollBarController->addHighlight(
|
||||
{Constants::SCROLL_BAR_SEARCH_RESULT, block.firstLineNumber() + line,
|
||||
Theme::TextEditor_SearchResult_ScrollBarColor, Highlight::HighPriority});
|
||||
{Constants::SCROLL_BAR_SEARCH_RESULT,
|
||||
block.blockNumber(),
|
||||
Theme::TextEditor_SearchResult_ScrollBarColor,
|
||||
Highlight::HighPriority});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user