diff --git a/crates/git/src/status.rs b/crates/git/src/status.rs index edf4d58373..1c8b6e757a 100644 --- a/crates/git/src/status.rs +++ b/crates/git/src/status.rs @@ -171,7 +171,13 @@ impl FileStatus { FileStatus::Tracked(TrackedStatus { index_status, worktree_status, - }) => index_status.summary() + worktree_status.summary(), + }) => { + let mut summary = index_status.to_summary() + worktree_status.to_summary(); + if summary != GitSummary::UNCHANGED { + summary.count = 1; + }; + summary + } } } } @@ -190,11 +196,23 @@ impl StatusCode { } } - fn summary(self) -> GitSummary { + /// Returns the contribution of this status code to the Git summary. + /// + /// Note that this does not include the count field, which must be set manually. + fn to_summary(self) -> GitSummary { match self { - StatusCode::Modified | StatusCode::TypeChanged => GitSummary::MODIFIED, - StatusCode::Added => GitSummary::ADDED, - StatusCode::Deleted => GitSummary::DELETED, + StatusCode::Modified | StatusCode::TypeChanged => GitSummary { + modified: 1, + ..GitSummary::UNCHANGED + }, + StatusCode::Added => GitSummary { + added: 1, + ..GitSummary::UNCHANGED + }, + StatusCode::Deleted => GitSummary { + deleted: 1, + ..GitSummary::UNCHANGED + }, StatusCode::Renamed | StatusCode::Copied | StatusCode::Unmodified => { GitSummary::UNCHANGED } @@ -220,31 +238,19 @@ pub struct GitSummary { pub conflict: usize, pub untracked: usize, pub deleted: usize, + pub count: usize, } impl GitSummary { - pub const ADDED: Self = Self { - added: 1, - ..Self::UNCHANGED - }; - - pub const MODIFIED: Self = Self { - modified: 1, - ..Self::UNCHANGED - }; - pub const CONFLICT: Self = Self { conflict: 1, - ..Self::UNCHANGED - }; - - pub const DELETED: Self = Self { - deleted: 1, + count: 1, ..Self::UNCHANGED }; pub const UNTRACKED: Self = Self { untracked: 1, + count: 1, ..Self::UNCHANGED }; @@ -254,6 +260,7 @@ impl GitSummary { conflict: 0, untracked: 0, deleted: 0, + count: 0, }; } @@ -291,6 +298,7 @@ impl std::ops::AddAssign for GitSummary { self.conflict += rhs.conflict; self.untracked += rhs.untracked; self.deleted += rhs.deleted; + self.count += rhs.count; } } @@ -304,6 +312,7 @@ impl std::ops::Sub for GitSummary { conflict: self.conflict - rhs.conflict, untracked: self.untracked - rhs.untracked, deleted: self.deleted - rhs.deleted, + count: self.count - rhs.count, } } } diff --git a/crates/git_ui/src/git_panel.rs b/crates/git_ui/src/git_panel.rs index 771113cf40..08f6ba6058 100644 --- a/crates/git_ui/src/git_panel.rs +++ b/crates/git_ui/src/git_panel.rs @@ -88,10 +88,6 @@ pub struct GitPanel { show_scrollbar: bool, rebuild_requested: Arc, commit_editor: View, - /// The visible entries in the list, accounting for folding & expanded state. - /// - /// At this point it doesn't matter what repository the entry belongs to, - /// as only one repositories' entries are visible in the list at a time. visible_entries: Vec, all_staged: Option, width: Option, @@ -363,8 +359,8 @@ impl GitPanel { git_panel } - fn git_state<'a>(&self, cx: &'a AppContext) -> Option<&'a Model> { - self.project.read(cx).git_state() + fn git_state(&self, cx: &AppContext) -> Option> { + self.project.read(cx).git_state().cloned() } fn active_repository<'a>( @@ -578,7 +574,7 @@ impl GitPanel { } fn select_first_entry_if_none(&mut self, cx: &mut ViewContext) { - if !self.no_entries() && self.selected_entry.is_none() { + if !self.no_entries(cx) && self.selected_entry.is_none() { self.selected_entry = Some(0); self.scroll_to_selected_entry(cx); cx.notify(); @@ -597,15 +593,24 @@ impl GitPanel { .and_then(|i| self.visible_entries.get(i)) } + fn open_selected(&mut self, _: &menu::Confirm, cx: &mut ViewContext) { + if let Some(entry) = self + .selected_entry + .and_then(|i| self.visible_entries.get(i)) + { + self.open_entry(entry, cx); + } + } + fn toggle_staged_for_entry(&mut self, entry: &GitListEntry, cx: &mut ViewContext) { - let Some(git_state) = self.git_state(cx).cloned() else { + let Some(git_state) = self.git_state(cx) else { return; }; git_state.update(cx, |git_state, _| { if entry.status.is_staged().unwrap_or(false) { - git_state.unstage_entry(entry.repo_path.clone()); + git_state.stage_entries(vec![entry.repo_path.clone()]); } else { - git_state.stage_entry(entry.repo_path.clone()); + git_state.stage_entries(vec![entry.repo_path.clone()]); } }); cx.notify(); @@ -617,15 +622,6 @@ impl GitPanel { } } - fn open_selected(&mut self, _: &menu::Confirm, cx: &mut ViewContext) { - if let Some(entry) = self - .selected_entry - .and_then(|i| self.visible_entries.get(i)) - { - self.open_entry(entry, cx); - } - } - fn open_entry(&self, entry: &GitListEntry, cx: &mut ViewContext) { let Some((worktree_id, path)) = maybe!({ let git_state = self.git_state(cx)?; @@ -646,32 +642,25 @@ impl GitPanel { } fn stage_all(&mut self, _: &git::StageAll, cx: &mut ViewContext) { - let to_stage = self - .visible_entries - .iter_mut() - .filter_map(|entry| { - let is_unstaged = !entry.is_staged.unwrap_or(false); - entry.is_staged = Some(true); - is_unstaged.then(|| entry.repo_path.clone()) - }) - .collect(); - self.all_staged = Some(true); - let Some(git_state) = self.git_state(cx).cloned() else { + let Some(git_state) = self.git_state(cx) else { return; }; - git_state.update(cx, |git_state, _| git_state.stage_entries(to_stage)); + for entry in &mut self.visible_entries { + entry.is_staged = Some(true); + } + self.all_staged = Some(true); + git_state.read(cx).stage_all(); } fn unstage_all(&mut self, _: &git::UnstageAll, cx: &mut ViewContext) { - // This should only be called when all entries are staged. + let Some(git_state) = self.git_state(cx) else { + return; + }; for entry in &mut self.visible_entries { entry.is_staged = Some(false); } self.all_staged = Some(false); - let Some(git_state) = self.git_state(cx).cloned() else { - return; - }; - git_state.update(cx, |git_state, _| git_state.unstage_all()); + git_state.read(cx).unstage_all(); } fn discard_all(&mut self, _: &git::RevertAll, _cx: &mut ViewContext) { @@ -680,7 +669,7 @@ impl GitPanel { } fn clear_message(&mut self, cx: &mut ViewContext) { - let Some(git_state) = self.git_state(cx).cloned() else { + let Some(git_state) = self.git_state(cx) else { return; }; git_state.update(cx, |git_state, _| { @@ -690,10 +679,28 @@ impl GitPanel { .update(cx, |editor, cx| editor.set_text("", cx)); } + fn can_commit(&self, commit_all: bool, cx: &AppContext) -> bool { + let Some(git_state) = self.git_state(cx) else { + return false; + }; + let has_message = !self.commit_editor.read(cx).text(cx).is_empty(); + let has_changes = git_state.read(cx).entry_count() > 0; + let has_staged_changes = self + .visible_entries + .iter() + .any(|entry| entry.is_staged == Some(true)); + + has_message && (commit_all || has_staged_changes) && has_changes + } + /// Commit all staged changes fn commit_changes(&mut self, _: &git::CommitChanges, cx: &mut ViewContext) { self.clear_message(cx); + if !self.can_commit(false, cx) { + return; + } + // TODO: Implement commit all staged println!("Commit staged changes triggered"); } @@ -702,16 +709,17 @@ impl GitPanel { fn commit_all_changes(&mut self, _: &git::CommitAllChanges, cx: &mut ViewContext) { self.clear_message(cx); + if !self.can_commit(true, cx) { + return; + } + // TODO: Implement commit all changes println!("Commit all changes triggered"); } - fn no_entries(&self) -> bool { - self.visible_entries.is_empty() - } - - fn entry_count(&self) -> usize { - self.visible_entries.len() + fn no_entries(&self, cx: &mut ViewContext) -> bool { + self.git_state(cx) + .map_or(true, |git_state| git_state.read(cx).entry_count() == 0) } fn for_each_visible_entry( @@ -828,7 +836,7 @@ impl GitPanel { if let language::BufferEvent::Reparsed | language::BufferEvent::Edited = event { let commit_message = self.commit_editor.update(cx, |editor, cx| editor.text(cx)); - let Some(git_state) = self.git_state(cx).cloned() else { + let Some(git_state) = self.git_state(cx) else { return; }; git_state.update(cx, |git_state, _| { @@ -866,8 +874,11 @@ impl GitPanel { pub fn render_panel_header(&self, cx: &mut ViewContext) -> impl IntoElement { let focus_handle = self.focus_handle(cx).clone(); + let entry_count = self + .git_state(cx) + .map_or(0, |git_state| git_state.read(cx).entry_count()); - let changes_string = match self.entry_count() { + let changes_string = match entry_count { 0 => "No changes".to_string(), 1 => "1 change".to_string(), n => format!("{} changes", n), @@ -887,7 +898,7 @@ impl GitPanel { .child( Checkbox::new( "all-changes", - if self.no_entries() { + if self.no_entries(cx) { ToggleState::Selected } else { self.all_staged @@ -1108,7 +1119,8 @@ impl GitPanel { } fn render_entries(&self, cx: &mut ViewContext) -> impl IntoElement { - let entry_count = self.entry_count(); + let entry_count = self.visible_entries.len(); + h_flex() .size_full() .overflow_hidden() @@ -1228,14 +1240,16 @@ impl GitPanel { ToggleState::Indeterminate => None, }; let repo_path = repo_path.clone(); - let Some(git_state) = this.git_state(cx).cloned() else { + let Some(git_state) = this.git_state(cx) else { return; }; git_state.update(cx, |git_state, _| match toggle { ToggleState::Selected | ToggleState::Indeterminate => { - git_state.stage_entry(repo_path); + git_state.stage_entries(vec![repo_path]); + } + ToggleState::Unselected => { + git_state.unstage_entries(vec![repo_path]) } - ToggleState::Unselected => git_state.unstage_entry(repo_path), }) }); } @@ -1330,7 +1344,7 @@ impl Render for GitPanel { .bg(ElevationIndex::Surface.bg(cx)) .child(self.render_panel_header(cx)) .child(self.render_divider(cx)) - .child(if !self.no_entries() { + .child(if !self.no_entries(cx) { self.render_entries(cx).into_any_element() } else { self.render_empty_state(cx).into_any_element() diff --git a/crates/project/src/git.rs b/crates/project/src/git.rs index 7c369c9337..cbb7ed90dc 100644 --- a/crates/project/src/git.rs +++ b/crates/project/src/git.rs @@ -73,52 +73,54 @@ impl GitState { self.commit_message = None; } - pub fn stage_entry(&mut self, repo_path: RepoPath) { + fn act_on_entries(&self, entries: Vec, action: StatusAction) { + if entries.is_empty() { + return; + } if let Some((_, _, git_repo)) = self.active_repository.as_ref() { - let _ = self.update_sender.unbounded_send(( - git_repo.clone(), - vec![repo_path], - StatusAction::Stage, - )); + let _ = self + .update_sender + .unbounded_send((git_repo.clone(), entries, action)); } } - pub fn unstage_entry(&mut self, repo_path: RepoPath) { - if let Some((_, _, git_repo)) = self.active_repository.as_ref() { - let _ = self.update_sender.unbounded_send(( - git_repo.clone(), - vec![repo_path], - StatusAction::Unstage, - )); - } + pub fn stage_entries(&self, entries: Vec) { + self.act_on_entries(entries, StatusAction::Stage); } - pub fn stage_entries(&mut self, entries: Vec) { - if let Some((_, _, git_repo)) = self.active_repository.as_ref() { - let _ = - self.update_sender - .unbounded_send((git_repo.clone(), entries, StatusAction::Stage)); - } + pub fn unstage_entries(&self, entries: Vec) { + self.act_on_entries(entries, StatusAction::Unstage); } - fn act_on_all(&mut self, action: StatusAction) { - if let Some((_, active_repository, git_repo)) = self.active_repository.as_ref() { - let _ = self.update_sender.unbounded_send(( - git_repo.clone(), - active_repository - .status() - .map(|entry| entry.repo_path) - .collect(), - action, - )); - } + pub fn stage_all(&self) { + let Some((_, entry, _)) = self.active_repository.as_ref() else { + return; + }; + let to_stage = entry + .status() + .filter(|entry| !entry.status.is_staged().unwrap_or(false)) + .map(|entry| entry.repo_path.clone()) + .collect(); + self.stage_entries(to_stage); } - pub fn stage_all(&mut self) { - self.act_on_all(StatusAction::Stage); + pub fn unstage_all(&self) { + let Some((_, entry, _)) = self.active_repository.as_ref() else { + return; + }; + let to_unstage = entry + .status() + .filter(|entry| entry.status.is_staged().unwrap_or(true)) + .map(|entry| entry.repo_path.clone()) + .collect(); + self.unstage_entries(to_unstage); } - pub fn unstage_all(&mut self) { - self.act_on_all(StatusAction::Unstage); + /// Get a count of all entries in the active repository, including + /// untracked files. + pub fn entry_count(&self) -> usize { + self.active_repository + .as_ref() + .map_or(0, |(_, entry, _)| entry.status_len()) } } diff --git a/crates/worktree/src/worktree.rs b/crates/worktree/src/worktree.rs index 4c65b41da4..2acbc15adb 100644 --- a/crates/worktree/src/worktree.rs +++ b/crates/worktree/src/worktree.rs @@ -227,6 +227,10 @@ impl RepositoryEntry { self.statuses_by_path.iter().cloned() } + pub fn status_len(&self) -> usize { + self.statuses_by_path.summary().item_summary.count + } + pub fn status_for_path(&self, path: &RepoPath) -> Option { self.statuses_by_path .get(&PathKey(path.0.clone()), &()) @@ -5718,7 +5722,7 @@ impl<'a> GitTraversal<'a> { if statuses.seek_forward(&PathTarget::Path(repo_path.as_ref()), Bias::Left, &()) { self.current_entry_summary = Some(statuses.item().unwrap().status.into()); } else { - self.current_entry_summary = Some(GitSummary::zero(&())); + self.current_entry_summary = Some(GitSummary::UNCHANGED); } } } @@ -5755,7 +5759,7 @@ impl<'a> GitTraversal<'a> { pub fn entry(&self) -> Option> { let entry = self.traversal.cursor.item()?; - let git_summary = self.current_entry_summary.unwrap_or_default(); + let git_summary = self.current_entry_summary.unwrap_or(GitSummary::UNCHANGED); Some(GitEntryRef { entry, git_summary }) } } diff --git a/crates/worktree/src/worktree_tests.rs b/crates/worktree/src/worktree_tests.rs index 87159548af..34c37626db 100644 --- a/crates/worktree/src/worktree_tests.rs +++ b/crates/worktree/src/worktree_tests.rs @@ -1512,9 +1512,9 @@ async fn test_bump_mtime_of_git_repo_workdir(cx: &mut TestAppContext) { check_git_statuses( &snapshot, &[ - (Path::new(""), GitSummary::MODIFIED), + (Path::new(""), MODIFIED), (Path::new("a.txt"), GitSummary::UNCHANGED), - (Path::new("b/c.txt"), GitSummary::MODIFIED), + (Path::new("b/c.txt"), MODIFIED), ], ); } @@ -2811,7 +2811,7 @@ async fn test_traverse_with_git_status(cx: &mut TestAppContext) { assert_eq!(entry.git_summary, GitSummary::UNCHANGED); let entry = traversal.next().unwrap(); assert_eq!(entry.path.as_ref(), Path::new("x/x2.txt")); - assert_eq!(entry.git_summary, GitSummary::MODIFIED); + assert_eq!(entry.git_summary, MODIFIED); let entry = traversal.next().unwrap(); assert_eq!(entry.path.as_ref(), Path::new("x/y/y1.txt")); assert_eq!(entry.git_summary, GitSummary::CONFLICT); @@ -2820,13 +2820,13 @@ async fn test_traverse_with_git_status(cx: &mut TestAppContext) { assert_eq!(entry.git_summary, GitSummary::UNCHANGED); let entry = traversal.next().unwrap(); assert_eq!(entry.path.as_ref(), Path::new("x/z.txt")); - assert_eq!(entry.git_summary, GitSummary::ADDED); + assert_eq!(entry.git_summary, ADDED); let entry = traversal.next().unwrap(); assert_eq!(entry.path.as_ref(), Path::new("z/z1.txt")); assert_eq!(entry.git_summary, GitSummary::UNCHANGED); let entry = traversal.next().unwrap(); assert_eq!(entry.path.as_ref(), Path::new("z/z2.txt")); - assert_eq!(entry.git_summary, GitSummary::ADDED); + assert_eq!(entry.git_summary, ADDED); } #[gpui::test] @@ -2893,10 +2893,7 @@ async fn test_propagate_git_statuses(cx: &mut TestAppContext) { check_git_statuses( &snapshot, &[ - ( - Path::new(""), - GitSummary::CONFLICT + GitSummary::MODIFIED + GitSummary::ADDED, - ), + (Path::new(""), GitSummary::CONFLICT + MODIFIED + ADDED), (Path::new("g"), GitSummary::CONFLICT), (Path::new("g/h2.txt"), GitSummary::CONFLICT), ], @@ -2905,16 +2902,13 @@ async fn test_propagate_git_statuses(cx: &mut TestAppContext) { check_git_statuses( &snapshot, &[ - ( - Path::new(""), - GitSummary::CONFLICT + GitSummary::ADDED + GitSummary::MODIFIED, - ), - (Path::new("a"), GitSummary::ADDED + GitSummary::MODIFIED), - (Path::new("a/b"), GitSummary::ADDED), - (Path::new("a/b/c1.txt"), GitSummary::ADDED), + (Path::new(""), GitSummary::CONFLICT + ADDED + MODIFIED), + (Path::new("a"), ADDED + MODIFIED), + (Path::new("a/b"), ADDED), + (Path::new("a/b/c1.txt"), ADDED), (Path::new("a/b/c2.txt"), GitSummary::UNCHANGED), - (Path::new("a/d"), GitSummary::MODIFIED), - (Path::new("a/d/e2.txt"), GitSummary::MODIFIED), + (Path::new("a/d"), MODIFIED), + (Path::new("a/d/e2.txt"), MODIFIED), (Path::new("f"), GitSummary::UNCHANGED), (Path::new("f/no-status.txt"), GitSummary::UNCHANGED), (Path::new("g"), GitSummary::CONFLICT), @@ -2925,12 +2919,12 @@ async fn test_propagate_git_statuses(cx: &mut TestAppContext) { check_git_statuses( &snapshot, &[ - (Path::new("a/b"), GitSummary::ADDED), - (Path::new("a/b/c1.txt"), GitSummary::ADDED), + (Path::new("a/b"), ADDED), + (Path::new("a/b/c1.txt"), ADDED), (Path::new("a/b/c2.txt"), GitSummary::UNCHANGED), - (Path::new("a/d"), GitSummary::MODIFIED), + (Path::new("a/d"), MODIFIED), (Path::new("a/d/e1.txt"), GitSummary::UNCHANGED), - (Path::new("a/d/e2.txt"), GitSummary::MODIFIED), + (Path::new("a/d/e2.txt"), MODIFIED), (Path::new("f"), GitSummary::UNCHANGED), (Path::new("f/no-status.txt"), GitSummary::UNCHANGED), (Path::new("g"), GitSummary::CONFLICT), @@ -2940,10 +2934,10 @@ async fn test_propagate_git_statuses(cx: &mut TestAppContext) { check_git_statuses( &snapshot, &[ - (Path::new("a/b/c1.txt"), GitSummary::ADDED), + (Path::new("a/b/c1.txt"), ADDED), (Path::new("a/b/c2.txt"), GitSummary::UNCHANGED), (Path::new("a/d/e1.txt"), GitSummary::UNCHANGED), - (Path::new("a/d/e2.txt"), GitSummary::MODIFIED), + (Path::new("a/d/e2.txt"), MODIFIED), (Path::new("f/no-status.txt"), GitSummary::UNCHANGED), ], ); @@ -3016,49 +3010,43 @@ async fn test_propagate_statuses_for_repos_under_project(cx: &mut TestAppContext check_git_statuses( &snapshot, - &[ - (Path::new("x"), GitSummary::ADDED), - (Path::new("x/x1.txt"), GitSummary::ADDED), - ], + &[(Path::new("x"), ADDED), (Path::new("x/x1.txt"), ADDED)], ); check_git_statuses( &snapshot, &[ - (Path::new("y"), GitSummary::CONFLICT + GitSummary::MODIFIED), + (Path::new("y"), GitSummary::CONFLICT + MODIFIED), (Path::new("y/y1.txt"), GitSummary::CONFLICT), - (Path::new("y/y2.txt"), GitSummary::MODIFIED), + (Path::new("y/y2.txt"), MODIFIED), ], ); check_git_statuses( &snapshot, &[ - (Path::new("z"), GitSummary::MODIFIED), - (Path::new("z/z2.txt"), GitSummary::MODIFIED), + (Path::new("z"), MODIFIED), + (Path::new("z/z2.txt"), MODIFIED), ], ); check_git_statuses( &snapshot, - &[ - (Path::new("x"), GitSummary::ADDED), - (Path::new("x/x1.txt"), GitSummary::ADDED), - ], + &[(Path::new("x"), ADDED), (Path::new("x/x1.txt"), ADDED)], ); check_git_statuses( &snapshot, &[ - (Path::new("x"), GitSummary::ADDED), - (Path::new("x/x1.txt"), GitSummary::ADDED), + (Path::new("x"), ADDED), + (Path::new("x/x1.txt"), ADDED), (Path::new("x/x2.txt"), GitSummary::UNCHANGED), - (Path::new("y"), GitSummary::CONFLICT + GitSummary::MODIFIED), + (Path::new("y"), GitSummary::CONFLICT + MODIFIED), (Path::new("y/y1.txt"), GitSummary::CONFLICT), - (Path::new("y/y2.txt"), GitSummary::MODIFIED), - (Path::new("z"), GitSummary::MODIFIED), + (Path::new("y/y2.txt"), MODIFIED), + (Path::new("z"), MODIFIED), (Path::new("z/z1.txt"), GitSummary::UNCHANGED), - (Path::new("z/z2.txt"), GitSummary::MODIFIED), + (Path::new("z/z2.txt"), MODIFIED), ], ); } @@ -3139,9 +3127,9 @@ async fn test_propagate_statuses_for_nested_repos(cx: &mut TestAppContext) { check_git_statuses( &snapshot, &[ - (Path::new("z"), GitSummary::ADDED), + (Path::new("z"), ADDED), (Path::new("z/z1.txt"), GitSummary::UNCHANGED), - (Path::new("z/z2.txt"), GitSummary::ADDED), + (Path::new("z/z2.txt"), ADDED), ], ); @@ -3149,7 +3137,7 @@ async fn test_propagate_statuses_for_nested_repos(cx: &mut TestAppContext) { check_git_statuses( &snapshot, &[ - (Path::new("x"), GitSummary::MODIFIED + GitSummary::ADDED), + (Path::new("x"), MODIFIED + ADDED), (Path::new("x/y"), GitSummary::CONFLICT), (Path::new("x/y/y1.txt"), GitSummary::CONFLICT), ], @@ -3159,13 +3147,13 @@ async fn test_propagate_statuses_for_nested_repos(cx: &mut TestAppContext) { check_git_statuses( &snapshot, &[ - (Path::new("x"), GitSummary::MODIFIED + GitSummary::ADDED), + (Path::new("x"), MODIFIED + ADDED), (Path::new("x/x1.txt"), GitSummary::UNCHANGED), - (Path::new("x/x2.txt"), GitSummary::MODIFIED), + (Path::new("x/x2.txt"), MODIFIED), (Path::new("x/y"), GitSummary::CONFLICT), (Path::new("x/y/y1.txt"), GitSummary::CONFLICT), (Path::new("x/y/y2.txt"), GitSummary::UNCHANGED), - (Path::new("x/z.txt"), GitSummary::ADDED), + (Path::new("x/z.txt"), ADDED), ], ); @@ -3174,7 +3162,7 @@ async fn test_propagate_statuses_for_nested_repos(cx: &mut TestAppContext) { &snapshot, &[ (Path::new(""), GitSummary::UNCHANGED), - (Path::new("x"), GitSummary::MODIFIED + GitSummary::ADDED), + (Path::new("x"), MODIFIED + ADDED), (Path::new("x/x1.txt"), GitSummary::UNCHANGED), ], ); @@ -3184,16 +3172,16 @@ async fn test_propagate_statuses_for_nested_repos(cx: &mut TestAppContext) { &snapshot, &[ (Path::new(""), GitSummary::UNCHANGED), - (Path::new("x"), GitSummary::MODIFIED + GitSummary::ADDED), + (Path::new("x"), MODIFIED + ADDED), (Path::new("x/x1.txt"), GitSummary::UNCHANGED), - (Path::new("x/x2.txt"), GitSummary::MODIFIED), + (Path::new("x/x2.txt"), MODIFIED), (Path::new("x/y"), GitSummary::CONFLICT), (Path::new("x/y/y1.txt"), GitSummary::CONFLICT), (Path::new("x/y/y2.txt"), GitSummary::UNCHANGED), - (Path::new("x/z.txt"), GitSummary::ADDED), - (Path::new("z"), GitSummary::ADDED), + (Path::new("x/z.txt"), ADDED), + (Path::new("z"), ADDED), (Path::new("z/z1.txt"), GitSummary::UNCHANGED), - (Path::new("z/z2.txt"), GitSummary::ADDED), + (Path::new("z/z2.txt"), ADDED), ], ); } @@ -3238,6 +3226,17 @@ fn check_git_statuses(snapshot: &Snapshot, expected_statuses: &[(&Path, GitSumma assert_eq!(found_statuses, expected_statuses); } +const ADDED: GitSummary = GitSummary { + added: 1, + count: 1, + ..GitSummary::UNCHANGED +}; +const MODIFIED: GitSummary = GitSummary { + modified: 1, + count: 1, + ..GitSummary::UNCHANGED +}; + #[track_caller] fn git_init(path: &Path) -> git2::Repository { git2::Repository::init(path).expect("Failed to initialize git repository")