From 069d4e341fd991ef66fb001c9a042f53013df5d8 Mon Sep 17 00:00:00 2001 From: GigabiteStudios Date: Fri, 19 Jun 2026 16:57:18 -0500 Subject: [PATCH] fix(user-data): keep ikvxx persistence in text format --- src/managers/user_data.cpp | 131 ++++++++++++++++++++----------------- 1 file changed, 71 insertions(+), 60 deletions(-) diff --git a/src/managers/user_data.cpp b/src/managers/user_data.cpp index b59e3ca..5ec69b5 100644 --- a/src/managers/user_data.cpp +++ b/src/managers/user_data.cpp @@ -2,10 +2,6 @@ #include #include -extern "C" -{ -#include -} #include #include @@ -133,6 +129,15 @@ namespace } } + std::optional readFloat(const ikv::Value &value) + { + if (value.isDouble()) + return static_cast(value.asDouble()); + if (value.isInt()) + return static_cast(value.asInt64()); + return std::nullopt; + } + // Load settings from an ikv::Value "settings" object into UserData fields. // Returns true if anything useful was read. void loadSettings(const ikv::Value &settings, float &sidebar_width, float &details_width, @@ -142,16 +147,20 @@ namespace std::array &sidebar_section_open, std::array &commit_table_column_widths) { - if (settings.isMember("sidebar_width") && settings["sidebar_width"].isDouble()) - sidebar_width = static_cast(settings["sidebar_width"].asDouble()); - if (settings.isMember("details_width") && settings["details_width"].isDouble()) - details_width = static_cast(settings["details_width"].asDouble()); + if (settings.isMember("sidebar_width")) + if (const auto value = readFloat(settings["sidebar_width"]); value) + sidebar_width = *value; + if (settings.isMember("details_width")) + if (const auto value = readFloat(settings["details_width"]); value) + details_width = *value; if (settings.isMember("sidebar_collapsed") && settings["sidebar_collapsed"].isBool()) sidebar_collapsed = settings["sidebar_collapsed"].asBool(); - if (settings.isMember("commit_message_height") && settings["commit_message_height"].isDouble()) - commit_message_height = static_cast(settings["commit_message_height"].asDouble()); - if (settings.isMember("working_composer_height") && settings["working_composer_height"].isDouble()) - working_composer_height = static_cast(settings["working_composer_height"].asDouble()); + if (settings.isMember("commit_message_height")) + if (const auto value = readFloat(settings["commit_message_height"]); value) + commit_message_height = *value; + if (settings.isMember("working_composer_height")) + if (const auto value = readFloat(settings["working_composer_height"]); value) + working_composer_height = *value; if (settings.isMember("pull_mode") && settings["pull_mode"].isInt()) pull_mode = static_cast(settings["pull_mode"].asInt64()); if (settings.isMember("zoom_percent") && settings["zoom_percent"].isInt()) @@ -162,7 +171,8 @@ namespace const ikv::Value &arr = settings["sidebar_sections"]; const auto count = std::min(arr.size(), sidebar_section_heights.size()); for (std::size_t i = 0; i < count; ++i) - sidebar_section_heights[i] = static_cast(arr[static_cast(i)].asDouble()); + if (const auto value = readFloat(arr[static_cast(i)]); value) + sidebar_section_heights[i] = *value; } if (settings.isMember("sidebar_section_open") && settings["sidebar_section_open"].isArray()) { @@ -176,7 +186,8 @@ namespace const ikv::Value &arr = settings["commit_table_columns"]; const auto count = std::min(arr.size(), commit_table_column_widths.size()); for (std::size_t i = 0; i < count; ++i) - commit_table_column_widths[i] = static_cast(arr[static_cast(i)].asDouble()); + if (const auto value = readFloat(arr[static_cast(i)]); value) + commit_table_column_widths[i] = *value; } } } // namespace @@ -234,7 +245,17 @@ void UserData::load() // ── Primary load: iKvxx binary (.ikv) ──────────────────────────────────── try { - ikv::Value root = ikv::Value::loadBinary(binary_path.string()); + const ikv::Value root = [&]() -> ikv::Value + { + try + { + return ikv::Value::load(binary_path.string()); + } + catch (const ikv::Error &) + { + return ikv::Value::loadBinary(binary_path.string()); + } + }(); if (root.isMember("settings") && root["settings"].isObject()) { @@ -536,76 +557,66 @@ void UserData::setPendingCommitDescription(const std::string &repo_path, const s void UserData::save() const { std::filesystem::create_directories(directory_); + ikv::Value root(ikv::objectValue, "gitree"); - ikv_node_t *root = ikv_create_object("gitree"); - if (!root) - return; + auto settings = root.makeObject("settings"); + settings["sidebar_width"] = static_cast(sidebar_width_); + settings["details_width"] = static_cast(details_width_); + settings["sidebar_collapsed"] = sidebar_collapsed_; + settings["commit_message_height"] = static_cast(commit_message_height_); + settings["working_composer_height"] = static_cast(working_composer_height_); + settings["pull_mode"] = static_cast(pull_mode_); + settings["zoom_percent"] = static_cast(zoom_percent_); - // ── settings ───────────────────────────────────────────────────────────── - ikv_node_t *settings = ikv_object_add_object(root, "settings"); - ikv_object_set_float(settings, "sidebar_width", sidebar_width_); - ikv_object_set_float(settings, "details_width", details_width_); - ikv_object_set_bool(settings, "sidebar_collapsed", sidebar_collapsed_); - ikv_object_set_float(settings, "commit_message_height", commit_message_height_); - ikv_object_set_float(settings, "working_composer_height", working_composer_height_); - ikv_object_set_int(settings, "pull_mode", pull_mode_); - ikv_object_set_int(settings, "zoom_percent", zoom_percent_); - - ikv_node_t *heights = ikv_object_add_array(settings, "sidebar_sections", IKV_FLOAT); + auto heights = settings.makeArray("sidebar_sections", ikv::realValue); for (const float h : sidebar_section_heights_) - ikv_array_add_float(heights, h); + heights.append(static_cast(h)); - ikv_node_t *open = ikv_object_add_array(settings, "sidebar_section_open", IKV_BOOL); + auto open = settings.makeArray("sidebar_section_open", ikv::booleanValue); for (const bool b : sidebar_section_open_) - ikv_array_add_bool(open, b); + open.append(b); - ikv_node_t *col_widths = ikv_object_add_array(settings, "commit_table_columns", IKV_FLOAT); + auto col_widths = settings.makeArray("commit_table_columns", ikv::realValue); for (const float w : commit_table_column_widths_) - ikv_array_add_float(col_widths, w); + col_widths.append(static_cast(w)); - // ── per-repository settings ─────────────────────────────────────────────── - ikv_node_t *repos = ikv_object_add_array(root, "repository_settings", IKV_OBJECT); + auto repos = root.makeArray("repository_settings", ikv::objectValue); for (const auto &[repo_path, rs] : repo_settings_) { - ikv_node_t *entry = ikv_array_add_object(repos); - ikv_object_set_string(entry, "path", repo_path.c_str()); - ikv_node_t *rw = ikv_object_add_array(entry, "commit_table_columns", IKV_FLOAT); + auto entry = repos.appendObject(); + entry["path"] = repo_path; + auto rw = entry.makeArray("commit_table_columns", ikv::realValue); for (const float w : rs.column_widths) - ikv_array_add_float(rw, w); + rw.append(static_cast(w)); if (!rs.pending_commit_summary.empty()) - ikv_object_set_string(entry, "commit_summary", rs.pending_commit_summary.c_str()); + entry["commit_summary"] = rs.pending_commit_summary; if (!rs.pending_commit_description.empty()) - ikv_object_set_string(entry, "commit_description", rs.pending_commit_description.c_str()); + entry["commit_description"] = rs.pending_commit_description; } - // ── recently closed ─────────────────────────────────────────────────────── - ikv_node_t *history = ikv_object_add_array(root, "recently_closed", IKV_STRING); + auto history = root.makeArray("recently_closed", ikv::stringValue); for (const auto &p : recently_closed_) - ikv_array_add_string(history, p.c_str()); + history.append(p); - // ── recent repositories ─────────────────────────────────────────────────── - ikv_node_t *recent = ikv_object_add_array(root, "recent_repositories", IKV_STRING); + auto recent = root.makeArray("recent_repositories", ikv::stringValue); for (const auto &p : recent_repositories_) - ikv_array_add_string(recent, p.c_str()); + recent.append(p); - // ── session ─────────────────────────────────────────────────────────────── - ikv_node_t *session = ikv_object_add_object(root, "session"); - ikv_object_set_int(session, "active_tab", static_cast(active_repository_)); - ikv_node_t *tabs = ikv_object_add_array(session, "tabs", IKV_STRING); + auto session = root.makeObject("session"); + session["active_tab"] = static_cast(active_repository_); + auto tabs = session.makeArray("tabs", ikv::stringValue); for (const auto &p : open_repositories_) - ikv_array_add_string(tabs, p.c_str()); + tabs.append(p); - // ── credentials ─────────────────────────────────────────────────────────── - ikv_node_t *credentials = ikv_object_add_array(root, "credentials", IKV_OBJECT); + auto credentials = root.makeArray("credentials", ikv::objectValue); for (const auto &[scope, secret] : encrypted_credentials_) { - ikv_node_t *entry = ikv_array_add_object(credentials); - ikv_object_set_string(entry, "scope", scope.c_str()); - ikv_object_set_string(entry, "secret", secret.c_str()); + auto entry = credentials.appendObject(); + entry["scope"] = scope; + entry["secret"] = secret; } - ikvb_write_file_version(dataPath().string().c_str(), root, IKV_VERSION_2); - ikv_free(root); + root.write(dataPath().string(), ikv::Version::v2); removeLegacyFiles(); }