Core: Make access to remote terminal easier in code

By re-routing through device hooks. Now basically a FilePath
is sufficient as a handle.

Change-Id: I0ee43c35096ada12114d50476d5156a6c1de1e70
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
This commit is contained in:
hjk
2023-01-18 14:23:23 +01:00
parent 128b21c959
commit 6c8afcde88
7 changed files with 81 additions and 78 deletions

View File

@@ -283,6 +283,7 @@ public:
std::function<Environment(const FilePath &)> environment;
std::function<bool(const FilePath &left, const FilePath &right)> isSameDevice;
std::function<expected_str<FilePath>(const FilePath &)> localSource;
std::function<void(const FilePath &, const Environment &)> openTerminal;
};
} // Utils

View File

@@ -347,19 +347,19 @@ void CorePlugin::addToPathChooserContextMenu(Utils::PathChooser *pathChooser, QM
QList<QAction*> actions = menu->actions();
QAction *firstAction = actions.isEmpty() ? nullptr : actions.first();
if (QDir().exists(pathChooser->filePath().toString())) {
auto *showInGraphicalShell = new QAction(Core::FileUtils::msgGraphicalShellAction(), menu);
if (pathChooser->filePath().exists()) {
auto showInGraphicalShell = new QAction(FileUtils::msgGraphicalShellAction(), menu);
connect(showInGraphicalShell, &QAction::triggered, pathChooser, [pathChooser] {
Core::FileUtils::showInGraphicalShell(pathChooser, pathChooser->filePath());
});
menu->insertAction(firstAction, showInGraphicalShell);
auto *showInTerminal = new QAction(Core::FileUtils::msgTerminalHereAction(), menu);
auto showInTerminal = new QAction(FileUtils::msgTerminalHereAction(), menu);
connect(showInTerminal, &QAction::triggered, pathChooser, [pathChooser] {
if (pathChooser->openTerminalHandler())
pathChooser->openTerminalHandler()();
else
FileUtils::openTerminal(pathChooser->filePath());
FileUtils::openTerminal(pathChooser->filePath(), {});
});
menu->insertAction(firstAction, showInTerminal);

View File

@@ -41,6 +41,7 @@
#include <utils/algorithm.h>
#include <utils/checkablemessagebox.h>
#include <utils/environment.h>
#include <utils/executeondestruction.h>
#include <utils/filepath.h>
#include <utils/hostosinfo.h>
@@ -2618,7 +2619,7 @@ void EditorManagerPrivate::openTerminal()
{
if (!d->m_contextMenuEntry || d->m_contextMenuEntry->filePath().isEmpty())
return;
FileUtils::openTerminal(d->m_contextMenuEntry->filePath().parentDir());
FileUtils::openTerminal(d->m_contextMenuEntry->filePath().parentDir(), {});
}
void EditorManagerPrivate::findInDirectory()

View File

@@ -32,15 +32,6 @@
#include <QTextCodec>
#include <QWidget>
#ifdef Q_OS_WIN
#include <windows.h>
#include <stdlib.h>
#include <cstring>
#endif
using namespace Utils;
namespace Core {
@@ -111,69 +102,10 @@ void FileUtils::showInFileSystemView(const FilePath &path)
navWidget->syncWithFilePath(path);
}
static void startTerminalEmulator(const QString &workingDir, const Environment &env)
{
#ifdef Q_OS_WIN
STARTUPINFO si;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
PROCESS_INFORMATION pinfo;
ZeroMemory(&pinfo, sizeof(pinfo));
static const auto quoteWinCommand = [](const QString &program) {
const QChar doubleQuote = QLatin1Char('"');
// add the program as the first arg ... it works better
QString programName = program;
programName.replace(QLatin1Char('/'), QLatin1Char('\\'));
if (!programName.startsWith(doubleQuote) && !programName.endsWith(doubleQuote)
&& programName.contains(QLatin1Char(' '))) {
programName.prepend(doubleQuote);
programName.append(doubleQuote);
}
return programName;
};
const QString cmdLine = quoteWinCommand(qtcEnvironmentVariable("COMSPEC"));
// cmdLine is assumed to be detached -
// https://blogs.msdn.microsoft.com/oldnewthing/20090601-00/?p=18083
const QString totalEnvironment = env.toStringList().join(QChar(QChar::Null)) + QChar(QChar::Null);
LPVOID envPtr = (env != Environment::systemEnvironment())
? (WCHAR *)(totalEnvironment.utf16()) : nullptr;
const bool success = CreateProcessW(0, (WCHAR *)cmdLine.utf16(),
0, 0, FALSE, CREATE_NEW_CONSOLE | CREATE_UNICODE_ENVIRONMENT,
envPtr, workingDir.isEmpty() ? 0 : (WCHAR *)workingDir.utf16(),
&si, &pinfo);
if (success) {
CloseHandle(pinfo.hThread);
CloseHandle(pinfo.hProcess);
}
#else
const TerminalCommand term = TerminalCommand::terminalEmulator();
QProcess process;
process.setProgram(term.command);
process.setArguments(ProcessArgs::splitArgs(term.openArgs));
process.setProcessEnvironment(env.toProcessEnvironment());
process.setWorkingDirectory(workingDir);
process.startDetached();
#endif
}
void FileUtils::openTerminal(const FilePath &path)
{
openTerminal(path, Environment::systemEnvironment());
}
void FileUtils::openTerminal(const FilePath &path, const Environment &env)
{
const QFileInfo fileInfo = path.toFileInfo();
const QString workingDir = QDir::toNativeSeparators(fileInfo.isDir() ?
fileInfo.absoluteFilePath() :
fileInfo.absolutePath());
startTerminalEmulator(workingDir, env);
QTC_ASSERT(DeviceFileHooks::instance().openTerminal, return);
DeviceFileHooks::instance().openTerminal(path, env);
}
QString FileUtils::msgFindInDirectory()

View File

@@ -22,7 +22,6 @@ struct CORE_EXPORT FileUtils
// Helpers for common directory browser options.
static void showInGraphicalShell(QWidget *parent, const Utils::FilePath &path);
static void showInFileSystemView(const Utils::FilePath &path);
static void openTerminal(const Utils::FilePath &path);
static void openTerminal(const Utils::FilePath &path, const Utils::Environment &env);
static QString msgFindInDirectory();
static QString msgFileSystemAction();

View File

@@ -17,16 +17,74 @@
#include <utils/portlist.h>
#include <utils/qtcassert.h>
#include <utils/qtcprocess.h>
#include <utils/terminalcommand.h>
#include <utils/url.h>
#include <QCoreApplication>
#include <QDateTime>
#ifdef Q_OS_WIN
#include <windows.h>
#include <stdlib.h>
#include <cstring>
#endif
using namespace ProjectExplorer::Constants;
using namespace Utils;
namespace ProjectExplorer {
static void startTerminalEmulator(const QString &workingDir, const Environment &env)
{
#ifdef Q_OS_WIN
STARTUPINFO si;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
PROCESS_INFORMATION pinfo;
ZeroMemory(&pinfo, sizeof(pinfo));
static const auto quoteWinCommand = [](const QString &program) {
const QChar doubleQuote = QLatin1Char('"');
// add the program as the first arg ... it works better
QString programName = program;
programName.replace(QLatin1Char('/'), QLatin1Char('\\'));
if (!programName.startsWith(doubleQuote) && !programName.endsWith(doubleQuote)
&& programName.contains(QLatin1Char(' '))) {
programName.prepend(doubleQuote);
programName.append(doubleQuote);
}
return programName;
};
const QString cmdLine = quoteWinCommand(qtcEnvironmentVariable("COMSPEC"));
// cmdLine is assumed to be detached -
// https://blogs.msdn.microsoft.com/oldnewthing/20090601-00/?p=18083
const QString totalEnvironment = env.toStringList().join(QChar(QChar::Null)) + QChar(QChar::Null);
LPVOID envPtr = (env != Environment::systemEnvironment())
? (WCHAR *)(totalEnvironment.utf16()) : nullptr;
const bool success = CreateProcessW(0, (WCHAR *)cmdLine.utf16(),
0, 0, FALSE, CREATE_NEW_CONSOLE | CREATE_UNICODE_ENVIRONMENT,
envPtr, workingDir.isEmpty() ? 0 : (WCHAR *)workingDir.utf16(),
&si, &pinfo);
if (success) {
CloseHandle(pinfo.hThread);
CloseHandle(pinfo.hProcess);
}
#else
const TerminalCommand term = TerminalCommand::terminalEmulator();
QProcess process;
process.setProgram(term.command);
process.setArguments(ProcessArgs::splitArgs(term.openArgs));
process.setProcessEnvironment(env.toProcessEnvironment());
process.setWorkingDirectory(workingDir);
process.startDetached();
#endif
}
DesktopDevice::DesktopDevice()
{
setFileAccess(DesktopDeviceFileAccess::instance());
@@ -43,8 +101,14 @@ DesktopDevice::DesktopDevice()
const QString portRange =
QString::fromLatin1("%1-%2").arg(DESKTOP_PORT_START).arg(DESKTOP_PORT_END);
setFreePorts(Utils::PortList::fromString(portRange));
setOpenTerminal([](const Environment &env, const FilePath &workingDir) {
Core::FileUtils::openTerminal(workingDir, env);
setOpenTerminal([](const Environment &env, const FilePath &path) {
const QFileInfo fileInfo = path.toFileInfo();
const QString workingDir = QDir::toNativeSeparators(fileInfo.isDir() ?
fileInfo.absoluteFilePath() :
fileInfo.absolutePath());
const Environment realEnv = env.hasChanges() ? env : Environment::systemEnvironment();
startTerminalEmulator(workingDir, realEnv);
});
}

View File

@@ -436,6 +436,12 @@ DeviceManager::DeviceManager(bool isInstance) : d(std::make_unique<DeviceManager
return device->ensureReachable(other);
};
deviceHooks.openTerminal = [](const FilePath &filePath, const Environment &env) {
auto device = DeviceManager::deviceForPath(filePath);
QTC_ASSERT(device, return);
device->openTerminal(env, filePath);
};
DeviceProcessHooks processHooks;
processHooks.processImplHook = [](const FilePath &filePath) -> ProcessInterface * {