zed2: Properly position terminal context menu & hide on dismiss

Julia created

Change summary

crates/terminal_view2/src/terminal_view.rs | 42 +++++++++++++++--------
1 file changed, 27 insertions(+), 15 deletions(-)

Detailed changes

crates/terminal_view2/src/terminal_view.rs 🔗

@@ -9,9 +9,10 @@ pub mod terminal_panel;
 // use crate::terminal_element::TerminalElement;
 use editor::{scroll::autoscroll::Autoscroll, Editor};
 use gpui::{
-    div, Action, AnyElement, AppContext, Div, EventEmitter, FocusEvent, FocusHandle, Focusable,
-    FocusableElement, FocusableView, KeyContext, KeyDownEvent, Keystroke, Model, MouseButton,
-    MouseDownEvent, Pixels, Render, Subscription, Task, View, VisualContext, WeakView,
+    div, overlay, Action, AnyElement, AppContext, DismissEvent, Div, EventEmitter, FocusEvent,
+    FocusHandle, Focusable, FocusableElement, FocusableView, KeyContext, KeyDownEvent, Keystroke,
+    Model, MouseButton, MouseDownEvent, Pixels, Render, Subscription, Task, View, VisualContext,
+    WeakView,
 };
 use language::Bias;
 use persistence::TERMINAL_DB;
@@ -81,7 +82,7 @@ pub struct TerminalView {
     has_new_content: bool,
     //Currently using iTerm bell, show bell emoji in tab until input is received
     has_bell: bool,
-    context_menu: Option<View<ContextMenu>>,
+    context_menu: Option<(View<ContextMenu>, gpui::Point<Pixels>, Subscription)>,
     blink_state: bool,
     blinking_on: bool,
     blinking_paused: bool,
@@ -312,14 +313,24 @@ impl TerminalView {
         position: gpui::Point<Pixels>,
         cx: &mut ViewContext<Self>,
     ) {
-        self.context_menu = Some(ContextMenu::build(cx, |menu, cx| {
+        let context_menu = ContextMenu::build(cx, |menu, cx| {
             menu.action("Clear", Box::new(Clear))
                 .action("Close", Box::new(CloseActiveItem { save_intent: None }))
-        }));
-        // todo!(context menus)
-        //     self.context_menu
-        //         .show(position, AnchorCorner::TopLeft, menu_entries, cx);
-        //     cx.notify();
+        });
+
+        cx.focus_view(&context_menu);
+        let subscription =
+            cx.subscribe(&context_menu, |this, _, _: &DismissEvent, cx| {
+                if this.context_menu.as_ref().is_some_and(|context_menu| {
+                    context_menu.0.focus_handle(cx).contains_focused(cx)
+                }) {
+                    cx.focus_self();
+                }
+                this.context_menu.take();
+                cx.notify();
+            });
+
+        self.context_menu = Some((context_menu, position, subscription));
     }
 
     fn show_character_palette(&mut self, _: &ShowCharacterPalette, cx: &mut ViewContext<Self>) {
@@ -658,11 +669,12 @@ impl Render for TerminalView {
                         }),
                     ),
             )
-            .children(
-                self.context_menu
-                    .clone()
-                    .map(|context_menu| div().z_index(1).absolute().child(context_menu)),
-            )
+            .children(self.context_menu.as_ref().map(|(menu, positon, _)| {
+                overlay()
+                    .position(*positon)
+                    .anchor(gpui::AnchorCorner::TopLeft)
+                    .child(menu.clone())
+            }))
             .track_focus(&self.focus_handle)
             .on_focus_in(cx.listener(Self::focus_in))
             .on_focus_out(cx.listener(Self::focus_out))