diff --git a/src/lib/abstracthighlighter.cpp b/src/lib/abstracthighlighter.cpp --- a/src/lib/abstracthighlighter.cpp +++ b/src/lib/abstracthighlighter.cpp @@ -139,8 +139,10 @@ // process empty lines if (text.isEmpty()) { - while (!stateData->topContext()->lineEmptyContext().isStay()) - d->switchContext(stateData, stateData->topContext()->lineEmptyContext(), QStringList()); + while (!stateData->topContext()->lineEmptyContext().isStay()) { + if (!d->switchContext(stateData, stateData->topContext()->lineEmptyContext(), QStringList())) + break; + } auto context = stateData->topContext(); applyFormat(0, 0, context->attributeFormat()); return newState; @@ -304,20 +306,18 @@ bool AbstractHighlighterPrivate::switchContext(StateData *data, const ContextSwitch &contextSwitch, const QStringList &captures) { - for (int i = 0; i < contextSwitch.popCount(); ++i) { - // don't pop the last context if we can't push one - if (data->size() == 1 && !contextSwitch.context()) - return false; - if (data->size() == 0) - break; - data->pop(); - } + // kill as many items as requested from the stack, will always keep the initial context alive! + const bool initialContextSurvived = data->pop(contextSwitch.popCount()); - if (contextSwitch.context()) + // if we have a new context to add, push it + // then we always "succeed" + if (contextSwitch.context()) { data->push(contextSwitch.context(), captures); + return true; + } - Q_ASSERT(!data->isEmpty()); - return true; + // else we abort, if we did try to pop the initial context + return initialContextSurvived; } void AbstractHighlighter::applyFolding(int offset, int length, FoldingRegion region) diff --git a/src/lib/state.cpp b/src/lib/state.cpp --- a/src/lib/state.cpp +++ b/src/lib/state.cpp @@ -58,9 +58,18 @@ m_contextStack.push_back(qMakePair(context, captures)); } -void StateData::pop() +bool StateData::pop(int popCount) { - m_contextStack.pop_back(); + // nop if nothing to pop + if (popCount <= 0) { + return true; + } + + // keep the initial context alive in any case + Q_ASSERT(!isEmpty()); + const bool initialContextSurvived = m_contextStack.size() > popCount; + m_contextStack.resize(std::max(1, m_contextStack.size() - popCount)); + return initialContextSurvived; } Context* StateData::topContext() const diff --git a/src/lib/state_p.h b/src/lib/state_p.h --- a/src/lib/state_p.h +++ b/src/lib/state_p.h @@ -52,7 +52,15 @@ void clear(); int size() const; void push(Context *context, const QStringList &captures); - void pop(); + + /** + * Pop the number of elements given from the top of the current stack. + * Will not pop the initial element. + * @param popCount number of elements to pop + * @return false if one has tried to pop the initial context, else true + */ + bool pop(int popCount); + Context* topContext() const; const QStringList &topCaptures() const;