diff --git a/crates/git_ui/src/git_panel.rs b/crates/git_ui/src/git_panel.rs index 5d34bd6a7bee21a4c62310e910df7556345097d4..777f7d6e37105af29528b3075ebf5f3807d6ebe1 100644 --- a/crates/git_ui/src/git_panel.rs +++ b/crates/git_ui/src/git_panel.rs @@ -2629,7 +2629,7 @@ impl GitPanel { && pending .ops .iter() - .any(|op| op.git_status == pending_op::GitStatus::Reverted && op.finished) + .any(|op| op.git_status == pending_op::GitStatus::Reverted && op.finished()) { continue; } diff --git a/crates/project/src/git_store.rs b/crates/project/src/git_store.rs index 7e0fc161d66ebcc80e51570c3dec3f9f9cce1771..4cac71c6ae3e2eb3f3615821443db7c82e01d810 100644 --- a/crates/project/src/git_store.rs +++ b/crates/project/src/git_store.rs @@ -5381,27 +5381,18 @@ impl Repository { let ids = self.new_pending_ops_for_paths(paths, git_status); cx.spawn(async move |this, cx| { - let (finished, result) = match f(this.clone(), cx).await { - Ok(()) => (true, Ok(())), - Err(err) if err.is::() => (false, Ok(())), - Err(err) => (false, Err(err)), + let (job_status, result) = match f(this.clone(), cx).await { + Ok(()) => (pending_op::JobStatus::Finished, Ok(())), + Err(err) if err.is::() => (pending_op::JobStatus::Skipped, Ok(())), + Err(err) => (pending_op::JobStatus::Error, Err(err)), }; this.update(cx, |this, _| { let mut edits = Vec::with_capacity(ids.len()); for (id, entry) in ids { if let Some(mut ops) = this.snapshot.pending_ops_for_path(&entry) { - if finished { - if let Some(op) = ops.op_by_id_mut(id) { - op.finished = true; - } - } else { - let idx = ops - .ops - .iter() - .position(|op| op.id == id) - .expect("pending operation must exist"); - ops.ops.remove(idx); + if let Some(op) = ops.op_by_id_mut(id) { + op.job_status = job_status; } edits.push(sum_tree::Edit::Insert(ops)); } @@ -5429,7 +5420,7 @@ impl Repository { ops.ops.push(PendingOp { id, git_status, - finished: false, + job_status: pending_op::JobStatus::Running, }); edits.push(sum_tree::Edit::Insert(ops)); ids.push((id, path)); @@ -5707,7 +5698,7 @@ async fn compute_snapshot( let pending_ops_by_path = SumTree::from_iter( prev_snapshot.pending_ops_by_path.iter().filter_map(|ops| { let inner_ops: Vec = - ops.ops.iter().filter(|op| !op.finished).cloned().collect(); + ops.ops.iter().filter(|op| op.running()).cloned().collect(); if inner_ops.is_empty() { None } else { diff --git a/crates/project/src/git_store/pending_op.rs b/crates/project/src/git_store/pending_op.rs index b5c7d9f00ec639576d498aaa3107c83758085c2e..1991eed407833d47fd35f6f573fbb46c692aed91 100644 --- a/crates/project/src/git_store/pending_op.rs +++ b/crates/project/src/git_store/pending_op.rs @@ -11,6 +11,14 @@ pub enum GitStatus { Unchanged, } +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum JobStatus { + Running, + Finished, + Skipped, + Error, +} + #[derive(Clone, Debug, PartialEq, Eq)] pub struct PendingOps { pub repo_path: RepoPath, @@ -21,7 +29,7 @@ pub struct PendingOps { pub struct PendingOp { pub id: PendingOpId, pub git_status: GitStatus, - pub finished: bool, + pub job_status: JobStatus, } #[derive(Clone, Debug)] @@ -106,7 +114,7 @@ impl PendingOps { /// File is staged if the last job is finished and has status Staged. pub fn staged(&self) -> bool { if let Some(last) = self.ops.last() { - if last.git_status == GitStatus::Staged && last.finished { + if last.git_status == GitStatus::Staged && last.job_status == JobStatus::Finished { return true; } } @@ -116,10 +124,24 @@ impl PendingOps { /// File is staged if the last job is not finished and has status Staged. pub fn staging(&self) -> bool { if let Some(last) = self.ops.last() { - if last.git_status == GitStatus::Staged && !last.finished { + if last.git_status == GitStatus::Staged && last.job_status != JobStatus::Finished { return true; } } false } } + +impl PendingOp { + pub fn running(&self) -> bool { + self.job_status == JobStatus::Running + } + + pub fn finished(&self) -> bool { + matches!(self.job_status, JobStatus::Finished | JobStatus::Skipped) + } + + pub fn error(&self) -> bool { + self.job_status == JobStatus::Error + } +} diff --git a/crates/project/src/project_tests.rs b/crates/project/src/project_tests.rs index 3a461334ded39bd90c40deded2d0a7d77332aee7..b7be84b3b41f0e5170d08d5cf8215e505816e9f0 100644 --- a/crates/project/src/project_tests.rs +++ b/crates/project/src/project_tests.rs @@ -8477,8 +8477,11 @@ fn merge_pending_ops_snapshots( .find_map(|(op, idx)| if op.id == s_op.id { Some(idx) } else { None }) { let t_op = &mut t_ops.ops[op_idx]; - if s_op.finished { - t_op.finished = true; + match (s_op.job_status, t_op.job_status) { + (pending_op::JobStatus::Running, _) => {} + (s_st, pending_op::JobStatus::Running) => t_op.job_status = s_st, + (s_st, t_st) if s_st == t_st => {} + _ => unreachable!(), } } else { t_ops.ops.push(s_op); @@ -8570,7 +8573,7 @@ async fn test_repository_pending_ops_staging( Some(&pending_op::PendingOp { id: id.into(), git_status, - finished: false, + job_status: pending_op::JobStatus::Running }) ); task @@ -8585,7 +8588,7 @@ async fn test_repository_pending_ops_staging( Some(&pending_op::PendingOp { id: id.into(), git_status, - finished: true, + job_status: pending_op::JobStatus::Finished }) ); }); @@ -8611,27 +8614,27 @@ async fn test_repository_pending_ops_staging( pending_op::PendingOp { id: 1u16.into(), git_status: pending_op::GitStatus::Staged, - finished: true, + job_status: pending_op::JobStatus::Finished }, pending_op::PendingOp { id: 2u16.into(), git_status: pending_op::GitStatus::Unstaged, - finished: true, + job_status: pending_op::JobStatus::Finished }, pending_op::PendingOp { id: 3u16.into(), git_status: pending_op::GitStatus::Staged, - finished: true, + job_status: pending_op::JobStatus::Finished }, pending_op::PendingOp { id: 4u16.into(), git_status: pending_op::GitStatus::Unstaged, - finished: true, + job_status: pending_op::JobStatus::Finished }, pending_op::PendingOp { id: 5u16.into(), git_status: pending_op::GitStatus::Staged, - finished: true, + job_status: pending_op::JobStatus::Finished } ], ); @@ -8728,11 +8731,18 @@ async fn test_repository_pending_ops_long_running_staging( .get(&worktree::PathKey(repo_path("a.txt").as_ref().clone()), ()) .unwrap() .ops, - vec![pending_op::PendingOp { - id: 2u16.into(), - git_status: pending_op::GitStatus::Staged, - finished: true, - }], + vec![ + pending_op::PendingOp { + id: 1u16.into(), + git_status: pending_op::GitStatus::Staged, + job_status: pending_op::JobStatus::Skipped + }, + pending_op::PendingOp { + id: 2u16.into(), + git_status: pending_op::GitStatus::Staged, + job_status: pending_op::JobStatus::Finished + } + ], ); repo.update(cx, |repo, _cx| { @@ -8833,12 +8843,12 @@ async fn test_repository_pending_ops_stage_all( pending_op::PendingOp { id: 1u16.into(), git_status: pending_op::GitStatus::Staged, - finished: true, + job_status: pending_op::JobStatus::Finished }, pending_op::PendingOp { id: 2u16.into(), git_status: pending_op::GitStatus::Unstaged, - finished: true, + job_status: pending_op::JobStatus::Finished }, ], ); @@ -8852,12 +8862,12 @@ async fn test_repository_pending_ops_stage_all( pending_op::PendingOp { id: 1u16.into(), git_status: pending_op::GitStatus::Staged, - finished: true, + job_status: pending_op::JobStatus::Finished }, pending_op::PendingOp { id: 2u16.into(), git_status: pending_op::GitStatus::Unstaged, - finished: true, + job_status: pending_op::JobStatus::Finished }, ], );