Add runner args abstraction and fix shm on macOS/BSD (#134)
* add runner args abstraction to allow different args patterns in various terminal apps; fix macOS shm IPC * extend platform support from Linux to XDG desktop * update build docs for Unix * improve terminal args pattern migration for macOS
This commit is contained in:
parent
18aa239b40
commit
7cf5d21b48
71
BUILD.md
71
BUILD.md
|
@ -198,11 +198,33 @@ To build with VS 2017 or later in Command Prompt:
|
|||
"%JOM%" install
|
||||
```
|
||||
|
||||
# Linux
|
||||
# Linux and Other freedesktop.org-conforming (XDG) Desktop Systems
|
||||
|
||||
- Install gcc and qt5
|
||||
- Optionally install fcitx5-qt for building with static version of Qt
|
||||
- Open `Red_Panda_CPP.pro` with Qt Creator
|
||||
General steps:
|
||||
|
||||
- Install recent version of GCC (≥ 7) or Clang (≥ 6) that supports C++17.
|
||||
- Install Qt 5 (≥ 5.12) Base, SVG and Tools modules, including both libraries and development files.
|
||||
- Optionally install fcitx5-qt for building with static Qt library.
|
||||
- Optionally install Qt Creator for development.
|
||||
|
||||
For build only:
|
||||
|
||||
1. Configure:
|
||||
```bash
|
||||
qmake PREFIX=/usr/local /path/to/src/Red_Panda_CPP.pro
|
||||
```
|
||||
2. Make:
|
||||
```bash
|
||||
make -j$(nproc)
|
||||
```
|
||||
3. Install:
|
||||
```bash
|
||||
sudo make install
|
||||
```
|
||||
|
||||
For development:
|
||||
|
||||
1. Open `Red_Panda_CPP.pro` with Qt Creator
|
||||
|
||||
qmake variables:
|
||||
- `PREFIX`: default to `/usr/local`. It should be set to `/usr` or `/opt/redpanda-cpp` when packaging.
|
||||
|
@ -296,7 +318,7 @@ Enter `RedPandaIDE` to launch RedPanda C++.
|
|||
|
||||
Note that makepkg checks out HEAD of the repo, so any change should be committed before building.
|
||||
|
||||
## AppImage
|
||||
## Linux AppImage
|
||||
|
||||
1. Install dependency: Docker or Podman.
|
||||
|
||||
|
@ -336,9 +358,9 @@ Note that makepkg checks out HEAD of the repo, so any change should be committed
|
|||
|
||||
It is possible to build Red Panda C++ for foreign architectures using targets’ native toolchains with QEMU user space emulation.
|
||||
|
||||
Note: Always run emulated native build **in containers**. Mixing architectures may kill your system.
|
||||
Note: Always run emulated native build **in containers or jails**. Mixing architectures may kill your system.
|
||||
|
||||
For Linux host, install statically linked QEMU user space emulator (package name is likely `qemu-user-static`) and make sure that binfmt support is enabled.
|
||||
For Linux or BSD host, install statically linked QEMU user space emulator (package name is likely `qemu-user-static`) and make sure that binfmt support is enabled.
|
||||
|
||||
For Windows host, Docker and Podman should have QEMU user space emulation enabled. If not,
|
||||
* For Docker:
|
||||
|
@ -350,3 +372,38 @@ For Windows host, Docker and Podman should have QEMU user space emulation enable
|
|||
wsl -d podman-machine-default sudo cp /usr/lib/binfmt.d/qemu-aarch64-static.conf /proc/sys/fs/binfmt_misc/register
|
||||
wsl -d podman-machine-default sudo cp /usr/lib/binfmt.d/qemu-riscv64-static.conf /proc/sys/fs/binfmt_misc/register
|
||||
```
|
||||
|
||||
# macOS
|
||||
|
||||
## Qt.io Qt Library
|
||||
|
||||
Prerequisites:
|
||||
|
||||
0. macOS 10.13 or later.
|
||||
1. Install Xcode Command Line Tools:
|
||||
```zsh
|
||||
xcode-select --install
|
||||
```
|
||||
2. Install Qt with online installer from [Qt.io](https://www.qt.io/download-qt-installer-oss).
|
||||
- Select the library (in _Qt_ group, _Qt 5.15.2_ subgroup, check _macOS_).
|
||||
|
||||
Build:
|
||||
|
||||
1. Set related variables:
|
||||
```bash
|
||||
SRC_DIR="~/redpanda-src"
|
||||
BUILD_DIR="~/redpanda-build"
|
||||
INSTALL_DIR="~/redpanda-pkg"
|
||||
```
|
||||
2. Navigate to build directory:
|
||||
```bash
|
||||
rm -rf "$BUILD_DIR" # optional for clean build
|
||||
mkdir -p "$BUILD_DIR" && cd "$BUILD_DIR"
|
||||
```
|
||||
3. Configure, build and install:
|
||||
```bash
|
||||
~/Qt/5.15.2/clang_64/bin/qmake PREFIX="$INSTALL_DIR" "$SRC_DIR/Red_Panda_CPP.pro"
|
||||
make -j$(sysctl -n hw.logicalcpu)
|
||||
make install
|
||||
~/Qt/5.15.2/clang_64/bin/macdeployqt "$INSTALL_DIR/bin/RedPandaIDE.app"
|
||||
```
|
||||
|
|
72
BUILD_cn.md
72
BUILD_cn.md
|
@ -198,12 +198,33 @@
|
|||
"%JOM%" install
|
||||
```
|
||||
|
||||
# Linux
|
||||
# Linux 和其他符合 freedesktop.org(XDG)规范的桌面系统
|
||||
|
||||
步骤:
|
||||
- 安装 gcc 和 qt5开发相关包
|
||||
- 如果使用静态版本的 Qt 编译,还要安装 fcitx5-qt
|
||||
- 使用qtcreator打开Red_Panda_CPP.pro文件
|
||||
通用步骤:
|
||||
|
||||
- 安装支持 C++17 的 GCC(≥ 7)或 Clang(≥ 6)。
|
||||
- 安装 Qt 5(≥ 5.12)Base、SVG、Tools 模块,包括库和开发文件。
|
||||
- 如果使用静态版本的 Qt 编译,还要安装 fcitx5-qt。
|
||||
- 根据需要,安装 Qt Creator 用于开发。
|
||||
|
||||
仅构建:
|
||||
|
||||
1. 配置:
|
||||
```bash
|
||||
qmake PREFIX=/usr/local /path/to/src/Red_Panda_CPP.pro
|
||||
```
|
||||
2. 构建:
|
||||
```bash
|
||||
make -j$(nproc)
|
||||
```
|
||||
3. 安装:
|
||||
```bash
|
||||
sudo make install
|
||||
```
|
||||
|
||||
开发:
|
||||
|
||||
1. 使用 Qt Creator 打开 `Red_Panda_CPP.pro` 文件。
|
||||
|
||||
qmake 变量:
|
||||
- `PREFIX`:默认值是 `/usr/local`。打包时应该定义为 `/usr` 或 `/opt/redpanda-cpp`。
|
||||
|
@ -297,7 +318,7 @@ Windows 宿主的额外要求:
|
|||
|
||||
注意:makepkg 签出此存储库的 HEAD,因此构建之前务必提交所有变更。
|
||||
|
||||
## AppImage
|
||||
## Linux AppImage
|
||||
|
||||
1. 安装依赖包:Docker 或 Podman。
|
||||
|
||||
|
@ -337,9 +358,9 @@ Windows 宿主的额外要求:
|
|||
|
||||
可以借助 QEMU 用户空间模拟,运行目标架构的本机工具链,来构建小熊猫 C++。
|
||||
|
||||
注意:始终**在容器中**运行模拟本机构建,因为混用不同架构的程序和库可能会损坏系统。
|
||||
注意:始终**在容器或 jail 中**运行模拟本机构建,因为混用不同架构的程序和库可能会损坏系统。
|
||||
|
||||
对于 Linux 宿主,需要安装静态链接的 QEMU 用户空间模拟器(包名通常为 `qemu-user-static`)并确认已经启用 binfmt 支持。
|
||||
对于 Linux 或 BSD 宿主,需要安装静态链接的 QEMU 用户空间模拟器(包名通常为 `qemu-user-static`)并确认已经启用 binfmt 支持。
|
||||
|
||||
对于 Windows 宿主,Docker 和 Podman 应该已经启用了 QEMU 用户空间模拟。如果没有启用,
|
||||
* Docker:
|
||||
|
@ -351,3 +372,38 @@ Windows 宿主的额外要求:
|
|||
wsl -d podman-machine-default sudo cp /usr/lib/binfmt.d/qemu-aarch64-static.conf /proc/sys/fs/binfmt_misc/register
|
||||
wsl -d podman-machine-default sudo cp /usr/lib/binfmt.d/qemu-riscv64-static.conf /proc/sys/fs/binfmt_misc/register
|
||||
```
|
||||
|
||||
# macOS
|
||||
|
||||
## Qt.io 的 Qt 库
|
||||
|
||||
前置条件:
|
||||
|
||||
0. macOS 10.13 或更高版本。
|
||||
1. 安装 Xcode 命令行工具:
|
||||
```bash
|
||||
xcode-select --install
|
||||
```
|
||||
2. 用 [Qt.io](https://www.qt.io/download-qt-installer-oss) 或[镜像站](https://mirrors.sjtug.sjtu.edu.cn/docs/qt)的在线安装器安装 Qt。
|
||||
- 选中 Qt 库(“Qt” 组下的 “Qt 5.15.2” 小组,勾选 “macOS”)。
|
||||
|
||||
构建:
|
||||
|
||||
1. 设置相关变量:
|
||||
```bash
|
||||
SRC_DIR="~/redpanda-src"
|
||||
BUILD_DIR="~/redpanda-build"
|
||||
INSTALL_DIR="~/redpanda-pkg"
|
||||
```
|
||||
2. 定位到构建目录:
|
||||
```bash
|
||||
rm -rf "$BUILD_DIR" # 根据需要进行全新构建
|
||||
mkdir -p "$BUILD_DIR" && cd "$BUILD_DIR"
|
||||
```
|
||||
3. 配置、构建、安装:
|
||||
```bash
|
||||
~/Qt/5.15.2/clang_64/bin/qmake PREFIX="$INSTALL_DIR" "$SRC_DIR/Red_Panda_CPP.pro"
|
||||
make -j$(sysctl -n hw.logicalcpu)
|
||||
make install
|
||||
~/Qt/5.15.2/clang_64/bin/macdeployqt "$INSTALL_DIR/bin/RedPandaIDE.app"
|
||||
```
|
||||
|
|
|
@ -29,10 +29,6 @@ contains(QMAKE_HOST.arch, x86_64):{
|
|||
}
|
||||
|
||||
macos: {
|
||||
# This package needs to be installed via homebrew before we can compile it
|
||||
INCLUDEPATH += \
|
||||
/opt/homebrew/opt/icu4c/include
|
||||
|
||||
QT += gui-private
|
||||
|
||||
ICON = ../macos/RedPandaIDE.icns
|
||||
|
@ -131,6 +127,7 @@ SOURCES += \
|
|||
settingsdialog/editortooltipswidget.cpp \
|
||||
settingsdialog/environmentfolderswidget.cpp \
|
||||
settingsdialog/environmentperformancewidget.cpp \
|
||||
settingsdialog/environmentprogramswidget.cpp \
|
||||
settingsdialog/environmentshortcutwidget.cpp \
|
||||
settingsdialog/executorproblemsetwidget.cpp \
|
||||
settingsdialog/formattergeneralwidget.cpp \
|
||||
|
@ -254,6 +251,7 @@ HEADERS += \
|
|||
settingsdialog/editortooltipswidget.h \
|
||||
settingsdialog/environmentfolderswidget.h \
|
||||
settingsdialog/environmentperformancewidget.h \
|
||||
settingsdialog/environmentprogramswidget.h \
|
||||
settingsdialog/environmentshortcutwidget.h \
|
||||
settingsdialog/executorproblemsetwidget.h \
|
||||
settingsdialog/formattergeneralwidget.h \
|
||||
|
@ -349,6 +347,7 @@ FORMS += \
|
|||
settingsdialog/editortooltipswidget.ui \
|
||||
settingsdialog/environmentfolderswidget.ui \
|
||||
settingsdialog/environmentperformancewidget.ui \
|
||||
settingsdialog/environmentprogramswidget.ui \
|
||||
settingsdialog/environmentshortcutwidget.ui \
|
||||
settingsdialog/executorproblemsetwidget.ui \
|
||||
settingsdialog/formattergeneralwidget.ui \
|
||||
|
@ -469,21 +468,18 @@ win32: {
|
|||
|
||||
unix: {
|
||||
HEADERS += \
|
||||
settingsdialog/formatterpathwidget.h \
|
||||
settingsdialog/environmentprogramswidget.h
|
||||
settingsdialog/formatterpathwidget.h
|
||||
|
||||
SOURCES += \
|
||||
settingsdialog/formatterpathwidget.cpp \
|
||||
settingsdialog/environmentprogramswidget.cpp
|
||||
settingsdialog/formatterpathwidget.cpp
|
||||
|
||||
FORMS += \
|
||||
settingsdialog/formatterpathwidget.ui \
|
||||
settingsdialog/environmentprogramswidget.ui
|
||||
settingsdialog/formatterpathwidget.ui
|
||||
}
|
||||
|
||||
linux: {
|
||||
LIBS+= \
|
||||
-lrt
|
||||
# legacy glibc compatibility -- modern Unices have all components in `libc.so`
|
||||
LIBS += -lrt
|
||||
|
||||
_LINUX_STATIC_IME_PLUGIN = $$(LINUX_STATIC_IME_PLUGIN)
|
||||
equals(_LINUX_STATIC_IME_PLUGIN, "ON") {
|
||||
|
|
|
@ -62,11 +62,13 @@ void AutolinkManager::load()
|
|||
file.write(content);
|
||||
file.close();
|
||||
preFile.close();
|
||||
#elif defined(Q_OS_LINUX)
|
||||
QFile preFile(":/config/autolink-linux.json");
|
||||
#elif defined(Q_OS_MACOS)
|
||||
return;
|
||||
#else // XDG desktop
|
||||
QFile preFile(":/config/autolink-xdg.json");
|
||||
if (!preFile.open(QFile::ReadOnly)) {
|
||||
throw FileError(QObject::tr("Can't open file '%1' for read.")
|
||||
.arg(":/config/autolink-linux.json"));
|
||||
.arg(":/config/autolink-xdg.json"));
|
||||
}
|
||||
QByteArray content=preFile.readAll();
|
||||
if (!file.open(QFile::WriteOnly|QFile::Truncate)) {
|
||||
|
@ -76,8 +78,6 @@ void AutolinkManager::load()
|
|||
file.write(content);
|
||||
file.close();
|
||||
preFile.close();
|
||||
#else
|
||||
return;
|
||||
#endif
|
||||
}
|
||||
if (file.open(QFile::ReadOnly)) {
|
||||
|
|
|
@ -177,9 +177,12 @@ void CompilerInfo::prepareCompilerOptions()
|
|||
sl.append(QPair<QString,QString>("Strong","-strong"));
|
||||
sl.append(QPair<QString,QString>("All","-all"));
|
||||
addOption(CC_CMD_OPT_STACK_PROTECTOR , QObject::tr("Check for stack smashing attacks (-fstack-protector)"), groupName, false, false, true, "-fstack-protector", CompilerOptionType::Choice, sl);
|
||||
#if defined(Q_OS_LINUX) || defined(Q_OS_MACOS)
|
||||
#if defined(Q_OS_UNIX)
|
||||
sl.clear();
|
||||
sl.append(QPair<QString,QString>("Address","address"));
|
||||
# ifdef __aarch64__
|
||||
sl.append(QPair<QString,QString>("Hardware-assisted Address","hwaddress"));
|
||||
# endif
|
||||
sl.append(QPair<QString,QString>("Thread","thread"));
|
||||
sl.append(QPair<QString,QString>("Leak","leak"));
|
||||
sl.append(QPair<QString,QString>("Undefined","undefined"));
|
||||
|
|
|
@ -31,6 +31,9 @@
|
|||
#include <QMessageBox>
|
||||
#include <QUuid>
|
||||
#include "projectcompiler.h"
|
||||
#ifdef Q_OS_MACOS
|
||||
#include <sys/posix_shm.h>
|
||||
#endif
|
||||
|
||||
enum RunProgramFlag {
|
||||
RPF_PAUSE_CONSOLE = 0x0001,
|
||||
|
@ -255,20 +258,32 @@ void CompilerManager::run(
|
|||
#ifdef Q_OS_WIN
|
||||
if (consoleFlag!=0) {
|
||||
QString sharedMemoryId = QUuid::createUuid().toString();
|
||||
QString newArguments = QString(" %1 %2 \"%3\" %4")
|
||||
.arg(consoleFlag)
|
||||
.arg(sharedMemoryId,localizePath(filename)).arg(arguments);
|
||||
|
||||
QString consolePauserPath = includeTrailingPathDelimiter(pSettings->dirs().appDir()) + CONSOLE_PAUSER;
|
||||
QStringList execArgs = QStringList{
|
||||
consolePauserPath,
|
||||
QString::number(consoleFlag),
|
||||
sharedMemoryId,
|
||||
localizePath(filename)
|
||||
} + splitProcessCommand(arguments);
|
||||
auto [filename, args, fileOwner] = wrapCommandForTerminalEmulator(
|
||||
pSettings->environment().terminalPathForExec(),
|
||||
pSettings->environment().terminalArgumentsPattern(),
|
||||
execArgs
|
||||
);
|
||||
//delete when thread finished
|
||||
execRunner = new ExecutableRunner(includeTrailingPathDelimiter(pSettings->dirs().appDir())+CONSOLE_PAUSER,newArguments,workDir);
|
||||
execRunner = new ExecutableRunner(filename, args, workDir);
|
||||
execRunner->setShareMemoryId(sharedMemoryId);
|
||||
mTempFileOwner = std::move(fileOwner);
|
||||
} else {
|
||||
//delete when thread finished
|
||||
execRunner = new ExecutableRunner(filename,arguments,workDir);
|
||||
execRunner = new ExecutableRunner(filename,splitProcessCommand(arguments),workDir);
|
||||
}
|
||||
#else
|
||||
QString newArguments;
|
||||
QStringList execArgs;
|
||||
QString sharedMemoryId = "/r"+QUuid::createUuid().toString(QUuid::StringFormat::Id128);
|
||||
#ifdef Q_OS_MACOS
|
||||
sharedMemoryId = sharedMemoryId.mid(0, PSHMNAMLEN);
|
||||
#endif
|
||||
if (consoleFlag!=0) {
|
||||
QString consolePauserPath=includeTrailingPathDelimiter(pSettings->dirs().appLibexecDir())+"consolepauser";
|
||||
if (!fileExists(consolePauserPath)) {
|
||||
|
@ -280,30 +295,39 @@ void CompilerManager::run(
|
|||
|
||||
}
|
||||
if (redirectInput) {
|
||||
newArguments = QString(" -e \"%1\" %2 %3 \"%4\" \"%5\" %6")
|
||||
.arg(consolePauserPath)
|
||||
.arg(consoleFlag)
|
||||
.arg(sharedMemoryId)
|
||||
.arg(escapeSpacesInString(redirectInputFilename))
|
||||
.arg(localizePath(escapeSpacesInString(filename)))
|
||||
.arg(arguments);
|
||||
execArgs = QStringList{
|
||||
consolePauserPath,
|
||||
QString::number(consoleFlag),
|
||||
sharedMemoryId,
|
||||
redirectInputFilename,
|
||||
localizePath(filename),
|
||||
} + splitProcessCommand(arguments);
|
||||
} else {
|
||||
newArguments = QString(" -e \"%1\" %2 %3 \"%4\" %5")
|
||||
.arg(consolePauserPath)
|
||||
.arg(consoleFlag)
|
||||
.arg(sharedMemoryId,localizePath(escapeSpacesInString(filename))).arg(arguments);
|
||||
execArgs = QStringList{
|
||||
consolePauserPath,
|
||||
QString::number(consoleFlag),
|
||||
sharedMemoryId,
|
||||
localizePath(filename),
|
||||
} + splitProcessCommand(arguments);
|
||||
}
|
||||
} else {
|
||||
newArguments = QString(" -e \"%1\" %2")
|
||||
.arg(localizePath(escapeSpacesInString(filename))).arg(arguments);
|
||||
execArgs = QStringList{
|
||||
localizePath(filename),
|
||||
} + splitProcessCommand(arguments);
|
||||
}
|
||||
execRunner = new ExecutableRunner(pSettings->environment().terminalPathForExec(),newArguments,workDir);
|
||||
auto [filename, args, fileOwner] = wrapCommandForTerminalEmulator(
|
||||
pSettings->environment().terminalPathForExec(),
|
||||
pSettings->environment().terminalArgumentsPattern(),
|
||||
execArgs
|
||||
);
|
||||
execRunner = new ExecutableRunner(filename, args, workDir);
|
||||
execRunner->setShareMemoryId(sharedMemoryId);
|
||||
mTempFileOwner = std::move(fileOwner);
|
||||
#endif
|
||||
execRunner->setStartConsole(true);
|
||||
} else {
|
||||
//delete when thread finished
|
||||
execRunner = new ExecutableRunner(filename,arguments,workDir);
|
||||
execRunner = new ExecutableRunner(filename,splitProcessCommand(arguments),workDir);
|
||||
}
|
||||
if (redirectInput) {
|
||||
execRunner->setRedirectInput(true);
|
||||
|
@ -347,7 +371,7 @@ void CompilerManager::doRunProblem(const QString &filename, const QString &argum
|
|||
if (mRunner!=nullptr) {
|
||||
return;
|
||||
}
|
||||
OJProblemCasesRunner * execRunner = new OJProblemCasesRunner(filename,arguments,workDir,problemCases);
|
||||
OJProblemCasesRunner * execRunner = new OJProblemCasesRunner(filename,splitProcessCommand(arguments),workDir,problemCases);
|
||||
mRunner = execRunner;
|
||||
if (pSettings->executor().enableCaseLimit()) {
|
||||
execRunner->setExecTimeout(pSettings->executor().caseTimeout());
|
||||
|
@ -380,6 +404,7 @@ void CompilerManager::stopRun()
|
|||
mRunner->stop();
|
||||
disconnect(mRunner, &Runner::finished, this ,&CompilerManager::onRunnerTerminated);
|
||||
mRunner=nullptr;
|
||||
mTempFileOwner=nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -395,6 +420,7 @@ void CompilerManager::stopPausing()
|
|||
disconnect(mRunner, &Runner::finished, this ,&CompilerManager::onRunnerTerminated);
|
||||
mRunner->stop();
|
||||
mRunner=nullptr;
|
||||
mTempFileOwner=nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -428,6 +454,7 @@ void CompilerManager::onRunnerTerminated()
|
|||
{
|
||||
QMutexLocker locker(&mRunnerMutex);
|
||||
mRunner=nullptr;
|
||||
mTempFileOwner=nullptr;
|
||||
}
|
||||
|
||||
void CompilerManager::onRunnerPausing()
|
||||
|
@ -438,6 +465,7 @@ void CompilerManager::onRunnerPausing()
|
|||
disconnect(mRunner, &Runner::runErrorOccurred, pMainWindow ,&MainWindow::onRunErrorOccured);
|
||||
connect(this, &CompilerManager::signalStopAllRunners, mRunner, &Runner::stop);
|
||||
mRunner=nullptr;
|
||||
mTempFileOwner=nullptr;
|
||||
}
|
||||
|
||||
void CompilerManager::onCompileIssue(PCompileIssue issue)
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include <QObject>
|
||||
#include <QMutex>
|
||||
#include "qt_utils/utils.h"
|
||||
#include "../utils.h"
|
||||
#include "../common.h"
|
||||
|
||||
class Runner;
|
||||
|
@ -96,6 +97,7 @@ private:
|
|||
int mSyntaxCheckIssueCount;
|
||||
Compiler* mBackgroundSyntaxChecker;
|
||||
Runner* mRunner;
|
||||
TemporaryFileOwner mTempFileOwner;
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
|
||||
QRecursiveMutex mCompileMutex;
|
||||
QRecursiveMutex mBackgroundSyntaxCheckMutex;
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
#ifdef Q_OS_WIN
|
||||
#include <QUuid>
|
||||
#include <windows.h>
|
||||
#elif defined(Q_OS_LINUX)
|
||||
#else
|
||||
#include <sys/mman.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
@ -32,7 +32,7 @@
|
|||
#endif
|
||||
|
||||
|
||||
ExecutableRunner::ExecutableRunner(const QString &filename, const QString &arguments, const QString &workDir
|
||||
ExecutableRunner::ExecutableRunner(const QString &filename, const QStringList &arguments, const QString &workDir
|
||||
,QObject* parent):
|
||||
Runner(filename,arguments,workDir,parent),
|
||||
mRedirectInput(false),
|
||||
|
@ -110,7 +110,7 @@ void ExecutableRunner::run()
|
|||
|
||||
mProcess = std::make_shared<QProcess>();
|
||||
mProcess->setProgram(mFilename);
|
||||
mProcess->setArguments(splitProcessCommand(mArguments));
|
||||
mProcess->setArguments(mArguments);
|
||||
//qDebug()<<splitProcessCommand(mArguments);
|
||||
mProcess->setWorkingDirectory(mWorkDir);
|
||||
QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
|
||||
|
@ -162,7 +162,7 @@ void ExecutableRunner::run()
|
|||
}
|
||||
}
|
||||
}
|
||||
#elif defined(Q_OS_LINUX)
|
||||
#else
|
||||
int BUF_SIZE=1024;
|
||||
char* pBuf=nullptr;
|
||||
int fd_shm = shm_open(mShareMemoryId.toLocal8Bit().data(),O_RDWR | O_CREAT,S_IRWXU);
|
||||
|
@ -214,7 +214,6 @@ void ExecutableRunner::run()
|
|||
}
|
||||
break;
|
||||
}
|
||||
#if defined(Q_OS_WIN) || defined(Q_OS_LINUX)
|
||||
if (mStartConsole && !mPausing && pBuf) {
|
||||
if (strncmp(pBuf,"FINISHED",sizeof("FINISHED"))==0) {
|
||||
#ifdef Q_OS_WIN
|
||||
|
@ -226,7 +225,7 @@ void ExecutableRunner::run()
|
|||
hSharedMemory = INVALID_HANDLE_VALUE;
|
||||
CloseHandle(hSharedMemory);
|
||||
}
|
||||
#elif defined(Q_OS_LINUX)
|
||||
#else
|
||||
if (pBuf) {
|
||||
munmap(pBuf,BUF_SIZE);
|
||||
pBuf = nullptr;
|
||||
|
@ -240,14 +239,13 @@ void ExecutableRunner::run()
|
|||
emit pausingForFinish();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#ifdef Q_OS_WIN
|
||||
if (pBuf)
|
||||
UnmapViewOfFile(pBuf);
|
||||
if (hSharedMemory!=INVALID_HANDLE_VALUE && hSharedMemory!=NULL)
|
||||
CloseHandle(hSharedMemory);
|
||||
#elif defined(Q_OS_LINUX)
|
||||
#else
|
||||
if (pBuf) {
|
||||
munmap(pBuf,BUF_SIZE);
|
||||
}
|
||||
|
|
|
@ -25,7 +25,7 @@ class ExecutableRunner : public Runner
|
|||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
ExecutableRunner(const QString& filename, const QString& arguments, const QString& workDir,
|
||||
ExecutableRunner(const QString& filename, const QStringList& arguments, const QString& workDir,
|
||||
QObject* parent = nullptr);
|
||||
ExecutableRunner(const ExecutableRunner&)=delete;
|
||||
ExecutableRunner& operator=(const ExecutableRunner&)=delete;
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
#endif
|
||||
|
||||
|
||||
OJProblemCasesRunner::OJProblemCasesRunner(const QString& filename, const QString& arguments, const QString& workDir,
|
||||
OJProblemCasesRunner::OJProblemCasesRunner(const QString& filename, const QStringList& arguments, const QString& workDir,
|
||||
const QVector<POJProblemCase>& problemCases, QObject *parent):
|
||||
Runner(filename,arguments,workDir,parent),
|
||||
mExecTimeout(0),
|
||||
|
@ -37,7 +37,7 @@ OJProblemCasesRunner::OJProblemCasesRunner(const QString& filename, const QStrin
|
|||
setWaitForFinishTime(100);
|
||||
}
|
||||
|
||||
OJProblemCasesRunner::OJProblemCasesRunner(const QString& filename, const QString& arguments, const QString& workDir,
|
||||
OJProblemCasesRunner::OJProblemCasesRunner(const QString& filename, const QStringList& arguments, const QString& workDir,
|
||||
POJProblemCase problemCase, QObject *parent):
|
||||
Runner(filename,arguments,workDir,parent),
|
||||
mExecTimeout(0),
|
||||
|
@ -64,7 +64,7 @@ void OJProblemCasesRunner::runCase(int index,POJProblemCase problemCase)
|
|||
QElapsedTimer elapsedTimer;
|
||||
bool execTimeouted = false;
|
||||
process.setProgram(mFilename);
|
||||
process.setArguments(splitProcessCommand(mArguments));
|
||||
process.setArguments(mArguments);
|
||||
process.setWorkingDirectory(mWorkDir);
|
||||
QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
|
||||
QString path = env.value("PATH");
|
||||
|
|
|
@ -25,10 +25,10 @@ class OJProblemCasesRunner : public Runner
|
|||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit OJProblemCasesRunner(const QString& filename, const QString& arguments, const QString& workDir,
|
||||
explicit OJProblemCasesRunner(const QString& filename, const QStringList& arguments, const QString& workDir,
|
||||
const QVector<POJProblemCase>& problemCases,
|
||||
QObject *parent = nullptr);
|
||||
explicit OJProblemCasesRunner(const QString& filename, const QString& arguments, const QString& workDir,
|
||||
explicit OJProblemCasesRunner(const QString& filename, const QStringList& arguments, const QString& workDir,
|
||||
POJProblemCase problemCase,
|
||||
QObject *parent = nullptr);
|
||||
OJProblemCasesRunner(const OJProblemCasesRunner&)=delete;
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
#include "runner.h"
|
||||
#include <QDebug>
|
||||
|
||||
Runner::Runner(const QString &filename, const QString &arguments, const QString &workDir
|
||||
Runner::Runner(const QString &filename, const QStringList &arguments, const QString &workDir
|
||||
,QObject *parent) : QThread(parent),
|
||||
mPausing(false),
|
||||
mStop(false),
|
||||
|
|
|
@ -23,7 +23,7 @@ class Runner : public QThread
|
|||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit Runner(const QString& filename, const QString& arguments, const QString& workDir, QObject *parent = nullptr);
|
||||
explicit Runner(const QString& filename, const QStringList& arguments, const QString& workDir, QObject *parent = nullptr);
|
||||
Runner(const Runner&)=delete;
|
||||
Runner operator=(const Runner&)=delete;
|
||||
|
||||
|
@ -48,7 +48,7 @@ protected:
|
|||
bool mPausing;
|
||||
bool mStop;
|
||||
QString mFilename;
|
||||
QString mArguments;
|
||||
QStringList mArguments; // without argv[0]
|
||||
QString mWorkDir;
|
||||
int mWaitForFinishTime;
|
||||
};
|
||||
|
|
|
@ -2,6 +2,6 @@
|
|||
<qresource prefix="/config">
|
||||
<file alias="autolink.json">resources/autolink.json</file>
|
||||
<file alias="codesnippets.json">resources/codesnippets.json</file>
|
||||
<file alias="autolink-linux.json">resources/autolink-linux.json</file>
|
||||
<file alias="autolink-xdg.json">resources/autolink-xdg.json</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
|
|
@ -248,6 +248,23 @@ int main(int argc, char *argv[])
|
|||
qputenv("QT_QPA_PLATFORM", "windows:darkmode=2");
|
||||
#endif
|
||||
|
||||
#ifdef Q_OS_MACOS
|
||||
// in macOS GUI apps, `/usr/local/bin` is not in PATH by default
|
||||
// follow the Unix way by prepending it to `/usr/bin`
|
||||
{
|
||||
QStringList pathList = getExecutableSearchPaths();
|
||||
if (!pathList.contains("/usr/local/bin")) {
|
||||
auto idxUsrBin = pathList.indexOf("/usr/bin");
|
||||
if (idxUsrBin >= 0)
|
||||
pathList.insert(idxUsrBin, "/usr/local/bin");
|
||||
else
|
||||
pathList.append("/usr/local/bin");
|
||||
}
|
||||
QString newPath = pathList.join(PATH_SEPARATOR);
|
||||
qputenv("PATH", newPath.toUtf8());
|
||||
}
|
||||
#endif
|
||||
|
||||
QApplication app(argc, argv);
|
||||
|
||||
app.setAttribute(Qt::AA_UseHighDpiPixmaps);
|
||||
|
|
|
@ -1,4 +1,12 @@
|
|||
[
|
||||
{
|
||||
"header": "fmt/core.h",
|
||||
"links": "-lfmt"
|
||||
},
|
||||
{
|
||||
"header": "math.h",
|
||||
"links": "-lm"
|
||||
},
|
||||
{
|
||||
"execUseUTF8": true,
|
||||
"header": "raylib.h",
|
||||
|
@ -11,5 +19,13 @@
|
|||
{
|
||||
"header": "rturtle.h",
|
||||
"links": "-lrturtle"
|
||||
},
|
||||
{
|
||||
"header": "thread",
|
||||
"links": "-lpthread"
|
||||
},
|
||||
{
|
||||
"header": "threads.h",
|
||||
"links": "-lpthread"
|
||||
}
|
||||
]
|
|
@ -203,13 +203,13 @@ QString Settings::Dirs::appResourceDir() const
|
|||
{
|
||||
#ifdef Q_OS_WIN
|
||||
return appDir();
|
||||
#elif defined(Q_OS_LINUX)
|
||||
// in AppImage PREFIX is not true, resolve from relative path
|
||||
const static QString absoluteResourceDir(QDir(appDir()).absoluteFilePath("../share/" APP_NAME));
|
||||
return absoluteResourceDir;
|
||||
#elif defined(Q_OS_MACOS)
|
||||
// return QApplication::instance()->applicationDirPath();
|
||||
return "";
|
||||
#else // XDG desktop
|
||||
// in AppImage or tarball PREFIX is not true, resolve from relative path
|
||||
const static QString absoluteResourceDir(QDir(appDir()).absoluteFilePath("../share/" APP_NAME));
|
||||
return absoluteResourceDir;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -218,13 +218,13 @@ QString Settings::Dirs::appLibexecDir() const
|
|||
{
|
||||
#ifdef Q_OS_WIN
|
||||
return appDir();
|
||||
#elif defined(Q_OS_LINUX)
|
||||
// in AppImage LIBEXECDIR is not true, resolve from relative path
|
||||
#elif defined(Q_OS_MACOS)
|
||||
return QApplication::instance()->applicationDirPath();
|
||||
#else // XDG desktop
|
||||
// in AppImage or tarball LIBEXECDIR is not true, resolve from relative path
|
||||
const static QString relativeLibExecDir(QDir(PREFIX "/bin").relativeFilePath(LIBEXECDIR "/" APP_NAME));
|
||||
const static QString absoluteLibExecDir(QDir(appDir()).absoluteFilePath(relativeLibExecDir));
|
||||
return absoluteLibExecDir;
|
||||
#elif defined(Q_OS_MACOS)
|
||||
return QApplication::instance()->applicationDirPath();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -1473,16 +1473,16 @@ void Settings::Editor::doLoad()
|
|||
mRightEdgeLineColor = colorValue("right_edge_line_color",Qt::yellow);
|
||||
|
||||
//Editor font
|
||||
#ifdef Q_OS_WIN
|
||||
mFontName = stringValue("font_name","consolas");
|
||||
mNonAsciiFontName = stringValue("non_ascii_font_name","consolas");
|
||||
#elif defined(Q_OS_MACOS)
|
||||
mFontName = stringValue("font_name","Menlo");
|
||||
mNonAsciiFontName = stringValue("non_ascii_font_name","PingFang SC");
|
||||
#else
|
||||
mFontName = stringValue("font_name","Dejavu Sans Mono");
|
||||
mNonAsciiFontName = stringValue("non_ascii_font_name","Dejavu Sans Mono");
|
||||
#endif
|
||||
mFontName = stringValue("font_name",DEFAULT_MONO_FONT);
|
||||
QString defaultCjkFontName = CJK_MONO_FONT_SC;
|
||||
QString defaultLocaleName = QLocale::system().name();
|
||||
if (defaultLocaleName == "zh_TW")
|
||||
defaultCjkFontName = CJK_MONO_FONT_TC;
|
||||
else if (defaultLocaleName == "ja_JP")
|
||||
defaultCjkFontName = CJK_MONO_FONT_J;
|
||||
else if (defaultLocaleName == "ko_KR")
|
||||
defaultCjkFontName = CJK_MONO_FONT_K;
|
||||
mNonAsciiFontName = stringValue("non_ascii_font_name",defaultCjkFontName);
|
||||
mFontSize = intValue("font_size",12);
|
||||
mFontOnlyMonospaced = boolValue("font_only_monospaced",true);
|
||||
mLineSpacing = doubleValue("line_spacing",1.0);
|
||||
|
@ -1504,11 +1504,7 @@ void Settings::Editor::doLoad()
|
|||
mGutterLineNumbersStartZero = boolValue("gutter_line_numbers_start_zero",false);
|
||||
mGutterUseCustomFont = boolValue("gutter_use_custom_font",false);
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
mGutterFontName = stringValue("gutter_font_name","consolas");
|
||||
#else
|
||||
mGutterFontName = stringValue("gutter_font_name","Dejavu Sans Mono");
|
||||
#endif
|
||||
mGutterFontName = stringValue("gutter_font_name",DEFAULT_MONO_FONT);
|
||||
mGutterFontSize = intValue("gutter_font_size",12);
|
||||
mGutterFontOnlyMonospaced = boolValue("gutter_font_only_monospaced",true);
|
||||
|
||||
|
@ -2999,11 +2995,11 @@ static void setDebugOptions(Settings::PCompilerSet pSet, bool enableAsan = false
|
|||
pSet->setCompileOption(CC_CMD_OPT_USE_PIPE, COMPILER_OPTION_ON);
|
||||
|
||||
if (enableAsan) {
|
||||
#ifdef __aarch64__
|
||||
pSet->setCompileOption(CC_CMD_OPT_ADDRESS_SANITIZER, "hwaddress");
|
||||
#else
|
||||
pSet->setCompileOption(CC_CMD_OPT_ADDRESS_SANITIZER, "address");
|
||||
// pSet->setCustomCompileParams("-fsanitize=address");
|
||||
// pSet->setUseCustomCompileParams(true);
|
||||
// pSet->setCustomLinkParams("-fsanitize=address");
|
||||
// pSet->setUseCustomLinkParams(true);
|
||||
#endif
|
||||
}
|
||||
//Some windows gcc don't correctly support this
|
||||
//pSet->setCompileOption(CC_CMD_OPT_STACK_PROTECTOR, "-strong");
|
||||
|
@ -3064,8 +3060,8 @@ bool Settings::CompilerSets::addSets(const QString &folder, const QString& c_pro
|
|||
}
|
||||
|
||||
#ifdef Q_OS_LINUX
|
||||
# if defined(__x86_64__) || __SIZEOF_POINTER__ == 4
|
||||
mDefaultIndex = (int)mList.size() - 1; // x86-64 Linux or 32-bit Unix, default to "debug with ASan"
|
||||
# if defined(__x86_64__) || defined(__aarch64__) || __SIZEOF_POINTER__ == 4
|
||||
mDefaultIndex = (int)mList.size() - 1; // x86-64, AArch64 Linux or 32-bit Unix, default to "debug with ASan"
|
||||
# else
|
||||
mDefaultIndex = (int)mList.size() - 2; // other Unix, where ASan can be very slow, default to "debug"
|
||||
# endif
|
||||
|
@ -3576,17 +3572,20 @@ void Settings::Environment::doLoad()
|
|||
{
|
||||
//Appearance
|
||||
mTheme = stringValue("theme","dark");
|
||||
QString defaultFontName = "Segoe UI";
|
||||
QString defaultFontName = DEFAULT_UI_FONT;
|
||||
QString defaultLocaleName = QLocale::system().name();
|
||||
if (defaultLocaleName == "zh_CN") {
|
||||
{
|
||||
QString fontName;
|
||||
#ifdef Q_OS_WINDOWS
|
||||
fontName = "Microsoft Yahei";
|
||||
#elif defined(Q_OS_MACOS)
|
||||
fontName = "PingFang SC";
|
||||
#elif defined(Q_OS_LINUX)
|
||||
fontName = "Noto Sans CJK";
|
||||
#endif
|
||||
if (defaultLocaleName == "zh_CN")
|
||||
fontName = CJK_UI_FONT_SC;
|
||||
else if (defaultLocaleName == "zh_TW")
|
||||
fontName = CJK_UI_FONT_TC;
|
||||
else if (defaultLocaleName == "ja_JP")
|
||||
fontName = CJK_UI_FONT_J;
|
||||
else if (defaultLocaleName == "ko_KR")
|
||||
fontName = CJK_UI_FONT_K;
|
||||
else
|
||||
fontName = DEFAULT_UI_FONT;
|
||||
QFont font(fontName);
|
||||
if (font.exactMatch()) {
|
||||
defaultFontName = fontName;
|
||||
|
@ -3608,58 +3607,85 @@ void Settings::Environment::doLoad()
|
|||
if (!fileExists(mDefaultOpenFolder)) {
|
||||
mDefaultOpenFolder = QDir::currentPath();
|
||||
}
|
||||
#ifdef Q_OS_LINUX
|
||||
|
||||
#define SYSTEM_TERMINAL(term) "/usr/bin/" #term, "/usr/local/bin/" #term
|
||||
const static QString terminals[] {
|
||||
using AP = TerminalEmulatorArgumentsPattern;
|
||||
struct TerminalSearchItem {
|
||||
QString appName;
|
||||
AP argsPattern;
|
||||
};
|
||||
|
||||
#ifdef Q_OS_WINDOWS
|
||||
const TerminalSearchItem terminals[] {
|
||||
/* explicitly installed terminals */
|
||||
|
||||
/* system */
|
||||
{"conhost.exe", AP::ImplicitSystem}, // dummy for system default
|
||||
|
||||
/* will not actually be searched, just a list for users who dig into here */
|
||||
{"conhost.exe", AP::MinusMinusAppendArgs}, // yes, it accepts GNU-style (--) arguments
|
||||
{"wt.exe", AP::MinusMinusAppendArgs}, // generally okay, but “Test” does not work
|
||||
{"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 */
|
||||
SYSTEM_TERMINAL(alacritty), // GPU-accelerated
|
||||
SYSTEM_TERMINAL(kitty), // GPU-accelerated
|
||||
SYSTEM_TERMINAL(wayst), // GPU-accelerated
|
||||
SYSTEM_TERMINAL(tilix), // tiling
|
||||
SYSTEM_TERMINAL(cool-retro-term), // old CRT style
|
||||
{"alacritty", AP::MinusEAppendArgs}, // GPU-accelerated
|
||||
{"kitty", AP::MinusEAppendArgs}, // GPU-accelerated
|
||||
{"wayst", AP::MinusEAppendArgs}, // GPU-accelerated
|
||||
|
||||
/* default terminal for DE */
|
||||
SYSTEM_TERMINAL(konsole), // KDE
|
||||
SYSTEM_TERMINAL(deepin-terminal), // DDE
|
||||
SYSTEM_TERMINAL(qterminal), // LXQt
|
||||
SYSTEM_TERMINAL(lxterminal), // LXDE
|
||||
{"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",
|
||||
{"./alacritty", AP::MinusEAppendArgs},
|
||||
|
||||
/* compatible, with minor issue */
|
||||
SYSTEM_TERMINAL(kgx), // GNOME Console, confirm to quit
|
||||
SYSTEM_TERMINAL(coreterminal), // not so conforming when parsing args
|
||||
SYSTEM_TERMINAL(sakura), // not so conforming when parsing args
|
||||
{"kgx", AP::MinusMinusAppendArgs}, // GNOME Console, confirm to quit
|
||||
|
||||
/* compatible, without out-of-box hidpi support */
|
||||
SYSTEM_TERMINAL(mlterm),
|
||||
SYSTEM_TERMINAL(st),
|
||||
SYSTEM_TERMINAL(terminology), // also not so conforming when parsing args
|
||||
SYSTEM_TERMINAL(urxvt),
|
||||
SYSTEM_TERMINAL(xterm),
|
||||
SYSTEM_TERMINAL(zutty),
|
||||
/* 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 */
|
||||
SYSTEM_TERMINAL(foot), // Wayland only
|
||||
SYSTEM_TERMINAL(x-terminal-emulator), // Debian alternatives
|
||||
{"foot", AP::MinusEAppendArgs}, // Wayland only
|
||||
|
||||
/* parameter incompatible */
|
||||
// "gnome-terminal",
|
||||
// "guake",
|
||||
// "hyper",
|
||||
// "io.elementary.terminal",
|
||||
// "kermit",
|
||||
// "liri-terminal",
|
||||
// "mate-terminal",
|
||||
// "roxterm",
|
||||
// "station",
|
||||
// "terminator",
|
||||
// "termite",
|
||||
// "tilda",
|
||||
// "xfce4-terminal",
|
||||
// "yakuake",
|
||||
// "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
|
||||
|
@ -3667,22 +3693,57 @@ void Settings::Environment::doLoad()
|
|||
// "rxvt", // no unicode support
|
||||
// "shellinabox", // AUR broken, unable to test
|
||||
};
|
||||
#undef SYSTEM_TERMINAL
|
||||
#endif
|
||||
|
||||
auto checkAndSetTerminalPath = [this](QString terminalPath) -> bool {
|
||||
QDir appDir(pSettings->dirs().appDir());
|
||||
QString absoluteTerminalPath = appDir.absoluteFilePath(terminalPath);
|
||||
QFileInfo termPathInfo(absoluteTerminalPath);
|
||||
if (termPathInfo.isFile() && termPathInfo.isReadable() && termPathInfo.isExecutable()) {
|
||||
mTerminalPath = terminalPath;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
auto checkAndSetTerminalPath = [this](const TerminalSearchItem &searchItem) -> bool {
|
||||
#define DO_CHECK_AND_SET do { \
|
||||
if (termPathInfo.isFile() && termPathInfo.isReadable() && termPathInfo.isExecutable()) { \
|
||||
mTerminalPath = searchItem.appName; \
|
||||
mTerminalArgumentsPattern = searchItem.argsPattern; \
|
||||
return true; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
switch (getPathUnixExecSemantics(searchItem.appName)) {
|
||||
case UnixExecSemantics::Absolute: {
|
||||
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: {
|
||||
auto pathList = getExecutableSearchPaths();
|
||||
for (auto &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
|
||||
if (!checkAndSetTerminalPath(stringValue("terminal_path", ""))) {
|
||||
QString savedTerminalPath = stringValue("terminal_path", "");
|
||||
int savedArgsPattern_ = intValue("terminal_arguments_pattern",
|
||||
#ifdef Q_OS_MACOS
|
||||
// macOS: old versions have set Terminal.app as default terminal
|
||||
// fallback to temp file to work with Terminal.app for smooth migration
|
||||
int(AP::WriteCommandLineToTempFileThenTempFilename)
|
||||
#else
|
||||
int(AP::MinusEAppendArgs) // Linux: keep old behaviour
|
||||
#endif
|
||||
);
|
||||
AP savedArgsPattern = static_cast<AP>(savedArgsPattern_);
|
||||
if (!checkAndSetTerminalPath(TerminalSearchItem{savedTerminalPath, savedArgsPattern})) {
|
||||
// if saved terminal path is invalid, try determing terminal from our list
|
||||
for (auto terminal: terminals) {
|
||||
if (checkAndSetTerminalPath(terminal))
|
||||
|
@ -3691,11 +3752,6 @@ void Settings::Environment::doLoad()
|
|||
}
|
||||
|
||||
mAStylePath = includeTrailingPathDelimiter(pSettings->dirs().appLibexecDir())+"astyle";
|
||||
#elif defined(Q_OS_MACOS)
|
||||
mTerminalPath = stringValue("terminal_path",
|
||||
"/System/Applications/Utilities/Terminal.app/Contents/MacOS/Terminal");
|
||||
mAStylePath = includeTrailingPathDelimiter(pSettings->dirs().appLibexecDir())+"astyle";
|
||||
#endif
|
||||
mHideNonSupportFilesInFileView=boolValue("hide_non_support_files_file_view",true);
|
||||
mOpenFilesInSingleInstance = boolValue("open_files_in_single_instance",false);
|
||||
}
|
||||
|
@ -3757,13 +3813,11 @@ QString Settings::Environment::terminalPath() const
|
|||
|
||||
QString Settings::Environment::terminalPathForExec() const
|
||||
{
|
||||
#ifdef Q_OS_LINUX
|
||||
// `mTerminalPath` can be reletive (bundled terminal in AppImage).
|
||||
QDir appDir(pSettings->dirs().appDir());
|
||||
return appDir.absoluteFilePath(mTerminalPath);
|
||||
#else
|
||||
return mTerminalPath;
|
||||
#endif
|
||||
if (getPathUnixExecSemantics(mTerminalPath) == UnixExecSemantics::RelativeToCwd) {
|
||||
QDir appDir(pSettings->dirs().appDir());
|
||||
return appDir.absoluteFilePath(mTerminalPath);
|
||||
} else
|
||||
return mTerminalPath;
|
||||
}
|
||||
|
||||
void Settings::Environment::setTerminalPath(const QString &terminalPath)
|
||||
|
@ -3781,6 +3835,16 @@ void Settings::Environment::setAStylePath(const QString &aStylePath)
|
|||
mAStylePath = aStylePath;
|
||||
}
|
||||
|
||||
TerminalEmulatorArgumentsPattern Settings::Environment::terminalArgumentsPattern() const
|
||||
{
|
||||
return mTerminalArgumentsPattern;
|
||||
}
|
||||
|
||||
void Settings::Environment::setTerminalArgumentsPattern(const TerminalEmulatorArgumentsPattern &argsPattern)
|
||||
{
|
||||
mTerminalArgumentsPattern = argsPattern;
|
||||
}
|
||||
|
||||
bool Settings::Environment::useCustomIconSet() const
|
||||
{
|
||||
return mUseCustomIconSet;
|
||||
|
@ -3845,10 +3909,9 @@ void Settings::Environment::doSave()
|
|||
|
||||
saveValue("current_folder",mCurrentFolder);
|
||||
saveValue("default_open_folder",mDefaultOpenFolder);
|
||||
#ifndef Q_OS_WIN
|
||||
saveValue("terminal_path",mTerminalPath);
|
||||
saveValue("terminal_arguments_pattern",int(mTerminalArgumentsPattern));
|
||||
saveValue("asyle_path",mAStylePath);
|
||||
#endif
|
||||
|
||||
saveValue("hide_non_support_files_file_view",mHideNonSupportFilesInFileView);
|
||||
saveValue("open_files_in_single_instance",mOpenFilesInSingleInstance);
|
||||
|
@ -4111,13 +4174,7 @@ void Settings::Executor::doLoad()
|
|||
mProblemCaseValidateType =(ProblemCaseValidateType)intValue("problem_case_validate_type", (int)ProblemCaseValidateType::Exact);
|
||||
mRedirectStderrToToolLog = boolValue("redirect_stderr_to_toollog", false);
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
mCaseEditorFontName = stringValue("case_editor_font_name","consolas");
|
||||
#elif defined(Q_OS_MACOS)
|
||||
mCaseEditorFontName = stringValue("case_editor_font_name", "Menlo");
|
||||
#else
|
||||
mCaseEditorFontName = stringValue("case_editor_font_name","Dejavu Sans Mono");
|
||||
#endif
|
||||
mCaseEditorFontName = stringValue("case_editor_font_name",DEFAULT_MONO_FONT);
|
||||
mCaseEditorFontSize = intValue("case_editor_font_size",11);
|
||||
mCaseEditorFontOnlyMonospaced = boolValue("case_editor_font_only_monospaced",true);
|
||||
int case_timeout = intValue("case_timeout", -1);
|
||||
|
|
|
@ -575,6 +575,9 @@ public:
|
|||
QString AStylePath() const;
|
||||
void setAStylePath(const QString &aStylePath);
|
||||
|
||||
TerminalEmulatorArgumentsPattern terminalArgumentsPattern() const;
|
||||
void setTerminalArgumentsPattern(const TerminalEmulatorArgumentsPattern &argsPattern);
|
||||
|
||||
bool useCustomIconSet() const;
|
||||
void setUseCustomIconSet(bool newUseCustomIconSet);
|
||||
|
||||
|
@ -606,6 +609,7 @@ public:
|
|||
QString mDefaultOpenFolder;
|
||||
QString mTerminalPath;
|
||||
QString mAStylePath;
|
||||
TerminalEmulatorArgumentsPattern mTerminalArgumentsPattern;
|
||||
bool mHideNonSupportFilesInFileView;
|
||||
bool mOpenFilesInSingleInstance;
|
||||
// _Base interface
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include "../settings.h"
|
||||
#include "../iconsmanager.h"
|
||||
#include "../systemconsts.h"
|
||||
#include "../compiler/executablerunner.h"
|
||||
|
||||
#include <QFileDialog>
|
||||
|
||||
|
@ -27,6 +28,16 @@ EnvironmentProgramsWidget::EnvironmentProgramsWidget(const QString& name, const
|
|||
ui(new Ui::EnvironmentProgramsWidget)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
QFont monoFont(DEFAULT_MONO_FONT);
|
||||
ui->rbImplicitSystem->setFont(monoFont);
|
||||
ui->rbMinusEAppendArgs->setFont(monoFont);
|
||||
ui->rbMinusXAppendArgs->setFont(monoFont);
|
||||
ui->rbMinusMinusAppendArgs->setFont(monoFont);
|
||||
ui->rbMinusEAppendCommandLine->setFont(monoFont);
|
||||
ui->rbWriteCommandLineToTempFileThenTempFilename->setFont(monoFont);
|
||||
#ifndef Q_OS_MACOS
|
||||
hideMacosSpecificPattern();
|
||||
#endif
|
||||
}
|
||||
|
||||
EnvironmentProgramsWidget::~EnvironmentProgramsWidget()
|
||||
|
@ -34,14 +45,62 @@ EnvironmentProgramsWidget::~EnvironmentProgramsWidget()
|
|||
delete ui;
|
||||
}
|
||||
|
||||
void EnvironmentProgramsWidget::hideMacosSpecificPattern()
|
||||
{
|
||||
ui->rbWriteCommandLineToTempFileThenTempFilename->setVisible(false);
|
||||
ui->rbWriteCommandLineToTempFileThenTempFilename->setEnabled(false);
|
||||
ui->pbWriteCommandLineToTempFileThenTempFilename->setVisible(false);
|
||||
ui->pbWriteCommandLineToTempFileThenTempFilename->setEnabled(false);
|
||||
}
|
||||
|
||||
void EnvironmentProgramsWidget::testTerminal(const TerminalEmulatorArgumentsPattern &pattern)
|
||||
{
|
||||
auto [filename, arguments, fileOwner] = wrapCommandForTerminalEmulator(ui->txtTerminal->text(), pattern, {defaultShell(), "-c", "echo hello; sleep 3"});
|
||||
ExecutableRunner runner(filename, arguments, "", nullptr);
|
||||
runner.start();
|
||||
runner.wait();
|
||||
}
|
||||
|
||||
void EnvironmentProgramsWidget::doLoad()
|
||||
{
|
||||
ui->txtTerminal->setText(pSettings->environment().terminalPath());
|
||||
switch (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()
|
||||
{
|
||||
pSettings->environment().setTerminalPath(ui->txtTerminal->text());
|
||||
if (ui->rbImplicitSystem->isChecked())
|
||||
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();
|
||||
}
|
||||
|
||||
|
@ -61,3 +120,62 @@ void EnvironmentProgramsWidget::on_btnChooseTerminal_clicked()
|
|||
ui->txtTerminal->setText(filename);
|
||||
}
|
||||
}
|
||||
|
||||
void EnvironmentProgramsWidget::on_txtTerminal_textChanged(const QString &terminalPath)
|
||||
{
|
||||
QString terminalPathForExec;
|
||||
if (getPathUnixExecSemantics(terminalPath) == UnixExecSemantics::RelativeToCwd) {
|
||||
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()
|
||||
{
|
||||
testTerminal(TerminalEmulatorArgumentsPattern::ImplicitSystem);
|
||||
}
|
||||
|
||||
void EnvironmentProgramsWidget::on_pbMinusEAppendArgs_clicked()
|
||||
{
|
||||
testTerminal(TerminalEmulatorArgumentsPattern::MinusEAppendArgs);
|
||||
}
|
||||
|
||||
void EnvironmentProgramsWidget::on_pbMinusXAppendArgs_clicked()
|
||||
{
|
||||
testTerminal(TerminalEmulatorArgumentsPattern::MinusXAppendArgs);
|
||||
}
|
||||
|
||||
void EnvironmentProgramsWidget::on_pbMinusMinusAppendArgs_clicked()
|
||||
{
|
||||
testTerminal(TerminalEmulatorArgumentsPattern::MinusMinusAppendArgs);
|
||||
}
|
||||
|
||||
void EnvironmentProgramsWidget::on_pbMinusEAppendCommandLine_clicked()
|
||||
{
|
||||
testTerminal(TerminalEmulatorArgumentsPattern::MinusEAppendCommandLine);
|
||||
}
|
||||
|
||||
void EnvironmentProgramsWidget::on_pbWriteCommandLineToTempFileThenTempFilename_clicked()
|
||||
{
|
||||
testTerminal(TerminalEmulatorArgumentsPattern::WriteCommandLineToTempFileThenTempFilename);
|
||||
}
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#define ENVIRONMENTPROGRAMSWIDGET_H
|
||||
|
||||
#include "settingswidget.h"
|
||||
#include "utils.h"
|
||||
|
||||
namespace Ui {
|
||||
class EnvironmentProgramsWidget;
|
||||
|
@ -30,6 +31,10 @@ class EnvironmentProgramsWidget : public SettingsWidget
|
|||
public:
|
||||
explicit EnvironmentProgramsWidget(const QString& name, const QString& group, QWidget *parent = nullptr);
|
||||
~EnvironmentProgramsWidget();
|
||||
void hideMacosSpecificPattern();
|
||||
|
||||
private:
|
||||
void testTerminal(const TerminalEmulatorArgumentsPattern &pattern);
|
||||
|
||||
private:
|
||||
Ui::EnvironmentProgramsWidget *ui;
|
||||
|
@ -41,6 +46,13 @@ protected:
|
|||
void updateIcons(const QSize &size) override;
|
||||
private slots:
|
||||
void on_btnChooseTerminal_clicked();
|
||||
void on_txtTerminal_textChanged(const QString &terminalPath);
|
||||
void on_pbImplicitSystem_clicked();
|
||||
void on_pbMinusEAppendArgs_clicked();
|
||||
void on_pbMinusXAppendArgs_clicked();
|
||||
void on_pbMinusMinusAppendArgs_clicked();
|
||||
void on_pbMinusEAppendCommandLine_clicked();
|
||||
void on_pbWriteCommandLineToTempFileThenTempFilename_clicked();
|
||||
};
|
||||
|
||||
#endif // ENVIRONMENTPROGRAMSWIDGET_H
|
||||
|
|
|
@ -35,7 +35,141 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<item row="1" column="0" colspan="3">
|
||||
<widget class="QGroupBox" name="groupBox">
|
||||
<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">
|
||||
<string>sh -c "echo hello; sleep 3"</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<spacer name="horizontalSpacer">
|
||||
<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">
|
||||
<string>term -e sh -c "echo hello; sleep 3"</string>
|
||||
</property>
|
||||
</widget>
|
||||
</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 "echo hello; sleep 3"</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="2">
|
||||
<widget class="QPushButton" name="pbMinusXAppendArgs">
|
||||
<property name="text">
|
||||
<string>Test</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QRadioButton" name="rbMinusMinusAppendArgs">
|
||||
<property name="text">
|
||||
<string>term -- sh -c "echo hello; sleep 3"</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="2">
|
||||
<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 "sh -c \"echo hello; sleep 3\""</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>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="2">
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
|
|
|
@ -21,12 +21,15 @@
|
|||
#include "../systemconsts.h"
|
||||
|
||||
#include <QFileDialog>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonArray>
|
||||
|
||||
ExecutorGeneralWidget::ExecutorGeneralWidget(const QString& name, const QString& group, QWidget *parent):
|
||||
SettingsWidget(name,group,parent),
|
||||
ui(new Ui::ExecutorGeneralWidget)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
ui->txtParsedArgsInJson->setFont(QFont(DEFAULT_MONO_FONT));
|
||||
}
|
||||
|
||||
ExecutorGeneralWidget::~ExecutorGeneralWidget()
|
||||
|
@ -73,3 +76,11 @@ void ExecutorGeneralWidget::updateIcons(const QSize &/*size*/)
|
|||
pIconsManager->setIcon(ui->btnBrowse,IconsManager::ACTION_FILE_OPEN_FOLDER);
|
||||
}
|
||||
|
||||
|
||||
void ExecutorGeneralWidget::on_txtExecuteParamaters_textChanged(const QString &commandLine)
|
||||
{
|
||||
QStringList parsed = splitProcessCommand(commandLine);
|
||||
QJsonArray obj = QJsonArray::fromStringList(parsed);
|
||||
ui->txtParsedArgsInJson->setText(QJsonDocument{obj}.toJson());
|
||||
}
|
||||
|
||||
|
|
|
@ -43,6 +43,8 @@ private slots:
|
|||
void on_btnBrowse_clicked();
|
||||
|
||||
// SettingsWidget interface
|
||||
void on_txtExecuteParamaters_textChanged(const QString &commandLine);
|
||||
|
||||
protected:
|
||||
void updateIcons(const QSize &size) override;
|
||||
};
|
||||
|
|
|
@ -55,10 +55,21 @@
|
|||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<widget class="QLineEdit" name="txtExecuteParamaters"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="labelParseArgsInJson">
|
||||
<property name="text">
|
||||
<string>Parsed argv array (represented in JSON):</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QTextBrowser" name="txtParsedArgsInJson">
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
|
@ -75,7 +86,6 @@
|
|||
<widget class="QLabel" name="label_3">
|
||||
<property name="font">
|
||||
<font>
|
||||
<weight>75</weight>
|
||||
<bold>true</bold>
|
||||
</font>
|
||||
</property>
|
||||
|
@ -88,7 +98,6 @@
|
|||
<widget class="QLabel" name="label_2">
|
||||
<property name="font">
|
||||
<font>
|
||||
<weight>75</weight>
|
||||
<bold>true</bold>
|
||||
</font>
|
||||
</property>
|
||||
|
@ -101,7 +110,6 @@
|
|||
<widget class="QLabel" name="label_4">
|
||||
<property name="font">
|
||||
<font>
|
||||
<weight>75</weight>
|
||||
<bold>true</bold>
|
||||
</font>
|
||||
</property>
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
#include "environmentshortcutwidget.h"
|
||||
#include "environmentfolderswidget.h"
|
||||
#include "environmentperformancewidget.h"
|
||||
#include "environmentprogramswidget.h"
|
||||
#include "executorgeneralwidget.h"
|
||||
#include "executorproblemsetwidget.h"
|
||||
#include "debuggeneralwidget.h"
|
||||
|
@ -58,8 +59,7 @@
|
|||
#include "environmentfileassociationwidget.h"
|
||||
#include "projectversioninfowidget.h"
|
||||
#endif
|
||||
#ifdef Q_OS_LINUX
|
||||
#include "environmentprogramswidget.h"
|
||||
#if defined(Q_OS_UNIX) && !defined(Q_OS_MACOS) // XDG desktop
|
||||
#include "formatterpathwidget.h"
|
||||
#endif
|
||||
#include <QDebug>
|
||||
|
@ -156,10 +156,8 @@ PSettingsDialog SettingsDialog::optionDialog()
|
|||
widget = new EnvironmentShortcutWidget(tr("Shortcuts"),tr("Environment"));
|
||||
dialog->addWidget(widget);
|
||||
|
||||
#ifdef Q_OS_LINUX
|
||||
widget = new EnvironmentProgramsWidget(tr("Terminal"),tr("Environment"));
|
||||
dialog->addWidget(widget);
|
||||
#endif
|
||||
|
||||
widget = new EnvironmentPerformanceWidget(tr("Performance"),tr("Environment"));
|
||||
dialog->addWidget(widget);
|
||||
|
@ -230,7 +228,7 @@ PSettingsDialog SettingsDialog::optionDialog()
|
|||
widget = new FormatterGeneralWidget(tr("General"),tr("Code Formatter"));
|
||||
dialog->addWidget(widget);
|
||||
|
||||
#ifdef Q_OS_LINUX
|
||||
#if defined(Q_OS_UNIX) && !defined(Q_OS_MACOS) // XDG desktop
|
||||
widget = new FormatterPathWidget(tr("Program"),tr("Code Formatter"));
|
||||
dialog->addWidget(widget);
|
||||
#endif
|
||||
|
|
|
@ -22,7 +22,6 @@
|
|||
#define APP_SETTSINGS_FILENAME "redpandacpp.ini"
|
||||
#ifdef Q_OS_WIN
|
||||
#define CONSOLE_PAUSER "consolepauser.exe"
|
||||
#define ASSEMBLER "nasm.exe"
|
||||
#define GCC_PROGRAM "gcc.exe"
|
||||
#define GPP_PROGRAM "g++.exe"
|
||||
#define GDB_PROGRAM "gdb.exe"
|
||||
|
@ -40,9 +39,8 @@
|
|||
#define SDCC_PROGRAM "sdcc.exe"
|
||||
#define PACKIHX_PROGRAM "packihx.exe"
|
||||
#define MAKEBIN_PROGRAM "makebin.exe"
|
||||
#elif defined(Q_OS_LINUX)
|
||||
#else // Unix
|
||||
#define CONSOLE_PAUSER "consolepauser"
|
||||
#define ASSEMBLER "nasm"
|
||||
#define GCC_PROGRAM "gcc"
|
||||
#define GPP_PROGRAM "g++"
|
||||
#define GDB_PROGRAM "gdb"
|
||||
|
@ -61,28 +59,6 @@
|
|||
#define SDCC_PROGRAM "sdcc"
|
||||
#define PACKIHX_PROGRAM "packihx"
|
||||
#define MAKEBIN_PROGRAM "makebin"
|
||||
#elif defined(Q_OS_MACOS)
|
||||
#define CONSOLE_PAUSER "consolepauser"
|
||||
#define ASSEMBLER "nasm"
|
||||
#define GCC_PROGRAM "gcc"
|
||||
#define GPP_PROGRAM "g++"
|
||||
#define GDB_PROGRAM "gdb"
|
||||
#define GDB_SERVER_PROGRAM "gdbserver"
|
||||
#define GDB32_PROGRAM "gdb32"
|
||||
#define MAKE_PROGRAM "make"
|
||||
#define WINDRES_PROGRAM ""
|
||||
#define CLEAN_PROGRAM "rm -rf"
|
||||
#define CPP_PROGRAM "cpp"
|
||||
#define GIT_PROGRAM "git"
|
||||
#define CLANG_PROGRAM "clang"
|
||||
#define CLANG_CPP_PROGRAM "clang++"
|
||||
#define LLDB_MI_PROGRAM "lldb-mi"
|
||||
#define LLDB_SERVER_PROGRAM "lldb-server"
|
||||
#define SDCC_PROGRAM "sdcc"
|
||||
#define PACKIHX_PROGRAM "packihx"
|
||||
#define MAKEBIN_PROGRAM "makebin"
|
||||
#else
|
||||
#error "Only support windows, Linux and MacOS now!"
|
||||
#endif
|
||||
|
||||
#define DEV_PROJECT_EXT "dev"
|
||||
|
@ -128,7 +104,7 @@
|
|||
# define MAKEFILE_NAME "makefile.win"
|
||||
# define XMAKEFILE_NAME "xmake.lua"
|
||||
# define ALL_FILE_WILDCARD "*.*"
|
||||
#elif defined(Q_OS_LINUX) || defined(Q_OS_MACOS)
|
||||
#else // Unix
|
||||
# define PATH_SENSITIVITY Qt::CaseSensitive
|
||||
# define PATH_SEPARATOR ":"
|
||||
# define LINE_BREAKER "\n"
|
||||
|
@ -142,8 +118,6 @@
|
|||
# define MAKEFILE_NAME "makefile"
|
||||
# define XMAKEFILE_NAME "xmake.lua"
|
||||
# define ALL_FILE_WILDCARD "*"
|
||||
#else
|
||||
#error "Only support windows, linux and macos now!"
|
||||
#endif
|
||||
|
||||
#define SDCC_IHX_SUFFIX "ihx"
|
||||
|
@ -151,6 +125,40 @@
|
|||
#define SDCC_HEX_SUFFIX "hex"
|
||||
#define SDCC_REL_SUFFIX "rel"
|
||||
|
||||
#if defined(Q_OS_WIN)
|
||||
# define DEFAULT_UI_FONT "Segoe UI"
|
||||
# define CJK_UI_FONT_SC "Microsoft YaHei UI"
|
||||
# define CJK_UI_FONT_TC "Microsoft JhengHei UI"
|
||||
# define CJK_UI_FONT_J "Yu Gothic UI"
|
||||
# define CJK_UI_FONT_K "Malgun Gothic"
|
||||
# define DEFAULT_MONO_FONT "Consolas"
|
||||
# define CJK_MONO_FONT_SC "Microsoft YaHei"
|
||||
# define CJK_MONO_FONT_TC "Microsoft JhengHei"
|
||||
# define CJK_MONO_FONT_J "Yu Gothic"
|
||||
# define CJK_MONO_FONT_K "Malgun Gothic"
|
||||
#elif defined(Q_OS_MACOS)
|
||||
# define DEFAULT_UI_FONT "Helvetica Neue"
|
||||
# define CJK_UI_FONT_SC "PingFang SC"
|
||||
# define CJK_UI_FONT_TC "PingFang TC"
|
||||
# define CJK_UI_FONT_J "Hiragino Sans"
|
||||
# define CJK_UI_FONT_K "Apple SD Gothic Neo"
|
||||
# define DEFAULT_MONO_FONT "Menlo"
|
||||
# define CJK_MONO_FONT_SC CJK_UI_FONT_SC
|
||||
# define CJK_MONO_FONT_TC CJK_UI_FONT_TC
|
||||
# define CJK_MONO_FONT_J CJK_UI_FONT_J
|
||||
# define CJK_MONO_FONT_K CJK_UI_FONT_K
|
||||
#else // XDG desktop
|
||||
# define DEFAULT_UI_FONT "Sans" // use fontconfig default
|
||||
# define CJK_UI_FONT_SC "Noto Sans CJK SC"
|
||||
# define CJK_UI_FONT_TC "Noto Sans CJK TC"
|
||||
# define CJK_UI_FONT_J "Noto Sans CJK JP"
|
||||
# define CJK_UI_FONT_K "Noto Sans CJK KR"
|
||||
# define DEFAULT_MONO_FONT "Monospace" // use fontconfig default
|
||||
# define CJK_MONO_FONT_SC CJK_UI_FONT_SC // intentionally: the "Mono" version is not stricly monospaced either, and has less weights
|
||||
# define CJK_MONO_FONT_TC CJK_UI_FONT_TC
|
||||
# define CJK_MONO_FONT_J CJK_UI_FONT_J
|
||||
# define CJK_MONO_FONT_K CJK_UI_FONT_K
|
||||
#endif
|
||||
|
||||
class SystemConsts
|
||||
{
|
||||
|
|
|
@ -1958,6 +1958,54 @@
|
|||
<source>All files (%1)</source>
|
||||
<translation>Todos os arquivos (%1)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Terminal emulator arguments pattern</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>sh -c "echo hello; sleep 3"</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Test</source>
|
||||
<translation type="unfinished">Testar</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>term -e sh -c "echo hello; sleep 3"</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>term -x sh -c "echo hello; sleep 3"</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>term -- sh -c "echo hello; sleep 3"</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>term -e "sh -c \"echo hello; sleep 3\""</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>On clicking “Test” for the correct pattern, the terminal emulator</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>• pops up;</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>• shows “hello”; and</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>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>EnvironmentShortcutModel</name>
|
||||
|
@ -2058,6 +2106,10 @@
|
|||
<source>All files (%1)</source>
|
||||
<translation>Todos os arquivos (%1)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Parsed argv array (represented in JSON):</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>ExecutorProblemSetWidget</name>
|
||||
|
|
|
@ -2689,7 +2689,72 @@ Are you really want to continue?</oldsource>
|
|||
<translation>终端</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../settingsdialog/environmentprogramswidget.cpp" line="57"/>
|
||||
<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 "echo hello; sleep 3"</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="116"/>
|
||||
<location filename="../settingsdialog/environmentprogramswidget.ui" line="137"/>
|
||||
<location filename="../settingsdialog/environmentprogramswidget.ui" line="158"/>
|
||||
<location filename="../settingsdialog/environmentprogramswidget.ui" line="179"/>
|
||||
<source>Test</source>
|
||||
<translation>测试</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../settingsdialog/environmentprogramswidget.ui" line="88"/>
|
||||
<source>term -e sh -c "echo hello; sleep 3"</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../settingsdialog/environmentprogramswidget.ui" line="109"/>
|
||||
<source>term -x sh -c "echo hello; sleep 3"</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../settingsdialog/environmentprogramswidget.ui" line="130"/>
|
||||
<source>term -- sh -c "echo hello; sleep 3"</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../settingsdialog/environmentprogramswidget.ui" line="151"/>
|
||||
<source>term -e "sh -c \"echo hello; sleep 3\""</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>
|
||||
<translation>选择终端程序</translation>
|
||||
</message>
|
||||
|
@ -2798,6 +2863,11 @@ Are you really want to continue?</oldsource>
|
|||
<source>Parameters to pass to your program</source>
|
||||
<translation>运行程序的命令行参数</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../settingsdialog/executorgeneralwidget.ui" line="65"/>
|
||||
<source>Parsed argv array (represented in JSON):</source>
|
||||
<translation>argv 数组解析结果(以 JSON 表示):</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../settingsdialog/executorgeneralwidget.ui" line="68"/>
|
||||
<source>Redirect input to the following file:</source>
|
||||
|
|
|
@ -1791,6 +1791,54 @@
|
|||
<source>All files (%1)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Terminal emulator arguments pattern</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>sh -c "echo hello; sleep 3"</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Test</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>term -e sh -c "echo hello; sleep 3"</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>term -x sh -c "echo hello; sleep 3"</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>term -- sh -c "echo hello; sleep 3"</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>term -e "sh -c \"echo hello; sleep 3\""</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>On clicking “Test” for the correct pattern, the terminal emulator</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>• pops up;</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>• shows “hello”; and</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>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>EnvironmentShortcutModel</name>
|
||||
|
@ -1891,6 +1939,10 @@
|
|||
<source>All files (%1)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Parsed argv array (represented in JSON):</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>ExecutorProblemSetWidget</name>
|
||||
|
|
|
@ -447,7 +447,7 @@ void executeFile(const QString &fileName, const QString ¶ms, const QString &
|
|||
{
|
||||
ExecutableRunner* runner=new ExecutableRunner(
|
||||
fileName,
|
||||
params,
|
||||
splitProcessCommand(params),
|
||||
workingDir);
|
||||
runner->connect(runner, &QThread::finished,
|
||||
[runner,tempFile](){
|
||||
|
@ -589,3 +589,190 @@ QColor alphaBlend(const QColor &lower, const QColor &upper) {
|
|||
int(lower.blue() * wl + upper.blue() * wu)
|
||||
);
|
||||
}
|
||||
|
||||
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();
|
||||
QString path = env.value("PATH");
|
||||
QStringList pathList = path.split(PATH_SEPARATOR);
|
||||
return pathList;
|
||||
}
|
||||
|
||||
QString escapeArgument(const QString &arg, [[maybe_unused]] bool isFirstArg)
|
||||
{
|
||||
auto argContainsOneOf = [&arg](auto... ch) { return (arg.contains(ch) || ...); };
|
||||
|
||||
#ifdef Q_OS_WINDOWS
|
||||
// See https://stackoverflow.com/questions/31838469/how-do-i-convert-argv-to-lpcommandline-parameter-of-createprocess ,
|
||||
// and https://learn.microsoft.com/en-gb/archive/blogs/twistylittlepassagesallalike/everyone-quotes-command-line-arguments-the-wrong-way .
|
||||
|
||||
// TODO: investigate whether we need escaping for cmd.
|
||||
|
||||
if (!arg.isEmpty() && !argContainsOneOf(' ', '\t', '\n', '\v', '"'))
|
||||
return arg;
|
||||
|
||||
QString result = "\"";
|
||||
for (auto it = arg.begin(); ; ++it) {
|
||||
int nBackslash = 0;
|
||||
while (it != arg.end() && *it == '\\') {
|
||||
++it;
|
||||
++nBackslash;
|
||||
}
|
||||
if (it == arg.end()) {
|
||||
// Escape all backslashes, but let the terminating double quotation mark we add below be interpreted as a metacharacter.
|
||||
result.append(QString('\\').repeated(nBackslash * 2));
|
||||
break;
|
||||
} else if (*it == '"') {
|
||||
// Escape all backslashes and the following double quotation mark.
|
||||
result.append(QString('\\').repeated(nBackslash * 2 + 1));
|
||||
result.push_back(*it);
|
||||
} else {
|
||||
// Backslashes aren't special here.
|
||||
result.append(QString('\\').repeated(nBackslash));
|
||||
result.push_back(*it);
|
||||
}
|
||||
}
|
||||
result.push_back('"');
|
||||
return result;
|
||||
#else
|
||||
/* be speculative, but keep readability.
|
||||
* ref. https://pubs.opengroup.org/onlinepubs/9699919799.2018edition/utilities/V3_chap02.html
|
||||
*/
|
||||
if (arg.isEmpty())
|
||||
return R"("")";
|
||||
|
||||
/* POSIX say the following reserved words (may) have special meaning:
|
||||
* !, {, }, case, do, done, elif, else, esac, fi, for, if, in, then, until, while,
|
||||
* [[, ]], function, select,
|
||||
* only if used as the _first word_ of a command (or somewhere we dot not care).
|
||||
*/
|
||||
const static QSet<QString> reservedWord{
|
||||
"!", "{", "}", "case", "do", "done", "elif", "else", "esac", "fi", "for", "if", "in", "then", "until", "while",
|
||||
"[[", "]]", "function", "select",
|
||||
};
|
||||
if (isFirstArg && reservedWord.contains(arg))
|
||||
return QString(R"("%1")").arg(arg);
|
||||
|
||||
/* POSIX say “shall quote”:
|
||||
* '|', '&', ';', '<', '>', '(', ')', '$', '`', '\\', '"', '\'', ' ', '\t', '\n';
|
||||
* and “may need to be quoted”:
|
||||
* '*', '?', '[', '#', '~', '=', '%'.
|
||||
* among which “may need to be quoted” there are 4 kinds:
|
||||
* - wildcards '*', '?', '[' are “danger anywhere” (handle it as if “shall quote”);
|
||||
* - comment '#', home '~', is “danger at first char in any word”;
|
||||
* - (environment) variable '=' is “danger at any char in first word”;
|
||||
* - foreground '%' is “danger at first char in first word”.
|
||||
* although not mentioned by POSIX, bash’s brace expansion '{', '}' are also “danger anywhere”.
|
||||
*/
|
||||
bool isDoubleQuotingDanger = argContainsOneOf('$', '`', '\\', '"');
|
||||
bool isSingleQuotingDanger = arg.contains('\'');
|
||||
bool isDangerAnyChar = isDoubleQuotingDanger || isSingleQuotingDanger || argContainsOneOf(
|
||||
'|', '&', ';', '<', '>', '(', ')', ' ', '\t', '\n',
|
||||
'*', '?', '[',
|
||||
'{', '}'
|
||||
);
|
||||
bool isDangerFirstChar = (arg[0] == '#') || (arg[0] == '~');
|
||||
if (isFirstArg) {
|
||||
isDangerAnyChar = isDangerAnyChar || arg.contains('=');
|
||||
isDangerFirstChar = isDangerFirstChar || (arg[0] == '%');
|
||||
}
|
||||
|
||||
// a “safe” string
|
||||
if (!isDangerAnyChar && !isDangerFirstChar)
|
||||
return arg;
|
||||
|
||||
// prefer more-common double quoting
|
||||
if (!isDoubleQuotingDanger)
|
||||
return QString(R"("%1")").arg(arg);
|
||||
|
||||
// and then check the opportunity of single quoting
|
||||
if (!isSingleQuotingDanger)
|
||||
return QString("'%1'").arg(arg);
|
||||
|
||||
// escaping is necessary
|
||||
// use double quoting since it’s less tricky
|
||||
QString result = "\"";
|
||||
for (auto ch : arg) {
|
||||
if (ch == '$' || ch == '`' || ch == '\\' || ch == '"')
|
||||
result.push_back('\\');
|
||||
result.push_back(ch);
|
||||
}
|
||||
result.push_back('"');
|
||||
return result;
|
||||
|
||||
/* single quoting, which is roughly raw string, is possible and quite simple in programming:
|
||||
* 1. replace each single quote with `'\''`, which contains
|
||||
* - a single quote to close quoting,
|
||||
* - an escaped single quote representing the single quote itself, and
|
||||
* - a single quote to open quoting again;
|
||||
* 2. enclose the string with a pair of single quotes.
|
||||
* e.g. `o'clock` => `'o'\''clock'`, really tricky and hard to read.
|
||||
*/
|
||||
#endif
|
||||
}
|
||||
|
||||
auto wrapCommandForTerminalEmulator(const QString &terminal, const TerminalEmulatorArgumentsPattern &argsPattern, const QStringList &argsWithArgv0)
|
||||
-> std::tuple<QString, QStringList, std::unique_ptr<QTemporaryFile>>
|
||||
{
|
||||
switch (argsPattern) {
|
||||
case TerminalEmulatorArgumentsPattern::ImplicitSystem:
|
||||
default: {
|
||||
return {argsWithArgv0[0], argsWithArgv0.mid(1), nullptr};
|
||||
}
|
||||
case TerminalEmulatorArgumentsPattern::MinusEAppendArgs: {
|
||||
return {terminal, QStringList{"-e"} + argsWithArgv0, nullptr};
|
||||
}
|
||||
case TerminalEmulatorArgumentsPattern::MinusXAppendArgs: {
|
||||
return {terminal, QStringList{"-x"} + argsWithArgv0, nullptr};
|
||||
}
|
||||
case TerminalEmulatorArgumentsPattern::MinusMinusAppendArgs: {
|
||||
return {terminal, QStringList{"--"} + argsWithArgv0, nullptr};
|
||||
}
|
||||
case TerminalEmulatorArgumentsPattern::MinusEAppendCommandLine: {
|
||||
QStringList escapedArgs;
|
||||
for (int i = 0; i < argsWithArgv0.length(); i++) {
|
||||
auto &arg = argsWithArgv0[i];
|
||||
auto escaped = escapeArgument(arg, i == 0);
|
||||
escapedArgs.append(escaped);
|
||||
}
|
||||
return {terminal, QStringList{"-e", escapedArgs.join(' ')}, nullptr};
|
||||
}
|
||||
case TerminalEmulatorArgumentsPattern::WriteCommandLineToTempFileThenTempFilename: {
|
||||
auto fileOwner = std::make_unique<QTemporaryFile>(QDir::tempPath() + "/redpanda_XXXXXX.command");
|
||||
if (fileOwner->open()) {
|
||||
QStringList escapedArgs;
|
||||
for (int i = 0; i < argsWithArgv0.length(); i++) {
|
||||
auto &arg = argsWithArgv0[i];
|
||||
auto escaped = escapeArgument(arg, i == 0);
|
||||
escapedArgs.append(escaped);
|
||||
}
|
||||
fileOwner->write(escapedArgs.join(' ').toUtf8());
|
||||
fileOwner->write(QString('\n').toUtf8());
|
||||
fileOwner->flush();
|
||||
}
|
||||
QFile(fileOwner->fileName()).setPermissions(QFileDevice::ReadOwner | QFileDevice::WriteOwner | QFileDevice::ExeOwner);
|
||||
return {terminal, QStringList{fileOwner->fileName()}, std::move(fileOwner)};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QString defaultShell()
|
||||
{
|
||||
#ifdef Q_OS_WINDOWS
|
||||
return "powershell.exe";
|
||||
#else
|
||||
return "sh";
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include <memory>
|
||||
#include <QThread>
|
||||
#include <QProcessEnvironment>
|
||||
#include <QTemporaryFile>
|
||||
#define SI_NO_CONVERSION
|
||||
#include "SimpleIni.h"
|
||||
#include "qt_utils/utils.h"
|
||||
|
@ -34,6 +35,7 @@
|
|||
|
||||
using SimpleIni = CSimpleIniA;
|
||||
using PSimpleIni = std::shared_ptr<SimpleIni>;
|
||||
using TemporaryFileOwner = std::unique_ptr<QTemporaryFile>;
|
||||
|
||||
enum class FileType{
|
||||
GAS, // GNU assembler source file (.s)
|
||||
|
@ -113,6 +115,22 @@ enum class ProblemCaseValidateType {
|
|||
IgnoreSpaces
|
||||
};
|
||||
|
||||
enum class UnixExecSemantics {
|
||||
Absolute,
|
||||
RelativeToCwd,
|
||||
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);
|
||||
QStringList splitProcessCommand(const QString& cmd);
|
||||
|
||||
|
@ -165,4 +183,15 @@ 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 TerminalEmulatorArgumentsPattern &argsPattern, const QStringList &argsWithArgv0)
|
||||
-> std::tuple<QString, QStringList, std::unique_ptr<QTemporaryFile>>;
|
||||
|
||||
QString defaultShell();
|
||||
|
||||
#endif // UTILS_H
|
||||
|
|
|
@ -25,7 +25,7 @@ void GitManager::createRepository(const QString &folder)
|
|||
contents.append("*.o");
|
||||
contents.append("*.exe");
|
||||
contents.append("*.layout");
|
||||
#ifdef Q_OS_LINUX
|
||||
#ifdef Q_OS_UNIX
|
||||
contents.append("*.");
|
||||
#endif
|
||||
|
||||
|
@ -593,7 +593,7 @@ QString GitManager::runGit(const QString& workingFolder, const QStringList &args
|
|||
#ifdef Q_OS_WIN
|
||||
env.insert("PATH",pSettings->dirs().appDir());
|
||||
env.insert("GIT_ASKPASS",includeTrailingPathDelimiter(pSettings->dirs().appDir())+"redpanda-win-git-askpass.exe");
|
||||
#elif defined(Q_OS_LINUX)
|
||||
#else // Unix
|
||||
env.insert(QProcessEnvironment::systemEnvironment());
|
||||
env.insert("LANG","en");
|
||||
env.insert("LANGUAGE","en");
|
||||
|
|
|
@ -56,15 +56,7 @@ QSynEdit::QSynEdit(QWidget *parent) : QAbstractScrollArea(parent),
|
|||
mPaintLock = 0;
|
||||
mPainterLock = 0;
|
||||
mPainting = false;
|
||||
#ifdef Q_OS_WIN
|
||||
mFontDummy = QFont("Consolas",12);
|
||||
#elif defined(Q_OS_LINUX)
|
||||
mFontDummy = QFont("terminal",14);
|
||||
#elif defined(Q_OS_MACOS)
|
||||
mFontDummy = QFont("Menlo", 14);
|
||||
#else
|
||||
#error "Not supported!"
|
||||
#endif
|
||||
mFontDummy = QFont("monospace",14);
|
||||
mFontDummy.setStyleStrategy(QFont::PreferAntialias);
|
||||
mDocument = std::make_shared<Document>(mFontDummy, mFontDummy, this);
|
||||
//fPlugins := TList.Create;
|
||||
|
|
|
@ -108,7 +108,7 @@ const QSet<QString> ASMSyntaxer::ATTDirectives {
|
|||
".seh_setframe",".seh_stackalloc",".seh_pushreg",
|
||||
".seh_savereg",".seh_savemm",".seh_savexmm",
|
||||
".seh_pushframe",".seh_scope",
|
||||
#elif defined(Q_OS_LINUX)
|
||||
#else // Unix
|
||||
".cfi_sections",".cfi_startproc",".cfi_endproc",
|
||||
".cfi_personality",".cfi_personality_id",".cfi_fde_data",
|
||||
".cfi_lsda",".cfi_inline_lsda",".cfi_def_cfa",
|
||||
|
|
|
@ -22,6 +22,7 @@ using std::string;
|
|||
using std::vector;
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
@ -184,15 +185,11 @@ int main(int argc, char** argv) {
|
|||
//todo: handle error
|
||||
printf("shm open failed %d:%s\n",errno,strerror(errno));
|
||||
} else {
|
||||
if (ftruncate(fd_shm,BUF_SIZE)==-1){
|
||||
printf("ftruncate failed %d:%s\n",errno,strerror(errno));
|
||||
//todo: set size error
|
||||
} else {
|
||||
pBuf = (char*)mmap(NULL,BUF_SIZE,PROT_READ | PROT_WRITE, MAP_SHARED, fd_shm,0);
|
||||
if (pBuf == MAP_FAILED) {
|
||||
printf("mmap failed %d:%s\n",errno,strerror(errno));
|
||||
pBuf = nullptr;
|
||||
}
|
||||
// `ftruncate` has already done in RedPandaIDE
|
||||
pBuf = (char*)mmap(NULL,BUF_SIZE,PROT_READ | PROT_WRITE, MAP_SHARED, fd_shm,0);
|
||||
if (pBuf == MAP_FAILED) {
|
||||
printf("mmap failed %d:%s\n",errno,strerror(errno));
|
||||
pBuf = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue