Adjust pane, tab, panel management bindings to match VS Code

This commit is contained in:
Max Brunsfeld 2022-06-29 15:09:18 -07:00
parent 806da0e9ba
commit 581c9af395
9 changed files with 211 additions and 85 deletions

View File

@ -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"
}
},
{

View File

@ -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]

View File

@ -108,7 +108,8 @@ actions!(
Cut,
Paste,
Delete,
Rename
Rename,
Toggle
]
);
impl_internal_actions!(project_panel, [Open, ToggleExpanded, DeployContextMenu]);

View File

@ -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);
});

View File

@ -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())

View File

@ -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,

View File

@ -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
})

View File

@ -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",

View File

@ -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));
});