Add an action to toggle the outline from the buffer search bar (#25225)

Mikayla Maki created

This was annoying.

Release Notes:

- Fixed a bug where you couldn't open the outline modal when focus was
in the buffer search bar.

Change summary

Cargo.lock                         |  1 +
assets/keymaps/default-macos.json  |  3 ++-
crates/search/Cargo.toml           |  1 +
crates/search/src/buffer_search.rs |  6 ++++++
crates/workspace/src/item.rs       | 12 ++++++++++--
5 files changed, 20 insertions(+), 3 deletions(-)

Detailed changes

Cargo.lock 🔗

@@ -11845,6 +11845,7 @@ dependencies = [
  "unindent",
  "util",
  "workspace",
+ "zed_actions",
 ]
 
 [[package]]

assets/keymaps/default-macos.json 🔗

@@ -286,7 +286,8 @@
       "alt-enter": "search::SelectAllMatches",
       "cmd-f": "search::FocusSearch",
       "cmd-alt-f": "search::ToggleReplace",
-      "cmd-alt-l": "search::ToggleSelection"
+      "cmd-alt-l": "search::ToggleSelection",
+      "cmd-shift-o": "outline::Toggle"
     }
   },
   {

crates/search/Cargo.toml 🔗

@@ -40,6 +40,7 @@ theme.workspace = true
 ui.workspace = true
 util.workspace = true
 workspace.workspace = true
+zed_actions.workspace = true
 
 [dev-dependencies]
 client = { workspace = true, features = ["test-support"] }

crates/search/src/buffer_search.rs 🔗

@@ -28,6 +28,7 @@ use serde::Deserialize;
 use settings::Settings;
 use std::sync::Arc;
 use theme::ThemeSettings;
+use zed_actions::outline::ToggleOutline;
 
 use ui::{
     h_flex, prelude::*, utils::SearchInputWidth, IconButton, IconButtonShape, IconName, Tooltip,
@@ -482,6 +483,11 @@ impl Render for BufferSearchBar {
             .on_action(cx.listener(Self::dismiss))
             .on_action(cx.listener(Self::select_next_match))
             .on_action(cx.listener(Self::select_prev_match))
+            .on_action(cx.listener(|this, _: &ToggleOutline, window, cx| {
+                if let Some(active_searchable_item) = &mut this.active_searchable_item {
+                    active_searchable_item.relay_action(Box::new(ToggleOutline), window, cx);
+                }
+            }))
             .when(self.supported_options(cx).replacement, |this| {
                 this.on_action(cx.listener(Self::toggle_replace))
                     .when(in_replace, |this| {

crates/workspace/src/item.rs 🔗

@@ -13,8 +13,8 @@ use client::{
 };
 use futures::{channel::mpsc, StreamExt};
 use gpui::{
-    AnyElement, AnyView, App, Context, Entity, EntityId, EventEmitter, FocusHandle, Focusable,
-    Font, HighlightStyle, Pixels, Point, Render, SharedString, Task, WeakEntity, Window,
+    Action, AnyElement, AnyView, App, Context, Entity, EntityId, EventEmitter, FocusHandle,
+    Focusable, Font, HighlightStyle, Pixels, Point, Render, SharedString, Task, WeakEntity, Window,
 };
 use project::{Project, ProjectEntryId, ProjectPath};
 use schemars::JsonSchema;
@@ -518,6 +518,7 @@ pub trait ItemHandle: 'static + Send {
     fn workspace_settings<'a>(&self, cx: &'a App) -> &'a WorkspaceSettings;
     fn preserve_preview(&self, cx: &App) -> bool;
     fn include_in_nav_history(&self) -> bool;
+    fn relay_action(&self, action: Box<dyn Action>, window: &mut Window, cx: &mut App);
 }
 
 pub trait WeakItemHandle: Send + Sync {
@@ -978,6 +979,13 @@ impl<T: Item> ItemHandle for Entity<T> {
     fn include_in_nav_history(&self) -> bool {
         T::include_in_nav_history()
     }
+
+    fn relay_action(&self, action: Box<dyn Action>, window: &mut Window, cx: &mut App) {
+        self.update(cx, |this, cx| {
+            this.focus_handle(cx).focus(window);
+            window.dispatch_action(action, cx);
+        })
+    }
 }
 
 impl From<Box<dyn ItemHandle>> for AnyView {