Fix flickering when staging and unstaging files (#27931)

Cole Miller created

This fixes a bug in #27568 that caused flickering in the git panel's
checkbox state when staging and unstaging entire files. The problem is
that that stage/unstage action first saves the target path (if it's open
as a buffer), and we do a targeted git status scan in response to that
filesystem event, which makes its way to the git panel and causes it to
clear its pending state before the actual stage or unstage has gone
through.

The fix is to not clear the panel's pending state for git repository
events that originated from a targeted scan (i.e. one that was triggered
by FS events for repo paths, as opposed to events inside `.git` which
cause all statuses to be recomputed).

Release Notes:

- N/A

Change summary

crates/editor/src/git/blame.rs    | 2 +-
crates/git_ui/src/git_panel.rs    | 8 ++++++--
crates/git_ui/src/project_diff.rs | 2 +-
crates/project/src/git_store.rs   | 8 ++++----
4 files changed, 12 insertions(+), 8 deletions(-)

Detailed changes

crates/editor/src/git/blame.rs 🔗

@@ -212,7 +212,7 @@ impl GitBlame {
         let git_store = project.read(cx).git_store().clone();
         let git_store_subscription =
             cx.subscribe(&git_store, move |this, _, event, cx| match event {
-                GitStoreEvent::RepositoryUpdated(_, RepositoryEvent::Updated, _)
+                GitStoreEvent::RepositoryUpdated(_, RepositoryEvent::Updated { .. }, _)
                 | GitStoreEvent::RepositoryAdded(_)
                 | GitStoreEvent::RepositoryRemoved(_) => {
                     log::debug!("Status of git repositories updated. Regenerating blame data...",);

crates/git_ui/src/git_panel.rs 🔗

@@ -408,8 +408,12 @@ impl GitPanel {
                     this.active_repository = git_store.read(cx).active_repository();
                     this.schedule_update(true, window, cx);
                 }
-                GitStoreEvent::RepositoryUpdated(_, RepositoryEvent::Updated, true) => {
-                    this.schedule_update(true, window, cx);
+                GitStoreEvent::RepositoryUpdated(
+                    _,
+                    RepositoryEvent::Updated { full_scan },
+                    true,
+                ) => {
+                    this.schedule_update(*full_scan, window, cx);
                 }
                 GitStoreEvent::RepositoryUpdated(_, _, _) => {}
                 GitStoreEvent::RepositoryAdded(_) | GitStoreEvent::RepositoryRemoved(_) => {

crates/git_ui/src/project_diff.rs 🔗

@@ -154,7 +154,7 @@ impl ProjectDiff {
             window,
             move |this, _git_store, event, _window, _cx| match event {
                 GitStoreEvent::ActiveRepositoryChanged(_)
-                | GitStoreEvent::RepositoryUpdated(_, RepositoryEvent::Updated, true) => {
+                | GitStoreEvent::RepositoryUpdated(_, RepositoryEvent::Updated { .. }, true) => {
                     *this.update_needed.borrow_mut() = ();
                 }
                 _ => {}

crates/project/src/git_store.rs 🔗

@@ -258,7 +258,7 @@ pub enum RepositoryState {
 
 #[derive(Clone, Debug)]
 pub enum RepositoryEvent {
-    Updated,
+    Updated { full_scan: bool },
     MergeHeadsChanged,
 }
 
@@ -3521,7 +3521,7 @@ impl Repository {
         if update.is_last_update {
             self.snapshot.scan_id = update.scan_id;
         }
-        cx.emit(RepositoryEvent::Updated);
+        cx.emit(RepositoryEvent::Updated { full_scan: true });
         Ok(())
     }
 
@@ -3866,7 +3866,7 @@ impl Repository {
                                 .ok();
                         }
                     }
-                    cx.emit(RepositoryEvent::Updated);
+                    cx.emit(RepositoryEvent::Updated { full_scan: false });
                 })
             },
         );
@@ -4106,7 +4106,7 @@ async fn compute_snapshot(
         || branch != prev_snapshot.branch
         || statuses_by_path != prev_snapshot.statuses_by_path
     {
-        events.push(RepositoryEvent::Updated);
+        events.push(RepositoryEvent::Updated { full_scan: true });
     }
 
     let mut current_merge_conflicts = TreeSet::default();