aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEike Ziller <git@eikeziller.de>2017-09-25 11:57:51 +0200
committerEike Ziller <git@eikeziller.de>2017-10-01 20:11:08 +0200
commitce0bd485ee6ff54099b564730f82ac7667b0fa08 (patch)
tree22657699d7231cfbe2e3a96c1fc3a5cedcc6b2b4
parent3f1f50c44847a0e76a95507c9566a35dfe809a78 (diff)
Initial Haskell project support
Shows all files from the file system tree around the .cabal file. Provides a simple build configuration with "stack build" step. Provides a simple run configuration with "stack exec" for each "executable" entry.
-rw-r--r--plugins/haskell/Haskell.json.in13
-rw-r--r--plugins/haskell/haskell.pro13
-rw-r--r--plugins/haskell/haskellbuildconfiguration.cpp200
-rw-r--r--plugins/haskell/haskellbuildconfiguration.h85
-rw-r--r--plugins/haskell/haskellconstants.h2
-rw-r--r--plugins/haskell/haskellplugin.cpp11
-rw-r--r--plugins/haskell/haskellproject.cpp122
-rw-r--r--plugins/haskell/haskellproject.h57
-rw-r--r--plugins/haskell/haskellrunconfiguration.cpp156
-rw-r--r--plugins/haskell/haskellrunconfiguration.h73
-rw-r--r--plugins/haskell/stackbuildstep.cpp105
-rw-r--r--plugins/haskell/stackbuildstep.h59
12 files changed, 892 insertions, 4 deletions
diff --git a/plugins/haskell/Haskell.json.in b/plugins/haskell/Haskell.json.in
index daecf89..fe8767b 100644
--- a/plugins/haskell/Haskell.json.in
+++ b/plugins/haskell/Haskell.json.in
@@ -7,5 +7,16 @@
\"License\" : \"MIT\",
\"Description\" : \"Haskell support\",
\"Url\" : \"https://haskell.org\",
- $$dependencyList
+ $$dependencyList,
+
+ \"Mimetypes\" : [
+ \"<?xml version=\'1.0\'?>\",
+ \"<mime-info xmlns=\'http://www.freedesktop.org/standards/shared-mime-info\'>\",
+ \" <mime-type type=\'text/x-haskell-project\'>\",
+ \" <sub-class-of type=\'text/plain\'/>\",
+ \" <comment>Haskell Cabal project file</comment>\",
+ \" <glob pattern=\'*.cabal\'/>\",
+ \" </mime-type>\",
+ \"</mime-info>\"
+ ]
}
diff --git a/plugins/haskell/haskell.pro b/plugins/haskell/haskell.pro
index 2c9739a..92d0307 100644
--- a/plugins/haskell/haskell.pro
+++ b/plugins/haskell/haskell.pro
@@ -15,7 +15,11 @@ SOURCES += \
optionspage.cpp \
filecache.cpp \
haskelleditorwidget.cpp \
- followsymbol.cpp
+ followsymbol.cpp \
+ haskellproject.cpp \
+ haskellbuildconfiguration.cpp \
+ stackbuildstep.cpp \
+ haskellrunconfiguration.cpp
HEADERS += \
haskell_global.h \
@@ -32,7 +36,11 @@ HEADERS += \
optionspage.h \
filecache.h \
haskelleditorwidget.h \
- followsymbol.h
+ followsymbol.h \
+ haskellproject.h \
+ haskellbuildconfiguration.h \
+ stackbuildstep.h \
+ haskellrunconfiguration.h
## uncomment to build plugin into user config directory
## <localappdata>/plugins/<ideversion>
@@ -52,6 +60,7 @@ QTC_LIB_DEPENDS += \
QTC_PLUGIN_DEPENDS += \
coreplugin \
+ projectexplorer \
texteditor
QTC_PLUGIN_RECOMMENDS += \
diff --git a/plugins/haskell/haskellbuildconfiguration.cpp b/plugins/haskell/haskellbuildconfiguration.cpp
new file mode 100644
index 0000000..0412340
--- /dev/null
+++ b/plugins/haskell/haskellbuildconfiguration.cpp
@@ -0,0 +1,200 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 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 "haskellbuildconfiguration.h"
+
+#include "haskellconstants.h"
+#include "haskellproject.h"
+#include "stackbuildstep.h"
+
+#include <projectexplorer/buildinfo.h>
+#include <projectexplorer/buildsteplist.h>
+#include <projectexplorer/project.h>
+#include <projectexplorer/projectexplorerconstants.h>
+#include <projectexplorer/target.h>
+#include <utils/algorithm.h>
+#include <utils/detailswidget.h>
+#include <utils/mimetypes/mimedatabase.h>
+#include <utils/pathchooser.h>
+#include <utils/qtcassert.h>
+
+#include <QHBoxLayout>
+#include <QLabel>
+#include <QVBoxLayout>
+
+using namespace ProjectExplorer;
+
+const char C_HASKELL_BUILDCONFIGURATION_ID[] = "Haskell.BuildConfiguration";
+
+namespace Haskell {
+namespace Internal {
+
+HaskellBuildConfigurationFactory::HaskellBuildConfigurationFactory() {}
+
+int HaskellBuildConfigurationFactory::priority(const Target *parent) const
+{
+ return HaskellProject::isHaskellProject(parent->project()) ? 0 : -1;
+}
+
+static QList<BuildInfo *> createInfos(const HaskellBuildConfigurationFactory *factory,
+ const Kit *k,
+ const Utils::FileName &projectFilePath)
+{
+ auto info = new BuildInfo(factory);
+ info->typeName = HaskellBuildConfigurationFactory::tr("Release");
+ info->displayName = info->typeName;
+ info->buildDirectory = projectFilePath.parentDir().appendPath(".stack-work");
+ info->kitId = k->id();
+ info->buildType = BuildConfiguration::BuildType::Release;
+ return {info};
+}
+
+QList<BuildInfo *> HaskellBuildConfigurationFactory::availableBuilds(const Target *parent) const
+{
+ // Entries that are available in add build configuration dropdown
+ QTC_ASSERT(priority(parent) > -1, return {});
+ return Utils::transform(createInfos(this, parent->kit(), parent->project()->projectFilePath()),
+ [](BuildInfo *info) {
+ info->displayName.clear();
+ return info;
+ });
+}
+
+int HaskellBuildConfigurationFactory::priority(const Kit *k, const QString &projectPath) const
+{
+ if (k && Utils::mimeTypeForFile(projectPath).matchesName(Constants::C_HASKELL_PROJECT_MIMETYPE))
+ return 0;
+ return -1;
+}
+
+QList<BuildInfo *> HaskellBuildConfigurationFactory::availableSetups(
+ const Kit *k, const QString &projectPath) const
+{
+ QTC_ASSERT(priority(k, projectPath) > -1, return {});
+ return createInfos(this, k, Utils::FileName::fromString(projectPath));
+}
+
+BuildConfiguration *HaskellBuildConfigurationFactory::create(Target *parent,
+ const BuildInfo *info) const
+{
+ QTC_ASSERT(HaskellProject::isHaskellProject(parent->project()), return nullptr);
+ auto config = new HaskellBuildConfiguration(parent);
+ config->setBuildDirectory(info->buildDirectory);
+ config->setBuildType(info->buildType);
+ config->setDisplayName(info->displayName);
+
+ BuildStepList *buildSteps = config->stepList(Core::Id(ProjectExplorer::Constants::BUILDSTEPS_BUILD));
+ auto stackBuildStep = new StackBuildStep(buildSteps);
+ buildSteps->appendStep(stackBuildStep);
+
+ return config;
+}
+
+bool HaskellBuildConfigurationFactory::canRestore(const Target *parent, const QVariantMap &map) const
+{
+ Q_UNUSED(map)
+ return HaskellProject::isHaskellProject(parent->project());
+}
+
+BuildConfiguration *HaskellBuildConfigurationFactory::restore(Target *parent, const QVariantMap &map)
+{
+ QTC_ASSERT(canRestore(parent, map), return nullptr);
+ auto config = new HaskellBuildConfiguration(parent);
+ config->fromMap(map);
+ return config;
+}
+
+bool HaskellBuildConfigurationFactory::canClone(const Target *parent,
+ BuildConfiguration *product) const
+{
+ Q_UNUSED(parent)
+ return product->id() == C_HASKELL_BUILDCONFIGURATION_ID;
+}
+
+BuildConfiguration *HaskellBuildConfigurationFactory::clone(Target *parent,
+ BuildConfiguration *product)
+{
+ QTC_ASSERT(canClone(parent, product), return nullptr);
+ auto config = new HaskellBuildConfiguration(parent);
+ config->fromMap(product->toMap());
+ return config;
+}
+
+HaskellBuildConfiguration::HaskellBuildConfiguration(Target *target)
+ : BuildConfiguration(target, C_HASKELL_BUILDCONFIGURATION_ID)
+{}
+
+NamedWidget *HaskellBuildConfiguration::createConfigWidget()
+{
+ return new HaskellBuildConfigurationWidget(this);
+}
+
+BuildConfiguration::BuildType HaskellBuildConfiguration::buildType() const
+{
+ return m_buildType;
+}
+
+void HaskellBuildConfiguration::setBuildType(BuildConfiguration::BuildType type)
+{
+ m_buildType = type;
+}
+
+HaskellBuildConfigurationWidget::HaskellBuildConfigurationWidget(HaskellBuildConfiguration *bc)
+ : NamedWidget()
+ , m_buildConfiguration(bc)
+{
+ setDisplayName(tr("General"));
+ setLayout(new QVBoxLayout);
+ layout()->setMargin(0);
+ auto box = new Utils::DetailsWidget;
+ box->setState(Utils::DetailsWidget::NoSummary);
+ layout()->addWidget(box);
+ auto details = new QWidget;
+ box->setWidget(details);
+ details->setLayout(new QHBoxLayout);
+ details->layout()->setMargin(0);
+ details->layout()->addWidget(new QLabel(tr("Build directory:")));
+
+ auto buildDirectoryInput = new Utils::PathChooser;
+ buildDirectoryInput->setExpectedKind(Utils::PathChooser::Directory);
+ buildDirectoryInput->setFileName(m_buildConfiguration->buildDirectory());
+ details->layout()->addWidget(buildDirectoryInput);
+
+ connect(m_buildConfiguration,
+ &BuildConfiguration::buildDirectoryChanged,
+ buildDirectoryInput,
+ [this, buildDirectoryInput] {
+ buildDirectoryInput->setFileName(m_buildConfiguration->buildDirectory());
+ });
+ connect(buildDirectoryInput,
+ &Utils::PathChooser::pathChanged,
+ m_buildConfiguration,
+ [this, buildDirectoryInput](const QString &) {
+ m_buildConfiguration->setBuildDirectory(buildDirectoryInput->rawFileName());
+ });
+}
+
+} // namespace Internal
+} // namespace Haskell
diff --git a/plugins/haskell/haskellbuildconfiguration.h b/plugins/haskell/haskellbuildconfiguration.h
new file mode 100644
index 0000000..56ec088
--- /dev/null
+++ b/plugins/haskell/haskellbuildconfiguration.h
@@ -0,0 +1,85 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 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/buildconfiguration.h>
+#include <projectexplorer/namedwidget.h>
+
+namespace Haskell {
+namespace Internal {
+
+class HaskellBuildConfigurationFactory : public ProjectExplorer::IBuildConfigurationFactory
+{
+ Q_OBJECT
+
+public:
+ HaskellBuildConfigurationFactory();
+
+ int priority(const ProjectExplorer::Target *parent) const override;
+ QList<ProjectExplorer::BuildInfo *> availableBuilds(
+ const ProjectExplorer::Target *parent) const override;
+ int priority(const ProjectExplorer::Kit *k, const QString &projectPath) const override;
+ QList<ProjectExplorer::BuildInfo *> availableSetups(const ProjectExplorer::Kit *k,
+ const QString &projectPath) const override;
+ ProjectExplorer::BuildConfiguration *create(
+ ProjectExplorer::Target *parent, const ProjectExplorer::BuildInfo *info) const override;
+ bool canRestore(const ProjectExplorer::Target *parent, const QVariantMap &map) const override;
+ ProjectExplorer::BuildConfiguration *restore(ProjectExplorer::Target *parent,
+ const QVariantMap &map) override;
+ bool canClone(const ProjectExplorer::Target *parent,
+ ProjectExplorer::BuildConfiguration *product) const override;
+ ProjectExplorer::BuildConfiguration *clone(
+ ProjectExplorer::Target *parent, ProjectExplorer::BuildConfiguration *product) override;
+};
+
+class HaskellBuildConfiguration : public ProjectExplorer::BuildConfiguration
+{
+ Q_OBJECT
+
+public:
+ explicit HaskellBuildConfiguration(ProjectExplorer::Target *target);
+
+ ProjectExplorer::NamedWidget *createConfigWidget() override;
+ BuildType buildType() const override;
+ void setBuildType(BuildType type);
+
+private:
+ BuildType m_buildType = BuildType::Release;
+};
+
+class HaskellBuildConfigurationWidget : public ProjectExplorer::NamedWidget
+{
+ Q_OBJECT
+
+public:
+ HaskellBuildConfigurationWidget(HaskellBuildConfiguration *bc);
+
+private:
+ HaskellBuildConfiguration *m_buildConfiguration;
+};
+
+} // namespace Internal
+} // namespace Haskell
diff --git a/plugins/haskell/haskellconstants.h b/plugins/haskell/haskellconstants.h
index 55be670..1ff285c 100644
--- a/plugins/haskell/haskellconstants.h
+++ b/plugins/haskell/haskellconstants.h
@@ -30,6 +30,8 @@ namespace Constants {
const char C_HASKELLEDITOR_ID[] = "Haskell.HaskellEditor";
const char C_HASKELLSNIPPETSGROUP_ID[] = "Haskell";
+const char C_HASKELL_PROJECT_MIMETYPE[] = "text/x-haskell-project";
+const char C_HASKELL_RUNCONFIG_ID_PREFIX[] = "Haskell.Run.";
} // namespace Haskell
} // namespace Constants
diff --git a/plugins/haskell/haskellplugin.cpp b/plugins/haskell/haskellplugin.cpp
index 362e00f..c5386a4 100644
--- a/plugins/haskell/haskellplugin.cpp
+++ b/plugins/haskell/haskellplugin.cpp
@@ -26,12 +26,17 @@
#include "haskellplugin.h"
#include "ghcmod.h"
+#include "haskellbuildconfiguration.h"
#include "haskellconstants.h"
#include "haskelleditorfactory.h"
#include "haskellmanager.h"
+#include "haskellproject.h"
+#include "haskellrunconfiguration.h"
#include "optionspage.h"
+#include "stackbuildstep.h"
#include <coreplugin/icore.h>
+#include <projectexplorer/projectmanager.h>
#include <texteditor/snippets/snippetprovider.h>
namespace Haskell {
@@ -62,7 +67,11 @@ bool HaskellPlugin::initialize(const QStringList &arguments, QString *errorStrin
addAutoReleasedObject(new HaskellEditorFactory);
addAutoReleasedObject(new OptionsPage);
-
+ addAutoReleasedObject(new HaskellBuildConfigurationFactory);
+ addAutoReleasedObject(new StackBuildStepFactory);
+ addAutoReleasedObject(new HaskellRunConfigurationFactory);
+ ProjectExplorer::ProjectManager::registerProjectType<HaskellProject>(
+ Constants::C_HASKELL_PROJECT_MIMETYPE);
TextEditor::SnippetProvider::registerGroup(Constants::C_HASKELLSNIPPETSGROUP_ID,
tr("Haskell", "SnippetProvider"));
diff --git a/plugins/haskell/haskellproject.cpp b/plugins/haskell/haskellproject.cpp
new file mode 100644
index 0000000..96855ee
--- /dev/null
+++ b/plugins/haskell/haskellproject.cpp
@@ -0,0 +1,122 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 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 "haskellproject.h"
+
+#include "haskellconstants.h"
+
+#include <coreplugin/iversioncontrol.h>
+#include <coreplugin/vcsmanager.h>
+#include <utils/algorithm.h>
+#include <utils/fileutils.h>
+#include <utils/runextensions.h>
+
+#include <QFile>
+#include <QTextStream>
+
+using namespace ProjectExplorer;
+using namespace Utils;
+
+const char C_HASKELL_PROJECT_ID[] = "Haskell.Project";
+
+namespace Haskell {
+namespace Internal {
+
+static QVector<QString> parseExecutableNames(const FileName &projectFilePath)
+{
+ static const QString EXECUTABLE = "executable";
+ static const int EXECUTABLE_LEN = EXECUTABLE.length();
+ QVector<QString> result;
+ QFile file(projectFilePath.toString());
+ if (file.open(QFile::ReadOnly)) {
+ QTextStream stream(&file);
+ while (!stream.atEnd()) {
+ const QString line = stream.readLine().trimmed();
+ if (line.length() > EXECUTABLE_LEN && line.startsWith(EXECUTABLE)
+ && line.at(EXECUTABLE_LEN).isSpace())
+ result.append(line.mid(EXECUTABLE_LEN + 1).trimmed());
+ }
+ }
+ return result;
+}
+
+HaskellProjectNode::HaskellProjectNode(const FileName &projectFilePath, Core::Id id)
+ : ProjectNode(projectFilePath, id.toString().toLatin1())
+{}
+
+HaskellProject::HaskellProject(const Utils::FileName &fileName)
+ : Project(Constants::C_HASKELL_PROJECT_MIMETYPE, fileName)
+{
+ setId(C_HASKELL_PROJECT_ID);
+ setDisplayName(fileName.toFileInfo().completeBaseName());
+ updateFiles();
+}
+
+bool HaskellProject::isHaskellProject(Project *project)
+{
+ return project && project->id() == C_HASKELL_PROJECT_ID;
+}
+
+HaskellProject *HaskellProject::toHaskellProject(Project *project)
+{
+ if (project && project->id() == C_HASKELL_PROJECT_ID)
+ return static_cast<HaskellProject *>(project);
+ return nullptr;
+}
+
+QList<Core::Id> HaskellProject::availableRunConfigurationIds() const
+{
+ return Utils::transform<QList>(parseExecutableNames(projectFilePath()), [](const QString &exe) {
+ return Core::Id(Constants::C_HASKELL_RUNCONFIG_ID_PREFIX).withSuffix(exe);
+ });
+}
+
+void HaskellProject::updateFiles()
+{
+ emitParsingStarted();
+ FileName projectDir = projectDirectory();
+ const QList<Core::IVersionControl *> versionControls = Core::VcsManager::versionControls();
+ QFuture<QList<FileNode *>> future = Utils::runAsync([this, projectDir, versionControls] {
+ return FileNode::scanForFilesWithVersionControls(
+ projectDir,
+ [this](const FileName &fn) -> FileNode * {
+ if (fn != FileName::fromString(projectFilePath().toString() + ".user"))
+ return new FileNode(fn, FileType::Source, false);
+ else
+ return nullptr;
+ },
+ versionControls);
+ });
+ Utils::onResultReady(future, this, [this](const QList<FileNode *> &nodes) {
+ auto root = new HaskellProjectNode(projectDirectory(), id());
+ root->setDisplayName(displayName());
+ root->addNestedNodes(nodes);
+ setRootProjectNode(root);
+ emitParsingFinished(true);
+ });
+}
+
+} // namespace Internal
+} // namespace Haskell
diff --git a/plugins/haskell/haskellproject.h b/plugins/haskell/haskellproject.h
new file mode 100644
index 0000000..cc6e308
--- /dev/null
+++ b/plugins/haskell/haskellproject.h
@@ -0,0 +1,57 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 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/project.h>
+#include <projectexplorer/projectnodes.h>
+
+namespace Haskell {
+namespace Internal {
+
+class HaskellProjectNode : public ProjectExplorer::ProjectNode
+{
+public:
+ HaskellProjectNode(const Utils::FileName &projectFilePath, Core::Id id);
+};
+
+class HaskellProject : public ProjectExplorer::Project
+{
+ Q_OBJECT
+
+public:
+ explicit HaskellProject(const Utils::FileName &fileName);
+
+ static bool isHaskellProject(Project *project);
+ static HaskellProject *toHaskellProject(Project *project);
+
+ QList<Core::Id> availableRunConfigurationIds() const;
+
+private:
+ void updateFiles();
+};
+
+} // namespace Internal
+} // namespace Haskell
diff --git a/plugins/haskell/haskellrunconfiguration.cpp b/plugins/haskell/haskellrunconfiguration.cpp
new file mode 100644
index 0000000..dfeee7e
--- /dev/null
+++ b/plugins/haskell/haskellrunconfiguration.cpp
@@ -0,0 +1,156 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 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 "haskellrunconfiguration.h"
+
+#include "haskellconstants.h"
+#include "haskellmanager.h"
+#include "haskellproject.h"
+
+#include <projectexplorer/buildconfiguration.h>
+#include <projectexplorer/localenvironmentaspect.h>
+#include <projectexplorer/runconfigurationaspects.h>
+#include <projectexplorer/runnables.h>
+#include <projectexplorer/target.h>
+#include <utils/detailswidget.h>
+
+#include <QFormLayout>
+
+using namespace ProjectExplorer;
+
+namespace Haskell {
+namespace Internal {
+
+HaskellRunConfigurationFactory::HaskellRunConfigurationFactory() {}
+
+QList<Core::Id> HaskellRunConfigurationFactory::availableCreationIds(
+ Target *parent,
+ IRunConfigurationFactory::CreationMode mode) const
+{
+ Q_UNUSED(mode)
+ const auto project = HaskellProject::toHaskellProject(parent->project());
+ if (project)
+ return project->availableRunConfigurationIds();
+ return {};
+}
+
+QString HaskellRunConfigurationFactory::displayNameForId(Core::Id id) const
+{
+ return id.suffixAfter(Constants::C_HASKELL_RUNCONFIG_ID_PREFIX);
+}
+
+bool HaskellRunConfigurationFactory::canCreate(Target *parent, Core::Id id) const
+{
+ return id.name().startsWith(Constants::C_HASKELL_RUNCONFIG_ID_PREFIX)
+ && HaskellProject::isHaskellProject(parent->project());
+}
+
+bool HaskellRunConfigurationFactory::canRestore(Target *parent, const QVariantMap &map) const
+{
+ return canCreate(parent, idFromMap(map));
+}
+
+bool HaskellRunConfigurationFactory::canClone(Target *parent, RunConfiguration *product) const
+{
+ return canCreate(parent, product->id());
+}
+
+RunConfiguration *HaskellRunConfigurationFactory::clone(Target *parent, RunConfiguration *product)
+{
+ return cloneHelper<HaskellRunConfiguration>(parent, product);
+}
+
+RunConfiguration *HaskellRunConfigurationFactory::doCreate(Target *parent, Core::Id id)
+{
+ QTC_ASSERT(canCreate(parent, id), return nullptr);
+ return createHelper<HaskellRunConfiguration>(parent, id);
+}
+
+RunConfiguration *HaskellRunConfigurationFactory::doRestore(Target *parent, const QVariantMap &map)
+{
+ QTC_ASSERT(canRestore(parent, map), return nullptr);
+ auto config = doCreate(parent, idFromMap(map));
+ config->fromMap(map);
+ return config;
+}
+
+HaskellRunConfiguration::HaskellRunConfiguration(Target *parent)
+ : RunConfiguration(parent)
+{
+ auto argumentAspect = new ArgumentsAspect(this, "Haskell.RunAspect.Arguments");
+ auto workingDirAspect = new WorkingDirectoryAspect(this, "Haskell.RunAspect.WorkingDirectory");
+ workingDirAspect->setDefaultWorkingDirectory(parent->project()->projectDirectory());
+ auto terminalAspect = new TerminalAspect(this, "Haskell.RunAspect.Terminal");
+ auto environmentAspect
+ = new LocalEnvironmentAspect(this, LocalEnvironmentAspect::BaseEnvironmentModifier());
+ addExtraAspect(argumentAspect);
+ addExtraAspect(terminalAspect);
+ addExtraAspect(environmentAspect);
+}
+
+QWidget *HaskellRunConfiguration::createConfigurationWidget()
+{
+ auto details = new Utils::DetailsWidget;
+ details->setState(Utils::DetailsWidget::NoSummary);
+ auto widget = new QWidget;
+ details->setWidget(widget);
+ auto layout = new QFormLayout(widget);
+ layout->setMargin(0);
+ layout->setFieldGrowthPolicy(QFormLayout::ExpandingFieldsGrow);
+ extraAspect<ArgumentsAspect>()->addToMainConfigurationWidget(widget, layout);
+ extraAspect<TerminalAspect>()->addToMainConfigurationWidget(widget, layout);
+ return details;
+}
+
+Runnable HaskellRunConfiguration::runnable() const
+{
+ const QString projectDirectory = target()->project()->projectDirectory().toString();
+ StandardRunnable r;
+ if (BuildConfiguration *buildConfiguration = target()->activeBuildConfiguration())
+ r.commandLineArguments += "--work-dir \""
+ + QDir(projectDirectory)
+ .relativeFilePath(
+ buildConfiguration->buildDirectory().toString())
+ + "\" ";
+ r.commandLineArguments += "exec \"" + m_executable + "\"";
+ auto argumentsAspect = extraAspect<ArgumentsAspect>();
+ if (!argumentsAspect->arguments().isEmpty())
+ r.commandLineArguments += " -- " + argumentsAspect->arguments();
+ r.workingDirectory = projectDirectory;
+ r.runMode = extraAspect<TerminalAspect>()->runMode();
+ r.environment = extraAspect<LocalEnvironmentAspect>()->environment();
+ r.executable = r.environment.searchInPath(HaskellManager::stackExecutable().toString()).toString();
+ return r;
+}
+
+void HaskellRunConfiguration::initialize(Core::Id id)
+{
+ RunConfiguration::initialize(id);
+ m_executable = id.suffixAfter(Constants::C_HASKELL_RUNCONFIG_ID_PREFIX);
+ setDefaultDisplayName(m_executable);
+}
+
+} // namespace Internal
+} // namespace Haskell
diff --git a/plugins/haskell/haskellrunconfiguration.h b/plugins/haskell/haskellrunconfiguration.h
new file mode 100644
index 0000000..44edfe6
--- /dev/null
+++ b/plugins/haskell/haskellrunconfiguration.h
@@ -0,0 +1,73 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 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 Haskell {
+namespace Internal {
+
+class HaskellRunConfigurationFactory : public ProjectExplorer::IRunConfigurationFactory
+{
+ Q_OBJECT
+
+public:
+ HaskellRunConfigurationFactory();
+
+ QList<Core::Id> availableCreationIds(ProjectExplorer::Target *parent,
+ CreationMode mode) const override;
+ QString displayNameForId(Core::Id id) const override;
+ bool canCreate(ProjectExplorer::Target *parent, Core::Id id) const override;
+ bool canRestore(ProjectExplorer::Target *parent, const QVariantMap &map) const override;
+ bool canClone(ProjectExplorer::Target *parent,
+ ProjectExplorer::RunConfiguration *product) const override;
+ ProjectExplorer::RunConfiguration *clone(ProjectExplorer::Target *parent,
+ ProjectExplorer::RunConfiguration *product) override;
+
+private:
+ ProjectExplorer::RunConfiguration *doCreate(ProjectExplorer::Target *parent,
+ Core::Id id) override;
+ ProjectExplorer::RunConfiguration *doRestore(ProjectExplorer::Target *parent,
+ const QVariantMap &map) override;
+};
+
+class HaskellRunConfiguration : public ProjectExplorer::RunConfiguration
+{
+ Q_OBJECT
+
+public:
+ HaskellRunConfiguration(ProjectExplorer::Target *parent);
+
+ QWidget *createConfigurationWidget() override;
+ ProjectExplorer::Runnable runnable() const override;
+ void initialize(Core::Id id);
+
+private:
+ QString m_executable;
+};
+
+} // namespace Internal
+} // namespace Haskell
diff --git a/plugins/haskell/stackbuildstep.cpp b/plugins/haskell/stackbuildstep.cpp
new file mode 100644
index 0000000..f4b1cfb
--- /dev/null
+++ b/plugins/haskell/stackbuildstep.cpp
@@ -0,0 +1,105 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 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 "stackbuildstep.h"
+
+#include "haskellmanager.h"
+
+#include <projectexplorer/buildconfiguration.h>
+#include <projectexplorer/project.h>
+
+using namespace ProjectExplorer;
+
+const char C_STACK_BUILD_STEP_ID[] = "Haskell.Stack.Build";
+
+namespace Haskell {
+namespace Internal {
+
+StackBuildStep::StackBuildStep(ProjectExplorer::BuildStepList *bsl)
+ : AbstractProcessStep(bsl, C_STACK_BUILD_STEP_ID)
+{
+ setDefaultDisplayName(trDisplayName());
+
+ const auto updateArguments = [this] {
+ const auto projectDir = QDir(project()->projectDirectory().toString());
+ processParameters()->setArguments(
+ "build --work-dir \""
+ + projectDir.relativeFilePath(buildConfiguration()->buildDirectory().toString()) + "\"");
+ };
+ const auto updateEnvironment = [this] {
+ processParameters()->setEnvironment(buildConfiguration()->environment());
+ };
+ processParameters()->setCommand(HaskellManager::stackExecutable().toString());
+ updateArguments();
+ processParameters()->setWorkingDirectory(project()->projectDirectory().toString());
+ updateEnvironment();
+ connect(HaskellManager::instance(),
+ &HaskellManager::stackExecutableChanged,
+ this,
+ [this](const Utils::FileName &stackExe) {
+ processParameters()->setCommand(stackExe.toString());
+ });
+ connect(buildConfiguration(), &BuildConfiguration::buildDirectoryChanged, this, updateArguments);
+ connect(buildConfiguration(), &BuildConfiguration::environmentChanged, this, updateEnvironment);
+}
+
+BuildStepConfigWidget *StackBuildStep::createConfigWidget()
+{
+ return new SimpleBuildStepConfigWidget(this);
+}
+
+QString StackBuildStep::trDisplayName()
+{
+ return tr("Stack Build");
+}
+
+QList<BuildStepInfo> StackBuildStepFactory::availableSteps(BuildStepList *parent) const
+{
+ Q_UNUSED(parent)
+ return {BuildStepInfo(C_STACK_BUILD_STEP_ID, StackBuildStep::trDisplayName())};
+}
+
+BuildStep *StackBuildStepFactory::create(BuildStepList *parent, Core::Id id)
+{
+ Q_UNUSED(id)
+ return new StackBuildStep(parent);
+}
+
+BuildStep *StackBuildStepFactory::restore(BuildStepList *parent, const QVariantMap &map)
+{
+ auto step = new StackBuildStep(parent);
+ step->fromMap(map);
+ return step;
+}
+
+BuildStep *StackBuildStepFactory::clone(BuildStepList *parent, BuildStep *product)
+{
+ auto step = new StackBuildStep(parent);
+ step->fromMap(product->toMap());
+ return step;
+}
+
+} // namespace Internal
+} // namespace Haskell
diff --git a/plugins/haskell/stackbuildstep.h b/plugins/haskell/stackbuildstep.h
new file mode 100644
index 0000000..e786d18
--- /dev/null
+++ b/plugins/haskell/stackbuildstep.h
@@ -0,0 +1,59 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 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/abstractprocessstep.h>
+
+namespace Haskell {
+namespace Internal {
+
+class StackBuildStep : public ProjectExplorer::AbstractProcessStep
+{
+ Q_OBJECT
+
+public:
+ StackBuildStep(ProjectExplorer::BuildStepList *bsl);
+
+ ProjectExplorer::BuildStepConfigWidget *createConfigWidget() override;
+
+ static QString trDisplayName();
+};
+
+class StackBuildStepFactory : public ProjectExplorer::IBuildStepFactory
+{
+ // IBuildStepFactory interface
+public:
+ QList<ProjectExplorer::BuildStepInfo> availableSteps(
+ ProjectExplorer::BuildStepList *parent) const override;
+ ProjectExplorer::BuildStep *create(ProjectExplorer::BuildStepList *parent, Core::Id id) override;
+ ProjectExplorer::BuildStep *restore(ProjectExplorer::BuildStepList *parent,
+ const QVariantMap &map) override;
+ ProjectExplorer::BuildStep *clone(ProjectExplorer::BuildStepList *parent,
+ ProjectExplorer::BuildStep *product) override;
+};
+
+} // namespace Internal
+} // namespace Haskell