Order history items by open recency (#7248)

Closes https://github.com/zed-industries/zed/issues/7244

Follow-up of https://github.com/zed-industries/zed/pull/7210 that
returns back ordering of history items by open recency (last opened
history item should be on top)

Release Notes:

- N/A

---------

Co-authored-by: Andrew Lygin <alygin@gmail.com>
This commit is contained in:
Kirill Bulatov 2024-02-01 23:45:03 +02:00 committed by GitHub
parent 0897c8eebd
commit da44f637ed
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 72 additions and 23 deletions

View File

@ -1,7 +1,7 @@
#[cfg(test)]
mod file_finder_tests;
use collections::HashMap;
use collections::{HashMap, HashSet};
use editor::{scroll::Autoscroll, Bias, Editor};
use fuzzy::{CharBag, PathMatch, PathMatchCandidate};
use gpui::{
@ -222,9 +222,11 @@ impl Matches {
query_matches: Option<&'a HashMap<Arc<Path>, ProjectPanelOrdMatch>>,
history_items: impl IntoIterator<Item = &'a FoundPath> + 'a,
) {
let history_items_to_show = history_items
let mut processed_paths = HashSet::default();
self.history = history_items
.into_iter()
.chain(currently_opened)
.filter(|&path| processed_paths.insert(path))
.filter_map(|history_item| match &query_matches {
Some(query_matches) => Some((
history_item.clone(),
@ -232,31 +234,22 @@ impl Matches {
)),
None => Some((history_item.clone(), None)),
})
.sorted_by(|(path_a, match_a), (path_b, match_b)| {
match (
.enumerate()
.sorted_by(
|(index_a, (path_a, match_a)), (index_b, (path_b, match_b))| match (
Some(path_a) == currently_opened,
Some(path_b) == currently_opened,
) {
// bubble currently opened files to the top
(true, false) => cmp::Ordering::Less,
(false, true) => cmp::Ordering::Greater,
_ => match_b.cmp(match_a),
}
});
self.history.clear();
util::extend_sorted(
&mut self.history,
history_items_to_show.collect::<Vec<_>>(),
100,
|(path_a, match_a), (path_b, match_b)| match (
Some(path_a) == currently_opened,
Some(path_b) == currently_opened,
) {
(true, false) => cmp::Ordering::Less,
(false, true) => cmp::Ordering::Greater,
_ => match_b.cmp(match_a).then(path_b.cmp(path_a)),
},
);
// arrange the files by their score (best score on top) and by their occurrence in the history
// (history items visited later are on the top)
_ => match_b.cmp(match_a).then(index_a.cmp(index_b)),
},
)
.map(|(_, paths)| paths)
.collect();
}
}
@ -319,7 +312,7 @@ fn matching_history_item_paths(
matching_history_paths
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
struct FoundPath {
project: ProjectPath,
absolute: Option<PathBuf>,

View File

@ -1177,6 +1177,62 @@ async fn test_keep_opened_file_on_top_of_search_results_and_select_next_one(
});
}
#[gpui::test]
async fn test_history_items_shown_in_order_of_open(cx: &mut TestAppContext) {
let app_state = init_test(cx);
app_state
.fs
.as_fake()
.insert_tree(
"/test",
json!({
"test": {
"1.txt": "// One",
"2.txt": "// Two",
"3.txt": "// Three",
}
}),
)
.await;
let project = Project::test(app_state.fs.clone(), ["/test".as_ref()], cx).await;
let (workspace, cx) = cx.add_window_view(|cx| Workspace::test_new(project, cx));
open_queried_buffer("1", 1, "1.txt", &workspace, cx).await;
open_queried_buffer("2", 1, "2.txt", &workspace, cx).await;
open_queried_buffer("3", 1, "3.txt", &workspace, cx).await;
let picker = open_file_picker(&workspace, cx);
picker.update(cx, |finder, _| {
assert_eq!(finder.delegate.matches.len(), 3);
assert_match_at_position(finder, 0, "3.txt");
assert_match_selection(finder, 1, "2.txt");
assert_match_at_position(finder, 2, "1.txt");
});
cx.dispatch_action(Confirm); // Open 2.txt
let picker = open_file_picker(&workspace, cx);
picker.update(cx, |finder, _| {
assert_eq!(finder.delegate.matches.len(), 3);
assert_match_at_position(finder, 0, "2.txt");
assert_match_selection(finder, 1, "3.txt");
assert_match_at_position(finder, 2, "1.txt");
});
cx.dispatch_action(SelectNext);
cx.dispatch_action(Confirm); // Open 1.txt
let picker = open_file_picker(&workspace, cx);
picker.update(cx, |finder, _| {
assert_eq!(finder.delegate.matches.len(), 3);
assert_match_at_position(finder, 0, "1.txt");
assert_match_selection(finder, 1, "2.txt");
assert_match_at_position(finder, 2, "3.txt");
});
}
#[gpui::test]
async fn test_history_items_vs_very_good_external_match(cx: &mut gpui::TestAppContext) {
let app_state = init_test(cx);