diff options
Diffstat (limited to 'src/plugins')
26 files changed, 1822 insertions, 26 deletions
diff --git a/src/plugins/nim/CMakeLists.txt b/src/plugins/nim/CMakeLists.txt index a26e787578..2601c60288 100644 --- a/src/plugins/nim/CMakeLists.txt +++ b/src/plugins/nim/CMakeLists.txt @@ -8,6 +8,14 @@ add_qtc_plugin(Nim nim.qrc nimconstants.h nimplugin.cpp nimplugin.h + project/nimblebuildstep.h project/nimblebuildstep.cpp + project/nimblebuildstepwidget.h project/nimblebuildstepwidget.cpp project/nimblebuildstepwidget.ui + project/nimbleproject.h project/nimbleproject.cpp + project/nimblerunconfiguration.h project/nimblerunconfiguration.cpp + project/nimbletaskstep.h project/nimbletaskstep.cpp + project/nimbletaskstepwidget.h project/nimbletaskstepwidget.cpp project/nimbletaskstepwidget.ui + project/nimblebuildsystem.h project/nimblebuildsystem.cpp + project/nimblebuildconfiguration.h project/nimblebuildconfiguration.cpp project/nimbuildsystem.cpp project/nimbuildsystem.h project/nimbuildconfiguration.cpp project/nimbuildconfiguration.h project/nimcompilerbuildstep.cpp project/nimcompilerbuildstep.h diff --git a/src/plugins/nim/Nim.json.in b/src/plugins/nim/Nim.json.in index b9e5d8709f..a3d98945c3 100644 --- a/src/plugins/nim/Nim.json.in +++ b/src/plugins/nim/Nim.json.in @@ -30,13 +30,19 @@ \" <mime-type type=\'text/x-nim\'>\", \" <sub-class-of type=\'text/plain\'/>\", - \" <comment>Nim source file </comment>\", + \" <comment>Nim source file</comment>\", \" <glob pattern=\'*.nim\'/>\", \" </mime-type>\", + \" <mime-type type=\'text/x-nimble\'>\", + \" <sub-class-of type=\'text/plain\'/>\", + \" <comment>Nimble project file</comment>\", + \" <glob pattern=\'*.nimble\'/>\", + \" </mime-type>\", + \" <mime-type type=\'text/x-nim-script\'>\", \" <sub-class-of type=\'text/plain\'/>\", - \" <comment>Nim script file </comment>\", + \" <comment>Nim script file</comment>\", \" <glob pattern=\'*.nims\'/>\", \" </mime-type>\", \"</mime-info>\" diff --git a/src/plugins/nim/nim.pro b/src/plugins/nim/nim.pro index 31b2adb173..46869353fb 100644 --- a/src/plugins/nim/nim.pro +++ b/src/plugins/nim/nim.pro @@ -14,9 +14,17 @@ HEADERS += \ editor/nimcompletionassistprovider.h \ editor/nimhighlighter.h \ editor/nimindenter.h \ + project/nimblebuildconfiguration.h \ + project/nimblebuildstep.h \ + project/nimblebuildstepwidget.h \ + project/nimbleproject.h \ + project/nimblerunconfiguration.h \ + project/nimbletaskstep.h \ + project/nimbletaskstepwidget.h \ tools/nimlexer.h \ tools/sourcecodestream.h \ project/nimbuildsystem.h \ + project/nimblebuildsystem.h \ project/nimproject.h \ project/nimprojectnode.h \ project/nimbuildconfiguration.h \ @@ -45,8 +53,16 @@ SOURCES += \ editor/nimcompletionassistprovider.cpp \ editor/nimhighlighter.cpp \ editor/nimindenter.cpp \ + project/nimblebuildconfiguration.cpp \ + project/nimblebuildstep.cpp \ + project/nimbletaskstep.cpp \ + project/nimblebuildstepwidget.cpp \ + project/nimbleproject.cpp \ + project/nimblerunconfiguration.cpp \ + project/nimbletaskstepwidget.cpp \ tools/nimlexer.cpp \ project/nimbuildsystem.cpp \ + project/nimblebuildsystem.cpp \ project/nimproject.cpp \ project/nimprojectnode.cpp \ project/nimbuildconfiguration.cpp \ @@ -69,6 +85,8 @@ SOURCES += \ suggest/server.cpp FORMS += \ + project/nimblebuildstepwidget.ui \ + project/nimbletaskstepwidget.ui \ project/nimcompilerbuildstepconfigwidget.ui \ settings/nimcodestylepreferenceswidget.ui \ settings/nimtoolssettingswidget.ui diff --git a/src/plugins/nim/nim.qbs b/src/plugins/nim/nim.qbs index 6964993cea..383999f377 100644 --- a/src/plugins/nim/nim.qbs +++ b/src/plugins/nim/nim.qbs @@ -46,6 +46,14 @@ QtcPlugin { "nimrunconfiguration.h", "nimrunconfiguration.cpp", "nimtoolchain.h", "nimtoolchain.cpp", "nimtoolchainfactory.h", "nimtoolchainfactory.cpp", + "nimblebuildstep.h", "nimblebuildstep.cpp", + "nimblebuildstepwidget.h", "nimblebuildstepwidget.cpp", "nimblebuildstepwidget.ui", + "nimbleproject.h", "nimbleproject.cpp", + "nimblerunconfiguration.h", "nimblerunconfiguration.cpp", + "nimbletaskstep.h", "nimbletaskstep.cpp", + "nimbletaskstepwidget.h", "nimbletaskstepwidget.cpp", "nimbletaskstepwidget.ui", + "nimblebuildsystem.h", "nimblebuildsystem.cpp", + "nimblebuildconfiguration.h", "nimblebuildconfiguration.cpp", ] } diff --git a/src/plugins/nim/nimconstants.h b/src/plugins/nim/nimconstants.h index 03f945689a..61b281fbc7 100644 --- a/src/plugins/nim/nimconstants.h +++ b/src/plugins/nim/nimconstants.h @@ -32,6 +32,7 @@ namespace Nim { namespace Constants { const char C_NIMPROJECT_ID[] = "Nim.NimProject"; +const char C_NIMBLEPROJECT_ID[] = "Nim.NimbleProject"; const char C_NIMEDITOR_ID[] = "Nim.NimEditor"; const char C_EDITOR_DISPLAY_NAME[] = QT_TRANSLATE_NOOP("OpenWith::Editors", "Nim Editor"); @@ -39,11 +40,28 @@ const char C_EDITOR_DISPLAY_NAME[] = QT_TRANSLATE_NOOP("OpenWith::Editors", "Nim const char C_NIMTOOLCHAIN_TYPEID[] = "Nim.NimToolChain"; const char C_NIMTOOLCHAIN_COMPILER_COMMAND_KEY[] = "Nim.NimToolChain.CompilerCommand"; +// NimbleProject +const char C_NIMBLEPROJECT_TASKS[] = "Nim.NimbleProject.Tasks"; +const char C_NIMBLEPROJECT_METADATA[] = "Nim.NimbleProject.Metadata"; + // NimProject const char C_NIMPROJECT_EXCLUDEDFILES[] = "Nim.NimProjectExcludedFiles"; // NimBuildConfiguration const char C_NIMBUILDCONFIGURATION_ID[] = "Nim.NimBuildConfiguration"; +const char C_NIMBLEBUILDCONFIGURATION_ID[] = "Nim.NimbleBuildConfiguration"; +const char C_NIMBLEBUILDCONFIGURATION_BUILDTYPE[] = "Nim.NimbleBuildConfiguration.BuildType"; + +// NimbleBuildStep +const char C_NIMBLEBUILDSTEP_ID[] = "Nim.NimbleBuildStep"; +const char C_NIMBLEBUILDSTEP_DISPLAY[] = QT_TRANSLATE_NOOP("NimbleBuildStep", "Nimble Build"); +const char C_NIMBLEBUILDSTEP_ARGUMENTS[] = "Nim.NimbleBuildStep.Arguments"; + +// NimbleTaskStep +const char C_NIMBLETASKSTEP_ID[] = "Nim.NimbleTaskStep"; +const char C_NIMBLETASKSTEP_DISPLAY[] = QT_TRANSLATE_NOOP("NimbleTaskStep", "Nimble Task"); +const QString C_NIMBLETASKSTEP_TASKNAME = QStringLiteral("Nim.NimbleTaskStep.TaskName"); +const QString C_NIMBLETASKSTEP_TASKARGS = QStringLiteral("Nim.NimbleTaskStep.TaskArgs"); // NimCompilerBuildStep const char C_NIMCOMPILERBUILDSTEP_ID[] = "Nim.NimCompilerBuildStep"; @@ -92,6 +110,7 @@ const char C_NIMCODESTYLEPREVIEWSNIPPET[] = * MIME type ******************************************************************************/ const char C_NIM_MIMETYPE[] = "text/x-nim"; +const char C_NIMBLE_MIMETYPE[] = "text/x-nimble"; const char C_NIM_SCRIPT_MIMETYPE[] = "text/x-nim-script"; const char C_NIM_MIME_ICON[] = "text-x-nim"; const char C_NIM_PROJECT_MIMETYPE[] = "text/x-nim-project"; diff --git a/src/plugins/nim/nimplugin.cpp b/src/plugins/nim/nimplugin.cpp index 7740e6096e..152249d4ee 100644 --- a/src/plugins/nim/nimplugin.cpp +++ b/src/plugins/nim/nimplugin.cpp @@ -28,12 +28,17 @@ #include "nimconstants.h" #include "editor/nimeditorfactory.h" #include "editor/nimhighlighter.h" +#include "project/nimblerunconfiguration.h" +#include "project/nimblebuildconfiguration.h" #include "project/nimbuildconfiguration.h" #include "project/nimcompilerbuildstep.h" #include "project/nimcompilercleanstep.h" #include "project/nimproject.h" +#include "project/nimbleproject.h" #include "project/nimrunconfiguration.h" #include "project/nimtoolchainfactory.h" +#include "project/nimblebuildstep.h" +#include "project/nimbletaskstep.h" #include "settings/nimcodestylepreferencesfactory.h" #include "settings/nimcodestylesettingspage.h" #include "settings/nimtoolssettingspage.h" @@ -66,12 +71,21 @@ public: NimSettings settings; NimEditorFactory editorFactory; NimBuildConfigurationFactory buildConfigFactory; - NimRunConfigurationFactory runConfigFactory; - RunWorkerFactory runWorkerFactory{ + NimbleBuildConfigurationFactory nimbleBuildConfigFactory; + NimRunConfigurationFactory nimRunConfigFactory; + NimbleRunConfigurationFactory nimbleRunConfigFactory; + RunWorkerFactory nimRunWorkerFactory { RunWorkerFactory::make<SimpleTargetRunner>(), {ProjectExplorer::Constants::NORMAL_RUN_MODE}, - {runConfigFactory.id()} + {nimRunConfigFactory.id()} }; + RunWorkerFactory nimbleRunWorkerFactory { + RunWorkerFactory::make<SimpleTargetRunner>(), + {ProjectExplorer::Constants::NORMAL_RUN_MODE}, + {nimbleRunConfigFactory.id()} + }; + NimbleBuildStepFactory nimbleBuildStepFactory; + NimbleTaskStepFactory nimbleTaskStepFactory; NimCompilerBuildStepFactory buildStepFactory; NimCompilerCleanStepFactory cleanStepFactory; NimCodeStyleSettingsPage codeStyleSettingsPage; @@ -99,6 +113,7 @@ bool NimPlugin::initialize(const QStringList &arguments, QString *errorMessage) &NimEditorFactory::decorateEditor); ProjectManager::registerProjectType<NimProject>(Constants::C_NIM_PROJECT_MIMETYPE); + ProjectManager::registerProjectType<NimbleProject>(Constants::C_NIMBLE_MIMETYPE); return true; } @@ -112,6 +127,7 @@ void NimPlugin::extensionsInitialized() if (!icon.isNull()) { Core::FileIconProvider::registerIconOverlayForMimeType(icon, Constants::C_NIM_MIMETYPE); Core::FileIconProvider::registerIconOverlayForMimeType(icon, Constants::C_NIM_SCRIPT_MIMETYPE); + Core::FileIconProvider::registerIconOverlayForMimeType(icon, Constants::C_NIMBLE_MIMETYPE); } } diff --git a/src/plugins/nim/project/nimblebuildconfiguration.cpp b/src/plugins/nim/project/nimblebuildconfiguration.cpp new file mode 100644 index 0000000000..8b947ce3cc --- /dev/null +++ b/src/plugins/nim/project/nimblebuildconfiguration.cpp @@ -0,0 +1,144 @@ +/**************************************************************************** +** +** Copyright (C) Filippo Cucchetto <filippocucchetto@gmail.com> +** Contact: http://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 "nimblebuildconfiguration.h" +#include "nimconstants.h" +#include "nimblebuildstep.h" +#include "nimbleproject.h" + +#include <projectexplorer/buildinfo.h> +#include <projectexplorer/buildstep.h> +#include <projectexplorer/buildsteplist.h> +#include <projectexplorer/kit.h> +#include <projectexplorer/project.h> +#include <projectexplorer/projectexplorer.h> +#include <projectexplorer/projectmacroexpander.h> +#include <utils/fileutils.h> +#include <utils/osspecificaspects.h> + +#include <QFileInfo> +#include <QDir> + +using namespace Nim; +using namespace ProjectExplorer; +using namespace Utils; + +NimbleBuildConfiguration::NimbleBuildConfiguration(Target *target, Core::Id id) + : BuildConfiguration(target, id) +{ + setConfigWidgetDisplayName(tr("General")); + setConfigWidgetHasFrame(true); + setBuildDirectorySettingsKey("Nim.NimbleBuildConfiguration.BuildDirectory"); + + m_nimbleProject = dynamic_cast<NimbleProject*>(project()); + QTC_ASSERT(m_nimbleProject, return); + QObject::connect(m_nimbleProject, &NimbleProject::metadataChanged, this, &NimbleBuildConfiguration::updateApplicationTargets); + updateApplicationTargets(); +} + +BuildConfiguration::BuildType NimbleBuildConfiguration::buildType() const +{ + return m_buildType; +} + +void NimbleBuildConfiguration::initialize() +{ + BuildConfiguration::initialize(); + + m_buildType = initialBuildType(); + + setBuildDirectory(project()->projectDirectory()); + + // Don't add a nimble build step when the package has no binaries (i.e a library package) + if (!m_nimbleProject->metadata().bin.empty()) + { + BuildStepList *buildSteps = stepList(ProjectExplorer::Constants::BUILDSTEPS_BUILD); + buildSteps->appendStep(new NimbleBuildStep(buildSteps)); + } +} + +void NimbleBuildConfiguration::updateApplicationTargets() +{ + QTC_ASSERT(m_nimbleProject, return); + + const NimbleMetadata &metaData = m_nimbleProject->metadata(); + const FilePath &projectDir = project()->projectDirectory(); + const FilePath binDir = projectDir.pathAppended(metaData.binDir); + const FilePath srcDir = projectDir.pathAppended("src"); + + QList<BuildTargetInfo> targets = Utils::transform(metaData.bin, [&](const QString &bin){ + BuildTargetInfo info = {}; + info.displayName = bin; + info.targetFilePath = binDir.pathAppended(HostOsInfo::withExecutableSuffix(bin)); + info.projectFilePath = srcDir.pathAppended(bin).stringAppended(".nim"); + info.workingDirectory = binDir; + info.buildKey = bin; + return info; + }); + + target()->setApplicationTargets(std::move(targets)); +} + +bool NimbleBuildConfiguration::fromMap(const QVariantMap &map) +{ + m_buildType = static_cast<BuildType>(map[Constants::C_NIMBLEBUILDCONFIGURATION_BUILDTYPE].toInt()); + return BuildConfiguration::fromMap(map); +} + +QVariantMap NimbleBuildConfiguration::toMap() const +{ + auto map = BuildConfiguration::toMap(); + map[Constants::C_NIMBLEBUILDCONFIGURATION_BUILDTYPE] = buildType(); + return map; +} + + +NimbleBuildConfigurationFactory::NimbleBuildConfigurationFactory() +{ + registerBuildConfiguration<NimbleBuildConfiguration>(Constants::C_NIMBLEBUILDCONFIGURATION_ID); + setSupportedProjectType(Constants::C_NIMBLEPROJECT_ID); + setSupportedProjectMimeTypeName(Constants::C_NIMBLE_MIMETYPE); +} + +QList<BuildInfo> NimbleBuildConfigurationFactory::availableBuilds(const Kit *k, const Utils::FilePath &projectPath, bool forSetup) const +{ + static const QList<BuildConfiguration::BuildType> configurations = {BuildConfiguration::Debug, BuildConfiguration::Release}; + return Utils::transform(configurations, [&](BuildConfiguration::BuildType buildType){ + BuildInfo info(this); + info.buildType = buildType; + info.kitId = k->id(); + + if (buildType == BuildConfiguration::Debug) + info.typeName = tr("Debug"); + else if (buildType == BuildConfiguration::Release) + info.typeName = tr("Release"); + + if (forSetup) { + info.displayName = info.typeName; + info.buildDirectory = projectPath.parentDir(); + } + return info; + }); +} diff --git a/src/plugins/nim/project/nimblebuildconfiguration.h b/src/plugins/nim/project/nimblebuildconfiguration.h new file mode 100644 index 0000000000..5ba6b5c218 --- /dev/null +++ b/src/plugins/nim/project/nimblebuildconfiguration.h @@ -0,0 +1,72 @@ +/**************************************************************************** +** +** Copyright (C) Filippo Cucchetto <filippocucchetto@gmail.com> +** Contact: http://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 <projectexplorer/buildconfiguration.h> +#include <projectexplorer/target.h> + +namespace Nim { + +class NimbleProject; + +class NimbleBuildConfiguration : public ProjectExplorer::BuildConfiguration +{ + Q_OBJECT + + friend class ProjectExplorer::BuildConfigurationFactory; + + NimbleBuildConfiguration(ProjectExplorer::Target *target, Core::Id id); + + BuildType buildType() const override; + + bool fromMap(const QVariantMap &map) override; + + QVariantMap toMap() const override; + +protected: + void initialize() override; + + void updateApplicationTargets(); + +private: + NimbleProject *m_nimbleProject = nullptr; + BuildType m_buildType; +}; + +class NimbleBuildConfigurationFactory : public ProjectExplorer::BuildConfigurationFactory +{ + Q_OBJECT + +public: + NimbleBuildConfigurationFactory(); + +private: + QList<ProjectExplorer::BuildInfo> availableBuilds(const ProjectExplorer::Kit *k, + const Utils::FilePath &projectPath, + bool forSetup) const override; +}; + +} diff --git a/src/plugins/nim/project/nimblebuildstep.cpp b/src/plugins/nim/project/nimblebuildstep.cpp new file mode 100644 index 0000000000..940c3e91eb --- /dev/null +++ b/src/plugins/nim/project/nimblebuildstep.cpp @@ -0,0 +1,189 @@ +/**************************************************************************** +** +** Copyright (C) Filippo Cucchetto <filippocucchetto@gmail.com> +** Contact: http://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 "nimblebuildstep.h" +#include "nimblebuildstepwidget.h" +#include "nimbletaskstepwidget.h" +#include "nimconstants.h" +#include "nimbleproject.h" + +#include <projectexplorer/buildconfiguration.h> +#include <projectexplorer/ioutputparser.h> +#include <projectexplorer/processparameters.h> +#include <projectexplorer/projectexplorerconstants.h> + +#include <QRegularExpression> +#include <QStandardPaths> + +using namespace Nim; +using namespace ProjectExplorer; +using namespace Utils; + +namespace { + +class NimParser : public IOutputParser +{ +public: + void stdOutput(const QString &line) final + { + parseLine(line.trimmed()); + IOutputParser::stdOutput(line); + } + + void stdError(const QString &line) final + { + parseLine(line.trimmed()); + IOutputParser::stdError(line); + } + +private: + void parseLine(const QString &line) + { + static QRegularExpression regex("(.+.nim)\\((\\d+), (\\d+)\\) (.+)", + QRegularExpression::OptimizeOnFirstUsageOption); + static QRegularExpression warning("(Warning):(.*)", + QRegularExpression::OptimizeOnFirstUsageOption); + static QRegularExpression error("(Error):(.*)", + QRegularExpression::OptimizeOnFirstUsageOption); + + QRegularExpressionMatch match = regex.match(line); + if (!match.hasMatch()) + return; + const QString filename = match.captured(1); + bool lineOk = false; + const int lineNumber = match.captured(2).toInt(&lineOk); + const QString message = match.captured(4); + if (!lineOk) + return; + + Task::TaskType type = Task::Unknown; + + if (warning.match(message).hasMatch()) + type = Task::Warning; + else if (error.match(message).hasMatch()) + type = Task::Error; + else + return; + + Task task(type, + message, + Utils::FilePath::fromUserInput(filename), + lineNumber, + ProjectExplorer::Constants::TASK_CATEGORY_COMPILE); + emit addTask(task); + } +}; + +} + +NimbleBuildStep::NimbleBuildStep(BuildStepList *parentList) + : AbstractProcessStep(parentList, Constants::C_NIMBLEBUILDSTEP_ID) +{ + setDefaultDisplayName(tr(Constants::C_NIMBLEBUILDSTEP_DISPLAY)); + setDisplayName(tr(Constants::C_NIMBLEBUILDSTEP_DISPLAY)); + QTC_ASSERT(buildConfiguration(), return); + QObject::connect(buildConfiguration(), &BuildConfiguration::buildTypeChanged, this, &NimbleBuildStep::resetArguments); + QObject::connect(this, &NimbleBuildStep::argumentsChanged, this, &NimbleBuildStep::onArgumentsChanged); + resetArguments(); +} + +bool NimbleBuildStep::init() +{ + auto parser = new NimParser(); + parser->setWorkingDirectory(project()->projectDirectory()); + setOutputParser(parser); + + ProcessParameters* params = processParameters(); + params->setEnvironment(buildConfiguration()->environment()); + params->setMacroExpander(buildConfiguration()->macroExpander()); + params->setWorkingDirectory(project()->projectDirectory()); + params->setCommandLine({QStandardPaths::findExecutable("nimble"), {"build", m_arguments}}); + return AbstractProcessStep::init(); +} + +BuildStepConfigWidget *NimbleBuildStep::createConfigWidget() +{ + return new NimbleBuildStepWidget(this); +} + +QString NimbleBuildStep::arguments() const +{ + return m_arguments; +} + +void NimbleBuildStep::setArguments(const QString &args) +{ + if (m_arguments == args) + return; + m_arguments = args; + emit argumentsChanged(args); +} + +void NimbleBuildStep::resetArguments() +{ + setArguments(defaultArguments()); +} + +bool NimbleBuildStep::fromMap(const QVariantMap &map) +{ + m_arguments = map.value(Constants::C_NIMBLEBUILDSTEP_ARGUMENTS, defaultArguments()).toString(); + return AbstractProcessStep::fromMap(map); +} + +QVariantMap NimbleBuildStep::toMap() const +{ + auto map = AbstractProcessStep::toMap(); + map[Constants::C_NIMBLEBUILDSTEP_ARGUMENTS] = m_arguments; + return map; +} + +QString NimbleBuildStep::defaultArguments() const +{ + QTC_ASSERT(buildConfiguration(), return {}; ); + switch (buildConfiguration()->buildType()) { + case ProjectExplorer::BuildConfiguration::Debug: + return "--debugger:native"; + case ProjectExplorer::BuildConfiguration::Unknown: + case ProjectExplorer::BuildConfiguration::Profile: + case ProjectExplorer::BuildConfiguration::Release: + default: + return ""; + } +} + +void NimbleBuildStep::onArgumentsChanged() +{ + ProcessParameters* params = processParameters(); + params->setCommandLine({QStandardPaths::findExecutable("nimble"), {"build", m_arguments}}); +} + +NimbleBuildStepFactory::NimbleBuildStepFactory() +{ + registerStep<NimbleBuildStep>(Constants::C_NIMBLEBUILDSTEP_ID); + setDisplayName(NimbleBuildStep::tr("Nimble Build")); + setSupportedStepList(ProjectExplorer::Constants::BUILDSTEPS_BUILD); + setSupportedConfiguration(Constants::C_NIMBLEBUILDCONFIGURATION_ID); + setRepeatable(true); +} diff --git a/src/plugins/nim/project/nimblebuildstep.h b/src/plugins/nim/project/nimblebuildstep.h new file mode 100644 index 0000000000..e8bcc18253 --- /dev/null +++ b/src/plugins/nim/project/nimblebuildstep.h @@ -0,0 +1,70 @@ +/**************************************************************************** +** +** Copyright (C) Filippo Cucchetto <filippocucchetto@gmail.com> +** Contact: http://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 <projectexplorer/abstractprocessstep.h> + +namespace Nim { + +class NimbleBuildStep : public ProjectExplorer::AbstractProcessStep +{ + Q_OBJECT + +public: + NimbleBuildStep(ProjectExplorer::BuildStepList *parentList); + + bool init() override; + + ProjectExplorer::BuildStepConfigWidget *createConfigWidget() override; + + QString arguments() const; + + void setArguments(const QString &args); + + void resetArguments(); + + bool fromMap(const QVariantMap &map) override; + + QVariantMap toMap() const override; + +signals: + void argumentsChanged(const QString &args); + +private: + QString defaultArguments() const; + + void onArgumentsChanged(); + + QString m_arguments; +}; + +class NimbleBuildStepFactory : public ProjectExplorer::BuildStepFactory +{ +public: + NimbleBuildStepFactory(); +}; + +} diff --git a/src/plugins/nim/project/nimblebuildstepwidget.cpp b/src/plugins/nim/project/nimblebuildstepwidget.cpp new file mode 100644 index 0000000000..ad841a4730 --- /dev/null +++ b/src/plugins/nim/project/nimblebuildstepwidget.cpp @@ -0,0 +1,58 @@ +/**************************************************************************** +** +** Copyright (C) Filippo Cucchetto <filippocucchetto@gmail.com> +** Contact: http://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 "nimblebuildstepwidget.h" +#include "ui_nimblebuildstepwidget.h" + +#include "nimblebuildstep.h" +#include "nimbleproject.h" + +#include <QAction> + +#include <projectexplorer/buildconfiguration.h> +#include <utils/utilsicons.h> + + +using namespace Nim; +using namespace ProjectExplorer; + +NimbleBuildStepWidget::NimbleBuildStepWidget(NimbleBuildStep *bs) + : BuildStepConfigWidget(bs) + , ui(new Ui::NimbleBuildStepWidget) +{ + ui->setupUi(this); + + ui->argumentsLineEdit->setText(bs->arguments()); + QObject::connect(bs, &NimbleBuildStep::argumentsChanged, ui->argumentsLineEdit, &QLineEdit::setText); + QObject::connect(ui->argumentsLineEdit, &QLineEdit::textEdited, bs, &NimbleBuildStep::setArguments); + + ui->resetButton->setIcon(Utils::Icons::RESET.icon()); + QObject::connect(ui->resetButton, &QToolButton::triggered, bs, &NimbleBuildStep::resetArguments); +} + +NimbleBuildStepWidget::~NimbleBuildStepWidget() +{ + delete ui; +} diff --git a/src/plugins/nim/project/nimblebuildstepwidget.h b/src/plugins/nim/project/nimblebuildstepwidget.h new file mode 100644 index 0000000000..b367e8319f --- /dev/null +++ b/src/plugins/nim/project/nimblebuildstepwidget.h @@ -0,0 +1,50 @@ +/**************************************************************************** +** +** Copyright (C) Filippo Cucchetto <filippocucchetto@gmail.com> +** Contact: http://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 <projectexplorer/buildstep.h> +#include <projectexplorer/buildconfiguration.h> + +namespace Nim { + +class NimbleBuildStep; + +namespace Ui { class NimbleBuildStepWidget; } + +class NimbleBuildStepWidget : public ProjectExplorer::BuildStepConfigWidget +{ + Q_OBJECT + +public: + explicit NimbleBuildStepWidget(NimbleBuildStep *bs); + + ~NimbleBuildStepWidget(); + +private: + Ui::NimbleBuildStepWidget *ui; +}; + +} diff --git a/src/plugins/nim/project/nimblebuildstepwidget.ui b/src/plugins/nim/project/nimblebuildstepwidget.ui new file mode 100644 index 0000000000..919fdb104b --- /dev/null +++ b/src/plugins/nim/project/nimblebuildstepwidget.ui @@ -0,0 +1,45 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>Nim::NimbleBuildStepWidget</class> + <widget class="QWidget" name="Nim::NimbleBuildStepWidget"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>400</width> + <height>50</height> + </rect> + </property> + <property name="windowTitle"> + <string>Form</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <layout class="QHBoxLayout" name="horizontalLayout"> + <item> + <widget class="QLabel" name="argumentsLabel"> + <property name="text"> + <string>Arguments:</string> + </property> + </widget> + </item> + <item> + <widget class="QLineEdit" name="argumentsLineEdit"/> + </item> + <item> + <widget class="QToolButton" name="resetButton"> + <property name="toolTip"> + <string>Reset to Default</string> + </property> + <property name="text"> + <string/> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </widget> + <resources/> + <connections/> +</ui> diff --git a/src/plugins/nim/project/nimblebuildsystem.cpp b/src/plugins/nim/project/nimblebuildsystem.cpp new file mode 100644 index 0000000000..c8d0e81d9a --- /dev/null +++ b/src/plugins/nim/project/nimblebuildsystem.cpp @@ -0,0 +1,149 @@ +/**************************************************************************** +** +** Copyright (C) Filippo Cucchetto <filippocucchetto@gmail.com> +** Contact: http://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 "nimblebuildsystem.h" +#include "nimbleproject.h" + +#include <utils/algorithm.h> +#include <utils/qtcassert.h> + +#include <QProcess> +#include <QStandardPaths> + +using namespace Nim; +using namespace ProjectExplorer; +using namespace Utils; + +namespace { + +std::vector<NimbleTask> parseTasks(const QString &nimblePath, const QString &workingDirectory) +{ + QProcess process; + process.setWorkingDirectory(workingDirectory); + process.start(QStandardPaths::findExecutable(nimblePath), {"tasks"}); + process.waitForFinished(); + + std::vector<NimbleTask> result; + + QList<QByteArray> lines = process.readAllStandardOutput().split('\n'); + lines = Utils::transform(lines, [](const QByteArray &line){ return line.trimmed(); }); + Utils::erase(lines, [](const QByteArray &line) { return line.isEmpty(); }); + + for (const QByteArray &line : lines) { + QList<QByteArray> tokens = line.trimmed().split(' '); + QTC_ASSERT(!tokens.empty(), continue); + QString taskName = QString::fromUtf8(tokens.takeFirst()); + QString taskDesc = QString::fromUtf8(tokens.join(' ')); + result.push_back({std::move(taskName), std::move(taskDesc)}); + } + + return result; +} + +NimbleMetadata parseMetadata(const QString &nimblePath, const QString &workingDirectory) { + QProcess process; + process.setWorkingDirectory(workingDirectory); + process.start(QStandardPaths::findExecutable(nimblePath), {"dump"}); + process.waitForFinished(); + + NimbleMetadata result = {}; + + QList<QByteArray> lines = process.readAllStandardOutput().split('\n'); + lines = Utils::transform(lines, [](const QByteArray &line){ return line.trimmed(); }); + Utils::erase(lines, [](const QByteArray &line) { return line.isEmpty(); }); + + for (const QByteArray &line : lines) { + QList<QByteArray> tokens = line.trimmed().split(':'); + QTC_ASSERT(tokens.size() == 2, continue); + QString name = QString::fromUtf8(tokens.takeFirst()).trimmed(); + QString value = QString::fromUtf8(tokens.takeFirst()).trimmed(); + QTC_ASSERT(value.size() >= 2, continue); + QTC_ASSERT(value.front() == QChar('"'), continue); + QTC_ASSERT(value.back() == QChar('"'), continue); + value.remove(0, 1); + value.remove(value.size() - 1, 1); + + if (name == "binDir") + result.binDir = value; + else if (name == "srcDir") + result.srcDir = value; + else if (name == "bin") { + QStringList bin = value.split(','); + bin = Utils::transform(bin, [](const QString &x){ return x.trimmed(); }); + Utils::erase(bin, [](const QString &x) { return x.isEmpty(); }); + result.bin = std::move(bin); + } + } + + return result; +} + +} + +NimbleBuildSystem::NimbleBuildSystem(Project *project) + : NimBuildSystem(project) +{ +} + +void NimbleBuildSystem::parseProject(BuildSystem::ParsingContext &&ctx) +{ + NimBuildSystem::parseProject(std::move(ctx)); +} + +void NimbleBuildSystem::updateProject() +{ + updateProjectMetaData(); + updateProjectTasks(); +} + +void NimbleBuildSystem::init() +{ + // Not called in parseProject due to nimble behavior to create temporary + // files in project directory. This creation in turn stimulate the fs watcher + // that in turn causes project parsing (thus a loop if invoke in parseProject). + // For this reason we call this function manually during project creation + // See https://github.com/nim-lang/nimble/issues/720 + m_directoryWatcher.addFile(project()->projectFilePath().toString(), FileSystemWatcher::WatchModifiedDate); + connect(&m_directoryWatcher, &FileSystemWatcher::fileChanged, this, [this](const QString &path) { + if (path == project()->projectFilePath().toString()) { + updateProject(); + } + }); + updateProject(); +} + +void NimbleBuildSystem::updateProjectTasks() +{ + auto prj = dynamic_cast<NimbleProject*>(project()); + QTC_ASSERT(prj, return); + prj->setTasks(parseTasks(QStandardPaths::findExecutable("nimble"), project()->projectDirectory().toString())); +} + +void NimbleBuildSystem::updateProjectMetaData() +{ + auto prj = dynamic_cast<NimbleProject*>(project()); + QTC_ASSERT(prj, return); + prj->setMetadata(parseMetadata(QStandardPaths::findExecutable("nimble"), project()->projectDirectory().toString())); +} diff --git a/src/plugins/nim/project/nimblebuildsystem.h b/src/plugins/nim/project/nimblebuildsystem.h new file mode 100644 index 0000000000..4ffd9185e7 --- /dev/null +++ b/src/plugins/nim/project/nimblebuildsystem.h @@ -0,0 +1,49 @@ +/**************************************************************************** +** +** Copyright (C) Filippo Cucchetto <filippocucchetto@gmail.com> +** Contact: http://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 <nim/project/nimbuildsystem.h> + +namespace Nim { + +class NimbleBuildSystem : public NimBuildSystem +{ + Q_OBJECT + +public: + NimbleBuildSystem(ProjectExplorer::Project *project); + + void init(); + +protected: + void parseProject(ParsingContext &&ctx) override; + + void updateProject(); + void updateProjectTasks(); + void updateProjectMetaData(); +}; + +} diff --git a/src/plugins/nim/project/nimbleproject.cpp b/src/plugins/nim/project/nimbleproject.cpp new file mode 100644 index 0000000000..067c647e97 --- /dev/null +++ b/src/plugins/nim/project/nimbleproject.cpp @@ -0,0 +1,112 @@ +/**************************************************************************** +** +** Copyright (C) Filippo Cucchetto <filippocucchetto@gmail.com> +** Contact: http://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 "nimbleproject.h" +#include "nimconstants.h" +#include "nimblebuildsystem.h" + +#include <coreplugin/icontext.h> +#include <projectexplorer/projectexplorerconstants.h> +#include <utils/qtcassert.h> + +using namespace Nim; +using namespace ProjectExplorer; + +NimbleProject::NimbleProject(const Utils::FilePath &fileName) + : ProjectExplorer::Project(Constants::C_NIMBLE_MIMETYPE, fileName) +{ + setId(Constants::C_NIMBLEPROJECT_ID); + setDisplayName(fileName.toFileInfo().completeBaseName()); + // ensure debugging is enabled (Nim plugin translates nim code to C code) + setProjectLanguages(Core::Context(ProjectExplorer::Constants::CXX_LANGUAGE_ID)); + auto bs = std::make_unique<NimbleBuildSystem>(this); + bs->init(); + setBuildSystem(std::move(bs)); +} + +std::vector<NimbleTask> NimbleProject::tasks() const +{ + return m_tasks; +} + +NimbleMetadata NimbleProject::metadata() const +{ + return m_metadata; +} + +void NimbleProject::setTasks(std::vector<NimbleTask> tasks) +{ + if (tasks == m_tasks) + return; + m_tasks = std::move(tasks); + emit tasksChanged(m_tasks); +} + +void NimbleProject::setMetadata(NimbleMetadata metadata) +{ + if (m_metadata == metadata) + return; + m_metadata = std::move(metadata); + emit metadataChanged(m_metadata); +} + +QVariantMap NimbleProject::toMap() const +{ + QVariantMap result = Project::toMap(); + result[Constants::C_NIMPROJECT_EXCLUDEDFILES] = static_cast<NimBuildSystem *>(buildSystem()) + ->excludedFiles(); + result[Constants::C_NIMBLEPROJECT_TASKS] = toStringList(m_tasks); + return result; +} + +Project::RestoreResult NimbleProject::fromMap(const QVariantMap &map, QString *errorMessage) +{ + static_cast<NimBuildSystem *>(buildSystem()) + ->setExcludedFiles(map.value(Constants::C_NIMPROJECT_EXCLUDEDFILES).toStringList()); + Project::RestoreResult result = Project::RestoreResult::Error; + std::tie(result, m_tasks) = fromStringList(map.value(Constants::C_NIMBLEPROJECT_TASKS).toStringList()); + return result == Project::RestoreResult::Ok ? Project::fromMap(map, errorMessage) : result; +} + +QStringList NimbleProject::toStringList(const std::vector<NimbleTask> &tasks) +{ + QStringList result; + for (const NimbleTask &task : tasks) { + result.push_back(task.name); + result.push_back(task.description); + } + return result; +} + +std::tuple<Project::RestoreResult, std::vector<NimbleTask>> NimbleProject::fromStringList(const QStringList &list) +{ + if (list.size() % 2 != 0) + return {Project::RestoreResult::Error, {}}; + + std::vector<NimbleTask> result; + for (int i = 0; i < list.size(); i += 2) + result.push_back({list[i], list[i + 1]}); + return {Project::RestoreResult::Ok, std::move(result)}; +} diff --git a/src/plugins/nim/project/nimbleproject.h b/src/plugins/nim/project/nimbleproject.h new file mode 100644 index 0000000000..e3c7cf9358 --- /dev/null +++ b/src/plugins/nim/project/nimbleproject.h @@ -0,0 +1,88 @@ +/**************************************************************************** +** +** Copyright (C) Filippo Cucchetto <filippocucchetto@gmail.com> +** Contact: http://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 <projectexplorer/project.h> + +namespace Nim { + +struct NimbleTask +{ + QString name; + QString description; + + bool operator==(const NimbleTask &o) const { + return name == o.name && description == o.description; + } +}; + +struct NimbleMetadata +{ + QStringList bin; + QString binDir; + QString srcDir; + + bool operator==(const NimbleMetadata &o) const { + return bin == o.bin && binDir == o.binDir && srcDir == o.srcDir; + } +}; + +class NimbleProject : public ProjectExplorer::Project +{ + Q_OBJECT + +public: + NimbleProject(const Utils::FilePath &filename); + + std::vector<NimbleTask> tasks() const; + + NimbleMetadata metadata() const; + + void setTasks(std::vector<NimbleTask> tasks); + + void setMetadata(NimbleMetadata metadata); + + // Keep for compatibility with Qt Creator 4.10 + QVariantMap toMap() const final; + +signals: + void tasksChanged(std::vector<NimbleTask>); + void metadataChanged(NimbleMetadata); + +protected: + // Keep for compatibility with Qt Creator 4.10 + RestoreResult fromMap(const QVariantMap &map, QString *errorMessage) final; + +private: + static QStringList toStringList(const std::vector<NimbleTask> &tasks); + + static std::tuple<RestoreResult, std::vector<NimbleTask>> fromStringList(const QStringList &list); + + NimbleMetadata m_metadata; + std::vector<NimbleTask> m_tasks; +}; + +} diff --git a/src/plugins/nim/project/nimblerunconfiguration.cpp b/src/plugins/nim/project/nimblerunconfiguration.cpp new file mode 100644 index 0000000000..4e4748ebd8 --- /dev/null +++ b/src/plugins/nim/project/nimblerunconfiguration.cpp @@ -0,0 +1,110 @@ +/**************************************************************************** +** +** Copyright (C) Filippo Cucchetto <filippocucchetto@gmail.com> +** Contact: http://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 "nimblerunconfiguration.h" +#include "nimconstants.h" +#include "nimbleproject.h" + +#include <projectexplorer/localenvironmentaspect.h> +#include <projectexplorer/runconfigurationaspects.h> +#include <projectexplorer/runcontrol.h> +#include <projectexplorer/target.h> + +#include <utils/algorithm.h> +#include <utils/environment.h> + +using namespace Nim; +using namespace ProjectExplorer; + +NimbleRunConfiguration::NimbleRunConfiguration(ProjectExplorer::Target *target, Core::Id id) + : RunConfiguration(target, id) +{ + auto project = dynamic_cast<NimbleProject*>(target->project()); + QTC_ASSERT(project, return); + + addAspect<LocalEnvironmentAspect>(target); + addAspect<ExecutableAspect>(); + addAspect<ArgumentsAspect>(); + addAspect<WorkingDirectoryAspect>(); + addAspect<TerminalAspect>(); + + connect(project, &Project::parsingFinished, + this, &NimbleRunConfiguration::updateTargetInformation); + connect(project, &NimbleProject::metadataChanged, + this, &NimbleRunConfiguration::updateTargetInformation); + connect(project, &NimbleProject::tasksChanged, + this, &NimbleRunConfiguration::updateTargetInformation); + + updateTargetInformation(); +} + +NimbleRunConfiguration::~NimbleRunConfiguration() +{ + +} + +void NimbleRunConfiguration::updateTargetInformation() +{ + BuildTargetInfo bti = buildTargetInfo(); + setDisplayName(bti.displayName); + setDefaultDisplayName(bti.displayName); + aspect<ExecutableAspect>()->setExecutable(bti.targetFilePath); + aspect<WorkingDirectoryAspect>()->setDefaultWorkingDirectory(bti.workingDirectory); +} + +bool NimbleRunConfiguration::isBuildTargetValid() const +{ + return Utils::anyOf(target()->applicationTargets(), [this](const BuildTargetInfo &bti) { + return bti.buildKey == buildKey(); + }); +} + +QString NimbleRunConfiguration::disabledReason() const +{ + if (!isBuildTargetValid()) + return tr("The project no longer builds the target associated with this run configuration."); + return RunConfiguration::disabledReason(); +} + +void NimbleRunConfiguration::updateEnabledState() +{ + if (!isBuildTargetValid()) + setEnabled(false); + else + RunConfiguration::updateEnabledState(); +} + +NimbleRunConfigurationFactory::NimbleRunConfigurationFactory() + : RunConfigurationFactory() +{ + registerRunConfiguration<NimbleRunConfiguration>("Nim.NimbleRunConfiguration"); + addSupportedProjectType(Constants::C_NIMBLEPROJECT_ID); + addSupportedTargetDeviceType(ProjectExplorer::Constants::DESKTOP_DEVICE_TYPE); +} + +QList<RunConfigurationCreationInfo> NimbleRunConfigurationFactory::availableCreators(Target *parent) const +{ + return RunConfigurationFactory::availableCreators(parent); +} diff --git a/src/plugins/nim/project/nimblerunconfiguration.h b/src/plugins/nim/project/nimblerunconfiguration.h new file mode 100644 index 0000000000..b273fd4f2b --- /dev/null +++ b/src/plugins/nim/project/nimblerunconfiguration.h @@ -0,0 +1,61 @@ +/**************************************************************************** +** +** Copyright (C) 2016 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 <projectexplorer/runconfiguration.h> + +namespace Nim { + +class NimbleRunConfiguration : public ProjectExplorer::RunConfiguration +{ + Q_OBJECT + +public: + NimbleRunConfiguration(ProjectExplorer::Target *target, Core::Id id); + + ~NimbleRunConfiguration(); + + QString disabledReason() const override; + +protected: + void updateEnabledState() override; + +private: + void updateTargetInformation(); + + bool isBuildTargetValid() const; +}; + +class NimbleRunConfigurationFactory : public ProjectExplorer::RunConfigurationFactory +{ +public: + NimbleRunConfigurationFactory(); + +protected: + QList<ProjectExplorer::RunConfigurationCreationInfo> availableCreators(ProjectExplorer::Target *parent) const override; +}; + +} diff --git a/src/plugins/nim/project/nimbletaskstep.cpp b/src/plugins/nim/project/nimbletaskstep.cpp new file mode 100644 index 0000000000..8a6ce49de9 --- /dev/null +++ b/src/plugins/nim/project/nimbletaskstep.cpp @@ -0,0 +1,132 @@ +/**************************************************************************** +** +** Copyright (C) Filippo Cucchetto <filippocucchetto@gmail.com> +** Contact: http://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 "nimbletaskstep.h" +#include "nimbletaskstepwidget.h" +#include "nimconstants.h" +#include "nimbleproject.h" + +#include <projectexplorer/buildstep.h> +#include <projectexplorer/buildconfiguration.h> +#include <projectexplorer/processparameters.h> +#include <utils/fileutils.h> + +#include <QStandardPaths> + +using namespace Nim; +using namespace ProjectExplorer; + +NimbleTaskStep::NimbleTaskStep(BuildStepList *parentList) + : AbstractProcessStep(parentList, Constants::C_NIMBLETASKSTEP_ID) +{ + setDefaultDisplayName(tr(Constants::C_NIMBLETASKSTEP_DISPLAY)); + setDisplayName(tr(Constants::C_NIMBLETASKSTEP_DISPLAY)); +} + +bool NimbleTaskStep::init() +{ + processParameters()->setEnvironment(buildConfiguration()->environment()); + processParameters()->setWorkingDirectory(project()->projectDirectory()); + return validate() && AbstractProcessStep::init(); +} + +BuildStepConfigWidget *NimbleTaskStep::createConfigWidget() +{ + return new NimbleTaskStepWidget(this); +} + +bool NimbleTaskStep::fromMap(const QVariantMap &map) +{ + setTaskName(map.value(Constants::C_NIMBLETASKSTEP_TASKNAME, QString()).toString()); + setTaskArgs(map.value(Constants::C_NIMBLETASKSTEP_TASKARGS, QString()).toString()); + return validate() ? AbstractProcessStep::fromMap(map) : false; +} + +QVariantMap NimbleTaskStep::toMap() const +{ + QVariantMap result = AbstractProcessStep::toMap(); + result[Constants::C_NIMBLETASKSTEP_TASKNAME] = taskName(); + result[Constants::C_NIMBLETASKSTEP_TASKARGS] = taskArgs(); + return result; +} + +void NimbleTaskStep::setTaskName(const QString &name) +{ + if (m_taskName == name) + return; + m_taskName = name; + emit taskNameChanged(name); + updateCommandLine(); +} + +void NimbleTaskStep::setTaskArgs(const QString &args) +{ + if (m_taskArgs == args) + return; + m_taskArgs = args; + emit taskArgsChanged(args); + updateCommandLine(); +} + +void NimbleTaskStep::updateCommandLine() +{ + QString args = m_taskName + " " + m_taskArgs; + Utils::CommandLine commandLine(Utils::FilePath::fromString(QStandardPaths::findExecutable("nimble")), + args, Utils::CommandLine::Raw); + + processParameters()->setCommandLine(commandLine); +} + +bool NimbleTaskStep::validate() +{ + if (m_taskName.isEmpty()) + return true; + + auto nimbleProject = dynamic_cast<NimbleProject*>(project()); + QTC_ASSERT(nimbleProject, return false); + + if (!Utils::contains(nimbleProject->tasks(), [this](const NimbleTask &task){ return task.name == m_taskName; })) { + emit addTask(Task(Task::Error, + tr("Nimble task %1 not found").arg(m_taskName), + Utils::FilePath(), -1, + ProjectExplorer::Constants::TASK_CATEGORY_BUILDSYSTEM)); + + emitFaultyConfigurationMessage(); + return false; + } + + return true; +} + +NimbleTaskStepFactory::NimbleTaskStepFactory() +{ + registerStep<NimbleTaskStep>(Constants::C_NIMBLETASKSTEP_ID); + setDisplayName(NimbleTaskStep::tr("Nimble Task")); + setSupportedStepLists({ProjectExplorer::Constants::BUILDSTEPS_BUILD, + ProjectExplorer::Constants::BUILDSTEPS_CLEAN, + ProjectExplorer::Constants::BUILDSTEPS_DEPLOY}); + setSupportedConfiguration(Constants::C_NIMBLEBUILDCONFIGURATION_ID); + setRepeatable(true); +} diff --git a/src/plugins/nim/project/nimbletaskstep.h b/src/plugins/nim/project/nimbletaskstep.h new file mode 100644 index 0000000000..47cf507a8d --- /dev/null +++ b/src/plugins/nim/project/nimbletaskstep.h @@ -0,0 +1,75 @@ +/**************************************************************************** +** +** Copyright (C) Filippo Cucchetto <filippocucchetto@gmail.com> +** Contact: http://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 <projectexplorer/processstep.h> + +namespace Nim { + +class NimbleTaskStep : public ProjectExplorer::AbstractProcessStep +{ + Q_OBJECT + +public: + NimbleTaskStep(ProjectExplorer::BuildStepList *parentList); + + bool init() override; + + ProjectExplorer::BuildStepConfigWidget *createConfigWidget() override; + + bool fromMap(const QVariantMap &map) override; + + QVariantMap toMap() const override; + + QString taskName() const { return m_taskName; } + + void setTaskName(const QString &name); + + QString taskArgs() const { return m_taskArgs; } + + void setTaskArgs(const QString &args); + +signals: + void taskNameChanged(const QString &name); + + void taskArgsChanged(const QString &args); + +private: + void updateCommandLine(); + + bool validate(); + + QString m_taskName; + QString m_taskArgs; +}; + +class NimbleTaskStepFactory : public ProjectExplorer::BuildStepFactory +{ +public: + NimbleTaskStepFactory(); +}; + +} diff --git a/src/plugins/nim/project/nimbletaskstepwidget.cpp b/src/plugins/nim/project/nimbletaskstepwidget.cpp new file mode 100644 index 0000000000..6d33fdcbe6 --- /dev/null +++ b/src/plugins/nim/project/nimbletaskstepwidget.cpp @@ -0,0 +1,157 @@ +/**************************************************************************** +** +** Copyright (C) Filippo Cucchetto <filippocucchetto@gmail.com> +** Contact: http://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 "nimbletaskstepwidget.h" +#include "ui_nimbletaskstepwidget.h" + +#include "nimbleproject.h" +#include "nimbletaskstep.h" + +#include <utils/algorithm.h> + +using namespace Nim; +using namespace ProjectExplorer; + +NimbleTaskStepWidget::NimbleTaskStepWidget(NimbleTaskStep *bs) + : BuildStepConfigWidget(bs) + , ui(new Ui::NimbleTaskStepWidget) +{ + ui->setupUi(this); + + auto project = dynamic_cast<NimbleProject*>(bs->project()); + QTC_ASSERT(project, return); + + ui->taskList->setModel(&m_tasks); + QObject::connect(&m_tasks, &QAbstractItemModel::dataChanged, this, &NimbleTaskStepWidget::onDataChanged); + + updateTaskList(project->tasks()); + QObject::connect(project, &NimbleProject::tasksChanged, this, &NimbleTaskStepWidget::updateTaskList); + + selectTask(bs->taskName()); + QObject::connect(bs, &NimbleTaskStep::taskNameChanged, this, &NimbleTaskStepWidget::selectTask); + QObject::connect(bs, &NimbleTaskStep::taskNameChanged, this, &NimbleTaskStepWidget::recreateSummary); + QObject::connect(this, &NimbleTaskStepWidget::selectedTaskChanged, bs, &NimbleTaskStep::setTaskName); + + ui->taskArgumentsLineEdit->setText(bs->taskArgs()); + QObject::connect(bs, &NimbleTaskStep::taskArgsChanged, ui->taskArgumentsLineEdit, &QLineEdit::setText); + QObject::connect(bs, &NimbleTaskStep::taskArgsChanged, this, &NimbleTaskStepWidget::recreateSummary); + QObject::connect(ui->taskArgumentsLineEdit, &QLineEdit::textChanged, bs ,&NimbleTaskStep::setTaskArgs); + + + setSummaryUpdater([this, bs] { + return QString("<b>%1:</b> nimble %2 %3") + .arg(displayName()) + .arg(bs->taskName()) + .arg(bs->taskArgs()); + }); +} + +NimbleTaskStepWidget::~NimbleTaskStepWidget() +{ + delete ui; +} + +void NimbleTaskStepWidget::updateTaskList(const std::vector<NimbleTask> &tasks) +{ + QSet<QString> newTasks; + for (const NimbleTask &t : tasks) + newTasks.insert(t.name); + + QSet<QString> currentTasks; + for (int i = 0; i < m_tasks.rowCount(); ++i) + currentTasks.insert(m_tasks.item(i)->text()); + + const QSet<QString> added = newTasks - currentTasks; + const QSet<QString> removed = currentTasks - newTasks; + + for (const QString &name : added) { + auto item = new QStandardItem(); + item->setText(name); + item->setCheckable(true); + item->setCheckState(Qt::Unchecked); + item->setEditable(false); + item->setSelectable(false); + m_tasks.appendRow(item); + } + + for (int i = m_tasks.rowCount() - 1; i >= 0; i--) + if (removed.contains(m_tasks.item(i)->text())) + m_tasks.removeRow(i); + + m_tasks.sort(0); +} + +void NimbleTaskStepWidget::selectTask(const QString &name) +{ + if (m_selecting) + return; + m_selecting = true; + + QList<QStandardItem*> items = m_tasks.findItems(name); + QStandardItem* item = items.empty() ? nullptr : items.front(); + uncheckedAllDifferentFrom(item); + if (item) + item->setCheckState(Qt::Checked); + + emit selectedTaskChanged(name); + + m_selecting = false; +} + +void NimbleTaskStepWidget::onDataChanged(const QModelIndex &topLeft, + const QModelIndex &bottomRight, + const QVector<int> &roles) +{ + QTC_ASSERT(topLeft == bottomRight, return ); + if (!roles.contains(Qt::CheckStateRole)) + return; + + auto item = m_tasks.itemFromIndex(topLeft); + if (!item) + return; + + if (m_selecting) + return; + m_selecting = true; + + if (item->checkState() == Qt::Checked) { + uncheckedAllDifferentFrom(item); + emit selectedTaskChanged(item->text()); + } else if (item->checkState() == Qt::Unchecked) { + emit selectedTaskChanged(QString()); + } + + m_selecting = false; +} + +void NimbleTaskStepWidget::uncheckedAllDifferentFrom(QStandardItem *toSkip) +{ + for (int i = 0; i < m_tasks.rowCount(); ++i) { + auto item = m_tasks.item(i); + if (!item || item == toSkip) + continue; + item->setCheckState(Qt::Unchecked); + } +} diff --git a/src/plugins/nim/project/nimbletaskstepwidget.h b/src/plugins/nim/project/nimbletaskstepwidget.h new file mode 100644 index 0000000000..73e15dcd05 --- /dev/null +++ b/src/plugins/nim/project/nimbletaskstepwidget.h @@ -0,0 +1,66 @@ +/**************************************************************************** +** +** Copyright (C) Filippo Cucchetto <filippocucchetto@gmail.com> +** Contact: http://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 <projectexplorer/buildstep.h> + +#include <nim/project/nimbleproject.h> + +#include <QStandardItemModel> + +namespace Nim { + +class NimbleTaskStep; + +namespace Ui { class NimbleTaskStepWidget; } + +class NimbleTaskStepWidget : public ProjectExplorer::BuildStepConfigWidget +{ + Q_OBJECT + +public: + explicit NimbleTaskStepWidget(NimbleTaskStep *buildStep); + + ~NimbleTaskStepWidget(); + +signals: + void selectedTaskChanged(const QString &name); + +private: + void updateTaskList(const std::vector<NimbleTask> &tasks); + + void selectTask(const QString &name); + + void onDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector<int> &roles); + + void uncheckedAllDifferentFrom(QStandardItem *item); + + Ui::NimbleTaskStepWidget *ui; + QStandardItemModel m_tasks; + bool m_selecting = false; +}; + +} diff --git a/src/plugins/nim/project/nimbletaskstepwidget.ui b/src/plugins/nim/project/nimbletaskstepwidget.ui new file mode 100644 index 0000000000..223c2ed404 --- /dev/null +++ b/src/plugins/nim/project/nimbletaskstepwidget.ui @@ -0,0 +1,82 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>Nim::NimbleTaskStepWidget</class> + <widget class="QWidget" name="Nim::NimbleTaskStepWidget"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>399</width> + <height>252</height> + </rect> + </property> + <property name="windowTitle"> + <string>Form</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <layout class="QFormLayout" name="formLayout"> + <property name="sizeConstraint"> + <enum>QLayout::SetDefaultConstraint</enum> + </property> + <property name="fieldGrowthPolicy"> + <enum>QFormLayout::ExpandingFieldsGrow</enum> + </property> + <item row="0" column="0"> + <widget class="QLabel" name="taskArgumentsLabel"> + <property name="text"> + <string>Task arguments:</string> + </property> + </widget> + </item> + <item row="0" column="1"> + <widget class="QLineEdit" name="taskArgumentsLineEdit"/> + </item> + <item row="1" column="0"> + <widget class="QLabel" name="tasksLabel"> + <property name="text"> + <string>Tasks:</string> + </property> + </widget> + </item> + <item row="1" column="1"> + <widget class="QFrame" name="tasksFrame"> + <property name="frameShape"> + <enum>QFrame::StyledPanel</enum> + </property> + <layout class="QHBoxLayout" name="horizontalLayout"> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <item> + <widget class="QListView" name="taskList"> + <property name="frameShape"> + <enum>QFrame::NoFrame</enum> + </property> + <property name="selectionMode"> + <enum>QAbstractItemView::NoSelection</enum> + </property> + <property name="selectionBehavior"> + <enum>QAbstractItemView::SelectRows</enum> + </property> + </widget> + </item> + </layout> + </widget> + </item> + </layout> + </item> + </layout> + </widget> + <resources/> + <connections/> +</ui> diff --git a/src/plugins/nim/project/nimbuildsystem.cpp b/src/plugins/nim/project/nimbuildsystem.cpp index 21b87702ea..740f42dec8 100644 --- a/src/plugins/nim/project/nimbuildsystem.cpp +++ b/src/plugins/nim/project/nimbuildsystem.cpp @@ -25,7 +25,7 @@ #include "nimbuildsystem.h" -#include "nimproject.h" +#include "nimbleproject.h" #include "nimprojectnode.h" #include <utils/algorithm.h> @@ -51,12 +51,14 @@ NimBuildSystem::NimBuildSystem(Project *project) connect(&m_scanner, &TreeScanner::finished, this, &NimBuildSystem::updateProject); m_scanner.setFilter([this](const Utils::MimeType &, const Utils::FilePath &fp) { const QString path = fp.toString(); - return excludedFiles().contains(path) || path.endsWith(".nimproject") - || path.contains(".nimproject.user"); + return excludedFiles().contains(path) + || path.endsWith(".nimproject") + || path.contains(".nimproject.user"); }); - connect(&m_directoryWatcher, &FileSystemWatcher::directoryChanged, this, [this]() { - requestParse(); + connect(&m_directoryWatcher, &FileSystemWatcher::directoryChanged, this, [this] { + if (!isWaitingForParse()) + requestDelayedParse(); }); } @@ -100,14 +102,14 @@ void NimBuildSystem::parseProject(BuildSystem::ParsingContext &&ctx) QTC_ASSERT(!m_currentContext.project, return ); m_currentContext = std::move(ctx); QTC_CHECK(m_currentContext.project); - m_scanner.asyncScanForFiles(m_currentContext.project->projectDirectory()); } const FilePathList NimBuildSystem::nimFiles() const { - return project()->files( - [](const Node *n) { return Project::AllFiles(n) && n->path().endsWith(".nim"); }); + return project()->files([](const Node *n) { + return Project::AllFiles(n) && n->path().endsWith(".nim"); + }); } void NimBuildSystem::loadSettings() @@ -128,23 +130,33 @@ void NimBuildSystem::saveSettings() void NimBuildSystem::updateProject() { - auto newRoot = std::make_unique<NimProjectNode>(project()->projectDirectory()); - - QSet<QString> directories; + // Collect scanned nodes + std::vector<std::unique_ptr<FileNode>> nodes; for (FileNode *node : m_scanner.release()) { - if (!node->path().endsWith(".nim")) + if (!node->path().endsWith(".nim") && !node->path().endsWith(".nimble")) node->setEnabled(false); // Disable files that do not end in .nim - directories.insert(node->directory()); - newRoot->addNestedNode(std::unique_ptr<FileNode>(node)); + nodes.emplace_back(node); } - newRoot->setDisplayName(project()->displayName()); - project()->setRootProjectNode(std::move(newRoot)); - - m_directoryWatcher.addDirectories(Utils::toList(directories), FileSystemWatcher::WatchAllChanges); + // Sync watched dirs + const QSet<QString> fsDirs = Utils::transform<QSet>(nodes, &FileNode::directory); + const QSet<QString> projectDirs = m_directoryWatcher.directories().toSet(); + m_directoryWatcher.addDirectories(Utils::toList(fsDirs - projectDirs), FileSystemWatcher::WatchAllChanges); + m_directoryWatcher.removeDirectories(Utils::toList(projectDirs - fsDirs)); + + // Sync project files + const QSet<FilePath> fsFiles = Utils::transform<QSet>(nodes, &FileNode::filePath); + const QSet<FilePath> projectFiles = project()->files([](const Node *n) { return Project::AllFiles(n); }).toSet(); + + if (fsFiles != projectFiles) { + auto projectNode = std::make_unique<ProjectNode>(project()->projectDirectory()); + projectNode->setDisplayName(project()->displayName()); + projectNode->addNestedNodes(std::move(nodes)); + project()->setRootProjectNode(std::move(projectNode)); + } + // Complete scan m_currentContext.guard.markAsSuccess(); - m_currentContext = {}; } diff --git a/src/plugins/nim/project/nimbuildsystem.h b/src/plugins/nim/project/nimbuildsystem.h index b725cf4d9d..686bab3aca 100644 --- a/src/plugins/nim/project/nimbuildsystem.h +++ b/src/plugins/nim/project/nimbuildsystem.h @@ -58,11 +58,11 @@ public: void setExcludedFiles(const QStringList &list); // Keep for compatibility with Qt Creator 4.10 QStringList excludedFiles(); // Make private when no longer supporting Qt Creator 4.10 - void parseProject(ParsingContext &&ctx) final; + void parseProject(ParsingContext &&ctx) override; const Utils::FilePathList nimFiles() const; -private: +protected: void loadSettings(); void saveSettings(); |