diff --git a/src/lib/abstracthighlighter.cpp b/src/lib/abstracthighlighter.cpp --- a/src/lib/abstracthighlighter.cpp +++ b/src/lib/abstracthighlighter.cpp @@ -178,6 +178,7 @@ int offset = 0, beginOffset = 0; bool lineContinuation = false; QHash skipOffsets; + QStringList capturesForLastDynamicSkipOffset; /** * current active format @@ -247,7 +248,12 @@ * shall we skip application of this rule? two cases: * - rule can't match at all => currentSkipOffset < 0 * - rule will only match for some higher offset => currentSkipOffset > offset + * + * we need to invalidate this if we are dynamic and have different captures then last time */ + if (rule->isDynamic() && (capturesForLastDynamicSkipOffset != stateData->topCaptures())) { + skipOffsets.clear(); + } const auto currentSkipOffset = skipOffsets.value(rule.get()); if (currentSkipOffset < 0 || currentSkipOffset > offset) continue; @@ -258,9 +264,15 @@ /** * update skip offset if new one rules out any later match or is larger than current one */ - if (newResult.skipOffset() < 0 || newResult.skipOffset() > currentSkipOffset) + if (newResult.skipOffset() < 0 || newResult.skipOffset() > currentSkipOffset) { skipOffsets.insert(rule.get(), newResult.skipOffset()); + // remember new captures, if dynamic to enforce proper reset above on change! + if (rule->isDynamic()) { + capturesForLastDynamicSkipOffset = stateData->topCaptures(); + } + } + if (newOffset <= offset) continue; diff --git a/src/lib/rule.cpp b/src/lib/rule.cpp --- a/src/lib/rule.cpp +++ b/src/lib/rule.cpp @@ -593,10 +593,9 @@ /** * no match - * the pattern of a dynamic regex depends on the previous contexts - * so that skipOffset cannot be computed + * we can always compute the skip offset as the highlighter will invalidate the cache for changed captures for dynamic rules! */ - return MatchResult(offset, m_dynamic ? 0 : result.capturedStart()); + return MatchResult(offset, result.capturedStart()); } bool StringDetect::doLoad(QXmlStreamReader &reader) diff --git a/src/lib/rule_p.h b/src/lib/rule_p.h --- a/src/lib/rule_p.h +++ b/src/lib/rule_p.h @@ -69,6 +69,11 @@ return m_lookAhead; } + bool isDynamic() const + { + return m_dynamic; + } + bool firstNonSpace() const { return m_firstNonSpace; @@ -117,6 +122,9 @@ // cache for DefinitionData::wordDelimiters, is accessed VERY often QStringRef m_wordDelimiter; + +protected: + bool m_dynamic = false; }; class AnyChar : public Rule @@ -137,7 +145,7 @@ private: QChar m_char; - bool m_dynamic = false; + int m_captureIndex = 0; }; @@ -258,7 +266,6 @@ private: QRegularExpression m_regexp; - bool m_dynamic = false; }; class StringDetect : public Rule @@ -270,7 +277,6 @@ private: QString m_string; Qt::CaseSensitivity m_caseSensitivity; - bool m_dynamic = false; }; class WordDetect : public Rule