diff --git a/default-plugins/status-bar/src/second_line.rs b/default-plugins/status-bar/src/second_line.rs index 0e59fcb8..1b90443c 100644 --- a/default-plugins/status-bar/src/second_line.rs +++ b/default-plugins/status-bar/src/second_line.rs @@ -90,14 +90,18 @@ fn quicknav_full(palette: Palette) -> LinePart { let text_first_part = " Tip: "; let alt = "Alt"; let text_second_part = " + "; - let new_pane_shortcut = "n"; + let new_pane_shortcut = ""; let text_third_part = " => open new pane. "; let second_alt = "Alt"; let text_fourth_part = " + "; - let brackets_navigation = "[]"; + let brackets_navigation = "<[]"; let text_fifth_part = " or "; - let hjkl_navigation = "hjkl"; - let text_sixths_part = " => navigate between panes."; + let hjkl_navigation = "hjkl>"; + let text_sixths_part = " => navigate between panes. "; + let third_alt = "Alt"; + let text_seventh_parth = " + "; + let increase_decrease_parth = "<+->"; + let text_eighth_parth = " => increase/decrease pane size."; let len = text_first_part.chars().count() + alt.chars().count() + text_second_part.chars().count() @@ -108,7 +112,11 @@ fn quicknav_full(palette: Palette) -> LinePart { + brackets_navigation.chars().count() + text_fifth_part.chars().count() + hjkl_navigation.chars().count() - + text_sixths_part.chars().count(); + + text_sixths_part.chars().count() + + third_alt.chars().count() + + text_seventh_parth.chars().count() + + increase_decrease_parth.chars().count() + + text_eighth_parth.chars().count(); let green_color = match palette.green { PaletteColor::Rgb((r, g, b)) => RGB(r, g, b), PaletteColor::EightBit(color) => Fixed(color), @@ -119,7 +127,7 @@ fn quicknav_full(palette: Palette) -> LinePart { }; LinePart { part: format!( - "{}{}{}{}{}{}{}{}{}{}{}", + "{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}", text_first_part, Style::new().fg(orange_color).bold().paint(alt), text_second_part, @@ -134,6 +142,13 @@ fn quicknav_full(palette: Palette) -> LinePart { text_fifth_part, Style::new().fg(green_color).bold().paint(hjkl_navigation), text_sixths_part, + Style::new().fg(orange_color).bold().paint(third_alt), + text_seventh_parth, + Style::new() + .fg(green_color) + .bold() + .paint(increase_decrease_parth), + text_eighth_parth, ), len, } @@ -143,14 +158,18 @@ fn quicknav_medium(palette: Palette) -> LinePart { let text_first_part = " Tip: "; let alt = "Alt"; let text_second_part = " + "; - let new_pane_shortcut = "n"; + let new_pane_shortcut = ""; let text_third_part = " => new pane. "; let second_alt = "Alt"; let text_fourth_part = " + "; - let brackets_navigation = "[]"; + let brackets_navigation = "<[]"; let text_fifth_part = " or "; - let hjkl_navigation = "hjkl"; - let text_sixths_part = " => navigate."; + let hjkl_navigation = "hjkl>"; + let text_sixths_part = " => navigate. "; + let third_alt = "Alt"; + let text_seventh_parth = " + "; + let increase_decrease_parth = "<+->"; + let text_eighth_parth = " => resize pane. "; let len = text_first_part.chars().count() + alt.chars().count() + text_second_part.chars().count() @@ -161,7 +180,11 @@ fn quicknav_medium(palette: Palette) -> LinePart { + brackets_navigation.chars().count() + text_fifth_part.chars().count() + hjkl_navigation.chars().count() - + text_sixths_part.chars().count(); + + text_sixths_part.chars().count() + + third_alt.chars().count() + + text_seventh_parth.chars().count() + + increase_decrease_parth.chars().count() + + text_eighth_parth.chars().count(); let green_color = match palette.green { PaletteColor::Rgb((r, g, b)) => RGB(r, g, b), PaletteColor::EightBit(color) => Fixed(color), @@ -172,7 +195,7 @@ fn quicknav_medium(palette: Palette) -> LinePart { }; LinePart { part: format!( - "{}{}{}{}{}{}{}{}{}{}{}", + "{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}", text_first_part, Style::new().fg(orange_color).bold().paint(alt), text_second_part, @@ -187,6 +210,13 @@ fn quicknav_medium(palette: Palette) -> LinePart { text_fifth_part, Style::new().fg(green_color).bold().paint(hjkl_navigation), text_sixths_part, + Style::new().fg(orange_color).bold().paint(third_alt), + text_seventh_parth, + Style::new() + .fg(green_color) + .bold() + .paint(increase_decrease_parth), + text_eighth_parth, ), len, } @@ -201,6 +231,8 @@ fn quicknav_short(palette: Palette) -> LinePart { let brackets_navigation = "[]"; let text_fifth_part = "/"; let hjkl_navigation = "hjkl"; + let text_sixth_part = "/"; + let increase_decrease_part = "+-"; let len = text_first_part.chars().count() + alt.chars().count() + text_second_part.chars().count() @@ -208,7 +240,9 @@ fn quicknav_short(palette: Palette) -> LinePart { + text_third_part.chars().count() + brackets_navigation.chars().count() + text_fifth_part.chars().count() - + hjkl_navigation.chars().count(); + + hjkl_navigation.chars().count() + + text_sixth_part.chars().count() + + increase_decrease_part.chars().count(); let green_color = match palette.green { PaletteColor::Rgb((r, g, b)) => RGB(r, g, b), PaletteColor::EightBit(color) => Fixed(color), @@ -219,7 +253,7 @@ fn quicknav_short(palette: Palette) -> LinePart { }; LinePart { part: format!( - "{}{}{}{}{}{}{}{}", + "{}{}{}{}{}{}{}{}{}{}", text_first_part, Style::new().fg(orange_color).bold().paint(alt), text_second_part, @@ -231,6 +265,11 @@ fn quicknav_short(palette: Palette) -> LinePart { .paint(brackets_navigation), text_fifth_part, Style::new().fg(green_color).bold().paint(hjkl_navigation), + text_sixth_part, + Style::new() + .fg(green_color) + .bold() + .paint(increase_decrease_part), ), len, } diff --git a/zellij-server/src/route.rs b/zellij-server/src/route.rs index 57fea124..444be5a0 100644 --- a/zellij-server/src/route.rs +++ b/zellij-server/src/route.rs @@ -12,7 +12,7 @@ use crate::{ use zellij_utils::{ channels::SenderWithContext, input::{ - actions::{Action, Direction}, + actions::{Action, Direction, ResizeDirection}, command::TerminalAction, get_mode_info, }, @@ -87,10 +87,12 @@ fn route_action( } Action::Resize(direction) => { let screen_instr = match direction { - Direction::Left => ScreenInstruction::ResizeLeft(client_id), - Direction::Right => ScreenInstruction::ResizeRight(client_id), - Direction::Up => ScreenInstruction::ResizeUp(client_id), - Direction::Down => ScreenInstruction::ResizeDown(client_id), + ResizeDirection::Left => ScreenInstruction::ResizeLeft(client_id), + ResizeDirection::Right => ScreenInstruction::ResizeRight(client_id), + ResizeDirection::Up => ScreenInstruction::ResizeUp(client_id), + ResizeDirection::Down => ScreenInstruction::ResizeDown(client_id), + ResizeDirection::Increase => ScreenInstruction::ResizeIncrease(client_id), + ResizeDirection::Decrease => ScreenInstruction::ResizeDecrease(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 4852b305..2a8c54c6 100644 --- a/zellij-server/src/screen.rs +++ b/zellij-server/src/screen.rs @@ -35,6 +35,8 @@ pub(crate) enum ScreenInstruction { ResizeRight(ClientId), ResizeDown(ClientId), ResizeUp(ClientId), + ResizeIncrease(ClientId), + ResizeDecrease(ClientId), SwitchFocus(ClientId), FocusNextPane(ClientId), FocusPreviousPane(ClientId), @@ -95,6 +97,8 @@ impl From<&ScreenInstruction> for ScreenContext { ScreenInstruction::ResizeRight(..) => ScreenContext::ResizeRight, ScreenInstruction::ResizeDown(..) => ScreenContext::ResizeDown, ScreenInstruction::ResizeUp(..) => ScreenContext::ResizeUp, + ScreenInstruction::ResizeIncrease(..) => ScreenContext::ResizeIncrease, + ScreenInstruction::ResizeDecrease(..) => ScreenContext::ResizeDecrease, ScreenInstruction::SwitchFocus(..) => ScreenContext::SwitchFocus, ScreenInstruction::FocusNextPane(..) => ScreenContext::FocusNextPane, ScreenInstruction::FocusPreviousPane(..) => ScreenContext::FocusPreviousPane, @@ -659,6 +663,22 @@ pub(crate) fn screen_thread_main( screen.render(); } + ScreenInstruction::ResizeIncrease(client_id) => { + screen + .get_active_tab_mut(client_id) + .unwrap() + .resize_increase(); + + screen.render(); + } + ScreenInstruction::ResizeDecrease(client_id) => { + screen + .get_active_tab_mut(client_id) + .unwrap() + .resize_decrease(); + + screen.render(); + } ScreenInstruction::SwitchFocus(client_id) => { screen.get_active_tab_mut(client_id).unwrap().move_focus(); diff --git a/zellij-server/src/tab.rs b/zellij-server/src/tab.rs index 4d774b60..ffdf7e64 100644 --- a/zellij-server/src/tab.rs +++ b/zellij-server/src/tab.rs @@ -1749,6 +1749,308 @@ impl Tab { false } } + fn try_increase_pane_and_surroundings_right( + &mut self, + pane_id: &PaneId, + reduce_by: f64, + ) -> bool { + if self.can_increase_pane_and_surroundings_right(pane_id, reduce_by) { + self.increase_pane_and_surroundings_right(pane_id, reduce_by); + self.relayout_tab(Direction::Horizontal); + return true; + } + false + } + fn try_increase_pane_and_surroundings_left( + &mut self, + pane_id: &PaneId, + reduce_by: f64, + ) -> bool { + if self.can_increase_pane_and_surroundings_left(pane_id, reduce_by) { + self.increase_pane_and_surroundings_left(pane_id, reduce_by); + self.relayout_tab(Direction::Horizontal); + return true; + } + false + } + fn try_increase_pane_and_surroundings_up(&mut self, pane_id: &PaneId, reduce_by: f64) -> bool { + if self.can_increase_pane_and_surroundings_up(pane_id, reduce_by) { + self.increase_pane_and_surroundings_up(pane_id, reduce_by); + self.relayout_tab(Direction::Vertical); + return true; + } + false + } + fn try_increase_pane_and_surroundings_down( + &mut self, + pane_id: &PaneId, + reduce_by: f64, + ) -> bool { + if self.can_increase_pane_and_surroundings_down(pane_id, reduce_by) { + self.increase_pane_and_surroundings_down(pane_id, reduce_by); + self.relayout_tab(Direction::Vertical); + return true; + } + false + } + fn try_increase_pane_and_surroundings_right_and_up(&mut self, pane_id: &PaneId) -> bool { + let can_increase_pane_right = + self.can_increase_pane_and_surroundings_right(pane_id, RESIZE_PERCENT); + let can_increase_pane_up = + self.can_increase_pane_and_surroundings_up(pane_id, RESIZE_PERCENT); + if can_increase_pane_right && can_increase_pane_up { + let pane_above_with_right_aligned_border = self + .viewport_pane_ids_directly_above(pane_id) + .iter() + .copied() + .find(|p_id| { + let pane = self.panes.get(p_id).unwrap(); + let active_pane = self.panes.get(pane_id).unwrap(); + active_pane.x() + active_pane.cols() == pane.x() + }); + self.try_increase_pane_and_surroundings_right(pane_id, RESIZE_PERCENT); + self.try_increase_pane_and_surroundings_up(pane_id, RESIZE_PERCENT); + if let Some(pane_above_with_right_aligned_border) = pane_above_with_right_aligned_border + { + self.try_reduce_pane_and_surroundings_right( + &pane_above_with_right_aligned_border, + RESIZE_PERCENT, + ); + } + true + } else { + false + } + } + fn try_increase_pane_and_surroundings_left_and_up(&mut self, pane_id: &PaneId) -> bool { + let can_increase_pane_left = + self.can_increase_pane_and_surroundings_left(pane_id, RESIZE_PERCENT); + let can_increase_pane_up = + self.can_increase_pane_and_surroundings_up(pane_id, RESIZE_PERCENT); + if can_increase_pane_left && can_increase_pane_up { + let pane_above_with_left_aligned_border = self + .viewport_pane_ids_directly_above(pane_id) + .iter() + .copied() + .find(|p_id| { + let pane = self.panes.get(p_id).unwrap(); + let active_pane = self.panes.get(pane_id).unwrap(); + active_pane.x() == pane.x() + pane.cols() + }); + self.try_increase_pane_and_surroundings_left(pane_id, RESIZE_PERCENT); + self.try_increase_pane_and_surroundings_up(pane_id, RESIZE_PERCENT); + if let Some(pane_above_with_left_aligned_border) = pane_above_with_left_aligned_border { + self.try_reduce_pane_and_surroundings_left( + &pane_above_with_left_aligned_border, + RESIZE_PERCENT, + ); + } + true + } else { + false + } + } + fn try_increase_pane_and_surroundings_right_and_down(&mut self, pane_id: &PaneId) -> bool { + let can_increase_pane_right = + self.can_increase_pane_and_surroundings_right(pane_id, RESIZE_PERCENT); + let can_increase_pane_down = + self.can_increase_pane_and_surroundings_down(pane_id, RESIZE_PERCENT); + if can_increase_pane_right && can_increase_pane_down { + let pane_below_with_right_aligned_border = self + .viewport_pane_ids_directly_below(pane_id) + .iter() + .copied() + .find(|p_id| { + let pane = self.panes.get(p_id).unwrap(); + let active_pane = self.panes.get(pane_id).unwrap(); + active_pane.x() + active_pane.cols() == pane.x() + }); + self.try_increase_pane_and_surroundings_right(pane_id, RESIZE_PERCENT); + self.try_increase_pane_and_surroundings_down(pane_id, RESIZE_PERCENT); + if let Some(pane_below_with_right_aligned_border) = pane_below_with_right_aligned_border + { + self.try_reduce_pane_and_surroundings_right( + &pane_below_with_right_aligned_border, + RESIZE_PERCENT, + ); + } + true + } else { + false + } + } + fn try_increase_pane_and_surroundings_left_and_down(&mut self, pane_id: &PaneId) -> bool { + let can_increase_pane_left = + self.can_increase_pane_and_surroundings_left(pane_id, RESIZE_PERCENT); + let can_increase_pane_down = + self.can_increase_pane_and_surroundings_down(pane_id, RESIZE_PERCENT); + if can_increase_pane_left && can_increase_pane_down { + let pane_below_with_left_aligned_border = self + .viewport_pane_ids_directly_below(pane_id) + .iter() + .copied() + .find(|p_id| { + let pane = self.panes.get(p_id).unwrap(); + let active_pane = self.panes.get(pane_id).unwrap(); + active_pane.x() == pane.x() + pane.cols() + }); + self.try_increase_pane_and_surroundings_left(pane_id, RESIZE_PERCENT); + self.try_increase_pane_and_surroundings_down(pane_id, RESIZE_PERCENT); + if let Some(pane_below_with_left_aligned_border) = pane_below_with_left_aligned_border { + self.try_reduce_pane_and_surroundings_left( + &pane_below_with_left_aligned_border, + RESIZE_PERCENT, + ); + } + true + } else { + false + } + } + fn try_reduce_pane_and_surroundings_right_and_up(&mut self, pane_id: &PaneId) -> bool { + let can_reduce_pane_right = + self.can_reduce_pane_and_surroundings_right(pane_id, RESIZE_PERCENT); + let can_reduce_pane_up = self.can_reduce_pane_and_surroundings_up(pane_id, RESIZE_PERCENT); + if can_reduce_pane_right && can_reduce_pane_up { + let pane_below_with_left_aligned_border = self + .viewport_pane_ids_directly_below(pane_id) + .iter() + .copied() + .find(|p_id| { + let pane = self.panes.get(p_id).unwrap(); + let active_pane = self.panes.get(pane_id).unwrap(); + active_pane.x() == pane.x() + pane.cols() + }); + self.try_reduce_pane_and_surroundings_right(pane_id, RESIZE_PERCENT); + self.try_reduce_pane_and_surroundings_up(pane_id, RESIZE_PERCENT); + if let Some(pane_below_with_left_aligned_border) = pane_below_with_left_aligned_border { + self.try_increase_pane_and_surroundings_right( + &pane_below_with_left_aligned_border, + RESIZE_PERCENT, + ); + } + true + } else { + false + } + } + fn try_reduce_pane_and_surroundings_left_and_up(&mut self, pane_id: &PaneId) -> bool { + let can_reduce_pane_left = + self.can_reduce_pane_and_surroundings_left(pane_id, RESIZE_PERCENT); + let can_reduce_pane_up = self.can_reduce_pane_and_surroundings_up(pane_id, RESIZE_PERCENT); + if can_reduce_pane_left && can_reduce_pane_up { + let pane_below_with_right_aligned_border = self + .viewport_pane_ids_directly_below(pane_id) + .iter() + .copied() + .find(|p_id| { + let pane = self.panes.get(p_id).unwrap(); + let active_pane = self.panes.get(pane_id).unwrap(); + active_pane.x() + active_pane.cols() == pane.x() + }); + self.try_reduce_pane_and_surroundings_left(pane_id, RESIZE_PERCENT); + self.try_reduce_pane_and_surroundings_up(pane_id, RESIZE_PERCENT); + if let Some(pane_below_with_right_aligned_border) = pane_below_with_right_aligned_border + { + self.try_increase_pane_and_surroundings_left( + &pane_below_with_right_aligned_border, + RESIZE_PERCENT, + ); + } + true + } else { + false + } + } + fn try_reduce_pane_and_surroundings_right_and_down(&mut self, pane_id: &PaneId) -> bool { + let can_reduce_pane_right = + self.can_reduce_pane_and_surroundings_right(pane_id, RESIZE_PERCENT); + let can_reduce_pane_down = + self.can_reduce_pane_and_surroundings_down(pane_id, RESIZE_PERCENT); + if can_reduce_pane_right && can_reduce_pane_down { + let pane_above_with_left_aligned_border = self + .viewport_pane_ids_directly_above(pane_id) + .iter() + .copied() + .find(|p_id| { + let pane = self.panes.get(p_id).unwrap(); + let active_pane = self.panes.get(pane_id).unwrap(); + active_pane.x() == pane.x() + pane.cols() + }); + self.try_reduce_pane_and_surroundings_right(pane_id, RESIZE_PERCENT); + self.try_reduce_pane_and_surroundings_down(pane_id, RESIZE_PERCENT); + if let Some(pane_above_with_left_aligned_border) = pane_above_with_left_aligned_border { + self.try_increase_pane_and_surroundings_right( + &pane_above_with_left_aligned_border, + RESIZE_PERCENT, + ); + } + true + } else { + false + } + } + fn try_reduce_pane_and_surroundings_left_and_down(&mut self, pane_id: &PaneId) -> bool { + let can_reduce_pane_left = + self.can_reduce_pane_and_surroundings_left(pane_id, RESIZE_PERCENT); + let can_reduce_pane_down = + self.can_reduce_pane_and_surroundings_down(pane_id, RESIZE_PERCENT); + if can_reduce_pane_left && can_reduce_pane_down { + let pane_above_with_right_aligned_border = self + .viewport_pane_ids_directly_above(pane_id) + .iter() + .copied() + .find(|p_id| { + let pane = self.panes.get(p_id).unwrap(); + let active_pane = self.panes.get(pane_id).unwrap(); + active_pane.x() + active_pane.cols() == pane.x() + }); + self.try_reduce_pane_and_surroundings_left(pane_id, RESIZE_PERCENT); + self.try_reduce_pane_and_surroundings_down(pane_id, RESIZE_PERCENT); + if let Some(pane_above_with_right_aligned_border) = pane_above_with_right_aligned_border + { + self.try_increase_pane_and_surroundings_left( + &pane_above_with_right_aligned_border, + RESIZE_PERCENT, + ); + } + true + } else { + false + } + } + fn try_reduce_pane_and_surroundings_right(&mut self, pane_id: &PaneId, reduce_by: f64) -> bool { + if self.can_reduce_pane_and_surroundings_right(pane_id, reduce_by) { + self.reduce_pane_and_surroundings_right(pane_id, reduce_by); + self.relayout_tab(Direction::Horizontal); + return true; + } + false + } + fn try_reduce_pane_and_surroundings_left(&mut self, pane_id: &PaneId, reduce_by: f64) -> bool { + if self.can_reduce_pane_and_surroundings_left(pane_id, reduce_by) { + self.reduce_pane_and_surroundings_left(pane_id, reduce_by); + self.relayout_tab(Direction::Horizontal); + return true; + } + false + } + fn try_reduce_pane_and_surroundings_up(&mut self, pane_id: &PaneId, reduce_by: f64) -> bool { + if self.can_reduce_pane_and_surroundings_up(pane_id, reduce_by) { + self.reduce_pane_and_surroundings_up(pane_id, reduce_by); + self.relayout_tab(Direction::Vertical); + return true; + } + false + } + fn try_reduce_pane_and_surroundings_down(&mut self, pane_id: &PaneId, reduce_by: f64) -> bool { + if self.can_reduce_pane_and_surroundings_down(pane_id, reduce_by) { + self.reduce_pane_and_surroundings_down(pane_id, reduce_by); + self.relayout_tab(Direction::Vertical); + return true; + } + false + } fn ids_are_flexible(&self, direction: Direction, pane_ids: Option>) -> bool { pane_ids.is_some() && pane_ids.unwrap().iter().all(|id| { @@ -1840,6 +2142,60 @@ impl Tab { } self.relayout_tab(Direction::Vertical); } + pub fn resize_increase(&mut self) { + if let Some(active_pane_id) = self.get_active_pane_id() { + if self.try_increase_pane_and_surroundings_right_and_down(&active_pane_id) { + return; + } + if self.try_increase_pane_and_surroundings_left_and_down(&active_pane_id) { + return; + } + if self.try_increase_pane_and_surroundings_right_and_up(&active_pane_id) { + return; + } + if self.try_increase_pane_and_surroundings_left_and_up(&active_pane_id) { + return; + } + + if self.try_increase_pane_and_surroundings_right(&active_pane_id, RESIZE_PERCENT) { + return; + } + if self.try_increase_pane_and_surroundings_down(&active_pane_id, RESIZE_PERCENT) { + return; + } + if self.try_increase_pane_and_surroundings_left(&active_pane_id, RESIZE_PERCENT) { + return; + } + self.try_increase_pane_and_surroundings_up(&active_pane_id, RESIZE_PERCENT); + } + } + pub fn resize_decrease(&mut self) { + if let Some(active_pane_id) = self.get_active_pane_id() { + if self.try_reduce_pane_and_surroundings_left_and_up(&active_pane_id) { + return; + } + if self.try_reduce_pane_and_surroundings_right_and_up(&active_pane_id) { + return; + } + if self.try_reduce_pane_and_surroundings_right_and_down(&active_pane_id) { + return; + } + if self.try_reduce_pane_and_surroundings_left_and_down(&active_pane_id) { + return; + } + if self.try_reduce_pane_and_surroundings_left(&active_pane_id, RESIZE_PERCENT) { + return; + } + if self.try_reduce_pane_and_surroundings_right(&active_pane_id, RESIZE_PERCENT) { + return; + } + if self.try_reduce_pane_and_surroundings_up(&active_pane_id, RESIZE_PERCENT) { + return; + } + self.try_reduce_pane_and_surroundings_down(&active_pane_id, RESIZE_PERCENT); + } + } + pub fn move_focus(&mut self) { if !self.has_selectable_panes() { return; @@ -2420,6 +2776,20 @@ impl Tab { pub fn get_pane_ids(&self) -> Vec { self.get_panes().map(|(&pid, _)| pid).collect() } + fn viewport_pane_ids_directly_above(&self, active_pane_id: &PaneId) -> Vec { + self.pane_ids_directly_above(active_pane_id) + .unwrap_or_default() + .into_iter() + .filter(|id| self.is_inside_viewport(id)) + .collect() + } + fn viewport_pane_ids_directly_below(&self, active_pane_id: &PaneId) -> Vec { + self.pane_ids_directly_below(active_pane_id) + .unwrap_or_default() + .into_iter() + .filter(|id| self.is_inside_viewport(id)) + .collect() + } pub fn set_pane_selectable(&mut self, id: PaneId, selectable: bool) { if let Some(pane) = self.panes.get_mut(&id) { pane.set_selectable(selectable); diff --git a/zellij-server/src/unit/tab_tests.rs b/zellij-server/src/unit/tab_tests.rs index 3d177ab8..ffb87f8d 100644 --- a/zellij-server/src/unit/tab_tests.rs +++ b/zellij-server/src/unit/tab_tests.rs @@ -12387,3 +12387,267 @@ pub fn cannot_resize_up_when_pane_above_is_at_minimum_height() { "pane 2 height stayed the same" ); } + +#[test] +pub fn nondirectional_resize_increase_with_1_pane() { + let size = Size { + cols: 121, + rows: 10, + }; + let mut tab = create_new_tab(size); + tab.resize_increase(); + + assert_eq!( + tab.get_active_pane().unwrap().position_and_size().y, + 0, + "There is only 1 pane so both coordinates should be 0" + ); + + assert_eq!( + tab.get_active_pane().unwrap().position_and_size().x, + 0, + "There is only 1 pane so both coordinates should be 0" + ); +} + +#[test] +pub fn nondirectional_resize_increase_with_1_pane_to_left() { + let size = Size { + cols: 121, + rows: 10, + }; + let mut tab = create_new_tab(size); + let new_pane_id_1 = PaneId::Terminal(2); + tab.vertical_split(new_pane_id_1); + tab.resize_increase(); + + // should behave like `resize_left_with_pane_to_the_left` + assert_eq!( + tab.panes + .get(&PaneId::Terminal(2)) + .unwrap() + .position_and_size() + .x, + 54, + "pane 2 x position" + ); + assert_eq!( + tab.panes + .get(&PaneId::Terminal(2)) + .unwrap() + .position_and_size() + .y, + 0, + "pane 2 y position" + ); +} + +#[test] +pub fn nondirectional_resize_increase_with_2_panes_to_left() { + let size = Size { + cols: 121, + rows: 20, + }; + let mut tab = create_new_tab(size); + tab.vertical_split(PaneId::Terminal(2)); + tab.move_focus_left(); + tab.horizontal_split(PaneId::Terminal(3)); + tab.move_focus_right(); + tab.resize_increase(); + + // should behave like `resize_left_with_multiple_panes_to_the_left` + assert_eq!( + tab.panes + .get(&PaneId::Terminal(2)) + .unwrap() + .position_and_size() + .x, + 54, + "pane 2 x position" + ); + assert_eq!( + tab.panes + .get(&PaneId::Terminal(2)) + .unwrap() + .position_and_size() + .y, + 0, + "pane 2 y position" + ); + assert_eq!( + tab.panes + .get(&PaneId::Terminal(2)) + .unwrap() + .position_and_size() + .cols + .as_usize(), + 67, + "pane 2 column count" + ); + assert_eq!( + tab.panes + .get(&PaneId::Terminal(2)) + .unwrap() + .position_and_size() + .rows + .as_usize(), + 20, + "pane 2 row count" + ); +} + +#[test] +pub fn nondirectional_resize_increase_with_1_pane_to_right_1_pane_above() { + let size = Size { + cols: 121, + rows: 20, + }; + let mut tab = create_new_tab(size); + tab.vertical_split(PaneId::Terminal(2)); + tab.move_focus_left(); + tab.horizontal_split(PaneId::Terminal(3)); + tab.resize_increase(); + + assert_eq!( + tab.panes + .get(&PaneId::Terminal(3)) + .unwrap() + .position_and_size() + .y, + 9, + "Pane 3 y coordinate" + ); + assert_eq!( + tab.panes + .get(&PaneId::Terminal(3)) + .unwrap() + .position_and_size() + .x, + 0, + "Pane 3 x coordinate" + ); + assert_eq!( + tab.panes + .get(&PaneId::Terminal(3)) + .unwrap() + .position_and_size() + .rows + .as_usize(), + 11, + "Pane 3 row count" + ); + assert_eq!( + tab.panes + .get(&PaneId::Terminal(3)) + .unwrap() + .position_and_size() + .cols + .as_usize(), + 67, + "Pane 3 col count" + ); +} + +#[test] +pub fn nondirectional_resize_increase_with_1_pane_to_right_1_pane_to_left() { + let size = Size { + cols: 121, + rows: 20, + }; + let mut tab = create_new_tab(size); + tab.vertical_split(PaneId::Terminal(2)); + tab.vertical_split(PaneId::Terminal(3)); + tab.move_focus_left(); + tab.resize_increase(); + + assert_eq!( + tab.panes + .get(&PaneId::Terminal(2)) + .unwrap() + .position_and_size() + .y, + 0, + "Pane 3 y coordinate" + ); + assert_eq!( + tab.panes + .get(&PaneId::Terminal(2)) + .unwrap() + .position_and_size() + .x, + 61, + "Pane 3 x coordinate" + ); + assert_eq!( + tab.panes + .get(&PaneId::Terminal(2)) + .unwrap() + .position_and_size() + .rows + .as_usize(), + 20, + "Pane 3 row count" + ); + assert_eq!( + tab.panes + .get(&PaneId::Terminal(2)) + .unwrap() + .position_and_size() + .cols + .as_usize(), + 36, + "Pane 3 col count" + ); +} + +#[test] +pub fn nondirectional_resize_increase_with_pane_above_aligned_right_with_current_pane() { + let size = Size { + cols: 121, + rows: 20, + }; + let mut tab = create_new_tab(size); + tab.vertical_split(PaneId::Terminal(2)); + tab.vertical_split(PaneId::Terminal(3)); + tab.move_focus_left(); + tab.resize_increase(); + + assert_eq!( + tab.panes + .get(&PaneId::Terminal(2)) + .unwrap() + .position_and_size() + .y, + 0, + "Pane 3 y coordinate" + ); + assert_eq!( + tab.panes + .get(&PaneId::Terminal(2)) + .unwrap() + .position_and_size() + .x, + 61, + "Pane 3 x coordinate" + ); + assert_eq!( + tab.panes + .get(&PaneId::Terminal(2)) + .unwrap() + .position_and_size() + .rows + .as_usize(), + 20, + "Pane 3 row count" + ); + assert_eq!( + tab.panes + .get(&PaneId::Terminal(2)) + .unwrap() + .position_and_size() + .cols + .as_usize(), + 36, + "Pane 3 col count" + ); +} diff --git a/zellij-utils/assets/config/default.yaml b/zellij-utils/assets/config/default.yaml index 51ef72c2..b1a1ad2e 100644 --- a/zellij-utils/assets/config/default.yaml +++ b/zellij-utils/assets/config/default.yaml @@ -38,6 +38,12 @@ keybinds: key: [ Alt: '[',] - action: [FocusNextPane,] key: [ Alt: ']',] + - action: [Resize: Increase,] + key: [ Alt: '='] + - action: [Resize: Increase,] + key: [ Alt: '+'] + - action: [Resize: Decrease,] + key: [ Alt: '-'] locked: - action: [SwitchToMode: Normal,] key: [Ctrl: 'g',] @@ -66,6 +72,12 @@ keybinds: key: [Char: 'k', Up, ] - action: [Resize: Right,] key: [Char: 'l', Right,] + - action: [Resize: Increase,] + key: [Char: '='] + - action: [Resize: Increase,] + key: [ Alt: '+'] + - action: [Resize: Decrease,] + key: [Char: '-'] - action: [NewPane: ,] key: [ Alt: 'n',] - action: [MoveFocus: Left,] diff --git a/zellij-utils/src/errors.rs b/zellij-utils/src/errors.rs index 401cdc10..a217f56c 100644 --- a/zellij-utils/src/errors.rs +++ b/zellij-utils/src/errors.rs @@ -216,6 +216,8 @@ pub enum ScreenContext { ResizeRight, ResizeDown, ResizeUp, + ResizeIncrease, + ResizeDecrease, SwitchFocus, FocusNextPane, FocusPreviousPane, diff --git a/zellij-utils/src/input/actions.rs b/zellij-utils/src/input/actions.rs index 9dd25958..13d3566d 100644 --- a/zellij-utils/src/input/actions.rs +++ b/zellij-utils/src/input/actions.rs @@ -17,6 +17,16 @@ pub enum Direction { Down, } +#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)] +pub enum ResizeDirection { + Left, + Right, + Up, + Down, + Increase, + Decrease, +} + // As these actions are bound to the default config, please // do take care when refactoring - or renaming. // They might need to be adjusted in the default config @@ -33,7 +43,7 @@ pub enum Action { /// Switch to the specified input mode. SwitchToMode(InputMode), /// Resize focus pane in specified direction. - Resize(Direction), + Resize(ResizeDirection), /// Switch focus to next pane in specified direction. FocusNextPane, FocusPreviousPane, diff --git a/zellij-utils/src/input/mod.rs b/zellij-utils/src/input/mod.rs index 3a26688d..c0a0f1ae 100644 --- a/zellij-utils/src/input/mod.rs +++ b/zellij-utils/src/input/mod.rs @@ -22,7 +22,10 @@ pub fn get_mode_info( ) -> ModeInfo { let keybinds = match mode { InputMode::Normal | InputMode::Locked => Vec::new(), - InputMode::Resize => vec![("←↓↑→".to_string(), "Resize".to_string())], + InputMode::Resize => vec![ + ("←↓↑→".to_string(), "Resize".to_string()), + ("+-".to_string(), "Increase/Decrease size".to_string()), + ], InputMode::Move => vec![ ("←↓↑→".to_string(), "Move".to_string()), ("n/Tab".to_string(), "Next Pane".to_string()),