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,