summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/plugins/projectexplorer/CMakeLists.txt1
-rw-r--r--src/plugins/projectexplorer/buildconfiguration.cpp43
-rw-r--r--src/plugins/projectexplorer/buildconfiguration.h3
-rw-r--r--src/plugins/projectexplorer/buildstep.cpp6
-rw-r--r--src/plugins/projectexplorer/customparser.cpp221
-rw-r--r--src/plugins/projectexplorer/customparser.h50
-rw-r--r--src/plugins/projectexplorer/customparserconfigdialog.cpp2
-rw-r--r--src/plugins/projectexplorer/customparserconfigdialog.h2
-rw-r--r--src/plugins/projectexplorer/customparserssettingspage.cpp144
-rw-r--r--src/plugins/projectexplorer/customparserssettingspage.h40
-rw-r--r--src/plugins/projectexplorer/customtoolchain.cpp143
-rw-r--r--src/plugins/projectexplorer/customtoolchain.h10
-rw-r--r--src/plugins/projectexplorer/projectexplorer.cpp35
-rw-r--r--src/plugins/projectexplorer/projectexplorer.h5
-rw-r--r--src/plugins/projectexplorer/projectexplorer.pro2
-rw-r--r--src/plugins/projectexplorer/projectexplorer.qbs1
-rw-r--r--src/plugins/projectexplorer/projectexplorerconstants.h1
-rw-r--r--src/plugins/projectexplorer/runconfiguration.h2
-rw-r--r--src/plugins/projectexplorer/runcontrol.cpp18
19 files changed, 617 insertions, 112 deletions
diff --git a/src/plugins/projectexplorer/CMakeLists.txt b/src/plugins/projectexplorer/CMakeLists.txt
index 35ed62afc6..81559e66f8 100644
--- a/src/plugins/projectexplorer/CMakeLists.txt
+++ b/src/plugins/projectexplorer/CMakeLists.txt
@@ -35,6 +35,7 @@ add_qtc_plugin(ProjectExplorer
customexecutablerunconfiguration.cpp customexecutablerunconfiguration.h
customparser.cpp customparser.h
customparserconfigdialog.cpp customparserconfigdialog.h customparserconfigdialog.ui
+ customparserssettingspage.cpp customparserssettingspage.h
customtoolchain.cpp customtoolchain.h
customwizard/customwizard.cpp customwizard/customwizard.h
customwizard/customwizardpage.cpp customwizard/customwizardpage.h
diff --git a/src/plugins/projectexplorer/buildconfiguration.cpp b/src/plugins/projectexplorer/buildconfiguration.cpp
index 09a7f822a9..de8ac4dbe4 100644
--- a/src/plugins/projectexplorer/buildconfiguration.cpp
+++ b/src/plugins/projectexplorer/buildconfiguration.cpp
@@ -30,6 +30,7 @@
#include "buildsteplist.h"
#include "buildstepspage.h"
#include "buildsystem.h"
+#include "customparser.h"
#include "environmentwidget.h"
#include "kit.h"
#include "kitinformation.h"
@@ -65,13 +66,14 @@ const char BUILD_STEP_LIST_COUNT[] = "ProjectExplorer.BuildConfiguration.BuildSt
const char BUILD_STEP_LIST_PREFIX[] = "ProjectExplorer.BuildConfiguration.BuildStepList.";
const char CLEAR_SYSTEM_ENVIRONMENT_KEY[] = "ProjectExplorer.BuildConfiguration.ClearSystemEnvironment";
const char USER_ENVIRONMENT_CHANGES_KEY[] = "ProjectExplorer.BuildConfiguration.UserEnvironmentChanges";
+const char CUSTOM_PARSERS_KEY[] = "ProjectExplorer.BuildConfiguration.CustomParsers";
namespace ProjectExplorer {
namespace Internal {
class BuildEnvironmentWidget : public NamedWidget
{
- Q_DECLARE_TR_FUNCTIONS(ProjectExplorer::BuildEnvironmentWidget)
+ Q_DECLARE_TR_FUNCTIONS(ProjectExplorer::Internal::BuildEnvironmentWidget)
public:
explicit BuildEnvironmentWidget(BuildConfiguration *bc)
@@ -107,6 +109,25 @@ public:
}
};
+class CustomParsersBuildWidget : public NamedWidget
+{
+ Q_DECLARE_TR_FUNCTIONS(ProjectExplorer::Internal::CustomParsersBuildWidget)
+public:
+ CustomParsersBuildWidget(BuildConfiguration *bc) : NamedWidget(tr("Custom Output Parsers"))
+ {
+ const auto selectionWidget = new CustomParsersSelectionWidget(this);
+ const auto layout = new QVBoxLayout(this);
+ layout->setContentsMargins(0, 0, 0, 0);
+ layout->addWidget(selectionWidget);
+
+ connect(selectionWidget, &CustomParsersSelectionWidget::selectionChanged,
+ [selectionWidget, bc] {
+ bc->setCustomParsers(selectionWidget->selectedParsers());
+ });
+ selectionWidget->setSelectedParsers(bc->customParsers());
+ }
+};
+
class BuildConfigurationPrivate
{
@@ -128,6 +149,7 @@ public:
QList<Core::Id> m_initialBuildSteps;
QList<Core::Id> m_initialCleanSteps;
Utils::MacroExpander m_macroExpander;
+ QList<Core::Id> m_customParsers;
// FIXME: Remove.
BuildConfiguration::BuildType m_initialBuildType = BuildConfiguration::Unknown;
@@ -294,7 +316,10 @@ NamedWidget *BuildConfiguration::createConfigWidget()
QList<NamedWidget *> BuildConfiguration::createSubConfigWidgets()
{
- return {new Internal::BuildEnvironmentWidget(this)};
+ return {
+ new Internal::BuildEnvironmentWidget(this),
+ new Internal::CustomParsersBuildWidget(this)
+ };
}
BuildSystem *BuildConfiguration::buildSystem() const
@@ -334,6 +359,8 @@ QVariantMap BuildConfiguration::toMap() const
map.insert(QLatin1String(BUILD_STEP_LIST_PREFIX) + QString::number(0), d->m_buildSteps.toMap());
map.insert(QLatin1String(BUILD_STEP_LIST_PREFIX) + QString::number(1), d->m_cleanSteps.toMap());
+ map.insert(CUSTOM_PARSERS_KEY, transform(d->m_customParsers,&Core::Id::toSetting));
+
return map;
}
@@ -366,6 +393,8 @@ bool BuildConfiguration::fromMap(const QVariantMap &map)
}
}
+ d->m_customParsers = transform(map.value(CUSTOM_PARSERS_KEY).toList(), &Core::Id::fromSetting);
+
return ProjectConfiguration::fromMap(map);
}
@@ -449,6 +478,16 @@ void BuildConfiguration::addToEnvironment(Environment &env) const
Q_UNUSED(env)
}
+const QList<Core::Id> BuildConfiguration::customParsers() const
+{
+ return d->m_customParsers;
+}
+
+void BuildConfiguration::setCustomParsers(const QList<Core::Id> &parsers)
+{
+ d->m_customParsers = parsers;
+}
+
bool BuildConfiguration::useSystemEnvironment() const
{
return !d->m_clearSystemEnvironment;
diff --git a/src/plugins/projectexplorer/buildconfiguration.h b/src/plugins/projectexplorer/buildconfiguration.h
index 2641ea3597..5e7bf1d03a 100644
--- a/src/plugins/projectexplorer/buildconfiguration.h
+++ b/src/plugins/projectexplorer/buildconfiguration.h
@@ -79,6 +79,9 @@ public:
virtual void addToEnvironment(Utils::Environment &env) const;
+ const QList<Core::Id> customParsers() const;
+ void setCustomParsers(const QList<Core::Id> &parsers);
+
BuildStepList *buildSteps() const;
BuildStepList *cleanSteps() const;
diff --git a/src/plugins/projectexplorer/buildstep.cpp b/src/plugins/projectexplorer/buildstep.cpp
index ca64125d3a..4a56d805c4 100644
--- a/src/plugins/projectexplorer/buildstep.cpp
+++ b/src/plugins/projectexplorer/buildstep.cpp
@@ -27,9 +27,11 @@
#include "buildconfiguration.h"
#include "buildsteplist.h"
+#include "customparser.h"
#include "deployconfiguration.h"
#include "kitinformation.h"
#include "project.h"
+#include "projectexplorer.h"
#include "projectexplorerconstants.h"
#include "target.h"
@@ -263,6 +265,10 @@ QString BuildStep::fallbackWorkingDirectory() const
void BuildStep::setupOutputFormatter(OutputFormatter *formatter)
{
+ for (const Core::Id id : buildConfiguration()->customParsers()) {
+ if (Internal::CustomParser * const parser = Internal::CustomParser::createFromId(id))
+ formatter->addLineParser(parser);
+ }
Utils::FileInProjectFinder fileFinder;
fileFinder.setProjectDirectory(project()->projectDirectory());
fileFinder.setProjectFiles(project()->files(Project::AllFiles));
diff --git a/src/plugins/projectexplorer/customparser.cpp b/src/plugins/projectexplorer/customparser.cpp
index dfd588fe20..7d6770c996 100644
--- a/src/plugins/projectexplorer/customparser.cpp
+++ b/src/plugins/projectexplorer/customparser.cpp
@@ -24,16 +24,41 @@
****************************************************************************/
#include "customparser.h"
-#include "task.h"
+
#include "projectexplorerconstants.h"
-#include "buildmanager.h"
+#include "task.h"
+#include <coreplugin/icore.h>
#include <utils/qtcassert.h>
+#include <QCheckBox>
+#include <QLabel>
+#include <QPair>
#include <QString>
+#include <QVBoxLayout>
+
+#ifdef WITH_TESTS
+# include <QTest>
+
+# include "projectexplorer.h"
+# include "outputparser_test.h"
+#endif
using namespace Utils;
-using namespace ProjectExplorer;
+
+const char idKey[] = "Id";
+const char nameKey[] = "Name";
+const char errorKey[] = "Error";
+const char warningKey[] = "Warning";
+const char patternKey[] = "Pattern";
+const char lineNumberCapKey[] = "LineNumberCap";
+const char fileNameCapKey[] = "FileNameCap";
+const char messageCapKey[] = "MessageCap";
+const char channelKey[] = "Channel";
+const char exampleKey[] = "Example";
+
+namespace ProjectExplorer {
+namespace Internal {
bool CustomParserExpression::operator ==(const CustomParserExpression &other) const
{
@@ -47,7 +72,7 @@ QString CustomParserExpression::pattern() const
return m_regExp.pattern();
}
-void ProjectExplorer::CustomParserExpression::setPattern(const QString &pattern)
+void CustomParserExpression::setPattern(const QString &pattern)
{
m_regExp.setPattern(pattern);
QTC_CHECK(m_regExp.isValid());
@@ -86,6 +111,31 @@ void CustomParserExpression::setMessageCap(int messageCap)
m_messageCap = messageCap;
}
+QVariantMap CustomParserExpression::toMap() const
+{
+ QVariantMap map;
+ map.insert(patternKey, pattern());
+ map.insert(messageCapKey, messageCap());
+ map.insert(fileNameCapKey, fileNameCap());
+ map.insert(lineNumberCapKey, lineNumberCap());
+ map.insert(exampleKey, example());
+ map.insert(channelKey, channel());
+ return map;
+}
+
+void CustomParserExpression::fromMap(const QVariantMap &map)
+{
+ setPattern(map.value(patternKey).toString());
+ setMessageCap(map.value(messageCapKey).toInt());
+ setFileNameCap(map.value(fileNameCapKey).toInt());
+ setLineNumberCap(map.value(lineNumberCapKey).toInt());
+ setExample(map.value(exampleKey).toString());
+ int channel = map.value(channelKey).toInt();
+ if (channel == ParseNoChannel || channel > ParseBothChannels)
+ channel = ParseStdErrChannel;
+ setChannel(static_cast<CustomParserChannel>(channel));
+}
+
int CustomParserExpression::lineNumberCap() const
{
return m_lineNumberCap;
@@ -108,7 +158,26 @@ void CustomParserExpression::setFileNameCap(int fileNameCap)
bool CustomParserSettings::operator ==(const CustomParserSettings &other) const
{
- return error == other.error && warning == other.warning;
+ return id == other.id && displayName == other.displayName
+ && error == other.error && warning == other.warning;
+}
+
+QVariantMap CustomParserSettings::toMap() const
+{
+ QVariantMap map;
+ map.insert(idKey, id.toSetting());
+ map.insert(nameKey, displayName);
+ map.insert(errorKey, error.toMap());
+ map.insert(warningKey, warning.toMap());
+ return map;
+}
+
+void CustomParserSettings::fromMap(const QVariantMap &map)
+{
+ id = Core::Id::fromSetting(map.value(idKey));
+ displayName = map.value(nameKey).toString();
+ error.fromMap(map.value(errorKey).toMap());
+ warning.fromMap(map.value(warningKey).toMap());
}
CustomParser::CustomParser(const CustomParserSettings &settings)
@@ -124,6 +193,15 @@ void CustomParser::setSettings(const CustomParserSettings &settings)
m_warning = settings.warning;
}
+CustomParser *CustomParser::createFromId(Core::Id id)
+{
+ const Internal::CustomParserSettings parser = findOrDefault(ProjectExplorerPlugin::customParsers(),
+ [id](const Internal::CustomParserSettings &p) { return p.id == id; });
+ if (parser.id.isValid())
+ return new CustomParser(parser);
+ return nullptr;
+}
+
Core::Id CustomParser::id()
{
return Core::Id("ProjectExplorer.OutputParser.Custom");
@@ -162,7 +240,7 @@ OutputLineParser::Result CustomParser::hasMatch(
addLinkSpecForAbsoluteFilePath(linkSpecs, fileName, lineNumber, match,
expression.fileNameCap());
scheduleTask(CompileTask(taskType, message, fileName, lineNumber), 1);
- return Status::Done;
+ return {Status::Done, linkSpecs};
}
OutputLineParser::Result CustomParser::parseLine(
@@ -177,13 +255,133 @@ OutputLineParser::Result CustomParser::parseLine(
return hasMatch(line, channel, m_warning, Task::Warning);
}
+namespace {
+class SelectionWidget : public QWidget
+{
+ Q_OBJECT
+public:
+ SelectionWidget(QWidget *parent = nullptr) : QWidget(parent)
+ {
+ const auto layout = new QVBoxLayout(this);
+ const auto explanatoryLabel = new QLabel(tr(
+ "Custom output parsers scan command line output for user-provided error patterns<br>"
+ "in order to create entries in the issues pane.<br>"
+ "The parsers can be configured <a href=\"dummy\">here</a>."));
+ layout->addWidget(explanatoryLabel);
+ connect(explanatoryLabel, &QLabel::linkActivated, [] {
+ Core::ICore::showOptionsDialog(Constants::CUSTOM_PARSERS_SETTINGS_PAGE_ID);
+ });
+ updateUi();
+ connect(ProjectExplorerPlugin::instance(), &ProjectExplorerPlugin::customParsersChanged,
+ this, &SelectionWidget::updateUi);
+ }
+
+ void setSelectedParsers(const QList<Core::Id> &parsers)
+ {
+ for (const auto &p : qAsConst(parserCheckBoxes))
+ p.first->setChecked(parsers.contains(p.second));
+ emit selectionChanged();
+ }
+
+ QList<Core::Id> selectedParsers() const
+ {
+ QList<Core::Id> parsers;
+ for (const auto &p : qAsConst(parserCheckBoxes)) {
+ if (p.first->isChecked())
+ parsers << p.second;
+ }
+ return parsers;
+ }
+
+signals:
+ void selectionChanged();
+
+private:
+ void updateUi()
+ {
+ const auto layout = qobject_cast<QVBoxLayout *>(this->layout());
+ QTC_ASSERT(layout, return);
+ const QList<Core::Id> parsers = selectedParsers();
+ for (const auto &p : qAsConst(parserCheckBoxes))
+ delete p.first;
+ parserCheckBoxes.clear();
+ for (const CustomParserSettings &s : ProjectExplorerPlugin::customParsers()) {
+ const auto checkBox = new QCheckBox(s.displayName, this);
+ connect(checkBox, &QCheckBox::stateChanged,
+ this, &SelectionWidget::selectionChanged);
+ parserCheckBoxes << qMakePair(checkBox, s.id);
+ layout->addWidget(checkBox);
+ }
+ setSelectedParsers(parsers);
+ }
+
+ QList<QPair<QCheckBox *, Core::Id>> parserCheckBoxes;
+};
+} // anonymous namespace
+
+CustomParsersSelectionWidget::CustomParsersSelectionWidget(QWidget *parent) : DetailsWidget(parent)
+{
+ const auto widget = new SelectionWidget(this);
+ connect(widget, &SelectionWidget::selectionChanged, [this] {
+ updateSummary();
+ emit selectionChanged();
+ });
+ setWidget(widget);
+ updateSummary();
+}
+
+void CustomParsersSelectionWidget::setSelectedParsers(const QList<Core::Id> &parsers)
+{
+ qobject_cast<SelectionWidget *>(widget())->setSelectedParsers(parsers);
+}
+
+QList<Core::Id> CustomParsersSelectionWidget::selectedParsers() const
+{
+ return qobject_cast<SelectionWidget *>(widget())->selectedParsers();
+}
+
+void CustomParsersSelectionWidget::updateSummary()
+{
+ const QList<Core::Id> parsers
+ = qobject_cast<SelectionWidget *>(widget())->selectedParsers();
+ if (parsers.isEmpty())
+ setSummaryText(tr("There are no custom parsers active"));
+ else
+ setSummaryText(tr("There are %n custom parsers active", nullptr, parsers.count()));
+}
+
+CustomParsersAspect::CustomParsersAspect(Target *target)
+{
+ Q_UNUSED(target)
+ setId("CustomOutputParsers");
+ setSettingsKey("CustomOutputParsers");
+ setDisplayName(tr("Custom Output Parsers"));
+ setConfigWidgetCreator([this] {
+ const auto widget = new CustomParsersSelectionWidget;
+ widget->setSelectedParsers(m_parsers);
+ connect(widget, &CustomParsersSelectionWidget::selectionChanged,
+ this, [this, widget] { m_parsers = widget->selectedParsers(); });
+ return widget;
+ });
+}
+
+void CustomParsersAspect::fromMap(const QVariantMap &map)
+{
+ m_parsers = transform(map.value(settingsKey()).toList(), &Core::Id::fromSetting);
+}
+
+void CustomParsersAspect::toMap(QVariantMap &map) const
+{
+ map.insert(settingsKey(), transform(m_parsers, &Core::Id::toSetting));
+}
+
+} // namespace Internal
+
// Unit tests:
#ifdef WITH_TESTS
-# include <QTest>
-# include "projectexplorer.h"
-# include "outputparser_test.h"
+using namespace Internal;
void ProjectExplorerPlugin::testCustomOutputParsers_data()
{
@@ -478,4 +676,9 @@ void ProjectExplorerPlugin::testCustomOutputParsers()
tasks, childStdOutLines, childStdErrLines,
outputLines);
}
+
+} // namespace ProjectExplorer
+
#endif
+
+#include <customparser.moc>
diff --git a/src/plugins/projectexplorer/customparser.h b/src/plugins/projectexplorer/customparser.h
index 00069f117f..48a88096d2 100644
--- a/src/plugins/projectexplorer/customparser.h
+++ b/src/plugins/projectexplorer/customparser.h
@@ -26,12 +26,18 @@
#pragma once
#include "ioutputparser.h"
+#include "projectconfiguration.h"
#include <projectexplorer/task.h>
+#include <utils/detailswidget.h>
#include <QRegularExpression>
+#include <QVariantMap>
namespace ProjectExplorer {
+class Target;
+
+namespace Internal {
class CustomParserExpression
{
@@ -62,6 +68,9 @@ public:
int messageCap() const;
void setMessageCap(int messageCap);
+ QVariantMap toMap() const;
+ void fromMap(const QVariantMap &map);
+
private:
QRegularExpression m_regExp;
CustomParserExpression::CustomParserChannel m_channel = ParseBothChannels;
@@ -77,6 +86,11 @@ public:
bool operator ==(const CustomParserSettings &other) const;
bool operator !=(const CustomParserSettings &other) const { return !operator==(other); }
+ QVariantMap toMap() const;
+ void fromMap(const QVariantMap &map);
+
+ Core::Id id;
+ QString displayName;
CustomParserExpression error;
CustomParserExpression warning;
};
@@ -88,6 +102,7 @@ public:
void setSettings(const CustomParserSettings &settings);
+ static CustomParser *createFromId(Core::Id id);
static Core::Id id();
private:
@@ -101,6 +116,39 @@ private:
CustomParserExpression m_warning;
};
+class CustomParsersSelectionWidget : public Utils::DetailsWidget
+{
+ Q_OBJECT
+public:
+ CustomParsersSelectionWidget(QWidget *parent = nullptr);
+
+ void setSelectedParsers(const QList<Core::Id> &parsers);
+ QList<Core::Id> selectedParsers() const;
+
+signals:
+ void selectionChanged();
+
+private:
+ void updateSummary();
+};
+
+class CustomParsersAspect : public ProjectConfigurationAspect
+{
+ Q_OBJECT
+public:
+ CustomParsersAspect(Target *target);
+
+ void setParsers(const QList<Core::Id> &parsers) { m_parsers = parsers; }
+ const QList<Core::Id> parsers() const { return m_parsers; }
+
+private:
+ void fromMap(const QVariantMap &map) override;
+ void toMap(QVariantMap &map) const override;
+
+ QList<Core::Id> m_parsers;
+};
+
+} // namespace Internal
} // namespace ProjectExplorer
-Q_DECLARE_METATYPE(ProjectExplorer::CustomParserExpression::CustomParserChannel);
+Q_DECLARE_METATYPE(ProjectExplorer::Internal::CustomParserExpression::CustomParserChannel);
diff --git a/src/plugins/projectexplorer/customparserconfigdialog.cpp b/src/plugins/projectexplorer/customparserconfigdialog.cpp
index 7e6bb28ee2..5584ae480a 100644
--- a/src/plugins/projectexplorer/customparserconfigdialog.cpp
+++ b/src/plugins/projectexplorer/customparserconfigdialog.cpp
@@ -35,7 +35,7 @@
namespace ProjectExplorer {
namespace Internal {
-CustomParserConfigDialog::CustomParserConfigDialog(QDialog *parent) :
+CustomParserConfigDialog::CustomParserConfigDialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::CustomParserConfigDialog)
{
diff --git a/src/plugins/projectexplorer/customparserconfigdialog.h b/src/plugins/projectexplorer/customparserconfigdialog.h
index c34dbfbf4e..fc787a72b6 100644
--- a/src/plugins/projectexplorer/customparserconfigdialog.h
+++ b/src/plugins/projectexplorer/customparserconfigdialog.h
@@ -43,7 +43,7 @@ class CustomParserConfigDialog : public QDialog
Q_OBJECT
public:
- explicit CustomParserConfigDialog(QDialog *parent = nullptr);
+ explicit CustomParserConfigDialog(QWidget *parent = nullptr);
~CustomParserConfigDialog() override;
void setExampleSettings();
diff --git a/src/plugins/projectexplorer/customparserssettingspage.cpp b/src/plugins/projectexplorer/customparserssettingspage.cpp
new file mode 100644
index 0000000000..78163555db
--- /dev/null
+++ b/src/plugins/projectexplorer/customparserssettingspage.cpp
@@ -0,0 +1,144 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#include "customparserssettingspage.h"
+
+#include "customparser.h"
+#include "customparserconfigdialog.h"
+#include "projectexplorer.h"
+#include "projectexplorerconstants.h"
+
+#include <utils/algorithm.h>
+#include <utils/qtcassert.h>
+
+#include <QHBoxLayout>
+#include <QList>
+#include <QListWidget>
+#include <QPushButton>
+#include <QUuid>
+#include <QVBoxLayout>
+
+namespace ProjectExplorer {
+namespace Internal {
+
+class CustomParsersSettingsWidget final : public Core::IOptionsPageWidget
+{
+ Q_DECLARE_TR_FUNCTIONS(ProjectExplorer::Internal::CustomParsersSettingsPage)
+
+public:
+ CustomParsersSettingsWidget()
+ {
+ m_customParsers = ProjectExplorerPlugin::customParsers();
+ resetListView();
+
+ const auto mainLayout = new QVBoxLayout(this);
+ const auto widgetLayout = new QHBoxLayout;
+ mainLayout->addLayout(widgetLayout);
+ widgetLayout->addWidget(&m_parserListView);
+ const auto buttonLayout = new QVBoxLayout;
+ widgetLayout->addLayout(buttonLayout);
+ const auto addButton = new QPushButton(tr("Add..."));
+ const auto removeButton = new QPushButton(tr("Remove"));
+ const auto editButton = new QPushButton("Edit...");
+ buttonLayout->addWidget(addButton);
+ buttonLayout->addWidget(removeButton);
+ buttonLayout->addWidget(editButton);
+ buttonLayout->addStretch(1);
+
+ connect(addButton, &QPushButton::clicked, [this] {
+ CustomParserConfigDialog dlg(this);
+ dlg.setSettings(CustomParserSettings());
+ if (dlg.exec() != QDialog::Accepted)
+ return;
+ CustomParserSettings newParser = dlg.settings();
+ newParser.id = Core::Id::fromString(QUuid::createUuid().toString());
+ newParser.displayName = tr("New Parser");
+ m_customParsers << newParser;
+ resetListView();
+ });
+ connect(removeButton, &QPushButton::clicked, [this] {
+ const QList<QListWidgetItem *> sel = m_parserListView.selectedItems();
+ QTC_ASSERT(sel.size() == 1, return);
+ m_customParsers.removeAt(m_parserListView.row(sel.first()));
+ delete sel.first();
+ });
+ connect(editButton, &QPushButton::clicked, [this] {
+ const QList<QListWidgetItem *> sel = m_parserListView.selectedItems();
+ QTC_ASSERT(sel.size() == 1, return);
+ CustomParserSettings &s = m_customParsers[m_parserListView.row(sel.first())];
+ CustomParserConfigDialog dlg(this);
+ dlg.setSettings(s);
+ if (dlg.exec() != QDialog::Accepted)
+ return;
+ s.error = dlg.settings().error;
+ s.warning = dlg.settings().warning;
+ });
+
+ connect(&m_parserListView, &QListWidget::itemChanged, [this](QListWidgetItem *item) {
+ m_customParsers[m_parserListView.row(item)].displayName = item->text();
+ resetListView();
+ });
+
+ const auto updateButtons = [this, removeButton, editButton] {
+ const bool enable = !m_parserListView.selectedItems().isEmpty();
+ removeButton->setEnabled(enable);
+ editButton->setEnabled(enable);
+ };
+ updateButtons();
+ connect(m_parserListView.selectionModel(), &QItemSelectionModel::selectionChanged,
+ updateButtons);
+ }
+
+private:
+ void apply() override { ProjectExplorerPlugin::setCustomParsers(m_customParsers); }
+
+ void resetListView()
+ {
+ m_parserListView.clear();
+ Utils::sort(m_customParsers,
+ [](const CustomParserSettings &s1, const CustomParserSettings &s2) {
+ return s1.displayName < s2.displayName;
+ });
+ for (const CustomParserSettings &s : qAsConst(m_customParsers)) {
+ const auto item = new QListWidgetItem(s.displayName);
+ item->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEditable);
+ m_parserListView.addItem(item);
+ }
+ }
+
+ QListWidget m_parserListView;
+ QList<CustomParserSettings> m_customParsers;
+};
+
+CustomParsersSettingsPage::CustomParsersSettingsPage()
+{
+ setId(Constants::CUSTOM_PARSERS_SETTINGS_PAGE_ID);
+ setDisplayName(CustomParsersSettingsWidget::tr("Custom Output Parsers"));
+ setCategory(Constants::BUILD_AND_RUN_SETTINGS_CATEGORY);
+ setWidgetCreator([] { return new CustomParsersSettingsWidget; });
+}
+
+} // namespace Internal
+} // namespace ProjectExplorer
diff --git a/src/plugins/projectexplorer/customparserssettingspage.h b/src/plugins/projectexplorer/customparserssettingspage.h
new file mode 100644
index 0000000000..7790d947bc
--- /dev/null
+++ b/src/plugins/projectexplorer/customparserssettingspage.h
@@ -0,0 +1,40 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#pragma once
+
+#include <coreplugin/dialogs/ioptionspage.h>
+
+namespace ProjectExplorer {
+namespace Internal {
+
+class CustomParsersSettingsPage final : public Core::IOptionsPage
+{
+public:
+ CustomParsersSettingsPage();
+};
+
+} // namespace Internal
+} // namespace ProjectExplorer
diff --git a/src/plugins/projectexplorer/customtoolchain.cpp b/src/plugins/projectexplorer/customtoolchain.cpp
index abe682a48e..2bada42658 100644
--- a/src/plugins/projectexplorer/customtoolchain.cpp
+++ b/src/plugins/projectexplorer/customtoolchain.cpp
@@ -30,7 +30,7 @@
#include "linuxiccparser.h"
#include "msvcparser.h"
#include "customparser.h"
-#include "customparserconfigdialog.h"
+#include "projectexplorer.h"
#include "projectexplorerconstants.h"
#include "projectmacro.h"
#include "toolchainmanager.h"
@@ -41,12 +41,12 @@
#include <utils/pathchooser.h>
#include <utils/qtcassert.h>
+#include <QComboBox>
#include <QFormLayout>
-#include <QPlainTextEdit>
-#include <QLineEdit>
#include <QHBoxLayout>
-#include <QComboBox>
-#include <QPushButton>
+#include <QLineEdit>
+#include <QPlainTextEdit>
+#include <QUuid>
using namespace Utils;
@@ -64,18 +64,6 @@ static const char headerPathsKeyC[] = "ProjectExplorer.CustomToolChain.HeaderPat
static const char cxx11FlagsKeyC[] = "ProjectExplorer.CustomToolChain.Cxx11Flags";
static const char mkspecsKeyC[] = "ProjectExplorer.CustomToolChain.Mkspecs";
static const char outputParserKeyC[] = "ProjectExplorer.CustomToolChain.OutputParser";
-static const char errorPatternKeyC[] = "ProjectExplorer.CustomToolChain.ErrorPattern";
-static const char errorLineNumberCapKeyC[] = "ProjectExplorer.CustomToolChain.ErrorLineNumberCap";
-static const char errorFileNameCapKeyC[] = "ProjectExplorer.CustomToolChain.ErrorFileNameCap";
-static const char errorMessageCapKeyC[] = "ProjectExplorer.CustomToolChain.ErrorMessageCap";
-static const char errorChannelKeyC[] = "ProjectExplorer.CustomToolChain.ErrorChannel";
-static const char errorExampleKeyC[] = "ProjectExplorer.CustomToolChain.ErrorExample";
-static const char warningPatternKeyC[] = "ProjectExplorer.CustomToolChain.WarningPattern";
-static const char warningLineNumberCapKeyC[] = "ProjectExplorer.CustomToolChain.WarningLineNumberCap";
-static const char warningFileNameCapKeyC[] = "ProjectExplorer.CustomToolChain.WarningFileNameCap";
-static const char warningMessageCapKeyC[] = "ProjectExplorer.CustomToolChain.WarningMessageCap";
-static const char warningChannelKeyC[] = "ProjectExplorer.CustomToolChain.WarningChannel";
-static const char warningExampleKeyC[] = "ProjectExplorer.CustomToolChain.WarningExample";
// --------------------------------------------------------------------------
// CustomToolChain
@@ -88,6 +76,14 @@ CustomToolChain::CustomToolChain() :
setTypeDisplayName(tr("Custom"));
}
+Internal::CustomParserSettings CustomToolChain::customParserSettings() const
+{
+ return findOrDefault(ProjectExplorerPlugin::customParsers(),
+ [this](const Internal::CustomParserSettings &s) {
+ return s.id == outputParserId();
+ });
+}
+
Abi CustomToolChain::targetAbi() const
{
return m_targetAbi;
@@ -206,8 +202,7 @@ QList<Utils::OutputLineParser *> CustomToolChain::createOutputParsers() const
return LinuxIccParser::iccParserSuite();
if (m_outputParserId == MsvcParser::id())
return {new MsvcParser};
- if (m_outputParserId == CustomParser::id())
- return {new CustomParser(m_customParserSettings)};
+ return {new Internal::CustomParser(customParserSettings())};
return {};
}
@@ -293,18 +288,6 @@ QVariantMap CustomToolChain::toMap() const
data.insert(QLatin1String(cxx11FlagsKeyC), m_cxx11Flags);
data.insert(QLatin1String(mkspecsKeyC), mkspecs());
data.insert(QLatin1String(outputParserKeyC), m_outputParserId.toSetting());
- data.insert(QLatin1String(errorPatternKeyC), m_customParserSettings.error.pattern());
- data.insert(QLatin1String(errorFileNameCapKeyC), m_customParserSettings.error.fileNameCap());
- data.insert(QLatin1String(errorLineNumberCapKeyC), m_customParserSettings.error.lineNumberCap());
- data.insert(QLatin1String(errorMessageCapKeyC), m_customParserSettings.error.messageCap());
- data.insert(QLatin1String(errorChannelKeyC), m_customParserSettings.error.channel());
- data.insert(QLatin1String(errorExampleKeyC), m_customParserSettings.error.example());
- data.insert(QLatin1String(warningPatternKeyC), m_customParserSettings.warning.pattern());
- data.insert(QLatin1String(warningFileNameCapKeyC), m_customParserSettings.warning.fileNameCap());
- data.insert(QLatin1String(warningLineNumberCapKeyC), m_customParserSettings.warning.lineNumberCap());
- data.insert(QLatin1String(warningMessageCapKeyC), m_customParserSettings.warning.messageCap());
- data.insert(QLatin1String(warningChannelKeyC), m_customParserSettings.warning.channel());
- data.insert(QLatin1String(warningExampleKeyC), m_customParserSettings.warning.example());
return data;
}
@@ -323,20 +306,48 @@ bool CustomToolChain::fromMap(const QVariantMap &data)
m_cxx11Flags = data.value(QLatin1String(cxx11FlagsKeyC)).toStringList();
setMkspecs(data.value(QLatin1String(mkspecsKeyC)).toString());
setOutputParserId(Core::Id::fromSetting(data.value(QLatin1String(outputParserKeyC))));
- m_customParserSettings.error.setPattern(data.value(QLatin1String(errorPatternKeyC)).toString());
- m_customParserSettings.error.setFileNameCap(data.value(QLatin1String(errorFileNameCapKeyC)).toInt());
- m_customParserSettings.error.setLineNumberCap(data.value(QLatin1String(errorLineNumberCapKeyC)).toInt());
- m_customParserSettings.error.setMessageCap(data.value(QLatin1String(errorMessageCapKeyC)).toInt());
- m_customParserSettings.error.setChannel(
- static_cast<CustomParserExpression::CustomParserChannel>(data.value(QLatin1String(errorChannelKeyC)).toInt()));
- m_customParserSettings.error.setExample(data.value(QLatin1String(errorExampleKeyC)).toString());
- m_customParserSettings.warning.setPattern(data.value(QLatin1String(warningPatternKeyC)).toString());
- m_customParserSettings.warning.setFileNameCap(data.value(QLatin1String(warningFileNameCapKeyC)).toInt());
- m_customParserSettings.warning.setLineNumberCap(data.value(QLatin1String(warningLineNumberCapKeyC)).toInt());
- m_customParserSettings.warning.setMessageCap(data.value(QLatin1String(warningMessageCapKeyC)).toInt());
- m_customParserSettings.warning.setChannel(
- static_cast<CustomParserExpression::CustomParserChannel>(data.value(QLatin1String(warningChannelKeyC)).toInt()));
- m_customParserSettings.warning.setExample(data.value(QLatin1String(warningExampleKeyC)).toString());
+
+ // Restore Pre-4.13 settings.
+ if (outputParserId() == Internal::CustomParser::id()) {
+ Internal::CustomParserSettings customParserSettings;
+ customParserSettings.error.setPattern(
+ data.value("ProjectExplorer.CustomToolChain.ErrorPattern").toString());
+ customParserSettings.error.setFileNameCap(
+ data.value("ProjectExplorer.CustomToolChain.ErrorLineNumberCap").toInt());
+ customParserSettings.error.setLineNumberCap(
+ data.value("ProjectExplorer.CustomToolChain.ErrorFileNameCap").toInt());
+ customParserSettings.error.setMessageCap(
+ data.value("ProjectExplorer.CustomToolChain.ErrorMessageCap").toInt());
+ customParserSettings.error.setChannel(
+ static_cast<Internal::CustomParserExpression::CustomParserChannel>(
+ data.value("ProjectExplorer.CustomToolChain.ErrorChannel").toInt()));
+ customParserSettings.error.setExample(
+ data.value("ProjectExplorer.CustomToolChain.ErrorExample").toString());
+ customParserSettings.warning.setPattern(
+ data.value("ProjectExplorer.CustomToolChain.WarningPattern").toString());
+ customParserSettings.warning.setFileNameCap(
+ data.value("ProjectExplorer.CustomToolChain.WarningLineNumberCap").toInt());
+ customParserSettings.warning.setLineNumberCap(
+ data.value("ProjectExplorer.CustomToolChain.WarningFileNameCap").toInt());
+ customParserSettings.warning.setMessageCap(
+ data.value("ProjectExplorer.CustomToolChain.WarningMessageCap").toInt());
+ customParserSettings.warning.setChannel(
+ static_cast<Internal::CustomParserExpression::CustomParserChannel>(
+ data.value("ProjectExplorer.CustomToolChain.WarningChannel").toInt()));
+ customParserSettings.warning.setExample(
+ data.value("ProjectExplorer.CustomToolChain.WarningExample").toString());
+ if (!customParserSettings.error.pattern().isEmpty()
+ || !customParserSettings.error.pattern().isEmpty()) {
+ // Found custom parser in old settings, move to new place.
+ customParserSettings.id = Core::Id::fromString(QUuid::createUuid().toString());
+ setOutputParserId(customParserSettings.id);
+ customParserSettings.displayName = tr("Parser for toolchain %1").arg(displayName());
+ QList<Internal::CustomParserSettings> settings
+ = ProjectExplorerPlugin::customParsers();
+ settings << customParserSettings;
+ ProjectExplorerPlugin::setCustomParsers(settings);
+ }
+ }
return true;
}
@@ -367,19 +378,6 @@ void CustomToolChain::setOutputParserId(Core::Id parserId)
toolChainUpdated();
}
-CustomParserSettings CustomToolChain::customParserSettings() const
-{
- return m_customParserSettings;
-}
-
-void CustomToolChain::setCustomParserSettings(const CustomParserSettings &settings)
-{
- if (m_customParserSettings == settings)
- return;
- m_customParserSettings = settings;
- toolChainUpdated();
-}
-
QList<CustomToolChain::Parser> CustomToolChain::parsers()
{
QList<CustomToolChain::Parser> result;
@@ -387,8 +385,6 @@ QList<CustomToolChain::Parser> CustomToolChain::parsers()
result.append({ClangParser::id(), tr("Clang")});
result.append({LinuxIccParser::id(), tr("ICC")});
result.append({MsvcParser::id(), tr("MSVC")});
- result.append({CustomParser::id(), tr("Custom")});
-
return result;
}
@@ -472,14 +468,15 @@ CustomToolChainConfigWidget::CustomToolChainConfigWidget(CustomToolChain *tc) :
m_headerDetails(new TextEditDetailsWidget(m_headerPaths)),
m_cxx11Flags(new QLineEdit),
m_mkspecs(new QLineEdit),
- m_errorParserComboBox(new QComboBox),
- m_customParserSettingsButton(new QPushButton(tr("Custom Parser Settings...")))
+ m_errorParserComboBox(new QComboBox)
{
Q_ASSERT(tc);
const QList<CustomToolChain::Parser> parsers = CustomToolChain::parsers();
for (const auto &parser : parsers)
m_errorParserComboBox->addItem(parser.displayName, parser.parserId.toString());
+ for (const Internal::CustomParserSettings &s : ProjectExplorerPlugin::customParsers())
+ m_errorParserComboBox->addItem(s.displayName, s.id.toString());
auto parserLayoutWidget = new QWidget;
auto parserLayout = new QHBoxLayout(parserLayoutWidget);
@@ -503,7 +500,6 @@ CustomToolChainConfigWidget::CustomToolChainConfigWidget(CustomToolChain *tc) :
m_mainLayout->addRow(tr("C++11 &flags:"), m_cxx11Flags);
m_mainLayout->addRow(tr("&Qt mkspecs:"), m_mkspecs);
parserLayout->addWidget(m_errorParserComboBox);
- parserLayout->addWidget(m_customParserSettingsButton);
m_mainLayout->addRow(tr("&Error parser:"), parserLayoutWidget);
addErrorLabel();
@@ -522,8 +518,6 @@ CustomToolChainConfigWidget::CustomToolChainConfigWidget(CustomToolChain *tc) :
connect(m_mkspecs, &QLineEdit::textChanged, this, &ToolChainConfigWidget::dirty);
connect(m_errorParserComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged),
this, &CustomToolChainConfigWidget::errorParserChanged);
- connect(m_customParserSettingsButton, &QAbstractButton::clicked,
- this, &CustomToolChainConfigWidget::openCustomParserSettingsDialog);
errorParserChanged();
}
@@ -538,23 +532,9 @@ void CustomToolChainConfigWidget::updateSummaries()
void CustomToolChainConfigWidget::errorParserChanged(int )
{
- const auto currentId = Core::Id::fromSetting(m_errorParserComboBox->currentData());
- m_customParserSettingsButton->setEnabled(currentId == CustomParser::id());
emit dirty();
}
-void CustomToolChainConfigWidget::openCustomParserSettingsDialog()
-{
- CustomParserConfigDialog dialog;
- dialog.setSettings(m_customParserSettings);
-
- if (dialog.exec() == QDialog::Accepted) {
- m_customParserSettings = dialog.settings();
- if (dialog.isDirty())
- emit dirty();
- }
-}
-
void CustomToolChainConfigWidget::applyImpl()
{
if (toolChain()->isAutoDetected())
@@ -577,7 +557,6 @@ void CustomToolChainConfigWidget::applyImpl()
tc->setMkspecs(m_mkspecs->text());
tc->setDisplayName(displayName); // reset display name
tc->setOutputParserId(Core::Id::fromSetting(m_errorParserComboBox->currentData()));
- tc->setCustomParserSettings(m_customParserSettings);
setFromToolchain(); // Refresh with actual data from the toolchain. This shows what e.g. the
// macro parser did with the input.
@@ -600,7 +579,6 @@ void CustomToolChainConfigWidget::setFromToolchain()
m_mkspecs->setText(tc->mkspecs());
int index = m_errorParserComboBox->findData(tc->outputParserId().toSetting());
m_errorParserComboBox->setCurrentIndex(index);
- m_customParserSettings = tc->customParserSettings();
}
bool CustomToolChainConfigWidget::isDirtyImpl() const
@@ -614,8 +592,7 @@ bool CustomToolChainConfigWidget::isDirtyImpl() const
|| m_headerDetails->entries() != tc->headerPathsList()
|| m_cxx11Flags->text().split(QLatin1Char(',')) != tc->cxx11Flags()
|| m_mkspecs->text() != tc->mkspecs()
- || Core::Id::fromSetting(m_errorParserComboBox->currentData()) == tc->outputParserId()
- || m_customParserSettings != tc->customParserSettings();
+ || Core::Id::fromSetting(m_errorParserComboBox->currentData()) == tc->outputParserId();
}
void CustomToolChainConfigWidget::makeReadOnlyImpl()
diff --git a/src/plugins/projectexplorer/customtoolchain.h b/src/plugins/projectexplorer/customtoolchain.h
index dc57fe3503..382cb3ebca 100644
--- a/src/plugins/projectexplorer/customtoolchain.h
+++ b/src/plugins/projectexplorer/customtoolchain.h
@@ -39,7 +39,6 @@ QT_BEGIN_NAMESPACE
class QPlainTextEdit;
class QTextEdit;
class QComboBox;
-class QPushButton;
QT_END_NAMESPACE
namespace Utils { class PathChooser; }
@@ -108,13 +107,13 @@ public:
Core::Id outputParserId() const;
void setOutputParserId(Core::Id parserId);
- CustomParserSettings customParserSettings() const;
- void setCustomParserSettings(const CustomParserSettings &settings);
static QList<CustomToolChain::Parser> parsers();
private:
CustomToolChain();
+ Internal::CustomParserSettings customParserSettings() const;
+
Utils::FilePath m_compilerCommand;
Utils::FilePath m_makeCommand;
@@ -125,7 +124,6 @@ private:
QStringList m_mkspecs;
Core::Id m_outputParserId;
- CustomParserSettings m_customParserSettings;
friend class Internal::CustomToolChainFactory;
friend class ToolChainFactory;
@@ -155,7 +153,6 @@ public:
private:
void updateSummaries();
void errorParserChanged(int index = -1);
- void openCustomParserSettingsDialog();
protected:
void applyImpl() override;
@@ -175,9 +172,6 @@ protected:
QLineEdit *m_cxx11Flags;
QLineEdit *m_mkspecs;
QComboBox *m_errorParserComboBox;
- QPushButton *m_customParserSettingsButton;
-
- CustomParserSettings m_customParserSettings;
};
} // namespace Internal
diff --git a/src/plugins/projectexplorer/projectexplorer.cpp b/src/plugins/projectexplorer/projectexplorer.cpp
index 3648e0c1a4..5ece973a05 100644
--- a/src/plugins/projectexplorer/projectexplorer.cpp
+++ b/src/plugins/projectexplorer/projectexplorer.cpp
@@ -33,6 +33,7 @@
#include "compileoutputwindow.h"
#include "configtaskhandler.h"
#include "customexecutablerunconfiguration.h"
+#include "customparserssettingspage.h"
#include "customwizard/customwizard.h"
#include "deployablefile.h"
#include "deployconfiguration.h"
@@ -283,6 +284,9 @@ const char SEPARATE_DEBUG_INFO_SETTINGS_KEY[] = "ProjectExplorer/Settings/Separa
const char QML_DEBUGGING_SETTINGS_KEY[] = "ProjectExplorer/Settings/QmlDebugging";
const char QT_QUICK_COMPILER_SETTINGS_KEY[] = "ProjectExplorer/Settings/QtQuickCompiler";
+const char CUSTOM_PARSER_COUNT_KEY[] = "ProjectExplorer/Settings/CustomParserCount";
+const char CUSTOM_PARSER_PREFIX_KEY[] = "ProjectExplorer/Settings/CustomParser";
+
} // namespace Constants
@@ -551,6 +555,7 @@ public:
MiniProjectTargetSelector * m_targetSelector;
ProjectExplorerSettings m_projectExplorerSettings;
BuildPropertiesSettings m_buildPropertiesSettings;
+ QList<Internal::CustomParserSettings> m_customParsers;
bool m_shouldHaveRunConfiguration = false;
bool m_shuttingDown = false;
Core::Id m_runMode = Constants::NO_RUN_MODE;
@@ -631,6 +636,7 @@ public:
CompileOutputSettingsPage m_compileOutputSettingsPage;
DeviceSettingsPage m_deviceSettingsPage;
SshSettingsPage m_sshSettingsPage;
+ CustomParsersSettingsPage m_customParsersSettingsPage;
ProjectTreeWidgetFactory m_projectTreeFactory;
FolderNavigationWidgetFactory m_folderNavigationWidgetFactory;
@@ -817,6 +823,8 @@ bool ProjectExplorerPlugin::initialize(const QStringList &arguments, QString *er
});
ProjectPanelFactory::registerFactory(panelFactory);
+ RunConfiguration::registerAspect<CustomParsersAspect>();
+
// context menus
ActionContainer *msessionContextMenu =
ActionManager::createMenu(Constants::M_SESSIONCONTEXT);
@@ -1547,6 +1555,14 @@ bool ProjectExplorerPlugin::initialize(const QStringList &arguments, QString *er
dd->m_buildPropertiesSettings.qtQuickCompiler
= loadTriStateValue(Constants::QT_QUICK_COMPILER_SETTINGS_KEY);
+ const int customParserCount = s->value(Constants::CUSTOM_PARSER_COUNT_KEY).toInt();
+ for (int i = 0; i < customParserCount; ++i) {
+ CustomParserSettings settings;
+ settings.fromMap(s->value(Constants::CUSTOM_PARSER_PREFIX_KEY
+ + QString::number(i)).toMap());
+ dd->m_customParsers << settings;
+ }
+
auto buildManager = new BuildManager(this, dd->m_cancelBuildAction);
connect(buildManager, &BuildManager::buildStateChanged,
dd, &ProjectExplorerPluginPrivate::updateActions);
@@ -2181,6 +2197,12 @@ void ProjectExplorerPluginPrivate::savePersistentSettings()
dd->m_buildPropertiesSettings.qmlDebugging.toVariant());
s->setValue(Constants::QT_QUICK_COMPILER_SETTINGS_KEY,
dd->m_buildPropertiesSettings.qtQuickCompiler.toVariant());
+
+ s->setValue(Constants::CUSTOM_PARSER_COUNT_KEY, dd->m_customParsers.count());
+ for (int i = 0; i < dd->m_customParsers.count(); ++i) {
+ s->setValue(Constants::CUSTOM_PARSER_PREFIX_KEY + QString::number(i),
+ dd->m_customParsers.at(i).toMap());
+ }
}
void ProjectExplorerPlugin::openProjectWelcomePage(const QString &fileName)
@@ -3869,6 +3891,19 @@ void ProjectExplorerPlugin::showQtSettings()
dd->m_buildPropertiesSettings.showQtSettings = true;
}
+void ProjectExplorerPlugin::setCustomParsers(const QList<CustomParserSettings> &settings)
+{
+ if (dd->m_customParsers != settings) {
+ dd->m_customParsers = settings;
+ emit m_instance->customParsersChanged();
+ }
+}
+
+const QList<CustomParserSettings> ProjectExplorerPlugin::customParsers()
+{
+ return dd->m_customParsers;
+}
+
QStringList ProjectExplorerPlugin::projectFilePatterns()
{
QStringList patterns;
diff --git a/src/plugins/projectexplorer/projectexplorer.h b/src/plugins/projectexplorer/projectexplorer.h
index d14177e96e..5f95965eb3 100644
--- a/src/plugins/projectexplorer/projectexplorer.h
+++ b/src/plugins/projectexplorer/projectexplorer.h
@@ -59,6 +59,7 @@ class FileNode;
namespace Internal {
class AppOutputSettings;
+class CustomParserSettings;
class MiniProjectTargetSelector;
class ProjectExplorerSettings;
}
@@ -141,6 +142,9 @@ public:
static const BuildPropertiesSettings &buildPropertiesSettings();
static void showQtSettings();
+ static void setCustomParsers(const QList<Internal::CustomParserSettings> &settings);
+ static const QList<Internal::CustomParserSettings> customParsers();
+
static void startRunControl(RunControl *runControl);
static void showOutputPaneForRunControl(RunControl *runControl);
@@ -192,6 +196,7 @@ signals:
void recentProjectsChanged();
void settingsChanged();
+ void customParsersChanged();
void runActionsUpdated();
diff --git a/src/plugins/projectexplorer/projectexplorer.pro b/src/plugins/projectexplorer/projectexplorer.pro
index 4a8f962198..d9f7cbf55b 100644
--- a/src/plugins/projectexplorer/projectexplorer.pro
+++ b/src/plugins/projectexplorer/projectexplorer.pro
@@ -19,6 +19,7 @@ HEADERS += projectexplorer.h \
buildtargettype.h \
clangparser.h \
configtaskhandler.h \
+ customparserssettingspage.h \
desktoprunconfiguration.h \
environmentaspect.h \
environmentaspectwidget.h \
@@ -176,6 +177,7 @@ SOURCES += projectexplorer.cpp \
buildpropertiessettingspage.cpp \
buildsystem.cpp \
clangparser.cpp \
+ customparserssettingspage.cpp \
configtaskhandler.cpp \
desktoprunconfiguration.cpp \
environmentaspect.cpp \
diff --git a/src/plugins/projectexplorer/projectexplorer.qbs b/src/plugins/projectexplorer/projectexplorer.qbs
index 38efedd210..d6429ca9d8 100644
--- a/src/plugins/projectexplorer/projectexplorer.qbs
+++ b/src/plugins/projectexplorer/projectexplorer.qbs
@@ -54,6 +54,7 @@ Project {
"customexecutablerunconfiguration.cpp", "customexecutablerunconfiguration.h",
"customparser.cpp", "customparser.h",
"customparserconfigdialog.cpp", "customparserconfigdialog.h", "customparserconfigdialog.ui",
+ "customparserssettingspage.cpp", "customparserssettingspage.h",
"customtoolchain.cpp", "customtoolchain.h",
"dependenciespanel.cpp", "dependenciespanel.h",
"deployablefile.cpp", "deployablefile.h",
diff --git a/src/plugins/projectexplorer/projectexplorerconstants.h b/src/plugins/projectexplorer/projectexplorerconstants.h
index 2fc0577056..08e8210610 100644
--- a/src/plugins/projectexplorer/projectexplorerconstants.h
+++ b/src/plugins/projectexplorer/projectexplorerconstants.h
@@ -110,6 +110,7 @@ const char KITS_SETTINGS_PAGE_ID[] = "D.ProjectExplorer.KitsOptions";
const char SSH_SETTINGS_PAGE_ID[] = "F.ProjectExplorer.SshOptions";
const char TOOLCHAIN_SETTINGS_PAGE_ID[] = "M.ProjectExplorer.ToolChainOptions";
const char DEBUGGER_SETTINGS_PAGE_ID[] = "N.ProjectExplorer.DebuggerOptions";
+const char CUSTOM_PARSERS_SETTINGS_PAGE_ID[] = "X.ProjectExplorer.CustomParsersSettingsPage";
// Build and Run settings category
const char BUILD_AND_RUN_SETTINGS_CATEGORY[] = "K.BuildAndRun";
diff --git a/src/plugins/projectexplorer/runconfiguration.h b/src/plugins/projectexplorer/runconfiguration.h
index d71f87ce75..e896968c10 100644
--- a/src/plugins/projectexplorer/runconfiguration.h
+++ b/src/plugins/projectexplorer/runconfiguration.h
@@ -136,8 +136,6 @@ public:
bool isConfigured() const { return checkForIssues().isEmpty(); }
virtual Tasks checkForIssues() const { return {}; }
- Utils::OutputFormatter *createOutputFormatter() const;
-
using CommandLineGetter = std::function<Utils::CommandLine()>;
void setCommandLineGetter(const CommandLineGetter &cmdGetter);
Utils::CommandLine commandLine() const;
diff --git a/src/plugins/projectexplorer/runcontrol.cpp b/src/plugins/projectexplorer/runcontrol.cpp
index 2c07d016db..29b98c945c 100644
--- a/src/plugins/projectexplorer/runcontrol.cpp
+++ b/src/plugins/projectexplorer/runcontrol.cpp
@@ -26,16 +26,17 @@
#include "runcontrol.h"
#include "devicesupport/desktopdevice.h"
-#include "project.h"
-#include "target.h"
-#include "toolchain.h"
#include "abi.h"
#include "buildconfiguration.h"
+#include "customparser.h"
#include "environmentaspect.h"
#include "kitinformation.h"
+#include "project.h"
+#include "projectexplorer.h"
#include "runconfigurationaspects.h"
#include "session.h"
-#include "kitinformation.h"
+#include "target.h"
+#include "toolchain.h"
#include <utils/algorithm.h>
#include <utils/checkablemessagebox.h>
@@ -825,7 +826,14 @@ void RunControlPrivate::showError(const QString &msg)
QList<Utils::OutputLineParser *> RunControl::createOutputParsers() const
{
- return OutputFormatterFactory::createFormatters(target());
+ QList<Utils::OutputLineParser *> parsers = OutputFormatterFactory::createFormatters(target());
+ if (const auto customParsersAspect = runConfiguration()->aspect<CustomParsersAspect>()) {
+ for (const Core::Id id : customParsersAspect->parsers()) {
+ if (CustomParser * const parser = CustomParser::createFromId(id))
+ parsers << parser;
+ }
+ }
+ return parsers;
}
Core::Id RunControl::runMode() const