diff --git a/crates/collab/src/integration_tests.rs b/crates/collab/src/integration_tests.rs index 2bf2701f23..e2b7f7ad68 100644 --- a/crates/collab/src/integration_tests.rs +++ b/crates/collab/src/integration_tests.rs @@ -908,7 +908,7 @@ async fn test_host_disconnect( cx_b.add_window(|cx| Workspace::new(project_b.clone(), |_, _| unimplemented!(), cx)); let editor_b = workspace_b .update(cx_b, |workspace, cx| { - workspace.open_path((worktree_id, "b.txt"), true, cx) + workspace.open_path((worktree_id, "b.txt"), None, true, cx) }) .await .unwrap() @@ -3704,7 +3704,7 @@ async fn test_collaborating_with_code_actions( cx_b.add_window(|cx| Workspace::new(project_b.clone(), |_, _| unimplemented!(), cx)); let editor_b = workspace_b .update(cx_b, |workspace, cx| { - workspace.open_path((worktree_id, "main.rs"), true, cx) + workspace.open_path((worktree_id, "main.rs"), None, true, cx) }) .await .unwrap() @@ -3925,7 +3925,7 @@ async fn test_collaborating_with_renames(cx_a: &mut TestAppContext, cx_b: &mut T cx_b.add_window(|cx| Workspace::new(project_b.clone(), |_, _| unimplemented!(), cx)); let editor_b = workspace_b .update(cx_b, |workspace, cx| { - workspace.open_path((worktree_id, "one.rs"), true, cx) + workspace.open_path((worktree_id, "one.rs"), None, true, cx) }) .await .unwrap() @@ -5134,7 +5134,7 @@ async fn test_following( let pane_a = workspace_a.read_with(cx_a, |workspace, _| workspace.active_pane().clone()); let editor_a1 = workspace_a .update(cx_a, |workspace, cx| { - workspace.open_path((worktree_id, "1.txt"), true, cx) + workspace.open_path((worktree_id, "1.txt"), None, true, cx) }) .await .unwrap() @@ -5142,7 +5142,7 @@ async fn test_following( .unwrap(); let editor_a2 = workspace_a .update(cx_a, |workspace, cx| { - workspace.open_path((worktree_id, "2.txt"), true, cx) + workspace.open_path((worktree_id, "2.txt"), None, true, cx) }) .await .unwrap() @@ -5153,7 +5153,7 @@ async fn test_following( let workspace_b = client_b.build_workspace(&project_b, cx_b); let editor_b1 = workspace_b .update(cx_b, |workspace, cx| { - workspace.open_path((worktree_id, "1.txt"), true, cx) + workspace.open_path((worktree_id, "1.txt"), None, true, cx) }) .await .unwrap() @@ -5411,7 +5411,7 @@ async fn test_peers_following_each_other(cx_a: &mut TestAppContext, cx_b: &mut T let pane_a1 = workspace_a.read_with(cx_a, |workspace, _| workspace.active_pane().clone()); let _editor_a1 = workspace_a .update(cx_a, |workspace, cx| { - workspace.open_path((worktree_id, "1.txt"), true, cx) + workspace.open_path((worktree_id, "1.txt"), None, true, cx) }) .await .unwrap() @@ -5423,7 +5423,7 @@ async fn test_peers_following_each_other(cx_a: &mut TestAppContext, cx_b: &mut T let pane_b1 = workspace_b.read_with(cx_b, |workspace, _| workspace.active_pane().clone()); let _editor_b1 = workspace_b .update(cx_b, |workspace, cx| { - workspace.open_path((worktree_id, "2.txt"), true, cx) + workspace.open_path((worktree_id, "2.txt"), None, true, cx) }) .await .unwrap() @@ -5474,7 +5474,7 @@ async fn test_peers_following_each_other(cx_a: &mut TestAppContext, cx_b: &mut T workspace_a .update(cx_a, |workspace, cx| { - workspace.open_path((worktree_id, "3.txt"), true, cx) + workspace.open_path((worktree_id, "3.txt"), None, true, cx) }) .await .unwrap(); @@ -5485,7 +5485,7 @@ async fn test_peers_following_each_other(cx_a: &mut TestAppContext, cx_b: &mut T workspace_b .update(cx_b, |workspace, cx| { assert_eq!(*workspace.active_pane(), pane_b1); - workspace.open_path((worktree_id, "4.txt"), true, cx) + workspace.open_path((worktree_id, "4.txt"), None, true, cx) }) .await .unwrap(); @@ -5586,7 +5586,7 @@ async fn test_auto_unfollowing(cx_a: &mut TestAppContext, cx_b: &mut TestAppCont let workspace_a = client_a.build_workspace(&project_a, cx_a); let _editor_a1 = workspace_a .update(cx_a, |workspace, cx| { - workspace.open_path((worktree_id, "1.txt"), true, cx) + workspace.open_path((worktree_id, "1.txt"), None, true, cx) }) .await .unwrap() @@ -5699,7 +5699,7 @@ async fn test_auto_unfollowing(cx_a: &mut TestAppContext, cx_b: &mut TestAppCont // When client B activates a different item in the original pane, it automatically stops following client A. workspace_b .update(cx_b, |workspace, cx| { - workspace.open_path((worktree_id, "2.txt"), true, cx) + workspace.open_path((worktree_id, "2.txt"), None, true, cx) }) .await .unwrap(); diff --git a/crates/drag_and_drop/src/drag_and_drop.rs b/crates/drag_and_drop/src/drag_and_drop.rs index e8a6d7f038..65f5985edf 100644 --- a/crates/drag_and_drop/src/drag_and_drop.rs +++ b/crates/drag_and_drop/src/drag_and_drop.rs @@ -1,5 +1,3 @@ -pub mod shared_payloads; - use std::{any::Any, rc::Rc}; use collections::HashSet; @@ -149,7 +147,6 @@ impl DragAndDrop { return None; } - dbg!("Rendered dragging state"); let position = position + region_offset; Some( Overlay::new( @@ -160,7 +157,6 @@ impl DragAndDrop { .on_up(MouseButton::Left, |_, cx| { cx.defer(|cx| { cx.update_global::(|this, cx| { - dbg!("Up with dragging state"); this.finish_dragging(cx) }); }); @@ -169,7 +165,6 @@ impl DragAndDrop { .on_up_out(MouseButton::Left, |_, cx| { cx.defer(|cx| { cx.update_global::(|this, cx| { - dbg!("Up out with dragging state"); this.finish_dragging(cx) }); }); @@ -186,35 +181,30 @@ impl DragAndDrop { ) } - State::Canceled => { - dbg!("Rendered canceled state"); - Some( - MouseEventHandler::::new(0, cx, |_, _| { - Empty::new() - .constrained() - .with_width(0.) - .with_height(0.) - .boxed() - }) - .on_up(MouseButton::Left, |_, cx| { - cx.defer(|cx| { - cx.update_global::(|this, _| { - dbg!("Up with canceled state"); - this.currently_dragged = None; - }); + State::Canceled => Some( + MouseEventHandler::::new(0, cx, |_, _| { + Empty::new() + .constrained() + .with_width(0.) + .with_height(0.) + .boxed() + }) + .on_up(MouseButton::Left, |_, cx| { + cx.defer(|cx| { + cx.update_global::(|this, _| { + this.currently_dragged = None; }); - }) - .on_up_out(MouseButton::Left, |_, cx| { - cx.defer(|cx| { - cx.update_global::(|this, _| { - dbg!("Up out with canceled state"); - this.currently_dragged = None; - }); + }); + }) + .on_up_out(MouseButton::Left, |_, cx| { + cx.defer(|cx| { + cx.update_global::(|this, _| { + this.currently_dragged = None; }); - }) - .boxed(), - ) - } + }); + }) + .boxed(), + ), } }) } @@ -227,7 +217,6 @@ impl DragAndDrop { if payload.is::

() { let window_id = *window_id; self.currently_dragged = Some(State::Canceled); - dbg!("Canceled"); self.notify_containers_for_window(window_id, cx); } } diff --git a/crates/drag_and_drop/src/shared_payloads.rs b/crates/drag_and_drop/src/shared_payloads.rs deleted file mode 100644 index 8644277abd..0000000000 --- a/crates/drag_and_drop/src/shared_payloads.rs +++ /dev/null @@ -1,6 +0,0 @@ -use std::{path::Path, sync::Arc}; - -#[derive(Debug, Clone)] -pub struct DraggedProjectEntry { - pub path: Arc, -} diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index a049239f70..d3f7aa2fdf 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -6394,7 +6394,7 @@ impl Editor { } fn jump(workspace: &mut Workspace, action: &Jump, cx: &mut ViewContext) { - let editor = workspace.open_path(action.path.clone(), true, cx); + let editor = workspace.open_path(action.path.clone(), None, true, cx); let position = action.position; let anchor = action.anchor; cx.spawn_weak(|_, mut cx| async move { diff --git a/crates/editor/src/test/editor_lsp_test_context.rs b/crates/editor/src/test/editor_lsp_test_context.rs index b4a4cd7ab8..69205e1991 100644 --- a/crates/editor/src/test/editor_lsp_test_context.rs +++ b/crates/editor/src/test/editor_lsp_test_context.rs @@ -76,7 +76,9 @@ impl<'a> EditorLspTestContext<'a> { let file = cx.read(|cx| workspace.file_project_paths(cx)[0].clone()); let item = workspace - .update(cx, |workspace, cx| workspace.open_path(file, true, cx)) + .update(cx, |workspace, cx| { + workspace.open_path(file, None, true, cx) + }) .await .expect("Could not open test file"); diff --git a/crates/file_finder/src/file_finder.rs b/crates/file_finder/src/file_finder.rs index 06041f8b0b..c6d4a8f121 100644 --- a/crates/file_finder/src/file_finder.rs +++ b/crates/file_finder/src/file_finder.rs @@ -104,7 +104,7 @@ impl FileFinder { match event { Event::Selected(project_path) => { workspace - .open_path(project_path.clone(), true, cx) + .open_path(project_path.clone(), None, true, cx) .detach_and_log_err(cx); workspace.dismiss_modal(cx); } diff --git a/crates/project_panel/src/project_panel.rs b/crates/project_panel/src/project_panel.rs index 797c68ae3c..3eb5d68516 100644 --- a/crates/project_panel/src/project_panel.rs +++ b/crates/project_panel/src/project_panel.rs @@ -1,5 +1,5 @@ use context_menu::{ContextMenu, ContextMenuItem}; -use drag_and_drop::{shared_payloads::DraggedProjectEntry, DragAndDrop, Draggable}; +use drag_and_drop::{DragAndDrop, Draggable}; use editor::{Cancel, Editor}; use futures::stream::StreamExt; use gpui::{ @@ -239,6 +239,7 @@ impl ProjectPanel { worktree_id: worktree.read(cx).id(), path: entry.path.clone(), }, + None, focus_opened_item, cx, ) @@ -607,7 +608,7 @@ impl ProjectPanel { } cx.update_global(|drag_and_drop: &mut DragAndDrop, cx| { - drag_and_drop.cancel_dragging::(cx); + drag_and_drop.cancel_dragging::(cx); }) } } @@ -1127,26 +1128,21 @@ impl ProjectPanel { position: e.position, }) }) - .as_draggable( - DraggedProjectEntry { - path: details.path.clone(), - }, - { - let row_container_style = theme.dragged_entry.container; + .as_draggable(entry_id, { + let row_container_style = theme.dragged_entry.container; - move |_, cx: &mut RenderContext| { - let theme = cx.global::().theme.clone(); - Self::render_entry_visual_element( - &details, - None, - padding, - row_container_style, - &theme.project_panel.dragged_entry, - cx, - ) - } - }, - ) + move |_, cx: &mut RenderContext| { + let theme = cx.global::().theme.clone(); + Self::render_entry_visual_element( + &details, + None, + padding, + row_container_style, + &theme.project_panel.dragged_entry, + cx, + ) + } + }) .with_cursor_style(CursorStyle::PointingHand) .boxed() } diff --git a/crates/vim/src/test/vim_test_context.rs b/crates/vim/src/test/vim_test_context.rs index 2fb446d127..1aeba9fd08 100644 --- a/crates/vim/src/test/vim_test_context.rs +++ b/crates/vim/src/test/vim_test_context.rs @@ -67,7 +67,9 @@ impl<'a> VimTestContext<'a> { let file = cx.read(|cx| workspace.file_project_paths(cx)[0].clone()); let item = workspace - .update(cx, |workspace, cx| workspace.open_path(file, true, cx)) + .update(cx, |workspace, cx| { + workspace.open_path(file, None, true, cx) + }) .await .expect("Could not open test file"); diff --git a/crates/workspace/src/pane/dragged_item_receiver.rs b/crates/workspace/src/pane/dragged_item_receiver.rs index a18d99630e..7a71bfe0e5 100644 --- a/crates/workspace/src/pane/dragged_item_receiver.rs +++ b/crates/workspace/src/pane/dragged_item_receiver.rs @@ -1,4 +1,4 @@ -use drag_and_drop::{shared_payloads::DraggedProjectEntry, DragAndDrop}; +use drag_and_drop::DragAndDrop; use gpui::{ color::Color, elements::{Canvas, MouseEventHandler, ParentElement, Stack}, @@ -7,9 +7,13 @@ use gpui::{ AppContext, Element, ElementBox, EventContext, MouseButton, MouseState, Quad, RenderContext, WeakViewHandle, }; +use project::ProjectEntryId; use settings::Settings; -use crate::{MoveItem, Pane, SplitDirection, SplitWithItem, Workspace}; +use crate::{ + MoveItem, OpenProjectEntryInPane, Pane, SplitDirection, SplitWithItem, SplitWithProjectEntry, + Workspace, +}; use super::DraggedItem; @@ -34,7 +38,7 @@ where .map(|(drag_position, _)| drag_position) .or_else(|| { cx.global::>() - .currently_dragged::(cx.window_id()) + .currently_dragged::(cx.window_id()) .map(|(drag_position, _)| drag_position) }) } else { @@ -82,7 +86,7 @@ where .currently_dragged::(cx.window_id()) .is_some() || drag_and_drop - .currently_dragged::(cx.window_id()) + .currently_dragged::(cx.window_id()) .is_some() { cx.notify(); @@ -100,30 +104,59 @@ pub fn handle_dropped_item( split_margin: Option, cx: &mut EventContext, ) { - if let Some((_, dragged_item)) = cx - .global::>() - .currently_dragged::(cx.window_id) + enum Action { + Move(WeakViewHandle, usize), + Open(ProjectEntryId), + } + let drag_and_drop = cx.global::>(); + let action = if let Some((_, dragged_item)) = + drag_and_drop.currently_dragged::(cx.window_id) { - if let Some(split_direction) = split_margin - .and_then(|margin| drop_split_direction(event.position, event.region, margin)) - { - cx.dispatch_action(SplitWithItem { - from: dragged_item.pane.clone(), - item_id_to_move: dragged_item.item.id(), - pane_to_split: pane.clone(), - split_direction, - }); - } else if pane != &dragged_item.pane || allow_same_pane { - // If no split margin or not close enough to the edge, just move the item - cx.dispatch_action(MoveItem { - item_id: dragged_item.item.id(), - from: dragged_item.pane.clone(), - to: pane.clone(), - destination_index: index, - }) - } + Action::Move(dragged_item.pane.clone(), dragged_item.item.id()) + } else if let Some((_, project_entry)) = + drag_and_drop.currently_dragged::(cx.window_id) + { + Action::Open(*project_entry) } else { - cx.propagate_event(); + return; + }; + + if let Some(split_direction) = + split_margin.and_then(|margin| drop_split_direction(event.position, event.region, margin)) + { + let pane_to_split = pane.clone(); + match action { + Action::Move(from, item_id_to_move) => cx.dispatch_action(SplitWithItem { + from, + item_id_to_move, + pane_to_split, + split_direction, + }), + Action::Open(project_entry) => cx.dispatch_action(SplitWithProjectEntry { + pane_to_split, + split_direction, + project_entry, + }), + }; + } else { + match action { + Action::Move(from, item_id) => { + if pane != &from || allow_same_pane { + cx.dispatch_action(MoveItem { + item_id, + from, + to: pane.clone(), + destination_index: index, + }) + } else { + cx.propagate_event(); + } + } + Action::Open(project_entry) => cx.dispatch_action(OpenProjectEntryInPane { + pane: pane.clone(), + project_entry, + }), + } } } diff --git a/crates/workspace/src/workspace.rs b/crates/workspace/src/workspace.rs index 349217985c..2dbf923484 100644 --- a/crates/workspace/src/workspace.rs +++ b/crates/workspace/src/workspace.rs @@ -128,12 +128,25 @@ pub struct OpenSharedScreen { #[derive(Clone, PartialEq)] pub struct SplitWithItem { - from: WeakViewHandle, pane_to_split: WeakViewHandle, split_direction: SplitDirection, + from: WeakViewHandle, item_id_to_move: usize, } +#[derive(Clone, PartialEq)] +pub struct SplitWithProjectEntry { + pane_to_split: WeakViewHandle, + split_direction: SplitDirection, + project_entry: ProjectEntryId, +} + +#[derive(Clone, PartialEq)] +pub struct OpenProjectEntryInPane { + pane: WeakViewHandle, + project_entry: ProjectEntryId, +} + impl_internal_actions!( workspace, [ @@ -143,6 +156,8 @@ impl_internal_actions!( OpenSharedScreen, RemoveWorktreeFromProject, SplitWithItem, + SplitWithProjectEntry, + OpenProjectEntryInPane, ] ); impl_actions!(workspace, [ActivatePane]); @@ -234,6 +249,57 @@ pub fn init(app_state: Arc, cx: &mut MutableAppContext) { }, ); + cx.add_async_action( + |workspace: &mut Workspace, + SplitWithProjectEntry { + pane_to_split, + split_direction, + project_entry, + }: &_, + cx| { + pane_to_split.upgrade(cx).and_then(|pane_to_split| { + let new_pane = workspace.add_pane(cx); + workspace + .center + .split(&pane_to_split, &new_pane, *split_direction) + .unwrap(); + + workspace + .project + .read(cx) + .path_for_entry(*project_entry, cx) + .map(|path| { + let task = workspace.open_path(path, Some(new_pane.downgrade()), true, cx); + cx.foreground().spawn(async move { + task.await?; + Ok(()) + }) + }) + }) + }, + ); + + cx.add_async_action( + |workspace: &mut Workspace, + OpenProjectEntryInPane { + pane, + project_entry, + }: &_, + cx| { + workspace + .project + .read(cx) + .path_for_entry(*project_entry, cx) + .map(|path| { + let task = workspace.open_path(path, Some(pane.clone()), true, cx); + cx.foreground().spawn(async move { + task.await?; + Ok(()) + }) + }) + }, + ); + let client = &app_state.client; client.add_view_request_handler(Workspace::handle_follow); client.add_view_message_handler(Workspace::handle_unfollow); @@ -1399,7 +1465,7 @@ impl Workspace { mut abs_paths: Vec, visible: bool, cx: &mut ViewContext, - ) -> Task, Arc>>>> { + ) -> Task, anyhow::Error>>>> { let fs = self.fs.clone(); // Sort the paths to ensure we add worktrees for parents before their children. @@ -1429,7 +1495,7 @@ impl Workspace { if fs.is_file(&abs_path).await { Some( this.update(&mut cx, |this, cx| { - this.open_path(project_path, true, cx) + this.open_path(project_path, None, true, cx) }) .await, ) @@ -1749,10 +1815,11 @@ impl Workspace { pub fn open_path( &mut self, path: impl Into, + pane: Option>, focus_item: bool, cx: &mut ViewContext, - ) -> Task, Arc>> { - let pane = self.active_pane().downgrade(); + ) -> Task, anyhow::Error>> { + let pane = pane.unwrap_or_else(|| self.active_pane().downgrade()); let task = self.load_path(path.into(), cx); cx.spawn(|this, mut cx| async move { let (project_entry_id, build_item) = task.await?; @@ -2874,7 +2941,7 @@ pub fn open_paths( cx: &mut MutableAppContext, ) -> Task<( ViewHandle, - Vec, Arc>>>, + Vec, anyhow::Error>>>, )> { log::info!("open paths {:?}", abs_paths); diff --git a/crates/zed/src/zed.rs b/crates/zed/src/zed.rs index 3c227fcf28..378f53ac9d 100644 --- a/crates/zed/src/zed.rs +++ b/crates/zed/src/zed.rs @@ -818,7 +818,7 @@ mod tests { // Open the first entry let entry_1 = workspace - .update(cx, |w, cx| w.open_path(file1.clone(), true, cx)) + .update(cx, |w, cx| w.open_path(file1.clone(), None, true, cx)) .await .unwrap(); cx.read(|cx| { @@ -832,7 +832,7 @@ mod tests { // Open the second entry workspace - .update(cx, |w, cx| w.open_path(file2.clone(), true, cx)) + .update(cx, |w, cx| w.open_path(file2.clone(), None, true, cx)) .await .unwrap(); cx.read(|cx| { @@ -846,7 +846,7 @@ mod tests { // Open the first entry again. The existing pane item is activated. let entry_1b = workspace - .update(cx, |w, cx| w.open_path(file1.clone(), true, cx)) + .update(cx, |w, cx| w.open_path(file1.clone(), None, true, cx)) .await .unwrap(); assert_eq!(entry_1.id(), entry_1b.id()); @@ -864,7 +864,7 @@ mod tests { workspace .update(cx, |w, cx| { w.split_pane(w.active_pane().clone(), SplitDirection::Right, cx); - w.open_path(file2.clone(), true, cx) + w.open_path(file2.clone(), None, true, cx) }) .await .unwrap(); @@ -883,8 +883,8 @@ mod tests { // Open the third entry twice concurrently. Only one pane item is added. let (t1, t2) = workspace.update(cx, |w, cx| { ( - w.open_path(file3.clone(), true, cx), - w.open_path(file3.clone(), true, cx), + w.open_path(file3.clone(), None, true, cx), + w.open_path(file3.clone(), None, true, cx), ) }); t1.await.unwrap(); @@ -1195,7 +1195,7 @@ mod tests { workspace .update(cx, |workspace, cx| { workspace.split_pane(workspace.active_pane().clone(), SplitDirection::Right, cx); - workspace.open_path((worktree.read(cx).id(), "the-new-name.rs"), true, cx) + workspace.open_path((worktree.read(cx).id(), "the-new-name.rs"), None, true, cx) }) .await .unwrap(); @@ -1284,7 +1284,7 @@ mod tests { let pane_1 = cx.read(|cx| workspace.read(cx).active_pane().clone()); workspace - .update(cx, |w, cx| w.open_path(file1.clone(), true, cx)) + .update(cx, |w, cx| w.open_path(file1.clone(), None, true, cx)) .await .unwrap(); @@ -1359,7 +1359,7 @@ mod tests { let file3 = entries[2].clone(); let editor1 = workspace - .update(cx, |w, cx| w.open_path(file1.clone(), true, cx)) + .update(cx, |w, cx| w.open_path(file1.clone(), None, true, cx)) .await .unwrap() .downcast::() @@ -1370,13 +1370,13 @@ mod tests { }); }); let editor2 = workspace - .update(cx, |w, cx| w.open_path(file2.clone(), true, cx)) + .update(cx, |w, cx| w.open_path(file2.clone(), None, true, cx)) .await .unwrap() .downcast::() .unwrap(); let editor3 = workspace - .update(cx, |w, cx| w.open_path(file3.clone(), true, cx)) + .update(cx, |w, cx| w.open_path(file3.clone(), None, true, cx)) .await .unwrap() .downcast::() @@ -1626,22 +1626,22 @@ mod tests { let file4 = entries[3].clone(); let file1_item_id = workspace - .update(cx, |w, cx| w.open_path(file1.clone(), true, cx)) + .update(cx, |w, cx| w.open_path(file1.clone(), None, true, cx)) .await .unwrap() .id(); let file2_item_id = workspace - .update(cx, |w, cx| w.open_path(file2.clone(), true, cx)) + .update(cx, |w, cx| w.open_path(file2.clone(), None, true, cx)) .await .unwrap() .id(); let file3_item_id = workspace - .update(cx, |w, cx| w.open_path(file3.clone(), true, cx)) + .update(cx, |w, cx| w.open_path(file3.clone(), None, true, cx)) .await .unwrap() .id(); let file4_item_id = workspace - .update(cx, |w, cx| w.open_path(file4.clone(), true, cx)) + .update(cx, |w, cx| w.open_path(file4.clone(), None, true, cx)) .await .unwrap() .id();