From 9a13a2ba2c0c269eca517685306ffc7bd4472005 Mon Sep 17 00:00:00 2001 From: Mikayla Maki Date: Mon, 5 Jun 2023 12:53:04 -0700 Subject: [PATCH] WIP: Add status bubbling to project panel --- crates/fs/src/repository.rs | 12 ++--- crates/project/src/worktree.rs | 56 +++++++++++++++-------- crates/project_panel/src/project_panel.rs | 12 ++++- 3 files changed, 54 insertions(+), 26 deletions(-) diff --git a/crates/fs/src/repository.rs b/crates/fs/src/repository.rs index 70f2916681..efe3a40092 100644 --- a/crates/fs/src/repository.rs +++ b/crates/fs/src/repository.rs @@ -25,7 +25,7 @@ pub trait GitRepository: Send { fn statuses(&self) -> Option>; - fn status(&self, path: &RepoPath) -> Option; + fn status(&self, path: &RepoPath) -> Result>; } impl std::fmt::Debug for dyn GitRepository { @@ -92,9 +92,9 @@ impl GitRepository for LibGitRepository { Some(map) } - fn status(&self, path: &RepoPath) -> Option { - let status = self.status_file(path).log_err()?; - read_status(status) + fn status(&self, path: &RepoPath) -> Result> { + let status = self.status_file(path)?; + Ok(read_status(status)) } } @@ -156,9 +156,9 @@ impl GitRepository for FakeGitRepository { Some(map) } - fn status(&self, path: &RepoPath) -> Option { + fn status(&self, path: &RepoPath) -> Result> { let state = self.state.lock(); - state.worktree_statuses.get(path).cloned() + Ok(state.worktree_statuses.get(path).cloned()) } } diff --git a/crates/project/src/worktree.rs b/crates/project/src/worktree.rs index 1c1c409dca..d808c41350 100644 --- a/crates/project/src/worktree.rs +++ b/crates/project/src/worktree.rs @@ -1670,11 +1670,14 @@ impl Snapshot { }) } - pub fn statuses_for_paths(&self, paths: &[&Path]) -> Vec> { + pub fn statuses_for_paths<'a>( + &self, + paths: impl IntoIterator, + ) -> Vec> { let mut cursor = self .entries_by_path .cursor::<(TraversalProgress, GitStatuses)>(); - let mut paths = paths.iter().peekable(); + let mut paths = paths.into_iter().peekable(); let mut path_stack = Vec::<(&Path, usize, GitStatuses)>::new(); let mut result = Vec::new(); @@ -2040,11 +2043,15 @@ impl LocalSnapshot { let Ok(repo_path) = entry.path.strip_prefix(&work_directory.0) else { continue; }; - let git_file_status = repo_ptr.status(&RepoPath(repo_path.into())); - let status = git_file_status; - entry.git_status = status; - changes.push(entry.path.clone()); - edits.push(Edit::Insert(entry)); + let git_file_status = repo_ptr + .status(&RepoPath(repo_path.into())) + .log_err() + .flatten(); + if entry.git_status != git_file_status { + entry.git_status = git_file_status; + changes.push(entry.path.clone()); + edits.push(Edit::Insert(entry)); + } } self.entries_by_path.edit(edits, &()); @@ -3068,11 +3075,16 @@ impl BackgroundScanner { } } else { child_entry.is_ignored = ignore_stack.is_abs_path_ignored(&child_abs_path, false); - - if let Some((repo_path, repo)) = &repository { - if let Ok(path) = child_path.strip_prefix(&repo_path.0) { - child_entry.git_status = - repo.repo_ptr.lock().status(&RepoPath(path.into())); + if !child_entry.is_ignored { + if let Some((repo_path, repo)) = &repository { + if let Ok(path) = child_path.strip_prefix(&repo_path.0) { + child_entry.git_status = repo + .repo_ptr + .lock() + .status(&RepoPath(path.into())) + .log_err() + .flatten(); + } } } } @@ -3170,11 +3182,19 @@ impl BackgroundScanner { ); fs_entry.is_ignored = ignore_stack.is_all(); - if !fs_entry.is_dir() { - if let Some((work_dir, repo)) = state.snapshot.local_repo_for_path(&path) { - if let Ok(path) = path.strip_prefix(work_dir.0) { - fs_entry.git_status = - repo.repo_ptr.lock().status(&RepoPath(path.into())) + if !fs_entry.is_ignored { + if !fs_entry.is_dir() { + if let Some((work_dir, repo)) = + state.snapshot.local_repo_for_path(&path) + { + if let Ok(path) = path.strip_prefix(work_dir.0) { + fs_entry.git_status = repo + .repo_ptr + .lock() + .status(&RepoPath(path.into())) + .log_err() + .flatten() + } } } } @@ -5345,7 +5365,7 @@ mod tests { let snapshot = tree.read_with(cx, |tree, _| tree.snapshot()); assert_eq!( - snapshot.statuses_for_paths(&[ + snapshot.statuses_for_paths([ Path::new(""), Path::new("a"), Path::new("a/b"), diff --git a/crates/project_panel/src/project_panel.rs b/crates/project_panel/src/project_panel.rs index f6f3d67f3a..3d7d32cef4 100644 --- a/crates/project_panel/src/project_panel.rs +++ b/crates/project_panel/src/project_panel.rs @@ -1109,8 +1109,16 @@ impl ProjectPanel { .unwrap_or(&[]); let entry_range = range.start.saturating_sub(ix)..end_ix - ix; - for entry in visible_worktree_entries[entry_range].iter() { - let status = git_status_setting.then(|| entry.git_status).flatten(); + let statuses = worktree.read(cx).statuses_for_paths( + visible_worktree_entries[entry_range.clone()] + .iter() + .map(|entry| entry.path.as_ref()), + ); + for (entry, status) in visible_worktree_entries[entry_range] + .iter() + .zip(statuses.into_iter()) + { + let status = git_status_setting.then(|| status).flatten(); let mut details = EntryDetails { filename: entry