git: Make GitJobKey::WriteIndex accept a string instead path

Jakub Konka created

This way, we can naively assign the same identifier to jobs
consisting of the same set of paths. Of course, this assumes
paths are always in the same order, etc. but it's the first
step towards maybe a bit smarter solution.

Change summary

crates/git_ui/src/git_panel.rs  | 34 +++++++++++++++++++-----------
crates/project/src/git_store.rs | 38 +++++++++++++++++-----------------
2 files changed, 40 insertions(+), 32 deletions(-)

Detailed changes

crates/git_ui/src/git_panel.rs 🔗

@@ -1223,14 +1223,18 @@ impl GitPanel {
         });
     }
 
-    pub fn stage_all(&mut self, _: &StageAll, _window: &mut Window, cx: &mut Context<Self>) {
+    pub fn change_all_files_stage(&mut self, stage: bool, cx: &mut Context<Self>) {
         let Some(active_repository) = self.active_repository.clone() else {
             return;
         };
         let op_id = self.pending.iter().map(|p| p.op_id).max().unwrap_or(0) + 1;
         self.pending.push(PendingOperation {
             op_id,
-            target_status: TargetStatus::Staged,
+            target_status: if stage {
+                TargetStatus::Staged
+            } else {
+                TargetStatus::Unstaged
+            },
             entries: PendingEntries::All,
             finished: false,
         });
@@ -1241,7 +1245,15 @@ impl GitPanel {
         cx.spawn({
             async move |this, cx| {
                 let result = cx
-                    .update(|cx| active_repository.update(cx, |repo, cx| repo.stage_all(cx)))?
+                    .update(|cx| {
+                        active_repository.update(cx, |repo, cx| {
+                            if stage {
+                                repo.stage_all(cx)
+                            } else {
+                                repo.unstage_all(cx)
+                            }
+                        })
+                    })?
                     .await;
 
                 this.update(cx, |this, cx| {
@@ -1252,7 +1264,7 @@ impl GitPanel {
                     }
                     result
                         .map_err(|e| {
-                            this.show_error_toast("add", e, cx);
+                            this.show_error_toast(if stage { "add" } else { "reset" }, e, cx);
                         })
                         .ok();
                     cx.notify();
@@ -1262,16 +1274,12 @@ impl GitPanel {
         .detach();
     }
 
+    pub fn stage_all(&mut self, _: &StageAll, _window: &mut Window, cx: &mut Context<Self>) {
+        self.change_all_files_stage(true, cx);
+    }
+
     pub fn unstage_all(&mut self, _: &UnstageAll, _window: &mut Window, cx: &mut Context<Self>) {
-        let entries = self
-            .entries
-            .iter()
-            .filter_map(|entry| entry.status_entry())
-            .filter(|status_entry| status_entry.staging.has_staged())
-            .cloned()
-            .collect::<Vec<_>>();
-        dbg!(&entries);
-        self.change_file_stage(false, entries, cx);
+        self.change_all_files_stage(false, cx);
     }
 
     fn toggle_staged_for_entry(

crates/project/src/git_store.rs 🔗

@@ -338,7 +338,7 @@ pub struct GitJob {
 
 #[derive(Debug, PartialEq, Eq)]
 enum GitJobKey {
-    WriteIndex(RepoPath),
+    WriteIndex(String),
     ReloadBufferDiffBases,
     RefreshStatuses,
     ReloadGitState,
@@ -3754,12 +3754,13 @@ impl Repository {
 
         let id = self.id;
         let save_tasks = self.save_buffers(&entries, cx);
-        let job_key = match entries.len() {
-            1 => Some(GitJobKey::WriteIndex(entries[0].clone())),
-            _ => None,
-        };
-        let paths: Vec<_> = entries.iter().map(|p| p.as_unix_str()).collect();
-        let status = format!("git add {}", paths.join(" "));
+        let paths = entries
+            .iter()
+            .map(|p| p.as_unix_str())
+            .collect::<Vec<_>>()
+            .join(" ");
+        let status = format!("git add {paths}");
+        let job_key = GitJobKey::WriteIndex(paths);
 
         cx.spawn(async move |this, cx| {
             for save_task in save_tasks {
@@ -3768,7 +3769,7 @@ impl Repository {
 
             this.update(cx, |this, _| {
                 this.send_keyed_job(
-                    job_key,
+                    Some(job_key),
                     Some(status.into()),
                     move |git_repo, _cx| async move {
                         match git_repo {
@@ -3813,12 +3814,13 @@ impl Repository {
 
         let id = self.id;
         let save_tasks = self.save_buffers(&entries, cx);
-        let job_key = match entries.len() {
-            1 => Some(GitJobKey::WriteIndex(entries[0].clone())),
-            _ => None,
-        };
-        let paths: Vec<_> = entries.iter().map(|p| p.as_unix_str()).collect();
-        let status = format!("git reset {}", paths.join(" "));
+        let paths = entries
+            .iter()
+            .map(|p| p.as_unix_str())
+            .collect::<Vec<_>>()
+            .join(" ");
+        let status = format!("git reset {paths}");
+        let job_key = GitJobKey::WriteIndex(paths);
 
         cx.spawn(async move |this, cx| {
             for save_task in save_tasks {
@@ -3827,7 +3829,7 @@ impl Repository {
 
             this.update(cx, |this, _| {
                 this.send_keyed_job(
-                    job_key,
+                    Some(job_key),
                     Some(status.into()),
                     move |git_repo, _cx| async move {
                         match git_repo {
@@ -3867,17 +3869,15 @@ impl Repository {
             .filter(|entry| !entry.status.staging().is_fully_staged())
             .map(|entry| entry.repo_path)
             .collect();
-        dbg!(&to_stage);
         self.stage_entries(to_stage, cx)
     }
 
     pub fn unstage_all(&self, cx: &mut Context<Self>) -> Task<anyhow::Result<()>> {
         let to_unstage = self
             .cached_status()
-            .filter(|entry| entry.status.staging().has_staged())
+            .filter(|entry| entry.status.staging().is_fully_unstaged())
             .map(|entry| entry.repo_path)
             .collect();
-        dbg!(&to_unstage);
         self.unstage_entries(to_unstage, cx)
     }
 
@@ -4303,7 +4303,7 @@ impl Repository {
         let this = cx.weak_entity();
         let git_store = self.git_store.clone();
         self.send_keyed_job(
-            Some(GitJobKey::WriteIndex(path.clone())),
+            Some(GitJobKey::WriteIndex(path.as_unix_str().to_string())),
             None,
             move |git_repo, mut cx| async move {
                 log::debug!(