8 Commits

Author SHA1 Message Date
Keith Smith
2b25f805cd Complete Milestone 4 interactive SSH session UX 2026-03-01 11:00:31 -07:00
Keith Smith
776ddc1a53 Integrate KodoTerm for SSH terminal sessions 2026-03-01 10:36:06 -07:00
Keith Smith
c3369b8e48 Improve terminal theming, cursor UX, and size negotiation 2026-03-01 10:14:43 -07:00
Keith Smith
20ee48db32 Add ANSI color rendering and terminal themes 2026-03-01 10:08:04 -07:00
Keith Smith
2b4f498259 Allow direct terminal typing and collapsible session panels 2026-03-01 09:58:21 -07:00
Keith Smith
614d31fa71 Restore built-in askpass helper for SSH password auth 2026-03-01 09:53:17 -07:00
Keith Smith
ceed19d517 Draft Milestone 4 scope and mark progress in docs 2026-03-01 09:50:08 -07:00
Keith Smith
2ea712db36 Start Milestone 4 interactive SSH terminal and host-key flow 2026-03-01 09:50:03 -07:00
515 changed files with 23892 additions and 177 deletions

View File

@@ -14,6 +14,8 @@ find_package(Qt6 6.2 REQUIRED COMPONENTS Widgets Sql)
qt_standard_project_setup() qt_standard_project_setup()
add_subdirectory(third_party/KodoTerm)
add_executable(orbithub add_executable(orbithub
src/main.cpp src/main.cpp
src/profile_dialog.cpp src/profile_dialog.cpp
@@ -27,6 +29,8 @@ add_executable(orbithub
src/session_backend_factory.h src/session_backend_factory.h
src/session_tab.cpp src/session_tab.cpp
src/session_tab.h src/session_tab.h
src/terminal_view.cpp
src/terminal_view.h
src/session_window.cpp src/session_window.cpp
src/session_window.h src/session_window.h
src/ssh_session_backend.cpp src/ssh_session_backend.cpp
@@ -36,5 +40,6 @@ add_executable(orbithub
) )
target_link_libraries(orbithub PRIVATE Qt6::Widgets Qt6::Sql) target_link_libraries(orbithub PRIVATE Qt6::Widgets Qt6::Sql)
target_link_libraries(orbithub PRIVATE KodoTerm::KodoTerm)
install(TARGETS orbithub RUNTIME DESTINATION bin) install(TARGETS orbithub RUNTIME DESTINATION bin)

View File

@@ -77,3 +77,17 @@ OrbitHub uses a two-window model:
- Per-session timestamped event log and user-friendly error mapping - Per-session timestamped event log and user-friendly error mapping
- Profile schema extended with `private_key_path` and `known_hosts_policy` - Profile schema extended with `private_key_path` and `known_hosts_policy`
- Tag: v0-m3-done - Tag: v0-m3-done
---
## Milestone 4 (Draft)
- Make SSH sessions actually usable as interactive sessions inside OrbitHub
- Replace placeholder surface with interactive SSH terminal panel (stream output + send input)
- Add SSH host-key trust prompt flow for `Ask` policy
- Improve auth flow UX for password / private key at connect time
- Preserve responsive UI under active session output
- Add terminal/session utilities (`Clear Terminal`, improved output visibility)
- Keep session controls stable (`Connect`, `Disconnect`, `Reconnect`, `Copy Error`)
- Add validation and diagnostics coverage for host-key, auth, and reconnect behavior
- Planned Tag: v0-m4-done (after completion approval)

View File

@@ -60,3 +60,21 @@ Delivered:
Git: Git:
- Tag: `v0-m3-done` - Tag: `v0-m3-done`
## Milestone 4 - Interactive SSH Session UX
Status: Completed
Delivered:
- Embedded interactive SSH terminal using `KodoTerm` + vendored `libvterm`
- Native in-terminal typing for SSH sessions (no separate input box)
- ANSI/color rendering with selectable terminal themes (`Dark`, `Light`, `Solarized Dark`)
- Cross-platform SSH auth path improvements (`ssh-askpass` handling and host-key policy wiring)
- Session UX simplification: auto-connect on tab open, disconnect on tab close
- Tab-state indicators via tab color and state suffix (`Connecting`, `Connected`, `Disconnected`, `Failed`)
- Right-click tab menu for `Disconnect`, `Reconnect`, `Theme`, and `Clear`
- Collapsible events panel retained as primary diagnostics surface; inline detail/status banners removed
- Terminal behavior polish: better fixed-width font selection, cursor visibility, backspace handling, and terminal-size negotiation stability
Git:
- Tag: `v0-m4-done` (pending push)

View File

@@ -4,6 +4,8 @@
int main(int argc, char* argv[]) int main(int argc, char* argv[])
{ {
Q_INIT_RESOURCE(KodoTermThemes);
QApplication app(argc, argv); QApplication app(argc, argv);
ProfilesWindow window; ProfilesWindow window;

View File

@@ -52,7 +52,7 @@ ProfileDialog::ProfileDialog(QWidget* parent)
m_protocolInput->addItems({QStringLiteral("SSH"), QStringLiteral("RDP"), QStringLiteral("VNC")}); m_protocolInput->addItems({QStringLiteral("SSH"), QStringLiteral("RDP"), QStringLiteral("VNC")});
m_authModeInput->addItems({QStringLiteral("Password"), QStringLiteral("Private Key")}); m_authModeInput->addItems({QStringLiteral("Password"), QStringLiteral("Private Key")});
m_knownHostsPolicyInput->addItems( m_knownHostsPolicyInput->addItems(
{QStringLiteral("Strict"), QStringLiteral("Accept New"), QStringLiteral("Ignore")}); {QStringLiteral("Ask"), QStringLiteral("Strict"), QStringLiteral("Accept New"), QStringLiteral("Ignore")});
m_privateKeyPathInput->setPlaceholderText(QStringLiteral("/home/user/.ssh/id_ed25519")); m_privateKeyPathInput->setPlaceholderText(QStringLiteral("/home/user/.ssh/id_ed25519"));

View File

@@ -32,7 +32,7 @@ void bindProfileFields(QSqlQuery& query, const Profile& profile)
query.addBindValue(profile.authMode.trimmed()); query.addBindValue(profile.authMode.trimmed());
query.addBindValue(profile.privateKeyPath.trimmed()); query.addBindValue(profile.privateKeyPath.trimmed());
query.addBindValue(profile.knownHostsPolicy.trimmed().isEmpty() query.addBindValue(profile.knownHostsPolicy.trimmed().isEmpty()
? QStringLiteral("Strict") ? QStringLiteral("Ask")
: profile.knownHostsPolicy.trimmed()); : profile.knownHostsPolicy.trimmed());
} }
@@ -49,7 +49,7 @@ Profile profileFromQuery(const QSqlQuery& query)
profile.privateKeyPath = query.value(7).toString(); profile.privateKeyPath = query.value(7).toString();
profile.knownHostsPolicy = query.value(8).toString(); profile.knownHostsPolicy = query.value(8).toString();
if (profile.knownHostsPolicy.isEmpty()) { if (profile.knownHostsPolicy.isEmpty()) {
profile.knownHostsPolicy = QStringLiteral("Strict"); profile.knownHostsPolicy = QStringLiteral("Ask");
} }
return profile; return profile;
} }
@@ -253,7 +253,7 @@ bool ProfileRepository::initializeDatabase()
"protocol TEXT NOT NULL DEFAULT 'SSH'," "protocol TEXT NOT NULL DEFAULT 'SSH',"
"auth_mode TEXT NOT NULL DEFAULT 'Password'," "auth_mode TEXT NOT NULL DEFAULT 'Password',"
"private_key_path TEXT NOT NULL DEFAULT ''," "private_key_path TEXT NOT NULL DEFAULT '',"
"known_hosts_policy TEXT NOT NULL DEFAULT 'Strict'" "known_hosts_policy TEXT NOT NULL DEFAULT 'Ask'"
")")); ")"));
if (!created) { if (!created) {
@@ -299,7 +299,7 @@ bool ProfileRepository::ensureProfileSchema() const
{QStringLiteral("protocol"), QStringLiteral("ALTER TABLE profiles ADD COLUMN protocol TEXT NOT NULL DEFAULT 'SSH'")}, {QStringLiteral("protocol"), QStringLiteral("ALTER TABLE profiles ADD COLUMN protocol TEXT NOT NULL DEFAULT 'SSH'")},
{QStringLiteral("auth_mode"), QStringLiteral("ALTER TABLE profiles ADD COLUMN auth_mode TEXT NOT NULL DEFAULT 'Password'")}, {QStringLiteral("auth_mode"), QStringLiteral("ALTER TABLE profiles ADD COLUMN auth_mode TEXT NOT NULL DEFAULT 'Password'")},
{QStringLiteral("private_key_path"), QStringLiteral("ALTER TABLE profiles ADD COLUMN private_key_path TEXT NOT NULL DEFAULT ''")}, {QStringLiteral("private_key_path"), QStringLiteral("ALTER TABLE profiles ADD COLUMN private_key_path TEXT NOT NULL DEFAULT ''")},
{QStringLiteral("known_hosts_policy"), QStringLiteral("ALTER TABLE profiles ADD COLUMN known_hosts_policy TEXT NOT NULL DEFAULT 'Strict'")}}; {QStringLiteral("known_hosts_policy"), QStringLiteral("ALTER TABLE profiles ADD COLUMN known_hosts_policy TEXT NOT NULL DEFAULT 'Ask'")}};
for (const ColumnDef& column : required) { for (const ColumnDef& column : required) {
if (columns.contains(column.name)) { if (columns.contains(column.name)) {

View File

@@ -17,7 +17,7 @@ struct Profile
QString protocol = QStringLiteral("SSH"); QString protocol = QStringLiteral("SSH");
QString authMode = QStringLiteral("Password"); QString authMode = QStringLiteral("Password");
QString privateKeyPath; QString privateKeyPath;
QString knownHostsPolicy = QStringLiteral("Strict"); QString knownHostsPolicy = QStringLiteral("Ask");
}; };
class ProfileRepository class ProfileRepository

View File

@@ -41,11 +41,16 @@ public slots:
virtual void connectSession(const SessionConnectOptions& options) = 0; virtual void connectSession(const SessionConnectOptions& options) = 0;
virtual void disconnectSession() = 0; virtual void disconnectSession() = 0;
virtual void reconnectSession(const SessionConnectOptions& options) = 0; virtual void reconnectSession(const SessionConnectOptions& options) = 0;
virtual void sendInput(const QString& input) = 0;
virtual void confirmHostKey(bool trustHost) = 0;
virtual void updateTerminalSize(int columns, int rows) = 0;
signals: signals:
void stateChanged(SessionState state, const QString& message); void stateChanged(SessionState state, const QString& message);
void eventLogged(const QString& message); void eventLogged(const QString& message);
void connectionError(const QString& displayMessage, const QString& rawMessage); void connectionError(const QString& displayMessage, const QString& rawMessage);
void outputReceived(const QString& text);
void hostKeyConfirmationRequested(const QString& prompt);
private: private:
Profile m_profile; Profile m_profile;

View File

@@ -1,44 +1,118 @@
#include "session_tab.h" #include "session_tab.h"
#include "session_backend_factory.h" #include "session_backend_factory.h"
#include "terminal_view.h"
#include <KodoTerm/KodoTerm.hpp>
#include <QClipboard>
#include <QDateTime> #include <QDateTime>
#include <QFileDialog> #include <QFileDialog>
#include <QFileInfo> #include <QFileInfo>
#include <QFont> #include <QFont>
#include <QGuiApplication> #include <QFontDatabase>
#include <QHBoxLayout> #include <QHBoxLayout>
#include <QInputDialog> #include <QInputDialog>
#include <QLabel> #include <QLabel>
#include <QLineEdit> #include <QLineEdit>
#include <QMessageBox> #include <QMessageBox>
#include <QPlainTextEdit> #include <QPlainTextEdit>
#include <QPushButton> #include <QProcessEnvironment>
#include <QThread> #include <QThread>
#include <QTimer>
#include <QToolButton>
#include <QVBoxLayout> #include <QVBoxLayout>
#include <memory> #include <memory>
namespace {
QFont defaultTerminalFont()
{
QFont font = QFontDatabase::systemFont(QFontDatabase::FixedFont);
font.setStyleHint(QFont::Monospace);
font.setFixedPitch(true);
font.setKerning(false);
font.setLetterSpacing(QFont::AbsoluteSpacing, 0.0);
return font;
}
TerminalTheme themeForName(const QString& themeName)
{
if (themeName.compare(QStringLiteral("Light"), Qt::CaseInsensitive) == 0) {
return TerminalTheme::loadKonsoleTheme(
QStringLiteral(":/KodoTermThemes/konsole/BlackOnWhite.colorscheme"));
}
if (themeName.compare(QStringLiteral("Solarized Dark"), Qt::CaseInsensitive) == 0) {
return TerminalTheme::loadKonsoleTheme(
QStringLiteral(":/KodoTermThemes/konsole/Solarized.colorscheme"));
}
return TerminalTheme::loadKonsoleTheme(
QStringLiteral(":/KodoTermThemes/konsole/Breeze.colorscheme"));
}
}
SessionTab::SessionTab(const Profile& profile, QWidget* parent) SessionTab::SessionTab(const Profile& profile, QWidget* parent)
: QWidget(parent), : QWidget(parent),
m_profile(profile), m_profile(profile),
m_backendThread(new QThread(this)), m_backendThread(nullptr),
m_backend(nullptr), m_backend(nullptr),
m_useKodoTermForSsh(profile.protocol.compare(QStringLiteral("SSH"), Qt::CaseInsensitive)
== 0),
m_state(SessionState::Disconnected), m_state(SessionState::Disconnected),
m_statusLabel(nullptr), m_terminalThemeName(QStringLiteral("Dark")),
m_errorLabel(nullptr), m_sshTerminal(nullptr),
m_terminalOutput(nullptr),
m_eventLog(nullptr), m_eventLog(nullptr),
m_connectButton(nullptr), m_toggleEventsButton(nullptr),
m_disconnectButton(nullptr), m_eventsPanel(nullptr)
m_reconnectButton(nullptr),
m_copyErrorButton(nullptr)
{ {
qRegisterMetaType<SessionConnectOptions>("SessionConnectOptions"); qRegisterMetaType<SessionConnectOptions>("SessionConnectOptions");
qRegisterMetaType<SessionState>("SessionState"); qRegisterMetaType<SessionState>("SessionState");
setupUi(); setupUi();
if (m_useKodoTermForSsh) {
connect(m_sshTerminal,
&KodoTerm::finished,
this,
[this](int exitCode, int) {
if (m_state == SessionState::Disconnected) {
return;
}
if (m_state == SessionState::Connected) {
if (exitCode != 0) {
appendEvent(QStringLiteral("SSH session closed with exit code %1.")
.arg(exitCode));
}
setState(SessionState::Disconnected,
QStringLiteral("SSH session closed."));
return;
}
if (exitCode == 0) {
setState(SessionState::Disconnected,
QStringLiteral("SSH session ended."));
return;
}
m_lastError = QStringLiteral("ssh exited with code %1").arg(exitCode);
appendEvent(QStringLiteral("Error: %1").arg(m_lastError));
setState(SessionState::Failed,
QStringLiteral("SSH session exited unexpectedly."));
});
connect(m_sshTerminal,
&KodoTerm::cwdChanged,
this,
[this](const QString& cwd) {
if (!cwd.trimmed().isEmpty()) {
appendEvent(QStringLiteral("Remote cwd: %1").arg(cwd));
}
});
} else {
m_backendThread = new QThread(this);
std::unique_ptr<SessionBackend> backend = createSessionBackend(m_profile); std::unique_ptr<SessionBackend> backend = createSessionBackend(m_profile);
m_backend = backend.release(); m_backend = backend.release();
m_backend->moveToThread(m_backendThread); m_backend->moveToThread(m_backendThread);
@@ -59,6 +133,21 @@ SessionTab::SessionTab(const Profile& profile, QWidget* parent)
m_backend, m_backend,
&SessionBackend::reconnectSession, &SessionBackend::reconnectSession,
Qt::QueuedConnection); Qt::QueuedConnection);
connect(this,
&SessionTab::requestInput,
m_backend,
&SessionBackend::sendInput,
Qt::QueuedConnection);
connect(this,
&SessionTab::requestHostKeyConfirmation,
m_backend,
&SessionBackend::confirmHostKey,
Qt::QueuedConnection);
connect(this,
&SessionTab::requestTerminalSize,
m_backend,
&SessionBackend::updateTerminalSize,
Qt::QueuedConnection);
connect(m_backend, connect(m_backend,
&SessionBackend::stateChanged, &SessionBackend::stateChanged,
@@ -75,20 +164,35 @@ SessionTab::SessionTab(const Profile& profile, QWidget* parent)
this, this,
&SessionTab::onBackendConnectionError, &SessionTab::onBackendConnectionError,
Qt::QueuedConnection); Qt::QueuedConnection);
connect(m_backend,
&SessionBackend::outputReceived,
this,
&SessionTab::onBackendOutputReceived,
Qt::QueuedConnection);
connect(m_backend,
&SessionBackend::hostKeyConfirmationRequested,
this,
&SessionTab::onBackendHostKeyConfirmationRequested,
Qt::QueuedConnection);
m_backendThread->start(); m_backendThread->start();
}
setState(SessionState::Disconnected, QStringLiteral("Ready to connect.")); setState(SessionState::Disconnected, QStringLiteral("Ready to connect."));
QTimer::singleShot(0, this, &SessionTab::connectSession);
} }
SessionTab::~SessionTab() SessionTab::~SessionTab()
{ {
if (m_backend != nullptr && m_backendThread->isRunning()) { if (m_useKodoTermForSsh && m_sshTerminal != nullptr && m_state != SessionState::Disconnected) {
QMetaObject::invokeMethod(m_backend, "disconnectSession", Qt::BlockingQueuedConnection); m_sshTerminal->kill();
} }
if (m_backend != nullptr && m_backendThread != nullptr && m_backendThread->isRunning()) {
QMetaObject::invokeMethod(m_backend, "disconnectSession", Qt::BlockingQueuedConnection);
m_backendThread->quit(); m_backendThread->quit();
m_backendThread->wait(2000); m_backendThread->wait(2000);
}
} }
QString SessionTab::tabTitle() const QString SessionTab::tabTitle() const
@@ -96,8 +200,12 @@ QString SessionTab::tabTitle() const
return QStringLiteral("%1 (%2)").arg(m_profile.name, stateSuffix()); return QStringLiteral("%1 (%2)").arg(m_profile.name, stateSuffix());
} }
void SessionTab::onConnectClicked() void SessionTab::connectSession()
{ {
if (m_state == SessionState::Connecting || m_state == SessionState::Connected) {
return;
}
if (!validateProfileForConnect()) { if (!validateProfileForConnect()) {
return; return;
} }
@@ -107,15 +215,36 @@ void SessionTab::onConnectClicked()
return; return;
} }
m_lastConnectOptions = options.value();
if (m_useKodoTermForSsh) {
if (!startSshTerminal(options.value())) {
return;
}
return;
}
emit requestConnect(options.value()); emit requestConnect(options.value());
} }
void SessionTab::onDisconnectClicked() void SessionTab::disconnectSession()
{ {
if (m_state == SessionState::Disconnected) {
return;
}
if (m_useKodoTermForSsh) {
if (m_sshTerminal != nullptr) {
m_sshTerminal->kill();
}
setState(SessionState::Disconnected, QStringLiteral("Session disconnected."));
return;
}
emit requestDisconnect(); emit requestDisconnect();
} }
void SessionTab::onReconnectClicked() void SessionTab::reconnectSession()
{ {
if (!validateProfileForConnect()) { if (!validateProfileForConnect()) {
return; return;
@@ -126,17 +255,57 @@ void SessionTab::onReconnectClicked()
return; return;
} }
emit requestReconnect(options.value()); m_lastConnectOptions = options.value();
}
void SessionTab::onCopyErrorClicked() if (m_useKodoTermForSsh) {
{ if (m_sshTerminal != nullptr) {
if (m_lastError.isEmpty()) { m_sshTerminal->kill();
}
QTimer::singleShot(50,
this,
[this, options]() { startSshTerminal(options.value()); });
return; return;
} }
QGuiApplication::clipboard()->setText(m_lastError); emit requestReconnect(options.value());
appendEvent(QStringLiteral("Copied last error to clipboard.")); }
void SessionTab::clearTerminal()
{
if (m_useKodoTermForSsh && m_sshTerminal != nullptr) {
m_sshTerminal->clearScrollback();
m_sshTerminal->setFocus();
return;
}
if (m_terminalOutput != nullptr) {
m_terminalOutput->clear();
if (m_state == SessionState::Connected) {
emit requestInput(QStringLiteral("\x0c"));
}
m_terminalOutput->setFocus();
}
}
void SessionTab::setTerminalThemeName(const QString& themeName)
{
const QString normalized = themeName.trimmed();
if (normalized.isEmpty()) {
return;
}
if (m_terminalThemeName.compare(normalized, Qt::CaseInsensitive) == 0) {
return;
}
m_terminalThemeName = normalized;
applyTerminalTheme(m_terminalThemeName);
appendEvent(QStringLiteral("Terminal theme set to %1.").arg(m_terminalThemeName));
}
QString SessionTab::terminalThemeName() const
{
return m_terminalThemeName;
} }
void SessionTab::onBackendStateChanged(SessionState state, const QString& message) void SessionTab::onBackendStateChanged(SessionState state, const QString& message)
@@ -152,68 +321,101 @@ void SessionTab::onBackendEventLogged(const QString& message)
void SessionTab::onBackendConnectionError(const QString& displayMessage, const QString& rawMessage) void SessionTab::onBackendConnectionError(const QString& displayMessage, const QString& rawMessage)
{ {
m_lastError = rawMessage.isEmpty() ? displayMessage : rawMessage; m_lastError = rawMessage.isEmpty() ? displayMessage : rawMessage;
m_errorLabel->setText(QStringLiteral("Last Error: %1").arg(displayMessage)); appendEvent(QStringLiteral("Error: %1").arg(displayMessage));
m_copyErrorButton->setEnabled(true); }
void SessionTab::onBackendOutputReceived(const QString& text)
{
if (text.isEmpty() || m_terminalOutput == nullptr) {
return;
}
m_terminalOutput->appendTerminalData(text);
}
void SessionTab::onBackendHostKeyConfirmationRequested(const QString& prompt)
{
const QString question = prompt.isEmpty()
? QStringLiteral("Unknown SSH host key. Do you trust this host?")
: prompt;
const QMessageBox::StandardButton reply = QMessageBox::question(
this,
QStringLiteral("SSH Host Key Confirmation"),
QStringLiteral("%1\n\nTrust and continue?").arg(question),
QMessageBox::Yes | QMessageBox::No,
QMessageBox::No);
emit requestHostKeyConfirmation(reply == QMessageBox::Yes);
} }
void SessionTab::setupUi() void SessionTab::setupUi()
{ {
auto* rootLayout = new QVBoxLayout(this); auto* rootLayout = new QVBoxLayout(this);
auto* profileLabel = new QLabel(QStringLiteral("Profile: %1").arg(m_profile.name), this); if (m_useKodoTermForSsh) {
auto* endpointLabel = new QLabel( m_sshTerminal = new KodoTerm(this);
QStringLiteral("Endpoint: %1://%2@%3:%4") const QFont terminalFont = defaultTerminalFont();
.arg(m_profile.protocol,
m_profile.username.isEmpty() ? QStringLiteral("<none>") : m_profile.username,
m_profile.host,
QString::number(m_profile.port)),
this);
auto* authLabel = new QLabel(QStringLiteral("Auth: %1").arg(m_profile.authMode), this);
m_statusLabel = new QLabel(this); KodoTermConfig config = m_sshTerminal->getConfig();
m_errorLabel = new QLabel(QStringLiteral("Last Error: None"), this); config.font = terminalFont;
m_errorLabel->setWordWrap(true); config.textAntialiasing = true;
config.maxScrollback = 12000;
m_sshTerminal->setConfig(config);
rootLayout->addWidget(m_sshTerminal, 1);
} else {
m_terminalOutput = new TerminalView(this);
m_terminalOutput->setFont(defaultTerminalFont());
m_terminalOutput->setMinimumHeight(260);
m_terminalOutput->setPlaceholderText(
QStringLiteral("Session is connecting. Type directly here once connected."));
rootLayout->addWidget(m_terminalOutput, 1);
}
auto* actionRow = new QHBoxLayout(); applyTerminalTheme(m_terminalThemeName);
m_connectButton = new QPushButton(QStringLiteral("Connect"), this);
m_disconnectButton = new QPushButton(QStringLiteral("Disconnect"), this);
m_reconnectButton = new QPushButton(QStringLiteral("Reconnect"), this);
m_copyErrorButton = new QPushButton(QStringLiteral("Copy Error"), this);
actionRow->addWidget(m_connectButton); auto* eventsHeader = new QHBoxLayout();
actionRow->addWidget(m_disconnectButton); m_toggleEventsButton = new QToolButton(this);
actionRow->addWidget(m_reconnectButton); m_toggleEventsButton->setCheckable(true);
actionRow->addWidget(m_copyErrorButton); eventsHeader->addWidget(m_toggleEventsButton);
actionRow->addStretch(); eventsHeader->addStretch();
auto* surfaceLabel = new QLabel(QStringLiteral("OrbitHub Native Surface"), this); m_eventsPanel = new QWidget(this);
QFont surfaceFont = surfaceLabel->font(); auto* eventsLayout = new QVBoxLayout(m_eventsPanel);
surfaceFont.setPointSize(surfaceFont.pointSize() + 6); eventsLayout->setContentsMargins(0, 0, 0, 0);
surfaceFont.setBold(true);
surfaceLabel->setFont(surfaceFont);
surfaceLabel->setAlignment(Qt::AlignCenter);
surfaceLabel->setMinimumHeight(180);
surfaceLabel->setStyleSheet(
QStringLiteral("border: 1px solid #8a8a8a; background-color: #f5f5f5;"));
m_eventLog = new QPlainTextEdit(this); auto* eventTitle = new QLabel(QStringLiteral("Session Events"), m_eventsPanel);
m_eventLog = new QPlainTextEdit(m_eventsPanel);
m_eventLog->setReadOnly(true); m_eventLog->setReadOnly(true);
m_eventLog->setPlaceholderText(QStringLiteral("Session event log...")); m_eventLog->setPlaceholderText(QStringLiteral("Session event log..."));
m_eventLog->setMinimumHeight(180); m_eventLog->setMinimumHeight(140);
rootLayout->addWidget(profileLabel); eventsLayout->addWidget(eventTitle);
rootLayout->addWidget(endpointLabel); eventsLayout->addWidget(m_eventLog);
rootLayout->addWidget(authLabel);
rootLayout->addWidget(m_statusLabel);
rootLayout->addWidget(m_errorLabel);
rootLayout->addLayout(actionRow);
rootLayout->addWidget(surfaceLabel);
rootLayout->addWidget(m_eventLog, 1);
connect(m_connectButton, &QPushButton::clicked, this, &SessionTab::onConnectClicked); rootLayout->addLayout(eventsHeader);
connect(m_disconnectButton, &QPushButton::clicked, this, &SessionTab::onDisconnectClicked); rootLayout->addWidget(m_eventsPanel);
connect(m_reconnectButton, &QPushButton::clicked, this, &SessionTab::onReconnectClicked);
connect(m_copyErrorButton, &QPushButton::clicked, this, &SessionTab::onCopyErrorClicked); setPanelExpanded(m_toggleEventsButton, m_eventsPanel, QStringLiteral("Events"), false);
connect(m_toggleEventsButton,
&QToolButton::toggled,
this,
[this](bool expanded) {
setPanelExpanded(
m_toggleEventsButton, m_eventsPanel, QStringLiteral("Events"), expanded);
});
if (m_terminalOutput != nullptr) {
connect(m_terminalOutput,
&TerminalView::inputGenerated,
this,
[this](const QString& input) { emit requestInput(input); });
connect(m_terminalOutput,
&TerminalView::terminalSizeChanged,
this,
[this](int columns, int rows) { emit requestTerminalSize(columns, rows); });
}
} }
std::optional<SessionConnectOptions> SessionTab::buildConnectOptions() std::optional<SessionConnectOptions> SessionTab::buildConnectOptions()
@@ -225,6 +427,12 @@ std::optional<SessionConnectOptions> SessionTab::buildConnectOptions()
return options; return options;
} }
if (m_useKodoTermForSsh
&& m_profile.authMode.compare(QStringLiteral("Password"), Qt::CaseInsensitive) == 0) {
// Password is entered directly in terminal prompt.
return options;
}
if (m_profile.authMode.compare(QStringLiteral("Password"), Qt::CaseInsensitive) == 0) { if (m_profile.authMode.compare(QStringLiteral("Password"), Qt::CaseInsensitive) == 0) {
bool accepted = false; bool accepted = false;
const QString password = QInputDialog::getText(this, const QString password = QInputDialog::getText(this,
@@ -310,28 +518,11 @@ void SessionTab::appendEvent(const QString& message)
void SessionTab::setState(SessionState state, const QString& message) void SessionTab::setState(SessionState state, const QString& message)
{ {
m_state = state; m_state = state;
appendEvent(QStringLiteral("Connection state: %1").arg(message));
QString style;
switch (state) {
case SessionState::Disconnected:
style = QStringLiteral("border: 1px solid #8a8a8a; background-color: #efefef; padding: 6px;");
break;
case SessionState::Connecting:
style = QStringLiteral("border: 1px solid #a5a5a5; background-color: #fff3cd; padding: 6px;");
break;
case SessionState::Connected:
style = QStringLiteral("border: 1px solid #3c763d; background-color: #dff0d8; padding: 6px;");
break;
case SessionState::Failed:
style = QStringLiteral("border: 1px solid #a94442; background-color: #f2dede; padding: 6px;");
break;
}
m_statusLabel->setStyleSheet(style);
m_statusLabel->setText(QStringLiteral("Connection State: %1").arg(message));
refreshActionButtons(); refreshActionButtons();
emit tabTitleChanged(tabTitle()); emit tabTitleChanged(tabTitle());
emit tabStateChanged(state);
} }
QString SessionTab::stateSuffix() const QString SessionTab::stateSuffix() const
@@ -352,12 +543,128 @@ QString SessionTab::stateSuffix() const
void SessionTab::refreshActionButtons() void SessionTab::refreshActionButtons()
{ {
m_connectButton->setEnabled(m_state == SessionState::Disconnected const bool isConnected = m_state == SessionState::Connected;
|| m_state == SessionState::Failed);
m_disconnectButton->setEnabled(m_state == SessionState::Connected if (m_useKodoTermForSsh && m_sshTerminal != nullptr) {
|| m_state == SessionState::Connecting); m_sshTerminal->setEnabled(true);
m_reconnectButton->setEnabled(m_state == SessionState::Connected m_sshTerminal->setFocus();
|| m_state == SessionState::Failed return;
|| m_state == SessionState::Disconnected); }
m_copyErrorButton->setEnabled(!m_lastError.isEmpty());
if (m_terminalOutput != nullptr) {
m_terminalOutput->setEnabled(isConnected);
m_terminalOutput->setFocus();
}
}
void SessionTab::setPanelExpanded(QToolButton* button,
QWidget* panel,
const QString& name,
bool expanded)
{
if (button == nullptr || panel == nullptr) {
return;
}
button->blockSignals(true);
button->setChecked(expanded);
button->blockSignals(false);
panel->setVisible(expanded);
button->setText(expanded ? QStringLiteral("Hide %1").arg(name)
: QStringLiteral("Show %1").arg(name));
}
bool SessionTab::startSshTerminal(const SessionConnectOptions& options)
{
if (m_sshTerminal == nullptr) {
return false;
}
QStringList args;
args << QStringLiteral("-tt") << QStringLiteral("-p") << QString::number(m_profile.port)
<< QStringLiteral("-o") << QStringLiteral("ConnectTimeout=12") << QStringLiteral("-o")
<< QStringLiteral("ServerAliveInterval=20") << QStringLiteral("-o")
<< QStringLiteral("ServerAliveCountMax=2");
const QString policy = options.knownHostsPolicy.trimmed().isEmpty()
? m_profile.knownHostsPolicy.trimmed()
: options.knownHostsPolicy.trimmed();
if (policy.compare(QStringLiteral("Ignore"), Qt::CaseInsensitive) == 0) {
#ifdef Q_OS_WIN
const QString knownHostsNullDevice = QStringLiteral("NUL");
#else
const QString knownHostsNullDevice = QStringLiteral("/dev/null");
#endif
args << QStringLiteral("-o") << QStringLiteral("StrictHostKeyChecking=no")
<< QStringLiteral("-o")
<< QStringLiteral("UserKnownHostsFile=%1").arg(knownHostsNullDevice);
} else if (policy.compare(QStringLiteral("Accept New"), Qt::CaseInsensitive) == 0) {
args << QStringLiteral("-o") << QStringLiteral("StrictHostKeyChecking=accept-new");
} else if (policy.compare(QStringLiteral("Ask"), Qt::CaseInsensitive) == 0) {
args << QStringLiteral("-o") << QStringLiteral("StrictHostKeyChecking=ask");
} else {
args << QStringLiteral("-o") << QStringLiteral("StrictHostKeyChecking=yes");
}
if (m_profile.authMode.compare(QStringLiteral("Private Key"), Qt::CaseInsensitive) == 0) {
QString keyPath = options.privateKeyPath.trimmed();
if (keyPath.isEmpty()) {
keyPath = m_profile.privateKeyPath.trimmed();
}
if (keyPath.isEmpty()) {
m_lastError = QStringLiteral("Private key path is required.");
appendEvent(QStringLiteral("Error: %1").arg(m_lastError));
setState(SessionState::Failed, m_lastError);
return false;
}
args << QStringLiteral("-i") << keyPath;
}
const QString target = m_profile.username.trimmed().isEmpty()
? m_profile.host.trimmed()
: QStringLiteral("%1@%2").arg(m_profile.username.trimmed(), m_profile.host.trimmed());
args << target;
QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
if (!env.contains(QStringLiteral("TERM"))) {
env.insert(QStringLiteral("TERM"), QStringLiteral("xterm-256color"));
}
if (!env.contains(QStringLiteral("COLORTERM"))) {
env.insert(QStringLiteral("COLORTERM"), QStringLiteral("truecolor"));
}
m_sshTerminal->setProgram(QStringLiteral("ssh"));
m_sshTerminal->setArguments(args);
m_sshTerminal->setProcessEnvironment(env);
appendEvent(QStringLiteral("Launching SSH terminal session."));
setState(SessionState::Connecting, QStringLiteral("Starting SSH terminal..."));
if (!m_sshTerminal->start()) {
m_lastError = QStringLiteral("Failed to start embedded SSH terminal process.");
appendEvent(QStringLiteral("Error: %1").arg(m_lastError));
setState(SessionState::Failed, QStringLiteral("Failed to start SSH terminal."));
return false;
}
setState(SessionState::Connected, QStringLiteral("SSH session established."));
return true;
}
void SessionTab::applyTerminalTheme(const QString& themeName)
{
if (m_useKodoTermForSsh) {
if (m_sshTerminal != nullptr) {
m_sshTerminal->setTheme(themeForName(themeName));
}
return;
}
if (m_terminalOutput != nullptr) {
m_terminalOutput->setThemeName(themeName);
}
} }

View File

@@ -8,11 +8,12 @@
#include <optional> #include <optional>
class QLabel;
class QPlainTextEdit; class QPlainTextEdit;
class QPushButton;
class QThread; class QThread;
class SessionBackend; class SessionBackend;
class TerminalView;
class QToolButton;
class KodoTerm;
class SessionTab : public QWidget class SessionTab : public QWidget
{ {
@@ -23,37 +24,45 @@ public:
~SessionTab() override; ~SessionTab() override;
QString tabTitle() const; QString tabTitle() const;
void connectSession();
void disconnectSession();
void reconnectSession();
void clearTerminal();
void setTerminalThemeName(const QString& themeName);
QString terminalThemeName() const;
signals: signals:
void tabTitleChanged(const QString& title); void tabTitleChanged(const QString& title);
void tabStateChanged(SessionState state);
void requestConnect(const SessionConnectOptions& options); void requestConnect(const SessionConnectOptions& options);
void requestDisconnect(); void requestDisconnect();
void requestReconnect(const SessionConnectOptions& options); void requestReconnect(const SessionConnectOptions& options);
void requestInput(const QString& input);
void requestHostKeyConfirmation(bool trustHost);
void requestTerminalSize(int columns, int rows);
private slots: private slots:
void onConnectClicked();
void onDisconnectClicked();
void onReconnectClicked();
void onCopyErrorClicked();
void onBackendStateChanged(SessionState state, const QString& message); void onBackendStateChanged(SessionState state, const QString& message);
void onBackendEventLogged(const QString& message); void onBackendEventLogged(const QString& message);
void onBackendConnectionError(const QString& displayMessage, const QString& rawMessage); void onBackendConnectionError(const QString& displayMessage, const QString& rawMessage);
void onBackendOutputReceived(const QString& text);
void onBackendHostKeyConfirmationRequested(const QString& prompt);
private: private:
Profile m_profile; Profile m_profile;
QThread* m_backendThread; QThread* m_backendThread;
SessionBackend* m_backend; SessionBackend* m_backend;
bool m_useKodoTermForSsh;
SessionState m_state; SessionState m_state;
QString m_lastError; QString m_lastError;
SessionConnectOptions m_lastConnectOptions;
QString m_terminalThemeName;
QLabel* m_statusLabel; KodoTerm* m_sshTerminal;
QLabel* m_errorLabel; TerminalView* m_terminalOutput;
QPlainTextEdit* m_eventLog; QPlainTextEdit* m_eventLog;
QPushButton* m_connectButton; QToolButton* m_toggleEventsButton;
QPushButton* m_disconnectButton; QWidget* m_eventsPanel;
QPushButton* m_reconnectButton;
QPushButton* m_copyErrorButton;
void setupUi(); void setupUi();
std::optional<SessionConnectOptions> buildConnectOptions(); std::optional<SessionConnectOptions> buildConnectOptions();
@@ -62,6 +71,9 @@ private:
void setState(SessionState state, const QString& message); void setState(SessionState state, const QString& message);
QString stateSuffix() const; QString stateSuffix() const;
void refreshActionButtons(); void refreshActionButtons();
void setPanelExpanded(QToolButton* button, QWidget* panel, const QString& name, bool expanded);
bool startSshTerminal(const SessionConnectOptions& options);
void applyTerminalTheme(const QString& themeName);
}; };
#endif #endif

View File

@@ -2,8 +2,37 @@
#include "session_tab.h" #include "session_tab.h"
#include <QAction>
#include <QColor>
#include <QMenu>
#include <QPalette>
#include <QStringList>
#include <QTabBar>
#include <QTabWidget> #include <QTabWidget>
namespace {
QColor tabColorForState(SessionState state, const QPalette& palette)
{
switch (state) {
case SessionState::Disconnected:
return palette.color(QPalette::WindowText);
case SessionState::Connecting:
return QColor(QStringLiteral("#9a6700"));
case SessionState::Connected:
return QColor(QStringLiteral("#2e7d32"));
case SessionState::Failed:
return QColor(QStringLiteral("#c62828"));
}
return palette.color(QPalette::WindowText);
}
QStringList terminalThemeNames()
{
return {QStringLiteral("Dark"), QStringLiteral("Light"), QStringLiteral("Solarized Dark")};
}
}
SessionWindow::SessionWindow(const Profile& profile, QWidget* parent) SessionWindow::SessionWindow(const Profile& profile, QWidget* parent)
: QMainWindow(parent), m_tabs(new QTabWidget(this)) : QMainWindow(parent), m_tabs(new QTabWidget(this))
{ {
@@ -16,12 +45,61 @@ SessionWindow::SessionWindow(const Profile& profile, QWidget* parent)
this, this,
[this](int index) { [this](int index) {
QWidget* tab = m_tabs->widget(index); QWidget* tab = m_tabs->widget(index);
if (auto* sessionTab = qobject_cast<SessionTab*>(tab)) {
sessionTab->disconnectSession();
}
m_tabs->removeTab(index); m_tabs->removeTab(index);
delete tab; delete tab;
if (m_tabs->count() == 0) { if (m_tabs->count() == 0) {
close(); close();
} }
}); });
m_tabs->tabBar()->setContextMenuPolicy(Qt::CustomContextMenu);
connect(m_tabs->tabBar(),
&QWidget::customContextMenuRequested,
this,
[this](const QPoint& pos) {
const int index = m_tabs->tabBar()->tabAt(pos);
if (index < 0) {
return;
}
auto* tab = qobject_cast<SessionTab*>(m_tabs->widget(index));
if (tab == nullptr) {
return;
}
QMenu menu(this);
QAction* disconnectAction = menu.addAction(QStringLiteral("Disconnect"));
QAction* reconnectAction = menu.addAction(QStringLiteral("Reconnect"));
menu.addSeparator();
QMenu* themeMenu = menu.addMenu(QStringLiteral("Theme"));
QList<QAction*> themeActions;
const QString currentTheme = tab->terminalThemeName();
for (const QString& themeName : terminalThemeNames()) {
QAction* themeAction = themeMenu->addAction(themeName);
themeAction->setCheckable(true);
themeAction->setChecked(
themeName.compare(currentTheme, Qt::CaseInsensitive) == 0);
themeActions.append(themeAction);
}
QAction* clearAction = menu.addAction(QStringLiteral("Clear"));
QAction* chosen = menu.exec(m_tabs->tabBar()->mapToGlobal(pos));
if (chosen == disconnectAction) {
tab->disconnectSession();
} else if (chosen == reconnectAction) {
tab->reconnectSession();
} else if (chosen == clearAction) {
tab->clearTerminal();
} else {
for (QAction* themeAction : themeActions) {
if (chosen == themeAction) {
tab->setTerminalThemeName(themeAction->text());
break;
}
}
}
});
setCentralWidget(m_tabs); setCentralWidget(m_tabs);
addSessionTab(profile); addSessionTab(profile);
@@ -32,11 +110,25 @@ void SessionWindow::addSessionTab(const Profile& profile)
auto* tab = new SessionTab(profile, this); auto* tab = new SessionTab(profile, this);
const int index = m_tabs->addTab(tab, tab->tabTitle()); const int index = m_tabs->addTab(tab, tab->tabTitle());
m_tabs->setCurrentIndex(index); m_tabs->setCurrentIndex(index);
m_tabs->tabBar()->setTabTextColor(
index, tabColorForState(SessionState::Disconnected, m_tabs->palette()));
connect(tab, connect(tab,
&SessionTab::tabTitleChanged, &SessionTab::tabTitleChanged,
this, this,
[this, tab](const QString& title) { updateTabTitle(tab, title); }); [this, tab](const QString& title) { updateTabTitle(tab, title); });
connect(tab,
&SessionTab::tabStateChanged,
this,
[this, tab](SessionState state) {
for (int i = 0; i < m_tabs->count(); ++i) {
if (m_tabs->widget(i) == tab) {
m_tabs->tabBar()->setTabTextColor(
i, tabColorForState(state, m_tabs->palette()));
return;
}
}
});
} }
void SessionWindow::updateTabTitle(SessionTab* tab, const QString& title) void SessionWindow::updateTabTitle(SessionTab* tab, const QString& title)

View File

@@ -14,17 +14,6 @@ QString escapeForShellSingleQuotes(const QString& value)
escaped.replace(QStringLiteral("'"), QStringLiteral("'\"'\"'")); escaped.replace(QStringLiteral("'"), QStringLiteral("'\"'\"'"));
return escaped; return escaped;
} }
QString escapedForWindowsEcho(const QString& value)
{
QString escaped = value;
escaped.replace(QStringLiteral("^"), QStringLiteral("^^"));
escaped.replace(QStringLiteral("&"), QStringLiteral("^&"));
escaped.replace(QStringLiteral("|"), QStringLiteral("^|"));
escaped.replace(QStringLiteral("<"), QStringLiteral("^<"));
escaped.replace(QStringLiteral(">"), QStringLiteral("^>"));
return escaped;
}
} }
SshSessionBackend::SshSessionBackend(const Profile& profile, QObject* parent) SshSessionBackend::SshSessionBackend(const Profile& profile, QObject* parent)
@@ -33,7 +22,12 @@ SshSessionBackend::SshSessionBackend(const Profile& profile, QObject* parent)
m_connectedProbeTimer(new QTimer(this)), m_connectedProbeTimer(new QTimer(this)),
m_state(SessionState::Disconnected), m_state(SessionState::Disconnected),
m_userInitiatedDisconnect(false), m_userInitiatedDisconnect(false),
m_reconnectPending(false) m_reconnectPending(false),
m_waitingForPasswordPrompt(false),
m_waitingForHostKeyConfirmation(false),
m_passwordSubmitted(false),
m_terminalColumns(0),
m_terminalRows(0)
{ {
m_connectedProbeTimer->setSingleShot(true); m_connectedProbeTimer->setSingleShot(true);
@@ -46,6 +40,10 @@ SshSessionBackend::SshSessionBackend(const Profile& profile, QObject* parent)
qOverload<int, QProcess::ExitStatus>(&QProcess::finished), qOverload<int, QProcess::ExitStatus>(&QProcess::finished),
this, this,
&SshSessionBackend::onProcessFinished); &SshSessionBackend::onProcessFinished);
connect(m_process,
&QProcess::readyReadStandardOutput,
this,
&SshSessionBackend::onReadyReadStandardOutput);
connect(m_process, connect(m_process,
&QProcess::readyReadStandardError, &QProcess::readyReadStandardError,
this, this,
@@ -75,6 +73,10 @@ void SshSessionBackend::connectSession(const SessionConnectOptions& options)
m_userInitiatedDisconnect = false; m_userInitiatedDisconnect = false;
m_reconnectPending = false; m_reconnectPending = false;
m_lastRawError.clear(); m_lastRawError.clear();
m_activeOptions = options;
m_waitingForPasswordPrompt = false;
m_waitingForHostKeyConfirmation = false;
m_passwordSubmitted = false;
if (!startSshProcess(options)) { if (!startSshProcess(options)) {
return; return;
@@ -123,6 +125,45 @@ void SshSessionBackend::reconnectSession(const SessionConnectOptions& options)
m_process->terminate(); m_process->terminate();
} }
void SshSessionBackend::sendInput(const QString& input)
{
if (m_process->state() != QProcess::Running) {
emit eventLogged(QStringLiteral("Input ignored: session is not running."));
return;
}
if (input.isEmpty()) {
return;
}
m_process->write(input.toUtf8());
}
void SshSessionBackend::confirmHostKey(bool trustHost)
{
if (m_process->state() != QProcess::Running || !m_waitingForHostKeyConfirmation) {
return;
}
m_waitingForHostKeyConfirmation = false;
const QString response = trustHost ? QStringLiteral("yes\n") : QStringLiteral("no\n");
m_process->write(response.toUtf8());
emit eventLogged(trustHost
? QStringLiteral("Host key accepted by user.")
: QStringLiteral("Host key rejected by user."));
}
void SshSessionBackend::updateTerminalSize(int columns, int rows)
{
m_terminalColumns = columns;
m_terminalRows = rows;
if (m_state == SessionState::Connected) {
applyTerminalSizeIfAvailable();
}
}
void SshSessionBackend::onProcessStarted() void SshSessionBackend::onProcessStarted()
{ {
emit eventLogged(QStringLiteral("ssh process started.")); emit eventLogged(QStringLiteral("ssh process started."));
@@ -178,6 +219,21 @@ void SshSessionBackend::onProcessFinished(int exitCode, QProcess::ExitStatus)
setState(SessionState::Disconnected, QStringLiteral("SSH session ended.")); setState(SessionState::Disconnected, QStringLiteral("SSH session ended."));
} }
void SshSessionBackend::onReadyReadStandardOutput()
{
const QString chunk = QString::fromUtf8(m_process->readAllStandardOutput());
if (chunk.isEmpty()) {
return;
}
emit outputReceived(chunk);
if (m_state == SessionState::Connecting && !m_waitingForHostKeyConfirmation
&& !m_waitingForPasswordPrompt) {
setState(SessionState::Connected, QStringLiteral("SSH session established."));
}
}
void SshSessionBackend::onReadyReadStandardError() void SshSessionBackend::onReadyReadStandardError()
{ {
const QString chunk = QString::fromUtf8(m_process->readAllStandardError()); const QString chunk = QString::fromUtf8(m_process->readAllStandardError());
@@ -186,10 +242,40 @@ void SshSessionBackend::onReadyReadStandardError()
} }
m_lastRawError += chunk; m_lastRawError += chunk;
emit outputReceived(chunk);
const QStringList lines = chunk.split(QLatin1Char('\n'), Qt::SkipEmptyParts); const QStringList lines = chunk.split(QLatin1Char('\n'), Qt::SkipEmptyParts);
for (const QString& line : lines) { for (const QString& line : lines) {
emit eventLogged(line.trimmed()); const QString trimmed = line.trimmed();
if (!trimmed.isEmpty()) {
emit eventLogged(trimmed);
}
if (trimmed.contains(QStringLiteral("Are you sure you want to continue connecting"),
Qt::CaseInsensitive)
&& !m_waitingForHostKeyConfirmation) {
m_waitingForHostKeyConfirmation = true;
emit eventLogged(QStringLiteral("Awaiting host key confirmation from user."));
emit hostKeyConfirmationRequested(trimmed);
continue;
}
if (trimmed.contains(QStringLiteral("password:"), Qt::CaseInsensitive)
&& profile().authMode.compare(QStringLiteral("Password"), Qt::CaseInsensitive) == 0
&& !m_passwordSubmitted) {
if (m_activeOptions.password.isEmpty()) {
const QString message = QStringLiteral("Password prompt received but no password is available.");
setState(SessionState::Failed, message);
emit connectionError(message, trimmed);
return;
}
m_waitingForPasswordPrompt = false;
m_passwordSubmitted = true;
m_process->write((m_activeOptions.password + QStringLiteral("\n")).toUtf8());
emit eventLogged(QStringLiteral("Password prompt received; credentials submitted."));
continue;
}
} }
} }
@@ -199,7 +285,8 @@ void SshSessionBackend::onConnectedProbeTimeout()
return; return;
} }
if (m_process->state() == QProcess::Running) { if (m_process->state() == QProcess::Running && !m_waitingForHostKeyConfirmation
&& !m_waitingForPasswordPrompt) {
setState(SessionState::Connected, QStringLiteral("SSH session established.")); setState(SessionState::Connected, QStringLiteral("SSH session established."));
} }
} }
@@ -209,6 +296,10 @@ void SshSessionBackend::setState(SessionState state, const QString& message)
m_state = state; m_state = state;
emit stateChanged(state, message); emit stateChanged(state, message);
emit eventLogged(message); emit eventLogged(message);
if (m_state == SessionState::Connected) {
applyTerminalSizeIfAvailable();
}
} }
bool SshSessionBackend::startSshProcess(const SessionConnectOptions& options) bool SshSessionBackend::startSshProcess(const SessionConnectOptions& options)
@@ -229,12 +320,9 @@ bool SshSessionBackend::startSshProcess(const SessionConnectOptions& options)
return false; return false;
} }
cleanupAskPassScript();
QStringList args; QStringList args;
args << QStringLiteral("-N") << QStringLiteral("-T") << QStringLiteral("-p") args << QStringLiteral("-tt") << QStringLiteral("-p") << QString::number(p.port)
<< QString::number(p.port) << QStringLiteral("-o") << QStringLiteral("-o") << QStringLiteral("ConnectTimeout=12") << QStringLiteral("-o")
<< QStringLiteral("ConnectTimeout=12") << QStringLiteral("-o")
<< QStringLiteral("ServerAliveInterval=20") << QStringLiteral("-o") << QStringLiteral("ServerAliveInterval=20") << QStringLiteral("-o")
<< QStringLiteral("ServerAliveCountMax=2"); << QStringLiteral("ServerAliveCountMax=2");
@@ -248,6 +336,8 @@ bool SshSessionBackend::startSshProcess(const SessionConnectOptions& options)
<< QStringLiteral("UserKnownHostsFile=%1").arg(knownHostsFileForNullDevice()); << QStringLiteral("UserKnownHostsFile=%1").arg(knownHostsFileForNullDevice());
} else if (policy.compare(QStringLiteral("Accept New"), Qt::CaseInsensitive) == 0) { } else if (policy.compare(QStringLiteral("Accept New"), Qt::CaseInsensitive) == 0) {
args << QStringLiteral("-o") << QStringLiteral("StrictHostKeyChecking=accept-new"); args << QStringLiteral("-o") << QStringLiteral("StrictHostKeyChecking=accept-new");
} else if (policy.compare(QStringLiteral("Ask"), Qt::CaseInsensitive) == 0) {
args << QStringLiteral("-o") << QStringLiteral("StrictHostKeyChecking=ask");
} else { } else {
args << QStringLiteral("-o") << QStringLiteral("StrictHostKeyChecking=yes"); args << QStringLiteral("-o") << QStringLiteral("StrictHostKeyChecking=yes");
} }
@@ -265,6 +355,7 @@ bool SshSessionBackend::startSshProcess(const SessionConnectOptions& options)
args << QStringLiteral("-o") << QStringLiteral("PreferredAuthentications=password") args << QStringLiteral("-o") << QStringLiteral("PreferredAuthentications=password")
<< QStringLiteral("-o") << QStringLiteral("PubkeyAuthentication=no") << QStringLiteral("-o") << QStringLiteral("PubkeyAuthentication=no")
<< QStringLiteral("-o") << QStringLiteral("NumberOfPasswordPrompts=1"); << QStringLiteral("-o") << QStringLiteral("NumberOfPasswordPrompts=1");
m_waitingForPasswordPrompt = false;
QString askPassError; QString askPassError;
if (!configureAskPass(options, environment, askPassError)) { if (!configureAskPass(options, environment, askPassError)) {
@@ -346,10 +437,11 @@ bool SshSessionBackend::configureAskPass(const SessionConnectOptions& options,
QTextStream out(&script); QTextStream out(&script);
#ifdef Q_OS_WIN #ifdef Q_OS_WIN
out << "@echo off\r\n"; out << "@echo off\r\n";
out << "echo " << escapedForWindowsEcho(options.password) << "\r\n"; out << "echo " << options.password << "\r\n";
#else #else
const QString escapedPassword = escapeForShellSingleQuotes(options.password);
out << "#!/bin/sh\n"; out << "#!/bin/sh\n";
out << "printf '%s\\n' '" << escapeForShellSingleQuotes(options.password) << "'\n"; out << "printf '%s\\n' '" << escapedPassword << "'\n";
#endif #endif
out.flush(); out.flush();
script.close(); script.close();
@@ -368,7 +460,6 @@ bool SshSessionBackend::configureAskPass(const SessionConnectOptions& options,
if (!environment.contains(QStringLiteral("DISPLAY"))) { if (!environment.contains(QStringLiteral("DISPLAY"))) {
environment.insert(QStringLiteral("DISPLAY"), QStringLiteral(":0")); environment.insert(QStringLiteral("DISPLAY"), QStringLiteral(":0"));
} }
return true; return true;
} }
@@ -407,10 +498,10 @@ QString SshSessionBackend::mapSshError(const QString& rawError) const
return QStringLiteral("Private key file is not accessible."); return QStringLiteral("Private key file is not accessible.");
} }
if (raw.contains(QStringLiteral("No such file or directory"), Qt::CaseInsensitive)) { if (raw.contains(QStringLiteral("No such file or directory"), Qt::CaseInsensitive)) {
return QStringLiteral("Required file was not found."); if (raw.contains(QStringLiteral("ssh-askpass"), Qt::CaseInsensitive)) {
return QStringLiteral("SSH password helper is missing or failed to launch.");
} }
if (raw.contains(QStringLiteral("Text file busy"), Qt::CaseInsensitive)) { return QStringLiteral("Required file was not found.");
return QStringLiteral("Credential helper could not start (text file busy). Retry the connection.");
} }
if (raw.isEmpty()) { if (raw.isEmpty()) {
return QStringLiteral("SSH connection failed for an unknown reason."); return QStringLiteral("SSH connection failed for an unknown reason.");
@@ -427,3 +518,21 @@ QString SshSessionBackend::knownHostsFileForNullDevice() const
return QStringLiteral("/dev/null"); return QStringLiteral("/dev/null");
#endif #endif
} }
void SshSessionBackend::applyTerminalSizeIfAvailable()
{
if (m_process->state() != QProcess::Running) {
return;
}
if (m_terminalColumns <= 0 || m_terminalRows <= 0) {
return;
}
const QString command = QStringLiteral("stty cols %1 rows %2\\n")
.arg(m_terminalColumns)
.arg(m_terminalRows);
m_process->write(command.toUtf8());
emit eventLogged(
QStringLiteral("Applied terminal size: %1x%2").arg(m_terminalColumns).arg(m_terminalRows));
}

View File

@@ -19,11 +19,15 @@ public slots:
void connectSession(const SessionConnectOptions& options) override; void connectSession(const SessionConnectOptions& options) override;
void disconnectSession() override; void disconnectSession() override;
void reconnectSession(const SessionConnectOptions& options) override; void reconnectSession(const SessionConnectOptions& options) override;
void sendInput(const QString& input) override;
void confirmHostKey(bool trustHost) override;
void updateTerminalSize(int columns, int rows) override;
private slots: private slots:
void onProcessStarted(); void onProcessStarted();
void onProcessErrorOccurred(QProcess::ProcessError error); void onProcessErrorOccurred(QProcess::ProcessError error);
void onProcessFinished(int exitCode, QProcess::ExitStatus exitStatus); void onProcessFinished(int exitCode, QProcess::ExitStatus exitStatus);
void onReadyReadStandardOutput();
void onReadyReadStandardError(); void onReadyReadStandardError();
void onConnectedProbeTimeout(); void onConnectedProbeTimeout();
@@ -34,8 +38,14 @@ private:
bool m_userInitiatedDisconnect; bool m_userInitiatedDisconnect;
bool m_reconnectPending; bool m_reconnectPending;
SessionConnectOptions m_reconnectOptions; SessionConnectOptions m_reconnectOptions;
SessionConnectOptions m_activeOptions;
QString m_lastRawError; QString m_lastRawError;
QString m_askPassScriptPath; QString m_askPassScriptPath;
bool m_waitingForPasswordPrompt;
bool m_waitingForHostKeyConfirmation;
bool m_passwordSubmitted;
int m_terminalColumns;
int m_terminalRows;
void setState(SessionState state, const QString& message); void setState(SessionState state, const QString& message);
bool startSshProcess(const SessionConnectOptions& options); bool startSshProcess(const SessionConnectOptions& options);
@@ -45,6 +55,7 @@ private:
void cleanupAskPassScript(); void cleanupAskPassScript();
QString mapSshError(const QString& rawError) const; QString mapSshError(const QString& rawError) const;
QString knownHostsFileForNullDevice() const; QString knownHostsFileForNullDevice() const;
void applyTerminalSizeIfAvailable();
}; };
#endif #endif

520
src/terminal_view.cpp Normal file
View File

@@ -0,0 +1,520 @@
#include "terminal_view.h"
#include <QApplication>
#include <QClipboard>
#include <QColor>
#include <QFocusEvent>
#include <QFontMetrics>
#include <QKeyEvent>
#include <QResizeEvent>
#include <QTimer>
#include <QTextCursor>
#include <algorithm>
namespace {
QString normalizedThemeName(const QString& value)
{
return value.trimmed().toLower();
}
}
TerminalView::TerminalView(QWidget* parent)
: QTextEdit(parent),
m_bold(false),
m_hasFgColor(false),
m_hasBgColor(false)
{
setReadOnly(false);
setUndoRedoEnabled(false);
setAcceptRichText(false);
setLineWrapMode(QTextEdit::NoWrap);
setContextMenuPolicy(Qt::NoContextMenu);
setCursorWidth(2);
document()->setMaximumBlockCount(4000);
applyThemePalette(paletteByName(QStringLiteral("Dark")));
resetSgrState();
QTimer::singleShot(0, this, [this]() {
moveCursor(QTextCursor::End);
emitTerminalSize();
});
}
QStringList TerminalView::themeNames()
{
return {QStringLiteral("Dark"), QStringLiteral("Light"), QStringLiteral("Solarized Dark")};
}
void TerminalView::setThemeName(const QString& themeName)
{
applyThemePalette(paletteByName(themeName));
}
void TerminalView::appendTerminalData(const QString& data)
{
if (data.isEmpty()) {
return;
}
const QString merged = m_pendingEscape + data;
m_pendingEscape.clear();
QString plainBuffer;
for (int i = 0; i < merged.size();) {
const QChar ch = merged.at(i);
if (ch == QChar::fromLatin1('\x1b')) {
if (!plainBuffer.isEmpty()) {
appendTextChunk(plainBuffer);
plainBuffer.clear();
}
if (i + 1 >= merged.size()) {
m_pendingEscape = merged.mid(i);
break;
}
if (merged.at(i + 1) != QChar::fromLatin1('[')) {
i += 2;
continue;
}
int end = i + 2;
while (end < merged.size()) {
const ushort c = merged.at(end).unicode();
if (c >= 0x40 && c <= 0x7e) {
break;
}
++end;
}
if (end >= merged.size()) {
m_pendingEscape = merged.mid(i);
break;
}
const QChar finalByte = merged.at(end);
const QString params = merged.mid(i + 2, end - (i + 2));
if (finalByte == QChar::fromLatin1('m')) {
handleSgrSequence(params);
} else if (finalByte == QChar::fromLatin1('J')) {
if (params.isEmpty() || params == QStringLiteral("2")) {
clear();
}
}
i = end + 1;
continue;
}
if (ch == QChar::fromLatin1('\r')) {
const bool hasLfAfter = (i + 1 < merged.size() && merged.at(i + 1) == QChar::fromLatin1('\n'));
if (!hasLfAfter) {
plainBuffer.append(QChar::fromLatin1('\n'));
}
++i;
continue;
}
plainBuffer.append(ch);
++i;
}
if (!plainBuffer.isEmpty()) {
appendTextChunk(plainBuffer);
}
}
void TerminalView::keyPressEvent(QKeyEvent* event)
{
if (event == nullptr) {
return;
}
moveCursor(QTextCursor::End);
const Qt::KeyboardModifiers modifiers = event->modifiers();
if (modifiers == (Qt::ControlModifier | Qt::ShiftModifier)
&& event->key() == Qt::Key_C) {
const QString selected = textCursor().selectedText();
if (!selected.isEmpty()) {
QApplication::clipboard()->setText(selected);
}
return;
}
if (modifiers == Qt::ControlModifier) {
switch (event->key()) {
case Qt::Key_C:
emit inputGenerated(QStringLiteral("\x03"));
return;
case Qt::Key_D:
emit inputGenerated(QStringLiteral("\x04"));
return;
case Qt::Key_L:
emit inputGenerated(QStringLiteral("\x0c"));
return;
case Qt::Key_V: {
const QString clipboardText = QApplication::clipboard()->text();
if (!clipboardText.isEmpty()) {
emit inputGenerated(clipboardText);
}
return;
}
default:
break;
}
}
switch (event->key()) {
case Qt::Key_Return:
case Qt::Key_Enter:
emit inputGenerated(QStringLiteral("\n"));
return;
case Qt::Key_Backspace:
emit inputGenerated(QStringLiteral("\x7f"));
return;
case Qt::Key_Tab:
emit inputGenerated(QStringLiteral("\t"));
return;
case Qt::Key_Left:
emit inputGenerated(QStringLiteral("\x1b[D"));
return;
case Qt::Key_Right:
emit inputGenerated(QStringLiteral("\x1b[C"));
return;
case Qt::Key_Up:
emit inputGenerated(QStringLiteral("\x1b[A"));
return;
case Qt::Key_Down:
emit inputGenerated(QStringLiteral("\x1b[B"));
return;
default:
break;
}
const QString text = event->text();
if (!text.isEmpty()) {
emit inputGenerated(text);
return;
}
}
void TerminalView::focusInEvent(QFocusEvent* event)
{
QTextEdit::focusInEvent(event);
moveCursor(QTextCursor::End);
}
void TerminalView::resizeEvent(QResizeEvent* event)
{
QTextEdit::resizeEvent(event);
emitTerminalSize();
}
TerminalView::ThemePalette TerminalView::paletteByName(const QString& themeName)
{
const QString theme = normalizedThemeName(themeName);
if (theme == QStringLiteral("light")) {
return ThemePalette{QStringLiteral("Light"),
QColor(QStringLiteral("#ececec")),
QColor(QStringLiteral("#000000")),
{QColor(QStringLiteral("#000000")),
QColor(QStringLiteral("#aa0000")),
QColor(QStringLiteral("#008000")),
QColor(QStringLiteral("#7a5f00")),
QColor(QStringLiteral("#0033cc")),
QColor(QStringLiteral("#8a00a8")),
QColor(QStringLiteral("#005f87")),
QColor(QStringLiteral("#333333"))},
{QColor(QStringLiteral("#5c5c5c")),
QColor(QStringLiteral("#d30000")),
QColor(QStringLiteral("#00a000")),
QColor(QStringLiteral("#9a7700")),
QColor(QStringLiteral("#0055ff")),
QColor(QStringLiteral("#b300db")),
QColor(QStringLiteral("#007ea7")),
QColor(QStringLiteral("#111111"))}};
}
if (theme == QStringLiteral("solarized dark")) {
return ThemePalette{QStringLiteral("Solarized Dark"),
QColor(QStringLiteral("#002b36")),
QColor(QStringLiteral("#839496")),
{QColor(QStringLiteral("#073642")),
QColor(QStringLiteral("#dc322f")),
QColor(QStringLiteral("#859900")),
QColor(QStringLiteral("#b58900")),
QColor(QStringLiteral("#268bd2")),
QColor(QStringLiteral("#d33682")),
QColor(QStringLiteral("#2aa198")),
QColor(QStringLiteral("#eee8d5"))},
{QColor(QStringLiteral("#586e75")),
QColor(QStringLiteral("#cb4b16")),
QColor(QStringLiteral("#586e75")),
QColor(QStringLiteral("#657b83")),
QColor(QStringLiteral("#839496")),
QColor(QStringLiteral("#6c71c4")),
QColor(QStringLiteral("#93a1a1")),
QColor(QStringLiteral("#fdf6e3"))}};
}
return ThemePalette{QStringLiteral("Dark"),
QColor(QStringLiteral("#1e1e1e")),
QColor(QStringLiteral("#d4d4d4")),
{QColor(QStringLiteral("#000000")),
QColor(QStringLiteral("#cd3131")),
QColor(QStringLiteral("#0dbc79")),
QColor(QStringLiteral("#e5e510")),
QColor(QStringLiteral("#2472c8")),
QColor(QStringLiteral("#bc3fbc")),
QColor(QStringLiteral("#11a8cd")),
QColor(QStringLiteral("#e5e5e5"))},
{QColor(QStringLiteral("#666666")),
QColor(QStringLiteral("#f14c4c")),
QColor(QStringLiteral("#23d18b")),
QColor(QStringLiteral("#f5f543")),
QColor(QStringLiteral("#3b8eea")),
QColor(QStringLiteral("#d670d6")),
QColor(QStringLiteral("#29b8db")),
QColor(QStringLiteral("#ffffff"))}};
}
QColor TerminalView::colorFrom256Index(int index)
{
if (index < 0) {
index = 0;
}
if (index > 255) {
index = 255;
}
if (index < 16) {
static const std::array<QColor, 16> base = {
QColor(QStringLiteral("#000000")), QColor(QStringLiteral("#800000")),
QColor(QStringLiteral("#008000")), QColor(QStringLiteral("#808000")),
QColor(QStringLiteral("#000080")), QColor(QStringLiteral("#800080")),
QColor(QStringLiteral("#008080")), QColor(QStringLiteral("#c0c0c0")),
QColor(QStringLiteral("#808080")), QColor(QStringLiteral("#ff0000")),
QColor(QStringLiteral("#00ff00")), QColor(QStringLiteral("#ffff00")),
QColor(QStringLiteral("#0000ff")), QColor(QStringLiteral("#ff00ff")),
QColor(QStringLiteral("#00ffff")), QColor(QStringLiteral("#ffffff"))};
return base.at(static_cast<size_t>(index));
}
if (index >= 16 && index <= 231) {
const int c = index - 16;
const int r = c / 36;
const int g = (c / 6) % 6;
const int b = c % 6;
const auto channel = [](int v) { return v == 0 ? 0 : 55 + v * 40; };
return QColor(channel(r), channel(g), channel(b));
}
const int gray = 8 + (index - 232) * 10;
return QColor(gray, gray, gray);
}
void TerminalView::applyThemePalette(const ThemePalette& palette)
{
m_palette = palette;
const QString stylesheet = QStringLiteral("QTextEdit { background: %1; color: %2; }")
.arg(m_palette.background.name(), m_palette.foreground.name());
setStyleSheet(stylesheet);
if (!m_hasFgColor) {
m_fgColor = m_palette.foreground;
}
if (!m_hasBgColor) {
m_bgColor = m_palette.background;
}
applyCurrentFormat();
}
void TerminalView::applyCurrentFormat()
{
m_currentFormat = QTextCharFormat();
m_currentFormat.setForeground(m_hasFgColor ? m_fgColor : m_palette.foreground);
if (m_hasBgColor) {
m_currentFormat.setBackground(m_bgColor);
}
QFont font = currentFont();
font.setBold(m_bold);
m_currentFormat.setFont(font);
}
void TerminalView::resetSgrState()
{
m_bold = false;
m_hasFgColor = false;
m_hasBgColor = false;
m_fgColor = m_palette.foreground;
m_bgColor = m_palette.background;
applyCurrentFormat();
}
void TerminalView::handleSgrSequence(const QString& params)
{
QStringList parts = params.split(QChar::fromLatin1(';'), Qt::KeepEmptyParts);
if (parts.isEmpty()) {
parts.push_back(QStringLiteral("0"));
}
for (int i = 0; i < parts.size(); ++i) {
const QString part = parts.at(i).trimmed();
bool ok = false;
const int code = part.isEmpty() ? 0 : part.toInt(&ok);
if (!ok && !part.isEmpty()) {
continue;
}
if (code == 0) {
resetSgrState();
continue;
}
if (code == 1) {
m_bold = true;
continue;
}
if (code == 22) {
m_bold = false;
continue;
}
if (code == 39) {
m_hasFgColor = false;
continue;
}
if (code == 49) {
m_hasBgColor = false;
continue;
}
if (code >= 30 && code <= 37) {
m_fgColor = paletteColor(false, code - 30, false);
m_hasFgColor = true;
continue;
}
if (code >= 90 && code <= 97) {
m_fgColor = paletteColor(false, code - 90, true);
m_hasFgColor = true;
continue;
}
if (code >= 40 && code <= 47) {
m_bgColor = paletteColor(true, code - 40, false);
m_hasBgColor = true;
continue;
}
if (code >= 100 && code <= 107) {
m_bgColor = paletteColor(true, code - 100, true);
m_hasBgColor = true;
continue;
}
if (code == 38 || code == 48) {
const bool background = (code == 48);
if (i + 1 >= parts.size()) {
continue;
}
const int mode = parts.at(i + 1).toInt(&ok);
if (!ok) {
continue;
}
if (mode == 5 && i + 2 < parts.size()) {
const int index = parts.at(i + 2).toInt(&ok);
if (ok) {
const QColor color = colorFrom256Index(index);
if (background) {
m_bgColor = color;
m_hasBgColor = true;
} else {
m_fgColor = color;
m_hasFgColor = true;
}
}
i += 2;
continue;
}
if (mode == 2 && i + 4 < parts.size()) {
const int r = parts.at(i + 2).toInt(&ok);
if (!ok) {
i += 4;
continue;
}
const int g = parts.at(i + 3).toInt(&ok);
if (!ok) {
i += 4;
continue;
}
const int b = parts.at(i + 4).toInt(&ok);
if (!ok) {
i += 4;
continue;
}
const QColor color(r, g, b);
if (background) {
m_bgColor = color;
m_hasBgColor = true;
} else {
m_fgColor = color;
m_hasFgColor = true;
}
i += 4;
continue;
}
}
}
applyCurrentFormat();
}
void TerminalView::appendTextChunk(const QString& text)
{
if (text.isEmpty()) {
return;
}
QTextCursor cursor = textCursor();
cursor.movePosition(QTextCursor::End);
cursor.insertText(text, m_currentFormat);
setTextCursor(cursor);
ensureCursorVisible();
}
QColor TerminalView::paletteColor(bool, int index, bool bright) const
{
const int safeIndex = std::clamp(index, 0, 7);
return bright ? m_palette.bright.at(static_cast<size_t>(safeIndex))
: m_palette.normal.at(static_cast<size_t>(safeIndex));
}
int TerminalView::terminalColumns() const
{
const QFontMetrics metrics(font());
const int cellWidth = std::max(1, metrics.horizontalAdvance(QChar::fromLatin1('M')));
return std::max(1, viewport()->width() / cellWidth);
}
int TerminalView::terminalRows() const
{
const QFontMetrics metrics(font());
const int cellHeight = std::max(1, metrics.lineSpacing());
return std::max(1, viewport()->height() / cellHeight);
}
void TerminalView::emitTerminalSize()
{
emit terminalSizeChanged(terminalColumns(), terminalRows());
}

66
src/terminal_view.h Normal file
View File

@@ -0,0 +1,66 @@
#ifndef ORBITHUB_TERMINAL_VIEW_H
#define ORBITHUB_TERMINAL_VIEW_H
#include <QTextEdit>
#include <array>
class QKeyEvent;
class QFocusEvent;
class QResizeEvent;
class TerminalView : public QTextEdit
{
Q_OBJECT
public:
explicit TerminalView(QWidget* parent = nullptr);
static QStringList themeNames();
void setThemeName(const QString& themeName);
void appendTerminalData(const QString& data);
signals:
void inputGenerated(const QString& input);
void terminalSizeChanged(int columns, int rows);
protected:
void keyPressEvent(QKeyEvent* event) override;
void focusInEvent(QFocusEvent* event) override;
void resizeEvent(QResizeEvent* event) override;
private:
struct ThemePalette {
QString name;
QColor background;
QColor foreground;
std::array<QColor, 8> normal;
std::array<QColor, 8> bright;
};
ThemePalette m_palette;
QString m_pendingEscape;
QString m_rawHistory;
bool m_bold;
bool m_hasFgColor;
bool m_hasBgColor;
QColor m_fgColor;
QColor m_bgColor;
QTextCharFormat m_currentFormat;
static ThemePalette paletteByName(const QString& themeName);
static QColor colorFrom256Index(int index);
void applyThemePalette(const ThemePalette& palette);
void applyCurrentFormat();
void resetSgrState();
void handleSgrSequence(const QString& params);
void appendTextChunk(const QString& text);
QColor paletteColor(bool background, int index, bool bright) const;
void processData(const QString& data, bool storeInHistory);
int terminalColumns() const;
int terminalRows() const;
void emitTerminalSize();
};
#endif

View File

@@ -24,3 +24,16 @@ void UnsupportedSessionBackend::reconnectSession(const SessionConnectOptions& op
{ {
connectSession(options); connectSession(options);
} }
void UnsupportedSessionBackend::sendInput(const QString&)
{
emit eventLogged(QStringLiteral("Input ignored: protocol backend is not interactive."));
}
void UnsupportedSessionBackend::confirmHostKey(bool)
{
}
void UnsupportedSessionBackend::updateTerminalSize(int, int)
{
}

View File

@@ -14,6 +14,9 @@ public slots:
void connectSession(const SessionConnectOptions& options) override; void connectSession(const SessionConnectOptions& options) override;
void disconnectSession() override; void disconnectSession() override;
void reconnectSession(const SessionConnectOptions& options) override; void reconnectSession(const SessionConnectOptions& options) override;
void sendInput(const QString& input) override;
void confirmHostKey(bool trustHost) override;
void updateTerminalSize(int columns, int rows) override;
}; };
#endif #endif

61
third_party/KodoTerm/CMakeLists.txt vendored Normal file
View File

@@ -0,0 +1,61 @@
# SPDX-License-Identifier: MIT
cmake_minimum_required(VERSION 3.21)
project(KodoTermVendor LANGUAGES C CXX)
find_package(Qt6 REQUIRED COMPONENTS Core Gui Widgets)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
set(LIBVTERM_SOURCE_DIR "${CMAKE_CURRENT_LIST_DIR}/../libvterm")
file(GLOB VTERM_SOURCES CONFIGURE_DEPENDS
"${LIBVTERM_SOURCE_DIR}/src/*.c"
)
add_library(vterm STATIC ${VTERM_SOURCES})
target_include_directories(vterm PUBLIC
"${LIBVTERM_SOURCE_DIR}/include"
"${LIBVTERM_SOURCE_DIR}/src"
)
set(KODOTERM_SOURCES
src/KodoTerm.cpp
src/KodoTermConfig.cpp
src/PtyProcess.cpp
src/PtyProcess.h
include/KodoTerm/KodoTerm.hpp
include/KodoTerm/KodoTermConfig.hpp
KodoTermThemes.qrc
)
if(UNIX)
list(APPEND KODOTERM_SOURCES
src/PtyProcess_unix.cpp
src/PtyProcess_unix.h
)
elseif(WIN32)
list(APPEND KODOTERM_SOURCES
src/PtyProcess_win.cpp
src/PtyProcess_win.h
)
endif()
add_library(KodoTerm ${KODOTERM_SOURCES})
add_library(KodoTerm::KodoTerm ALIAS KodoTerm)
target_compile_features(KodoTerm PUBLIC cxx_std_20)
target_include_directories(KodoTerm PRIVATE src)
target_include_directories(KodoTerm PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:include>
)
target_link_libraries(KodoTerm PUBLIC
Qt6::Core
Qt6::Gui
Qt6::Widgets
vterm
)

470
third_party/KodoTerm/KodoTermThemes.qrc vendored Normal file
View File

@@ -0,0 +1,470 @@
<!DOCTYPE RCC><RCC version="1.0">
<qresource prefix="/">
<file>KodoTermThemes/konsole/BlackOnLightYellow.colorscheme</file>
<file>KodoTermThemes/konsole/BlackOnRandomLight.colorscheme</file>
<file>KodoTermThemes/konsole/BlackOnWhite.colorscheme</file>
<file>KodoTermThemes/konsole/BlueOnBlack.colorscheme</file>
<file>KodoTermThemes/konsole/Breeze.colorscheme</file>
<file>KodoTermThemes/konsole/Campbell.colorscheme</file>
<file>KodoTermThemes/konsole/DarkPastels.colorscheme</file>
<file>KodoTermThemes/konsole/GreenOnBlack.colorscheme</file>
<file>KodoTermThemes/konsole/Linux.colorscheme</file>
<file>KodoTermThemes/konsole/RedOnBlack.colorscheme</file>
<file>KodoTermThemes/konsole/Solarized.colorscheme</file>
<file>KodoTermThemes/konsole/SolarizedLight.colorscheme</file>
<file>KodoTermThemes/konsole/WhiteOnBlack.colorscheme</file>
<file>KodoTermThemes/windowsterminal/0x96f.json</file>
<file>KodoTermThemes/windowsterminal/12-bit Rainbow.json</file>
<file>KodoTermThemes/windowsterminal/3024 Day.json</file>
<file>KodoTermThemes/windowsterminal/3024 Night.json</file>
<file>KodoTermThemes/windowsterminal/Aardvark Blue.json</file>
<file>KodoTermThemes/windowsterminal/Abernathy.json</file>
<file>KodoTermThemes/windowsterminal/Adventure Time.json</file>
<file>KodoTermThemes/windowsterminal/Adventure.json</file>
<file>KodoTermThemes/windowsterminal/Adwaita Dark.json</file>
<file>KodoTermThemes/windowsterminal/Adwaita.json</file>
<file>KodoTermThemes/windowsterminal/Afterglow.json</file>
<file>KodoTermThemes/windowsterminal/Aizen Dark.json</file>
<file>KodoTermThemes/windowsterminal/Aizen Light.json</file>
<file>KodoTermThemes/windowsterminal/Alabaster.json</file>
<file>KodoTermThemes/windowsterminal/Alien Blood.json</file>
<file>KodoTermThemes/windowsterminal/Andromeda.json</file>
<file>KodoTermThemes/windowsterminal/Apple Classic.json</file>
<file>KodoTermThemes/windowsterminal/Apple System Colors Light.json</file>
<file>KodoTermThemes/windowsterminal/Apple System Colors.json</file>
<file>KodoTermThemes/windowsterminal/Arcoiris.json</file>
<file>KodoTermThemes/windowsterminal/Ardoise.json</file>
<file>KodoTermThemes/windowsterminal/Argonaut.json</file>
<file>KodoTermThemes/windowsterminal/Arthur.json</file>
<file>KodoTermThemes/windowsterminal/Atelier Sulphurpool.json</file>
<file>KodoTermThemes/windowsterminal/Atom One Dark.json</file>
<file>KodoTermThemes/windowsterminal/Atom One Light.json</file>
<file>KodoTermThemes/windowsterminal/Atom.json</file>
<file>KodoTermThemes/windowsterminal/Aura.json</file>
<file>KodoTermThemes/windowsterminal/Aurora.json</file>
<file>KodoTermThemes/windowsterminal/Ayu Light.json</file>
<file>KodoTermThemes/windowsterminal/Ayu Mirage.json</file>
<file>KodoTermThemes/windowsterminal/Ayu.json</file>
<file>KodoTermThemes/windowsterminal/Banana Blueberry.json</file>
<file>KodoTermThemes/windowsterminal/Batman.json</file>
<file>KodoTermThemes/windowsterminal/Belafonte Day.json</file>
<file>KodoTermThemes/windowsterminal/Belafonte Night.json</file>
<file>KodoTermThemes/windowsterminal/Birds Of Paradise.json</file>
<file>KodoTermThemes/windowsterminal/Black Metal (Bathory).json</file>
<file>KodoTermThemes/windowsterminal/Black Metal (Burzum).json</file>
<file>KodoTermThemes/windowsterminal/Black Metal (Dark Funeral).json</file>
<file>KodoTermThemes/windowsterminal/Black Metal (Gorgoroth).json</file>
<file>KodoTermThemes/windowsterminal/Black Metal (Immortal).json</file>
<file>KodoTermThemes/windowsterminal/Black Metal (Khold).json</file>
<file>KodoTermThemes/windowsterminal/Black Metal (Marduk).json</file>
<file>KodoTermThemes/windowsterminal/Black Metal (Mayhem).json</file>
<file>KodoTermThemes/windowsterminal/Black Metal (Nile).json</file>
<file>KodoTermThemes/windowsterminal/Black Metal (Venom).json</file>
<file>KodoTermThemes/windowsterminal/Black Metal.json</file>
<file>KodoTermThemes/windowsterminal/Blazer.json</file>
<file>KodoTermThemes/windowsterminal/Blue Berry Pie.json</file>
<file>KodoTermThemes/windowsterminal/Blue Dolphin.json</file>
<file>KodoTermThemes/windowsterminal/Blue Matrix.json</file>
<file>KodoTermThemes/windowsterminal/Bluloco Dark.json</file>
<file>KodoTermThemes/windowsterminal/Bluloco Light.json</file>
<file>KodoTermThemes/windowsterminal/Borland.json</file>
<file>KodoTermThemes/windowsterminal/Box.json</file>
<file>KodoTermThemes/windowsterminal/Breadog.json</file>
<file>KodoTermThemes/windowsterminal/Breeze.json</file>
<file>KodoTermThemes/windowsterminal/Bright Lights.json</file>
<file>KodoTermThemes/windowsterminal/Broadcast.json</file>
<file>KodoTermThemes/windowsterminal/Brogrammer.json</file>
<file>KodoTermThemes/windowsterminal/Builtin Dark.json</file>
<file>KodoTermThemes/windowsterminal/Builtin Light.json</file>
<file>KodoTermThemes/windowsterminal/Builtin Pastel Dark.json</file>
<file>KodoTermThemes/windowsterminal/Builtin Tango Dark.json</file>
<file>KodoTermThemes/windowsterminal/Builtin Tango Light.json</file>
<file>KodoTermThemes/windowsterminal/C64.json</file>
<file>KodoTermThemes/windowsterminal/CGA.json</file>
<file>KodoTermThemes/windowsterminal/CLRS.json</file>
<file>KodoTermThemes/windowsterminal/Calamity.json</file>
<file>KodoTermThemes/windowsterminal/Carbonfox.json</file>
<file>KodoTermThemes/windowsterminal/Catppuccin Frappe.json</file>
<file>KodoTermThemes/windowsterminal/Catppuccin Latte.json</file>
<file>KodoTermThemes/windowsterminal/Catppuccin Macchiato.json</file>
<file>KodoTermThemes/windowsterminal/Catppuccin Mocha.json</file>
<file>KodoTermThemes/windowsterminal/Chalk.json</file>
<file>KodoTermThemes/windowsterminal/Chalkboard.json</file>
<file>KodoTermThemes/windowsterminal/Challenger Deep.json</file>
<file>KodoTermThemes/windowsterminal/Chester.json</file>
<file>KodoTermThemes/windowsterminal/Ciapre.json</file>
<file>KodoTermThemes/windowsterminal/Citruszest.json</file>
<file>KodoTermThemes/windowsterminal/Cobalt Neon.json</file>
<file>KodoTermThemes/windowsterminal/Cobalt Next Dark.json</file>
<file>KodoTermThemes/windowsterminal/Cobalt Next Minimal.json</file>
<file>KodoTermThemes/windowsterminal/Cobalt Next.json</file>
<file>KodoTermThemes/windowsterminal/Cobalt2.json</file>
<file>KodoTermThemes/windowsterminal/Coffee Theme.json</file>
<file>KodoTermThemes/windowsterminal/Crayon Pony Fish.json</file>
<file>KodoTermThemes/windowsterminal/Cursor Dark.json</file>
<file>KodoTermThemes/windowsterminal/Cutie Pro.json</file>
<file>KodoTermThemes/windowsterminal/Cyberdyne.json</file>
<file>KodoTermThemes/windowsterminal/Cyberpunk Scarlet Protocol.json</file>
<file>KodoTermThemes/windowsterminal/Cyberpunk.json</file>
<file>KodoTermThemes/windowsterminal/Dark Modern.json</file>
<file>KodoTermThemes/windowsterminal/Dark Pastel.json</file>
<file>KodoTermThemes/windowsterminal/Dark+.json</file>
<file>KodoTermThemes/windowsterminal/Darkermatrix.json</file>
<file>KodoTermThemes/windowsterminal/Darkmatrix.json</file>
<file>KodoTermThemes/windowsterminal/Darkside.json</file>
<file>KodoTermThemes/windowsterminal/Dawnfox.json</file>
<file>KodoTermThemes/windowsterminal/Dayfox.json</file>
<file>KodoTermThemes/windowsterminal/Deep.json</file>
<file>KodoTermThemes/windowsterminal/Desert.json</file>
<file>KodoTermThemes/windowsterminal/Detuned.json</file>
<file>KodoTermThemes/windowsterminal/Dimidium.json</file>
<file>KodoTermThemes/windowsterminal/Dimmed Monokai.json</file>
<file>KodoTermThemes/windowsterminal/Django Reborn Again.json</file>
<file>KodoTermThemes/windowsterminal/Django Smooth.json</file>
<file>KodoTermThemes/windowsterminal/Django.json</file>
<file>KodoTermThemes/windowsterminal/Doom One.json</file>
<file>KodoTermThemes/windowsterminal/Doom Peacock.json</file>
<file>KodoTermThemes/windowsterminal/Dot Gov.json</file>
<file>KodoTermThemes/windowsterminal/Dracula+.json</file>
<file>KodoTermThemes/windowsterminal/Dracula.json</file>
<file>KodoTermThemes/windowsterminal/Duckbones.json</file>
<file>KodoTermThemes/windowsterminal/Duotone Dark.json</file>
<file>KodoTermThemes/windowsterminal/Duskfox.json</file>
<file>KodoTermThemes/windowsterminal/ENCOM.json</file>
<file>KodoTermThemes/windowsterminal/Earthsong.json</file>
<file>KodoTermThemes/windowsterminal/Electron Highlighter.json</file>
<file>KodoTermThemes/windowsterminal/Elegant.json</file>
<file>KodoTermThemes/windowsterminal/Elemental.json</file>
<file>KodoTermThemes/windowsterminal/Elementary.json</file>
<file>KodoTermThemes/windowsterminal/Embark.json</file>
<file>KodoTermThemes/windowsterminal/Embers Dark.json</file>
<file>KodoTermThemes/windowsterminal/Espresso Libre.json</file>
<file>KodoTermThemes/windowsterminal/Espresso.json</file>
<file>KodoTermThemes/windowsterminal/Everblush.json</file>
<file>KodoTermThemes/windowsterminal/Everforest Dark Hard.json</file>
<file>KodoTermThemes/windowsterminal/Everforest Light Med.json</file>
<file>KodoTermThemes/windowsterminal/Fahrenheit.json</file>
<file>KodoTermThemes/windowsterminal/Fairyfloss.json</file>
<file>KodoTermThemes/windowsterminal/Farmhouse Dark.json</file>
<file>KodoTermThemes/windowsterminal/Farmhouse Light.json</file>
<file>KodoTermThemes/windowsterminal/Fideloper.json</file>
<file>KodoTermThemes/windowsterminal/Firefly Traditional.json</file>
<file>KodoTermThemes/windowsterminal/Firefox Dev.json</file>
<file>KodoTermThemes/windowsterminal/Firewatch.json</file>
<file>KodoTermThemes/windowsterminal/Fish Tank.json</file>
<file>KodoTermThemes/windowsterminal/Flat.json</file>
<file>KodoTermThemes/windowsterminal/Flatland.json</file>
<file>KodoTermThemes/windowsterminal/Flexoki Dark.json</file>
<file>KodoTermThemes/windowsterminal/Flexoki Light.json</file>
<file>KodoTermThemes/windowsterminal/Floraverse.json</file>
<file>KodoTermThemes/windowsterminal/Forest Blue.json</file>
<file>KodoTermThemes/windowsterminal/Framer.json</file>
<file>KodoTermThemes/windowsterminal/Front End Delight.json</file>
<file>KodoTermThemes/windowsterminal/Fun Forrest.json</file>
<file>KodoTermThemes/windowsterminal/Galaxy.json</file>
<file>KodoTermThemes/windowsterminal/Galizur.json</file>
<file>KodoTermThemes/windowsterminal/Ghostty Default Style Dark.json</file>
<file>KodoTermThemes/windowsterminal/GitHub Dark Colorblind.json</file>
<file>KodoTermThemes/windowsterminal/GitHub Dark Default.json</file>
<file>KodoTermThemes/windowsterminal/GitHub Dark Dimmed.json</file>
<file>KodoTermThemes/windowsterminal/GitHub Dark High Contrast.json</file>
<file>KodoTermThemes/windowsterminal/GitHub Dark.json</file>
<file>KodoTermThemes/windowsterminal/GitHub Light Colorblind.json</file>
<file>KodoTermThemes/windowsterminal/GitHub Light Default.json</file>
<file>KodoTermThemes/windowsterminal/GitHub Light High Contrast.json</file>
<file>KodoTermThemes/windowsterminal/GitHub.json</file>
<file>KodoTermThemes/windowsterminal/GitLab Dark Grey.json</file>
<file>KodoTermThemes/windowsterminal/GitLab Dark.json</file>
<file>KodoTermThemes/windowsterminal/GitLab Light.json</file>
<file>KodoTermThemes/windowsterminal/Glacier.json</file>
<file>KodoTermThemes/windowsterminal/Grape.json</file>
<file>KodoTermThemes/windowsterminal/Grass.json</file>
<file>KodoTermThemes/windowsterminal/Grey Green.json</file>
<file>KodoTermThemes/windowsterminal/Gruber Darker.json</file>
<file>KodoTermThemes/windowsterminal/Gruvbox Dark Hard.json</file>
<file>KodoTermThemes/windowsterminal/Gruvbox Dark.json</file>
<file>KodoTermThemes/windowsterminal/Gruvbox Light Hard.json</file>
<file>KodoTermThemes/windowsterminal/Gruvbox Light.json</file>
<file>KodoTermThemes/windowsterminal/Gruvbox Material Dark.json</file>
<file>KodoTermThemes/windowsterminal/Gruvbox Material Light.json</file>
<file>KodoTermThemes/windowsterminal/Gruvbox Material.json</file>
<file>KodoTermThemes/windowsterminal/Guezwhoz.json</file>
<file>KodoTermThemes/windowsterminal/HaX0R Blue.json</file>
<file>KodoTermThemes/windowsterminal/HaX0R Gr33N.json</file>
<file>KodoTermThemes/windowsterminal/HaX0R R3D.json</file>
<file>KodoTermThemes/windowsterminal/Hacktober.json</file>
<file>KodoTermThemes/windowsterminal/Hardcore.json</file>
<file>KodoTermThemes/windowsterminal/Harper.json</file>
<file>KodoTermThemes/windowsterminal/Havn Daggry.json</file>
<file>KodoTermThemes/windowsterminal/Havn Skumring.json</file>
<file>KodoTermThemes/windowsterminal/Heeler.json</file>
<file>KodoTermThemes/windowsterminal/Highway.json</file>
<file>KodoTermThemes/windowsterminal/Hipster Green.json</file>
<file>KodoTermThemes/windowsterminal/Hivacruz.json</file>
<file>KodoTermThemes/windowsterminal/Homebrew.json</file>
<file>KodoTermThemes/windowsterminal/Hopscotch.256.json</file>
<file>KodoTermThemes/windowsterminal/Hopscotch.json</file>
<file>KodoTermThemes/windowsterminal/Horizon Bright.json</file>
<file>KodoTermThemes/windowsterminal/Horizon.json</file>
<file>KodoTermThemes/windowsterminal/Hot Dog Stand (Mustard).json</file>
<file>KodoTermThemes/windowsterminal/Hot Dog Stand.json</file>
<file>KodoTermThemes/windowsterminal/Hurtado.json</file>
<file>KodoTermThemes/windowsterminal/Hybrid.json</file>
<file>KodoTermThemes/windowsterminal/IBM 5153 CGA (Black).json</file>
<file>KodoTermThemes/windowsterminal/IBM 5153 CGA.json</file>
<file>KodoTermThemes/windowsterminal/IC Green PPL.json</file>
<file>KodoTermThemes/windowsterminal/IC Orange PPL.json</file>
<file>KodoTermThemes/windowsterminal/IR Black.json</file>
<file>KodoTermThemes/windowsterminal/IRIX Console.json</file>
<file>KodoTermThemes/windowsterminal/IRIX Terminal.json</file>
<file>KodoTermThemes/windowsterminal/Iceberg Dark.json</file>
<file>KodoTermThemes/windowsterminal/Iceberg Light.json</file>
<file>KodoTermThemes/windowsterminal/Idea.json</file>
<file>KodoTermThemes/windowsterminal/Idle Toes.json</file>
<file>KodoTermThemes/windowsterminal/Jackie Brown.json</file>
<file>KodoTermThemes/windowsterminal/Japanesque.json</file>
<file>KodoTermThemes/windowsterminal/Jellybeans.json</file>
<file>KodoTermThemes/windowsterminal/JetBrains Darcula.json</file>
<file>KodoTermThemes/windowsterminal/Jubi.json</file>
<file>KodoTermThemes/windowsterminal/Kanagawa Dragon.json</file>
<file>KodoTermThemes/windowsterminal/Kanagawa Wave.json</file>
<file>KodoTermThemes/windowsterminal/Kanagawabones.json</file>
<file>KodoTermThemes/windowsterminal/Kibble.json</file>
<file>KodoTermThemes/windowsterminal/Kitty Default.json</file>
<file>KodoTermThemes/windowsterminal/Kitty Low Contrast.json</file>
<file>KodoTermThemes/windowsterminal/Kolorit.json</file>
<file>KodoTermThemes/windowsterminal/Konsolas.json</file>
<file>KodoTermThemes/windowsterminal/Kurokula.json</file>
<file>KodoTermThemes/windowsterminal/Lab Fox.json</file>
<file>KodoTermThemes/windowsterminal/Laser.json</file>
<file>KodoTermThemes/windowsterminal/Later This Evening.json</file>
<file>KodoTermThemes/windowsterminal/Lavandula.json</file>
<file>KodoTermThemes/windowsterminal/Light Owl.json</file>
<file>KodoTermThemes/windowsterminal/Liquid Carbon Transparent.json</file>
<file>KodoTermThemes/windowsterminal/Liquid Carbon.json</file>
<file>KodoTermThemes/windowsterminal/Lovelace.json</file>
<file>KodoTermThemes/windowsterminal/Man Page.json</file>
<file>KodoTermThemes/windowsterminal/Mariana.json</file>
<file>KodoTermThemes/windowsterminal/Material Dark.json</file>
<file>KodoTermThemes/windowsterminal/Material Darker.json</file>
<file>KodoTermThemes/windowsterminal/Material Design Colors.json</file>
<file>KodoTermThemes/windowsterminal/Material Ocean.json</file>
<file>KodoTermThemes/windowsterminal/Material.json</file>
<file>KodoTermThemes/windowsterminal/Mathias.json</file>
<file>KodoTermThemes/windowsterminal/Matrix.json</file>
<file>KodoTermThemes/windowsterminal/Matte Black.json</file>
<file>KodoTermThemes/windowsterminal/Medallion.json</file>
<file>KodoTermThemes/windowsterminal/Melange Dark.json</file>
<file>KodoTermThemes/windowsterminal/Melange Light.json</file>
<file>KodoTermThemes/windowsterminal/Mellifluous.json</file>
<file>KodoTermThemes/windowsterminal/Mellow.json</file>
<file>KodoTermThemes/windowsterminal/Miasma.json</file>
<file>KodoTermThemes/windowsterminal/Midnight In Mojave.json</file>
<file>KodoTermThemes/windowsterminal/Mirage.json</file>
<file>KodoTermThemes/windowsterminal/Misterioso.json</file>
<file>KodoTermThemes/windowsterminal/Molokai.json</file>
<file>KodoTermThemes/windowsterminal/Mona Lisa.json</file>
<file>KodoTermThemes/windowsterminal/Monokai Classic.json</file>
<file>KodoTermThemes/windowsterminal/Monokai Pro Light Sun.json</file>
<file>KodoTermThemes/windowsterminal/Monokai Pro Light.json</file>
<file>KodoTermThemes/windowsterminal/Monokai Pro Machine.json</file>
<file>KodoTermThemes/windowsterminal/Monokai Pro Octagon.json</file>
<file>KodoTermThemes/windowsterminal/Monokai Pro Ristretto.json</file>
<file>KodoTermThemes/windowsterminal/Monokai Pro Spectrum.json</file>
<file>KodoTermThemes/windowsterminal/Monokai Pro.json</file>
<file>KodoTermThemes/windowsterminal/Monokai Remastered.json</file>
<file>KodoTermThemes/windowsterminal/Monokai Soda.json</file>
<file>KodoTermThemes/windowsterminal/Monokai Vivid.json</file>
<file>KodoTermThemes/windowsterminal/Moonfly.json</file>
<file>KodoTermThemes/windowsterminal/N0Tch2K.json</file>
<file>KodoTermThemes/windowsterminal/Neobones Dark.json</file>
<file>KodoTermThemes/windowsterminal/Neobones Light.json</file>
<file>KodoTermThemes/windowsterminal/Neon.json</file>
<file>KodoTermThemes/windowsterminal/Neopolitan.json</file>
<file>KodoTermThemes/windowsterminal/Neutron.json</file>
<file>KodoTermThemes/windowsterminal/Night Lion V1.json</file>
<file>KodoTermThemes/windowsterminal/Night Lion V2.json</file>
<file>KodoTermThemes/windowsterminal/Night Owl.json</file>
<file>KodoTermThemes/windowsterminal/Night Owlish Light.json</file>
<file>KodoTermThemes/windowsterminal/Nightfox.json</file>
<file>KodoTermThemes/windowsterminal/Niji.json</file>
<file>KodoTermThemes/windowsterminal/No Clown Fiesta Light.json</file>
<file>KodoTermThemes/windowsterminal/No Clown Fiesta.json</file>
<file>KodoTermThemes/windowsterminal/Nocturnal Winter.json</file>
<file>KodoTermThemes/windowsterminal/Nord Light.json</file>
<file>KodoTermThemes/windowsterminal/Nord Wave.json</file>
<file>KodoTermThemes/windowsterminal/Nord.json</file>
<file>KodoTermThemes/windowsterminal/Nordfox.json</file>
<file>KodoTermThemes/windowsterminal/Novel.json</file>
<file>KodoTermThemes/windowsterminal/Nvim Dark.json</file>
<file>KodoTermThemes/windowsterminal/Nvim Light.json</file>
<file>KodoTermThemes/windowsterminal/Obsidian.json</file>
<file>KodoTermThemes/windowsterminal/Ocean.json</file>
<file>KodoTermThemes/windowsterminal/Oceanic Material.json</file>
<file>KodoTermThemes/windowsterminal/Oceanic Next.json</file>
<file>KodoTermThemes/windowsterminal/Ollie.json</file>
<file>KodoTermThemes/windowsterminal/One Dark Two.json</file>
<file>KodoTermThemes/windowsterminal/One Double Dark.json</file>
<file>KodoTermThemes/windowsterminal/One Double Light.json</file>
<file>KodoTermThemes/windowsterminal/One Half Dark.json</file>
<file>KodoTermThemes/windowsterminal/One Half Light.json</file>
<file>KodoTermThemes/windowsterminal/Onenord Light.json</file>
<file>KodoTermThemes/windowsterminal/Onenord.json</file>
<file>KodoTermThemes/windowsterminal/Operator Mono Dark.json</file>
<file>KodoTermThemes/windowsterminal/Overnight Slumber.json</file>
<file>KodoTermThemes/windowsterminal/Oxocarbon.json</file>
<file>KodoTermThemes/windowsterminal/Pale Night Hc.json</file>
<file>KodoTermThemes/windowsterminal/Pandora.json</file>
<file>KodoTermThemes/windowsterminal/Paraiso Dark.json</file>
<file>KodoTermThemes/windowsterminal/Paul Millr.json</file>
<file>KodoTermThemes/windowsterminal/Pencil Dark.json</file>
<file>KodoTermThemes/windowsterminal/Pencil Light.json</file>
<file>KodoTermThemes/windowsterminal/Peppermint.json</file>
<file>KodoTermThemes/windowsterminal/Phala Green Dark.json</file>
<file>KodoTermThemes/windowsterminal/Piatto Light.json</file>
<file>KodoTermThemes/windowsterminal/Pnevma.json</file>
<file>KodoTermThemes/windowsterminal/Poimandres Darker.json</file>
<file>KodoTermThemes/windowsterminal/Poimandres Storm.json</file>
<file>KodoTermThemes/windowsterminal/Poimandres White.json</file>
<file>KodoTermThemes/windowsterminal/Poimandres.json</file>
<file>KodoTermThemes/windowsterminal/Popping And Locking.json</file>
<file>KodoTermThemes/windowsterminal/Powershell.json</file>
<file>KodoTermThemes/windowsterminal/Primary.json</file>
<file>KodoTermThemes/windowsterminal/Pro Light.json</file>
<file>KodoTermThemes/windowsterminal/Pro.json</file>
<file>KodoTermThemes/windowsterminal/Purple Rain.json</file>
<file>KodoTermThemes/windowsterminal/Purplepeter.json</file>
<file>KodoTermThemes/windowsterminal/Rapture.json</file>
<file>KodoTermThemes/windowsterminal/Raycast Dark.json</file>
<file>KodoTermThemes/windowsterminal/Raycast Light.json</file>
<file>KodoTermThemes/windowsterminal/Rebecca.json</file>
<file>KodoTermThemes/windowsterminal/Red Alert.json</file>
<file>KodoTermThemes/windowsterminal/Red Planet.json</file>
<file>KodoTermThemes/windowsterminal/Red Sands.json</file>
<file>KodoTermThemes/windowsterminal/Relaxed.json</file>
<file>KodoTermThemes/windowsterminal/Retro Legends.json</file>
<file>KodoTermThemes/windowsterminal/Retro.json</file>
<file>KodoTermThemes/windowsterminal/Rippedcasts.json</file>
<file>KodoTermThemes/windowsterminal/Rose Pine Dawn.json</file>
<file>KodoTermThemes/windowsterminal/Rose Pine Moon.json</file>
<file>KodoTermThemes/windowsterminal/Rose Pine.json</file>
<file>KodoTermThemes/windowsterminal/Rouge 2.json</file>
<file>KodoTermThemes/windowsterminal/Royal.json</file>
<file>KodoTermThemes/windowsterminal/Ryuuko.json</file>
<file>KodoTermThemes/windowsterminal/Sakura.json</file>
<file>KodoTermThemes/windowsterminal/Scarlet Protocol.json</file>
<file>KodoTermThemes/windowsterminal/Sea Shells.json</file>
<file>KodoTermThemes/windowsterminal/Seafoam Pastel.json</file>
<file>KodoTermThemes/windowsterminal/Selenized Black.json</file>
<file>KodoTermThemes/windowsterminal/Selenized Dark.json</file>
<file>KodoTermThemes/windowsterminal/Selenized Light.json</file>
<file>KodoTermThemes/windowsterminal/Seoulbones Dark.json</file>
<file>KodoTermThemes/windowsterminal/Seoulbones Light.json</file>
<file>KodoTermThemes/windowsterminal/Seti.json</file>
<file>KodoTermThemes/windowsterminal/Shades Of Purple.json</file>
<file>KodoTermThemes/windowsterminal/Shaman.json</file>
<file>KodoTermThemes/windowsterminal/Slate.json</file>
<file>KodoTermThemes/windowsterminal/Sleepy Hollow.json</file>
<file>KodoTermThemes/windowsterminal/Smyck.json</file>
<file>KodoTermThemes/windowsterminal/Snazzy Soft.json</file>
<file>KodoTermThemes/windowsterminal/Snazzy.json</file>
<file>KodoTermThemes/windowsterminal/Soft Server.json</file>
<file>KodoTermThemes/windowsterminal/Solarized Darcula.json</file>
<file>KodoTermThemes/windowsterminal/Solarized Dark Higher Contrast.json</file>
<file>KodoTermThemes/windowsterminal/Solarized Dark Patched.json</file>
<file>KodoTermThemes/windowsterminal/Solarized Osaka Night.json</file>
<file>KodoTermThemes/windowsterminal/Sonokai.json</file>
<file>KodoTermThemes/windowsterminal/Spacedust.json</file>
<file>KodoTermThemes/windowsterminal/Spacegray Bright.json</file>
<file>KodoTermThemes/windowsterminal/Spacegray Eighties Dull.json</file>
<file>KodoTermThemes/windowsterminal/Spacegray Eighties.json</file>
<file>KodoTermThemes/windowsterminal/Spacegray.json</file>
<file>KodoTermThemes/windowsterminal/Spiderman.json</file>
<file>KodoTermThemes/windowsterminal/Spring.json</file>
<file>KodoTermThemes/windowsterminal/Square.json</file>
<file>KodoTermThemes/windowsterminal/Squirrelsong Dark.json</file>
<file>KodoTermThemes/windowsterminal/Srcery.json</file>
<file>KodoTermThemes/windowsterminal/Starlight.json</file>
<file>KodoTermThemes/windowsterminal/Sublette.json</file>
<file>KodoTermThemes/windowsterminal/Subliminal.json</file>
<file>KodoTermThemes/windowsterminal/Sugarplum.json</file>
<file>KodoTermThemes/windowsterminal/Sundried.json</file>
<file>KodoTermThemes/windowsterminal/Symfonic.json</file>
<file>KodoTermThemes/windowsterminal/Synthwave Alpha.json</file>
<file>KodoTermThemes/windowsterminal/Synthwave Everything.json</file>
<file>KodoTermThemes/windowsterminal/Synthwave.json</file>
<file>KodoTermThemes/windowsterminal/Tango Adapted.json</file>
<file>KodoTermThemes/windowsterminal/Tango Half Adapted.json</file>
<file>KodoTermThemes/windowsterminal/Tearout.json</file>
<file>KodoTermThemes/windowsterminal/Teerb.json</file>
<file>KodoTermThemes/windowsterminal/Terafox.json</file>
<file>KodoTermThemes/windowsterminal/Terminal Basic Dark.json</file>
<file>KodoTermThemes/windowsterminal/Terminal Basic.json</file>
<file>KodoTermThemes/windowsterminal/Thayer Bright.json</file>
<file>KodoTermThemes/windowsterminal/The Hulk.json</file>
<file>KodoTermThemes/windowsterminal/Tinacious Design Dark.json</file>
<file>KodoTermThemes/windowsterminal/Tinacious Design Light.json</file>
<file>KodoTermThemes/windowsterminal/TokyoNight Day.json</file>
<file>KodoTermThemes/windowsterminal/TokyoNight Moon.json</file>
<file>KodoTermThemes/windowsterminal/TokyoNight Night.json</file>
<file>KodoTermThemes/windowsterminal/TokyoNight Storm.json</file>
<file>KodoTermThemes/windowsterminal/TokyoNight.json</file>
<file>KodoTermThemes/windowsterminal/Tomorrow Night Blue.json</file>
<file>KodoTermThemes/windowsterminal/Tomorrow Night Bright.json</file>
<file>KodoTermThemes/windowsterminal/Tomorrow Night Burns.json</file>
<file>KodoTermThemes/windowsterminal/Tomorrow Night Eighties.json</file>
<file>KodoTermThemes/windowsterminal/Tomorrow Night.json</file>
<file>KodoTermThemes/windowsterminal/Tomorrow.json</file>
<file>KodoTermThemes/windowsterminal/Toy Chest.json</file>
<file>KodoTermThemes/windowsterminal/Treehouse.json</file>
<file>KodoTermThemes/windowsterminal/Twilight.json</file>
<file>KodoTermThemes/windowsterminal/Ubuntu.json</file>
<file>KodoTermThemes/windowsterminal/Ultra Dark.json</file>
<file>KodoTermThemes/windowsterminal/Ultra Violent.json</file>
<file>KodoTermThemes/windowsterminal/Under The Sea.json</file>
<file>KodoTermThemes/windowsterminal/Unikitty.json</file>
<file>KodoTermThemes/windowsterminal/Urple.json</file>
<file>KodoTermThemes/windowsterminal/Vague.json</file>
<file>KodoTermThemes/windowsterminal/Vaughn.json</file>
<file>KodoTermThemes/windowsterminal/Vercel.json</file>
<file>KodoTermThemes/windowsterminal/Vesper.json</file>
<file>KodoTermThemes/windowsterminal/Vibrant Ink.json</file>
<file>KodoTermThemes/windowsterminal/Vimbones.json</file>
<file>KodoTermThemes/windowsterminal/Violet Dark.json</file>
<file>KodoTermThemes/windowsterminal/Violet Light.json</file>
<file>KodoTermThemes/windowsterminal/Violite.json</file>
<file>KodoTermThemes/windowsterminal/Warm Neon.json</file>
<file>KodoTermThemes/windowsterminal/Wez.json</file>
<file>KodoTermThemes/windowsterminal/Whimsy.json</file>
<file>KodoTermThemes/windowsterminal/Wild Cherry.json</file>
<file>KodoTermThemes/windowsterminal/Wilmersdorf.json</file>
<file>KodoTermThemes/windowsterminal/Wombat.json</file>
<file>KodoTermThemes/windowsterminal/Wryan.json</file>
<file>KodoTermThemes/windowsterminal/Xcode Dark hc.json</file>
<file>KodoTermThemes/windowsterminal/Xcode Dark.json</file>
<file>KodoTermThemes/windowsterminal/Xcode Light hc.json</file>
<file>KodoTermThemes/windowsterminal/Xcode Light.json</file>
<file>KodoTermThemes/windowsterminal/Xcode WWDC.json</file>
<file>KodoTermThemes/windowsterminal/Zenbones Dark.json</file>
<file>KodoTermThemes/windowsterminal/Zenbones Light.json</file>
<file>KodoTermThemes/windowsterminal/Zenbones.json</file>
<file>KodoTermThemes/windowsterminal/Zenburn.json</file>
<file>KodoTermThemes/windowsterminal/Zenburned.json</file>
<file>KodoTermThemes/windowsterminal/Zenwritten Dark.json</file>
<file>KodoTermThemes/windowsterminal/Zenwritten Light.json</file>
<file>KodoTermThemes/windowsterminal/branch.json</file>
<file>KodoTermThemes/windowsterminal/iTerm2 Dark Background.json</file>
<file>KodoTermThemes/windowsterminal/iTerm2 Default.json</file>
<file>KodoTermThemes/windowsterminal/iTerm2 Light Background.json</file>
<file>KodoTermThemes/windowsterminal/iTerm2 Pastel Dark Background.json</file>
<file>KodoTermThemes/windowsterminal/iTerm2 Smoooooth.json</file>
<file>KodoTermThemes/windowsterminal/iTerm2 Solarized Dark.json</file>
<file>KodoTermThemes/windowsterminal/iTerm2 Solarized Light.json</file>
<file>KodoTermThemes/windowsterminal/iTerm2 Tango Dark.json</file>
<file>KodoTermThemes/windowsterminal/iTerm2 Tango Light.json</file>
<file>KodoTermThemes/windowsterminal/novmbr.json</file>
<file>KodoTermThemes/windowsterminal/owl.json</file>
<file>KodoTermThemes/windowsterminal/traffic.json</file>
<file>KodoTermThemes/windowsterminal/urban.json</file>
</qresource>
</RCC>

View File

@@ -0,0 +1,94 @@
[Background]
Color=255,255,221
[BackgroundIntense]
Color=255,255,221
[BackgroundFaint]
Color=255,255,221
[Color0]
Color=0,0,0
[Color0Intense]
Color=104,104,104
[Color0Faint]
Color=192,192,192
[Color1]
Color=178,24,24
[Color1Intense]
Color=255,84,84
[Color1Faint]
Color=224,142,142
[Color2]
Color=24,178,24
[Color2Intense]
Color=84,255,84
[Color2Faint]
Color=142,224,142
[Color3]
Color=178,104,24
[Color3Intense]
Color=255,255,84
[Color3Faint]
Color=224,224,142
[Color4]
Color=24,24,178
[Color4Intense]
Color=84,84,255
[Color4Faint]
Color=142,142,224
[Color5]
Color=178,24,178
[Color5Intense]
Color=255,84,255
[Color5Faint]
Color=224,142,224
[Color6]
Color=24,178,178
[Color6Intense]
Color=84,255,255
[Color6Faint]
Color=142,224,224
[Color7]
Color=178,178,178
[Color7Intense]
Color=255,255,255
[Color7Faint]
Color=142,142,142
[Foreground]
Color=0,0,0
[ForegroundIntense]
Bold=true
Color=0,0,0
[ForegroundFaint]
Color=0,0,0
[General]
Description=Black on Light Yellow
Opacity=1

View File

@@ -0,0 +1,104 @@
[Background]
Color=247,247,214
RandomHueRange=360
RandomSaturationRange=25
RandomLightnessRange=10
[BackgroundIntense]
Color=255,255,221
RandomHueRange=360
RandomSaturationRange=25
RandomLightnessRange=10
[BackgroundFaint]
Color=247,247,214
RandomHueRange=360
RandomSaturationRange=25
RandomLightnessRange=10
[Color0]
Color=0,0,0
[Color0Intense]
Color=104,104,104
[Color0Faint]
Color=192,192,192
[Color1]
Color=178,24,24
[Color1Intense]
Color=255,84,84
[Color1Faint]
Color=224,142,142
[Color2]
Color=24,178,24
[Color2Intense]
Color=84,255,84
[Color2Faint]
Color=142,224,142
[Color3]
Color=178,104,24
[Color3Intense]
Color=255,255,84
[Color3Faint]
Color=224,224,142
[Color4]
Color=24,24,178
[Color4Intense]
Color=84,84,255
[Color4Faint]
Color=142,142,224
[Color5]
Color=178,24,178
[Color5Intense]
Color=255,84,255
[Color5Faint]
Color=224,142,224
[Color6]
Color=24,178,178
[Color6Intense]
Color=84,255,255
[Color6Faint]
Color=142,224,224
[Color7]
Color=178,178,178
[Color7Intense]
Color=255,255,255
[Color7Faint]
Color=142,142,142
[Foreground]
Color=0,0,0
[ForegroundIntense]
Bold=true
Color=0,0,0
[ForegroundFaint]
Color=0,0,0
[General]
Description=Black on Random Light
ColorRandomization=true
Opacity=1

View File

@@ -0,0 +1,94 @@
[Background]
Color=255,255,255
[BackgroundIntense]
Color=255,255,255
[BackgroundFaint]
Color=255,255,255
[Color0]
Color=0,0,0
[Color0Intense]
Color=104,104,104
[Color0Faint]
Color=192,192,192
[Color1]
Color=178,24,24
[Color1Intense]
Color=255,84,84
[Color1Faint]
Color=224,142,142
[Color2]
Color=24,178,24
[Color2Intense]
Color=84,255,84
[Color2Faint]
Color=142,224,142
[Color3]
Color=178,104,24
[Color3Intense]
Color=255,255,84
[Color3Faint]
Color=224,224,142
[Color4]
Color=24,24,178
[Color4Intense]
Color=84,84,255
[Color4Faint]
Color=142,142,224
[Color5]
Color=178,24,178
[Color5Intense]
Color=255,84,255
[Color5Faint]
Color=224,142,224
[Color6]
Color=24,178,178
[Color6Intense]
Color=84,255,255
[Color6Faint]
Color=142,224,224
[Color7]
Color=178,178,178
[Color7Intense]
Color=255,255,255
[Color7Faint]
Color=142,142,142
[Foreground]
Color=0,0,0
[ForegroundIntense]
Bold=true
Color=0,0,0
[ForegroundFaint]
Color=0,0,0
[General]
Description=Black on White
Opacity=1

View File

@@ -0,0 +1,94 @@
[Background]
Color=0,0,0
[BackgroundIntense]
Color=0,0,0
[BackgroundFaint]
Color=0,0,0
[Color0]
Color=0,0,0
[Color0Intense]
Color=104,104,104
[Color0Faint]
Color=192,192,192
[Color1]
Color=250,0,0
[Color1Intense]
Color=75,93,255
[Color1Faint]
Color=250,0,0
[Color2]
Color=24,178,24
[Color2Intense]
Color=84,255,84
[Color2Faint]
Color=142,224,142
[Color3]
Color=178,104,24
[Color3Intense]
Color=255,255,84
[Color3Faint]
Color=224,224,142
[Color4]
Color=125,152,35
[Color4Intense]
Color=84,84,255
[Color4Faint]
Color=125,152,35
[Color5]
Color=225,30,225
[Color5Intense]
Color=255,84,255
[Color5Faint]
Color=175,29,175
[Color6]
Color=0,134,223
[Color6Intense]
Color=0,68,255
[Color6Faint]
Color=0,98,173
[Color7]
Color=255,255,255
[Color7Intense]
Color=50,50,50
[Color7Faint]
Color=200,200,200
[Foreground]
Color=0,119,255
[ForegroundIntense]
Bold=true
Color=23,74,240
[ForegroundFaint]
Color=0,90,195
[General]
Description=Blue on Black
Opacity=1

View File

@@ -0,0 +1,94 @@
[Background]
Color=35,38,39
[BackgroundFaint]
Color=49,54,59
[BackgroundIntense]
Color=0,0,0
[Color0]
Color=35,38,39
[Color0Faint]
Color=49,54,59
[Color0Intense]
Color=127,140,141
[Color1]
Color=237,21,21
[Color1Faint]
Color=120,50,40
[Color1Intense]
Color=192,57,43
[Color2]
Color=17,209,22
[Color2Faint]
Color=23,162,98
[Color2Intense]
Color=28,220,154
[Color3]
Color=246,116,0
[Color3Faint]
Color=182,86,25
[Color3Intense]
Color=253,188,75
[Color4]
Color=29,153,243
[Color4Faint]
Color=27,102,143
[Color4Intense]
Color=61,174,233
[Color5]
Color=155,89,182
[Color5Faint]
Color=97,74,115
[Color5Intense]
Color=142,68,173
[Color6]
Color=26,188,156
[Color6Faint]
Color=24,108,96
[Color6Intense]
Color=22,160,133
[Color7]
Color=252,252,252
[Color7Faint]
Color=99,104,109
[Color7Intense]
Color=255,255,255
[Foreground]
Color=252,252,252
[ForegroundFaint]
Color=239,240,241
[ForegroundIntense]
Color=61,174,233
[General]
Description=Breeze
Opacity=1
Wallpaper=

View File

@@ -0,0 +1,100 @@
[Background]
Color=12,12,12
[BackgroundFaint]
Color=44,44,44
[BackgroundIntense]
Color=0,0,0
[Color0]
Color=12,12,12
[Color0Faint]
Color=44,44,44
[Color0Intense]
Color=124,124,124
[Color1]
Color=197,15,31
[Color1Faint]
Color=150,11,25
[Color1Intense]
Color=231,72,86
[Color2]
Color=19,161,14
[Color2Faint]
Color=16,120,10
[Color2Intense]
Color=22,198,12
[Color3]
Color=193,156,0
[Color3Faint]
Color=150,120,0
[Color3Intense]
Color=249,241,165
[Color4]
Color=0,55,218
[Color4Faint]
Color=0,45,170
[Color4Intense]
Color=59,120,255
[Color5]
Color=136,23,152
[Color5Faint]
Color=106,18,120
[Color5Intense]
Color=180,0,158
[Color6]
Color=58,150,221
[Color6Faint]
Color=47,122,180
[Color6Intense]
Color=97,214,214
[Color7]
Color=204,204,204
[Color7Faint]
Color=170,170,170
[Color7Intense]
Color=242,242,242
[Foreground]
Color=204,204,204
[ForegroundFaint]
Color=170,170,170
[ForegroundIntense]
Color=255,255,255
[General]
Anchor=0.5,0.5
Blur=false
ColorRandomization=false
Description=Campbell
FillStyle=Tile
Opacity=1
Wallpaper=
WallpaperFlipType=NoFlip
WallpaperOpacity=1

View File

@@ -0,0 +1,103 @@
[Background]
Color=44,44,44
[BackgroundIntense]
Bold=true
Color=44,44,44
[BackgroundFaint]
Color=44,44,44
[Color0]
Color=63,63,63
[Color0Intense]
Bold=true
Color=112,144,128
[Color0Faint]
Color=52,52,52
[Color1]
Color=112,80,80
[Color1Intense]
Bold=true
Color=220,163,163
[Color1Faint]
Color=102,72,72
[Color2]
Color=96,180,138
[Color2Intense]
Bold=true
Color=114,213,163
[Color2Faint]
Color=87,163,124
[Color3]
Color=223,175,143
[Color3Intense]
Bold=true
Color=240,223,175
[Color3Faint]
Color=170,133,111
[Color4]
Color=154,184,215
[Color4Intense]
Bold=true
Color=148,191,243
[Color4Faint]
Color=117,141,161
[Color5]
Color=220,140,195
[Color5Intense]
Bold=true
Color=236,147,211
[Color5Faint]
Color=154,98,137
[Color6]
Color=140,208,211
[Color6Intense]
Bold=true
Color=147,224,227
[Color6Faint]
Color=107,159,161
[Color7]
Color=220,220,204
[Color7Intense]
Bold=true
Color=255,255,255
[Color7Faint]
Color=149,149,139
[Foreground]
Color=220,220,204
[ForegroundIntense]
Bold=true
Color=220,220,204
[ForegroundFaint]
Color=220,220,204
[General]
Description=Dark Pastels
Opacity=1

View File

@@ -0,0 +1,94 @@
[Background]
Color=0,0,0
[BackgroundIntense]
Color=0,0,0
[BackgroundFaint]
Color=0,0,0
[Color0]
Color=0,0,0
[Color0Intense]
Color=104,104,104
[Color0Faint]
Color=24,24,24
[Color1]
Color=250,75,75
[Color1Intense]
Color=255,84,84
[Color1Faint]
Color=101,25,25
[Color2]
Color=24,178,24
[Color2Intense]
Color=84,255,84
[Color2Faint]
Color=0,101,0
[Color3]
Color=178,104,24
[Color3Intense]
Color=255,255,84
[Color3Faint]
Color=101,74,0
[Color4]
Color=24,24,178
[Color4Intense]
Color=84,84,255
[Color4Faint]
Color=0,0,101
[Color5]
Color=225,30,225
[Color5Intense]
Color=255,84,255
[Color5Faint]
Color=95,5,95
[Color6]
Color=24,178,178
[Color6Intense]
Color=84,255,255
[Color6Faint]
Color=0,101,101
[Color7]
Color=178,178,178
[Color7Intense]
Color=255,255,255
[Color7Faint]
Color=101,101,101
[Foreground]
Color=24,240,24
[ForegroundIntense]
Bold=true
Color=24,240,24
[ForegroundFaint]
Color=18,200,18
[General]
Description=Green on Black
Opacity=1

View File

@@ -0,0 +1,92 @@
[Background]
Color=0,0,0
[BackgroundIntense]
Color=104,104,104
[BackgroundFaint]
Color=0,0,0
[Color0]
Color=0,0,0
[Color0Intense]
Color=104,104,104
[Color0Faint]
Color=24,24,24
[Color1]
Color=178,24,24
[Color1Intense]
Color=255,84,84
[Color1Faint]
Color=101,0,0
[Color2]
Color=24,178,24
[Color2Intense]
Color=84,255,84
[Color2Faint]
Color=0,101,0
[Color3]
Color=178,104,24
[Color3Intense]
Color=255,255,84
[Color3Faint]
Color=101,94,0
[Color4]
Color=24,24,178
[Color4Intense]
Color=84,84,255
[Color4Faint]
Color=0,0,101
[Color5]
Color=178,24,178
[Color5Intense]
Color=255,84,255
[Color5Faint]
Color=101,0,101
[Color6]
Color=24,178,178
[Color6Intense]
Color=84,255,255
[Color6Faint]
Color=0,101,101
[Color7]
Color=178,178,178
[Color7Intense]
Color=255,255,255
[Color7Faint]
Color=101,101,101
[Foreground]
Color=178,178,178
[ForegroundIntense]
Color=255,255,255
[ForegroundFaint]
Color=101,101,101
[General]
Description=Linux Colors

View File

@@ -0,0 +1,94 @@
[Background]
Color=0,0,0
[BackgroundIntense]
Color=0,0,0
[BackgroundFaint]
Color=0,0,0
[Color0]
Color=0,0,0
[Color0Intense]
Color=104,104,104
[Color0Faint]
Color=24,24,24
[Color1]
Color=250,142,8
[Color1Intense]
Color=255,84,84
[Color1Faint]
Color=101,25,0
[Color2]
Color=24,178,24
[Color2Intense]
Color=84,255,84
[Color2Faint]
Color=0,101,0
[Color3]
Color=178,104,24
[Color3Intense]
Color=255,255,84
[Color3Faint]
Color=101,74,0
[Color4]
Color=30,71,152
[Color4Intense]
Color=84,84,255
[Color4Faint]
Color=0,24,102
[Color5]
Color=225,30,225
[Color5Intense]
Color=255,84,255
[Color5Faint]
Color=95,5,95
[Color6]
Color=0,134,223
[Color6Intense]
Color=255,0,4
[Color6Faint]
Color=0,94,163
[Color7]
Color=255,255,255
[Color7Intense]
Color=50,50,50
[Color7Faint]
Color=101,101,101
[Foreground]
Color=255,0,0
[ForegroundIntense]
Bold=true
Color=24,240,24
[ForegroundFaint]
Color=205,0,0
[General]
Description=Red on Black
Opacity=1

View File

@@ -0,0 +1,93 @@
[Color0]
Color=7,54,66
[Color0Intense]
Color=0,43,54
[Color0Faint]
Color=6,48,59
[Color1]
Color=220,50,47
[Color1Intense]
Color=203,75,22
[Color1Faint]
Color=147,33,31
[Color2]
Color=133,153,0
[Color2Intense]
Color=88,110,117
[Color2Faint]
Color=94,106,0
[Color3]
Color=181,137,0
[Color3Intense]
Color=101,123,131
[Color3Faint]
Color=138,103,0
[Color4]
Color=38,139,210
[Color4Intense]
Color=131,148,150
[Color4Faint]
Color=20,77,115
[Color5]
Color=211,54,130
[Color5Intense]
Color=108,113,196
[Color5Faint]
Color=120,30,75
[Color6]
Color=42,161,152
[Color6Intense]
Color=147,161,161
[Color6Faint]
Color=24,94,88
[Color7]
Color=238,232,213
[Color7Intense]
Color=253,246,227
[Color7Faint]
Color=171,167,154
[Background]
Color=0,43,54
[BackgroundIntense]
Color=7,54,66
[BackgroundFaint]
Color=0,43,54
[Foreground]
Color=131,148,150
[ForegroundIntense]
Color=147,161,161
[ForegroundFaint]
Color=106,119,121
[General]
Description=Solarized
Opacity=1

View File

@@ -0,0 +1,93 @@
[Color0]
Color=7,54,66
[Color0Intense]
Color=0,43,54
[Color0Faint]
Color=8,65,80
[Color1]
Color=220,50,47
[Color1Intense]
Color=203,75,22
[Color1Faint]
Color=222,81,81
[Color2]
Color=133,153,0
[Color2Intense]
Color=88,110,117
[Color2Faint]
Color=153,168,39
[Color3]
Color=181,137,0
[Color3Intense]
Color=101,123,131
[Color3Faint]
Color=213,170,49
[Color4]
Color=38,139,210
[Color4Intense]
Color=131,148,150
[Color4Faint]
Color=80,173,226
[Color5]
Color=211,54,130
[Color5Intense]
Color=108,113,196
[Color5Faint]
Color=223,92,158
[Color6]
Color=42,161,152
[Color6Intense]
Color=147,161,161
[Color6Faint]
Color=78,211,200
[Color7]
Color=238,232,213
[Color7Intense]
Color=253,246,227
[Color7Faint]
Color=238,232,213
[Background]
Color=253,246,227
[BackgroundIntense]
Color=238,232,213
[BackgroundFaint]
Color=253,246,227
[Foreground]
Color=101,123,131
[ForegroundIntense]
Color=88,110,117
[ForegroundFaint]
Color=141,172,182
[General]
Description=Solarized Light
Opacity=1

View File

@@ -0,0 +1,94 @@
[Background]
Color=0,0,0
[BackgroundIntense]
Color=0,0,0
[BackgroundFaint]
Color=0,0,0
[Color0]
Color=0,0,0
[Color0Intense]
Color=104,104,104
[Color0Faint]
Color=24,24,24
[Color1]
Color=178,24,24
[Color1Intense]
Color=255,84,84
[Color1Faint]
Color=101,0,0
[Color2]
Color=24,178,24
[Color2Intense]
Color=84,255,84
[Color2Faint]
Color=0,101,0
[Color3]
Color=178,104,24
[Color3Intense]
Color=255,255,84
[Color3Faint]
Color=101,74,0
[Color4]
Color=24,24,178
[Color4Intense]
Color=84,84,255
[Color4Faint]
Color=0,0,101
[Color5]
Color=178,24,178
[Color5Intense]
Color=255,84,255
[Color5Faint]
Color=95,5,95
[Color6]
Color=24,178,178
[Color6Intense]
Color=84,255,255
[Color6Faint]
Color=24,178,178
[Color7]
Color=178,178,178
[Color7Intense]
Color=255,255,255
[Color7Faint]
Color=101,101,101
[Foreground]
Color=255,255,255
[ForegroundIntense]
Bold=true
Color=255,255,255
[ForegroundFaint]
Color=255,255,255
[General]
Description=White on Black
Opacity=1

View File

@@ -0,0 +1,23 @@
{
"name": "0x96f",
"black": "#262427",
"red": "#ff666d",
"green": "#b3e03a",
"yellow": "#ffc739",
"blue": "#00cde8",
"purple": "#a392e8",
"cyan": "#9deaf6",
"white": "#fcfcfa",
"brightBlack": "#545452",
"brightRed": "#ff7e83",
"brightGreen": "#bee55e",
"brightYellow": "#ffd05e",
"brightBlue": "#1bd5eb",
"brightPurple": "#b0a3eb",
"brightCyan": "#acedf8",
"brightWhite": "#fcfcfa",
"background": "#262427",
"foreground": "#fcfcfa",
"cursorColor": "#fcfcfa",
"selectionBackground": "#fcfcfa"
}

View File

@@ -0,0 +1,23 @@
{
"name": "12-bit Rainbow",
"black": "#000000",
"red": "#a03050",
"green": "#40d080",
"yellow": "#e09040",
"blue": "#3060b0",
"purple": "#603090",
"cyan": "#0090c0",
"white": "#dbded8",
"brightBlack": "#685656",
"brightRed": "#c06060",
"brightGreen": "#90d050",
"brightYellow": "#e0d000",
"brightBlue": "#00b0c0",
"brightPurple": "#801070",
"brightCyan": "#20b0c0",
"brightWhite": "#ffffff",
"background": "#040404",
"foreground": "#feffff",
"cursorColor": "#e0d000",
"selectionBackground": "#606060"
}

View File

@@ -0,0 +1,23 @@
{
"name": "3024 Day",
"black": "#090300",
"red": "#db2d20",
"green": "#01a252",
"yellow": "#caba00",
"blue": "#01a0e4",
"purple": "#a16a94",
"cyan": "#8fbece",
"white": "#a5a2a2",
"brightBlack": "#5c5855",
"brightRed": "#dbaec3",
"brightGreen": "#3a3432",
"brightYellow": "#4a4543",
"brightBlue": "#807d7c",
"brightPurple": "#bcbbba",
"brightCyan": "#cdab53",
"brightWhite": "#f7f7f7",
"background": "#f7f7f7",
"foreground": "#4a4543",
"cursorColor": "#4a4543",
"selectionBackground": "#a5a2a2"
}

View File

@@ -0,0 +1,23 @@
{
"name": "3024 Night",
"black": "#090300",
"red": "#db2d20",
"green": "#01a252",
"yellow": "#fded02",
"blue": "#01a0e4",
"purple": "#a16a94",
"cyan": "#b5e4f4",
"white": "#a5a2a2",
"brightBlack": "#5c5855",
"brightRed": "#e8bbd0",
"brightGreen": "#47413f",
"brightYellow": "#4a4543",
"brightBlue": "#807d7c",
"brightPurple": "#d6d5d4",
"brightCyan": "#cdab53",
"brightWhite": "#f7f7f7",
"background": "#090300",
"foreground": "#a5a2a2",
"cursorColor": "#a5a2a2",
"selectionBackground": "#4a4543"
}

View File

@@ -0,0 +1,23 @@
{
"name": "Aardvark Blue",
"black": "#191919",
"red": "#aa342e",
"green": "#4b8c0f",
"yellow": "#dbba00",
"blue": "#1370d3",
"purple": "#c43ac3",
"cyan": "#008eb0",
"white": "#bebebe",
"brightBlack": "#525252",
"brightRed": "#f05b50",
"brightGreen": "#95dc55",
"brightYellow": "#ffe763",
"brightBlue": "#60a4ec",
"brightPurple": "#e26be2",
"brightCyan": "#60b6cb",
"brightWhite": "#f7f7f7",
"background": "#102040",
"foreground": "#dddddd",
"cursorColor": "#007acc",
"selectionBackground": "#bfdbfe"
}

View File

@@ -0,0 +1,23 @@
{
"name": "Abernathy",
"black": "#000000",
"red": "#cd0000",
"green": "#00cd00",
"yellow": "#cdcd00",
"blue": "#1093f5",
"purple": "#cd00cd",
"cyan": "#00cdcd",
"white": "#faebd7",
"brightBlack": "#404040",
"brightRed": "#ff0000",
"brightGreen": "#00ff00",
"brightYellow": "#ffff00",
"brightBlue": "#11b5f6",
"brightPurple": "#ff00ff",
"brightCyan": "#00ffff",
"brightWhite": "#ffffff",
"background": "#111416",
"foreground": "#eeeeec",
"cursorColor": "#bbbbbb",
"selectionBackground": "#eeeeec"
}

View File

@@ -0,0 +1,23 @@
{
"name": "Adventure Time",
"black": "#050404",
"red": "#bd0013",
"green": "#4ab118",
"yellow": "#e7741e",
"blue": "#0f4ac6",
"purple": "#665993",
"cyan": "#70a598",
"white": "#f8dcc0",
"brightBlack": "#4e7cbf",
"brightRed": "#fc5f5a",
"brightGreen": "#9eff6e",
"brightYellow": "#efc11a",
"brightBlue": "#1997c6",
"brightPurple": "#9b5953",
"brightCyan": "#c8faf4",
"brightWhite": "#f6f5fb",
"background": "#1f1d45",
"foreground": "#f8dcc0",
"cursorColor": "#efbf38",
"selectionBackground": "#706b4e"
}

View File

@@ -0,0 +1,23 @@
{
"name": "Adventure",
"black": "#040404",
"red": "#d84a33",
"green": "#5da602",
"yellow": "#eebb6e",
"blue": "#417ab3",
"purple": "#e5c499",
"cyan": "#bdcfe5",
"white": "#dbded8",
"brightBlack": "#685656",
"brightRed": "#d76b42",
"brightGreen": "#99b52c",
"brightYellow": "#ffb670",
"brightBlue": "#97d7ef",
"brightPurple": "#aa7900",
"brightCyan": "#bdcfe5",
"brightWhite": "#e4d5c7",
"background": "#040404",
"foreground": "#feffff",
"cursorColor": "#feffff",
"selectionBackground": "#606060"
}

View File

@@ -0,0 +1,23 @@
{
"name": "Adwaita Dark",
"black": "#241f31",
"red": "#c01c28",
"green": "#2ec27e",
"yellow": "#f5c211",
"blue": "#1e78e4",
"purple": "#9841bb",
"cyan": "#0ab9dc",
"white": "#c0bfbc",
"brightBlack": "#5e5c64",
"brightRed": "#ed333b",
"brightGreen": "#57e389",
"brightYellow": "#f8e45c",
"brightBlue": "#51a1ff",
"brightPurple": "#c061cb",
"brightCyan": "#4fd2fd",
"brightWhite": "#f6f5f4",
"background": "#1d1d20",
"foreground": "#ffffff",
"cursorColor": "#ffffff",
"selectionBackground": "#ffffff"
}

View File

@@ -0,0 +1,23 @@
{
"name": "Adwaita",
"black": "#241f31",
"red": "#c01c28",
"green": "#2ec27e",
"yellow": "#e8b504",
"blue": "#1e78e4",
"purple": "#9841bb",
"cyan": "#0ab9dc",
"white": "#c0bfbc",
"brightBlack": "#5e5c64",
"brightRed": "#ed333b",
"brightGreen": "#4ad67c",
"brightYellow": "#d2be36",
"brightBlue": "#51a1ff",
"brightPurple": "#c061cb",
"brightCyan": "#4fd2fd",
"brightWhite": "#f6f5f4",
"background": "#ffffff",
"foreground": "#000000",
"cursorColor": "#000000",
"selectionBackground": "#c0bfbc"
}

View File

@@ -0,0 +1,23 @@
{
"name": "Afterglow",
"black": "#151515",
"red": "#ac4142",
"green": "#7e8e50",
"yellow": "#e5b567",
"blue": "#6c99bb",
"purple": "#9f4e85",
"cyan": "#7dd6cf",
"white": "#d0d0d0",
"brightBlack": "#505050",
"brightRed": "#ac4142",
"brightGreen": "#7e8e50",
"brightYellow": "#e5b567",
"brightBlue": "#6c99bb",
"brightPurple": "#9f4e85",
"brightCyan": "#7dd6cf",
"brightWhite": "#f5f5f5",
"background": "#212121",
"foreground": "#d0d0d0",
"cursorColor": "#d0d0d0",
"selectionBackground": "#303030"
}

View File

@@ -0,0 +1,23 @@
{
"name": "Aizen Dark",
"black": "#1a1a1a",
"red": "#f08898",
"green": "#a4e09c",
"yellow": "#f5dea4",
"blue": "#84b4f8",
"purple": "#c8a2f4",
"cyan": "#90dcd0",
"white": "#d0d6f0",
"brightBlack": "#444444",
"brightRed": "#f08898",
"brightGreen": "#a4e09c",
"brightYellow": "#f5dea4",
"brightBlue": "#84b4f8",
"brightPurple": "#c8a2f4",
"brightCyan": "#90dcd0",
"brightWhite": "#ffffff",
"background": "#1a1a1a",
"foreground": "#d0d6f0",
"cursorColor": "#f8b080",
"selectionBackground": "#333333"
}

View File

@@ -0,0 +1,23 @@
{
"name": "Aizen Light",
"black": "#f0f2f6",
"red": "#d00c36",
"green": "#3e9e28",
"yellow": "#dd8c1a",
"blue": "#1c64f2",
"purple": "#8636ec",
"cyan": "#159096",
"white": "#4a4d66",
"brightBlack": "#adb2bc",
"brightRed": "#d00c36",
"brightGreen": "#3e9e28",
"brightYellow": "#dd8c1a",
"brightBlue": "#1c64f2",
"brightPurple": "#8636ec",
"brightCyan": "#159096",
"brightWhite": "#4a4d66",
"background": "#f0f2f6",
"foreground": "#4a4d66",
"cursorColor": "#fc6008",
"selectionBackground": "#bdc2cc"
}

View File

@@ -0,0 +1,23 @@
{
"name": "Alabaster",
"black": "#000000",
"red": "#aa3731",
"green": "#448c27",
"yellow": "#cb9000",
"blue": "#325cc0",
"purple": "#7a3e9d",
"cyan": "#0083b2",
"white": "#b7b7b7",
"brightBlack": "#777777",
"brightRed": "#f05050",
"brightGreen": "#60cb00",
"brightYellow": "#f2af50",
"brightBlue": "#007acc",
"brightPurple": "#e64ce6",
"brightCyan": "#00aacb",
"brightWhite": "#f7f7f7",
"background": "#f7f7f7",
"foreground": "#000000",
"cursorColor": "#007acc",
"selectionBackground": "#bfdbfe"
}

View File

@@ -0,0 +1,23 @@
{
"name": "Alien Blood",
"black": "#112616",
"red": "#7f2b27",
"green": "#2f7e25",
"yellow": "#717f24",
"blue": "#2f6a7f",
"purple": "#47587f",
"cyan": "#327f77",
"white": "#647d75",
"brightBlack": "#3c4812",
"brightRed": "#e08009",
"brightGreen": "#18e000",
"brightYellow": "#bde000",
"brightBlue": "#00aae0",
"brightPurple": "#0058e0",
"brightCyan": "#00e0c4",
"brightWhite": "#73fa91",
"background": "#0f1610",
"foreground": "#637d75",
"cursorColor": "#73fa91",
"selectionBackground": "#1d4125"
}

View File

@@ -0,0 +1,23 @@
{
"name": "Andromeda",
"black": "#000000",
"red": "#cd3131",
"green": "#05bc79",
"yellow": "#e5e512",
"blue": "#2472c8",
"purple": "#bc3fbc",
"cyan": "#0fa8cd",
"white": "#e5e5e5",
"brightBlack": "#666666",
"brightRed": "#cd3131",
"brightGreen": "#05bc79",
"brightYellow": "#e5e512",
"brightBlue": "#2472c8",
"brightPurple": "#bc3fbc",
"brightCyan": "#0fa8cd",
"brightWhite": "#e5e5e5",
"background": "#262a33",
"foreground": "#e5e5e5",
"cursorColor": "#f8f8f0",
"selectionBackground": "#5a5c62"
}

View File

@@ -0,0 +1,23 @@
{
"name": "Apple Classic",
"black": "#000000",
"red": "#c91b00",
"green": "#00c200",
"yellow": "#c7c400",
"blue": "#1c3fe1",
"purple": "#ca30c7",
"cyan": "#00c5c7",
"white": "#c7c7c7",
"brightBlack": "#686868",
"brightRed": "#ff6e67",
"brightGreen": "#5ffa68",
"brightYellow": "#fffc67",
"brightBlue": "#6871ff",
"brightPurple": "#ff77ff",
"brightCyan": "#60fdff",
"brightWhite": "#ffffff",
"background": "#2c2b2b",
"foreground": "#d5a200",
"cursorColor": "#c7c7c7",
"selectionBackground": "#6b5b02"
}

View File

@@ -0,0 +1,23 @@
{
"name": "Apple System Colors Light",
"black": "#1a1a1a",
"red": "#cc372e",
"green": "#26a439",
"yellow": "#cdac08",
"blue": "#0869cb",
"purple": "#9647bf",
"cyan": "#479ec2",
"white": "#98989d",
"brightBlack": "#464646",
"brightRed": "#ff453a",
"brightGreen": "#32d74b",
"brightYellow": "#e5bc00",
"brightBlue": "#0a84ff",
"brightPurple": "#bf5af2",
"brightCyan": "#69c9f2",
"brightWhite": "#ffffff",
"background": "#feffff",
"foreground": "#000000",
"cursorColor": "#98989d",
"selectionBackground": "#abd8ff"
}

View File

@@ -0,0 +1,23 @@
{
"name": "Apple System Colors",
"black": "#1a1a1a",
"red": "#cc372e",
"green": "#26a439",
"yellow": "#cdac08",
"blue": "#0869cb",
"purple": "#9647bf",
"cyan": "#479ec2",
"white": "#98989d",
"brightBlack": "#464646",
"brightRed": "#ff453a",
"brightGreen": "#32d74b",
"brightYellow": "#ffd60a",
"brightBlue": "#0a84ff",
"brightPurple": "#bf5af2",
"brightCyan": "#76d6ff",
"brightWhite": "#ffffff",
"background": "#1e1e1e",
"foreground": "#ffffff",
"cursorColor": "#98989d",
"selectionBackground": "#3f638b"
}

View File

@@ -0,0 +1,23 @@
{
"name": "Arcoiris",
"black": "#333333",
"red": "#da2700",
"green": "#12c258",
"yellow": "#ffc656",
"blue": "#518bfc",
"purple": "#e37bd9",
"cyan": "#63fad5",
"white": "#bab2b2",
"brightBlack": "#777777",
"brightRed": "#ffb9b9",
"brightGreen": "#e3f6aa",
"brightYellow": "#ffddaa",
"brightBlue": "#b3e8f3",
"brightPurple": "#cbbaf9",
"brightCyan": "#bcffc7",
"brightWhite": "#efefef",
"background": "#201f1e",
"foreground": "#eee4d9",
"cursorColor": "#872929",
"selectionBackground": "#25524a"
}

View File

@@ -0,0 +1,23 @@
{
"name": "Ardoise",
"black": "#2c2c2c",
"red": "#d3322d",
"green": "#588b35",
"yellow": "#fca93a",
"blue": "#2465c2",
"purple": "#7332b4",
"cyan": "#64e1b8",
"white": "#f7f7f7",
"brightBlack": "#535353",
"brightRed": "#fa5852",
"brightGreen": "#8dc252",
"brightYellow": "#ffea51",
"brightBlue": "#6ab5f8",
"brightPurple": "#be68ca",
"brightCyan": "#89ffdb",
"brightWhite": "#fefefe",
"background": "#1e1e1e",
"foreground": "#eaeaea",
"cursorColor": "#f7f7f7",
"selectionBackground": "#46515e"
}

View File

@@ -0,0 +1,23 @@
{
"name": "Argonaut",
"black": "#232323",
"red": "#ff000f",
"green": "#8ce10b",
"yellow": "#ffb900",
"blue": "#008df8",
"purple": "#6d43a6",
"cyan": "#00d8eb",
"white": "#ffffff",
"brightBlack": "#444444",
"brightRed": "#ff2740",
"brightGreen": "#abe15b",
"brightYellow": "#ffd242",
"brightBlue": "#0092ff",
"brightPurple": "#9a5feb",
"brightCyan": "#67fff0",
"brightWhite": "#ffffff",
"background": "#0e1019",
"foreground": "#fffaf4",
"cursorColor": "#ff0018",
"selectionBackground": "#002a3b"
}

View File

@@ -0,0 +1,23 @@
{
"name": "Arthur",
"black": "#3d352a",
"red": "#cd5c5c",
"green": "#86af80",
"yellow": "#e8ae5b",
"blue": "#6495ed",
"purple": "#deb887",
"cyan": "#b0c4de",
"white": "#bbaa99",
"brightBlack": "#554444",
"brightRed": "#cc5533",
"brightGreen": "#88aa22",
"brightYellow": "#ffa75d",
"brightBlue": "#87ceeb",
"brightPurple": "#996600",
"brightCyan": "#b0c4de",
"brightWhite": "#ddccbb",
"background": "#1c1c1c",
"foreground": "#ddeedd",
"cursorColor": "#e2bbef",
"selectionBackground": "#4d4d4d"
}

View File

@@ -0,0 +1,23 @@
{
"name": "Atelier Sulphurpool",
"black": "#202746",
"red": "#c94922",
"green": "#ac9739",
"yellow": "#c08b30",
"blue": "#3d8fd1",
"purple": "#6679cc",
"cyan": "#22a2c9",
"white": "#979db4",
"brightBlack": "#6b7394",
"brightRed": "#c76b29",
"brightGreen": "#4f587c",
"brightYellow": "#5e6687",
"brightBlue": "#898ea4",
"brightPurple": "#dfe2f1",
"brightCyan": "#9c637a",
"brightWhite": "#f5f7ff",
"background": "#202746",
"foreground": "#979db4",
"cursorColor": "#979db4",
"selectionBackground": "#5e6687"
}

View File

@@ -0,0 +1,23 @@
{
"name": "Atom One Dark",
"black": "#21252b",
"red": "#e06c75",
"green": "#98c379",
"yellow": "#e5c07b",
"blue": "#61afef",
"purple": "#c678dd",
"cyan": "#56b6c2",
"white": "#abb2bf",
"brightBlack": "#767676",
"brightRed": "#e06c75",
"brightGreen": "#98c379",
"brightYellow": "#e5c07b",
"brightBlue": "#61afef",
"brightPurple": "#c678dd",
"brightCyan": "#56b6c2",
"brightWhite": "#abb2bf",
"background": "#21252b",
"foreground": "#abb2bf",
"cursorColor": "#abb2bf",
"selectionBackground": "#323844"
}

View File

@@ -0,0 +1,23 @@
{
"name": "Atom One Light",
"black": "#000000",
"red": "#de3e35",
"green": "#3f953a",
"yellow": "#d2b67c",
"blue": "#2f5af3",
"purple": "#950095",
"cyan": "#3f953a",
"white": "#bbbbbb",
"brightBlack": "#000000",
"brightRed": "#de3e35",
"brightGreen": "#3f953a",
"brightYellow": "#d2b67c",
"brightBlue": "#2f5af3",
"brightPurple": "#a00095",
"brightCyan": "#3f953a",
"brightWhite": "#ffffff",
"background": "#f9f9f9",
"foreground": "#2a2c33",
"cursorColor": "#bbbbbb",
"selectionBackground": "#ededed"
}

View File

@@ -0,0 +1,23 @@
{
"name": "Atom",
"black": "#000000",
"red": "#fd5ff1",
"green": "#87c38a",
"yellow": "#ffd7b1",
"blue": "#85befd",
"purple": "#b9b6fc",
"cyan": "#85befd",
"white": "#e0e0e0",
"brightBlack": "#4c4c4c",
"brightRed": "#fd5ff1",
"brightGreen": "#94fa36",
"brightYellow": "#f5ffa8",
"brightBlue": "#96cbfe",
"brightPurple": "#b9b6fc",
"brightCyan": "#85befd",
"brightWhite": "#e0e0e0",
"background": "#161719",
"foreground": "#c5c8c6",
"cursorColor": "#d0d0d0",
"selectionBackground": "#444444"
}

View File

@@ -0,0 +1,23 @@
{
"name": "Aura",
"black": "#110f18",
"red": "#ff6767",
"green": "#61ffca",
"yellow": "#ffca85",
"blue": "#a277ff",
"purple": "#a277ff",
"cyan": "#61ffca",
"white": "#edecee",
"brightBlack": "#4d4d4d",
"brightRed": "#ffca85",
"brightGreen": "#a277ff",
"brightYellow": "#ffca85",
"brightBlue": "#a277ff",
"brightPurple": "#a277ff",
"brightCyan": "#61ffca",
"brightWhite": "#edecee",
"background": "#15141b",
"foreground": "#edecee",
"cursorColor": "#a277ff",
"selectionBackground": "#a277ff"
}

View File

@@ -0,0 +1,23 @@
{
"name": "Aurora",
"black": "#23262e",
"red": "#f0266f",
"green": "#8fd46d",
"yellow": "#ffe66d",
"blue": "#102ee4",
"purple": "#ee5d43",
"cyan": "#03d6b8",
"white": "#c74ded",
"brightBlack": "#4f545e",
"brightRed": "#f92672",
"brightGreen": "#8fd46d",
"brightYellow": "#ffe66d",
"brightBlue": "#03d6b8",
"brightPurple": "#ee5d43",
"brightCyan": "#03d6b8",
"brightWhite": "#c74ded",
"background": "#23262e",
"foreground": "#ffca28",
"cursorColor": "#ee5d43",
"selectionBackground": "#292e38"
}

View File

@@ -0,0 +1,23 @@
{
"name": "Ayu Light",
"black": "#000000",
"red": "#ea6c6d",
"green": "#6cbf43",
"yellow": "#eca944",
"blue": "#3199e1",
"purple": "#9e75c7",
"cyan": "#46ba94",
"white": "#bababa",
"brightBlack": "#686868",
"brightRed": "#f07171",
"brightGreen": "#86b300",
"brightYellow": "#f2ae49",
"brightBlue": "#399ee6",
"brightPurple": "#a37acc",
"brightCyan": "#4cbf99",
"brightWhite": "#d1d1d1",
"background": "#f8f9fa",
"foreground": "#5c6166",
"cursorColor": "#ffaa33",
"selectionBackground": "#035bd6"
}

View File

@@ -0,0 +1,23 @@
{
"name": "Ayu Mirage",
"black": "#171b24",
"red": "#ed8274",
"green": "#87d96c",
"yellow": "#facc6e",
"blue": "#6dcbfa",
"purple": "#dabafa",
"cyan": "#90e1c6",
"white": "#c7c7c7",
"brightBlack": "#686868",
"brightRed": "#f28779",
"brightGreen": "#d5ff80",
"brightYellow": "#ffd173",
"brightBlue": "#73d0ff",
"brightPurple": "#dfbfff",
"brightCyan": "#95e6cb",
"brightWhite": "#ffffff",
"background": "#1f2430",
"foreground": "#cccac2",
"cursorColor": "#ffcc66",
"selectionBackground": "#409fff"
}

View File

@@ -0,0 +1,23 @@
{
"name": "Ayu",
"black": "#11151c",
"red": "#ea6c73",
"green": "#7fd962",
"yellow": "#f9af4f",
"blue": "#53bdfa",
"purple": "#cda1fa",
"cyan": "#90e1c6",
"white": "#c7c7c7",
"brightBlack": "#686868",
"brightRed": "#f07178",
"brightGreen": "#aad94c",
"brightYellow": "#ffb454",
"brightBlue": "#59c2ff",
"brightPurple": "#d2a6ff",
"brightCyan": "#95e6cb",
"brightWhite": "#ffffff",
"background": "#0b0e14",
"foreground": "#bfbdb6",
"cursorColor": "#e6b450",
"selectionBackground": "#409fff"
}

View File

@@ -0,0 +1,23 @@
{
"name": "Banana Blueberry",
"black": "#17141f",
"red": "#ff6b7f",
"green": "#00bd9c",
"yellow": "#e6c62f",
"blue": "#22e8df",
"purple": "#dc396a",
"cyan": "#56b6c2",
"white": "#f1f1f1",
"brightBlack": "#495162",
"brightRed": "#fe9ea1",
"brightGreen": "#98c379",
"brightYellow": "#f9e46b",
"brightBlue": "#91fff4",
"brightPurple": "#da70d6",
"brightCyan": "#bcf3ff",
"brightWhite": "#ffffff",
"background": "#191323",
"foreground": "#cccccc",
"cursorColor": "#e07d13",
"selectionBackground": "#220525"
}

View File

@@ -0,0 +1,23 @@
{
"name": "Batman",
"black": "#1b1d1e",
"red": "#e6dc44",
"green": "#c8be46",
"yellow": "#f4fd22",
"blue": "#737174",
"purple": "#747271",
"cyan": "#62605f",
"white": "#c6c5bf",
"brightBlack": "#505354",
"brightRed": "#fff78e",
"brightGreen": "#fff27d",
"brightYellow": "#feed6c",
"brightBlue": "#919495",
"brightPurple": "#9a9a9d",
"brightCyan": "#a3a3a6",
"brightWhite": "#dadbd6",
"background": "#1b1d1e",
"foreground": "#6f6f6f",
"cursorColor": "#fcef0c",
"selectionBackground": "#4d504c"
}

View File

@@ -0,0 +1,23 @@
{
"name": "Belafonte Day",
"black": "#20111b",
"red": "#be100e",
"green": "#858162",
"yellow": "#d08b30",
"blue": "#426a79",
"purple": "#97522c",
"cyan": "#989a9c",
"white": "#968c83",
"brightBlack": "#5e5252",
"brightRed": "#be100e",
"brightGreen": "#858162",
"brightYellow": "#d08b30",
"brightBlue": "#426a79",
"brightPurple": "#97522c",
"brightCyan": "#989a9c",
"brightWhite": "#d5ccba",
"background": "#d5ccba",
"foreground": "#45373c",
"cursorColor": "#45373c",
"selectionBackground": "#968c83"
}

View File

@@ -0,0 +1,23 @@
{
"name": "Belafonte Night",
"black": "#20111b",
"red": "#be100e",
"green": "#858162",
"yellow": "#eaa549",
"blue": "#426a79",
"purple": "#97522c",
"cyan": "#989a9c",
"white": "#968c83",
"brightBlack": "#5e5252",
"brightRed": "#be100e",
"brightGreen": "#858162",
"brightYellow": "#eaa549",
"brightBlue": "#426a79",
"brightPurple": "#97522c",
"brightCyan": "#989a9c",
"brightWhite": "#d5ccba",
"background": "#20111b",
"foreground": "#968c83",
"cursorColor": "#968c83",
"selectionBackground": "#45373c"
}

View File

@@ -0,0 +1,23 @@
{
"name": "Birds Of Paradise",
"black": "#573d26",
"red": "#be2d26",
"green": "#6ba18a",
"yellow": "#e99d2a",
"blue": "#5a86ad",
"purple": "#ac80a6",
"cyan": "#74a6ad",
"white": "#e0dbb7",
"brightBlack": "#9b6c4a",
"brightRed": "#e84627",
"brightGreen": "#95d8ba",
"brightYellow": "#d0d150",
"brightBlue": "#b8d3ed",
"brightPurple": "#d19ecb",
"brightCyan": "#93cfd7",
"brightWhite": "#fff9d5",
"background": "#2a1f1d",
"foreground": "#e0dbb7",
"cursorColor": "#644a33",
"selectionBackground": "#563c27"
}

View File

@@ -0,0 +1,23 @@
{
"name": "Black Metal (Bathory)",
"black": "#000000",
"red": "#5f8787",
"green": "#fbcb97",
"yellow": "#e78a53",
"blue": "#888888",
"purple": "#999999",
"cyan": "#aaaaaa",
"white": "#c1c1c1",
"brightBlack": "#404040",
"brightRed": "#5f8787",
"brightGreen": "#fbcb97",
"brightYellow": "#e78a53",
"brightBlue": "#888888",
"brightPurple": "#999999",
"brightCyan": "#aaaaaa",
"brightWhite": "#c1c1c1",
"background": "#000000",
"foreground": "#c1c1c1",
"cursorColor": "#c1c1c1",
"selectionBackground": "#c1c1c1"
}

View File

@@ -0,0 +1,23 @@
{
"name": "Black Metal (Burzum)",
"black": "#000000",
"red": "#5f8787",
"green": "#ddeecc",
"yellow": "#99bbaa",
"blue": "#888888",
"purple": "#999999",
"cyan": "#aaaaaa",
"white": "#c1c1c1",
"brightBlack": "#404040",
"brightRed": "#5f8787",
"brightGreen": "#ddeecc",
"brightYellow": "#99bbaa",
"brightBlue": "#888888",
"brightPurple": "#999999",
"brightCyan": "#aaaaaa",
"brightWhite": "#c1c1c1",
"background": "#000000",
"foreground": "#c1c1c1",
"cursorColor": "#c1c1c1",
"selectionBackground": "#c1c1c1"
}

View File

@@ -0,0 +1,23 @@
{
"name": "Black Metal (Dark Funeral)",
"black": "#000000",
"red": "#5f8787",
"green": "#d0dfee",
"yellow": "#5f81a5",
"blue": "#888888",
"purple": "#999999",
"cyan": "#aaaaaa",
"white": "#c1c1c1",
"brightBlack": "#404040",
"brightRed": "#5f8787",
"brightGreen": "#d0dfee",
"brightYellow": "#5f81a5",
"brightBlue": "#888888",
"brightPurple": "#999999",
"brightCyan": "#aaaaaa",
"brightWhite": "#c1c1c1",
"background": "#000000",
"foreground": "#c1c1c1",
"cursorColor": "#c1c1c1",
"selectionBackground": "#c1c1c1"
}

View File

@@ -0,0 +1,23 @@
{
"name": "Black Metal (Gorgoroth)",
"black": "#000000",
"red": "#5f8787",
"green": "#9b8d7f",
"yellow": "#8c7f70",
"blue": "#888888",
"purple": "#999999",
"cyan": "#aaaaaa",
"white": "#c1c1c1",
"brightBlack": "#404040",
"brightRed": "#5f8787",
"brightGreen": "#9b8d7f",
"brightYellow": "#8c7f70",
"brightBlue": "#888888",
"brightPurple": "#999999",
"brightCyan": "#aaaaaa",
"brightWhite": "#c1c1c1",
"background": "#000000",
"foreground": "#c1c1c1",
"cursorColor": "#c1c1c1",
"selectionBackground": "#c1c1c1"
}

View File

@@ -0,0 +1,23 @@
{
"name": "Black Metal (Immortal)",
"black": "#000000",
"red": "#5f8787",
"green": "#7799bb",
"yellow": "#556677",
"blue": "#888888",
"purple": "#999999",
"cyan": "#aaaaaa",
"white": "#c1c1c1",
"brightBlack": "#404040",
"brightRed": "#5f8787",
"brightGreen": "#7799bb",
"brightYellow": "#556677",
"brightBlue": "#888888",
"brightPurple": "#999999",
"brightCyan": "#aaaaaa",
"brightWhite": "#c1c1c1",
"background": "#000000",
"foreground": "#c1c1c1",
"cursorColor": "#c1c1c1",
"selectionBackground": "#c1c1c1"
}

View File

@@ -0,0 +1,23 @@
{
"name": "Black Metal (Khold)",
"black": "#000000",
"red": "#5f8787",
"green": "#eceee3",
"yellow": "#974b46",
"blue": "#888888",
"purple": "#999999",
"cyan": "#aaaaaa",
"white": "#c1c1c1",
"brightBlack": "#404040",
"brightRed": "#5f8787",
"brightGreen": "#eceee3",
"brightYellow": "#974b46",
"brightBlue": "#888888",
"brightPurple": "#999999",
"brightCyan": "#aaaaaa",
"brightWhite": "#c1c1c1",
"background": "#000000",
"foreground": "#c1c1c1",
"cursorColor": "#c1c1c1",
"selectionBackground": "#c1c1c1"
}

View File

@@ -0,0 +1,23 @@
{
"name": "Black Metal (Marduk)",
"black": "#000000",
"red": "#5f8787",
"green": "#a5aaa7",
"yellow": "#626b67",
"blue": "#888888",
"purple": "#999999",
"cyan": "#aaaaaa",
"white": "#c1c1c1",
"brightBlack": "#404040",
"brightRed": "#5f8787",
"brightGreen": "#a5aaa7",
"brightYellow": "#626b67",
"brightBlue": "#888888",
"brightPurple": "#999999",
"brightCyan": "#aaaaaa",
"brightWhite": "#c1c1c1",
"background": "#000000",
"foreground": "#c1c1c1",
"cursorColor": "#c1c1c1",
"selectionBackground": "#c1c1c1"
}

View File

@@ -0,0 +1,23 @@
{
"name": "Black Metal (Mayhem)",
"black": "#000000",
"red": "#5f8787",
"green": "#f3ecd4",
"yellow": "#eecc6c",
"blue": "#888888",
"purple": "#999999",
"cyan": "#aaaaaa",
"white": "#c1c1c1",
"brightBlack": "#404040",
"brightRed": "#5f8787",
"brightGreen": "#f3ecd4",
"brightYellow": "#eecc6c",
"brightBlue": "#888888",
"brightPurple": "#999999",
"brightCyan": "#aaaaaa",
"brightWhite": "#c1c1c1",
"background": "#000000",
"foreground": "#c1c1c1",
"cursorColor": "#c1c1c1",
"selectionBackground": "#c1c1c1"
}

View File

@@ -0,0 +1,23 @@
{
"name": "Black Metal (Nile)",
"black": "#000000",
"red": "#5f8787",
"green": "#aa9988",
"yellow": "#777755",
"blue": "#888888",
"purple": "#999999",
"cyan": "#aaaaaa",
"white": "#c1c1c1",
"brightBlack": "#404040",
"brightRed": "#5f8787",
"brightGreen": "#aa9988",
"brightYellow": "#777755",
"brightBlue": "#888888",
"brightPurple": "#999999",
"brightCyan": "#aaaaaa",
"brightWhite": "#c1c1c1",
"background": "#000000",
"foreground": "#c1c1c1",
"cursorColor": "#c1c1c1",
"selectionBackground": "#c1c1c1"
}

View File

@@ -0,0 +1,23 @@
{
"name": "Black Metal (Venom)",
"black": "#000000",
"red": "#5f8787",
"green": "#f8f7f2",
"yellow": "#79241f",
"blue": "#888888",
"purple": "#999999",
"cyan": "#aaaaaa",
"white": "#c1c1c1",
"brightBlack": "#404040",
"brightRed": "#5f8787",
"brightGreen": "#f8f7f2",
"brightYellow": "#79241f",
"brightBlue": "#888888",
"brightPurple": "#999999",
"brightCyan": "#aaaaaa",
"brightWhite": "#c1c1c1",
"background": "#000000",
"foreground": "#c1c1c1",
"cursorColor": "#c1c1c1",
"selectionBackground": "#c1c1c1"
}

View File

@@ -0,0 +1,23 @@
{
"name": "Black Metal",
"black": "#000000",
"red": "#486e6f",
"green": "#dd9999",
"yellow": "#a06666",
"blue": "#888888",
"purple": "#999999",
"cyan": "#aaaaaa",
"white": "#c1c1c1",
"brightBlack": "#404040",
"brightRed": "#486e6f",
"brightGreen": "#dd9999",
"brightYellow": "#a06666",
"brightBlue": "#888888",
"brightPurple": "#999999",
"brightCyan": "#aaaaaa",
"brightWhite": "#c1c1c1",
"background": "#000000",
"foreground": "#c1c1c1",
"cursorColor": "#c1c1c1",
"selectionBackground": "#c1c1c1"
}

View File

@@ -0,0 +1,23 @@
{
"name": "Blazer",
"black": "#000000",
"red": "#b87a7a",
"green": "#7ab87a",
"yellow": "#b8b87a",
"blue": "#7a7ab8",
"purple": "#b87ab8",
"cyan": "#7ab8b8",
"white": "#d9d9d9",
"brightBlack": "#4c4c4c",
"brightRed": "#dbbdbd",
"brightGreen": "#bddbbd",
"brightYellow": "#dbdbbd",
"brightBlue": "#bdbddb",
"brightPurple": "#dbbddb",
"brightCyan": "#bddbdb",
"brightWhite": "#ffffff",
"background": "#0d1926",
"foreground": "#d9e6f2",
"cursorColor": "#d9e6f2",
"selectionBackground": "#c1ddff"
}

View File

@@ -0,0 +1,23 @@
{
"name": "Blue Berry Pie",
"black": "#0a4c62",
"red": "#99246e",
"green": "#5cb1b3",
"yellow": "#eab9a8",
"blue": "#90a5bd",
"purple": "#9d54a7",
"cyan": "#7e83cc",
"white": "#f0e8d6",
"brightBlack": "#463c5d",
"brightRed": "#c87272",
"brightGreen": "#0a6c7e",
"brightYellow": "#7a3188",
"brightBlue": "#5f3d63",
"brightPurple": "#bc94b7",
"brightCyan": "#5e6071",
"brightWhite": "#0a6c7e",
"background": "#1c0c28",
"foreground": "#babab9",
"cursorColor": "#fcfad6",
"selectionBackground": "#606060"
}

View File

@@ -0,0 +1,23 @@
{
"name": "Blue Dolphin",
"black": "#292d3e",
"red": "#ff8288",
"green": "#b4e88d",
"yellow": "#f4d69f",
"blue": "#82aaff",
"purple": "#e9c1ff",
"cyan": "#89ebff",
"white": "#d0d0d0",
"brightBlack": "#9094a4",
"brightRed": "#ff8b92",
"brightGreen": "#ddffa7",
"brightYellow": "#ffe585",
"brightBlue": "#9cc4ff",
"brightPurple": "#ddb0f6",
"brightCyan": "#a3f7ff",
"brightWhite": "#ffffff",
"background": "#006984",
"foreground": "#c5f2ff",
"cursorColor": "#ffcc00",
"selectionBackground": "#2baeca"
}

View File

@@ -0,0 +1,23 @@
{
"name": "Blue Matrix",
"black": "#101116",
"red": "#ff5680",
"green": "#00ff9c",
"yellow": "#fffc58",
"blue": "#00b0ff",
"purple": "#d57bff",
"cyan": "#76c1ff",
"white": "#c7c7c7",
"brightBlack": "#686868",
"brightRed": "#ff6e67",
"brightGreen": "#5ffa68",
"brightYellow": "#fffc67",
"brightBlue": "#6871ff",
"brightPurple": "#d682ec",
"brightCyan": "#60fdff",
"brightWhite": "#ffffff",
"background": "#101116",
"foreground": "#00a2ff",
"cursorColor": "#76ff9f",
"selectionBackground": "#c1deff"
}

View File

@@ -0,0 +1,23 @@
{
"name": "Bluloco Dark",
"black": "#41444d",
"red": "#fc2f52",
"green": "#25a45c",
"yellow": "#ff936a",
"blue": "#3476ff",
"purple": "#7a82da",
"cyan": "#4483aa",
"white": "#cdd4e0",
"brightBlack": "#8f9aae",
"brightRed": "#ff6480",
"brightGreen": "#3fc56b",
"brightYellow": "#f9c859",
"brightBlue": "#10b1fe",
"brightPurple": "#ff78f8",
"brightCyan": "#5fb9bc",
"brightWhite": "#ffffff",
"background": "#282c34",
"foreground": "#b9c0cb",
"cursorColor": "#ffcc00",
"selectionBackground": "#b9c0ca"
}

View File

@@ -0,0 +1,23 @@
{
"name": "Bluloco Light",
"black": "#373a41",
"red": "#d52753",
"green": "#23974a",
"yellow": "#df631c",
"blue": "#275fe4",
"purple": "#823ff1",
"cyan": "#27618d",
"white": "#babbc2",
"brightBlack": "#676a77",
"brightRed": "#ff6480",
"brightGreen": "#3cbc66",
"brightYellow": "#c5a332",
"brightBlue": "#0099e1",
"brightPurple": "#ce33c0",
"brightCyan": "#6d93bb",
"brightWhite": "#d3d3d3",
"background": "#f9f9f9",
"foreground": "#373a41",
"cursorColor": "#f32759",
"selectionBackground": "#daf0ff"
}

View File

@@ -0,0 +1,23 @@
{
"name": "Borland",
"black": "#4f4f4f",
"red": "#ff6c60",
"green": "#a8ff60",
"yellow": "#ffffb6",
"blue": "#96cbfe",
"purple": "#ff73fd",
"cyan": "#c6c5fe",
"white": "#eeeeee",
"brightBlack": "#7c7c7c",
"brightRed": "#ffb6b0",
"brightGreen": "#ceffac",
"brightYellow": "#ffffcc",
"brightBlue": "#b5dcff",
"brightPurple": "#ff9cfe",
"brightCyan": "#dfdffe",
"brightWhite": "#ffffff",
"background": "#0000a4",
"foreground": "#ffff4e",
"cursorColor": "#ffa560",
"selectionBackground": "#a4a4a4"
}

View File

@@ -0,0 +1,23 @@
{
"name": "Box",
"black": "#000000",
"red": "#cc0403",
"green": "#19cb00",
"yellow": "#cecb00",
"blue": "#0d73cc",
"purple": "#cb1ed1",
"cyan": "#0dcdcd",
"white": "#dddddd",
"brightBlack": "#767676",
"brightRed": "#f2201f",
"brightGreen": "#23fd00",
"brightYellow": "#fffd00",
"brightBlue": "#1a8fff",
"brightPurple": "#fd28ff",
"brightCyan": "#14ffff",
"brightWhite": "#ffffff",
"background": "#141d2b",
"foreground": "#9fef00",
"cursorColor": "#9fef00",
"selectionBackground": "#a4b1cd"
}

View File

@@ -0,0 +1,23 @@
{
"name": "Breadog",
"black": "#362c24",
"red": "#b10b00",
"green": "#007232",
"yellow": "#8b4c00",
"blue": "#005cb4",
"purple": "#9b0097",
"cyan": "#006a78",
"white": "#baa99d",
"brightBlack": "#514337",
"brightRed": "#de1100",
"brightGreen": "#008f40",
"brightYellow": "#ae6000",
"brightBlue": "#0074e1",
"brightPurple": "#c300bd",
"brightCyan": "#008697",
"brightWhite": "#eae1da",
"background": "#f1ebe6",
"foreground": "#362c24",
"cursorColor": "#362c24",
"selectionBackground": "#362c24"
}

View File

@@ -0,0 +1,23 @@
{
"name": "Breeze",
"black": "#31363b",
"red": "#ed1515",
"green": "#11d116",
"yellow": "#f67400",
"blue": "#1d99f3",
"purple": "#9b59b6",
"cyan": "#1abc9c",
"white": "#eff0f1",
"brightBlack": "#7f8c8d",
"brightRed": "#c0392b",
"brightGreen": "#1cdc9a",
"brightYellow": "#fdbc4b",
"brightBlue": "#3daee9",
"brightPurple": "#8e44ad",
"brightCyan": "#16a085",
"brightWhite": "#fcfcfc",
"background": "#31363b",
"foreground": "#eff0f1",
"cursorColor": "#eff0f1",
"selectionBackground": "#eff0f1"
}

View File

@@ -0,0 +1,23 @@
{
"name": "Bright Lights",
"black": "#191919",
"red": "#ff355b",
"green": "#b7e876",
"yellow": "#ffc251",
"blue": "#76d4ff",
"purple": "#ba76e7",
"cyan": "#6cbfb5",
"white": "#c2c8d7",
"brightBlack": "#4c4c4c",
"brightRed": "#ff355b",
"brightGreen": "#b7e876",
"brightYellow": "#ffc251",
"brightBlue": "#76d5ff",
"brightPurple": "#ba76e7",
"brightCyan": "#6cbfb5",
"brightWhite": "#c2c8d7",
"background": "#191919",
"foreground": "#b3c9d7",
"cursorColor": "#f34b00",
"selectionBackground": "#b3c9d7"
}

View File

@@ -0,0 +1,23 @@
{
"name": "Broadcast",
"black": "#000000",
"red": "#da4939",
"green": "#519f50",
"yellow": "#ffd24a",
"blue": "#6d9cbe",
"purple": "#d0d0ff",
"cyan": "#6e9cbe",
"white": "#ffffff",
"brightBlack": "#585858",
"brightRed": "#ff7b6b",
"brightGreen": "#83d182",
"brightYellow": "#ffff7c",
"brightBlue": "#9fcef0",
"brightPurple": "#ffffff",
"brightCyan": "#a0cef0",
"brightWhite": "#ffffff",
"background": "#2b2b2b",
"foreground": "#e6e1dc",
"cursorColor": "#ffffff",
"selectionBackground": "#5a647e"
}

View File

@@ -0,0 +1,23 @@
{
"name": "Brogrammer",
"black": "#1f1f1f",
"red": "#f81118",
"green": "#2dc55e",
"yellow": "#ecba0f",
"blue": "#2a84d2",
"purple": "#4e5ab7",
"cyan": "#1081d6",
"white": "#d6dbe5",
"brightBlack": "#d6dbe5",
"brightRed": "#de352e",
"brightGreen": "#1dd361",
"brightYellow": "#f3bd09",
"brightBlue": "#1081d6",
"brightPurple": "#5350b9",
"brightCyan": "#0f7ddb",
"brightWhite": "#ffffff",
"background": "#131313",
"foreground": "#d6dbe5",
"cursorColor": "#b9b9b9",
"selectionBackground": "#1f1f1f"
}

View File

@@ -0,0 +1,23 @@
{
"name": "Builtin Dark",
"black": "#000000",
"red": "#bb0000",
"green": "#00bb00",
"yellow": "#bbbb00",
"blue": "#0d0dc8",
"purple": "#bb00bb",
"cyan": "#00bbbb",
"white": "#bbbbbb",
"brightBlack": "#555555",
"brightRed": "#ff5555",
"brightGreen": "#55ff55",
"brightYellow": "#ffff55",
"brightBlue": "#5555ff",
"brightPurple": "#ff55ff",
"brightCyan": "#55ffff",
"brightWhite": "#ffffff",
"background": "#000000",
"foreground": "#bbbbbb",
"cursorColor": "#bbbbbb",
"selectionBackground": "#b5d5ff"
}

View File

@@ -0,0 +1,23 @@
{
"name": "Builtin Light",
"black": "#000000",
"red": "#bb0000",
"green": "#00bb00",
"yellow": "#bbbb00",
"blue": "#0000bb",
"purple": "#bb00bb",
"cyan": "#00bbbb",
"white": "#bbbbbb",
"brightBlack": "#555555",
"brightRed": "#ff5555",
"brightGreen": "#2fd92f",
"brightYellow": "#bfbf15",
"brightBlue": "#5555ff",
"brightPurple": "#ff55ff",
"brightCyan": "#22cccc",
"brightWhite": "#ffffff",
"background": "#ffffff",
"foreground": "#000000",
"cursorColor": "#000000",
"selectionBackground": "#b5d5ff"
}

View File

@@ -0,0 +1,23 @@
{
"name": "Builtin Pastel Dark",
"black": "#4f4f4f",
"red": "#ff6c60",
"green": "#a8ff60",
"yellow": "#ffffb6",
"blue": "#96cbfe",
"purple": "#ff73fd",
"cyan": "#c6c5fe",
"white": "#eeeeee",
"brightBlack": "#7c7c7c",
"brightRed": "#ffb6b0",
"brightGreen": "#ceffac",
"brightYellow": "#ffffcc",
"brightBlue": "#b5dcff",
"brightPurple": "#ff9cfe",
"brightCyan": "#dfdffe",
"brightWhite": "#ffffff",
"background": "#000000",
"foreground": "#bbbbbb",
"cursorColor": "#ffa560",
"selectionBackground": "#363983"
}

View File

@@ -0,0 +1,23 @@
{
"name": "Builtin Tango Dark",
"black": "#000000",
"red": "#cc0000",
"green": "#4e9a06",
"yellow": "#c4a000",
"blue": "#3465a4",
"purple": "#75507b",
"cyan": "#06989a",
"white": "#d3d7cf",
"brightBlack": "#555753",
"brightRed": "#ef2929",
"brightGreen": "#8ae234",
"brightYellow": "#fce94f",
"brightBlue": "#729fcf",
"brightPurple": "#ad7fa8",
"brightCyan": "#34e2e2",
"brightWhite": "#eeeeec",
"background": "#000000",
"foreground": "#ffffff",
"cursorColor": "#ffffff",
"selectionBackground": "#b5d5ff"
}

View File

@@ -0,0 +1,23 @@
{
"name": "Builtin Tango Light",
"black": "#000000",
"red": "#cc0000",
"green": "#4e9a06",
"yellow": "#c4a000",
"blue": "#3465a4",
"purple": "#75507b",
"cyan": "#06989a",
"white": "#b9bdb5",
"brightBlack": "#555753",
"brightRed": "#ef2929",
"brightGreen": "#7dd527",
"brightYellow": "#d6c329",
"brightBlue": "#729fcf",
"brightPurple": "#ad7fa8",
"brightCyan": "#27d5d5",
"brightWhite": "#eeeeec",
"background": "#ffffff",
"foreground": "#000000",
"cursorColor": "#000000",
"selectionBackground": "#b5d5ff"
}

View File

@@ -0,0 +1,23 @@
{
"name": "C64",
"black": "#090300",
"red": "#a2524c",
"green": "#55a049",
"yellow": "#bfce72",
"blue": "#6657b3",
"purple": "#984ca3",
"cyan": "#67b6bd",
"white": "#ffffff",
"brightBlack": "#000000",
"brightRed": "#a2524c",
"brightGreen": "#55a049",
"brightYellow": "#bfce72",
"brightBlue": "#6657b3",
"brightPurple": "#984ca3",
"brightCyan": "#67b6bd",
"brightWhite": "#f7f7f7",
"background": "#40318d",
"foreground": "#7869c4",
"cursorColor": "#7869c4",
"selectionBackground": "#7869c4"
}

View File

@@ -0,0 +1,23 @@
{
"name": "CGA",
"black": "#000000",
"red": "#aa0000",
"green": "#00aa00",
"yellow": "#aa5500",
"blue": "#0d0db7",
"purple": "#aa00aa",
"cyan": "#00aaaa",
"white": "#aaaaaa",
"brightBlack": "#555555",
"brightRed": "#ff5555",
"brightGreen": "#55ff55",
"brightYellow": "#ffff55",
"brightBlue": "#5555ff",
"brightPurple": "#ff55ff",
"brightCyan": "#55ffff",
"brightWhite": "#ffffff",
"background": "#000000",
"foreground": "#aaaaaa",
"cursorColor": "#b8b8b8",
"selectionBackground": "#c1deff"
}

Some files were not shown because too many files have changed in this diff Show More