forked from qt-creator/qt-creator
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:
@@ -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;
|
||||||
|
@@ -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;
|
||||||
|
@@ -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,17 +250,8 @@ 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;
|
|
||||||
|
|
||||||
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);
|
m_foldValidator.process(docBlock);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -198,7 +259,9 @@ void SyntaxHighlighterRunner::applyFormatRanges(const QList<SyntaxHighlighter::R
|
|||||||
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,8 +325,25 @@ void SyntaxHighlighterRunner::setEnabled(bool enabled)
|
|||||||
|
|
||||||
void SyntaxHighlighterRunner::rehighlight()
|
void SyntaxHighlighterRunner::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(); });
|
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()
|
||||||
{
|
{
|
||||||
|
@@ -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;
|
||||||
|
Reference in New Issue
Block a user