From 3f777f0c686b04b1a3cf4dc1c2f97b3175870316 Mon Sep 17 00:00:00 2001 From: Danilo Leal <67129314+danilo-leal@users.noreply.github.com> Date: Wed, 6 Nov 2024 04:59:06 -0300 Subject: [PATCH] Fix project panel losing focus after file creation attempt (#20273) Closes https://github.com/zed-industries/zed/issues/19771 ### Before When pressing esc after attempting to create a file, the focus is lost and you don't know where it went. https://github.com/user-attachments/assets/2ccd82b7-b7d2-49e4-b1c7-1867331ab9dc ### After Now, after pressing esc, the focus returns to where it was before trying to create a new file. https://github.com/user-attachments/assets/a8eb1cf1-dfef-42eb-9f3d-2ab6200056c4 Release Notes: - Fix project panel losing focus after file creation attempt ([#19771](https://github.com/zed-industries/zed/issues/19771)) --------- Co-authored-by: Kirill Bulatov --- crates/project_panel/src/project_panel.rs | 77 ++++++++++++++++++++++- 1 file changed, 76 insertions(+), 1 deletion(-) diff --git a/crates/project_panel/src/project_panel.rs b/crates/project_panel/src/project_panel.rs index 5073616e9a526d9b7d2a82954af930a49f13831c..a7d826076c026e24ee5deea7b5e6ade88f45fc71 100644 --- a/crates/project_panel/src/project_panel.rs +++ b/crates/project_panel/src/project_panel.rs @@ -101,6 +101,7 @@ struct EditState { is_dir: bool, depth: usize, processing_filename: Option, + previously_focused: Option, } impl EditState { @@ -945,9 +946,17 @@ impl ProjectPanel { } fn cancel(&mut self, _: &menu::Cancel, cx: &mut ViewContext) { - self.edit_state = None; + let previous_edit_state = self.edit_state.take(); self.update_visible_entries(None, cx); self.marked_entries.clear(); + + if let Some(previously_focused) = + previous_edit_state.and_then(|edit_state| edit_state.previously_focused) + { + self.selection = Some(previously_focused); + self.autoscroll(cx); + } + cx.focus(&self.focus_handle); cx.notify(); } @@ -1026,6 +1035,7 @@ impl ProjectPanel { leaf_entry_id: None, is_dir, processing_filename: None, + previously_focused: self.selection, depth: 0, }); self.filename_editor.update(cx, |editor, cx| { @@ -1065,6 +1075,7 @@ impl ProjectPanel { leaf_entry_id: Some(entry_id), is_dir: entry.is_dir(), processing_filename: None, + previously_focused: None, depth: 0, }); let file_name = entry @@ -6015,6 +6026,70 @@ mod tests { ); } + #[gpui::test] + async fn test_selection_restored_when_creation_cancelled(cx: &mut gpui::TestAppContext) { + init_test_with_editor(cx); + + let fs = FakeFs::new(cx.executor().clone()); + fs.insert_tree( + "/src", + json!({ + "test": { + "first.rs": "// First Rust file", + "second.rs": "// Second Rust file", + "third.rs": "// Third Rust file", + } + }), + ) + .await; + + let project = Project::test(fs.clone(), ["/src".as_ref()], cx).await; + let workspace = cx.add_window(|cx| Workspace::test_new(project.clone(), cx)); + let cx = &mut VisualTestContext::from_window(*workspace, cx); + let panel = workspace + .update(cx, |workspace, cx| { + let panel = ProjectPanel::new(workspace, cx); + workspace.add_panel(panel.clone(), cx); + panel + }) + .unwrap(); + + select_path(&panel, "src/", cx); + panel.update(cx, |panel, cx| panel.confirm(&Confirm, cx)); + cx.executor().run_until_parked(); + assert_eq!( + visible_entries_as_strings(&panel, 0..10, cx), + &[ + // + "v src <== selected", + " > test" + ] + ); + panel.update(cx, |panel, cx| panel.new_directory(&NewDirectory, cx)); + panel.update(cx, |panel, cx| { + assert!(panel.filename_editor.read(cx).is_focused(cx)); + }); + assert_eq!( + visible_entries_as_strings(&panel, 0..10, cx), + &[ + // + "v src", + " > [EDITOR: ''] <== selected", + " > test" + ] + ); + + panel.update(cx, |panel, cx| panel.cancel(&menu::Cancel, cx)); + assert_eq!( + visible_entries_as_strings(&panel, 0..10, cx), + &[ + // + "v src <== selected", + " > test" + ] + ); + } + fn toggle_expand_dir( panel: &View, path: impl AsRef,