@@ -1389,63 +1389,81 @@ impl ProjectPanel {
}
fn add_entry(&mut self, is_dir: bool, window: &mut Window, cx: &mut Context<Self>) {
- 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;
- }
+ 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;
}
+ 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 {
@@ -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<ProjectPanel>, path: impl AsRef<Path>, cx: &mut VisualTestContext) {
let path = path.as_ref();
panel.update(cx, |panel, cx| {