diff options
Diffstat (limited to 'src/libs/3rdparty/syntax-highlighting/src/lib/abstracthighlighter.cpp')
-rw-r--r-- | src/libs/3rdparty/syntax-highlighting/src/lib/abstracthighlighter.cpp | 49 |
1 files changed, 33 insertions, 16 deletions
diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/abstracthighlighter.cpp b/src/libs/3rdparty/syntax-highlighting/src/lib/abstracthighlighter.cpp index c4ef86a771..fc5c627812 100644 --- a/src/libs/3rdparty/syntax-highlighting/src/lib/abstracthighlighter.cpp +++ b/src/libs/3rdparty/syntax-highlighting/src/lib/abstracthighlighter.cpp @@ -27,11 +27,11 @@ #include "definition_p.h" #include "foldingregion.h" #include "format.h" +#include "ksyntaxhighlighting_logging.h" #include "repository.h" #include "rule_p.h" #include "state.h" #include "state_p.h" -#include "ksyntaxhighlighting_logging.h" #include "theme.h" using namespace KSyntaxHighlighting; @@ -60,13 +60,13 @@ void AbstractHighlighterPrivate::ensureDefinitionLoaded() defData->load(); } -AbstractHighlighter::AbstractHighlighter() : - d_ptr(new AbstractHighlighterPrivate) +AbstractHighlighter::AbstractHighlighter() + : d_ptr(new AbstractHighlighterPrivate) { } -AbstractHighlighter::AbstractHighlighter(AbstractHighlighterPrivate *dd) : - d_ptr(dd) +AbstractHighlighter::AbstractHighlighter(AbstractHighlighterPrivate *dd) + : d_ptr(dd) { } @@ -102,7 +102,7 @@ void AbstractHighlighter::setTheme(const Theme &theme) * Returns the index of the first non-space character. If the line is empty, * or only contains white spaces, text.size() is returned. */ -static inline int firstNonSpaceChar(const QString & text) +static inline int firstNonSpaceChar(const QString &text) { for (int i = 0; i < text.length(); ++i) { if (!text[i].isSpace()) { @@ -112,7 +112,7 @@ static inline int firstNonSpaceChar(const QString & text) return text.size(); } -State AbstractHighlighter::highlightLine(const QString& text, const State &state) +State AbstractHighlighter::highlightLine(const QString &text, const State &state) { Q_D(AbstractHighlighter); @@ -156,12 +156,11 @@ State AbstractHighlighter::highlightLine(const QString& text, const State &state */ break; } - /** - * line end context switches only when lineEmptyContext is #stay. This avoids - * skipping empty lines after a line continuation character (see bug 405903) - */ - } else if (!stateData->topContext()->lineEndContext().isStay() && - !d->switchContext(stateData, stateData->topContext()->lineEndContext(), QStringList())) + /** + * line end context switches only when lineEmptyContext is #stay. This avoids + * skipping empty lines after a line continuation character (see bug 405903) + */ + } else if (!stateData->topContext()->lineEndContext().isStay() && !d->switchContext(stateData, stateData->topContext()->lineEndContext(), QStringList())) break; // guard against endless loops @@ -178,7 +177,15 @@ State AbstractHighlighter::highlightLine(const QString& text, const State &state int offset = 0, beginOffset = 0; bool lineContinuation = false; - QHash<Rule*, int> skipOffsets; + + /** + * for expensive rules like regexes we do: + * - match them for the complete line, as this is faster than re-trying them at all positions + * - store the result of the first position that matches (or -1 for no match in the full line) in the skipOffsets hash for re-use + * - have capturesForLastDynamicSkipOffset as guard for dynamic regexes to invalidate the cache if they might have changed + */ + QHash<Rule *, int> skipOffsets; + QStringList capturesForLastDynamicSkipOffset; /** * current active format @@ -248,21 +255,31 @@ State AbstractHighlighter::highlightLine(const QString& text, const State &state * 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; - const auto newResult = rule->doMatch(text, offset, stateData->topCaptures()); newOffset = newResult.offset(); /** * 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; |