improve custom terminal settings (#137)

- custom terminal on Windows now require explicit enablement
- customizable terminal arguments pattern and its auto detection
- move hard-coded terminals to resource files
This commit is contained in:
Cyano Hao 2023-09-20 10:52:54 +08:00 committed by GitHub
parent 660cd63532
commit 52c5ea4caf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 707 additions and 582 deletions

View File

@ -265,6 +265,7 @@ void CompilerManager::run(
sharedMemoryId, sharedMemoryId,
localizePath(filename) localizePath(filename)
} + splitProcessCommand(arguments); } + splitProcessCommand(arguments);
if (pSettings->environment().useCustomTerminal()) {
auto [filename, args, fileOwner] = wrapCommandForTerminalEmulator( auto [filename, args, fileOwner] = wrapCommandForTerminalEmulator(
pSettings->environment().terminalPathForExec(), pSettings->environment().terminalPathForExec(),
pSettings->environment().terminalArgumentsPattern(), pSettings->environment().terminalArgumentsPattern(),
@ -274,6 +275,11 @@ void CompilerManager::run(
execRunner = new ExecutableRunner(filename, args, workDir); execRunner = new ExecutableRunner(filename, args, workDir);
execRunner->setShareMemoryId(sharedMemoryId); execRunner->setShareMemoryId(sharedMemoryId);
mTempFileOwner = std::move(fileOwner); mTempFileOwner = std::move(fileOwner);
} else {
//delete when thread finished
execRunner = new ExecutableRunner(execArgs[0], execArgs.mid(1), workDir);
execRunner->setShareMemoryId(sharedMemoryId);
}
} else { } else {
//delete when thread finished //delete when thread finished
execRunner = new ExecutableRunner(filename,splitProcessCommand(arguments),workDir); execRunner = new ExecutableRunner(filename,splitProcessCommand(arguments),workDir);

View File

@ -3,5 +3,7 @@
<file alias="autolink.json">resources/autolink.json</file> <file alias="autolink.json">resources/autolink.json</file>
<file alias="codesnippets.json">resources/codesnippets.json</file> <file alias="codesnippets.json">resources/codesnippets.json</file>
<file alias="autolink-xdg.json">resources/autolink-xdg.json</file> <file alias="autolink-xdg.json">resources/autolink-xdg.json</file>
<file alias="terminal-windows.json">resources/terminal-windows.json</file>
<file alias="terminal-unix.json">resources/terminal-unix.json</file>
</qresource> </qresource>
</RCC> </RCC>

View File

@ -0,0 +1,207 @@
[
{
"group": "User Installed",
"terminals": [
{
"name": "Alacritty",
"path": "alacritty",
"argsPattern": "$term -e $argv"
},
{
"name": "cool-retro-term",
"path": "cool-retro-term",
"argsPattern": "$term -e $argv"
},
{
"name": "CoreTerminal",
"path": "coreterminal",
"argsPattern": "$term -e \"$command\"",
"comment": "The pair of quotation mark around `$command` is only a visual symbol, not actually required."
},
{
"name": "iTerm2",
"path": "/Applications/iTerm.app/Contents/MacOS/iTerm2",
"argsPattern": "$term $tmpfile"
},
{
"name": "kermit",
"path": "kermit",
"argsPattern": "$term -e \"$command\""
},
{
"name": "Kitty",
"path": "kitty",
"argsPattern": "$term -e $argv"
},
{
"name": "ROXTerm",
"path": "roxterm",
"argsPattern": "$term -e \"$command\""
},
{
"name": "sakura",
"path": "sakura",
"argsPattern": "$term -e \"$command\""
},
{
"name": "Termit",
"path": "termit",
"argsPattern": "$term -e $argv"
},
{
"name": "Termite",
"path": "termite",
"argsPattern": "$term -e \"$command\""
},
{
"name": "Tilix",
"path": "tilix",
"argsPattern": "$term -e $argv"
},
{
"name": "Wayst",
"path": "wayst",
"argsPattern": "$term -e $argv"
}
]
},
{
"group": "Desktop Default",
"terminals": [
{
"name": "Deepin Terminal",
"path": "deepin-terminal",
"argsPattern": "$term -e $argv"
},
{
"name": "Konsole (KDE)",
"path": "konsole",
"argsPattern": "$term -e $argv"
},
{
"name": "GNOME Terminal",
"path": "gnome-terminal",
"argsPattern": "$term -- $argv"
},
{
"name": "GNOME Terminator",
"path": "terminator",
"argsPattern": "$term -x $argv"
},
{
"name": "LXTerminal (LXDE)",
"path": "lxterminal",
"argsPattern": "$term -e $argv"
},
{
"name": "MATE Terminal",
"path": "mate-terminal",
"argsPattern": "$term -x $argv"
},
{
"name": "QTerminal (LXQt)",
"path": "qterminal",
"argsPattern": "$term -e $argv"
},
{
"name": "Terminal.app (macOS 10.14 or earlier)",
"path": "/Applications/Utilities/Terminal.app/Contents/MacOS/Terminal",
"argsPattern": "$term $tmpfile"
},
{
"name": "Terminal.app (macOS 10.15 or later)",
"path": "/System/Applications/Utilities/Terminal.app/Contents/MacOS/Terminal",
"argsPattern": "$term $tmpfile"
},
{
"name": "Terminology (Enlightenment)",
"path": "terminology",
"argsPattern": "$term -e \"$command\""
},
{
"name": "Xfce Terminal",
"path": "xfce4-terminal",
"argsPattern": "$term -x $argv"
}
]
},
{
"group": "Bundled",
"terminals": [
{
"name": "Alacritty (Bundled)",
"path": "./alacritty",
"argsPattern": "$term -e $argv"
}
]
},
{
"group": "With minor issue",
"terminals": [
{
"name": "Elementary Terminal",
"path": "io.elementary.terminal",
"argsPattern": "$term -e \"$command\"",
"comment": "confirm to quit"
},
{
"name": "foot",
"path": "foot",
"argsPattern": "$term -e $argv",
"comment": "wayland only"
},
{
"name": "GNOME Console",
"path": "kgx",
"argsPattern": "$term -- $argv",
"comment": "confirm to quit"
},
{
"name": "mlterm",
"path": "mlterm",
"argsPattern": "$term -e $argv",
"comment": "no out of box HiDPI support"
},
{
"name": "st",
"path": "st",
"argsPattern": "$term -e $argv",
"comment": "no out of box HiDPI support"
},
{
"name": "urxvt",
"path": "urxvt",
"argsPattern": "$term -e $argv",
"comment": "no out of box HiDPI support"
},
{
"name": "xterm",
"path": "xterm",
"argsPattern": "$term -e $argv",
"comment": "no out of box HiDPI support"
},
{
"name": "zutty",
"path": "zutty",
"argsPattern": "$term -e $argv",
"comment": "no out of box HiDPI support"
}
]
},
{
"group": "Unavailable",
"terminals": [],
"unavailableTerminals": {
"aterm": "AUR broken, unable to test",
"eterm": "AUR broken, unable to test",
"guake": "drop down terminal",
"hyper": "no execute support",
"liri-terminal": "no execute support",
"rxvt": "no unicode support",
"shellinabox": "AUR broken, unable to test",
"station": "no execute support",
"tilda": "drop down terminal",
"yakuake": "drop down terminal"
}
}
]

View File

@ -0,0 +1,52 @@
[
{
"group": "Bundled",
"terminals": [
{
"name": "UTF-8 compatible Console Host",
"path": "./OpenConsole.exe",
"argsPattern": "$term -- $argv"
}
]
},
{
"group": "System",
"terminals": [
{
"name": "System Default",
"path": "",
"argsPattern": "$argv"
}
]
},
{
"group": "Predefined arguments pattern (will not be searched)",
"terminals": [
{
"name": "Console Host",
"path": "conhost.exe",
"argsPattern": "$term -- $argv"
},
{
"name": "Windows Terminal",
"path": "wt.exe",
"argsPattern": "$term -- $argv"
},
{
"name": "Alacritty",
"path": "alacritty.exe",
"argsPattern": "$term -e $argv"
},
{
"name": "Konsole",
"path": "konsole.exe",
"argsPattern": "$term -e $argv"
},
{
"name": "Mintty",
"path": "mintty.exe",
"argsPattern": "$term -e $argv"
}
]
}
]

View File

@ -27,6 +27,9 @@
#include <QScreen> #include <QScreen>
#include <QDesktopWidget> #include <QDesktopWidget>
#include <QRegularExpression> #include <QRegularExpression>
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonArray>
#ifdef Q_OS_LINUX #ifdef Q_OS_LINUX
#include <sys/sysinfo.h> #include <sys/sysinfo.h>
#endif #endif
@ -3608,146 +3611,46 @@ void Settings::Environment::doLoad()
mDefaultOpenFolder = QDir::currentPath(); mDefaultOpenFolder = QDir::currentPath();
} }
using AP = TerminalEmulatorArgumentsPattern;
struct TerminalSearchItem {
QString appName;
AP argsPattern;
};
#ifdef Q_OS_WINDOWS #ifdef Q_OS_WINDOWS
const TerminalSearchItem terminals[] { # if defined (__aarch64__) || defined(_M_ARM64) || defined (_M_ARM64EC)
/* explicitly installed terminals */ // the only native MinGW toolchain (LLVM-MinGW) does not have local codepage support
// prefer UTF-8 compatible OpenConsole.exe
/* system */ mUseCustomTerminal = boolValue("use_custom_terminal", true);
{"conhost.exe", AP::ImplicitSystem}, // dummy for system default # else // x86 or x64
mUseCustomTerminal = boolValue("use_custom_terminal", false);
/* will not actually be searched, just a list for users who dig into here */ # endif
{"conhost.exe", AP::MinusMinusAppendArgs}, // yes, it accepts GNU-style (--) arguments #else // UNIX
{"wt.exe", AP::MinusMinusAppendArgs}, // generally okay, but “Test” does not work mUseCustomTerminal = true;
{"alacritty.exe", AP::MinusEAppendArgs}, // GPU-accelerated
{"C:/Program Files/Alacritty/alacritty.exe", AP::MinusEAppendArgs},
{"C:/Program Files/konsole/bin/konsole.exe", AP::MinusEAppendArgs}, // generally okay, but “Test” does not work
{"C:/Program Files/Git/usr/bin/mintty.exe", AP::MinusEAppendArgs}, // Git Mintty
{"C:/msys64/usr/bin/mintty.exe", AP::MinusEAppendArgs}, // MSYS2 Mintty
};
#else
const TerminalSearchItem terminals[] {
/* modern, specialized or stylized terminal -- user who installed them are likely to prefer them */
{"alacritty", AP::MinusEAppendArgs}, // GPU-accelerated
{"kitty", AP::MinusEAppendArgs}, // GPU-accelerated
{"wayst", AP::MinusEAppendArgs}, // GPU-accelerated
{"coreterminal", AP::MinusEAppendCommandLine}, // lightweighted
{"kermit", AP::MinusEAppendCommandLine}, // lightweighted
{"roxterm", AP::MinusEAppendCommandLine}, // lightweighted
{"sakura", AP::MinusEAppendCommandLine}, // lightweighted
{"termit", AP::MinusEAppendArgs}, // Lua scripting
{"termite", AP::MinusEAppendCommandLine}, // tiling, keyboard-centric
{"tilix", AP::MinusEAppendArgs}, // tiling
{"cool-retro-term", AP::MinusEAppendArgs}, // old CRT style
/* default terminal for XDG DE -- macOS user who installed them are likely to prefer them */
{"deepin-terminal", AP::MinusEAppendArgs}, // DDE
{"konsole", AP::MinusEAppendArgs}, // KDE
{"gnome-terminal", AP::MinusMinusAppendArgs}, // GNOME
{"io.elementary.terminal", AP::MinusEAppendCommandLine}, // Pantheon (elementary OS)
{"lxterminal", AP::MinusEAppendArgs}, // LXDE
{"mate-terminal", AP::MinusXAppendArgs}, // MATE
{"qterminal", AP::MinusEAppendArgs}, // LXQt
{"terminator", AP::MinusXAppendArgs}, // tiling, also seen in SBC images
{"terminology", AP::MinusEAppendCommandLine}, // Enlightenment
{"xfce4-terminal", AP::MinusXAppendArgs}, // Xfce
/* bundled terminal in AppImage */
{"./alacritty", AP::MinusEAppendArgs},
/* compatible, with minor issue */
{"kgx", AP::MinusMinusAppendArgs}, // GNOME Console, confirm to quit
/* compatible, without out-of-box hidpi support on Linux */
{"mlterm", AP::MinusEAppendArgs},
{"st", AP::MinusEAppendArgs},
{"urxvt", AP::MinusEAppendArgs},
{"xterm", AP::MinusEAppendArgs},
{"zutty", AP::MinusEAppendArgs},
/* macOS system */
{"/Applications/iTerm.app/Contents/MacOS/iTerm2", AP::WriteCommandLineToTempFileThenTempFilename},
{"/System/Applications/Utilities/Terminal.app/Contents/MacOS/Terminal", AP::WriteCommandLineToTempFileThenTempFilename},
{"/Applications/Utilities/Terminal.app/Contents/MacOS/Terminal", AP::WriteCommandLineToTempFileThenTempFilename},
/* fallbacks */
{"foot", AP::MinusEAppendArgs}, // Wayland only
/* parameter incompatible */
// "guake", // drop down
// "hyper", // no execute support
// "liri-terminal", // no execute support
// "station", // no execute support
// "tilda", // drop down
/* incompatible -- other */
// "aterm", // AUR broken, unable to test
// "eterm", // AUR broken, unable to test
// "rxvt", // no unicode support
// "shellinabox", // AUR broken, unable to test
};
#endif #endif
auto checkAndSetTerminalPath = [this](const TerminalSearchItem &searchItem) -> bool { #ifdef Q_OS_WINDOWS
#define DO_CHECK_AND_SET do { \ QString terminalListFilename(":/config/terminal-windows.json");
if (termPathInfo.isFile() && termPathInfo.isReadable() && termPathInfo.isExecutable()) { \ #else // UNIX
mTerminalPath = searchItem.appName; \ QString terminalListFilename(":/config/terminal-unix.json");
mTerminalArgumentsPattern = searchItem.argsPattern; \ #endif
return true; \ QFile terminalListFile(terminalListFilename);
} \ if (!terminalListFile.open(QFile::ReadOnly))
} while (0) throw FileError(QObject::tr("Can't open file '%1' for read.")
.arg(terminalListFilename));
switch (getPathUnixExecSemantics(searchItem.appName)) { QByteArray terminalListContent = terminalListFile.readAll();
case UnixExecSemantics::Absolute: { QJsonDocument terminalListDocument(QJsonDocument::fromJson(terminalListContent));
QFileInfo termPathInfo(searchItem.appName);
DO_CHECK_AND_SET;
break;
}
case UnixExecSemantics::RelativeToCwd: {
QDir appDir(pSettings->dirs().appDir());
QString absoluteTerminalPath = appDir.absoluteFilePath(searchItem.appName);
QFileInfo termPathInfo(absoluteTerminalPath);
DO_CHECK_AND_SET;
break;
}
case UnixExecSemantics::SearchInPath: {
QStringList pathList = getExecutableSearchPaths();
for (const QString &dir: pathList) {
QString absoluteTerminalPath = QDir(dir).absoluteFilePath(searchItem.appName);
QFileInfo termPathInfo(absoluteTerminalPath);
DO_CHECK_AND_SET;
}
break;
}
}
return false;
};
#undef DO_CHECK_AND_SET
// check saved terminal path // check saved terminal path
QString savedTerminalPath = stringValue("terminal_path", ""); QString savedTerminalPath = stringValue("terminal_path", "");
int savedArgsPattern_ = intValue("terminal_arguments_pattern", QString savedArgsPattern = stringValue("terminal_arguments_pattern", "");
#ifdef Q_OS_MACOS bool terminalSet = checkAndSetTerminal(savedTerminalPath, savedArgsPattern);
// macOS: old versions have set Terminal.app as default terminal
// fallback to temp file to work with Terminal.app for smooth migration // determing terminal (if not set yet) and build predefined arguments pattern map from our list
int(AP::WriteCommandLineToTempFileThenTempFilename) for (const auto &terminalGroup: terminalListDocument.array()) {
#else const QJsonArray &terminals = terminalGroup.toObject()["terminals"].toArray();
int(AP::MinusEAppendArgs) // Linux: keep old behaviour for (const auto &terminal_: terminals) {
#endif const QJsonObject &terminal = terminal_.toObject();
); const QString &path = terminal["path"].toString();
AP savedArgsPattern = static_cast<AP>(savedArgsPattern_); const QString &executable = QFileInfo(path).fileName();
if (!checkAndSetTerminalPath(TerminalSearchItem{savedTerminalPath, savedArgsPattern})) { const QString &pattern = terminal["argsPattern"].toString();
// if saved terminal path is invalid, try determing terminal from our list mPredefinedTerminalArgumentsPattern[executable] = pattern;
for (auto terminal: terminals) { if (!terminalSet)
if (checkAndSetTerminalPath(terminal)) terminalSet = checkAndSetTerminal(path, pattern);
break;
} }
} }
@ -3835,12 +3738,12 @@ void Settings::Environment::setAStylePath(const QString &aStylePath)
mAStylePath = aStylePath; mAStylePath = aStylePath;
} }
TerminalEmulatorArgumentsPattern Settings::Environment::terminalArgumentsPattern() const QString Settings::Environment::terminalArgumentsPattern() const
{ {
return mTerminalArgumentsPattern; return mTerminalArgumentsPattern;
} }
void Settings::Environment::setTerminalArgumentsPattern(const TerminalEmulatorArgumentsPattern &argsPattern) void Settings::Environment::setTerminalArgumentsPattern(const QString &argsPattern)
{ {
mTerminalArgumentsPattern = argsPattern; mTerminalArgumentsPattern = argsPattern;
} }
@ -3895,6 +3798,89 @@ void Settings::Environment::setIconZoomFactor(double newIconZoomFactor)
mIconZoomFactor = newIconZoomFactor; mIconZoomFactor = newIconZoomFactor;
} }
QMap<QString, QString> Settings::Environment::predefinedTerminalArgumentsPattern() const
{
return mPredefinedTerminalArgumentsPattern;
}
void Settings::Environment::setPredefinedTerminalArgumentsPattern(const QMap<QString, QString> &newPredefinedTerminalArgumentsPattern)
{
mPredefinedTerminalArgumentsPattern = newPredefinedTerminalArgumentsPattern;
}
std::unique_ptr<QString> Settings::Environment::queryPredefinedTerminalArgumentsPattern(const QString &executable) const
{
auto it = mPredefinedTerminalArgumentsPattern.find(executable);
if (it != mPredefinedTerminalArgumentsPattern.end())
return std::make_unique<QString>(*it);
else
return nullptr;
}
bool Settings::Environment::useCustomTerminal() const
{
return mUseCustomTerminal;
}
void Settings::Environment::setUseCustomTerminal(bool newUseCustomTerminal)
{
mUseCustomTerminal = newUseCustomTerminal;
}
bool Settings::Environment::checkAndSetTerminal(QString terminalPath, QString argsPattern)
{
QStringList patternItems = splitProcessCommand(argsPattern);
if (patternItems.empty() ||
!(patternItems.contains("$argv") || patternItems.contains("$command") || patternItems.contains("$tmpfile")) // program not referenced
)
return false;
// `term` is not referenced ("$argv"),
// or is not directly called ("open -app $term -args $tmpfile"),
// do not check terminal path
if (patternItems[0] != "$term") {
setTerminalPath(terminalPath);
setTerminalArgumentsPattern(argsPattern);
return true;
}
#define DO_CHECK_AND_SET do { \
if (termPathInfo.isFile() && termPathInfo.isReadable() && termPathInfo.isExecutable()) { \
mTerminalPath = terminalPath; \
mTerminalArgumentsPattern = argsPattern; \
return true; \
} \
} while (0)
switch (getPathUnixExecSemantics(terminalPath)) {
case UnixExecSemantics::Absolute: {
QFileInfo termPathInfo(terminalPath);
DO_CHECK_AND_SET;
break;
}
case UnixExecSemantics::RelativeToCwd: {
QDir appDir(pSettings->dirs().appDir());
QString absoluteTerminalPath = appDir.absoluteFilePath(terminalPath);
QFileInfo termPathInfo(absoluteTerminalPath);
DO_CHECK_AND_SET;
break;
}
case UnixExecSemantics::SearchInPath: {
QStringList pathList = getExecutableSearchPaths();
for (const QString &dir: pathList) {
QString absoluteTerminalPath = QDir(dir).absoluteFilePath(terminalPath);
QFileInfo termPathInfo(absoluteTerminalPath);
DO_CHECK_AND_SET;
}
break;
}
}
#undef DO_CHECK_AND_SET
return false;
}
void Settings::Environment::doSave() void Settings::Environment::doSave()
{ {
//Appearance //Appearance
@ -3910,7 +3896,10 @@ void Settings::Environment::doSave()
saveValue("current_folder",mCurrentFolder); saveValue("current_folder",mCurrentFolder);
saveValue("default_open_folder",mDefaultOpenFolder); saveValue("default_open_folder",mDefaultOpenFolder);
saveValue("terminal_path",mTerminalPath); saveValue("terminal_path",mTerminalPath);
saveValue("terminal_arguments_pattern",int(mTerminalArgumentsPattern)); saveValue("terminal_arguments_pattern",mTerminalArgumentsPattern);
#ifdef Q_OS_WINDOWS
saveValue("use_custom_terminal",mUseCustomTerminal);
#endif
saveValue("asyle_path",mAStylePath); saveValue("asyle_path",mAStylePath);
saveValue("hide_non_support_files_file_view",mHideNonSupportFilesInFileView); saveValue("hide_non_support_files_file_view",mHideNonSupportFilesInFileView);

View File

@ -575,8 +575,8 @@ public:
QString AStylePath() const; QString AStylePath() const;
void setAStylePath(const QString &aStylePath); void setAStylePath(const QString &aStylePath);
TerminalEmulatorArgumentsPattern terminalArgumentsPattern() const; QString terminalArgumentsPattern() const;
void setTerminalArgumentsPattern(const TerminalEmulatorArgumentsPattern &argsPattern); void setTerminalArgumentsPattern(const QString &argsPattern);
bool useCustomIconSet() const; bool useCustomIconSet() const;
void setUseCustomIconSet(bool newUseCustomIconSet); void setUseCustomIconSet(bool newUseCustomIconSet);
@ -593,7 +593,22 @@ public:
double iconZoomFactor() const; double iconZoomFactor() const;
void setIconZoomFactor(double newIconZoomFactor); void setIconZoomFactor(double newIconZoomFactor);
QJsonArray availableTerminals() const;
void setAvailableTerminals(const QJsonArray &availableTerminals);
QMap<QString, QString> predefinedTerminalArgumentsPattern() const;
void setPredefinedTerminalArgumentsPattern(const QMap<QString, QString> &newPredefinedTerminalArgumentsPattern);
// it should be `std::optional<QString>`.
// `std::unique_ptr` is a work around for Debian 10, where Qt 5.11 doesnt recognize `CONFIG += c++17`,
// and macOS, where official Qt 5.15 is built against macOS 10.13 and `std::optional` is explicitly disabled.
std::unique_ptr<QString> queryPredefinedTerminalArgumentsPattern(const QString &executable) const;
bool useCustomTerminal() const;
void setUseCustomTerminal(bool newUseCustomTerminal);
private: private:
bool checkAndSetTerminal(QString terminalPath, QString argsPattern);
bool updateTerminalList();
//Appearance //Appearance
QString mTheme; QString mTheme;
@ -609,7 +624,9 @@ public:
QString mDefaultOpenFolder; QString mDefaultOpenFolder;
QString mTerminalPath; QString mTerminalPath;
QString mAStylePath; QString mAStylePath;
TerminalEmulatorArgumentsPattern mTerminalArgumentsPattern; QString mTerminalArgumentsPattern;
QMap<QString, QString> mPredefinedTerminalArgumentsPattern;
bool mUseCustomTerminal;
bool mHideNonSupportFilesInFileView; bool mHideNonSupportFilesInFileView;
bool mOpenFilesInSingleInstance; bool mOpenFilesInSingleInstance;
// _Base interface // _Base interface

View File

@ -22,21 +22,16 @@
#include "../compiler/executablerunner.h" #include "../compiler/executablerunner.h"
#include <QFileDialog> #include <QFileDialog>
#include <QMessageBox>
EnvironmentProgramsWidget::EnvironmentProgramsWidget(const QString& name, const QString& group, QWidget *parent) : EnvironmentProgramsWidget::EnvironmentProgramsWidget(const QString& name, const QString& group, QWidget *parent) :
SettingsWidget(name,group,parent), SettingsWidget(name,group,parent),
ui(new Ui::EnvironmentProgramsWidget) ui(new Ui::EnvironmentProgramsWidget)
{ {
ui->setupUi(this); ui->setupUi(this);
QFont monoFont(DEFAULT_MONO_FONT); ui->labelCmdPreviewResult->setFont(QFont(DEFAULT_MONO_FONT));
ui->rbImplicitSystem->setFont(monoFont); #ifndef Q_OS_WINDOWS
ui->rbMinusEAppendArgs->setFont(monoFont); ui->grpUseCustomTerminal->setCheckable(false);
ui->rbMinusXAppendArgs->setFont(monoFont);
ui->rbMinusMinusAppendArgs->setFont(monoFont);
ui->rbMinusEAppendCommandLine->setFont(monoFont);
ui->rbWriteCommandLineToTempFileThenTempFilename->setFont(monoFont);
#ifndef Q_OS_MACOS
hideMacosSpecificPattern();
#endif #endif
} }
@ -45,68 +40,67 @@ EnvironmentProgramsWidget::~EnvironmentProgramsWidget()
delete ui; delete ui;
} }
void EnvironmentProgramsWidget::hideMacosSpecificPattern() auto EnvironmentProgramsWidget::resolveExecArguments(const QString &terminalPath, const QString &argsPattern)
-> std::tuple<QString, QStringList, std::unique_ptr<QTemporaryFile>>
{ {
ui->rbWriteCommandLineToTempFileThenTempFilename->setVisible(false); QString terminalPathForExec;
ui->rbWriteCommandLineToTempFileThenTempFilename->setEnabled(false); if (getPathUnixExecSemantics(terminalPath) == UnixExecSemantics::RelativeToCwd) {
ui->pbWriteCommandLineToTempFileThenTempFilename->setVisible(false); QDir appDir(pSettings->dirs().appDir());
ui->pbWriteCommandLineToTempFileThenTempFilename->setEnabled(false); terminalPathForExec = appDir.absoluteFilePath(terminalPath);
} else
terminalPathForExec = terminalPath;
QString shell = defaultShell();
QStringList payloadArgs{shell, "-c", "echo hello; sleep 3"};
return wrapCommandForTerminalEmulator(terminalPathForExec, argsPattern, payloadArgs);
} }
void EnvironmentProgramsWidget::testTerminal(const TerminalEmulatorArgumentsPattern &pattern) void EnvironmentProgramsWidget::updateCommandPreview(const QString &terminalPath, const QString &argsPattern)
{ {
auto [filename, arguments, fileOwner] = wrapCommandForTerminalEmulator(ui->txtTerminal->text(), pattern, {defaultShell(), "-c", "echo hello; sleep 3"}); auto [filename, arguments, fileOwner] = resolveExecArguments(terminalPath, argsPattern);
ExecutableRunner runner(filename, arguments, "", nullptr); for (auto &arg : arguments)
runner.start(); arg = escapeArgument(arg, false);
runner.wait();
ui->labelCmdPreviewResult->setText(escapeArgument(filename, true) + " " + arguments.join(' '));
}
void EnvironmentProgramsWidget::autoDetectAndUpdateArgumentsPattern(const QString &terminalPath)
{
const QString &executable = QFileInfo(terminalPath).fileName();
const std::unique_ptr<QString> &pattern = pSettings->environment().queryPredefinedTerminalArgumentsPattern(executable);
if (pattern != nullptr)
ui->txtArgsPattern->setText(*pattern);
else
QMessageBox::warning(nullptr,
QObject::tr("Auto Detection Failed"),
QObject::tr("Failed to detect terminal arguments pattern for “%1”.").arg(executable),
QMessageBox::Ok);
} }
void EnvironmentProgramsWidget::doLoad() void EnvironmentProgramsWidget::doLoad()
{ {
#ifdef Q_OS_WINDOWS
ui->grpUseCustomTerminal->setChecked(pSettings->environment().useCustomTerminal());
#endif
ui->txtTerminal->setText(pSettings->environment().terminalPath()); ui->txtTerminal->setText(pSettings->environment().terminalPath());
switch (pSettings->environment().terminalArgumentsPattern()) { ui->txtArgsPattern->setText(pSettings->environment().terminalArgumentsPattern());
case TerminalEmulatorArgumentsPattern::ImplicitSystem:
ui->rbImplicitSystem->setChecked(true);
break;
case TerminalEmulatorArgumentsPattern::MinusEAppendArgs:
ui->rbMinusEAppendArgs->setChecked(true);
break;
case TerminalEmulatorArgumentsPattern::MinusXAppendArgs:
ui->rbMinusXAppendArgs->setChecked(true);
break;
case TerminalEmulatorArgumentsPattern::MinusMinusAppendArgs:
ui->rbMinusMinusAppendArgs->setChecked(true);
break;
case TerminalEmulatorArgumentsPattern::MinusEAppendCommandLine:
ui->rbMinusEAppendCommandLine->setChecked(true);
break;
case TerminalEmulatorArgumentsPattern::WriteCommandLineToTempFileThenTempFilename:
ui->rbWriteCommandLineToTempFileThenTempFilename->setChecked(true);
break;
}
} }
void EnvironmentProgramsWidget::doSave() void EnvironmentProgramsWidget::doSave()
{ {
#ifdef Q_OS_WINDOWS
pSettings->environment().setUseCustomTerminal(ui->grpUseCustomTerminal->isChecked());
#endif
pSettings->environment().setTerminalPath(ui->txtTerminal->text()); pSettings->environment().setTerminalPath(ui->txtTerminal->text());
if (ui->rbImplicitSystem->isChecked()) pSettings->environment().setTerminalArgumentsPattern(ui->txtArgsPattern->text());
pSettings->environment().setTerminalArgumentsPattern(TerminalEmulatorArgumentsPattern::ImplicitSystem);
if (ui->rbMinusEAppendArgs->isChecked())
pSettings->environment().setTerminalArgumentsPattern(TerminalEmulatorArgumentsPattern::MinusEAppendArgs);
if (ui->rbMinusXAppendArgs->isChecked())
pSettings->environment().setTerminalArgumentsPattern(TerminalEmulatorArgumentsPattern::MinusXAppendArgs);
if (ui->rbMinusMinusAppendArgs->isChecked())
pSettings->environment().setTerminalArgumentsPattern(TerminalEmulatorArgumentsPattern::MinusMinusAppendArgs);
if (ui->rbMinusEAppendCommandLine->isChecked())
pSettings->environment().setTerminalArgumentsPattern(TerminalEmulatorArgumentsPattern::MinusEAppendCommandLine);
if (ui->rbWriteCommandLineToTempFileThenTempFilename->isChecked())
pSettings->environment().setTerminalArgumentsPattern(TerminalEmulatorArgumentsPattern::WriteCommandLineToTempFileThenTempFilename);
pSettings->environment().save(); pSettings->environment().save();
} }
void EnvironmentProgramsWidget::updateIcons(const QSize &) void EnvironmentProgramsWidget::updateIcons(const QSize &)
{ {
pIconsManager->setIcon(ui->btnChooseTerminal,IconsManager::ACTION_FILE_OPEN_FOLDER); pIconsManager->setIcon(ui->btnChooseTerminal,IconsManager::ACTION_FILE_OPEN_FOLDER);
pIconsManager->setIcon(ui->btnAutoDetectArgsPattern,IconsManager::ACTION_EDIT_SEARCH);
pIconsManager->setIcon(ui->btnTest,IconsManager::ACTION_RUN_RUN);
} }
void EnvironmentProgramsWidget::on_btnChooseTerminal_clicked() void EnvironmentProgramsWidget::on_btnChooseTerminal_clicked()
@ -118,64 +112,34 @@ void EnvironmentProgramsWidget::on_btnChooseTerminal_clicked()
tr("All files (%1)").arg(ALL_FILE_WILDCARD)); tr("All files (%1)").arg(ALL_FILE_WILDCARD));
if (!filename.isEmpty() && fileExists(filename) ) { if (!filename.isEmpty() && fileExists(filename) ) {
ui->txtTerminal->setText(filename); ui->txtTerminal->setText(filename);
autoDetectAndUpdateArgumentsPattern(filename);
} }
} }
void EnvironmentProgramsWidget::on_txtTerminal_textChanged(const QString &terminalPath) void EnvironmentProgramsWidget::on_txtTerminal_textChanged(const QString &terminalPath)
{ {
QString terminalPathForExec; const QString &argsPattern = ui->txtArgsPattern->text();
if (getPathUnixExecSemantics(terminalPath) == UnixExecSemantics::RelativeToCwd) { updateCommandPreview(terminalPath, argsPattern);
QDir appDir(pSettings->dirs().appDir());
terminalPathForExec = appDir.absoluteFilePath(terminalPath);
} else
terminalPathForExec = terminalPath;
QString terminalPathEscaped = escapeArgument(terminalPathForExec, true);
QString shell = defaultShell();
QStringList execArgs{shell, "-c", "echo hello; sleep 3"};
auto displayCommand = [this, &execArgs](const TerminalEmulatorArgumentsPattern &pattern) {
auto [filename, arguments, fileOwner] = wrapCommandForTerminalEmulator(ui->txtTerminal->text(), pattern, execArgs);
for (auto &arg : arguments)
arg = escapeArgument(arg, false);
return escapeArgument(filename, true) + " " + arguments.join(' ');
};
ui->rbImplicitSystem->setText(displayCommand(TerminalEmulatorArgumentsPattern::ImplicitSystem));
ui->rbMinusEAppendArgs->setText(displayCommand(TerminalEmulatorArgumentsPattern::MinusEAppendArgs));
ui->rbMinusXAppendArgs->setText(displayCommand(TerminalEmulatorArgumentsPattern::MinusXAppendArgs));
ui->rbMinusMinusAppendArgs->setText(displayCommand(TerminalEmulatorArgumentsPattern::MinusMinusAppendArgs));
ui->rbMinusEAppendCommandLine->setText(displayCommand(TerminalEmulatorArgumentsPattern::MinusEAppendCommandLine));
if (ui->rbWriteCommandLineToTempFileThenTempFilename->isEnabled())
ui->rbWriteCommandLineToTempFileThenTempFilename->setText(displayCommand(TerminalEmulatorArgumentsPattern::WriteCommandLineToTempFileThenTempFilename));
} }
void EnvironmentProgramsWidget::on_pbImplicitSystem_clicked() void EnvironmentProgramsWidget::on_txtArgsPattern_textChanged(const QString &argsPattern)
{ {
testTerminal(TerminalEmulatorArgumentsPattern::ImplicitSystem); const QString &terminalPath = ui->txtTerminal->text();
updateCommandPreview(terminalPath, argsPattern);
} }
void EnvironmentProgramsWidget::on_pbMinusEAppendArgs_clicked() void EnvironmentProgramsWidget::on_btnAutoDetectArgsPattern_clicked()
{ {
testTerminal(TerminalEmulatorArgumentsPattern::MinusEAppendArgs); const QString &terminalPath = ui->txtTerminal->text();
autoDetectAndUpdateArgumentsPattern(terminalPath);
} }
void EnvironmentProgramsWidget::on_pbMinusXAppendArgs_clicked() void EnvironmentProgramsWidget::on_btnTest_clicked()
{ {
testTerminal(TerminalEmulatorArgumentsPattern::MinusXAppendArgs); const QString &terminalPath = ui->txtTerminal->text();
const QString &argsPattern = ui->txtArgsPattern->text();
auto [filename, arguments, fileOwner] = resolveExecArguments(terminalPath, argsPattern);
ExecutableRunner runner(filename, arguments, "", nullptr);
runner.start();
runner.wait();
} }
void EnvironmentProgramsWidget::on_pbMinusMinusAppendArgs_clicked()
{
testTerminal(TerminalEmulatorArgumentsPattern::MinusMinusAppendArgs);
}
void EnvironmentProgramsWidget::on_pbMinusEAppendCommandLine_clicked()
{
testTerminal(TerminalEmulatorArgumentsPattern::MinusEAppendCommandLine);
}
void EnvironmentProgramsWidget::on_pbWriteCommandLineToTempFileThenTempFilename_clicked()
{
testTerminal(TerminalEmulatorArgumentsPattern::WriteCommandLineToTempFileThenTempFilename);
}

View File

@ -31,10 +31,12 @@ class EnvironmentProgramsWidget : public SettingsWidget
public: public:
explicit EnvironmentProgramsWidget(const QString& name, const QString& group, QWidget *parent = nullptr); explicit EnvironmentProgramsWidget(const QString& name, const QString& group, QWidget *parent = nullptr);
~EnvironmentProgramsWidget(); ~EnvironmentProgramsWidget();
void hideMacosSpecificPattern();
private: private:
void testTerminal(const TerminalEmulatorArgumentsPattern &pattern); auto resolveExecArguments(const QString &terminalPath, const QString &argsPatter)
-> std::tuple<QString, QStringList, std::unique_ptr<QTemporaryFile>>;
void updateCommandPreview(const QString &terminalPath, const QString &argsPatter);
void autoDetectAndUpdateArgumentsPattern(const QString &terminalPath);
private: private:
Ui::EnvironmentProgramsWidget *ui; Ui::EnvironmentProgramsWidget *ui;
@ -47,12 +49,9 @@ protected:
private slots: private slots:
void on_btnChooseTerminal_clicked(); void on_btnChooseTerminal_clicked();
void on_txtTerminal_textChanged(const QString &terminalPath); void on_txtTerminal_textChanged(const QString &terminalPath);
void on_pbImplicitSystem_clicked(); void on_txtArgsPattern_textChanged(const QString &argsPattern);
void on_pbMinusEAppendArgs_clicked(); void on_btnAutoDetectArgsPattern_clicked();
void on_pbMinusXAppendArgs_clicked(); void on_btnTest_clicked();
void on_pbMinusMinusAppendArgs_clicked();
void on_pbMinusEAppendCommandLine_clicked();
void on_pbWriteCommandLineToTempFileThenTempFilename_clicked();
}; };
#endif // ENVIRONMENTPROGRAMSWIDGET_H #endif // ENVIRONMENTPROGRAMSWIDGET_H

View File

@ -13,10 +13,36 @@
<property name="windowTitle"> <property name="windowTitle">
<string>Form</string> <string>Form</string>
</property> </property>
<layout class="QGridLayout" name="gridLayout"> <layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QGroupBox" name="grpUseCustomTerminal">
<property name="title">
<string>Use custom terminal</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
<property name="checked">
<bool>true</bool>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="1"> <item row="0" column="1">
<widget class="QLineEdit" name="txtTerminal"/> <widget class="QLineEdit" name="txtTerminal"/>
</item> </item>
<item row="1" column="1">
<widget class="QLineEdit" name="txtArgsPattern">
<property name="text">
<string>$term -e $argv</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="labelArgsPattern">
<property name="text">
<string>Args. pattern</string>
</property>
</widget>
</item>
<item row="0" column="2"> <item row="0" column="2">
<widget class="QToolButton" name="btnChooseTerminal"> <widget class="QToolButton" name="btnChooseTerminal">
<property name="text"> <property name="text">
@ -28,148 +54,59 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="1" column="2">
<widget class="QToolButton" name="btnAutoDetectArgsPattern">
<property name="toolTip">
<string>Auto Detect Terminal Arguments Pattern</string>
</property>
<property name="text">
<string>...</string>
</property>
<property name="icon">
<iconset resource="../icons.qrc">
<normaloff>:/icons/images/newlook24/087-update.png</normaloff>:/icons/images/newlook24/087-update.png</iconset>
</property>
</widget>
</item>
<item row="0" column="0"> <item row="0" column="0">
<widget class="QLabel" name="label"> <widget class="QLabel" name="labelTerminal">
<property name="text"> <property name="text">
<string>Terminal</string> <string>Terminal</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="1" column="0" colspan="3"> <item row="2" column="0">
<widget class="QGroupBox" name="groupBox"> <widget class="QLabel" name="labelCmdPreview">
<property name="title">
<string>Terminal emulator arguments pattern</string>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0">
<widget class="QRadioButton" name="rbImplicitSystem">
<property name="text"> <property name="text">
<string>sh -c &quot;echo hello; sleep 3&quot;</string> <string>Cmd. preview</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="0" column="1"> <item row="2" column="1">
<spacer name="horizontalSpacer"> <widget class="QLabel" name="labelCmdPreviewResult">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="0" column="2">
<widget class="QPushButton" name="pbImplicitSystem">
<property name="text">
<string>Test</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QRadioButton" name="rbMinusEAppendArgs">
<property name="text"> <property name="text">
<string>term -e sh -c &quot;echo hello; sleep 3&quot;</string> <string>term -e sh -c &quot;echo hello; sleep 3&quot;</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="1" column="2">
<widget class="QPushButton" name="pbMinusEAppendArgs">
<property name="text">
<string>Test</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QRadioButton" name="rbMinusXAppendArgs">
<property name="text">
<string>term -x sh -c &quot;echo hello; sleep 3&quot;</string>
</property>
</widget>
</item>
<item row="2" column="2"> <item row="2" column="2">
<widget class="QPushButton" name="pbMinusXAppendArgs"> <widget class="QToolButton" name="btnTest">
<property name="text"> <property name="toolTip">
<string>Test</string> <string>Test Command</string>
</property> </property>
</widget>
</item>
<item row="3" column="0">
<widget class="QRadioButton" name="rbMinusMinusAppendArgs">
<property name="text"> <property name="text">
<string>term -- sh -c &quot;echo hello; sleep 3&quot;</string> <string>...</string>
</property> </property>
</widget> <property name="icon">
</item> <iconset resource="../icons.qrc">
<item row="3" column="2"> <normaloff>:/icons/images/newlook24/069-run.png</normaloff>:/icons/images/newlook24/069-run.png</iconset>
<widget class="QPushButton" name="pbMinusMinusAppendArgs">
<property name="text">
<string>Test</string>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QRadioButton" name="rbMinusEAppendCommandLine">
<property name="text">
<string>term -e &quot;sh -c \&quot;echo hello; sleep 3\&quot;&quot;</string>
</property>
</widget>
</item>
<item row="4" column="2">
<widget class="QPushButton" name="pbMinusEAppendCommandLine">
<property name="text">
<string>Test</string>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QRadioButton" name="rbWriteCommandLineToTempFileThenTempFilename">
<property name="text">
<string>term /tmp/redpanda_XXXXXX.command</string>
</property>
</widget>
</item>
<item row="5" column="2">
<widget class="QPushButton" name="pbWriteCommandLineToTempFileThenTempFilename">
<property name="text">
<string>Test</string>
</property>
</widget>
</item>
<item row="6" column="0" colspan="3">
<widget class="QLabel" name="lExpectedBahavior0">
<property name="text">
<string>On clicking “Test” for the correct pattern, the terminal emulator</string>
</property>
</widget>
</item>
<item row="7" column="0" colspan="3">
<widget class="QLabel" name="lExpectedBahavior1">
<property name="text">
<string>• pops up;</string>
</property>
</widget>
</item>
<item row="8" column="0" colspan="3">
<widget class="QLabel" name="lExpectedBahavior2">
<property name="text">
<string>• shows “hello”; and</string>
</property>
</widget>
</item>
<item row="9" column="0" colspan="3">
<widget class="QLabel" name="lExpectedBahavior3">
<property name="text">
<string>• quits in 3 seconds.</string>
</property> </property>
</widget> </widget>
</item> </item>
</layout> </layout>
</widget> </widget>
</item> </item>
<item row="2" column="2"> <item>
<spacer name="verticalSpacer"> <spacer name="verticalSpacer">
<property name="orientation"> <property name="orientation">
<enum>Qt::Vertical</enum> <enum>Qt::Vertical</enum>

View File

@ -1958,52 +1958,32 @@
<source>All files (%1)</source> <source>All files (%1)</source>
<translation>Todos os arquivos (%1)</translation> <translation>Todos os arquivos (%1)</translation>
</message> </message>
<message>
<source>Terminal emulator arguments pattern</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>sh -c &quot;echo hello; sleep 3&quot;</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Test</source>
<translation type="unfinished">Testar</translation>
</message>
<message> <message>
<source>term -e sh -c &quot;echo hello; sleep 3&quot;</source> <source>term -e sh -c &quot;echo hello; sleep 3&quot;</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<source>term -x sh -c &quot;echo hello; sleep 3&quot;</source> <source>Auto Detect Terminal Arguments Pattern</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<source>term -- sh -c &quot;echo hello; sleep 3&quot;</source> <source>Test Command</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<source>term -e &quot;sh -c \&quot;echo hello; sleep 3\&quot;&quot;</source> <source>$term -e $argv</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<source>On clicking Test for the correct pattern, the terminal emulator</source> <source>Use custom terminal</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<source> pops up;</source> <source>Args. pattern</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<source> shows hello; and</source> <source>Cmd. preview</source>
<translation type="unfinished"></translation>
</message>
<message>
<source> quits in 3 seconds.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>term /tmp/redpanda_XXXXXX.command</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
</context> </context>
@ -7077,6 +7057,14 @@
<source>Replaces lcall/ljmp with acall/ajmp</source> <source>Replaces lcall/ljmp with acall/ajmp</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message>
<source>Auto Detection Failed</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Failed to detect terminal arguments pattern for %1.</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>RegisterModel</name> <name>RegisterModel</name>

View File

@ -2670,103 +2670,74 @@ Are you really want to continue?</oldsource>
<source>Editors share one code parser</source> <source>Editors share one code parser</source>
<translation></translation> <translation></translation>
</message> </message>
</context> </context><context>
<context> <name>EnvironmentProgramsWidget</name>
<name>EnvironmentProgramsWidget</name> <message>
<message>
<location filename="../settingsdialog/environmentprogramswidget.ui" line="14"/> <location filename="../settingsdialog/environmentprogramswidget.ui" line="14"/>
<source>Form</source> <source>Form</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../settingsdialog/environmentprogramswidget.ui" line="23"/> <location filename="../settingsdialog/environmentprogramswidget.ui" line="20"/>
<source>Use custom terminal</source>
<translation>使</translation>
</message>
<message>
<location filename="../settingsdialog/environmentprogramswidget.ui" line="49"/>
<location filename="../settingsdialog/environmentprogramswidget.ui" line="63"/>
<location filename="../settingsdialog/environmentprogramswidget.ui" line="98"/>
<source>...</source> <source>...</source>
<translation>...</translation> <translation>...</translation>
</message> </message>
<message> <message>
<location filename="../settingsdialog/environmentprogramswidget.ui" line="34"/> <location filename="../settingsdialog/environmentprogramswidget.ui" line="81"/>
<source>Cmd. preview</source>
<translation></translation>
</message>
<message>
<location filename="../settingsdialog/environmentprogramswidget.ui" line="60"/>
<source>Auto Detect Terminal Arguments Pattern</source>
<translation></translation>
</message>
<message>
<location filename="../settingsdialog/environmentprogramswidget.ui" line="74"/>
<source>Terminal</source> <source>Terminal</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../settingsdialog/environmentprogramswidget.ui" line="41"/>
<source>Terminal emulator arguments pattern</source>
<translation></translation>
</message>
<message>
<location filename="../settingsdialog/environmentprogramswidget.ui" line="54"/>
<source>sh -c &quot;echo hello; sleep 3&quot;</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../settingsdialog/environmentprogramswidget.ui" line="74"/>
<location filename="../settingsdialog/environmentprogramswidget.ui" line="95"/> <location filename="../settingsdialog/environmentprogramswidget.ui" line="95"/>
<location filename="../settingsdialog/environmentprogramswidget.ui" line="116"/> <source>Test Command</source>
<location filename="../settingsdialog/environmentprogramswidget.ui" line="137"/> <translation></translation>
<location filename="../settingsdialog/environmentprogramswidget.ui" line="158"/> </message>
<location filename="../settingsdialog/environmentprogramswidget.ui" line="179"/> <message>
<source>Test</source> <location filename="../settingsdialog/environmentprogramswidget.ui" line="35"/>
<translation></translation> <source>$term -e $argv</source>
</message> <translation type="unfinished"></translation>
<message> </message>
<message>
<location filename="../settingsdialog/environmentprogramswidget.ui" line="42"/>
<source>Args. pattern</source>
<translation></translation>
</message>
<message>
<location filename="../settingsdialog/environmentprogramswidget.ui" line="88"/> <location filename="../settingsdialog/environmentprogramswidget.ui" line="88"/>
<source>term -e sh -c &quot;echo hello; sleep 3&quot;</source> <source>term -e sh -c &quot;echo hello; sleep 3&quot;</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../settingsdialog/environmentprogramswidget.ui" line="109"/> <location filename="../settingsdialog/environmentprogramswidget.cpp" line="108"/>
<source>term -x sh -c &quot;echo hello; sleep 3&quot;</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../settingsdialog/environmentprogramswidget.ui" line="130"/>
<source>term -- sh -c &quot;echo hello; sleep 3&quot;</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../settingsdialog/environmentprogramswidget.ui" line="151"/>
<source>term -e &quot;sh -c \&quot;echo hello; sleep 3\&quot;&quot;</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../settingsdialog/environmentprogramswidget.ui" line="172"/>
<source>term /tmp/redpanda_XXXXXX.command</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../settingsdialog/environmentprogramswidget.ui" line="186"/>
<source>On clicking Test for the correct pattern, the terminal emulator</source>
<translation> </translation>
</message>
<message>
<location filename="../settingsdialog/environmentprogramswidget.ui" line="193"/>
<source> pops up;</source>
<translation> </translation>
</message>
<message>
<location filename="../settingsdialog/environmentprogramswidget.ui" line="200"/>
<source> shows hello; and</source>
<translation> hello</translation>
</message>
<message>
<location filename="../settingsdialog/environmentprogramswidget.ui" line="207"/>
<source> quits in 3 seconds.</source>
<translation> 3 </translation>
</message>
<message>
<location filename="../settingsdialog/environmentprogramswidget.cpp" line="109"/>
<source>Choose Terminal Program</source> <source>Choose Terminal Program</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../settingsdialog/environmentprogramswidget.cpp" line="59"/> <location filename="../settingsdialog/environmentprogramswidget.cpp" line="110"/>
<source>All files (%1)</source> <source>All files (%1)</source>
<translation> (%1)</translation> <translation> (%1)</translation>
</message> </message>
<message> <message>
<source>All files (*.*)</source> <source>All files (*.*)</source>
<translation type="vanished"> (*.*)</translation> <translation type="vanished"> (*.*)</translation>
</message> </message>
</context> </context>
<context> <context>
<name>EnvironmentShortcutModel</name> <name>EnvironmentShortcutModel</name>
@ -9633,6 +9604,16 @@ Are you really want to continue?</oldsource>
<source>Error when writing file &quot;%1&quot;.</source> <source>Error when writing file &quot;%1&quot;.</source>
<translation>%1</translation> <translation>%1</translation>
</message> </message>
<message>
<location filename="../settingsdialog/environmentprogramswidget.cpp" line="74"/>
<source>Auto Detection Failed</source>
<translation></translation>
</message>
<message>
<location filename="../settingsdialog/environmentprogramswidget.cpp" line="75"/>
<source>Failed to detect terminal arguments pattern for %1.</source>
<translation> %1 </translation>
</message>
</context> </context>
<context> <context>
<name>RegisterModel</name> <name>RegisterModel</name>

View File

@ -1791,52 +1791,32 @@
<source>All files (%1)</source> <source>All files (%1)</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message>
<source>Terminal emulator arguments pattern</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>sh -c &quot;echo hello; sleep 3&quot;</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Test</source>
<translation type="unfinished"></translation>
</message>
<message> <message>
<source>term -e sh -c &quot;echo hello; sleep 3&quot;</source> <source>term -e sh -c &quot;echo hello; sleep 3&quot;</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<source>term -x sh -c &quot;echo hello; sleep 3&quot;</source> <source>Auto Detect Terminal Arguments Pattern</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<source>term -- sh -c &quot;echo hello; sleep 3&quot;</source> <source>Test Command</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<source>term -e &quot;sh -c \&quot;echo hello; sleep 3\&quot;&quot;</source> <source>$term -e $argv</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<source>On clicking Test for the correct pattern, the terminal emulator</source> <source>Use custom terminal</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<source> pops up;</source> <source>Args. pattern</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<source> shows hello; and</source> <source>Cmd. preview</source>
<translation type="unfinished"></translation>
</message>
<message>
<source> quits in 3 seconds.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>term /tmp/redpanda_XXXXXX.command</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
</context> </context>
@ -6602,6 +6582,14 @@
<source>Replaces lcall/ljmp with acall/ajmp</source> <source>Replaces lcall/ljmp with acall/ajmp</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message>
<source>Auto Detection Failed</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Failed to detect terminal arguments pattern for %1.</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>RegisterModel</name> <name>RegisterModel</name>

View File

@ -723,49 +723,51 @@ QString escapeArgument(const QString &arg, [[maybe_unused]] bool isFirstArg)
#endif #endif
} }
auto wrapCommandForTerminalEmulator(const QString &terminal, const TerminalEmulatorArgumentsPattern &argsPattern, const QStringList &argsWithArgv0) auto wrapCommandForTerminalEmulator(const QString &terminal, const QStringList &argsPattern, const QStringList &payloadArgsWithArgv0)
-> std::tuple<QString, QStringList, std::unique_ptr<QTemporaryFile>> -> std::tuple<QString, QStringList, std::unique_ptr<QTemporaryFile>>
{ {
switch (argsPattern) { QStringList wrappedArgs;
case TerminalEmulatorArgumentsPattern::ImplicitSystem: std::unique_ptr<QTemporaryFile> temproryFile;
default: { for (const QString &patternItem : argsPattern) {
return {argsWithArgv0[0], argsWithArgv0.mid(1), nullptr}; if (patternItem == "$term")
} wrappedArgs.push_back(terminal);
case TerminalEmulatorArgumentsPattern::MinusEAppendArgs: { else if (patternItem == "$argv")
return {terminal, QStringList{"-e"} + argsWithArgv0, nullptr}; wrappedArgs.append(payloadArgsWithArgv0);
} else if (patternItem == "$command") {
case TerminalEmulatorArgumentsPattern::MinusXAppendArgs: {
return {terminal, QStringList{"-x"} + argsWithArgv0, nullptr};
}
case TerminalEmulatorArgumentsPattern::MinusMinusAppendArgs: {
return {terminal, QStringList{"--"} + argsWithArgv0, nullptr};
}
case TerminalEmulatorArgumentsPattern::MinusEAppendCommandLine: {
QStringList escapedArgs; QStringList escapedArgs;
for (int i = 0; i < argsWithArgv0.length(); i++) { for (int i = 0; i < payloadArgsWithArgv0.length(); i++) {
auto &arg = argsWithArgv0[i]; auto &arg = payloadArgsWithArgv0[i];
auto escaped = escapeArgument(arg, i == 0); auto escaped = escapeArgument(arg, i == 0);
escapedArgs.append(escaped); escapedArgs.append(escaped);
} }
return {terminal, QStringList{"-e", escapedArgs.join(' ')}, nullptr}; wrappedArgs.push_back(escapedArgs.join(' '));
} } else if (patternItem == "$tmpfile") {
case TerminalEmulatorArgumentsPattern::WriteCommandLineToTempFileThenTempFilename: { temproryFile = std::make_unique<QTemporaryFile>(QDir::tempPath() + "/redpanda_XXXXXX.command");
auto fileOwner = std::make_unique<QTemporaryFile>(QDir::tempPath() + "/redpanda_XXXXXX.command"); if (temproryFile->open()) {
if (fileOwner->open()) {
QStringList escapedArgs; QStringList escapedArgs;
for (int i = 0; i < argsWithArgv0.length(); i++) { for (int i = 0; i < payloadArgsWithArgv0.length(); i++) {
auto &arg = argsWithArgv0[i]; auto &arg = payloadArgsWithArgv0[i];
auto escaped = escapeArgument(arg, i == 0); auto escaped = escapeArgument(arg, i == 0);
escapedArgs.append(escaped); escapedArgs.append(escaped);
} }
fileOwner->write(escapedArgs.join(' ').toUtf8()); temproryFile->write(escapedArgs.join(' ').toUtf8());
fileOwner->write(QString('\n').toUtf8()); temproryFile->write("\n");
fileOwner->flush(); temproryFile->flush();
} QFile(temproryFile->fileName()).setPermissions(QFileDevice::ReadOwner | QFileDevice::WriteOwner | QFileDevice::ExeOwner);
QFile(fileOwner->fileName()).setPermissions(QFileDevice::ReadOwner | QFileDevice::WriteOwner | QFileDevice::ExeOwner);
return {terminal, QStringList{fileOwner->fileName()}, std::move(fileOwner)};
} }
wrappedArgs.push_back(temproryFile->fileName());
} else
wrappedArgs.push_back(patternItem);
} }
if (wrappedArgs.empty())
return {QString(""), QStringList{}, std::move(temproryFile)};
return {wrappedArgs[0], wrappedArgs.mid(1), std::move(temproryFile)};
}
auto wrapCommandForTerminalEmulator(const QString &terminal, const QString &argsPattern, const QStringList &payloadArgsWithArgv0)
-> std::tuple<QString, QStringList, std::unique_ptr<QTemporaryFile>>
{
return wrapCommandForTerminalEmulator(terminal, splitProcessCommand(argsPattern), payloadArgsWithArgv0);
} }
QString defaultShell() QString defaultShell()

View File

@ -121,16 +121,6 @@ enum class UnixExecSemantics {
SearchInPath, SearchInPath,
}; };
enum class TerminalEmulatorArgumentsPattern {
ImplicitSystem = 0, // bash -c "echo hello, world; sleep 3"
MinusEAppendArgs, // term -e bash -c "echo hello, world; sleep 3" # xterm-compatible
MinusXAppendArgs, // term -x bash -c "echo hello, world; sleep 3" # some VTE-based
MinusMinusAppendArgs, // term -- bash -c "echo hello, world; sleep 3" # gnome-terminal, kgx
MinusEAppendCommandLine, // term -e "bash -c \"echo hello, world; sleep 3\"" # some lightweighted; alternative form for VTE-based
WriteCommandLineToTempFileThenTempFilename = 6226700, // macOS Terminal.app and iTerm2.app; 6226700 is how you dial “macOS00”
};
FileType getFileType(const QString& filename); FileType getFileType(const QString& filename);
QStringList splitProcessCommand(const QString& cmd); QStringList splitProcessCommand(const QString& cmd);
@ -189,7 +179,10 @@ QStringList getExecutableSearchPaths();
QString escapeArgument(const QString &arg, bool isFirstArg); QString escapeArgument(const QString &arg, bool isFirstArg);
auto wrapCommandForTerminalEmulator(const QString &terminal, const TerminalEmulatorArgumentsPattern &argsPattern, const QStringList &argsWithArgv0) auto wrapCommandForTerminalEmulator(const QString &terminal, const QStringList &argsPattern, const QStringList &payloadArgsWithArgv0)
-> std::tuple<QString, QStringList, std::unique_ptr<QTemporaryFile>>;
auto wrapCommandForTerminalEmulator(const QString &terminal, const QString &argsPattern, const QStringList &payloadArgsWithArgv0)
-> std::tuple<QString, QStringList, std::unique_ptr<QTemporaryFile>>; -> std::tuple<QString, QStringList, std::unique_ptr<QTemporaryFile>>;
QString defaultShell(); QString defaultShell();