diff --git a/crates/project_panel/src/project_panel.rs b/crates/project_panel/src/project_panel.rs index 4d38eb2810..acf7c7973c 100644 --- a/crates/project_panel/src/project_panel.rs +++ b/crates/project_panel/src/project_panel.rs @@ -1389,63 +1389,81 @@ impl ProjectPanel { } fn add_entry(&mut self, is_dir: bool, window: &mut Window, cx: &mut Context) { - if let Some(SelectedEntry { - worktree_id, - entry_id, - }) = self.selection + let Some((worktree_id, entry_id)) = self + .selection + .map(|entry| (entry.worktree_id, entry.entry_id)) + .or_else(|| { + let entry_id = self.last_worktree_root_id?; + let worktree_id = self + .project + .read(cx) + .worktree_for_entry(entry_id, cx)? + .read(cx) + .id(); + + self.selection = Some(SelectedEntry { + worktree_id, + entry_id, + }); + + Some((worktree_id, entry_id)) + }) + else { + return; + }; + + let directory_id; + let new_entry_id = self.resolve_entry(entry_id); + if let Some((worktree, expanded_dir_ids)) = self + .project + .read(cx) + .worktree_for_id(worktree_id, cx) + .zip(self.expanded_dir_ids.get_mut(&worktree_id)) { - let directory_id; - let new_entry_id = self.resolve_entry(entry_id); - if let Some((worktree, expanded_dir_ids)) = self - .project - .read(cx) - .worktree_for_id(worktree_id, cx) - .zip(self.expanded_dir_ids.get_mut(&worktree_id)) - { - let worktree = worktree.read(cx); - if let Some(mut entry) = worktree.entry_for_id(new_entry_id) { - loop { - if entry.is_dir() { - if let Err(ix) = expanded_dir_ids.binary_search(&entry.id) { - expanded_dir_ids.insert(ix, entry.id); - } - directory_id = entry.id; - break; - } else { - if let Some(parent_path) = entry.path.parent() { - if let Some(parent_entry) = worktree.entry_for_path(parent_path) { - entry = parent_entry; - continue; - } - } - return; + let worktree = worktree.read(cx); + if let Some(mut entry) = worktree.entry_for_id(new_entry_id) { + loop { + if entry.is_dir() { + if let Err(ix) = expanded_dir_ids.binary_search(&entry.id) { + expanded_dir_ids.insert(ix, entry.id); } + directory_id = entry.id; + break; + } else { + if let Some(parent_path) = entry.path.parent() { + if let Some(parent_entry) = worktree.entry_for_path(parent_path) { + entry = parent_entry; + continue; + } + } + return; } - } else { - return; - }; + } } else { return; }; - self.marked_entries.clear(); - self.edit_state = Some(EditState { - worktree_id, - entry_id: directory_id, - leaf_entry_id: None, - is_dir, - processing_filename: None, - previously_focused: self.selection, - depth: 0, - validation_state: ValidationState::None, - }); - self.filename_editor.update(cx, |editor, cx| { - editor.clear(window, cx); - window.focus(&editor.focus_handle(cx)); - }); - self.update_visible_entries(Some((worktree_id, NEW_ENTRY_ID)), cx); - self.autoscroll(cx); - cx.notify(); - } + } else { + return; + }; + + self.marked_entries.clear(); + self.edit_state = Some(EditState { + worktree_id, + entry_id: directory_id, + leaf_entry_id: None, + is_dir, + processing_filename: None, + previously_focused: self.selection, + depth: 0, + validation_state: ValidationState::None, + }); + self.filename_editor.update(cx, |editor, cx| { + editor.clear(window, cx); + window.focus(&editor.focus_handle(cx)); + }); + self.update_visible_entries(Some((worktree_id, NEW_ENTRY_ID)), cx); + self.autoscroll(cx); + cx.notify(); } fn unflatten_entry_id(&self, leaf_entry_id: ProjectEntryId) -> ProjectEntryId { diff --git a/crates/project_panel/src/project_panel_tests.rs b/crates/project_panel/src/project_panel_tests.rs index 990b446dcb..65eeae795e 100644 --- a/crates/project_panel/src/project_panel_tests.rs +++ b/crates/project_panel/src/project_panel_tests.rs @@ -4948,6 +4948,71 @@ async fn test_collapse_all_for_entry(cx: &mut gpui::TestAppContext) { } } +#[gpui::test] +async fn test_create_entries_without_selection(cx: &mut gpui::TestAppContext) { + init_test(cx); + + let fs = FakeFs::new(cx.executor().clone()); + fs.insert_tree( + path!("/root"), + json!({ + "dir1": { + "file1.txt": "", + }, + }), + ) + .await; + + let project = Project::test(fs.clone(), [path!("/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, |workspace, window, cx| { + let panel = ProjectPanel::new(workspace, window, cx); + workspace.add_panel(panel.clone(), window, cx); + panel + }) + .unwrap(); + + #[rustfmt::skip] + assert_eq!( + visible_entries_as_strings(&panel, 0..20, cx), + &[ + separator!("v root"), + separator!(" > dir1"), + ], + "Initial state with nothing selected" + ); + + panel.update_in(cx, |panel, window, cx| { + panel.new_file(&NewFile, window, cx); + }); + panel.update_in(cx, |panel, window, cx| { + assert!(panel.filename_editor.read(cx).is_focused(window)); + }); + panel + .update_in(cx, |panel, window, cx| { + panel.filename_editor.update(cx, |editor, cx| { + editor.set_text("hello_from_no_selections", window, cx) + }); + panel.confirm_edit(window, cx).unwrap() + }) + .await + .unwrap(); + + #[rustfmt::skip] + assert_eq!( + visible_entries_as_strings(&panel, 0..20, cx), + &[ + separator!("v root"), + separator!(" > dir1"), + separator!(" hello_from_no_selections <== selected <== marked"), + ], + "A new file is created under the root directory" + ); +} + fn select_path(panel: &Entity, path: impl AsRef, cx: &mut VisualTestContext) { let path = path.as_ref(); panel.update(cx, |panel, cx| {