Detailed changes
@@ -210,6 +210,43 @@
{
"context": "Pane",
"bindings": {
+ "ctrl-1": [
+ "pane::ActivateItem",
+ 0
+ ],
+ "ctrl-2": [
+ "pane::ActivateItem",
+ 1
+ ],
+ "ctrl-3": [
+ "pane::ActivateItem",
+ 2
+ ],
+ "ctrl-4": [
+ "pane::ActivateItem",
+ 3
+ ],
+ "ctrl-5": [
+ "pane::ActivateItem",
+ 4
+ ],
+ "ctrl-6": [
+ "pane::ActivateItem",
+ 5
+ ],
+ "ctrl-7": [
+ "pane::ActivateItem",
+ 6
+ ],
+ "ctrl-8": [
+ "pane::ActivateItem",
+ 7
+ ],
+ "ctrl-9": [
+ "pane::ActivateItem",
+ 8
+ ],
+ "ctrl-0": "pane::ActivateLastItem",
"ctrl--": "pane::GoBack",
"shift-ctrl-_": "pane::GoForward",
"cmd-shift-T": "pane::ReopenClosedItem",
@@ -219,6 +256,43 @@
{
"context": "Workspace",
"bindings": {
+ "cmd-1": [
+ "workspace::ActivatePane",
+ 0
+ ],
+ "cmd-2": [
+ "workspace::ActivatePane",
+ 1
+ ],
+ "cmd-3": [
+ "workspace::ActivatePane",
+ 2
+ ],
+ "cmd-4": [
+ "workspace::ActivatePane",
+ 3
+ ],
+ "cmd-5": [
+ "workspace::ActivatePane",
+ 4
+ ],
+ "cmd-6": [
+ "workspace::ActivatePane",
+ 5
+ ],
+ "cmd-7": [
+ "workspace::ActivatePane",
+ 6
+ ],
+ "cmd-8": [
+ "workspace::ActivatePane",
+ 7
+ ],
+ "cmd-9": [
+ "workspace::ActivatePane",
+ 8
+ ],
+ "cmd-b": "workspace::ToggleLeftSidebar",
"cmd-shift-F": "project_search::Deploy",
"cmd-k cmd-t": "theme_selector::Toggle",
"cmd-k cmd-s": "zed::OpenKeymap",
@@ -226,6 +300,7 @@
"cmd-p": "file_finder::Toggle",
"cmd-shift-P": "command_palette::Toggle",
"cmd-shift-M": "diagnostics::Deploy",
+ "cmd-shift-E": "project_panel::Toggle",
"cmd-alt-s": "workspace::SaveAll"
}
},
@@ -310,34 +385,8 @@
{
"context": "Workspace",
"bindings": {
- "cmd-1": [
- "workspace::ToggleSidebarItemFocus",
- {
- "side": "Left",
- "item_index": 0
- }
- ],
- "cmd-shift-!": [
- "workspace::ToggleSidebarItem",
- {
- "side": "Left",
- "item_index": 0
- }
- ],
- "cmd-9": [
- "workspace::ToggleSidebarItemFocus",
- {
- "side": "Right",
- "item_index": 0
- }
- ],
- "cmd-shift-(": [
- "workspace::ToggleSidebarItem",
- {
- "side": "Right",
- "item_index": 0
- }
- ]
+ "cmd-shift-C": "contacts_panel::Toggle",
+ "cmd-shift-B": "workspace::ToggleRightSidebar"
}
},
{
@@ -8,6 +8,7 @@ use contact_notification::ContactNotification;
use editor::{Cancel, Editor};
use fuzzy::{match_strings, StringMatchCandidate};
use gpui::{
+ actions,
elements::*,
geometry::{rect::RectF, vector::vec2f},
impl_actions, impl_internal_actions,
@@ -24,6 +25,8 @@ use std::{ops::DerefMut, sync::Arc};
use theme::IconButton;
use workspace::{sidebar::SidebarItem, JoinProject, ToggleProjectOnline, Workspace};
+actions!(contacts_panel, [Toggle]);
+
impl_actions!(
contacts_panel,
[RequestContact, RemoveContact, RespondToContactRequest]
@@ -108,7 +108,8 @@ actions!(
Cut,
Paste,
Delete,
- Rename
+ Rename,
+ Toggle
]
);
impl_internal_actions!(project_panel, [Open, ToggleExpanded, DeployContextMenu]);
@@ -18,11 +18,15 @@ use settings::Settings;
use std::{any::Any, cell::RefCell, mem, path::Path, rc::Rc};
use util::ResultExt;
+#[derive(Clone, Deserialize, PartialEq)]
+pub struct ActivateItem(pub usize);
+
actions!(
pane,
[
ActivatePrevItem,
ActivateNextItem,
+ ActivateLastItem,
CloseActiveItem,
CloseInactiveItems,
ReopenClosedItem,
@@ -39,9 +43,6 @@ pub struct CloseItem {
pub pane: WeakViewHandle<Pane>,
}
-#[derive(Clone, Deserialize, PartialEq)]
-pub struct ActivateItem(pub usize);
-
#[derive(Clone, Deserialize, PartialEq)]
pub struct GoBack {
#[serde(skip_deserializing)]
@@ -54,8 +55,8 @@ pub struct GoForward {
pub pane: Option<WeakViewHandle<Pane>>,
}
-impl_actions!(pane, [GoBack, GoForward]);
-impl_internal_actions!(pane, [CloseItem, ActivateItem]);
+impl_actions!(pane, [GoBack, GoForward, ActivateItem]);
+impl_internal_actions!(pane, [CloseItem]);
const MAX_NAVIGATION_HISTORY_LEN: usize = 1024;
@@ -63,6 +64,9 @@ pub fn init(cx: &mut MutableAppContext) {
cx.add_action(|pane: &mut Pane, action: &ActivateItem, cx| {
pane.activate_item(action.0, true, true, cx);
});
+ cx.add_action(|pane: &mut Pane, _: &ActivateLastItem, cx| {
+ pane.activate_item(pane.items.len() - 1, true, true, cx);
+ });
cx.add_action(|pane: &mut Pane, _: &ActivatePrevItem, cx| {
pane.activate_prev_item(cx);
});
@@ -55,7 +55,8 @@ impl Into<AnyViewHandle> for &dyn SidebarItemHandle {
pub struct Sidebar {
side: Side,
items: Vec<Item>,
- active_item_ix: Option<usize>,
+ is_open: bool,
+ active_item_ix: usize,
actual_width: Rc<RefCell<f32>>,
custom_width: Rc<RefCell<f32>>,
}
@@ -83,25 +84,41 @@ pub struct ToggleSidebarItem {
pub item_index: usize,
}
-#[derive(Clone, Debug, Deserialize, PartialEq)]
-pub struct ToggleSidebarItemFocus {
- pub side: Side,
- pub item_index: usize,
-}
-
-impl_actions!(workspace, [ToggleSidebarItem, ToggleSidebarItemFocus]);
+impl_actions!(workspace, [ToggleSidebarItem]);
impl Sidebar {
pub fn new(side: Side) -> Self {
Self {
side,
items: Default::default(),
- active_item_ix: None,
+ active_item_ix: 0,
+ is_open: false,
actual_width: Rc::new(RefCell::new(260.)),
custom_width: Rc::new(RefCell::new(260.)),
}
}
+ pub fn is_open(&self) -> bool {
+ self.is_open
+ }
+
+ pub fn active_item_ix(&self) -> usize {
+ self.active_item_ix
+ }
+
+ pub fn set_open(&mut self, open: bool, cx: &mut ViewContext<Self>) {
+ if open != self.is_open {
+ self.is_open = open;
+ cx.notify();
+ }
+ }
+
+ pub fn toggle_open(&mut self, cx: &mut ViewContext<Self>) {
+ if self.is_open {}
+ self.is_open = !self.is_open;
+ cx.notify();
+ }
+
pub fn add_item<T: SidebarItem>(
&mut self,
icon_path: &'static str,
@@ -133,23 +150,25 @@ impl Sidebar {
}
pub fn activate_item(&mut self, item_ix: usize, cx: &mut ViewContext<Self>) {
- self.active_item_ix = Some(item_ix);
+ self.active_item_ix = item_ix;
cx.notify();
}
pub fn toggle_item(&mut self, item_ix: usize, cx: &mut ViewContext<Self>) {
- if self.active_item_ix == Some(item_ix) {
- self.active_item_ix = None;
+ if self.active_item_ix == item_ix {
+ self.is_open = false;
} else {
- self.active_item_ix = Some(item_ix);
+ self.active_item_ix = item_ix;
}
cx.notify();
}
pub fn active_item(&self) -> Option<&Rc<dyn SidebarItemHandle>> {
- self.active_item_ix
- .and_then(|ix| self.items.get(ix))
- .map(|item| &item.view)
+ if self.is_open {
+ self.items.get(self.active_item_ix).map(|item| &item.view)
+ } else {
+ None
+ }
}
fn render_resize_handle(&self, theme: &Theme, cx: &mut RenderContext<Self>) -> ElementBox {
@@ -249,6 +268,7 @@ impl View for SidebarButtons {
let item_style = theme.item;
let badge_style = theme.badge;
let active_ix = sidebar.active_item_ix;
+ let is_open = sidebar.is_open;
let side = sidebar.side;
let group_style = match side {
Side::Left => theme.group_left,
@@ -267,7 +287,7 @@ impl View for SidebarButtons {
item_index: ix,
};
MouseEventHandler::new::<Self, _, _>(ix, cx, move |state, cx| {
- let is_active = Some(ix) == active_ix;
+ let is_active = is_open && ix == active_ix;
let style = item_style.style_for(state, is_active);
Stack::new()
.with_child(Svg::new(icon_path).with_color(style.icon_color).boxed())
@@ -1,7 +1,4 @@
-use crate::{
- sidebar::{Side, ToggleSidebarItem},
- AppState, ToggleFollow, Workspace,
-};
+use crate::{sidebar::Side, AppState, ToggleFollow, Workspace};
use anyhow::Result;
use client::{proto, Client, Contact};
use gpui::{
@@ -104,13 +101,7 @@ impl WaitingRoom {
&app_state,
cx,
);
- workspace.toggle_sidebar_item(
- &ToggleSidebarItem {
- side: Side::Left,
- item_index: 0,
- },
- cx,
- );
+ workspace.toggle_sidebar(Side::Left, cx);
if let Some((host_peer_id, _)) =
workspace.project.read(cx).collaborators().iter().find(
|(_, collaborator)| collaborator.replica_id == 0,
@@ -31,7 +31,7 @@ use postage::prelude::Stream;
use project::{fs, Fs, Project, ProjectEntryId, ProjectPath, ProjectStore, Worktree, WorktreeId};
use serde::Deserialize;
use settings::Settings;
-use sidebar::{Side, Sidebar, SidebarButtons, ToggleSidebarItem, ToggleSidebarItemFocus};
+use sidebar::{Side, Sidebar, SidebarButtons, ToggleSidebarItem};
use smallvec::SmallVec;
use status_bar::StatusBar;
pub use status_bar::StatusItemView;
@@ -90,6 +90,8 @@ actions!(
ActivatePreviousPane,
ActivateNextPane,
FollowNextCollaborator,
+ ToggleLeftSidebar,
+ ToggleRightSidebar,
]
);
@@ -104,6 +106,9 @@ pub struct ToggleProjectOnline {
pub project: Option<ModelHandle<Project>>,
}
+#[derive(Clone, Deserialize, PartialEq)]
+pub struct ActivatePane(pub usize);
+
#[derive(Clone, PartialEq)]
pub struct ToggleFollow(pub PeerId);
@@ -122,7 +127,7 @@ impl_internal_actions!(
RemoveWorktreeFromProject
]
);
-impl_actions!(workspace, [ToggleProjectOnline]);
+impl_actions!(workspace, [ToggleProjectOnline, ActivatePane]);
pub fn init(app_state: Arc<AppState>, cx: &mut MutableAppContext) {
pane::init(cx);
@@ -185,7 +190,6 @@ pub fn init(app_state: Arc<AppState>, cx: &mut MutableAppContext) {
},
);
cx.add_action(Workspace::toggle_sidebar_item);
- cx.add_action(Workspace::toggle_sidebar_item_focus);
cx.add_action(Workspace::focus_center);
cx.add_action(|workspace: &mut Workspace, _: &ActivatePreviousPane, cx| {
workspace.activate_previous_pane(cx)
@@ -193,6 +197,13 @@ pub fn init(app_state: Arc<AppState>, cx: &mut MutableAppContext) {
cx.add_action(|workspace: &mut Workspace, _: &ActivateNextPane, cx| {
workspace.activate_next_pane(cx)
});
+ cx.add_action(|workspace: &mut Workspace, _: &ToggleLeftSidebar, cx| {
+ workspace.toggle_sidebar(Side::Left, cx);
+ });
+ cx.add_action(|workspace: &mut Workspace, _: &ToggleRightSidebar, cx| {
+ workspace.toggle_sidebar(Side::Right, cx);
+ });
+ cx.add_action(Workspace::activate_pane_at_index);
let client = &app_state.client;
client.add_view_request_handler(Workspace::handle_follow);
@@ -1248,17 +1259,39 @@ impl Workspace {
}
}
+ pub fn toggle_sidebar(&mut self, side: Side, cx: &mut ViewContext<Self>) {
+ let sidebar = match side {
+ Side::Left => &mut self.left_sidebar,
+ Side::Right => &mut self.right_sidebar,
+ };
+ sidebar.update(cx, |sidebar, cx| {
+ sidebar.set_open(!sidebar.is_open(), cx);
+ });
+ cx.focus_self();
+ cx.notify();
+ }
+
pub fn toggle_sidebar_item(&mut self, action: &ToggleSidebarItem, cx: &mut ViewContext<Self>) {
let sidebar = match action.side {
Side::Left => &mut self.left_sidebar,
Side::Right => &mut self.right_sidebar,
};
let active_item = sidebar.update(cx, |sidebar, cx| {
- sidebar.toggle_item(action.item_index, cx);
- sidebar.active_item().map(|item| item.to_any())
+ if sidebar.is_open() && sidebar.active_item_ix() == action.item_index {
+ sidebar.set_open(false, cx);
+ None
+ } else {
+ sidebar.set_open(true, cx);
+ sidebar.activate_item(action.item_index, cx);
+ sidebar.active_item().cloned()
+ }
});
if let Some(active_item) = active_item {
- cx.focus(active_item);
+ if active_item.is_focused(cx) {
+ cx.focus_self();
+ } else {
+ cx.focus(active_item.to_any());
+ }
} else {
cx.focus_self();
}
@@ -1267,15 +1300,17 @@ impl Workspace {
pub fn toggle_sidebar_item_focus(
&mut self,
- action: &ToggleSidebarItemFocus,
+ side: Side,
+ item_index: usize,
cx: &mut ViewContext<Self>,
) {
- let sidebar = match action.side {
+ let sidebar = match side {
Side::Left => &mut self.left_sidebar,
Side::Right => &mut self.right_sidebar,
};
let active_item = sidebar.update(cx, |sidebar, cx| {
- sidebar.activate_item(action.item_index, cx);
+ sidebar.set_open(true, cx);
+ sidebar.activate_item(item_index, cx);
sidebar.active_item().cloned()
});
if let Some(active_item) = active_item {
@@ -1405,6 +1440,15 @@ impl Workspace {
}
}
+ fn activate_pane_at_index(&mut self, action: &ActivatePane, cx: &mut ViewContext<Self>) {
+ let panes = self.center.panes();
+ if let Some(pane) = panes.get(action.0).map(|p| (*p).clone()) {
+ self.activate_pane(pane, cx);
+ } else {
+ self.split_pane(self.active_pane.clone(), SplitDirection::Right, cx);
+ }
+ }
+
pub fn activate_next_pane(&mut self, cx: &mut ViewContext<Self>) {
let next_pane = {
let panes = self.center.panes();
@@ -2481,13 +2525,7 @@ pub fn open_paths(
let mut workspace = Workspace::new(project, cx);
(app_state.initialize_workspace)(&mut workspace, &app_state, cx);
if contains_directory {
- workspace.toggle_sidebar_item(
- &ToggleSidebarItem {
- side: Side::Left,
- item_index: 0,
- },
- cx,
- );
+ workspace.toggle_sidebar(Side::Left, cx);
}
workspace
})
@@ -187,11 +187,21 @@ pub fn menus() -> Vec<Menu<'static>> {
},
MenuItem::Separator,
MenuItem::Action {
- name: "Project Browser",
- action: Box::new(workspace::sidebar::ToggleSidebarItemFocus {
- side: workspace::sidebar::Side::Left,
- item_index: 0,
- }),
+ name: "Toggle Left Sidebar",
+ action: Box::new(workspace::ToggleLeftSidebar),
+ },
+ MenuItem::Action {
+ name: "Toggle Right Sidebar",
+ action: Box::new(workspace::ToggleRightSidebar),
+ },
+ MenuItem::Separator,
+ MenuItem::Action {
+ name: "Project Panel",
+ action: Box::new(project_panel::Toggle),
+ },
+ MenuItem::Action {
+ name: "Contacts Panel",
+ action: Box::new(contacts_panel::Toggle),
},
MenuItem::Action {
name: "Command Palette",
@@ -34,7 +34,7 @@ use std::{
};
use util::ResultExt;
pub use workspace;
-use workspace::{AppState, Workspace};
+use workspace::{sidebar::Side, AppState, Workspace};
#[derive(Deserialize, Clone, PartialEq)]
struct OpenBrowser {
@@ -128,6 +128,16 @@ pub fn init(app_state: &Arc<AppState>, cx: &mut gpui::MutableAppContext) {
}
},
);
+ cx.add_action(
+ |workspace: &mut Workspace, _: &project_panel::Toggle, cx: &mut ViewContext<Workspace>| {
+ workspace.toggle_sidebar_item_focus(Side::Left, 0, cx);
+ },
+ );
+ cx.add_action(
+ |workspace: &mut Workspace, _: &contacts_panel::Toggle, cx: &mut ViewContext<Workspace>| {
+ workspace.toggle_sidebar_item_focus(Side::Right, 0, cx);
+ },
+ );
lsp_status::init(cx);
settings::KeymapFileContent::load_defaults(cx);
@@ -429,7 +439,7 @@ mod tests {
let workspace_1 = cx.root_view::<Workspace>(cx.window_ids()[0]).unwrap();
workspace_1.update(cx, |workspace, cx| {
assert_eq!(workspace.worktrees(cx).count(), 2);
- assert!(workspace.left_sidebar().read(cx).active_item().is_some());
+ assert!(workspace.left_sidebar().read(cx).is_open());
assert!(workspace.active_pane().is_focused(cx));
});