diff --git a/crates/file_finder/src/file_finder.rs b/crates/file_finder/src/file_finder.rs index c4fce49152..13dc46382f 100644 --- a/crates/file_finder/src/file_finder.rs +++ b/crates/file_finder/src/file_finder.rs @@ -6,7 +6,7 @@ use gpui::{ use picker::{Picker, PickerDelegate}; use project::{PathMatchCandidateSet, Project, ProjectPath, WorktreeId}; use std::{ - path::Path, + path::{Path, PathBuf}, sync::{ atomic::{self, AtomicBool}, Arc, @@ -25,11 +25,17 @@ pub struct FileFinderDelegate { latest_search_id: usize, latest_search_did_cancel: bool, latest_search_query: Option>, - currently_opened_path: Option, + currently_opened_path: Option, matches: Vec, selected: Option<(usize, Arc)>, cancel_flag: Arc, - history_items: Vec, + history_items: Vec, +} + +#[derive(Debug, Clone, PartialEq, Eq)] +struct FoundPath { + project: ProjectPath, + absolute: Option, } actions!(file_finder, [Toggle]); @@ -43,10 +49,36 @@ const MAX_RECENT_SELECTIONS: usize = 20; fn toggle_file_finder(workspace: &mut Workspace, _: &Toggle, cx: &mut ViewContext) { workspace.toggle_modal(cx, |workspace, cx| { - let history_items = workspace.recent_navigation_history(Some(MAX_RECENT_SELECTIONS), cx); + let project = workspace.project().read(cx); + let project_to_found_path = |project_path: ProjectPath| FoundPath { + absolute: project + .worktree_for_id(project_path.worktree_id, cx) + .map(|worktree| worktree.read(cx).abs_path().join(&project_path.path)), + project: project_path, + }; + let currently_opened_path = workspace .active_item(cx) - .and_then(|item| item.project_path(cx)); + .and_then(|item| item.project_path(cx)) + .map(project_to_found_path); + + // if exists, bubble the currently opened path to the top + let history_items = currently_opened_path + .clone() + .into_iter() + .chain( + workspace + .recent_navigation_history(Some(MAX_RECENT_SELECTIONS), cx) + .into_iter() + .filter(|history_path| { + Some(history_path) + != currently_opened_path + .as_ref() + .map(|found_path| &found_path.project) + }) + .map(project_to_found_path), + ) + .collect(); let project = workspace.project().clone(); let workspace = cx.handle().downgrade(); @@ -113,11 +145,11 @@ impl FileFinderDelegate { (file_name, file_name_positions, full_path, path_positions) } - pub fn new( + fn new( workspace: WeakViewHandle, project: ModelHandle, - currently_opened_path: Option, - history_items: Vec, + currently_opened_path: Option, + history_items: Vec, cx: &mut ViewContext, ) -> Self { cx.observe(&project, |picker, _, cx| { @@ -147,7 +179,7 @@ impl FileFinderDelegate { let relative_to = self .currently_opened_path .as_ref() - .map(|project_path| Arc::clone(&project_path.path)); + .map(|found_path| Arc::clone(&found_path.project.path)); let worktrees = self .project .read(cx) @@ -255,20 +287,33 @@ impl PickerDelegate for FileFinderDelegate { self.latest_search_id = post_inc(&mut self.search_count); self.matches.clear(); + let project = self.project.read(cx); self.matches = self - .currently_opened_path - .iter() // if exists, bubble the currently opened path to the top - .chain(self.history_items.iter().filter(|history_item| { - Some(*history_item) != self.currently_opened_path.as_ref() - })) + .history_items + .iter() .enumerate() - .map(|(i, history_item)| PathMatch { - score: i as f64, - positions: Vec::new(), - worktree_id: history_item.worktree_id.to_usize(), - path: Arc::clone(&history_item.path), - path_prefix: "".into(), - distance_to_relative_ancestor: usize::MAX, + .map(|(i, found_path)| { + let worktree_id = found_path.project.worktree_id; + // TODO kb wrong: + // * for no worktree, check the project path + // * if no project path exists — filter out(?), otherwise take it and open a workspace for it (enum for match kinds?) + let path = if project.worktree_for_id(worktree_id, cx).is_some() { + Arc::clone(&found_path.project.path) + } else { + found_path + .absolute + .as_ref() + .map(|abs_path| Arc::from(abs_path.as_path())) + .unwrap_or_else(|| Arc::clone(&found_path.project.path)) + }; + PathMatch { + score: i as f64, + positions: Vec::new(), + worktree_id: worktree_id.to_usize(), + path, + path_prefix: "".into(), + distance_to_relative_ancestor: usize::MAX, + } }) .collect(); cx.notify(); @@ -876,10 +921,10 @@ mod tests { // When workspace has an active item, sort items which are closer to that item // first when they have the same name. In this case, b.txt is closer to dir2's a.txt // so that one should be sorted earlier - let b_path = Some(ProjectPath { + let b_path = Some(dummy_found_path(ProjectPath { worktree_id, path: Arc::from(Path::new("/root/dir2/b.txt")), - }); + })); let (_, finder) = cx.add_window(|cx| { Picker::new( FileFinderDelegate::new( @@ -1012,10 +1057,10 @@ mod tests { .await; assert_eq!( history_after_first, - vec![ProjectPath { + vec![dummy_found_path(ProjectPath { worktree_id, path: Arc::from(Path::new("test/first.rs")), - }], + })], "Should show 1st opened item in the history when opening the 2nd item" ); @@ -1032,14 +1077,14 @@ mod tests { assert_eq!( history_after_second, vec![ - ProjectPath { + dummy_found_path(ProjectPath { worktree_id, path: Arc::from(Path::new("test/second.rs")), - }, - ProjectPath { + }), + dummy_found_path(ProjectPath { worktree_id, path: Arc::from(Path::new("test/first.rs")), - }, + }), ], "Should show 1st and 2nd opened items in the history when opening the 3rd item. \ 2nd item should be the first in the history, as the last opened." @@ -1058,18 +1103,18 @@ mod tests { assert_eq!( history_after_third, vec![ - ProjectPath { + dummy_found_path(ProjectPath { worktree_id, path: Arc::from(Path::new("test/third.rs")), - }, - ProjectPath { + }), + dummy_found_path(ProjectPath { worktree_id, path: Arc::from(Path::new("test/second.rs")), - }, - ProjectPath { + }), + dummy_found_path(ProjectPath { worktree_id, path: Arc::from(Path::new("test/first.rs")), - }, + }), ], "Should show 1st, 2nd and 3rd opened items in the history when opening the 2nd item again. \ 3rd item should be the first in the history, as the last opened." @@ -1088,18 +1133,18 @@ mod tests { assert_eq!( history_after_second_again, vec![ - ProjectPath { + dummy_found_path(ProjectPath { worktree_id, path: Arc::from(Path::new("test/second.rs")), - }, - ProjectPath { + }), + dummy_found_path(ProjectPath { worktree_id, path: Arc::from(Path::new("test/third.rs")), - }, - ProjectPath { + }), + dummy_found_path(ProjectPath { worktree_id, path: Arc::from(Path::new("test/first.rs")), - }, + }), ], "Should show 1st, 2nd and 3rd opened items in the history when opening the 3rd item again. \ 2nd item, as the last opened, 3rd item should go next as it was opened right before." @@ -1114,7 +1159,7 @@ mod tests { workspace: &ViewHandle, deterministic: &gpui::executor::Deterministic, cx: &mut gpui::TestAppContext, - ) -> Vec { + ) -> Vec { cx.dispatch_action(window_id, Toggle); let finder = cx.read(|cx| workspace.read(cx).modal::().unwrap()); finder @@ -1216,4 +1261,11 @@ mod tests { }) .unwrap() } + + fn dummy_found_path(project_path: ProjectPath) -> FoundPath { + FoundPath { + project: project_path, + absolute: None, + } + } }