forked from qt-creator/qt-creator
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:
@@ -283,6 +283,7 @@ public:
|
|||||||
std::function<Environment(const FilePath &)> environment;
|
std::function<Environment(const FilePath &)> environment;
|
||||||
std::function<bool(const FilePath &left, const FilePath &right)> isSameDevice;
|
std::function<bool(const FilePath &left, const FilePath &right)> isSameDevice;
|
||||||
std::function<expected_str<FilePath>(const FilePath &)> localSource;
|
std::function<expected_str<FilePath>(const FilePath &)> localSource;
|
||||||
|
std::function<void(const FilePath &, const Environment &)> openTerminal;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // Utils
|
} // Utils
|
||||||
|
|||||||
@@ -347,19 +347,19 @@ void CorePlugin::addToPathChooserContextMenu(Utils::PathChooser *pathChooser, QM
|
|||||||
QList<QAction*> actions = menu->actions();
|
QList<QAction*> actions = menu->actions();
|
||||||
QAction *firstAction = actions.isEmpty() ? nullptr : actions.first();
|
QAction *firstAction = actions.isEmpty() ? nullptr : actions.first();
|
||||||
|
|
||||||
if (QDir().exists(pathChooser->filePath().toString())) {
|
if (pathChooser->filePath().exists()) {
|
||||||
auto *showInGraphicalShell = new QAction(Core::FileUtils::msgGraphicalShellAction(), menu);
|
auto showInGraphicalShell = new QAction(FileUtils::msgGraphicalShellAction(), menu);
|
||||||
connect(showInGraphicalShell, &QAction::triggered, pathChooser, [pathChooser] {
|
connect(showInGraphicalShell, &QAction::triggered, pathChooser, [pathChooser] {
|
||||||
Core::FileUtils::showInGraphicalShell(pathChooser, pathChooser->filePath());
|
Core::FileUtils::showInGraphicalShell(pathChooser, pathChooser->filePath());
|
||||||
});
|
});
|
||||||
menu->insertAction(firstAction, showInGraphicalShell);
|
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] {
|
connect(showInTerminal, &QAction::triggered, pathChooser, [pathChooser] {
|
||||||
if (pathChooser->openTerminalHandler())
|
if (pathChooser->openTerminalHandler())
|
||||||
pathChooser->openTerminalHandler()();
|
pathChooser->openTerminalHandler()();
|
||||||
else
|
else
|
||||||
FileUtils::openTerminal(pathChooser->filePath());
|
FileUtils::openTerminal(pathChooser->filePath(), {});
|
||||||
});
|
});
|
||||||
menu->insertAction(firstAction, showInTerminal);
|
menu->insertAction(firstAction, showInTerminal);
|
||||||
|
|
||||||
|
|||||||
@@ -41,6 +41,7 @@
|
|||||||
|
|
||||||
#include <utils/algorithm.h>
|
#include <utils/algorithm.h>
|
||||||
#include <utils/checkablemessagebox.h>
|
#include <utils/checkablemessagebox.h>
|
||||||
|
#include <utils/environment.h>
|
||||||
#include <utils/executeondestruction.h>
|
#include <utils/executeondestruction.h>
|
||||||
#include <utils/filepath.h>
|
#include <utils/filepath.h>
|
||||||
#include <utils/hostosinfo.h>
|
#include <utils/hostosinfo.h>
|
||||||
@@ -2618,7 +2619,7 @@ void EditorManagerPrivate::openTerminal()
|
|||||||
{
|
{
|
||||||
if (!d->m_contextMenuEntry || d->m_contextMenuEntry->filePath().isEmpty())
|
if (!d->m_contextMenuEntry || d->m_contextMenuEntry->filePath().isEmpty())
|
||||||
return;
|
return;
|
||||||
FileUtils::openTerminal(d->m_contextMenuEntry->filePath().parentDir());
|
FileUtils::openTerminal(d->m_contextMenuEntry->filePath().parentDir(), {});
|
||||||
}
|
}
|
||||||
|
|
||||||
void EditorManagerPrivate::findInDirectory()
|
void EditorManagerPrivate::findInDirectory()
|
||||||
|
|||||||
@@ -32,15 +32,6 @@
|
|||||||
#include <QTextCodec>
|
#include <QTextCodec>
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
|
|
||||||
#ifdef Q_OS_WIN
|
|
||||||
|
|
||||||
#include <windows.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <cstring>
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
using namespace Utils;
|
using namespace Utils;
|
||||||
|
|
||||||
namespace Core {
|
namespace Core {
|
||||||
@@ -111,69 +102,10 @@ void FileUtils::showInFileSystemView(const FilePath &path)
|
|||||||
navWidget->syncWithFilePath(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)
|
void FileUtils::openTerminal(const FilePath &path, const Environment &env)
|
||||||
{
|
{
|
||||||
const QFileInfo fileInfo = path.toFileInfo();
|
QTC_ASSERT(DeviceFileHooks::instance().openTerminal, return);
|
||||||
const QString workingDir = QDir::toNativeSeparators(fileInfo.isDir() ?
|
DeviceFileHooks::instance().openTerminal(path, env);
|
||||||
fileInfo.absoluteFilePath() :
|
|
||||||
fileInfo.absolutePath());
|
|
||||||
startTerminalEmulator(workingDir, env);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QString FileUtils::msgFindInDirectory()
|
QString FileUtils::msgFindInDirectory()
|
||||||
|
|||||||
@@ -22,7 +22,6 @@ struct CORE_EXPORT FileUtils
|
|||||||
// Helpers for common directory browser options.
|
// Helpers for common directory browser options.
|
||||||
static void showInGraphicalShell(QWidget *parent, const Utils::FilePath &path);
|
static void showInGraphicalShell(QWidget *parent, const Utils::FilePath &path);
|
||||||
static void showInFileSystemView(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 void openTerminal(const Utils::FilePath &path, const Utils::Environment &env);
|
||||||
static QString msgFindInDirectory();
|
static QString msgFindInDirectory();
|
||||||
static QString msgFileSystemAction();
|
static QString msgFileSystemAction();
|
||||||
|
|||||||
@@ -17,16 +17,74 @@
|
|||||||
#include <utils/portlist.h>
|
#include <utils/portlist.h>
|
||||||
#include <utils/qtcassert.h>
|
#include <utils/qtcassert.h>
|
||||||
#include <utils/qtcprocess.h>
|
#include <utils/qtcprocess.h>
|
||||||
|
#include <utils/terminalcommand.h>
|
||||||
#include <utils/url.h>
|
#include <utils/url.h>
|
||||||
|
|
||||||
#include <QCoreApplication>
|
#include <QCoreApplication>
|
||||||
#include <QDateTime>
|
#include <QDateTime>
|
||||||
|
|
||||||
|
#ifdef Q_OS_WIN
|
||||||
|
#include <windows.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <cstring>
|
||||||
|
#endif
|
||||||
|
|
||||||
using namespace ProjectExplorer::Constants;
|
using namespace ProjectExplorer::Constants;
|
||||||
using namespace Utils;
|
using namespace Utils;
|
||||||
|
|
||||||
namespace ProjectExplorer {
|
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()
|
DesktopDevice::DesktopDevice()
|
||||||
{
|
{
|
||||||
setFileAccess(DesktopDeviceFileAccess::instance());
|
setFileAccess(DesktopDeviceFileAccess::instance());
|
||||||
@@ -43,8 +101,14 @@ DesktopDevice::DesktopDevice()
|
|||||||
const QString portRange =
|
const QString portRange =
|
||||||
QString::fromLatin1("%1-%2").arg(DESKTOP_PORT_START).arg(DESKTOP_PORT_END);
|
QString::fromLatin1("%1-%2").arg(DESKTOP_PORT_START).arg(DESKTOP_PORT_END);
|
||||||
setFreePorts(Utils::PortList::fromString(portRange));
|
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);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -436,6 +436,12 @@ DeviceManager::DeviceManager(bool isInstance) : d(std::make_unique<DeviceManager
|
|||||||
return device->ensureReachable(other);
|
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;
|
DeviceProcessHooks processHooks;
|
||||||
|
|
||||||
processHooks.processImplHook = [](const FilePath &filePath) -> ProcessInterface * {
|
processHooks.processImplHook = [](const FilePath &filePath) -> ProcessInterface * {
|
||||||
|
|||||||
Reference in New Issue
Block a user