forked from qt-creator/qt-creator
Terminal: Use PageSettings for settings
The DropSupport is disabled for now, plan is to have a DropArea LayoutItem later and use that. Change-Id: I7fd1e55ad0c053f0357bb53a7cc20e9da8a933a7 Reviewed-by: Marcus Tillmanns <marcus.tillmanns@qt.io>
This commit is contained in:
@@ -12,11 +12,10 @@ add_qtc_plugin(Terminal
|
|||||||
terminal.qrc
|
terminal.qrc
|
||||||
terminalcommands.cpp terminalcommands.h
|
terminalcommands.cpp terminalcommands.h
|
||||||
terminalpane.cpp terminalpane.h
|
terminalpane.cpp terminalpane.h
|
||||||
terminalplugin.cpp terminalplugin.h
|
terminalplugin.cpp
|
||||||
terminalprocessimpl.cpp terminalprocessimpl.h
|
terminalprocessimpl.cpp terminalprocessimpl.h
|
||||||
terminalsearch.cpp terminalsearch.h
|
terminalsearch.cpp terminalsearch.h
|
||||||
terminalsettings.cpp terminalsettings.h
|
terminalsettings.cpp terminalsettings.h
|
||||||
terminalsettingspage.cpp terminalsettingspage.h
|
|
||||||
terminalsurface.cpp terminalsurface.h
|
terminalsurface.cpp terminalsurface.h
|
||||||
terminaltr.h
|
terminaltr.h
|
||||||
terminalwidget.cpp terminalwidget.h
|
terminalwidget.cpp terminalwidget.h
|
||||||
|
|||||||
@@ -27,15 +27,12 @@ QtcPlugin {
|
|||||||
"terminalpane.cpp",
|
"terminalpane.cpp",
|
||||||
"terminalpane.h",
|
"terminalpane.h",
|
||||||
"terminalplugin.cpp",
|
"terminalplugin.cpp",
|
||||||
"terminalplugin.h",
|
|
||||||
"terminalprocessimpl.cpp",
|
"terminalprocessimpl.cpp",
|
||||||
"terminalprocessimpl.h",
|
"terminalprocessimpl.h",
|
||||||
"terminalsearch.cpp",
|
"terminalsearch.cpp",
|
||||||
"terminalsearch.h",
|
"terminalsearch.h",
|
||||||
"terminalsettings.cpp",
|
"terminalsettings.cpp",
|
||||||
"terminalsettings.h",
|
"terminalsettings.h",
|
||||||
"terminalsettingspage.cpp",
|
|
||||||
"terminalsettingspage.h",
|
|
||||||
"terminalsurface.cpp",
|
"terminalsurface.cpp",
|
||||||
"terminalsurface.h",
|
"terminalsurface.h",
|
||||||
"terminaltr.h",
|
"terminaltr.h",
|
||||||
|
|||||||
@@ -151,7 +151,6 @@ TerminalPane::TerminalPane(QObject *parent)
|
|||||||
|
|
||||||
connect(m_escSettingButton, &QToolButton::toggled, this, [this] {
|
connect(m_escSettingButton, &QToolButton::toggled, this, [this] {
|
||||||
TerminalSettings::instance().sendEscapeToTerminal.setValue(m_escSettingButton->isChecked());
|
TerminalSettings::instance().sendEscapeToTerminal.setValue(m_escSettingButton->isChecked());
|
||||||
TerminalSettings::instance().apply();
|
|
||||||
TerminalSettings::instance().writeSettings(Core::ICore::settings());
|
TerminalSettings::instance().writeSettings(Core::ICore::settings());
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,9 @@
|
|||||||
// Copyright (C) 2016 The Qt Company Ltd.
|
// Copyright (C) 2016 The Qt Company Ltd.
|
||||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||||
|
|
||||||
#include "terminalplugin.h"
|
|
||||||
|
|
||||||
#include "terminalpane.h"
|
#include "terminalpane.h"
|
||||||
#include "terminalprocessimpl.h"
|
#include "terminalprocessimpl.h"
|
||||||
#include "terminalsettings.h"
|
#include "terminalsettings.h"
|
||||||
#include "terminalsettingspage.h"
|
|
||||||
#include "terminalcommands.h"
|
#include "terminalcommands.h"
|
||||||
|
|
||||||
#include <coreplugin/actionmanager/actioncontainer.h>
|
#include <coreplugin/actionmanager/actioncontainer.h>
|
||||||
@@ -16,6 +13,7 @@
|
|||||||
#include <coreplugin/imode.h>
|
#include <coreplugin/imode.h>
|
||||||
#include <coreplugin/modemanager.h>
|
#include <coreplugin/modemanager.h>
|
||||||
|
|
||||||
|
#include <extensionsystem/iplugin.h>
|
||||||
#include <extensionsystem/pluginmanager.h>
|
#include <extensionsystem/pluginmanager.h>
|
||||||
|
|
||||||
#include <QAction>
|
#include <QAction>
|
||||||
@@ -24,61 +22,70 @@
|
|||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
#include <QPushButton>
|
#include <QPushButton>
|
||||||
|
|
||||||
namespace Terminal {
|
namespace Terminal::Internal {
|
||||||
namespace Internal {
|
|
||||||
|
|
||||||
TerminalPlugin::TerminalPlugin() {}
|
class TerminalPlugin final : public ExtensionSystem::IPlugin
|
||||||
|
|
||||||
TerminalPlugin::~TerminalPlugin()
|
|
||||||
{
|
{
|
||||||
ExtensionSystem::PluginManager::instance()->removeObject(m_terminalPane);
|
Q_OBJECT
|
||||||
delete m_terminalPane;
|
Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QtCreatorPlugin" FILE "Terminal.json")
|
||||||
m_terminalPane = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool TerminalPlugin::delayedInitialize()
|
public:
|
||||||
{
|
TerminalPlugin() = default;
|
||||||
TerminalCommands::instance().lazyInitCommands();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void TerminalPlugin::extensionsInitialized()
|
~TerminalPlugin() final
|
||||||
{
|
{
|
||||||
(void) TerminalSettingsPage::instance();
|
ExtensionSystem::PluginManager::removeObject(m_terminalPane);
|
||||||
TerminalSettings::instance().readSettings(Core::ICore::settings());
|
delete m_terminalPane;
|
||||||
|
m_terminalPane = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
m_terminalPane = new TerminalPane();
|
void initialize() final
|
||||||
ExtensionSystem::PluginManager::instance()->addObject(m_terminalPane);
|
{
|
||||||
|
addManaged<TerminalSettings>();
|
||||||
|
}
|
||||||
|
|
||||||
auto enable = [this] {
|
void extensionsInitialized() final
|
||||||
Utils::Terminal::Hooks::instance()
|
{
|
||||||
.addCallbackSet("Internal",
|
m_terminalPane = new TerminalPane;
|
||||||
{[this](const Utils::Terminal::OpenTerminalParameters &p) {
|
ExtensionSystem::PluginManager::addObject(m_terminalPane);
|
||||||
m_terminalPane->openTerminal(p);
|
|
||||||
},
|
|
||||||
[this] { return new TerminalProcessImpl(m_terminalPane); }});
|
|
||||||
};
|
|
||||||
|
|
||||||
auto disable = [] { Utils::Terminal::Hooks::instance().removeCallbackSet("Internal"); };
|
auto enable = [this] {
|
||||||
|
Utils::Terminal::Hooks::instance()
|
||||||
|
.addCallbackSet("Internal",
|
||||||
|
{[this](const Utils::Terminal::OpenTerminalParameters &p) {
|
||||||
|
m_terminalPane->openTerminal(p);
|
||||||
|
},
|
||||||
|
[this] { return new TerminalProcessImpl(m_terminalPane); }});
|
||||||
|
};
|
||||||
|
|
||||||
static bool isEnabled = false;
|
auto disable = [] { Utils::Terminal::Hooks::instance().removeCallbackSet("Internal"); };
|
||||||
auto settingsChanged = [enable, disable] {
|
|
||||||
if (isEnabled != TerminalSettings::instance().enableTerminal.value()) {
|
|
||||||
isEnabled = TerminalSettings::instance().enableTerminal.value();
|
|
||||||
if (isEnabled)
|
|
||||||
enable();
|
|
||||||
else
|
|
||||||
disable();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
QObject::connect(&TerminalSettings::instance(),
|
static bool isEnabled = false;
|
||||||
&Utils::AspectContainer::applied,
|
auto settingsChanged = [enable, disable] {
|
||||||
this,
|
if (isEnabled != TerminalSettings::instance().enableTerminal()) {
|
||||||
settingsChanged);
|
isEnabled = TerminalSettings::instance().enableTerminal();
|
||||||
|
if (isEnabled)
|
||||||
|
enable();
|
||||||
|
else
|
||||||
|
disable();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
settingsChanged();
|
QObject::connect(&TerminalSettings::instance(), &Utils::AspectContainer::applied, this, settingsChanged);
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Internal
|
settingsChanged();
|
||||||
} // namespace Terminal
|
}
|
||||||
|
|
||||||
|
bool delayedInitialize() final
|
||||||
|
{
|
||||||
|
TerminalCommands::instance().lazyInitCommands();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
TerminalPane *m_terminalPane{nullptr};
|
||||||
|
};
|
||||||
|
|
||||||
|
} // Terminal::Internal
|
||||||
|
|
||||||
|
#include "terminalplugin.moc"
|
||||||
|
|||||||
@@ -1,30 +0,0 @@
|
|||||||
// Copyright (C) 2016 The Qt Company Ltd.
|
|
||||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <extensionsystem/iplugin.h>
|
|
||||||
|
|
||||||
namespace Terminal {
|
|
||||||
|
|
||||||
class TerminalPane;
|
|
||||||
namespace Internal {
|
|
||||||
|
|
||||||
class TerminalPlugin : public ExtensionSystem::IPlugin
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QtCreatorPlugin" FILE "Terminal.json")
|
|
||||||
|
|
||||||
public:
|
|
||||||
TerminalPlugin();
|
|
||||||
~TerminalPlugin() override;
|
|
||||||
|
|
||||||
void extensionsInitialized() override;
|
|
||||||
bool delayedInitialize() override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
TerminalPane *m_terminalPane{nullptr};
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace Internal
|
|
||||||
} // namespace Terminal
|
|
||||||
@@ -5,10 +5,26 @@
|
|||||||
|
|
||||||
#include "terminaltr.h"
|
#include "terminaltr.h"
|
||||||
|
|
||||||
|
#include <coreplugin/icore.h>
|
||||||
|
|
||||||
|
#include <utils/dropsupport.h>
|
||||||
#include <utils/environment.h>
|
#include <utils/environment.h>
|
||||||
|
#include <utils/expected.h>
|
||||||
|
#include <utils/fileutils.h>
|
||||||
#include <utils/hostosinfo.h>
|
#include <utils/hostosinfo.h>
|
||||||
|
#include <utils/layoutbuilder.h>
|
||||||
|
#include <utils/pathchooser.h>
|
||||||
#include <utils/theme/theme.h>
|
#include <utils/theme/theme.h>
|
||||||
|
|
||||||
|
#include <QFontComboBox>
|
||||||
|
#include <QJsonDocument>
|
||||||
|
#include <QJsonObject>
|
||||||
|
#include <QMessageBox>
|
||||||
|
#include <QPushButton>
|
||||||
|
#include <QRegularExpression>
|
||||||
|
#include <QTemporaryFile>
|
||||||
|
#include <QXmlStreamReader>
|
||||||
|
|
||||||
using namespace Utils;
|
using namespace Utils;
|
||||||
|
|
||||||
namespace Terminal {
|
namespace Terminal {
|
||||||
@@ -46,12 +62,6 @@ static QString defaultShell()
|
|||||||
return shPath.nativePath();
|
return shPath.nativePath();
|
||||||
}
|
}
|
||||||
|
|
||||||
TerminalSettings &TerminalSettings::instance()
|
|
||||||
{
|
|
||||||
static TerminalSettings settings;
|
|
||||||
return settings;
|
|
||||||
}
|
|
||||||
|
|
||||||
void setupColor(TerminalSettings *settings,
|
void setupColor(TerminalSettings *settings,
|
||||||
ColorAspect &color,
|
ColorAspect &color,
|
||||||
const QString &label,
|
const QString &label,
|
||||||
@@ -64,10 +74,305 @@ void setupColor(TerminalSettings *settings,
|
|||||||
settings->registerAspect(&color);
|
settings->registerAspect(&color);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static expected_str<void> loadXdefaults(const FilePath &path)
|
||||||
|
{
|
||||||
|
const expected_str<QByteArray> readResult = path.fileContents();
|
||||||
|
if (!readResult)
|
||||||
|
return make_unexpected(readResult.error());
|
||||||
|
|
||||||
|
QRegularExpression re(R"(.*\*(color[0-9]{1,2}|foreground|background):\s*(#[0-9a-f]{6}))");
|
||||||
|
|
||||||
|
for (const QByteArray &line : readResult->split('\n')) {
|
||||||
|
if (line.trimmed().startsWith('!'))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
const auto match = re.match(QString::fromUtf8(line));
|
||||||
|
if (match.hasMatch()) {
|
||||||
|
const QString colorName = match.captured(1);
|
||||||
|
const QColor color(match.captured(2));
|
||||||
|
if (colorName == "foreground") {
|
||||||
|
TerminalSettings::instance().foregroundColor.setVolatileValue(color);
|
||||||
|
} else if (colorName == "background") {
|
||||||
|
TerminalSettings::instance().backgroundColor.setVolatileValue(color);
|
||||||
|
} else {
|
||||||
|
const int colorIndex = colorName.mid(5).toInt();
|
||||||
|
if (colorIndex >= 0 && colorIndex < 16)
|
||||||
|
TerminalSettings::instance().colors[colorIndex].setVolatileValue(color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
static expected_str<void> loadItermColors(const FilePath &path)
|
||||||
|
{
|
||||||
|
QFile f(path.toFSPathString());
|
||||||
|
const bool opened = f.open(QIODevice::ReadOnly);
|
||||||
|
if (!opened)
|
||||||
|
return make_unexpected(Tr::tr("Failed to open file"));
|
||||||
|
|
||||||
|
QXmlStreamReader reader(&f);
|
||||||
|
while (!reader.atEnd() && reader.readNextStartElement()) {
|
||||||
|
if (reader.name() == u"plist") {
|
||||||
|
while (!reader.atEnd() && reader.readNextStartElement()) {
|
||||||
|
if (reader.name() == u"dict") {
|
||||||
|
QString colorName;
|
||||||
|
while (!reader.atEnd() && reader.readNextStartElement()) {
|
||||||
|
if (reader.name() == u"key") {
|
||||||
|
colorName = reader.readElementText();
|
||||||
|
} else if (reader.name() == u"dict") {
|
||||||
|
QColor color;
|
||||||
|
int component = 0;
|
||||||
|
while (!reader.atEnd() && reader.readNextStartElement()) {
|
||||||
|
if (reader.name() == u"key") {
|
||||||
|
const auto &text = reader.readElementText();
|
||||||
|
if (text == u"Red Component")
|
||||||
|
component = 0;
|
||||||
|
else if (text == u"Green Component")
|
||||||
|
component = 1;
|
||||||
|
else if (text == u"Blue Component")
|
||||||
|
component = 2;
|
||||||
|
else if (text == u"Alpha Component")
|
||||||
|
component = 3;
|
||||||
|
} else if (reader.name() == u"real") {
|
||||||
|
// clang-format off
|
||||||
|
switch (component) {
|
||||||
|
case 0: color.setRedF(reader.readElementText().toDouble()); break;
|
||||||
|
case 1: color.setGreenF(reader.readElementText().toDouble()); break;
|
||||||
|
case 2: color.setBlueF(reader.readElementText().toDouble()); break;
|
||||||
|
case 3: color.setAlphaF(reader.readElementText().toDouble()); break;
|
||||||
|
}
|
||||||
|
// clang-format on
|
||||||
|
} else {
|
||||||
|
reader.skipCurrentElement();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (colorName.startsWith("Ansi")) {
|
||||||
|
const auto c = colorName.mid(5, 2);
|
||||||
|
const int colorIndex = c.toInt();
|
||||||
|
if (colorIndex >= 0 && colorIndex < 16)
|
||||||
|
TerminalSettings::instance().colors[colorIndex].setVolatileValue(
|
||||||
|
color);
|
||||||
|
} else if (colorName == "Foreground Color") {
|
||||||
|
TerminalSettings::instance().foregroundColor.setVolatileValue(color);
|
||||||
|
} else if (colorName == "Background Color") {
|
||||||
|
TerminalSettings::instance().backgroundColor.setVolatileValue(color);
|
||||||
|
} else if (colorName == "Selection Color") {
|
||||||
|
TerminalSettings::instance().selectionColor.setVolatileValue(color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (reader.hasError())
|
||||||
|
return make_unexpected(reader.errorString());
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
static expected_str<void> loadVsCodeColors(const FilePath &path)
|
||||||
|
{
|
||||||
|
const expected_str<QByteArray> readResult = path.fileContents();
|
||||||
|
if (!readResult)
|
||||||
|
return make_unexpected(readResult.error());
|
||||||
|
|
||||||
|
QJsonParseError error;
|
||||||
|
QJsonDocument doc = QJsonDocument::fromJson(*readResult, &error);
|
||||||
|
if (error.error != QJsonParseError::NoError)
|
||||||
|
return make_unexpected(Tr::tr("JSON parsing error: \"%1\", at offset: %2")
|
||||||
|
.arg(error.errorString())
|
||||||
|
.arg(error.offset));
|
||||||
|
|
||||||
|
const QJsonObject root = doc.object();
|
||||||
|
const auto itColors = root.find("colors");
|
||||||
|
if (itColors == root.end())
|
||||||
|
return make_unexpected(Tr::tr("No colors found"));
|
||||||
|
|
||||||
|
const QJsonObject colors = itColors->toObject();
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
const QList<QPair<QStringView, ColorAspect *>> colorKeys = {
|
||||||
|
qMakePair(u"editor.background", &TerminalSettings::instance().backgroundColor),
|
||||||
|
qMakePair(u"terminal.foreground", &TerminalSettings::instance().foregroundColor),
|
||||||
|
qMakePair(u"terminal.selectionBackground", &TerminalSettings::instance().selectionColor),
|
||||||
|
|
||||||
|
qMakePair(u"terminal.ansiBlack", &TerminalSettings::instance().colors[0]),
|
||||||
|
qMakePair(u"terminal.ansiBrightBlack", &TerminalSettings::instance().colors[8]),
|
||||||
|
|
||||||
|
qMakePair(u"terminal.ansiRed", &TerminalSettings::instance().colors[1]),
|
||||||
|
qMakePair(u"terminal.ansiBrightRed", &TerminalSettings::instance().colors[9]),
|
||||||
|
|
||||||
|
qMakePair(u"terminal.ansiGreen", &TerminalSettings::instance().colors[2]),
|
||||||
|
qMakePair(u"terminal.ansiBrightGreen", &TerminalSettings::instance().colors[10]),
|
||||||
|
|
||||||
|
qMakePair(u"terminal.ansiYellow", &TerminalSettings::instance().colors[3]),
|
||||||
|
qMakePair(u"terminal.ansiBrightYellow", &TerminalSettings::instance().colors[11]),
|
||||||
|
|
||||||
|
qMakePair(u"terminal.ansiBlue", &TerminalSettings::instance().colors[4]),
|
||||||
|
qMakePair(u"terminal.ansiBrightBlue", &TerminalSettings::instance().colors[12]),
|
||||||
|
|
||||||
|
qMakePair(u"terminal.ansiMagenta", &TerminalSettings::instance().colors[5]),
|
||||||
|
qMakePair(u"terminal.ansiBrightMagenta", &TerminalSettings::instance().colors[13]),
|
||||||
|
|
||||||
|
qMakePair(u"terminal.ansiCyan", &TerminalSettings::instance().colors[6]),
|
||||||
|
qMakePair(u"terminal.ansiBrightCyan", &TerminalSettings::instance().colors[14]),
|
||||||
|
|
||||||
|
qMakePair(u"terminal.ansiWhite", &TerminalSettings::instance().colors[7]),
|
||||||
|
qMakePair(u"terminal.ansiBrightWhite", &TerminalSettings::instance().colors[15])
|
||||||
|
};
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
for (const auto &pair : colorKeys) {
|
||||||
|
const auto it = colors.find(pair.first);
|
||||||
|
if (it != colors.end()) {
|
||||||
|
const QString colorString = it->toString();
|
||||||
|
if (colorString.startsWith("#")) {
|
||||||
|
QColor color(colorString.mid(0, 7));
|
||||||
|
if (colorString.size() > 7) {
|
||||||
|
int alpha = colorString.mid(7).toInt(nullptr, 16);
|
||||||
|
color.setAlpha(alpha);
|
||||||
|
}
|
||||||
|
if (color.isValid())
|
||||||
|
pair.second->setVolatileValue(color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
static expected_str<void> loadKonsoleColorScheme(const FilePath &path)
|
||||||
|
{
|
||||||
|
QSettings settings(path.toFSPathString(), QSettings::IniFormat);
|
||||||
|
|
||||||
|
auto parseColor = [](const QStringList &parts) -> expected_str<QColor> {
|
||||||
|
if (parts.size() != 3 && parts.size() != 4)
|
||||||
|
return make_unexpected(Tr::tr("Invalid color format"));
|
||||||
|
int alpha = parts.size() == 4 ? parts[3].toInt() : 255;
|
||||||
|
return QColor(parts[0].toInt(), parts[1].toInt(), parts[2].toInt(), alpha);
|
||||||
|
};
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
const QList<QPair<QString, ColorAspect *>> colorKeys = {
|
||||||
|
qMakePair(QLatin1String("Background/Color"), &TerminalSettings::instance().backgroundColor),
|
||||||
|
qMakePair(QLatin1String("Foreground/Color"), &TerminalSettings::instance().foregroundColor),
|
||||||
|
|
||||||
|
qMakePair(QLatin1String("Color0/Color"), &TerminalSettings::instance().colors[0]),
|
||||||
|
qMakePair(QLatin1String("Color0Intense/Color"), &TerminalSettings::instance().colors[8]),
|
||||||
|
|
||||||
|
qMakePair(QLatin1String("Color1/Color"), &TerminalSettings::instance().colors[1]),
|
||||||
|
qMakePair(QLatin1String("Color1Intense/Color"), &TerminalSettings::instance().colors[9]),
|
||||||
|
|
||||||
|
qMakePair(QLatin1String("Color2/Color"), &TerminalSettings::instance().colors[2]),
|
||||||
|
qMakePair(QLatin1String("Color2Intense/Color"), &TerminalSettings::instance().colors[10]),
|
||||||
|
|
||||||
|
qMakePair(QLatin1String("Color3/Color"), &TerminalSettings::instance().colors[3]),
|
||||||
|
qMakePair(QLatin1String("Color3Intense/Color"), &TerminalSettings::instance().colors[11]),
|
||||||
|
|
||||||
|
qMakePair(QLatin1String("Color4/Color"), &TerminalSettings::instance().colors[4]),
|
||||||
|
qMakePair(QLatin1String("Color4Intense/Color"), &TerminalSettings::instance().colors[12]),
|
||||||
|
|
||||||
|
qMakePair(QLatin1String("Color5/Color"), &TerminalSettings::instance().colors[5]),
|
||||||
|
qMakePair(QLatin1String("Color5Intense/Color"), &TerminalSettings::instance().colors[13]),
|
||||||
|
|
||||||
|
qMakePair(QLatin1String("Color6/Color"), &TerminalSettings::instance().colors[6]),
|
||||||
|
qMakePair(QLatin1String("Color6Intense/Color"), &TerminalSettings::instance().colors[14]),
|
||||||
|
|
||||||
|
qMakePair(QLatin1String("Color7/Color"), &TerminalSettings::instance().colors[7]),
|
||||||
|
qMakePair(QLatin1String("Color7Intense/Color"), &TerminalSettings::instance().colors[15])
|
||||||
|
};
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
for (const auto &colorKey : colorKeys) {
|
||||||
|
if (settings.contains(colorKey.first)) {
|
||||||
|
const auto color = parseColor(settings.value(colorKey.first).toStringList());
|
||||||
|
if (!color)
|
||||||
|
return make_unexpected(color.error());
|
||||||
|
|
||||||
|
colorKey.second->setVolatileValue(*color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
static expected_str<void> loadXFCE4ColorScheme(const FilePath &path)
|
||||||
|
{
|
||||||
|
expected_str<QByteArray> arr = path.fileContents();
|
||||||
|
if (!arr)
|
||||||
|
return make_unexpected(arr.error());
|
||||||
|
|
||||||
|
arr->replace(';', ',');
|
||||||
|
|
||||||
|
QTemporaryFile f;
|
||||||
|
f.open();
|
||||||
|
f.write(*arr);
|
||||||
|
f.close();
|
||||||
|
|
||||||
|
QSettings settings(f.fileName(), QSettings::IniFormat);
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
const QList<QPair<QString, ColorAspect *>> colorKeys = {
|
||||||
|
qMakePair(QLatin1String("Scheme/ColorBackground"), &TerminalSettings::instance().backgroundColor),
|
||||||
|
qMakePair(QLatin1String("Scheme/ColorForeground"), &TerminalSettings::instance().foregroundColor),
|
||||||
|
};
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
for (const auto &colorKey : colorKeys) {
|
||||||
|
if (settings.contains(colorKey.first)) {
|
||||||
|
colorKey.second->setVolatileValue(QColor(settings.value(colorKey.first).toString()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QStringList colors = settings.value(QLatin1String("Scheme/ColorPalette")).toStringList();
|
||||||
|
int i = 0;
|
||||||
|
for (const auto &color : colors) {
|
||||||
|
TerminalSettings::instance().colors[i++].setVolatileValue(QColor(color));
|
||||||
|
}
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
static expected_str<void> loadColorScheme(const FilePath &path)
|
||||||
|
{
|
||||||
|
if (path.endsWith("Xdefaults"))
|
||||||
|
return loadXdefaults(path);
|
||||||
|
else if (path.suffix() == "itermcolors")
|
||||||
|
return loadItermColors(path);
|
||||||
|
else if (path.suffix() == "json")
|
||||||
|
return loadVsCodeColors(path);
|
||||||
|
else if (path.suffix() == "colorscheme")
|
||||||
|
return loadKonsoleColorScheme(path);
|
||||||
|
else if (path.suffix() == "theme" || path.completeSuffix() == "theme.txt")
|
||||||
|
return loadXFCE4ColorScheme(path);
|
||||||
|
|
||||||
|
return make_unexpected(Tr::tr("Unknown color scheme format"));
|
||||||
|
}
|
||||||
|
|
||||||
|
static TerminalSettings *s_instance;
|
||||||
|
|
||||||
|
TerminalSettings &TerminalSettings::instance()
|
||||||
|
{
|
||||||
|
return *s_instance;
|
||||||
|
}
|
||||||
|
|
||||||
TerminalSettings::TerminalSettings()
|
TerminalSettings::TerminalSettings()
|
||||||
{
|
{
|
||||||
|
s_instance = this;
|
||||||
|
|
||||||
setAutoApply(false);
|
setAutoApply(false);
|
||||||
setSettingsGroup("Terminal");
|
setSettingsGroup("Terminal");
|
||||||
|
setId("Terminal.General");
|
||||||
|
setDisplayName("Terminal");
|
||||||
|
setCategory("ZY.Terminal");
|
||||||
|
setDisplayCategory("Terminal");
|
||||||
|
setSettings(&TerminalSettings::instance());
|
||||||
|
setCategoryIconPath(":/terminal/images/settingscategory_terminal.png");
|
||||||
|
|
||||||
enableTerminal.setSettingsKey("EnableTerminal");
|
enableTerminal.setSettingsKey("EnableTerminal");
|
||||||
enableTerminal.setLabelText(Tr::tr("Use internal terminal"));
|
enableTerminal.setLabelText(Tr::tr("Use internal terminal"));
|
||||||
@@ -122,15 +427,6 @@ TerminalSettings::TerminalSettings()
|
|||||||
"character is received."));
|
"character is received."));
|
||||||
audibleBell.setDefaultValue(true);
|
audibleBell.setDefaultValue(true);
|
||||||
|
|
||||||
registerAspect(&font);
|
|
||||||
registerAspect(&fontSize);
|
|
||||||
registerAspect(&shell);
|
|
||||||
registerAspect(&allowBlinkingCursor);
|
|
||||||
registerAspect(&enableTerminal);
|
|
||||||
registerAspect(&sendEscapeToTerminal);
|
|
||||||
registerAspect(&audibleBell);
|
|
||||||
registerAspect(&shellArguments);
|
|
||||||
|
|
||||||
setupColor(this,
|
setupColor(this,
|
||||||
foregroundColor,
|
foregroundColor,
|
||||||
"Foreground",
|
"Foreground",
|
||||||
@@ -172,6 +468,127 @@ TerminalSettings::TerminalSettings()
|
|||||||
|
|
||||||
setupColor(this, colors[7], "7", Utils::creatorTheme()->color(Theme::TerminalAnsi7));
|
setupColor(this, colors[7], "7", Utils::creatorTheme()->color(Theme::TerminalAnsi7));
|
||||||
setupColor(this, colors[15], "15", Utils::creatorTheme()->color(Theme::TerminalAnsi15));
|
setupColor(this, colors[15], "15", Utils::creatorTheme()->color(Theme::TerminalAnsi15));
|
||||||
|
|
||||||
|
setLayouter([this] {
|
||||||
|
using namespace Layouting;
|
||||||
|
|
||||||
|
QFontComboBox *fontComboBox = new QFontComboBox;
|
||||||
|
fontComboBox->setFontFilters(QFontComboBox::MonospacedFonts);
|
||||||
|
fontComboBox->setCurrentFont(font());
|
||||||
|
|
||||||
|
connect(fontComboBox, &QFontComboBox::currentFontChanged, this, [this](const QFont &f) {
|
||||||
|
font.setValue(f.family());
|
||||||
|
});
|
||||||
|
|
||||||
|
auto loadThemeButton = new QPushButton(Tr::tr("Load Theme..."));
|
||||||
|
auto resetTheme = new QPushButton(Tr::tr("Reset Theme"));
|
||||||
|
|
||||||
|
connect(loadThemeButton, &QPushButton::clicked, this, [this] {
|
||||||
|
const FilePath path = FileUtils::getOpenFilePath(
|
||||||
|
Core::ICore::dialogParent(),
|
||||||
|
"Open Theme",
|
||||||
|
{},
|
||||||
|
"All Scheme formats (*.itermcolors *.json *.colorscheme *.theme *.theme.txt);;"
|
||||||
|
"Xdefaults (.Xdefaults Xdefaults);;"
|
||||||
|
"iTerm Color Schemes(*.itermcolors);;"
|
||||||
|
"VS Code Color Schemes(*.json);;"
|
||||||
|
"Konsole Color Schemes(*.colorscheme);;"
|
||||||
|
"XFCE4 Terminal Color Schemes(*.theme *.theme.txt);;"
|
||||||
|
"All files (*)",
|
||||||
|
nullptr,
|
||||||
|
{},
|
||||||
|
true,
|
||||||
|
false);
|
||||||
|
|
||||||
|
if (path.isEmpty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
const expected_str<void> result = loadColorScheme(path);
|
||||||
|
if (!result)
|
||||||
|
QMessageBox::warning(Core::ICore::dialogParent(), Tr::tr("Error"), result.error());
|
||||||
|
});
|
||||||
|
|
||||||
|
connect(resetTheme, &QPushButton::clicked, this, [this] {
|
||||||
|
foregroundColor.setVolatileValue(foregroundColor.defaultValue());
|
||||||
|
backgroundColor.setVolatileValue(backgroundColor.defaultValue());
|
||||||
|
selectionColor.setVolatileValue(selectionColor.defaultValue());
|
||||||
|
|
||||||
|
for (ColorAspect &color : colors)
|
||||||
|
color.setVolatileValue(color.defaultValue());
|
||||||
|
});
|
||||||
|
|
||||||
|
// FIXME: Implement and use a Layouting::DropArea item
|
||||||
|
|
||||||
|
// DropSupport *dropSupport = new DropSupport;
|
||||||
|
// connect(dropSupport,
|
||||||
|
// &DropSupport::filesDropped,
|
||||||
|
// this,
|
||||||
|
// [this](const QList<DropSupport::FileSpec> &files) {
|
||||||
|
// if (files.size() != 1)
|
||||||
|
// return;
|
||||||
|
|
||||||
|
// const expected_str<void> result = loadColorScheme(files.at(0).filePath);
|
||||||
|
// if (!result)
|
||||||
|
// QMessageBox::warning(Core::ICore::dialogParent(), Tr::tr("Error"), result.error());
|
||||||
|
// });
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
return Column {
|
||||||
|
Group {
|
||||||
|
title(Tr::tr("General")),
|
||||||
|
Column {
|
||||||
|
enableTerminal, st,
|
||||||
|
sendEscapeToTerminal, st,
|
||||||
|
audibleBell, st,
|
||||||
|
allowBlinkingCursor, st,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Group {
|
||||||
|
title(Tr::tr("Font")),
|
||||||
|
Row {
|
||||||
|
font.labelText(), fontComboBox, Space(20),
|
||||||
|
fontSize, st,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Group {
|
||||||
|
title(Tr::tr("Colors")),
|
||||||
|
Column {
|
||||||
|
Row {
|
||||||
|
Tr::tr("Foreground"), foregroundColor, st,
|
||||||
|
Tr::tr("Background"), backgroundColor, st,
|
||||||
|
Tr::tr("Selection"), selectionColor, st,
|
||||||
|
Tr::tr("Find match"), findMatchColor, st,
|
||||||
|
},
|
||||||
|
Row {
|
||||||
|
colors[0], colors[1],
|
||||||
|
colors[2], colors[3],
|
||||||
|
colors[4], colors[5],
|
||||||
|
colors[6], colors[7]
|
||||||
|
},
|
||||||
|
Row {
|
||||||
|
colors[8], colors[9],
|
||||||
|
colors[10], colors[11],
|
||||||
|
colors[12], colors[13],
|
||||||
|
colors[14], colors[15]
|
||||||
|
},
|
||||||
|
Row {
|
||||||
|
loadThemeButton, resetTheme, st,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Group {
|
||||||
|
title(Tr::tr("Default Shell")),
|
||||||
|
Column {
|
||||||
|
shell,
|
||||||
|
shellArguments,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
st,
|
||||||
|
};
|
||||||
|
// clang-format on
|
||||||
|
});
|
||||||
|
|
||||||
|
readSettings();
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Terminal
|
} // Terminal
|
||||||
|
|||||||
@@ -3,22 +3,23 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <utils/aspects.h>
|
#include <coreplugin/dialogs/ioptionspage.h>
|
||||||
|
|
||||||
namespace Terminal {
|
namespace Terminal {
|
||||||
class TerminalSettings : public Utils::AspectContainer
|
|
||||||
|
class TerminalSettings : public Core::PagedSettings
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
TerminalSettings();
|
TerminalSettings();
|
||||||
|
|
||||||
static TerminalSettings &instance();
|
static TerminalSettings &instance();
|
||||||
|
|
||||||
Utils::BoolAspect enableTerminal;
|
Utils::BoolAspect enableTerminal{this};
|
||||||
|
|
||||||
Utils::StringAspect font;
|
Utils::StringAspect font{this};
|
||||||
Utils::IntegerAspect fontSize;
|
Utils::IntegerAspect fontSize{this};
|
||||||
Utils::StringAspect shell;
|
Utils::StringAspect shell{this};
|
||||||
Utils::StringAspect shellArguments;
|
Utils::StringAspect shellArguments{this};
|
||||||
|
|
||||||
Utils::ColorAspect foregroundColor;
|
Utils::ColorAspect foregroundColor;
|
||||||
Utils::ColorAspect backgroundColor;
|
Utils::ColorAspect backgroundColor;
|
||||||
@@ -27,10 +28,10 @@ public:
|
|||||||
|
|
||||||
Utils::ColorAspect colors[16];
|
Utils::ColorAspect colors[16];
|
||||||
|
|
||||||
Utils::BoolAspect allowBlinkingCursor;
|
Utils::BoolAspect allowBlinkingCursor{this};
|
||||||
|
|
||||||
Utils::BoolAspect sendEscapeToTerminal;
|
Utils::BoolAspect sendEscapeToTerminal{this};
|
||||||
Utils::BoolAspect audibleBell;
|
Utils::BoolAspect audibleBell{this};
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Terminal
|
} // Terminal
|
||||||
|
|||||||
@@ -1,464 +0,0 @@
|
|||||||
// Copyright (C) 2023 The Qt Company Ltd.
|
|
||||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
|
|
||||||
|
|
||||||
#include "terminalsettingspage.h"
|
|
||||||
|
|
||||||
#include "terminalsettings.h"
|
|
||||||
#include "terminaltr.h"
|
|
||||||
|
|
||||||
#include <coreplugin/icore.h>
|
|
||||||
|
|
||||||
#include <utils/aspects.h>
|
|
||||||
#include <utils/dropsupport.h>
|
|
||||||
#include <utils/expected.h>
|
|
||||||
#include <utils/fileutils.h>
|
|
||||||
#include <utils/layoutbuilder.h>
|
|
||||||
#include <utils/pathchooser.h>
|
|
||||||
|
|
||||||
#include <QFontComboBox>
|
|
||||||
#include <QJsonDocument>
|
|
||||||
#include <QJsonObject>
|
|
||||||
#include <QMessageBox>
|
|
||||||
#include <QPushButton>
|
|
||||||
#include <QRegularExpression>
|
|
||||||
#include <QTemporaryFile>
|
|
||||||
#include <QXmlStreamReader>
|
|
||||||
|
|
||||||
using namespace Utils;
|
|
||||||
|
|
||||||
namespace Terminal {
|
|
||||||
|
|
||||||
static expected_str<void> loadXdefaults(const FilePath &path)
|
|
||||||
{
|
|
||||||
const expected_str<QByteArray> readResult = path.fileContents();
|
|
||||||
if (!readResult)
|
|
||||||
return make_unexpected(readResult.error());
|
|
||||||
|
|
||||||
QRegularExpression re(R"(.*\*(color[0-9]{1,2}|foreground|background):\s*(#[0-9a-f]{6}))");
|
|
||||||
|
|
||||||
for (const QByteArray &line : readResult->split('\n')) {
|
|
||||||
if (line.trimmed().startsWith('!'))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
const auto match = re.match(QString::fromUtf8(line));
|
|
||||||
if (match.hasMatch()) {
|
|
||||||
const QString colorName = match.captured(1);
|
|
||||||
const QColor color(match.captured(2));
|
|
||||||
if (colorName == "foreground") {
|
|
||||||
TerminalSettings::instance().foregroundColor.setVolatileValue(color);
|
|
||||||
} else if (colorName == "background") {
|
|
||||||
TerminalSettings::instance().backgroundColor.setVolatileValue(color);
|
|
||||||
} else {
|
|
||||||
const int colorIndex = colorName.mid(5).toInt();
|
|
||||||
if (colorIndex >= 0 && colorIndex < 16)
|
|
||||||
TerminalSettings::instance().colors[colorIndex].setVolatileValue(color);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
static expected_str<void> loadItermColors(const FilePath &path)
|
|
||||||
{
|
|
||||||
QFile f(path.toFSPathString());
|
|
||||||
const bool opened = f.open(QIODevice::ReadOnly);
|
|
||||||
if (!opened)
|
|
||||||
return make_unexpected(Tr::tr("Failed to open file"));
|
|
||||||
|
|
||||||
QXmlStreamReader reader(&f);
|
|
||||||
while (!reader.atEnd() && reader.readNextStartElement()) {
|
|
||||||
if (reader.name() == u"plist") {
|
|
||||||
while (!reader.atEnd() && reader.readNextStartElement()) {
|
|
||||||
if (reader.name() == u"dict") {
|
|
||||||
QString colorName;
|
|
||||||
while (!reader.atEnd() && reader.readNextStartElement()) {
|
|
||||||
if (reader.name() == u"key") {
|
|
||||||
colorName = reader.readElementText();
|
|
||||||
} else if (reader.name() == u"dict") {
|
|
||||||
QColor color;
|
|
||||||
int component = 0;
|
|
||||||
while (!reader.atEnd() && reader.readNextStartElement()) {
|
|
||||||
if (reader.name() == u"key") {
|
|
||||||
const auto &text = reader.readElementText();
|
|
||||||
if (text == u"Red Component")
|
|
||||||
component = 0;
|
|
||||||
else if (text == u"Green Component")
|
|
||||||
component = 1;
|
|
||||||
else if (text == u"Blue Component")
|
|
||||||
component = 2;
|
|
||||||
else if (text == u"Alpha Component")
|
|
||||||
component = 3;
|
|
||||||
} else if (reader.name() == u"real") {
|
|
||||||
// clang-format off
|
|
||||||
switch (component) {
|
|
||||||
case 0: color.setRedF(reader.readElementText().toDouble()); break;
|
|
||||||
case 1: color.setGreenF(reader.readElementText().toDouble()); break;
|
|
||||||
case 2: color.setBlueF(reader.readElementText().toDouble()); break;
|
|
||||||
case 3: color.setAlphaF(reader.readElementText().toDouble()); break;
|
|
||||||
}
|
|
||||||
// clang-format on
|
|
||||||
} else {
|
|
||||||
reader.skipCurrentElement();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (colorName.startsWith("Ansi")) {
|
|
||||||
const auto c = colorName.mid(5, 2);
|
|
||||||
const int colorIndex = c.toInt();
|
|
||||||
if (colorIndex >= 0 && colorIndex < 16)
|
|
||||||
TerminalSettings::instance().colors[colorIndex].setVolatileValue(
|
|
||||||
color);
|
|
||||||
} else if (colorName == "Foreground Color") {
|
|
||||||
TerminalSettings::instance().foregroundColor.setVolatileValue(color);
|
|
||||||
} else if (colorName == "Background Color") {
|
|
||||||
TerminalSettings::instance().backgroundColor.setVolatileValue(color);
|
|
||||||
} else if (colorName == "Selection Color") {
|
|
||||||
TerminalSettings::instance().selectionColor.setVolatileValue(color);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (reader.hasError())
|
|
||||||
return make_unexpected(reader.errorString());
|
|
||||||
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
static expected_str<void> loadVsCodeColors(const FilePath &path)
|
|
||||||
{
|
|
||||||
const expected_str<QByteArray> readResult = path.fileContents();
|
|
||||||
if (!readResult)
|
|
||||||
return make_unexpected(readResult.error());
|
|
||||||
|
|
||||||
QJsonParseError error;
|
|
||||||
QJsonDocument doc = QJsonDocument::fromJson(*readResult, &error);
|
|
||||||
if (error.error != QJsonParseError::NoError)
|
|
||||||
return make_unexpected(Tr::tr("JSON parsing error: \"%1\", at offset: %2")
|
|
||||||
.arg(error.errorString())
|
|
||||||
.arg(error.offset));
|
|
||||||
|
|
||||||
const QJsonObject root = doc.object();
|
|
||||||
const auto itColors = root.find("colors");
|
|
||||||
if (itColors == root.end())
|
|
||||||
return make_unexpected(Tr::tr("No colors found"));
|
|
||||||
|
|
||||||
const QJsonObject colors = itColors->toObject();
|
|
||||||
|
|
||||||
// clang-format off
|
|
||||||
const QList<QPair<QStringView, ColorAspect *>> colorKeys = {
|
|
||||||
qMakePair(u"editor.background", &TerminalSettings::instance().backgroundColor),
|
|
||||||
qMakePair(u"terminal.foreground", &TerminalSettings::instance().foregroundColor),
|
|
||||||
qMakePair(u"terminal.selectionBackground", &TerminalSettings::instance().selectionColor),
|
|
||||||
|
|
||||||
qMakePair(u"terminal.ansiBlack", &TerminalSettings::instance().colors[0]),
|
|
||||||
qMakePair(u"terminal.ansiBrightBlack", &TerminalSettings::instance().colors[8]),
|
|
||||||
|
|
||||||
qMakePair(u"terminal.ansiRed", &TerminalSettings::instance().colors[1]),
|
|
||||||
qMakePair(u"terminal.ansiBrightRed", &TerminalSettings::instance().colors[9]),
|
|
||||||
|
|
||||||
qMakePair(u"terminal.ansiGreen", &TerminalSettings::instance().colors[2]),
|
|
||||||
qMakePair(u"terminal.ansiBrightGreen", &TerminalSettings::instance().colors[10]),
|
|
||||||
|
|
||||||
qMakePair(u"terminal.ansiYellow", &TerminalSettings::instance().colors[3]),
|
|
||||||
qMakePair(u"terminal.ansiBrightYellow", &TerminalSettings::instance().colors[11]),
|
|
||||||
|
|
||||||
qMakePair(u"terminal.ansiBlue", &TerminalSettings::instance().colors[4]),
|
|
||||||
qMakePair(u"terminal.ansiBrightBlue", &TerminalSettings::instance().colors[12]),
|
|
||||||
|
|
||||||
qMakePair(u"terminal.ansiMagenta", &TerminalSettings::instance().colors[5]),
|
|
||||||
qMakePair(u"terminal.ansiBrightMagenta", &TerminalSettings::instance().colors[13]),
|
|
||||||
|
|
||||||
qMakePair(u"terminal.ansiCyan", &TerminalSettings::instance().colors[6]),
|
|
||||||
qMakePair(u"terminal.ansiBrightCyan", &TerminalSettings::instance().colors[14]),
|
|
||||||
|
|
||||||
qMakePair(u"terminal.ansiWhite", &TerminalSettings::instance().colors[7]),
|
|
||||||
qMakePair(u"terminal.ansiBrightWhite", &TerminalSettings::instance().colors[15])
|
|
||||||
};
|
|
||||||
// clang-format on
|
|
||||||
|
|
||||||
for (const auto &pair : colorKeys) {
|
|
||||||
const auto it = colors.find(pair.first);
|
|
||||||
if (it != colors.end()) {
|
|
||||||
const QString colorString = it->toString();
|
|
||||||
if (colorString.startsWith("#")) {
|
|
||||||
QColor color(colorString.mid(0, 7));
|
|
||||||
if (colorString.size() > 7) {
|
|
||||||
int alpha = colorString.mid(7).toInt(nullptr, 16);
|
|
||||||
color.setAlpha(alpha);
|
|
||||||
}
|
|
||||||
if (color.isValid())
|
|
||||||
pair.second->setVolatileValue(color);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
static expected_str<void> loadKonsoleColorScheme(const FilePath &path)
|
|
||||||
{
|
|
||||||
QSettings settings(path.toFSPathString(), QSettings::IniFormat);
|
|
||||||
|
|
||||||
auto parseColor = [](const QStringList &parts) -> expected_str<QColor> {
|
|
||||||
if (parts.size() != 3 && parts.size() != 4)
|
|
||||||
return make_unexpected(Tr::tr("Invalid color format"));
|
|
||||||
int alpha = parts.size() == 4 ? parts[3].toInt() : 255;
|
|
||||||
return QColor(parts[0].toInt(), parts[1].toInt(), parts[2].toInt(), alpha);
|
|
||||||
};
|
|
||||||
|
|
||||||
// clang-format off
|
|
||||||
const QList<QPair<QString, ColorAspect *>> colorKeys = {
|
|
||||||
qMakePair(QLatin1String("Background/Color"), &TerminalSettings::instance().backgroundColor),
|
|
||||||
qMakePair(QLatin1String("Foreground/Color"), &TerminalSettings::instance().foregroundColor),
|
|
||||||
|
|
||||||
qMakePair(QLatin1String("Color0/Color"), &TerminalSettings::instance().colors[0]),
|
|
||||||
qMakePair(QLatin1String("Color0Intense/Color"), &TerminalSettings::instance().colors[8]),
|
|
||||||
|
|
||||||
qMakePair(QLatin1String("Color1/Color"), &TerminalSettings::instance().colors[1]),
|
|
||||||
qMakePair(QLatin1String("Color1Intense/Color"), &TerminalSettings::instance().colors[9]),
|
|
||||||
|
|
||||||
qMakePair(QLatin1String("Color2/Color"), &TerminalSettings::instance().colors[2]),
|
|
||||||
qMakePair(QLatin1String("Color2Intense/Color"), &TerminalSettings::instance().colors[10]),
|
|
||||||
|
|
||||||
qMakePair(QLatin1String("Color3/Color"), &TerminalSettings::instance().colors[3]),
|
|
||||||
qMakePair(QLatin1String("Color3Intense/Color"), &TerminalSettings::instance().colors[11]),
|
|
||||||
|
|
||||||
qMakePair(QLatin1String("Color4/Color"), &TerminalSettings::instance().colors[4]),
|
|
||||||
qMakePair(QLatin1String("Color4Intense/Color"), &TerminalSettings::instance().colors[12]),
|
|
||||||
|
|
||||||
qMakePair(QLatin1String("Color5/Color"), &TerminalSettings::instance().colors[5]),
|
|
||||||
qMakePair(QLatin1String("Color5Intense/Color"), &TerminalSettings::instance().colors[13]),
|
|
||||||
|
|
||||||
qMakePair(QLatin1String("Color6/Color"), &TerminalSettings::instance().colors[6]),
|
|
||||||
qMakePair(QLatin1String("Color6Intense/Color"), &TerminalSettings::instance().colors[14]),
|
|
||||||
|
|
||||||
qMakePair(QLatin1String("Color7/Color"), &TerminalSettings::instance().colors[7]),
|
|
||||||
qMakePair(QLatin1String("Color7Intense/Color"), &TerminalSettings::instance().colors[15])
|
|
||||||
};
|
|
||||||
// clang-format on
|
|
||||||
|
|
||||||
for (const auto &colorKey : colorKeys) {
|
|
||||||
if (settings.contains(colorKey.first)) {
|
|
||||||
const auto color = parseColor(settings.value(colorKey.first).toStringList());
|
|
||||||
if (!color)
|
|
||||||
return make_unexpected(color.error());
|
|
||||||
|
|
||||||
colorKey.second->setVolatileValue(*color);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
static expected_str<void> loadXFCE4ColorScheme(const FilePath &path)
|
|
||||||
{
|
|
||||||
expected_str<QByteArray> arr = path.fileContents();
|
|
||||||
if (!arr)
|
|
||||||
return make_unexpected(arr.error());
|
|
||||||
|
|
||||||
arr->replace(';', ',');
|
|
||||||
|
|
||||||
QTemporaryFile f;
|
|
||||||
f.open();
|
|
||||||
f.write(*arr);
|
|
||||||
f.close();
|
|
||||||
|
|
||||||
QSettings settings(f.fileName(), QSettings::IniFormat);
|
|
||||||
|
|
||||||
// clang-format off
|
|
||||||
const QList<QPair<QString, ColorAspect *>> colorKeys = {
|
|
||||||
qMakePair(QLatin1String("Scheme/ColorBackground"), &TerminalSettings::instance().backgroundColor),
|
|
||||||
qMakePair(QLatin1String("Scheme/ColorForeground"), &TerminalSettings::instance().foregroundColor),
|
|
||||||
};
|
|
||||||
// clang-format on
|
|
||||||
|
|
||||||
for (const auto &colorKey : colorKeys) {
|
|
||||||
if (settings.contains(colorKey.first)) {
|
|
||||||
colorKey.second->setVolatileValue(QColor(settings.value(colorKey.first).toString()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
QStringList colors = settings.value(QLatin1String("Scheme/ColorPalette")).toStringList();
|
|
||||||
int i = 0;
|
|
||||||
for (const auto &color : colors) {
|
|
||||||
TerminalSettings::instance().colors[i++].setVolatileValue(QColor(color));
|
|
||||||
}
|
|
||||||
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
static expected_str<void> loadColorScheme(const FilePath &path)
|
|
||||||
{
|
|
||||||
if (path.endsWith("Xdefaults"))
|
|
||||||
return loadXdefaults(path);
|
|
||||||
else if (path.suffix() == "itermcolors")
|
|
||||||
return loadItermColors(path);
|
|
||||||
else if (path.suffix() == "json")
|
|
||||||
return loadVsCodeColors(path);
|
|
||||||
else if (path.suffix() == "colorscheme")
|
|
||||||
return loadKonsoleColorScheme(path);
|
|
||||||
else if (path.suffix() == "theme" || path.completeSuffix() == "theme.txt")
|
|
||||||
return loadXFCE4ColorScheme(path);
|
|
||||||
|
|
||||||
return make_unexpected(Tr::tr("Unknown color scheme format"));
|
|
||||||
}
|
|
||||||
|
|
||||||
class TerminalSettingsPageWidget : public Core::IOptionsPageWidget
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
TerminalSettingsPageWidget()
|
|
||||||
{
|
|
||||||
using namespace Layouting;
|
|
||||||
|
|
||||||
QFontComboBox *fontComboBox = new QFontComboBox(this);
|
|
||||||
fontComboBox->setFontFilters(QFontComboBox::MonospacedFonts);
|
|
||||||
fontComboBox->setCurrentFont(TerminalSettings::instance().font.value());
|
|
||||||
|
|
||||||
connect(fontComboBox, &QFontComboBox::currentFontChanged, this, [](const QFont &f) {
|
|
||||||
TerminalSettings::instance().font.setValue(f.family());
|
|
||||||
});
|
|
||||||
|
|
||||||
TerminalSettings &settings = TerminalSettings::instance();
|
|
||||||
|
|
||||||
QPushButton *loadThemeButton = new QPushButton(Tr::tr("Load Theme..."));
|
|
||||||
QPushButton *resetTheme = new QPushButton(Tr::tr("Reset Theme"));
|
|
||||||
|
|
||||||
connect(loadThemeButton, &QPushButton::clicked, this, [this] {
|
|
||||||
const FilePath path = FileUtils::getOpenFilePath(
|
|
||||||
this,
|
|
||||||
"Open Theme",
|
|
||||||
{},
|
|
||||||
"All Scheme formats (*.itermcolors *.json *.colorscheme *.theme *.theme.txt);;"
|
|
||||||
"Xdefaults (.Xdefaults Xdefaults);;"
|
|
||||||
"iTerm Color Schemes(*.itermcolors);;"
|
|
||||||
"VS Code Color Schemes(*.json);;"
|
|
||||||
"Konsole Color Schemes(*.colorscheme);;"
|
|
||||||
"XFCE4 Terminal Color Schemes(*.theme *.theme.txt);;"
|
|
||||||
"All files (*)",
|
|
||||||
nullptr,
|
|
||||||
{},
|
|
||||||
true,
|
|
||||||
false);
|
|
||||||
|
|
||||||
if (path.isEmpty())
|
|
||||||
return;
|
|
||||||
|
|
||||||
const expected_str<void> result = loadColorScheme(path);
|
|
||||||
if (!result)
|
|
||||||
QMessageBox::warning(this, Tr::tr("Error"), result.error());
|
|
||||||
});
|
|
||||||
|
|
||||||
connect(resetTheme, &QPushButton::clicked, this, [] {
|
|
||||||
TerminalSettings &settings = TerminalSettings::instance();
|
|
||||||
settings.foregroundColor.setVolatileValue(settings.foregroundColor.defaultValue());
|
|
||||||
settings.backgroundColor.setVolatileValue(settings.backgroundColor.defaultValue());
|
|
||||||
settings.selectionColor.setVolatileValue(settings.selectionColor.defaultValue());
|
|
||||||
|
|
||||||
for (auto &color : settings.colors)
|
|
||||||
color.setVolatileValue(color.defaultValue());
|
|
||||||
});
|
|
||||||
|
|
||||||
// clang-format off
|
|
||||||
Column {
|
|
||||||
Group {
|
|
||||||
title(Tr::tr("General")),
|
|
||||||
Column {
|
|
||||||
settings.enableTerminal, st,
|
|
||||||
settings.sendEscapeToTerminal, st,
|
|
||||||
settings.audibleBell, st,
|
|
||||||
settings.allowBlinkingCursor, st,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Group {
|
|
||||||
title(Tr::tr("Font")),
|
|
||||||
Row {
|
|
||||||
settings.font.labelText(), fontComboBox, Space(20),
|
|
||||||
settings.fontSize, st,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Group {
|
|
||||||
title(Tr::tr("Colors")),
|
|
||||||
Column {
|
|
||||||
Row {
|
|
||||||
Tr::tr("Foreground"), settings.foregroundColor, st,
|
|
||||||
Tr::tr("Background"), settings.backgroundColor, st,
|
|
||||||
Tr::tr("Selection"), settings.selectionColor, st,
|
|
||||||
Tr::tr("Find match"), settings.findMatchColor, st,
|
|
||||||
},
|
|
||||||
Row {
|
|
||||||
settings.colors[0], settings.colors[1],
|
|
||||||
settings.colors[2], settings.colors[3],
|
|
||||||
settings.colors[4], settings.colors[5],
|
|
||||||
settings.colors[6], settings.colors[7]
|
|
||||||
},
|
|
||||||
Row {
|
|
||||||
settings.colors[8], settings.colors[9],
|
|
||||||
settings.colors[10], settings.colors[11],
|
|
||||||
settings.colors[12], settings.colors[13],
|
|
||||||
settings.colors[14], settings.colors[15]
|
|
||||||
},
|
|
||||||
Row {
|
|
||||||
loadThemeButton, resetTheme, st,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Group {
|
|
||||||
title(Tr::tr("Default Shell")),
|
|
||||||
Column {
|
|
||||||
settings.shell,
|
|
||||||
settings.shellArguments,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
st,
|
|
||||||
}.attachTo(this);
|
|
||||||
// clang-format on
|
|
||||||
|
|
||||||
DropSupport *dropSupport = new DropSupport(this);
|
|
||||||
connect(dropSupport,
|
|
||||||
&DropSupport::filesDropped,
|
|
||||||
this,
|
|
||||||
[this](const QList<DropSupport::FileSpec> &files) {
|
|
||||||
if (files.size() != 1)
|
|
||||||
return;
|
|
||||||
|
|
||||||
const expected_str<void> result = loadColorScheme(files.at(0).filePath);
|
|
||||||
if (!result)
|
|
||||||
QMessageBox::warning(this, Tr::tr("Error"), result.error());
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
void apply() final
|
|
||||||
{
|
|
||||||
TerminalSettings &settings = TerminalSettings::instance();
|
|
||||||
if (settings.isDirty()) {
|
|
||||||
settings.apply();
|
|
||||||
settings.writeSettings(Core::ICore::settings());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// TerminalSettingsPage
|
|
||||||
|
|
||||||
TerminalSettingsPage::TerminalSettingsPage()
|
|
||||||
{
|
|
||||||
setId("Terminal.General");
|
|
||||||
setDisplayName("Terminal");
|
|
||||||
setCategory("ZY.Terminal");
|
|
||||||
setDisplayCategory("Terminal");
|
|
||||||
setSettings(&TerminalSettings::instance());
|
|
||||||
setCategoryIconPath(":/terminal/images/settingscategory_terminal.png");
|
|
||||||
setWidgetCreator([] { return new TerminalSettingsPageWidget; });
|
|
||||||
}
|
|
||||||
|
|
||||||
TerminalSettingsPage &TerminalSettingsPage::instance()
|
|
||||||
{
|
|
||||||
static TerminalSettingsPage settingsPage;
|
|
||||||
return settingsPage;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Terminal
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
// Copyright (C) 2023 The Qt Company Ltd.
|
|
||||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <coreplugin/dialogs/ioptionspage.h>
|
|
||||||
|
|
||||||
namespace Terminal {
|
|
||||||
|
|
||||||
class TerminalSettingsPage : public Core::IOptionsPage
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
TerminalSettingsPage();
|
|
||||||
|
|
||||||
static TerminalSettingsPage &instance();
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace Terminal
|
|
||||||
Reference in New Issue
Block a user