forked from qt-creator/qt-creator
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 <hjk@qt.io>
This commit is contained in:
@@ -136,10 +136,10 @@ AbstractProcessStep::~AbstractProcessStep()
|
|||||||
|
|
||||||
void AbstractProcessStep::setOutputParser(IOutputParser *parser)
|
void AbstractProcessStep::setOutputParser(IOutputParser *parser)
|
||||||
{
|
{
|
||||||
d->m_outputParserChain.reset(new AnsiFilterParser);
|
parser->addFilter(&Internal::filterAnsiEscapeCodes);
|
||||||
d->m_outputParserChain->appendOutputParser(parser);
|
d->m_outputParserChain.reset(parser);
|
||||||
|
connect(d->m_outputParserChain.get(), &IOutputParser::addTask,
|
||||||
connect(d->m_outputParserChain.get(), &IOutputParser::addTask, this, &AbstractProcessStep::taskAdded);
|
this, &AbstractProcessStep::taskAdded);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@@ -25,7 +25,18 @@
|
|||||||
|
|
||||||
#include "ansifilterparser.h"
|
#include "ansifilterparser.h"
|
||||||
|
|
||||||
namespace {
|
#ifdef WITH_TESTS
|
||||||
|
#include "projectexplorer.h"
|
||||||
|
#include "outputparser_test.h"
|
||||||
|
#include "task.h"
|
||||||
|
|
||||||
|
#include <QTest>
|
||||||
|
#endif // WITH_TESTS
|
||||||
|
|
||||||
|
|
||||||
|
namespace ProjectExplorer {
|
||||||
|
namespace Internal {
|
||||||
|
|
||||||
enum AnsiState {
|
enum AnsiState {
|
||||||
PLAIN,
|
PLAIN,
|
||||||
ANSI_START,
|
ANSI_START,
|
||||||
@@ -34,26 +45,8 @@ enum AnsiState {
|
|||||||
ANSI_WAITING_FOR_ST,
|
ANSI_WAITING_FOR_ST,
|
||||||
ANSI_ST_STARTED
|
ANSI_ST_STARTED
|
||||||
};
|
};
|
||||||
} // namespace
|
|
||||||
|
|
||||||
using namespace ProjectExplorer;
|
QString filterAnsiEscapeCodes(const QString &line)
|
||||||
|
|
||||||
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 result;
|
QString result;
|
||||||
result.reserve(line.count());
|
result.reserve(line.count());
|
||||||
@@ -104,15 +97,9 @@ QString AnsiFilterParser::filterLine(const QString &line)
|
|||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
} // namespace Internal
|
||||||
|
|
||||||
// Unit tests:
|
|
||||||
#ifdef WITH_TESTS
|
#ifdef WITH_TESTS
|
||||||
# include <QTest>
|
|
||||||
|
|
||||||
# include "projectexplorer.h"
|
|
||||||
# include "outputparser_test.h"
|
|
||||||
# include "task.h"
|
|
||||||
|
|
||||||
void ProjectExplorerPlugin::testAnsiFilterOutputParser_data()
|
void ProjectExplorerPlugin::testAnsiFilterOutputParser_data()
|
||||||
{
|
{
|
||||||
QTest::addColumn<QString>("input");
|
QTest::addColumn<QString>("input");
|
||||||
@@ -161,7 +148,7 @@ void ProjectExplorerPlugin::testAnsiFilterOutputParser_data()
|
|||||||
void ProjectExplorerPlugin::testAnsiFilterOutputParser()
|
void ProjectExplorerPlugin::testAnsiFilterOutputParser()
|
||||||
{
|
{
|
||||||
OutputParserTester testbench;
|
OutputParserTester testbench;
|
||||||
testbench.appendOutputParser(new AnsiFilterParser);
|
testbench.addFilter(&Internal::filterAnsiEscapeCodes);
|
||||||
QFETCH(QString, input);
|
QFETCH(QString, input);
|
||||||
QFETCH(OutputParserTester::Channel, inputChannel);
|
QFETCH(OutputParserTester::Channel, inputChannel);
|
||||||
QFETCH(QString, childStdOutLines);
|
QFETCH(QString, childStdOutLines);
|
||||||
@@ -173,3 +160,5 @@ void ProjectExplorerPlugin::testAnsiFilterOutputParser()
|
|||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
} // namespace ProjectExplorer
|
||||||
|
@@ -30,18 +30,9 @@
|
|||||||
#include "projectexplorer_export.h"
|
#include "projectexplorer_export.h"
|
||||||
|
|
||||||
namespace ProjectExplorer {
|
namespace ProjectExplorer {
|
||||||
|
namespace Internal {
|
||||||
|
|
||||||
class PROJECTEXPLORER_EXPORT AnsiFilterParser : public IOutputParser
|
QString filterAnsiEscapeCodes(const QString &line);
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
|
||||||
AnsiFilterParser();
|
|
||||||
void stdOutput(const QString &line) override;
|
|
||||||
void stdError(const QString &line) override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
QString filterLine(const QString &line);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
} // namespace Internal
|
||||||
} // namespace ProjectExplorer
|
} // namespace ProjectExplorer
|
||||||
|
@@ -111,8 +111,9 @@ class OutputChannelState
|
|||||||
public:
|
public:
|
||||||
using LineHandler = void (IOutputParser::*)(const QString &line);
|
using LineHandler = void (IOutputParser::*)(const QString &line);
|
||||||
|
|
||||||
OutputChannelState(IOutputParser *parser, LineHandler lineHandler)
|
OutputChannelState(IOutputParser *parser, LineHandler lineHandler,
|
||||||
: parser(parser), lineHandler(lineHandler) {}
|
QList<IOutputParser::Filter> &filters)
|
||||||
|
: parser(parser), lineHandler(lineHandler), filters(filters) {}
|
||||||
|
|
||||||
void handleData(const QString &newData)
|
void handleData(const QString &newData)
|
||||||
{
|
{
|
||||||
@@ -124,20 +125,30 @@ public:
|
|||||||
break;
|
break;
|
||||||
const QString line = pendingData.left(eolPos + 1);
|
const QString line = pendingData.left(eolPos + 1);
|
||||||
pendingData.remove(0, eolPos + 1);
|
pendingData.remove(0, eolPos + 1);
|
||||||
(parser->*lineHandler)(line);
|
(parser->*lineHandler)(filteredLine(line));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void flush()
|
void flush()
|
||||||
{
|
{
|
||||||
if (!pendingData.isEmpty()) {
|
if (!pendingData.isEmpty()) {
|
||||||
(parser->*lineHandler)(pendingData);
|
(parser->*lineHandler)(filteredLine(pendingData));
|
||||||
pendingData.clear();
|
pendingData.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString filteredLine(const QString &line)
|
||||||
|
{
|
||||||
|
QString l = line;
|
||||||
|
for (const IOutputParser::Filter &f : filters)
|
||||||
|
l = f(l);
|
||||||
|
return l;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
IOutputParser * const parser;
|
IOutputParser * const parser;
|
||||||
LineHandler lineHandler;
|
const LineHandler lineHandler;
|
||||||
|
QList<IOutputParser::Filter> &filters;
|
||||||
QString pendingData;
|
QString pendingData;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -145,11 +156,12 @@ class IOutputParser::IOutputParserPrivate
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
IOutputParserPrivate(IOutputParser *parser)
|
IOutputParserPrivate(IOutputParser *parser)
|
||||||
: stdoutState(parser, &IOutputParser::stdOutput),
|
: stdoutState(parser, &IOutputParser::stdOutput, filters),
|
||||||
stderrState(parser, &IOutputParser::stdError)
|
stderrState(parser, &IOutputParser::stdError, filters)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
IOutputParser *childParser = nullptr;
|
IOutputParser *childParser = nullptr;
|
||||||
|
QList<Filter> filters;
|
||||||
Utils::FilePath workingDir;
|
Utils::FilePath workingDir;
|
||||||
OutputChannelState stdoutState;
|
OutputChannelState stdoutState;
|
||||||
OutputChannelState stderrState;
|
OutputChannelState stderrState;
|
||||||
@@ -261,4 +273,9 @@ QString IOutputParser::rightTrimmed(const QString &in)
|
|||||||
return in.mid(0, pos);
|
return in.mid(0, pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void IOutputParser::addFilter(const Filter &filter)
|
||||||
|
{
|
||||||
|
d->filters << filter;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace ProjectExplorer
|
} // namespace ProjectExplorer
|
||||||
|
@@ -30,6 +30,8 @@
|
|||||||
|
|
||||||
#include <utils/fileutils.h>
|
#include <utils/fileutils.h>
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
namespace ProjectExplorer {
|
namespace ProjectExplorer {
|
||||||
class Task;
|
class Task;
|
||||||
|
|
||||||
@@ -51,6 +53,9 @@ public:
|
|||||||
|
|
||||||
virtual bool hasFatalErrors() const;
|
virtual bool hasFatalErrors() const;
|
||||||
|
|
||||||
|
using Filter = std::function<QString(const QString &)>;
|
||||||
|
void addFilter(const Filter &filter);
|
||||||
|
|
||||||
void setWorkingDirectory(const Utils::FilePath &fn);
|
void setWorkingDirectory(const Utils::FilePath &fn);
|
||||||
|
|
||||||
void flush(); // flush pending tasks & output
|
void flush(); // flush pending tasks & output
|
||||||
|
Reference in New Issue
Block a user