From fb98fe6106cbdc9da3b008344da7ff44b4a37d55 Mon Sep 17 00:00:00 2001 From: GigabiteStudios Date: Thu, 18 Jun 2026 23:49:14 -0500 Subject: [PATCH] feat(refresh): add timed background repository reloads --- src/models/repository.h | 3 +++ src/ui/gitree_ui.cpp | 48 ++++++++++++++++++++++++++++++++++++++--- 2 files changed, 48 insertions(+), 3 deletions(-) diff --git a/src/models/repository.h b/src/models/repository.h index 476e38d..db5a078 100644 --- a/src/models/repository.h +++ b/src/models/repository.h @@ -1,6 +1,7 @@ #pragma once #include +#include #include #include #include @@ -85,6 +86,8 @@ struct RepositoryView { std::vector working_files; int selected_commit = 0; int scroll_to_commit = -1; + std::chrono::steady_clock::time_point last_background_refresh{}; + bool pending_background_refresh = false; ToolbarHistoryAction undo_action; ToolbarHistoryAction redo_action; diff --git a/src/ui/gitree_ui.cpp b/src/ui/gitree_ui.cpp index 7194998..f3b9091 100644 --- a/src/ui/gitree_ui.cpp +++ b/src/ui/gitree_ui.cpp @@ -116,6 +116,9 @@ float g_outline_icon_size = 15.0f; enum class ToolbarActionRequest { none, pull, push }; ToolbarActionRequest g_pending_toolbar_action = ToolbarActionRequest::none; ToolbarActionRequest g_running_toolbar_action = ToolbarActionRequest::none; +using RefreshClock = std::chrono::steady_clock; +constexpr auto active_refresh_interval = std::chrono::seconds(2); +constexpr auto background_refresh_interval = std::chrono::seconds(5); float ui(float value) { return value * g_ui_scale; } @@ -175,11 +178,45 @@ bool copy_to_clipboard(std::string_view text, const char* description) { return true; } +void mark_repository_refreshed(RepositoryView& repository) { + repository.last_background_refresh = RefreshClock::now(); + repository.pending_background_refresh = false; +} + +bool reload_repository_background(RepositoryView& repository, bool surface_errors = false) { + if (!g_git_manager || !repository.repo || repository.path.empty()) return false; + std::string error; + repository.pending_background_refresh = false; + repository.last_background_refresh = RefreshClock::now(); + if (!g_git_manager->reload(repository, error)) { + if (surface_errors && !error.empty()) g_notice = error; + return false; + } + return true; +} + +void process_repository_background_refreshes() { + if (!g_git_manager || g_tabs.empty()) return; + if (g_running_toolbar_action != ToolbarActionRequest::none) return; + if (!g_running_branch_checkout.empty() || !g_requested_branch_checkout.empty()) return; + const RefreshClock::time_point now = RefreshClock::now(); + for (size_t index = 0; index < g_tabs.size(); ++index) { + RepositoryView& repository = *g_tabs[index]; + if (!repository.repo || repository.path.empty()) continue; + const auto interval = index == g_active_tab ? active_refresh_interval : background_refresh_interval; + const bool due = repository.pending_background_refresh || + repository.last_background_refresh.time_since_epoch().count() == 0 || + now - repository.last_background_refresh >= interval; + if (due) reload_repository_background(repository, index == g_active_tab); + } +} + bool run_repository_action(const std::vector& arguments, const std::string& success_notice, const std::string& focus_commit = {}) { std::string output; if (!g_git_manager->captureGit(repo(), arguments, output, g_notice)) return false; if (!g_git_manager->reload(repo(), g_notice)) return false; + mark_repository_refreshed(repo()); if (!focus_commit.empty()) g_pending_commit_jump = focus_commit; g_notice = success_notice; return true; @@ -295,6 +332,7 @@ void activate_repository_tab(size_t index) { g_active_tab = index; g_tab_to_select = g_tabs[index].get(); reset_repository_view(); + g_tabs[index]->pending_background_refresh = true; persist_repository_session(); } @@ -322,6 +360,7 @@ void close_tab(size_t index) { bool open_repository(const char* path) { const bool opened = g_git_manager->openRepository(repo(), path, g_notice); if (opened) { + mark_repository_refreshed(repo()); if (g_user_data && path && *path) g_user_data->addRecentRepository(path); reset_repository_view(); persist_repository_session(); @@ -2844,7 +2883,7 @@ void draw_popups() { std::string output; g_git_manager->captureGit(repo(), {"lfs", "install", "--local"}, output, g_notice); } - g_git_manager->reload(repo(), g_notice); + if (g_git_manager->reload(repo(), g_notice)) mark_repository_refreshed(repo()); ImGui::CloseCurrentPopup(); } } @@ -3086,7 +3125,8 @@ void draw_app() { } if (ImGui::BeginMenu("Edit")) { ImGui::MenuItem("Preferences", nullptr, false, false); ImGui::EndMenu(); } if (ImGui::BeginMenu("View")) { - if (ImGui::MenuItem("Refresh", "F5")) g_git_manager->reload(repo(), g_notice); + if (ImGui::MenuItem("Refresh", "F5") && g_git_manager->reload(repo(), g_notice)) + mark_repository_refreshed(repo()); ImGui::EndMenu(); } if (ImGui::BeginMenu("Help")) { @@ -3431,7 +3471,8 @@ int runGitree(int argc, char** argv) { } else if (!user_data.openRepositories().empty()) { for (const std::string& path : user_data.openRepositories()) { g_tabs.push_back(std::make_unique()); - if (!path.empty()) git_manager.openRepository(*g_tabs.back(), path, g_notice); + if (!path.empty() && git_manager.openRepository(*g_tabs.back(), path, g_notice)) + mark_repository_refreshed(*g_tabs.back()); } g_active_tab = std::min(user_data.activeRepository(), g_tabs.size() - 1); g_tab_to_select = g_tabs[g_active_tab].get(); @@ -3457,6 +3498,7 @@ int runGitree(int argc, char** argv) { while (!window_manager.shouldClose()) { window_manager.pollEvents(); + process_repository_background_refreshes(); const bool dpi_changed = window_manager.consumeDpiChange(); if (dpi_changed || g_zoom_reload_requested) { load_fonts(combined_ui_scale(window_manager.dpiScale(), g_zoom_percent));