diff --git a/src/libs/utils/filepath.h b/src/libs/utils/filepath.h index dfc4af4108a..41aaf7dcccb 100644 --- a/src/libs/utils/filepath.h +++ b/src/libs/utils/filepath.h @@ -283,6 +283,7 @@ public: std::function environment; std::function isSameDevice; std::function(const FilePath &)> localSource; + std::function openTerminal; }; } // Utils diff --git a/src/plugins/coreplugin/coreplugin.cpp b/src/plugins/coreplugin/coreplugin.cpp index e406f5b7a9a..b02a47d4f0e 100644 --- a/src/plugins/coreplugin/coreplugin.cpp +++ b/src/plugins/coreplugin/coreplugin.cpp @@ -347,19 +347,19 @@ void CorePlugin::addToPathChooserContextMenu(Utils::PathChooser *pathChooser, QM QList 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); diff --git a/src/plugins/coreplugin/editormanager/editormanager.cpp b/src/plugins/coreplugin/editormanager/editormanager.cpp index 4128cbdc0d7..2953a833b70 100644 --- a/src/plugins/coreplugin/editormanager/editormanager.cpp +++ b/src/plugins/coreplugin/editormanager/editormanager.cpp @@ -41,6 +41,7 @@ #include #include +#include #include #include #include @@ -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() diff --git a/src/plugins/coreplugin/fileutils.cpp b/src/plugins/coreplugin/fileutils.cpp index 3525d602a6b..05aeb219b2e 100644 --- a/src/plugins/coreplugin/fileutils.cpp +++ b/src/plugins/coreplugin/fileutils.cpp @@ -32,15 +32,6 @@ #include #include -#ifdef Q_OS_WIN - -#include -#include -#include - -#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() diff --git a/src/plugins/coreplugin/fileutils.h b/src/plugins/coreplugin/fileutils.h index f54f890d7ec..2b5c65c800d 100644 --- a/src/plugins/coreplugin/fileutils.h +++ b/src/plugins/coreplugin/fileutils.h @@ -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(); diff --git a/src/plugins/projectexplorer/devicesupport/desktopdevice.cpp b/src/plugins/projectexplorer/devicesupport/desktopdevice.cpp index 097f175d664..57984a6b11c 100644 --- a/src/plugins/projectexplorer/devicesupport/desktopdevice.cpp +++ b/src/plugins/projectexplorer/devicesupport/desktopdevice.cpp @@ -17,16 +17,74 @@ #include #include #include +#include #include #include #include +#ifdef Q_OS_WIN +#include +#include +#include +#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); }); } diff --git a/src/plugins/projectexplorer/devicesupport/devicemanager.cpp b/src/plugins/projectexplorer/devicesupport/devicemanager.cpp index e6ecfe4659b..9f8e0594fd8 100644 --- a/src/plugins/projectexplorer/devicesupport/devicemanager.cpp +++ b/src/plugins/projectexplorer/devicesupport/devicemanager.cpp @@ -436,6 +436,12 @@ DeviceManager::DeviceManager(bool isInstance) : d(std::make_uniqueensureReachable(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 * {