SyntaxHighlighter: Add rerun if highlighting was interrupted

Added mechanism of highlighting restart when the previous
highlighting was interrupted.

Change-Id: Ic44c06442fd9f0002fed760472d5d39903e7ef50
Reviewed-by: <github-actions-qt-creator@cristianadam.eu>
Reviewed-by: David Schulz <david.schulz@qt.io>
This commit is contained in:
Artem Sokolovskii
2024-02-12 11:10:04 +01:00
parent e31a06a0f4
commit bb87db09e2
4 changed files with 136 additions and 29 deletions

View File

@@ -206,8 +206,11 @@ void SyntaxHighlighterPrivate::reformatBlocks(int from, int charsRemoved, int ch
vecRes << resStart; vecRes << resStart;
while (block.isValid() && (block.position() < endPosition || forceHighlightOfNextBlock)) { while (block.isValid() && (block.position() < endPosition || forceHighlightOfNextBlock)) {
if (QThread::currentThread()->isInterruptionRequested()) if (QThread::currentThread()->isInterruptionRequested() || q->isInterrupted()) {
break; inReformatBlocks = false;
emit q->resultsReady({});
return;
}
const int stateBeforeHighlight = block.userState(); const int stateBeforeHighlight = block.userState();
@@ -767,9 +770,7 @@ void SyntaxHighlighter::setExtraFormats(const QTextBlock &block,
res.m_formatRanges = block.layout()->formats(); res.m_formatRanges = block.layout()->formats();
res.fillByBlock(block); res.fillByBlock(block);
res.m_state = SyntaxHighlighter::State::Extras; res.m_state = SyntaxHighlighter::State::Extras;
SyntaxHighlighter::Result resDone; emit resultsReady({std::move(res)});
resDone.m_state = SyntaxHighlighter::State::Done;
emit resultsReady({res, resDone});
document()->markContentsDirty(block.position(), blockLength - 1); document()->markContentsDirty(block.position(), blockLength - 1);
d->inReformatBlocks = wasInReformatBlocks; d->inReformatBlocks = wasInReformatBlocks;
@@ -796,9 +797,7 @@ void SyntaxHighlighter::clearExtraFormats(const QTextBlock &block)
res.m_formatRanges = block.layout()->formats(); res.m_formatRanges = block.layout()->formats();
res.fillByBlock(block); res.fillByBlock(block);
res.m_state = SyntaxHighlighter::State::Extras; res.m_state = SyntaxHighlighter::State::Extras;
SyntaxHighlighter::Result resDone; emit resultsReady({std::move(res)});
resDone.m_state = SyntaxHighlighter::State::Done;
emit resultsReady({res, resDone});
document()->markContentsDirty(block.position(), blockLength - 1); document()->markContentsDirty(block.position(), blockLength - 1);
d->inReformatBlocks = wasInReformatBlocks; d->inReformatBlocks = wasInReformatBlocks;

View File

@@ -56,15 +56,15 @@ public:
enum State { enum State {
Start, Start,
InProgress, InProgress,
Extras, Done,
Done Extras
}; };
struct Result struct Result
{ {
void fillByBlock(const QTextBlock &block) void fillByBlock(const QTextBlock &block)
{ {
m_blockNumber = block.position(); m_blockNumber = block.blockNumber();
m_userState = block.userState(); m_userState = block.userState();
TextBlockUserData *userDate = TextDocumentLayout::textUserData(block); TextBlockUserData *userDate = TextDocumentLayout::textUserData(block);
@@ -117,6 +117,8 @@ public:
State m_state = InProgress; State m_state = InProgress;
}; };
void setInterrupted(bool interrupted) { m_interrupted = interrupted; }
bool isInterrupted() { return m_interrupted; }
void setExtraFormats(const QTextBlock &block, const QList<QTextLayout::FormatRange> &formats); void setExtraFormats(const QTextBlock &block, const QList<QTextLayout::FormatRange> &formats);
virtual void setLanguageFeaturesFlags(unsigned int /*flags*/) {}; // needed for CppHighlighting virtual void setLanguageFeaturesFlags(unsigned int /*flags*/) {}; // needed for CppHighlighting
virtual void setEnabled(bool /*enabled*/) {}; // needed for DiffAndLogHighlighter virtual void setEnabled(bool /*enabled*/) {}; // needed for DiffAndLogHighlighter
@@ -126,6 +128,7 @@ public slots:
virtual void rehighlight(); virtual void rehighlight();
void rehighlightBlock(const QTextBlock &block); void rehighlightBlock(const QTextBlock &block);
void clearExtraFormats(const QTextBlock &block); void clearExtraFormats(const QTextBlock &block);
void reformatBlocks(int from, int charsRemoved, int charsAdded);
void clearAllExtraFormats(); void clearAllExtraFormats();
protected: protected:
@@ -165,10 +168,10 @@ signals:
private: private:
void setTextFormatCategories(const QList<std::pair<int, TextStyle>> &categories); void setTextFormatCategories(const QList<std::pair<int, TextStyle>> &categories);
void reformatBlocks(int from, int charsRemoved, int charsAdded);
void delayedRehighlight(); void delayedRehighlight();
QScopedPointer<SyntaxHighlighterPrivate> d_ptr; QScopedPointer<SyntaxHighlighterPrivate> d_ptr;
std::atomic<bool> m_interrupted = false;
#ifdef WITH_TESTS #ifdef WITH_TESTS
friend class tst_highlighter; friend class tst_highlighter;

View File

@@ -81,7 +81,6 @@ public:
void setFontSettings(const TextEditor::FontSettings &fontSettings) void setFontSettings(const TextEditor::FontSettings &fontSettings)
{ {
m_highlighter->setFontSettings(fontSettings); m_highlighter->setFontSettings(fontSettings);
rehighlight();
} }
void setDefinitionName(const QString &name) void setDefinitionName(const QString &name)
@@ -98,13 +97,51 @@ public:
void rehighlight() { m_highlighter->rehighlight(); } void rehighlight() { m_highlighter->rehighlight(); }
void reformatBlocks(int from, int charsRemoved, int charsAdded)
{
m_highlighter->reformatBlocks(from, charsRemoved, charsAdded);
}
void setInterrupted(bool interrupted) { m_highlighter->setInterrupted(interrupted); }
SyntaxHighlighter *m_highlighter = nullptr; SyntaxHighlighter *m_highlighter = nullptr;
QTextDocument *m_document = nullptr; QTextDocument *m_document = nullptr;
signals: signals:
void resultsReady(const QList<SyntaxHighlighter::Result> &result); void resultsReady(const QList<SyntaxHighlighter::Result> &result);
}; };
void SyntaxHighlighterRunner::HighlightingStatus::notInterrupted(int from,
int charsRemoved,
int charsAdded)
{
m_from = from;
m_addedChars = charsAdded;
m_removedChars = charsRemoved;
m_current = from;
m_newFrom = from + m_addedChars;
m_interruptionRequested = false;
}
void SyntaxHighlighterRunner::HighlightingStatus::interrupted(int from,
int charsRemoved,
int charsAdded)
{
m_newFrom = std::min(m_newFrom, from);
m_newFrom = std::min(m_current, m_newFrom);
m_removedChars += charsRemoved;
m_addedChars += charsAdded;
m_interruptionRequested = true;
}
void SyntaxHighlighterRunner::HighlightingStatus::applyNewFrom()
{
m_from = m_newFrom;
m_current = m_newFrom;
m_interruptionRequested = false;
}
SyntaxHighlighterRunner::SyntaxHighlighterRunner(SyntaxHighlighter *highlighter, SyntaxHighlighterRunner::SyntaxHighlighterRunner(SyntaxHighlighter *highlighter,
QTextDocument *document, QTextDocument *document,
bool async) bool async)
@@ -124,8 +161,8 @@ SyntaxHighlighterRunner::SyntaxHighlighterRunner(SyntaxHighlighter *highlighter,
this, this,
&SyntaxHighlighterRunner::applyFormatRanges); &SyntaxHighlighterRunner::applyFormatRanges);
changeDocument(0, 0, document->characterCount()); changeDocument(0, 0, m_document->characterCount());
connect(document, connect(m_document,
&QTextDocument::contentsChange, &QTextDocument::contentsChange,
this, this,
&SyntaxHighlighterRunner::changeDocument); &SyntaxHighlighterRunner::changeDocument);
@@ -136,10 +173,15 @@ SyntaxHighlighterRunner::SyntaxHighlighterRunner(SyntaxHighlighter *highlighter,
&SyntaxHighlighterRunnerPrivate::resultsReady, &SyntaxHighlighterRunnerPrivate::resultsReady,
this, this,
[this](const QList<SyntaxHighlighter::Result> &result) { [this](const QList<SyntaxHighlighter::Result> &result) {
if (result.size() == 1
&& result.at(0).m_state == SyntaxHighlighter::State::Extras)
return;
auto done = std::find_if(result.cbegin(), auto done = std::find_if(result.cbegin(),
result.cend(), result.cend(),
[](const SyntaxHighlighter::Result &res) { [](const SyntaxHighlighter::Result &res) {
return res.m_state == SyntaxHighlighter::State::Done; return res.m_state
== SyntaxHighlighter::State::Done;
}); });
if (done != result.cend()) { if (done != result.cend()) {
m_syntaxInfoUpdated = SyntaxHighlighter::State::Done; m_syntaxInfoUpdated = SyntaxHighlighter::State::Done;
@@ -168,6 +210,34 @@ void SyntaxHighlighterRunner::applyFormatRanges(const QList<SyntaxHighlighter::R
if (m_document == nullptr) if (m_document == nullptr)
return; return;
if (m_highlightingStatus.m_interruptionRequested) {
d->setInterrupted(false);
m_highlightingStatus.applyNewFrom();
reformatBlocks(m_highlightingStatus.m_newFrom,
m_highlightingStatus.m_removedChars,
m_highlightingStatus.m_addedChars);
return;
}
auto processResult = [this](SyntaxHighlighter::Result result, QTextBlock docBlock) {
if (!docBlock.isValid())
return;
result.copyToBlock(docBlock);
m_highlightingStatus.m_current = docBlock.position() + docBlock.length() - 1;
if (result.m_formatRanges != docBlock.layout()->formats()) {
docBlock.layout()->setFormats(result.m_formatRanges);
m_document->markContentsDirty(docBlock.position(), docBlock.length());
}
};
if (results.size() == 1 && results.at(0).m_state == SyntaxHighlighter::State::Extras) {
QTextBlock docBlock = m_document->findBlockByNumber(results.at(0).m_blockNumber);
processResult(results.at(0), docBlock);
return;
}
for (const SyntaxHighlighter::Result &result : results) { for (const SyntaxHighlighter::Result &result : results) {
m_syntaxInfoUpdated = result.m_state; m_syntaxInfoUpdated = result.m_state;
if (m_syntaxInfoUpdated == SyntaxHighlighter::State::Start) { if (m_syntaxInfoUpdated == SyntaxHighlighter::State::Start) {
@@ -180,25 +250,18 @@ void SyntaxHighlighterRunner::applyFormatRanges(const QList<SyntaxHighlighter::R
return; return;
} }
QTextBlock docBlock = m_document->findBlock(result.m_blockNumber); QTextBlock docBlock = m_document->findBlockByNumber(result.m_blockNumber);
if (!docBlock.isValid()) processResult(result, docBlock);
return; m_foldValidator.process(docBlock);
result.copyToBlock(docBlock);
if (result.m_formatRanges != docBlock.layout()->formats()) {
docBlock.layout()->setFormats(result.m_formatRanges);
m_document->markContentsDirty(docBlock.position(), docBlock.length());
}
if (m_syntaxInfoUpdated != SyntaxHighlighter::State::Extras)
m_foldValidator.process(docBlock);
} }
} }
void SyntaxHighlighterRunner::changeDocument(int from, int charsRemoved, int charsAdded) void SyntaxHighlighterRunner::changeDocument(int from, int charsRemoved, int charsAdded)
{ {
QTC_ASSERT(m_document, return); QTC_ASSERT(m_document, return);
SyntaxHighlighter::State prevSyntaxInfoUpdated = m_syntaxInfoUpdated;
m_syntaxInfoUpdated = SyntaxHighlighter::State::InProgress; m_syntaxInfoUpdated = SyntaxHighlighter::State::InProgress;
QMap<int, BlockPreeditData> blocksPreedit; QMap<int, BlockPreeditData> blocksPreedit;
QTextBlock block = m_document->findBlock(from); QTextBlock block = m_document->findBlock(from);
const QTextBlock endBlock = m_document->findBlock(from + charsAdded); const QTextBlock endBlock = m_document->findBlock(from + charsAdded);
@@ -213,6 +276,14 @@ void SyntaxHighlighterRunner::changeDocument(int from, int charsRemoved, int cha
QMetaObject::invokeMethod(d, [this, from, charsRemoved, text, blocksPreedit] { QMetaObject::invokeMethod(d, [this, from, charsRemoved, text, blocksPreedit] {
d->changeDocument(from, charsRemoved, text, blocksPreedit); d->changeDocument(from, charsRemoved, text, blocksPreedit);
}); });
if (prevSyntaxInfoUpdated == SyntaxHighlighter::State::InProgress) {
m_highlightingStatus.interrupted(from, charsRemoved, charsAdded);
d->setInterrupted(true);
} else {
m_highlightingStatus.notInterrupted(from, charsRemoved, charsAdded);
d->setInterrupted(false);
}
} }
bool SyntaxHighlighterRunner::useGenericHighlighter() const bool SyntaxHighlighterRunner::useGenericHighlighter() const
@@ -239,6 +310,7 @@ void SyntaxHighlighterRunner::clearAllExtraFormats()
void SyntaxHighlighterRunner::setFontSettings(const TextEditor::FontSettings &fontSettings) void SyntaxHighlighterRunner::setFontSettings(const TextEditor::FontSettings &fontSettings)
{ {
QMetaObject::invokeMethod(d, [this, fontSettings] { d->setFontSettings(fontSettings); }); QMetaObject::invokeMethod(d, [this, fontSettings] { d->setFontSettings(fontSettings); });
rehighlight();
} }
void SyntaxHighlighterRunner::setLanguageFeaturesFlags(unsigned int flags) void SyntaxHighlighterRunner::setLanguageFeaturesFlags(unsigned int flags)
@@ -253,7 +325,24 @@ void SyntaxHighlighterRunner::setEnabled(bool enabled)
void SyntaxHighlighterRunner::rehighlight() void SyntaxHighlighterRunner::rehighlight()
{ {
QMetaObject::invokeMethod(d, [this] { d->rehighlight(); }); if (m_syntaxInfoUpdated == SyntaxHighlighter::State::InProgress) {
m_highlightingStatus.interrupted(0, 0, m_document->characterCount());
d->setInterrupted(true);
} else {
m_highlightingStatus.notInterrupted(0, 0, m_document->characterCount());
d->setInterrupted(false);
QMetaObject::invokeMethod(d, [this] { d->rehighlight(); });
}
}
void SyntaxHighlighterRunner::reformatBlocks(int from, int charsRemoved, int charsAdded)
{
QMetaObject::invokeMethod(
d,
[this, from, charsRemoved, charsAdded] {
d->reformatBlocks(from, charsRemoved, charsAdded);
});
} }
QString SyntaxHighlighterRunner::definitionName() QString SyntaxHighlighterRunner::definitionName()

View File

@@ -34,6 +34,7 @@ public:
void setLanguageFeaturesFlags(unsigned int flags); void setLanguageFeaturesFlags(unsigned int flags);
void setEnabled(bool enabled); void setEnabled(bool enabled);
void rehighlight(); void rehighlight();
void reformatBlocks(int from, int charsRemoved, int charsAdded);
QString definitionName(); QString definitionName();
void setDefinitionName(const QString &name); void setDefinitionName(const QString &name);
@@ -53,6 +54,21 @@ private:
SyntaxHighlighterRunnerPrivate *d; SyntaxHighlighterRunnerPrivate *d;
QPointer<QTextDocument> m_document = nullptr; QPointer<QTextDocument> m_document = nullptr;
SyntaxHighlighter::State m_syntaxInfoUpdated = SyntaxHighlighter::State::Done; SyntaxHighlighter::State m_syntaxInfoUpdated = SyntaxHighlighter::State::Done;
struct HighlightingStatus
{
int m_from = 0;
int m_addedChars = 0;
int m_current = 0;
int m_removedChars = 0;
int m_newFrom = 0;
bool m_interruptionRequested = false;
void notInterrupted(int from, int charsRemoved, int charsAdded);
void interrupted(int from, int charsRemoved, int charsAdded);
void applyNewFrom();
} m_highlightingStatus;
bool m_useGenericHighlighter = false; bool m_useGenericHighlighter = false;
QString m_definitionName; QString m_definitionName;
std::optional<QThread> m_thread; std::optional<QThread> m_thread;