Redesign terminal settings

This commit is contained in:
Roy Qu 2023-09-21 16:31:22 +08:00
parent 9557dd8378
commit 7b5fa255da
8 changed files with 124 additions and 114 deletions

View File

@ -270,7 +270,7 @@ void CompilerManager::run(
} + splitProcessCommand(arguments);
if (pSettings->environment().useCustomTerminal()) {
auto [filename, args, fileOwner] = wrapCommandForTerminalEmulator(
pSettings->environment().terminalPathForExec(),
pSettings->environment().terminalPath(),
pSettings->environment().terminalArgumentsPattern(),
execArgs
);

View File

@ -4,7 +4,7 @@
"terminals": [
{
"name": "UTF-8 compatible Console Host",
"path": "./OpenConsole.exe",
"path": "%*APP_DIR*%/OpenConsole.exe",
"argsPattern": "$term -- $argv"
}
]

View File

@ -3625,6 +3625,7 @@ void Settings::Environment::doLoad()
// check saved terminal path
mTerminalPath = stringValue("terminal_path", "");
mTerminalPath.replace("%*APP_DIR*%",pSettings->dirs().appDir());
mTerminalArgumentsPattern = stringValue("terminal_arguments_pattern", "");
checkAndSetTerminal();
@ -3689,15 +3690,6 @@ QString Settings::Environment::terminalPath() const
return mTerminalPath;
}
QString Settings::Environment::terminalPathForExec() const
{
if (getPathUnixExecSemantics(mTerminalPath) == UnixExecSemantics::RelativeToCwd) {
QDir appDir(pSettings->dirs().appDir());
return appDir.absoluteFilePath(mTerminalPath);
} else
return mTerminalPath;
}
void Settings::Environment::setTerminalPath(const QString &terminalPath)
{
mTerminalPath = terminalPath;
@ -3775,8 +3767,10 @@ void Settings::Environment::setIconZoomFactor(double newIconZoomFactor)
QString Settings::Environment::queryPredefinedTerminalArgumentsPattern(const QString &executable) const
{
QString execName = extractFileName(executable);
for (const TerminalItem& item: loadTerminalList()) {
if (item.terminal.compare(executable,PATH_SENSITIVITY)==0) return item.param;
QString termName = extractFileName(item.terminal);
if (termName.compare(execName,PATH_SENSITIVITY)==0) return item.param;
}
return QString();
}
@ -3793,19 +3787,30 @@ void Settings::Environment::setUseCustomTerminal(bool newUseCustomTerminal)
void Settings::Environment::checkAndSetTerminal()
{
if (!mUseCustomTerminal) return;
if (!mTerminalPath.isEmpty() && !mTerminalArgumentsPattern.isEmpty()) return;
if (isTerminalValid()) return;
QStringList pathList = getExecutableSearchPaths();
QList<TerminalItem> terminalList = loadTerminalList();
for (const QString &dirPath: pathList) {
QDir dir{dirPath};
for (const TerminalItem& termItem:terminalList) {
QString absoluteTerminalPath = dir.absoluteFilePath(termItem.terminal);
for (const TerminalItem& termItem:terminalList) {
QString term=termItem.terminal;
term.replace("%*APP_DIR*%",pSettings->dirs().appDir());
QFileInfo info{term};
QString absoluteTerminalPath;
if (info.isAbsolute()) {
absoluteTerminalPath = info.absoluteFilePath();
if(fileExists(absoluteTerminalPath)) {
mTerminalPath = absoluteTerminalPath;
mTerminalArgumentsPattern = termItem.param;
return;
}
} else {
for (const QString &dirPath: pathList) {
QDir dir{dirPath};
absoluteTerminalPath = dir.absoluteFilePath(termItem.terminal);
if(fileExists(absoluteTerminalPath)) {
mTerminalPath = absoluteTerminalPath;
mTerminalArgumentsPattern = termItem.param;
break;
}
}
}
}
@ -3835,11 +3840,12 @@ QList<Settings::Environment::TerminalItem> Settings::Environment::loadTerminalLi
for (const auto &terminalGroup: terminalListDocument.array()) {
const QJsonArray &terminals = terminalGroup.toObject()["terminals"].toArray();
for (const auto &terminal_: terminals) {
const QJsonObject &terminal = terminal_.toObject();
const QString &path = terminal["path"].toString();
const QString &termExecutable = QFileInfo(path).fileName();
const QString &pattern = terminal["argsPattern"].toString();
const QJsonObject& terminal = terminal_.toObject();
QString path = terminal["path"].toString();
QString termExecutable = QFileInfo(path).fileName();
QString pattern = terminal["argsPattern"].toString();
Settings::Environment::TerminalItem terminalItem;
path.replace("%*APP_DIR*%", pSettings->dirs().appDir());
terminalItem.terminal = path;
terminalItem.param = pattern;
result.append(terminalItem);
@ -3848,6 +3854,36 @@ QList<Settings::Environment::TerminalItem> Settings::Environment::loadTerminalLi
return result;
}
bool Settings::Environment::isTerminalValid()
{
// don't use custom terminal
if (!mUseCustomTerminal) return true;
// terminal patter is empty
if (mTerminalArgumentsPattern.isEmpty()) return false;
QStringList patternItems = splitProcessCommand(mTerminalArgumentsPattern);
if (!(patternItems.contains("$argv")
|| patternItems.contains("$command")
|| patternItems.contains("$tmpfile"))) {
// program not referenced
return false;
}
QFileInfo termPathInfo{mTerminalPath};
if (termPathInfo.isAbsolute()) {
return termPathInfo.exists();
} else {
QStringList pathList = getExecutableSearchPaths();
for (const QString &dirName: pathList) {
QDir dir{dirName};
QString absoluteTerminalPath = dir.absoluteFilePath(mTerminalPath);
QFileInfo absTermPathInfo(absoluteTerminalPath);
if (absTermPathInfo.exists()) return true;
}
}
return false;
}
void Settings::Environment::doSave()
{
//Appearance
@ -3862,7 +3898,10 @@ void Settings::Environment::doSave()
saveValue("current_folder",mCurrentFolder);
saveValue("default_open_folder",mDefaultOpenFolder);
saveValue("terminal_path",mTerminalPath);
QString terminalPath = mTerminalPath;
terminalPath.replace(pSettings->dirs().appDir(), "%*APP_DIR*%");
saveValue("terminal_path",terminalPath);
saveValue("terminal_arguments_pattern",mTerminalArgumentsPattern);
#ifdef Q_OS_WINDOWS
saveValue("use_custom_terminal",mUseCustomTerminal);
@ -6347,3 +6386,50 @@ void Settings::Languages::setNoDebugDirectivesWhenGenerateASM(bool newNoDebugDir
{
mNoDebugDirectivesWhenGenerateASM = newNoDebugDirectivesWhenGenerateASM;
}
std::tuple<QString, QStringList, std::unique_ptr<QTemporaryFile>> wrapCommandForTerminalEmulator(const QString &terminal, const QStringList &argsPattern, const QStringList &payloadArgsWithArgv0)
{
QStringList wrappedArgs;
std::unique_ptr<QTemporaryFile> temproryFile;
for (const QString &patternItem : argsPattern) {
if (patternItem == "$term")
wrappedArgs.append(terminal);
else if (patternItem == "$integrated_term")
wrappedArgs.append(includeTrailingPathDelimiter(pSettings->dirs().appDir())+terminal);
else if (patternItem == "$argv")
wrappedArgs.append(payloadArgsWithArgv0);
else if (patternItem == "$command") {
QStringList escapedArgs;
for (int i = 0; i < payloadArgsWithArgv0.length(); i++) {
auto &arg = payloadArgsWithArgv0[i];
auto escaped = escapeArgument(arg, i == 0);
escapedArgs.append(escaped);
}
wrappedArgs.push_back(escapedArgs.join(' '));
} else if (patternItem == "$tmpfile") {
temproryFile = std::make_unique<QTemporaryFile>(QDir::tempPath() + "/redpanda_XXXXXX.command");
if (temproryFile->open()) {
QStringList escapedArgs;
for (int i = 0; i < payloadArgsWithArgv0.length(); i++) {
auto &arg = payloadArgsWithArgv0[i];
auto escaped = escapeArgument(arg, i == 0);
escapedArgs.append(escaped);
}
temproryFile->write(escapedArgs.join(' ').toUtf8());
temproryFile->write("\n");
temproryFile->flush();
QFile(temproryFile->fileName()).setPermissions(QFileDevice::ReadOwner | QFileDevice::WriteOwner | QFileDevice::ExeOwner);
}
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)};
}
std::tuple<QString, QStringList, std::unique_ptr<QTemporaryFile>> wrapCommandForTerminalEmulator(const QString &terminal, const QString &argsPattern, const QStringList &payloadArgsWithArgv0)
{
return wrapCommandForTerminalEmulator(terminal, splitProcessCommand(argsPattern), payloadArgsWithArgv0);
}

View File

@ -575,7 +575,6 @@ public:
void setIconSet(const QString &newIconSet);
QString terminalPath() const;
QString terminalPathForExec() const;
void setTerminalPath(const QString &terminalPath);
QString AStylePath() const;
@ -610,6 +609,7 @@ public:
QList<TerminalItem> loadTerminalList() const;
private:
bool isTerminalValid();
void checkAndSetTerminal();
//Appearance
@ -1623,6 +1623,10 @@ private:
};
std::tuple<QString, QStringList, std::unique_ptr<QTemporaryFile>> wrapCommandForTerminalEmulator(const QString &terminal, const QStringList &argsPattern, const QStringList &payloadArgsWithArgv0);
std::tuple<QString, QStringList, std::unique_ptr<QTemporaryFile>> wrapCommandForTerminalEmulator(const QString &terminal, const QString &argsPattern, const QStringList &payloadArgsWithArgv0);
extern Settings* pSettings;
#endif // SETTINGS_H

View File

@ -43,16 +43,9 @@ EnvironmentProgramsWidget::~EnvironmentProgramsWidget()
auto EnvironmentProgramsWidget::resolveExecArguments(const QString &terminalPath, const QString &argsPattern)
-> std::tuple<QString, QStringList, std::unique_ptr<QTemporaryFile>>
{
QString terminalPathForExec;
if (getPathUnixExecSemantics(terminalPath) == UnixExecSemantics::RelativeToCwd) {
QDir appDir(pSettings->dirs().appDir());
terminalPathForExec = appDir.absoluteFilePath(terminalPath);
} else
terminalPathForExec = terminalPath;
QString shell = defaultShell();
QStringList payloadArgs{shell, "-c", "echo hello; sleep 3"};
return wrapCommandForTerminalEmulator(terminalPathForExec, argsPattern, payloadArgs);
return wrapCommandForTerminalEmulator(terminalPath, argsPattern, payloadArgs);
}
void EnvironmentProgramsWidget::updateCommandPreview(const QString &terminalPath, const QString &argsPattern)
@ -61,7 +54,7 @@ void EnvironmentProgramsWidget::updateCommandPreview(const QString &terminalPath
for (auto &arg : arguments)
arg = escapeArgument(arg, false);
ui->labelCmdPreviewResult->setText(escapeArgument(filename, true) + " " + arguments.join(' '));
ui->labelCmdPreviewResult->setPlainText(escapeArgument(filename, true) + " " + arguments.join(' '));
}
void EnvironmentProgramsWidget::autoDetectAndUpdateArgumentsPattern(const QString &terminalPath)

View File

@ -82,13 +82,6 @@
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLabel" name="labelCmdPreviewResult">
<property name="text">
<string>term -e sh -c &quot;echo hello; sleep 3&quot;</string>
</property>
</widget>
</item>
<item row="2" column="2">
<widget class="QToolButton" name="btnTest">
<property name="toolTip">
@ -103,6 +96,13 @@
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QPlainTextEdit" name="labelCmdPreviewResult">
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
</item>

View File

@ -590,18 +590,6 @@ QColor alphaBlend(const QColor &lower, const QColor &upper) {
);
}
UnixExecSemantics getPathUnixExecSemantics(const QString &path)
{
QFileInfo pathInfo(path);
if (pathInfo.isRelative()) {
if (path.contains('/'))
return UnixExecSemantics::RelativeToCwd;
else
return UnixExecSemantics::SearchInPath;
} else
return UnixExecSemantics::Absolute;
}
QStringList getExecutableSearchPaths()
{
QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
@ -723,53 +711,6 @@ QString escapeArgument(const QString &arg, [[maybe_unused]] bool isFirstArg)
#endif
}
auto wrapCommandForTerminalEmulator(const QString &terminal, const QStringList &argsPattern, const QStringList &payloadArgsWithArgv0)
-> std::tuple<QString, QStringList, std::unique_ptr<QTemporaryFile>>
{
QStringList wrappedArgs;
std::unique_ptr<QTemporaryFile> temproryFile;
for (const QString &patternItem : argsPattern) {
if (patternItem == "$term")
wrappedArgs.push_back(terminal);
else if (patternItem == "$argv")
wrappedArgs.append(payloadArgsWithArgv0);
else if (patternItem == "$command") {
QStringList escapedArgs;
for (int i = 0; i < payloadArgsWithArgv0.length(); i++) {
auto &arg = payloadArgsWithArgv0[i];
auto escaped = escapeArgument(arg, i == 0);
escapedArgs.append(escaped);
}
wrappedArgs.push_back(escapedArgs.join(' '));
} else if (patternItem == "$tmpfile") {
temproryFile = std::make_unique<QTemporaryFile>(QDir::tempPath() + "/redpanda_XXXXXX.command");
if (temproryFile->open()) {
QStringList escapedArgs;
for (int i = 0; i < payloadArgsWithArgv0.length(); i++) {
auto &arg = payloadArgsWithArgv0[i];
auto escaped = escapeArgument(arg, i == 0);
escapedArgs.append(escaped);
}
temproryFile->write(escapedArgs.join(' ').toUtf8());
temproryFile->write("\n");
temproryFile->flush();
QFile(temproryFile->fileName()).setPermissions(QFileDevice::ReadOwner | QFileDevice::WriteOwner | QFileDevice::ExeOwner);
}
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()
{
#ifdef Q_OS_WINDOWS

View File

@ -115,12 +115,6 @@ enum class ProblemCaseValidateType {
IgnoreSpaces
};
enum class UnixExecSemantics {
Absolute,
RelativeToCwd,
SearchInPath,
};
FileType getFileType(const QString& filename);
QStringList splitProcessCommand(const QString& cmd);
@ -173,18 +167,10 @@ void saveComboHistory(QComboBox* cb,const QString& text);
QColor alphaBlend(const QColor &lower, const QColor &upper);
UnixExecSemantics getPathUnixExecSemantics(const QString &path);
QStringList getExecutableSearchPaths();
QString escapeArgument(const QString &arg, bool isFirstArg);
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>>;
QString defaultShell();
#endif // UTILS_H