diff --git a/zellij-client/src/input_handler.rs b/zellij-client/src/input_handler.rs index 1b2c0f22..78869fd5 100644 --- a/zellij-client/src/input_handler.rs +++ b/zellij-client/src/input_handler.rs @@ -176,6 +176,7 @@ impl InputHandler { let mut should_break = false; match action { + Action::NoOp => {} Action::Quit | Action::Detach => { self.os_input .send_to_server(ClientToServerMsg::Action(action)); diff --git a/zellij-server/src/route.rs b/zellij-server/src/route.rs index bfdf18ca..9b1201b6 100644 --- a/zellij-server/src/route.rs +++ b/zellij-server/src/route.rs @@ -120,10 +120,11 @@ fn route_action( } Action::MovePane(direction) => { let screen_instr = match direction { - Direction::Left => ScreenInstruction::MovePaneLeft(client_id), - Direction::Right => ScreenInstruction::MovePaneRight(client_id), - Direction::Up => ScreenInstruction::MovePaneUp(client_id), - Direction::Down => ScreenInstruction::MovePaneDown(client_id), + Some(Direction::Left) => ScreenInstruction::MovePaneLeft(client_id), + Some(Direction::Right) => ScreenInstruction::MovePaneRight(client_id), + Some(Direction::Up) => ScreenInstruction::MovePaneUp(client_id), + Some(Direction::Down) => ScreenInstruction::MovePaneDown(client_id), + None => ScreenInstruction::MovePane(client_id), }; session.senders.send_to_screen(screen_instr).unwrap(); } diff --git a/zellij-server/src/screen.rs b/zellij-server/src/screen.rs index 28ef40a2..72c681c9 100644 --- a/zellij-server/src/screen.rs +++ b/zellij-server/src/screen.rs @@ -44,6 +44,7 @@ pub(crate) enum ScreenInstruction { MoveFocusUp(ClientId), MoveFocusRight(ClientId), MoveFocusRightOrNextTab(ClientId), + MovePane(ClientId), MovePaneUp(ClientId), MovePaneDown(ClientId), MovePaneRight(ClientId), @@ -106,6 +107,7 @@ impl From<&ScreenInstruction> for ScreenContext { ScreenInstruction::MoveFocusRightOrNextTab(..) => { ScreenContext::MoveFocusRightOrNextTab } + ScreenInstruction::MovePane(..) => ScreenContext::MovePane, ScreenInstruction::MovePaneDown(..) => ScreenContext::MovePaneDown, ScreenInstruction::MovePaneUp(..) => ScreenContext::MovePaneUp, ScreenInstruction::MovePaneRight(..) => ScreenContext::MovePaneRight, @@ -736,6 +738,14 @@ pub(crate) fn screen_thread_main( screen.render(); } + ScreenInstruction::MovePane(client_id) => { + screen + .get_active_tab_mut(client_id) + .unwrap() + .move_active_pane(); + + screen.render(); + } ScreenInstruction::MovePaneDown(client_id) => { screen .get_active_tab_mut(client_id) diff --git a/zellij-server/src/tab.rs b/zellij-server/src/tab.rs index e5586caa..d50aba42 100644 --- a/zellij-server/src/tab.rs +++ b/zellij-server/src/tab.rs @@ -2033,6 +2033,56 @@ impl Tab { self.active_terminal = updated_active_terminal; false } + pub fn move_active_pane(&mut self) { + if !self.has_selectable_panes() { + return; + } + if self.fullscreen_is_active { + return; + } + let active_pane_id = self.get_active_pane_id().unwrap(); + let mut panes: Vec<(&PaneId, &Box)> = self.get_selectable_panes().collect(); + panes.sort_by(|(_a_id, a_pane), (_b_id, b_pane)| { + if a_pane.y() == b_pane.y() { + a_pane.x().cmp(&b_pane.x()) + } else { + a_pane.y().cmp(&b_pane.y()) + } + }); + let active_pane_position = panes + .iter() + .position(|(id, _)| *id == &active_pane_id) // TODO: better + .unwrap(); + + let new_position_id = panes + .get(active_pane_position + 1) + .or_else(|| panes.get(0)) + .map(|p| *p.0); + + if let Some(p) = new_position_id { + let current_position = self.panes.get(&active_pane_id).unwrap(); + let prev_geom = current_position.position_and_size(); + let prev_geom_override = current_position.geom_override(); + + let new_position = self.panes.get_mut(&p).unwrap(); + let next_geom = new_position.position_and_size(); + let next_geom_override = new_position.geom_override(); + new_position.set_geom(prev_geom); + if let Some(geom) = prev_geom_override { + new_position.get_geom_override(geom); + } + resize_pty!(new_position, self.os_api); + new_position.set_should_render(true); + + let current_position = self.panes.get_mut(&active_pane_id).unwrap(); + current_position.set_geom(next_geom); + if let Some(geom) = next_geom_override { + current_position.get_geom_override(geom); + } + resize_pty!(current_position, self.os_api); + current_position.set_should_render(true); + } + } pub fn move_active_pane_down(&mut self) { if !self.has_selectable_panes() { return; diff --git a/zellij-utils/assets/config/default.yaml b/zellij-utils/assets/config/default.yaml index 323c96e9..51ef72c2 100644 --- a/zellij-utils/assets/config/default.yaml +++ b/zellij-utils/assets/config/default.yaml @@ -140,6 +140,8 @@ keybinds: key: [Ctrl: 'o',] - action: [Quit] key: [Ctrl: 'q'] + - action: [MovePane: ,] + key: [Char: 'n', Char: "\t",] - action: [MovePane: Left,] key: [Char: 'h', Left,] - action: [MovePane: Down,] diff --git a/zellij-utils/src/errors.rs b/zellij-utils/src/errors.rs index b6353c5b..be75e4ad 100644 --- a/zellij-utils/src/errors.rs +++ b/zellij-utils/src/errors.rs @@ -226,6 +226,7 @@ pub enum ScreenContext { MoveFocusUp, MoveFocusRight, MoveFocusRightOrNextTab, + MovePane, MovePaneDown, MovePaneUp, MovePaneRight, diff --git a/zellij-utils/src/input/actions.rs b/zellij-utils/src/input/actions.rs index ed1865f7..8446bf0d 100644 --- a/zellij-utils/src/input/actions.rs +++ b/zellij-utils/src/input/actions.rs @@ -41,7 +41,7 @@ pub enum Action { /// Tries to move the focus pane in specified direction. /// If there is no pane in the direction, move to previous/next Tab. MoveFocusOrTab(Direction), - MovePane(Direction), + MovePane(Option), /// Scroll up in focus pane. ScrollUp, /// Scroll up at point diff --git a/zellij-utils/src/input/mod.rs b/zellij-utils/src/input/mod.rs index 80e5e451..3a26688d 100644 --- a/zellij-utils/src/input/mod.rs +++ b/zellij-utils/src/input/mod.rs @@ -23,7 +23,10 @@ pub fn get_mode_info( let keybinds = match mode { InputMode::Normal | InputMode::Locked => Vec::new(), InputMode::Resize => vec![("←↓↑→".to_string(), "Resize".to_string())], - InputMode::Move => vec![("←↓↑→".to_string(), "Move".to_string())], + InputMode::Move => vec![ + ("←↓↑→".to_string(), "Move".to_string()), + ("n/Tab".to_string(), "Next Pane".to_string()), + ], InputMode::Pane => vec![ ("←↓↑→".to_string(), "Move focus".to_string()), ("p".to_string(), "Next".to_string()),