Prepare for external file drop in pane

Kirill Bulatov created

Change summary

crates/gpui/src/app.rs                       |  6 --
crates/gpui/src/interactive.rs               |  2 
crates/gpui/src/platform/mac/window.rs       |  5 -
crates/gpui/src/window.rs                    |  6 +-
crates/terminal_view/src/terminal_element.rs |  2 
crates/terminal_view/src/terminal_panel.rs   |  5 -
crates/workspace/src/pane.rs                 | 49 ++++++++++++++++++++-
crates/workspace/src/workspace.rs            | 16 ++++--
8 files changed, 63 insertions(+), 28 deletions(-)

Detailed changes

crates/gpui/src/app.rs 🔗

@@ -1099,12 +1099,6 @@ impl AppContext {
     pub fn has_active_drag(&self) -> bool {
         self.active_drag.is_some()
     }
-
-    pub fn active_drag<T: 'static>(&self) -> Option<&T> {
-        self.active_drag
-            .as_ref()
-            .and_then(|drag| drag.value.downcast_ref())
-    }
 }
 
 impl Context for AppContext {

crates/gpui/src/interactive.rs 🔗

@@ -214,7 +214,7 @@ impl Render for ExternalPaths {
 pub enum FileDropEvent {
     Entered {
         position: Point<Pixels>,
-        files: ExternalPaths,
+        paths: ExternalPaths,
     },
     Pending {
         position: Point<Pixels>,

crates/gpui/src/platform/mac/window.rs 🔗

@@ -1673,10 +1673,7 @@ extern "C" fn dragging_entered(this: &Object, _: Sel, dragging_info: id) -> NSDr
     if send_new_event(&window_state, {
         let position = drag_event_position(&window_state, dragging_info);
         let paths = external_paths_from_event(dragging_info);
-        InputEvent::FileDrop(FileDropEvent::Entered {
-            position,
-            files: paths,
-        })
+        InputEvent::FileDrop(FileDropEvent::Entered { position, paths })
     }) {
         NSDragOperationCopy
     } else {

crates/gpui/src/window.rs 🔗

@@ -1462,12 +1462,12 @@ impl<'a> WindowContext<'a> {
             // Translate dragging and dropping of external files from the operating system
             // to internal drag and drop events.
             InputEvent::FileDrop(file_drop) => match file_drop {
-                FileDropEvent::Entered { position, files } => {
+                FileDropEvent::Entered { position, paths } => {
                     self.window.mouse_position = position;
                     if self.active_drag.is_none() {
                         self.active_drag = Some(AnyDrag {
-                            value: Box::new(files.clone()),
-                            view: self.new_view(|_| files).into(),
+                            value: Box::new(paths.clone()),
+                            view: self.new_view(|_| paths).into(),
                             cursor_offset: position,
                         });
                     }

crates/terminal_view/src/terminal_element.rs 🔗

@@ -693,9 +693,9 @@ impl TerminalElement {
                     .join("");
                 new_text.push(' ');
                 terminal.update(cx, |terminal, _| {
-                    // todo!() long paths are not displayed properly albeit the text is there
                     terminal.paste(&new_text);
                 });
+                cx.stop_propagation();
             }
         });
 

crates/terminal_view/src/terminal_panel.rs 🔗

@@ -65,11 +65,8 @@ impl TerminalPanel {
                             return item.downcast::<TerminalView>().is_some();
                         }
                     }
-                    if a.downcast_ref::<ExternalPaths>().is_some() {
-                        return true;
-                    }
 
-                    false
+                    a.downcast_ref::<ExternalPaths>().is_some()
                 })),
                 cx,
             );

crates/workspace/src/pane.rs 🔗

@@ -8,9 +8,10 @@ use anyhow::Result;
 use collections::{HashMap, HashSet, VecDeque};
 use gpui::{
     actions, impl_actions, overlay, prelude::*, Action, AnchorCorner, AnyElement, AppContext,
-    AsyncWindowContext, DismissEvent, Div, DragMoveEvent, EntityId, EventEmitter, FocusHandle,
-    FocusableView, Model, MouseButton, NavigationDirection, Pixels, Point, PromptLevel, Render,
-    ScrollHandle, Subscription, Task, View, ViewContext, VisualContext, WeakView, WindowContext,
+    AsyncWindowContext, DismissEvent, Div, DragMoveEvent, EntityId, EventEmitter, ExternalPaths,
+    FocusHandle, FocusableView, Model, MouseButton, NavigationDirection, Pixels, Point,
+    PromptLevel, Render, ScrollHandle, Subscription, Task, View, ViewContext, VisualContext,
+    WeakView, WindowContext,
 };
 use parking_lot::Mutex;
 use project::{Project, ProjectEntryId, ProjectPath};
@@ -1555,6 +1556,10 @@ impl Pane {
                 this.drag_split_direction = None;
                 this.handle_project_entry_drop(entry_id, cx)
             }))
+            .on_drop(cx.listener(move |this, paths, cx| {
+                this.drag_split_direction = None;
+                this.handle_external_paths_drop(paths, cx)
+            }))
             .when_some(item.tab_tooltip_text(cx), |tab, text| {
                 tab.tooltip(move |cx| Tooltip::text(text.clone(), cx))
             })
@@ -1721,6 +1726,10 @@ impl Pane {
                     .on_drop(cx.listener(move |this, entry_id: &ProjectEntryId, cx| {
                         this.drag_split_direction = None;
                         this.handle_project_entry_drop(entry_id, cx)
+                    }))
+                    .on_drop(cx.listener(move |this, paths, cx| {
+                        this.drag_split_direction = None;
+                        this.handle_external_paths_drop(paths, cx)
                     })),
             )
     }
@@ -1855,6 +1864,35 @@ impl Pane {
             .log_err();
     }
 
+    fn handle_external_paths_drop(
+        &mut self,
+        paths: &ExternalPaths,
+        cx: &mut ViewContext<'_, Pane>,
+    ) {
+        // let mut to_pane = cx.view().clone();
+        // let split_direction = self.drag_split_direction;
+        // let project_entry_id = *project_entry_id;
+        // self.workspace
+        //     .update(cx, |_, cx| {
+        //         cx.defer(move |workspace, cx| {
+        //             if let Some(path) = workspace
+        //                 .project()
+        //                 .read(cx)
+        //                 .path_for_entry(project_entry_id, cx)
+        //             {
+        //                 if let Some(split_direction) = split_direction {
+        //                     to_pane = workspace.split_pane(to_pane, split_direction, cx);
+        //                 }
+        //                 workspace
+        //                     .open_path(path, Some(to_pane.downgrade()), true, cx)
+        //                     .detach_and_log_err(cx);
+        //             }
+        //         });
+        //     })
+        //     .log_err();
+        dbg!("@@@@@@@@@@@@@@", paths);
+    }
+
     pub fn display_nav_history_buttons(&mut self, display: bool) {
         self.display_nav_history_buttons = display;
     }
@@ -1956,6 +1994,7 @@ impl Render for Pane {
                     .group("")
                     .on_drag_move::<DraggedTab>(cx.listener(Self::handle_drag_move))
                     .on_drag_move::<ProjectEntryId>(cx.listener(Self::handle_drag_move))
+                    .on_drag_move::<ExternalPaths>(cx.listener(Self::handle_drag_move))
                     .map(|div| {
                         if let Some(item) = self.active_item() {
                             div.v_flex()
@@ -1985,6 +2024,7 @@ impl Render for Pane {
                             ))
                             .group_drag_over::<DraggedTab>("", |style| style.visible())
                             .group_drag_over::<ProjectEntryId>("", |style| style.visible())
+                            .group_drag_over::<ExternalPaths>("", |style| style.visible())
                             .when_some(self.can_drop_predicate.clone(), |this, p| {
                                 this.can_drop(move |a, cx| p(a, cx))
                             })
@@ -1994,6 +2034,9 @@ impl Render for Pane {
                             .on_drop(cx.listener(move |this, entry_id, cx| {
                                 this.handle_project_entry_drop(entry_id, cx)
                             }))
+                            .on_drop(cx.listener(move |this, paths, cx| {
+                                this.handle_external_paths_drop(paths, cx)
+                            }))
                             .map(|div| match self.drag_split_direction {
                                 None => div.top_0().left_0().right_0().bottom_0(),
                                 Some(SplitDirection::Up) => div.top_0().left_0().right_0().h_32(),

crates/workspace/src/workspace.rs 🔗

@@ -27,11 +27,11 @@ use futures::{
 use gpui::{
     actions, canvas, div, impl_actions, point, size, Action, AnyElement, AnyModel, AnyView,
     AnyWeakView, AnyWindowHandle, AppContext, AsyncAppContext, AsyncWindowContext, BorrowWindow,
-    Bounds, Context, Div, DragMoveEvent, Element, Entity, EntityId, EventEmitter, FocusHandle,
-    FocusableView, GlobalPixels, InteractiveElement, IntoElement, KeyContext, LayoutId,
-    ManagedView, Model, ModelContext, ParentElement, PathPromptOptions, Pixels, Point, PromptLevel,
-    Render, Size, Styled, Subscription, Task, View, ViewContext, VisualContext, WeakView,
-    WindowBounds, WindowContext, WindowHandle, WindowOptions,
+    Bounds, Context, Div, DragMoveEvent, Element, Entity, EntityId, EventEmitter, ExternalPaths,
+    FocusHandle, FocusableView, GlobalPixels, InteractiveElement, IntoElement, KeyContext,
+    LayoutId, ManagedView, Model, ModelContext, ParentElement, PathPromptOptions, Pixels, Point,
+    PromptLevel, Render, Size, Styled, Subscription, Task, View, ViewContext, VisualContext,
+    WeakView, WindowBounds, WindowContext, WindowHandle, WindowOptions,
 };
 use item::{FollowableItem, FollowableItemHandle, Item, ItemHandle, ItemSettings, ProjectItem};
 use itertools::Itertools;
@@ -544,7 +544,11 @@ impl Workspace {
                 weak_handle.clone(),
                 project.clone(),
                 pane_history_timestamp.clone(),
-                None,
+                Some(Arc::new(|a, _| {
+                    a.downcast_ref::<ExternalPaths>().is_some()
+                        || a.downcast_ref::<DraggedTab>().is_some()
+                        || a.downcast_ref::<ProjectEntryId>().is_some()
+                })),
                 cx,
             )
         });