From c58b1b2ca6915a4d62330863687b064cba423f37 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Fri, 3 Apr 2020 17:22:19 +0200 Subject: [PATCH] ProjectExplorer: Dissolve the AnsiFilterParser class This class was different from all the other output parsers in that its only responsibility was to pre-process the output before it was passed to the real parsers. We now make this explicit by introducing the concept of a filter function and turning the AnsiFilterParser class into one of those. This also gets rid of a case where the order of output parsers in the chain matters, which we want to move away from. Task-number: QTCREATORBUG-22665 Change-Id: Ica135e54ab43cf2ca8186073dc2487c906d4b38d Reviewed-by: hjk --- .../projectexplorer/abstractprocessstep.cpp | 8 ++-- .../projectexplorer/ansifilterparser.cpp | 45 +++++++------------ .../projectexplorer/ansifilterparser.h | 15 ++----- src/plugins/projectexplorer/ioutputparser.cpp | 31 ++++++++++--- src/plugins/projectexplorer/ioutputparser.h | 5 +++ 5 files changed, 53 insertions(+), 51 deletions(-) diff --git a/src/plugins/projectexplorer/abstractprocessstep.cpp b/src/plugins/projectexplorer/abstractprocessstep.cpp index b8902ea98ad..fce8f478185 100644 --- a/src/plugins/projectexplorer/abstractprocessstep.cpp +++ b/src/plugins/projectexplorer/abstractprocessstep.cpp @@ -136,10 +136,10 @@ AbstractProcessStep::~AbstractProcessStep() void AbstractProcessStep::setOutputParser(IOutputParser *parser) { - d->m_outputParserChain.reset(new AnsiFilterParser); - d->m_outputParserChain->appendOutputParser(parser); - - connect(d->m_outputParserChain.get(), &IOutputParser::addTask, this, &AbstractProcessStep::taskAdded); + parser->addFilter(&Internal::filterAnsiEscapeCodes); + d->m_outputParserChain.reset(parser); + connect(d->m_outputParserChain.get(), &IOutputParser::addTask, + this, &AbstractProcessStep::taskAdded); } /*! diff --git a/src/plugins/projectexplorer/ansifilterparser.cpp b/src/plugins/projectexplorer/ansifilterparser.cpp index a2db2c1a6f9..a4540845ce8 100644 --- a/src/plugins/projectexplorer/ansifilterparser.cpp +++ b/src/plugins/projectexplorer/ansifilterparser.cpp @@ -25,7 +25,18 @@ #include "ansifilterparser.h" -namespace { +#ifdef WITH_TESTS +#include "projectexplorer.h" +#include "outputparser_test.h" +#include "task.h" + +#include +#endif // WITH_TESTS + + +namespace ProjectExplorer { +namespace Internal { + enum AnsiState { PLAIN, ANSI_START, @@ -34,26 +45,8 @@ enum AnsiState { ANSI_WAITING_FOR_ST, ANSI_ST_STARTED }; -} // namespace -using namespace ProjectExplorer; - -AnsiFilterParser::AnsiFilterParser() -{ - setObjectName(QLatin1String("AnsiFilterParser")); -} - -void AnsiFilterParser::stdOutput(const QString &line) -{ - IOutputParser::stdOutput(filterLine(line)); -} - -void AnsiFilterParser::stdError(const QString &line) -{ - IOutputParser::stdError(filterLine(line)); -} - -QString AnsiFilterParser::filterLine(const QString &line) +QString filterAnsiEscapeCodes(const QString &line) { QString result; result.reserve(line.count()); @@ -104,15 +97,9 @@ QString AnsiFilterParser::filterLine(const QString &line) } return result; } +} // namespace Internal -// Unit tests: #ifdef WITH_TESTS -# include - -# include "projectexplorer.h" -# include "outputparser_test.h" -# include "task.h" - void ProjectExplorerPlugin::testAnsiFilterOutputParser_data() { QTest::addColumn("input"); @@ -161,7 +148,7 @@ void ProjectExplorerPlugin::testAnsiFilterOutputParser_data() void ProjectExplorerPlugin::testAnsiFilterOutputParser() { OutputParserTester testbench; - testbench.appendOutputParser(new AnsiFilterParser); + testbench.addFilter(&Internal::filterAnsiEscapeCodes); QFETCH(QString, input); QFETCH(OutputParserTester::Channel, inputChannel); QFETCH(QString, childStdOutLines); @@ -173,3 +160,5 @@ void ProjectExplorerPlugin::testAnsiFilterOutputParser() } #endif + +} // namespace ProjectExplorer diff --git a/src/plugins/projectexplorer/ansifilterparser.h b/src/plugins/projectexplorer/ansifilterparser.h index 6e19915a580..b3ec351c357 100644 --- a/src/plugins/projectexplorer/ansifilterparser.h +++ b/src/plugins/projectexplorer/ansifilterparser.h @@ -30,18 +30,9 @@ #include "projectexplorer_export.h" namespace ProjectExplorer { +namespace Internal { -class PROJECTEXPLORER_EXPORT AnsiFilterParser : public IOutputParser -{ - Q_OBJECT - -public: - AnsiFilterParser(); - void stdOutput(const QString &line) override; - void stdError(const QString &line) override; - -private: - QString filterLine(const QString &line); -}; +QString filterAnsiEscapeCodes(const QString &line); +} // namespace Internal } // namespace ProjectExplorer diff --git a/src/plugins/projectexplorer/ioutputparser.cpp b/src/plugins/projectexplorer/ioutputparser.cpp index 5a77a7384b5..3190c52f1a6 100644 --- a/src/plugins/projectexplorer/ioutputparser.cpp +++ b/src/plugins/projectexplorer/ioutputparser.cpp @@ -111,8 +111,9 @@ class OutputChannelState public: using LineHandler = void (IOutputParser::*)(const QString &line); - OutputChannelState(IOutputParser *parser, LineHandler lineHandler) - : parser(parser), lineHandler(lineHandler) {} + OutputChannelState(IOutputParser *parser, LineHandler lineHandler, + QList &filters) + : parser(parser), lineHandler(lineHandler), filters(filters) {} void handleData(const QString &newData) { @@ -124,20 +125,30 @@ public: break; const QString line = pendingData.left(eolPos + 1); pendingData.remove(0, eolPos + 1); - (parser->*lineHandler)(line); + (parser->*lineHandler)(filteredLine(line)); } } void flush() { if (!pendingData.isEmpty()) { - (parser->*lineHandler)(pendingData); + (parser->*lineHandler)(filteredLine(pendingData)); pendingData.clear(); } } + QString filteredLine(const QString &line) + { + QString l = line; + for (const IOutputParser::Filter &f : filters) + l = f(l); + return l; + } + + IOutputParser * const parser; - LineHandler lineHandler; + const LineHandler lineHandler; + QList &filters; QString pendingData; }; @@ -145,11 +156,12 @@ class IOutputParser::IOutputParserPrivate { public: IOutputParserPrivate(IOutputParser *parser) - : stdoutState(parser, &IOutputParser::stdOutput), - stderrState(parser, &IOutputParser::stdError) + : stdoutState(parser, &IOutputParser::stdOutput, filters), + stderrState(parser, &IOutputParser::stdError, filters) {} IOutputParser *childParser = nullptr; + QList filters; Utils::FilePath workingDir; OutputChannelState stdoutState; OutputChannelState stderrState; @@ -261,4 +273,9 @@ QString IOutputParser::rightTrimmed(const QString &in) return in.mid(0, pos); } +void IOutputParser::addFilter(const Filter &filter) +{ + d->filters << filter; +} + } // namespace ProjectExplorer diff --git a/src/plugins/projectexplorer/ioutputparser.h b/src/plugins/projectexplorer/ioutputparser.h index cbebbf49d58..e288873fd35 100644 --- a/src/plugins/projectexplorer/ioutputparser.h +++ b/src/plugins/projectexplorer/ioutputparser.h @@ -30,6 +30,8 @@ #include +#include + namespace ProjectExplorer { class Task; @@ -51,6 +53,9 @@ public: virtual bool hasFatalErrors() const; + using Filter = std::function; + void addFilter(const Filter &filter); + void setWorkingDirectory(const Utils::FilePath &fn); void flush(); // flush pending tasks & output