diff options
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 |