Co-authored-by: Mikayla <mikayla@zed.dev>
This commit is contained in:
Cole Miller 2024-12-18 18:53:19 -05:00
parent f1651196cb
commit ff2a364b24
2 changed files with 69 additions and 88 deletions

View file

@ -2480,13 +2480,17 @@ impl Snapshot {
}) })
} }
pub fn propagate_git_statuses2(&self, entries: &[Entry]) -> Vec<Option<GitFileStatus>> { pub fn propagate_git_statuses(&self, entries: &[Entry]) -> Vec<Option<GitFileStatus>> {
let mut cursor = all_statuses_cursor(self); let mut cursor = all_statuses_cursor(self);
let mut entry_stack = Vec::<(usize, GitStatuses)>::new(); let mut entry_stack = Vec::<(usize, GitStatuses)>::new();
let mut result = entries let mut result = entries
.iter() .iter()
.map(|entry| { .map(|entry| {
if entry.is_dir() {
return None;
}
let (work_directory, repo_entry) = let (work_directory, repo_entry) =
self.repository_and_work_directory_for_path(&entry.path)?; self.repository_and_work_directory_for_path(&entry.path)?;
let RepoPath(path) = repo_entry.relativize(self, &entry.path).ok()?; let RepoPath(path) = repo_entry.relativize(self, &entry.path).ok()?;
@ -2495,11 +2499,22 @@ impl Snapshot {
}) })
.collect::<Vec<_>>(); .collect::<Vec<_>>();
// dbg!(entries
// .iter()
// .zip(result.iter())
// .map(|(entry, status)| { (entry.path.clone(), status) })
// .collect::<Vec<_>>());
let mut entry_ix = 0; let mut entry_ix = 0;
loop { loop {
let next_entry = entries.get(entry_ix); let next_entry = entries.get(entry_ix);
let containing_entry = entry_stack.last().map(|(ix, _)| &entries[*ix]); let containing_entry = entry_stack.last().map(|(ix, _)| &entries[*ix]);
dbg!(entry_stack
.iter()
.map(|(ix, statuses)| (entries[*ix].path.clone(), statuses))
.collect::<Vec<_>>());
let entry_to_finish = match (containing_entry, next_entry) { let entry_to_finish = match (containing_entry, next_entry) {
(Some(_), None) => entry_stack.pop(), (Some(_), None) => entry_stack.pop(),
(Some(containing_entry), Some(next_path)) => { (Some(containing_entry), Some(next_path)) => {
@ -2514,12 +2529,15 @@ impl Snapshot {
}; };
if let Some((entry_ix, prev_statuses)) = entry_to_finish { if let Some((entry_ix, prev_statuses)) = entry_to_finish {
cursor.seek_forward(&GitEntryTraversalTarget::PathSuccessor(dbg!( dbg!("seeking for entry to finish");
cursor.seek_forward(dbg!(&GitEntryTraversalTarget::PathSuccessor(
&entries[entry_ix].path &entries[entry_ix].path
))); )));
let statuses = dbg!(cursor.start()) - dbg!(prev_statuses); let statuses = dbg!(cursor.start()) - dbg!(prev_statuses);
dbg!((&entries[entry_ix].path, &statuses));
result[entry_ix] = if statuses.conflict > 0 { result[entry_ix] = if statuses.conflict > 0 {
Some(GitFileStatus::Conflict) Some(GitFileStatus::Conflict)
} else if statuses.modified > 0 { } else if statuses.modified > 0 {
@ -2531,6 +2549,7 @@ impl Snapshot {
}; };
} else { } else {
if entries[entry_ix].is_dir() { if entries[entry_ix].is_dir() {
dbg!("seeking for entry is_dir");
cursor.seek_forward(&GitEntryTraversalTarget::Path(&entries[entry_ix].path)); cursor.seek_forward(&GitEntryTraversalTarget::Path(&entries[entry_ix].path));
entry_stack.push((entry_ix, cursor.start())); entry_stack.push((entry_ix, cursor.start()));
} }
@ -2541,72 +2560,6 @@ impl Snapshot {
result result
} }
/// TODO: Redo this entirely, API is wrong, conceptually it's a bit weird
/// Updates the `git_status` of the given entries such that files'
/// statuses bubble up to their ancestor directories.
pub fn propagate_git_statuses(&self, entries: &[Entry]) -> Vec<Option<GitFileStatus>> {
let mut cursor = all_statuses_cursor(self);
let mut entry_stack = Vec::<(usize, GitStatuses)>::new();
let mut result = vec![None; entries.len()];
let mut entry_ix = 0;
loop {
let next_entry = entries.get(entry_ix);
dbg!(&next_entry);
let containing_entry = entry_stack.last().map(|(ix, _)| &entries[*ix]);
dbg!(&containing_entry);
let entry_to_finish = match (containing_entry, next_entry) {
(Some(_), None) => entry_stack.pop(),
(Some(containing_entry), Some(next_path)) => {
if next_path.path.starts_with(&containing_entry.path) {
None
} else {
entry_stack.pop()
}
}
(None, Some(_)) => None,
(None, None) => break,
};
if let Some((entry_ix, prev_statuses)) = entry_to_finish {
dbg!(cursor.item());
cursor.seek_forward(&GitEntryTraversalTarget::PathSuccessor(
&entries[entry_ix].path,
));
let statuses = cursor.start() - prev_statuses;
result[entry_ix] = if statuses.conflict > 0 {
Some(GitFileStatus::Conflict)
} else if statuses.modified > 0 {
Some(GitFileStatus::Modified)
} else if statuses.added > 0 {
Some(GitFileStatus::Added)
} else if statuses.untracked > 0 {
Some(GitFileStatus::Untracked)
} else {
None
};
} else {
if entries[entry_ix].is_dir() {
cursor.seek_forward(&GitEntryTraversalTarget::PathSuccessor(
&entries[entry_ix].path,
));
dbg!(cursor.start());
dbg!(cursor.item());
entry_stack.push((entry_ix, cursor.start()));
} else {
cursor.seek_forward(&GitEntryTraversalTarget::Path(&entries[entry_ix].path));
dbg!(cursor.item());
result[entry_ix] = cursor.item().map(|entry| entry.git_status)
}
entry_ix += 1;
}
}
result
}
pub fn paths(&self) -> impl Iterator<Item = &Arc<Path>> { pub fn paths(&self) -> impl Iterator<Item = &Arc<Path>> {
let empty_path = Path::new(""); let empty_path = Path::new("");
self.entries_by_path self.entries_by_path
@ -3778,14 +3731,15 @@ where
I: Iterator<Item = (&'a RepositoryWorkDirectory, &'a RepositoryEntry)>, I: Iterator<Item = (&'a RepositoryWorkDirectory, &'a RepositoryEntry)>,
{ {
fn seek_forward(&mut self, target: &GitEntryTraversalTarget<'_>) { fn seek_forward(&mut self, target: &GitEntryTraversalTarget<'_>) {
dbg!(target);
loop { loop {
dbg!("starting loop");
let cursor = match &mut self.current_cursor { let cursor = match &mut self.current_cursor {
Some(cursor) => cursor, Some(cursor) => cursor,
None => { None => {
let Some((_, entry)) = self.repositories.next() else { let Some((work_dir, entry)) = self.repositories.next() else {
break; break;
}; };
dbg!(work_dir);
self.current_cursor = Some( self.current_cursor = Some(
entry entry
.git_entries_by_path .git_entries_by_path
@ -3795,9 +3749,10 @@ where
} }
}; };
let found = cursor.seek_forward(target, Bias::Left, &()); let found = cursor.seek_forward(target, Bias::Left, &());
if found { if dbg!(found) {
break; break;
} }
self.statuses_so_far = cursor.start().1;
self.current_cursor = None; self.current_cursor = None;
} }
} }
@ -3809,10 +3764,12 @@ where
} }
fn start(&self) -> GitStatuses { fn start(&self) -> GitStatuses {
dbg!(self.current_cursor.is_none());
if let Some(cursor) = self.current_cursor.as_ref() { if let Some(cursor) = self.current_cursor.as_ref() {
dbg!(cursor.start().1) cursor.start().1
} else { } else {
dbg!(GitStatuses::default()) self.statuses_so_far
} }
} }
} }
@ -3821,18 +3778,23 @@ fn all_statuses_cursor<'a>(
snapshot: &'a Snapshot, snapshot: &'a Snapshot,
) -> AllStatusesCursor<'a, impl Iterator<Item = (&'a RepositoryWorkDirectory, &'a RepositoryEntry)>> ) -> AllStatusesCursor<'a, impl Iterator<Item = (&'a RepositoryWorkDirectory, &'a RepositoryEntry)>>
{ {
dbg!(snapshot
.repositories()
.map(|(workdir, _)| workdir)
.collect::<Vec<_>>());
let mut repositories = snapshot.repositories(); let mut repositories = snapshot.repositories();
let cursor = util::maybe!({ // let cursor = util::maybe!({
let (workdir, entry) = repositories.next()?; // let (workdir, entry) = repositories.next()?;
Some( // dbg!(workdir);
entry // Some(
.git_entries_by_path // entry
.cursor::<(TraversalProgress<'_>, GitStatuses)>(&()), // .git_entries_by_path
) // .cursor::<(TraversalProgress<'_>, GitStatuses)>(&()),
}); // )
// });
AllStatusesCursor { AllStatusesCursor {
repositories, repositories,
current_cursor: cursor, current_cursor: None,
statuses_so_far: Default::default(), statuses_so_far: Default::default(),
} }
} }

View file

@ -2759,7 +2759,6 @@ async fn test_propagate_git_statuses(cx: &mut TestAppContext) {
"h1.txt": "", "h1.txt": "",
"h2.txt": "" "h2.txt": ""
}, },
}), }),
) )
.await; .await;
@ -2789,19 +2788,39 @@ async fn test_propagate_git_statuses(cx: &mut TestAppContext) {
cx.executor().run_until_parked(); cx.executor().run_until_parked();
let snapshot = tree.read_with(cx, |tree, _| tree.snapshot()); let snapshot = tree.read_with(cx, |tree, _| tree.snapshot());
dbg!("********************************");
check_propagated_statuses( check_propagated_statuses(
&snapshot, &snapshot,
&[ &[
(Path::new(""), Some(GitFileStatus::Conflict)), (Path::new(""), Some(GitFileStatus::Conflict)), // This one is missing
// (Path::new("a"), Some(GitFileStatus::Added)),
// (Path::new("a/b"), Some(GitFileStatus::Modified)), // This one ISN'T
// (Path::new("a/b/c1.txt"), Some(GitFileStatus::Added)),
// (Path::new("a/b/c2.txt"), None),
// (Path::new("a/d"), Some(GitFileStatus::Modified)), //This one is missing
// (Path::new("a/d/e2.txt"), Some(GitFileStatus::Modified)),
// (Path::new("f"), None),
// (Path::new("f/no-status.txt"), None),
(Path::new("g"), Some(GitFileStatus::Conflict)), // This one is missing
(Path::new("g/h2.txt"), Some(GitFileStatus::Conflict)),
],
);
panic!("first test passed");
check_propagated_statuses(
&snapshot,
&[
(Path::new(""), Some(GitFileStatus::Conflict)), // This one is missing
(Path::new("a"), Some(GitFileStatus::Modified)), (Path::new("a"), Some(GitFileStatus::Modified)),
(Path::new("a/b"), Some(GitFileStatus::Added)), (Path::new("a/b"), Some(GitFileStatus::Added)), // This one ISN'T
(Path::new("a/b/c1.txt"), Some(GitFileStatus::Added)), (Path::new("a/b/c1.txt"), Some(GitFileStatus::Added)),
(Path::new("a/b/c2.txt"), None), (Path::new("a/b/c2.txt"), None),
(Path::new("a/d"), Some(GitFileStatus::Modified)), (Path::new("a/d"), Some(GitFileStatus::Modified)), //This one is missing
(Path::new("a/d/e2.txt"), Some(GitFileStatus::Modified)), (Path::new("a/d/e2.txt"), Some(GitFileStatus::Modified)),
(Path::new("f"), None), (Path::new("f"), None),
(Path::new("f/no-status.txt"), None), (Path::new("f/no-status.txt"), None),
(Path::new("g"), Some(GitFileStatus::Conflict)), (Path::new("g"), Some(GitFileStatus::Conflict)), // This one is missing
(Path::new("g/h2.txt"), Some(GitFileStatus::Conflict)), (Path::new("g/h2.txt"), Some(GitFileStatus::Conflict)),
], ],
); );
@ -2920,7 +2939,7 @@ fn check_propagated_statuses(
.iter() .iter()
.map(|(path, _)| snapshot.entry_for_path(path).unwrap().clone()) .map(|(path, _)| snapshot.entry_for_path(path).unwrap().clone())
.collect::<Vec<_>>(); .collect::<Vec<_>>();
let statuses = snapshot.propagate_git_statuses2(&entries); let statuses = snapshot.propagate_git_statuses(&entries);
assert_eq!( assert_eq!(
entries entries
.iter() .iter()