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()};
|
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
|
int Range::length(const QString &text) const
|
||||||
{
|
{
|
||||||
if (end.line < begin.line)
|
if (end.line < begin.line)
|
||||||
|
@@ -33,6 +33,8 @@ public:
|
|||||||
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);
|
||||||
|
|
||||||
|
int toPositionInDocument(const QTextDocument *document) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
class QTCREATOR_UTILS_EXPORT Range
|
class QTCREATOR_UTILS_EXPORT Range
|
||||||
|
@@ -425,9 +425,17 @@ bool BaseTextFind::inScope(const QTextCursor &candidate) const
|
|||||||
return false;
|
return false;
|
||||||
if (d->m_scope.isNull())
|
if (d->m_scope.isNull())
|
||||||
return true;
|
return true;
|
||||||
return Utils::anyOf(d->m_scope, [candidate](const QTextCursor &scope){
|
return inScope(candidate.selectionStart(), candidate.selectionEnd());
|
||||||
return candidate.selectionStart() >= scope.selectionStart()
|
}
|
||||||
&& candidate.selectionEnd() <= scope.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 ()>;
|
using CursorProvider = std::function<Utils::MultiTextCursor ()>;
|
||||||
void setMultiTextCursorProvider(const CursorProvider &provider);
|
void setMultiTextCursorProvider(const CursorProvider &provider);
|
||||||
bool inScope(const QTextCursor &candidate) const;
|
bool inScope(const QTextCursor &candidate) const;
|
||||||
|
bool inScope(int candidateStart, int candidateEnd) const;
|
||||||
|
|
||||||
static QRegularExpression regularExpression(const QString &txt, Utils::FindFlags flags);
|
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 start = blockPosition + idx;
|
||||||
const int end = start + l;
|
const int end = start + l;
|
||||||
QTextCursor result = cursor;
|
if (!m_find->inScope(start, end))
|
||||||
result.setPosition(start);
|
|
||||||
result.setPosition(end, QTextCursor::KeepAnchor);
|
|
||||||
if (!q->inFindScope(result))
|
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// check if the result is inside the visibale area for long blocks
|
// 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) {
|
Utils::onResultReady(m_searchFuture, this, [this](const SearchResultItems &resultList) {
|
||||||
QList<SearchResult> results;
|
QList<SearchResult> results;
|
||||||
for (const SearchResultItem &result : resultList) {
|
for (const SearchResultItem &result : resultList) {
|
||||||
SearchResult searchResult;
|
int start = result.mainRange().begin.toPositionInDocument(m_document->document());
|
||||||
if (q->inFindScope(selectRange(q->document(), result.mainRange(), &searchResult)))
|
if (start < 0)
|
||||||
results << searchResult;
|
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;
|
m_searchResults << results;
|
||||||
addSearchResultsToScrollBar(results);
|
addSearchResultsToScrollBar(results);
|
||||||
@@ -6924,12 +6928,20 @@ void TextEditorWidgetPrivate::addSearchResultsToScrollBar(const QVector<SearchRe
|
|||||||
for (const SearchResult &result : results) {
|
for (const SearchResult &result : results) {
|
||||||
const QTextBlock &block = q->document()->findBlock(result.start);
|
const QTextBlock &block = q->document()->findBlock(result.start);
|
||||||
if (block.isValid() && block.isVisible()) {
|
if (block.isValid() && block.isVisible()) {
|
||||||
const int firstLine = block.layout()->lineForTextPosition(result.start - block.position()).lineNumber();
|
if (q->lineWrapMode() == QPlainTextEdit::WidgetWidth) {
|
||||||
const int lastLine = block.layout()->lineForTextPosition(result.start - block.position() + result.length).lineNumber();
|
const int firstLine = block.layout()->lineForTextPosition(result.start - block.position()).lineNumber();
|
||||||
for (int line = firstLine; line <= lastLine; ++line) {
|
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(
|
m_highlightScrollBarController->addHighlight(
|
||||||
{Constants::SCROLL_BAR_SEARCH_RESULT, block.firstLineNumber() + line,
|
{Constants::SCROLL_BAR_SEARCH_RESULT,
|
||||||
Theme::TextEditor_SearchResult_ScrollBarColor, Highlight::HighPriority});
|
block.blockNumber(),
|
||||||
|
Theme::TextEditor_SearchResult_ScrollBarColor,
|
||||||
|
Highlight::HighPriority});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user