aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorDoron Tsur <qballer@gmail.com>2020-12-19 18:36:23 +0200
committerGitHub <noreply@github.com>2020-12-19 17:36:23 +0100
commit75b00b7932e85ae6b88aa1dfc7c70e26a437cd2e (patch)
tree33f44ced59228ad496cd05bfd749f3e07e4ecc66 /src
parentfix(compatibility): fish multiline paste (#112) (diff)
downloadsl0ppij-75b00b7932e85ae6b88aa1dfc7c70e26a437cd2e.tar.gz
sl0ppij-75b00b7932e85ae6b88aa1dfc7c70e26a437cd2e.tar.xz
sl0ppij-75b00b7932e85ae6b88aa1dfc7c70e26a437cd2e.zip
refactor(tabs): lay down infrastructure for status bar (#116)
* resolves #76 * move private fun to bottom * refactor(tabs): do not allocate when filtering panes to terminals * style(formatting): make rustfmt happy Co-authored-by: Aram Drevekenin <aram@poor.dev>
Diffstat (limited to 'src')
-rw-r--r--src/screen.rs2
-rw-r--r--src/tab.rs407
-rw-r--r--src/tests/integration/snapshots/mosaic__tests__integration__basic__max_panes-10.snap22
-rw-r--r--src/tests/integration/snapshots/mosaic__tests__integration__basic__max_panes-11.snap16
-rw-r--r--src/tests/integration/snapshots/mosaic__tests__integration__basic__max_panes-9.snap24
5 files changed, 285 insertions, 186 deletions
diff --git a/src/screen.rs b/src/screen.rs
index b0cd4d83..b8249a5b 100644
--- a/src/screen.rs
+++ b/src/screen.rs
@@ -135,7 +135,7 @@ impl Screen {
self.switch_tab_prev();
}
let mut active_tab = self.tabs.remove(&active_tab_index).unwrap();
- let pane_ids = active_tab.get_pane_ids();
+ let pane_ids = active_tab.get_terminal_pane_ids();
self.send_pty_instructions
.send(PtyInstruction::CloseTab(pane_ids))
.unwrap();
diff --git a/src/tab.rs b/src/tab.rs
index 48238702..2032cca4 100644
--- a/src/tab.rs
+++ b/src/tab.rs
@@ -49,9 +49,14 @@ fn split_horizontally_with_gap(rect: &PositionAndSize) -> (PositionAndSize, Posi
(first_rect, second_rect)
}
+#[derive(PartialEq, Eq, Ord, PartialOrd, Hash, Clone, Copy)]
+enum PaneKind {
+ Terminal(RawFd),
+ BuiltInPane(u32),
+}
pub struct Tab {
pub index: usize,
- terminals: BTreeMap<RawFd, TerminalPane>,
+ panes: BTreeMap<PaneKind, TerminalPane>,
panes_to_hide: HashSet<RawFd>,
active_terminal: Option<RawFd>,
max_panes: Option<usize>,
@@ -72,22 +77,22 @@ impl Tab {
max_panes: Option<usize>,
pane_id: Option<RawFd>,
) -> Self {
- let terminals = if let Some(pid) = pane_id {
+ let panes = if let Some(pid) = pane_id {
let new_terminal = TerminalPane::new(pid, *full_screen_ws, 0, 0);
os_api.set_terminal_size_using_fd(
new_terminal.pid,
new_terminal.get_columns() as u16,
new_terminal.get_rows() as u16,
);
- let mut terminals = BTreeMap::new();
- terminals.insert(pid, new_terminal);
- terminals
+ let mut panes = BTreeMap::new();
+ panes.insert(PaneKind::Terminal(pid), new_terminal);
+ panes
} else {
BTreeMap::new()
};
Tab {
index: index,
- terminals,
+ panes,
max_panes,
panes_to_hide: HashSet::new(),
active_terminal: pane_id,
@@ -110,21 +115,24 @@ impl Tab {
self.panes_to_hide.clear();
let positions_in_layout = layout.position_panes_in_space(&free_space);
let mut positions_and_size = positions_in_layout.iter();
- for (pid, terminal_pane) in self.terminals.iter_mut() {
- match positions_and_size.next() {
- Some(position_and_size) => {
- terminal_pane.reset_size_and_position_override();
- terminal_pane.change_size_p(&position_and_size);
- self.os_api.set_terminal_size_using_fd(
- *pid,
- position_and_size.columns as u16,
- position_and_size.rows as u16,
- );
- }
- None => {
- // we filled the entire layout, no room for this pane
- // TODO: handle active terminal
- self.panes_to_hide.insert(*pid);
+ for (pane_kind, terminal_pane) in self.panes.iter_mut() {
+ // for now the layout only supports terminal panes
+ if let PaneKind::Terminal(pid) = pane_kind {
+ match positions_and_size.next() {
+ Some(position_and_size) => {
+ terminal_pane.reset_size_and_position_override();
+ terminal_pane.change_size_p(&position_and_size);
+ self.os_api.set_terminal_size_using_fd(
+ *pid,
+ position_and_size.columns as u16,
+ position_and_size.rows as u16,
+ );
+ }
+ None => {
+ // we filled the entire layout, no room for this pane
+ // TODO: handle active terminal
+ self.panes_to_hide.insert(*pid);
+ }
}
}
}
@@ -144,7 +152,7 @@ impl Tab {
new_terminal.get_columns() as u16,
new_terminal.get_rows() as u16,
);
- self.terminals.insert(*pid, new_terminal);
+ self.panes.insert(PaneKind::Terminal(*pid), new_terminal);
}
for unused_pid in new_pids {
// this is a bit of a hack and happens because we don't have any central location that
@@ -154,7 +162,14 @@ impl Tab {
.send(PtyInstruction::ClosePane(*unused_pid))
.unwrap();
}
- self.active_terminal = Some(*self.terminals.iter().next().unwrap().0);
+ self.active_terminal = self
+ .panes
+ .iter()
+ .filter_map(|(pane_kind, _)| match pane_kind {
+ PaneKind::Terminal(pid) => Some(*pid),
+ _ => None,
+ })
+ .next();
self.render();
}
pub fn new_pane(&mut self, pid: RawFd) {
@@ -162,7 +177,7 @@ impl Tab {
if self.fullscreen_is_active {
self.toggle_active_terminal_fullscreen();
}
- if self.terminals.is_empty() {
+ if !self.has_terminal_panes() {
let x = 0;
let y = 0;
let new_terminal = TerminalPane::new(pid, self.full_screen_ws, x, y);
@@ -171,25 +186,28 @@ impl Tab {
new_terminal.get_columns() as u16,
new_terminal.get_rows() as u16,
);
- self.terminals.insert(pid, new_terminal);
+ self.panes.insert(PaneKind::Terminal(pid), new_terminal);
self.active_terminal = Some(pid);
} else {
// TODO: check minimum size of active terminal
- let (_longest_edge, terminal_id_to_split) = self.terminals.iter().fold(
+ let (_longest_edge, terminal_id_to_split) = self.get_terminals().fold(
(0, 0),
|(current_longest_edge, current_terminal_id_to_split), id_and_terminal_to_check| {
let (id_of_terminal_to_check, terminal_to_check) = id_and_terminal_to_check;
let terminal_size = (terminal_to_check.get_rows() * CURSOR_HEIGHT_WIDTH_RATIO)
* terminal_to_check.get_columns();
if terminal_size > current_longest_edge {
- (terminal_size, *id_of_terminal_to_check)
+ (terminal_size, id_of_terminal_to_check)
} else {
(current_longest_edge, current_terminal_id_to_split)
}
},
);
- let terminal_to_split = self.terminals.get_mut(&terminal_id_to_split).unwrap();
+ let terminal_to_split = self
+ .panes
+ .get_mut(&PaneKind::Terminal(terminal_id_to_split))
+ .unwrap();
let terminal_ws = PositionAndSize {
rows: terminal_to_split.get_rows(),
columns: terminal_to_split.get_columns(),
@@ -209,7 +227,7 @@ impl Tab {
bottom_winsize.rows as u16,
);
terminal_to_split.change_size(&top_winsize);
- self.terminals.insert(pid, new_terminal);
+ self.panes.insert(PaneKind::Terminal(pid), new_terminal);
self.os_api.set_terminal_size_using_fd(
terminal_id_to_split,
top_winsize.columns as u16,
@@ -227,7 +245,7 @@ impl Tab {
right_winsize.rows as u16,
);
terminal_to_split.change_size(&left_winszie);
- self.terminals.insert(pid, new_terminal);
+ self.panes.insert(PaneKind::Terminal(pid), new_terminal);
self.os_api.set_terminal_size_using_fd(
terminal_id_to_split,
left_winszie.columns as u16,
@@ -243,7 +261,7 @@ impl Tab {
if self.fullscreen_is_active {
self.toggle_active_terminal_fullscreen();
}
- if self.terminals.is_empty() {
+ if !self.has_terminal_panes() {
let x = 0;
let y = 0;
let new_terminal = TerminalPane::new(pid, self.full_screen_ws, x, y);
@@ -252,7 +270,7 @@ impl Tab {
new_terminal.get_columns() as u16,
new_terminal.get_rows() as u16,
);
- self.terminals.insert(pid, new_terminal);
+ self.panes.insert(PaneKind::Terminal(pid), new_terminal);
self.active_terminal = Some(pid);
} else {
// TODO: check minimum size of active terminal
@@ -281,11 +299,14 @@ impl Tab {
{
let active_terminal_id = &self.get_active_terminal_id().unwrap();
- let active_terminal = &mut self.terminals.get_mut(&active_terminal_id).unwrap();
+ let active_terminal = &mut self
+ .panes
+ .get_mut(&PaneKind::Terminal(*active_terminal_id))
+ .unwrap();
active_terminal.change_size(&top_winsize);
}
- self.terminals.insert(pid, new_terminal);
+ self.panes.insert(PaneKind::Terminal(pid), new_terminal);
let active_terminal_pid = self.get_active_terminal_id().unwrap();
self.os_api.set_terminal_size_using_fd(
active_terminal_pid,
@@ -301,7 +322,7 @@ impl Tab {
if self.fullscreen_is_active {
self.toggle_active_terminal_fullscreen();
}
- if self.terminals.is_empty() {
+ if !self.has_terminal_panes() {
let x = 0;
let y = 0;
let new_terminal = TerminalPane::new(pid, self.full_screen_ws, x, y);
@@ -310,7 +331,7 @@ impl Tab {
new_terminal.get_columns() as u16,
new_terminal.get_rows() as u16,
);
- self.terminals.insert(pid, new_terminal);
+ self.panes.insert(PaneKind::Terminal(pid), new_terminal);
self.active_terminal = Some(pid);
} else {
// TODO: check minimum size of active terminal
@@ -339,11 +360,14 @@ impl Tab {
{
let active_terminal_id = &self.get_active_terminal_id().unwrap();
- let active_terminal = &mut self.terminals.get_mut(&active_terminal_id).unwrap();
+ let active_terminal = &mut self
+ .panes
+ .get_mut(&PaneKind::Terminal(*active_terminal_id))
+ .unwrap();
active_terminal.change_size(&left_winszie);
}
- self.terminals.insert(pid, new_terminal);
+ self.panes.insert(PaneKind::Terminal(pid), new_terminal);
let active_terminal_pid = self.get_active_terminal_id().unwrap();
self.os_api.set_terminal_size_using_fd(
active_terminal_pid,
@@ -356,13 +380,18 @@ impl Tab {
}
pub fn get_active_terminal(&self) -> Option<&TerminalPane> {
match self.active_terminal {
- Some(active_terminal) => self.terminals.get(&active_terminal),
+ Some(active_terminal) => self.panes.get(&PaneKind::Terminal(active_terminal)),
None => None,
}
}
fn get_active_terminal_id(&self) -> Option<RawFd> {
match self.active_terminal {
- Some(active_terminal) => Some(self.terminals.get(&active_terminal).unwrap().pid),
+ Some(active_terminal) => Some(
+ self.panes
+ .get(&PaneKind::Terminal(active_terminal))
+ .unwrap()
+ .pid,
+ ),
None => None,
}
}
@@ -372,7 +401,7 @@ impl Tab {
// yet been created in Screen. These events are currently not buffered, so
// if you're debugging seemingly randomly missing stdout data, this is
// the reason
- if let Some(terminal_output) = self.terminals.get_mut(&pid) {
+ if let Some(terminal_output) = self.panes.get_mut(&PaneKind::Terminal(pid)) {
terminal_output.handle_event(event);
}
}
@@ -408,21 +437,37 @@ impl Tab {
.is_some()
{
for terminal_id in self.panes_to_hide.iter() {
- self.terminals.get_mut(terminal_id).unwrap().should_render = true;
+ self.panes
+ .get_mut(&PaneKind::Terminal(*terminal_id))
+ .unwrap()
+ .should_render = true;
}
self.panes_to_hide.clear();
- let active_terminal = self.terminals.get_mut(&active_terminal_id).unwrap();
+ let active_terminal = self
+ .panes
+ .get_mut(&PaneKind::Terminal(active_terminal_id))
+ .unwrap();
active_terminal.reset_size_and_position_override();
} else {
- let all_ids_except_current = self
- .terminals
- .keys()
- .filter(|id| **id != active_terminal_id);
- self.panes_to_hide = all_ids_except_current.copied().collect();
- let active_terminal = self.terminals.get_mut(&active_terminal_id).unwrap();
+ let terminals = self.get_terminals();
+ let all_ids_except_current = terminals.filter_map(|(id, _)| {
+ if id != active_terminal_id {
+ Some(id)
+ } else {
+ None
+ }
+ });
+ self.panes_to_hide = all_ids_except_current.collect();
+ let active_terminal = self
+ .panes
+ .get_mut(&PaneKind::Terminal(active_terminal_id))
+ .unwrap();
active_terminal.override_size_and_position(0, 0, &self.full_screen_ws);
}
- let active_terminal = self.terminals.get(&active_terminal_id).unwrap();
+ let active_terminal = self
+ .panes
+ .get(&PaneKind::Terminal(active_terminal_id))
+ .unwrap();
self.os_api.set_terminal_size_using_fd(
active_terminal_id,
active_terminal.get_columns() as u16,
@@ -446,13 +491,20 @@ impl Tab {
self.full_screen_ws.columns as u16,
self.full_screen_ws.rows as u16,
);
- for (pid, terminal) in self.terminals.iter_mut() {
- if !self.panes_to_hide.contains(pid) {
- boundaries.add_rect(&terminal);
- if let Some(vte_output) = terminal.buffer_as_vte_output() {
- stdout
- .write_all(&vte_output.as_bytes())
- .expect("cannot write to stdout");
+ for (pane_kind, terminal) in self.panes.iter_mut() {
+ match pane_kind {
+ PaneKind::Terminal(pid) => {
+ if !self.panes_to_hide.contains(pid) {
+ boundaries.add_rect(&terminal);
+ if let Some(vte_output) = terminal.buffer_as_vte_output() {
+ stdout
+ .write_all(&vte_output.as_bytes())
+ .expect("cannot write to stdout");
+ }
+ }
+ }
+ PaneKind::BuiltInPane(builtin_id) => {
+ // TBD
}
}
}
@@ -488,15 +540,27 @@ impl Tab {
}
}
}
+ fn get_terminals(&self) -> impl Iterator<Item = (RawFd, &TerminalPane)> {
+ self.panes
+ .iter()
+ .filter_map(|(pane_kind, terminal_pane)| match pane_kind {
+ PaneKind::Terminal(pid) => Some((*pid, terminal_pane)),
+ _ => None,
+ })
+ }
+ fn has_terminal_panes(&self) -> bool {
+ let mut all_terminals = self.get_terminals();
+ all_terminals.next().is_some()
+ }
fn terminal_ids_directly_left_of(&self, id: &RawFd) -> Option<Vec<RawFd>> {
let mut ids = vec![];
- let terminal_to_check = self.terminals.get(id).unwrap();
+ let terminal_to_check = self.panes.get(&PaneKind::Terminal(*id)).unwrap();
if terminal_to_check.get_x() == 0 {
return None;
}
- for (pid, terminal) in self.terminals.iter() {
+ for (pid, terminal) in self.get_terminals() {
if terminal.get_x() + terminal.get_columns() == terminal_to_check.get_x() - 1 {
- ids.push(*pid);
+ ids.push(pid);
}
}
if ids.is_empty() {
@@ -507,10 +571,10 @@ impl Tab {
}
fn terminal_ids_directly_right_of(&self, id: &RawFd) -> Option<Vec<RawFd>> {
let mut ids = vec![];
- let terminal_to_check = self.terminals.get(id).unwrap();
- for (pid, terminal) in self.terminals.iter() {
+ let terminal_to_check = self.panes.get(&PaneKind::Terminal(*id)).unwrap();
+ for (pid, terminal) in self.get_terminals() {
if terminal.get_x() == terminal_to_check.get_x() + terminal_to_check.get_columns() + 1 {
- ids.push(*pid);
+ ids.push(pid);
}
}
if ids.is_empty() {
@@ -521,10 +585,10 @@ impl Tab {
}
fn terminal_ids_directly_below(&self, id: &RawFd) -> Option<Vec<RawFd>> {
let mut ids = vec![];
- let terminal_to_check = self.terminals.get(id).unwrap();
- for (pid, terminal) in self.terminals.iter() {
+ let terminal_to_check = self.panes.get(&PaneKind::Terminal(*id)).unwrap();
+ for (pid, terminal) in self.get_terminals() {
if terminal.get_y() == terminal_to_check.get_y() + terminal_to_check.get_rows() + 1 {
- ids.push(*pid);
+ ids.push(pid);
}
}
if ids.is_empty() {
@@ -535,10 +599,10 @@ impl Tab {
}
fn terminal_ids_directly_above(&self, id: &RawFd) -> Option<Vec<RawFd>> {
let mut ids = vec![];
- let terminal_to_check = self.terminals.get(id).unwrap();
- for (pid, terminal) in self.terminals.iter() {
+ let terminal_to_check = self.panes.get(&PaneKind::Terminal(*id)).unwrap();
+ for (pid, terminal) in self.get_terminals() {
if terminal.get_y() + terminal.get_rows() + 1 == terminal_to_check.get_y() {
- ids.push(*pid);
+ ids.push(pid);
}
}
if ids.is_empty() {
@@ -548,16 +612,16 @@ impl Tab {
}
}
fn panes_top_aligned_with_pane(&self, pane: &TerminalPane) -> Vec<&TerminalPane> {
- self.terminals
+ self.panes
.keys()
- .map(|t_id| self.terminals.get(&t_id).unwrap())
+ .map(|t_id| self.panes.get(&t_id).unwrap())
.filter(|terminal| terminal.pid != pane.pid && terminal.get_y() == pane.get_y())
.collect()
}
fn panes_bottom_aligned_with_pane(&self, pane: &TerminalPane) -> Vec<&TerminalPane> {
- self.terminals
+ self.panes
.keys()
- .map(|t_id| self.terminals.get(&t_id).unwrap())
+ .map(|t_id| self.panes.get(&t_id).unwrap())
.filter(|terminal| {
terminal.pid != pane.pid
&& terminal.get_y() + terminal.get_rows() == pane.get_y() + pane.get_rows()
@@ -565,9 +629,9 @@ impl Tab {
.collect()
}
fn panes_right_aligned_with_pane(&self, pane: &TerminalPane) -> Vec<&TerminalPane> {
- self.terminals
+ self.panes
.keys()
- .map(|t_id| self.terminals.get(&t_id).unwrap())
+ .map(|t_id| self.panes.get(&t_id).unwrap())
.filter(|terminal| {
terminal.pid != pane.pid
&& terminal.get_x() + terminal.get_columns()
@@ -576,9 +640,9 @@ impl Tab {
.collect()
}
fn panes_left_aligned_with_pane(&self, pane: &TerminalPane) -> Vec<&TerminalPane> {
- self.terminals
+ self.panes
.keys()
- .map(|t_id| self.terminals.get(&t_id).unwrap())
+ .map(|t_id| self.panes.get(&t_id).unwrap())
.filter(|terminal| terminal.pid != pane.pid && terminal.get_x() == pane.get_x())
.collect()
}
@@ -588,7 +652,10 @@ impl Tab {
terminal_borders_to_the_right: &HashSet<usize>,
) -> BorderAndPaneIds {
let mut terminals = vec![];
- let terminal_to_check = self.terminals.get(id).expect("terminal id does not exist");
+ let terminal_to_check = self
+ .panes
+ .get(&PaneKind::Terminal(*id))
+ .expect("terminal id does not exist");
let mut right_aligned_terminals = self.panes_right_aligned_with_pane(&terminal_to_check);
// terminals that are next to each other up to current
right_aligned_terminals.sort_by(|a, b| b.get_y().cmp(&a.get_y()));
@@ -627,7 +694,10 @@ impl Tab {
terminal_borders_to_the_right: &HashSet<usize>,
) -> BorderAndPaneIds {
let mut terminals = vec![];
- let terminal_to_check = self.terminals.get(id).expect("terminal id does not exist");
+ let terminal_to_check = self
+ .panes
+ .get(&PaneKind::Terminal(*id))
+ .expect("terminal id does not exist");
let mut right_aligned_terminals = self.panes_right_aligned_with_pane(&terminal_to_check);
// terminals that are next to each other up to current
right_aligned_terminals.sort_by(|a, b| a.get_y().cmp(&b.get_y()));
@@ -666,7 +736,10 @@ impl Tab {
terminal_borders_to_the_left: &HashSet<usize>,
) -> BorderAndPaneIds {
let mut terminals = vec![];
- let terminal_to_check = self.terminals.get(id).expect("terminal id does not exist");
+ let terminal_to_check = self
+ .panes
+ .get(&PaneKind::Terminal(*id))
+ .expect("terminal id does not exist");
let mut left_aligned_terminals = self.panes_left_aligned_with_pane(&terminal_to_check);
// terminals that are next to each other up to current
left_aligned_terminals.sort_by(|a, b| b.get_y().cmp(&a.get_y()));
@@ -705,7 +778,10 @@ impl Tab {
terminal_borders_to_the_left: &HashSet<usize>,
) -> BorderAndPaneIds {
let mut terminals = vec![];
- let terminal_to_check = self.terminals.get(id).expect("terminal id does not exist");
+ let terminal_to_check = self
+ .panes
+ .get(&PaneKind::Terminal(*id))
+ .expect("terminal id does not exist");
let mut left_aligned_terminals = self.panes_left_aligned_with_pane(&terminal_to_check);
// terminals that are next to each other up to current
left_aligned_terminals.sort_by(|a, b| a.get_y().cmp(&b.get_y()));
@@ -747,7 +823,10 @@ impl Tab {
terminal_borders_above: &HashSet<usize>,
) -> BorderAndPaneIds {
let mut terminals = vec![];
- let terminal_to_check = self.terminals.get(id).expect("terminal id does not exist");
+ let terminal_to_check = self
+ .panes
+ .get(&PaneKind::Terminal(*id))
+ .expect("terminal id does not exist");
let mut top_aligned_terminals = self.panes_top_aligned_with_pane(&terminal_to_check);
// terminals that are next to each other up to current
top_aligned_terminals.sort_by(|a, b| b.get_x().cmp(&a.get_x()));
@@ -786,7 +865,7 @@ impl Tab {
terminal_borders_above: &HashSet<usize>,
) -> BorderAndPaneIds {
let mut terminals = vec![];
- let terminal_to_check = self.terminals.get(id).unwrap();
+ let terminal_to_check = self.panes.get(&PaneKind::Terminal(*id)).unwrap();
let mut top_aligned_terminals = self.panes_top_aligned_with_pane(&terminal_to_check);
// terminals that are next to each other up to current
top_aligned_terminals.sort_by(|a, b| a.get_x().cmp(&b.get_x()));
@@ -826,7 +905,7 @@ impl Tab {
terminal_borders_below: &HashSet<usize>,
) -> BorderAndPaneIds {
let mut terminals = vec![];
- let terminal_to_check = self.terminals.get(id).unwrap();
+ let terminal_to_check = self.panes.get(&PaneKind::Terminal(*id)).unwrap();
let mut bottom_aligned_terminals = self.panes_bottom_aligned_with_pane(&terminal_to_check);
bottom_aligned_terminals.sort_by(|a, b| b.get_x().cmp(&a.get_x()));
// terminals that are next to each other up to current
@@ -865,7 +944,7 @@ impl Tab {
terminal_borders_below: &HashSet<usize>,
) -> BorderAndPaneIds {
let mut terminals = vec![];
- let terminal_to_check = self.terminals.get(id).unwrap();
+ let terminal_to_check = self.panes.get(&PaneKind::Terminal(*id)).unwrap();
let mut bottom_aligned_terminals = self.panes_bottom_aligned_with_pane(&terminal_to_check);
bottom_aligned_terminals.sort_by(|a, b| a.get_x().cmp(&b.get_x()));
// terminals that are next to each other up to current
@@ -898,7 +977,7 @@ impl Tab {
(right_resize_border, terminal_ids)
}
fn reduce_pane_height_down(&mut self, id: &RawFd, count: usize) {
- let terminal = self.terminals.get_mut(id).unwrap();
+ let terminal = self.panes.get_mut(&PaneKind::Terminal(*id)).unwrap();
terminal.reduce_height_down(count);
self.os_api.set_terminal_size_using_fd(
*id,
@@ -907,7 +986,7 @@ impl Tab {
);
}
fn reduce_pane_height_up(&mut self, id: &RawFd, count: usize) {
- let terminal = self.terminals.get_mut(id).unwrap();
+ let terminal = self.panes.get_mut(&PaneKind::Terminal(*id)).unwrap();
terminal.reduce_height_up(count);
self.os_api.set_terminal_size_using_fd(
*id,
@@ -916,7 +995,7 @@ impl Tab {
);
}
fn increase_pane_height_down(&mut self, id: &RawFd, count: usize) {
- let terminal = self.terminals.get_mut(&id).unwrap();
+ let terminal = self.panes.get_mut(&PaneKind::Terminal(*id)).unwrap();
terminal.increase_height_down(count);
self.os_api.set_terminal_size_using_fd(
terminal.pid,
@@ -925,7 +1004,7 @@ impl Tab {
);
}
fn increase_pane_height_up(&mut self, id: &RawFd, count: usize) {
- let terminal = self.terminals.get_mut(&id).unwrap();
+ let terminal = self.panes.get_mut(&PaneKind::Terminal(*id)).unwrap();
terminal.increase_height_up(count);
self.os_api.set_terminal_size_using_fd(
terminal.pid,
@@ -934,7 +1013,7 @@ impl Tab {
);
}
fn increase_pane_width_right(&mut self, id: &RawFd, count: usize) {
- let terminal = self.terminals.get_mut(&id).unwrap();
+ let terminal = self.panes.get_mut(&PaneKind::Terminal(*id)).unwrap();
terminal.increase_width_right(count);
self.os_api.set_terminal_size_using_fd(
terminal.pid,
@@ -943,7 +1022,7 @@ impl Tab {
);
}
fn increase_pane_width_left(&mut self, id: &RawFd, count: usize) {
- let terminal = self.terminals.get_mut(&id).unwrap();
+ let terminal = self.panes.get_mut(&PaneKind::Terminal(*id)).unwrap();
terminal.increase_width_left(count);
self.os_api.set_terminal_size_using_fd(
terminal.pid,
@@ -952,7 +1031,7 @@ impl Tab {
);
}
fn reduce_pane_width_right(&mut self, id: &RawFd, count: usize) {
- let terminal = self.terminals.get_mut(&id).unwrap();
+ let terminal = self.panes.get_mut(&PaneKind::Terminal(*id)).unwrap();
terminal.reduce_width_right(count);
self.os_api.set_terminal_size_using_fd(
terminal.pid,
@@ -961,7 +1040,7 @@ impl Tab {
);
}
fn reduce_pane_width_left(&mut self, id: &RawFd, count: usize) {
- let terminal = self.terminals.get_mut(&id).unwrap();
+ let terminal = self.panes.get_mut(&PaneKind::Terminal(*id)).unwrap();
terminal.reduce_width_left(count);
self.os_api.set_terminal_size_using_fd(
terminal.pid,
@@ -976,8 +1055,8 @@ impl Tab {
right_border_x: usize,
) -> bool {
let terminal = self
- .terminals
- .get(id)
+ .panes
+ .get(&PaneKind::Terminal(*id))
.expect("could not find terminal to check between borders");
terminal.get_x() >= left_border_x
&& terminal.get_x() + terminal.get_columns() <= right_border_x
@@ -989,8 +1068,8 @@ impl Tab {
bottom_border_y: usize,
) -> bool {
let terminal = self
- .terminals
- .get(id)
+ .panes
+ .get(&PaneKind::Terminal(*id))
.expect("could not find terminal to check between borders");
terminal.get_y() >= top_border_y
&& terminal.get_y() + terminal.get_rows() <= bottom_border_y
@@ -1001,7 +1080,7 @@ impl Tab {
.expect("can't reduce pane size up if there are no terminals below");
let terminal_borders_below: HashSet<usize> = terminals_below
.iter()
- .map(|t| self.terminals.get(t).unwrap().get_x())
+ .map(|t| self.panes.get(&PaneKind::Terminal(*t)).unwrap().get_x())
.collect();
let (left_resize_border, terminals_to_the_left) =
self.bottom_aligned_contiguous_panes_to_the_left(&id, &terminal_borders_below);
@@ -1027,7 +1106,7 @@ impl Tab {
.expect("can't reduce pane size down if there are no terminals above");
let terminal_borders_above: HashSet<usize> = terminals_above
.iter()
- .map(|t| self.terminals.get(t).unwrap().get_x())
+ .map(|t| self.panes.get(&PaneKind::Terminal(*t)).unwrap().get_x())
.collect();
let (left_resize_border, terminals_to_the_left) =
self.top_aligned_contiguous_panes_to_the_left(&id, &terminal_borders_above);
@@ -1053,7 +1132,7 @@ impl Tab {
.expect("can't reduce pane size right if there are no terminals to the left");
let terminal_borders_to_the_left: HashSet<usize> = terminals_to_the_left
.iter()
- .map(|t| self.terminals.get(t).unwrap().get_y())
+ .map(|t| self.panes.get(&PaneKind::Terminal(*t)).unwrap().get_y())
.collect();
let (top_resize_border, terminals_above) =
self.left_aligned_contiguous_panes_above(&id, &terminal_borders_to_the_left);
@@ -1076,7 +1155,7 @@ impl Tab {
.expect("can't reduce pane size left if there are no terminals to the right");
let terminal_borders_to_the_right: HashSet<usize> = terminals_to_the_right
.iter()
- .map(|t| self.terminals.get(t).unwrap().get_y())
+ .map(|t| self.panes.get(&PaneKind::Terminal(*t)).unwrap().get_y())
.collect();
let (top_resize_border, terminals_above) =
self.right_aligned_contiguous_panes_above(&id, &terminal_borders_to_the_right);
@@ -1099,7 +1178,7 @@ impl Tab {
.expect("can't increase pane size up if there are no terminals above");
let terminal_borders_above: HashSet<usize> = terminals_above
.iter()
- .map(|t| self.terminals.get(t).unwrap().get_x())
+ .map(|t| self.panes.get(&PaneKind::Terminal(*t)).unwrap().get_x())
.collect();
let (left_resize_border, terminals_to_the_left) =
self.top_aligned_contiguous_panes_to_the_left(&id, &terminal_borders_above);
@@ -1125,7 +1204,7 @@ impl Tab {
.expect("can't increase pane size down if there are no terminals below");
let terminal_borders_below: HashSet<usize> = terminals_below
.iter()
- .map(|t| self.terminals.get(t).unwrap().get_x())
+ .map(|t| self.panes.get(&PaneKind::Terminal(*t)).unwrap().get_x())
.collect();
let (left_resize_border, terminals_to_the_left) =
self.bottom_aligned_contiguous_panes_to_the_left(&id, &terminal_borders_below);
@@ -1151,7 +1230,7 @@ impl Tab {
.expect("can't increase pane size right if there are no terminals to the right");
let terminal_borders_to_the_right: HashSet<usize> = terminals_to_the_right
.iter()
- .map(|t| self.terminals.get(t).unwrap().get_y())
+ .map(|t| self.panes.get(&PaneKind::Terminal(*t)).unwrap().get_y())
.collect();
let (top_resize_border, terminals_above) =
self.right_aligned_contiguous_panes_above(&id, &terminal_borders_to_the_right);
@@ -1174,7 +1253,7 @@ impl Tab {
.expect("can't increase pane size right if there are no terminals to the right");
let terminal_borders_to_the_left: HashSet<usize> = terminals_to_the_left
.iter()
- .map(|t| self.terminals.get(t).unwrap().get_y())
+ .map(|t| self.panes.get(&PaneKind::Terminal(*t)).unwrap().get_y())
.collect();
let (top_resize_border, terminals_above) =
self.left_aligned_contiguous_panes_above(&id, &terminal_borders_to_the_left);
@@ -1192,19 +1271,31 @@ impl Tab {
}
}
fn panes_exist_above(&self, pane_id: &RawFd) -> bool {
- let pane = self.terminals.get(pane_id).expect("pane does not exist");
+ let pane = self
+ .panes
+ .get(&PaneKind::Terminal(*pane_id))
+ .expect("pane does not exist");
pane.get_y() > 0
}
fn panes_exist_below(&self, pane_id: &RawFd) -> bool {
- let pane = self.terminals.get(pane_id).expect("pane does not exist");
+ let pane = self
+ .panes
+ .get(&PaneKind::Terminal(*pane_id))
+ .expect("pane does not exist");
pane.get_y() + pane.get_rows() < self.full_screen_ws.rows
}
fn panes_exist_to_the_right(&self, pane_id: &RawFd) -> bool {
- let pane = self.terminals.get(pane_id).expect("pane does not exist");
+ let pane = self
+ .panes
+ .get(&PaneKind::Terminal(*pane_id))
+ .expect("pane does not exist");
pane.get_x() + pane.get_columns() < self.full_screen_ws.columns
}
fn panes_exist_to_the_left(&self, pane_id: &RawFd) -> bool {
- let pane = self.terminals.get(pane_id).expect("pane does not exist");
+ let pane = self
+ .panes
+ .get(&PaneKind::Terminal(*pane_id))
+ .expect("pane does not exist");
pane.get_x() > 0
}
pub fn resize_right(&mut self) {
@@ -1256,14 +1347,17 @@ impl Tab {
}
}
pub fn move_focus(&mut self) {
- if self.terminals.is_empty() {
+ if !self.has_terminal_panes() {
return;
}
if self.fullscreen_is_active {
return;
}
let active_terminal_id = self.get_active_terminal_id().unwrap();
- let terminal_ids: Vec<RawFd> = self.terminals.keys().copied().collect(); // TODO: better, no allocations
+ let terminal_ids: Vec<RawFd> = self
+ .get_terminals()
+ .filter_map(|(pid, _)| Some(pid))
+ .collect(); // TODO: better, no allocations
let first_terminal = terminal_ids.get(0).unwrap();
let active_terminal_id_position = terminal_ids
.iter()
@@ -1277,7 +1371,7 @@ impl Tab {
self.render();
}
pub fn move_focus_left(&mut self) {
- if self.terminals.is_empty() {
+ if !self.has_terminal_panes() {
return;
}
if self.fullscreen_is_active {
@@ -1285,9 +1379,8 @@ impl Tab {
}
let active_terminal = self.get_active_terminal();
if let Some(active) = active_terminal {
- let next_index = self
- .terminals
- .iter()
+ let terminals = self.get_terminals();
+ let next_index = terminals
.enumerate()
.filter(|(_, (_, c))| {
c.is_directly_left_of(&active) && c.horizontally_overlaps_with(&active)
@@ -1296,7 +1389,7 @@ impl Tab {
.map(|(_, (pid, _))| pid);
match next_index {
Some(p) => {
- self.active_terminal = Some(*p);
+ self.active_terminal = Some(p);
}
None => {
self.active_terminal = Some(active.pid);
@@ -1308,7 +1401,7 @@ impl Tab {
self.render();
}
pub fn move_focus_down(&mut self) {
- if self.terminals.is_empty() {
+ if !self.has_terminal_panes() {
return;
}
if self.fullscreen_is_active {
@@ -1316,9 +1409,8 @@ impl Tab {
}
let active_terminal = self.get_active_terminal();
if let Some(active) = active_terminal {
- let next_index = self
- .terminals
- .iter()
+ let terminals = self.get_terminals();
+ let next_index = terminals
.enumerate()
.filter(|(_, (_, c))| {
c.is_directly_below(&active) && c.vertically_overlaps_with(&active)
@@ -1327,7 +1419,7 @@ impl Tab {
.map(|(_, (pid, _))| pid);
match next_index {
Some(p) => {
- self.active_terminal = Some(*p);
+ self.active_terminal = Some(p);
}
None => {
self.active_terminal = Some(active.pid);
@@ -1339,7 +1431,7 @@ impl Tab {
self.render();
}
pub fn move_focus_up(&mut self) {
- if self.terminals.is_empty() {
+ if !self.has_terminal_panes() {
return;
}
if self.fullscreen_is_active {
@@ -1347,9 +1439,8 @@ impl Tab {
}
let active_terminal = self.get_active_terminal();
if let Some(active) = active_terminal {
- let next_index = self
- .terminals
- .iter()
+ let terminals = self.get_terminals();
+ let next_index = terminals
.enumerate()
.filter(|(_, (_, c))| {
c.is_directly_above(&active) && c.vertically_overlaps_with(&active)
@@ -1358,7 +1449,7 @@ impl Tab {
.map(|(_, (pid, _))| pid);
match next_index {
Some(p) => {
- self.active_terminal = Some(*p);
+ self.active_terminal = Some(p);
}
None => {
self.active_terminal = Some(active.pid);
@@ -1370,7 +1461,7 @@ impl Tab {
self.render();
}
pub fn move_focus_right(&mut self) {
- if self.terminals.is_empty() {
+ if !self.has_terminal_panes() {
return;
}
if self.fullscreen_is_active {
@@ -1378,9 +1469,8 @@ impl Tab {
}
let active_terminal = self.get_active_terminal();
if let Some(active) = active_terminal {
- let next_index = self
- .terminals
- .iter()
+ let terminals = self.get_terminals();
+ let next_index = terminals
.enumerate()
.filter(|(_, (_, c))| {
c.is_directly_right_of(&active) && c.horizontally_overlaps_with(&active)
@@ -1389,7 +1479,7 @@ impl Tab {
.map(|(_, (pid, _))| pid);
match next_index {
Some(p) => {
- self.active_terminal = Some(*p);
+ self.active_terminal = Some(p);
}
None => {
self.active_terminal = Some(active.pid);
@@ -1402,7 +1492,7 @@ impl Tab {
}
fn horizontal_borders(&self, terminals: &[RawFd]) -> HashSet<usize> {
terminals.iter().fold(HashSet::new(), |mut borders, t| {
- let terminal = self.terminals.get(t).unwrap();
+ let terminal = self.panes.get(&PaneKind::Terminal(*t)).unwrap();
borders.insert(terminal.get_y());
borders.insert(terminal.get_y() + terminal.get_rows() + 1); // 1 for the border width
borders
@@ -1410,14 +1500,14 @@ impl Tab {
}
fn vertical_borders(&self, terminals: &[RawFd]) -> HashSet<usize> {
terminals.iter().fold(HashSet::new(), |mut borders, t| {
- let terminal = self.terminals.get(t).unwrap();
+ let terminal = self.panes.get(&PaneKind::Terminal(*t)).unwrap();
borders.insert(terminal.get_x());
borders.insert(terminal.get_x() + terminal.get_columns() + 1); // 1 for the border width
borders
})
}
fn terminals_to_the_left_between_aligning_borders(&self, id: RawFd) -> Option<Vec<RawFd>> {
- if let Some(terminal) = &self.terminals.get(&id) {
+ if let Some(terminal) = &self.panes.get(&PaneKind::Terminal(id)) {
let upper_close_border = terminal.get_y();
let lower_close_border = terminal.get_y() + terminal.get_rows() + 1;
@@ -1440,7 +1530,7 @@ impl Tab {
None
}
fn terminals_to_the_right_between_aligning_borders(&self, id: RawFd) -> Option<Vec<RawFd>> {
- if let Some(terminal) = &self.terminals.get(&id) {
+ if let Some(terminal) = &self.panes.get(&PaneKind::Terminal(id)) {
let upper_close_border = terminal.get_y();
let lower_close_border = terminal.get_y() + terminal.get_rows() + 1;
@@ -1464,7 +1554,7 @@ impl Tab {
None
}
fn terminals_above_between_aligning_borders(&self, id: RawFd) -> Option<Vec<RawFd>> {
- if let Some(terminal) = &self.terminals.get(&id) {
+ if let Some(terminal) = &self.panes.get(&PaneKind::Terminal(id)) {
let left_close_border = terminal.get_x();
let right_close_border = terminal.get_x() + terminal.get_columns() + 1;
@@ -1487,7 +1577,7 @@ impl Tab {
None
}
fn terminals_below_between_aligning_borders(&self, id: RawFd) -> Option<Vec<RawFd>> {
- if let Some(terminal) = &self.terminals.get(&id) {
+ if let Some(terminal) = &self.panes.get(&PaneKind::Terminal(id)) {
let left_close_border = terminal.get_x();
let right_close_border = terminal.get_x() + terminal.get_columns() + 1;
@@ -1511,27 +1601,27 @@ impl Tab {
}
fn close_down_to_max_terminals(&mut self) {
if let Some(max_panes) = self.max_panes {
- if self.terminals.len() >= max_panes {
- for _ in max_panes..=self.terminals.len() {
- let first_pid = *self.terminals.iter().next().unwrap().0;
- self.send_pty_instructions
- .send(PtyInstruction::ClosePane(first_pid))
- .unwrap();
- self.close_pane_without_rerender(first_pid); // TODO: do not render yet
- }
+ let terminals = self.get_terminal_pane_ids();
+ for pid in terminals.iter().skip(max_panes - 1) {
+ self.send_pty_instructions
+ .send(PtyInstruction::ClosePane(*pid))
+ .unwrap();
+ self.close_pane_without_rerender(*pid);
}
}
}
- pub fn get_pane_ids(&mut self) -> Vec<RawFd> {
- self.terminals.keys().copied().collect::<Vec<RawFd>>()
+ pub fn get_terminal_pane_ids(&mut self) -> Vec<RawFd> {
+ self.get_terminals()
+ .filter_map(|(pid, _)| Some(pid))
+ .collect()
}
pub fn close_pane(&mut self, id: RawFd) {
- if self.terminals.get(&id).is_some() {
+ if self.panes.get(&PaneKind::Terminal(id)).is_some() {
self.close_pane_without_rerender(id);
}
}
pub fn close_pane_without_rerender(&mut self, id: RawFd) {
- if let Some(terminal_to_close) = &self.terminals.get(&id) {
+ if let Some(terminal_to_close) = &self.panes.get(&PaneKind::Terminal(id)) {
let terminal_to_close_width = terminal_to_close.get_columns();
let terminal_to_close_height = terminal_to_close.get_rows();
if let Some(terminals) = self.terminals_to_the_left_between_aligning_borders(id) {
@@ -1569,8 +1659,8 @@ impl Tab {
}
} else {
}
- self.terminals.remove(&id);
- if self.terminals.is_empty() {
+ self.panes.remove(&PaneKind::Terminal(id));
+ if !self.has_terminal_panes() {
self.active_terminal = None;
}
}
@@ -1585,21 +1675,30 @@ impl Tab {
}
pub fn scroll_active_terminal_up(&mut self) {
if let Some(active_terminal_id) = self.get_active_terminal_id() {
- let active_terminal = self.terminals.get_mut(&active_terminal_id).unwrap();
+ let active_terminal = self
+ .panes
+ .get_mut(&PaneKind::Terminal(active_terminal_id))
+ .unwrap();
active_terminal.scroll_up(1);
self.render();
}
}
pub fn scroll_active_terminal_down(&mut self) {
if let Some(active_terminal_id) = self.get_active_terminal_id() {
- let active_terminal = self.terminals.get_mut(&active_terminal_id).unwrap();
+ let active_terminal = self
+ .panes
+ .get_mut(&PaneKind::Terminal(active_terminal_id))
+ .unwrap();
active_terminal.scroll_down(1);
self.render();
}
}
pub fn clear_active_terminal_scroll(&mut self) {
if let Some(active_terminal_id) = self.get_active_terminal_id() {
- let active_terminal = self.terminals.get_mut(&active_terminal_id).unwrap();
+ let active_terminal = self
+ .panes
+ .get_mut(&PaneKind::Terminal(active_terminal_id))
+ .unwrap();
active_terminal.clear_scroll();
}
}
diff --git a/src/tests/integration/snapshots/mosaic__tests__integration__basic__max_panes-10.snap b/src/tests/integration/snapshots/mosaic__tests__integration__basic__max_panes-10.snap
index 9dc18e7c..e7d9ee8c 100644
--- a/src/tests/integration/snapshots/mosaic__tests__integration__basic__max_panes-10.snap
+++ b/src/tests/integration/snapshots/mosaic__tests__integration__basic__max_panes-10.snap
@@ -2,16 +2,16 @@
source: src/tests/integration/basic.rs
expression: snapshot
---
-line11-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb│line11-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
-line12-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb│line12-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
-line13-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb│line13-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
-line14-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb│line14-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
-line15-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb│line15-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
-line16-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb│line16-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
-line17-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb│line17-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
-line18-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb│line18-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
-line19-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb│line19-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
-prompt $ │prompt $ █
+line17-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa│line11-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa│line12-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
+a │line13-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
+line18-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa│line14-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa│line15-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
+a │line16-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
+line19-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa│line17-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa│line18-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
+a │line19-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
+prompt $ │prompt $
────────────────────────────────────────────────────────────┼────────────────────────────────────────────────────────────
line12-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb│line12-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
line13-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb│line13-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
@@ -21,4 +21,4 @@ line16-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb│line16-bbbbbbbbbb
line17-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb│line17-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
line18-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb│line18-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
line19-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb│line19-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
-prompt $ │prompt $
+prompt $ │prompt $ █
diff --git a/src/tests/integration/snapshots/mosaic__tests__integration__basic__max_panes-11.snap b/src/tests/integration/snapshots/mosaic__tests__integration__basic__max_panes-11.snap
index fa8c19b2..be0817da 100644
--- a/src/tests/integration/snapshots/mosaic__tests__integration__basic__max_panes-11.snap
+++ b/src/tests/integration/snapshots/mosaic__tests__integration__basic__max_panes-11.snap
@@ -2,14 +2,14 @@
source: src/tests/integration/basic.rs
expression: snapshot
---
-line12-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb│line12-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
-line13-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb│line13-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
-line14-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb│line14-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
-line15-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb│line15-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
-line16-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb│line16-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
-line17-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb│line17-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
-line18-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb│line18-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
-line19-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb│line19-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa│line12-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
+a │line13-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
+line18-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa│line14-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa│line15-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
+a │line16-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
+line19-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa│line17-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa│line18-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
+a │line19-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
prompt $ │prompt $
────────────────────────────────────────────────────────────┼────────────────────────────────────────────────────────────
line12-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb│line12-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
diff --git a/src/tests/integration/snapshots/mosaic__tests__integration__basic__max_panes-9.snap b/src/tests/integration/snapshots/mosaic__tests__integration__basic__max_panes-9.snap
index dc96752b..b0f22d41 100644
--- a/src/tests/integration/snapshots/mosaic__tests__integration__basic__max_panes-9.snap
+++ b/src/tests/integration/snapshots/mosaic__tests__integration__basic__max_panes-9.snap
@@ -2,8 +2,18 @@
source: src/tests/integration/basic.rs
expression: snapshot
---
-line11-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb│█
-line12-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb│
+line17-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa│line11-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa│line12-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
+a │line13-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
+line18-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa│line14-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa│line15-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
+a │line16-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
+line19-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa│line17-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa│line18-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
+a │line19-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
+prompt $ │prompt $
+────────────────────────────────────────────────────────────┼────────────────────────────────────────────────────────────
+line12-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb│█
line13-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb│
line14-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb│
line15-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb│
@@ -12,13 +22,3 @@ line17-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb│
line18-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb│
line19-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb│
prompt $ │
-────────────────────────────────────────────────────────────┼────────────────────────────────────────────────────────────
-line12-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb│line12-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
-line13-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb│line13-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
-line14-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb│line14-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
-line15-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb│line15-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
-line16-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb│line16-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
-line17-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb│line17-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
-line18-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb│line18-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
-line19-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb│line19-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
-prompt $ │prompt $