* fix(ui): react to terminal window size changes (SIGWINCH) (#245)
* fix(ui): react to terminal window size changes (SIGWINCH) * style(fmt): rustfmt * style(format): remove some warnings * style(fmt): rustfmt
This commit is contained in:
parent
9cb2b727cb
commit
1739f370f9
24 changed files with 1007 additions and 57 deletions
14
Cargo.lock
generated
14
Cargo.lock
generated
|
|
@ -130,7 +130,7 @@ dependencies = [
|
||||||
"event-listener",
|
"event-listener",
|
||||||
"futures-lite",
|
"futures-lite",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"signal-hook 0.3.6",
|
"signal-hook",
|
||||||
"winapi",
|
"winapi",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
@ -1414,16 +1414,6 @@ dependencies = [
|
||||||
"yaml-rust",
|
"yaml-rust",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "signal-hook"
|
|
||||||
version = "0.1.17"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "7e31d442c16f047a671b5a71e2161d6e68814012b7f5379d269ebd915fac2729"
|
|
||||||
dependencies = [
|
|
||||||
"libc",
|
|
||||||
"signal-hook-registry",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "signal-hook"
|
name = "signal-hook"
|
||||||
version = "0.3.6"
|
version = "0.3.6"
|
||||||
|
|
@ -2259,7 +2249,7 @@ dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"serde_yaml",
|
"serde_yaml",
|
||||||
"signal-hook 0.1.17",
|
"signal-hook",
|
||||||
"strip-ansi-escapes",
|
"strip-ansi-escapes",
|
||||||
"structopt",
|
"structopt",
|
||||||
"strum",
|
"strum",
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ nom = "6.0.1"
|
||||||
serde = { version = "1.0", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
serde_json = "1.0"
|
serde_json = "1.0"
|
||||||
serde_yaml = "0.8"
|
serde_yaml = "0.8"
|
||||||
signal-hook = "0.1.10"
|
signal-hook = "0.3"
|
||||||
strip-ansi-escapes = "0.1.0"
|
strip-ansi-escapes = "0.1.0"
|
||||||
structopt = "0.3"
|
structopt = "0.3"
|
||||||
termion = "1.5.0"
|
termion = "1.5.0"
|
||||||
|
|
|
||||||
|
|
@ -99,7 +99,7 @@ fn unselected_mode_shortcut(letter: char, text: &str) -> LinePart {
|
||||||
suffix_separator,
|
suffix_separator,
|
||||||
])
|
])
|
||||||
.to_string(),
|
.to_string(),
|
||||||
len: text.chars().count() + 6, // 2 for the arrows, 3 for the char separators, 1 for the character
|
len: text.chars().count() + 7, // 2 for the arrows, 3 for the char separators, 1 for the character, 1 for the text padding
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -129,7 +129,7 @@ fn selected_mode_shortcut(letter: char, text: &str) -> LinePart {
|
||||||
suffix_separator,
|
suffix_separator,
|
||||||
])
|
])
|
||||||
.to_string(),
|
.to_string(),
|
||||||
len: text.chars().count() + 6, // 2 for the arrows, 3 for the char separators, 1 for the character
|
len: text.chars().count() + 7, // 2 for the arrows, 3 for the char separators, 1 for the character, 1 for the text padding
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
pub mod boundaries;
|
pub mod boundaries;
|
||||||
pub mod layout;
|
pub mod layout;
|
||||||
|
pub mod pane_resizer;
|
||||||
pub mod panes;
|
pub mod panes;
|
||||||
pub mod tab;
|
pub mod tab;
|
||||||
|
|
||||||
|
|
|
||||||
508
src/client/pane_resizer.rs
Normal file
508
src/client/pane_resizer.rs
Normal file
|
|
@ -0,0 +1,508 @@
|
||||||
|
use crate::os_input_output::OsApi;
|
||||||
|
use crate::panes::{PaneId, PositionAndSize};
|
||||||
|
use crate::tab::Pane;
|
||||||
|
use std::collections::{BTreeMap, HashSet};
|
||||||
|
|
||||||
|
pub struct PaneResizer<'a> {
|
||||||
|
panes: &'a mut BTreeMap<PaneId, Box<dyn Pane>>,
|
||||||
|
os_api: &'a mut Box<dyn OsApi>,
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: currently there are some functions here duplicated with Tab
|
||||||
|
// the reason for this is that we need to get rid of the expansion_boundary
|
||||||
|
// otherwise we'll have a big separation of concerns issue
|
||||||
|
// once that is done, all resizing functions should move here
|
||||||
|
|
||||||
|
impl<'a> PaneResizer<'a> {
|
||||||
|
pub fn new(
|
||||||
|
panes: &'a mut BTreeMap<PaneId, Box<dyn Pane>>,
|
||||||
|
os_api: &'a mut Box<dyn OsApi>,
|
||||||
|
) -> Self {
|
||||||
|
PaneResizer { panes, os_api }
|
||||||
|
}
|
||||||
|
pub fn resize(
|
||||||
|
&mut self,
|
||||||
|
mut current_size: PositionAndSize,
|
||||||
|
new_size: PositionAndSize,
|
||||||
|
) -> Option<(isize, isize)> {
|
||||||
|
// (column_difference, row_difference)
|
||||||
|
let mut successfully_resized = false;
|
||||||
|
let mut column_difference: isize = 0;
|
||||||
|
let mut row_difference: isize = 0;
|
||||||
|
if new_size.columns < current_size.columns {
|
||||||
|
let reduce_by = current_size.columns - new_size.columns;
|
||||||
|
find_reducible_vertical_chain(
|
||||||
|
&self.panes,
|
||||||
|
reduce_by,
|
||||||
|
current_size.columns,
|
||||||
|
current_size.rows,
|
||||||
|
)
|
||||||
|
.map(|panes_to_resize| {
|
||||||
|
self.reduce_panes_left_and_pull_adjacents_left(panes_to_resize, reduce_by);
|
||||||
|
column_difference = new_size.columns as isize - current_size.columns as isize;
|
||||||
|
current_size.columns = (current_size.columns as isize + column_difference) as usize;
|
||||||
|
successfully_resized = true;
|
||||||
|
});
|
||||||
|
} else if new_size.columns > current_size.columns {
|
||||||
|
let increase_by = new_size.columns - current_size.columns;
|
||||||
|
find_increasable_vertical_chain(
|
||||||
|
&self.panes,
|
||||||
|
increase_by,
|
||||||
|
current_size.columns,
|
||||||
|
current_size.rows,
|
||||||
|
)
|
||||||
|
.map(|panes_to_resize| {
|
||||||
|
self.increase_panes_right_and_push_adjacents_right(panes_to_resize, increase_by);
|
||||||
|
column_difference = new_size.columns as isize - current_size.columns as isize;
|
||||||
|
current_size.columns = (current_size.columns as isize + column_difference) as usize;
|
||||||
|
successfully_resized = true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if new_size.rows < current_size.rows {
|
||||||
|
let reduce_by = current_size.rows - new_size.rows;
|
||||||
|
find_reducible_horizontal_chain(
|
||||||
|
&self.panes,
|
||||||
|
reduce_by,
|
||||||
|
current_size.columns,
|
||||||
|
current_size.rows,
|
||||||
|
)
|
||||||
|
.map(|panes_to_resize| {
|
||||||
|
self.reduce_panes_up_and_pull_adjacents_up(panes_to_resize, reduce_by);
|
||||||
|
row_difference = new_size.rows as isize - current_size.rows as isize;
|
||||||
|
current_size.rows = (current_size.rows as isize + row_difference) as usize;
|
||||||
|
successfully_resized = true;
|
||||||
|
});
|
||||||
|
} else if new_size.rows > current_size.rows {
|
||||||
|
let increase_by = new_size.rows - current_size.rows;
|
||||||
|
find_increasable_horizontal_chain(
|
||||||
|
&self.panes,
|
||||||
|
increase_by,
|
||||||
|
current_size.columns,
|
||||||
|
current_size.rows,
|
||||||
|
)
|
||||||
|
.map(|panes_to_resize| {
|
||||||
|
self.increase_panes_down_and_push_down_adjacents(panes_to_resize, increase_by);
|
||||||
|
row_difference = new_size.rows as isize - current_size.rows as isize;
|
||||||
|
current_size.rows = (current_size.rows as isize + row_difference) as usize;
|
||||||
|
successfully_resized = true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if successfully_resized {
|
||||||
|
Some((column_difference, row_difference))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn reduce_panes_left_and_pull_adjacents_left(
|
||||||
|
&mut self,
|
||||||
|
panes_to_reduce: Vec<PaneId>,
|
||||||
|
reduce_by: usize,
|
||||||
|
) {
|
||||||
|
let mut pulled_panes: HashSet<PaneId> = HashSet::new();
|
||||||
|
for pane_id in panes_to_reduce {
|
||||||
|
let (pane_x, pane_y, pane_columns, pane_rows) = {
|
||||||
|
let pane = self.panes.get(&pane_id).unwrap();
|
||||||
|
(pane.x(), pane.y(), pane.columns(), pane.rows())
|
||||||
|
};
|
||||||
|
let panes_to_pull = self.panes.values_mut().filter(|p| {
|
||||||
|
p.x() > pane_x + pane_columns
|
||||||
|
&& (p.y() <= pane_y && p.y() + p.rows() >= pane_y
|
||||||
|
|| p.y() >= pane_y && p.y() + p.rows() <= pane_y + pane_rows)
|
||||||
|
});
|
||||||
|
for pane in panes_to_pull {
|
||||||
|
if !pulled_panes.contains(&pane.pid()) {
|
||||||
|
pane.pull_left(reduce_by);
|
||||||
|
pulled_panes.insert(pane.pid());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.reduce_pane_width_left(&pane_id, reduce_by);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn reduce_panes_up_and_pull_adjacents_up(
|
||||||
|
&mut self,
|
||||||
|
panes_to_reduce: Vec<PaneId>,
|
||||||
|
reduce_by: usize,
|
||||||
|
) {
|
||||||
|
let mut pulled_panes: HashSet<PaneId> = HashSet::new();
|
||||||
|
for pane_id in panes_to_reduce {
|
||||||
|
let (pane_x, pane_y, pane_columns, pane_rows) = {
|
||||||
|
let pane = self.panes.get(&pane_id).unwrap();
|
||||||
|
(pane.x(), pane.y(), pane.columns(), pane.rows())
|
||||||
|
};
|
||||||
|
let panes_to_pull = self.panes.values_mut().filter(|p| {
|
||||||
|
p.y() > pane_y + pane_rows
|
||||||
|
&& (p.x() <= pane_x && p.x() + p.columns() >= pane_x
|
||||||
|
|| p.x() >= pane_x && p.x() + p.columns() <= pane_x + pane_columns)
|
||||||
|
});
|
||||||
|
for pane in panes_to_pull {
|
||||||
|
if !pulled_panes.contains(&pane.pid()) {
|
||||||
|
pane.pull_up(reduce_by);
|
||||||
|
pulled_panes.insert(pane.pid());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.reduce_pane_height_up(&pane_id, reduce_by);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn increase_panes_down_and_push_down_adjacents(
|
||||||
|
&mut self,
|
||||||
|
panes_to_increase: Vec<PaneId>,
|
||||||
|
increase_by: usize,
|
||||||
|
) {
|
||||||
|
let mut pushed_panes: HashSet<PaneId> = HashSet::new();
|
||||||
|
for pane_id in panes_to_increase {
|
||||||
|
let (pane_x, pane_y, pane_columns, pane_rows) = {
|
||||||
|
let pane = self.panes.get(&pane_id).unwrap();
|
||||||
|
(pane.x(), pane.y(), pane.columns(), pane.rows())
|
||||||
|
};
|
||||||
|
let panes_to_push = self.panes.values_mut().filter(|p| {
|
||||||
|
p.y() > pane_y + pane_rows
|
||||||
|
&& (p.x() <= pane_x && p.x() + p.columns() >= pane_x
|
||||||
|
|| p.x() >= pane_x && p.x() + p.columns() <= pane_x + pane_columns)
|
||||||
|
});
|
||||||
|
for pane in panes_to_push {
|
||||||
|
if !pushed_panes.contains(&pane.pid()) {
|
||||||
|
pane.push_down(increase_by);
|
||||||
|
pushed_panes.insert(pane.pid());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.increase_pane_height_down(&pane_id, increase_by);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn increase_panes_right_and_push_adjacents_right(
|
||||||
|
&mut self,
|
||||||
|
panes_to_increase: Vec<PaneId>,
|
||||||
|
increase_by: usize,
|
||||||
|
) {
|
||||||
|
let mut pushed_panes: HashSet<PaneId> = HashSet::new();
|
||||||
|
for pane_id in panes_to_increase {
|
||||||
|
let (pane_x, pane_y, pane_columns, pane_rows) = {
|
||||||
|
let pane = self.panes.get(&pane_id).unwrap();
|
||||||
|
(pane.x(), pane.y(), pane.columns(), pane.rows())
|
||||||
|
};
|
||||||
|
let panes_to_push = self.panes.values_mut().filter(|p| {
|
||||||
|
p.x() > pane_x + pane_columns
|
||||||
|
&& (p.y() <= pane_y && p.y() + p.rows() >= pane_y
|
||||||
|
|| p.y() >= pane_y && p.y() + p.rows() <= pane_y + pane_rows)
|
||||||
|
});
|
||||||
|
for pane in panes_to_push {
|
||||||
|
if !pushed_panes.contains(&pane.pid()) {
|
||||||
|
pane.push_right(increase_by);
|
||||||
|
pushed_panes.insert(pane.pid());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.increase_pane_width_right(&pane_id, increase_by);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn reduce_pane_height_up(&mut self, id: &PaneId, count: usize) {
|
||||||
|
let pane = self.panes.get_mut(id).unwrap();
|
||||||
|
pane.reduce_height_up(count);
|
||||||
|
if let PaneId::Terminal(pid) = id {
|
||||||
|
self.os_api
|
||||||
|
.set_terminal_size_using_fd(*pid, pane.columns() as u16, pane.rows() as u16);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn increase_pane_height_down(&mut self, id: &PaneId, count: usize) {
|
||||||
|
let pane = self.panes.get_mut(id).unwrap();
|
||||||
|
pane.increase_height_down(count);
|
||||||
|
if let PaneId::Terminal(pid) = pane.pid() {
|
||||||
|
self.os_api
|
||||||
|
.set_terminal_size_using_fd(pid, pane.columns() as u16, pane.rows() as u16);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn increase_pane_width_right(&mut self, id: &PaneId, count: usize) {
|
||||||
|
let pane = self.panes.get_mut(id).unwrap();
|
||||||
|
pane.increase_width_right(count);
|
||||||
|
if let PaneId::Terminal(pid) = pane.pid() {
|
||||||
|
self.os_api
|
||||||
|
.set_terminal_size_using_fd(pid, pane.columns() as u16, pane.rows() as u16);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn reduce_pane_width_left(&mut self, id: &PaneId, count: usize) {
|
||||||
|
let pane = self.panes.get_mut(id).unwrap();
|
||||||
|
pane.reduce_width_left(count);
|
||||||
|
if let PaneId::Terminal(pid) = pane.pid() {
|
||||||
|
self.os_api
|
||||||
|
.set_terminal_size_using_fd(pid, pane.columns() as u16, pane.rows() as u16);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn find_next_increasable_horizontal_pane(
|
||||||
|
panes: &BTreeMap<PaneId, Box<dyn Pane>>,
|
||||||
|
right_of: &Box<dyn Pane>,
|
||||||
|
increase_by: usize,
|
||||||
|
) -> Option<PaneId> {
|
||||||
|
let next_pane_candidates = panes.values().filter(
|
||||||
|
|p| {
|
||||||
|
p.x() == right_of.x() + right_of.columns() + 1
|
||||||
|
&& p.horizontally_overlaps_with(right_of.as_ref())
|
||||||
|
}, // TODO: the name here is wrong, it should be vertically_overlaps_with
|
||||||
|
);
|
||||||
|
let resizable_candidates =
|
||||||
|
next_pane_candidates.filter(|p| p.can_increase_height_by(increase_by));
|
||||||
|
resizable_candidates.fold(None, |next_pane_id, p| match next_pane_id {
|
||||||
|
Some(next_pane) => {
|
||||||
|
let next_pane = panes.get(&next_pane).unwrap();
|
||||||
|
if next_pane.y() < p.y() {
|
||||||
|
next_pane_id
|
||||||
|
} else {
|
||||||
|
Some(p.pid())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => Some(p.pid()),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn find_next_increasable_vertical_pane(
|
||||||
|
panes: &BTreeMap<PaneId, Box<dyn Pane>>,
|
||||||
|
below: &Box<dyn Pane>,
|
||||||
|
increase_by: usize,
|
||||||
|
) -> Option<PaneId> {
|
||||||
|
let next_pane_candidates = panes.values().filter(
|
||||||
|
|p| p.y() == below.y() + below.rows() + 1 && p.vertically_overlaps_with(below.as_ref()), // TODO: the name here is wrong, it should be horizontally_overlaps_with
|
||||||
|
);
|
||||||
|
let resizable_candidates =
|
||||||
|
next_pane_candidates.filter(|p| p.can_increase_width_by(increase_by));
|
||||||
|
resizable_candidates.fold(None, |next_pane_id, p| match next_pane_id {
|
||||||
|
Some(next_pane) => {
|
||||||
|
let next_pane = panes.get(&next_pane).unwrap();
|
||||||
|
if next_pane.x() < p.x() {
|
||||||
|
next_pane_id
|
||||||
|
} else {
|
||||||
|
Some(p.pid())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => Some(p.pid()),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn find_next_reducible_vertical_pane(
|
||||||
|
panes: &BTreeMap<PaneId, Box<dyn Pane>>,
|
||||||
|
below: &Box<dyn Pane>,
|
||||||
|
reduce_by: usize,
|
||||||
|
) -> Option<PaneId> {
|
||||||
|
let next_pane_candidates = panes.values().filter(
|
||||||
|
|p| p.y() == below.y() + below.rows() + 1 && p.vertically_overlaps_with(below.as_ref()), // TODO: the name here is wrong, it should be horizontally_overlaps_with
|
||||||
|
);
|
||||||
|
let resizable_candidates = next_pane_candidates.filter(|p| p.can_reduce_width_by(reduce_by));
|
||||||
|
resizable_candidates.fold(None, |next_pane_id, p| match next_pane_id {
|
||||||
|
Some(next_pane) => {
|
||||||
|
let next_pane = panes.get(&next_pane).unwrap();
|
||||||
|
if next_pane.x() < p.x() {
|
||||||
|
next_pane_id
|
||||||
|
} else {
|
||||||
|
Some(p.pid())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => Some(p.pid()),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn find_next_reducible_horizontal_pane(
|
||||||
|
panes: &BTreeMap<PaneId, Box<dyn Pane>>,
|
||||||
|
right_of: &Box<dyn Pane>,
|
||||||
|
reduce_by: usize,
|
||||||
|
) -> Option<PaneId> {
|
||||||
|
let next_pane_candidates = panes.values().filter(
|
||||||
|
|p| {
|
||||||
|
p.x() == right_of.x() + right_of.columns() + 1
|
||||||
|
&& p.horizontally_overlaps_with(right_of.as_ref())
|
||||||
|
}, // TODO: the name here is wrong, it should be vertically_overlaps_with
|
||||||
|
);
|
||||||
|
let resizable_candidates = next_pane_candidates.filter(|p| p.can_reduce_height_by(reduce_by));
|
||||||
|
resizable_candidates.fold(None, |next_pane_id, p| match next_pane_id {
|
||||||
|
Some(next_pane) => {
|
||||||
|
let next_pane = panes.get(&next_pane).unwrap();
|
||||||
|
if next_pane.y() < p.y() {
|
||||||
|
next_pane_id
|
||||||
|
} else {
|
||||||
|
Some(p.pid())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => Some(p.pid()),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn find_increasable_horizontal_chain(
|
||||||
|
panes: &BTreeMap<PaneId, Box<dyn Pane>>,
|
||||||
|
increase_by: usize,
|
||||||
|
screen_width: usize,
|
||||||
|
screen_height: usize, // TODO: this is the previous size (make this clearer)
|
||||||
|
) -> Option<Vec<PaneId>> {
|
||||||
|
let mut horizontal_coordinate = 0;
|
||||||
|
loop {
|
||||||
|
if horizontal_coordinate == screen_height {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
match panes
|
||||||
|
.values()
|
||||||
|
.find(|p| p.x() == 0 && p.y() == horizontal_coordinate)
|
||||||
|
{
|
||||||
|
Some(leftmost_pane) => {
|
||||||
|
if !leftmost_pane.can_increase_height_by(increase_by) {
|
||||||
|
horizontal_coordinate = leftmost_pane.y() + leftmost_pane.rows() + 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let mut panes_to_resize = vec![];
|
||||||
|
let mut current_pane = leftmost_pane;
|
||||||
|
loop {
|
||||||
|
panes_to_resize.push(current_pane.pid());
|
||||||
|
if current_pane.x() + current_pane.columns() == screen_width {
|
||||||
|
return Some(panes_to_resize);
|
||||||
|
}
|
||||||
|
match find_next_increasable_horizontal_pane(panes, ¤t_pane, increase_by) {
|
||||||
|
Some(next_pane_id) => {
|
||||||
|
current_pane = panes.get(&next_pane_id).unwrap();
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
horizontal_coordinate = leftmost_pane.y() + leftmost_pane.rows() + 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn find_increasable_vertical_chain(
|
||||||
|
panes: &BTreeMap<PaneId, Box<dyn Pane>>,
|
||||||
|
increase_by: usize,
|
||||||
|
screen_width: usize,
|
||||||
|
screen_height: usize, // TODO: this is the previous size (make this clearer)
|
||||||
|
) -> Option<Vec<PaneId>> {
|
||||||
|
let mut vertical_coordinate = 0;
|
||||||
|
loop {
|
||||||
|
if vertical_coordinate == screen_width {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
match panes
|
||||||
|
.values()
|
||||||
|
.find(|p| p.y() == 0 && p.x() == vertical_coordinate)
|
||||||
|
{
|
||||||
|
Some(topmost_pane) => {
|
||||||
|
if !topmost_pane.can_increase_width_by(increase_by) {
|
||||||
|
vertical_coordinate = topmost_pane.x() + topmost_pane.columns() + 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let mut panes_to_resize = vec![];
|
||||||
|
let mut current_pane = topmost_pane;
|
||||||
|
loop {
|
||||||
|
panes_to_resize.push(current_pane.pid());
|
||||||
|
if current_pane.y() + current_pane.rows() == screen_height {
|
||||||
|
return Some(panes_to_resize);
|
||||||
|
}
|
||||||
|
match find_next_increasable_vertical_pane(panes, ¤t_pane, increase_by) {
|
||||||
|
Some(next_pane_id) => {
|
||||||
|
current_pane = panes.get(&next_pane_id).unwrap();
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
vertical_coordinate = topmost_pane.x() + topmost_pane.columns() + 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn find_reducible_horizontal_chain(
|
||||||
|
panes: &BTreeMap<PaneId, Box<dyn Pane>>,
|
||||||
|
reduce_by: usize,
|
||||||
|
screen_width: usize,
|
||||||
|
screen_height: usize, // TODO: this is the previous size (make this clearer)
|
||||||
|
) -> Option<Vec<PaneId>> {
|
||||||
|
let mut horizontal_coordinate = 0;
|
||||||
|
loop {
|
||||||
|
if horizontal_coordinate == screen_height {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
match panes
|
||||||
|
.values()
|
||||||
|
.find(|p| p.x() == 0 && p.y() == horizontal_coordinate)
|
||||||
|
{
|
||||||
|
Some(leftmost_pane) => {
|
||||||
|
if !leftmost_pane.can_reduce_height_by(reduce_by) {
|
||||||
|
horizontal_coordinate = leftmost_pane.y() + leftmost_pane.rows() + 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let mut panes_to_resize = vec![];
|
||||||
|
let mut current_pane = leftmost_pane;
|
||||||
|
loop {
|
||||||
|
panes_to_resize.push(current_pane.pid());
|
||||||
|
if current_pane.x() + current_pane.columns() == screen_width {
|
||||||
|
return Some(panes_to_resize);
|
||||||
|
}
|
||||||
|
match find_next_reducible_horizontal_pane(panes, ¤t_pane, reduce_by) {
|
||||||
|
Some(next_pane_id) => {
|
||||||
|
current_pane = panes.get(&next_pane_id).unwrap();
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
horizontal_coordinate = leftmost_pane.y() + leftmost_pane.rows() + 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn find_reducible_vertical_chain(
|
||||||
|
panes: &BTreeMap<PaneId, Box<dyn Pane>>,
|
||||||
|
increase_by: usize,
|
||||||
|
screen_width: usize,
|
||||||
|
screen_height: usize, // TODO: this is the previous size (make this clearer)
|
||||||
|
) -> Option<Vec<PaneId>> {
|
||||||
|
let mut vertical_coordinate = 0;
|
||||||
|
loop {
|
||||||
|
if vertical_coordinate == screen_width {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
match panes
|
||||||
|
.values()
|
||||||
|
.find(|p| p.y() == 0 && p.x() == vertical_coordinate)
|
||||||
|
{
|
||||||
|
Some(topmost_pane) => {
|
||||||
|
if !topmost_pane.can_reduce_width_by(increase_by) {
|
||||||
|
vertical_coordinate = topmost_pane.x() + topmost_pane.columns() + 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let mut panes_to_resize = vec![];
|
||||||
|
let mut current_pane = topmost_pane;
|
||||||
|
loop {
|
||||||
|
panes_to_resize.push(current_pane.pid());
|
||||||
|
if current_pane.y() + current_pane.rows() == screen_height {
|
||||||
|
return Some(panes_to_resize);
|
||||||
|
}
|
||||||
|
match find_next_reducible_vertical_pane(panes, ¤t_pane, increase_by) {
|
||||||
|
Some(next_pane_id) => {
|
||||||
|
current_pane = panes.get(&next_pane_id).unwrap();
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
vertical_coordinate = topmost_pane.x() + topmost_pane.columns() + 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -173,6 +173,18 @@ impl Pane for PluginPane {
|
||||||
self.position_and_size.columns += count;
|
self.position_and_size.columns += count;
|
||||||
self.should_render = true;
|
self.should_render = true;
|
||||||
}
|
}
|
||||||
|
fn push_down(&mut self, count: usize) {
|
||||||
|
self.position_and_size.y += count;
|
||||||
|
}
|
||||||
|
fn push_right(&mut self, count: usize) {
|
||||||
|
self.position_and_size.x += count;
|
||||||
|
}
|
||||||
|
fn pull_left(&mut self, count: usize) {
|
||||||
|
self.position_and_size.x -= count;
|
||||||
|
}
|
||||||
|
fn pull_up(&mut self, count: usize) {
|
||||||
|
self.position_and_size.y -= count;
|
||||||
|
}
|
||||||
fn scroll_up(&mut self, _count: usize) {
|
fn scroll_up(&mut self, _count: usize) {
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -282,6 +282,18 @@ impl Pane for TerminalPane {
|
||||||
self.position_and_size.columns += count;
|
self.position_and_size.columns += count;
|
||||||
self.reflow_lines();
|
self.reflow_lines();
|
||||||
}
|
}
|
||||||
|
fn push_down(&mut self, count: usize) {
|
||||||
|
self.position_and_size.y += count;
|
||||||
|
}
|
||||||
|
fn push_right(&mut self, count: usize) {
|
||||||
|
self.position_and_size.x += count;
|
||||||
|
}
|
||||||
|
fn pull_left(&mut self, count: usize) {
|
||||||
|
self.position_and_size.x -= count;
|
||||||
|
}
|
||||||
|
fn pull_up(&mut self, count: usize) {
|
||||||
|
self.position_and_size.y -= count;
|
||||||
|
}
|
||||||
fn scroll_up(&mut self, count: usize) {
|
fn scroll_up(&mut self, count: usize) {
|
||||||
self.grid.move_viewport_up(count);
|
self.grid.move_viewport_up(count);
|
||||||
self.mark_for_rerender();
|
self.mark_for_rerender();
|
||||||
|
|
|
||||||
|
|
@ -2,13 +2,16 @@
|
||||||
//! as well as how they should be resized
|
//! as well as how they should be resized
|
||||||
|
|
||||||
use crate::boundaries::colors;
|
use crate::boundaries::colors;
|
||||||
|
use crate::client::pane_resizer::PaneResizer;
|
||||||
use crate::common::{input::handler::parse_keys, AppInstruction, SenderWithContext};
|
use crate::common::{input::handler::parse_keys, AppInstruction, SenderWithContext};
|
||||||
use crate::layout::Layout;
|
use crate::layout::Layout;
|
||||||
|
use crate::os_input_output::OsApi;
|
||||||
use crate::panes::{PaneId, PositionAndSize, TerminalPane};
|
use crate::panes::{PaneId, PositionAndSize, TerminalPane};
|
||||||
use crate::pty_bus::{PtyInstruction, VteEvent};
|
use crate::pty_bus::{PtyInstruction, VteEvent};
|
||||||
|
use crate::utils::shared::adjust_to_size;
|
||||||
use crate::wasm_vm::PluginInstruction;
|
use crate::wasm_vm::PluginInstruction;
|
||||||
use crate::{boundaries::Boundaries, panes::PluginPane};
|
use crate::{boundaries::Boundaries, panes::PluginPane};
|
||||||
use crate::{os_input_output::OsApi, utils::shared::pad_to_size};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::os::unix::io::RawFd;
|
use std::os::unix::io::RawFd;
|
||||||
use std::{
|
use std::{
|
||||||
cmp::Reverse,
|
cmp::Reverse,
|
||||||
|
|
@ -66,6 +69,16 @@ pub struct Tab {
|
||||||
pub send_plugin_instructions: SenderWithContext<PluginInstruction>,
|
pub send_plugin_instructions: SenderWithContext<PluginInstruction>,
|
||||||
pub send_app_instructions: SenderWithContext<AppInstruction>,
|
pub send_app_instructions: SenderWithContext<AppInstruction>,
|
||||||
expansion_boundary: Option<PositionAndSize>,
|
expansion_boundary: Option<PositionAndSize>,
|
||||||
|
should_clear_display_before_rendering: bool,
|
||||||
|
pub mode_info: ModeInfo,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
|
||||||
|
pub struct TabData {
|
||||||
|
/* subset of fields to publish to plugins */
|
||||||
|
pub position: usize,
|
||||||
|
pub name: String,
|
||||||
|
pub active: bool,
|
||||||
pub mode_info: ModeInfo,
|
pub mode_info: ModeInfo,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -99,6 +112,10 @@ pub trait Pane {
|
||||||
fn reduce_width_right(&mut self, count: usize);
|
fn reduce_width_right(&mut self, count: usize);
|
||||||
fn reduce_width_left(&mut self, count: usize);
|
fn reduce_width_left(&mut self, count: usize);
|
||||||
fn increase_width_left(&mut self, count: usize);
|
fn increase_width_left(&mut self, count: usize);
|
||||||
|
fn push_down(&mut self, count: usize);
|
||||||
|
fn push_right(&mut self, count: usize);
|
||||||
|
fn pull_left(&mut self, count: usize);
|
||||||
|
fn pull_up(&mut self, count: usize);
|
||||||
fn scroll_up(&mut self, count: usize);
|
fn scroll_up(&mut self, count: usize);
|
||||||
fn scroll_down(&mut self, count: usize);
|
fn scroll_down(&mut self, count: usize);
|
||||||
fn clear_scroll(&mut self);
|
fn clear_scroll(&mut self);
|
||||||
|
|
@ -153,6 +170,22 @@ pub trait Pane {
|
||||||
rows: self.rows(),
|
rows: self.rows(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
fn can_increase_height_by(&self, increase_by: usize) -> bool {
|
||||||
|
self.max_height()
|
||||||
|
.map(|max_height| self.rows() + increase_by <= max_height)
|
||||||
|
.unwrap_or(true)
|
||||||
|
}
|
||||||
|
fn can_increase_width_by(&self, increase_by: usize) -> bool {
|
||||||
|
self.max_width()
|
||||||
|
.map(|max_width| self.columns() + increase_by <= max_width)
|
||||||
|
.unwrap_or(true)
|
||||||
|
}
|
||||||
|
fn can_reduce_height_by(&self, reduce_by: usize) -> bool {
|
||||||
|
self.rows() > reduce_by && self.rows() - reduce_by >= self.min_height()
|
||||||
|
}
|
||||||
|
fn can_reduce_width_by(&self, reduce_by: usize) -> bool {
|
||||||
|
self.columns() > reduce_by && self.columns() - reduce_by >= self.min_width()
|
||||||
|
}
|
||||||
fn min_width(&self) -> usize {
|
fn min_width(&self) -> usize {
|
||||||
MIN_TERMINAL_WIDTH
|
MIN_TERMINAL_WIDTH
|
||||||
}
|
}
|
||||||
|
|
@ -213,6 +246,7 @@ impl Tab {
|
||||||
send_pty_instructions,
|
send_pty_instructions,
|
||||||
send_plugin_instructions,
|
send_plugin_instructions,
|
||||||
expansion_boundary: None,
|
expansion_boundary: None,
|
||||||
|
should_clear_display_before_rendering: false,
|
||||||
mode_info,
|
mode_info,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -630,28 +664,33 @@ impl Tab {
|
||||||
stdout
|
stdout
|
||||||
.write_all(&hide_cursor.as_bytes())
|
.write_all(&hide_cursor.as_bytes())
|
||||||
.expect("cannot write to stdout");
|
.expect("cannot write to stdout");
|
||||||
for (kind, terminal) in self.panes.iter_mut() {
|
if self.should_clear_display_before_rendering {
|
||||||
if !self.panes_to_hide.contains(&terminal.pid()) {
|
let clear_display = "\u{1b}[2J";
|
||||||
match self.active_terminal.unwrap() == terminal.pid() {
|
stdout
|
||||||
true => boundaries.add_rect(
|
.write_all(&clear_display.as_bytes())
|
||||||
terminal.as_ref(),
|
.expect("cannot write to stdout");
|
||||||
self.mode_info.mode,
|
self.should_clear_display_before_rendering = false;
|
||||||
Some(colors::GREEN),
|
|
||||||
),
|
|
||||||
false => boundaries.add_rect(terminal.as_ref(), self.mode_info.mode, None),
|
|
||||||
}
|
}
|
||||||
if let Some(vte_output) = terminal.render() {
|
for (kind, pane) in self.panes.iter_mut() {
|
||||||
|
if !self.panes_to_hide.contains(&pane.pid()) {
|
||||||
|
match self.active_terminal.unwrap() == pane.pid() {
|
||||||
|
true => {
|
||||||
|
boundaries.add_rect(pane.as_ref(), self.mode_info.mode, Some(colors::GREEN))
|
||||||
|
}
|
||||||
|
false => boundaries.add_rect(pane.as_ref(), self.mode_info.mode, None),
|
||||||
|
}
|
||||||
|
if let Some(vte_output) = pane.render() {
|
||||||
let vte_output = if let PaneId::Terminal(_) = kind {
|
let vte_output = if let PaneId::Terminal(_) = kind {
|
||||||
vte_output
|
vte_output
|
||||||
} else {
|
} else {
|
||||||
pad_to_size(&vte_output, terminal.rows(), terminal.columns())
|
adjust_to_size(&vte_output, pane.rows(), pane.columns())
|
||||||
};
|
};
|
||||||
// FIXME: Use Termion for cursor and style clearing?
|
// FIXME: Use Termion for cursor and style clearing?
|
||||||
write!(
|
write!(
|
||||||
stdout,
|
stdout,
|
||||||
"\u{1b}[{};{}H\u{1b}[m{}",
|
"\u{1b}[{};{}H\u{1b}[m{}",
|
||||||
terminal.y() + 1,
|
pane.y() + 1,
|
||||||
terminal.x() + 1,
|
pane.x() + 1,
|
||||||
vte_output
|
vte_output
|
||||||
)
|
)
|
||||||
.expect("cannot write to stdout");
|
.expect("cannot write to stdout");
|
||||||
|
|
@ -1664,17 +1703,30 @@ impl Tab {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn resize_right(&mut self) {
|
pub fn resize_whole_tab(&mut self, new_screen_size: PositionAndSize) {
|
||||||
// TODO: find out by how much we actually reduced and only reduce by that much
|
if self.fullscreen_is_active {
|
||||||
let count = 10;
|
// this is not ideal but until we get rid of expansion_boundary, it's a necessity
|
||||||
if let Some(active_pane_id) = self.get_active_pane_id() {
|
self.toggle_active_pane_fullscreen();
|
||||||
if self.can_increase_pane_and_surroundings_right(&active_pane_id, count) {
|
|
||||||
self.increase_pane_and_surroundings_right(&active_pane_id, count);
|
|
||||||
} else if self.can_reduce_pane_and_surroundings_right(&active_pane_id, count) {
|
|
||||||
self.reduce_pane_and_surroundings_right(&active_pane_id, count);
|
|
||||||
}
|
}
|
||||||
|
match PaneResizer::new(&mut self.panes, &mut self.os_api)
|
||||||
|
.resize(self.full_screen_ws, new_screen_size)
|
||||||
|
{
|
||||||
|
Some((column_difference, row_difference)) => {
|
||||||
|
self.should_clear_display_before_rendering = true;
|
||||||
|
self.expansion_boundary.as_mut().map(|expansion_boundary| {
|
||||||
|
// TODO: this is not always accurate
|
||||||
|
expansion_boundary.columns =
|
||||||
|
(expansion_boundary.columns as isize + column_difference) as usize;
|
||||||
|
expansion_boundary.rows =
|
||||||
|
(expansion_boundary.rows as isize + row_difference) as usize;
|
||||||
|
});
|
||||||
|
self.full_screen_ws.columns =
|
||||||
|
(self.full_screen_ws.columns as isize + column_difference) as usize;
|
||||||
|
self.full_screen_ws.rows =
|
||||||
|
(self.full_screen_ws.rows as isize + row_difference) as usize;
|
||||||
}
|
}
|
||||||
self.render();
|
None => {}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
pub fn resize_left(&mut self) {
|
pub fn resize_left(&mut self) {
|
||||||
// TODO: find out by how much we actually reduced and only reduce by that much
|
// TODO: find out by how much we actually reduced and only reduce by that much
|
||||||
|
|
@ -1688,6 +1740,18 @@ impl Tab {
|
||||||
}
|
}
|
||||||
self.render();
|
self.render();
|
||||||
}
|
}
|
||||||
|
pub fn resize_right(&mut self) {
|
||||||
|
// TODO: find out by how much we actually reduced and only reduce by that much
|
||||||
|
let count = 10;
|
||||||
|
if let Some(active_pane_id) = self.get_active_pane_id() {
|
||||||
|
if self.can_increase_pane_and_surroundings_right(&active_pane_id, count) {
|
||||||
|
self.increase_pane_and_surroundings_right(&active_pane_id, count);
|
||||||
|
} else if self.can_reduce_pane_and_surroundings_right(&active_pane_id, count) {
|
||||||
|
self.reduce_pane_and_surroundings_right(&active_pane_id, count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.render();
|
||||||
|
}
|
||||||
pub fn resize_down(&mut self) {
|
pub fn resize_down(&mut self) {
|
||||||
// TODO: find out by how much we actually reduced and only reduce by that much
|
// TODO: find out by how much we actually reduced and only reduce by that much
|
||||||
let count = 2;
|
let count = 2;
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,7 @@ pub fn handle_panic(
|
||||||
msg,
|
msg,
|
||||||
location.file(),
|
location.file(),
|
||||||
location.line(),
|
location.line(),
|
||||||
backtrace
|
backtrace,
|
||||||
),
|
),
|
||||||
(Some(location), None) => format!(
|
(Some(location), None) => format!(
|
||||||
"{}\n\u{1b}[0;0mError: \u{1b}[0;31mthread '{}' panicked: {}:{}\n\u{1b}[0;0m{:?}",
|
"{}\n\u{1b}[0;0mError: \u{1b}[0;31mthread '{}' panicked: {}:{}\n\u{1b}[0;0m{:?}",
|
||||||
|
|
@ -200,6 +200,7 @@ pub enum ScreenContext {
|
||||||
CloseTab,
|
CloseTab,
|
||||||
GoToTab,
|
GoToTab,
|
||||||
UpdateTabName,
|
UpdateTabName,
|
||||||
|
TerminalResize,
|
||||||
ChangeMode,
|
ChangeMode,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -241,6 +242,7 @@ impl From<&ScreenInstruction> for ScreenContext {
|
||||||
ScreenInstruction::CloseTab => ScreenContext::CloseTab,
|
ScreenInstruction::CloseTab => ScreenContext::CloseTab,
|
||||||
ScreenInstruction::GoToTab(_) => ScreenContext::GoToTab,
|
ScreenInstruction::GoToTab(_) => ScreenContext::GoToTab,
|
||||||
ScreenInstruction::UpdateTabName(_) => ScreenContext::UpdateTabName,
|
ScreenInstruction::UpdateTabName(_) => ScreenContext::UpdateTabName,
|
||||||
|
ScreenInstruction::TerminalResize => ScreenContext::TerminalResize,
|
||||||
ScreenInstruction::ChangeMode(_) => ScreenContext::ChangeMode,
|
ScreenInstruction::ChangeMode(_) => ScreenContext::ChangeMode,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -389,6 +389,9 @@ pub fn start(mut os_input: Box<dyn OsApi>, opts: CliArgs) {
|
||||||
ScreenInstruction::UpdateTabName(c) => {
|
ScreenInstruction::UpdateTabName(c) => {
|
||||||
screen.update_active_tab_name(c);
|
screen.update_active_tab_name(c);
|
||||||
}
|
}
|
||||||
|
ScreenInstruction::TerminalResize => {
|
||||||
|
screen.resize_to_screen();
|
||||||
|
}
|
||||||
ScreenInstruction::ChangeMode(mode_info) => {
|
ScreenInstruction::ChangeMode(mode_info) => {
|
||||||
screen.change_mode(mode_info);
|
screen.change_mode(mode_info);
|
||||||
}
|
}
|
||||||
|
|
@ -506,6 +509,19 @@ pub fn start(mut os_input: Box<dyn OsApi>, opts: CliArgs) {
|
||||||
})
|
})
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
let _signal_thread = thread::Builder::new()
|
||||||
|
.name("signal_listener".to_string())
|
||||||
|
.spawn({
|
||||||
|
let os_input = os_input.clone();
|
||||||
|
let send_screen_instructions = send_screen_instructions.clone();
|
||||||
|
move || {
|
||||||
|
os_input.receive_sigwinch(Box::new(move || {
|
||||||
|
let _ = send_screen_instructions.send(ScreenInstruction::TerminalResize);
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
// TODO: currently we don't wait for this to quit
|
// TODO: currently we don't wait for this to quit
|
||||||
// because otherwise the app will hang. Need to fix this so it both
|
// because otherwise the app will hang. Need to fix this so it both
|
||||||
// listens to the ipc-bus and is able to quit cleanly
|
// listens to the ipc-bus and is able to quit cleanly
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,8 @@ use std::path::PathBuf;
|
||||||
use std::process::{Child, Command};
|
use std::process::{Child, Command};
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
|
use signal_hook::{consts::signal::*, iterator::Signals};
|
||||||
|
|
||||||
use std::env;
|
use std::env;
|
||||||
|
|
||||||
fn into_raw_mode(pid: RawFd) {
|
fn into_raw_mode(pid: RawFd) {
|
||||||
|
|
@ -65,7 +67,7 @@ pub fn set_terminal_size_using_fd(fd: RawFd, columns: u16, rows: u16) {
|
||||||
/// process exits.
|
/// process exits.
|
||||||
fn handle_command_exit(mut child: Child) {
|
fn handle_command_exit(mut child: Child) {
|
||||||
// register the SIGINT signal (TODO handle more signals)
|
// register the SIGINT signal (TODO handle more signals)
|
||||||
let signals = ::signal_hook::iterator::Signals::new(&[::signal_hook::SIGINT]).unwrap();
|
let mut signals = ::signal_hook::iterator::Signals::new(&[SIGINT]).unwrap();
|
||||||
'handle_exit: loop {
|
'handle_exit: loop {
|
||||||
// test whether the child process has exited
|
// test whether the child process has exited
|
||||||
match child.try_wait() {
|
match child.try_wait() {
|
||||||
|
|
@ -82,11 +84,16 @@ fn handle_command_exit(mut child: Child) {
|
||||||
}
|
}
|
||||||
|
|
||||||
for signal in signals.pending() {
|
for signal in signals.pending() {
|
||||||
if signal == signal_hook::SIGINT {
|
// FIXME: We need to handle more signals here!
|
||||||
|
#[allow(clippy::single_match)]
|
||||||
|
match signal {
|
||||||
|
SIGINT => {
|
||||||
child.kill().unwrap();
|
child.kill().unwrap();
|
||||||
child.wait().unwrap();
|
child.wait().unwrap();
|
||||||
break 'handle_exit;
|
break 'handle_exit;
|
||||||
}
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -188,6 +195,7 @@ pub trait OsApi: Send + Sync {
|
||||||
fn get_stdout_writer(&self) -> Box<dyn io::Write>;
|
fn get_stdout_writer(&self) -> Box<dyn io::Write>;
|
||||||
/// Returns a [`Box`] pointer to this [`OsApi`] struct.
|
/// Returns a [`Box`] pointer to this [`OsApi`] struct.
|
||||||
fn box_clone(&self) -> Box<dyn OsApi>;
|
fn box_clone(&self) -> Box<dyn OsApi>;
|
||||||
|
fn receive_sigwinch(&self, cb: Box<dyn Fn()>);
|
||||||
}
|
}
|
||||||
|
|
||||||
impl OsApi for OsInputOutput {
|
impl OsApi for OsInputOutput {
|
||||||
|
|
@ -238,6 +246,20 @@ impl OsApi for OsInputOutput {
|
||||||
waitpid(Pid::from_raw(pid), None).unwrap();
|
waitpid(Pid::from_raw(pid), None).unwrap();
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
fn receive_sigwinch(&self, cb: Box<dyn Fn()>) {
|
||||||
|
let mut signals = Signals::new(&[SIGWINCH, SIGTERM, SIGINT, SIGQUIT]).unwrap();
|
||||||
|
for signal in signals.forever() {
|
||||||
|
match signal {
|
||||||
|
SIGWINCH => {
|
||||||
|
cb();
|
||||||
|
}
|
||||||
|
SIGTERM | SIGINT | SIGQUIT => {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Clone for Box<dyn OsApi> {
|
impl Clone for Box<dyn OsApi> {
|
||||||
|
|
|
||||||
|
|
@ -50,6 +50,7 @@ pub enum ScreenInstruction {
|
||||||
CloseTab,
|
CloseTab,
|
||||||
GoToTab(u32),
|
GoToTab(u32),
|
||||||
UpdateTabName(Vec<u8>),
|
UpdateTabName(Vec<u8>),
|
||||||
|
TerminalResize,
|
||||||
ChangeMode(ModeInfo),
|
ChangeMode(ModeInfo),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -213,6 +214,15 @@ impl Screen {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn resize_to_screen(&mut self) {
|
||||||
|
let new_screen_size = self.os_api.get_terminal_size_using_fd(0);
|
||||||
|
self.full_screen_ws = new_screen_size;
|
||||||
|
for (_, tab) in self.tabs.iter_mut() {
|
||||||
|
tab.resize_whole_tab(new_screen_size);
|
||||||
|
}
|
||||||
|
self.render();
|
||||||
|
}
|
||||||
|
|
||||||
/// Renders this [`Screen`], which amounts to rendering its active [`Tab`].
|
/// Renders this [`Screen`], which amounts to rendering its active [`Tab`].
|
||||||
pub fn render(&mut self) {
|
pub fn render(&mut self) {
|
||||||
if let Some(active_tab) = self.get_active_tab_mut() {
|
if let Some(active_tab) = self.get_active_tab_mut() {
|
||||||
|
|
|
||||||
|
|
@ -11,9 +11,18 @@ fn ansi_len(s: &str) -> usize {
|
||||||
.count()
|
.count()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn pad_to_size(s: &str, rows: usize, columns: usize) -> String {
|
pub fn adjust_to_size(s: &str, rows: usize, columns: usize) -> String {
|
||||||
s.lines()
|
s.lines()
|
||||||
.map(|l| [l, &str::repeat(" ", columns - ansi_len(l))].concat())
|
.map(|l| {
|
||||||
|
let actual_len = ansi_len(l);
|
||||||
|
if actual_len > columns {
|
||||||
|
let mut line = String::from(l);
|
||||||
|
line.truncate(columns);
|
||||||
|
return line;
|
||||||
|
} else {
|
||||||
|
return [l, &str::repeat(" ", columns - ansi_len(l))].concat();
|
||||||
|
}
|
||||||
|
})
|
||||||
.chain(iter::repeat(str::repeat(" ", columns)))
|
.chain(iter::repeat(str::repeat(" ", columns)))
|
||||||
.take(rows)
|
.take(rows)
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
|
|
|
||||||
|
|
@ -3,14 +3,13 @@ use std::collections::{HashMap, VecDeque};
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
use std::os::unix::io::RawFd;
|
use std::os::unix::io::RawFd;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::sync::atomic::{AtomicBool, Ordering};
|
use std::sync::{Arc, Condvar, Mutex};
|
||||||
use std::sync::{Arc, Mutex};
|
|
||||||
use std::time::{Duration, Instant};
|
use std::time::{Duration, Instant};
|
||||||
|
|
||||||
use crate::os_input_output::OsApi;
|
use crate::os_input_output::OsApi;
|
||||||
use crate::tests::possible_tty_inputs::{get_possible_tty_inputs, Bytes};
|
use crate::tests::possible_tty_inputs::{get_possible_tty_inputs, Bytes};
|
||||||
|
|
||||||
use crate::tests::utils::commands::SLEEP;
|
use crate::tests::utils::commands::{QUIT, SLEEP};
|
||||||
|
|
||||||
const MIN_TIME_BETWEEN_SNAPSHOTS: Duration = Duration::from_millis(50);
|
const MIN_TIME_BETWEEN_SNAPSHOTS: Duration = Duration::from_millis(50);
|
||||||
|
|
||||||
|
|
@ -72,7 +71,8 @@ pub struct FakeInputOutput {
|
||||||
win_sizes: Arc<Mutex<HashMap<RawFd, PositionAndSize>>>,
|
win_sizes: Arc<Mutex<HashMap<RawFd, PositionAndSize>>>,
|
||||||
possible_tty_inputs: HashMap<u16, Bytes>,
|
possible_tty_inputs: HashMap<u16, Bytes>,
|
||||||
last_snapshot_time: Arc<Mutex<Instant>>,
|
last_snapshot_time: Arc<Mutex<Instant>>,
|
||||||
started_reading_from_pty: Arc<AtomicBool>,
|
should_trigger_sigwinch: Arc<(Mutex<bool>, Condvar)>,
|
||||||
|
sigwinch_event: Option<PositionAndSize>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FakeInputOutput {
|
impl FakeInputOutput {
|
||||||
|
|
@ -91,7 +91,8 @@ impl FakeInputOutput {
|
||||||
io_events: Arc::new(Mutex::new(vec![])),
|
io_events: Arc::new(Mutex::new(vec![])),
|
||||||
win_sizes: Arc::new(Mutex::new(win_sizes)),
|
win_sizes: Arc::new(Mutex::new(win_sizes)),
|
||||||
possible_tty_inputs: get_possible_tty_inputs(),
|
possible_tty_inputs: get_possible_tty_inputs(),
|
||||||
started_reading_from_pty: Arc::new(AtomicBool::new(false)),
|
should_trigger_sigwinch: Arc::new((Mutex::new(false), Condvar::new())),
|
||||||
|
sigwinch_event: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn with_tty_inputs(mut self, tty_inputs: HashMap<u16, Bytes>) -> Self {
|
pub fn with_tty_inputs(mut self, tty_inputs: HashMap<u16, Bytes>) -> Self {
|
||||||
|
|
@ -108,10 +109,20 @@ impl FakeInputOutput {
|
||||||
pub fn add_terminal(&mut self, fd: RawFd) {
|
pub fn add_terminal(&mut self, fd: RawFd) {
|
||||||
self.stdin_writes.lock().unwrap().insert(fd, vec![]);
|
self.stdin_writes.lock().unwrap().insert(fd, vec![]);
|
||||||
}
|
}
|
||||||
|
pub fn add_sigwinch_event(&mut self, new_position_and_size: PositionAndSize) {
|
||||||
|
self.sigwinch_event = Some(new_position_and_size);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl OsApi for FakeInputOutput {
|
impl OsApi for FakeInputOutput {
|
||||||
fn get_terminal_size_using_fd(&self, pid: RawFd) -> PositionAndSize {
|
fn get_terminal_size_using_fd(&self, pid: RawFd) -> PositionAndSize {
|
||||||
|
if let Some(new_position_and_size) = self.sigwinch_event {
|
||||||
|
let (lock, _cvar) = &*self.should_trigger_sigwinch;
|
||||||
|
let should_trigger_sigwinch = lock.lock().unwrap();
|
||||||
|
if *should_trigger_sigwinch && pid == 0 {
|
||||||
|
return new_position_and_size;
|
||||||
|
}
|
||||||
|
}
|
||||||
let win_sizes = self.win_sizes.lock().unwrap();
|
let win_sizes = self.win_sizes.lock().unwrap();
|
||||||
let winsize = win_sizes.get(&pid).unwrap();
|
let winsize = win_sizes.get(&pid).unwrap();
|
||||||
*winsize
|
*winsize
|
||||||
|
|
@ -159,7 +170,6 @@ impl OsApi for FakeInputOutput {
|
||||||
if bytes_read > bytes.read_position {
|
if bytes_read > bytes.read_position {
|
||||||
bytes.set_read_position(bytes_read);
|
bytes.set_read_position(bytes_read);
|
||||||
}
|
}
|
||||||
self.started_reading_from_pty.store(true, Ordering::Release);
|
|
||||||
return Ok(bytes_read);
|
return Ok(bytes_read);
|
||||||
}
|
}
|
||||||
None => Err(nix::Error::Sys(nix::errno::Errno::EAGAIN)),
|
None => Err(nix::Error::Sys(nix::errno::Errno::EAGAIN)),
|
||||||
|
|
@ -199,6 +209,12 @@ impl OsApi for FakeInputOutput {
|
||||||
.unwrap_or(vec![]);
|
.unwrap_or(vec![]);
|
||||||
if command == SLEEP {
|
if command == SLEEP {
|
||||||
std::thread::sleep(std::time::Duration::from_millis(200));
|
std::thread::sleep(std::time::Duration::from_millis(200));
|
||||||
|
} else if command == QUIT && self.sigwinch_event.is_some() {
|
||||||
|
let (lock, cvar) = &*self.should_trigger_sigwinch;
|
||||||
|
let mut should_trigger_sigwinch = lock.lock().unwrap();
|
||||||
|
*should_trigger_sigwinch = true;
|
||||||
|
cvar.notify_one();
|
||||||
|
::std::thread::sleep(MIN_TIME_BETWEEN_SNAPSHOTS); // give some time for the app to resize before quitting
|
||||||
}
|
}
|
||||||
command
|
command
|
||||||
}
|
}
|
||||||
|
|
@ -209,4 +225,14 @@ impl OsApi for FakeInputOutput {
|
||||||
self.io_events.lock().unwrap().push(IoEvent::Kill(fd));
|
self.io_events.lock().unwrap().push(IoEvent::Kill(fd));
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
fn receive_sigwinch(&self, cb: Box<dyn Fn()>) {
|
||||||
|
if self.sigwinch_event.is_some() {
|
||||||
|
let (lock, cvar) = &*self.should_trigger_sigwinch;
|
||||||
|
let mut should_trigger_sigwinch = lock.lock().unwrap();
|
||||||
|
while !*should_trigger_sigwinch {
|
||||||
|
should_trigger_sigwinch = cvar.wait(should_trigger_sigwinch).unwrap();
|
||||||
|
}
|
||||||
|
cb();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ use crate::tests::utils::{get_next_to_last_snapshot, get_output_frame_snapshots}
|
||||||
use crate::{start, CliArgs};
|
use crate::{start, CliArgs};
|
||||||
|
|
||||||
use crate::tests::utils::commands::{
|
use crate::tests::utils::commands::{
|
||||||
CLOSE_PANE_IN_PANE_MODE, COMMAND_TOGGLE, ESC, MOVE_FOCUS_IN_PANE_MODE, PANE_MODE, QUIT,
|
CLOSE_PANE_IN_PANE_MODE, ESC, MOVE_FOCUS_IN_PANE_MODE, PANE_MODE, QUIT,
|
||||||
RESIZE_DOWN_IN_RESIZE_MODE, RESIZE_LEFT_IN_RESIZE_MODE, RESIZE_MODE, RESIZE_UP_IN_RESIZE_MODE,
|
RESIZE_DOWN_IN_RESIZE_MODE, RESIZE_LEFT_IN_RESIZE_MODE, RESIZE_MODE, RESIZE_UP_IN_RESIZE_MODE,
|
||||||
SPLIT_DOWN_IN_PANE_MODE, SPLIT_RIGHT_IN_PANE_MODE,
|
SPLIT_DOWN_IN_PANE_MODE, SPLIT_RIGHT_IN_PANE_MODE,
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -12,4 +12,5 @@ pub mod resize_left;
|
||||||
pub mod resize_right;
|
pub mod resize_right;
|
||||||
pub mod resize_up;
|
pub mod resize_up;
|
||||||
pub mod tabs;
|
pub mod tabs;
|
||||||
|
pub mod terminal_window_resize;
|
||||||
pub mod toggle_fullscreen;
|
pub mod toggle_fullscreen;
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,25 @@
|
||||||
|
---
|
||||||
|
source: src/tests/integration/terminal_window_resize.rs
|
||||||
|
expression: snapshot_before_quit
|
||||||
|
|
||||||
|
---
|
||||||
|
line1-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||||
|
line2-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||||
|
line3-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||||
|
line4-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||||
|
line5-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||||
|
line6-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||||
|
line7-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||||
|
line8-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||||
|
line9-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||||
|
line10-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||||
|
line11-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||||
|
line12-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||||
|
line13-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||||
|
line14-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||||
|
line15-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||||
|
line16-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||||
|
line17-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||||
|
line18-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||||
|
line19-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||||
|
█
|
||||||
|
|
@ -0,0 +1,25 @@
|
||||||
|
---
|
||||||
|
source: src/tests/integration/terminal_window_resize.rs
|
||||||
|
expression: snapshot_before_quit
|
||||||
|
|
||||||
|
---
|
||||||
|
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||||
|
line16-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||||
|
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||||
|
line17-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||||
|
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||||
|
line18-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||||
|
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||||
|
line19-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||||
|
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||||
|
prompt $ █
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,25 @@
|
||||||
|
---
|
||||||
|
source: src/tests/integration/terminal_window_resize.rs
|
||||||
|
expression: snapshot_before_quit
|
||||||
|
|
||||||
|
---
|
||||||
|
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||||
|
line11-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||||
|
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||||
|
line12-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||||
|
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||||
|
line13-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||||
|
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||||
|
line14-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||||
|
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||||
|
line15-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||||
|
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||||
|
line16-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||||
|
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||||
|
line17-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||||
|
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||||
|
line18-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||||
|
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||||
|
line19-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||||
|
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||||
|
prompt $ █
|
||||||
|
|
@ -0,0 +1,25 @@
|
||||||
|
---
|
||||||
|
source: src/tests/integration/terminal_window_resize.rs
|
||||||
|
expression: snapshot_before_quit
|
||||||
|
|
||||||
|
---
|
||||||
|
line2-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||||
|
line3-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||||
|
line4-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||||
|
line5-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||||
|
line6-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||||
|
line7-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||||
|
line8-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||||
|
line9-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||||
|
line10-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||||
|
line11-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||||
|
line12-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||||
|
line13-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||||
|
line14-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||||
|
line15-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||||
|
line16-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||||
|
line17-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||||
|
line18-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||||
|
line19-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||||
|
prompt $
|
||||||
|
█
|
||||||
127
src/tests/integration/terminal_window_resize.rs
Normal file
127
src/tests/integration/terminal_window_resize.rs
Normal file
|
|
@ -0,0 +1,127 @@
|
||||||
|
use crate::panes::PositionAndSize;
|
||||||
|
use ::insta::assert_snapshot;
|
||||||
|
|
||||||
|
use crate::tests::fakes::FakeInputOutput;
|
||||||
|
use crate::tests::utils::commands::QUIT;
|
||||||
|
use crate::tests::utils::{get_next_to_last_snapshot, get_output_frame_snapshots};
|
||||||
|
use crate::{start, CliArgs};
|
||||||
|
|
||||||
|
fn get_fake_os_input(fake_win_size: &PositionAndSize) -> FakeInputOutput {
|
||||||
|
FakeInputOutput::new(fake_win_size.clone())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
pub fn window_width_decrease_with_one_pane() {
|
||||||
|
let fake_win_size = PositionAndSize {
|
||||||
|
columns: 121,
|
||||||
|
rows: 20,
|
||||||
|
x: 0,
|
||||||
|
y: 0,
|
||||||
|
};
|
||||||
|
let mut fake_input_output = get_fake_os_input(&fake_win_size);
|
||||||
|
fake_input_output.add_terminal_input(&[&QUIT]);
|
||||||
|
fake_input_output.add_sigwinch_event(PositionAndSize {
|
||||||
|
columns: 90,
|
||||||
|
rows: 20,
|
||||||
|
x: 0,
|
||||||
|
y: 0,
|
||||||
|
});
|
||||||
|
let opts = CliArgs::default();
|
||||||
|
start(Box::new(fake_input_output.clone()), opts);
|
||||||
|
let output_frames = fake_input_output
|
||||||
|
.stdout_writer
|
||||||
|
.output_frames
|
||||||
|
.lock()
|
||||||
|
.unwrap();
|
||||||
|
let snapshots = get_output_frame_snapshots(&output_frames, &fake_win_size);
|
||||||
|
let snapshot_before_quit =
|
||||||
|
get_next_to_last_snapshot(snapshots).expect("could not find snapshot");
|
||||||
|
assert_snapshot!(snapshot_before_quit);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
pub fn window_width_increase_with_one_pane() {
|
||||||
|
let fake_win_size = PositionAndSize {
|
||||||
|
columns: 121,
|
||||||
|
rows: 20,
|
||||||
|
x: 0,
|
||||||
|
y: 0,
|
||||||
|
};
|
||||||
|
let mut fake_input_output = get_fake_os_input(&fake_win_size);
|
||||||
|
fake_input_output.add_terminal_input(&[&QUIT]);
|
||||||
|
fake_input_output.add_sigwinch_event(PositionAndSize {
|
||||||
|
columns: 141,
|
||||||
|
rows: 20,
|
||||||
|
x: 0,
|
||||||
|
y: 0,
|
||||||
|
});
|
||||||
|
let opts = CliArgs::default();
|
||||||
|
start(Box::new(fake_input_output.clone()), opts);
|
||||||
|
let output_frames = fake_input_output
|
||||||
|
.stdout_writer
|
||||||
|
.output_frames
|
||||||
|
.lock()
|
||||||
|
.unwrap();
|
||||||
|
let snapshots = get_output_frame_snapshots(&output_frames, &fake_win_size);
|
||||||
|
let snapshot_before_quit =
|
||||||
|
get_next_to_last_snapshot(snapshots).expect("could not find snapshot");
|
||||||
|
assert_snapshot!(snapshot_before_quit);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
pub fn window_height_increase_with_one_pane() {
|
||||||
|
let fake_win_size = PositionAndSize {
|
||||||
|
columns: 121,
|
||||||
|
rows: 20,
|
||||||
|
x: 0,
|
||||||
|
y: 0,
|
||||||
|
};
|
||||||
|
let mut fake_input_output = get_fake_os_input(&fake_win_size);
|
||||||
|
fake_input_output.add_terminal_input(&[&QUIT]);
|
||||||
|
fake_input_output.add_sigwinch_event(PositionAndSize {
|
||||||
|
columns: 121,
|
||||||
|
rows: 30,
|
||||||
|
x: 0,
|
||||||
|
y: 0,
|
||||||
|
});
|
||||||
|
let opts = CliArgs::default();
|
||||||
|
start(Box::new(fake_input_output.clone()), opts);
|
||||||
|
let output_frames = fake_input_output
|
||||||
|
.stdout_writer
|
||||||
|
.output_frames
|
||||||
|
.lock()
|
||||||
|
.unwrap();
|
||||||
|
let snapshots = get_output_frame_snapshots(&output_frames, &fake_win_size);
|
||||||
|
let snapshot_before_quit =
|
||||||
|
get_next_to_last_snapshot(snapshots).expect("could not find snapshot");
|
||||||
|
assert_snapshot!(snapshot_before_quit);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
pub fn window_width_and_height_decrease_with_one_pane() {
|
||||||
|
let fake_win_size = PositionAndSize {
|
||||||
|
columns: 121,
|
||||||
|
rows: 20,
|
||||||
|
x: 0,
|
||||||
|
y: 0,
|
||||||
|
};
|
||||||
|
let mut fake_input_output = get_fake_os_input(&fake_win_size);
|
||||||
|
fake_input_output.add_terminal_input(&[&QUIT]);
|
||||||
|
fake_input_output.add_sigwinch_event(PositionAndSize {
|
||||||
|
columns: 90,
|
||||||
|
rows: 10,
|
||||||
|
x: 0,
|
||||||
|
y: 0,
|
||||||
|
});
|
||||||
|
let opts = CliArgs::default();
|
||||||
|
start(Box::new(fake_input_output.clone()), opts);
|
||||||
|
let output_frames = fake_input_output
|
||||||
|
.stdout_writer
|
||||||
|
.output_frames
|
||||||
|
.lock()
|
||||||
|
.unwrap();
|
||||||
|
let snapshots = get_output_frame_snapshots(&output_frames, &fake_win_size);
|
||||||
|
let snapshot_before_quit =
|
||||||
|
get_next_to_last_snapshot(snapshots).expect("could not find snapshot");
|
||||||
|
assert_snapshot!(snapshot_before_quit);
|
||||||
|
}
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
use crate::tests::tty_inputs::{
|
use crate::tests::tty_inputs::{
|
||||||
COL_10, COL_121, COL_14, COL_15, COL_19, COL_20, COL_24, COL_25, COL_29, COL_30, COL_34,
|
COL_10, COL_121, COL_14, COL_141, COL_15, COL_19, COL_20, COL_24, COL_25, COL_29, COL_30,
|
||||||
COL_39, COL_4, COL_40, COL_47, COL_50, COL_60, COL_70, COL_8, COL_9, COL_90, COL_96,
|
COL_34, COL_39, COL_4, COL_40, COL_47, COL_50, COL_60, COL_70, COL_8, COL_80, COL_9, COL_90,
|
||||||
|
COL_96,
|
||||||
};
|
};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
|
|
@ -69,9 +70,11 @@ pub fn get_possible_tty_inputs() -> HashMap<u16, Bytes> {
|
||||||
let col_50_bytes = Bytes::new().content_from_str(&COL_50);
|
let col_50_bytes = Bytes::new().content_from_str(&COL_50);
|
||||||
let col_60_bytes = Bytes::new().content_from_str(&COL_60);
|
let col_60_bytes = Bytes::new().content_from_str(&COL_60);
|
||||||
let col_70_bytes = Bytes::new().content_from_str(&COL_70);
|
let col_70_bytes = Bytes::new().content_from_str(&COL_70);
|
||||||
|
let col_80_bytes = Bytes::new().content_from_str(&COL_80);
|
||||||
let col_90_bytes = Bytes::new().content_from_str(&COL_90);
|
let col_90_bytes = Bytes::new().content_from_str(&COL_90);
|
||||||
let col_96_bytes = Bytes::new().content_from_str(&COL_96);
|
let col_96_bytes = Bytes::new().content_from_str(&COL_96);
|
||||||
let col_121_bytes = Bytes::new().content_from_str(&COL_121);
|
let col_121_bytes = Bytes::new().content_from_str(&COL_121);
|
||||||
|
let col_141_bytes = Bytes::new().content_from_str(&COL_141);
|
||||||
possible_inputs.insert(4, col_4_bytes);
|
possible_inputs.insert(4, col_4_bytes);
|
||||||
possible_inputs.insert(8, col_8_bytes);
|
possible_inputs.insert(8, col_8_bytes);
|
||||||
possible_inputs.insert(9, col_9_bytes);
|
possible_inputs.insert(9, col_9_bytes);
|
||||||
|
|
@ -91,8 +94,10 @@ pub fn get_possible_tty_inputs() -> HashMap<u16, Bytes> {
|
||||||
possible_inputs.insert(50, col_50_bytes);
|
possible_inputs.insert(50, col_50_bytes);
|
||||||
possible_inputs.insert(60, col_60_bytes);
|
possible_inputs.insert(60, col_60_bytes);
|
||||||
possible_inputs.insert(70, col_70_bytes);
|
possible_inputs.insert(70, col_70_bytes);
|
||||||
|
possible_inputs.insert(80, col_80_bytes);
|
||||||
possible_inputs.insert(90, col_90_bytes);
|
possible_inputs.insert(90, col_90_bytes);
|
||||||
possible_inputs.insert(96, col_96_bytes);
|
possible_inputs.insert(96, col_96_bytes);
|
||||||
possible_inputs.insert(121, col_121_bytes);
|
possible_inputs.insert(121, col_121_bytes);
|
||||||
|
possible_inputs.insert(141, col_141_bytes);
|
||||||
possible_inputs
|
possible_inputs
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,26 @@
|
||||||
|
pub const COL_141: [&str; 20] = [
|
||||||
|
"line1-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\r\n",
|
||||||
|
"line2-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\r\n",
|
||||||
|
"line3-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\r\n",
|
||||||
|
"line4-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\r\n",
|
||||||
|
"line5-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\r\n",
|
||||||
|
"line6-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\r\n",
|
||||||
|
"line7-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\r\n",
|
||||||
|
"line8-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\r\n",
|
||||||
|
"line9-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\r\n",
|
||||||
|
"line10-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\r\n",
|
||||||
|
"line11-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\r\n",
|
||||||
|
"line12-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\r\n",
|
||||||
|
"line13-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\r\n",
|
||||||
|
"line14-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\r\n",
|
||||||
|
"line15-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\r\n",
|
||||||
|
"line16-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\r\n",
|
||||||
|
"line17-baaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\r\n",
|
||||||
|
"line18-baaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\r\n",
|
||||||
|
"line19-baaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\r\n",
|
||||||
|
"prompt $ ",
|
||||||
|
];
|
||||||
|
|
||||||
pub const COL_121: [&str; 20] = [
|
pub const COL_121: [&str; 20] = [
|
||||||
"line1-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\r\n",
|
"line1-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\r\n",
|
||||||
"line2-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\r\n",
|
"line2-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\r\n",
|
||||||
|
|
@ -457,6 +480,29 @@ pub const COL_70: [&str; 20] = [
|
||||||
"prompt $ ",
|
"prompt $ ",
|
||||||
];
|
];
|
||||||
|
|
||||||
|
pub const COL_80: [&str; 20] = [
|
||||||
|
"line1-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
|
"line2-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
|
"line3-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
|
"line4-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
|
"line5-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
|
"line6-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
|
"line7-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
|
"line8-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
|
"line9-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
|
"line10-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
|
"line11-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
|
"line12-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
|
"line13-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
|
"line14-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
|
"line15-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
|
"line16-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
|
"line17-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
|
"line18-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
|
"line19-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
|
"prompt $ ",
|
||||||
|
];
|
||||||
|
|
||||||
pub const COL_90: [&str; 20] = [
|
pub const COL_90: [&str; 20] = [
|
||||||
"line1-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
"line1-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line2-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
"line2-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
|
|
|
||||||
|
|
@ -45,7 +45,6 @@ pub fn get_next_to_last_snapshot(mut snapshots: Vec<String>) -> Option<String> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub mod commands {
|
pub mod commands {
|
||||||
pub const COMMAND_TOGGLE: [u8; 1] = [7]; // ctrl-g
|
|
||||||
pub const QUIT: [u8; 1] = [17]; // ctrl-q
|
pub const QUIT: [u8; 1] = [17]; // ctrl-q
|
||||||
pub const ESC: [u8; 1] = [27];
|
pub const ESC: [u8; 1] = [27];
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue