From b6fd06d63c6ff09ecf8c168736053732c1fcfbe8 Mon Sep 17 00:00:00 2001 From: PJ Tatlow Date: Wed, 19 Feb 2025 09:00:23 -0700 Subject: [PATCH] project_panel: Make scroll to bottom to use the last visible entry (#25160) Closes #25159 Release Notes: - Fixed project panel implementation of the `menu::SelectLast` action --- crates/project_panel/src/project_panel.rs | 96 ++++++++++++++++++++--- 1 file changed, 83 insertions(+), 13 deletions(-) diff --git a/crates/project_panel/src/project_panel.rs b/crates/project_panel/src/project_panel.rs index b423c1cedc..078ae81b86 100644 --- a/crates/project_panel/src/project_panel.rs +++ b/crates/project_panel/src/project_panel.rs @@ -1942,19 +1942,19 @@ impl ProjectPanel { } fn select_last(&mut self, _: &SelectLast, _: &mut Window, cx: &mut Context) { - let worktree = self.visible_entries.last().and_then(|(worktree_id, _, _)| { - self.project.read(cx).worktree_for_id(*worktree_id, cx) - }); - if let Some(worktree) = worktree { - let worktree = worktree.read(cx); - let worktree_id = worktree.id(); - if let Some(last_entry) = worktree.entries(true, 0).last() { - self.selection = Some(SelectedEntry { - worktree_id, - entry_id: last_entry.id, - }); - self.autoscroll(cx); - cx.notify(); + if let Some((worktree_id, visible_worktree_entries, _)) = self.visible_entries.last() { + let worktree = self.project.read(cx).worktree_for_id(*worktree_id, cx); + if let (Some(worktree), Some(entry)) = (worktree, visible_worktree_entries.last()) { + let worktree = worktree.read(cx); + if let Some(entry) = worktree.entry_for_id(entry.id) { + let selection = SelectedEntry { + worktree_id: *worktree_id, + entry_id: entry.id, + }; + self.selection = Some(selection); + self.autoscroll(cx); + cx.notify(); + } } } } @@ -7124,6 +7124,76 @@ mod tests { ] ); } + #[gpui::test] + async fn test_select_first_last(cx: &mut gpui::TestAppContext) { + init_test_with_editor(cx); + + let fs = FakeFs::new(cx.executor().clone()); + fs.insert_tree( + "/project_root", + json!({ + "dir_1": { + "nested_dir": { + "file_a.py": "# File contents", + } + }, + "file_1.py": "# File contents", + "file_2.py": "# File contents", + "zdir_2": { + "nested_dir2": { + "file_b.py": "# File contents", + } + }, + }), + ) + .await; + + let project = Project::test(fs.clone(), ["/project_root".as_ref()], cx).await; + let workspace = + cx.add_window(|window, cx| Workspace::test_new(project.clone(), window, cx)); + let cx = &mut VisualTestContext::from_window(*workspace, cx); + let panel = workspace.update(cx, ProjectPanel::new).unwrap(); + + assert_eq!( + visible_entries_as_strings(&panel, 0..10, cx), + &[ + "v project_root", + " > dir_1", + " > zdir_2", + " file_1.py", + " file_2.py", + ] + ); + panel.update_in(cx, |panel, window, cx| { + panel.select_first(&SelectFirst, window, cx) + }); + + assert_eq!( + visible_entries_as_strings(&panel, 0..10, cx), + &[ + "v project_root <== selected", + " > dir_1", + " > zdir_2", + " file_1.py", + " file_2.py", + ] + ); + + panel.update_in(cx, |panel, window, cx| { + panel.select_last(&SelectLast, window, cx) + }); + + assert_eq!( + visible_entries_as_strings(&panel, 0..10, cx), + &[ + "v project_root", + " > dir_1", + " > zdir_2", + " file_1.py", + " file_2.py <== selected", + ] + ); + } #[gpui::test] async fn test_dir_toggle_collapse(cx: &mut gpui::TestAppContext) {