feat: add editor project switching workflow
This commit is contained in:
119
editor/src/Utils/ProjectFileUtils.h
Normal file
119
editor/src/Utils/ProjectFileUtils.h
Normal file
@@ -0,0 +1,119 @@
|
||||
#pragma once
|
||||
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
|
||||
namespace XCEngine {
|
||||
namespace Editor {
|
||||
namespace ProjectFileUtils {
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
struct ProjectDescriptor {
|
||||
std::string name;
|
||||
std::string startupScene;
|
||||
};
|
||||
|
||||
inline fs::path GetProjectFilePath(const std::string& projectRoot) {
|
||||
return fs::path(projectRoot) / "Project.xcproject";
|
||||
}
|
||||
|
||||
inline std::string GetProjectName(const std::string& projectRoot) {
|
||||
const fs::path rootPath(projectRoot);
|
||||
const fs::path folderName = rootPath.filename().empty() ? rootPath.parent_path().filename() : rootPath.filename();
|
||||
return folderName.empty() ? "XCEngineProject" : folderName.string();
|
||||
}
|
||||
|
||||
inline std::string Trim(const std::string& value) {
|
||||
const size_t begin = value.find_first_not_of(" \t\r\n");
|
||||
if (begin == std::string::npos) {
|
||||
return {};
|
||||
}
|
||||
|
||||
const size_t end = value.find_last_not_of(" \t\r\n");
|
||||
return value.substr(begin, end - begin + 1);
|
||||
}
|
||||
|
||||
inline bool SaveProjectDescriptor(const std::string& projectRoot, const ProjectDescriptor& descriptor) {
|
||||
std::error_code ec;
|
||||
fs::create_directories(fs::path(projectRoot), ec);
|
||||
|
||||
std::ofstream output(GetProjectFilePath(projectRoot), std::ios::out | std::ios::trunc);
|
||||
if (!output.is_open()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
output << "version=1\n";
|
||||
output << "name=" << descriptor.name << "\n";
|
||||
output << "startup_scene=" << descriptor.startupScene << "\n";
|
||||
return output.good();
|
||||
}
|
||||
|
||||
inline std::optional<ProjectDescriptor> LoadProjectDescriptor(const std::string& projectRoot) {
|
||||
std::ifstream input(GetProjectFilePath(projectRoot));
|
||||
if (!input.is_open()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
ProjectDescriptor descriptor;
|
||||
descriptor.name = GetProjectName(projectRoot);
|
||||
|
||||
std::string line;
|
||||
while (std::getline(input, line)) {
|
||||
const size_t equalsPos = line.find('=');
|
||||
if (equalsPos == std::string::npos) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const std::string key = Trim(line.substr(0, equalsPos));
|
||||
const std::string value = Trim(line.substr(equalsPos + 1));
|
||||
if (key == "name") {
|
||||
descriptor.name = value;
|
||||
} else if (key == "startup_scene") {
|
||||
descriptor.startupScene = value;
|
||||
}
|
||||
}
|
||||
|
||||
return descriptor;
|
||||
}
|
||||
|
||||
inline std::string MakeProjectRelativePath(const std::string& projectRoot, const std::string& fullPath) {
|
||||
if (projectRoot.empty() || fullPath.empty()) {
|
||||
return {};
|
||||
}
|
||||
|
||||
std::error_code ec;
|
||||
const fs::path root = fs::weakly_canonical(fs::path(projectRoot), ec);
|
||||
ec.clear();
|
||||
const fs::path target = fs::weakly_canonical(fs::path(fullPath), ec);
|
||||
if (ec) {
|
||||
return fullPath;
|
||||
}
|
||||
|
||||
ec.clear();
|
||||
const fs::path relative = fs::relative(target, root, ec);
|
||||
if (ec) {
|
||||
return fullPath;
|
||||
}
|
||||
|
||||
return relative.lexically_normal().generic_string();
|
||||
}
|
||||
|
||||
inline std::string ResolveProjectPath(const std::string& projectRoot, const std::string& pathValue) {
|
||||
if (pathValue.empty()) {
|
||||
return {};
|
||||
}
|
||||
|
||||
const fs::path path(pathValue);
|
||||
if (path.is_absolute()) {
|
||||
return path.lexically_normal().string();
|
||||
}
|
||||
|
||||
return (fs::path(projectRoot) / path).lexically_normal().string();
|
||||
}
|
||||
|
||||
} // namespace ProjectFileUtils
|
||||
} // namespace Editor
|
||||
} // namespace XCEngine
|
||||
Reference in New Issue
Block a user