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 status(&self, path: &RepoPath) -> Option<GitFileStatus>;
fn status(&self, path: &RepoPath) -> Result<Option<GitFileStatus>>;
}
impl std::fmt::Debug for dyn GitRepository {
@ -92,9 +92,9 @@ impl GitRepository for LibGitRepository {
Some(map)
}
fn status(&self, path: &RepoPath) -> Option<GitFileStatus> {
let status = self.status_file(path).log_err()?;
read_status(status)
fn status(&self, path: &RepoPath) -> Result<Option<GitFileStatus>> {
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<GitFileStatus> {
fn status(&self, path: &RepoPath) -> Result<Option<GitFileStatus>> {
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
.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"),

View File

@ -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