wip: need to figure out how to clear lines

This commit is contained in:
denis 2021-04-08 16:29:52 +03:00
commit 7774edd45a
28 changed files with 1102 additions and 108 deletions

92
Cargo.lock generated
View File

@ -130,7 +130,7 @@ dependencies = [
"event-listener",
"futures-lite",
"once_cell",
"signal-hook 0.3.7",
"signal-hook",
"winapi",
]
@ -524,9 +524,9 @@ dependencies = [
[[package]]
name = "dtoa"
version = "0.4.7"
version = "0.4.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "88d7ed2934d741c6b37e33e3832298e8850b53fd2d2bea03873375596c7cea4e"
checksum = "56899898ce76aaf4a0f24d914c97ea6ed976d42fec6ad33fcbb0a1103e07b2b0"
[[package]]
name = "either"
@ -824,9 +824,9 @@ dependencies = [
[[package]]
name = "insta"
version = "1.7.0"
version = "1.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e1b6cf41e31a7e7b78055b548826da45c7dc74e6a13a3fa6b897a17a01322f26"
checksum = "c4a1b21a2971cea49ca4613c0e9fe8225ecaf5de64090fddc6002284726e9244"
dependencies = [
"console",
"lazy_static",
@ -899,9 +899,9 @@ checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736"
[[package]]
name = "js-sys"
version = "0.3.49"
version = "0.3.50"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc15e39392125075f60c95ba416f5381ff6c3a948ff02ab12464715adf56c821"
checksum = "2d99f9e3e84b8f67f846ef5b4cbbc3b1c29f6c759fcbce6f01aa0e73d932a24c"
dependencies = [
"wasm-bindgen",
]
@ -942,9 +942,9 @@ dependencies = [
[[package]]
name = "libc"
version = "0.2.91"
version = "0.2.92"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8916b1f6ca17130ec6568feccee27c156ad12037880833a3b842a823236502e7"
checksum = "56d855069fafbb9b344c0f962150cd2c1187975cb1c22c1522c240d8c4986714"
[[package]]
name = "libloading"
@ -964,9 +964,9 @@ checksum = "7fb9b38af92608140b86b693604b9ffcc5824240a484d1ecd4795bacb2fe88f3"
[[package]]
name = "lock_api"
version = "0.4.2"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd96ffd135b2fd7b973ac026d28085defbe8983df057ced3eb4f2130b0831312"
checksum = "5a3c91c24eae6777794bb1997ad98bbb87daf92890acab859f7eaa4320333176"
dependencies = [
"scopeguard",
]
@ -998,18 +998,18 @@ checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525"
[[package]]
name = "memmap2"
version = "0.2.1"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "04e3e85b970d650e2ae6d70592474087051c11c54da7f7b4949725c5735fbcc6"
checksum = "397d1a6d6d0563c0f5462bbdae662cf6c784edf5e828e40c7257f85d82bf56dd"
dependencies = [
"libc",
]
[[package]]
name = "memoffset"
version = "0.6.2"
version = "0.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cc14fc54a812b4472b4113facc3e44d099fbc0ea2ce0551fa5c703f8edfbfd38"
checksum = "f83fb6581e8ed1f85fd45c116db8405483899489e38406156c25eb743554361d"
dependencies = [
"autocfg",
]
@ -1194,9 +1194,9 @@ checksum = "bc881b2c22681370c6a780e47af9840ef841837bc98118431d4e1868bd0c1086"
[[package]]
name = "proc-macro2"
version = "1.0.24"
version = "1.0.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71"
checksum = "a152013215dca273577e18d2bf00fa862b89b24169fb78c4c95aeb07992c9cec"
dependencies = [
"unicode-xid",
]
@ -1428,19 +1428,9 @@ dependencies = [
[[package]]
name = "signal-hook"
version = "0.1.17"
version = "0.3.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7e31d442c16f047a671b5a71e2161d6e68814012b7f5379d269ebd915fac2729"
dependencies = [
"libc",
"signal-hook-registry",
]
[[package]]
name = "signal-hook"
version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6aa894ef3fade0ee7243422f4fbbd6c2b48e6de767e621d37ef65f2310f53cea"
checksum = "ef33d6d0cd06e0840fba9985aab098c147e67e05cee14d412d3345ed14ff30ac"
dependencies = [
"libc",
"signal-hook-registry",
@ -1587,9 +1577,9 @@ dependencies = [
[[package]]
name = "syn"
version = "1.0.65"
version = "1.0.68"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f3a1d708c221c5a612956ef9f75b37e454e88d1f7b899fbd3a18d4252012d663"
checksum = "3ce15dd3ed8aa2f8eeac4716d6ef5ab58b6b9256db41d7e1a0224c2788e8fd87"
dependencies = [
"proc-macro2",
"quote",
@ -1894,9 +1884,9 @@ checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6"
[[package]]
name = "wasm-bindgen"
version = "0.2.72"
version = "0.2.73"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8fe8f61dba8e5d645a4d8132dc7a0a66861ed5e1045d2c0ed940fab33bac0fbe"
checksum = "83240549659d187488f91f33c0f8547cbfef0b2088bc470c116d1d260ef623d9"
dependencies = [
"cfg-if 1.0.0",
"wasm-bindgen-macro",
@ -1904,9 +1894,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-backend"
version = "0.2.72"
version = "0.2.73"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "046ceba58ff062da072c7cb4ba5b22a37f00a302483f7e2a6cdc18fedbdc1fd3"
checksum = "ae70622411ca953215ca6d06d3ebeb1e915f0f6613e3b495122878d7ebec7dae"
dependencies = [
"bumpalo",
"lazy_static",
@ -1919,9 +1909,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-futures"
version = "0.4.22"
version = "0.4.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "73157efb9af26fb564bb59a009afd1c7c334a44db171d280690d0c3faaec3468"
checksum = "81b8b767af23de6ac18bf2168b690bed2902743ddf0fb39252e36f9e2bfc63ea"
dependencies = [
"cfg-if 1.0.0",
"js-sys",
@ -1931,9 +1921,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro"
version = "0.2.72"
version = "0.2.73"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ef9aa01d36cda046f797c57959ff5f3c615c9cc63997a8d545831ec7976819b"
checksum = "3e734d91443f177bfdb41969de821e15c516931c3c3db3d318fa1b68975d0f6f"
dependencies = [
"quote",
"wasm-bindgen-macro-support",
@ -1941,9 +1931,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro-support"
version = "0.2.72"
version = "0.2.73"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "96eb45c1b2ee33545a813a92dbb53856418bf7eb54ab34f7f7ff1448a5b3735d"
checksum = "d53739ff08c8a68b0fdbcd54c372b8ab800b1449ab3c9d706503bc7dd1621b2c"
dependencies = [
"proc-macro2",
"quote",
@ -1954,9 +1944,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-shared"
version = "0.2.72"
version = "0.2.73"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b7148f4696fb4960a346eaa60bbfb42a1ac4ebba21f750f75fc1375b098d5ffa"
checksum = "d9a543ae66aa233d14bb765ed9af4a33e81b8b58d1584cf1b47ff8cd0b9e4489"
[[package]]
name = "wasmer"
@ -2169,18 +2159,18 @@ dependencies = [
[[package]]
name = "wat"
version = "1.0.36"
version = "1.0.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b0fa059022c5dabe129f02b429d67086400deb8277f89c975555dacc1dadbcc"
checksum = "8ec280a739b69173e0ffd12c1658507996836ba4e992ed9bc1e5385a0bd72a02"
dependencies = [
"wast",
]
[[package]]
name = "web-sys"
version = "0.3.49"
version = "0.3.50"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "59fe19d70f5dacc03f6e46777213facae5ac3801575d56ca6cbd4c93dcd12310"
checksum = "a905d57e488fec8861446d3393670fb50d27a262344013181c2cdf9fff5481be"
dependencies = [
"js-sys",
"wasm-bindgen",
@ -2197,12 +2187,12 @@ dependencies = [
[[package]]
name = "which"
version = "4.0.2"
version = "4.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "87c14ef7e1b8b8ecfc75d5eca37949410046e66f15d185c01d70824f1f8111ef"
checksum = "b55551e42cbdf2ce2bedd2203d0cc08dba002c27510f86dab6d0ce304cba3dfe"
dependencies = [
"either",
"libc",
"thiserror",
]
[[package]]
@ -2292,7 +2282,7 @@ dependencies = [
"serde",
"serde_json",
"serde_yaml",
"signal-hook 0.1.17",
"signal-hook",
"strip-ansi-escapes",
"structopt",
"strum",

View File

@ -24,7 +24,7 @@ nom = "6.0.1"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
serde_yaml = "0.8"
signal-hook = "0.1.10"
signal-hook = "0.3"
strip-ansi-escapes = "0.1.0"
structopt = "0.3"
termion = "1.5.0"

View File

@ -26,3 +26,6 @@ Once the organization reaches 10 members, a reasonable and achievable process mu
* Denis Maximov <denis_maxim0v@protonmail.com>
* Kunal Mohan <kunalmohan99@gmail.com>
* Henil Dedania <dedaniahenil@gmail.com>
* Roee Shapira <ro33.sha@gmail.com>
* Alex Kenji Berthold <aks.kenji@protonmail.com>
* Kyle Sutherland-Cash <kyle.sutherlandcash@gmail.com>

View File

@ -105,7 +105,7 @@ fn unselected_mode_shortcut(letter: char, text: &str, palette: Palette) -> LineP
suffix_separator,
])
.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
}
}
@ -151,7 +151,7 @@ fn selected_mode_shortcut(letter: char, text: &str, palette: Palette) -> LinePar
suffix_separator,
])
.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
}
}

View File

@ -2,7 +2,7 @@ mod first_line;
mod second_line;
use std::fmt::{Display, Error, Formatter};
use zellij_tile::prelude::*;
use zellij_tile::{prelude::*, data::Theme};
use first_line::{ctrl_keys, superkey};
use second_line::keybinds;
@ -62,21 +62,30 @@ impl ZellijTile for State {
let first_line = format!("{}{}", superkey, ctrl_keys);
let second_line = keybinds(&self.mode_info, cols);
let first_line_color = match self.mode_info.palette.theme {
Theme::Light => self.mode_info.palette.black,
Theme::Dark => self.mode_info.palette.white,
};
let second_line_color = match self.mode_info.palette.theme {
Theme::Light => self.mode_info.palette.bg,
Theme::Dark => self.mode_info.palette.bg,
};
// [48;5;238m is gray background, [0K is so that it fills the rest of the line
// [48;5;16m is black background, [0K is so that it fills the rest of the line
println!(
"{}\u{1b}[{};{};{}m\u{1b}[0K",
"{}\x1B[38;2;{};{};{}m\u{1b}[0K",
first_line,
self.mode_info.palette.black.0,
self.mode_info.palette.black.1,
self.mode_info.palette.black.2
first_line_color.0,
first_line_color.1,
first_line_color.2
);
println!(
"{}\u{1b}[{};{};{}m\u{1b}[0K",
second_line,
self.mode_info.palette.fg.0,
self.mode_info.palette.fg.1,
self.mode_info.palette.fg.2
second_line_color.0,
second_line_color.1,
second_line_color.2
);
}
}

View File

@ -1,5 +1,6 @@
pub mod boundaries;
pub mod layout;
pub mod pane_resizer;
pub mod panes;
pub mod tab;

508
src/client/pane_resizer.rs Normal file
View 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, &current_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, &current_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, &current_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, &current_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;
}
}
}
}

View File

@ -173,6 +173,18 @@ impl Pane for PluginPane {
self.position_and_size.columns += count;
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) {
unimplemented!()
}

View File

@ -282,6 +282,18 @@ impl Pane for TerminalPane {
self.position_and_size.columns += count;
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) {
self.grid.move_viewport_up(count);
self.mark_for_rerender();

View File

@ -1,20 +1,23 @@
//! `Tab`s holds multiple panes. It tracks their coordinates (x/y) and size,
//! as well as how they should be resized
use crate::common::{colors, input::handler::parse_keys, AppInstruction, SenderWithContext};
use crate::client::pane_resizer::PaneResizer;
use crate::common::{input::handler::parse_keys, AppInstruction, SenderWithContext};
use crate::layout::Layout;
use crate::os_input_output::OsApi;
use crate::panes::{PaneId, PositionAndSize, TerminalPane};
use crate::pty_bus::{PtyInstruction, VteEvent};
use crate::utils::shared::adjust_to_size;
use crate::wasm_vm::PluginInstruction;
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::{
cmp::Reverse,
collections::{BTreeMap, HashSet},
};
use std::{io::Write, sync::mpsc::channel};
use zellij_tile::data::{Event, InputMode, ModeInfo, Palette};
use zellij_tile::data::{Event, InputMode, ModeInfo, Palette, colors};
const CURSOR_HEIGHT_WIDTH_RATIO: usize = 4; // this is not accurate and kind of a magic number, TODO: look into this
const MIN_TERMINAL_HEIGHT: usize = 2;
@ -65,6 +68,18 @@ pub struct Tab {
pub send_plugin_instructions: SenderWithContext<PluginInstruction>,
pub send_app_instructions: SenderWithContext<AppInstruction>,
expansion_boundary: Option<PositionAndSize>,
should_clear_display_before_rendering: bool,
pub mode_info: ModeInfo,
pub input_mode: InputMode,
pub colors: Palette
}
#[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 input_mode: InputMode,
pub colors: Palette,
@ -100,6 +115,10 @@ pub trait Pane {
fn reduce_width_right(&mut self, count: usize);
fn reduce_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_down(&mut self, count: usize);
fn clear_scroll(&mut self);
@ -154,6 +173,22 @@ pub trait Pane {
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 {
MIN_TERMINAL_WIDTH
}
@ -216,6 +251,7 @@ impl Tab {
send_pty_instructions,
send_plugin_instructions,
expansion_boundary: None,
should_clear_display_before_rendering: false,
mode_info,
input_mode,
colors,
@ -635,28 +671,33 @@ impl Tab {
stdout
.write_all(&hide_cursor.as_bytes())
.expect("cannot write to stdout");
for (kind, terminal) in self.panes.iter_mut() {
if !self.panes_to_hide.contains(&terminal.pid()) {
match self.active_terminal.unwrap() == terminal.pid() {
true => boundaries.add_rect(
terminal.as_ref(),
self.mode_info.mode,
Some(self.colors),
),
false => boundaries.add_rect(terminal.as_ref(), self.mode_info.mode, None),
if self.should_clear_display_before_rendering {
let clear_display = "\u{1b}[2J";
stdout
.write_all(&clear_display.as_bytes())
.expect("cannot write to stdout");
self.should_clear_display_before_rendering = false;
}
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(self.colors))
}
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 {
vte_output
} 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?
write!(
stdout,
"\u{1b}[{};{}H\u{1b}[m{}",
terminal.y() + 1,
terminal.x() + 1,
pane.y() + 1,
pane.x() + 1,
vte_output
)
.expect("cannot write to stdout");
@ -1669,17 +1710,30 @@ impl Tab {
false
}
}
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);
pub fn resize_whole_tab(&mut self, new_screen_size: PositionAndSize) {
if self.fullscreen_is_active {
// this is not ideal but until we get rid of expansion_boundary, it's a necessity
self.toggle_active_pane_fullscreen();
}
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) {
// TODO: find out by how much we actually reduced and only reduce by that much
@ -1693,6 +1747,18 @@ impl Tab {
}
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) {
// TODO: find out by how much we actually reduced and only reduce by that much
let count = 2;

View File

@ -42,7 +42,7 @@ pub fn handle_panic(
msg,
location.file(),
location.line(),
backtrace
backtrace,
),
(Some(location), None) => format!(
"{}\n\u{1b}[0;0mError: \u{1b}[0;31mthread '{}' panicked: {}:{}\n\u{1b}[0;0m{:?}",
@ -200,6 +200,7 @@ pub enum ScreenContext {
CloseTab,
GoToTab,
UpdateTabName,
TerminalResize,
ChangeMode,
}
@ -241,6 +242,7 @@ impl From<&ScreenInstruction> for ScreenContext {
ScreenInstruction::CloseTab => ScreenContext::CloseTab,
ScreenInstruction::GoToTab(_) => ScreenContext::GoToTab,
ScreenInstruction::UpdateTabName(_) => ScreenContext::UpdateTabName,
ScreenInstruction::TerminalResize => ScreenContext::TerminalResize,
ScreenInstruction::ChangeMode(_) => ScreenContext::ChangeMode,
}
}

View File

@ -81,7 +81,8 @@ impl InputHandler {
}
termion::event::Event::Mouse(_)
| termion::event::Event::Unsupported(_) => {
unimplemented!("Mouse and unsupported events aren't supported!");
// Mouse and unsupported events aren't implemented yet,
// use a NoOp untill then.
}
},
Err(err) => panic!("Encountered read error: {:?}", err),

View File

@ -39,7 +39,9 @@ use wasm_vm::{wasi_stdout, wasi_write_string, zellij_imports, PluginInstruction}
use wasmer::{ChainableNamedResolver, Instance, Module, Store, Value};
use wasmer_wasi::{Pipe, WasiState};
use xrdb::Colors;
use zellij_tile::data::{EventType, InputMode, ModeInfo, Palette};
use zellij_tile::data::{EventType, InputMode, ModeInfo, Palette, Theme};
use self::utils::logging::debug_log_to_file;
#[derive(Serialize, Deserialize, Debug)]
pub enum ApiCommand {
@ -126,6 +128,19 @@ pub mod colors {
pub const BLACK: (u8, u8, u8) = (0, 0, 0);
}
pub fn detect_theme(bg: (u8, u8, u8)) -> Theme {
let (r, g, b) = bg;
// HSP, P stands for perceived brightness
let hsp: f64 = (0.299 * (r as f64 * r as f64)
+ 0.587 * (g as f64 * g as f64)
+ 0.114 * (b as f64 * b as f64))
.sqrt();
match hsp > 127.5 {
true => Theme::Light,
false => Theme::Dark,
}
}
pub fn load_palette() -> Palette {
let palette = match Colors::new("xresources") {
Some(colors) => {
@ -150,7 +165,13 @@ pub fn load_palette() -> Palette {
(rgb.0 as u8, rgb.1 as u8, rgb.2 as u8)
})
.collect();
let theme = detect_theme(bg);
debug_log_to_file(format!(
"{:?} {:?}, white: {:?}, black: {:?}, fg: {:?}",
theme, bg, colors[7], colors[0], fg
));
Palette {
theme,
fg,
bg,
black: colors[0],
@ -164,6 +185,7 @@ pub fn load_palette() -> Palette {
}
}
None => Palette {
theme: Theme::Dark,
fg: colors::BRIGHT_GRAY,
bg: colors::BLACK,
black: colors::BLACK,
@ -459,6 +481,9 @@ pub fn start(mut os_input: Box<dyn OsApi>, opts: CliArgs) {
ScreenInstruction::UpdateTabName(c) => {
screen.update_active_tab_name(c);
}
ScreenInstruction::TerminalResize => {
screen.resize_to_screen();
}
ScreenInstruction::ChangeMode(mode_info) => {
screen.change_mode(mode_info);
}
@ -576,6 +601,19 @@ pub fn start(mut os_input: Box<dyn OsApi>, opts: CliArgs) {
})
.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
// because otherwise the app will hang. Need to fix this so it both
// listens to the ipc-bus and is able to quit cleanly

View File

@ -13,6 +13,8 @@ use std::path::PathBuf;
use std::process::{Child, Command};
use std::sync::{Arc, Mutex};
use signal_hook::{consts::signal::*, iterator::Signals};
use std::env;
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.
fn handle_command_exit(mut child: Child) {
// 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 {
// test whether the child process has exited
match child.try_wait() {
@ -82,11 +84,16 @@ fn handle_command_exit(mut child: Child) {
}
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.wait().unwrap();
break 'handle_exit;
}
_ => {}
}
}
}
}
@ -188,6 +195,7 @@ pub trait OsApi: Send + Sync {
fn get_stdout_writer(&self) -> Box<dyn io::Write>;
/// Returns a [`Box`] pointer to this [`OsApi`] struct.
fn box_clone(&self) -> Box<dyn OsApi>;
fn receive_sigwinch(&self, cb: Box<dyn Fn()>);
}
impl OsApi for OsInputOutput {
@ -238,6 +246,20 @@ impl OsApi for OsInputOutput {
waitpid(Pid::from_raw(pid), None).unwrap();
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> {

View File

@ -50,6 +50,7 @@ pub enum ScreenInstruction {
CloseTab,
GoToTab(u32),
UpdateTabName(Vec<u8>),
TerminalResize,
ChangeMode(ModeInfo),
}
@ -221,6 +222,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`].
pub fn render(&mut self) {
if let Some(active_tab) = self.get_active_tab_mut() {

View File

@ -11,9 +11,18 @@ fn ansi_len(s: &str) -> usize {
.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()
.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)))
.take(rows)
.collect::<Vec<_>>()

View File

@ -3,14 +3,13 @@ use std::collections::{HashMap, VecDeque};
use std::io::Write;
use std::os::unix::io::RawFd;
use std::path::PathBuf;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::{Arc, Mutex};
use std::sync::{Arc, Condvar, Mutex};
use std::time::{Duration, Instant};
use crate::os_input_output::OsApi;
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);
@ -72,7 +71,8 @@ pub struct FakeInputOutput {
win_sizes: Arc<Mutex<HashMap<RawFd, PositionAndSize>>>,
possible_tty_inputs: HashMap<u16, Bytes>,
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 {
@ -91,7 +91,8 @@ impl FakeInputOutput {
io_events: Arc::new(Mutex::new(vec![])),
win_sizes: Arc::new(Mutex::new(win_sizes)),
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 {
@ -108,10 +109,20 @@ impl FakeInputOutput {
pub fn add_terminal(&mut self, fd: RawFd) {
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 {
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 winsize = win_sizes.get(&pid).unwrap();
*winsize
@ -159,7 +170,6 @@ impl OsApi for FakeInputOutput {
if bytes_read > bytes.read_position {
bytes.set_read_position(bytes_read);
}
self.started_reading_from_pty.store(true, Ordering::Release);
return Ok(bytes_read);
}
None => Err(nix::Error::Sys(nix::errno::Errno::EAGAIN)),
@ -199,6 +209,12 @@ impl OsApi for FakeInputOutput {
.unwrap_or(vec![]);
if command == SLEEP {
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
}
@ -209,4 +225,14 @@ impl OsApi for FakeInputOutput {
self.io_events.lock().unwrap().push(IoEvent::Kill(fd));
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();
}
}
}

View File

@ -6,7 +6,7 @@ use crate::tests::utils::{get_next_to_last_snapshot, get_output_frame_snapshots}
use crate::{start, CliArgs};
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,
SPLIT_DOWN_IN_PANE_MODE, SPLIT_RIGHT_IN_PANE_MODE,
};

View File

@ -12,4 +12,5 @@ pub mod resize_left;
pub mod resize_right;
pub mod resize_up;
pub mod tabs;
pub mod terminal_window_resize;
pub mod toggle_fullscreen;

View File

@ -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

View File

@ -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 $ █

View File

@ -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 $ █

View File

@ -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 $

View 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);
}

View File

@ -1,6 +1,7 @@
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_39, COL_4, COL_40, COL_47, COL_50, COL_60, COL_70, COL_8, COL_9, COL_90, COL_96,
COL_10, COL_121, COL_14, COL_141, COL_15, COL_19, COL_20, COL_24, COL_25, COL_29, COL_30,
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::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_60_bytes = Bytes::new().content_from_str(&COL_60);
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_96_bytes = Bytes::new().content_from_str(&COL_96);
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(8, col_8_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(60, col_60_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(96, col_96_bytes);
possible_inputs.insert(121, col_121_bytes);
possible_inputs.insert(141, col_141_bytes);
possible_inputs
}

View File

@ -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] = [
"line1-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\r\n",
"line2-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\r\n",
@ -457,6 +480,29 @@ pub const COL_70: [&str; 20] = [
"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] = [
"line1-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
"line2-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",

View File

@ -45,7 +45,6 @@ pub fn get_next_to_last_snapshot(mut snapshots: Vec<String>) -> Option<String> {
}
pub mod commands {
pub const COMMAND_TOGGLE: [u8; 1] = [7]; // ctrl-g
pub const QUIT: [u8; 1] = [17]; // ctrl-q
pub const ESC: [u8; 1] = [27];

View File

@ -58,6 +58,11 @@ impl Default for InputMode {
}
}
#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
pub enum Theme {
Light,
Dark
}
pub mod colors {
pub const WHITE: (u8, u8, u8) = (238, 238, 238);
pub const GREEN: (u8, u8, u8) = (175, 255, 0);
@ -69,6 +74,7 @@ pub mod colors {
#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
pub struct Palette {
pub theme: Theme,
pub fg: (u8, u8, u8),
pub bg: (u8, u8, u8),
pub black: (u8, u8, u8),
@ -84,6 +90,7 @@ pub struct Palette {
impl Default for Palette {
fn default() -> Palette {
Palette {
theme: Theme::Dark,
fg: colors::BRIGHT_GRAY,
bg: colors::BLACK,
black: colors::BLACK,