aboutsummaryrefslogtreecommitdiffstats
path: root/src/libs/3rdparty/syntax-highlighting/src/lib/abstracthighlighter.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/libs/3rdparty/syntax-highlighting/src/lib/abstracthighlighter.cpp')
-rw-r--r--src/libs/3rdparty/syntax-highlighting/src/lib/abstracthighlighter.cpp49
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;