Add key bindings to toggle the project panel

Max Brunsfeld created

- Use `cmd-1` to open the project panel and toggle focus between it and the workspace center.
- Use `cmd-shift-1` to open or close the project panel.

Change summary

gpui/src/app.rs              |  5 ++++
zed/src/workspace.rs         | 39 +++++++++++++++++++++++++++++++++++++
zed/src/workspace/sidebar.rs | 14 ++++++++++--
3 files changed, 54 insertions(+), 4 deletions(-)

Detailed changes

gpui/src/app.rs 🔗

@@ -2900,6 +2900,11 @@ impl AnyViewHandle {
         TypeId::of::<T>() == self.view_type
     }
 
+    pub fn is_focused(&self, cx: &AppContext) -> bool {
+        cx.focused_view_id(self.window_id)
+            .map_or(false, |focused_id| focused_id == self.view_id)
+    }
+
     pub fn downcast<T: View>(self) -> Option<ViewHandle<T>> {
         if self.is::<T>() {
             let result = Some(ViewHandle {

zed/src/workspace.rs 🔗

@@ -12,6 +12,7 @@ use crate::{
     rpc,
     settings::Settings,
     user,
+    workspace::sidebar::{Side, Sidebar, SidebarItemId, ToggleSidebarItem, ToggleSidebarItemFocus},
     worktree::{File, Worktree},
     AppState, Authenticate,
 };
@@ -31,7 +32,6 @@ use log::error;
 pub use pane::*;
 pub use pane_group::*;
 use postage::{prelude::Stream, watch};
-use sidebar::{Side, Sidebar, ToggleSidebarItem};
 use std::{
     collections::{hash_map::Entry, HashMap},
     future::Future,
@@ -55,6 +55,7 @@ pub fn init(cx: &mut MutableAppContext) {
     cx.add_action(Workspace::debug_elements);
     cx.add_action(Workspace::open_new_file);
     cx.add_action(Workspace::toggle_sidebar_item);
+    cx.add_action(Workspace::toggle_sidebar_item_focus);
     cx.add_action(Workspace::share_worktree);
     cx.add_action(Workspace::unshare_worktree);
     cx.add_action(Workspace::join_worktree);
@@ -62,6 +63,22 @@ pub fn init(cx: &mut MutableAppContext) {
     cx.add_bindings(vec![
         Binding::new("cmd-s", Save, None),
         Binding::new("cmd-alt-i", DebugElements, None),
+        Binding::new(
+            "cmd-shift-!",
+            ToggleSidebarItem(SidebarItemId {
+                side: Side::Left,
+                item_index: 0,
+            }),
+            None,
+        ),
+        Binding::new(
+            "cmd-1",
+            ToggleSidebarItemFocus(SidebarItemId {
+                side: Side::Left,
+                item_index: 0,
+            }),
+            None,
+        ),
     ]);
     pane::init(cx);
 }
@@ -805,6 +822,26 @@ impl Workspace {
         cx.notify();
     }
 
+    pub fn toggle_sidebar_item_focus(
+        &mut self,
+        action: &ToggleSidebarItemFocus,
+        cx: &mut ViewContext<Self>,
+    ) {
+        let sidebar = match action.0.side {
+            Side::Left => &mut self.left_sidebar,
+            Side::Right => &mut self.right_sidebar,
+        };
+        sidebar.activate_item(action.0.item_index);
+        if let Some(active_item) = sidebar.active_item() {
+            if active_item.is_focused(cx) {
+                cx.focus_self();
+            } else {
+                cx.focus(active_item);
+            }
+        }
+        cx.notify();
+    }
+
     pub fn debug_elements(&mut self, _: &DebugElements, cx: &mut ViewContext<Self>) {
         match to_string_pretty(&cx.debug_elements()) {
             Ok(json) => {

zed/src/workspace/sidebar.rs 🔗

@@ -23,10 +23,11 @@ struct Item {
     view: AnyViewHandle,
 }
 
-action!(ToggleSidebarItem, ToggleArg);
+action!(ToggleSidebarItem, SidebarItemId);
+action!(ToggleSidebarItemFocus, SidebarItemId);
 
 #[derive(Clone)]
-pub struct ToggleArg {
+pub struct SidebarItemId {
     pub side: Side,
     pub item_index: usize,
 }
@@ -45,6 +46,10 @@ impl Sidebar {
         self.items.push(Item { icon_path, view });
     }
 
+    pub fn activate_item(&mut self, item_ix: usize) {
+        self.active_item_ix = Some(item_ix);
+    }
+
     pub fn toggle_item(&mut self, item_ix: usize) {
         if self.active_item_ix == Some(item_ix) {
             self.active_item_ix = None;
@@ -102,7 +107,10 @@ impl Sidebar {
                         )
                         .with_cursor_style(CursorStyle::PointingHand)
                         .on_mouse_down(move |cx| {
-                            cx.dispatch_action(ToggleSidebarItem(ToggleArg { side, item_index }))
+                            cx.dispatch_action(ToggleSidebarItem(SidebarItemId {
+                                side,
+                                item_index,
+                            }))
                         })
                         .boxed()
                     }))