summaryrefslogtreecommitdiffstats
path: root/zellij-server/src/ui
diff options
context:
space:
mode:
authorBrooks J Rady <b.j.rady@gmail.com>2021-05-29 23:12:11 +0100
committerBrooks J Rady <b.j.rady@gmail.com>2021-05-29 23:12:11 +0100
commitf2c5ee44f7f2c61f50b043bd8e55f915a3667fce (patch)
tree3e0ab2bb70869352c47085cc857b6e86becb840a /zellij-server/src/ui
parentfe299325eb54e6642d27a417a3922a757b4390e4 (diff)
Getting back to where we started... (Buggy Resizing)
Diffstat (limited to 'zellij-server/src/ui')
-rw-r--r--zellij-server/src/ui/layout.rs29
-rw-r--r--zellij-server/src/ui/pane_resizer.rs680
2 files changed, 208 insertions, 501 deletions
diff --git a/zellij-server/src/ui/layout.rs b/zellij-server/src/ui/layout.rs
index a9af665fa..7a19d889a 100644
--- a/zellij-server/src/ui/layout.rs
+++ b/zellij-server/src/ui/layout.rs
@@ -19,17 +19,14 @@ fn split_space_to_parts_vertically(
// First fit in the parameterized sizes
for size in sizes {
- let (columns, max_columns) = match size {
+ let columns = match size {
Some(SplitSize::Percent(percent)) => {
- ((max_width as f32 * (percent as f32 / 100.0)) as usize, None)
+ (max_width as f32 * (percent as f32 / 100.0)) as usize
} // TODO: round properly
- Some(SplitSize::Fixed(size)) => (size as usize, Some(size as usize)),
+ Some(SplitSize::Fixed(size)) => size as usize,
None => {
parts_to_grow.push(current_x_position);
- (
- 1, // This is grown later on
- None,
- )
+ 1 // This is grown later on
}
};
split_parts.push(PositionAndSize {
@@ -37,7 +34,6 @@ fn split_space_to_parts_vertically(
y: space_to_split.y,
columns,
rows: space_to_split.rows,
- max_columns,
..Default::default()
});
current_width += columns;
@@ -87,18 +83,14 @@ fn split_space_to_parts_horizontally(
let mut parts_to_grow = Vec::new();
for size in sizes {
- let (rows, max_rows) = match size {
- Some(SplitSize::Percent(percent)) => (
- (max_height as f32 * (percent as f32 / 100.0)) as usize,
- None,
- ), // TODO: round properly
- Some(SplitSize::Fixed(size)) => (size as usize, Some(size as usize)),
+ let rows = match size {
+ Some(SplitSize::Percent(percent)) => {
+ (max_height as f32 * (percent as f32 / 100.0)) as usize
+ } // TODO: round properly
+ Some(SplitSize::Fixed(size)) => size as usize,
None => {
parts_to_grow.push(current_y_position);
- (
- 1, // This is grown later on
- None,
- )
+ 1 // This is grown later on
}
};
split_parts.push(PositionAndSize {
@@ -106,7 +98,6 @@ fn split_space_to_parts_horizontally(
y: current_y_position,
columns: space_to_split.columns,
rows,
- max_rows,
..Default::default()
});
current_height += rows;
diff --git a/zellij-server/src/ui/pane_resizer.rs b/zellij-server/src/ui/pane_resizer.rs
index b2001945e..73673a9c5 100644
--- a/zellij-server/src/ui/pane_resizer.rs
+++ b/zellij-server/src/ui/pane_resizer.rs
@@ -1,531 +1,247 @@
use crate::{os_input_output::ServerOsApi, panes::PaneId, tab::Pane};
+use cassowary::{
+ strength::{REQUIRED, STRONG},
+ Constraint, Solver, Variable,
+ WeightedRelation::*,
+};
use std::{
- cmp::Ordering,
collections::{BTreeMap, HashSet},
+ ops::Not,
};
use zellij_utils::pane_size::PositionAndSize;
-pub(crate) struct PaneResizer<'a> {
+const GAP_SIZE: usize = 1; // Panes are separated by this number of rows / columns
+
+pub struct PaneResizer<'a> {
panes: &'a mut BTreeMap<PaneId, Box<dyn Pane>>,
+ vars: BTreeMap<PaneId, (Variable, Variable)>,
+ solver: Solver,
os_api: &'a mut Box<dyn ServerOsApi>,
}
+#[derive(Debug, Clone, Copy)]
+enum Direction {
+ Horizontal,
+ Vertical,
+}
+
+impl Not for Direction {
+ type Output = Self;
+
+ fn not(self) -> Self::Output {
+ match self {
+ Direction::Horizontal => Direction::Vertical,
+ Direction::Vertical => Direction::Horizontal,
+ }
+ }
+}
+
+#[derive(Debug, Clone, Copy)]
+struct Span {
+ pid: PaneId,
+ direction: Direction,
+ fixed: bool,
+ pos: usize,
+ size: usize,
+ pos_var: Variable,
+ size_var: Variable,
+}
+
// TODO: currently there are some functions here duplicated with Tab
// all resizing functions should move here
+// FIXME:
+// 1. Rounding causes a loss of ratios, I need to store an internal f64 for
+// each pane as well as the displayed usize and add custom rounding logic.
+// 2. Vertical resizing doesn't seem to respect the space consumed by the tab
+// and status bars?
+// 3. A 2x2 layout and simultaneous vertical + horizontal resizing sometimes
+// leads to unsolvable constraints? Maybe related to 2 (and possibly 1).
+// I should sanity-check the `spans_in_boundary()` here!
+
impl<'a> PaneResizer<'a> {
pub fn new(
panes: &'a mut BTreeMap<PaneId, Box<dyn Pane>>,
os_api: &'a mut Box<dyn ServerOsApi>,
) -> Self {
- PaneResizer { panes, os_api }
+ let mut vars = BTreeMap::new();
+ for &k in panes.keys() {
+ vars.insert(k, (Variable::new(), Variable::new()));
+ }
+ PaneResizer {
+ panes,
+ vars,
+ solver: Solver::new(),
+ os_api,
+ }
}
+
pub fn resize(
&mut self,
- mut current_size: PositionAndSize,
+ current_size: PositionAndSize,
new_size: PositionAndSize,
) -> Option<(isize, isize)> {
- // (column_difference, row_difference)
- let mut successfully_resized = false;
- let mut column_difference: isize = 0;
- let mut row_difference: isize = 0;
- match new_size.columns.cmp(&current_size.columns) {
- Ordering::Greater => {
- let increase_by = new_size.columns - current_size.columns;
- if let Some(panes_to_resize) = find_increasable_vertical_chain(
- &self.panes,
- increase_by,
- current_size.columns,
- current_size.rows,
- ) {
- self.increase_panes_right_and_push_adjacents_right(
- panes_to_resize,
- increase_by,
- );
- column_difference = new_size.columns as isize - current_size.columns as isize;
- current_size.columns =
- (current_size.columns as isize + column_difference) as usize;
- successfully_resized = true;
- };
- }
- Ordering::Less => {
- let reduce_by = current_size.columns - new_size.columns;
- if let Some(panes_to_resize) = find_reducible_vertical_chain(
- &self.panes,
- reduce_by,
- current_size.columns,
- current_size.rows,
- ) {
- self.reduce_panes_left_and_pull_adjacents_left(panes_to_resize, reduce_by);
- column_difference = new_size.columns as isize - current_size.columns as isize;
- current_size.columns =
- (current_size.columns as isize + column_difference) as usize;
- successfully_resized = true;
- };
- }
- Ordering::Equal => (),
- }
- match new_size.rows.cmp(&current_size.rows) {
- Ordering::Greater => {
- let increase_by = new_size.rows - current_size.rows;
- if let Some(panes_to_resize) = find_increasable_horizontal_chain(
- &self.panes,
- increase_by,
- current_size.columns,
- current_size.rows,
- ) {
- self.increase_panes_down_and_push_down_adjacents(panes_to_resize, increase_by);
- row_difference = new_size.rows as isize - current_size.rows as isize;
- current_size.rows = (current_size.rows as isize + row_difference) as usize;
- successfully_resized = true;
- };
- }
- Ordering::Less => {
- let reduce_by = current_size.rows - new_size.rows;
- if let Some(panes_to_resize) = find_reducible_horizontal_chain(
- &self.panes,
- reduce_by,
- current_size.columns,
- current_size.rows,
- ) {
- self.reduce_panes_up_and_pull_adjacents_up(panes_to_resize, reduce_by);
- row_difference = new_size.rows as isize - current_size.rows as isize;
- current_size.rows = (current_size.rows as isize + row_difference) as usize;
- successfully_resized = true;
- };
- }
- Ordering::Equal => (),
- }
- if successfully_resized {
- Some((column_difference, row_difference))
- } else {
- None
- }
- }
- fn reduce_panes_left_and_pull_adjacents_left(
- &mut self,
- panes_to_reduce: Vec<PaneId>,
- reduce_by: usize,
- ) {
- let mut pulled_panes: HashSet<PaneId> = HashSet::new();
- for pane_id in panes_to_reduce {
- let (pane_x, pane_y, pane_columns, pane_rows) = {
- let pane = self.panes.get(&pane_id).unwrap();
- (pane.x(), pane.y(), pane.columns(), pane.rows())
- };
- let panes_to_pull = self.panes.values_mut().filter(|p| {
- p.x() > pane_x + pane_columns
- && (p.y() <= pane_y && p.y() + p.rows() >= pane_y
- || p.y() >= pane_y && p.y() + p.rows() <= pane_y + pane_rows)
- });
- for pane in panes_to_pull {
- if !pulled_panes.contains(&pane.pid()) {
- pane.pull_left(reduce_by);
- pulled_panes.insert(pane.pid());
- }
- }
- self.reduce_pane_width_left(&pane_id, reduce_by);
- }
- }
- fn reduce_panes_up_and_pull_adjacents_up(
- &mut self,
- panes_to_reduce: Vec<PaneId>,
- reduce_by: usize,
- ) {
- let mut pulled_panes: HashSet<PaneId> = HashSet::new();
- for pane_id in panes_to_reduce {
- let (pane_x, pane_y, pane_columns, pane_rows) = {
- let pane = self.panes.get(&pane_id).unwrap();
- (pane.x(), pane.y(), pane.columns(), pane.rows())
- };
- let panes_to_pull = self.panes.values_mut().filter(|p| {
- p.y() > pane_y + pane_rows
- && (p.x() <= pane_x && p.x() + p.columns() >= pane_x
- || p.x() >= pane_x && p.x() + p.columns() <= pane_x + pane_columns)
- });
- for pane in panes_to_pull {
- if !pulled_panes.contains(&pane.pid()) {
- pane.pull_up(reduce_by);
- pulled_panes.insert(pane.pid());
- }
- }
- self.reduce_pane_height_up(&pane_id, reduce_by);
- }
- }
- fn increase_panes_down_and_push_down_adjacents(
- &mut self,
- panes_to_increase: Vec<PaneId>,
- increase_by: usize,
- ) {
- let mut pushed_panes: HashSet<PaneId> = HashSet::new();
- for pane_id in panes_to_increase {
- let (pane_x, pane_y, pane_columns, pane_rows) = {
- let pane = self.panes.get(&pane_id).unwrap();
- (pane.x(), pane.y(), pane.columns(), pane.rows())
- };
- let panes_to_push = self.panes.values_mut().filter(|p| {
- p.y() > pane_y + pane_rows
- && (p.x() <= pane_x && p.x() + p.columns() >= pane_x
- || p.x() >= pane_x && p.x() + p.columns() <= pane_x + pane_columns)
- });
- for pane in panes_to_push {
- if !pushed_panes.contains(&pane.pid()) {
- pane.push_down(increase_by);
- pushed_panes.insert(pane.pid());
- }
- }
- self.increase_pane_height_down(&pane_id, increase_by);
- }
- }
- fn increase_panes_right_and_push_adjacents_right(
- &mut self,
- panes_to_increase: Vec<PaneId>,
- increase_by: usize,
- ) {
- let mut pushed_panes: HashSet<PaneId> = HashSet::new();
- for pane_id in panes_to_increase {
- let (pane_x, pane_y, pane_columns, pane_rows) = {
- let pane = self.panes.get(&pane_id).unwrap();
- (pane.x(), pane.y(), pane.columns(), pane.rows())
- };
- let panes_to_push = self.panes.values_mut().filter(|p| {
- p.x() > pane_x + pane_columns
- && (p.y() <= pane_y && p.y() + p.rows() >= pane_y
- || p.y() >= pane_y && p.y() + p.rows() <= pane_y + pane_rows)
- });
- for pane in panes_to_push {
- if !pushed_panes.contains(&pane.pid()) {
- pane.push_right(increase_by);
- pushed_panes.insert(pane.pid());
- }
- }
- self.increase_pane_width_right(&pane_id, increase_by);
- }
- }
- fn reduce_pane_height_up(&mut self, id: &PaneId, count: usize) {
- let pane = self.panes.get_mut(id).unwrap();
- pane.reduce_height_up(count);
- if let PaneId::Terminal(pid) = id {
- self.os_api
- .set_terminal_size_using_fd(*pid, pane.columns() as u16, pane.rows() as u16);
- }
- }
- fn increase_pane_height_down(&mut self, id: &PaneId, count: usize) {
- let pane = self.panes.get_mut(id).unwrap();
- pane.increase_height_down(count);
- if let PaneId::Terminal(pid) = pane.pid() {
- self.os_api
- .set_terminal_size_using_fd(pid, pane.columns() as u16, pane.rows() as u16);
- }
- }
- fn increase_pane_width_right(&mut self, id: &PaneId, count: usize) {
- let pane = self.panes.get_mut(id).unwrap();
- pane.increase_width_right(count);
- if let PaneId::Terminal(pid) = pane.pid() {
- self.os_api
- .set_terminal_size_using_fd(pid, pane.columns() as u16, pane.rows() as u16);
- }
- }
- fn reduce_pane_width_left(&mut self, id: &PaneId, count: usize) {
- let pane = self.panes.get_mut(id).unwrap();
- pane.reduce_width_left(count);
- if let PaneId::Terminal(pid) = pane.pid() {
- self.os_api
- .set_terminal_size_using_fd(pid, pane.columns() as u16, pane.rows() as u16);
- }
+ let col_delta = new_size.columns as isize - current_size.columns as isize;
+ let row_delta = new_size.rows as isize - current_size.rows as isize;
+ if col_delta != 0 {
+ let spans = self.solve_direction(Direction::Horizontal, new_size.columns)?;
+ self.collapse_spans(&spans);
+ }
+ self.solver.reset();
+ if row_delta != 0 {
+ let spans = self.solve_direction(Direction::Vertical, new_size.rows)?;
+ self.collapse_spans(&spans);
+ }
+ Some((col_delta, row_delta))
}
-}
-fn find_next_increasable_horizontal_pane(
- panes: &BTreeMap<PaneId, Box<dyn Pane>>,
- right_of: &dyn Pane,
- increase_by: usize,
-) -> Option<PaneId> {
- let next_pane_candidates = panes.values().filter(
- |p| {
- p.x() == right_of.x() + right_of.columns() + 1 && p.horizontally_overlaps_with(right_of)
- }, // TODO: the name here is wrong, it should be vertically_overlaps_with
- );
- let resizable_candidates =
- next_pane_candidates.filter(|p| p.can_increase_height_by(increase_by));
- resizable_candidates.fold(None, |next_pane_id, p| match next_pane_id {
- Some(next_pane) => {
- let next_pane = panes.get(&next_pane).unwrap();
- if next_pane.y() < p.y() {
- next_pane_id
- } else {
- Some(p.pid())
- }
+ fn solve_direction(&mut self, direction: Direction, space: usize) -> Option<Vec<Span>> {
+ let mut grid = Vec::new();
+ for boundary in self.grid_boundaries(direction) {
+ grid.push(self.spans_in_boundary(direction, boundary));
}
- None => Some(p.pid()),
- })
-}
-fn find_next_increasable_vertical_pane(
- panes: &BTreeMap<PaneId, Box<dyn Pane>>,
- below: &dyn Pane,
- increase_by: usize,
-) -> Option<PaneId> {
- let next_pane_candidates = panes.values().filter(
- |p| p.y() == below.y() + below.rows() + 1 && p.vertically_overlaps_with(below), // TODO: the name here is wrong, it should be horizontally_overlaps_with
- );
- let resizable_candidates =
- next_pane_candidates.filter(|p| p.can_increase_width_by(increase_by));
- resizable_candidates.fold(None, |next_pane_id, p| match next_pane_id {
- Some(next_pane) => {
- let next_pane = panes.get(&next_pane).unwrap();
- if next_pane.x() < p.x() {
- next_pane_id
- } else {
- Some(p.pid())
- }
- }
- None => Some(p.pid()),
- })
-}
+ let constraints: Vec<_> = grid
+ .iter()
+ .flat_map(|s| constrain_spans(space, s))
+ .collect();
-fn find_next_reducible_vertical_pane(
- panes: &BTreeMap<PaneId, Box<dyn Pane>>,
- below: &dyn Pane,
- reduce_by: usize,
-) -> Option<PaneId> {
- let next_pane_candidates = panes.values().filter(
- |p| p.y() == below.y() + below.rows() + 1 && p.vertically_overlaps_with(below), // TODO: the name here is wrong, it should be horizontally_overlaps_with
- );
- let resizable_candidates = next_pane_candidates.filter(|p| p.can_reduce_width_by(reduce_by));
- resizable_candidates.fold(None, |next_pane_id, p| match next_pane_id {
- Some(next_pane) => {
- let next_pane = panes.get(&next_pane).unwrap();
- if next_pane.x() < p.x() {
- next_pane_id
- } else {
- Some(p.pid())
- }
- }
- None => Some(p.pid()),
- })
-}
+ // FIXME: This line needs to be restored before merging!
+ //self.solver.add_constraints(&constraints).ok()?;
+ self.solver.add_constraints(&constraints).unwrap();
+ Some(grid.into_iter().flatten().collect())
+ }
-fn find_next_reducible_horizontal_pane(
- panes: &BTreeMap<PaneId, Box<dyn Pane>>,
- right_of: &dyn Pane,
- reduce_by: usize,
-) -> Option<PaneId> {
- let next_pane_candidates = panes.values().filter(
- |p| {
- p.x() == right_of.x() + right_of.columns() + 1 && p.horizontally_overlaps_with(right_of)
- }, // TODO: the name here is wrong, it should be vertically_overlaps_with
- );
- let resizable_candidates = next_pane_candidates.filter(|p| p.can_reduce_height_by(reduce_by));
- resizable_candidates.fold(None, |next_pane_id, p| match next_pane_id {
- Some(next_pane) => {
- let next_pane = panes.get(&next_pane).unwrap();
- if next_pane.y() < p.y() {
- next_pane_id
+ fn grid_boundaries(&self, direction: Direction) -> Vec<(usize, usize)> {
+ // Select the spans running *perpendicular* to the direction of resize
+ let spans: Vec<Span> = self
+ .panes
+ .values()
+ .map(|p| self.get_span(!direction, p.as_ref()))
+ .collect();
+
+ let mut last_edge = 0;
+ let mut bounds = Vec::new();
+ loop {
+ let mut spans_on_edge: Vec<&Span> =
+ spans.iter().filter(|p| p.pos == last_edge).collect();
+ spans_on_edge.sort_unstable_by_key(|s| s.size);
+ if let Some(next) = spans_on_edge.first() {
+ let next_edge = last_edge + next.size;
+ bounds.push((last_edge, next_edge));
+ last_edge = next_edge + GAP_SIZE;
} else {
- Some(p.pid())
+ break;
}
}
- None => Some(p.pid()),
- })
-}
-
-fn find_increasable_horizontal_chain(
- panes: &BTreeMap<PaneId, Box<dyn Pane>>,
- increase_by: usize,
- screen_width: usize,
- screen_height: usize, // TODO: this is the previous size (make this clearer)
-) -> Option<Vec<PaneId>> {
- let mut horizontal_coordinate = 0;
- loop {
- if horizontal_coordinate == screen_height {
- return None;
- }
+ bounds
+ }
- match panes
+ fn spans_in_boundary(&self, direction: Direction, boundary: (usize, usize)) -> Vec<Span> {
+ let (start, end) = boundary;
+ let bwn = |v| start <= v && v < end;
+ let mut spans: Vec<_> = self
+ .panes
.values()
- .find(|p| p.x() == 0 && p.y() == horizontal_coordinate)
- {
- Some(leftmost_pane) => {
- if !leftmost_pane.can_increase_height_by(increase_by) {
- horizontal_coordinate = leftmost_pane.y() + leftmost_pane.rows() + 1;
- continue;
- }
- let mut panes_to_resize = vec![];
- let mut current_pane = leftmost_pane;
- loop {
- panes_to_resize.push(current_pane.pid());
- if current_pane.x() + current_pane.columns() == screen_width {
- return Some(panes_to_resize);
- }
- match find_next_increasable_horizontal_pane(
- panes,
- current_pane.as_ref(),
- increase_by,
- ) {
- Some(next_pane_id) => {
- current_pane = panes.get(&next_pane_id).unwrap();
- }
- None => {
- horizontal_coordinate = leftmost_pane.y() + leftmost_pane.rows() + 1;
- break;
- }
- };
- }
- }
- None => {
- return None;
- }
- }
+ .filter(|p| {
+ let s = self.get_span(!direction, p.as_ref());
+ bwn(s.pos) || bwn(s.pos + s.size)
+ })
+ .map(|p| self.get_span(direction, p.as_ref()))
+ .collect();
+ spans.sort_unstable_by_key(|s| s.pos);
+ spans
}
-}
-fn find_increasable_vertical_chain(
- panes: &BTreeMap<PaneId, Box<dyn Pane>>,
- increase_by: usize,
- screen_width: usize,
- screen_height: usize, // TODO: this is the previous size (make this clearer)
-) -> Option<Vec<PaneId>> {
- let mut vertical_coordinate = 0;
- loop {
- if vertical_coordinate == screen_width {
- return None;
+ fn get_span(&self, direction: Direction, pane: &dyn Pane) -> Span {
+ let pas = pane.position_and_size();
+ let (pos_var, size_var) = self.vars[&pane.pid()];
+ match direction {
+ Direction::Horizontal => Span {
+ pid: pane.pid(),
+ direction,
+ fixed: pas.cols_fixed,
+ pos: pas.x,
+ size: pas.columns,
+ pos_var,
+ size_var,
+ },
+ Direction::Vertical => Span {
+ pid: pane.pid(),
+ direction,
+ fixed: pas.rows_fixed,
+ pos: pas.y,
+ size: pas.rows,
+ pos_var,
+ size_var,
+ },
}
+ }
- match panes
- .values()
- .find(|p| p.y() == 0 && p.x() == vertical_coordinate)
- {
- Some(topmost_pane) => {
- if !topmost_pane.can_increase_width_by(increase_by) {
- vertical_coordinate = topmost_pane.x() + topmost_pane.columns() + 1;
- continue;
- }
- let mut panes_to_resize = vec![];
- let mut current_pane = topmost_pane;
- loop {
- panes_to_resize.push(current_pane.pid());
- if current_pane.y() + current_pane.rows() == screen_height {
- return Some(panes_to_resize);
- }
- match find_next_increasable_vertical_pane(
- panes,
- current_pane.as_ref(),
- increase_by,
- ) {
- Some(next_pane_id) => {
- current_pane = panes.get(&next_pane_id).unwrap();
- }
- None => {
- vertical_coordinate = topmost_pane.x() + topmost_pane.columns() + 1;
- break;
- }
- };
- }
- }
- None => {
- return None;
+ fn collapse_spans(&mut self, spans: &[Span]) {
+ for span in spans {
+ let solver = &self.solver; // Hand-holding the borrow-checker
+ let pane = self.panes.get_mut(&span.pid).unwrap();
+ let fetch_usize = |v| solver.get_value(v).round() as usize;
+ match span.direction {
+ Direction::Horizontal => pane.change_pos_and_size(&PositionAndSize {
+ x: fetch_usize(span.pos_var),
+ columns: fetch_usize(span.size_var),
+ ..pane.position_and_size()
+ }),
+ Direction::Vertical => pane.change_pos_and_size(&PositionAndSize {
+ y: fetch_usize(span.pos_var),
+ rows: fetch_usize(span.size_var),
+ ..pane.position_and_size()
+ }),
+ }
+ if let PaneId::Terminal(pid) = pane.pid() {
+ self.os_api.set_terminal_size_using_fd(
+ pid,
+ pane.columns() as u16,
+ pane.rows() as u16,
+ );
}
}
}
}
-fn find_reducible_horizontal_chain(
- panes: &BTreeMap<PaneId, Box<dyn Pane>>,
- reduce_by: usize,
- screen_width: usize,
- screen_height: usize, // TODO: this is the previous size (make this clearer)
-) -> Option<Vec<PaneId>> {
- let mut horizontal_coordinate = 0;
- loop {
- if horizontal_coordinate == screen_height {
- return None;
- }
+fn constrain_spans(space: usize, spans: &[Span]) -> HashSet<Constraint> {
+ let mut constraints = HashSet::new();
- match panes
- .values()
- .find(|p| p.x() == 0 && p.y() == horizontal_coordinate)
-