diff options
author | Christian Kandeler <christian.kandeler@qt.io> | 2020-05-06 12:51:08 +0200 |
---|---|---|
committer | Christian Kandeler <christian.kandeler@qt.io> | 2020-05-11 15:59:32 +0000 |
commit | c15e09e0fe880c58ad39d5d8d0a1baeb84fc7e3b (patch) | |
tree | 0a0b0f7e93af8dce0dd6c1b979aea129e7559a9d /src/plugins | |
parent | c7973c7d352ac44181703b1c799d44af4f79549e (diff) | |
download | qt-creator-c15e09e0fe880c58ad39d5d8d0a1baeb84fc7e3b.tar.gz |
ProjectExplorer: Generalize the concept of custom output parsers
They can now be created independently of any toolchains, and we expose
them in the build and run configurations, so that users can easily get
tasks for output that comes from custom tools or is otherwise specific
to the user's environment.
Fixes: QTCREATORBUG-23993
Change-Id: I405753b9b68508ffe5deb4fcac08d6b213c7554d
Reviewed-by: André Hartmann <aha_1980@gmx.de>
Reviewed-by: hjk <hjk@qt.io>
Diffstat (limited to 'src/plugins')
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 |