- Replaced direct calls to GetConfigDirectory with PlatformPaths::GetConfigDirectory across multiple files to standardize configuration directory access. - Updated RecentFilesManager, EditorManager, and various agent components to handle potential errors when retrieving the configuration directory. - Enhanced file loading functions to utilize the new LoadFileFromConfigDir method for improved clarity and error handling. - Introduced new methods in file_util.h for better file management practices, leveraging std::filesystem for cross-platform consistency.
179 lines
4.9 KiB
C++
179 lines
4.9 KiB
C++
#include "util/platform_paths.h"
|
|
|
|
#include <cstdlib>
|
|
|
|
#include "absl/strings/str_cat.h"
|
|
#include "absl/strings/str_replace.h"
|
|
|
|
#ifdef _WIN32
|
|
#include <windows.h>
|
|
#include <shlobj.h>
|
|
#else
|
|
#include <unistd.h>
|
|
#include <pwd.h>
|
|
#endif
|
|
|
|
namespace yaze {
|
|
namespace util {
|
|
|
|
std::filesystem::path PlatformPaths::GetHomeDirectory() {
|
|
#ifdef _WIN32
|
|
// Windows: Use USERPROFILE environment variable
|
|
const char* userprofile = std::getenv("USERPROFILE");
|
|
if (userprofile && *userprofile) {
|
|
return std::filesystem::path(userprofile);
|
|
}
|
|
|
|
// Fallback to HOMEDRIVE + HOMEPATH
|
|
const char* homedrive = std::getenv("HOMEDRIVE");
|
|
const char* homepath = std::getenv("HOMEPATH");
|
|
if (homedrive && homepath) {
|
|
return std::filesystem::path(std::string(homedrive) + std::string(homepath));
|
|
}
|
|
|
|
// Last resort: use temp directory
|
|
return std::filesystem::temp_directory_path();
|
|
#else
|
|
// Unix/macOS: Use HOME environment variable
|
|
const char* home = std::getenv("HOME");
|
|
if (home && *home) {
|
|
return std::filesystem::path(home);
|
|
}
|
|
|
|
// Fallback: try getpwuid
|
|
struct passwd* pw = getpwuid(getuid());
|
|
if (pw && pw->pw_dir) {
|
|
return std::filesystem::path(pw->pw_dir);
|
|
}
|
|
|
|
// Last resort: current directory
|
|
return std::filesystem::current_path();
|
|
#endif
|
|
}
|
|
|
|
absl::StatusOr<std::filesystem::path> PlatformPaths::GetAppDataDirectory() {
|
|
#ifdef _WIN32
|
|
wchar_t path[MAX_PATH];
|
|
if (SUCCEEDED(SHGetFolderPathW(NULL, CSIDL_APPDATA, NULL, 0, path))) {
|
|
std::filesystem::path app_data = std::filesystem::path(path) / "yaze";
|
|
auto status = EnsureDirectoryExists(app_data);
|
|
if (!status.ok()) {
|
|
return status;
|
|
}
|
|
return app_data;
|
|
}
|
|
// Fallback if SHGetFolderPathW fails
|
|
std::filesystem::path home = GetHomeDirectory();
|
|
std::filesystem::path app_data = home / "yaze_data";
|
|
auto status = EnsureDirectoryExists(app_data);
|
|
if (!status.ok()) {
|
|
return status;
|
|
}
|
|
return app_data;
|
|
#elif defined(__APPLE__)
|
|
std::filesystem::path home = GetHomeDirectory();
|
|
std::filesystem::path app_data = home / "Library" / "Application Support" / "yaze";
|
|
auto status = EnsureDirectoryExists(app_data);
|
|
if (!status.ok()) {
|
|
return status;
|
|
}
|
|
return app_data;
|
|
#else // Linux and other Unix-like systems
|
|
const char* xdg_config_home = std::getenv("XDG_CONFIG_HOME");
|
|
std::filesystem::path config_dir;
|
|
if (xdg_config_home && *xdg_config_home) {
|
|
config_dir = std::filesystem::path(xdg_config_home);
|
|
} else {
|
|
config_dir = GetHomeDirectory() / ".config";
|
|
}
|
|
std::filesystem::path app_data = config_dir / "yaze";
|
|
auto status = EnsureDirectoryExists(app_data);
|
|
if (!status.ok()) {
|
|
return status;
|
|
}
|
|
return app_data;
|
|
#endif
|
|
}
|
|
|
|
absl::StatusOr<std::filesystem::path> PlatformPaths::GetConfigDirectory() {
|
|
// For yaze, config and data directories are the same.
|
|
// This provides a semantically clearer API for config access.
|
|
return GetAppDataDirectory();
|
|
}
|
|
|
|
absl::StatusOr<std::filesystem::path> PlatformPaths::GetAppDataSubdirectory(
|
|
const std::string& subdir) {
|
|
auto app_data_result = GetAppDataDirectory();
|
|
if (!app_data_result.ok()) {
|
|
return app_data_result.status();
|
|
}
|
|
|
|
std::filesystem::path subdir_path = *app_data_result / subdir;
|
|
|
|
auto status = EnsureDirectoryExists(subdir_path);
|
|
if (!status.ok()) {
|
|
return status;
|
|
}
|
|
|
|
return subdir_path;
|
|
}
|
|
|
|
absl::Status PlatformPaths::EnsureDirectoryExists(
|
|
const std::filesystem::path& path) {
|
|
if (Exists(path)) {
|
|
return absl::OkStatus();
|
|
}
|
|
|
|
std::error_code ec;
|
|
if (!std::filesystem::create_directories(path, ec)) {
|
|
if (ec) {
|
|
return absl::InternalError(
|
|
absl::StrCat("Failed to create directory: ", path.string(),
|
|
" - Error: ", ec.message()));
|
|
}
|
|
}
|
|
|
|
return absl::OkStatus();
|
|
}
|
|
|
|
bool PlatformPaths::Exists(const std::filesystem::path& path) {
|
|
std::error_code ec;
|
|
bool exists = std::filesystem::exists(path, ec);
|
|
return exists && !ec;
|
|
}
|
|
|
|
absl::StatusOr<std::filesystem::path> PlatformPaths::GetTempDirectory() {
|
|
std::error_code ec;
|
|
std::filesystem::path temp_base = std::filesystem::temp_directory_path(ec);
|
|
|
|
if (ec) {
|
|
return absl::InternalError(
|
|
absl::StrCat("Failed to get temp directory: ", ec.message()));
|
|
}
|
|
|
|
std::filesystem::path yaze_temp = temp_base / "yaze";
|
|
|
|
auto status = EnsureDirectoryExists(yaze_temp);
|
|
if (!status.ok()) {
|
|
return status;
|
|
}
|
|
|
|
return yaze_temp;
|
|
}
|
|
|
|
std::string PlatformPaths::NormalizePathForDisplay(
|
|
const std::filesystem::path& path) {
|
|
// Convert to string and replace backslashes with forward slashes
|
|
// Forward slashes work on all platforms for display purposes
|
|
std::string path_str = path.string();
|
|
return absl::StrReplaceAll(path_str, {{"\\", "/"}});
|
|
}
|
|
|
|
std::string PlatformPaths::ToNativePath(const std::filesystem::path& path) {
|
|
// std::filesystem::path::string() already returns the native format
|
|
return path.string();
|
|
}
|
|
|
|
} // namespace util
|
|
} // namespace yaze
|