aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAram Drevekenin <aram@poor.dev>2022-01-03 15:56:41 +0100
committerGitHub <noreply@github.com>2022-01-03 15:56:41 +0100
commit7dad61e529b4a3dfcb413345f1b9bbb0e046e5ed (patch)
tree1eb011545e003681c77df54beb32ff437bb5a9b2
parentdocs(changelog): multi user tab click crash (diff)
downloadsl0ppij-7dad61e529b4a3dfcb413345f1b9bbb0e046e5ed.tar.gz
sl0ppij-7dad61e529b4a3dfcb413345f1b9bbb0e046e5ed.tar.xz
sl0ppij-7dad61e529b4a3dfcb413345f1b9bbb0e046e5ed.zip
refactor(tab): separate concerns (namely move pane positioning actions out of tab) (#985)
* refactor: move resizing methods to pane resizer * refactor: move focus and close methods to pane grid * refactor(tab): move move methods positioning to pane grid * refactor(tab): separate pane resizer from pane grid * style(fmt): make rustfmt happy * style(fmt): make clippy happy
-rw-r--r--zellij-server/src/tab/mod.rs (renamed from zellij-server/src/tab.rs)1830
-rw-r--r--zellij-server/src/tab/pane_grid.rs1745
-rw-r--r--zellij-server/src/tab/pane_resizer.rs (renamed from zellij-server/src/ui/pane_resizer.rs)17
-rw-r--r--zellij-server/src/tab/unit/tab_tests.rs (renamed from zellij-server/src/unit/tab_tests.rs)0
-rw-r--r--zellij-server/src/ui/mod.rs1
5 files changed, 1902 insertions, 1691 deletions
diff --git a/zellij-server/src/tab.rs b/zellij-server/src/tab/mod.rs
index 9aceafd6..247f809c 100644
--- a/zellij-server/src/tab.rs
+++ b/zellij-server/src/tab/mod.rs
@@ -1,11 +1,14 @@
//! `Tab`s holds multiple panes. It tracks their coordinates (x/y) and size,
//! as well as how they should be resized
+mod pane_grid;
+mod pane_resizer;
+
use zellij_utils::position::{Column, Line};
use zellij_utils::{position::Position, serde, zellij_tile};
use crate::ui::pane_boundaries_frame::FrameParams;
-use crate::ui::pane_resizer::PaneResizer;
+use pane_grid::{split, PaneGrid};
use crate::{
os_input_output::ServerOsApi,
@@ -24,7 +27,6 @@ use std::rc::Rc;
use std::sync::mpsc::channel;
use std::time::Instant;
use std::{
- cmp::Reverse,
collections::{BTreeMap, HashMap, HashSet},
str,
};
@@ -34,55 +36,15 @@ use zellij_utils::{
layout::{Direction, Layout, Run},
parse_keys,
},
- pane_size::{Dimension, Offset, PaneGeom, Size, Viewport},
+ pane_size::{Offset, PaneGeom, Size, Viewport},
};
-const CURSOR_HEIGHT_WIDTH_RATIO: usize = 4; // this is not accurate and kind of a magic number, TODO: look into this
-
// FIXME: This should be replaced by `RESIZE_PERCENT` at some point
const MIN_TERMINAL_HEIGHT: usize = 5;
const MIN_TERMINAL_WIDTH: usize = 5;
-const RESIZE_PERCENT: f64 = 5.0;
-
const MAX_PENDING_VTE_EVENTS: usize = 7000;
-type BorderAndPaneIds = (usize, Vec<PaneId>);
-
-fn split(direction: Direction, rect: &PaneGeom) -> Option<(PaneGeom, PaneGeom)> {
- let space = match direction {
- Direction::Vertical => rect.cols,
- Direction::Horizontal => rect.rows,
- };
- if let Some(p) = space.as_percent() {
- let first_rect = match direction {
- Direction::Vertical => PaneGeom {
- cols: Dimension::percent(p / 2.0),
- ..*rect
- },
- Direction::Horizontal => PaneGeom {
- rows: Dimension::percent(p / 2.0),
- ..*rect
- },
- };
- let second_rect = match direction {
- Direction::Vertical => PaneGeom {
- x: first_rect.x + 1,
- cols: first_rect.cols,
- ..*rect
- },
- Direction::Horizontal => PaneGeom {
- y: first_rect.y + 1,
- rows: first_rect.rows,
- ..*rect
- },
- };
- Some((first_rect, second_rect))
- } else {
- None
- }
-}
-
fn pane_content_offset(position_and_size: &PaneGeom, viewport: &Viewport) -> (usize, usize) {
// (columns_offset, rows_offset)
// if the pane is not on the bottom or right edge on the screen, we need to reserve one space
@@ -580,83 +542,43 @@ impl Tab {
if self.fullscreen_is_active {
self.unset_fullscreen();
}
- // TODO: check minimum size of active terminal
-
- let (_largest_terminal_size, terminal_id_to_split) = self.get_panes().fold(
- (0, None),
- |(current_largest_terminal_size, current_terminal_id_to_split),
- id_and_terminal_to_check| {
- let (id_of_terminal_to_check, terminal_to_check) = id_and_terminal_to_check;
- let terminal_size = (terminal_to_check.rows() * CURSOR_HEIGHT_WIDTH_RATIO)
- * terminal_to_check.cols();
- let terminal_can_be_split = terminal_to_check.cols() >= MIN_TERMINAL_WIDTH
- && terminal_to_check.rows() >= MIN_TERMINAL_HEIGHT
- && ((terminal_to_check.cols() > terminal_to_check.min_width() * 2)
- || (terminal_to_check.rows() > terminal_to_check.min_height() * 2));
- if terminal_can_be_split && terminal_size > current_largest_terminal_size {
- (terminal_size, Some(*id_of_terminal_to_check))
- } else {
- (current_largest_terminal_size, current_terminal_id_to_split)
- }
- },
- );
- if terminal_id_to_split.is_none() {
- self.senders
- .send_to_pty(PtyInstruction::ClosePane(pid)) // we can't open this pane, close the pty
- .unwrap();
- return; // likely no terminal large enough to split
- }
- let terminal_id_to_split = terminal_id_to_split.unwrap();
- let next_terminal_position = self.get_next_terminal_position();
- let terminal_to_split = self.panes.get_mut(&terminal_id_to_split).unwrap();
- let terminal_ws = terminal_to_split.position_and_size();
- if terminal_to_split.rows() * CURSOR_HEIGHT_WIDTH_RATIO > terminal_to_split.cols()
- && terminal_to_split.rows() > terminal_to_split.min_height() * 2
- {
- if let PaneId::Terminal(term_pid) = pid {
- if let Some((top_winsize, bottom_winsize)) =
- split(Direction::Horizontal, &terminal_ws)
- {
- let new_terminal = TerminalPane::new(
- term_pid,
- bottom_winsize,
- self.colors,
- next_terminal_position,
- String::new(),
- );
- terminal_to_split.set_geom(top_winsize);
- self.panes.insert(pid, Box::new(new_terminal));
- self.relayout_tab(Direction::Vertical);
- }
- }
- } else if terminal_to_split.cols() > terminal_to_split.min_width() * 2 {
+ let pane_grid = PaneGrid::new(&mut self.panes, self.display_area, self.viewport);
+ let terminal_id_and_split_direction = pane_grid.find_room_for_new_pane();
+ if let Some((terminal_id_to_split, split_direction)) = terminal_id_and_split_direction {
+ let next_terminal_position = self.get_next_terminal_position();
+ let terminal_to_split = self.panes.get_mut(&terminal_id_to_split).unwrap();
+ let terminal_ws = terminal_to_split.position_and_size();
if let PaneId::Terminal(term_pid) = pid {
- if let Some((left_winsize, right_winsize)) =
- split(Direction::Vertical, &terminal_ws)
+ if let Some((first_winsize, second_winsize)) = split(split_direction, &terminal_ws)
{
let new_terminal = TerminalPane::new(
term_pid,
- right_winsize,
+ second_winsize,
self.colors,
next_terminal_position,
String::new(),
);
- terminal_to_split.set_geom(left_winsize);
+ terminal_to_split.set_geom(first_winsize);
self.panes.insert(pid, Box::new(new_terminal));
- self.relayout_tab(Direction::Horizontal);
+ // ¯\_(ツ)_/¯
+ let relayout_direction = match split_direction {
+ Direction::Vertical => Direction::Horizontal,
+ Direction::Horizontal => Direction::Vertical,
+ };
+ self.relayout_tab(relayout_direction);
}
}
- }
- if let Some(client_id) = client_id {
- if self.session_is_mirrored {
- // move all clients
- let connected_clients: Vec<ClientId> =
- self.connected_clients.iter().copied().collect();
- for client_id in connected_clients {
+ if let Some(client_id) = client_id {
+ if self.session_is_mirrored {
+ // move all clients
+ let connected_clients: Vec<ClientId> =
+ self.connected_clients.iter().copied().collect();
+ for client_id in connected_clients {
+ self.active_panes.insert(client_id, pid);
+ }
+ } else {
self.active_panes.insert(client_id, pid);
}
- } else {
- self.active_panes.insert(client_id, pid);
}
}
}
@@ -1133,1147 +1055,11 @@ impl Tab {
.find(|pid| self.panes.get(pid).unwrap().selectable())
.copied()
}
- fn pane_ids_directly_left_of(&self, id: &PaneId) -> Option<Vec<PaneId>> {
- let mut ids = vec![];
- let terminal_to_check = self.panes.get(id).unwrap();
- if terminal_to_check.x() == 0 {
- return None;
- }
- for (&pid, terminal) in self.get_panes() {
- if terminal.x() + terminal.cols() == terminal_to_check.x() {
- ids.push(pid);
- }
- }
- if ids.is_empty() {
- None
- } else {
- Some(ids)
- }
- }
- fn pane_ids_directly_right_of(&self, id: &PaneId) -> Option<Vec<PaneId>> {
- let mut ids = vec![];
- let terminal_to_check = self.panes.get(id).unwrap();
- for (&pid, terminal) in self.get_panes() {
- if terminal.x() == terminal_to_check.x() + terminal_to_check.cols() {
- ids.push(pid);
- }
- }
- if ids.is_empty() {
- None
- } else {
- Some(ids)
- }
- }
- fn pane_ids_directly_below(&self, id: &PaneId) -> Option<Vec<PaneId>> {
- let mut ids = vec![];
- let terminal_to_check = self.panes.get(id).unwrap();
- for (&pid, terminal) in self.get_panes() {
- if terminal.y() == terminal_to_check.y() + terminal_to_check.rows() {
- ids.push(pid);
- }
- }
- if ids.is_empty() {
- None
- } else {
- Some(ids)
- }
- }
- fn pane_ids_directly_above(&self, id: &PaneId) -> Option<Vec<PaneId>> {
- let mut ids = vec![];
- let terminal_to_check = self.panes.get(id).unwrap();
- for (&pid, terminal) in self.get_panes() {
- if terminal.y() + terminal.rows() == terminal_to_check.y() {
- ids.push(pid);
- }
- }
- if ids.is_empty() {
- None
- } else {
- Some(ids)
- }
- }
- fn panes_top_aligned_with_pane(&self, pane: &dyn Pane) -> Vec<&dyn Pane> {
- self.panes
- .keys()
- .map(|t_id| self.panes.get(t_id).unwrap().as_ref())
- .filter(|terminal| terminal.pid() != pane.pid() && terminal.y() == pane.y())
- .collect()
- }
- fn panes_bottom_aligned_with_pane(&self, pane: &dyn Pane) -> Vec<&dyn Pane> {
- self.panes
- .keys()
- .map(|t_id| self.panes.get(t_id).unwrap().as_ref())
- .filter(|terminal| {
- terminal.pid() != pane.pid()
- && terminal.y() + terminal.rows() == pane.y() + pane.rows()
- })
- .collect()
- }
- fn panes_right_aligned_with_pane(&self, pane: &dyn Pane) -> Vec<&dyn Pane> {
- self.panes
- .keys()
- .map(|t_id| self.panes.get(t_id).unwrap().as_ref())
- .filter(|terminal| {
- terminal.pid() != pane.pid()
- && terminal.x() + terminal.cols() == pane.x() + pane.cols()
- })
- .collect()
- }
- fn panes_left_aligned_with_pane(&self, pane: &dyn Pane) -> Vec<&dyn Pane> {
- self.panes
- .keys()
- .map(|t_id| self.panes.get(t_id).unwrap().as_ref())
- .filter(|terminal| terminal.pid() != pane.pid() && terminal.x() == pane.x())
- .collect()
- }
- fn right_aligned_contiguous_panes_above(
- &self,
- id: &PaneId,
- terminal_borders_to_the_right: &HashSet<usize>,
- ) -> BorderAndPaneIds {
- let mut terminals = vec![];
- let terminal_to_check = self
- .panes
- .get(id)
- .expect("terminal id does not exist")
- .as_ref();
- let mut right_aligned_terminals = self.panes_right_aligned_with_pane(terminal_to_check);
- // terminals that are next to each other up to current
- right_aligned_terminals.sort_by_key(|a| Reverse(a.y()));
- for terminal in right_aligned_terminals {
- let terminal_to_check = terminals.last().unwrap_or(&terminal_to_check);
- if terminal.y() + terminal.rows() == terminal_to_check.y() {
- terminals.push(terminal);
- }
- }
- // top-most border aligned with a pane border to the right
- let mut top_resize_border = 0;
- for terminal in &terminals {
- let bottom_terminal_boundary = terminal.y() + terminal.rows();
- if terminal_borders_to_the_right
- .get(&bottom_terminal_boundary)
- .is_some()
- && top_resize_border < bottom_terminal_boundary
- {
- top_resize_border = bottom_terminal_boundary;
- }
- }
- terminals.retain(|terminal| terminal.y() >= top_resize_border);
- // if there are no adjacent panes to resize, we use the border of the main pane we're
- // resizing
- let top_resize_border = if terminals.is_empty() {
- terminal_to_check.y()
- } else {
- top_resize_border
- };
- let terminal_ids: Vec<PaneId> = terminals.iter().map(|t| t.pid()).collect();
- (top_resize_border, terminal_ids)
- }
- fn right_aligned_contiguous_panes_below(
- &self,
- id: &PaneId,
- terminal_borders_to_the_right: &HashSet<usize>,
- ) -> BorderAndPaneIds {
- let mut terminals = vec![];
- let terminal_to_check = self
- .panes
- .get(id)
- .expect("terminal id does not exist")
- .as_ref();
- let mut right_aligned_terminals = self.panes_right_aligned_with_pane(terminal_to_check);
- // terminals that are next to each other up to current
- right_aligned_terminals.sort_by_key(|a| a.y());
- for terminal in right_aligned_terminals {
- let terminal_to_check = terminals.last().unwrap_or(&terminal_to_check);
- if terminal.y() == terminal_to_check.y() + terminal_to_check.rows() {
- terminals.push(terminal);
- }
- }
- // bottom-most border aligned with a pane border to the right
- let mut bottom_resize_border = self.viewport.y + self.viewport.rows;
- for terminal in &terminals {
- let top_terminal_boundary = terminal.y();
- if terminal_borders_to_the_right
- .get(&(top_terminal_boundary))
- .is_some()
- && top_terminal_boundary < bottom_resize_border
- {
- bottom_resize_border = top_terminal_boundary;
- }
- }
- terminals.retain(|terminal| terminal.y() + terminal.rows() <= bottom_resize_border);
- // if there are no adjacent panes to resize, we use the border of the main pane we're
- // resizing
- let bottom_resize_border = if terminals.is_empty() {
- terminal_to_check.y() + terminal_to_check.rows()
- } else {
- bottom_resize_border
- };
- let terminal_ids: Vec<PaneId> = terminals.iter().map(|t| t.pid()).collect();
- (bottom_resize_border, terminal_ids)
- }
- fn left_aligned_contiguous_panes_above(
- &self,
- id: &PaneId,
- terminal_borders_to_the_left: &HashSet<usize>,
- ) -> BorderAndPaneIds {
- let mut terminals = vec![];
- let terminal_to_check = self
- .panes
- .get(id)
- .expect("terminal id does not exist")
- .as_ref();
- let mut left_aligned_terminals = self.panes_left_aligned_with_pane(terminal_to_check);
- // terminals that are next to each other up to current
- left_aligned_terminals.sort_by_key(|a| Reverse(a.y()));
- for terminal in left_aligned_terminals {
- let terminal_to_check = terminals.last().unwrap_or(&terminal_to_check);
- if terminal.y() + terminal.rows() == terminal_to_check.y() {
- terminals.push(terminal);
- }
- }
- // top-most border aligned with a pane border to the right
- let mut top_resize_border = 0;
- for terminal in &terminals {
- let bottom_terminal_boundary = terminal.y() + terminal.rows();
- if terminal_borders_to_the_left
- .get(&bottom_terminal_boundary)
- .is_some()
- && top_resize_border < bottom_terminal_boundary
- {
- top_resize_border = bottom_terminal_boundary;
- }
- }
- terminals.retain(|terminal| terminal.y() >= top_resize_border);
- // if there are no adjacent panes to resize, we use the border of the main pane we're
- // resizing
- let top_resize_border = if terminals.is_empty() {
- terminal_to_check.y()
- } else {
- top_resize_border
- };
- let terminal_ids: Vec<PaneId> = terminals.iter().map(|t| t.pid()).collect();
- (top_resize_border, terminal_ids)
- }
- fn left_aligned_contiguous_panes_below(
- &self,
- id: &PaneId,
- terminal_borders_to_the_left: &HashSet<usize>,
- ) -> BorderAndPaneIds {
- let mut terminals = vec![];
- let terminal_to_check = self
- .panes
- .get(id)
- .expect("terminal id does not exist")
- .as_ref();
- let mut left_aligned_terminals = self.panes_left_aligned_with_pane(terminal_to_check);
- // terminals that are next to each other up to current
- left_aligned_terminals.sort_by_key(|a| a.y());
- for terminal in left_aligned_terminals {
- let terminal_to_check = terminals.last().unwrap_or(&terminal_to_check);
- if terminal.y() == terminal_to_check.y() + terminal_to_check.rows() {
- terminals.push(terminal);
- }
- }
- // bottom-most border aligned with a pane border to the left
- let mut bottom_resize_border = self.viewport.y + self.viewport.rows;
- for terminal in &terminals {
- let top_terminal_boundary = terminal.y();
- if terminal_borders_to_the_left
- .get(&(top_terminal_boundary))
- .is_some()
- && top_terminal_boundary < bottom_resize_border
- {
- bottom_resize_border = top_terminal_boundary;
- }
- }
- terminals.retain(|terminal| {
- // terminal.y() + terminal.rows() < bottom_resize_border
- terminal.y() + terminal.rows() <= bottom_resize_border
- });
- // if there are no adjacent panes to resize, we use the border of the main pane we're
- // resizing
- let bottom_resize_border = if terminals.is_empty() {
- terminal_to_check.y() + terminal_to_check.rows()
- } else {
- bottom_resize_border
- };
- let terminal_ids: Vec<PaneId> = terminals.iter().map(|t| t.pid()).collect();
- (bottom_resize_border, terminal_ids)
- }
- fn top_aligned_contiguous_panes_to_the_left(
- &self,
- id: &PaneId,
- terminal_borders_above: &HashSet<usize>,
- ) -> BorderAndPaneIds {
- let mut terminals = vec![];
- let terminal_to_check = self
- .panes
- .get(id)
- .expect("terminal id does not exist")
- .as_ref();
- let mut top_aligned_terminals = self.panes_top_aligned_with_pane(terminal_to_check);
- // terminals that are next to each other up to current
- top_aligned_terminals.sort_by_key(|a| Reverse(a.x()));
- for terminal in top_aligned_terminals {
- let terminal_to_check = terminals.last().unwrap_or(&terminal_to_check);
- if terminal.x() + terminal.cols() == terminal_to_check.x() {
- terminals.push(terminal);
- }
- }
- // leftmost border aligned with a pane border above
- let mut left_resize_border = 0;
- for terminal in &terminals {
- let right_terminal_boundary = terminal.x() + terminal.cols();
- if terminal_borders_above
- .get(&right_terminal_boundary)
- .is_some()
- && left_resize_border < right_terminal_boundary
- {
- left_resize_border = right_terminal_boundary;
- }
- }
- terminals.retain(|terminal| terminal.x() >= left_resize_border);
- // if there are no adjacent panes to resize, we use the border of the main pane we're
- // resizing
- let left_resize_border = if terminals.is_empty() {
- terminal_to_check.x()
- } else {
- left_resize_border
- };
- let terminal_ids: Vec<PaneId> = terminals.iter().map(|t| t.pid()).collect();
- (left_resize_border, terminal_ids)
- }
- fn top_aligned_contiguous_panes_to_the_right(
- &self,
- id: &PaneId,
- terminal_borders_above: &HashSet<usize>,
- ) -> BorderAndPaneIds {
- let mut terminals = vec![];
- let terminal_to_check = self.panes.get(id).unwrap().as_ref();
- let mut top_aligned_terminals = self.panes_top_aligned_with_pane(terminal_to_check);
- // terminals that are next to each other up to current
- top_aligned_terminals.sort_by_key(|a| a.x());
- for terminal in top_aligned_terminals {
- let terminal_to_check = terminals.last().unwrap_or(&terminal_to_check);
- if terminal.x() == terminal_to_check.x() + terminal_to_check.cols() {
- terminals.push(terminal);
- }
- }
- // rightmost border aligned with a pane border above
- let mut right_resize_border = self.viewport.x + self.viewport.cols;
- for terminal in &terminals {
- let left_terminal_boundary = terminal.x();
- if terminal_borders_above
- .get(&left_terminal_boundary)
- .is_some()
- && right_resize_border > left_terminal_boundary
- {
- right_resize_border = left_terminal_boundary;
- }
- }
- terminals.retain(|terminal| terminal.x() + terminal.cols() <= right_resize_border);
- // if there are no adjacent panes to resize, we use the border of the main pane we're
- // resizing
- let right_resize_border = if terminals.is_empty() {
- terminal_to_check.x() + terminal_to_check.cols()
- } else {
- right_resize_border
- };
- let terminal_ids: Vec<PaneId> = terminals.iter().map(|t| t.pid()).collect();
- (right_resize_border, terminal_ids)
- }
- fn bottom_aligned_contiguous_panes_to_the_left(
- &self,
- id: &PaneId,
- terminal_borders_below: &HashSet<usize>,
- ) -> BorderAndPaneIds {
- let mut terminals = vec![];
- let terminal_to_check = self.panes.get(id).unwrap().as_ref();
- let mut bottom_aligned_terminals = self.panes_bottom_aligned_with_pane(terminal_to_check);
- bottom_aligned_terminals.sort_by_key(|a| Reverse(a.x()));
- // terminals that are next to each other up to current
- for terminal in bottom_aligned_terminals {
- let terminal_to_check = terminals.last().unwrap_or(&terminal_to_check);
- if terminal.x() + terminal.cols() == terminal_to_check.x() {
- terminals.push(terminal);
- }
- }
- // leftmost border aligned with a pane border above
- let mut left_resize_border = 0;
- for terminal in &terminals {
- let right_terminal_boundary = terminal.x() + terminal.cols();
- if terminal_borders_below
- .get(&right_terminal_boundary)
- .is_some()
- && left_resize_border < right_terminal_boundary
- {
- left_resize_border = right_terminal_boundary;
- }
- }
- terminals.retain(|terminal| terminal.x() >= left_resize_border);
- // if there are no adjacent panes to resize, we use the border of the main pane we're
- // resizing
- let left_resize_border = if terminals.is_empty() {
- terminal_to_check.x()
- } else {
- left_resize_border
- };
- let terminal_ids: Vec<PaneId> = terminals.iter().map(|t| t.pid()).collect();
- (left_resize_border, terminal_ids)
- }
- fn bottom_aligned_contiguous_panes_to_the_right(
- &self,
- id: &PaneId,
- terminal_borders_below: &HashSet<usize>,
- ) -> BorderAndPaneIds {
- let mut terminals = vec![];
- let terminal_to_check = self.panes.get(id).unwrap().as_ref();
- let mut bottom_aligned_terminals = self.panes_bottom_aligned_with_pane(terminal_to_check);
- bottom_aligned_terminals.sort_by_key(|a| a.x());
- // terminals that are next to each other up to current
- for terminal in bottom_aligned_terminals {
- let terminal_to_check = terminals.last().unwrap_or(&terminal_to_check);
- if terminal.x() == terminal_to_check.x() + terminal_to_check.cols() {
- terminals.push(terminal);
- }
- }
- // leftmost border aligned with a pane border above
- let mut right_resize_border = self.viewport.x + self.viewport.cols;
- for terminal in &terminals {
- let left_terminal_boundary = terminal.x();
- if terminal_borders_below
- .get(&left_terminal_boundary)
- .is_some()
- && right_resize_border > left_terminal_boundary
- {
- right_resize_border = left_terminal_boundary;
- }
- }
- terminals.retain(|terminal| terminal.x() + terminal.cols() <= right_resize_border);
- let right_resize_border = if terminals.is_empty() {
- terminal_to_check.x() + terminal_to_check.cols()
- } else {
- right_resize_border
- };
- let terminal_ids: Vec<PaneId> = terminals.iter().map(|t| t.pid()).collect();
- (right_resize_border, terminal_ids)
- }
- fn reduce_pane_height(&mut self, id: &PaneId, percent: f64) {
- let terminal = self.panes.get_mut(id).unwrap();
- terminal.reduce_height(percent);
- }
- fn increase_pane_height(&mut self, id: &PaneId, percent: f64) {
- let terminal = self.panes.get_mut(id).unwrap();
- terminal.increase_height(percent);
- }
- fn increase_pane_width(&mut self, id: &PaneId, percent: f64) {
- let terminal = self.panes.get_mut(id).unwrap();
- terminal.increase_width(percent);
- }
- fn reduce_pane_width(&mut self, id: &PaneId, percent: f64) {
- let terminal = self.panes.get_mut(id).unwrap();
- terminal.reduce_width(percent);
- }
- fn pane_is_between_vertical_borders(
- &self,
- id: &PaneId,
- left_border_x: usize,
- right_border_x: usize,
- ) -> bool {
- let terminal = self
- .panes
- .get(id)
- .expect("could not find terminal to check between borders");
- terminal.x() >= left_border_x && terminal.x() + terminal.cols() <= right_border_x
- }
- fn pane_is_between_horizontal_borders(
- &self,
- id: &PaneId,
- top_border_y: usize,
- bottom_border_y: usize,
- ) -> bool {
- let terminal = self
- .panes
- .get(id)
- .expect("could not find terminal to check between borders");
- terminal.y() >= top_border_y && terminal.y() + terminal.rows() <= bottom_border_y
- }
- fn reduce_pane_and_surroundings_up(&mut self, id: &PaneId, percent: f64) {
- let mut terminals_below = self
- .pane_ids_directly_below(id)
- .expect("can't reduce pane size up if there are no terminals below");
- let terminal_borders_below: HashSet<usize> = terminals_below
- .iter()
- .map(|t| self.panes.get(t).unwrap().x())
- .collect();
- let (left_resize_border, terminals_to_the_left) =
- self.bottom_aligned_contiguous_panes_to_the_left(id, &terminal_borders_below);
- let (right_resize_border, terminals_to_the_right) =
- self.bottom_aligned_contiguous_panes_to_the_right(id, &terminal_borders_below);
- terminals_below.retain(|t| {
- self.pane_is_between_vertical_borders(t, left_resize_border, right_resize_border)
- });
-
- // FIXME: This checks that we aren't violating the resize constraints of the aligned panes
- // above and below this one. This should be moved to a `can_resize` function eventually.
- for terminal_id in terminals_to_the_left.iter().chain(&terminals_to_the_right) {
- let pane = self.panes.get(terminal_id).unwrap();
- if pane.current_geom().rows.as_percent().unwrap() - percent < RESIZE_PERCENT {
- return;
- }
- }
-
- self.reduce_pane_height(id, percent);
- for terminal_id in terminals_below {
- self.increase_pane_height(&terminal_id, percent);
- }
- for terminal_id in terminals_to_the_left.iter().chain(&terminals_to_the_right) {
- self.reduce_pane_height(terminal_id, percent);
- }
- }
- fn reduce_pane_and_surroundings_down(&mut self, id: &PaneId, percent: f64) {
- let mut terminals_above = self
- .pane_ids_directly_above(id)
- .expect("can't reduce pane size down if there are no terminals above");
- let terminal_borders_above: HashSet<usize> = terminals_above
- .iter()
- .map(|t| self.panes.get(t).unwrap().x())
- .collect();
- let (left_resize_border, terminals_to_the_left) =
- self.top_aligned_contiguous_panes_to_the_left(id, &terminal_borders_above);
- let (right_resize_border, terminals_to_the_right) =
- self.top_aligned_contiguous_panes_to_the_right(id, &terminal_borders_above);
- terminals_above.retain(|t| {
- self.pane_is_between_vertical_borders(t, left_resize_border, right_resize_border)
- });
-
- // FIXME: This checks that we aren't violating the resize constraints of the aligned panes
- // above and below this one. This should be moved to a `can_resize` function eventually.
- for terminal_id in terminals_to_the_left.iter().chain(&terminals_to_the_right) {
- let pane = self.panes.get(terminal_id).unwrap();
- if pane.current_geom().rows.as_percent().unwrap() - percent < RESIZE_PERCENT {
- return;
- }
- }
-
- self.reduce_pane_height(id, percent);
- for terminal_id in terminals_above {
- self.increase_pane_height(&terminal_id, percent);
- }
- for terminal_id in terminals_to_the_left.iter().chain(&terminals_to_the_right) {
- self.reduce_pane_height(terminal_id, percent);
- }
- }
- fn reduce_pane_and_surroundings_right(&mut self, id: &PaneId, percent: f64) {
- let mut terminals_to_the_left = self
- .pane_ids_directly_left_of(id)
- .expect("can't reduce pane size right if there are no terminals to the left");
- let terminal_borders_to_the_left: HashSet<usize> = terminals_to_the_left
- .iter()
- .map(|t| self.panes.get(t).unwrap().y())
- .collect();
- let (top_resize_border, terminals_above) =
- self.left_aligned_contiguous_panes_above(id, &terminal_borders_to_the_left);
- let (bottom_resize_border, terminals_below) =
- self.left_aligned_contiguous_panes_below(id, &terminal_borders_to_the_left);
- terminals_to_the_left.retain(|t| {
- self.pane_is_between_horizontal_borders(t, top_resize_border, bottom_resize_border)
- });
-
- // FIXME: This checks that we aren't violating the resize constraints of the aligned panes
- // above and below this one. This should be moved to a `can_resize` function eventually.
- for terminal_id in terminals_above.iter().chain(&terminals_below) {
- let pane = self.panes.get(terminal_id).unwrap();
- if pane.current_geom().cols.as_percent().unwrap() - percent < RESIZE_PERCENT {
- return;
- }
- }
-
- self.reduce_pane_width(id, percent);
- for terminal_id in terminals_to_the_left {
- self.increase_pane_width(&terminal_id, percent);
- }
- for terminal_id in terminals_above.iter().chain(&terminals_below) {
- self.reduce_pane_width(terminal_id, percent);
- }
- }
- fn reduce_pane_and_surroundings_left(&mut self, id: &PaneId, percent: f64) {
- let mut terminals_to_the_right = self
- .pane_ids_directly_right_of(id)
- .expect("can't reduce pane size left if there are no terminals to the right");
- let terminal_borders_to_the_right: HashSet<usize> = terminals_to_the_right
- .iter()
- .map(|t| self.panes.get(t).unwrap().y())
- .collect();
- let (top_resize_border, terminals_above) =
- self.right_aligned_contiguous_panes_above(id, &terminal_borders_to_the_right);
- let (bottom_resize_border, terminals_below) =
- self.right_aligned_contiguous_panes_below(id, &terminal_borders_to_the_right);
- terminals_to_the_right.retain(|t| {
- self.pane_is_between_horizontal_borders(t, top_resize_border, bottom_resize_border)
- });
-
- // FIXME: This checks that we aren't violating the resize constraints of the aligned panes
- // above and below this one. This should be moved to a `can_resize` function eventually.
- for terminal_id in terminals_above.iter().chain(&terminals_below) {
- let pane = self.panes.get(terminal_id).unwrap();
- if pane.current_geom().cols.as_percent().unwrap() - percent < RESIZE_PERCENT {
- return;
- }
- }
-
- self.reduce_pane_width(id, percent);
- for terminal_id in terminals_to_the_right {
- self.increase_pane_width(&terminal_id, percent);
- }
- for terminal_id in terminals_above.iter().chain(&terminals_below) {
- self.reduce_pane_width(terminal_id, percent);
- }
- }
- fn increase_pane_and_surroundings_up(&mut self, id: &PaneId, percent: f64) {
- let mut terminals_above = self
- .pane_ids_directly_above(id)
- .expect("can't increase pane size up if there are no terminals above");
- let terminal_borders_above: HashSet<usize> = terminals_above
- .iter()
- .map(|t| self.panes.get(t).unwrap().x())
- .collect();
- let (left_resize_border, terminals_to_the_left) =
- self.top_aligned_contiguous_panes_to_the_left(id, &terminal_borders_above);
- let (right_resize_border, terminals_to_the_right) =
- self.top_aligned_contiguous_panes_to_the_right(id, &terminal_borders_above);
- terminals_above.retain(|t| {
- self.pane_is_between_vertical_borders(t, left_resize_border, right_resize_border)
- });
- self.increase_pane_height(id, percent);
- for terminal_id in terminals_above {
- self.reduce_pane_height(&terminal_id, percent);
- }
- for terminal_id in terminals_to_the_left.iter().chain(&terminals_to_the_right) {
- self.increase_pane_height(terminal_id, percent);
- }
- }
- fn increase_pane_and_surroundings_down(&mut self, id: &PaneId, percent: f64) {
- let mut terminals_below = self
- .pane_ids_directly_below(id)
- .expect("can't increase pane size down if there are no terminals below");
- let terminal_borders_below: HashSet<usize> = terminals_below
- .iter()
- .map(|t| self.panes.get(t).unwrap().x())
- .collect();
- let (left_resize_border, terminals_to_the_left) =
- self.bottom_aligned_contiguous_panes_to_the_left(id, &terminal_borders_below);
- let (right_resize_border, terminals_to_the_right) =
- self.bottom_aligned_contiguous_panes_to_the_right(id, &terminal_borders_below);
- terminals_below.retain(|t| {
- self.pane_is_between_vertical_borders(t, left_resize_border, right_resize_border)
- });
- self.increase_pane_height(id, percent);
- for terminal_id in terminals_below {
- self.reduce_pane_height(&terminal_id, percent);
- }
- for terminal_id in terminals_to_the_left.iter().chain(&terminals_to_the_right) {
- self.increase_pane_height(terminal_id, percent);
- }
- }
- fn increase_pane_and_surroundings_right(&mut self, id: &PaneId, percent: f64) {
- let mut terminals_to_the_right = self
- .pane_ids_directly_right_of(id)
- .expect("can't increase pane size right if there are no terminals to the right");
- let terminal_borders_to_the_right: HashSet<usize> = terminals_to_the_right
- .iter()
- .map(|t| {
- return self.panes.get(t).unwrap().y();
- })
- .collect();
- let (top_resize_border, terminals_above) =
- self.right_aligned_contiguous_panes_above(id, &terminal_borders_to_the_right);
- let (bottom_resize_border, terminals_below) =
- self.right_aligned_contiguous_panes_below(id, &terminal_borders_to_the_right);
- terminals_to_the_right.retain(|t| {
- self.pane_is_between_horizontal_borders(t, top_resize_border, bottom_resize_border)
- });
- self.increase_pane_width(id, percent);
- for terminal_id in terminals_to_the_right {
- self.reduce_pane_width(&terminal_id, percent);
- }
- for terminal_id in terminals_above.iter().chain(&terminals_below) {
- self.increase_pane_width(terminal_id, percent);
- }
- }
- fn increase_pane_and_surroundings_left(&mut self, id: &PaneId, percent: f64) {
- let mut terminals_to_the_left = self
- .pane_ids_directly_left_of(id)
- .expect("can't increase pane size right if there are no terminals to the right");
- let terminal_borders_to_the_left: HashSet<usize> = terminals_to_the_left
- .iter()
- .map(|t| self.panes.get(t).unwrap().y())
- .collect();
- let (top_resize_border, terminals_above) =
- self.left_aligned_contiguous_panes_above(id, &terminal_borders_to_the_left);
- let (bottom_resize_border, terminals_below) =
- self.left_aligned_contiguous_panes_below(id, &terminal_borders_to_the_left);
- terminals_to_the_left.retain(|t| {
- self.pane_is_between_horizontal_borders(t, top_resize_border, bottom_resize_border)
- });
- self.increase_pane_width(id, percent);
- for terminal_id in terminals_to_the_left {
- self.reduce_pane_width(&terminal_id, percent);
- }
- for terminal_id in terminals_above.iter().chain(&terminals_below) {
- self.increase_pane_width(terminal_id, percent);
- }
- }
- // FIXME: The if-let nesting and explicit `false`s are... suboptimal.
- // FIXME: Quite a lot of duplication between these functions...
- fn can_increase_pane_and_surroundings_right(&self, pane_id: &PaneId, increase_by: f64) -> bool {
- if let Some(panes_to_the_right) = self.pane_ids_directly_right_of(pane_id) {
- panes_to_the_right.iter().all(|id| {
- let p = self.panes.get(id).unwrap();
- if let Some(cols) = p.position_and_size().cols.as_percent() {
- let current_fixed_cols = p.position_and_size().cols.as_usize();
- let will_reduce_by =
- ((self.display_area.cols as f64 / 100.0) * increase_by) as usize;
- cols - increase_by >= RESIZE_PERCENT
- && current_fixed_cols.saturating_sub(will_reduce_by) >= p.min_width()
- } else {
- false
- }
- })
- } else {
- false
- }
- }
- fn can_increase_pane_and_surroundings_left(&self, pane_id: &PaneId, increase_by: f64) -> bool {
- if let Some(panes_to_the_left) = self.pane_ids_directly_left_of(pane_id) {
- panes_to_the_left.iter().all(|id| {
- let p = self.panes.get(id).unwrap();
- if let Some(cols) = p.position_and_size().cols.as_percent() {
- let current_fixed_cols = p.position_and_size().cols.as_usize();
- let will_reduce_by =
- ((self.display_area.cols as f64 / 100.0) * increase_by) as usize;
- cols - increase_by >= RESIZE_PERCENT
- && current_fixed_cols.saturating_sub(will_reduce_by) >= p.min_width()
- } else {
- false
- }
- })
- } else {
- false
- }
- }
- fn can_increase_pane_and_surroundings_down(&self, pane_id: &PaneId, increase_by: f64) -> bool {
- if let Some(panes_below) = self.pane_ids_directly_below(pane_id) {
- panes_below.iter().all(|id| {
- let p = self.panes.get(id).unwrap();
- if let Some(rows) = p.position_and_size().rows.as_percent() {
- let current_fixed_rows = p.position_and_size().rows.as_usize();
- let will_reduce_by =
- ((self.display_area.rows as f64 / 100.0) * increase_by) as usize;
- rows - increase_by >= RESIZE_PERCENT
- && current_fixed_rows.saturating_sub(will_reduce_by) >= p.min_height()
- } else {
- false
- }
- })
- } else {
- false
- }
- }
-
- fn can_increase_pane_and_surroundings_up(&self, pane_id: &PaneId, increase_by: f64) -> bool {
- if let Some(panes_above) = self.pane_ids_directly_above(pane_id) {
- panes_above.iter().all(|id| {
- let p = self.panes.get(id).unwrap();
- if let Some(rows) = p.position_and_size().rows.as_percent() {
- let current_fixed_rows = p.position_and_size().rows.as_usize();
- let will_reduce_by =
- ((self.display_area.rows as f64 / 100.0) * increase_by) as usize;
- rows - increase_by >= RESIZE_PERCENT
- && current_fixed_rows.saturating_sub(will_reduce_by) >= p.min_height()
- } else {
- false
- }
- })
- } else {
- false
- }
- }
- fn can_reduce_pane_and_surroundings_right(&self, pane_id: &PaneId, reduce_by: f64) -> bool {
- let pane = self.panes.get(pane_id).unwrap();
- if let Some(cols) = pane.position_and_size().cols.as_percent() {
- let current_fixed_cols = pane.position_and_size().cols.as_usize();
- let will_reduce_by = ((self.display_area.cols as f64 / 100.0) * reduce_by) as usize;
- let ids_left = self.pane_ids_directly_left_of(pane_id);
- let flexible_left = self.ids_are_flexible(Direction::Horizontal, ids_left);
- cols - reduce_by >= RESIZE_PERCENT
- && flexible_left
- && current_fixed_cols.saturating_sub(will_reduce_by) >= pane.min_width()
- } else {
- false
- }
- }
- fn can_reduce_pane_and_surroundings_left(&self, pane_id: &PaneId, reduce_by: f64) -> bool {
- let pane = self.panes.get(pane_id).unwrap();
- if let Some(cols) = pane.position_and_size().cols.as_percent() {
- let current_fixed_cols = pane.position_and_size().cols.as_usize();
- let will_reduce_by = ((self.display_area.cols as f64 / 100.0) * reduce_by) as usize;
- let ids_right = self.pane_ids_directly_right_of(pane_id);
- let flexible_right = self.ids_are_flexible(Direction::Horizontal, ids_right);
- cols - reduce_by >= RESIZE_PERCENT
- && flexible_right
- && current_fixed_cols.saturating_sub(will_reduce_by) >= pane.min_width()
- } else {
- false
- }
- }
- fn can_reduce_pane_and_surroundings_down(&self, pane_id: &PaneId, reduce_by: f64) -> bool {
- let pane = self.panes.get(pane_id).unwrap();
- if let Some(rows) = pane.position_and_size().rows.as_percent() {
- let current_fixed_rows = pane.position_and_size().rows.as_usize();
- let will_reduce_by = ((self.display_area.rows as f64 / 100.0) * reduce_by) as usize;
- let ids_above = self.pane_ids_directly_above(pane_id);
- let flexible_above = self.ids_are_flexible(Direction::Vertical, ids_above);
- rows - reduce_by >= RESIZE_PERCENT
- && flexible_above
- && current_fixed_rows.saturating_sub(will_reduce_by) >= pane.min_height()
- } else {
- false
- }
- }
- fn can_reduce_pane_and_surroundings_up(&self, pane_id: &PaneId, reduce_by: f64) -> bool {
- let pane = self.panes.get(pane_id).unwrap();
- if let Some(rows) = pane.position_and_size().rows.as_percent() {
- let current_fixed_rows = pane.position_and_size().rows.as_usize();
- let will_reduce_by = ((self.display_area.rows as f64 / 100.0) * reduce_by) as usize;
- let ids_below = self.pane_ids_directly_below(pane_id);
- let flexible_below = self.ids_are_flexible(Direction::Vertical, ids_below);
- rows - reduce_by >= RESIZE_PERCENT
- && flexible_below
- && current_fixed_rows.saturating_sub(will_reduce_by) >= pane.min_height()
- } else {
- 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<Vec<PaneId>>) -> bool {
- pane_ids.is_some()
- && pane_ids.unwrap().iter().all(|id| {
- let geom = self.panes[id].current_geom();
- let dimension = match direction {
- Direction::Vertical => geom.rows,
- Direction::Horizontal => geom.cols,
- };
- !dimension.is_fixed()
- })
- }
pub fn relayout_tab(&mut self, direction: Direction) {
- let mut resizer = PaneResizer::new(&mut self.panes);
+ let mut pane_grid = PaneGrid::new(&mut self.panes, self.display_area, self.viewport);
let result = match direction {
- Direction::Horizontal => resizer.layout(direction, self.display_area.cols),
- Direction::Vertical => resizer.layout(direction, self.display_area.rows),
+ Direction::Horizontal => pane_grid.layout(direction, self.display_area.cols),
+ Direction::Vertical => pane_grid.layout(direction, self.display_area.rows),
};
if let Err(e) = &result {
log::error!("{:?} relayout of the tab failed: {}", direction, e);
@@ -2286,8 +1072,8 @@ impl Tab {
.iter_mut()
.filter(|(pid, _)| !self.panes_to_hide.contains(pid));
let Size { rows, cols } = new_screen_size;
- let mut resizer = PaneResizer::new(panes);
- if resizer.layout(Direction::Horizontal, cols).is_ok() {
+ let mut pane_grid = PaneGrid::new(panes, self.display_area, self.viewport);
+ if pane_grid.layout(Direction::Horizontal, cols).is_ok() {
let column_difference = cols as isize - self.display_area.cols as isize;
// FIXME: Should the viewport be an Offset?
self.viewport.cols = (self.viewport.cols as isize + column_difference) as usize;
@@ -2295,7 +1081,7 @@ impl Tab {
} else {
log::error!("Failed to horizontally resize the tab!!!");
}
- if resizer.layout(Direction::Vertical, rows).is_ok() {
+ if pane_grid.layout(Direction::Vertical, rows).is_ok() {
let row_difference = rows as isize - self.display_area.rows as isize;
self.viewport.rows = (self.viewport.rows as isize + row_difference) as usize;
self.display_area.rows = rows;
@@ -2306,100 +1092,60 @@ impl Tab {
self.set_pane_frames(self.draw_pane_frames);
}
pub fn resize_left(&mut self, client_id: ClientId) {
- // TODO: find out by how much we actually reduced and only reduce by that much
+ println!("tab resize_left active_panes: {:?}", self.active_panes);
if let Some(active_pane_id) = self.get_active_pane_id(client_id) {
- if self.can_increase_pane_and_surroundings_left(&active_pane_id, RESIZE_PERCENT) {
- self.increase_pane_and_surroundings_left(&active_pane_id, RESIZE_PERCENT);
- } else if self.can_reduce_pane_and_surroundings_left(&active_pane_id, RESIZE_PERCENT) {
- self.reduce_pane_and_surroundings_left(&active_pane_id, RESIZE_PERCENT);
+ let mut pane_grid = PaneGrid::new(&mut self.panes, self.display_area, self.viewport);
+ pane_grid.resize_pane_left(&active_pane_id);
+ for pane in self.panes.values_mut() {
+ resize_pty!(pane, self.os_api);
}
+ // TODO: can we live without the set_pane_frames we dropped here through layout_tab and in the other
+ // resize methods?
}
- self.relayout_tab(Direction::Horizontal);
}
pub fn resize_right(&mut self, client_id: ClientId) {
- // TODO: find out by how much we actually reduced and only reduce by that much
if let Some(active_pane_id) = self.get_active_pane_id(client_id) {
- if self.can_increase_pane_and_surroundings_right(&active_pane_id, RESIZE_PERCENT) {
- self.increase_pane_and_surroundings_right(&active_pane_id, RESIZE_PERCENT);
- } else if self.can_reduce_pane_and_surroundings_right(&active_pane_id, RESIZE_PERCENT) {
- self.reduce_pane_and_surroundings_right(&active_pane_id, RESIZE_PERCENT);
+ let mut pane_grid = PaneGrid::new(&mut self.panes, self.display_area, self.viewport);
+ pane_grid.resize_pane_right(&active_pane_id);
+ for pane in self.panes.values_mut() {
+ resize_pty!(pane, self.os_api);
}
}
- self.relayout_tab(Direction::Horizontal);
}
pub fn resize_down(&mut self, client_id: ClientId) {
- // TODO: find out by how much we actually reduced and only reduce by that much
if let Some(active_pane_id) = self.get_active_pane_id(client_id) {
- if self.can_increase_pane_and_surroundings_down(&active_pane_id, RESIZE_PERCENT) {
- self.increase_pane_and_surroundings_down(&active_pane_id, RESIZE_PERCENT);
- } else if self.can_reduce_pane_and_surroundings_down(&active_pane_id, RESIZE_PERCENT) {
- self.reduce_pane_and_surroundings_down(&active_pane_id, RESIZE_PERCENT);
+ let mut pane_grid = PaneGrid::new(&mut self.panes, self.display_area, self.viewport);
+ pane_grid.resize_pane_down(&active_pane_id);
+ for pane in self.panes.values_mut() {
+ resize_pty!(pane, self.os_api);
}
}
- self.relayout_tab(Direction::Vertical);
}
pub fn resize_up(&mut self, client_id: ClientId) {
- // TODO: find out by how much we actually reduced and only reduce by that much
if let Some(active_pane_id) = self.get_active_pane_id(client_id) {
- if self.can_increase_pane_and_surroundings_up(&active_pane_id, RESIZE_PERCENT) {
- self.increase_pane_and_surroundings_up(&active_pane_id, RESIZE_PERCENT);
- } else if self.can_reduce_pane_and_surroundings_up(&active_pane_id, RESIZE_PERCENT) {
- self.reduce_pane_and_surroundings_up(&active_pane_id, RESIZE_PERCENT);
+ let mut pane_grid = PaneGrid::new(&mut self.panes, self.display_area, self.viewport);
+ pane_grid.resize_pane_up(&active_pane_id);
+ for pane in self.panes.values_mut() {
+ resize_pty!(pane, self.os_api);
}
}
- self.relayout_tab(Direction::Vertical);
}
pub fn resize_increase(&mut self, client_id: ClientId) {
if let Some(active_pane_id) = self.get_active_pane_id(client_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;
+ let mut pane_grid = PaneGrid::new(&mut self.panes, self.display_area, self.viewport);
+ pane_grid.resize_increase(&active_pane_id);
+ for pane in self.panes.values_mut() {
+ resize_pty!(pane, self.os_api);
}
- self.try_increase_pane_and_surroundings_up(&active_pane_id, RESIZE_PERCENT);
}
}
pub fn resize_decrease(&mut self, client_id: ClientId) {
if let Some(active_pane_id) = self.get_active_pane_id(client_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;
+ let mut pane_grid = PaneGrid::new(&mut self.panes, self.display_area, self.viewport);
+ pane_grid.resize_decrease(&active_pane_id);
+ for pane in self.panes.values_mut() {
+ resize_pty!(pane, self.os_api);
}
- 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);
}
}
@@ -2411,17 +1157,8 @@ impl Tab {
return;
}
let current_active_pane_id = self.get_active_pane_id(client_id).unwrap();
- let pane_ids: Vec<PaneId> = self.get_selectable_panes().map(|(&pid, _)| pid).collect(); // TODO: better, no allocations
- let active_pane_id_position = pane_ids
- .iter()
- .position(|id| id == &current_active_pane_id)
- .unwrap();
- let next_active_pane_id = pane_ids
- .get(active_pane_id_position + 1)
- .or_else(|| pane_ids.get(0))
- .copied()
- .unwrap();
-
+ let pane_grid = PaneGrid::new(&mut self.panes, self.display_area, self.viewport);
+ let next_active_pane_id = pane_grid.next_selectable_pane_id(&current_active_pane_id);
let connected_clients: Vec<ClientId> = self.connected_clients.iter().copied().collect();
for client_id in connected_clients {
self.active_panes.insert(client_id, next_active_pane_id);
@@ -2435,25 +1172,8 @@ impl Tab {
return;
}
let active_pane_id = self.get_active_pane_id(client_id).unwrap();
- let mut panes: Vec<(&PaneId, &Box<dyn Pane>)> = 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 next_active_pane_id = panes
- .get(active_pane_position + 1)
- .or_else(|| panes.get(0))
- .map(|p| *p.0)
- .unwrap();
-
+ let pane_grid = PaneGrid::new(&mut self.panes, self.display_area, self.viewport);
+ let next_active_pane_id = pane_grid.next_selectable_pane_id(&active_pane_id);
let connected_clients: Vec<ClientId> = self.connected_clients.iter().copied().collect();
for client_id in connected_clients {
self.active_panes.insert(client_id, next_active_pane_id);
@@ -2467,25 +1187,8 @@ impl Tab {
return;
}
let active_pane_id = self.get_active_pane_id(client_id).unwrap();
- let mut panes: Vec<(&PaneId, &Box<dyn Pane>)> = 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 last_pane = panes.last().unwrap();
- let active_pane_position = panes
- .iter()
- .position(|(id, _)| *id == &active_pane_id) // TODO: better
- .unwrap();
-
- let next_active_pane_id = if active_pane_position == 0 {
- *last_pane.0
- } else {
- *panes.get(active_pane_position - 1).unwrap().0
- };
+ let pane_grid = PaneGrid::new(&mut self.panes, self.display_area, self.viewport);
+ let next_active_pane_id = pane_grid.previous_selectable_pane_id(&active_pane_id);
let connected_clients: Vec<ClientId> = self.connected_clients.iter().copied().collect();
for client_id in connected_clients {
self.active_panes.insert(client_id, next_active_pane_id);
@@ -2499,18 +1202,12 @@ impl Tab {
if self.fullscreen_is_active {
return false;
}
- let active_pane = self.get_active_pane(client_id);
- let updated_active_pane = if let Some(active) = active_pane {
- let terminals = self.get_selectable_panes();
- let next_index = terminals
- .enumerate()
- .filter(|(_, (_, c))| {
- c.is_directly_left_of(active) && c.horizontally_overlaps_with(active)
- })
- .max_by_key(|(_, (_, c))| c.active_at())
- .map(|(_, (pid, _))| pid);
+ let active_pane_id = self.get_active_pane_id(client_id);
+ let updated_active_pane = if let Some(active_pane_id) = active_pane_id {
+ let pane_grid = PaneGrid::new(&mut self.panes, self.display_area, self.viewport);
+ let next_index = pane_grid.next_selectable_pane_id_to_the_left(&active_pane_id);
match next_index {
- Some(&p) => {
+ Some(p) => {
// render previously active pane so that its frame does not remain actively
// colored
let previously_active_pane = self
@@ -2542,10 +1239,10 @@ impl Tab {
return true;
}
- None => Some(active.pid()),
+ None => Some(active_pane_id),
}
} else {
- Some(active_pane.unwrap().pid())
+ active_pane_id
};
match updated_active_pane {
Some(updated_active_pane) => {
@@ -2570,18 +1267,12 @@ impl Tab {
if self.fullscreen_is_active {
return;
}
- let active_pane = self.get_active_pane(client_id);
- let updated_active_pane = if let Some(active) = active_pane {
- let panes = self.get_selectable_panes();
- let next_index = panes
- .enumerate()
- .filter(|(_, (_, c))| {
- c.is_directly_below(active) && c.vertically_overlaps_with(active)
- })
- .max_by_key(|(_, (_, c))| c.active_at())
- .map(|(_, (pid, _))| pid);
+ let active_pane_id = self.get_active_pane_id(client_id);
+ let updated_active_pane = if let Some(active_pane_id) = active_pane_id {
+ let pane_grid = PaneGrid::new(&mut self.panes, self.display_area, self.viewport);
+ let next_index = pane_grid.next_selectable_pane_id_below(&active_pane_id);
match next_index {
- Some(&p) => {
+ Some(p) => {
// render previously active pane so that its frame does not remain actively
// colored
let previously_active_pane = self
@@ -2600,10 +1291,10 @@ impl Tab {
Some(p)
}
- None => Some(active.pid()),
+ None => Some(active_pane_id),
}
} else {
- Some(active_pane.unwrap().pid())
+ active_pane_id
};
match updated_active_pane {
Some(updated_active_pane) => {
@@ -2631,18 +1322,12 @@ impl Tab {
if self.fullscreen_is_active {
return;
}
- let active_pane = self.get_active_pane(client_id);
- let updated_active_pane = if let Some(active) = active_pane {
- let terminals = self.get_selectable_panes();
- let next_index = terminals
- .enumerate()
- .filter(|(_, (_, c))| {
- c.is_directly_above(active) && c.vertically_overlaps_with(active)
- })
- .max_by_key(|(_, (_, c))| c.active_at())
- .map(|(_, (pid, _))| pid);
+ let active_pane_id = self.get_active_pane_id(client_id);
+ let updated_active_pane = if let Some(active_pane_id) = active_pane_id {
+ let pane_grid = PaneGrid::new(&mut self.panes, self.display_area, self.viewport);
+ let next_index = pane_grid.next_selectable_pane_id_above(&active_pane_id);
match next_index {
- Some(&p) => {
+ Some(p) => {
// render previously active pane so that its frame does not remain actively
// colored
let previously_active_pane = self
@@ -2661,10 +1346,10 @@ impl Tab {
Some(p)
}
- None => Some(active.pid()),
+ None => Some(active_pane_id),
}
} else {
- Some(active_pane.unwrap().pid())
+ active_pane_id
};
match updated_active_pane {
Some(updated_active_pane) => {
@@ -2693,18 +1378,12 @@ impl Tab {
if self.fullscreen_is_active {
return false;
}
- let active_pane = self.get_active_pane(client_id);
- let updated_active_pane = if let Some(active) = active_pane {
- let terminals = self.get_selectable_panes();
- let next_index = terminals
- .enumerate()
- .filter(|(_, (_, c))| {
- c.is_directly_right_of(active) && c.horizontally_overlaps_with(active)
- })
- .max_by_key(|(_, (_, c))| c.active_at())
- .map(|(_, (pid, _))| pid);
+ let active_pane_id = self.get_active_pane_id(client_id);
+ let updated_active_pane = if let Some(active_pane_id) = active_pane_id {
+ let pane_grid = PaneGrid::new(&mut self.panes, self.display_area, self.viewport);
+ let next_index = pane_grid.next_selectable_pane_id_to_the_right(&active_pane_id);
match next_index {
- Some(&p) => {
+ Some(p) => {
// render previously active pane so that its frame does not remain actively
// colored
let previously_active_pane = self
@@ -2733,10 +1412,10 @@ impl Tab {
}
return true;
}
- None => Some(active.pid()),
+ None => Some(active_pane_id),
}
} else {
- Some(active_pane.unwrap().pid())
+ active_pane_id
};
match updated_active_pane {
Some(updated_active_pane) => {
@@ -2766,47 +1445,29 @@ impl Tab {
return;
}
let active_pane_id = self.get_active_pane_id(client_id).unwrap();
- let mut panes: Vec<(&PaneId, &Box<dyn Pane>)> = 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 pane_grid = PaneGrid::new(&mut self.panes, self.display_area, self.viewport);
+ let new_position_id = pane_grid.next_selectable_pane_id(&active_pane_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 new_position = self.panes.get_mut(&new_position_id).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);
+ 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, client_id: ClientId) {
if !self.has_selectable_panes() {
@@ -2815,16 +1476,10 @@ impl Tab {
if self.fullscreen_is_active {
return;
}
- if let Some(active) = self.get_active_pane(client_id) {
- let terminals = self.get_selectable_panes();
- let next_index = terminals
- .enumerate()
- .filter(|(_, (_, c))| {
- c.is_directly_below(active) && c.vertically_overlaps_with(active)
- })
- .max_by_key(|(_, (_, c))| c.active_at())
- .map(|(_, (pid, _))| pid);
- if let Some(&p) = next_index {
+ if let Some(active_pane_id) = self.get_active_pane_id(client_id) {
+ let pane_grid = PaneGrid::new(&mut self.panes, self.display_area, self.viewport);
+ let next_index = pane_grid.next_selectable_pane_id_below(&active_pane_id);
+ if let Some(p) = next_index {
let active_pane_id = self.active_panes.get(&client_id).unwrap();
let current_position = self.panes.get(active_pane_id).unwrap();
let prev_geom = current_position.position_and_size();
@@ -2857,16 +1512,10 @@ impl Tab {
if self.fullscreen_is_active {
return;
}
- if let Some(active) = self.get_active_pane(client_id) {
- let terminals = self.get_selectable_panes();
- let next_index = terminals
- .enumerate()
- .filter(|(_, (_, c))| {
- c.is_directly_above(active) && c.vertically_overlaps_with(active)
- })
- .max_by_key(|(_, (_, c))| c.active_at())
- .map(|(_, (pid, _))| pid);
- if let Some(&p) = next_index {
+ if let Some(active_pane_id) = self.get_active_pane_id(client_id) {
+ let pane_grid = PaneGrid::new(&mut self.panes, self.display_area, self.viewport);
+ let next_index = pane_grid.next_selectable_pane_id_above(&active_pane_id);
+ if let Some(p) = next_index {
let active_pane_id = self.active_panes.get(&client_id).unwrap();
let current_position = self.panes.get(active_pane_id).unwrap();
let prev_geom = current_position.position_and_size();
@@ -2899,16 +1548,10 @@ impl Tab {
if self.fullscreen_is_active {
return;
}
- if let Some(active) = self.get_active_pane(client_id) {
- let terminals = self.get_selectable_panes();
- let next_index = terminals
- .enumerate()
- .filter(|(_, (_, c))| {
- c.is_directly_right_of(active) && c.horizontally_overlaps_with(active)
- })
- .max_by_key(|(_, (_, c))| c.active_at())
- .map(|(_, (pid, _))| pid);
- if let Some(&p) = next_index {
+ if let Some(active_pane_id) = self.get_active_pane_id(client_id) {
+ let pane_grid = PaneGrid::new(&mut self.panes, self.display_area, self.viewport);
+ let next_index = pane_grid.next_selectable_pane_id_to_the_right(&active_pane_id);
+ if let Some(p) = next_index {
let active_pane_id = self.active_panes.get(&client_id).unwrap();
let current_position = self.panes.get(active_pane_id).unwrap();
let prev_geom = current_position.position_and_size();
@@ -2941,16 +1584,10 @@ impl Tab {
if self.fullscreen_is_active {
return;
}
- if let Some(active) = self.get_active_pane(client_id) {
- let terminals = self.get_selectable_panes();
- let next_index = terminals
- .enumerate()
- .filter(|(_, (_, c))| {
- c.is_directly_left_of(active) && c.horizontally_overlaps_with(active)
- })
- .max_by_key(|(_, (_, c))| c.active_at())
- .map(|(_, (pid, _))| pid);
- if let Some(&p) = next_index {
+ if let Some(active_pane_id) = self.get_active_pane_id(client_id) {
+ let pane_grid = PaneGrid::new(&mut self.panes, self.display_area, self.viewport);
+ let next_index = pane_grid.next_selectable_pane_id_to_the_left(&active_pane_id);
+ if let Some(p) = next_index {
let active_pane_id = self.active_panes.get(&client_id).unwrap();
let current_position = self.panes.get(active_pane_id).unwrap();
let prev_geom = current_position.position_and_size();
@@ -2976,131 +1613,6 @@ impl Tab {
}
}
}
- fn horizontal_borders(&self, terminals: &[PaneId]) -> HashSet<usize> {
- terminals.iter().fold(HashSet::new(), |mut borders, t| {
- let terminal = self.panes.get(t).unwrap();
- borders.insert(terminal.y());
- borders.insert(terminal.y() + terminal.rows());
- borders
- })
- }
- fn vertical_borders(&self, terminals: &[PaneId]) -> HashSet<usize> {
- terminals.iter().fold(HashSet::new(), |mut borders, t| {
- let terminal = self.panes.get(t).unwrap();
- borders.insert(terminal.x());
- borders.insert(terminal.x() + terminal.cols());
- borders
- })
- }
-
- fn panes_to_the_left_between_aligning_borders(&self, id: PaneId) -> Option<Vec<PaneId>> {
- if let Some(terminal) = self.panes.get(&id) {
- let upper_close_border = terminal.y();
- let lower_close_border = terminal.y() + terminal.rows();
-
- if let Some(terminals_to_the_left) = self.pane_ids_directly_left_of(&id) {
- let mut selectable_panes: Vec<_> = terminals_to_the_left
- .into_iter()
- .filter(|pid| self.panes[pid].selectable())
- .collect();
- let terminal_borders_to_the_left = self.horizontal_borders(&selectable_panes);
- if terminal_borders_to_the_left.contains(&upper_close_border)
- && terminal_borders_to_the_left.contains(&lower_close_border)
- {
- selectable_panes.retain(|t| {
- self.pane_is_between_horizontal_borders(
- t,
- upper_close_border,
- lower_close_border,
- )
- });
- return Some(selectable_panes);
- }
- }
- }
- None
- }
- fn panes_to_the_right_between_aligning_borders(&self, id: PaneId) -> Option<Vec<PaneId>> {
- if let Some(terminal) = self.panes.get(&id) {
- let upper_close_border = terminal.y();
- let lower_close_border = terminal.y() + terminal.rows();
-
- if let Some(terminals_to_the_right) = self.pane_ids_directly_right_of(&id) {
- let mut selectable_panes: Vec<_> = terminals_to_the_right
- .into_iter()
- .filter(|pid| self.panes[pid].selectable())
- .collect();
- let terminal_borders_to_the_right = self.horizontal_borders(&selectable_panes);
- if terminal_borders_to_the_right.contains(&upper_close_border)
- && terminal_borders_to_the_right.contains(&lower_close_border)
- {
- selectable_panes.retain(|t| {
- self.pane_is_between_horizontal_borders(
- t,
- upper_close_border,
- lower_close_border,
- )
- });
- return Some(selectable_panes);
- }
- }
- }
- None
- }
- fn panes_above_between_aligning_borders(&self, id: PaneId) -> Option<Vec<PaneId>> {
- if let Some(terminal) = self.panes.get(&id) {
- let left_close_border = terminal.x();
- let right_close_border = terminal.x() + terminal.cols();
-
- if let Some(terminals_above) = self.pane_ids_directly_above(&id) {
- let mut selectable_panes: Vec<_> = terminals_above
- .into_iter()
- .filter(|pid| self.panes[pid].selectable())
- .collect();
- let terminal_borders_above = self.vertical_borders(&selectable_panes);
- if terminal_borders_above.contains(&left_close_border)
- && terminal_borders_above.contains(&right_close_border)
- {
- selectable_panes.retain(|t| {
- self.pane_is_between_vertical_borders(
- t,
- left_close_border,
- right_close_border,
- )
- });
- return Some(selectable_panes);
- }
- }
- }
- None
- }
- fn panes_below_between_aligning_borders(&self, id: PaneId) -> Option<Vec<PaneId>> {
- if let Some(terminal) = self.panes.get(&id) {
- let left_close_border = terminal.x();
- let right_close_border = terminal.x() + terminal.cols();
-
- if let Some(terminals_below) = self.pane_ids_directly_below(&id) {
- let mut selectable_panes: Vec<_> = terminals_below
- .into_iter()
- .filter(|pid| self.panes[pid].selectable())
- .collect();
- let terminal_borders_below = self.vertical_borders(&selectable_panes);
- if terminal_borders_below.contains(&left_close_border)
- && terminal_borders_below.contains(&right_close_border)
- {
- selectable_panes.retain(|t| {
- self.pane_is_between_vertical_borders(
- t,
- left_close_border,
- right_close_border,
- )
- });
- return Some(selectable_panes);
- }
- }
- }
- None
- }
fn close_down_to_max_terminals(&mut self) {
if let Some(max_panes) = self.max_panes {
let terminals = self.get_pane_ids();
@@ -3115,20 +1627,6 @@ impl Tab {
pub fn get_pane_ids(&self) -> Vec<PaneId> {
self.get_panes().map(|(&pid, _)| pid).collect()
}
- fn viewport_pane_ids_directly_above(&self, active_pane_id: &PaneId) -> Vec<PaneId> {
- 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<PaneId> {
- 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);
@@ -3167,58 +1665,22 @@ impl Tab {
if self.fullscreen_is_active {
self.unset_fullscreen();
}
- if let Some(pane_to_close) = self.panes.get(&id) {
- let freed_space = pane_to_close.position_and_size();
- if let (Some(freed_width), Some(freed_height)) =
- (freed_space.cols.as_percent(), freed_space.rows.as_percent())
- {
- if let Some((panes, direction)) = self.find_panes_to_grow(id) {
- self.grow_panes(&panes, direction, (freed_width, freed_height));
- let pane = self.panes.remove(&id);
- self.move_clients_out_of_pane(id);
- self.relayout_tab(direction);
- return pane;
- }
+ let mut pane_grid = PaneGrid::new(&mut self.panes, self.display_area, self.viewport);
+ if pane_grid.fill_space_over_pane(id) {
+ // successfully filled space over pane
+ let closed_pane = self.panes.remove(&id);
+ self.move_clients_out_of_pane(id);
+ for pane in self.panes.values_mut() {
+ resize_pty!(pane, self.os_api);
}
- // if we reached here, this is either the last pane or there's some sort of
- // configuration error (eg. we're trying to close a pane surrounded by fixed panes)
- let pane = self.panes.remove(&id);
+ closed_pane
+ } else {
+ self.panes.remove(&id);
+ // this is a bit of a roundabout way to say: this is the last pane and so the tab
+ // should be destroyed
self.active_panes.clear();
- self.resize_whole_tab(self.display_area);
- return pane;
- }
- None
- }
- fn find_panes_to_grow(&self, id: PaneId) -> Option<(Vec<PaneId>, Direction)> {
- if let Some(panes) = self
- .panes_to_the_left_between_aligning_borders(id)
- .or_else(|| self.panes_to_the_right_between_aligning_borders(id))
- {
- return Some((panes, Direction::Horizontal));
- }
-
- if let Some(panes) = self
- .panes_above_between_aligning_borders(id)
- .or_else(|| self.panes_below_between_aligning_borders(id))
- {
- return Some((panes, Direction::Vertical));
+ None
}
-
- None
- }
- fn grow_panes(&mut self, panes: &[PaneId], direction: Direction, (width, height): (f64, f64)) {
- match direction {
- Direction::Horizontal => {
- for pane_id in panes {
- self.increase_pane_width(pane_id, width);
- }
- }
- Direction::Vertical => {
- for pane_id in panes {
- self.increase_pane_height(pane_id, height);
- }
- }
- };
}
pub fn close_focused_pane(&mut self, client_id: ClientId) {
if let Some(active_pane_id) = self.get_active_pane_id(client_id) {
@@ -3543,7 +2005,7 @@ impl Tab {
}
#[allow(clippy::borrowed_box)]
-fn is_inside_viewport(viewport: &Viewport, pane: &Box<dyn Pane>) -> bool {
+pub fn is_inside_viewport(viewport: &Viewport, pane: &Box<dyn Pane>) -> bool {
let pane_position_and_size = pane.current_geom();
pane_position_and_size.y >= viewport.y
&& pane_position_and_size.y + pane_position_and_size.rows.as_usize()
diff --git a/zellij-server/src/tab/pane_grid.rs b/zellij-server/src/tab/pane_grid.rs
new file mode 100644
index 00000000..e1e2cbeb
--- /dev/null
+++ b/zellij-server/src/tab/pane_grid.rs
@@ -0,0 +1,1745 @@
+use super::pane_resizer::PaneResizer;
+use crate::tab::is_inside_viewport;
+use crate::{panes::PaneId, tab::Pane};
+use std::cmp::Reverse;
+use std::collections::{HashMap, HashSet};
+use zellij_utils::{
+ input::layout::Direction,
+ pane_size::{Dimension, PaneGeom, Size, Viewport},
+};
+
+use std::cell::RefCell;
+use std::rc::Rc;
+
+const RESIZE_PERCENT: f64 = 5.0;
+const CURSOR_HEIGHT_WIDTH_RATIO: usize = 4; // this is not accurate and kind of a magic number, TODO: look into this
+
+// FIXME: This should be replaced by `RESIZE_PERCENT` at some point
+const MIN_TERMINAL_HEIGHT: usize = 5;
+const MIN_TERMINAL_WIDTH: usize = 5;
+type BorderAndPaneIds = (usize, Vec<PaneId>);
+
+pub struct PaneGrid<'a> {
+ // panes: HashMap<&'a PaneId, &'a mut Box<dyn Pane>>,
+ panes: Rc<RefCell<HashMap<PaneId, &'a mut Box<dyn Pane>>>>,
+ display_area: Size, // includes all panes (including eg. the status bar and tab bar in the default layout)
+ viewport: Viewport, // includes all non-UI panes
+}
+
+impl<'a> PaneGrid<'a> {
+ pub fn new(
+ panes: impl IntoIterator<Item = (&'a PaneId, &'a mut Box<dyn Pane>)>,
+ display_area: Size,
+ viewport: Viewport,
+ ) -> Self {
+ let panes: HashMap<_, _> = panes.into_iter().map(|(p_id, p)| (*p_id, p)).collect();
+ PaneGrid {
+ panes: Rc::new(RefCell::new(panes)),
+ display_area,
+ viewport,
+ }
+ }
+
+ pub fn layout(&mut self, direction: Direction, space: usize) -> Result<(), String> {
+ let mut pane_resizer = PaneResizer::new(self.panes.clone());
+ pane_resizer.layout(direction, space)
+ }
+ pub fn resize_pane_left(&'a mut self, pane_id: &PaneId) {
+ // TODO: find out by how much we actually reduced and only reduce by that much
+ if self.can_increase_pane_and_surroundings_left(pane_id, RESIZE_PERCENT) {
+ self.increase_pane_and_surroundings_left(pane_id, RESIZE_PERCENT);
+ // let mut pane_resizer = PaneResizer::new(self.panes.clone());
+ let mut pane_resizer = PaneResizer::new(self.panes.clone());
+ let _ = pane_resizer.layout(Direction::Horizontal, self.display_area.cols);
+ } else if self.can_reduce_pane_and_surroundings_left(pane_id, RESIZE_PERCENT) {
+ self.reduce_pane_and_surroundings_left(pane_id, RESIZE_PERCENT);
+ let mut pane_resizer = PaneResizer::new(self.panes.clone());
+ let _ = pane_resizer.layout(Direction::Horizontal, self.display_area.cols);
+ }
+ }
+ pub fn resize_pane_right(&mut self, pane_id: &PaneId) {
+ // TODO: find out by how much we actually reduced and only reduce by that much
+ if self.can_increase_pane_and_surroundings_right(pane_id, RESIZE_PERCENT) {
+ self.increase_pane_and_surroundings_right(pane_id, RESIZE_PERCENT);
+ // TODO: CONTINUE HERE - fix these to self.panes.clone() - then fix the rest of the
+ // functions to match, those functions that break out of the RC (eg. return panes) make
+ // return pane ids and handle them in function, a little work, but eh - we'll get
+ // through it!
+ let mut pane_resizer = PaneResizer::new(self.panes.clone());
+ let _ = pane_resizer.layout(Direction::Horizontal, self.display_area.cols);
+ } else if self.can_reduce_pane_and_surroundings_right(pane_id, RESIZE_PERCENT) {
+ self.reduce_pane_and_surroundings_right(pane_id, RESIZE_PERCENT);
+ let mut pane_resizer = PaneResizer::new(self.panes.clone());
+ let _ = pane_resizer.layout(Direction::Horizontal, self.display_area.cols);
+ }
+ }
+ pub fn resize_pane_down(&mut self, pane_id: &PaneId) {
+ // TODO: find out by how much we actually reduced and only reduce by that much
+ if self.can_increase_pane_and_surroundings_down(pane_id, RESIZE_PERCENT) {
+ self.increase_pane_and_surroundings_down(pane_id, RESIZE_PERCENT);
+ let mut pane_resizer = PaneResizer::new(self.panes.clone());
+ let _ = pane_resizer.layout(Direction::Vertical, self.display_area.rows);
+ } else if self.can_reduce_pane_and_surroundings_down(pane_id, RESIZE_PERCENT) {
+ self.reduce_pane_and_surroundings_down(pane_id, RESIZE_PERCENT);
+ let mut pane_resizer = PaneResizer::new(self.panes.clone());
+ let _ = pane_resizer.layout(Direction::Vertical, self.display_area.rows);
+ }
+ }
+ pub fn resize_pane_up(&mut self, pane_id: &PaneId) {
+ // TODO: find out by how much we actually reduced and only reduce by that much
+ if self.can_increase_pane_and_surroundings_up(pane_id, RESIZE_PERCENT) {
+ self.increase_pane_and_surroundings_up(pane_id, RESIZE_PERCENT);
+ let mut pane_resizer = PaneResizer::new(self.panes.clone());
+ let _ = pane_resizer.layout(Direction::Vertical, self.display_area.rows);
+ } else if self.can_reduce_pane_and_surroundings_up(pane_id, RESIZE_PERCENT) {
+ self.reduce_pane_and_surroundings_up(pane_id, RESIZE_PERCENT);
+ let mut pane_resizer = PaneResizer::new(self.panes.clone());
+ let _ = pane_resizer.layout(Direction::Vertical, self.display_area.rows);
+ }
+ }
+ pub fn resize_increase(&mut self, pane_id: &PaneId) {
+ if self.try_increase_pane_and_surroundings_right_and_down(pane_id) {
+ return;
+ }
+ if self.try_increase_pane_and_surroundings_left_and_down(pane_id) {
+ return;
+ }
+ if self.try_increase_pane_and_surroundings_right_and_up(pane_id) {
+ return;
+ }
+ if self.try_increase_pane_and_surroundings_left_and_up(pane_id) {
+ return;
+ }
+
+ if self.try_increase_pane_and_surroundings_right(pane_id, RESIZE_PERCENT) {
+ return;
+ }
+ if self.try_increase_pane_and_surroundings_down(pane_id, RESIZE_PERCENT) {
+ return;
+ }
+ if self.try_increase_pane_and_surroundings_left(pane_id, RESIZE_PERCENT) {
+ return;
+ }
+ self.try_increase_pane_and_surroundings_up(pane_id, RESIZE_PERCENT);
+ }
+ pub fn resize_decrease(&mut self, pane_id: &PaneId) {
+ if self.try_reduce_pane_and_surroundings_left_and_up(pane_id) {
+ return;
+ }
+ if self.try_reduce_pane_and_surroundings_right_and_up(pane_id) {
+ return;
+ }
+ if self.try_reduce_pane_and_surroundings_right_and_down(pane_id) {
+ return;
+ }
+ if self.try_reduce_pane_and_surroundings_left_and_down(pane_id) {
+ return;
+ }
+ if self.try_reduce_pane_and_surroundings_left(pane_id, RESIZE_PERCENT) {
+ return;
+ }
+ if self.try_reduce_pane_and_surroundings_right(pane_id, RESIZE_PERCENT) {
+ return;
+ }
+ if self.try_reduce_pane_and_surroundings_up(pane_id, RESIZE_PERCENT) {
+ return;
+ }
+ self.try_reduce_pane_and_surroundings_down(pane_id, RESIZE_PERCENT);
+ }
+ fn can_increase_pane_and_surroundings_right(&self, pane_id: &PaneId, increase_by: f64) -> bool {
+ let panes = self.panes.borrow();
+ if let Some(panes_to_the_right) = self.pane_ids_directly_right_of(pane_id) {
+ panes_to_the_right.iter().all(|id| {
+ let p = panes.get(id).unwrap();
+ if let Some(cols) = p.position_and_size().cols.as_percent() {
+ let current_fixed_cols = p.position_and_size().cols.as_usize();
+ let will_reduce_by =
+ ((self.display_area.cols as f64 / 100.0) * increase_by) as usize;
+ cols - increase_by >= RESIZE_PERCENT
+ && current_fixed_cols.saturating_sub(will_reduce_by) >= p.min_width()
+ } else {
+ false
+ }
+ })
+ } else {
+ false
+ }
+ }
+ fn can_increase_pane_and_surroundings_left(&self, pane_id: &PaneId, increase_by: f64) -> bool {
+ let panes = self.panes.borrow();
+ if let Some(panes_to_the_left) = self.pane_ids_directly_left_of(pane_id) {
+ panes_to_the_left.iter().all(|id| {
+ let p = panes.get(id).unwrap();
+ if let Some(cols) = p.position_and_size().cols.as_percent() {
+ let current_fixed_cols = p.position_and_size().cols.as_usize();
+ let will_reduce_by =
+ ((self.display_area.cols as f64 / 100.0) * increase_by) as usize;
+ cols - increase_by >= RESIZE_PERCENT
+ && current_fixed_cols.saturating_sub(will_reduce_by) >= p.min_width()
+ } else {
+ false
+ }
+ })
+ } else {
+ false
+ }
+ }
+ fn can_increase_pane_and_surroundings_down(&self, pane_id: &PaneId, increase_by: f64) -> bool {
+ let panes = self.panes.borrow();
+ if let Some(panes_below) = self.pane_ids_directly_below(pane_id) {
+ panes_below.iter().all(|id| {
+ let p = panes.get(id).unwrap();
+ if let Some(rows) = p.position_and_size().rows.as_percent() {
+ let current_fixed_rows = p.position_and_size().rows.as_usize();
+ let will_reduce_by =
+ ((self.display_area.rows as f64 / 100.0) * increase_by) as usize;
+ rows - increase_by >= RESIZE_PERCENT
+ && current_fixed_rows.saturating_sub(will_reduce_by) >= p.min_height()
+ } else {
+ false
+ }
+ })
+ } else {
+ false
+ }
+ }
+
+ fn can_increase_pane_and_surroundings_up(&self, pane_id: &PaneId, increase_by: f64) -> bool {
+ let panes = self.panes.borrow();
+ if let Some(panes_above) = self.pane_ids_directly_above(pane_id) {
+ panes_above.iter().all(|id| {
+ let p = panes.get(id).unwrap();
+ if let Some(rows) = p.position_and_size().rows.as_percent() {
+ let current_fixed_rows = p.position_and_size().rows.as_usize();
+ let will_reduce_by =
+ ((self.display_area.rows as f64 / 100.0) * increase_by) as usize;
+ rows - increase_by >= RESIZE_PERCENT
+ && current_fixed_rows.saturating_sub(will_reduce_by) >= p.min_height()
+ } else {
+ false
+ }
+ })
+ } else {
+ false
+ }
+ }
+ fn can_reduce_pane_and_surroundings_right(&self, pane_id: &PaneId, reduce_by: f64) -> bool {
+ let panes = self.panes.borrow();
+ let pane = panes.get(pane_id).unwrap();
+ if let Some(cols) = pane.position_and_size().cols.as_percent() {
+ let current_fixed_cols = pane.position_and_size().cols.as_usize();
+ let will_reduce_by = ((self.display_area.cols as f64 / 100.0) * reduce_by) as usize;
+ let ids_left = self.pane_ids_directly_left_of(pane_id);
+ let flexible_left = self.ids_are_flexible(Direction::Horizontal, ids_left);
+ cols - reduce_by >= RESIZE_PERCENT
+ && flexible_left
+ && current_fixed_cols.saturating_sub(will_reduce_by) >= pane.min_width()
+ } else {
+ false
+ }
+ }
+ fn can_reduce_pane_and_surroundings_left(&self, pane_id: &PaneId, reduce_by: f64) -> bool {
+ let panes = self.panes.borrow();
+ let pane = panes.get(pane_id).unwrap();
+ if let Some(cols) = pane.position_and_size().cols.as_percent() {
+ let current_fixed_cols = pane.position_and_size().cols.as_usize();
+ let will_reduce_by = ((self.display_area.cols as f64 / 100.0) * reduce_by) as usize;
+ let ids_right = self.pane_ids_directly_right_of(pane_id);
+ let flexible_right = self.ids_are_flexible(Direction::Horizontal, ids_right);
+ cols - reduce_by >= RESIZE_PERCENT
+ && flexible_right
+ && current_fixed_cols.saturating_sub(will_reduce_by) >= pane.min_width()
+ } else {
+ false
+ }
+ }
+ fn can_reduce_pane_and_surroundings_down(&self, pane_id: &PaneId, reduce_by: f64) -> bool {
+ let panes = self.panes.borrow();
+ let pane = panes.get(pane_id).unwrap();
+ if let Some(rows) = pane.position_and_size().rows.as_percent() {
+ let current_fixed_rows = pane.position_and_size().rows.as_usize();
+ let will_reduce_by = ((self.display_area.rows as f64 / 100.0) * reduce_by) as usize;
+ let ids_above = self.pane_ids_directly_above(pane_id);
+ let flexible_above = self.ids_are_flexible(Direction::Vertical, ids_above);
+ rows - reduce_by >= RESIZE_PERCENT
+ && flexible_above
+ && current_fixed_rows.saturating_sub(will_reduce_by) >= pane.min_height()
+ } else {
+ false
+ }
+ }
+ fn can_reduce_pane_and_surroundings_up(&self, pane_id: &PaneId, reduce_by: f64) -> bool {
+ let panes = self.panes.borrow();
+ let pane = panes.get(pane_id).unwrap();
+ if let Some(rows) = pane.position_and_size().rows.as_percent() {
+ let current_fixed_rows = pane.position_and_size().rows.as_usize();
+ let will_reduce_by = ((self.display_area.rows as f64 / 100.0) * reduce_by) as usize;
+ let ids_below = self.pane_ids_directly_below(pane_id);
+ let flexible_below = self.ids_are_flexible(Direction::Vertical, ids_below);
+ rows - reduce_by >= RESIZE_PERCENT
+ && flexible_below
+ && current_fixed_rows.saturating_sub(will_reduce_by) >= pane.min_height()
+ } else {
+ false
+ }
+ }
+ fn reduce_pane_height(&mut self, id: &PaneId, percent: f64) {
+ let mut panes = self.panes.borrow_mut();
+ let terminal = panes.get_mut(id).unwrap();
+ terminal.reduce_height(percent);
+ }
+ fn increase_pane_height(&mut self, id: &PaneId, percent: f64) {
+ let mut panes = self.panes.borrow_mut();
+ let terminal = panes.get_mut(id).unwrap();
+ terminal.increase_height(percent);
+ }
+ fn increase_pane_width(&mut self, id: &PaneId, percent: f64) {
+ let mut panes = self.panes.borrow_mut();
+ let terminal = panes.get_mut(id).unwrap();
+ terminal.increase_width(percent);
+ }
+ fn reduce_pane_width(&mut self, id: &PaneId, percent: f64) {
+ let mut panes = self.panes.borrow_mut();
+ let terminal = panes.get_mut(id).unwrap();
+ terminal.reduce_width(percent);
+ }
+ fn increase_pane_and_surroundings_up(&mut self, id: &PaneId, percent: f64) {
+ let mut terminals_above = self
+ .pane_ids_directly_above(id)
+ .expect("can't increase pane size up if there are no terminals above");
+ let terminal_borders_above: HashSet<usize> = terminals_above
+ .iter()
+ .map(|t| self.panes.borrow().get(t).unwrap().x())
+ .collect();
+ let (left_resize_border, terminals_to_the_left) =
+ self.top_aligned_contiguous_panes_to_the_left(id, &terminal_borders_above);
+ let (right_resize_border, terminals_to_the_right) =
+ self.top_aligned_contiguous_panes_to_the_right(id, &terminal_borders_above);
+ terminals_above.retain(|t| {
+ self.pane_is_between_vertical_borders(t, left_resize_border, right_resize_border)
+ });
+ self.increase_pane_height(id, percent);
+ for terminal_id in terminals_above {
+ self.reduce_pane_height(&terminal_id, percent);
+ }
+ for terminal_id in terminals_to_the_left.iter().chain(&terminals_to_the_right) {
+ self.increase_pane_height(terminal_id, percent);
+ }
+ }
+ fn increase_pane_and_surroundings_down(&mut self, id: &PaneId, percent: f64) {
+ let mut terminals_below = self
+ .pane_ids_directly_below(id)
+ .expect("can't increase pane size down if there are no terminals below");
+ let terminal_borders_below: HashSet<usize> = terminals_below
+ .iter()
+ .map(|t| self.panes.borrow().get(t).unwrap().x())
+ .collect();
+ let (left_resize_border, terminals_to_the_left) =
+ self.bottom_aligned_contiguous_panes_to_the_left(id, &terminal_borders_below);
+ let (right_resize_border, terminals_to_the_right) =
+ self.bottom_aligned_contiguous_panes_to_the_right(id, &terminal_borders_below);
+ terminals_below.retain(|t| {
+ self.pane_is_between_vertical_borders(t, left_resize_border, right_resize_border)
+ });
+ self.increase_pane_height(id, percent);
+ for terminal_id in terminals_below {
+ self.reduce_pane_height(&terminal_id, percent);
+ }
+ for terminal_id in terminals_to_the_left.iter().chain(&terminals_to_the_right) {
+ self.increase_pane_height(terminal_id, percent);
+ }
+ }
+ fn increase_pane_and_surroundings_right(&mut self, id: &PaneId, percent: f64) {
+ let mut terminals_to_the_right = self
+ .pane_ids_directly_right_of(id)
+ .expect("can't increase pane size right if there are no terminals to the right");
+ let terminal_borders_to_the_right: HashSet<usize> = terminals_to_the_right
+ .iter()
+ .map(|t| {
+ return self.panes.borrow().get(t).unwrap().y();
+ })
+ .collect();
+ let (top_resize_border, terminals_above) =
+ self.right_aligned_contiguous_panes_above(id, &terminal_borders_to_the_right);
+ let (bottom_resize_border, terminals_below) =
+ self.right_aligned_contiguous_panes_below(id, &terminal_borders_to_the_right);
+ terminals_to_the_right.retain(|t| {
+ self.pane_is_between_horizontal_borders(t, top_resize_border, bottom_resize_border)
+ });
+ self.increase_pane_width(id, percent);
+ for terminal_id in terminals_to_the_right {
+ self.reduce_pane_width(&terminal_id, percent);
+ }
+ for terminal_id in terminals_above.iter().chain(&terminals_below) {
+ self.increase_pane_width(terminal_id, percent);
+ }
+ }
+ fn increase_pane_and_surroundings_left(&mut self, id: &PaneId, percent: f64) {
+ let mut terminals_to_the_left = self
+ .pane_ids_directly_left_of(id)
+ .expect("can't increase pane size right if there are no terminals to the right");
+ let terminal_borders_to_the_left: HashSet<usize> = terminals_to_the_left
+ .iter()
+ .map(|t| self.panes.borrow().get(t).unwrap().y())
+ .collect();
+ let (top_resize_border, terminals_above) =
+ self.left_aligned_contiguous_panes_above(id, &terminal_borders_to_the_left);
+ let (bottom_resize_border, terminals_below) =
+ self.left_aligned_contiguous_panes_below(id, &terminal_borders_to_the_left);
+ terminals_to_the_left.retain(|t| {
+ self.pane_is_between_horizontal_borders(t, top_resize_border, bottom_resize_border)
+ });
+ self.increase_pane_width(id, percent);
+ for terminal_id in terminals_to_the_left {
+ self.reduce_pane_width(&terminal_id, percent);
+ }
+ for terminal_id in terminals_above.iter().chain(&terminals_below) {
+ self.increase_pane_width(terminal_id, percent);
+ }
+ }
+ fn reduce_pane_and_surroundings_up(&mut self, id: &PaneId, percent: f64) {
+ let mut terminals_below = self
+ .pane_ids_directly_below(id)
+ .expect("can't reduce pane size up if there are no terminals below");
+ let terminal_borders_below: HashSet<usize> = terminals_below
+ .iter()
+ .map(|t| self.panes.borrow().get(t).unwrap().x())
+ .collect();
+ let (left_resize_border, terminals_to_the_left) =
+ self.bottom_aligned_contiguous_panes_to_the_left(id, &terminal_borders_below);
+ let (right_resize_border, terminals_to_the_right) =
+ self.bottom_aligned_contiguous_panes_to_the_right(id, &terminal_borders_below);
+ terminals_below.retain(|t| {
+ self.pane_is_between_vertical_borders(t, left_resize_border, right_resize_border)
+ });
+
+ // FIXME: This checks that we aren't violating the resize constraints of the aligned panes
+ // above and below this one. This should be moved to a `can_resize` function eventually.
+ for terminal_id in terminals_to_the_left.iter().chain(&terminals_to_the_right) {
+ let panes = self.panes.borrow();
+ let pane = panes.get(terminal_id).unwrap();
+ if pane.current_geom().rows.as_percent().unwrap() - percent < RESIZE_PERCENT {
+ return;
+ }
+ }
+
+ self.reduce_pane_height(id, percent);
+ for terminal_id in terminals_below {
+ self.increase_pane_height(&terminal_id, percent);
+ }
+ for terminal_id in terminals_to_the_left.iter().chain(&terminals_to_the_right) {
+ self.reduce_pane_height(terminal_id, percent);
+ }
+ }
+ fn reduce_pane_and_surroundings_down(&mut self, id: &PaneId, percent: f64) {
+ let mut terminals_above = self
+ .pane_ids_directly_above(id)
+ .expect("can't reduce pane size down if there are no terminals above");
+ let terminal_borders_above: HashSet<usize> = terminals_above
+ .iter()
+ .map(|t| self.panes.borrow().get(t).unwrap().x())
+ .collect();
+ let (left_resize_border, terminals_to_the_left) =
+ self.top_aligned_contiguous_panes_to_the_left(id, &terminal_borders_above);
+ let (right_resize_border, terminals_to_the_right) =
+ self.top_aligned_contiguous_panes_to_the_right(id, &terminal_borders_above);
+ terminals_above.retain(|t| {
+ self.pane_is_between_vertical_borders(t, left_resize_border, right_resize_border)
+ });
+
+ // FIXME: This checks that we aren't violating the resize constraints of the aligned panes
+ // above and below this one. This should be moved to a `can_resize` function eventually.
+ for terminal_id in terminals_to_the_left.iter().chain(&terminals_to_the_right) {
+ let panes = self.panes.borrow();
+ let pane = panes.get(terminal_id).unwrap();
+ if pane.current_geom().rows.as_percent().unwrap() - percent < RESIZE_PERCENT {
+ return;
+ }
+ }
+
+ self.reduce_pane_height(id, percent);
+ for terminal_id in terminals_above {
+ self.increase_pane_height(&terminal_id, percent);
+ }
+ for terminal_id in terminals_to_the_left.iter().chain(&terminals_to_the_right) {
+ self.reduce_pane_height(terminal_id, percent);
+ }
+ }
+ fn reduce_pane_and_surroundings_right(&mut self, id: &PaneId, percent: f64) {
+ let mut terminals_to_the_left = self
+ .pane_ids_directly_left_of(id)
+ .expect("can't reduce pane size right if there are no terminals to the left");
+ let terminal_borders_to_the_left: HashSet<usize> = terminals_to_the_left
+ .iter()
+ .map(|t| self.panes.borrow().get(t).unwrap().y())
+ .collect();
+ let (top_resize_border, terminals_above) =
+ self.left_aligned_contiguous_panes_above(id, &terminal_borders_to_the_left);
+ let (bottom_resize_border, terminals_below) =
+ self.left_aligned_contiguous_panes_below(id, &terminal_borders_to_the_left);
+ terminals_to_the_left.retain(|t| {
+ self.pane_is_between_horizontal_borders(t, top_resize_border, bottom_resize_border)
+ });
+
+ // FIXME: This checks that we aren't violating the resize constraints of the aligned panes
+ // above and below this one. This should be moved to a `can_resize` function eventually.
+ for terminal_id in terminals_above.iter().chain(&terminals_below) {
+ let panes = self.panes.borrow();
+ let pane = panes.get(terminal_id).unwrap();
+ if pane.current_geom().cols.as_percent().unwrap() - percent < RESIZE_PERCENT {
+ return;
+ }
+ }
+
+ self.reduce_pane_width(id, percent);
+ for terminal_id in terminals_to_the_left {
+ self.increase_pane_width(&terminal_id, percent);
+ }
+ for terminal_id in terminals_above.iter().chain(&terminals_below) {
+ self.reduce_pane_width(terminal_id, percent);
+ }
+ }
+ fn reduce_pane_and_surroundings_left(&mut self, id: &PaneId, percent: f64) {
+ let mut terminals_to_the_right = self
+ .pane_ids_directly_right_of(id)
+ .expect("can't reduce pane size left if there are no terminals to the right");
+ let terminal_borders_to_the_right: HashSet<usize> = terminals_to_the_right
+ .iter()
+ .map(|t| self.panes.borrow().get(t).unwrap().y())
+ .collect();
+ let (top_resize_border, terminals_above) =
+ self.right_aligned_contiguous_panes_above(id, &terminal_borders_to_the_right);
+ let (bottom_resize_border, terminals_below) =
+ self.right_aligned_contiguous_panes_below(id, &terminal_borders_to_the_right);
+ terminals_to_the_right.retain(|t| {
+ self.pane_is_between_horizontal_borders(t, top_resize_border, bottom_resize_border)
+ });
+
+ // FIXME: This checks that we aren't violating the resize constraints of the aligned panes
+ // above and below this one. This should be moved to a `can_resize` function eventually.
+ for terminal_id in terminals_above.iter().chain(&terminals_below) {
+ let panes = self.panes.borrow();
+ let pane = panes.get(terminal_id).unwrap();
+ if pane.current_geom().cols.as_percent().unwrap() - percent < RESIZE_PERCENT {
+ return;
+ }
+ }
+
+ self.reduce_pane_width(id, percent);
+ for terminal_id in terminals_to_the_right {
+ self.increase_pane_width(&terminal_id, percent);
+ }
+ for terminal_id in terminals_above.iter().chain(&terminals_below) {
+ self.reduce_pane_width(terminal_id, percent);
+ }
+ }
+ fn pane_ids_directly_left_of(&self, id: &PaneId) -> Option<Vec<PaneId>> {
+ let panes = self.panes.borrow();
+ let mut ids = vec![];
+ let terminal_to_check = panes.get(id).unwrap();
+ if terminal_to_check.x() == 0 {
+ return None;
+ }
+ // for (&pid, terminal) in self.get_panes() {
+ for (&pid, terminal) in panes.iter() {
+ if terminal.x() + terminal.cols() == terminal_to_check.x() {
+ ids.push(pid);
+ }
+ }
+ if ids.is_empty() {
+ None
+ } else {
+ Some(ids)
+ }
+ }
+ fn pane_ids_directly_right_of(&self, id: &PaneId) -> Option<Vec<PaneId>> {
+ let mut ids = vec![];
+ let panes = self.panes.borrow();
+ let terminal_to_check = panes.get(id).unwrap();
+ // for (&pid, terminal) in self.get_panes() {
+ for (&pid, terminal) in panes.iter() {
+ if terminal.x() == terminal_to_check.x() + terminal_to_check.cols() {
+ ids.push(pid);
+ }
+ }
+ if ids.is_empty() {
+ None
+ } else {
+ Some(ids)
+ }
+ }
+ fn pane_ids_directly_below(&self, id: &PaneId) -> Option<Vec<PaneId>> {
+ let mut ids = vec![];
+ let panes = self.panes.borrow();
+ let terminal_to_check = panes.get(id).unwrap();
+ // for (&pid, terminal) in self.get_panes() {
+ for (&pid, terminal) in panes.iter() {
+ if terminal.y() == terminal_to_check.y() + terminal_to_check.rows() {
+ ids.push(pid);
+ }
+ }
+ if ids.is_empty() {
+ None
+ } else {
+ Some(ids)
+ }
+ }
+ fn pane_ids_directly_above(&self, id: &PaneId) -> Option<Vec<PaneId>> {
+ let mut ids = vec![];
+ let panes = self.panes.borrow();
+ let terminal_to_check = panes.get(id).unwrap();
+ // for (&pid, terminal) in self.get_panes() {
+ for (&pid, terminal) in panes.iter() {
+ if terminal.y() + terminal.rows() == terminal_to_check.y() {
+ ids.push(pid);
+ }
+ }
+ if ids.is_empty() {
+ None
+ } else {
+ Some(ids)
+ }
+ }
+ fn pane_ids_top_aligned_with_pane_id(&self, pane_id: &PaneId) -> Vec<PaneId> {
+ let panes = self.panes.borrow();
+ let pane_to_check = panes.get(pane_id).unwrap();
+ panes
+ .iter()
+ .filter(|(p_id, p)| *p_id != pane_id && p.y() == pane_to_check.y())
+ .map(|(p_id, _p)| *p_id)
+ .collect()
+ }
+ fn pane_ids_bottom_aligned_with_pane_id(&self, pane_id: &PaneId) -> Vec<PaneId> {
+ let panes = self.panes.borrow();
+ let pane_to_check = panes.get(pane_id).unwrap();
+ panes
+ .iter()
+ .filter(|(p_id, p)| {
+ *p_id != pane_id && p.y() + p.rows() == pane_to_check.y() + pane_to_check.rows()
+ })
+ .map(|(p_id, _p)| *p_id)
+ .collect()
+ }
+ fn pane_ids_right_aligned_with_pane_id(&self, pane_id: &PaneId) -> Vec<PaneId> {
+ let panes = self.panes.borrow();
+ let pane_to_check = panes.get(pane_id).unwrap();
+ panes
+ .iter()
+ .filter(|(p_id, p)| {
+ *p_id != pane_id && p.x() + p.cols() == pane_to_check.x() + pane_to_check.cols()
+ })
+ .map(|(p_id, _p)| *p_id)
+ .collect()
+ }
+ fn pane_ids_left_aligned_with_pane_id(&self, pane_id: &PaneId) -> Vec<PaneId> {
+ let panes = self.panes.borrow();
+ let pane_to_check = panes.get(pane_id).unwrap();
+ panes
+ .iter()
+ .filter(|(p_id, p)| *p_id != pane_id && p.x() == pane_to_check.x())
+ .map(|(p_id, _p)| *p_id)
+ .collect()
+ }
+ fn right_aligned_contiguous_panes_above(
+ &self,
+ id: &PaneId,
+ pane_borders_to_the_right: &HashSet<usize>,
+ ) -> BorderAndPaneIds {
+ let panes = self.panes.borrow();
+ let mut result_panes = vec![];
+ let mut right_aligned_panes: Vec<_> = self
+ .pane_ids_right_aligned_with_pane_id(id)
+ .iter()
+ .map(|p_id| panes.get(p_id).unwrap())
+ .collect();
+ // panes that are next to each other up to current
+ right_aligned_panes.sort_by_key(|a| Reverse(a.y()));
+ for pane in right_aligned_panes {
+ let pane_to_check = panes.get(id).unwrap();
+ let pane_to_check = result_panes.last().unwrap_or(&pane_to_check);
+ if pane.y() + pane.rows() == pane_to_check.y() {
+ result_panes.push(pane);
+ }
+ }
+ // top-most border aligned with a pane border to the right
+ let mut top_resize_border = 0;
+ for pane in &result_panes {
+ let bottom_pane_boundary = pane.y() + pane.rows();
+ if pane_borders_to_the_right
+ .get(&bottom_pane_boundary)
+ .is_some()
+ && top_resize_border < bottom_pane_boundary
+ {
+ top_resize_border = bottom_pane_boundary;
+ }
+ }
+ result_panes.retain(|pane| pane.y() >= top_resize_border);
+ // if there are no adjacent panes to resize, we use the border of the main pane we're
+ // resizing
+ let top_resize_border = if result_panes.is_empty() {
+ let pane_to_check = panes.get(id).unwrap();
+ pane_to_check.y()
+ } else {
+ top_resize_border
+ };
+ let pane_ids: Vec<PaneId> = result_panes.iter().map(|t| t.pid()).collect();
+ (top_resize_border, pane_ids)
+ }
+ fn right_aligned_contiguous_panes_below(
+ &self,
+ id: &PaneId,
+ pane_borders_to_the_right: &HashSet<usize>,
+ ) -> BorderAndPaneIds {
+ let panes = self.panes.borrow();
+ let mut result_panes = vec![];
+ let mut right_aligned_panes: Vec<_> = self
+ .pane_ids_right_aligned_with_pane_id(id)
+ .iter()
+ .map(|p_id| panes.get(p_id).unwrap())
+ .collect();
+ // panes that are next to each other up to current
+ right_aligned_panes.sort_by_key(|a| a.y());
+ for pane in right_aligned_panes {
+ let pane_to_check = panes.get(id).unwrap();
+ let pane_to_check = result_panes.last().unwrap_or(&pane_to_check);
+ if pane.y() == pane_to_check.y() + pane_to_check.rows() {
+ result_panes.push(pane);
+ }
+ }
+ // bottom-most border aligned with a pane border to the right
+ let mut bottom_resize_border = self.viewport.y + self.viewport.rows;
+ for pane in &result_panes {
+ let top_pane_boundary = pane.y();
+ if pane_borders_to_the_right
+ .get(&(top_pane_boundary))
+ .is_some()
+ && top_pane_boundary < bottom_resize_border
+ {
+ bottom_resize_border = top_pane_boundary;
+ }
+ }
+ result_panes.retain(|pane| pane.y() + pane.rows() <= bottom_resize_border);
+ // if there are no adjacent panes to resize, we use the border of the main pane we're
+ // resizing
+ let bottom_resize_border = if result_panes.is_empty() {
+ let pane_to_check = panes.get(id).unwrap();
+ pane_to_check.y() + pane_to_check.rows()
+ } else {
+ bottom_resize_border
+ };
+ let pane_ids: Vec<PaneId> = result_panes.iter().map(|t| t.pid()).collect();
+ (bottom_resize_border, pane_ids)
+ }
+ fn left_aligned_contiguous_panes_above(
+ &self,
+ id: &PaneId,
+ pane_borders_to_the_left: &HashSet<usize>,
+ ) -> BorderAndPaneIds {
+ let panes = self.panes.borrow();
+ let mut result_panes = vec![];
+ let mut left_aligned_panes: Vec<_> = self
+ .pane_ids_left_aligned_with_pane_id(id)
+ .iter()
+ .map(|p_id| panes.get(p_id).unwrap())
+ .collect();
+ // panes that are next to each other up to current
+ left_aligned_panes.sort_by_key(|a| Reverse(a.y()));
+ for pane in left_aligned_panes {
+ let pane_to_check = panes.get(id).unwrap();
+ let pane_to_check = result_panes.last().unwrap_or(&pane_to_check);
+ if pane.y() + pane.rows() == pane_to_check.y() {
+ result_panes.push(pane);
+ }
+ }
+ // top-most border aligned with a pane border to the right
+ let mut top_resize_border = 0;
+ for pane in &result_panes {
+ let bottom_pane_boundary = pane.y() + pane.rows();
+ if pane_borders_to_the_left
+ .get(&bottom_pane_boundary)
+ .is_some()
+ && top_resize_border < bottom_pane_boundary
+ {
+ top_resize_border = bottom_pane_boundary;
+ }
+ }
+ result_panes.retain(|pane| pane.y() >= top_resize_border);
+ // if there are no adjacent panes to resize, we use the border of the main pane we're
+ // resizing
+ let top_resize_border = if panes.is_empty() {
+ let pane_to_check = panes.get(id).unwrap();
+ pane_to_check.y()
+ } else {
+ top_resize_border
+ };
+ let pane_ids: Vec<PaneId> = result_panes.iter().map(|t| t.pid()).collect();
+ (top_resize_border, pane_ids)
+ }
+ fn left_aligned_contiguous_panes_below(
+ &self,
+ id: &PaneId,
+ pane_borders_to_the_left: &HashSet<usize>,
+ ) -> BorderAndPaneIds {
+ let panes = self.panes.borrow();
+ let mut result_panes = vec![];
+ let mut left_aligned_panes: Vec<_> = self
+ .pane_ids_left_aligned_with_pane_id(id)
+ .iter()
+ .map(|p_id| panes.get(p_id).unwrap())
+ .collect();
+ // panes that are next to each other up to current
+ left_aligned_panes.sort_by_key(|a| a.y());
+ for pane in left_aligned_panes {
+ let pane_to_check = panes.get(id).unwrap();
+ let pane_to_check = result_panes.last().unwrap_or(&pane_to_check);
+ if pane.y() == pane_to_check.y() + pane_to_check.rows() {
+ result_panes.push(pane);
+ }
+ }
+ // bottom-most border aligned with a pane border to the left
+ let mut bottom_resize_border = self.viewport.y + self.viewport.rows;
+ for pane in &result_panes {
+ let top_pane_boundary = pane.y();
+ if pane_borders_to_the_left.get(&(top_pane_boundary)).is_some()
+ && top_pane_boundary < bottom_resize_border
+ {
+ bottom_resize_border = top_pane_boundary;
+ }
+ }
+ result_panes.retain(|pane| pane.y() + pane.rows() <= bottom_resize_border);
+ // if there are no adjacent panes to resize, we use the border of the main pane we're
+ // resizing
+ let bottom_resize_border = if result_panes.is_empty() {
+ let pane_to_check = panes.get(id).unwrap();
+ pane_to_check.y() + pane_to_check.rows()
+ } else {
+ bottom_resize_border
+ };
+ let pane_ids: Vec<PaneId> = result_panes.iter().map(|t| t.pid()).collect();
+ (bottom_resize_border, pane_ids)
+ }
+ fn top_aligned_contiguous_panes_to_the_left(
+ &self,
+ id: &PaneId,
+ pane_borders_above: &HashSet<usize>,
+ ) -> BorderAndPaneIds {
+ let panes = self.panes.borrow();
+ let mut result_panes = vec![];
+ let mut top_aligned_panes: Vec<_> = self
+ .pane_ids_top_aligned_with_pane_id(id)
+ .iter()
+ .map(|p_id| panes.get(p_id).unwrap())
+ .collect();
+ // panes that are next to each other up to current
+ top_aligned_panes.sort_by_key(|a| Reverse(a.x()));
+ for pane in top_aligned_panes {
+ let pane_to_check = panes.get(id).unwrap();
+ let pane_to_check = result_panes.last().unwrap_or(&pane_to_check);
+ if pane.x() + pane.cols() == pane_to_check.x() {
+ result_panes.push(pane);
+ }
+ }
+ // leftmost border aligned with a pane border above
+ let mut left_resize_border = 0;
+ for pane in &result_panes {
+ let right_pane_boundary = pane.x() + pane.cols();
+ if pane_borders_above.get(&right_pane_boundary).is_some()
+ && left_resize_border < right_pane_boundary
+ {
+ left_resize_border = right_pane_boundary
+ }
+ }
+ result_panes.retain(|pane| pane.x() >= left_resize_border);
+ // if there are no adjacent panes to resize, we use the border of the main pane we're
+ // resizing
+ let left_resize_border = if result_panes.is_empty() {
+ let pane_to_check = panes.get(id).unwrap();
+ pane_to_check.x()
+ } else {
+ left_resize_border
+ };
+ let pane_ids: Vec<PaneId> = result_panes.iter().map(|t| t.pid()).collect();
+ (left_resize_border, pane_ids)
+ }
+ fn top_aligned_contiguous_panes_to_the_right(
+ &self,
+ id: &PaneId,
+ pane_borders_above: &HashSet<usize>,
+ ) -> BorderAndPaneIds {
+ let panes = self.panes.borrow();
+ let mut result_panes = vec![];
+ let mut top_aligned_panes: Vec<_> = self
+ .pane_ids_top_aligned_with_pane_id(id)
+ .iter()
+ .map(|p_id| panes.get(p_id).unwrap())
+ .collect();
+ // panes that are next to each other up to current
+ top_aligned_panes.sort_by_key(|a| a.x());
+ for pane in top_aligned_panes {
+ let pane_to_check = panes.get(id).unwrap();
+ let pane_to_check = result_panes.last().unwrap_or(&pane_to_check);
+ if pane.x() == pane_to_check.x() + pane_to_check.cols() {
+ result_panes.push(pane);
+ }
+ }
+ // rightmost border aligned with a pane border above
+ let mut right_resize_border = self.viewport.x + self.viewport.cols;
+ for pane in &result_panes {
+ let left_pane_boundary = pane.x();
+ if pane_borders_above.get(&left_pane_boundary).is_some()
+ && right_resize_border > left_pane_boundary
+ {
+ right_resize_border = left_pane_boundary;
+ }
+ }
+ result_panes.retain(|pane| pane.x() + pane.cols() <= right_resize_border);
+ // if there are no adjacent panes to resize, we use the border of the main pane we're
+ // resizing
+ let right_resize_border = if result_panes.is_empty() {
+ let pane_to_check = panes.get(id).unwrap();
+ pane_to_check.x() + pane_to_check.cols()
+ } else {
+ right_resize_border
+ };
+ let pane_ids: Vec<PaneId> = result_panes.iter().map(|t| t.pid()).collect();
+ (right_resize_border, pane_ids)
+ }
+ fn bottom_aligned_contiguous_panes_to_the_left(
+ &self,
+ id: &PaneId,
+ pane_borders_below: &HashSet<usize>,
+ ) -> BorderAndPaneIds {
+ let panes = self.panes.borrow();
+ let mut result_panes = vec![];
+ let mut bottom_aligned_panes: Vec<_> = self
+ .pane_ids_bottom_aligned_with_pane_id(id)
+ .iter()
+ .map(|p_id| panes.get(p_id).unwrap())
+ .collect();
+ bottom_aligned_panes.sort_by_key(|a| Reverse(a.x()));
+ // panes that are next to each other up to current
+ for pane in bottom_aligned_panes {
+ let pane_to_check = panes.get(id).unwrap();
+ let pane_to_check = result_panes.last().unwrap_or(&pane_to_check);
+ if pane.x() + pane.cols() == pane_to_check.x() {
+ result_panes.push(pane);
+ }
+ }
+ // leftmost border aligned with a pane border above
+ let mut left_resize_border = 0;
+ for pane in &result_panes {
+ let right_pane_boundary = pane.x() + pane.cols();
+ if pane_borders_below.get(&right_pane_boundary).is_some()
+ && left_resize_border < right_pane_boundary
+ {
+ left_resize_border = right_pane_boundary;
+ }
+ }
+ result_panes.retain(|terminal| terminal.x() >= left_resize_border);
+ // if there are no adjacent panes to resize, we use the border of the main pane we're
+ // resizing
+ let left_resize_border = if result_panes.is_empty() {
+ let pane_to_check = panes.get(id).unwrap();
+ pane_to_check.x()
+ } else {
+ left_resize_border
+ };
+ let pane_ids: Vec<PaneId> = result_panes.iter().map(|t| t.pid()).collect();
+ (left_resize_border, pane_ids)
+ }
+ fn bottom_aligned_contiguous_panes_to_the_right(
+ &self,
+ id: &PaneId,
+ pane_borders_below: &HashSet<usize>,
+ ) -> BorderAndPaneIds {
+ let panes = self.panes.borrow();
+ let mut result_panes = vec![];
+ let mut bottom_aligned_panes: Vec<_> = self
+ .pane_ids_bottom_aligned_with_pane_id(id)
+ .iter()
+ .map(|p_id| panes.get(p_id).unwrap())
+ .collect();
+ bottom_aligned_panes.sort_by_key(|a| a.x());
+ // panes that are next to each other up to current
+ for pane in bottom_aligned_panes {
+ let pane_to_check = panes.get(id).unwrap();
+ let pane_to_check = result_panes.last().unwrap_or(&pane_to_check);
+ if pane.x() == pane_to_check.x() + pane_to_check.cols() {
+ result_panes.push(pane);
+ }
+ }
+ // leftmost border aligned with a pane border above
+ let mut right_resize_border = self.viewport.x + self.viewport.cols;
+ for pane in &result_panes {
+ let left_pane_boundary = pane.x();
+ if pane_borders_below.get(&left_pane_boundary).is_some()
+ && right_resize_border > left_pane_boundary
+ {
+ right_resize_border = left_pane_boundary;
+ }
+ }
+ result_panes.retain(|terminal| terminal.x() + terminal.cols() <= right_resize_border);
+ let right_resize_border = if result_panes.is_empty() {
+ let pane_to_check = panes.get(id).unwrap();
+ pane_to_check.x() + pane_to_check.cols()
+ } else {
+ right_resize_border
+ };
+ let pane_ids: Vec<PaneId> = result_panes.iter().map(|t| t.pid()).collect();
+ (right_resize_border, pane_ids)
+ }
+ fn ids_are_flexible(&self, direction: Direction, pane_ids: Option<Vec<PaneId>>) -> bool {
+ let panes = self.panes.borrow();
+ pane_ids.is_some()
+ && pane_ids.unwrap().iter().all(|id| {
+ let pane_to_check = panes.get(id).unwrap();
+ let geom = pane_to_check.current_geom();
+ let dimension = match direction {
+ Direction::Vertical => geom.rows,
+ Direction::Horizontal => geom.cols,
+ };
+ !dimension.is_fixed()
+ })
+ }
+ fn pane_is_between_vertical_borders(
+ &self,
+ id: &PaneId,
+ left_border_x: usize,
+ right_border_x: usize,
+ ) -> bool {
+ let panes = self.panes.borrow();
+ let pane = panes.get(id).unwrap();
+ pane.x() >= left_border_x && pane.x() + pane.cols() <= right_border_x
+ }
+ fn pane_is_between_horizontal_borders(
+ &self,
+ id: &PaneId,
+ top_border_y: usize,
+ bottom_border_y: usize,
+ ) -> bool {
+ let panes = self.panes.borrow();
+ let pane = panes.get(id).unwrap();
+ pane.y() >= top_border_y && pane.y() + pane.rows() <= bottom_border_y
+ }
+ 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);
+ let mut pane_resizer = PaneResizer::new(self.panes.clone());
+ let _ = pane_resizer.layout(Direction::Horizontal, self.display_area.cols);
+ 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);
+ let mut pane_resizer = PaneResizer::new(self.panes.clone());
+ let _ = pane_resizer.layout(Direction::Horizontal, self.display_area.cols);
+ 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);
+ let mut pane_resizer = PaneResizer::new(self.panes.clone());
+ let _ = pane_resizer.layout(Direction::Vertical, self.display_area.rows);
+ 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);
+ let mut pane_resizer = PaneResizer::new(self.panes.clone());
+ let _ = pane_resizer.layout(Direction::Vertical, self.display_area.rows);
+ 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 panes = self.panes.borrow();
+ let pane = panes.get(p_id).unwrap();
+ let active_pane = 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 panes = self.panes.borrow();
+ let pane = panes.get(p_id).unwrap();
+ let active_pane = 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 panes = self.panes.borrow();
+ let pane = panes.get(p_id).unwrap();
+ let active_pane = 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 panes = self.panes.borrow();
+ let pane = panes.get(p_id).unwrap();
+ let active_pane = 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 panes = self.panes.borrow();
+ let pane = panes.get(p_id).unwrap();
+ let active_pane = 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 panes = self.panes.borrow();
+ let pane = panes.get(p_id).unwrap();
+ let active_pane = 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 panes = self.panes.borrow();
+ let pane = panes.get(p_id).unwrap();
+ let active_pane = 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 panes = self.panes.borrow();
+ let pane = panes.get(p_id).unwrap();
+ let active_pane = 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);
+ let mut pane_resizer = PaneResizer::new(self.panes.clone());
+ let _ = pane_resizer.layout(Direction::Horizontal, self.display_area.cols);
+ 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);
+ let mut pane_resizer = PaneResizer::new(self.panes.clone());
+ let _ = pane_resizer.layout(Direction::Horizontal, self.display_area.cols);
+ 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);
+ let mut pane_resizer = PaneResizer::new(self.panes.clone());
+ let _ = pane_resizer.layout(Direction::Vertical, self.display_area.rows);
+ 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);
+ let mut pane_resizer = PaneResizer::new(self.panes.clone());
+ let _ = pane_resizer.layout(Direction::Vertical, self.display_area.rows);
+ return true;
+ }
+ false
+ }
+ fn viewport_pane_ids_directly_above(&self, pane_id: &PaneId) -> Vec<PaneId> {
+ self.pane_ids_directly_above(pane_id)
+ .unwrap_or_default()
+ .into_iter()
+ .filter(|id| self.is_inside_viewport(id))
+ .collect()
+ }
+ fn viewport_pane_ids_directly_below(&self, pane_id: &PaneId) -> Vec<PaneId> {
+ self.pane_ids_directly_below(pane_id)
+ .unwrap_or_default()
+ .into_iter()
+ .filter(|id| self.is_inside_viewport(id))
+ .collect()
+ }
+ fn is_inside_viewport(&self, pane_id: &PaneId) -> bool {
+ is_inside_viewport(&self.viewport, self.panes.borrow().get(pane_id).unwrap())
+ }
+ pub fn next_selectable_pane_id(&self, current_pane_id: &PaneId) -> PaneId {
+ let panes = self.panes.borrow();
+ let mut panes: Vec<(&PaneId, &&mut Box<dyn Pane>)> =
+ panes.iter().filter(|(_, p)| p.selectable()).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 == current_pane_id) // TODO: better
+ .unwrap();
+
+ let next_active_pane_id = panes
+ .get(active_pane_position + 1)
+ .or_else(|| panes.get(0))
+ .map(|p| *p.0)
+ .unwrap();
+ next_active_pane_id
+ }
+ pub fn previous_selectable_pane_id(&self, current_pane_id: &PaneId) -> PaneId {
+ let panes = self.panes.borrow();
+ let mut panes: Vec<(&PaneId, &&mut Box<dyn Pane>)> =
+ panes.iter().filter(|(_, p)| p.selectable()).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 last_pane = panes.last().unwrap();
+ let active_pane_position = panes
+ .iter()
+ .position(|(id, _)| *id == current_pane_id) // TODO: better
+ .unwrap();
+
+ let previous_active_pane_id = if active_pane_position == 0 {
+ *last_pane.0
+ } else {
+ *panes.get(active_pane_position - 1).unwrap().0
+ };
+ previous_active_pane_id
+ }
+ pub fn next_selectable_pane_id_to_the_left(&self, current_pane_id: &PaneId) -> Option<PaneId> {
+ let panes = self.panes.borrow();
+ let current_pane = panes.get(current_pane_id)?;
+ let panes: Vec<(PaneId, &&mut Box<dyn Pane>)> = panes
+ .iter()
+ .filter(|(_, p)| p.selectable())
+ .map(|(p_id, p)| (*p_id, p))
+ .collect();
+ let next_index = panes
+ .iter()
+ .enumerate()
+ .filter(|(_, (_, c))| {
+ c.is_directly_left_of(Box::as_ref(current_pane))
+ && c.horizontally_overlaps_with(Box::as_ref(current_pane))
+ })
+ .max_by_key(|(_, (_, c))| c.active_at())
+ .map(|(_, (pid, _))| pid)
+ .copied();
+ next_index
+ }
+ pub fn next_selectable_pane_id_below(&self, current_pane_id: &PaneId) -> Option<PaneId> {
+ let panes = self.panes.borrow();
+ let current_pane = panes.get(current_pane_id)?;
+ let panes: Vec<(PaneId, &&mut Box<dyn Pane>)> = panes
+ .iter()
+ .filter(|(_, p)| p.selectable())
+ .map(|(p_id, p)| (*p_id, p))
+ .collect();
+ let next_index = panes
+ .iter()
+ .enumerate()
+ .filter(|(_, (_, c))| {
+ c.is_directly_below(Box::as_ref(current_pane))
+ && c.vertically_overlaps_with(Box::as_ref(current_pane))
+ })
+ .max_by_key(|(_, (_, c))| c.active_at())
+ .map(|(_, (pid, _))| pid)
+ .copied();
+ next_index
+ }
+ pub fn next_selectable_pane_id_above(&self, current_pane_id: &PaneId) -> Option<PaneId> {
+ let panes = self.panes.borrow();
+ let current_pane = panes.get(current_pane_id)?;
+ let panes: Vec<(PaneId, &&mut Box<dyn Pane>)> = panes
+ .iter()
+ .filter(|(_, p)| p.selectable())
+ .map(|(p_id, p)| (*p_id, p))
+ .collect();
+ let next_index = panes
+ .iter()
+ .enumerate()
+ .filter(|(_, (_, c))| {
+ c.is_directly_above(Box::as_ref(current_pane))
+ && c.vertically_overlaps_with(Box::as_ref(current_pane))
+ })
+ .max_by_key(|(_, (_, c))| c.active_at())
+ .map(|(_, (pid, _))| pid)
+ .copied();
+ next_index
+ }
+ pub fn next_selectable_pane_id_to_the_right(&self, current_pane_id: &PaneId) -> Option<PaneId> {
+ let panes = self.panes.borrow();
+ let current_pane = panes.get(current_pane_id)?;
+ let panes: Vec<(PaneId, &&mut Box<dyn Pane>)> = panes
+ .iter()
+ .filter(|(_, p)| p.selectable())
+ .map(|(p_id, p)| (*p_id, p))
+ .collect();
+ let next_index = panes
+ .iter()
+ .enumerate()
+ .filter(|(_, (_, c))| {
+ c.is_directly_right_of(Box::as_ref(current_pane))
+ && c.horizontally_overlaps_with(Box::as_ref(current_pane))
+ })
+ .max_by_key(|(_, (_, c))| c.active_at())
+ .map(|(_, (pid, _))| pid)
+ .copied();
+ next_index
+ }
+ fn horizontal_borders(&self, pane_ids: &[PaneId]) -> HashSet<usize> {
+ pane_ids.iter().fold(HashSet::new(), |mut borders, p| {
+ let panes = self.panes.borrow();
+ let pane = panes.get(p).unwrap();
+ borders.insert(pane.y());
+ borders.insert(pane.y() + pane.rows());
+ borders
+ })
+ }
+ fn vertical_borders(&self, pane_ids: &[PaneId]) -> HashSet<usize> {
+ pane_ids.iter().fold(HashSet::new(), |mut borders, p| {
+ let panes = self.panes.borrow();
+ let pane = panes.get(p).unwrap();
+ borders.insert(pane.x());
+ borders.insert(pane.x() + pane.cols());
+ borders
+ })
+ }
+ fn panes_to_the_left_between_aligning_borders(&self, id: PaneId) -> Option<Vec<PaneId>> {
+ let panes = self.panes.borrow();
+ if let Some(pane) = panes.get(&id) {
+ let upper_close_border = pane.y();
+ let lower_close_border = pane.y() + pane.rows();
+
+ if let Some(panes_to_the_left) = self.pane_ids_directly_left_of(&id) {
+ let mut selectable_panes: Vec<_> = panes_to_the_left
+ .into_iter()
+ .filter(|pid| panes.get(pid).unwrap().selectable())
+ .collect();
+ let pane_borders_to_the_left = self.horizontal_borders(&selectable_panes);
+ if pane_borders_to_the_left.contains(&upper_close_border)
+ && pane_borders_to_the_left.contains(&lower_close_border)
+ {
+ selectable_panes.retain(|t| {
+ self.pane_is_between_horizontal_borders(
+ t,
+ upper_close_border,
+ lower_close_border,
+ )
+ });
+ return Some(selectable_panes);
+ }
+ }
+ }
+ None
+ }
+ fn panes_to_the_right_between_aligning_borders(&self, id: PaneId) -> Option<Vec<PaneId>> {
+ let panes = self.panes.borrow();
+ if let Some(pane) = panes.get(&id) {
+ let upper_close_border = pane.y();
+ let lower_close_border = pane.y() + pane.rows();
+
+ if let Some(panes_to_the_right) = self.pane_ids_directly_right_of(&id) {
+ let mut selectable_panes: Vec<_> = panes_to_the_right
+ .into_iter()
+ .filter(|pid| panes.get(pid).unwrap().selectable())
+ .collect();
+ let pane_borders_to_the_right = self.horizontal_borders(&selectable_panes);
+ if pane_borders_to_the_right.contains(&upper_close_border)
+ && pane_borders_to_the_right.contains(&lower_close_border)
+ {
+ selectable_panes.retain(|t| {
+ self.pane_is_between_horizontal_borders(
+ t,
+ upper_close_border,
+ lower_close_border,
+ )
+ });
+ return Some(selectable_panes);
+ }
+ }
+ }
+ None
+ }
+ fn panes_above_between_aligning_borders(&self, id: PaneId) -> Option<Vec<PaneId>> {
+ let panes = self.panes.borrow();
+ if let Some(pane) = panes.get(&id) {
+ let left_close_border = pane.x();
+ let right_close_border = pane.x() + pane.cols();
+
+ if let Some(panes_above) = self.pane_ids_directly_above(&id) {
+ let mut selectable_panes: Vec<_> = panes_above
+ .into_iter()
+ .filter(|pid| panes.get(pid).unwrap().selectable())
+ .collect();
+ let pane_borders_above = self.vertical_borders(&selectable_panes);
+ if pane_borders_above.contains(&left_close_border)
+ && pane_borders_above.contains(&right_close_border)
+ {
+ selectable_panes.retain(|t| {
+ self.pane_is_between_vertical_borders(
+ t,
+ left_close_border,
+ right_close_border,
+ )
+ });
+ return Some(selectable_panes);
+ }
+ }
+ }
+ None
+ }
+ fn panes_below_between_aligning_borders(&self, id: PaneId) -> Option<Vec<PaneId>> {
+ let panes = self.panes.borrow();
+ if let Some(pane) = panes.get(&id) {
+ let left_close_border = pane.x();
+ let right_close_border = pane.x() + pane.cols();
+
+ if let Some(panes_below) = self.pane_ids_directly_below(&id) {
+ let mut selectable_panes: Vec<_> = panes_below
+ .into_iter()
+ .filter(|pid| panes[pid].selectable())
+ .collect();
+ let pane_borders_below = self.vertical_borders(&selectable_panes);
+ if pane_borders_below.contains(&left_close_border)
+ && pane_borders_below.contains(&right_close_border)
+ {
+ selectable_panes.retain(|t| {
+ self.pane_is_between_vertical_borders(
+ t,
+ left_close_border,
+ right_close_border,
+ )
+ });
+ return Some(selectable_panes);
+ }
+ }
+ }
+ None
+ }
+ fn find_panes_to_grow(&self, id: PaneId) -> Option<(Vec<PaneId>, Direction)> {
+ if let Some(panes) = self
+ .panes_to_the_left_between_aligning_borders(id)
+ .or_else(|| self.panes_to_the_right_between_aligning_borders(id))
+ {
+ return Some((panes, Direction::Horizontal));
+ }
+
+ if let Some(panes) = self
+ .panes_above_between_aligning_borders(id)
+ .or_else(|| self.panes_below_between_aligning_borders(id))
+ {
+ return Some((panes, Direction::Vertical));
+ }
+
+ None
+ }
+ fn grow_panes(&mut self, panes: &[PaneId], direction: Direction, (width, height): (f64, f64)) {
+ match direction {
+ Direction::Horizontal => {
+ for pane_id in panes {
+ self.increase_pane_width(pane_id, width);
+ }
+ }
+ Direction::Vertical => {
+ for pane_id in panes {
+ self.increase_pane_height(pane_id, height);
+ }
+ }
+ };
+ }
+ pub fn fill_space_over_pane(&mut self, id: PaneId) -> bool {
+ // true => successfully filled space over pane
+ // false => didn't succeed, so didn't do anything
+ let (freed_width, freed_height) = {
+ let panes = self.panes.borrow_mut();
+ let pane_to_close = panes.get(&id).unwrap();
+ let freed_space = pane_to_close.position_and_size();
+ let freed_width = freed_space.cols.as_percent().unwrap();
+ let freed_height = freed_space.rows.as_percent().unwrap();
+ (freed_width, freed_height)
+ };
+ if let Some((panes_to_grow, direction)) = self.find_panes_to_grow(id) {
+ self.grow_panes(&panes_to_grow, direction, (freed_width, freed_height));
+ let side_length = match direction {
+ Direction::Vertical => self.display_area.rows,
+ Direction::Horizontal => self.display_area.cols,
+ };
+ {
+ let mut panes = self.panes.borrow_mut();
+ (*panes).remove(&id);
+ }
+ let mut pane_resizer = PaneResizer::new(self.panes.clone());
+ let _ = pane_resizer.layout(direction, side_length);
+ return true;
+ }
+ false
+ }
+ pub fn find_room_for_new_pane(&self) -> Option<(PaneId, Direction)> {
+ let panes = self.panes.borrow();
+ let pane_sequence: Vec<(&PaneId, &&mut Box<dyn Pane>)> =
+ panes.iter().filter(|(_, p)| p.selectable()).collect();
+ let (_largest_pane_size, pane_id_to_split) = pane_sequence.iter().fold(
+ (0, None),
+ |(current_largest_pane_size, current_pane_id_to_split), id_and_pane_to_check| {
+ let (id_of_pane_to_check, pane_to_check) = id_and_pane_to_check;
+ let pane_size =
+ (pane_to_check.rows() * CURSOR_HEIGHT_WIDTH_RATIO) * pane_to_check.cols();
+ let pane_can_be_split = pane_to_check.cols() >= MIN_TERMINAL_WIDTH
+ && pane_to_check.rows() >= MIN_TERMINAL_HEIGHT
+ && ((pane_to_check.cols() > pane_to_check.min_width() * 2)
+ || (pane_to_check.rows() > pane_to_check.min_height() * 2));
+ if pane_can_be_split && pane_size > current_largest_pane_size {
+ (pane_size, Some(*id_of_pane_to_check))
+ } else {
+ (current_largest_pane_size, current_pane_id_to_split)
+ }
+ },
+ );
+ pane_id_to_split.and_then(|t_id_to_split| {
+ let pane_to_split = panes.get(t_id_to_split).unwrap();
+ let direction = if pane_to_split.rows() * CURSOR_HEIGHT_WIDTH_RATIO
+ > pane_to_split.cols()
+ && pane_to_split.rows() > pane_to_split.min_height() * 2
+ {
+ Some(Direction::Horizontal)
+ } else if pane_to_split.cols() > pane_to_split.min_width() * 2 {
+ Some(Direction::Vertical)
+ } else {
+ None
+ };
+
+ direction.map(|direction| (*t_id_to_split, direction))
+ })
+ }
+}
+
+pub fn split(direction: Direction, rect: &PaneGeom) -> Option<(PaneGeom, PaneGeom)> {
+ let space = match direction {
+ Direction::Vertical => rect.cols,
+ Direction::Horizontal => rect.rows,
+ };
+ if let Some(p) = space.as_percent() {
+ let first_rect = match direction {
+ Direction::Vertical => PaneGeom {
+ cols: Dimension::percent(p / 2.0),
+ ..*rect
+ },
+ Direction::Horizontal => PaneGeom {
+ rows: Dimension::percent(p / 2.0),
+ ..*rect
+ },
+ };
+ let second_rect = match direction {
+ Direction::Vertical => PaneGeom {
+ x: first_rect.x + 1,
+ cols: first_rect.cols,
+ ..*rect
+ },
+ Direction::Horizontal => PaneGeom {
+ y: first_rect.y + 1,
+ rows: first_rect.rows,
+ ..*rect
+ },
+ };
+ Some((first_rect, second_rect))
+ } else {
+ None
+ }
+}
diff --git a/zellij-server/src/ui/pane_resizer.rs b/zellij-server/src/tab/pane_resizer.rs
index 53455e3e..7264c49a 100644
--- a/zellij-server/src/ui/pane_resizer.rs
+++ b/zellij-server/src/tab/pane_resizer.rs
@@ -4,14 +4,16 @@ use cassowary::{
Expression, Solver, Variable,
WeightedRelation::EQ,
};
+use std::cell::RefCell;
use std::collections::{HashMap, HashSet};
+use std::rc::Rc;
use zellij_utils::{
input::layout::Direction,
pane_size::{Constraint, Dimension, PaneGeom},
};
pub struct PaneResizer<'a> {
- panes: HashMap<&'a PaneId, &'a mut Box<dyn Pane>>,
+ panes: Rc<RefCell<HashMap<PaneId, &'a mut Box<dyn Pane>>>>,
vars: HashMap<PaneId, Variable>,
solver: Solver,
}
@@ -30,10 +32,9 @@ struct Span {
type Grid = Vec<Vec<Span>>;
impl<'a> PaneResizer<'a> {
- pub fn new(panes: impl IntoIterator<Item = (&'a PaneId, &'a mut Box<dyn Pane>)>) -> Self {
- let panes: HashMap<_, _> = panes.into_iter().collect();
+ pub fn new(panes: Rc<RefCell<HashMap<PaneId, &'a mut Box<dyn Pane>>>>) -> Self {
let mut vars = HashMap::new();
- for &&k in panes.keys() {
+ for &k in panes.borrow().keys() {
vars.insert(k, Variable::new());
}
PaneResizer {
@@ -122,8 +123,9 @@ impl<'a> PaneResizer<'a> {
}
fn apply_spans(&mut self, spans: Vec<Span>) {
+ let mut panes = self.panes.borrow_mut();
for span in spans {
- let pane = self.panes.get_mut(&span.pid).unwrap();
+ let pane = panes.get_mut(&span.pid).unwrap();
let new_geom = match span.direction {
Direction::Horizontal => PaneGeom {
x: span.pos,
@@ -149,6 +151,7 @@ impl<'a> PaneResizer<'a> {
// Select the spans running *perpendicular* to the direction of resize
let spans: Vec<Span> = self
.panes
+ .borrow()
.values()
.map(|p| self.get_span(!direction, p.as_ref()))
.collect();
@@ -170,6 +173,7 @@ impl<'a> PaneResizer<'a> {
let bwn = |v, (s, e)| s <= v && v < e;
let mut spans: Vec<_> = self
.panes
+ .borrow()
.values()
.filter(|p| {
let s = self.get_span(!direction, p.as_ref());
@@ -186,7 +190,8 @@ impl<'a> PaneResizer<'a> {
fn get_span(&self, direction: Direction, pane: &dyn Pane) -> Span {
let pas = pane.current_geom();
- let size_var = self.vars[&pane.pid()];
+ // let size_var = self.vars[&pane.pid()];
+ let size_var = *self.vars.get(&pane.pid()).unwrap();
match direction {
Direction::Horizontal => Span {
pid: pane.pid(),
diff --git a/zellij-server/src/unit/tab_tests.rs b/zellij-server/src/tab/unit/tab_tests.rs
index 13b97124..13b97124 100644
--- a/zellij-server/src/unit/tab_tests.rs
+++ b/zellij-server/src/tab/unit/tab_tests.rs
diff --git a/zellij-server/src/ui/mod.rs b/zellij-server/src/ui/mod.rs
index 1bf63071..71cdaab5 100644
--- a/zellij-server/src/ui/mod.rs
+++ b/zellij-server/src/ui/mod.rs
@@ -2,4 +2,3 @@ pub mod boundaries;
pub mod overlay;
pub mod pane_boundaries_frame;
pub mod pane_contents_and_ui;
-pub mod pane_resizer;