feat(refresh): add timed background repository reloads

This commit is contained in:
2026-06-18 23:49:14 -05:00
parent c99f0cc34a
commit fb98fe6106
2 changed files with 48 additions and 3 deletions

View File

@@ -1,6 +1,7 @@
#pragma once
#include <git2.h>
#include <chrono>
#include <map>
#include <set>
#include <string>
@@ -85,6 +86,8 @@ struct RepositoryView {
std::vector<WorkingFile> 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;

View File

@@ -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<std::string>& 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<RepositoryView>());
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));