From 5b2ee63f80d8b83583713b65e8bfe2ee5f0589b2 Mon Sep 17 00:00:00 2001 From: Mikayla Maki Date: Thu, 11 May 2023 12:01:42 -0700 Subject: [PATCH] Added status trickle up --- Cargo.lock | 7 ++++ crates/collab/src/tests/integration_tests.rs | 2 +- crates/fs/src/repository.rs | 2 +- crates/project/src/worktree.rs | 28 ++++++++++++- crates/project_panel/src/project_panel.rs | 10 +++-- crates/sum_tree/src/tree_map.rs | 44 +++++++++++++++++++- crates/util/Cargo.toml | 1 + crates/util/src/util.rs | 2 + 8 files changed, 88 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0190b4d8f5..81e4a4e025 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6537,6 +6537,12 @@ dependencies = [ "winx", ] +[[package]] +name = "take-until" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8bdb6fa0dfa67b38c1e66b7041ba9dcf23b99d8121907cd31c807a332f7a0bbb" + [[package]] name = "target-lexicon" version = "0.12.5" @@ -7596,6 +7602,7 @@ dependencies = [ "serde", "serde_json", "smol", + "take-until", "tempdir", "url", ] diff --git a/crates/collab/src/tests/integration_tests.rs b/crates/collab/src/tests/integration_tests.rs index aefc172268..47455c0a70 100644 --- a/crates/collab/src/tests/integration_tests.rs +++ b/crates/collab/src/tests/integration_tests.rs @@ -2760,7 +2760,7 @@ async fn test_git_status_sync( let worktree = worktrees[0].clone(); let snapshot = worktree.read(cx).snapshot(); let root_entry = snapshot.root_git_entry().unwrap(); - assert_eq!(root_entry.status_for(&snapshot, file), status); + assert_eq!(root_entry.status_for_file(&snapshot, file), status); } // Smoke test status reading diff --git a/crates/fs/src/repository.rs b/crates/fs/src/repository.rs index 2fe31f5569..13f55b9c94 100644 --- a/crates/fs/src/repository.rs +++ b/crates/fs/src/repository.rs @@ -184,7 +184,7 @@ fn check_path_to_repo_path_errors(relative_file_path: &Path) -> Result<()> { } } -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] pub enum GitFileStatus { Added, Modified, diff --git a/crates/project/src/worktree.rs b/crates/project/src/worktree.rs index a970067230..07302b4e2e 100644 --- a/crates/project/src/worktree.rs +++ b/crates/project/src/worktree.rs @@ -55,7 +55,7 @@ use std::{ time::{Duration, SystemTime}, }; use sum_tree::{Bias, Edit, SeekTarget, SumTree, TreeMap, TreeSet}; -use util::{paths::HOME, ResultExt, TryFutureExt}; +use util::{paths::HOME, ResultExt, TakeUntilExt, TryFutureExt}; #[derive(Copy, Clone, PartialEq, Eq, Debug, Hash, PartialOrd, Ord)] pub struct WorktreeId(usize); @@ -173,13 +173,37 @@ impl RepositoryEntry { self.work_directory.contains(snapshot, path) } - pub fn status_for(&self, snapshot: &Snapshot, path: &Path) -> Option { + pub fn status_for_file(&self, snapshot: &Snapshot, path: &Path) -> Option { self.work_directory .relativize(snapshot, path) .and_then(|repo_path| self.worktree_statuses.get(&repo_path)) .cloned() } + pub fn status_for_path(&self, snapshot: &Snapshot, path: &Path) -> Option { + self.work_directory + .relativize(snapshot, path) + .and_then(|repo_path| { + self.worktree_statuses + .get_from_while(&repo_path, |repo_path, key, _| key.starts_with(repo_path)) + .map(|(_, status)| status) + // Short circut once we've found the highest level + .take_until(|status| status == &&GitFileStatus::Conflict) + .reduce( + |status_first, status_second| match (status_first, status_second) { + (GitFileStatus::Conflict, _) | (_, GitFileStatus::Conflict) => { + &GitFileStatus::Conflict + } + (GitFileStatus::Added, _) | (_, GitFileStatus::Added) => { + &GitFileStatus::Added + } + _ => &GitFileStatus::Modified, + }, + ) + .copied() + }) + } + pub fn build_update(&self, other: &Self) -> proto::RepositoryEntry { let mut updated_statuses: Vec = Vec::new(); let mut removed_statuses: Vec = Vec::new(); diff --git a/crates/project_panel/src/project_panel.rs b/crates/project_panel/src/project_panel.rs index 49741ea49f..1066875022 100644 --- a/crates/project_panel/src/project_panel.rs +++ b/crates/project_panel/src/project_panel.rs @@ -1013,9 +1013,13 @@ impl ProjectPanel { let entry_range = range.start.saturating_sub(ix)..end_ix - ix; for entry in &visible_worktree_entries[entry_range] { let path = &entry.path; - let status = snapshot - .repo_for(path) - .and_then(|entry| entry.status_for(&snapshot, path)); + let status = (entry.path.parent().is_some() && !entry.is_ignored) + .then(|| { + snapshot + .repo_for(path) + .and_then(|entry| entry.status_for_path(&snapshot, path)) + }) + .flatten(); let mut details = EntryDetails { filename: entry diff --git a/crates/sum_tree/src/tree_map.rs b/crates/sum_tree/src/tree_map.rs index 3942d00b29..e59b05f00f 100644 --- a/crates/sum_tree/src/tree_map.rs +++ b/crates/sum_tree/src/tree_map.rs @@ -1,4 +1,4 @@ -use std::{cmp::Ordering, fmt::Debug}; +use std::{cmp::Ordering, fmt::Debug, iter}; use crate::{Bias, Dimension, Edit, Item, KeyedItem, SeekTarget, SumTree, Summary}; @@ -111,6 +111,26 @@ impl TreeMap { self.0 = new_tree; } + + pub fn get_from_while<'tree, F>(&'tree self, from: &'tree K, mut f: F) -> impl Iterator + '_ + where + F: FnMut(&K, &K, &V) -> bool + 'tree, + { + let mut cursor = self.0.cursor::>(); + let from_key = MapKeyRef(Some(from)); + cursor.seek(&from_key, Bias::Left, &()); + + iter::from_fn(move || { + let result = cursor.item().and_then(|item| { + (f(from, &item.key, &item.value)) + .then(|| (&item.key, &item.value)) + }); + cursor.next(&()); + result + }) + } + + pub fn update(&mut self, key: &K, f: F) -> Option where F: FnOnce(&mut V) -> T, @@ -354,6 +374,28 @@ mod tests { assert_eq!(map.get(&"c"), Some(&5)); } + #[test] + fn test_get_from_while() { + let mut map = TreeMap::default(); + + map.insert("a", 1); + map.insert("b", 2); + map.insert("baa", 3); + map.insert("baaab", 4); + map.insert("c", 5); + + let result = map.get_from_while(&"ba", |key, _| key.starts_with(&"ba")).collect::>(); + + assert_eq!(result.len(), 2); + assert!(result.iter().find(|(k, _)| k == &&"baa").is_some()); + assert!(result.iter().find(|(k, _)| k == &&"baaab").is_some()); + + let result = map.get_from_while(&"c", |key, _| key.starts_with(&"c")).collect::>(); + + assert_eq!(result.len(), 1); + assert!(result.iter().find(|(k, _)| k == &&"c").is_some()); + } + #[test] fn test_insert_tree() { let mut map = TreeMap::default(); diff --git a/crates/util/Cargo.toml b/crates/util/Cargo.toml index 319d815d17..4ec8f7553c 100644 --- a/crates/util/Cargo.toml +++ b/crates/util/Cargo.toml @@ -26,6 +26,7 @@ serde.workspace = true serde_json.workspace = true git2 = { version = "0.15", default-features = false, optional = true } dirs = "3.0" +take-until = "0.2.0" [dev-dependencies] tempdir.workspace = true diff --git a/crates/util/src/util.rs b/crates/util/src/util.rs index 903b0eec59..63b2d5f279 100644 --- a/crates/util/src/util.rs +++ b/crates/util/src/util.rs @@ -17,6 +17,8 @@ pub use backtrace::Backtrace; use futures::Future; use rand::{seq::SliceRandom, Rng}; +pub use take_until::*; + #[macro_export] macro_rules! debug_panic { ( $($fmt_arg:tt)* ) => {