diff options
author | Artem Sokolovskii <artem.sokolovskii@qt.io> | 2024-02-12 11:10:04 +0100 |
---|---|---|
committer | Artem Sokolovskii <artem.sokolovskii@qt.io> | 2024-03-06 11:52:41 +0000 |
commit | bb87db09e287a2e60782d8eb212586415a630f98 (patch) | |
tree | c8b74996970d0f278616589280238bc70a1bf12c /src | |
parent | e31a06a0f42143724ebf35aa2cc669dbcf54fbf0 (diff) |
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>
Diffstat (limited to 'src')
-rw-r--r-- | src/plugins/texteditor/syntaxhighlighter.cpp | 15 | ||||
-rw-r--r-- | src/plugins/texteditor/syntaxhighlighter.h | 11 | ||||
-rw-r--r-- | src/plugins/texteditor/syntaxhighlighterrunner.cpp | 123 | ||||
-rw-r--r-- | src/plugins/texteditor/syntaxhighlighterrunner.h | 16 |
4 files changed, 136 insertions, 29 deletions
diff --git a/src/plugins/texteditor/syntaxhighlighter.cpp b/src/plugins/texteditor/syntaxhighlighter.cpp index 34f4b1c7772..f7db190852d 100644 --- a/src/plugins/texteditor/syntaxhighlighter.cpp +++ b/src/plugins/texteditor/syntaxhighlighter.cpp @@ -206,8 +206,11 @@ void SyntaxHighlighterPrivate::reformatBlocks(int from, int charsRemoved, int ch vecRes << resStart; while (block.isValid() && (block.position() < endPosition || forceHighlightOfNextBlock)) { - if (QThread::currentThread()->isInterruptionRequested()) - break; + if (QThread::currentThread()->isInterruptionRequested() || q->isInterrupted()) { + inReformatBlocks = false; + emit q->resultsReady({}); + return; + } const int stateBeforeHighlight = block.userState(); @@ -767,9 +770,7 @@ void SyntaxHighlighter::setExtraFormats(const QTextBlock &block, res.m_formatRanges = block.layout()->formats(); res.fillByBlock(block); res.m_state = SyntaxHighlighter::State::Extras; - SyntaxHighlighter::Result resDone; - resDone.m_state = SyntaxHighlighter::State::Done; - emit resultsReady({res, resDone}); + emit resultsReady({std::move(res)}); document()->markContentsDirty(block.position(), blockLength - 1); d->inReformatBlocks = wasInReformatBlocks; @@ -796,9 +797,7 @@ void SyntaxHighlighter::clearExtraFormats(const QTextBlock &block) res.m_formatRanges = block.layout()->formats(); res.fillByBlock(block); res.m_state = SyntaxHighlighter::State::Extras; - SyntaxHighlighter::Result resDone; - resDone.m_state = SyntaxHighlighter::State::Done; - emit resultsReady({res, resDone}); + emit resultsReady({std::move(res)}); document()->markContentsDirty(block.position(), blockLength - 1); d->inReformatBlocks = wasInReformatBlocks; diff --git a/src/plugins/texteditor/syntaxhighlighter.h b/src/plugins/texteditor/syntaxhighlighter.h index 533c628b9cd..6b07d333f33 100644 --- a/src/plugins/texteditor/syntaxhighlighter.h +++ b/src/plugins/texteditor/syntaxhighlighter.h @@ -56,15 +56,15 @@ public: enum State { Start, InProgress, - Extras, - Done + Done, + Extras }; struct Result { void fillByBlock(const QTextBlock &block) { - m_blockNumber = block.position(); + m_blockNumber = block.blockNumber(); m_userState = block.userState(); TextBlockUserData *userDate = TextDocumentLayout::textUserData(block); @@ -117,6 +117,8 @@ public: 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); virtual void setLanguageFeaturesFlags(unsigned int /*flags*/) {}; // needed for CppHighlighting virtual void setEnabled(bool /*enabled*/) {}; // needed for DiffAndLogHighlighter @@ -126,6 +128,7 @@ public slots: virtual void rehighlight(); void rehighlightBlock(const QTextBlock &block); void clearExtraFormats(const QTextBlock &block); + void reformatBlocks(int from, int charsRemoved, int charsAdded); void clearAllExtraFormats(); protected: @@ -165,10 +168,10 @@ signals: private: void setTextFormatCategories(const QList<std::pair<int, TextStyle>> &categories); - void reformatBlocks(int from, int charsRemoved, int charsAdded); void delayedRehighlight(); QScopedPointer<SyntaxHighlighterPrivate> d_ptr; + std::atomic<bool> m_interrupted = false; #ifdef WITH_TESTS friend class tst_highlighter; diff --git a/src/plugins/texteditor/syntaxhighlighterrunner.cpp b/src/plugins/texteditor/syntaxhighlighterrunner.cpp index 228b8668493..1a649af5329 100644 --- a/src/plugins/texteditor/syntaxhighlighterrunner.cpp +++ b/src/plugins/texteditor/syntaxhighlighterrunner.cpp @@ -81,7 +81,6 @@ public: void setFontSettings(const TextEditor::FontSettings &fontSettings) { m_highlighter->setFontSettings(fontSettings); - rehighlight(); } void setDefinitionName(const QString &name) @@ -98,13 +97,51 @@ public: 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; QTextDocument *m_document = nullptr; + signals: 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, QTextDocument *document, bool async) @@ -124,8 +161,8 @@ SyntaxHighlighterRunner::SyntaxHighlighterRunner(SyntaxHighlighter *highlighter, this, &SyntaxHighlighterRunner::applyFormatRanges); - changeDocument(0, 0, document->characterCount()); - connect(document, + changeDocument(0, 0, m_document->characterCount()); + connect(m_document, &QTextDocument::contentsChange, this, &SyntaxHighlighterRunner::changeDocument); @@ -136,10 +173,15 @@ SyntaxHighlighterRunner::SyntaxHighlighterRunner(SyntaxHighlighter *highlighter, &SyntaxHighlighterRunnerPrivate::resultsReady, this, [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(), result.cend(), [](const SyntaxHighlighter::Result &res) { - return res.m_state == SyntaxHighlighter::State::Done; + return res.m_state + == SyntaxHighlighter::State::Done; }); if (done != result.cend()) { m_syntaxInfoUpdated = SyntaxHighlighter::State::Done; @@ -168,6 +210,34 @@ void SyntaxHighlighterRunner::applyFormatRanges(const QList<SyntaxHighlighter::R if (m_document == nullptr) 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) { m_syntaxInfoUpdated = result.m_state; if (m_syntaxInfoUpdated == SyntaxHighlighter::State::Start) { @@ -180,25 +250,18 @@ void SyntaxHighlighterRunner::applyFormatRanges(const QList<SyntaxHighlighter::R return; } - QTextBlock docBlock = m_document->findBlock(result.m_blockNumber); - if (!docBlock.isValid()) - 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); + QTextBlock docBlock = m_document->findBlockByNumber(result.m_blockNumber); + processResult(result, docBlock); + m_foldValidator.process(docBlock); } } void SyntaxHighlighterRunner::changeDocument(int from, int charsRemoved, int charsAdded) { QTC_ASSERT(m_document, return); + SyntaxHighlighter::State prevSyntaxInfoUpdated = m_syntaxInfoUpdated; m_syntaxInfoUpdated = SyntaxHighlighter::State::InProgress; + QMap<int, BlockPreeditData> blocksPreedit; QTextBlock block = m_document->findBlock(from); 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] { 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 @@ -239,6 +310,7 @@ void SyntaxHighlighterRunner::clearAllExtraFormats() void SyntaxHighlighterRunner::setFontSettings(const TextEditor::FontSettings &fontSettings) { QMetaObject::invokeMethod(d, [this, fontSettings] { d->setFontSettings(fontSettings); }); + rehighlight(); } void SyntaxHighlighterRunner::setLanguageFeaturesFlags(unsigned int flags) @@ -253,7 +325,24 @@ void SyntaxHighlighterRunner::setEnabled(bool enabled) 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() diff --git a/src/plugins/texteditor/syntaxhighlighterrunner.h b/src/plugins/texteditor/syntaxhighlighterrunner.h index 5540bd666a9..16b7c1535c8 100644 --- a/src/plugins/texteditor/syntaxhighlighterrunner.h +++ b/src/plugins/texteditor/syntaxhighlighterrunner.h @@ -34,6 +34,7 @@ public: void setLanguageFeaturesFlags(unsigned int flags); void setEnabled(bool enabled); void rehighlight(); + void reformatBlocks(int from, int charsRemoved, int charsAdded); QString definitionName(); void setDefinitionName(const QString &name); @@ -53,6 +54,21 @@ private: SyntaxHighlighterRunnerPrivate *d; QPointer<QTextDocument> m_document = nullptr; 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; QString m_definitionName; std::optional<QThread> m_thread; |