From c6dc54b34366c98273bf1992e0f54da5e085ca05 Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Thu, 23 Feb 2023 15:21:26 +0100 Subject: [PATCH] Terminal: Add Shell option menu Change-Id: I08ea3c52ed28ab65f2dc902051bab9e6975e6a7e Reviewed-by: Cristian Adam --- src/plugins/coreplugin/manhattanstyle.cpp | 6 ++ src/plugins/terminal/terminalpane.cpp | 93 +++++++++++++++++++++-- src/plugins/terminal/terminalwidget.cpp | 5 +- 3 files changed, 95 insertions(+), 9 deletions(-) diff --git a/src/plugins/coreplugin/manhattanstyle.cpp b/src/plugins/coreplugin/manhattanstyle.cpp index 3ec83405535..7cf4746f951 100644 --- a/src/plugins/coreplugin/manhattanstyle.cpp +++ b/src/plugins/coreplugin/manhattanstyle.cpp @@ -189,6 +189,12 @@ int ManhattanStyle::pixelMetric(PixelMetric metric, const QStyleOption *option, int retval = 0; retval = QProxyStyle::pixelMetric(metric, option, widget); switch (metric) { +#ifdef Q_OS_MACOS + case PM_MenuButtonIndicator: + if (widget && option->type == QStyleOption::SO_ToolButton) + return 12; + break; +#endif case PM_SplitterWidth: if (widget && widget->property("minisplitter").toBool()) retval = 1; diff --git a/src/plugins/terminal/terminalpane.cpp b/src/plugins/terminal/terminalpane.cpp index 5e57317c0fc..a355ca02725 100644 --- a/src/plugins/terminal/terminalpane.cpp +++ b/src/plugins/terminal/terminalpane.cpp @@ -9,10 +9,71 @@ #include #include +#include +#include #include +#include +#include +#include + namespace Terminal { +using namespace Utils; + +FilePaths availableShells() +{ + if (Utils::HostOsInfo::isWindowsHost()) { + FilePaths shells; + + FilePath comspec = FilePath::fromUserInput(qtcEnvironmentVariable("COMSPEC")); + shells << comspec; + + if (comspec.fileName() != "cmd.exe") { + FilePath cmd = FilePath::fromUserInput(QStandardPaths::findExecutable("cmd.exe")); + shells << cmd; + } + + FilePath powershell = FilePath::fromUserInput( + QStandardPaths::findExecutable("powershell.exe")); + if (powershell.exists()) + shells << powershell; + + FilePath bash = FilePath::fromUserInput(QStandardPaths::findExecutable("bash.exe")); + if (bash.exists()) + shells << bash; + + FilePath git_bash = FilePath::fromUserInput(QStandardPaths::findExecutable("git.exe")); + if (git_bash.exists()) + shells << git_bash.parentDir().parentDir().pathAppended("usr/bin/bash.exe"); + + FilePath msys2_bash = FilePath::fromUserInput(QStandardPaths::findExecutable("msys2.exe")); + if (msys2_bash.exists()) + shells << msys2_bash.parentDir().pathAppended("usr/bin/bash.exe"); + + return shells; + } else { + FilePath shellsFile = FilePath::fromString("/etc/shells"); + const auto shellFileContent = shellsFile.fileContents(); + QTC_ASSERT_EXPECTED(shellFileContent, return {}); + + QString shellFileContentString = QString::fromUtf8(*shellFileContent); + + // Filter out comments ... + const QStringList lines + = Utils::filtered(shellFileContentString.split('\n', Qt::SkipEmptyParts), + [](const QString &line) { return !line.trimmed().startsWith('#'); }); + + // Convert lines to file paths ... + const FilePaths shells = Utils::transform(lines, [](const QString &line) { + return FilePath::fromUserInput(line.trimmed()); + }); + + // ... and filter out non-existing shells. + return Utils::filtered(shells, [](const FilePath &shell) { return shell.exists(); }); + } +} + TerminalPane::TerminalPane(QObject *parent) : Core::IOutputPane(parent) { @@ -21,13 +82,7 @@ TerminalPane::TerminalPane(QObject *parent) m_newTerminal.setIcon(Utils::Icons::PLUS_TOOLBAR.icon()); m_newTerminal.setToolTip(Tr::tr("Create a new Terminal.")); - connect(&m_newTerminal, &QAction::triggered, this, [this] { - m_tabWidget->setCurrentIndex( - m_tabWidget->addTab(new TerminalWidget(m_tabWidget), Tr::tr("Terminal"))); - - m_closeTerminal.setEnabled(m_tabWidget->count() > 1); - emit navigateStateUpdate(); - }); + connect(&m_newTerminal, &QAction::triggered, this, [this] { openTerminal({}); }); m_closeTerminal.setIcon(Utils::Icons::CLOSE_TOOLBAR.icon()); m_closeTerminal.setToolTip(Tr::tr("Close the current Terminal.")); @@ -41,6 +96,30 @@ TerminalPane::TerminalPane(QObject *parent) //cmd->setDescription(m_newTerminal->toolTip()); m_newTerminalButton = new QToolButton(); + + QMenu *shellMenu = new QMenu(m_newTerminalButton); + + const FilePaths shells = availableShells(); + + QFileIconProvider iconProvider; + + // Create an action for each available shell ... + for (const FilePath &shell : shells) { + const QIcon icon = iconProvider.icon(shell.toFileInfo()); + + QAction *action = new QAction(icon, shell.toUserOutput(), shellMenu); + action->setData(shell.toVariant()); + shellMenu->addAction(action); + } + connect(shellMenu, &QMenu::triggered, this, [this](QAction *action) { + openTerminal( + Utils::Terminal::OpenTerminalParameters{CommandLine{FilePath::fromVariant(action->data()), {}}, + std::nullopt, + std::nullopt, + Utils::Terminal::ExitBehavior::Close}); + }); + m_newTerminal.setMenu(shellMenu); + m_newTerminalButton->setDefaultAction(&m_newTerminal); m_closeTerminalButton = new QToolButton(); diff --git a/src/plugins/terminal/terminalwidget.cpp b/src/plugins/terminal/terminalwidget.cpp index a6169846291..a4bf0ae37a9 100644 --- a/src/plugins/terminal/terminalwidget.cpp +++ b/src/plugins/terminal/terminalwidget.cpp @@ -92,12 +92,13 @@ void TerminalWidget::setupPty() m_ptyProcess.reset(PtyQt::createPtyProcess(IPtyProcess::PtyType::AutoPty)); Environment env = m_openParameters.environment.value_or(Environment::systemEnvironment()); - // Why? - env.appendOrSetPath(TerminalSettings::instance().shell.filePath().parentDir()); CommandLine shellCommand = m_openParameters.shellCommand.value_or( CommandLine{TerminalSettings::instance().shell.filePath(), {}}); + // For git bash on Windows + env.prependOrSetPath(shellCommand.executable().parentDir()); + QStringList envList = filtered(env.toStringList(), [](const QString &envPair) { return envPair != "CLINK_NOAUTORUN=1"; });