From 94e6d5276e64edc4ad18155cd17cf26b8defaaf3 Mon Sep 17 00:00:00 2001 From: Kelsi Date: Tue, 5 May 2026 09:45:00 -0700 Subject: [PATCH] feat(editor): git integration for collaborative expansion development - File > Project > Git submenu: Init, Commit, Push, Pull operations - Init Git Repo: initializes git in the project directory with initial commit - Commit Changes: auto-saves zone then commits all changes - Push/Pull: sync with remote repositories for team collaboration - Git Status: shows current repo state directly in the menu - Teams can collaborate on custom expansions using standard git workflows --- tools/editor/editor_project.cpp | 36 +++++++++++++++++++++++++++++++++ tools/editor/editor_project.hpp | 7 +++++++ tools/editor/editor_ui.cpp | 21 +++++++++++++++++++ 3 files changed, 64 insertions(+) diff --git a/tools/editor/editor_project.cpp b/tools/editor/editor_project.cpp index d9f1a265..0789ed5a 100644 --- a/tools/editor/editor_project.cpp +++ b/tools/editor/editor_project.cpp @@ -100,6 +100,42 @@ bool EditorProject::load(const std::string& path) { return true; } +bool EditorProject::initGitRepo() const { + if (projectDir.empty()) return false; + int ret = std::system(("cd \"" + projectDir + "\" && git init && git add -A && " + "git commit -m \"Initial project commit\"").c_str()); + return ret == 0; +} + +bool EditorProject::gitCommit(const std::string& message) const { + if (projectDir.empty()) return false; + int ret = std::system(("cd \"" + projectDir + "\" && git add -A && " + "git commit -m \"" + message + "\"").c_str()); + return ret == 0; +} + +bool EditorProject::gitPush() const { + if (projectDir.empty()) return false; + return std::system(("cd \"" + projectDir + "\" && git push").c_str()) == 0; +} + +bool EditorProject::gitPull() const { + if (projectDir.empty()) return false; + return std::system(("cd \"" + projectDir + "\" && git pull").c_str()) == 0; +} + +std::string EditorProject::gitStatus() const { + if (projectDir.empty()) return "No project directory"; + std::string cmd = "cd \"" + projectDir + "\" && git status --short 2>&1"; + FILE* pipe = popen(cmd.c_str(), "r"); + if (!pipe) return "git not available"; + char buf[256]; + std::string result; + while (fgets(buf, sizeof(buf), pipe)) result += buf; + pclose(pipe); + return result.empty() ? "Clean (no changes)" : result; +} + std::string EditorProject::getZoneOutputDir(int zoneIdx) const { if (zoneIdx < 0 || zoneIdx >= static_cast(zones.size())) return ""; return projectDir + "/" + zones[zoneIdx].mapName; diff --git a/tools/editor/editor_project.hpp b/tools/editor/editor_project.hpp index 97fbe887..7f973336 100644 --- a/tools/editor/editor_project.hpp +++ b/tools/editor/editor_project.hpp @@ -26,6 +26,13 @@ struct EditorProject { bool save(const std::string& path) const; bool load(const std::string& path); std::string getZoneOutputDir(int zoneIdx) const; + + // Git integration for collaborative expansion development + bool initGitRepo() const; + bool gitCommit(const std::string& message) const; + bool gitPush() const; + bool gitPull() const; + std::string gitStatus() const; }; } // namespace editor diff --git a/tools/editor/editor_ui.cpp b/tools/editor/editor_ui.cpp index 15e352c5..0d2dad6f 100644 --- a/tools/editor/editor_ui.cpp +++ b/tools/editor/editor_ui.cpp @@ -172,6 +172,27 @@ void EditorUI::renderMenuBar(EditorApp& app) { } ImGui::EndMenu(); } + ImGui::Separator(); + if (ImGui::BeginMenu("Git (Collaboration)")) { + if (ImGui::MenuItem("Init Git Repo")) { + if (app.getProject().initGitRepo()) + app.showToast("Git repo initialized"); + else + app.showToast("Git init failed"); + } + if (ImGui::MenuItem("Commit Changes")) { + app.quickSave(); + if (app.getProject().gitCommit("Editor save")) + app.showToast("Changes committed"); + } + if (ImGui::MenuItem("Push to Remote")) + app.getProject().gitPush() ? app.showToast("Pushed") : app.showToast("Push failed"); + if (ImGui::MenuItem("Pull from Remote")) + app.getProject().gitPull() ? app.showToast("Pulled") : app.showToast("Pull failed"); + ImGui::Separator(); + ImGui::TextWrapped("%s", app.getProject().gitStatus().c_str()); + ImGui::EndMenu(); + } ImGui::Text("Project: %s (%zu zones)", app.getProject().name.c_str(), app.getProject().zones.size());