aboutsummaryrefslogtreecommitdiff
path: root/src/app/mod.rs
diff options
context:
space:
mode:
authorCan Celik <ogulcancelik@gmail.com>2026-07-25 04:26:55 +0300
committerGitHub <noreply@github.com>2026-07-25 04:26:55 +0300
commitd4e0dd3d903c50d2edb8c3cec71952a83989b310 (patch)
treec90ec43a08fab1fc79e1d6db865c723877a051af /src/app/mod.rs
parentb33e5f973fc89381aa4ac72b3a31fa087ec66e23 (diff)
perf: eliminate repeated workspace git discovery (#1842)
* perf: eliminate repeated workspace git discovery refs #1838 * fix: keep workspace labels current without extra redraws refs #1838 * fix: retain discovered workspace git metadata refs #1838
Diffstat (limited to 'src/app/mod.rs')
-rw-r--r--src/app/mod.rs50
1 files changed, 45 insertions, 5 deletions
diff --git a/src/app/mod.rs b/src/app/mod.rs
index 84f6d917..c2d479b3 100644
--- a/src/app/mod.rs
+++ b/src/app/mod.rs
@@ -12,6 +12,7 @@ mod api;
mod api_helpers;
mod config_io;
mod creation;
+mod git_refresh;
mod ids;
mod input;
mod popup;
@@ -38,6 +39,7 @@ pub(crate) const HEADLESS_ANIMATION_TICK_STEP: u32 = 8;
pub(crate) const SELECTION_AUTOSCROLL_INTERVAL: Duration = Duration::from_millis(30);
const RESIZE_POLL_INTERVAL: Duration = Duration::from_millis(100);
const GIT_REMOTE_STATUS_REFRESH_INTERVAL: Duration = Duration::from_millis(1500);
+const GIT_REPO_DISCOVERY_REFRESH_INTERVAL: Duration = Duration::from_secs(5 * 60);
const AUTO_UPDATE_CHECK_INTERVAL: Duration = Duration::from_secs(30 * 60);
const PENDING_AGENT_RESUME_THEME_WAIT: Duration = Duration::from_millis(750);
const SESSION_SAVE_DEBOUNCE: Duration = Duration::from_secs(5);
@@ -110,8 +112,10 @@ pub struct App {
pub(crate) copy_feedback_deadline: Option<Instant>,
pub(crate) last_api_notification_at: Option<Instant>,
pub(crate) last_git_remote_status_refresh: Instant,
+ pub(crate) last_git_repo_discovery_refresh: Instant,
pub(crate) git_refresh_in_flight: bool,
pub(crate) git_refresh_due_after_in_flight: bool,
+ pub(crate) git_identity_refresh_requested: bool,
pub(crate) git_status_cache: HashMap<std::path::PathBuf, crate::workspace::GitStatusCacheEntry>,
pub(crate) pending_api_worktree_creates: HashMap<std::path::PathBuf, u64>,
pub(crate) pending_api_worktree_removes: HashMap<String, u64>,
@@ -736,8 +740,10 @@ impl App {
event_tx,
event_rx,
last_git_remote_status_refresh: Instant::now() - GIT_REMOTE_STATUS_REFRESH_INTERVAL,
+ last_git_repo_discovery_refresh: Instant::now(),
git_refresh_in_flight: false,
git_refresh_due_after_in_flight: false,
+ git_identity_refresh_requested: false,
git_status_cache: HashMap::new(),
pending_api_worktree_creates: HashMap::new(),
pending_api_worktree_removes: HashMap::new(),
@@ -892,10 +898,11 @@ impl App {
pub(crate) fn handle_internal_event_with_prefix_sync(
&mut self,
event: crate::events::AppEvent,
- ) {
+ ) -> bool {
let previous_mode = self.state.mode;
- self.handle_internal_event(event);
+ let changed = self.handle_internal_event_with_render_impact(event);
self.sync_prefix_input_source(previous_mode);
+ changed
}
#[cfg(test)]
@@ -1126,8 +1133,9 @@ impl App {
match event {
LoopEvent::Timer => {}
LoopEvent::Internal(ev) => {
- self.handle_internal_event_with_prefix_sync(ev);
- needs_render = true;
+ if self.handle_internal_event_with_prefix_sync(ev) {
+ needs_render = true;
+ }
}
LoopEvent::Api(msg) => {
if self.handle_api_request_message(*msg) {
@@ -2131,6 +2139,20 @@ mod tests {
}
#[test]
+ fn unchanged_git_status_event_has_no_render_impact() {
+ let mut app = test_app();
+ app.git_refresh_in_flight = true;
+
+ let changed = app.handle_internal_event_with_prefix_sync(AppEvent::GitStatusRefreshed {
+ results: Vec::new(),
+ cache_updates: Vec::new(),
+ });
+
+ assert!(!changed);
+ assert!(!app.git_refresh_in_flight);
+ }
+
+ #[test]
fn git_status_event_clears_in_flight_refresh() {
let mut app = test_app();
app.git_refresh_in_flight = true;
@@ -2157,7 +2179,10 @@ mod tests {
app.handle_internal_event(AppEvent::GitStatusRefreshed {
results: vec![crate::workspace::WorkspaceGitStatus {
workspace_id,
- resolved_identity_cwd,
+ resolved_identity_cwd: resolved_identity_cwd.clone(),
+ status_cache_key: resolved_identity_cwd,
+ demand: crate::workspace::GitStatusRefreshDemand::ALL,
+ auto_label: "one".into(),
branch: Some("render-dirty-test".into()),
ahead_behind: Some((1, 0)),
space: None,
@@ -2388,6 +2413,21 @@ mod tests {
}
#[test]
+ fn unchanged_git_status_drain_has_no_render_impact() {
+ let mut app = test_app();
+ app.git_refresh_in_flight = true;
+ app.event_tx
+ .try_send(AppEvent::GitStatusRefreshed {
+ results: Vec::new(),
+ cache_updates: Vec::new(),
+ })
+ .unwrap();
+
+ assert!(!app.drain_internal_events());
+ assert!(!app.git_refresh_in_flight);
+ }
+
+ #[test]
fn internal_event_drain_limits_work_per_tick() {
let mut app = test_app();
for i in 0..=APP_EVENT_DRAIN_LIMIT {