Solve a bad performance problem in text processing that leads to hangs of the UI. (#2487)

Signed-off-by: Adam Treat <treat.adam@gmail.com>
This commit is contained in:
AT 2024-06-29 17:59:45 -04:00 committed by GitHub
parent 720ea5a147
commit 55858f93b0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -830,29 +830,40 @@ void SyntaxHighlighter::highlightBlock(const QString &text)
{ {
QTextBlock block = this->currentBlock(); QTextBlock block = this->currentBlock();
// Search the first block of the frame we're in for the code to use for highlighting
int userState = block.userState();
if (QTextFrame *frame = block.document()->frameAt(block.position())) {
QTextBlock firstBlock = frame->begin().currentBlock();
if (firstBlock.isValid())
userState = firstBlock.userState();
}
QVector<HighlightingRule> rules; QVector<HighlightingRule> rules;
if (block.userState() == Python) switch (userState) {
rules = pythonHighlightingRules(); case Python:
else if (block.userState() == Cpp) rules = pythonHighlightingRules(); break;
rules = cppHighlightingRules(); case Cpp:
else if (block.userState() == Csharp) rules = cppHighlightingRules(); break;
rules = csharpHighlightingRules(); case Csharp:
else if (block.userState() == Bash) rules = csharpHighlightingRules(); break;
rules = bashHighlightingRules(); case Bash:
else if (block.userState() == TypeScript) rules = bashHighlightingRules(); break;
rules = typescriptHighlightingRules(); case TypeScript:
else if (block.userState() == Java) rules = typescriptHighlightingRules(); break;
rules = javaHighlightingRules(); case Java:
else if (block.userState() == Go) rules = javaHighlightingRules(); break;
rules = javaHighlightingRules(); case Go:
else if (block.userState() == Json) rules = javaHighlightingRules(); break;
rules = jsonHighlightingRules(); case Json:
else if (block.userState() == Latex) rules = jsonHighlightingRules(); break;
rules = latexHighlightingRules(); case Latex:
else if (block.userState() == Html) rules = latexHighlightingRules(); break;
rules = htmlHighlightingRules(); case Html:
else if (block.userState() == Php) rules = htmlHighlightingRules(); break;
rules = phpHighlightingRules(); case Php:
rules = phpHighlightingRules(); break;
default: break;
}
for (const HighlightingRule &rule : std::as_const(rules)) { for (const HighlightingRule &rule : std::as_const(rules)) {
QRegularExpressionMatchIterator matchIterator = rule.pattern.globalMatch(text); QRegularExpressionMatchIterator matchIterator = rule.pattern.globalMatch(text);
@ -922,38 +933,24 @@ void ChatViewTextProcessor::setShouldProcessText(bool b)
handleTextChanged(); handleTextChanged();
} }
void traverseDocument(QTextDocument *doc) void traverseDocument(QTextDocument *doc, QTextFrame *frame)
{ {
QTextFrame *rootFrame = doc->rootFrame(); QTextFrame *rootFrame = frame ? frame : doc->rootFrame();
QTextFrame::iterator rootIt; QTextFrame::iterator rootIt;
if (!frame)
qDebug() << "Begin traverse";
for (rootIt = rootFrame->begin(); !rootIt.atEnd(); ++rootIt) { for (rootIt = rootFrame->begin(); !rootIt.atEnd(); ++rootIt) {
QTextFrame *childFrame = rootIt.currentFrame(); QTextFrame *childFrame = rootIt.currentFrame();
QTextBlock childBlock = rootIt.currentBlock(); QTextBlock childBlock = rootIt.currentBlock();
if (childFrame) { if (childFrame) {
qDebug() << "Frame from" << childFrame->firstPosition() << "to" << childFrame->lastPosition(); qDebug() << "Frame from" << childFrame->firstPosition() << "to" << childFrame->lastPosition();
traverseDocument(doc, childFrame);
// Iterate over blocks within the frame
QTextFrame::iterator frameIt;
for (frameIt = childFrame->begin(); !frameIt.atEnd(); ++frameIt) {
QTextBlock block = frameIt.currentBlock();
if (block.isValid()) {
qDebug() << " Block position:" << block.position();
qDebug() << " Block text:" << block.text();
// Iterate over lines within the block
for (QTextBlock::iterator blockIt = block.begin(); !(blockIt.atEnd()); ++blockIt) {
QTextFragment fragment = blockIt.fragment();
if (fragment.isValid()) {
qDebug() << " Fragment text:" << fragment.text();
}
}
}
}
} else if (childBlock.isValid()) { } else if (childBlock.isValid()) {
qDebug() << "Block position:" << childBlock.position(); qDebug() << QString(" Block %1 position:").arg(childBlock.userState()) << childBlock.position();
qDebug() << "Block text:" << childBlock.text(); qDebug() << QString(" Block %1 text:").arg(childBlock.userState()) << childBlock.text();
// Iterate over lines within the block // Iterate over lines within the block
for (QTextBlock::iterator blockIt = childBlock.begin(); !(blockIt.atEnd()); ++blockIt) { for (QTextBlock::iterator blockIt = childBlock.begin(); !(blockIt.atEnd()); ++blockIt) {
@ -964,6 +961,9 @@ void traverseDocument(QTextDocument *doc)
} }
} }
} }
if (!frame)
qDebug() << "End traverse";
} }
void ChatViewTextProcessor::handleTextChanged() void ChatViewTextProcessor::handleTextChanged()
@ -1136,13 +1136,7 @@ void ChatViewTextProcessor::handleCodeBlocks()
codeCursor.setCharFormat(codeBlockCharFormat); codeCursor.setCharFormat(codeBlockCharFormat);
codeCursor.block().setUserState(stringToLanguage(codeLanguage)); codeCursor.block().setUserState(stringToLanguage(codeLanguage));
for (int i = 0; i < lines.size(); ++i) { codeCursor.insertText(lines.join('\n'));
codeCursor.insertText(lines[i]);
if (i < lines.size() - 1) {
codeCursor.insertBlock();
codeCursor.block().setUserState(stringToLanguage(codeLanguage));
}
}
cursor = mainFrame->lastCursorPosition(); cursor = mainFrame->lastCursorPosition();
cursor.setCharFormat(QTextCharFormat()); cursor.setCharFormat(QTextCharFormat());