Haskell: More compact settings/manager setup

Use PagedSettings, move related parts Manager interface there, too.

Change-Id: I079dad8bbbea39d2424a25867b08c34ab0234ad5
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
Reviewed-by: Eike Ziller <eike.ziller@qt.io>
This commit is contained in:
hjk
2023-05-15 15:15:17 +02:00
parent 21cb45e665
commit 22fa5f2d3a
12 changed files with 95 additions and 165 deletions

View File

@@ -12,9 +12,9 @@ add_qtc_plugin(Haskell
haskellplugin.cpp haskellplugin.h
haskellproject.cpp haskellproject.h
haskellrunconfiguration.cpp haskellrunconfiguration.h
haskellsettings.cpp haskellsettings.h
haskelltokenizer.cpp haskelltokenizer.h
haskelltr.h
optionspage.cpp optionspage.h
stackbuildstep.cpp stackbuildstep.h
)

View File

@@ -21,8 +21,8 @@ QtcPlugin {
"haskellplugin.cpp", "haskellplugin.h",
"haskellproject.cpp", "haskellproject.h",
"haskellrunconfiguration.cpp", "haskellrunconfiguration.h",
"haskellsettings.cpp", "haskellsettings.h",
"haskelltokenizer.cpp", "haskelltokenizer.h",
"optionspage.cpp", "optionspage.h",
"stackbuildstep.cpp", "stackbuildstep.h"
]
}

View File

@@ -14,17 +14,14 @@
#include <texteditor/texteditoractionhandler.h>
#include <texteditor/textindenter.h>
#include <QCoreApplication>
namespace Haskell::Internal {
namespace Haskell {
namespace Internal {
static QWidget *createEditorWidget()
static QWidget *createEditorWidget(QObject *guard)
{
auto widget = new TextEditor::TextEditorWidget;
auto ghciButton = new Core::CommandButton(Constants::A_RUN_GHCI, widget);
ghciButton->setText(Tr::tr("GHCi"));
QObject::connect(ghciButton, &QToolButton::clicked, HaskellManager::instance(), [widget] {
QObject::connect(ghciButton, &QToolButton::clicked, guard, [widget] {
HaskellManager::openGhci(widget->textDocument()->filePath());
});
widget->insertExtraToolBarWidget(TextEditor::TextEditorWidget::Left, ghciButton);
@@ -40,12 +37,11 @@ HaskellEditorFactory::HaskellEditorFactory()
| TextEditor::TextEditorActionHandler::FollowSymbolUnderCursor);
setDocumentCreator([] { return new TextEditor::TextDocument(Constants::C_HASKELLEDITOR_ID); });
setIndenterCreator([](QTextDocument *doc) { return new TextEditor::TextIndenter(doc); });
setEditorWidgetCreator(createEditorWidget);
setEditorWidgetCreator([this] { return createEditorWidget(this); });
setCommentDefinition(Utils::CommentDefinition("--", "{-", "-}"));
setParenthesesMatchingEnabled(true);
setMarksVisible(true);
setSyntaxHighlighterCreator([] { return new HaskellHighlighter(); });
}
} // Internal
} // Haskell
} // Haskell::Internal

View File

@@ -5,8 +5,7 @@
#include <texteditor/texteditor.h>
namespace Haskell {
namespace Internal {
namespace Haskell::Internal {
class HaskellEditorFactory : public TextEditor::TextEditorFactory
{
@@ -14,5 +13,4 @@ public:
HaskellEditorFactory();
};
} // Internal
} // Haskell
} // Haskell::Internal

View File

@@ -3,9 +3,9 @@
#include "haskellmanager.h"
#include "haskellsettings.h"
#include "haskelltr.h"
#include <coreplugin/messagemanager.h>
#include <utils/algorithm.h>
#include <utils/commandline.h>
#include <utils/hostosinfo.h>
@@ -13,33 +13,12 @@
#include <utils/process.h>
#include <utils/processenums.h>
#include <QCoreApplication>
#include <QDir>
#include <QFileInfo>
#include <QSettings>
#include <unordered_map>
static const char kStackExecutableKey[] = "Haskell/StackExecutable";
using namespace Utils;
namespace Haskell {
namespace Internal {
class HaskellManagerPrivate
{
public:
FilePath stackExecutable;
};
Q_GLOBAL_STATIC(HaskellManagerPrivate, m_d)
Q_GLOBAL_STATIC(HaskellManager, m_instance)
HaskellManager *HaskellManager::instance()
{
return m_instance;
}
namespace Haskell::Internal {
FilePath HaskellManager::findProjectDirectory(const FilePath &filePath)
{
@@ -57,28 +36,6 @@ FilePath HaskellManager::findProjectDirectory(const FilePath &filePath)
return {};
}
FilePath defaultStackExecutable()
{
// stack from brew or the installer script from https://docs.haskellstack.org
// install to /usr/local/bin.
if (HostOsInfo::isAnyUnixHost())
return FilePath::fromString("/usr/local/bin/stack");
return FilePath::fromString("stack");
}
FilePath HaskellManager::stackExecutable()
{
return m_d->stackExecutable;
}
void HaskellManager::setStackExecutable(const FilePath &filePath)
{
if (filePath == m_d->stackExecutable)
return;
m_d->stackExecutable = filePath;
emit m_instance->stackExecutableChanged(m_d->stackExecutable);
}
void HaskellManager::openGhci(const FilePath &haskellFile)
{
const QList<MimeType> mimeTypes = mimeTypesForFileName(haskellFile.toString());
@@ -89,25 +46,9 @@ void HaskellManager::openGhci(const FilePath &haskellFile)
+ (isHaskell ? QStringList{haskellFile.fileName()} : QStringList());
Process p;
p.setTerminalMode(TerminalMode::Detached);
p.setCommand({stackExecutable(), args});
p.setCommand({settings().stackPath.filePath(), args});
p.setWorkingDirectory(haskellFile.absolutePath());
p.start();
}
void HaskellManager::readSettings(QSettings *settings)
{
m_d->stackExecutable = FilePath::fromString(
settings->value(kStackExecutableKey, defaultStackExecutable().toString()).toString());
emit m_instance->stackExecutableChanged(m_d->stackExecutable);
}
void HaskellManager::writeSettings(QSettings *settings)
{
if (m_d->stackExecutable == defaultStackExecutable())
settings->remove(kStackExecutableKey);
else
settings->setValue(kStackExecutableKey, m_d->stackExecutable.toString());
}
} // namespace Internal
} // namespace Haskell
} // Haskell::Internal

View File

@@ -7,30 +7,15 @@
#include <utils/fileutils.h>
QT_BEGIN_NAMESPACE
class QSettings;
QT_END_NAMESPACE
namespace Haskell::Internal {
namespace Haskell {
namespace Internal {
class HaskellManager : public QObject
class HaskellManager
{
Q_OBJECT
public:
static HaskellManager *instance();
static Utils::FilePath findProjectDirectory(const Utils::FilePath &filePath);
static Utils::FilePath stackExecutable();
static void setStackExecutable(const Utils::FilePath &filePath);
static void openGhci(const Utils::FilePath &haskellFile);
static void readSettings(QSettings *settings);
static void writeSettings(QSettings *settings);
signals:
void stackExecutableChanged(const Utils::FilePath &filePath);
};
} // namespace Internal
} // namespace Haskell
} // Haskell::Internal

View File

@@ -9,8 +9,8 @@
#include "haskellmanager.h"
#include "haskellproject.h"
#include "haskellrunconfiguration.h"
#include "haskellsettings.h"
#include "haskelltr.h"
#include "optionspage.h"
#include "stackbuildstep.h"
#include <coreplugin/actionmanager/actionmanager.h>
@@ -28,8 +28,8 @@ namespace Internal {
class HaskellPluginPrivate
{
public:
HaskellSettings settings;
HaskellEditorFactory editorFactory;
OptionsPage optionsPage;
HaskellBuildConfigurationFactory buildConfigFactory;
StackBuildStepFactory stackBuildStepFactory;
HaskellRunConfigurationFactory runConfigFactory;
@@ -41,11 +41,11 @@ HaskellPlugin::~HaskellPlugin()
delete d;
}
static void registerGhciAction()
static void registerGhciAction(QObject *guard)
{
QAction *action = new QAction(Tr::tr("Run GHCi"), HaskellManager::instance());
QAction *action = new QAction(Tr::tr("Run GHCi"), guard);
Core::ActionManager::registerAction(action, Constants::A_RUN_GHCI);
QObject::connect(action, &QAction::triggered, HaskellManager::instance(), [] {
QObject::connect(action, &QAction::triggered, guard, [] {
if (Core::IDocument *doc = Core::EditorManager::currentDocument())
HaskellManager::openGhci(doc->filePath());
});
@@ -63,13 +63,7 @@ bool HaskellPlugin::initialize(const QStringList &arguments, QString *errorStrin
TextEditor::SnippetProvider::registerGroup(Constants::C_HASKELLSNIPPETSGROUP_ID,
Tr::tr("Haskell", "SnippetProvider"));
connect(Core::ICore::instance(), &Core::ICore::saveSettingsRequested, this, [] {
HaskellManager::writeSettings(Core::ICore::settings());
});
registerGhciAction();
HaskellManager::readSettings(Core::ICore::settings());
registerGhciAction(this);
ProjectExplorer::JsonWizardFactory::addWizardPath(":/haskell/share/wizards/");
return true;

View File

@@ -4,9 +4,9 @@
#include "haskellrunconfiguration.h"
#include "haskellconstants.h"
#include "haskellmanager.h"
#include "haskellproject.h"
#include "haskelltr.h"
#include "haskellsettings.h"
#include <projectexplorer/buildconfiguration.h>
#include <projectexplorer/localenvironmentaspect.h>
@@ -68,7 +68,7 @@ Runnable HaskellRunConfiguration::runnable() const
r.workingDirectory = projectDirectory;
r.environment = aspect<LocalEnvironmentAspect>()->environment();
r.command = {r.environment.searchInPath(HaskellManager::stackExecutable().toString()), args};
r.command = {r.environment.searchInPath(settings().stackPath()), args};
return r;
}

View File

@@ -0,0 +1,63 @@
// Copyright (c) 2017 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include "haskellsettings.h"
#include "haskellconstants.h"
#include "haskelltr.h"
#include <coreplugin/icore.h>
#include <utils/hostosinfo.h>
#include <utils/pathchooser.h>
#include <utils/layoutbuilder.h>
using namespace Utils;
namespace Haskell::Internal {
static HaskellSettings *theSettings;
HaskellSettings &settings()
{
return *theSettings;
}
HaskellSettings::HaskellSettings()
{
theSettings = this;
setId(Constants::OPTIONS_GENERAL);
setDisplayName(Tr::tr("General"));
setCategory("J.Z.Haskell");
setDisplayCategory(Tr::tr("Haskell"));
setCategoryIconPath(":/haskell/images/settingscategory_haskell.png");
registerAspect(&stackPath);
stackPath.setSettingsKey("Haskell/StackExecutable");
stackPath.setDisplayStyle(StringAspect::PathChooserDisplay);
stackPath.setExpectedKind(PathChooser::ExistingCommand);
stackPath.setPromptDialogTitle(Tr::tr("Choose Stack Executable"));
stackPath.setCommandVersionArguments({"--version"});
// stack from brew or the installer script from https://docs.haskellstack.org
// install to /usr/local/bin.
stackPath.setDefaultFilePath(HostOsInfo::isAnyUnixHost()
? FilePath::fromString("/usr/local/bin/stack")
: FilePath::fromString("stack"));
setLayouter([this](QWidget *widget) {
using namespace Layouting;
Column {
Group {
title(Tr::tr("General")),
Row { Tr::tr("Stack executable:"), stackPath }
},
st,
}.attachTo(widget);
});
readSettings(Core::ICore::settings());
}
} // Haskell::Internal

View File

@@ -7,10 +7,14 @@
namespace Haskell::Internal {
class OptionsPage : public Core::IOptionsPage
class HaskellSettings : public Core::PagedSettings
{
public:
OptionsPage();
HaskellSettings();
Utils::StringAspect stackPath;
};
HaskellSettings &settings();
} // Haskell::Internal

View File

@@ -1,51 +0,0 @@
// Copyright (c) 2017 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include "optionspage.h"
#include "haskellconstants.h"
#include "haskellmanager.h"
#include "haskelltr.h"
#include <utils/pathchooser.h>
#include <utils/layoutbuilder.h>
using namespace Utils;
namespace Haskell::Internal {
class HaskellOptionsPageWidget : public Core::IOptionsPageWidget
{
public:
HaskellOptionsPageWidget()
{
auto stackPath = new PathChooser;
stackPath->setExpectedKind(PathChooser::ExistingCommand);
stackPath->setPromptDialogTitle(Tr::tr("Choose Stack Executable"));
stackPath->setFilePath(HaskellManager::stackExecutable());
stackPath->setCommandVersionArguments({"--version"});
setOnApply([stackPath] { HaskellManager::setStackExecutable(stackPath->rawFilePath()); });
using namespace Layouting;
Column {
Group {
title(Tr::tr("General")),
Row { Tr::tr("Stack executable:"), stackPath }
},
st,
}.attachTo(this);
}
};
OptionsPage::OptionsPage()
{
setId(Constants::OPTIONS_GENERAL);
setDisplayName(Tr::tr("General"));
setCategory("J.Z.Haskell");
setDisplayCategory(Tr::tr("Haskell"));
setCategoryIconPath(":/haskell/images/settingscategory_haskell.png");
setWidgetCreator([] { return new HaskellOptionsPageWidget; });
}
} // Haskell::Internal

View File

@@ -4,7 +4,7 @@
#include "stackbuildstep.h"
#include "haskellconstants.h"
#include "haskellmanager.h"
#include "haskellsettings.h"
#include "haskelltr.h"
#include <projectexplorer/buildconfiguration.h>
@@ -38,7 +38,7 @@ bool StackBuildStep::init()
if (AbstractProcessStep::init()) {
const auto projectDir = QDir(project()->projectDirectory().toString());
processParameters()->setCommandLine(
{HaskellManager::stackExecutable(),
{settings().stackPath.filePath(),
{"build", "--work-dir", projectDir.relativeFilePath(buildDirectory().toString())}});
processParameters()->setEnvironment(buildEnvironment());
}