From 37b6e1cbb7662157d6d57736bef5fb60c74d391b Mon Sep 17 00:00:00 2001 From: Conrad Irwin Date: Tue, 26 Sep 2023 21:59:21 -0600 Subject: [PATCH] Add SwapPaneInDirection Add keybindings for vim (and non-vim) --- assets/keymaps/default.json | 16 +++++++++++ assets/keymaps/vim.json | 32 +++++++++++++++++++++ crates/workspace/src/pane_group.rs | 22 ++++++++++++++ crates/workspace/src/workspace.rs | 46 ++++++++++++++++++++++++------ 4 files changed, 107 insertions(+), 9 deletions(-) diff --git a/assets/keymaps/default.json b/assets/keymaps/default.json index fa75d0ce1b..ab025f46ef 100644 --- a/assets/keymaps/default.json +++ b/assets/keymaps/default.json @@ -506,6 +506,22 @@ "cmd-k cmd-down": [ "workspace::ActivatePaneInDirection", "Down" + ], + "cmd-k shift-left": [ + "workspace::SwapPaneInDirection", + "Left" + ], + "cmd-k shift-right": [ + "workspace::SwapPaneInDirection", + "Right" + ], + "cmd-k shift-up": [ + "workspace::SwapPaneInDirection", + "Up" + ], + "cmd-k shift-down": [ + "workspace::SwapPaneInDirection", + "Down" ] } }, diff --git a/assets/keymaps/vim.json b/assets/keymaps/vim.json index 3aaa3e4e1a..5362f7c0e5 100644 --- a/assets/keymaps/vim.json +++ b/assets/keymaps/vim.json @@ -316,6 +316,38 @@ "workspace::ActivatePaneInDirection", "Down" ], + "ctrl-w shift-left": [ + "workspace::SwapPaneInDirection", + "Left" + ], + "ctrl-w shift-right": [ + "workspace::SwapPaneInDirection", + "Right" + ], + "ctrl-w shift-up": [ + "workspace::SwapPaneInDirection", + "Up" + ], + "ctrl-w shift-down": [ + "workspace::SwapPaneInDirection", + "Down" + ], + "ctrl-w shift-h": [ + "workspace::SwapPaneInDirection", + "Left" + ], + "ctrl-w shift-l": [ + "workspace::SwapPaneInDirection", + "Right" + ], + "ctrl-w shift-k": [ + "workspace::SwapPaneInDirection", + "Up" + ], + "ctrl-w shift-j": [ + "workspace::SwapPaneInDirection", + "Down" + ], "ctrl-w g t": "pane::ActivateNextItem", "ctrl-w ctrl-g t": "pane::ActivateNextItem", "ctrl-w g shift-t": "pane::ActivatePrevItem", diff --git a/crates/workspace/src/pane_group.rs b/crates/workspace/src/pane_group.rs index bffdce0f3e..f4dd4b5512 100644 --- a/crates/workspace/src/pane_group.rs +++ b/crates/workspace/src/pane_group.rs @@ -84,6 +84,13 @@ impl PaneGroup { } } + pub fn swap(&mut self, from: &ViewHandle, to: &ViewHandle) { + match &mut self.root { + Member::Pane(_) => {} + Member::Axis(axis) => axis.swap(from, to), + }; + } + pub(crate) fn render( &self, project: &ModelHandle, @@ -428,6 +435,21 @@ impl PaneAxis { } } + fn swap(&mut self, from: &ViewHandle, to: &ViewHandle) { + for member in self.members.iter_mut() { + match member { + Member::Axis(axis) => axis.swap(from, to), + Member::Pane(pane) => { + if pane == from { + *member = Member::Pane(to.clone()); + } else if pane == to { + *member = Member::Pane(from.clone()) + } + } + } + } + } + fn bounding_box_for_pane(&self, pane: &ViewHandle) -> Option { debug_assert!(self.members.len() == self.bounding_boxes.borrow().len()); diff --git a/crates/workspace/src/workspace.rs b/crates/workspace/src/workspace.rs index f081eb9efa..2f82ed3701 100644 --- a/crates/workspace/src/workspace.rs +++ b/crates/workspace/src/workspace.rs @@ -157,6 +157,9 @@ pub struct ActivatePane(pub usize); #[derive(Clone, Deserialize, PartialEq)] pub struct ActivatePaneInDirection(pub SplitDirection); +#[derive(Clone, Deserialize, PartialEq)] +pub struct SwapPaneInDirection(pub SplitDirection); + #[derive(Clone, Deserialize, PartialEq)] pub struct NewFileInDirection(pub SplitDirection); @@ -233,6 +236,7 @@ impl_actions!( [ ActivatePane, ActivatePaneInDirection, + SwapPaneInDirection, NewFileInDirection, Toast, OpenTerminal, @@ -318,6 +322,12 @@ pub fn init(app_state: Arc, cx: &mut AppContext) { }, ); + cx.add_action( + |workspace: &mut Workspace, action: &SwapPaneInDirection, cx| { + workspace.swap_pane_in_direction(action.0, cx) + }, + ); + cx.add_action(|workspace: &mut Workspace, _: &ToggleLeftDock, cx| { workspace.toggle_dock(DockPosition::Left, cx); }); @@ -2236,11 +2246,32 @@ impl Workspace { direction: SplitDirection, cx: &mut ViewContext, ) { - let bounding_box = match self.center.bounding_box_for_pane(&self.active_pane) { - Some(coordinates) => coordinates, - None => { - return; - } + if let Some(pane) = self.find_pane_in_direction(direction, cx) { + cx.focus(pane); + } + } + + pub fn swap_pane_in_direction( + &mut self, + direction: SplitDirection, + cx: &mut ViewContext, + ) { + if let Some(to) = self + .find_pane_in_direction(direction, cx) + .map(|pane| pane.clone()) + { + self.center.swap(&self.active_pane.clone(), &to); + cx.notify(); + } + } + + fn find_pane_in_direction( + &mut self, + direction: SplitDirection, + cx: &mut ViewContext, + ) -> Option<&ViewHandle> { + let Some(bounding_box) = self.center.bounding_box_for_pane(&self.active_pane) else { + return None; }; let cursor = self.active_pane.read(cx).pixel_position_of_cursor(cx); let center = match cursor { @@ -2256,10 +2287,7 @@ impl Workspace { SplitDirection::Up => vec2f(center.x(), bounding_box.origin_y() - distance_to_next), SplitDirection::Down => vec2f(center.x(), bounding_box.max_y() + distance_to_next), }; - - if let Some(pane) = self.center.pane_at_pixel_position(target) { - cx.focus(pane); - } + self.center.pane_at_pixel_position(target) } fn handle_pane_focused(&mut self, pane: ViewHandle, cx: &mut ViewContext) {