diff options
author | Marcus Tillmanns <[email protected]> | 2025-09-10 11:27:32 +0200 |
---|---|---|
committer | Marcus Tillmanns <[email protected]> | 2025-09-11 06:51:27 +0000 |
commit | b462dd6b597c7f95b3fb56f7b7ebeb1664ab32eb (patch) | |
tree | 714142195bdc4c697b79c4bbbf58a97c55e1e3b4 | |
parent | 8ef92a38e09f26b732f829c0ce6c9617f8ad7c09 (diff) |
Devcontainer: Add (re-)start action to editor toolbar
Change-Id: I12ed3ec85207f4fbbe4242de64f2e68dd034892b
Reviewed-by: David Schulz <[email protected]>
-rw-r--r-- | src/libs/devcontainer/devcontainerconfig.cpp | 31 | ||||
-rw-r--r-- | src/libs/devcontainer/devcontainerconfig.h | 3 | ||||
-rw-r--r-- | src/plugins/devcontainer/CMakeLists.txt | 2 | ||||
-rw-r--r-- | src/plugins/devcontainer/devcontainerplugin.cpp | 80 | ||||
-rw-r--r-- | src/plugins/devcontainer/devcontainerplugin_constants.h | 2 |
5 files changed, 115 insertions, 3 deletions
diff --git a/src/libs/devcontainer/devcontainerconfig.cpp b/src/libs/devcontainer/devcontainerconfig.cpp index 0df9c45117b..632bb1530be 100644 --- a/src/libs/devcontainer/devcontainerconfig.cpp +++ b/src/libs/devcontainer/devcontainerconfig.cpp @@ -1259,4 +1259,35 @@ FilePath Config::workspaceFolder(const Config &config) *config.containerConfig)); } +bool Config::isValidConfigPath( + const Utils::FilePath &workspaceFolder, const Utils::FilePath &configPath) +{ + /* + Possible locations: + .devcontainer.json + .devcontainer/devcontainer.json + .devcontainer/<folder>/devcontainer.json (where <folder> is a sub-folder, one level deep) +*/ + // .devcontainer.json + if (configPath.fileName() == ".devcontainer.json" && configPath.parentDir() == workspaceFolder) + return true; + + if (configPath.fileName() != "devcontainer.json") + return false; + + const FilePath parentDir = configPath.parentDir(); + const FilePath secondLvlParentDir = parentDir.parentDir(); + + // .devcontainer/devcontainer.json + if (parentDir.fileName() == ".devcontainer" && secondLvlParentDir == workspaceFolder) + return true; + + // .devcontainer/<folder>/devcontainer.json (where <folder> is a sub-folder, one level deep) + if (secondLvlParentDir.fileName() == ".devcontainer" + && secondLvlParentDir.parentDir() == workspaceFolder) + return true; + + return false; +} + } // namespace DevContainer diff --git a/src/libs/devcontainer/devcontainerconfig.h b/src/libs/devcontainer/devcontainerconfig.h index 23648e680f7..d12a04e724e 100644 --- a/src/libs/devcontainer/devcontainerconfig.h +++ b/src/libs/devcontainer/devcontainerconfig.h @@ -241,6 +241,9 @@ struct DEVCONTAINER_EXPORT Config const QJsonObject &json, JsonStringToString jsonStringToString); static Utils::Result<Config> fromJson( const QByteArray &data, const JsonStringToString &jsonStringToString); + + static bool isValidConfigPath( + const Utils::FilePath &workspaceFolder, const Utils::FilePath &configPath); }; //! Returns a QJsonValue for the specified path. e.g.: customization(config, "qt-creator/device/mount-cmd-bridge") diff --git a/src/plugins/devcontainer/CMakeLists.txt b/src/plugins/devcontainer/CMakeLists.txt index d3702513547..ed3704b4f8a 100644 --- a/src/plugins/devcontainer/CMakeLists.txt +++ b/src/plugins/devcontainer/CMakeLists.txt @@ -1,5 +1,5 @@ add_qtc_plugin(DevContainerPlugin - PLUGIN_DEPENDS Core ProjectExplorer + PLUGIN_DEPENDS Core ProjectExplorer TextEditor PLUGIN_TEST_DEPENDS CMakeProjectManager DEPENDS DevContainer CmdBridgeClient LONG_DESCRIPTION_MD README.md diff --git a/src/plugins/devcontainer/devcontainerplugin.cpp b/src/plugins/devcontainer/devcontainerplugin.cpp index 9b568f69f94..b6d38c5c53e 100644 --- a/src/plugins/devcontainer/devcontainerplugin.cpp +++ b/src/plugins/devcontainer/devcontainerplugin.cpp @@ -5,6 +5,7 @@ #include "devcontainerplugin_constants.h" #include "devcontainerplugintr.h" +#include <coreplugin/editormanager/editormanager.h> #include <coreplugin/icore.h> #include <coreplugin/messagemanager.h> @@ -22,11 +23,14 @@ #include <projectexplorer/projectmanager.h> #include <projectexplorer/target.h> +#include <texteditor/texteditor.h> + #include <utils/algorithm.h> #include <utils/fsengine/fsengine.h> #include <utils/guardedcallback.h> #include <utils/icon.h> #include <utils/infobar.h> +#include <utils/theme/theme.h> #include <QMessageBox> @@ -35,6 +39,8 @@ using namespace Utils; namespace DevContainer::Internal { +const Icon DEVCONTAINER_ICON({{":/devcontainer/images/container.png", Theme::IconsBaseColor}}); + #ifdef WITH_TESTS QObject *createDevcontainerTest(); #endif @@ -80,6 +86,12 @@ public: this, &DevContainerPlugin::onProjectRemoved); + connect( + Core::EditorManager::instance(), + &Core::EditorManager::editorCreated, + this, + &DevContainerPlugin::onEditorCreated); + for (auto project : ProjectManager::instance()->projects()) onProjectAdded(project); @@ -91,9 +103,12 @@ public: }); #endif } + void onProjectAdded(Project *project); void onProjectRemoved(Project *project); + void onEditorCreated(Core::IEditor *editor, const Utils::FilePath &filePath); + void startDeviceForProject(Project *project, DevContainer::InstanceConfig instanceConfig); #ifdef WITH_TESTS @@ -130,7 +145,7 @@ void DevContainerPlugin::onProjectRemoved(Project *project) devices.erase(it); } -void DevContainerPlugin::onProjectAdded(Project *project) +static FilePaths devContainerFilesForProject(Project *project) { /* Possible locations: @@ -142,12 +157,17 @@ void DevContainerPlugin::onProjectAdded(Project *project) const FilePath rootDevcontainer = project->projectDirectory() / ".devcontainer.json"; const FilePaths paths{rootDevcontainer, containerFolder / ".devcontainer"}; - const FilePaths devContainerFiles = filtered( + return filtered( transform( containerFolder.dirEntries(QDir::Dirs | QDir::NoDotAndDotDot), [](const FilePath &path) { return path / "devcontainer.json"; }) << rootDevcontainer << containerFolder / "devcontainer.json", &FilePath::isFile); +} + +void DevContainerPlugin::onProjectAdded(Project *project) +{ + const FilePaths devContainerFiles = devContainerFilesForProject(project); if (!devContainerFiles.isEmpty()) { const QList<DevContainer::InstanceConfig> instanceConfigs @@ -252,6 +272,62 @@ void DevContainerPlugin::onProjectAdded(Project *project) }; } +void DevContainerPlugin::onEditorCreated(Core::IEditor *editor, const Utils::FilePath &filePath) +{ + if (filePath.fileName() != "devcontainer.json" && filePath.fileName() != ".devcontainer.json") + return; + + auto textEditor = qobject_cast<TextEditor::BaseTextEditor *>(editor); + if (!textEditor) + return; + + Project *project = ProjectManager::projectForFile(filePath); + if (!project) + return; + + if (!DevContainer::Config::isValidConfigPath(project->rootProjectDirectory(), filePath)) + return; + + TextEditor::TextEditorWidget *textEditorWidget = textEditor->editorWidget(); + if (!textEditorWidget) + return; + + QAction *restartAction = new QAction(textEditorWidget); + restartAction->setIcon(DEVCONTAINER_ICON.icon()); + restartAction->setText(Tr::tr("(Re-)Start Development Container")); + restartAction->setToolTip(Tr::tr("Start or Restart the development container.")); + + const FilePath workspaceFolder = project->rootProjectDirectory(); + + connect(restartAction, &QAction::triggered, [this, project, workspaceFolder, filePath]() { + auto it = devices.find(project); + if (it != devices.end()) { + std::shared_ptr<Device> existingDevice = it->second; + existingDevice->restart([](Result<> result) { + if (!result) { + QMessageBox box(Core::ICore::dialogParent()); + box.setWindowTitle(Tr::tr("Development Container Error")); + box.setIcon(QMessageBox::Critical); + box.setText(result.error()); + box.exec(); + } + }); + } else { + DevContainer::InstanceConfig instanceConfig{ + .dockerCli = "docker", + .workspaceFolder = workspaceFolder, + .configFilePath = filePath, + .mounts = {}, + }; + + startDeviceForProject(project, instanceConfig); + } + }); + + textEditorWidget + ->insertExtraToolBarAction(TextEditor::TextEditorWidget::Side::Left, restartAction); +} + void DevContainerPlugin::startDeviceForProject( Project *project, DevContainer::InstanceConfig instanceConfig) { diff --git a/src/plugins/devcontainer/devcontainerplugin_constants.h b/src/plugins/devcontainer/devcontainerplugin_constants.h index e21caa4daf4..81b2abb3bdb 100644 --- a/src/plugins/devcontainer/devcontainerplugin_constants.h +++ b/src/plugins/devcontainer/devcontainerplugin_constants.h @@ -6,4 +6,6 @@ namespace DevContainer::Constants { const char DEVCONTAINER_DEVICE_TYPE[] = "DevContainerDeviceType"; const char16_t DEVCONTAINER_FS_SCHEME[] = u"devcontainer"; + +const char ACTION_START_DEVCONTAINER[] = "devcontainer.start"; } // namespace DevContainer::Constants |