diff --git a/autotests/foldingtest.cpp b/autotests/foldingtest.cpp --- a/autotests/foldingtest.cpp +++ b/autotests/foldingtest.cpp @@ -178,16 +178,10 @@ highlighter.setDefinition(def); highlighter.highlightFile(inFile, outFile); - const auto diffExecutable = QStandardPaths::findExecutable(QStringLiteral("diff")); - if (!diffExecutable.isEmpty()) { - QProcess proc; - proc.setProcessChannelMode(QProcess::ForwardedChannels); - proc.start(diffExecutable, {QStringLiteral("-u"), refFile, outFile}); - QVERIFY(proc.waitForFinished()); - QCOMPARE(proc.exitCode(), 0); - } else { - qDebug() << "Skipping part of the test since the 'diff' executable is not in PATH"; - } + /** + * compare results + */ + compareFiles(refFile, outFile); } }; diff --git a/autotests/htmlhighlighter_test.cpp b/autotests/htmlhighlighter_test.cpp --- a/autotests/htmlhighlighter_test.cpp +++ b/autotests/htmlhighlighter_test.cpp @@ -107,16 +107,10 @@ highlighter.setOutputFile(outFile); highlighter.highlightFile(inFile); - const auto diffExecutable = QStandardPaths::findExecutable(QStringLiteral("diff")); - if (!diffExecutable.isEmpty()) { - QProcess proc; - proc.setProcessChannelMode(QProcess::ForwardedChannels); - proc.start(diffExecutable, {QStringLiteral("-u"), refFile, outFile}); - QVERIFY(proc.waitForFinished()); - QCOMPARE(proc.exitCode(), 0); - } else { - qDebug() << "Skipping part of the test since the 'diff' executable is not in PATH"; - } + /** + * compare results + */ + compareFiles(refFile, outFile); } }; diff --git a/autotests/test-config.h.in b/autotests/test-config.h.in --- a/autotests/test-config.h.in +++ b/autotests/test-config.h.in @@ -21,7 +21,11 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +#include +#include +#include #include +#include #include @@ -34,12 +38,51 @@ * * @param repository repository to init search paths */ -static void initRepositorySearchPaths(KSyntaxHighlighting::Repository &repository) +void initRepositorySearchPaths(KSyntaxHighlighting::Repository &repository) { #ifdef HAS_SYNTAX_RESOURCE Q_UNUSED(repository) #else repository.addCustomSearchPath(QStringLiteral("@CMAKE_SOURCE_DIR@/data")); repository.addCustomSearchPath(QStringLiteral("@CMAKE_BINARY_DIR@/data")); #endif } + +/** + * helper to compare files + * @param refFile reference file + * @param outFile output file + */ +void compareFiles(const QString &refFile, const QString &outFile) +{ + /** + * quick compare, all fine, if no diffs! + */ + QFile ref(refFile); + QFile out(outFile); + QVERIFY(ref.open(QIODevice::ReadOnly)); + QVERIFY(out.open(QIODevice::ReadOnly)); + const bool equalResults = ref.readAll() == out.readAll(); + if (equalResults) { + return; + } + + /** + * elaborate diff output, if possible + */ + const auto diffExecutable = QStandardPaths::findExecutable(QStringLiteral("diff")); + if (!diffExecutable.isEmpty()) { + QProcess proc; + proc.setProcessChannelMode(QProcess::ForwardedChannels); + proc.start(diffExecutable, {QStringLiteral("-u"), refFile, outFile}); + QVERIFY(proc.waitForFinished()); + QCOMPARE(proc.exitCode(), 0); + } else { + qDebug() << "Skipping differences output as the 'diff' executable is not in the PATH"; + } + + /** + * if we arrive here, all lost! + */ + QVERIFY(equalResults); +} diff --git a/autotests/testhighlighter.cpp b/autotests/testhighlighter.cpp --- a/autotests/testhighlighter.cpp +++ b/autotests/testhighlighter.cpp @@ -33,8 +33,6 @@ #include #include #include -#include -#include #include #include @@ -176,16 +174,10 @@ highlighter.setDefinition(def); highlighter.highlightFile(inFile, outFile); - const auto diffExecutable = QStandardPaths::findExecutable(QStringLiteral("diff")); - if (!diffExecutable.isEmpty()) { - QProcess proc; - proc.setProcessChannelMode(QProcess::ForwardedChannels); - proc.start(diffExecutable, {QStringLiteral("-u"), refFile, outFile}); - QVERIFY(proc.waitForFinished()); - QCOMPARE(proc.exitCode(), 0); - } else { - qDebug() << "Skipping part of the test since the 'diff' executable is not in PATH"; - } + /** + * compare results + */ + compareFiles(refFile, outFile); } }; diff --git a/src/lib/abstracthighlighter.cpp b/src/lib/abstracthighlighter.cpp --- a/src/lib/abstracthighlighter.cpp +++ b/src/lib/abstracthighlighter.cpp @@ -127,13 +127,12 @@ auto defData = DefinitionData::get(d->m_definition); auto newState = state; auto stateData = StateData::get(newState); - if (stateData->m_defData && defData != stateData->m_defData) { + if (stateData->initialContext() && DefinitionData::get(stateData->initialContext()->definition()) != defData) { qCDebug(Log) << "Got invalid state, resetting."; stateData->clear(); } if (stateData->isEmpty()) { stateData->push(defData->initialContext(), QStringList()); - stateData->m_defData = defData; } // process empty lines diff --git a/src/lib/state.cpp b/src/lib/state.cpp --- a/src/lib/state.cpp +++ b/src/lib/state.cpp @@ -1,5 +1,6 @@ /* Copyright (C) 2016 Volker Krause + Copyright (C) 2018 Christoph Cullmann Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the @@ -38,46 +39,45 @@ bool StateData::isEmpty() const { - Q_ASSERT(m_contextStack.size() == m_captureStack.size()); return m_contextStack.isEmpty(); } void StateData::clear() { m_contextStack.clear(); - m_captureStack.clear(); } int StateData::size() const { - Q_ASSERT(m_contextStack.size() == m_captureStack.size()); return m_contextStack.size(); } void StateData::push(Context *context, const QStringList &captures) { Q_ASSERT(context); - m_contextStack.push(context); - m_captureStack.push(captures); - Q_ASSERT(m_contextStack.size() == m_captureStack.size()); + m_contextStack.push_back(qMakePair(context, captures)); } void StateData::pop() { - m_contextStack.pop(); - m_captureStack.pop(); + m_contextStack.pop_back(); +} + +Context* StateData::initialContext() const +{ + return isEmpty() ? nullptr : m_contextStack.first().first; } Context* StateData::topContext() const { Q_ASSERT(!isEmpty()); - return m_contextStack.top(); + return m_contextStack.last().first; } -QStringList StateData::topCaptures() const +const QStringList &StateData::topCaptures() const { Q_ASSERT(!isEmpty()); - return m_captureStack.top(); + return m_contextStack.last().second; } State::State() : @@ -102,7 +102,7 @@ bool State::operator==(const State &other) const { - return d->m_contextStack == other.d->m_contextStack && d->m_captureStack == other.d->m_captureStack && d->m_defData == other.d->m_defData; + return d->m_contextStack == other.d->m_contextStack; } bool State::operator!=(const State &other) const @@ -114,5 +114,5 @@ { if (d->m_contextStack.isEmpty()) return false; - return d->m_contextStack.top()->indentationBasedFoldingEnabled(); + return d->m_contextStack.last().first->indentationBasedFoldingEnabled(); } 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 @@ -1,5 +1,6 @@ /* Copyright (C) 2016 Volker Krause + Copyright (C) 2018 Christoph Cullmann Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the @@ -25,7 +26,7 @@ #define KSYNTAXHIGHLIGHTING_STATE_P_H #include -#include +#include QT_BEGIN_NAMESPACE class QStringList; @@ -39,6 +40,8 @@ class StateData : public QSharedData { + friend class State; + public: StateData() = default; static StateData* get(State &state); @@ -48,14 +51,15 @@ int size() const; void push(Context *context, const QStringList &captures); void pop(); + Context* initialContext() const; Context* topContext() const; - QStringList topCaptures() const; + const QStringList &topCaptures() const; - DefinitionData *m_defData = nullptr; private: - friend class State; - QStack m_contextStack; - QStack m_captureStack; + /** + * the context stack combines the active context + valid captures + */ + QVector> m_contextStack; }; }