From d30385f07ceef97ebdbba4fd71dda78e0d274f06 Mon Sep 17 00:00:00 2001 From: Kirill Bulatov Date: Thu, 28 Sep 2023 09:49:25 -0700 Subject: [PATCH] Show path matches inside history items matching the query --- crates/file_finder/src/file_finder.rs | 58 +++++++++++++++++++-------- 1 file changed, 41 insertions(+), 17 deletions(-) diff --git a/crates/file_finder/src/file_finder.rs b/crates/file_finder/src/file_finder.rs index cb41533112..6e587d8c98 100644 --- a/crates/file_finder/src/file_finder.rs +++ b/crates/file_finder/src/file_finder.rs @@ -1,4 +1,4 @@ -use collections::{HashMap, HashSet}; +use collections::HashMap; use editor::{scroll::autoscroll::Autoscroll, Bias, Editor}; use fuzzy::{CharBag, PathMatch, PathMatchCandidate}; use gpui::{ @@ -35,13 +35,13 @@ pub struct FileFinderDelegate { #[derive(Debug, Default)] struct Matches { - history: Vec, + history: Vec<(FoundPath, Option)>, search: Vec, } #[derive(Debug)] enum Match<'a> { - History(&'a FoundPath), + History(&'a FoundPath, Option<&'a PathMatch>), Search(&'a PathMatch), } @@ -52,7 +52,9 @@ impl Matches { fn get(&self, index: usize) -> Option> { if index < self.history.len() { - self.history.get(index).map(Match::History) + self.history + .get(index) + .map(|(path, path_match)| Match::History(path, path_match.as_ref())) } else { self.search .get(index - self.history.len()) @@ -68,16 +70,25 @@ impl Matches { extend_old_matches: bool, ) { let matching_history_paths = matching_history_item_paths(history_items, query); - new_search_matches.retain(|path_match| !matching_history_paths.contains(&path_match.path)); + new_search_matches + .retain(|path_match| !matching_history_paths.contains_key(&path_match.path)); let history_items_to_show = history_items .iter() - .filter(|history_item| matching_history_paths.contains(&history_item.project.path)) - .cloned() + .filter_map(|history_item| { + Some(( + history_item.clone(), + Some( + matching_history_paths + .get(&history_item.project.path)? + .clone(), + ), + )) + }) .collect::>(); self.history = history_items_to_show; if extend_old_matches { self.search - .retain(|path_match| !matching_history_paths.contains(&path_match.path)); + .retain(|path_match| !matching_history_paths.contains_key(&path_match.path)); util::extend_sorted( &mut self.search, new_search_matches.into_iter(), @@ -93,7 +104,7 @@ impl Matches { fn matching_history_item_paths( history_items: &Vec, query: &PathLikeWithPosition, -) -> HashSet> { +) -> HashMap, PathMatch> { let history_items_by_worktrees = history_items .iter() .map(|found_path| { @@ -114,7 +125,7 @@ fn matching_history_item_paths( candidates }, ); - let mut matching_history_paths = HashSet::default(); + let mut matching_history_paths = HashMap::default(); for (worktree, candidates) in history_items_by_worktrees { let max_results = candidates.len() + 1; matching_history_paths.extend( @@ -126,7 +137,7 @@ fn matching_history_item_paths( max_results, ) .into_iter() - .map(|path_match| path_match.path), + .map(|path_match| (Arc::clone(&path_match.path), path_match)), ); } matching_history_paths @@ -358,7 +369,7 @@ impl FileFinderDelegate { ix: usize, ) -> (String, Vec, String, Vec) { let (file_name, file_name_positions, full_path, full_path_positions) = match path_match { - Match::History(found_path) => { + Match::History(found_path, found_path_match) => { let worktree_id = found_path.project.worktree_id; let project_relative_path = &found_path.project.path; let has_worktree = self @@ -390,14 +401,22 @@ impl FileFinderDelegate { path = Arc::from(absolute_path.as_path()); } } - self.labels_for_path_match(&PathMatch { + + let mut path_match = PathMatch { score: ix as f64, positions: Vec::new(), worktree_id: worktree_id.to_usize(), path, path_prefix: "".into(), distance_to_relative_ancestor: usize::MAX, - }) + }; + if let Some(found_path_match) = found_path_match { + path_match + .positions + .extend(found_path_match.positions.iter()) + } + + self.labels_for_path_match(&path_match) } Match::Search(path_match) => self.labels_for_path_match(path_match), }; @@ -494,6 +513,7 @@ impl PickerDelegate for FileFinderDelegate { .is_some()) }) .cloned() + .map(|p| (p, None)) .collect(), search: Vec::new(), }; @@ -528,7 +548,7 @@ impl PickerDelegate for FileFinderDelegate { } }; match m { - Match::History(history_match) => { + Match::History(history_match, _) => { let worktree_id = history_match.project.worktree_id; if workspace .project() @@ -1723,7 +1743,9 @@ mod tests { finder.read_with(cx, |finder, _| { let delegate = finder.delegate(); assert_eq!(delegate.matches.history.len(), 1, "Only one history item contains {first_query}, it should be present and others should be filtered out"); - assert_eq!(delegate.matches.history.first().unwrap(), &FoundPath::new( + let history_match = delegate.matches.history.first().unwrap(); + assert!(history_match.1.is_some(), "Should have path matches for history items after querying"); + assert_eq!(history_match.0, FoundPath::new( ProjectPath { worktree_id, path: Arc::from(Path::new("test/first.rs")), @@ -1767,7 +1789,9 @@ mod tests { finder.read_with(cx, |finder, _| { let delegate = finder.delegate(); assert_eq!(delegate.matches.history.len(), 1, "Only one history item contains {first_query_again}, it should be present and others should be filtered out, even after non-matching query"); - assert_eq!(delegate.matches.history.first().unwrap(), &FoundPath::new( + let history_match = delegate.matches.history.first().unwrap(); + assert!(history_match.1.is_some(), "Should have path matches for history items after querying"); + assert_eq!(history_match.0, FoundPath::new( ProjectPath { worktree_id, path: Arc::from(Path::new("test/first.rs")),