diff --git a/src/core/common/version.hpp b/src/core/common/version.hpp index b570a5a..0e1fa60 100644 --- a/src/core/common/version.hpp +++ b/src/core/common/version.hpp @@ -6,7 +6,7 @@ namespace clrsync::core { -const std::string GIT_SEMVER = "0.1.6+git.g0288773"; +const std::string GIT_SEMVER = "0.1.6+git.g9be0a15"; const std::string version_string(); } // namespace clrsync::core diff --git a/src/core/config/config.cpp b/src/core/config/config.cpp index 0c1bf60..8be5015 100644 --- a/src/core/config/config.cpp +++ b/src/core/config/config.cpp @@ -1,6 +1,7 @@ #include "config.hpp" #include "core/common/error.hpp" #include "core/common/utils.hpp" +#include "core/io/toml_file.hpp" #include "core/palette/color.hpp" #include @@ -31,6 +32,37 @@ Result config::initialize(std::unique_ptr file) return Err(error_code::config_invalid, parse_result.error().message, parse_result.error().context); + std::filesystem::path config_path = get_user_config_dir() / "config.toml"; + std::filesystem::path temp_config_path = get_user_config_dir() / "config-temp.toml"; + + if (std::filesystem::exists(config_path)) + { + std::error_code ec; + auto perms = std::filesystem::status(config_path, ec).permissions(); + + if (ec || (perms & std::filesystem::perms::owner_write) == std::filesystem::perms::none) + { + m_temp_config_path = temp_config_path.string(); + + if (std::filesystem::exists(temp_config_path)) + { + try + { + auto temp_conf = std::make_unique(temp_config_path.string()); + auto temp_parse = temp_conf->parse(); + if (temp_parse) + { + m_temp_file = std::move(temp_conf); + } + } + catch (const std::exception &e) + { + std::cerr << "Warning: Failed to load temp config: " << e.what() << std::endl; + } + } + } + } + return Ok(); } @@ -40,6 +72,30 @@ std::filesystem::path config::get_user_config_dir() return home / ".config" / "clrsync"; } +std::filesystem::path config::get_user_state_dir() +{ + std::filesystem::path home = normalize_path("~"); + return home / ".local" / "state" / "clrsync"; +} + +std::filesystem::path config::get_writable_config_path() +{ + std::filesystem::path config_path = get_user_config_dir() / "config.toml"; + + if (std::filesystem::exists(config_path)) + { + std::error_code ec; + auto perms = std::filesystem::status(config_path, ec).permissions(); + + if (ec || (perms & std::filesystem::perms::owner_write) == std::filesystem::perms::none) + { + return get_user_config_dir() / "config-temp.toml"; + } + } + + return config_path; +} + std::filesystem::path config::get_data_dir() { if (std::filesystem::exists(CLRSYNC_DATADIR)) @@ -135,15 +191,50 @@ void config::copy_default_configs() } } +Result config::save_config_value(const std::string §ion, const std::string &key, const value_type &value) +{ + if (!m_temp_config_path.empty()) + { + if (!m_temp_file) + { + m_temp_file = std::make_unique(m_temp_config_path); + m_temp_file->parse(); + } + + m_temp_file->set_value(section, key, value); + return m_temp_file->save_file(); + } + + m_file->set_value(section, key, value); + return m_file->save_file(); +} + const std::string &config::palettes_path() { if (m_palettes_dir.empty() && m_file) + { + if (m_temp_file) + { + auto temp_value = m_temp_file->get_string_value("general", "palettes_path"); + if (!temp_value.empty()) + { + m_palettes_dir = temp_value; + return m_palettes_dir; + } + } m_palettes_dir = m_file->get_string_value("general", "palettes_path"); + } return m_palettes_dir; } const std::string config::default_theme() const { + if (m_temp_file) + { + auto temp_value = m_temp_file->get_string_value("general", "default_theme"); + if (!temp_value.empty()) + return temp_value; + } if (m_file) return m_file->get_string_value("general", "default_theme"); return {}; @@ -151,6 +242,12 @@ const std::string config::default_theme() const const std::string config::font() const { + if (m_temp_file) + { + auto temp_value = m_temp_file->get_string_value("general", "font"); + if (!temp_value.empty()) + return temp_value; + } if (m_file) return m_file->get_string_value("general", "font"); return {}; @@ -158,6 +255,12 @@ const std::string config::font() const const uint32_t config::font_size() const { + if (m_temp_file) + { + auto temp_value = m_temp_file->get_uint_value("general", "font_size"); + if (temp_value != 0) + return temp_value; + } if (m_file) return m_file->get_uint_value("general", "font_size"); return 14; @@ -168,8 +271,7 @@ Result config::set_default_theme(const std::string &theme) if (!m_file) return Err(error_code::config_missing, "Configuration not initialized"); - m_file->set_value("general", "default_theme", theme); - return m_file->save_file(); + return save_config_value("general", "default_theme", theme); } Result config::set_palettes_path(const std::string &path) @@ -177,8 +279,7 @@ Result config::set_palettes_path(const std::string &path) if (!m_file) return Err(error_code::config_missing, "Configuration not initialized"); - m_file->set_value("general", "palettes_path", path); - return m_file->save_file(); + return save_config_value("general", "palettes_path", path); } Result config::set_font(const std::string &font) @@ -186,16 +287,14 @@ Result config::set_font(const std::string &font) if (!m_file) return Err(error_code::config_missing, "Configuration not initialized"); - m_file->set_value("general", "font", font); - return m_file->save_file(); + return save_config_value("general", "font", font); } Result config::set_font_size(int font_size) { if (!m_file) return Err(error_code::config_missing, "Configuration not initialized"); - m_file->set_value("general", "font_size", font_size); - return m_file->save_file(); + return save_config_value("general", "font_size", static_cast(font_size)); } Result config::update_template(const std::string &key, @@ -205,11 +304,17 @@ Result config::update_template(const std::string &key, return Err(error_code::config_missing, "Configuration not initialized"); m_themes[key] = theme_template; - m_file->set_value("templates." + key, "input_path", theme_template.template_path()); - m_file->set_value("templates." + key, "output_path", theme_template.output_path()); - m_file->set_value("templates." + key, "enabled", theme_template.enabled()); - m_file->set_value("templates." + key, "reload_cmd", theme_template.reload_command()); - return m_file->save_file(); + + auto result1 = save_config_value("templates." + key, "input_path", theme_template.template_path()); + if (!result1) return result1; + + auto result2 = save_config_value("templates." + key, "output_path", theme_template.output_path()); + if (!result2) return result2; + + auto result3 = save_config_value("templates." + key, "enabled", theme_template.enabled()); + if (!result3) return result3; + + return save_config_value("templates." + key, "reload_cmd", theme_template.reload_command()); } Result config::remove_template(const std::string &key) @@ -237,8 +342,18 @@ Result config::remove_template(const std::string &key) m_themes.erase(it); + if (!m_temp_config_path.empty()) + { + if (!m_temp_file) + { + m_temp_file = std::make_unique(m_temp_config_path); + m_temp_file->parse(); + } + m_temp_file->remove_section("templates." + key); + return m_temp_file->save_file(); + } + m_file->remove_section("templates." + key); - return m_file->save_file(); } diff --git a/src/core/config/config.hpp b/src/core/config/config.hpp index 101d713..fee32ff 100644 --- a/src/core/config/config.hpp +++ b/src/core/config/config.hpp @@ -24,6 +24,8 @@ class config const std::unordered_map templates(); Result template_by_name(const std::string &name) const; std::filesystem::path get_user_config_dir(); + std::filesystem::path get_user_state_dir(); + std::filesystem::path get_writable_config_path(); Result set_default_theme(const std::string &theme); Result set_palettes_path(const std::string &path); @@ -42,7 +44,10 @@ class config std::string m_palettes_dir{}; std::unique_ptr m_file; + std::unique_ptr m_temp_file; + std::string m_temp_config_path; std::unordered_map m_themes{}; + Result save_config_value(const std::string §ion, const std::string &key, const value_type &value); static void copy_file(const std::filesystem::path &src, const std::filesystem::path &dst); static void copy_dir(const std::filesystem::path &src, const std::filesystem::path &dst); void copy_default_configs();