Add absolute paths to historic elements

This commit is contained in:
Kirill Bulatov 2023-05-26 14:03:44 +03:00
parent 128c19875d
commit 364631a155

View file

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