diff --git a/crates/file_finder/src/file_finder.rs b/crates/file_finder/src/file_finder.rs index 9d23844c9e..ff3158f22c 100644 --- a/crates/file_finder/src/file_finder.rs +++ b/crates/file_finder/src/file_finder.rs @@ -1847,6 +1847,11 @@ impl PickerDelegate for FileFinderDelegate { self.selected_index } + fn set_hovered_index(&mut self, ix: usize, _: &mut Window, cx: &mut Context>) { + self.selected_index = ix; + cx.notify(); + } + fn set_selected_index(&mut self, ix: usize, _: &mut Window, cx: &mut Context>) { self.has_changed_selected_index = true; self.selected_index = ix; diff --git a/crates/file_finder/src/file_finder_tests.rs b/crates/file_finder/src/file_finder_tests.rs index 7a31da1374..6d0184325d 100644 --- a/crates/file_finder/src/file_finder_tests.rs +++ b/crates/file_finder/src/file_finder_tests.rs @@ -5186,3 +5186,64 @@ async fn test_exact_filename_with_directory_token(cx: &mut TestAppContext) { ); }); } + +#[gpui::test] +async fn test_hover_does_not_set_has_changed_selected_index(cx: &mut TestAppContext) { + let app_state = init_test(cx); + + app_state + .fs + .as_fake() + .insert_tree( + path!("/root"), + json!({ + "a.rs": "", + "b.rs": "", + }), + ) + .await; + + let project = Project::test(app_state.fs.clone(), [path!("/root").as_ref()], cx).await; + let (multi_workspace, cx) = + cx.add_window_view(|window, cx| MultiWorkspace::test_new(project, window, cx)); + let workspace = multi_workspace.read_with(cx, |mw, _| mw.workspace().clone()); + + open_close_queried_buffer("a", 1, "a.rs", &workspace, cx).await; + open_close_queried_buffer("b", 1, "b.rs", &workspace, cx).await; + + let picker = open_file_picker(&workspace, cx); + + picker.update(cx, |picker, _| { + assert!( + picker.delegate.matches.len() >= 2, + "need at least 2 matches" + ); + }); + + picker.update_in(cx, |picker, window, cx| { + picker.set_hovered_index(1, window, cx); + }); + + picker.update(cx, |picker, _| { + assert!( + !picker.delegate.has_changed_selected_index, + "hover should not set `has_changed_selected_index`" + ); + assert_eq!( + picker.delegate.selected_index(), + 1, + "hover should change `selected_index`" + ); + }); + + picker.update_in(cx, |picker, window, cx| { + picker.cycle_selection(window, cx); + }); + + picker.update(cx, |picker, _| { + assert!( + picker.delegate.has_changed_selected_index, + "keyboard should set `has_changed_selected_index`" + ); + }); +} diff --git a/crates/picker/src/picker.rs b/crates/picker/src/picker.rs index c1c95fba6d..3a93c7cd75 100644 --- a/crates/picker/src/picker.rs +++ b/crates/picker/src/picker.rs @@ -172,6 +172,14 @@ pub trait PickerDelegate: Sized + 'static { fn separators_after_indices(&self) -> Vec { Vec::new() } + fn set_hovered_index( + &mut self, + ix: usize, + window: &mut Window, + cx: &mut Context>, + ) { + self.set_selected_index(ix, window, cx); + } fn set_selected_index( &mut self, ix: usize, @@ -797,6 +805,32 @@ impl Picker { self.focus_handle(cx).focus(window, cx); } + pub fn set_hovered_index(&mut self, ix: usize, window: &mut Window, cx: &mut Context) { + let match_count = self.delegate.match_count(); + if match_count == 0 { + return; + } + + if !self.delegate.can_select(ix, window, cx) { + return; + } + + let previous_index = self.delegate.selected_index(); + self.delegate.set_hovered_index(ix, window, cx); + let current_index = self.delegate.selected_index(); + + if previous_index != current_index { + if let Some(action) = self.delegate.selected_index_changed(ix, window, cx) { + action(window, cx); + } + if let Some(preview) = &mut self.preview + && let Some(update) = self.delegate.try_get_preview_data_for_match(cx) + { + preview.update(update, window, cx); + } + } + } + /// Handles the selecting an index, and passing the change to the delegate. /// If `fallback_direction` is set to `None`, the index will not be selected /// if the element at that index cannot be selected. @@ -1414,7 +1448,7 @@ impl Picker { .when(self.delegate.select_on_hover(), |this| { this.on_hover(cx.listener(move |this, hovered: &bool, window, cx| { if *hovered { - this.set_selected_index(ix, None, false, window, cx); + this.set_hovered_index(ix, window, cx); cx.notify(); } }))