feat(ui): stacked resize (#3957)

* work

* tests and initial notes for refactoring

* refactor(stacked-panes): break out pane

* vertical functionality working with a single stack

* refactor: break out pane from stack

* fix: properly support multiple stacks in tab

* combining multiple stacks vertically

* vertical resizing working for all cases

* base functionality and tests

* some UX tweaking

* final functionality for directionless stacked increase

* some cleanups

* moar cleanups

* refactor: stacked resize

* fix: issue where resizing stacked geoms to 0 would cause them to overflow afterwards

* fix: handle uneven stacking

* functionality with tombstones

* new open new pane functionality

* match decrease increment behavior to increase one and fix some issues

* set fullscreen if maxed out

* allow splitting stacks

* fix tests mostly by parameterizing stacked_resize

* add tests

* some cleanups

* style(fmt): rustfmt

* add to config

* disable ci cache

* is_stacked => stacked

* docs(config): remove duplication
This commit is contained in:
Aram Drevekenin 2025-01-28 21:24:07 +01:00 committed by GitHub
parent 7f0b8b6416
commit 407120b872
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
72 changed files with 7132 additions and 295 deletions

View file

@ -408,3 +408,8 @@ load_plugins {
// Default: true (if the host terminal supports it) // Default: true (if the host terminal supports it)
// //
// support_kitty_keyboard_protocol false // support_kitty_keyboard_protocol false
// Whether to stack panes when resizing beyond a certain size
// Default: true
//
// stacked_resize false

View file

@ -455,7 +455,7 @@ impl RemoteRunner {
y: 0, y: 0,
rows, rows,
cols, cols,
is_stacked: false, stacked: None,
is_pinned: false, is_pinned: false,
logical_position: None, logical_position: None,
}; };
@ -493,7 +493,7 @@ impl RemoteRunner {
y: 0, y: 0,
rows, rows,
cols, cols,
is_stacked: false, stacked: None,
is_pinned: false, is_pinned: false,
logical_position: None, logical_position: None,
}; };
@ -531,7 +531,7 @@ impl RemoteRunner {
y: 0, y: 0,
rows, rows,
cols, cols,
is_stacked: false, stacked: None,
is_pinned: false, is_pinned: false,
logical_position: None, logical_position: None,
}; };
@ -572,7 +572,7 @@ impl RemoteRunner {
y: 0, y: 0,
rows, rows,
cols, cols,
is_stacked: false, stacked: None,
is_pinned: false, is_pinned: false,
logical_position: None, logical_position: None,
}; };
@ -620,7 +620,7 @@ impl RemoteRunner {
y: 0, y: 0,
rows, rows,
cols, cols,
is_stacked: false, stacked: None,
is_pinned: false, is_pinned: false,
logical_position: None, logical_position: None,
}; };
@ -658,7 +658,7 @@ impl RemoteRunner {
y: 0, y: 0,
rows, rows,
cols, cols,
is_stacked: false, stacked: None,
is_pinned: false, is_pinned: false,
logical_position: None, logical_position: None,
}; };
@ -696,7 +696,7 @@ impl RemoteRunner {
y: 0, y: 0,
rows, rows,
cols, cols,
is_stacked: false, stacked: None,
is_pinned: false, is_pinned: false,
logical_position: None, logical_position: None,
}; };
@ -735,7 +735,7 @@ impl RemoteRunner {
y: 0, y: 0,
rows, rows,
cols, cols,
is_stacked: false, stacked: None,
is_pinned: false, is_pinned: false,
logical_position: None, logical_position: None,
}; };

View file

@ -363,6 +363,7 @@ impl SessionMetaData {
auto_layout: new_config.options.auto_layout.unwrap_or(true), auto_layout: new_config.options.auto_layout.unwrap_or(true),
rounded_corners: new_config.ui.pane_frames.rounded_corners, rounded_corners: new_config.ui.pane_frames.rounded_corners,
hide_session_name: new_config.ui.pane_frames.hide_session_name, hide_session_name: new_config.ui.pane_frames.hide_session_name,
stacked_resize: new_config.options.stacked_resize.unwrap_or(true),
}) })
.unwrap(); .unwrap();
self.senders self.senders

View file

@ -856,7 +856,7 @@ pub fn half_size_middle_geom(space: &Viewport, offset: usize) -> PaneGeom {
y: space.y + (space.rows as f64 / 4.0).round() as usize + offset, y: space.y + (space.rows as f64 / 4.0).round() as usize + offset,
cols: Dimension::fixed(space.cols / 2), cols: Dimension::fixed(space.cols / 2),
rows: Dimension::fixed(space.rows / 2), rows: Dimension::fixed(space.rows / 2),
is_stacked: false, stacked: None,
is_pinned: false, is_pinned: false,
logical_position: None, logical_position: None,
}; };
@ -871,7 +871,7 @@ fn half_size_top_left_geom(space: &Viewport, offset: usize) -> PaneGeom {
y: space.y + 2 + offset, y: space.y + 2 + offset,
cols: Dimension::fixed(space.cols / 3), cols: Dimension::fixed(space.cols / 3),
rows: Dimension::fixed(space.rows / 3), rows: Dimension::fixed(space.rows / 3),
is_stacked: false, stacked: None,
is_pinned: false, is_pinned: false,
logical_position: None, logical_position: None,
}; };
@ -886,7 +886,7 @@ fn half_size_top_right_geom(space: &Viewport, offset: usize) -> PaneGeom {
y: space.y + 2 + offset, y: space.y + 2 + offset,
cols: Dimension::fixed(space.cols / 3), cols: Dimension::fixed(space.cols / 3),
rows: Dimension::fixed(space.rows / 3), rows: Dimension::fixed(space.rows / 3),
is_stacked: false, stacked: None,
is_pinned: false, is_pinned: false,
logical_position: None, logical_position: None,
}; };
@ -901,7 +901,7 @@ fn half_size_bottom_left_geom(space: &Viewport, offset: usize) -> PaneGeom {
y: ((space.y + space.rows) - (space.rows / 3) - 2).saturating_sub(offset), y: ((space.y + space.rows) - (space.rows / 3) - 2).saturating_sub(offset),
cols: Dimension::fixed(space.cols / 3), cols: Dimension::fixed(space.cols / 3),
rows: Dimension::fixed(space.rows / 3), rows: Dimension::fixed(space.rows / 3),
is_stacked: false, stacked: None,
is_pinned: false, is_pinned: false,
logical_position: None, logical_position: None,
}; };
@ -916,7 +916,7 @@ fn half_size_bottom_right_geom(space: &Viewport, offset: usize) -> PaneGeom {
y: ((space.y + space.rows) - (space.rows / 3) - 2).saturating_sub(offset), y: ((space.y + space.rows) - (space.rows / 3) - 2).saturating_sub(offset),
cols: Dimension::fixed(space.cols / 3), cols: Dimension::fixed(space.cols / 3),
rows: Dimension::fixed(space.rows / 3), rows: Dimension::fixed(space.rows / 3),
is_stacked: false, stacked: None,
is_pinned: false, is_pinned: false,
logical_position: None, logical_position: None,
}; };

View file

@ -18,7 +18,7 @@ use crate::{
}; };
use stacked_panes::StackedPanes; use stacked_panes::StackedPanes;
use zellij_utils::{ use zellij_utils::{
data::{Direction, ModeInfo, Palette, PaneInfo, ResizeStrategy, Style}, data::{Direction, ModeInfo, Palette, PaneInfo, Resize, ResizeStrategy, Style},
errors::prelude::*, errors::prelude::*,
input::{ input::{
command::RunCommand, command::RunCommand,
@ -61,6 +61,7 @@ pub struct TiledPanes {
connected_clients_in_app: Rc<RefCell<HashSet<ClientId>>>, connected_clients_in_app: Rc<RefCell<HashSet<ClientId>>>,
mode_info: Rc<RefCell<HashMap<ClientId, ModeInfo>>>, mode_info: Rc<RefCell<HashMap<ClientId, ModeInfo>>>,
character_cell_size: Rc<RefCell<Option<SizeInPixels>>>, character_cell_size: Rc<RefCell<Option<SizeInPixels>>>,
stacked_resize: Rc<RefCell<bool>>,
default_mode_info: ModeInfo, default_mode_info: ModeInfo,
style: Style, style: Style,
session_is_mirrored: bool, session_is_mirrored: bool,
@ -71,6 +72,8 @@ pub struct TiledPanes {
senders: ThreadSenders, senders: ThreadSenders,
window_title: Option<String>, window_title: Option<String>,
client_id_to_boundaries: HashMap<ClientId, Boundaries>, client_id_to_boundaries: HashMap<ClientId, Boundaries>,
tombstones_before_increase: Option<(PaneId, Vec<HashMap<PaneId, PaneGeom>>)>,
tombstones_before_decrease: Option<(PaneId, Vec<HashMap<PaneId, PaneGeom>>)>,
} }
impl TiledPanes { impl TiledPanes {
@ -82,6 +85,7 @@ impl TiledPanes {
connected_clients_in_app: Rc<RefCell<HashSet<ClientId>>>, connected_clients_in_app: Rc<RefCell<HashSet<ClientId>>>,
mode_info: Rc<RefCell<HashMap<ClientId, ModeInfo>>>, mode_info: Rc<RefCell<HashMap<ClientId, ModeInfo>>>,
character_cell_size: Rc<RefCell<Option<SizeInPixels>>>, character_cell_size: Rc<RefCell<Option<SizeInPixels>>>,
stacked_resize: Rc<RefCell<bool>>,
session_is_mirrored: bool, session_is_mirrored: bool,
draw_pane_frames: bool, draw_pane_frames: bool,
default_mode_info: ModeInfo, default_mode_info: ModeInfo,
@ -97,6 +101,7 @@ impl TiledPanes {
connected_clients_in_app, connected_clients_in_app,
mode_info, mode_info,
character_cell_size, character_cell_size,
stacked_resize,
default_mode_info, default_mode_info,
style, style,
session_is_mirrored, session_is_mirrored,
@ -107,6 +112,8 @@ impl TiledPanes {
senders, senders,
window_title: None, window_title: None,
client_id_to_boundaries: HashMap::new(), client_id_to_boundaries: HashMap::new(),
tombstones_before_increase: None,
tombstones_before_decrease: None,
} }
} }
pub fn add_pane_with_existing_geom(&mut self, pane_id: PaneId, mut pane: Box<dyn Pane>) { pub fn add_pane_with_existing_geom(&mut self, pane_id: PaneId, mut pane: Box<dyn Pane>) {
@ -162,13 +169,23 @@ impl TiledPanes {
self.reapply_pane_frames(); self.reapply_pane_frames();
removed_pane removed_pane
} }
pub fn insert_pane(&mut self, pane_id: PaneId, pane: Box<dyn Pane>) { pub fn insert_pane(
&mut self,
pane_id: PaneId,
pane: Box<dyn Pane>,
client_id: Option<ClientId>,
) {
let should_relayout = true; let should_relayout = true;
self.add_pane(pane_id, pane, should_relayout); self.add_pane(pane_id, pane, should_relayout, client_id);
} }
pub fn insert_pane_without_relayout(&mut self, pane_id: PaneId, pane: Box<dyn Pane>) { pub fn insert_pane_without_relayout(
&mut self,
pane_id: PaneId,
pane: Box<dyn Pane>,
client_id: Option<ClientId>,
) {
let should_relayout = false; let should_relayout = false;
self.add_pane(pane_id, pane, should_relayout); self.add_pane(pane_id, pane, should_relayout, client_id);
} }
pub fn has_room_for_new_pane(&mut self) -> bool { pub fn has_room_for_new_pane(&mut self) -> bool {
let cursor_height_width_ratio = self.cursor_height_width_ratio(); let cursor_height_width_ratio = self.cursor_height_width_ratio();
@ -200,15 +217,29 @@ impl TiledPanes {
.copied() .copied()
{ {
if let Some(pane) = self.panes.remove(&pane_id) { if let Some(pane) = self.panes.remove(&pane_id) {
self.add_pane(pane.pid(), pane, true); self.add_pane(pane.pid(), pane, true, None);
} }
} }
} }
fn add_pane(&mut self, pane_id: PaneId, mut pane: Box<dyn Pane>, should_relayout: bool) { fn add_pane(
&mut self,
pane_id: PaneId,
mut pane: Box<dyn Pane>,
should_relayout: bool,
client_id: Option<ClientId>,
) {
if self.panes.is_empty() { if self.panes.is_empty() {
self.panes.insert(pane_id, pane); self.panes.insert(pane_id, pane);
return; return;
} }
let stacked_resize = { *self.stacked_resize.borrow() };
if let Some(client_id) = client_id {
if stacked_resize {
self.add_pane_with_stacked_resize(pane_id, pane, should_relayout, client_id);
return;
}
}
let cursor_height_width_ratio = self.cursor_height_width_ratio(); let cursor_height_width_ratio = self.cursor_height_width_ratio();
let mut pane_grid = TiledPaneGrid::new( let mut pane_grid = TiledPaneGrid::new(
&mut self.panes, &mut self.panes,
@ -216,6 +247,8 @@ impl TiledPanes {
*self.display_area.borrow(), *self.display_area.borrow(),
*self.viewport.borrow(), *self.viewport.borrow(),
); );
// TODO: make sure this is really the same as the pre-stacked-resizes function... and
// behaves the same and all
let pane_id_and_split_direction = let pane_id_and_split_direction =
pane_grid.find_room_for_new_pane(cursor_height_width_ratio); pane_grid.find_room_for_new_pane(cursor_height_width_ratio);
match pane_id_and_split_direction { match pane_id_and_split_direction {
@ -248,6 +281,76 @@ impl TiledPanes {
}, },
} }
} }
fn add_pane_with_stacked_resize(
&mut self,
pane_id: PaneId,
mut pane: Box<dyn Pane>,
should_relayout: bool,
client_id: ClientId,
) {
let cursor_height_width_ratio = self.cursor_height_width_ratio();
let mut pane_grid = TiledPaneGrid::new(
&mut self.panes,
&self.panes_to_hide,
*self.display_area.borrow(),
*self.viewport.borrow(),
);
let Some(active_pane_id) = self.active_panes.get(&client_id) else {
log::error!("Could not find active pane id for client_id");
return;
};
if pane_grid
.get_pane_geom(active_pane_id)
.map(|p| p.is_stacked())
.unwrap_or(false)
{
// try to add the pane to the stack of the active pane
match pane_grid.make_room_in_stack_of_pane_id_for_pane(active_pane_id) {
Ok(new_pane_geom) => {
pane.set_geom(new_pane_geom);
self.panes.insert(pane_id, pane);
self.set_force_render(); // TODO: why do we need this?
return;
},
Err(e) => {
log::error!("Failed to add pane to stack: {:?}", e);
},
}
}
let pane_id_and_split_direction =
pane_grid.split_pane(active_pane_id, cursor_height_width_ratio);
match pane_id_and_split_direction {
Some((pane_id_to_split, split_direction)) => {
// this unwrap is safe because floating panes should not be visible if there are no floating panes
let pane_to_split = self.panes.get_mut(&pane_id_to_split).unwrap();
let size_of_both_panes = pane_to_split.position_and_size();
if let Some((first_geom, second_geom)) = split(split_direction, &size_of_both_panes)
{
pane_to_split.set_geom(first_geom);
pane.set_geom(second_geom);
self.panes.insert(pane_id, pane);
if should_relayout {
self.relayout(!split_direction);
}
}
},
None => {
// we couldn't add the pane normally, let's see if there's room in one of the
// stacks...
let _ = pane_grid.make_pane_stacked(active_pane_id);
match pane_grid.make_room_in_stack_of_pane_id_for_pane(active_pane_id) {
Ok(new_pane_geom) => {
pane.set_geom(new_pane_geom);
self.panes.insert(pane_id, pane); // TODO: is set_geom the right one?
return;
},
Err(e) => {
log::error!("Failed to add pane to stack: {:?}", e);
},
}
},
}
}
pub fn fixed_pane_geoms(&self) -> Vec<Viewport> { pub fn fixed_pane_geoms(&self) -> Vec<Viewport> {
self.panes self.panes
.values() .values()
@ -349,7 +452,7 @@ impl TiledPanes {
let position_and_size = pane.current_geom(); let position_and_size = pane.current_geom();
let (pane_columns_offset, pane_rows_offset) = let (pane_columns_offset, pane_rows_offset) =
pane_content_offset(&position_and_size, &viewport); pane_content_offset(&position_and_size, &viewport);
if !draw_pane_frames && pane.current_geom().is_stacked { if !draw_pane_frames && pane.current_geom().is_stacked() {
// stacked panes should always leave 1 top row for a title // stacked panes should always leave 1 top row for a title
pane.set_content_offset(Offset::shift_right_and_top(pane_columns_offset, 1)); pane.set_content_offset(Offset::shift_right_and_top(pane_columns_offset, 1));
} else { } else {
@ -364,10 +467,20 @@ impl TiledPanes {
pub fn can_split_pane_horizontally(&mut self, client_id: ClientId) -> bool { pub fn can_split_pane_horizontally(&mut self, client_id: ClientId) -> bool {
if let Some(active_pane_id) = &self.active_panes.get(&client_id) { if let Some(active_pane_id) = &self.active_panes.get(&client_id) {
if let Some(active_pane) = self.panes.get_mut(active_pane_id) { if let Some(active_pane) = self.panes.get_mut(active_pane_id) {
let full_pane_size = active_pane.position_and_size(); let mut full_pane_size = active_pane.position_and_size();
if full_pane_size.rows.as_usize() < MIN_TERMINAL_HEIGHT * 2
|| full_pane_size.is_stacked if full_pane_size.is_stacked() {
{ let Some(position_and_size_of_stack) =
StackedPanes::new_from_btreemap(&mut self.panes, &self.panes_to_hide)
.position_and_size_of_stack(&active_pane_id)
else {
log::error!("Failed to find position and size of stack");
return false;
};
full_pane_size = position_and_size_of_stack;
}
if full_pane_size.rows.as_usize() < MIN_TERMINAL_HEIGHT * 2 {
return false; return false;
} else { } else {
return split(SplitDirection::Horizontal, &full_pane_size).is_some(); return split(SplitDirection::Horizontal, &full_pane_size).is_some();
@ -379,10 +492,20 @@ impl TiledPanes {
pub fn can_split_pane_vertically(&mut self, client_id: ClientId) -> bool { pub fn can_split_pane_vertically(&mut self, client_id: ClientId) -> bool {
if let Some(active_pane_id) = &self.active_panes.get(&client_id) { if let Some(active_pane_id) = &self.active_panes.get(&client_id) {
if let Some(active_pane) = self.panes.get_mut(active_pane_id) { if let Some(active_pane) = self.panes.get_mut(active_pane_id) {
let full_pane_size = active_pane.position_and_size(); let mut full_pane_size = active_pane.position_and_size();
if full_pane_size.cols.as_usize() < MIN_TERMINAL_WIDTH * 2
|| full_pane_size.is_stacked if full_pane_size.is_stacked() {
{ let Some(position_and_size_of_stack) =
StackedPanes::new_from_btreemap(&mut self.panes, &self.panes_to_hide)
.position_and_size_of_stack(&active_pane_id)
else {
log::error!("Failed to find position and size of stack");
return false;
};
full_pane_size = position_and_size_of_stack;
}
if full_pane_size.cols.as_usize() < MIN_TERMINAL_WIDTH * 2 {
return false; return false;
} }
return split(SplitDirection::Vertical, &full_pane_size).is_some(); return split(SplitDirection::Vertical, &full_pane_size).is_some();
@ -390,19 +513,6 @@ impl TiledPanes {
} }
false false
} }
pub fn can_split_active_pane_horizontally(&self, client_id: ClientId) -> bool {
let active_pane_id = &self.active_panes.get(&client_id).unwrap();
let active_pane = self.panes.get(active_pane_id).unwrap();
let full_pane_size = active_pane.position_and_size();
if full_pane_size.rows.is_fixed() || full_pane_size.is_stacked {
return false;
}
if split(SplitDirection::Horizontal, &full_pane_size).is_some() {
true
} else {
false
}
}
pub fn split_pane_horizontally( pub fn split_pane_horizontally(
&mut self, &mut self,
pid: PaneId, pid: PaneId,
@ -410,30 +520,44 @@ impl TiledPanes {
client_id: ClientId, client_id: ClientId,
) { ) {
let active_pane_id = &self.active_panes.get(&client_id).unwrap(); let active_pane_id = &self.active_panes.get(&client_id).unwrap();
let mut full_pane_size = self
.panes
.get(active_pane_id)
.map(|p| p.position_and_size())
.unwrap();
if full_pane_size.is_stacked() {
match StackedPanes::new_from_btreemap(&mut self.panes, &self.panes_to_hide)
.position_and_size_of_stack(&active_pane_id)
{
Some(position_and_size_of_stack) => {
full_pane_size = position_and_size_of_stack;
},
None => {
log::error!("Failed to find position and size of stack");
},
}
}
let active_pane = self.panes.get_mut(active_pane_id).unwrap(); let active_pane = self.panes.get_mut(active_pane_id).unwrap();
let full_pane_size = active_pane.position_and_size();
if let Some((top_winsize, bottom_winsize)) = if let Some((top_winsize, bottom_winsize)) =
split(SplitDirection::Horizontal, &full_pane_size) split(SplitDirection::Horizontal, &full_pane_size)
{ {
if active_pane.position_and_size().is_stacked() {
match StackedPanes::new_from_btreemap(&mut self.panes, &self.panes_to_hide)
.resize_panes_in_stack(&active_pane_id, top_winsize)
{
Ok(_) => {},
Err(e) => {
log::error!("Failed to resize stack: {}", e);
},
}
} else {
active_pane.set_geom(top_winsize); active_pane.set_geom(top_winsize);
}
new_pane.set_geom(bottom_winsize); new_pane.set_geom(bottom_winsize);
self.panes.insert(pid, new_pane); self.panes.insert(pid, new_pane);
self.relayout(SplitDirection::Vertical); self.relayout(SplitDirection::Vertical);
} }
} }
pub fn can_split_active_pane_vertically(&self, client_id: ClientId) -> bool {
let active_pane_id = &self.active_panes.get(&client_id).unwrap();
let active_pane = self.panes.get(active_pane_id).unwrap();
let full_pane_size = active_pane.position_and_size();
if full_pane_size.cols.is_fixed() || full_pane_size.is_stacked {
return false;
}
if split(SplitDirection::Vertical, &full_pane_size).is_some() {
true
} else {
false
}
}
pub fn split_pane_vertically( pub fn split_pane_vertically(
&mut self, &mut self,
pid: PaneId, pid: PaneId,
@ -441,12 +565,39 @@ impl TiledPanes {
client_id: ClientId, client_id: ClientId,
) { ) {
let active_pane_id = &self.active_panes.get(&client_id).unwrap(); let active_pane_id = &self.active_panes.get(&client_id).unwrap();
let mut full_pane_size = self
.panes
.get(active_pane_id)
.map(|p| p.position_and_size())
.unwrap();
if full_pane_size.is_stacked() {
match StackedPanes::new_from_btreemap(&mut self.panes, &self.panes_to_hide)
.position_and_size_of_stack(&active_pane_id)
{
Some(position_and_size_of_stack) => {
full_pane_size = position_and_size_of_stack;
},
None => {
log::error!("Failed to find position and size of stack");
},
}
}
let active_pane = self.panes.get_mut(active_pane_id).unwrap(); let active_pane = self.panes.get_mut(active_pane_id).unwrap();
let full_pane_size = active_pane.position_and_size();
if let Some((left_winsize, right_winsize)) = if let Some((left_winsize, right_winsize)) =
split(SplitDirection::Vertical, &full_pane_size) split(SplitDirection::Vertical, &full_pane_size)
{ {
if active_pane.position_and_size().is_stacked() {
match StackedPanes::new_from_btreemap(&mut self.panes, &self.panes_to_hide)
.resize_panes_in_stack(&active_pane_id, left_winsize)
{
Ok(_) => {},
Err(e) => {
log::error!("Failed to resize stack: {}", e);
},
}
} else {
active_pane.set_geom(left_winsize); active_pane.set_geom(left_winsize);
}
new_pane.set_geom(right_winsize); new_pane.set_geom(right_winsize);
self.panes.insert(pid, new_pane); self.panes.insert(pid, new_pane);
self.relayout(SplitDirection::Horizontal); self.relayout(SplitDirection::Horizontal);
@ -459,7 +610,7 @@ impl TiledPanes {
if self if self
.panes .panes
.get(&pane_id) .get(&pane_id)
.map(|p| p.current_geom().is_stacked) .map(|p| p.current_geom().is_stacked())
.unwrap_or(false) .unwrap_or(false)
{ {
let _ = StackedPanes::new_from_btreemap(&mut self.panes, &self.panes_to_hide) let _ = StackedPanes::new_from_btreemap(&mut self.panes, &self.panes_to_hide)
@ -481,7 +632,7 @@ impl TiledPanes {
if self if self
.panes .panes
.get(&pane_id) .get(&pane_id)
.map(|p| p.current_geom().is_stacked) .map(|p| p.current_geom().is_stacked())
.unwrap_or(false) .unwrap_or(false)
{ {
let _ = let _ =
@ -498,7 +649,7 @@ impl TiledPanes {
if self if self
.panes .panes
.get(&pane_id) .get(&pane_id)
.map(|p| p.current_geom().is_stacked) .map(|p| p.current_geom().is_stacked())
.unwrap_or(false) .unwrap_or(false)
{ {
let _ = StackedPanes::new_from_btreemap( let _ = StackedPanes::new_from_btreemap(
@ -562,7 +713,7 @@ impl TiledPanes {
if self if self
.panes .panes
.get(&pane_id) .get(&pane_id)
.map(|p| p.current_geom().is_stacked) .map(|p| p.current_geom().is_stacked())
.unwrap_or(false) .unwrap_or(false)
{ {
let _ = StackedPanes::new_from_btreemap(&mut self.panes, &self.panes_to_hide) let _ = StackedPanes::new_from_btreemap(&mut self.panes, &self.panes_to_hide)
@ -694,7 +845,7 @@ impl TiledPanes {
let pane_is_stacked_over = let pane_is_stacked_over =
stacked_pane_ids_over_flexible_pane.contains(&pane.pid()); stacked_pane_ids_over_flexible_pane.contains(&pane.pid());
let should_draw_pane_frames = self.draw_pane_frames; let should_draw_pane_frames = self.draw_pane_frames;
let pane_is_stacked = pane.current_geom().is_stacked; let pane_is_stacked = pane.current_geom().is_stacked();
let mut pane_contents_and_ui = PaneContentsAndUi::new( let mut pane_contents_and_ui = PaneContentsAndUi::new(
pane, pane,
output, output,
@ -828,9 +979,16 @@ impl TiledPanes {
}, },
} }
} }
fn display_area_changed(&self, new_screen_size: Size) -> bool {
let display_area = self.display_area.borrow();
new_screen_size.rows != display_area.rows || new_screen_size.cols != display_area.cols
}
pub fn resize(&mut self, new_screen_size: Size) { pub fn resize(&mut self, new_screen_size: Size) {
// this is blocked out to appease the borrow checker // this is blocked out to appease the borrow checker
{ {
if self.display_area_changed(new_screen_size) {
self.clear_tombstones();
}
let mut display_area = self.display_area.borrow_mut(); let mut display_area = self.display_area.borrow_mut();
let mut viewport = self.viewport.borrow_mut(); let mut viewport = self.viewport.borrow_mut();
let Size { rows, cols } = new_screen_size; let Size { rows, cols } = new_screen_size;
@ -884,13 +1042,388 @@ impl TiledPanes {
client_id: ClientId, client_id: ClientId,
strategy: &ResizeStrategy, strategy: &ResizeStrategy,
) -> Result<()> { ) -> Result<()> {
if *self.stacked_resize.borrow() && strategy.direction.is_none() {
if let Some(active_pane_id) = self.get_active_pane_id(client_id) { if let Some(active_pane_id) = self.get_active_pane_id(client_id) {
self.resize_pane_with_id(*strategy, active_pane_id)?; self.stacked_resize_pane_with_id(active_pane_id, strategy)?;
self.reapply_pane_frames();
}
} else {
if let Some(active_pane_id) = self.get_active_pane_id(client_id) {
self.resize_pane_with_id(*strategy, active_pane_id, None)?;
}
} }
Ok(()) Ok(())
} }
pub fn resize_pane_with_id(&mut self, strategy: ResizeStrategy, pane_id: PaneId) -> Result<()> { fn resize_or_stack_pane_up(&mut self, pane_id: PaneId, resize_percent: (f64, f64)) -> bool {
// true - successfully resized
let mut strategy = ResizeStrategy::new(Resize::Increase, Some(Direction::Up));
strategy.invert_on_boundaries = false;
let successfully_resized_up =
match self.resize_pane_with_id(strategy, pane_id, Some(resize_percent)) {
Ok(_) => true,
Err(_) => false,
};
if successfully_resized_up {
return true;
} else {
let mut pane_grid = TiledPaneGrid::new(
&mut self.panes,
&self.panes_to_hide,
*self.display_area.borrow(),
*self.viewport.borrow(),
);
if let Some(pane_ids_to_resize) = pane_grid.stack_pane_up(&pane_id) {
for pane_id in pane_ids_to_resize {
if let Some(pane) = self.panes.get_mut(&pane_id) {
let _ =
resize_pty!(pane, self.os_api, self.senders, self.character_cell_size);
}
}
return true;
}
}
false
}
fn resize_or_stack_pane_down(&mut self, pane_id: PaneId, resize_percent: (f64, f64)) -> bool {
// true - successfully resized
let mut strategy = ResizeStrategy::new(Resize::Increase, Some(Direction::Down));
strategy.invert_on_boundaries = false;
let successfully_resized_up =
match self.resize_pane_with_id(strategy, pane_id, Some(resize_percent)) {
Ok(_) => true,
Err(_) => false,
};
if successfully_resized_up {
return true;
} else {
let mut pane_grid = TiledPaneGrid::new(
&mut self.panes,
&self.panes_to_hide,
*self.display_area.borrow(),
*self.viewport.borrow(),
);
if let Some(pane_ids_to_resize) = pane_grid.stack_pane_down(&pane_id) {
for pane_id in pane_ids_to_resize {
if let Some(pane) = self.panes.get_mut(&pane_id) {
let _ =
resize_pty!(pane, self.os_api, self.senders, self.character_cell_size);
}
}
return true;
}
}
false
}
fn resize_or_stack_pane_left(&mut self, pane_id: PaneId, resize_percent: (f64, f64)) -> bool {
// true - successfully resized
let mut strategy = ResizeStrategy::new(Resize::Increase, Some(Direction::Left));
strategy.invert_on_boundaries = false;
let successfully_resized_up =
match self.resize_pane_with_id(strategy, pane_id, Some(resize_percent)) {
Ok(_) => true,
Err(_) => false,
};
if successfully_resized_up {
return true;
} else {
let mut pane_grid = TiledPaneGrid::new(
&mut self.panes,
&self.panes_to_hide,
*self.display_area.borrow(),
*self.viewport.borrow(),
);
if let Some(pane_ids_to_resize) = pane_grid.stack_pane_left(&pane_id) {
for pane_id in pane_ids_to_resize {
if let Some(pane) = self.panes.get_mut(&pane_id) {
let _ =
resize_pty!(pane, self.os_api, self.senders, self.character_cell_size);
}
}
return true;
}
}
false
}
fn resize_or_stack_pane_right(&mut self, pane_id: PaneId, resize_percent: (f64, f64)) -> bool {
// true - successfully resized
let mut strategy = ResizeStrategy::new(Resize::Increase, Some(Direction::Right));
strategy.invert_on_boundaries = false;
let successfully_resized_up =
match self.resize_pane_with_id(strategy, pane_id, Some(resize_percent)) {
Ok(_) => true,
Err(_) => false,
};
if successfully_resized_up {
return true;
} else {
let mut pane_grid = TiledPaneGrid::new(
&mut self.panes,
&self.panes_to_hide,
*self.display_area.borrow(),
*self.viewport.borrow(),
);
if let Some(pane_ids_to_resize) = pane_grid.stack_pane_right(&pane_id) {
for pane_id in pane_ids_to_resize {
if let Some(pane) = self.panes.get_mut(&pane_id) {
let _ =
resize_pty!(pane, self.os_api, self.senders, self.character_cell_size);
}
}
return true;
}
}
false
}
fn update_tombstones_before_increase(
&mut self,
focused_pane_id: PaneId,
pane_state: HashMap<PaneId, PaneGeom>,
) {
match self.tombstones_before_increase.as_mut() {
Some((focused_pane_id_in_tombstone, pane_geoms)) => {
let last_state = pane_geoms.last();
let last_state_has_same_pane_count = last_state
.map(|last_state| last_state.len() == pane_state.len())
.unwrap_or(false);
let last_state_equals_current_state = last_state
.map(|last_state| last_state == &pane_state)
.unwrap_or(false);
if last_state_equals_current_state {
return;
}
if *focused_pane_id_in_tombstone == focused_pane_id
&& last_state_has_same_pane_count
{
pane_geoms.push(pane_state);
} else {
self.clear_tombstones();
self.tombstones_before_increase = Some((focused_pane_id, vec![pane_state]));
}
},
None => {
self.clear_tombstones();
self.tombstones_before_increase = Some((focused_pane_id, vec![pane_state]));
},
}
}
fn update_tombstones_before_decrease(
&mut self,
focused_pane_id: PaneId,
pane_state: HashMap<PaneId, PaneGeom>,
) {
match self.tombstones_before_decrease.as_mut() {
Some((focused_pane_id_in_tombstone, pane_geoms)) => {
let last_state = pane_geoms.last();
let last_state_has_same_pane_count = last_state
.map(|last_state| last_state.len() == pane_state.len())
.unwrap_or(false);
let last_state_equals_current_state = last_state
.map(|last_state| last_state == &pane_state)
.unwrap_or(false);
if last_state_equals_current_state {
return;
}
if *focused_pane_id_in_tombstone == focused_pane_id
&& last_state_has_same_pane_count
{
pane_geoms.push(pane_state);
} else {
self.clear_tombstones();
self.tombstones_before_decrease = Some((focused_pane_id, vec![pane_state]));
}
},
None => {
self.clear_tombstones();
self.tombstones_before_decrease = Some((focused_pane_id, vec![pane_state]));
},
}
}
fn clear_tombstones(&mut self) {
self.tombstones_before_increase = None;
self.tombstones_before_decrease = None;
}
fn stacked_resize_pane_with_id(
&mut self,
pane_id: PaneId,
strategy: &ResizeStrategy,
) -> Result<bool> {
let resize_percent = (30.0, 30.0);
match strategy.resize {
Resize::Increase => {
match self.tombstones_before_decrease.as_mut() {
Some((tombstone_pane_id, tombstone_pane_state))
if *tombstone_pane_id == pane_id =>
{
if let Some(last_state) = tombstone_pane_state.pop() {
if last_state.len() == self.panes.len() {
for (pane_id, pane_geom) in last_state {
self.panes
.get_mut(&pane_id)
.map(|pane| pane.set_geom(pane_geom));
}
self.reapply_pane_frames();
return Ok(true);
} else {
self.tombstones_before_decrease = None;
}
}
},
_ => {},
}
let mut current_pane_state = HashMap::new();
for (pane_id, pane) in &self.panes {
current_pane_state.insert(*pane_id, pane.current_geom());
}
let (
direct_neighboring_pane_ids_above,
direct_neighboring_pane_ids_below,
direct_neighboring_pane_ids_to_the_left,
direct_neighboring_pane_ids_to_the_right,
) = {
let pane_grid = TiledPaneGrid::new(
&mut self.panes,
&self.panes_to_hide,
*self.display_area.borrow(),
*self.viewport.borrow(),
);
(
pane_grid.direct_neighboring_pane_ids_above(&pane_id),
pane_grid.direct_neighboring_pane_ids_below(&pane_id),
pane_grid.direct_neighboring_pane_ids_to_the_left(&pane_id),
pane_grid.direct_neighboring_pane_ids_to_the_right(&pane_id),
)
};
if !direct_neighboring_pane_ids_above.is_empty() {
if self.resize_or_stack_pane_up(pane_id, resize_percent) {
self.update_tombstones_before_increase(pane_id, current_pane_state);
return Ok(true);
}
}
if !direct_neighboring_pane_ids_below.is_empty() {
if self.resize_or_stack_pane_down(pane_id, resize_percent) {
self.update_tombstones_before_increase(pane_id, current_pane_state);
return Ok(true);
}
}
if !direct_neighboring_pane_ids_to_the_left.is_empty() {
if self.resize_or_stack_pane_left(pane_id, resize_percent) {
self.update_tombstones_before_increase(pane_id, current_pane_state);
return Ok(true);
}
}
if !direct_neighboring_pane_ids_to_the_right.is_empty() {
if self.resize_or_stack_pane_right(pane_id, resize_percent) {
self.update_tombstones_before_increase(pane_id, current_pane_state);
return Ok(true);
}
}
// normal resize if we can't do anything...
match self.resize_pane_with_id(*strategy, pane_id, None) {
Ok(size_changed) => {
if size_changed {
self.update_tombstones_before_increase(pane_id, current_pane_state);
} else {
if self.fullscreen_is_active.is_none() {
self.toggle_pane_fullscreen(pane_id);
return Ok(self.fullscreen_is_active.is_some());
} else {
return Ok(false);
}
}
return Ok(size_changed);
},
Err(e) => Err(e),
}
},
Resize::Decrease => {
if self.fullscreen_is_active.is_some() {
self.unset_fullscreen();
return Ok(true);
}
match self.tombstones_before_increase.as_mut() {
Some((tombstone_pane_id, tombstone_pane_state))
if *tombstone_pane_id == pane_id =>
{
if let Some(last_state) = tombstone_pane_state.pop() {
if last_state.len() == self.panes.len() {
for (pane_id, pane_geom) in last_state {
self.panes
.get_mut(&pane_id)
.map(|pane| pane.set_geom(pane_geom));
}
self.reapply_pane_frames();
return Ok(true);
} else {
self.tombstones_before_increase = None;
}
}
},
_ => {},
}
let mut current_pane_state = HashMap::new();
for (pane_id, pane) in &self.panes {
current_pane_state.insert(*pane_id, pane.current_geom());
}
let mut pane_grid = TiledPaneGrid::new(
&mut self.panes,
&self.panes_to_hide,
*self.display_area.borrow(),
*self.viewport.borrow(),
);
if let Some(pane_ids_to_resize) = pane_grid.unstack_pane_up(&pane_id) {
for pane_id in pane_ids_to_resize {
if let Some(pane) = self.panes.get_mut(&pane_id) {
resize_pty!(pane, self.os_api, self.senders, self.character_cell_size)
.unwrap();
}
}
self.reapply_pane_frames();
self.update_tombstones_before_decrease(pane_id, current_pane_state);
Ok(true)
} else {
// normal resize if we were not inside a stack
// first try with our custom resize_percent
match self.resize_pane_with_id(*strategy, pane_id, Some(resize_percent)) {
Ok(pane_size_changed) => {
if pane_size_changed {
self.update_tombstones_before_decrease(pane_id, current_pane_state);
self.reapply_pane_frames();
Ok(pane_size_changed)
} else {
// if it doesn't work, try with the default resize percent
match self.resize_pane_with_id(*strategy, pane_id, None) {
Ok(pane_size_changed) => {
if pane_size_changed {
self.update_tombstones_before_decrease(
pane_id,
current_pane_state,
);
self.reapply_pane_frames();
}
Ok(pane_size_changed)
},
Err(e) => Err(e),
}
}
},
Err(e) => Err(e),
}
}
},
}
}
pub fn resize_pane_with_id(
&mut self,
strategy: ResizeStrategy,
pane_id: PaneId,
resize_percent: Option<(f64, f64)>,
) -> Result<bool> {
let err_context = || format!("failed to resize pand with id: {:?}", pane_id); let err_context = || format!("failed to resize pand with id: {:?}", pane_id);
let mut pane_grid = TiledPaneGrid::new( let mut pane_grid = TiledPaneGrid::new(
@ -900,11 +1433,18 @@ impl TiledPanes {
*self.viewport.borrow(), *self.viewport.borrow(),
); );
let mut pane_size_changed = false;
match pane_grid match pane_grid
.change_pane_size(&pane_id, &strategy, (RESIZE_PERCENT, RESIZE_PERCENT)) .change_pane_size(
&pane_id,
&strategy,
resize_percent.unwrap_or((RESIZE_PERCENT, RESIZE_PERCENT)),
)
.with_context(err_context) .with_context(err_context)
{ {
Ok(_) => {}, Ok(changed) => {
pane_size_changed = changed;
},
Err(err) => match err.downcast_ref::<ZellijError>() { Err(err) => match err.downcast_ref::<ZellijError>() {
Some(ZellijError::PaneSizeUnchanged) => { Some(ZellijError::PaneSizeUnchanged) => {
// try once more with double the resize percent, but let's keep it at that // try once more with double the resize percent, but let's keep it at that
@ -932,10 +1472,11 @@ impl TiledPanes {
} }
for pane in self.panes.values_mut() { for pane in self.panes.values_mut() {
// TODO: only for the panes whose width/height actually changed
resize_pty!(pane, self.os_api, self.senders, self.character_cell_size).unwrap(); resize_pty!(pane, self.os_api, self.senders, self.character_cell_size).unwrap();
} }
self.reset_boundaries(); self.reset_boundaries();
Ok(()) Ok(pane_size_changed)
} }
pub fn focus_next_pane(&mut self, client_id: ClientId) { pub fn focus_next_pane(&mut self, client_id: ClientId) {
@ -954,7 +1495,7 @@ impl TiledPanes {
if self if self
.panes .panes
.get(&next_active_pane_id) .get(&next_active_pane_id)
.map(|p| p.current_geom().is_stacked) .map(|p| p.current_geom().is_stacked())
.unwrap_or(false) .unwrap_or(false)
{ {
let _ = StackedPanes::new_from_btreemap(&mut self.panes, &self.panes_to_hide) let _ = StackedPanes::new_from_btreemap(&mut self.panes, &self.panes_to_hide)
@ -986,7 +1527,7 @@ impl TiledPanes {
if self if self
.panes .panes
.get(&next_active_pane_id) .get(&next_active_pane_id)
.map(|p| p.current_geom().is_stacked) .map(|p| p.current_geom().is_stacked())
.unwrap_or(false) .unwrap_or(false)
{ {
let _ = StackedPanes::new_from_btreemap(&mut self.panes, &self.panes_to_hide) let _ = StackedPanes::new_from_btreemap(&mut self.panes, &self.panes_to_hide)
@ -1103,7 +1644,7 @@ impl TiledPanes {
.unwrap(); .unwrap();
let previously_active_pane_is_stacked = let previously_active_pane_is_stacked =
previously_active_pane.current_geom().is_stacked; previously_active_pane.current_geom().is_stacked();
previously_active_pane.set_should_render(true); previously_active_pane.set_should_render(true);
// we render the full viewport to remove any ui elements that might have been // we render the full viewport to remove any ui elements that might have been
// there before (eg. another user's cursor) // there before (eg. another user's cursor)
@ -1111,7 +1652,7 @@ impl TiledPanes {
let next_active_pane = self.panes.get_mut(&p).unwrap(); let next_active_pane = self.panes.get_mut(&p).unwrap();
let next_active_pane_is_stacked = let next_active_pane_is_stacked =
next_active_pane.current_geom().is_stacked; next_active_pane.current_geom().is_stacked();
next_active_pane.set_should_render(true); next_active_pane.set_should_render(true);
// we render the full viewport to remove any ui elements that might have been // we render the full viewport to remove any ui elements that might have been
// there before (eg. another user's cursor) // there before (eg. another user's cursor)
@ -1157,7 +1698,7 @@ impl TiledPanes {
.unwrap(); .unwrap();
let previously_active_pane_is_stacked = let previously_active_pane_is_stacked =
previously_active_pane.current_geom().is_stacked; previously_active_pane.current_geom().is_stacked();
previously_active_pane.set_should_render(true); previously_active_pane.set_should_render(true);
// we render the full viewport to remove any ui elements that might have been // we render the full viewport to remove any ui elements that might have been
// there before (eg. another user's cursor) // there before (eg. another user's cursor)
@ -1165,7 +1706,7 @@ impl TiledPanes {
let next_active_pane = self.panes.get_mut(&p).unwrap(); let next_active_pane = self.panes.get_mut(&p).unwrap();
let next_active_pane_is_stacked = let next_active_pane_is_stacked =
next_active_pane.current_geom().is_stacked; next_active_pane.current_geom().is_stacked();
next_active_pane.set_should_render(true); next_active_pane.set_should_render(true);
// we render the full viewport to remove any ui elements that might have been // we render the full viewport to remove any ui elements that might have been
// there before (eg. another user's cursor) // there before (eg. another user's cursor)
@ -1296,7 +1837,7 @@ impl TiledPanes {
if self if self
.panes .panes
.get(&new_position_id) .get(&new_position_id)
.map(|p| p.current_geom().is_stacked) .map(|p| p.current_geom().is_stacked())
.unwrap_or(false) .unwrap_or(false)
{ {
let _ = StackedPanes::new_from_btreemap(&mut self.panes, &self.panes_to_hide) let _ = StackedPanes::new_from_btreemap(&mut self.panes, &self.panes_to_hide)
@ -1577,7 +2118,7 @@ impl TiledPanes {
if self if self
.panes .panes
.get(&next_active_pane_id) .get(&next_active_pane_id)
.map(|p| p.current_geom().is_stacked) .map(|p| p.current_geom().is_stacked())
.unwrap_or(false) .unwrap_or(false)
{ {
self.expand_pane_in_stack(next_active_pane_id); self.expand_pane_in_stack(next_active_pane_id);

View file

@ -138,7 +138,7 @@ impl<'a> PaneResizer<'a> {
.get(&span.pid) .get(&span.pid)
.unwrap() .unwrap()
.current_geom() .current_geom()
.is_stacked; .is_stacked();
if pane_is_stacked { if pane_is_stacked {
let current_geom = StackedPanes::new(self.panes.clone()) let current_geom = StackedPanes::new(self.panes.clone())
.position_and_size_of_stack(&span.pid) .position_and_size_of_stack(&span.pid)
@ -156,7 +156,6 @@ impl<'a> PaneResizer<'a> {
}, },
}; };
StackedPanes::new(self.panes.clone()).resize_panes_in_stack(&span.pid, new_geom)?; StackedPanes::new(self.panes.clone()).resize_panes_in_stack(&span.pid, new_geom)?;
// TODO: test with geom_override (fullscreen)
if new_geom.rows.as_usize() != current_geom.rows.as_usize() if new_geom.rows.as_usize() != current_geom.rows.as_usize()
|| new_geom.cols.as_usize() != current_geom.cols.as_usize() || new_geom.cols.as_usize() != current_geom.cols.as_usize()
{ {
@ -248,10 +247,10 @@ impl<'a> PaneResizer<'a> {
fn get_span(&self, direction: SplitDirection, pane: &dyn Pane) -> Option<Span> { fn get_span(&self, direction: SplitDirection, pane: &dyn Pane) -> Option<Span> {
let position_and_size = { let position_and_size = {
let pas = pane.current_geom(); let pas = pane.current_geom();
if pas.is_stacked && pas.rows.is_percent() { if pas.is_stacked() && pas.rows.is_percent() {
// this is the main pane of the stack // this is the main pane of the stack
StackedPanes::new(self.panes.clone()).position_and_size_of_stack(&pane.pid()) StackedPanes::new(self.panes.clone()).position_and_size_of_stack(&pane.pid())
} else if pas.is_stacked { } else if pas.is_stacked() {
// this is a one-liner stacked pane and should be handled as the same rect with // this is a one-liner stacked pane and should be handled as the same rect with
// the rest of the stack, represented by the main pane in the if branch above // the rest of the stack, represented by the main pane in the if branch above
None None

View file

@ -33,21 +33,21 @@ impl<'a> StackedPanes<'a> {
destination_pane_id: &PaneId, destination_pane_id: &PaneId,
) -> Result<()> { ) -> Result<()> {
let err_context = || format!("Failed to move stacked pane focus down"); let err_context = || format!("Failed to move stacked pane focus down");
let source_pane_is_stacked = self let source_pane_stack_id = self
.panes .panes
.borrow() .borrow()
.get(source_pane_id) .get(source_pane_id)
.with_context(err_context)? .with_context(err_context)?
.position_and_size() .position_and_size()
.is_stacked; .stacked;
let destination_pane_is_stacked = self let destination_pane_stack_id = self
.panes .panes
.borrow() .borrow()
.get(destination_pane_id) .get(destination_pane_id)
.with_context(err_context)? .with_context(err_context)?
.position_and_size() .position_and_size()
.is_stacked; .stacked;
if source_pane_is_stacked && destination_pane_is_stacked { if source_pane_stack_id == destination_pane_stack_id {
let mut panes = self.panes.borrow_mut(); let mut panes = self.panes.borrow_mut();
let source_pane = panes.get_mut(source_pane_id).with_context(err_context)?; let source_pane = panes.get_mut(source_pane_id).with_context(err_context)?;
let mut source_pane_geom = source_pane.position_and_size(); let mut source_pane_geom = source_pane.position_and_size();
@ -59,7 +59,7 @@ impl<'a> StackedPanes<'a> {
.get_mut(&destination_pane_id) .get_mut(&destination_pane_id)
.with_context(err_context)?; .with_context(err_context)?;
destination_pane.set_geom(destination_pane_geom); destination_pane.set_geom(destination_pane_geom);
} else if destination_pane_is_stacked { } else if destination_pane_stack_id.is_some() {
// we're moving down to the highest pane in the stack, we need to expand it and shrink the // we're moving down to the highest pane in the stack, we need to expand it and shrink the
// expanded stack pane // expanded stack pane
self.make_highest_pane_in_stack_flexible(destination_pane_id)?; self.make_highest_pane_in_stack_flexible(destination_pane_id)?;
@ -68,21 +68,21 @@ impl<'a> StackedPanes<'a> {
} }
pub fn move_up(&mut self, source_pane_id: &PaneId, destination_pane_id: &PaneId) -> Result<()> { pub fn move_up(&mut self, source_pane_id: &PaneId, destination_pane_id: &PaneId) -> Result<()> {
let err_context = || format!("Failed to move stacked pane focus up"); let err_context = || format!("Failed to move stacked pane focus up");
let source_pane_is_stacked = self let source_pane_stack_id = self
.panes .panes
.borrow() .borrow()
.get(source_pane_id) .get(source_pane_id)
.with_context(err_context)? .with_context(err_context)?
.position_and_size() .position_and_size()
.is_stacked; .stacked;
let destination_pane_is_stacked = self let destination_pane_stack_id = self
.panes .panes
.borrow() .borrow()
.get(destination_pane_id) .get(destination_pane_id)
.with_context(err_context)? .with_context(err_context)?
.position_and_size() .position_and_size()
.is_stacked; .stacked;
if source_pane_is_stacked && destination_pane_is_stacked { if source_pane_stack_id == destination_pane_stack_id {
let mut panes = self.panes.borrow_mut(); let mut panes = self.panes.borrow_mut();
let source_pane = panes.get_mut(source_pane_id).with_context(err_context)?; let source_pane = panes.get_mut(source_pane_id).with_context(err_context)?;
let mut source_pane_geom = source_pane.position_and_size(); let mut source_pane_geom = source_pane.position_and_size();
@ -95,7 +95,7 @@ impl<'a> StackedPanes<'a> {
.get_mut(&destination_pane_id) .get_mut(&destination_pane_id)
.with_context(err_context)?; .with_context(err_context)?;
destination_pane.set_geom(destination_pane_geom); destination_pane.set_geom(destination_pane_geom);
} else if destination_pane_is_stacked { } else if destination_pane_stack_id.is_some() {
// we're moving up to the lowest pane in the stack, we need to expand it and shrink the // we're moving up to the lowest pane in the stack, we need to expand it and shrink the
// expanded stack pane // expanded stack pane
self.make_lowest_pane_in_stack_flexible(destination_pane_id)?; self.make_lowest_pane_in_stack_flexible(destination_pane_id)?;
@ -188,7 +188,7 @@ impl<'a> StackedPanes<'a> {
x: first_pane_in_stack.x, x: first_pane_in_stack.x,
cols: first_pane_in_stack.cols, cols: first_pane_in_stack.cols,
rows, rows,
is_stacked: true, // important because otherwise the minimum stack size will not be stacked: None, // important because otherwise the minimum stack size will not be
// respected // respected
..Default::default() ..Default::default()
}) })
@ -265,11 +265,10 @@ impl<'a> StackedPanes<'a> {
let all_stacked_pane_positions = self.positions_in_stack(id).with_context(err_context)?; let all_stacked_pane_positions = self.positions_in_stack(id).with_context(err_context)?;
let position_of_flexible_pane = let position_of_flexible_pane =
self.position_of_flexible_pane(&all_stacked_pane_positions)?; self.position_of_flexible_pane(&all_stacked_pane_positions)?;
let (flexible_pane_id, flexible_pane) = all_stacked_pane_positions let (_flexible_pane_id, flexible_pane) = all_stacked_pane_positions
.iter() .iter()
.nth(position_of_flexible_pane) .nth(position_of_flexible_pane)
.with_context(err_context)?; .with_context(err_context)?;
let current_rows = all_stacked_pane_positions.len() + (flexible_pane.rows.as_usize() - 1);
let new_rows = new_full_stack_geom.rows.as_usize(); let new_rows = new_full_stack_geom.rows.as_usize();
let adjust_stack_geoms = |new_flexible_pane_geom: PaneGeom| -> Result<()> { let adjust_stack_geoms = |new_flexible_pane_geom: PaneGeom| -> Result<()> {
@ -295,35 +294,15 @@ impl<'a> StackedPanes<'a> {
} }
Ok(()) Ok(())
}; };
let new_rows_for_flexible_pane =
if new_rows >= current_rows { new_rows.saturating_sub(all_stacked_pane_positions.len()) + 1;
let extra_rows = new_rows - current_rows; let mut new_flexible_pane_geom = new_full_stack_geom;
let mut new_flexible_pane_geom = *flexible_pane; new_flexible_pane_geom.stacked = flexible_pane.stacked;
new_flexible_pane_geom.logical_position = flexible_pane.logical_position;
new_flexible_pane_geom new_flexible_pane_geom
.rows .rows
.set_inner(new_flexible_pane_geom.rows.as_usize() + extra_rows); .set_inner(new_rows_for_flexible_pane);
self.panes
.borrow_mut()
.get_mut(&flexible_pane_id)
.with_context(err_context)?
.set_geom(new_flexible_pane_geom);
adjust_stack_geoms(new_flexible_pane_geom)?; adjust_stack_geoms(new_flexible_pane_geom)?;
} else {
if new_rows < all_stacked_pane_positions.len() {
return Err(anyhow!("Not enough room for stacked panes"));
}
let rows_deficit = current_rows - new_rows;
let mut new_flexible_pane_geom = *flexible_pane;
new_flexible_pane_geom
.rows
.set_inner(new_flexible_pane_geom.rows.as_usize() - rows_deficit);
self.panes
.borrow_mut()
.get_mut(&flexible_pane_id)
.with_context(err_context)?
.set_geom(new_flexible_pane_geom);
adjust_stack_geoms(new_flexible_pane_geom)?;
}
Ok(()) Ok(())
} }
fn pane_is_one_liner(&self, id: &PaneId) -> Result<bool> { fn pane_is_one_liner(&self, id: &PaneId) -> Result<bool> {
@ -337,9 +316,12 @@ impl<'a> StackedPanes<'a> {
let err_context = || format!("Failed to find stacked panes"); let err_context = || format!("Failed to find stacked panes");
let panes = self.panes.borrow(); let panes = self.panes.borrow();
let pane_in_stack = panes.get(id).with_context(err_context)?; let pane_in_stack = panes.get(id).with_context(err_context)?;
let stack_id = pane_in_stack.position_and_size().stacked;
let mut all_stacked_pane_positions: Vec<(PaneId, PaneGeom)> = panes let mut all_stacked_pane_positions: Vec<(PaneId, PaneGeom)> = panes
.iter() .iter()
.filter(|(_pid, p)| p.position_and_size().is_stacked) .filter(|(_pid, p)| {
p.position_and_size().is_stacked() && p.position_and_size().stacked == stack_id
})
.filter(|(_pid, p)| { .filter(|(_pid, p)| {
p.position_and_size().x == pane_in_stack.position_and_size().x p.position_and_size().x == pane_in_stack.position_and_size().x
&& p.position_and_size().cols == pane_in_stack.position_and_size().cols && p.position_and_size().cols == pane_in_stack.position_and_size().cols
@ -402,7 +384,7 @@ impl<'a> StackedPanes<'a> {
self.panes self.panes
.borrow() .borrow()
.iter() .iter()
.filter(|(_p_id, p)| p.position_and_size().is_stacked) .filter(|(_p_id, p)| p.position_and_size().is_stacked())
.map(|(p_id, _p)| *p_id) .map(|(p_id, _p)| *p_id)
.collect() .collect()
}; };
@ -464,7 +446,39 @@ impl<'a> StackedPanes<'a> {
} }
Err(anyhow!("Not enough room for another pane!")) Err(anyhow!("Not enough room for another pane!"))
} }
pub fn new_stack(&mut self, root_pane_id: PaneId, pane_count_in_stack: usize) -> Vec<PaneGeom> { pub fn make_room_for_new_pane_in_stack(&mut self, pane_id: &PaneId) -> Result<PaneGeom> {
let err_context = || format!("Failed to add pane to stack");
let stack = self.positions_in_stack(pane_id).with_context(err_context)?;
if let Some((id_of_flexible_pane_in_stack, _flexible_pane_in_stack)) = stack
.iter()
.find(|(_p_id, p)| !p.rows.is_fixed() && p.rows.as_usize() > 1)
{
self.make_lowest_pane_in_stack_flexible(id_of_flexible_pane_in_stack)?;
let all_stacked_pane_positions =
self.positions_in_stack(id_of_flexible_pane_in_stack)?;
let position_of_flexible_pane =
self.position_of_flexible_pane(&all_stacked_pane_positions)?;
let (flexible_pane_id, mut flexible_pane_geom) = *all_stacked_pane_positions
.iter()
.nth(position_of_flexible_pane)
.with_context(err_context)?;
let mut position_for_new_pane = flexible_pane_geom.clone();
position_for_new_pane
.rows
.set_inner(position_for_new_pane.rows.as_usize() - 1);
position_for_new_pane.y = position_for_new_pane.y + 1;
flexible_pane_geom.rows = Dimension::fixed(1);
self.panes
.borrow_mut()
.get_mut(&flexible_pane_id)
.with_context(err_context)?
.set_geom(flexible_pane_geom);
return Ok(position_for_new_pane);
}
Err(anyhow!("Not enough room for another pane!"))
}
pub fn new_stack(&self, root_pane_id: PaneId, pane_count_in_stack: usize) -> Vec<PaneGeom> {
let mut stacked_geoms = vec![]; let mut stacked_geoms = vec![];
let panes = self.panes.borrow(); let panes = self.panes.borrow();
let running_stack_geom = panes.get(&root_pane_id).map(|p| p.position_and_size()); let running_stack_geom = panes.get(&root_pane_id).map(|p| p.position_and_size());
@ -472,7 +486,8 @@ impl<'a> StackedPanes<'a> {
log::error!("Pane not found"); // TODO: better error log::error!("Pane not found"); // TODO: better error
return stacked_geoms; return stacked_geoms;
}; };
running_stack_geom.is_stacked = true; let stack_id = self.next_stack_id();
running_stack_geom.stacked = Some(stack_id);
let mut pane_index_in_stack = 0; let mut pane_index_in_stack = 0;
loop { loop {
if pane_index_in_stack == pane_count_in_stack { if pane_index_in_stack == pane_count_in_stack {
@ -493,13 +508,449 @@ impl<'a> StackedPanes<'a> {
} }
stacked_geoms stacked_geoms
} }
fn extract_geoms_from_stack(
&self,
root_pane_id: PaneId,
) -> Option<(PaneGeom, Vec<(PaneId, PaneGeom)>)> {
let panes = self.panes.borrow();
let mut geom_of_main_pane = panes.get(&root_pane_id).map(|p| p.position_and_size())?;
let mut extra_stacked_geoms_of_main_pane = vec![];
if geom_of_main_pane.is_stacked() {
let other_panes_in_stack = self.positions_in_stack(&root_pane_id).ok()?;
for other_pane in other_panes_in_stack {
if other_pane.0 != root_pane_id {
// so it is not duplicated
extra_stacked_geoms_of_main_pane.push(other_pane);
}
}
let logical_position = geom_of_main_pane.logical_position;
geom_of_main_pane = self.position_and_size_of_stack(&root_pane_id)?;
geom_of_main_pane.logical_position = logical_position;
}
Some((geom_of_main_pane, extra_stacked_geoms_of_main_pane))
}
fn positions_of_panes_and_their_stacks(
&self,
pane_ids: Vec<PaneId>,
) -> Option<Vec<(PaneId, PaneGeom)>> {
let mut positions = vec![];
let panes = self.panes.borrow();
for pane_id in &pane_ids {
let geom_of_pane = panes.get(pane_id).map(|p| p.position_and_size())?;
if geom_of_pane.is_stacked() {
let mut other_panes_in_stack = self.positions_in_stack(pane_id).ok()?;
positions.append(&mut other_panes_in_stack);
} else {
positions.push((*pane_id, geom_of_pane));
}
}
Some(positions)
}
fn combine_geoms_horizontally(
&self,
pane_ids_and_geoms: &Vec<(PaneId, PaneGeom)>,
) -> Option<PaneGeom> {
let mut geoms_to_combine = HashSet::new();
for (other_pane_id, other_geom) in pane_ids_and_geoms {
if other_geom.is_stacked() {
geoms_to_combine.insert(self.position_and_size_of_stack(other_pane_id)?);
} else {
geoms_to_combine.insert(*other_geom);
}
}
let mut geoms_to_combine: Vec<PaneGeom> = geoms_to_combine.iter().copied().collect();
geoms_to_combine.sort_by(|a_geom, b_geom| a_geom.x.cmp(&b_geom.x));
let geom_to_combine = geoms_to_combine.get(0)?;
geom_to_combine
.combine_horizontally_with_many(&geoms_to_combine.iter().copied().skip(1).collect())
}
fn combine_geoms_vertically(
&self,
pane_ids_and_geoms: &Vec<(PaneId, PaneGeom)>,
) -> Option<PaneGeom> {
let mut geoms_to_combine = HashSet::new();
for (other_pane_id, other_geom) in pane_ids_and_geoms {
if other_geom.is_stacked() {
geoms_to_combine.insert(self.position_and_size_of_stack(other_pane_id)?);
} else {
geoms_to_combine.insert(*other_geom);
}
}
let mut geoms_to_combine: Vec<PaneGeom> = geoms_to_combine.iter().copied().collect();
geoms_to_combine.sort_by(|a_geom, b_geom| a_geom.y.cmp(&b_geom.y));
let geom_to_combine = geoms_to_combine.get(0)?;
geom_to_combine
.combine_vertically_with_many(&geoms_to_combine.iter().copied().skip(1).collect())
}
pub fn combine_vertically_aligned_panes_to_stack(
&mut self,
root_pane_id: &PaneId,
neighboring_pane_ids: Vec<PaneId>,
) -> Result<()> {
let (geom_of_main_pane, mut extra_stacked_geoms_of_main_pane) = self
.extract_geoms_from_stack(*root_pane_id)
.ok_or_else(|| anyhow!("Failed to extract geoms from stack"))?;
let mut other_pane_ids_and_geoms = self
.positions_of_panes_and_their_stacks(neighboring_pane_ids)
.ok_or_else(|| anyhow!("Failed to get pane geoms"))?;
if other_pane_ids_and_geoms.is_empty() {
// nothing to do
return Ok(());
};
let Some(geom_to_combine) = self.combine_geoms_horizontally(&other_pane_ids_and_geoms)
else {
log::error!("Failed to combine geoms horizontally");
return Ok(());
};
let new_stack_geom = if geom_to_combine.y < geom_of_main_pane.y {
geom_to_combine.combine_vertically_with(&geom_of_main_pane)
} else {
geom_of_main_pane.combine_vertically_with(&geom_to_combine)
};
let Some(new_stack_geom) = new_stack_geom else {
// nothing to do, likely the pane below is fixed
return Ok(());
};
let stack_id = self.next_stack_id();
// we add the extra panes in the original stack (if any) so that they will be assigned pane
// positions but not affect the stack geometry
other_pane_ids_and_geoms.append(&mut extra_stacked_geoms_of_main_pane);
let mut panes = self.panes.borrow_mut();
let mut running_y = new_stack_geom.y;
let mut geom_of_flexible_pane = new_stack_geom.clone();
geom_of_flexible_pane
.rows
.decrease_inner(other_pane_ids_and_geoms.len());
geom_of_flexible_pane.stacked = Some(stack_id);
let mut all_stack_geoms = other_pane_ids_and_geoms;
let original_geom_of_main_pane = panes
.get(&root_pane_id)
.ok_or_else(|| anyhow!("Failed to find root geom"))?
.position_and_size(); // for sorting purposes
all_stack_geoms.push((*root_pane_id, original_geom_of_main_pane));
all_stack_geoms.sort_by(|(_a_id, a_geom), (_b_id, b_geom)| {
if a_geom.y == b_geom.y {
a_geom.x.cmp(&b_geom.x)
} else {
a_geom.y.cmp(&b_geom.y)
}
});
for (pane_id, mut pane_geom) in all_stack_geoms {
if let Some(pane_in_stack) = panes.get_mut(&pane_id) {
if &pane_id == root_pane_id {
pane_geom.x = new_stack_geom.x;
pane_geom.cols = new_stack_geom.cols;
pane_geom.y = running_y;
pane_geom.rows = geom_of_flexible_pane.rows;
pane_geom.stacked = Some(stack_id);
running_y += geom_of_flexible_pane.rows.as_usize();
pane_in_stack.set_geom(pane_geom);
} else {
pane_geom.x = new_stack_geom.x;
pane_geom.cols = new_stack_geom.cols;
pane_geom.y = running_y;
pane_geom.rows = Dimension::fixed(1);
pane_geom.stacked = Some(stack_id);
running_y += 1;
pane_in_stack.set_geom(pane_geom);
}
}
}
Ok(())
}
pub fn combine_horizontally_aligned_panes_to_stack(
&mut self,
root_pane_id: &PaneId,
neighboring_pane_ids: Vec<PaneId>,
) -> Result<()> {
let (geom_of_main_pane, mut extra_stacked_geoms_of_main_pane) = self
.extract_geoms_from_stack(*root_pane_id)
.ok_or_else(|| anyhow!("Failed to extract geoms from stack"))?;
let mut other_pane_ids_and_geoms = self
.positions_of_panes_and_their_stacks(neighboring_pane_ids)
.ok_or_else(|| anyhow!("Failed to get pane geoms"))?;
if other_pane_ids_and_geoms.is_empty() {
// nothing to do
return Ok(());
};
let Some(geom_to_combine) = self.combine_geoms_vertically(&other_pane_ids_and_geoms) else {
log::error!("Failed to combine geoms vertically");
return Ok(());
};
let new_stack_geom = if geom_to_combine.x < geom_of_main_pane.x {
geom_to_combine.combine_horizontally_with(&geom_of_main_pane)
} else {
geom_of_main_pane.combine_horizontally_with(&geom_to_combine)
};
let Some(new_stack_geom) = new_stack_geom else {
// nothing to do, likely the pane below is fixed
return Ok(());
};
let stack_id = self.next_stack_id();
// we add the extra panes in the original stack (if any) so that they will be assigned pane
// positions but not affect the stack geometry
other_pane_ids_and_geoms.append(&mut extra_stacked_geoms_of_main_pane);
let mut panes = self.panes.borrow_mut();
let mut running_y = new_stack_geom.y;
let mut geom_of_flexible_pane = new_stack_geom.clone();
geom_of_flexible_pane
.rows
.decrease_inner(other_pane_ids_and_geoms.len());
let mut all_stacked_geoms = other_pane_ids_and_geoms;
let original_geom_of_main_pane = panes
.get(&root_pane_id)
.ok_or_else(|| anyhow!("Failed to find root geom"))?
.position_and_size(); // for sorting purposes
all_stacked_geoms.push((*root_pane_id, original_geom_of_main_pane));
all_stacked_geoms.sort_by(|(_a_id, a_geom), (_b_id, b_geom)| {
if a_geom.x == b_geom.x {
a_geom.y.cmp(&b_geom.y)
} else {
a_geom.x.cmp(&b_geom.x)
}
});
for (pane_id, mut pane_geom) in all_stacked_geoms {
if &pane_id == root_pane_id {
if let Some(root_pane) = panes.get_mut(&root_pane_id) {
pane_geom.x = new_stack_geom.x;
pane_geom.cols = new_stack_geom.cols;
pane_geom.y = running_y;
pane_geom.rows = geom_of_flexible_pane.rows;
pane_geom.stacked = Some(stack_id);
pane_geom.logical_position = root_pane.position_and_size().logical_position;
root_pane.set_geom(pane_geom);
running_y += pane_geom.rows.as_usize();
}
} else {
if let Some(pane_in_stack) = panes.get_mut(&pane_id) {
pane_geom.x = new_stack_geom.x;
pane_geom.cols = new_stack_geom.cols;
pane_geom.y = running_y;
pane_geom.rows = Dimension::fixed(1);
pane_geom.stacked = Some(stack_id);
running_y += 1;
pane_in_stack.set_geom(pane_geom);
}
}
}
Ok(())
}
pub fn break_pane_out_of_stack(&mut self, pane_id: &PaneId) -> Option<Vec<PaneId>> {
let err_context = || "Failed to break pane out of stack";
let mut pane_ids_that_were_resized = vec![];
let Some(position_and_size_of_stack) = self.position_and_size_of_stack(pane_id) else {
log::error!("Could not find stack size for pane id: {:?}", pane_id);
return None;
};
let mut all_stacked_pane_positions = self
.positions_in_stack(&pane_id)
.with_context(err_context)
.ok()?;
if all_stacked_pane_positions.is_empty() {
return None;
}
let flexible_pane_id_is_on_the_bottom = all_stacked_pane_positions
.iter()
.last()
.map(|(_, last_pane_geom_in_stack)| last_pane_geom_in_stack.rows.is_percent())
.unwrap_or(false);
let (
mut new_position_and_size_of_stack,
position_and_size_of_broken_out_pane,
pane_id_to_break_out,
) = if flexible_pane_id_is_on_the_bottom {
self.break_out_stack_geom_upwards(
position_and_size_of_stack,
&mut all_stacked_pane_positions,
)?
} else {
self.break_out_stack_geom_downwards(
position_and_size_of_stack,
&mut all_stacked_pane_positions,
)?
};
let stack_id = all_stacked_pane_positions
.iter()
.next()
.and_then(|(_, first_geom)| first_geom.stacked)?;
let flexible_pane_id = self.get_flexible_pane_id(&all_stacked_pane_positions)?;
self.set_geom_of_broken_out_pane(
pane_id_to_break_out,
position_and_size_of_broken_out_pane,
);
pane_ids_that_were_resized.push(pane_id_to_break_out);
new_position_and_size_of_stack.stacked = Some(stack_id);
self.reset_stack_size(
&new_position_and_size_of_stack,
&all_stacked_pane_positions,
flexible_pane_id,
&mut pane_ids_that_were_resized,
);
Some(pane_ids_that_were_resized)
}
pub fn next_stack_id(&self) -> usize {
let mut highest_stack_id = 0;
let panes = self.panes.borrow();
for pane in panes.values() {
if let Some(stack_id) = pane.position_and_size().stacked {
highest_stack_id = std::cmp::max(highest_stack_id, stack_id + 1);
}
}
highest_stack_id
}
fn reset_stack_size(
&self,
new_position_and_size_of_stack: &PaneGeom,
all_stacked_pane_positions: &Vec<(PaneId, PaneGeom)>,
flexible_pane_id: PaneId,
pane_ids_that_were_resized: &mut Vec<PaneId>,
) {
let mut running_pane_geom = new_position_and_size_of_stack.clone();
let only_one_pane_left_in_stack = all_stacked_pane_positions.len() == 1;
let count_of_one_liners_in_stack =
all_stacked_pane_positions.iter().len().saturating_sub(1);
let flexible_pane_row_count = running_pane_geom
.rows
.as_usize()
.saturating_sub(count_of_one_liners_in_stack);
for (pane_id_in_stack, pane_geom_in_stack) in all_stacked_pane_positions.iter() {
let logical_position = pane_geom_in_stack.logical_position;
if only_one_pane_left_in_stack {
self.set_geom_of_broken_out_pane(*pane_id_in_stack, running_pane_geom);
} else if pane_id_in_stack == &flexible_pane_id {
self.set_geom_of_flexible_pane(
*pane_id_in_stack,
&mut running_pane_geom,
flexible_pane_row_count,
logical_position,
);
} else {
self.set_geom_of_one_liner_pane(
*pane_id_in_stack,
&mut running_pane_geom,
logical_position,
);
}
pane_ids_that_were_resized.push(*pane_id_in_stack);
}
}
fn set_geom_of_broken_out_pane(
&self,
pane_id_to_break_out: PaneId,
mut position_and_size: PaneGeom,
) {
let mut panes = self.panes.borrow_mut();
if let Some(pane_to_break_out) = panes.get_mut(&pane_id_to_break_out) {
let logical_position_of_pane = pane_to_break_out.current_geom().logical_position;
position_and_size.logical_position = logical_position_of_pane;
position_and_size.stacked = None;
pane_to_break_out.set_geom(position_and_size);
}
}
fn set_geom_of_flexible_pane(
&self,
pane_id_of_flexible_pane: PaneId,
running_pane_geom: &mut PaneGeom,
row_count: usize,
logical_position: Option<usize>,
) {
let mut flexible_pane_geom = running_pane_geom.clone();
let mut panes = self.panes.borrow_mut();
if let Some(pane_in_stack) = panes.get_mut(&pane_id_of_flexible_pane) {
flexible_pane_geom.rows.set_inner(row_count);
running_pane_geom.y += flexible_pane_geom.rows.as_usize();
running_pane_geom
.rows
.decrease_inner(flexible_pane_geom.rows.as_usize());
flexible_pane_geom.logical_position = logical_position;
pane_in_stack.set_geom(flexible_pane_geom);
}
}
fn set_geom_of_one_liner_pane(
&self,
pane_id_of_one_liner_pane: PaneId,
running_pane_geom: &mut PaneGeom,
logical_position: Option<usize>,
) {
let mut one_liner_geom = running_pane_geom.clone();
let mut panes = self.panes.borrow_mut();
if let Some(pane_in_stack) = panes.get_mut(&pane_id_of_one_liner_pane) {
one_liner_geom.rows = Dimension::fixed(1);
running_pane_geom.y += 1;
running_pane_geom.rows.decrease_inner(1);
one_liner_geom.logical_position = logical_position;
pane_in_stack.set_geom(one_liner_geom);
}
}
fn break_out_stack_geom_upwards(
&self,
position_and_size_of_stack: PaneGeom,
all_stacked_pane_positions: &mut Vec<(PaneId, PaneGeom)>,
) -> Option<(PaneGeom, PaneGeom, PaneId)> {
let mut new_position_and_size_of_stack = position_and_size_of_stack.clone();
let rows_for_broken_out_pane = new_position_and_size_of_stack
.rows
.split_out(all_stacked_pane_positions.len() as f64);
let mut position_and_size_of_broken_out_pane = position_and_size_of_stack.clone();
position_and_size_of_broken_out_pane.stacked = None;
position_and_size_of_broken_out_pane.rows = rows_for_broken_out_pane;
new_position_and_size_of_stack.y = position_and_size_of_broken_out_pane.y
+ position_and_size_of_broken_out_pane.rows.as_usize();
let pane_id_to_break_out = all_stacked_pane_positions.remove(0).0;
Some((
new_position_and_size_of_stack,
position_and_size_of_broken_out_pane,
pane_id_to_break_out,
))
}
fn break_out_stack_geom_downwards(
&self,
position_and_size_of_stack: PaneGeom,
all_stacked_pane_positions: &mut Vec<(PaneId, PaneGeom)>,
) -> Option<(PaneGeom, PaneGeom, PaneId)> {
let mut new_position_and_size_of_stack = position_and_size_of_stack.clone();
let rows_for_broken_out_pane = new_position_and_size_of_stack
.rows
.split_out(all_stacked_pane_positions.len() as f64);
let mut position_and_size_of_broken_out_pane = position_and_size_of_stack.clone();
position_and_size_of_broken_out_pane.stacked = None;
position_and_size_of_broken_out_pane.y =
new_position_and_size_of_stack.y + new_position_and_size_of_stack.rows.as_usize();
position_and_size_of_broken_out_pane.rows = rows_for_broken_out_pane;
let pane_id_to_break_out = all_stacked_pane_positions.pop()?.0;
Some((
new_position_and_size_of_stack,
position_and_size_of_broken_out_pane,
pane_id_to_break_out,
))
}
fn get_flexible_pane_id(
&self,
all_stacked_pane_positions: &Vec<(PaneId, PaneGeom)>,
) -> Option<PaneId> {
let err_context = || "Failed to get flexible pane id";
let position_of_flexible_pane = self
.position_of_flexible_pane(&all_stacked_pane_positions)
.with_context(err_context)
.ok()?;
let (flexible_pane_id, _flexible_pane_geom) = all_stacked_pane_positions
.iter()
.nth(position_of_flexible_pane)
.copied()
.with_context(err_context)
.ok()?;
Some(flexible_pane_id)
}
fn get_all_stacks(&self) -> Result<Vec<Vec<(PaneId, PaneGeom)>>> { fn get_all_stacks(&self) -> Result<Vec<Vec<(PaneId, PaneGeom)>>> {
let err_context = || "Failed to get positions in stack"; let err_context = || "Failed to get positions in stack";
let panes = self.panes.borrow(); let panes = self.panes.borrow();
let all_flexible_panes_in_stack: Vec<PaneId> = panes let all_flexible_panes_in_stack: Vec<PaneId> = panes
.iter() .iter()
.filter(|(_pid, p)| { .filter(|(_pid, p)| {
p.position_and_size().is_stacked && !p.position_and_size().rows.is_fixed() p.position_and_size().is_stacked() && !p.position_and_size().rows.is_fixed()
}) })
.map(|(pid, _p)| *pid) .map(|(pid, _p)| *pid)
.collect(); .collect();
@ -528,6 +979,7 @@ impl<'a> StackedPanes<'a> {
let pane_to_close = panes.get(id).with_context(err_context)?; let pane_to_close = panes.get(id).with_context(err_context)?;
let position_of_current_pane = let position_of_current_pane =
self.position_of_current_pane(&all_stacked_pane_positions, &pane_to_close)?; self.position_of_current_pane(&all_stacked_pane_positions, &pane_to_close)?;
let only_one_pane_remaining_in_stack_after_close = all_stacked_pane_positions.len() == 2;
if all_stacked_pane_positions.len() > position_of_current_pane + 1 { if all_stacked_pane_positions.len() > position_of_current_pane + 1 {
let mut pane_to_close_position_and_size = pane_to_close.position_and_size(); let mut pane_to_close_position_and_size = pane_to_close.position_and_size();
pane_to_close_position_and_size pane_to_close_position_and_size
@ -538,6 +990,9 @@ impl<'a> StackedPanes<'a> {
.nth(position_of_current_pane + 1) .nth(position_of_current_pane + 1)
.map(|(pid, _)| *pid) .map(|(pid, _)| *pid)
.with_context(err_context)?; .with_context(err_context)?;
if only_one_pane_remaining_in_stack_after_close {
pane_to_close_position_and_size.stacked = None;
}
let pane_below = panes.get_mut(&pane_id_below).with_context(err_context)?; let pane_below = panes.get_mut(&pane_id_below).with_context(err_context)?;
pane_below.set_geom(pane_to_close_position_and_size); pane_below.set_geom(pane_to_close_position_and_size);
return Ok(true); return Ok(true);
@ -552,6 +1007,9 @@ impl<'a> StackedPanes<'a> {
.nth(position_of_current_pane - 1) .nth(position_of_current_pane - 1)
.map(|(pid, _)| *pid) .map(|(pid, _)| *pid)
.with_context(err_context)?; .with_context(err_context)?;
if only_one_pane_remaining_in_stack_after_close {
pane_to_close_position_and_size.stacked = None;
}
let pane_above = panes.get_mut(&pane_id_above).with_context(err_context)?; let pane_above = panes.get_mut(&pane_id_above).with_context(err_context)?;
pane_above.set_geom(pane_to_close_position_and_size); pane_above.set_geom(pane_to_close_position_and_size);
return Ok(true); return Ok(true);
@ -710,3 +1168,7 @@ impl<'a> StackedPanes<'a> {
Ok(()) Ok(())
} }
} }
#[cfg(test)]
#[path = "./unit/stacked_panes_tests.rs"]
mod stacked_panes_tests;

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,112 @@
---
source: zellij-server/src/panes/tiled_panes/./unit/stacked_panes_tests.rs
assertion_line: 176
expression: "format!(\"{:#?}\", pane_geoms_after)"
---
[
PaneGeom {
x: 0,
y: 0,
rows: Dimension {
constraint: Percent(
33.3,
),
inner: 33,
},
cols: Dimension {
constraint: Percent(
100.0,
),
inner: 1,
},
is_stacked: false,
is_pinned: false,
logical_position: Some(
1,
),
},
PaneGeom {
x: 0,
y: 33,
rows: Dimension {
constraint: Percent(
33.3,
),
inner: 33,
},
cols: Dimension {
constraint: Percent(
100.0,
),
inner: 1,
},
is_stacked: false,
is_pinned: false,
logical_position: Some(
2,
),
},
PaneGeom {
x: 0,
y: 66,
rows: Dimension {
constraint: Percent(
11.1,
),
inner: 11,
},
cols: Dimension {
constraint: Percent(
100.0,
),
inner: 1,
},
is_stacked: false,
is_pinned: false,
logical_position: Some(
3,
),
},
PaneGeom {
x: 0,
y: 77,
rows: Dimension {
constraint: Percent(
22.199999999999996,
),
inner: 22,
},
cols: Dimension {
constraint: Percent(
100.0,
),
inner: 1,
},
is_stacked: true,
is_pinned: false,
logical_position: Some(
4,
),
},
PaneGeom {
x: 0,
y: 99,
rows: Dimension {
constraint: Fixed(
1,
),
inner: 1,
},
cols: Dimension {
constraint: Percent(
100.0,
),
inner: 1,
},
is_stacked: true,
is_pinned: false,
logical_position: Some(
5,
),
},
]

View file

@ -0,0 +1,112 @@
---
source: zellij-server/src/panes/tiled_panes/./unit/stacked_panes_tests.rs
assertion_line: 221
expression: "format!(\"{:#?}\", pane_geoms_after)"
---
[
PaneGeom {
x: 0,
y: 0,
rows: Dimension {
constraint: Percent(
33.3,
),
inner: 33,
},
cols: Dimension {
constraint: Percent(
100.0,
),
inner: 1,
},
stacked: None,
is_pinned: false,
logical_position: Some(
1,
),
},
PaneGeom {
x: 0,
y: 33,
rows: Dimension {
constraint: Percent(
33.3,
),
inner: 33,
},
cols: Dimension {
constraint: Percent(
100.0,
),
inner: 1,
},
stacked: None,
is_pinned: false,
logical_position: Some(
2,
),
},
PaneGeom {
x: 0,
y: 66,
rows: Dimension {
constraint: Percent(
22.1,
),
inner: 22,
},
cols: Dimension {
constraint: Percent(
100.0,
),
inner: 1,
},
stacked: None,
is_pinned: false,
logical_position: Some(
3,
),
},
PaneGeom {
x: 0,
y: 88,
rows: Dimension {
constraint: Percent(
5.6,
),
inner: 6,
},
cols: Dimension {
constraint: Percent(
100.0,
),
inner: 1,
},
stacked: None,
is_pinned: false,
logical_position: Some(
4,
),
},
PaneGeom {
x: 0,
y: 94,
rows: Dimension {
constraint: Percent(
5.6,
),
inner: 6,
},
cols: Dimension {
constraint: Percent(
100.0,
),
inner: 1,
},
stacked: None,
is_pinned: false,
logical_position: Some(
5,
),
},
]

View file

@ -0,0 +1,112 @@
---
source: zellij-server/src/panes/tiled_panes/./unit/stacked_panes_tests.rs
assertion_line: 156
expression: "format!(\"{:#?}\", pane_geoms_after)"
---
[
PaneGeom {
x: 0,
y: 0,
rows: Dimension {
constraint: Percent(
33.3,
),
inner: 33,
},
cols: Dimension {
constraint: Percent(
100.0,
),
inner: 1,
},
is_stacked: false,
is_pinned: false,
logical_position: Some(
1,
),
},
PaneGeom {
x: 0,
y: 33,
rows: Dimension {
constraint: Percent(
33.3,
),
inner: 33,
},
cols: Dimension {
constraint: Percent(
100.0,
),
inner: 1,
},
is_stacked: false,
is_pinned: false,
logical_position: Some(
2,
),
},
PaneGeom {
x: 0,
y: 66,
rows: Dimension {
constraint: Fixed(
1,
),
inner: 1,
},
cols: Dimension {
constraint: Percent(
100.0,
),
inner: 1,
},
is_stacked: true,
is_pinned: false,
logical_position: Some(
3,
),
},
PaneGeom {
x: 0,
y: 67,
rows: Dimension {
constraint: Percent(
22.199999999999996,
),
inner: 22,
},
cols: Dimension {
constraint: Percent(
100.0,
),
inner: 1,
},
is_stacked: true,
is_pinned: false,
logical_position: Some(
4,
),
},
PaneGeom {
x: 0,
y: 89,
rows: Dimension {
constraint: Percent(
11.1,
),
inner: 11,
},
cols: Dimension {
constraint: Percent(
100.0,
),
inner: 1,
},
is_stacked: false,
is_pinned: false,
logical_position: Some(
5,
),
},
]

View file

@ -0,0 +1,116 @@
---
source: zellij-server/src/panes/tiled_panes/./unit/stacked_panes_tests.rs
assertion_line: 201
expression: "format!(\"{:#?}\", pane_geoms_after)"
---
[
PaneGeom {
x: 0,
y: 0,
rows: Dimension {
constraint: Percent(
33.3,
),
inner: 33,
},
cols: Dimension {
constraint: Percent(
100.0,
),
inner: 1,
},
stacked: None,
is_pinned: false,
logical_position: Some(
1,
),
},
PaneGeom {
x: 0,
y: 33,
rows: Dimension {
constraint: Percent(
33.3,
),
inner: 33,
},
cols: Dimension {
constraint: Percent(
100.0,
),
inner: 1,
},
stacked: None,
is_pinned: false,
logical_position: Some(
2,
),
},
PaneGeom {
x: 0,
y: 66,
rows: Dimension {
constraint: Percent(
11.1,
),
inner: 11,
},
cols: Dimension {
constraint: Percent(
100.0,
),
inner: 1,
},
stacked: None,
is_pinned: false,
logical_position: Some(
3,
),
},
PaneGeom {
x: 0,
y: 77,
rows: Dimension {
constraint: Fixed(
1,
),
inner: 1,
},
cols: Dimension {
constraint: Percent(
100.0,
),
inner: 1,
},
stacked: Some(
0,
),
is_pinned: false,
logical_position: Some(
4,
),
},
PaneGeom {
x: 0,
y: 78,
rows: Dimension {
constraint: Percent(
22.199999999999996,
),
inner: 22,
},
cols: Dimension {
constraint: Percent(
100.0,
),
inner: 1,
},
stacked: Some(
0,
),
is_pinned: false,
logical_position: Some(
5,
),
},
]

View file

@ -0,0 +1,116 @@
---
source: zellij-server/src/panes/tiled_panes/./unit/stacked_panes_tests.rs
assertion_line: 179
expression: "format!(\"{:#?}\", pane_geoms_after)"
---
[
PaneGeom {
x: 0,
y: 0,
rows: Dimension {
constraint: Percent(
33.3,
),
inner: 33,
},
cols: Dimension {
constraint: Percent(
100.0,
),
inner: 1,
},
stacked: None,
is_pinned: false,
logical_position: Some(
1,
),
},
PaneGeom {
x: 0,
y: 33,
rows: Dimension {
constraint: Percent(
33.3,
),
inner: 33,
},
cols: Dimension {
constraint: Percent(
100.0,
),
inner: 1,
},
stacked: None,
is_pinned: false,
logical_position: Some(
2,
),
},
PaneGeom {
x: 0,
y: 66,
rows: Dimension {
constraint: Fixed(
1,
),
inner: 1,
},
cols: Dimension {
constraint: Percent(
100.0,
),
inner: 1,
},
stacked: Some(
0,
),
is_pinned: false,
logical_position: Some(
3,
),
},
PaneGeom {
x: 0,
y: 67,
rows: Dimension {
constraint: Percent(
22.199999999999996,
),
inner: 22,
},
cols: Dimension {
constraint: Percent(
100.0,
),
inner: 1,
},
stacked: Some(
0,
),
is_pinned: false,
logical_position: Some(
4,
),
},
PaneGeom {
x: 0,
y: 89,
rows: Dimension {
constraint: Percent(
11.1,
),
inner: 11,
},
cols: Dimension {
constraint: Percent(
100.0,
),
inner: 1,
},
stacked: None,
is_pinned: false,
logical_position: Some(
5,
),
},
]

View file

@ -0,0 +1,116 @@
---
source: zellij-server/src/panes/tiled_panes/./unit/stacked_panes_tests.rs
assertion_line: 158
expression: "format!(\"{:#?}\", pane_geoms_after)"
---
[
PaneGeom {
x: 0,
y: 0,
rows: Dimension {
constraint: Percent(
33.3,
),
inner: 33,
},
cols: Dimension {
constraint: Percent(
100.0,
),
inner: 1,
},
stacked: None,
is_pinned: false,
logical_position: Some(
1,
),
},
PaneGeom {
x: 0,
y: 33,
rows: Dimension {
constraint: Percent(
33.3,
),
inner: 33,
},
cols: Dimension {
constraint: Percent(
100.0,
),
inner: 1,
},
stacked: None,
is_pinned: false,
logical_position: Some(
2,
),
},
PaneGeom {
x: 0,
y: 66,
rows: Dimension {
constraint: Percent(
22.199999999999996,
),
inner: 22,
},
cols: Dimension {
constraint: Percent(
100.0,
),
inner: 1,
},
stacked: Some(
0,
),
is_pinned: false,
logical_position: Some(
3,
),
},
PaneGeom {
x: 0,
y: 88,
rows: Dimension {
constraint: Fixed(
1,
),
inner: 1,
},
cols: Dimension {
constraint: Percent(
100.0,
),
inner: 1,
},
stacked: Some(
0,
),
is_pinned: false,
logical_position: Some(
4,
),
},
PaneGeom {
x: 0,
y: 89,
rows: Dimension {
constraint: Percent(
11.1,
),
inner: 11,
},
cols: Dimension {
constraint: Percent(
100.0,
),
inner: 1,
},
stacked: None,
is_pinned: false,
logical_position: Some(
5,
),
},
]

View file

@ -0,0 +1,76 @@
---
source: zellij-server/src/panes/tiled_panes/./unit/stacked_panes_tests.rs
assertion_line: 233
expression: "format!(\"{:#?}\", pane_geoms_after)"
---
[
PaneGeom {
x: 0,
y: 0,
rows: Dimension {
constraint: Percent(
100.0,
),
inner: 98,
},
cols: Dimension {
constraint: Percent(
100.0,
),
inner: 100,
},
stacked: Some(
0,
),
is_pinned: false,
logical_position: Some(
1,
),
},
PaneGeom {
x: 0,
y: 98,
rows: Dimension {
constraint: Fixed(
1,
),
inner: 1,
},
cols: Dimension {
constraint: Percent(
100.0,
),
inner: 100,
},
stacked: Some(
0,
),
is_pinned: false,
logical_position: Some(
2,
),
},
PaneGeom {
x: 0,
y: 99,
rows: Dimension {
constraint: Fixed(
1,
),
inner: 1,
},
cols: Dimension {
constraint: Percent(
100.0,
),
inner: 100,
},
stacked: Some(
0,
),
is_pinned: false,
logical_position: Some(
3,
),
},
]

View file

@ -0,0 +1,122 @@
---
source: zellij-server/src/panes/tiled_panes/./unit/stacked_panes_tests.rs
assertion_line: 302
expression: "format!(\"{:#?}\", pane_geoms_after)"
---
[
PaneGeom {
x: 0,
y: 0,
rows: Dimension {
constraint: Percent(
100.0,
),
inner: 96,
},
cols: Dimension {
constraint: Percent(
100.0,
),
inner: 100,
},
stacked: Some(
1,
),
is_pinned: false,
logical_position: Some(
1,
),
},
PaneGeom {
x: 0,
y: 96,
rows: Dimension {
constraint: Fixed(
1,
),
inner: 1,
},
cols: Dimension {
constraint: Percent(
100.0,
),
inner: 100,
},
stacked: Some(
1,
),
is_pinned: false,
logical_position: Some(
2,
),
},
PaneGeom {
x: 0,
y: 97,
rows: Dimension {
constraint: Fixed(
1,
),
inner: 1,
},
cols: Dimension {
constraint: Percent(
100.0,
),
inner: 100,
},
stacked: Some(
1,
),
is_pinned: false,
logical_position: Some(
3,
),
},
PaneGeom {
x: 0,
y: 98,
rows: Dimension {
constraint: Fixed(
1,
),
inner: 1,
},
cols: Dimension {
constraint: Percent(
100.0,
),
inner: 100,
},
stacked: Some(
1,
),
is_pinned: false,
logical_position: Some(
4,
),
},
PaneGeom {
x: 0,
y: 99,
rows: Dimension {
constraint: Fixed(
1,
),
inner: 1,
},
cols: Dimension {
constraint: Percent(
100.0,
),
inner: 100,
},
stacked: Some(
1,
),
is_pinned: false,
logical_position: Some(
5,
),
},
]

View file

@ -0,0 +1,122 @@
---
source: zellij-server/src/panes/tiled_panes/./unit/stacked_panes_tests.rs
assertion_line: 324
expression: "format!(\"{:#?}\", pane_geoms_after)"
---
[
PaneGeom {
x: 0,
y: 2,
rows: Dimension {
constraint: Percent(
100.0,
),
inner: 96,
},
cols: Dimension {
constraint: Percent(
100.0,
),
inner: 100,
},
stacked: Some(
1,
),
is_pinned: false,
logical_position: Some(
1,
),
},
PaneGeom {
x: 0,
y: 98,
rows: Dimension {
constraint: Fixed(
1,
),
inner: 1,
},
cols: Dimension {
constraint: Percent(
100.0,
),
inner: 100,
},
stacked: Some(
1,
),
is_pinned: false,
logical_position: Some(
2,
),
},
PaneGeom {
x: 0,
y: 99,
rows: Dimension {
constraint: Fixed(
1,
),
inner: 1,
},
cols: Dimension {
constraint: Percent(
100.0,
),
inner: 100,
},
stacked: Some(
1,
),
is_pinned: false,
logical_position: Some(
3,
),
},
PaneGeom {
x: 0,
y: 0,
rows: Dimension {
constraint: Fixed(
1,
),
inner: 1,
},
cols: Dimension {
constraint: Percent(
100.0,
),
inner: 100,
},
stacked: Some(
1,
),
is_pinned: false,
logical_position: Some(
4,
),
},
PaneGeom {
x: 0,
y: 1,
rows: Dimension {
constraint: Fixed(
1,
),
inner: 1,
},
cols: Dimension {
constraint: Percent(
100.0,
),
inner: 100,
},
stacked: Some(
1,
),
is_pinned: false,
logical_position: Some(
5,
),
},
]

View file

@ -0,0 +1,53 @@
---
source: zellij-server/src/panes/tiled_panes/./unit/stacked_panes_tests.rs
assertion_line: 132
expression: "format!(\"{:#?}\", pane_geoms_after)"
---
[
PaneGeom {
x: 0,
y: 0,
rows: Dimension {
constraint: Percent(
100.0,
),
inner: 99,
},
cols: Dimension {
constraint: Percent(
100.0,
),
inner: 1,
},
stacked: Some(
0,
),
is_pinned: false,
logical_position: Some(
1,
),
},
PaneGeom {
x: 0,
y: 99,
rows: Dimension {
constraint: Fixed(
1,
),
inner: 1,
},
cols: Dimension {
constraint: Percent(
100.0,
),
inner: 1,
},
stacked: Some(
0,
),
is_pinned: false,
logical_position: Some(
2,
),
},
]

View file

@ -0,0 +1,122 @@
---
source: zellij-server/src/panes/tiled_panes/./unit/stacked_panes_tests.rs
assertion_line: 214
expression: "format!(\"{:#?}\", pane_geoms_after)"
---
[
PaneGeom {
x: 0,
y: 0,
rows: Dimension {
constraint: Fixed(
1,
),
inner: 1,
},
cols: Dimension {
constraint: Percent(
100.0,
),
inner: 1,
},
stacked: Some(
2,
),
is_pinned: false,
logical_position: Some(
1,
),
},
PaneGeom {
x: 0,
y: 1,
rows: Dimension {
constraint: Percent(
100.0,
),
inner: 96,
},
cols: Dimension {
constraint: Percent(
100.0,
),
inner: 1,
},
stacked: Some(
2,
),
is_pinned: false,
logical_position: Some(
2,
),
},
PaneGeom {
x: 0,
y: 97,
rows: Dimension {
constraint: Fixed(
1,
),
inner: 1,
},
cols: Dimension {
constraint: Percent(
100.0,
),
inner: 1,
},
stacked: Some(
2,
),
is_pinned: false,
logical_position: Some(
3,
),
},
PaneGeom {
x: 0,
y: 98,
rows: Dimension {
constraint: Fixed(
1,
),
inner: 1,
},
cols: Dimension {
constraint: Percent(
100.0,
),
inner: 1,
},
stacked: Some(
2,
),
is_pinned: false,
logical_position: Some(
4,
),
},
PaneGeom {
x: 0,
y: 99,
rows: Dimension {
constraint: Fixed(
1,
),
inner: 1,
},
cols: Dimension {
constraint: Percent(
100.0,
),
inner: 1,
},
stacked: Some(
2,
),
is_pinned: false,
logical_position: Some(
5,
),
},
]

View file

@ -0,0 +1,97 @@
---
source: zellij-server/src/panes/tiled_panes/./unit/stacked_panes_tests.rs
assertion_line: 152
expression: "format!(\"{:#?}\", pane_geoms_after)"
---
[
PaneGeom {
x: 0,
y: 0,
rows: Dimension {
constraint: Percent(
33.3,
),
inner: 33,
},
cols: Dimension {
constraint: Percent(
100.0,
),
inner: 1,
},
stacked: None,
is_pinned: false,
logical_position: Some(
1,
),
},
PaneGeom {
x: 0,
y: 33,
rows: Dimension {
constraint: Percent(
66.6,
),
inner: 65,
},
cols: Dimension {
constraint: Percent(
100.0,
),
inner: 1,
},
stacked: Some(
1,
),
is_pinned: false,
logical_position: Some(
2,
),
},
PaneGeom {
x: 0,
y: 98,
rows: Dimension {
constraint: Fixed(
1,
),
inner: 1,
},
cols: Dimension {
constraint: Percent(
100.0,
),
inner: 1,
},
stacked: Some(
1,
),
is_pinned: false,
logical_position: Some(
3,
),
},
PaneGeom {
x: 0,
y: 99,
rows: Dimension {
constraint: Fixed(
1,
),
inner: 1,
},
cols: Dimension {
constraint: Percent(
100.0,
),
inner: 1,
},
stacked: Some(
1,
),
is_pinned: false,
logical_position: Some(
4,
),
},
]

View file

@ -0,0 +1,120 @@
---
source: zellij-server/src/panes/tiled_panes/./unit/stacked_panes_tests.rs
assertion_line: 193
expression: "format!(\"{:#?}\", pane_geoms_after)"
---
[
PaneGeom {
x: 0,
y: 0,
rows: Dimension {
constraint: Percent(
33.3,
),
inner: 33,
},
cols: Dimension {
constraint: Percent(
100.0,
),
inner: 1,
},
stacked: None,
is_pinned: false,
logical_position: Some(
1,
),
},
PaneGeom {
x: 0,
y: 33,
rows: Dimension {
constraint: Percent(
66.6,
),
inner: 64,
},
cols: Dimension {
constraint: Percent(
100.0,
),
inner: 1,
},
stacked: Some(
1,
),
is_pinned: false,
logical_position: Some(
2,
),
},
PaneGeom {
x: 0,
y: 97,
rows: Dimension {
constraint: Fixed(
1,
),
inner: 1,
},
cols: Dimension {
constraint: Percent(
100.0,
),
inner: 1,
},
stacked: Some(
1,
),
is_pinned: false,
logical_position: Some(
3,
),
},
PaneGeom {
x: 0,
y: 98,
rows: Dimension {
constraint: Fixed(
1,
),
inner: 1,
},
cols: Dimension {
constraint: Percent(
100.0,
),
inner: 1,
},
stacked: Some(
1,
),
is_pinned: false,
logical_position: Some(
4,
),
},
PaneGeom {
x: 0,
y: 99,
rows: Dimension {
constraint: Fixed(
1,
),
inner: 1,
},
cols: Dimension {
constraint: Percent(
100.0,
),
inner: 1,
},
stacked: Some(
1,
),
is_pinned: false,
logical_position: Some(
5,
),
},
]

View file

@ -0,0 +1,97 @@
---
source: zellij-server/src/panes/tiled_panes/./unit/stacked_panes_tests.rs
assertion_line: 172
expression: "format!(\"{:#?}\", pane_geoms_after)"
---
[
PaneGeom {
x: 0,
y: 0,
rows: Dimension {
constraint: Percent(
33.3,
),
inner: 33,
},
cols: Dimension {
constraint: Percent(
100.0,
),
inner: 1,
},
stacked: None,
is_pinned: false,
logical_position: Some(
1,
),
},
PaneGeom {
x: 0,
y: 33,
rows: Dimension {
constraint: Percent(
66.6,
),
inner: 65,
},
cols: Dimension {
constraint: Percent(
100.0,
),
inner: 1,
},
stacked: Some(
1,
),
is_pinned: false,
logical_position: Some(
2,
),
},
PaneGeom {
x: 0,
y: 98,
rows: Dimension {
constraint: Fixed(
1,
),
inner: 1,
},
cols: Dimension {
constraint: Percent(
100.0,
),
inner: 1,
},
stacked: Some(
1,
),
is_pinned: false,
logical_position: Some(
3,
),
},
PaneGeom {
x: 0,
y: 99,
rows: Dimension {
constraint: Fixed(
1,
),
inner: 1,
},
cols: Dimension {
constraint: Percent(
100.0,
),
inner: 1,
},
stacked: Some(
1,
),
is_pinned: false,
logical_position: Some(
4,
),
},
]

View file

@ -0,0 +1,122 @@
---
source: zellij-server/src/panes/tiled_panes/./unit/stacked_panes_tests.rs
assertion_line: 241
expression: "format!(\"{:#?}\", pane_geoms_after)"
---
[
PaneGeom {
x: 0,
y: 0,
rows: Dimension {
constraint: Fixed(
1,
),
inner: 1,
},
cols: Dimension {
constraint: Percent(
100.0,
),
inner: 100,
},
stacked: Some(
2,
),
is_pinned: false,
logical_position: Some(
1,
),
},
PaneGeom {
x: 0,
y: 1,
rows: Dimension {
constraint: Fixed(
1,
),
inner: 1,
},
cols: Dimension {
constraint: Percent(
100.0,
),
inner: 100,
},
stacked: Some(
2,
),
is_pinned: false,
logical_position: Some(
2,
),
},
PaneGeom {
x: 0,
y: 2,
rows: Dimension {
constraint: Fixed(
1,
),
inner: 1,
},
cols: Dimension {
constraint: Percent(
100.0,
),
inner: 100,
},
stacked: Some(
2,
),
is_pinned: false,
logical_position: Some(
3,
),
},
PaneGeom {
x: 0,
y: 3,
rows: Dimension {
constraint: Percent(
100.0,
),
inner: 96,
},
cols: Dimension {
constraint: Percent(
100.0,
),
inner: 100,
},
stacked: Some(
2,
),
is_pinned: false,
logical_position: Some(
4,
),
},
PaneGeom {
x: 0,
y: 99,
rows: Dimension {
constraint: Fixed(
1,
),
inner: 1,
},
cols: Dimension {
constraint: Percent(
100.0,
),
inner: 100,
},
stacked: Some(
2,
),
is_pinned: false,
logical_position: Some(
5,
),
},
]

View file

@ -0,0 +1,145 @@
---
source: zellij-server/src/panes/tiled_panes/./unit/stacked_panes_tests.rs
assertion_line: 261
expression: "format!(\"{:#?}\", pane_geoms_after)"
---
[
PaneGeom {
x: 0,
y: 0,
rows: Dimension {
constraint: Fixed(
1,
),
inner: 1,
},
cols: Dimension {
constraint: Percent(
100.0,
),
inner: 100,
},
stacked: Some(
3,
),
is_pinned: false,
logical_position: Some(
1,
),
},
PaneGeom {
x: 0,
y: 1,
rows: Dimension {
constraint: Fixed(
1,
),
inner: 1,
},
cols: Dimension {
constraint: Percent(
100.0,
),
inner: 100,
},
stacked: Some(
3,
),
is_pinned: false,
logical_position: Some(
2,
),
},
PaneGeom {
x: 0,
y: 2,
rows: Dimension {
constraint: Fixed(
1,
),
inner: 1,
},
cols: Dimension {
constraint: Percent(
100.0,
),
inner: 100,
},
stacked: Some(
3,
),
is_pinned: false,
logical_position: Some(
3,
),
},
PaneGeom {
x: 0,
y: 3,
rows: Dimension {
constraint: Fixed(
1,
),
inner: 1,
},
cols: Dimension {
constraint: Percent(
100.0,
),
inner: 100,
},
stacked: Some(
3,
),
is_pinned: false,
logical_position: Some(
4,
),
},
PaneGeom {
x: 0,
y: 4,
rows: Dimension {
constraint: Percent(
100.0,
),
inner: 95,
},
cols: Dimension {
constraint: Percent(
100.0,
),
inner: 100,
},
stacked: Some(
3,
),
is_pinned: false,
logical_position: Some(
5,
),
},
PaneGeom {
x: 0,
y: 99,
rows: Dimension {
constraint: Fixed(
1,
),
inner: 1,
},
cols: Dimension {
constraint: Percent(
100.0,
),
inner: 100,
},
stacked: Some(
3,
),
is_pinned: false,
logical_position: Some(
6,
),
},
]

File diff suppressed because it is too large Load diff

View file

@ -367,6 +367,7 @@ pub enum ScreenInstruction {
auto_layout: bool, auto_layout: bool,
rounded_corners: bool, rounded_corners: bool,
hide_session_name: bool, hide_session_name: bool,
stacked_resize: bool,
}, },
RerunCommandPane(u32), // u32 - terminal pane id RerunCommandPane(u32), // u32 - terminal pane id
ResizePaneWithId(ResizeStrategy, PaneId), ResizePaneWithId(ResizeStrategy, PaneId),
@ -655,6 +656,7 @@ pub(crate) struct Screen {
size: Size, size: Size,
pixel_dimensions: PixelDimensions, pixel_dimensions: PixelDimensions,
character_cell_size: Rc<RefCell<Option<SizeInPixels>>>, character_cell_size: Rc<RefCell<Option<SizeInPixels>>>,
stacked_resize: Rc<RefCell<bool>>,
sixel_image_store: Rc<RefCell<SixelImageStore>>, sixel_image_store: Rc<RefCell<SixelImageStore>>,
/// The overlay that is drawn on top of [`Pane`]'s', [`Tab`]'s and the [`Screen`] /// The overlay that is drawn on top of [`Pane`]'s', [`Tab`]'s and the [`Screen`]
overlay: OverlayWindow, overlay: OverlayWindow,
@ -711,6 +713,7 @@ impl Screen {
arrow_fonts: bool, arrow_fonts: bool,
layout_dir: Option<PathBuf>, layout_dir: Option<PathBuf>,
explicitly_disable_kitty_keyboard_protocol: bool, explicitly_disable_kitty_keyboard_protocol: bool,
stacked_resize: bool,
) -> Self { ) -> Self {
let session_name = mode_info.session_name.clone().unwrap_or_default(); let session_name = mode_info.session_name.clone().unwrap_or_default();
let session_info = SessionInfo::new(session_name.clone()); let session_info = SessionInfo::new(session_name.clone());
@ -723,6 +726,7 @@ impl Screen {
size: client_attributes.size, size: client_attributes.size,
pixel_dimensions: Default::default(), pixel_dimensions: Default::default(),
character_cell_size: Rc::new(RefCell::new(None)), character_cell_size: Rc::new(RefCell::new(None)),
stacked_resize: Rc::new(RefCell::new(stacked_resize)),
sixel_image_store: Rc::new(RefCell::new(SixelImageStore::default())), sixel_image_store: Rc::new(RefCell::new(SixelImageStore::default())),
style: client_attributes.style, style: client_attributes.style,
connected_clients: Rc::new(RefCell::new(HashSet::new())), connected_clients: Rc::new(RefCell::new(HashSet::new())),
@ -1326,6 +1330,7 @@ impl Screen {
tab_name, tab_name,
self.size, self.size,
self.character_cell_size.clone(), self.character_cell_size.clone(),
self.stacked_resize.clone(),
self.sixel_image_store.clone(), self.sixel_image_store.clone(),
self.bus self.bus
.os_input .os_input
@ -2428,6 +2433,7 @@ impl Screen {
auto_layout: bool, auto_layout: bool,
rounded_corners: bool, rounded_corners: bool,
hide_session_name: bool, hide_session_name: bool,
stacked_resize: bool,
client_id: ClientId, client_id: ClientId,
) -> Result<()> { ) -> Result<()> {
let should_support_arrow_fonts = !simplified_ui; let should_support_arrow_fonts = !simplified_ui;
@ -2445,6 +2451,9 @@ impl Screen {
.update_arrow_fonts(should_support_arrow_fonts); .update_arrow_fonts(should_support_arrow_fonts);
self.default_mode_info self.default_mode_info
.update_hide_session_name(hide_session_name); .update_hide_session_name(hide_session_name);
{
*self.stacked_resize.borrow_mut() = stacked_resize;
}
if let Some(copy_to_clipboard) = copy_to_clipboard { if let Some(copy_to_clipboard) = copy_to_clipboard {
self.copy_options.clipboard = copy_to_clipboard; self.copy_options.clipboard = copy_to_clipboard;
} }
@ -2747,6 +2756,7 @@ pub(crate) fn screen_thread_main(
// explicitly_disable_kitty_keyboard_protocol is false and vice versa // explicitly_disable_kitty_keyboard_protocol is false and vice versa
.unwrap_or(false); // by default, we try to support this if the terminal supports it and .unwrap_or(false); // by default, we try to support this if the terminal supports it and
// the program running inside a pane requests it // the program running inside a pane requests it
let stacked_resize = config_options.stacked_resize.unwrap_or(true);
let thread_senders = bus.senders.clone(); let thread_senders = bus.senders.clone();
let mut screen = Screen::new( let mut screen = Screen::new(
@ -2778,6 +2788,7 @@ pub(crate) fn screen_thread_main(
arrow_fonts, arrow_fonts,
layout_dir, layout_dir,
explicitly_disable_kitty_keyboard_protocol, explicitly_disable_kitty_keyboard_protocol,
stacked_resize,
); );
let mut pending_tab_ids: HashSet<usize> = HashSet::new(); let mut pending_tab_ids: HashSet<usize> = HashSet::new();
@ -4493,6 +4504,7 @@ pub(crate) fn screen_thread_main(
auto_layout, auto_layout,
rounded_corners, rounded_corners,
hide_session_name, hide_session_name,
stacked_resize,
} => { } => {
screen screen
.reconfigure( .reconfigure(
@ -4508,6 +4520,7 @@ pub(crate) fn screen_thread_main(
auto_layout, auto_layout,
rounded_corners, rounded_corners,
hide_session_name, hide_session_name,
stacked_resize,
client_id, client_id,
) )
.non_fatal(); .non_fatal();

View file

@ -1000,7 +1000,7 @@ impl<'a> PaneApplier<'a> {
) { ) {
for pane_id in remaining_pane_ids { for pane_id in remaining_pane_ids {
if let Some(pane) = existing_tab_state.remove_pane(&pane_id) { if let Some(pane) = existing_tab_state.remove_pane(&pane_id) {
self.tiled_panes.insert_pane(pane.pid(), pane); self.tiled_panes.insert_pane(pane.pid(), pane, None);
} }
} }
} }

View file

@ -157,6 +157,7 @@ pub(crate) struct Tab {
viewport: Rc<RefCell<Viewport>>, // includes all non-UI panes viewport: Rc<RefCell<Viewport>>, // includes all non-UI panes
display_area: Rc<RefCell<Size>>, // includes all panes (including eg. the status bar and tab bar in the default layout) display_area: Rc<RefCell<Size>>, // includes all panes (including eg. the status bar and tab bar in the default layout)
character_cell_size: Rc<RefCell<Option<SizeInPixels>>>, character_cell_size: Rc<RefCell<Option<SizeInPixels>>>,
stacked_resize: Rc<RefCell<bool>>,
sixel_image_store: Rc<RefCell<SixelImageStore>>, sixel_image_store: Rc<RefCell<SixelImageStore>>,
os_api: Box<dyn ServerOsApi>, os_api: Box<dyn ServerOsApi>,
pub senders: ThreadSenders, pub senders: ThreadSenders,
@ -564,6 +565,7 @@ impl Tab {
name: String, name: String,
display_area: Size, display_area: Size,
character_cell_size: Rc<RefCell<Option<SizeInPixels>>>, character_cell_size: Rc<RefCell<Option<SizeInPixels>>>,
stacked_resize: Rc<RefCell<bool>>,
sixel_image_store: Rc<RefCell<SixelImageStore>>, sixel_image_store: Rc<RefCell<SixelImageStore>>,
os_api: Box<dyn ServerOsApi>, os_api: Box<dyn ServerOsApi>,
senders: ThreadSenders, senders: ThreadSenders,
@ -608,6 +610,7 @@ impl Tab {
connected_clients_in_app.clone(), connected_clients_in_app.clone(),
mode_info.clone(), mode_info.clone(),
character_cell_size.clone(), character_cell_size.clone(),
stacked_resize.clone(),
session_is_mirrored, session_is_mirrored,
draw_pane_frames, draw_pane_frames,
default_mode_info.clone(), default_mode_info.clone(),
@ -647,6 +650,7 @@ impl Tab {
viewport, viewport,
display_area, display_area,
character_cell_size, character_cell_size,
stacked_resize,
sixel_image_store, sixel_image_store,
synchronize_is_active: false, synchronize_is_active: false,
os_api, os_api,
@ -4256,9 +4260,10 @@ impl Tab {
if should_auto_layout { if should_auto_layout {
// no need to relayout here, we'll do it when reapplying the swap layout // no need to relayout here, we'll do it when reapplying the swap layout
// below // below
self.tiled_panes.insert_pane_without_relayout(pane_id, pane); self.tiled_panes
.insert_pane_without_relayout(pane_id, pane, client_id);
} else { } else {
self.tiled_panes.insert_pane(pane_id, pane); self.tiled_panes.insert_pane(pane_id, pane, client_id);
} }
self.set_should_clear_display_before_rendering(); self.set_should_clear_display_before_rendering();
if let Some(client_id) = client_id { if let Some(client_id) = client_id {
@ -4346,7 +4351,10 @@ impl Tab {
self.set_force_render(); // we force render here to make sure the panes under the floating pane render and don't leave "garbage" in case of a decrease self.set_force_render(); // we force render here to make sure the panes under the floating pane render and don't leave "garbage" in case of a decrease
} }
} else if self.tiled_panes.panes_contain(&pane_id) { } else if self.tiled_panes.panes_contain(&pane_id) {
match self.tiled_panes.resize_pane_with_id(strategy, pane_id) { match self
.tiled_panes
.resize_pane_with_id(strategy, pane_id, None)
{
Ok(_) => {}, Ok(_) => {},
Err(err) => match err.downcast_ref::<ZellijError>() { Err(err) => match err.downcast_ref::<ZellijError>() {
Some(ZellijError::CantResizeFixedPanes { pane_ids }) => { Some(ZellijError::CantResizeFixedPanes { pane_ids }) => {

View file

@ -0,0 +1,46 @@
---
source: zellij-server/src/tab/./unit/tab_integration_tests.rs
assertion_line: 830
expression: snapshot
---
00 (C): ┌ Pane #1 ─────────────────────────────────────────────────────────────────────────────────────────┐┌ Pane #2 ─────────────────────────────────────────────────────────────────────────────────────────┐
01 (C): │ │┌ Pane #3 ─────────────────────────────────────────────────────────────────────────────────────────┐
02 (C): │ │┌ Pane #4 ─────────────────────────────────────────────────────────────────────────────────────────┐
03 (C): │ ││ │
04 (C): │ ││ │
05 (C): │ ││ │
06 (C): │ ││ │
07 (C): │ ││ │
08 (C): │ ││ │
09 (C): │ ││ │
10 (C): │ ││ │
11 (C): │ ││ │
12 (C): │ ││ │
13 (C): │ ││ │
14 (C): │ ││ │
15 (C): │ ││ │
16 (C): │ ││ │
17 (C): │ ││ │
18 (C): │ ││ │
19 (C): │ ││ │
20 (C): │ ││ │
21 (C): │ ││ │
22 (C): │ ││ │
23 (C): │ ││ │
24 (C): │ ││ │
25 (C): │ ││ │
26 (C): │ ││ │
27 (C): │ ││ │
28 (C): │ ││ │
29 (C): │ ││ │
30 (C): │ ││ │
31 (C): │ ││ │
32 (C): │ ││ │
33 (C): │ ││ │
34 (C): │ ││ │
35 (C): │ ││ │
36 (C): │ ││ │
37 (C): │ ││ │
38 (C): │ ││ │
39 (C): └──────────────────────────────────────────────────────────────────────────────────────────────────┘└──────────────────────────────────────────────────────────────────────────────────────────────────┘

View file

@ -0,0 +1,46 @@
---
source: zellij-server/src/tab/./unit/tab_integration_tests.rs
assertion_line: 830
expression: snapshot
---
00 (C): ┌ Pane #1 ─────────────────────────────────────────────────────────────────────────────────────────┐┌ Pane #2 ─────────────────────────────────────────────────────────────────────────────────────────┐
01 (C): │ ││ │
02 (C): │ ││ │
03 (C): │ ││ │
04 (C): │ ││ │
05 (C): │ ││ │
06 (C): │ ││ │
07 (C): │ │└──────────────────────────────────────────────────────────────────────────────────────────────────┘
08 (C): │ │┌ Pane #3 ─────────────────────────────────────────────────────────────────────────────────────────┐
09 (C): │ │┌ Pane #4 ─────────────────────────────────────────────────────────────────────────────────────────┐
10 (C): │ ││ │
11 (C): │ ││ │
12 (C): │ ││ │
13 (C): │ ││ │
14 (C): │ ││ │
15 (C): │ ││ │
16 (C): │ ││ │
17 (C): │ ││ │
18 (C): │ ││ │
19 (C): │ ││ │
20 (C): │ ││ │
21 (C): │ ││ │
22 (C): │ ││ │
23 (C): │ ││ │
24 (C): │ ││ │
25 (C): │ ││ │
26 (C): │ ││ │
27 (C): │ ││ │
28 (C): │ ││ │
29 (C): │ ││ │
30 (C): │ ││ │
31 (C): │ ││ │
32 (C): │ ││ │
33 (C): │ ││ │
34 (C): │ ││ │
35 (C): │ ││ │
36 (C): │ ││ │
37 (C): │ ││ │
38 (C): │ ││ │
39 (C): └──────────────────────────────────────────────────────────────────────────────────────────────────┘└──────────────────────────────────────────────────────────────────────────────────────────────────┘

View file

@ -0,0 +1,46 @@
---
source: zellij-server/src/tab/./unit/tab_integration_tests.rs
assertion_line: 830
expression: snapshot
---
00 (C): ┌ Pane #1 ─────────────────────────────────────────────────────────────────────────────────────────┐┌ Pane #2 ─────────────────────────────────────────────────────────────────────────────────────────┐
01 (C): │ ││ │
02 (C): │ ││ │
03 (C): │ ││ │
04 (C): │ ││ │
05 (C): │ ││ │
06 (C): │ ││ │
07 (C): │ ││ │
08 (C): │ ││ │
09 (C): │ ││ │
10 (C): │ ││ │
11 (C): │ ││ │
12 (C): │ ││ │
13 (C): │ ││ │
14 (C): │ ││ │
15 (C): │ ││ │
16 (C): │ ││ │
17 (C): │ ││ │
18 (C): │ ││ │
19 (C): │ │└──────────────────────────────────────────────────────────────────────────────────────────────────┘
20 (C): │ │┌ Pane #3 ─────────────────────────────────────────────────────────────────────────────────────────┐
21 (C): │ │┌ Pane #4 ─────────────────────────────────────────────────────────────────────────────────────────┐
22 (C): │ ││ │
23 (C): │ ││ │
24 (C): │ ││ │
25 (C): │ ││ │
26 (C): │ ││ │
27 (C): │ ││ │
28 (C): │ ││ │
29 (C): │ ││ │
30 (C): │ ││ │
31 (C): │ ││ │
32 (C): │ ││ │
33 (C): │ ││ │
34 (C): │ ││ │
35 (C): │ ││ │
36 (C): │ ││ │
37 (C): │ ││ │
38 (C): │ ││ │
39 (C): └──────────────────────────────────────────────────────────────────────────────────────────────────┘└──────────────────────────────────────────────────────────────────────────────────────────────────┘

View file

@ -0,0 +1,46 @@
---
source: zellij-server/src/tab/./unit/tab_integration_tests.rs
assertion_line: 830
expression: snapshot
---
00 (C): ┌ Pane #1 ─────────────────────────────────────────────────────────────────────────────────────────┐┌ Pane #2 ─────────────────────────────────────────────────────────────────────────────────────────┐
01 (C): │ ││ │
02 (C): │ ││ │
03 (C): │ ││ │
04 (C): │ ││ │
05 (C): │ ││ │
06 (C): │ ││ │
07 (C): │ ││ │
08 (C): │ ││ │
09 (C): │ ││ │
10 (C): │ ││ │
11 (C): │ ││ │
12 (C): │ ││ │
13 (C): │ ││ │
14 (C): │ ││ │
15 (C): │ ││ │
16 (C): │ ││ │
17 (C): │ ││ │
18 (C): │ ││ │
19 (C): │ │└──────────────────────────────────────────────────────────────────────────────────────────────────┘
20 (C): │ │┌ Pane #3 ───────────────────────────────────────┐┌ Pane #4 ───────────────────────────────────────┐
21 (C): │ ││ ││ │
22 (C): │ ││ ││ │
23 (C): │ ││ ││ │
24 (C): │ ││ ││ │
25 (C): │ ││ ││ │
26 (C): │ ││ ││ │
27 (C): │ ││ ││ │
28 (C): │ ││ ││ │
29 (C): │ ││ ││ │
30 (C): │ ││ ││ │
31 (C): │ ││ ││ │
32 (C): │ ││ ││ │
33 (C): │ ││ ││ │
34 (C): │ ││ ││ │
35 (C): │ ││ ││ │
36 (C): │ ││ ││ │
37 (C): │ ││ ││ │
38 (C): │ ││ ││ │
39 (C): └──────────────────────────────────────────────────────────────────────────────────────────────────┘└────────────────────────────────────────────────┘└────────────────────────────────────────────────┘

View file

@ -0,0 +1,46 @@
---
source: zellij-server/src/tab/./unit/tab_integration_tests.rs
assertion_line: 815
expression: snapshot
---
00 (C): ┌ Pane #1 ─────────────────────────────────────────────────────────────────────────────────────────┐┌ Pane #2 ─────────────────────────────────────────────────────────────────────────────────────────┐
01 (C): │ ││ │
02 (C): │ ││ │
03 (C): │ ││ │
04 (C): │ ││ │
05 (C): │ ││ │
06 (C): │ ││ │
07 (C): │ │└──────────────────────────────────────────────────────────────────────────────────────────────────┘
08 (C): │ │┌ Pane #3 ─────────────────────────────────────────────────────────────────────────────────────────┐
09 (C): │ │┌ Pane #4 ─────────────────────────────────────────────────────────────────────────────────────────┐
10 (C): │ ││ │
11 (C): │ ││ │
12 (C): │ ││ │
13 (C): │ ││ │
14 (C): │ ││ │
15 (C): │ ││ │
16 (C): │ ││ │
17 (C): │ ││ │
18 (C): │ ││ │
19 (C): │ ││ │
20 (C): │ ││ │
21 (C): │ ││ │
22 (C): │ ││ │
23 (C): │ ││ │
24 (C): │ ││ │
25 (C): │ ││ │
26 (C): │ ││ │
27 (C): │ ││ │
28 (C): │ ││ │
29 (C): │ ││ │
30 (C): │ ││ │
31 (C): │ ││ │
32 (C): │ ││ │
33 (C): │ ││ │
34 (C): │ ││ │
35 (C): │ ││ │
36 (C): │ ││ │
37 (C): │ ││ │
38 (C): │ ││ │
39 (C): └──────────────────────────────────────────────────────────────────────────────────────────────────┘└──────────────────────────────────────────────────────────────────────────────────────────────────┘

View file

@ -0,0 +1,46 @@
---
source: zellij-server/src/tab/./unit/tab_integration_tests.rs
assertion_line: 816
expression: snapshot
---
00 (C): ┌ Pane #1 ─────────────────────────────────────────────────────────────────────────────────────────┐┌ Pane #2 ─────────────────────────────────────────────────────────────────────────────────────────┐
01 (C): │ │┌ Pane #3 ─────────────────────────────────────────────────────────────────────────────────────────┐
02 (C): │ │┌ Pane #4 ─────────────────────────────────────────────────────────────────────────────────────────┐
03 (C): │ ││ │
04 (C): │ ││ │
05 (C): │ ││ │
06 (C): │ ││ │
07 (C): │ ││ │
08 (C): │ ││ │
09 (C): │ ││ │
10 (C): │ ││ │
11 (C): │ ││ │
12 (C): │ ││ │
13 (C): │ ││ │
14 (C): │ ││ │
15 (C): │ ││ │
16 (C): │ ││ │
17 (C): │ ││ │
18 (C): │ ││ │
19 (C): │ ││ │
20 (C): │ ││ │
21 (C): │ ││ │
22 (C): │ ││ │
23 (C): │ ││ │
24 (C): │ ││ │
25 (C): │ ││ │
26 (C): │ ││ │
27 (C): │ ││ │
28 (C): │ ││ │
29 (C): │ ││ │
30 (C): │ ││ │
31 (C): │ ││ │
32 (C): │ ││ │
33 (C): │ ││ │
34 (C): │ ││ │
35 (C): │ ││ │
36 (C): │ ││ │
37 (C): │ ││ │
38 (C): │ ││ │
39 (C): └──────────────────────────────────────────────────────────────────────────────────────────────────┘└──────────────────────────────────────────────────────────────────────────────────────────────────┘

View file

@ -0,0 +1,46 @@
---
source: zellij-server/src/tab/./unit/tab_integration_tests.rs
assertion_line: 816
expression: snapshot
---
00 (C): ┌ Pane #1 ─────────────────────────────┐┌ Pane #2 ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
01 (C): │ │┌ Pane #3 ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
02 (C): │ │┌ Pane #4 ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
03 (C): │ ││ │
04 (C): │ ││ │
05 (C): │ ││ │
06 (C): │ ││ │
07 (C): │ ││ │
08 (C): │ ││ │
09 (C): │ ││ │
10 (C): │ ││ │
11 (C): │ ││ │
12 (C): │ ││ │
13 (C): │ ││ │
14 (C): │ ││ │
15 (C): │ ││ │
16 (C): │ ││ │
17 (C): │ ││ │
18 (C): │ ││ │
19 (C): │ ││ │
20 (C): │ ││ │
21 (C): │ ││ │
22 (C): │ ││ │
23 (C): │ ││ │
24 (C): │ ││ │
25 (C): │ ││ │
26 (C): │ ││ │
27 (C): │ ││ │
28 (C): │ ││ │
29 (C): │ ││ │
30 (C): │ ││ │
31 (C): │ ││ │
32 (C): │ ││ │
33 (C): │ ││ │
34 (C): │ ││ │
35 (C): │ ││ │
36 (C): │ ││ │
37 (C): │ ││ │
38 (C): │ ││ │
39 (C): └──────────────────────────────────────┘└──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘

View file

@ -0,0 +1,46 @@
---
source: zellij-server/src/tab/./unit/tab_integration_tests.rs
assertion_line: 816
expression: snapshot
---
00 (C): ┌ Pane #1 ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
01 (C): ┌ Pane #2 ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
02 (C): ┌ Pane #3 ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
03 (C): ┌ Pane #4 ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
04 (C): │ │
05 (C): │ │
06 (C): │ │
07 (C): │ │
08 (C): │ │
09 (C): │ │
10 (C): │ │
11 (C): │ │
12 (C): │ │
13 (C): │ │
14 (C): │ │
15 (C): │ │
16 (C): │ │
17 (C): │ │
18 (C): │ │
19 (C): │ │
20 (C): │ │
21 (C): │ │
22 (C): │ │
23 (C): │ │
24 (C): │ │
25 (C): │ │
26 (C): │ │
27 (C): │ │
28 (C): │ │
29 (C): │ │
30 (C): │ │
31 (C): │ │
32 (C): │ │
33 (C): │ │
34 (C): │ │
35 (C): │ │
36 (C): │ │
37 (C): │ │
38 (C): │ │
39 (C): └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘

View file

@ -0,0 +1,46 @@
---
source: zellij-server/src/tab/./unit/tab_integration_tests.rs
assertion_line: 816
expression: snapshot
---
00 (C): ┌ Pane #4 ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
01 (C): │ │
02 (C): │ │
03 (C): │ │
04 (C): │ │
05 (C): │ │
06 (C): │ │
07 (C): │ │
08 (C): │ │
09 (C): │ │
10 (C): │ │
11 (C): │ │
12 (C): │ │
13 (C): │ │
14 (C): │ │
15 (C): │ │
16 (C): │ │
17 (C): │ │
18 (C): │ │
19 (C): │ │
20 (C): │ │
21 (C): │ │
22 (C): │ │
23 (C): │ │
24 (C): │ │
25 (C): │ │
26 (C): │ │
27 (C): │ │
28 (C): │ │
29 (C): │ │
30 (C): │ │
31 (C): │ │
32 (C): │ │
33 (C): │ │
34 (C): │ │
35 (C): │ │
36 (C): │ │
37 (C): │ │
38 (C): │ │
39 (C): └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘

View file

@ -0,0 +1,46 @@
---
source: zellij-server/src/tab/./unit/tab_integration_tests.rs
assertion_line: 816
expression: snapshot
---
00 (C): ┌ Pane #4 ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
01 (C): │ │
02 (C): │ │
03 (C): │ │
04 (C): │ │
05 (C): │ │
06 (C): │ │
07 (C): │ │
08 (C): │ │
09 (C): │ │
10 (C): │ │
11 (C): │ │
12 (C): │ │
13 (C): │ │
14 (C): │ │
15 (C): │ │
16 (C): │ │
17 (C): │ │
18 (C): │ │
19 (C): │ │
20 (C): │ │
21 (C): │ │
22 (C): │ │
23 (C): │ │
24 (C): │ │
25 (C): │ │
26 (C): │ │
27 (C): │ │
28 (C): │ │
29 (C): │ │
30 (C): │ │
31 (C): │ │
32 (C): │ │
33 (C): │ │
34 (C): │ │
35 (C): │ │
36 (C): │ │
37 (C): │ │
38 (C): │ │
39 (C): └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘

View file

@ -0,0 +1,46 @@
---
source: zellij-server/src/tab/./unit/tab_integration_tests.rs
assertion_line: 830
expression: snapshot
---
00 (C): ┌ Pane #1 ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
01 (C): ┌ Pane #2 ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
02 (C): ┌ Pane #3 ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
03 (C): ┌ Pane #4 ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
04 (C): │ │
05 (C): │ │
06 (C): │ │
07 (C): │ │
08 (C): │ │
09 (C): │ │
10 (C): │ │
11 (C): │ │
12 (C): │ │
13 (C): │ │
14 (C): │ │
15 (C): │ │
16 (C): │ │
17 (C): │ │
18 (C): │ │
19 (C): │ │
20 (C): │ │
21 (C): │ │
22 (C): │ │
23 (C): │ │
24 (C): │ │
25 (C): │ │
26 (C): │ │
27 (C): │ │
28 (C): │ │
29 (C): │ │
30 (C): │ │
31 (C): │ │
32 (C): │ │
33 (C): │ │
34 (C): │ │
35 (C): │ │
36 (C): │ │
37 (C): │ │
38 (C): │ │
39 (C): └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘

View file

@ -0,0 +1,46 @@
---
source: zellij-server/src/tab/./unit/tab_integration_tests.rs
assertion_line: 830
expression: snapshot
---
00 (C): ┌ Pane #1 ─────────────────────────────┐┌ Pane #2 ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
01 (C): │ │┌ Pane #3 ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
02 (C): │ │┌ Pane #4 ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
03 (C): │ ││ │
04 (C): │ ││ │
05 (C): │ ││ │
06 (C): │ ││ │
07 (C): │ ││ │
08 (C): │ ││ │
09 (C): │ ││ │
10 (C): │ ││ │
11 (C): │ ││ │
12 (C): │ ││ │
13 (C): │ ││ │
14 (C): │ ││ │
15 (C): │ ││ │
16 (C): │ ││ │
17 (C): │ ││ │
18 (C): │ ││ │
19 (C): │ ││ │
20 (C): │ ││ │
21 (C): │ ││ │
22 (C): │ ││ │
23 (C): │ ││ │
24 (C): │ ││ │
25 (C): │ ││ │
26 (C): │ ││ │
27 (C): │ ││ │
28 (C): │ ││ │
29 (C): │ ││ │
30 (C): │ ││ │
31 (C): │ ││ │
32 (C): │ ││ │
33 (C): │ ││ │
34 (C): │ ││ │
35 (C): │ ││ │
36 (C): │ ││ │
37 (C): │ ││ │
38 (C): │ ││ │
39 (C): └──────────────────────────────────────┘└──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘

View file

@ -0,0 +1,46 @@
---
source: zellij-server/src/tab/./unit/tab_integration_tests.rs
assertion_line: 815
expression: snapshot
---
00 (C): ┌ Pane #1 ─────────────────────────────────────────────────────────────────────────────────────────┐┌ Pane #2 ─────────────────────────────────────────────────────────────────────────────────────────┐
01 (C): │ ││ │
02 (C): │ ││ │
03 (C): │ ││ │
04 (C): │ ││ │
05 (C): │ ││ │
06 (C): │ ││ │
07 (C): │ ││ │
08 (C): │ ││ │
09 (C): │ ││ │
10 (C): │ ││ │
11 (C): │ ││ │
12 (C): │ ││ │
13 (C): │ ││ │
14 (C): │ ││ │
15 (C): │ ││ │
16 (C): │ ││ │
17 (C): │ ││ │
18 (C): │ ││ │
19 (C): │ │└──────────────────────────────────────────────────────────────────────────────────────────────────┘
20 (C): │ │┌ Pane #3 ─────────────────────────────────────────────────────────────────────────────────────────┐
21 (C): │ │┌ Pane #4 ─────────────────────────────────────────────────────────────────────────────────────────┐
22 (C): │ ││ │
23 (C): │ ││ │
24 (C): │ ││ │
25 (C): │ ││ │
26 (C): │ ││ │
27 (C): │ ││ │
28 (C): │ ││ │
29 (C): │ ││ │
30 (C): │ ││ │
31 (C): │ ││ │
32 (C): │ ││ │
33 (C): │ ││ │
34 (C): │ ││ │
35 (C): │ ││ │
36 (C): │ ││ │
37 (C): │ ││ │
38 (C): │ ││ │
39 (C): └──────────────────────────────────────────────────────────────────────────────────────────────────┘└──────────────────────────────────────────────────────────────────────────────────────────────────┘

View file

@ -0,0 +1,46 @@
---
source: zellij-server/src/tab/./unit/tab_integration_tests.rs
assertion_line: 875
expression: snapshot
---
00 (C): ┌ Pane #1 ─────────────────────────────────────────────────────────────────────────────────────────┐┌ Pane #2 ─────────────────────────────────────────────────────────────────────────────────────────┐
01 (C): │ │┌ Pane #4 ─────────────────────────────────────────────────────────────────────────────────────────┐
02 (C): │ │┌ Pane #5 ─────────────────────────────────────────────────────────────────────────────────────────┐
03 (C): │ │┌ Pane #3 ─────────────────────────────────────────────────────────────────────────────────────────┐
04 (C): │ ││ │
05 (C): │ ││ │
06 (C): │ ││ │
07 (C): │ ││ │
08 (C): │ ││ │
09 (C): │ ││ │
10 (C): │ ││ │
11 (C): │ ││ │
12 (C): │ ││ │
13 (C): │ ││ │
14 (C): │ ││ │
15 (C): │ ││ │
16 (C): │ ││ │
17 (C): │ ││ │
18 (C): │ ││ │
19 (C): │ ││ │
20 (C): │ ││ │
21 (C): │ ││ │
22 (C): │ ││ │
23 (C): │ ││ │
24 (C): │ ││ │
25 (C): │ ││ │
26 (C): │ ││ │
27 (C): │ ││ │
28 (C): │ ││ │
29 (C): │ ││ │
30 (C): │ ││ │
31 (C): │ ││ │
32 (C): │ ││ │
33 (C): │ ││ │
34 (C): │ ││ │
35 (C): │ ││ │
36 (C): │ ││ │
37 (C): │ ││ │
38 (C): │ ││ │
39 (C): └──────────────────────────────────────────────────────────────────────────────────────────────────┘└──────────────────────────────────────────────────────────────────────────────────────────────────┘

View file

@ -0,0 +1,46 @@
---
source: zellij-server/src/tab/./unit/tab_integration_tests.rs
assertion_line: 889
expression: snapshot
---
00 (C): ┌ Pane #1 ─────────────────────────────────────────────────────────────────────────────────────────┐┌ Pane #2 ───────────────────────────────────────┐┌ Pane #4 ───────────────────────────────────────┐
01 (C): │ ││ ││ │
02 (C): │ ││ ││ │
03 (C): │ ││ ││ │
04 (C): │ ││ ││ │
05 (C): │ ││ ││ │
06 (C): │ ││ ││ │
07 (C): │ ││ ││ │
08 (C): │ ││ ││ │
09 (C): │ │└────────────────────────────────────────────────┘└────────────────────────────────────────────────┘
10 (C): │ │┌ Pane #5 ─────────────────────────────────────────────────────────────────────────────────────────┐
11 (C): │ │┌ Pane #3 ─────────────────────────────────────────────────────────────────────────────────────────┐
12 (C): │ ││ │
13 (C): │ ││ │
14 (C): │ ││ │
15 (C): │ ││ │
16 (C): │ ││ │
17 (C): │ ││ │
18 (C): │ ││ │
19 (C): │ ││ │
20 (C): │ ││ │
21 (C): │ ││ │
22 (C): │ ││ │
23 (C): │ ││ │
24 (C): │ ││ │
25 (C): │ ││ │
26 (C): │ ││ │
27 (C): │ ││ │
28 (C): │ ││ │
29 (C): │ ││ │
30 (C): │ ││ │
31 (C): │ ││ │
32 (C): │ ││ │
33 (C): │ ││ │
34 (C): │ ││ │
35 (C): │ ││ │
36 (C): │ ││ │
37 (C): │ ││ │
38 (C): │ ││ │
39 (C): └──────────────────────────────────────────────────────────────────────────────────────────────────┘└──────────────────────────────────────────────────────────────────────────────────────────────────┘

View file

@ -0,0 +1,46 @@
---
source: zellij-server/src/tab/./unit/tab_integration_tests.rs
assertion_line: 889
expression: snapshot
---
00 (C): ┌ Pane #1 ─────────────────────────────────────────────────────────────────────────────────────────┐┌ Pane #2 ───────────────────────────────────────┐┌ Pane #4 ───────────────────────────────────────┐
01 (C): │ ││ ││ │
02 (C): │ ││ ││ │
03 (C): │ ││ ││ │
04 (C): │ ││ ││ │
05 (C): │ ││ ││ │
06 (C): │ ││ ││ │
07 (C): │ ││ ││ │
08 (C): │ ││ ││ │
09 (C): │ ││ │└────────────────────────────────────────────────┘
10 (C): │ ││ │┌ Pane #5 ───────────────────────────────────────┐
11 (C): │ ││ ││ │
12 (C): │ ││ ││ │
13 (C): │ ││ ││ │
14 (C): │ ││ ││ │
15 (C): │ ││ ││ │
16 (C): │ ││ ││ │
17 (C): │ ││ ││ │
18 (C): │ ││ ││ │
19 (C): │ │└────────────────────────────────────────────────┘└────────────────────────────────────────────────┘
20 (C): │ │┌ Pane #3 ─────────────────────────────────────────────────────────────────────────────────────────┐
21 (C): │ ││ │
22 (C): │ ││ │
23 (C): │ ││ │
24 (C): │ ││ │
25 (C): │ ││ │
26 (C): │ ││ │
27 (C): │ ││ │
28 (C): │ ││ │
29 (C): │ ││ │
30 (C): │ ││ │
31 (C): │ ││ │
32 (C): │ ││ │
33 (C): │ ││ │
34 (C): │ ││ │
35 (C): │ ││ │
36 (C): │ ││ │
37 (C): │ ││ │
38 (C): │ ││ │
39 (C): └──────────────────────────────────────────────────────────────────────────────────────────────────┘└──────────────────────────────────────────────────────────────────────────────────────────────────┘

View file

@ -0,0 +1,46 @@
---
source: zellij-server/src/tab/./unit/tab_integration_tests.rs
assertion_line: 875
expression: snapshot
---
00 (C): ┌ Pane #1 ─────────────────────────────────────────────────────────────────────────────────────────┐┌ Pane #2 ───────────────────────────────────────┐┌ Pane #4 ───────────────────────────────────────┐
01 (C): │ ││ ││ │
02 (C): │ ││ ││ │
03 (C): │ ││ ││ │
04 (C): │ ││ ││ │
05 (C): │ ││ ││ │
06 (C): │ ││ ││ │
07 (C): │ ││ ││ │
08 (C): │ ││ ││ │
09 (C): │ │└────────────────────────────────────────────────┘└────────────────────────────────────────────────┘
10 (C): │ │┌ Pane #5 ─────────────────────────────────────────────────────────────────────────────────────────┐
11 (C): │ │┌ Pane #3 ─────────────────────────────────────────────────────────────────────────────────────────┐
12 (C): │ ││ │
13 (C): │ ││ │
14 (C): │ ││ │
15 (C): │ ││ │
16 (C): │ ││ │
17 (C): │ ││ │
18 (C): │ ││ │
19 (C): │ ││ │
20 (C): │ ││ │
21 (C): │ ││ │
22 (C): │ ││ │
23 (C): │ ││ │
24 (C): │ ││ │
25 (C): │ ││ │
26 (C): │ ││ │
27 (C): │ ││ │
28 (C): │ ││ │
29 (C): │ ││ │
30 (C): │ ││ │
31 (C): │ ││ │
32 (C): │ ││ │
33 (C): │ ││ │
34 (C): │ ││ │
35 (C): │ ││ │
36 (C): │ ││ │
37 (C): │ ││ │
38 (C): │ ││ │
39 (C): └──────────────────────────────────────────────────────────────────────────────────────────────────┘└──────────────────────────────────────────────────────────────────────────────────────────────────┘

View file

@ -0,0 +1,46 @@
---
source: zellij-server/src/tab/./unit/tab_integration_tests.rs
assertion_line: 7598
expression: snapshot
---
00 (C): ┌ Pane #1 ─────────────────────────────────────────────────────────────────────────────────────────┐┌ Pane #2 ─────────────────────────────────────────────────────────────────────────────────────────┐
01 (C): │ ││ │
02 (C): │ ││ │
03 (C): │ ││ │
04 (C): │ ││ │
05 (C): │ ││ │
06 (C): │ ││ │
07 (C): │ ││ │
08 (C): │ ││ │
09 (C): │ ││ │
10 (C): │ ││ │
11 (C): │ ││ │
12 (C): │ ││ │
13 (C): │ ││ │
14 (C): │ ││ │
15 (C): │ ││ │
16 (C): │ ││ │
17 (C): │ ││ │
18 (C): │ ││ │
19 (C): │ │└──────────────────────────────────────────────────────────────────────────────────────────────────┘
20 (C): │ │┌ Pane #3 ─────────────────────────────────────────────────────────────────────────────────────────┐
21 (C): │ ││ │
22 (C): │ ││ │
23 (C): │ ││ │
24 (C): │ ││ │
25 (C): │ ││ │
26 (C): │ ││ │
27 (C): │ ││ │
28 (C): │ ││ │
29 (C): │ ││ │
30 (C): │ ││ │
31 (C): │ ││ │
32 (C): │ ││ │
33 (C): │ ││ │
34 (C): │ ││ │
35 (C): │ ││ │
36 (C): │ ││ │
37 (C): │ ││ │
38 (C): │ ││ │
39 (C): └──────────────────────────────────────────────────────────────────────────────────────────────────┘└──────────────────────────────────────────────────────────────────────────────────────────────────┘

View file

@ -0,0 +1,46 @@
---
source: zellij-server/src/tab/./unit/tab_integration_tests.rs
assertion_line: 7598
expression: snapshot
---
00 (C): ┌ Pane #1 ─────────────────────────────────────────────────────────────────────────────────────────┐┌ Pane #2 ─────────────────────────────────────────────────────────────────────────────────────────┐
01 (C): │ ││ │
02 (C): │ ││ │
03 (C): │ ││ │
04 (C): │ ││ │
05 (C): │ ││ │
06 (C): │ ││ │
07 (C): │ ││ │
08 (C): │ ││ │
09 (C): │ ││ │
10 (C): │ ││ │
11 (C): │ ││ │
12 (C): │ ││ │
13 (C): │ ││ │
14 (C): │ ││ │
15 (C): │ ││ │
16 (C): │ ││ │
17 (C): │ ││ │
18 (C): │ ││ │
19 (C): │ │└──────────────────────────────────────────────────────────────────────────────────────────────────┘
20 (C): │ │┌ Pane #3 ───────────────────────────────────────┐┌ Pane #4 ───────────────────────────────────────┐
21 (C): │ ││ ││ │
22 (C): │ ││ ││ │
23 (C): │ ││ ││ │
24 (C): │ ││ ││ │
25 (C): │ ││ ││ │
26 (C): │ ││ ││ │
27 (C): │ ││ ││ │
28 (C): │ ││ ││ │
29 (C): │ ││ ││ │
30 (C): │ ││ ││ │
31 (C): │ ││ ││ │
32 (C): │ ││ ││ │
33 (C): │ ││ ││ │
34 (C): │ ││ ││ │
35 (C): │ ││ ││ │
36 (C): │ ││ ││ │
37 (C): │ ││ ││ │
38 (C): │ ││ ││ │
39 (C): └──────────────────────────────────────────────────────────────────────────────────────────────────┘└────────────────────────────────────────────────┘└────────────────────────────────────────────────┘

View file

@ -0,0 +1,46 @@
---
source: zellij-server/src/tab/./unit/tab_integration_tests.rs
assertion_line: 7598
expression: snapshot
---
00 (C): ┌ Pane #1 ─────────────────────────────────────────────────────────────────────────────────────────┐┌ Pane #2 ─────────────────────────────────────────────────────────────────────────────────────────┐
01 (C): │ ││ │
02 (C): │ ││ │
03 (C): │ ││ │
04 (C): │ ││ │
05 (C): │ ││ │
06 (C): │ ││ │
07 (C): │ ││ │
08 (C): │ ││ │
09 (C): │ ││ │
10 (C): │ ││ │
11 (C): │ ││ │
12 (C): │ ││ │
13 (C): │ ││ │
14 (C): │ ││ │
15 (C): │ ││ │
16 (C): │ ││ │
17 (C): │ ││ │
18 (C): │ ││ │
19 (C): │ │└──────────────────────────────────────────────────────────────────────────────────────────────────┘
20 (C): │ │┌ Pane #3 ───────────────────────────────────────┐┌ Pane #4 ───────────────────────────────────────┐
21 (C): │ ││ │┌ Pane #5 ───────────────────────────────────────┐
22 (C): │ ││ ││ │
23 (C): │ ││ ││ │
24 (C): │ ││ ││ │
25 (C): │ ││ ││ │
26 (C): │ ││ ││ │
27 (C): │ ││ ││ │
28 (C): │ ││ ││ │
29 (C): │ ││ ││ │
30 (C): │ ││ ││ │
31 (C): │ ││ ││ │
32 (C): │ ││ ││ │
33 (C): │ ││ ││ │
34 (C): │ ││ ││ │
35 (C): │ ││ ││ │
36 (C): │ ││ ││ │
37 (C): │ ││ ││ │
38 (C): │ ││ ││ │
39 (C): └──────────────────────────────────────────────────────────────────────────────────────────────────┘└────────────────────────────────────────────────┘└────────────────────────────────────────────────┘

View file

@ -0,0 +1,46 @@
---
source: zellij-server/src/tab/./unit/tab_integration_tests.rs
assertion_line: 7598
expression: snapshot
---
00 (C): ┌ Pane #1 ─────────────────────────────────────────────────────────────────────────────────────────┐┌ Pane #2 ─────────────────────────────────────────────────────────────────────────────────────────┐
01 (C): │ ││ │
02 (C): │ ││ │
03 (C): │ ││ │
04 (C): │ ││ │
05 (C): │ ││ │
06 (C): │ ││ │
07 (C): │ ││ │
08 (C): │ ││ │
09 (C): │ ││ │
10 (C): │ ││ │
11 (C): │ ││ │
12 (C): │ ││ │
13 (C): │ ││ │
14 (C): │ ││ │
15 (C): │ ││ │
16 (C): │ ││ │
17 (C): │ ││ │
18 (C): │ ││ │
19 (C): │ ││ │
20 (C): │ ││ │
21 (C): │ ││ │
22 (C): │ ││ │
23 (C): │ ││ │
24 (C): │ ││ │
25 (C): │ ││ │
26 (C): │ ││ │
27 (C): │ ││ │
28 (C): │ ││ │
29 (C): │ ││ │
30 (C): │ ││ │
31 (C): │ ││ │
32 (C): │ ││ │
33 (C): │ ││ │
34 (C): │ ││ │
35 (C): │ ││ │
36 (C): │ ││ │
37 (C): │ ││ │
38 (C): │ ││ │
39 (C): └──────────────────────────────────────────────────────────────────────────────────────────────────┘└──────────────────────────────────────────────────────────────────────────────────────────────────┘

View file

@ -0,0 +1,46 @@
---
source: zellij-server/src/tab/./unit/tab_integration_tests.rs
assertion_line: 970
expression: snapshot
---
00 (C): ┌ Pane #1 ─────────────────────────────────────────────────────────────────────────────────────────┐┌ Pane #2 ─────────────────────────────────────────────────────────────────────────────────────────┐
01 (C): │ │┌ Pane #3 ─────────────────────────────────────────────────────────────────────────────────────────┐
02 (C): │ ││ │
03 (C): │ ││ │
04 (C): │ ││ │
05 (C): │ ││ │
06 (C): │ ││ │
07 (C): │ ││ │
08 (C): │ ││ │
09 (C): │ ││ │
10 (C): │ ││ │
11 (C): │ ││ │
12 (C): │ ││ │
13 (C): │ ││ │
14 (C): │ ││ │
15 (C): │ ││ │
16 (C): │ ││ │
17 (C): │ ││ │
18 (C): │ ││ │
19 (C): │ │└──────────────────────────────────────────────────────────────────────────────────────────────────┘
20 (C): │ │┌ Pane #4 ─────────────────────────────────────────────────────────────────────────────────────────┐
21 (C): │ ││ │
22 (C): │ ││ │
23 (C): │ ││ │
24 (C): │ ││ │
25 (C): │ ││ │
26 (C): │ ││ │
27 (C): │ ││ │
28 (C): │ ││ │
29 (C): │ ││ │
30 (C): │ ││ │
31 (C): │ ││ │
32 (C): │ ││ │
33 (C): │ ││ │
34 (C): │ ││ │
35 (C): │ ││ │
36 (C): │ ││ │
37 (C): │ ││ │
38 (C): │ ││ │
39 (C): └──────────────────────────────────────────────────────────────────────────────────────────────────┘└──────────────────────────────────────────────────────────────────────────────────────────────────┘

View file

@ -0,0 +1,46 @@
---
source: zellij-server/src/tab/./unit/tab_integration_tests.rs
assertion_line: 931
expression: snapshot
---
00 (C): ┌ Pane #1 ─────────────────────────────────────────────────────────────────────────────────────────┐┌ Pane #2 ───────────────────────────────────────┐┌ Pane #4 ───────────────────────────────────────┐
01 (C): │ │┌ Pane #3 ───────────────────────────────────────┐│ │
02 (C): │ ││ ││ │
03 (C): │ ││ ││ │
04 (C): │ ││ ││ │
05 (C): │ ││ ││ │
06 (C): │ ││ ││ │
07 (C): │ ││ ││ │
08 (C): │ ││ ││ │
09 (C): │ ││ ││ │
10 (C): │ ││ ││ │
11 (C): │ ││ ││ │
12 (C): │ ││ ││ │
13 (C): │ ││ ││ │
14 (C): │ ││ ││ │
15 (C): │ ││ ││ │
16 (C): │ ││ ││ │
17 (C): │ ││ ││ │
18 (C): │ ││ ││ │
19 (C): │ ││ ││ │
20 (C): │ ││ ││ │
21 (C): │ ││ ││ │
22 (C): │ ││ ││ │
23 (C): │ ││ ││ │
24 (C): │ ││ ││ │
25 (C): │ ││ ││ │
26 (C): │ ││ ││ │
27 (C): │ ││ ││ │
28 (C): │ ││ ││ │
29 (C): │ ││ ││ │
30 (C): │ ││ ││ │
31 (C): │ ││ ││ │
32 (C): │ ││ ││ │
33 (C): │ ││ ││ │
34 (C): │ ││ ││ │
35 (C): │ ││ ││ │
36 (C): │ ││ ││ │
37 (C): │ ││ ││ │
38 (C): │ ││ ││ │
39 (C): └──────────────────────────────────────────────────────────────────────────────────────────────────┘└────────────────────────────────────────────────┘└────────────────────────────────────────────────┘

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -445,7 +445,7 @@ impl Boundaries {
} }
} }
pub fn add_rect(&mut self, rect: &dyn Pane, color: Option<PaletteColor>) { pub fn add_rect(&mut self, rect: &dyn Pane, color: Option<PaletteColor>) {
let pane_is_stacked = rect.current_geom().is_stacked; let pane_is_stacked = rect.current_geom().is_stacked();
if !self.is_fully_inside_screen(rect) { if !self.is_fully_inside_screen(rect) {
return; return;
} }
@ -576,7 +576,7 @@ impl Boundaries {
rect.y() + rect.rows() < self.viewport.y + self.viewport.rows rect.y() + rect.rows() < self.viewport.y + self.viewport.rows
} }
fn rect_right_boundary_row_start(&self, rect: &dyn Pane) -> usize { fn rect_right_boundary_row_start(&self, rect: &dyn Pane) -> usize {
let pane_is_stacked = rect.current_geom().is_stacked; let pane_is_stacked = rect.current_geom().is_stacked();
let horizontal_frame_offset = if pane_is_stacked { 0 } else { 1 }; let horizontal_frame_offset = if pane_is_stacked { 0 } else { 1 };
if rect.y() > self.viewport.y { if rect.y() > self.viewport.y {
rect.y() - horizontal_frame_offset rect.y() - horizontal_frame_offset

View file

@ -271,6 +271,7 @@ fn create_new_screen(size: Size) -> Screen {
let styled_underlines = true; let styled_underlines = true;
let arrow_fonts = true; let arrow_fonts = true;
let explicitly_disable_kitty_keyboard_protocol = false; let explicitly_disable_kitty_keyboard_protocol = false;
let stacked_resize = true;
let screen = Screen::new( let screen = Screen::new(
bus, bus,
&client_attributes, &client_attributes,
@ -291,6 +292,7 @@ fn create_new_screen(size: Size) -> Screen {
arrow_fonts, arrow_fonts,
layout_dir, layout_dir,
explicitly_disable_kitty_keyboard_protocol, explicitly_disable_kitty_keyboard_protocol,
stacked_resize,
); );
screen screen
} }

View file

@ -408,3 +408,8 @@ load_plugins {
// Default: true (if the host terminal supports it) // Default: true (if the host terminal supports it)
// //
// support_kitty_keyboard_protocol false // support_kitty_keyboard_protocol false
// Whether to stack panes when resizing beyond a certain size
// Default: true
//
// stacked_resize false

View file

@ -914,9 +914,15 @@ impl TiledPaneLayout {
layout_to_split.focus_deepest_pane(); layout_to_split.focus_deepest_pane();
} }
split_space(space, &layout_to_split, space, ignore_percent_split_sizes)? split_space(
space,
&layout_to_split,
space,
ignore_percent_split_sizes,
0,
)?
}, },
None => split_space(space, self, space, ignore_percent_split_sizes)?, None => split_space(space, self, space, ignore_percent_split_sizes, 0)?,
}; };
for (_pane_layout, pane_geom) in layouts.iter() { for (_pane_layout, pane_geom) in layouts.iter() {
if !pane_geom.is_at_least_minimum_size() { if !pane_geom.is_at_least_minimum_size() {
@ -1611,6 +1617,7 @@ fn split_space(
layout: &TiledPaneLayout, layout: &TiledPaneLayout,
total_space_to_split: &PaneGeom, total_space_to_split: &PaneGeom,
ignore_percent_split_sizes: bool, ignore_percent_split_sizes: bool,
mut next_stack_id: usize,
) -> Result<Vec<(TiledPaneLayout, PaneGeom)>, &'static str> { ) -> Result<Vec<(TiledPaneLayout, PaneGeom)>, &'static str> {
let sizes: Vec<Option<SplitSize>> = if layout.children_are_stacked { let sizes: Vec<Option<SplitSize>> = if layout.children_are_stacked {
let index_of_expanded_pane = layout.children.iter().position(|p| p.is_expanded_in_stack); let index_of_expanded_pane = layout.children.iter().position(|p| p.is_expanded_in_stack);
@ -1675,6 +1682,13 @@ fn split_space(
acc acc
} }
}); });
let stacked = if layout.children_are_stacked {
let stack_id = next_stack_id;
next_stack_id += 1;
Some(stack_id)
} else {
None
};
let mut total_pane_size = 0; let mut total_pane_size = 0;
for (&size, _part) in sizes.iter().zip(&*layout.children) { for (&size, _part) in sizes.iter().zip(&*layout.children) {
@ -1710,7 +1724,7 @@ fn split_space(
y: space_to_split.y, y: space_to_split.y,
cols: split_dimension, cols: split_dimension,
rows: inherited_dimension, rows: inherited_dimension,
is_stacked: layout.children_are_stacked, stacked,
is_pinned: false, is_pinned: false,
logical_position: None, logical_position: None,
}, },
@ -1719,7 +1733,7 @@ fn split_space(
y: current_position, y: current_position,
cols: inherited_dimension, cols: inherited_dimension,
rows: split_dimension, rows: split_dimension,
is_stacked: layout.children_are_stacked, stacked,
is_pinned: false, is_pinned: false,
logical_position: None, logical_position: None,
}, },
@ -1743,6 +1757,7 @@ fn split_space(
part, part,
total_space_to_split, total_space_to_split,
ignore_percent_split_sizes, ignore_percent_split_sizes,
next_stack_id,
)?; )?;
// add the only first child to pane_positions only adding the others after all the // add the only first child to pane_positions only adding the others after all the
// childfree panes have been added so that the returned vec will be sorted breadth-first // childfree panes have been added so that the returned vec will be sorted breadth-first

View file

@ -161,6 +161,12 @@ pub struct Options {
#[clap(long, value_parser)] #[clap(long, value_parser)]
#[serde(default)] #[serde(default)]
pub support_kitty_keyboard_protocol: Option<bool>, pub support_kitty_keyboard_protocol: Option<bool>,
/// Whether to stack panes when resizing beyond a certain size
/// default is true
#[clap(long, value_parser)]
#[serde(default)]
pub stacked_resize: Option<bool>,
} }
#[derive(ArgEnum, Deserialize, Serialize, Debug, Clone, Copy, PartialEq)] #[derive(ArgEnum, Deserialize, Serialize, Debug, Clone, Copy, PartialEq)]
@ -239,6 +245,7 @@ impl Options {
let support_kitty_keyboard_protocol = other let support_kitty_keyboard_protocol = other
.support_kitty_keyboard_protocol .support_kitty_keyboard_protocol
.or(self.support_kitty_keyboard_protocol); .or(self.support_kitty_keyboard_protocol);
let stacked_resize = other.stacked_resize.or(self.stacked_resize);
Options { Options {
simplified_ui, simplified_ui,
@ -268,6 +275,7 @@ impl Options {
serialization_interval, serialization_interval,
disable_session_metadata, disable_session_metadata,
support_kitty_keyboard_protocol, support_kitty_keyboard_protocol,
stacked_resize,
} }
} }
@ -326,6 +334,7 @@ impl Options {
let support_kitty_keyboard_protocol = other let support_kitty_keyboard_protocol = other
.support_kitty_keyboard_protocol .support_kitty_keyboard_protocol
.or(self.support_kitty_keyboard_protocol); .or(self.support_kitty_keyboard_protocol);
let stacked_resize = other.stacked_resize.or(self.stacked_resize);
Options { Options {
simplified_ui, simplified_ui,
@ -355,6 +364,7 @@ impl Options {
serialization_interval, serialization_interval,
disable_session_metadata, disable_session_metadata,
support_kitty_keyboard_protocol, support_kitty_keyboard_protocol,
stacked_resize,
} }
} }
@ -420,6 +430,7 @@ impl From<CliOptions> for Options {
styled_underlines: opts.styled_underlines, styled_underlines: opts.styled_underlines,
serialization_interval: opts.serialization_interval, serialization_interval: opts.serialization_interval,
support_kitty_keyboard_protocol: opts.support_kitty_keyboard_protocol, support_kitty_keyboard_protocol: opts.support_kitty_keyboard_protocol,
stacked_resize: opts.stacked_resize,
..Default::default() ..Default::default()
} }
} }

View file

@ -2241,6 +2241,8 @@ impl Options {
"support_kitty_keyboard_protocol" "support_kitty_keyboard_protocol"
) )
.map(|(v, _)| v); .map(|(v, _)| v);
let stacked_resize =
kdl_property_first_arg_as_bool_or_error!(kdl_options, "stacked_resize").map(|(v, _)| v);
Ok(Options { Ok(Options {
simplified_ui, simplified_ui,
theme, theme,
@ -2269,6 +2271,7 @@ impl Options {
serialization_interval, serialization_interval,
disable_session_metadata, disable_session_metadata,
support_kitty_keyboard_protocol, support_kitty_keyboard_protocol,
stacked_resize,
}) })
} }
pub fn from_string(stringified_keybindings: &String) -> Result<Self, ConfigError> { pub fn from_string(stringified_keybindings: &String) -> Result<Self, ConfigError> {
@ -3068,6 +3071,34 @@ impl Options {
None None
} }
} }
fn stacked_resize_to_kdl(&self, add_comments: bool) -> Option<KdlNode> {
let comment_text = format!(
"{}\n{}\n{}\n{}",
" ",
"// Whether to stack panes when resizing beyond a certain size",
"// Default: true",
"// ",
);
let create_node = |node_value: bool| -> KdlNode {
let mut node = KdlNode::new("stacked_resize");
node.push(KdlValue::Bool(node_value));
node
};
if let Some(stacked_resize) = self.stacked_resize {
let mut node = create_node(stacked_resize);
if add_comments {
node.set_leading(format!("{}\n", comment_text));
}
Some(node)
} else if add_comments {
let mut node = create_node(false);
node.set_leading(format!("{}\n// ", comment_text));
Some(node)
} else {
None
}
}
pub fn to_kdl(&self, add_comments: bool) -> Vec<KdlNode> { pub fn to_kdl(&self, add_comments: bool) -> Vec<KdlNode> {
let mut nodes = vec![]; let mut nodes = vec![];
if let Some(simplified_ui_node) = self.simplified_ui_to_kdl(add_comments) { if let Some(simplified_ui_node) = self.simplified_ui_to_kdl(add_comments) {
@ -3155,6 +3186,9 @@ impl Options {
{ {
nodes.push(support_kitty_keyboard_protocol); nodes.push(support_kitty_keyboard_protocol);
} }
if let Some(stacked_resize) = self.stacked_resize_to_kdl(add_comments) {
nodes.push(stacked_resize);
}
nodes nodes
} }
} }

View file

@ -1,6 +1,6 @@
--- ---
source: zellij-utils/src/kdl/mod.rs source: zellij-utils/src/kdl/mod.rs
assertion_line: 5563 assertion_line: 5598
expression: fake_config_stringified expression: fake_config_stringified
--- ---
keybinds clear-defaults=true { keybinds clear-defaults=true {
@ -433,3 +433,8 @@ load_plugins {
// //
// support_kitty_keyboard_protocol false // support_kitty_keyboard_protocol false
// Whether to stack panes when resizing beyond a certain size
// Default: true
//
// stacked_resize false

View file

@ -1,6 +1,6 @@
--- ---
source: zellij-utils/src/kdl/mod.rs source: zellij-utils/src/kdl/mod.rs
assertion_line: 5380 assertion_line: 5537
expression: fake_document.to_string() expression: fake_document.to_string()
--- ---
@ -181,3 +181,8 @@ disable_session_metadata true
// //
support_kitty_keyboard_protocol false support_kitty_keyboard_protocol false
// Whether to stack panes when resizing beyond a certain size
// Default: true
//
// stacked_resize false

View file

@ -16,7 +16,7 @@ pub struct PaneGeom {
pub y: usize, pub y: usize,
pub rows: Dimension, pub rows: Dimension,
pub cols: Dimension, pub cols: Dimension,
pub is_stacked: bool, pub stacked: Option<usize>, // usize - stack id
pub is_pinned: bool, // only relevant to floating panes pub is_pinned: bool, // only relevant to floating panes
pub logical_position: Option<usize>, // relevant when placing this pane in a layout pub logical_position: Option<usize>, // relevant when placing this pane in a layout
} }
@ -29,7 +29,7 @@ impl PartialEq for PaneGeom {
&& self.y == other.y && self.y == other.y
&& self.rows == other.rows && self.rows == other.rows
&& self.cols == other.cols && self.cols == other.cols
&& self.is_stacked == other.is_stacked && self.stacked == other.stacked
} }
} }
@ -40,7 +40,7 @@ impl std::hash::Hash for PaneGeom {
self.y.hash(state); self.y.hash(state);
self.rows.hash(state); self.rows.hash(state);
self.cols.hash(state); self.cols.hash(state);
self.is_stacked.hash(state); self.stacked.hash(state);
} }
} }
@ -170,6 +170,35 @@ impl Dimension {
}, },
} }
} }
pub fn split_out(&mut self, by: f64) -> Self {
match self.constraint {
Constraint::Percent(percent) => {
let split_out_value = percent / by;
let split_out_inner_value = self.inner / by as usize;
self.constraint = Constraint::Percent(percent - split_out_value);
self.inner = self.inner.saturating_sub(split_out_inner_value);
let mut split_out_dimension = Self::percent(split_out_value);
split_out_dimension.inner = split_out_inner_value;
split_out_dimension
},
Constraint::Fixed(fixed) => {
let split_out_value = fixed / by as usize;
self.constraint = Constraint::Fixed(fixed - split_out_value);
Self::fixed(split_out_value)
},
}
}
pub fn reduce_by(&mut self, by: f64, by_inner: usize) {
match self.constraint {
Constraint::Percent(percent) => {
self.constraint = Constraint::Percent(percent - by);
self.inner = self.inner.saturating_sub(by_inner);
},
Constraint::Fixed(_fixed) => {
log::error!("Cannot reduce_by fixed dimensions");
},
}
}
} }
#[derive(Clone, Copy, PartialEq, Debug, Serialize, Deserialize)] #[derive(Clone, Copy, PartialEq, Debug, Serialize, Deserialize)]
@ -257,6 +286,85 @@ impl PaneGeom {
self.rows.set_inner(new_rows); self.rows.set_inner(new_rows);
} }
} }
pub fn combine_vertically_with(&self, geom_below: &PaneGeom) -> Option<Self> {
match (self.rows.constraint, geom_below.rows.constraint) {
(Constraint::Percent(self_percent), Constraint::Percent(geom_below_percent)) => {
let mut combined = self.clone();
combined.rows = Dimension::percent(self_percent + geom_below_percent);
combined.rows.inner = self.rows.inner + geom_below.rows.inner;
Some(combined)
},
_ => {
log::error!("Can't combine fixed panes");
None
},
}
}
pub fn combine_horizontally_with(&self, geom_to_the_right: &PaneGeom) -> Option<Self> {
match (self.cols.constraint, geom_to_the_right.cols.constraint) {
(Constraint::Percent(self_percent), Constraint::Percent(geom_to_the_right_percent)) => {
let mut combined = self.clone();
combined.cols = Dimension::percent(self_percent + geom_to_the_right_percent);
combined.cols.inner = self.cols.inner + geom_to_the_right.cols.inner;
Some(combined)
},
_ => {
log::error!("Can't combine fixed panes");
None
},
}
}
pub fn combine_vertically_with_many(&self, geoms_below: &Vec<PaneGeom>) -> Option<Self> {
// here we expect the geoms to be sorted by their y and be contiguous (i.e. same x and
// width, no overlaps) and be below self
let mut combined = self.clone();
for geom_below in geoms_below {
match (combined.rows.constraint, geom_below.rows.constraint) {
(
Constraint::Percent(combined_percent),
Constraint::Percent(geom_below_percent),
) => {
let new_rows_inner = combined.rows.inner + geom_below.rows.inner;
combined.rows = Dimension::percent(combined_percent + geom_below_percent);
combined.rows.inner = new_rows_inner;
},
_ => {
log::error!("Can't combine fixed panes");
return None;
},
}
}
Some(combined)
}
pub fn combine_horizontally_with_many(
&self,
geoms_to_the_right: &Vec<PaneGeom>,
) -> Option<Self> {
// here we expect the geoms to be sorted by their x and be contiguous (i.e. same x and
// width, no overlaps) and be right of self
let mut combined = self.clone();
for geom_to_the_right in geoms_to_the_right {
match (combined.cols.constraint, geom_to_the_right.cols.constraint) {
(
Constraint::Percent(combined_percent),
Constraint::Percent(geom_to_the_right_percent),
) => {
let new_cols = combined.cols.inner + geom_to_the_right.cols.inner;
combined.cols =
Dimension::percent(combined_percent + geom_to_the_right_percent);
combined.cols.inner = new_cols;
},
_ => {
log::error!("Can't combine fixed panes");
return None;
},
}
}
Some(combined)
}
pub fn is_stacked(&self) -> bool {
self.stacked.is_some()
}
} }
impl Display for PaneGeom { impl Display for PaneGeom {
@ -266,7 +374,8 @@ impl Display for PaneGeom {
write!(f, r#""y": {},"#, self.y)?; write!(f, r#""y": {},"#, self.y)?;
write!(f, r#""cols": {},"#, self.cols.constraint)?; write!(f, r#""cols": {},"#, self.cols.constraint)?;
write!(f, r#""rows": {},"#, self.rows.constraint)?; write!(f, r#""rows": {},"#, self.rows.constraint)?;
write!(f, r#""stacked": {}"#, self.is_stacked)?; write!(f, r#""stacked": {:?}"#, self.stacked)?;
write!(f, r#""logical_position": {:?}"#, self.logical_position)?;
write!(f, " }}")?; write!(f, " }}")?;
Ok(()) Ok(())

View file

@ -682,7 +682,7 @@ fn tiled_pane_layout_from_manifest(
( (
run, run,
g.is_borderless, g.is_borderless,
g.geom.is_stacked && g.geom.rows.inner > 1, g.geom.is_stacked() && g.geom.rows.inner > 1,
g.title.clone(), g.title.clone(),
Some(g.is_focused), Some(g.is_focused),
g.pane_contents.clone(), g.pane_contents.clone(),
@ -756,7 +756,7 @@ fn get_tiled_panes_layout_from_panegeoms(
let children_are_stacked = children_split_direction == SplitDirection::Horizontal let children_are_stacked = children_split_direction == SplitDirection::Horizontal
&& new_geoms && new_geoms
.iter() .iter()
.all(|c| c.iter().all(|c| c.geom.is_stacked)); .all(|c| c.iter().all(|c| c.geom.is_stacked()));
Some(TiledPaneLayout { Some(TiledPaneLayout {
children_split_direction, children_split_direction,
split_size, split_size,
@ -1284,7 +1284,7 @@ mod tests {
y: 0, y: 0,
rows: Dimension::fixed(10), rows: Dimension::fixed(10),
cols: Dimension::fixed(10), cols: Dimension::fixed(10),
is_stacked: false, stacked: None,
is_pinned: false, is_pinned: false,
logical_position: None, logical_position: None,
}, },
@ -1297,7 +1297,7 @@ mod tests {
y: 10, y: 10,
rows: Dimension::fixed(10), rows: Dimension::fixed(10),
cols: Dimension::fixed(10), cols: Dimension::fixed(10),
is_stacked: false, stacked: None,
is_pinned: false, is_pinned: false,
logical_position: None, logical_position: None,
}, },
@ -1314,7 +1314,7 @@ mod tests {
y: 20, y: 20,
rows: Dimension::fixed(10), rows: Dimension::fixed(10),
cols: Dimension::fixed(10), cols: Dimension::fixed(10),
is_stacked: false, stacked: None,
is_pinned: false, is_pinned: false,
logical_position: None, logical_position: None,
}, },
@ -1330,7 +1330,7 @@ mod tests {
y: 30, y: 30,
rows: Dimension::fixed(10), rows: Dimension::fixed(10),
cols: Dimension::fixed(10), cols: Dimension::fixed(10),
is_stacked: false, stacked: None,
is_pinned: false, is_pinned: false,
logical_position: None, logical_position: None,
}, },
@ -1351,7 +1351,7 @@ mod tests {
y: 40, y: 40,
rows: Dimension::fixed(10), rows: Dimension::fixed(10),
cols: Dimension::fixed(10), cols: Dimension::fixed(10),
is_stacked: false, stacked: None,
is_pinned: false, is_pinned: false,
logical_position: None, logical_position: None,
}, },
@ -1366,7 +1366,7 @@ mod tests {
y: 50, y: 50,
rows: Dimension::fixed(10), rows: Dimension::fixed(10),
cols: Dimension::fixed(10), cols: Dimension::fixed(10),
is_stacked: false, stacked: None,
is_pinned: false, is_pinned: false,
logical_position: None, logical_position: None,
}, },
@ -1383,7 +1383,7 @@ mod tests {
y: 60, y: 60,
rows: Dimension::fixed(10), rows: Dimension::fixed(10),
cols: Dimension::fixed(10), cols: Dimension::fixed(10),
is_stacked: false, stacked: None,
is_pinned: false, is_pinned: false,
logical_position: None, logical_position: None,
}, },
@ -1396,7 +1396,7 @@ mod tests {
y: 70, y: 70,
rows: Dimension::fixed(10), rows: Dimension::fixed(10),
cols: Dimension::fixed(10), cols: Dimension::fixed(10),
is_stacked: false, stacked: None,
is_pinned: false, is_pinned: false,
logical_position: None, logical_position: None,
}, },
@ -1411,7 +1411,7 @@ mod tests {
y: 80, y: 80,
rows: Dimension::fixed(10), rows: Dimension::fixed(10),
cols: Dimension::fixed(10), cols: Dimension::fixed(10),
is_stacked: false, stacked: None,
is_pinned: false, is_pinned: false,
logical_position: None, logical_position: None,
}, },
@ -1442,7 +1442,7 @@ mod tests {
y: 0, y: 0,
rows: Dimension::fixed(10), rows: Dimension::fixed(10),
cols: Dimension::fixed(10), cols: Dimension::fixed(10),
is_stacked: false, stacked: None,
is_pinned: false, is_pinned: false,
logical_position: None, logical_position: None,
}, },
@ -1455,7 +1455,7 @@ mod tests {
y: 10, y: 10,
rows: Dimension::fixed(10), rows: Dimension::fixed(10),
cols: Dimension::fixed(10), cols: Dimension::fixed(10),
is_stacked: false, stacked: None,
is_pinned: false, is_pinned: false,
logical_position: None, logical_position: None,
}, },
@ -1472,7 +1472,7 @@ mod tests {
y: 20, y: 20,
rows: Dimension::fixed(10), rows: Dimension::fixed(10),
cols: Dimension::fixed(10), cols: Dimension::fixed(10),
is_stacked: false, stacked: None,
is_pinned: false, is_pinned: false,
logical_position: None, logical_position: None,
}, },
@ -1488,7 +1488,7 @@ mod tests {
y: 30, y: 30,
rows: Dimension::fixed(10), rows: Dimension::fixed(10),
cols: Dimension::fixed(10), cols: Dimension::fixed(10),
is_stacked: false, stacked: None,
is_pinned: false, is_pinned: false,
logical_position: None, logical_position: None,
}, },
@ -1509,7 +1509,7 @@ mod tests {
y: 40, y: 40,
rows: Dimension::fixed(10), rows: Dimension::fixed(10),
cols: Dimension::fixed(10), cols: Dimension::fixed(10),
is_stacked: false, stacked: None,
is_pinned: false, is_pinned: false,
logical_position: None, logical_position: None,
}, },
@ -1524,7 +1524,7 @@ mod tests {
y: 50, y: 50,
rows: Dimension::fixed(10), rows: Dimension::fixed(10),
cols: Dimension::fixed(10), cols: Dimension::fixed(10),
is_stacked: false, stacked: None,
is_pinned: false, is_pinned: false,
logical_position: None, logical_position: None,
}, },
@ -1541,7 +1541,7 @@ mod tests {
y: 60, y: 60,
rows: Dimension::fixed(10), rows: Dimension::fixed(10),
cols: Dimension::fixed(10), cols: Dimension::fixed(10),
is_stacked: false, stacked: None,
is_pinned: false, is_pinned: false,
logical_position: None, logical_position: None,
}, },
@ -1556,7 +1556,7 @@ mod tests {
y: 70, y: 70,
rows: Dimension::fixed(10), rows: Dimension::fixed(10),
cols: Dimension::fixed(10), cols: Dimension::fixed(10),
is_stacked: false, stacked: None,
is_pinned: false, is_pinned: false,
logical_position: None, logical_position: None,
}, },
@ -1571,7 +1571,7 @@ mod tests {
y: 80, y: 80,
rows: Dimension::fixed(10), rows: Dimension::fixed(10),
cols: Dimension::fixed(10), cols: Dimension::fixed(10),
is_stacked: false, stacked: None,
is_pinned: false, is_pinned: false,
logical_position: None, logical_position: None,
}, },
@ -1600,7 +1600,7 @@ mod tests {
y: 0, y: 0,
rows: Dimension::fixed(1), rows: Dimension::fixed(1),
cols: Dimension::fixed(10), cols: Dimension::fixed(10),
is_stacked: true, stacked: Some(0),
is_pinned: false, is_pinned: false,
logical_position: None, logical_position: None,
}, },
@ -1612,7 +1612,7 @@ mod tests {
y: 1, y: 1,
rows: Dimension::fixed(10), rows: Dimension::fixed(10),
cols: Dimension::fixed(10), cols: Dimension::fixed(10),
is_stacked: true, stacked: Some(0),
is_pinned: false, is_pinned: false,
logical_position: None, logical_position: None,
}, },
@ -1624,7 +1624,7 @@ mod tests {
y: 11, y: 11,
rows: Dimension::fixed(1), rows: Dimension::fixed(1),
cols: Dimension::fixed(10), cols: Dimension::fixed(10),
is_stacked: true, stacked: Some(0),
is_pinned: false, is_pinned: false,
logical_position: None, logical_position: None,
}, },
@ -1649,7 +1649,7 @@ mod tests {
y: 0, y: 0,
rows: Dimension::percent(100.0), rows: Dimension::percent(100.0),
cols: Dimension::percent(100.0), cols: Dimension::percent(100.0),
is_stacked: false, stacked: None,
is_pinned: false, is_pinned: false,
logical_position: None, logical_position: None,
}, },
@ -1665,7 +1665,7 @@ mod tests {
y: 0, y: 0,
rows: Dimension::fixed(10), rows: Dimension::fixed(10),
cols: Dimension::fixed(10), cols: Dimension::fixed(10),
is_stacked: false, stacked: None,
is_pinned: false, is_pinned: false,
logical_position: None, logical_position: None,
}, },
@ -1677,7 +1677,7 @@ mod tests {
y: 0, y: 0,
rows: Dimension::fixed(10), rows: Dimension::fixed(10),
cols: Dimension::fixed(10), cols: Dimension::fixed(10),
is_stacked: false, stacked: None,
is_pinned: false, is_pinned: false,
logical_position: None, logical_position: None,
}, },
@ -1810,7 +1810,7 @@ mod tests {
y: data["y"].to_string().parse().unwrap(), y: data["y"].to_string().parse().unwrap(),
rows: get_dim(&data["rows"]), rows: get_dim(&data["rows"]),
cols: get_dim(&data["cols"]), cols: get_dim(&data["cols"]),
is_stacked: data["is_stacked"].to_string().parse().unwrap(), stacked: None,
is_pinned: false, is_pinned: false,
logical_position: None, logical_position: None,
} }

View file

@ -1,6 +1,6 @@
--- ---
source: zellij-utils/src/setup.rs source: zellij-utils/src/setup.rs
assertion_line: 740 assertion_line: 770
expression: "format!(\"{:#?}\", options)" expression: "format!(\"{:#?}\", options)"
--- ---
Options { Options {
@ -33,4 +33,5 @@ Options {
serialization_interval: None, serialization_interval: None,
disable_session_metadata: None, disable_session_metadata: None,
support_kitty_keyboard_protocol: None, support_kitty_keyboard_protocol: None,
stacked_resize: None,
} }

View file

@ -1,6 +1,6 @@
--- ---
source: zellij-utils/src/setup.rs source: zellij-utils/src/setup.rs
assertion_line: 768 assertion_line: 798
expression: "format!(\"{:#?}\", options)" expression: "format!(\"{:#?}\", options)"
--- ---
Options { Options {
@ -33,4 +33,5 @@ Options {
serialization_interval: None, serialization_interval: None,
disable_session_metadata: None, disable_session_metadata: None,
support_kitty_keyboard_protocol: None, support_kitty_keyboard_protocol: None,
stacked_resize: None,
} }

View file

@ -1,6 +1,6 @@
--- ---
source: zellij-utils/src/setup.rs source: zellij-utils/src/setup.rs
assertion_line: 727 assertion_line: 757
expression: "format!(\"{:#?}\", options)" expression: "format!(\"{:#?}\", options)"
--- ---
Options { Options {
@ -31,4 +31,5 @@ Options {
serialization_interval: None, serialization_interval: None,
disable_session_metadata: None, disable_session_metadata: None,
support_kitty_keyboard_protocol: None, support_kitty_keyboard_protocol: None,
stacked_resize: None,
} }

View file

@ -5610,6 +5610,7 @@ Config {
serialization_interval: None, serialization_interval: None,
disable_session_metadata: None, disable_session_metadata: None,
support_kitty_keyboard_protocol: None, support_kitty_keyboard_protocol: None,
stacked_resize: None,
}, },
themes: {}, themes: {},
plugins: PluginAliases { plugins: PluginAliases {

View file

@ -5610,6 +5610,7 @@ Config {
serialization_interval: None, serialization_interval: None,
disable_session_metadata: None, disable_session_metadata: None,
support_kitty_keyboard_protocol: None, support_kitty_keyboard_protocol: None,
stacked_resize: None,
}, },
themes: {}, themes: {},
plugins: PluginAliases { plugins: PluginAliases {

View file

@ -1,6 +1,6 @@
--- ---
source: zellij-utils/src/setup.rs source: zellij-utils/src/setup.rs
assertion_line: 854 assertion_line: 855
expression: "format!(\"{:#?}\", config)" expression: "format!(\"{:#?}\", config)"
--- ---
Config { Config {
@ -118,6 +118,7 @@ Config {
serialization_interval: None, serialization_interval: None,
disable_session_metadata: None, disable_session_metadata: None,
support_kitty_keyboard_protocol: None, support_kitty_keyboard_protocol: None,
stacked_resize: None,
}, },
themes: {}, themes: {},
plugins: PluginAliases { plugins: PluginAliases {

View file

@ -1,6 +1,6 @@
--- ---
source: zellij-utils/src/setup.rs source: zellij-utils/src/setup.rs
assertion_line: 750 assertion_line: 780
expression: "format!(\"{:#?}\", options)" expression: "format!(\"{:#?}\", options)"
--- ---
Options { Options {
@ -33,4 +33,5 @@ Options {
serialization_interval: None, serialization_interval: None,
disable_session_metadata: None, disable_session_metadata: None,
support_kitty_keyboard_protocol: None, support_kitty_keyboard_protocol: None,
stacked_resize: None,
} }

View file

@ -5610,6 +5610,7 @@ Config {
serialization_interval: None, serialization_interval: None,
disable_session_metadata: None, disable_session_metadata: None,
support_kitty_keyboard_protocol: None, support_kitty_keyboard_protocol: None,
stacked_resize: None,
}, },
themes: { themes: {
"other-theme-from-config": Theme { "other-theme-from-config": Theme {

View file

@ -5610,6 +5610,7 @@ Config {
serialization_interval: None, serialization_interval: None,
disable_session_metadata: None, disable_session_metadata: None,
support_kitty_keyboard_protocol: None, support_kitty_keyboard_protocol: None,
stacked_resize: None,
}, },
themes: {}, themes: {},
plugins: PluginAliases { plugins: PluginAliases {