Utils/all: Create an OutputFormatterFactory

Essentially following the scheme used for the various project
configurations. This makes it possible to construct OutputFormatters
by Id only, potentially reducing hard plugin dependencies and
opening the road to have several output formatters per
RunConfiguration/Outputpane/...

Change-Id: I4b5fb6fb6be8b0d9a0859f178bb0effc3398b09e
Reviewed-by: Christian Kandeler <christian.kandeler@qt.io>
This commit is contained in:
hjk
2019-08-06 10:57:59 +02:00
parent 86e9c42c90
commit fcffb5f2fc
16 changed files with 137 additions and 100 deletions

View File

@@ -35,7 +35,6 @@
#include <projectexplorer/project.h> #include <projectexplorer/project.h>
#include <projectexplorer/target.h> #include <projectexplorer/target.h>
#include <qtsupport/qtoutputformatter.h>
#include <qtsupport/qtkitinformation.h> #include <qtsupport/qtkitinformation.h>
#include <utils/detailswidget.h> #include <utils/detailswidget.h>
@@ -133,7 +132,6 @@ AndroidRunConfiguration::AndroidRunConfiguration(Target *target, Core::Id id)
postStartShellCmdAspect->setSettingsKey("Android.PostStartShellCmdListKey"); postStartShellCmdAspect->setSettingsKey("Android.PostStartShellCmdListKey");
postStartShellCmdAspect->setLabel(tr("Shell commands to run on Android device after application quits.")); postStartShellCmdAspect->setLabel(tr("Shell commands to run on Android device after application quits."));
setOutputFormatter<QtSupport::QtOutputFormatter>();
connect(target->project(), &Project::parsingFinished, this, [this] { connect(target->project(), &Project::parsingFinished, this, [this] {
updateTargetInformation(); updateTargetInformation();
}); });

View File

@@ -33,8 +33,6 @@
#include <projectexplorer/runconfigurationaspects.h> #include <projectexplorer/runconfigurationaspects.h>
#include <projectexplorer/target.h> #include <projectexplorer/target.h>
#include <qtsupport/qtoutputformatter.h>
#include <remotelinux/remotelinuxenvironmentaspect.h> #include <remotelinux/remotelinuxenvironmentaspect.h>
using namespace ProjectExplorer; using namespace ProjectExplorer;
@@ -87,8 +85,6 @@ QdbRunConfiguration::QdbRunConfiguration(Target *target, Core::Id id)
addAspect<WorkingDirectoryAspect>(); addAspect<WorkingDirectoryAspect>();
addAspect<FullCommandLineAspect>(this); addAspect<FullCommandLineAspect>(this);
setOutputFormatter<QtSupport::QtOutputFormatter>();
connect(target, &Target::deploymentDataChanged, connect(target, &Target::deploymentDataChanged,
this, &QdbRunConfiguration::updateTargetInformation); this, &QdbRunConfiguration::updateTargetInformation);
connect(target, &Target::applicationTargetsChanged, connect(target, &Target::applicationTargetsChanged,

View File

@@ -39,7 +39,6 @@
#include <projectexplorer/runconfigurationaspects.h> #include <projectexplorer/runconfigurationaspects.h>
#include <projectexplorer/target.h> #include <projectexplorer/target.h>
#include <qtsupport/qtoutputformatter.h>
#include <qtsupport/qtkitinformation.h> #include <qtsupport/qtkitinformation.h>
#include <utils/algorithm.h> #include <utils/algorithm.h>
@@ -114,8 +113,6 @@ IosRunConfiguration::IosRunConfiguration(Target *target, Core::Id id)
addAspect<ArgumentsAspect>(); addAspect<ArgumentsAspect>();
m_deviceTypeAspect = addAspect<IosDeviceTypeAspect>(this); m_deviceTypeAspect = addAspect<IosDeviceTypeAspect>(this);
setOutputFormatter<QtSupport::QtOutputFormatter>();
} }
void IosDeviceTypeAspect::deviceChanges() void IosDeviceTypeAspect::deviceChanges()

View File

@@ -406,14 +406,6 @@ Runnable RunConfiguration::runnable() const
return r; return r;
} }
OutputFormatter *RunConfiguration::createOutputFormatter() const
{
if (m_outputFormatterCreator)
return m_outputFormatterCreator(project());
return new OutputFormatter();
}
/*! /*!
\class ProjectExplorer::IRunConfigurationFactory \class ProjectExplorer::IRunConfigurationFactory

View File

@@ -180,11 +180,6 @@ protected:
/// convenience function to get current build configuration. /// convenience function to get current build configuration.
BuildConfiguration *activeBuildConfiguration() const; BuildConfiguration *activeBuildConfiguration() const;
template<class T> void setOutputFormatter()
{
m_outputFormatterCreator = [](Project *project) { return new T(project); };
}
virtual void updateEnabledState(); virtual void updateEnabledState();
virtual void doAdditionalSetup(const RunConfigurationCreationInfo &) {} virtual void doAdditionalSetup(const RunConfigurationCreationInfo &) {}
@@ -195,7 +190,6 @@ private:
QString m_buildKey; QString m_buildKey;
bool m_isEnabled = false; bool m_isEnabled = false;
std::function<Utils::OutputFormatter *(Project *)> m_outputFormatterCreator;
CommandLineGetter m_commandLineGetter; CommandLineGetter m_commandLineGetter;
}; };

View File

@@ -327,10 +327,6 @@ void RunControl::setRunConfiguration(RunConfiguration *runConfig)
d->runConfigId = runConfig->id(); d->runConfigId = runConfig->id();
d->runnable = runConfig->runnable(); d->runnable = runConfig->runnable();
d->displayName = runConfig->displayName(); d->displayName = runConfig->displayName();
if (auto outputFormatter = runConfig->createOutputFormatter()) {
delete d->outputFormatter;
d->outputFormatter = outputFormatter;
}
d->macroExpander = runConfig->macroExpander(); d->macroExpander = runConfig->macroExpander();
setTarget(runConfig->target()); setTarget(runConfig->target());
} }
@@ -340,6 +336,12 @@ void RunControl::setTarget(Target *target)
QTC_ASSERT(target, return); QTC_ASSERT(target, return);
QTC_CHECK(!d->target); QTC_CHECK(!d->target);
d->target = target; d->target = target;
delete d->outputFormatter;
d->outputFormatter = OutputFormatterFactory::createFormatter(target);
if (!d->outputFormatter)
d->outputFormatter = new OutputFormatter();
setKit(target->kit()); setKit(target->kit());
d->project = target->project(); d->project = target->project();
} }
@@ -1557,4 +1559,37 @@ void Runnable::setCommandLine(const CommandLine &cmdLine)
commandLineArguments = cmdLine.arguments(); commandLineArguments = cmdLine.arguments();
} }
// OutputFormatterFactory
static QList<OutputFormatterFactory *> g_outputFormatterFactories;
OutputFormatterFactory::OutputFormatterFactory()
{
// This is a bit cheating: We know that only two formatters exist right now,
// and this here gives the second (python) implicit more priority.
// For a final solution, probably all matching formatters should be used
// in parallel, so there's no need to invent a fancy priority system here.
g_outputFormatterFactories.prepend(this);
}
OutputFormatterFactory::~OutputFormatterFactory()
{
g_outputFormatterFactories.removeOne(this);
}
OutputFormatter *OutputFormatterFactory::createFormatter(Target *target)
{
for (auto factory : qAsConst(g_outputFormatterFactories)) {
if (auto formatter = factory->m_creator(target))
return formatter;
}
return nullptr;
}
void OutputFormatterFactory::setFormatterCreator
(const std::function<OutputFormatter *(Target *)> &creator)
{
m_creator = creator;
}
} // namespace ProjectExplorer } // namespace ProjectExplorer

View File

@@ -309,4 +309,21 @@ private:
bool m_useTerminal = false; bool m_useTerminal = false;
}; };
class PROJECTEXPLORER_EXPORT OutputFormatterFactory
{
protected:
OutputFormatterFactory();
public:
virtual ~OutputFormatterFactory();
static Utils::OutputFormatter *createFormatter(Target *target);
protected:
void setFormatterCreator(const std::function<Utils::OutputFormatter *(Target *)> &creator);
private:
std::function<Utils::OutputFormatter *(Target *)> m_creator;
};
} // namespace ProjectExplorer } // namespace ProjectExplorer

View File

@@ -147,7 +147,7 @@ static QTextCharFormat linkFormat(const QTextCharFormat &inputFormat, const QStr
class PythonOutputFormatter : public OutputFormatter class PythonOutputFormatter : public OutputFormatter
{ {
public: public:
PythonOutputFormatter(Project *) PythonOutputFormatter()
// Note that moc dislikes raw string literals. // Note that moc dislikes raw string literals.
: filePattern("^(\\s*)(File \"([^\"]+)\", line (\\d+), .*$)") : filePattern("^(\\s*)(File \"([^\"]+)\", line (\\d+), .*$)")
{ {
@@ -217,6 +217,19 @@ private:
const QRegularExpression filePattern; const QRegularExpression filePattern;
}; };
class PythonOutputFormatterFactory : public OutputFormatterFactory
{
public:
PythonOutputFormatterFactory()
{
setFormatterCreator([](Target *t) -> OutputFormatter * {
if (t->project()->mimeType() == Constants::C_PY_MIMETYPE)
return new PythonOutputFormatter;
return nullptr;
});
}
};
//////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////
class InterpreterAspect : public ProjectConfigurationAspect class InterpreterAspect : public ProjectConfigurationAspect
@@ -370,7 +383,6 @@ PythonRunConfiguration::PythonRunConfiguration(Target *target, Core::Id id)
addAspect<TerminalAspect>(); addAspect<TerminalAspect>();
setOutputFormatter<PythonOutputFormatter>();
setCommandLineGetter([this, interpreterAspect, argumentsAspect] { setCommandLineGetter([this, interpreterAspect, argumentsAspect] {
CommandLine cmd{interpreterAspect->currentInterpreter().command, {mainScript()}}; CommandLine cmd{interpreterAspect->currentInterpreter().command, {mainScript()}};
cmd.addArgs(argumentsAspect->arguments(macroExpander()), CommandLine::Raw); cmd.addArgs(argumentsAspect->arguments(macroExpander()), CommandLine::Raw);
@@ -810,7 +822,9 @@ class PythonPluginPrivate
{ {
public: public:
PythonEditorFactory editorFactory; PythonEditorFactory editorFactory;
PythonOutputFormatterFactory outputFormatterFactory;
PythonRunConfigurationFactory runConfigFactory; PythonRunConfigurationFactory runConfigFactory;
RunWorkerFactory runWorkerFactory{ RunWorkerFactory runWorkerFactory{
RunWorkerFactory::make<SimpleTargetRunner>(), RunWorkerFactory::make<SimpleTargetRunner>(),
{ProjectExplorer::Constants::NORMAL_RUN_MODE}, {ProjectExplorer::Constants::NORMAL_RUN_MODE},

View File

@@ -38,7 +38,6 @@
#include <projectexplorer/target.h> #include <projectexplorer/target.h>
#include <qtsupport/qtkitinformation.h> #include <qtsupport/qtkitinformation.h>
#include <qtsupport/qtoutputformatter.h>
#include <qtsupport/qtsupportconstants.h> #include <qtsupport/qtsupportconstants.h>
#include <qtsupport/desktopqtversion.h> #include <qtsupport/desktopqtversion.h>
@@ -319,7 +318,6 @@ QmlProjectRunConfiguration::QmlProjectRunConfiguration(Target *target, Id id)
connect(m_mainQmlFileAspect, &MainQmlFileAspect::changed, connect(m_mainQmlFileAspect, &MainQmlFileAspect::changed,
this, &QmlProjectRunConfiguration::updateEnabledState); this, &QmlProjectRunConfiguration::updateEnabledState);
setOutputFormatter<QtSupport::QtOutputFormatter>();
connect(target, &Target::kitChanged, connect(target, &Target::kitChanged,
this, &QmlProjectRunConfiguration::updateEnabledState); this, &QmlProjectRunConfiguration::updateEnabledState);

View File

@@ -68,8 +68,6 @@ QnxRunConfiguration::QnxRunConfiguration(Target *target, Core::Id id)
libAspect->setLabelText(tr("Path to Qt libraries on device")); libAspect->setLabelText(tr("Path to Qt libraries on device"));
libAspect->setDisplayStyle(BaseStringAspect::LineEditDisplay); libAspect->setDisplayStyle(BaseStringAspect::LineEditDisplay);
setOutputFormatter<QtSupport::QtOutputFormatter>();
auto updateTargetInformation = [this, target, exeAspect, symbolsAspect] { auto updateTargetInformation = [this, target, exeAspect, symbolsAspect] {
BuildTargetInfo bti = buildTargetInfo(); BuildTargetInfo bti = buildTargetInfo();

View File

@@ -98,8 +98,6 @@ DesktopRunConfiguration::DesktopRunConfiguration(Target *target, Core::Id id, Ki
} }
setOutputFormatter<QtSupport::QtOutputFormatter>();
connect(target->project(), &Project::parsingFinished, connect(target->project(), &Project::parsingFinished,
this, &DesktopRunConfiguration::updateTargetInformation); this, &DesktopRunConfiguration::updateTargetInformation);
} }

View File

@@ -25,13 +25,18 @@
#include "qtoutputformatter.h" #include "qtoutputformatter.h"
#include "qtkitinformation.h"
#include "qtsupportconstants.h"
#include <coreplugin/editormanager/editormanager.h> #include <coreplugin/editormanager/editormanager.h>
#include <projectexplorer/project.h> #include <projectexplorer/project.h>
#include <projectexplorer/target.h>
#include <utils/algorithm.h> #include <utils/algorithm.h>
#include <utils/ansiescapecodehandler.h> #include <utils/ansiescapecodehandler.h>
#include <utils/fileinprojectfinder.h> #include <utils/fileinprojectfinder.h>
#include <utils/hostosinfo.h> #include <utils/hostosinfo.h>
#include <utils/outputformatter.h>
#include <utils/theme/theme.h> #include <utils/theme/theme.h>
#include <QPlainTextEdit> #include <QPlainTextEdit>
@@ -44,13 +49,19 @@ using namespace ProjectExplorer;
using namespace Utils; using namespace Utils;
namespace QtSupport { namespace QtSupport {
namespace Internal { namespace Internal {
struct LinkResult
{
int start = -1;
int end = -1;
QString href;
};
class QtOutputFormatterPrivate class QtOutputFormatterPrivate
{ {
public: public:
QtOutputFormatterPrivate(Project *proj) QtOutputFormatterPrivate()
: qmlError("(" QT_QML_URL_REGEXP // url : qmlError("(" QT_QML_URL_REGEXP // url
":\\d+" // colon, line ":\\d+" // colon, line
"(?::\\d+)?)" // colon, column (optional) "(?::\\d+)?)" // colon, column (optional)
@@ -60,11 +71,6 @@ public:
, qtAssertX(QT_ASSERT_X_REGEXP) , qtAssertX(QT_ASSERT_X_REGEXP)
, qtTestFailUnix(QT_TEST_FAIL_UNIX_REGEXP) , qtTestFailUnix(QT_TEST_FAIL_UNIX_REGEXP)
, qtTestFailWin(QT_TEST_FAIL_WIN_REGEXP) , qtTestFailWin(QT_TEST_FAIL_WIN_REGEXP)
, project(proj)
{
}
~QtOutputFormatterPrivate()
{ {
} }
@@ -80,16 +86,41 @@ public:
QTextCursor cursor; QTextCursor cursor;
}; };
} // namespace Internal class QtOutputFormatter : public OutputFormatter
QtOutputFormatter::QtOutputFormatter(Project *project)
: d(new Internal::QtOutputFormatterPrivate(project))
{ {
if (project) { public:
d->projectFinder.setProjectFiles(project->files(Project::SourceFiles)); explicit QtOutputFormatter(Target *target);
d->projectFinder.setProjectDirectory(project->projectDirectory()); ~QtOutputFormatter() override;
connect(project, void appendMessage(const QString &text, Utils::OutputFormat format) override;
void handleLink(const QString &href) override;
void setPlainTextEdit(QPlainTextEdit *plainText) override;
protected:
void clearLastLine() override;
virtual void openEditor(const QString &fileName, int line, int column = -1);
private:
void updateProjectFileList();
LinkResult matchLine(const QString &line) const;
void appendMessagePart(const QString &txt, const QTextCharFormat &fmt);
void appendLine(const LinkResult &lr, const QString &line, Utils::OutputFormat format);
void appendLine(const LinkResult &lr, const QString &line, const QTextCharFormat &format);
void appendMessage(const QString &text, const QTextCharFormat &format) override;
QtOutputFormatterPrivate *d;
friend class QtSupportPlugin; // for testing
};
QtOutputFormatter::QtOutputFormatter(Target *target)
: d(new QtOutputFormatterPrivate)
{
d->project = target ? target->project() : nullptr;
if (d->project) {
d->projectFinder.setProjectFiles(d->project->files(Project::SourceFiles));
d->projectFinder.setProjectDirectory(d->project->projectDirectory());
connect(d->project,
&Project::fileListChanged, &Project::fileListChanged,
this, this,
&QtOutputFormatter::updateProjectFileList, &QtOutputFormatter::updateProjectFileList,
@@ -308,6 +339,17 @@ void QtOutputFormatter::updateProjectFileList()
d->projectFinder.setProjectFiles(d->project->files(Project::SourceFiles)); d->projectFinder.setProjectFiles(d->project->files(Project::SourceFiles));
} }
// QtOutputFormatterFactory
QtOutputFormatterFactory::QtOutputFormatterFactory()
{
setFormatterCreator([](Target *t) -> OutputFormatter * {
BaseQtVersion *qt = QtKitAspect::qtVersion(t->kit());
return qt ? new QtOutputFormatter(t) : nullptr;
});
}
} // namespace Internal
} // namespace QtSupport } // namespace QtSupport
// Unit tests: // Unit tests:

View File

@@ -25,9 +25,7 @@
#pragma once #pragma once
#include "qtsupport_global.h" #include <projectexplorer/runcontrol.h>
#include <utils/outputformatter.h>
// "file" or "qrc", colon, optional '//', '/' and further characters // "file" or "qrc", colon, optional '//', '/' and further characters
#define QT_QML_URL_REGEXP "(?:file|qrc):(?://)?/.+?" #define QT_QML_URL_REGEXP "(?:file|qrc):(?://)?/.+?"
@@ -36,50 +34,14 @@
#define QT_TEST_FAIL_UNIX_REGEXP "^ Loc: \\[((?<file>.+)(?|\\((?<line>\\d+)\\)|:(?<line>\\d+)))\\]$" #define QT_TEST_FAIL_UNIX_REGEXP "^ Loc: \\[((?<file>.+)(?|\\((?<line>\\d+)\\)|:(?<line>\\d+)))\\]$"
#define QT_TEST_FAIL_WIN_REGEXP "^((?<file>.+)\\((?<line>\\d+)\\)) : failure location\\s*$" #define QT_TEST_FAIL_WIN_REGEXP "^((?<file>.+)\\((?<line>\\d+)\\)) : failure location\\s*$"
namespace ProjectExplorer { class Project; }
namespace QtSupport { namespace QtSupport {
struct LinkResult
{
int start = -1;
int end = -1;
QString href;
};
namespace Internal { namespace Internal {
class QtOutputFormatterPrivate;
class QtSupportPlugin;
}
class QTSUPPORT_EXPORT QtOutputFormatter : public Utils::OutputFormatter class QtOutputFormatterFactory : public ProjectExplorer::OutputFormatterFactory
{ {
Q_OBJECT
public: public:
explicit QtOutputFormatter(ProjectExplorer::Project *project); QtOutputFormatterFactory();
~QtOutputFormatter() override;
void appendMessage(const QString &text, Utils::OutputFormat format) override;
void handleLink(const QString &href) override;
void setPlainTextEdit(QPlainTextEdit *plainText) override;
protected:
void clearLastLine() override;
virtual void openEditor(const QString &fileName, int line, int column = -1);
private:
void updateProjectFileList();
LinkResult matchLine(const QString &line) const;
void appendMessagePart(const QString &txt, const QTextCharFormat &fmt);
void appendLine(const LinkResult &lr, const QString &line, Utils::OutputFormat format);
void appendLine(const LinkResult &lr, const QString &line, const QTextCharFormat &format);
void appendMessage(const QString &text, const QTextCharFormat &format) override;
Internal::QtOutputFormatterPrivate *d;
// for testing
friend class Internal::QtSupportPlugin;
}; };
} // namespace Internal
} // namespace QtSupport } // namespace QtSupport

View File

@@ -31,6 +31,7 @@
#include "gettingstartedwelcomepage.h" #include "gettingstartedwelcomepage.h"
#include "qtkitinformation.h" #include "qtkitinformation.h"
#include "qtoptionspage.h" #include "qtoptionspage.h"
#include "qtoutputformatter.h"
#include "qtsupportconstants.h" #include "qtsupportconstants.h"
#include "qtversionfactory.h" #include "qtversionfactory.h"
#include "qtversionmanager.h" #include "qtversionmanager.h"
@@ -85,6 +86,8 @@ public:
ExamplesWelcomePage tutorialPage{false}; ExamplesWelcomePage tutorialPage{false};
QtKitAspect qtKiAspect; QtKitAspect qtKiAspect;
QtOutputFormatterFactory qtOutputFormatterFactory;
}; };
QtSupportPlugin::~QtSupportPlugin() QtSupportPlugin::~QtSupportPlugin()

View File

@@ -33,8 +33,6 @@
#include <projectexplorer/runcontrol.h> #include <projectexplorer/runcontrol.h>
#include <projectexplorer/target.h> #include <projectexplorer/target.h>
#include <qtsupport/qtoutputformatter.h>
#include <utils/hostosinfo.h> #include <utils/hostosinfo.h>
using namespace ProjectExplorer; using namespace ProjectExplorer;
@@ -68,7 +66,6 @@ RemoteLinuxCustomRunConfiguration::RemoteLinuxCustomRunConfiguration(Target *tar
addAspect<X11ForwardingAspect>(); addAspect<X11ForwardingAspect>();
setDefaultDisplayName(runConfigDefaultDisplayName()); setDefaultDisplayName(runConfigDefaultDisplayName());
setOutputFormatter<QtSupport::QtOutputFormatter>();
} }
bool RemoteLinuxCustomRunConfiguration::isConfigured() const bool RemoteLinuxCustomRunConfiguration::isConfigured() const

View File

@@ -37,8 +37,6 @@
#include <projectexplorer/runcontrol.h> #include <projectexplorer/runcontrol.h>
#include <projectexplorer/target.h> #include <projectexplorer/target.h>
#include <qtsupport/qtoutputformatter.h>
#include <utils/hostosinfo.h> #include <utils/hostosinfo.h>
using namespace ProjectExplorer; using namespace ProjectExplorer;
@@ -70,8 +68,6 @@ RemoteLinuxRunConfiguration::RemoteLinuxRunConfiguration(Target *target, Core::I
if (HostOsInfo::isAnyUnixHost()) if (HostOsInfo::isAnyUnixHost())
addAspect<X11ForwardingAspect>(); addAspect<X11ForwardingAspect>();
setOutputFormatter<QtSupport::QtOutputFormatter>();
connect(target, &Target::deploymentDataChanged, connect(target, &Target::deploymentDataChanged,
this, &RemoteLinuxRunConfiguration::updateTargetInformation); this, &RemoteLinuxRunConfiguration::updateTargetInformation);
connect(target, &Target::applicationTargetsChanged, connect(target, &Target::applicationTargetsChanged,