Fix file finder menu actions (#21087)

Kirill Bulatov created

Closes https://github.com/zed-industries/zed/issues/21077

* BREAKING: rename `file_finder::OpenMenu` into
`file_finder::ToggleMenu`
* Display the keybinding for menu toggling when the menu is open
* Fix `enter` not working in the menu

Release Notes:

- Fixed enter not working and menu toggle binding not shown in the file
finder menu

Change summary

assets/keymaps/default-linux.json      |  7 +++++
assets/keymaps/default-macos.json      |  7 +++++
crates/file_finder/src/file_finder.rs  | 31 +++++++++++++++------------
crates/ui/src/components/keybinding.rs |  2 
4 files changed, 30 insertions(+), 17 deletions(-)

Detailed changes

assets/keymaps/default-linux.json 🔗

@@ -649,11 +649,16 @@
       "tab": "channel_modal::ToggleMode"
     }
   },
+  {
+    "context": "FileFinder",
+    "bindings": {
+      "ctrl": "file_finder::ToggleMenu"
+    }
+  },
   {
     "context": "FileFinder && !menu_open",
     "bindings": {
       "ctrl-shift-p": "file_finder::SelectPrev",
-      "ctrl": "file_finder::OpenMenu",
       "ctrl-j": "pane::SplitDown",
       "ctrl-k": "pane::SplitUp",
       "ctrl-h": "pane::SplitLeft",

assets/keymaps/default-macos.json 🔗

@@ -650,11 +650,16 @@
       "tab": "channel_modal::ToggleMode"
     }
   },
+  {
+    "context": "FileFinder",
+    "bindings": {
+      "cmd": "file_finder::ToggleMenu"
+    }
+  },
   {
     "context": "FileFinder && !menu_open",
     "bindings": {
       "cmd-shift-p": "file_finder::SelectPrev",
-      "cmd": "file_finder::OpenMenu",
       "cmd-j": "pane::SplitDown",
       "cmd-k": "pane::SplitUp",
       "cmd-h": "pane::SplitLeft",

crates/file_finder/src/file_finder.rs 🔗

@@ -42,7 +42,7 @@ use workspace::{
     Workspace,
 };
 
-actions!(file_finder, [SelectPrev, OpenMenu]);
+actions!(file_finder, [SelectPrev, ToggleMenu]);
 
 impl ModalView for FileFinder {
     fn on_before_dismiss(&mut self, cx: &mut ViewContext<Self>) -> workspace::DismissDecision {
@@ -189,10 +189,12 @@ impl FileFinder {
         cx.dispatch_action(Box::new(menu::SelectPrev));
     }
 
-    fn handle_open_menu(&mut self, _: &OpenMenu, cx: &mut ViewContext<Self>) {
+    fn handle_toggle_menu(&mut self, _: &ToggleMenu, cx: &mut ViewContext<Self>) {
         self.picker.update(cx, |picker, cx| {
             let menu_handle = &picker.delegate.popover_menu_handle;
-            if !menu_handle.is_deployed() {
+            if menu_handle.is_deployed() {
+                menu_handle.hide(cx);
+            } else {
                 menu_handle.show(cx);
             }
         });
@@ -282,7 +284,7 @@ impl Render for FileFinder {
             .w(modal_max_width)
             .on_modifiers_changed(cx.listener(Self::handle_modifiers_changed))
             .on_action(cx.listener(Self::handle_select_prev))
-            .on_action(cx.listener(Self::handle_open_menu))
+            .on_action(cx.listener(Self::handle_toggle_menu))
             .on_action(cx.listener(Self::go_to_file_split_left))
             .on_action(cx.listener(Self::go_to_file_split_right))
             .on_action(cx.listener(Self::go_to_file_split_up))
@@ -1242,6 +1244,7 @@ impl PickerDelegate for FileFinderDelegate {
     }
 
     fn render_footer(&self, cx: &mut ViewContext<Picker<Self>>) -> Option<AnyElement> {
+        let context = self.focus_handle.clone();
         Some(
             h_flex()
                 .w_full()
@@ -1263,19 +1266,19 @@ impl PickerDelegate for FileFinderDelegate {
                         .trigger(
                             Button::new("actions-trigger", "Split Options")
                                 .selected_label_color(Color::Accent)
-                                .key_binding(KeyBinding::for_action_in(
-                                    &OpenMenu,
-                                    &self.focus_handle,
-                                    cx,
-                                )),
+                                .key_binding(KeyBinding::for_action_in(&ToggleMenu, &context, cx)),
                         )
                         .menu({
                             move |cx| {
-                                Some(ContextMenu::build(cx, move |menu, _| {
-                                    menu.action("Split Left", pane::SplitLeft.boxed_clone())
-                                        .action("Split Right", pane::SplitRight.boxed_clone())
-                                        .action("Split Up", pane::SplitUp.boxed_clone())
-                                        .action("Split Down", pane::SplitDown.boxed_clone())
+                                Some(ContextMenu::build(cx, {
+                                    let context = context.clone();
+                                    move |menu, _| {
+                                        menu.context(context)
+                                            .action("Split Left", pane::SplitLeft.boxed_clone())
+                                            .action("Split Right", pane::SplitRight.boxed_clone())
+                                            .action("Split Up", pane::SplitUp.boxed_clone())
+                                            .action("Split Down", pane::SplitDown.boxed_clone())
+                                    }
                                 }))
                             }
                         }),

crates/ui/src/components/keybinding.rs 🔗

@@ -3,7 +3,7 @@ use crate::PlatformStyle;
 use crate::{h_flex, prelude::*, Icon, IconName, IconSize};
 use gpui::{relative, Action, FocusHandle, IntoElement, Keystroke, WindowContext};
 
-#[derive(IntoElement, Clone)]
+#[derive(Debug, IntoElement, Clone)]
 pub struct KeyBinding {
     /// A keybinding consists of a key and a set of modifier keys.
     /// More then one keybinding produces a chord.