WIP: Add status bubbling to project panel

This commit is contained in:
Mikayla Maki 2023-06-05 12:53:04 -07:00
parent 49c5a3fa86
commit 9a13a2ba2c
No known key found for this signature in database
3 changed files with 54 additions and 26 deletions

View file

@ -25,7 +25,7 @@ pub trait GitRepository: Send {
fn statuses(&self) -> Option<TreeMap<RepoPath, GitFileStatus>>; fn statuses(&self) -> Option<TreeMap<RepoPath, GitFileStatus>>;
fn status(&self, path: &RepoPath) -> Option<GitFileStatus>; fn status(&self, path: &RepoPath) -> Result<Option<GitFileStatus>>;
} }
impl std::fmt::Debug for dyn GitRepository { impl std::fmt::Debug for dyn GitRepository {
@ -92,9 +92,9 @@ impl GitRepository for LibGitRepository {
Some(map) Some(map)
} }
fn status(&self, path: &RepoPath) -> Option<GitFileStatus> { fn status(&self, path: &RepoPath) -> Result<Option<GitFileStatus>> {
let status = self.status_file(path).log_err()?; let status = self.status_file(path)?;
read_status(status) Ok(read_status(status))
} }
} }
@ -156,9 +156,9 @@ impl GitRepository for FakeGitRepository {
Some(map) Some(map)
} }
fn status(&self, path: &RepoPath) -> Option<GitFileStatus> { fn status(&self, path: &RepoPath) -> Result<Option<GitFileStatus>> {
let state = self.state.lock(); let state = self.state.lock();
state.worktree_statuses.get(path).cloned() Ok(state.worktree_statuses.get(path).cloned())
} }
} }

View file

@ -1670,11 +1670,14 @@ impl Snapshot {
}) })
} }
pub fn statuses_for_paths(&self, paths: &[&Path]) -> Vec<Option<GitFileStatus>> { pub fn statuses_for_paths<'a>(
&self,
paths: impl IntoIterator<Item = &'a Path>,
) -> Vec<Option<GitFileStatus>> {
let mut cursor = self let mut cursor = self
.entries_by_path .entries_by_path
.cursor::<(TraversalProgress, GitStatuses)>(); .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 path_stack = Vec::<(&Path, usize, GitStatuses)>::new();
let mut result = Vec::new(); let mut result = Vec::new();
@ -2040,11 +2043,15 @@ impl LocalSnapshot {
let Ok(repo_path) = entry.path.strip_prefix(&work_directory.0) else { let Ok(repo_path) = entry.path.strip_prefix(&work_directory.0) else {
continue; continue;
}; };
let git_file_status = repo_ptr.status(&RepoPath(repo_path.into())); let git_file_status = repo_ptr
let status = git_file_status; .status(&RepoPath(repo_path.into()))
entry.git_status = status; .log_err()
changes.push(entry.path.clone()); .flatten();
edits.push(Edit::Insert(entry)); 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, &()); self.entries_by_path.edit(edits, &());
@ -3068,11 +3075,16 @@ impl BackgroundScanner {
} }
} else { } else {
child_entry.is_ignored = ignore_stack.is_abs_path_ignored(&child_abs_path, false); child_entry.is_ignored = ignore_stack.is_abs_path_ignored(&child_abs_path, false);
if !child_entry.is_ignored {
if let Some((repo_path, repo)) = &repository { if let Some((repo_path, repo)) = &repository {
if let Ok(path) = child_path.strip_prefix(&repo_path.0) { if let Ok(path) = child_path.strip_prefix(&repo_path.0) {
child_entry.git_status = child_entry.git_status = repo
repo.repo_ptr.lock().status(&RepoPath(path.into())); .repo_ptr
.lock()
.status(&RepoPath(path.into()))
.log_err()
.flatten();
}
} }
} }
} }
@ -3170,11 +3182,19 @@ impl BackgroundScanner {
); );
fs_entry.is_ignored = ignore_stack.is_all(); fs_entry.is_ignored = ignore_stack.is_all();
if !fs_entry.is_dir() { if !fs_entry.is_ignored {
if let Some((work_dir, repo)) = state.snapshot.local_repo_for_path(&path) { if !fs_entry.is_dir() {
if let Ok(path) = path.strip_prefix(work_dir.0) { if let Some((work_dir, repo)) =
fs_entry.git_status = state.snapshot.local_repo_for_path(&path)
repo.repo_ptr.lock().status(&RepoPath(path.into())) {
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()); let snapshot = tree.read_with(cx, |tree, _| tree.snapshot());
assert_eq!( assert_eq!(
snapshot.statuses_for_paths(&[ snapshot.statuses_for_paths([
Path::new(""), Path::new(""),
Path::new("a"), Path::new("a"),
Path::new("a/b"), Path::new("a/b"),

View file

@ -1109,8 +1109,16 @@ impl ProjectPanel {
.unwrap_or(&[]); .unwrap_or(&[]);
let entry_range = range.start.saturating_sub(ix)..end_ix - ix; let entry_range = range.start.saturating_sub(ix)..end_ix - ix;
for entry in visible_worktree_entries[entry_range].iter() { let statuses = worktree.read(cx).statuses_for_paths(
let status = git_status_setting.then(|| entry.git_status).flatten(); 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 { let mut details = EntryDetails {
filename: entry filename: entry