diff --git a/crates/file_finder/src/file_finder_tests.rs b/crates/file_finder/src/file_finder_tests.rs index bc80041707..f3d63a09ee 100644 --- a/crates/file_finder/src/file_finder_tests.rs +++ b/crates/file_finder/src/file_finder_tests.rs @@ -4380,6 +4380,41 @@ async fn test_open_without_dismiss_then_confirm_closes_finder(cx: &mut TestAppCo }); } +#[gpui::test] +async fn test_reopen_with_preview_keeps_results_width(cx: &mut TestAppContext) { + let app_state = init_test(cx); + app_state + .fs + .as_fake() + .insert_tree(path!("/root"), json!({ "a.txt": "", "b.txt": "" })) + .await; + let project = Project::test(app_state.fs.clone(), [path!("/root").as_ref()], cx).await; + let (picker, workspace, cx) = build_find_picker(project, cx); + + cx.dispatch_action(picker::SetPreviewRight); + cx.run_until_parked(); + let in_session_width = picker.update_in(cx, |picker, window, _| picker.results_width(window)); + + cx.dispatch_action(Cancel); + cx.run_until_parked(); + + let picker = open_file_picker(&workspace, cx); + cx.run_until_parked(); + let reopened_width = picker.update_in(cx, |picker, window, _| picker.results_width(window)); + + assert_eq!( + in_session_width, reopened_width, + "reopening with the side preview must keep the same results width as the in-session toggle" + ); + + // The preview layout is persisted in the key-value store, and tests in a + // process share one in-memory fallback store (no per-App `AppDatabase` is + // set in tests, so `AppDatabase::global` falls back to the shared static). + // Reset to the default layout so this write doesn't leak into other tests. + cx.dispatch_action(picker::SetPreviewHidden); + cx.run_until_parked(); +} + async fn open_close_queried_buffer( input: &str, expected_matches: usize, diff --git a/crates/picker/src/picker.rs b/crates/picker/src/picker.rs index 352f60168e..ef58058e5c 100644 --- a/crates/picker/src/picker.rs +++ b/crates/picker/src/picker.rs @@ -571,7 +571,7 @@ impl Picker { pub fn initial_width(mut self, width: impl Into) -> Self { let width = width.into(); self.default_shape.width = width; - if !self.shape_loaded_from_persistence { + if self.live_shape_is_hidden_default() { self.shape.set_initial_width(width); } // A plain picker's whole-picker minimum tracks its opening width. Preview @@ -591,12 +591,23 @@ impl Picker { pub fn max_height(mut self, height: impl Into) -> Self { let height = height.into(); self.default_shape.height = height; - if !self.shape_loaded_from_persistence { + if self.live_shape_is_hidden_default() { self.shape.set_initial_height(height); } self } + /// Whether the live shape still reflects the hidden-layout default, i.e. it + /// was not restored from a persisted size and currently opens with no + /// preview. Only then may `initial_width`/`max_height` push their + /// hidden/no-preview defaults onto it; a picker reopened in a preview layout + /// keeps the larger telescope default, which those (smaller) no-preview + /// values must not shrink. + fn live_shape_is_hidden_default(&self) -> bool { + !self.shape_loaded_from_persistence + && self.preview_layout().unwrap_or(preview::Layout::Hidden) == preview::Layout::Hidden + } + /// Whether the picker fills its full height (preview visible) or shrinks to /// fit its content, treating the height as a maximum (no preview visible). fn fill_height(&self) -> bool { @@ -1242,6 +1253,15 @@ impl Picker { self.preview.as_ref().map(|p| p.layout) } + #[cfg(any(test, feature = "test-support"))] + pub fn results_width(&self, window: &Window) -> gpui::Pixels { + let layout = self.preview_layout().unwrap_or(preview::Layout::Hidden); + let pos = self + .shape + .results_position_and_size(layout, &self.size_bounds, window); + pos.right - pos.left + } + fn toggle_preview(&mut self, _: &TogglePreview, window: &mut Window, cx: &mut Context) { self.toggle_preview_visible(window, cx); }