diff options
| author | denis <denismaximov98@gmail.com> | 2021-04-22 11:45:29 +0300 |
|---|---|---|
| committer | denis <denismaximov98@gmail.com> | 2021-04-22 11:45:29 +0300 |
| commit | 8d98ca7da0bc278a832e4e7de23ff63a84deb529 (patch) | |
| tree | e7fdfaa6c1ae25e7737dbb36bd1dbcb94d62ab47 /src | |
| parent | wip: fixing the first arrow (diff) | |
| parent | fix(cargo): reduce crate size by 4.8MB using `cargo diet`, to 77kB (diff) | |
| download | sl0ppij-8d98ca7da0bc278a832e4e7de23ff63a84deb529.tar.gz sl0ppij-8d98ca7da0bc278a832e4e7de23ff63a84deb529.tar.xz sl0ppij-8d98ca7da0bc278a832e4e7de23ff63a84deb529.zip | |
wip: merge main in
Diffstat (limited to 'src')
37 files changed, 1028 insertions, 1056 deletions
@@ -1,6 +1,9 @@ use std::path::PathBuf; use structopt::StructOpt; +// TODO add to consts.rs +const ZELLIJ_CONFIG_ENV: &str = "ZELLIJ_CONFIG"; + #[derive(StructOpt, Default, Debug)] #[structopt(name = "zellij")] pub struct CliArgs { @@ -20,12 +23,20 @@ pub struct CliArgs { #[structopt(long)] pub max_panes: Option<usize>, + /// Change where zellij looks for layouts and plugins + #[structopt(long)] + pub data_dir: Option<PathBuf>, + /// Path to a layout yaml file #[structopt(short, long)] pub layout: Option<PathBuf>, + /// Change where zellij looks for the configuration + #[structopt(short, long, env=ZELLIJ_CONFIG_ENV)] + pub config: Option<PathBuf>, + #[structopt(subcommand)] - pub config: Option<ConfigCli>, + pub option: Option<ConfigCli>, #[structopt(short, long)] pub debug: bool, @@ -33,10 +44,9 @@ pub struct CliArgs { #[derive(Debug, StructOpt)] pub enum ConfigCli { - /// Path to the configuration yaml file - #[structopt(alias = "c")] + /// Change the behaviour of zellij + #[structopt(name = "option")] Config { - path: Option<PathBuf>, #[structopt(long)] /// Disables loading of configuration file at default location clean: bool, diff --git a/src/client/layout.rs b/src/client/layout.rs index 2d1daaf4..e82f9045 100644 --- a/src/client/layout.rs +++ b/src/client/layout.rs @@ -1,6 +1,5 @@ -use directories_next::ProjectDirs; use serde::{Deserialize, Serialize}; -use std::path::PathBuf; +use std::path::{Path, PathBuf}; use std::{fs::File, io::prelude::*}; use crate::panes::PositionAndSize; @@ -177,16 +176,12 @@ pub struct Layout { pub split_size: Option<SplitSize>, #[serde(skip_serializing_if = "Option::is_none")] pub plugin: Option<PathBuf>, - #[serde(default)] - pub expansion_boundary: bool, } impl Layout { - pub fn new(layout_path: PathBuf) -> Self { - let project_dirs = ProjectDirs::from("org", "Zellij Contributors", "Zellij").unwrap(); - let layout_dir = project_dirs.data_dir().join("layouts/"); + pub fn new(layout_path: &Path, data_dir: &Path) -> Self { + let layout_dir = data_dir.join("layouts/"); let mut layout_file = File::open(&layout_path) - .or_else(|_| File::open(&layout_path.with_extension("yaml"))) .or_else(|_| File::open(&layout_dir.join(&layout_path).with_extension("yaml"))) .unwrap_or_else(|_| panic!("cannot find layout {}", &layout_path.display())); diff --git a/src/client/pane_resizer.rs b/src/client/pane_resizer.rs index 007dc33f..f9ec71b8 100644 --- a/src/client/pane_resizer.rs +++ b/src/client/pane_resizer.rs @@ -1,7 +1,10 @@ use crate::os_input_output::OsApi; use crate::panes::{PaneId, PositionAndSize}; use crate::tab::Pane; -use std::collections::{BTreeMap, HashSet}; +use std::{ + cmp::Ordering, + collections::{BTreeMap, HashSet}, +}; pub struct PaneResizer<'a> { panes: &'a mut BTreeMap<PaneId, Box<dyn Pane>>, @@ -9,9 +12,7 @@ pub struct PaneResizer<'a> { } // 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 +// all resizing functions should move here impl<'a> PaneResizer<'a> { pub fn new( @@ -29,63 +30,72 @@ impl<'a> PaneResizer<'a> { 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; - }); + match new_size.columns.cmp(¤t_size.columns) { + Ordering::Greater => { + let increase_by = new_size.columns - current_size.columns; + if let Some(panes_to_resize) = find_increasable_vertical_chain( + &self.panes, + increase_by, + current_size.columns, + current_size.rows, + ) { + self.increase_panes_right_and_push_adjacents_right( + panes_to_resize, + increase_by, + ); + column_difference = new_size.columns as isize - current_size.columns as isize; + current_size.columns = + (current_size.columns as isize + column_difference) as usize; + successfully_resized = true; + }; + } + Ordering::Less => { + let reduce_by = current_size.columns - new_size.columns; + if let Some(panes_to_resize) = find_reducible_vertical_chain( + &self.panes, + reduce_by, + current_size.columns, + current_size.rows, + ) { + self.reduce_panes_left_and_pull_adjacents_left(panes_to_resize, reduce_by); + column_difference = new_size.columns as isize - current_size.columns as isize; + current_size.columns = + (current_size.columns as isize + column_difference) as usize; + successfully_resized = true; + }; + } + Ordering::Equal => (), } - 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; - }); + match new_size.rows.cmp(¤t_size.rows) { + Ordering::Greater => { + let increase_by = new_size.rows - current_size.rows; + if let Some(panes_to_resize) = find_increasable_horizontal_chain( + &self.panes, + increase_by, + current_size.columns, + current_size.rows, + ) { + self.increase_panes_down_and_push_down_adjacents(panes_to_resize, increase_by); + row_difference = new_size.rows as isize - current_size.rows as isize; + current_size.rows = (current_size.rows as isize + row_difference) as usize; + successfully_resized = true; + }; + } + Ordering::Less => { + let reduce_by = current_size.rows - new_size.rows; + if let Some(panes_to_resize) = find_reducible_horizontal_chain( + &self.panes, + reduce_by, + current_size.columns, + current_size.rows, + ) { + self.reduce_panes_up_and_pull_adjacents_up(panes_to_resize, reduce_by); + row_difference = new_size.rows as isize - current_size.rows as isize; + current_size.rows = (current_size.rows as isize + row_difference) as usize; + successfully_resized = true; + }; + } + Ordering::Equal => (), } if successfully_resized { Some((column_difference, row_difference)) @@ -229,13 +239,12 @@ impl<'a> PaneResizer<'a> { fn find_next_increasable_horizontal_pane( panes: &BTreeMap<PaneId, Box<dyn Pane>>, - right_of: &Box<dyn Pane>, + right_of: &dyn Pane, increase_by: usize, ) -> Option<PaneId> { let next_pane_candidates = panes.values().filter( |p| { - p.x() == right_of.x() + right_of.columns() + 1 - && p.horizontally_overlaps_with(right_of.as_ref()) + p.x() == right_of.x() + right_of.columns() + 1 && p.horizontally_overlaps_with(right_of) }, // TODO: the name here is wrong, it should be vertically_overlaps_with ); let resizable_candidates = @@ -255,11 +264,11 @@ fn find_next_increasable_horizontal_pane( fn find_next_increasable_vertical_pane( panes: &BTreeMap<PaneId, Box<dyn Pane>>, - below: &Box<dyn Pane>, + below: &dyn Pane, increase_by: usize, ) -> Option<PaneId> { let next_pane_candidates = panes.values().filter( - |p| p.y() == below.y() + below.rows() + 1 && p.vertically_overlaps_with(below.as_ref()), // TODO: the name here is wrong, it should be horizontally_overlaps_with + |p| p.y() == below.y() + below.rows() + 1 && p.vertically_overlaps_with(below), // TODO: the name here is wrong, it should be horizontally_overlaps_with ); let resizable_candidates = next_pane_candidates.filter(|p| p.can_increase_width_by(increase_by)); @@ -278,11 +287,11 @@ fn find_next_increasable_vertical_pane( fn find_next_reducible_vertical_pane( panes: &BTreeMap<PaneId, Box<dyn Pane>>, - below: &Box<dyn Pane>, + below: &dyn Pane, reduce_by: usize, ) -> Option<PaneId> { let next_pane_candidates = panes.values().filter( - |p| p.y() == below.y() + below.rows() + 1 && p.vertically_overlaps_with(below.as_ref()), // TODO: the name here is wrong, it should be horizontally_overlaps_with + |p| p.y() == below.y() + below.rows() + 1 && p.vertically_overlaps_with(below), // TODO: the name here is wrong, it should be horizontally_overlaps_with ); let resizable_candidates = next_pane_candidates.filter(|p| p.can_reduce_width_by(reduce_by)); resizable_candidates.fold(None, |next_pane_id, p| match next_pane_id { @@ -300,13 +309,12 @@ fn find_next_reducible_vertical_pane( fn find_next_reducible_horizontal_pane( panes: &BTreeMap<PaneId, Box<dyn Pane>>, - right_of: &Box<dyn Pane>, + right_of: &dyn Pane, reduce_by: usize, ) -> Option<PaneId> { let next_pane_candidates = panes.values().filter( |p| { - p.x() == right_of.x() + right_of.columns() + 1 - && p.horizontally_overlaps_with(right_of.as_ref()) + p.x() == right_of.x() + right_of.columns() + 1 && p.horizontally_overlaps_with(right_of) }, // TODO: the name here is wrong, it should be vertically_overlaps_with ); let resizable_candidates = next_pane_candidates.filter(|p| p.can_reduce_height_by(reduce_by)); @@ -351,7 +359,11 @@ fn find_increasable_horizontal_chain( 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) { + match find_next_increasable_horizontal_pane( + panes, + current_pane.as_ref(), + increase_by, + ) { Some(next_pane_id) => { current_pane = panes.get(&next_pane_id).unwrap(); } @@ -397,7 +409,11 @@ fn find_increasable_vertical_chain( 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) { + match find_next_increasable_vertical_pane( + panes, + current_pane.as_ref(), + increase_by, + ) { Some(next_pane_id) => { current_pane = panes.get(&next_pane_id).unwrap(); } @@ -443,7 +459,11 @@ fn find_reducible_horizontal_chain( 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) { + match find_next_reducible_horizontal_pane( + panes, + current_pane.as_ref(), + reduce_by, + ) { Some(next_pane_id) => { current_pane = panes.get(&next_pane_id).unwrap(); } @@ -489,7 +509,11 @@ fn find_reducible_vertical_chain( 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) { + match find_next_reducible_vertical_pane( + panes, + current_pane.as_ref(), + increase_by, + ) { Some(next_pane_id) => { current_pane = panes.get(&next_pane_id).unwrap(); } diff --git a/src/client/panes/grid.rs b/src/client/panes/grid.rs index 7651bdc0..c6dd201e 100644 --- a/src/client/panes/grid.rs +++ b/src/client/panes/grid.rs @@ -1,9 +1,13 @@ use std::{ cmp::Ordering, + collections::VecDeque, fmt::{self, Debug, Formatter}, }; -static TABSTOP_WIDTH: usize = 8; // TODO: is this always right? +const TABSTOP_WIDTH: usize = 8; // TODO: is this always right? +const SCROLL_BACK: usize = 10_000; + +use crate::utils::logging::debug_log_to_file; use crate::panes::terminal_character::{ CharacterStyles, TerminalCharacter, EMPTY_TERMINAL_CHARACTER, @@ -26,14 +30,12 @@ fn get_top_non_canonical_rows(rows: &mut Vec<Row>) -> Vec<Row> { } } -fn get_bottom_canonical_row_and_wraps(rows: &mut Vec<Row>) -> Vec<Row> { +fn get_bottom_canonical_row_and_wraps(rows: &mut VecDeque<Row>) -> Vec<Row> { let mut index_of_last_non_canonical_row = None; for (i, row) in rows.iter().enumerate().rev() { + index_of_last_non_canonical_row = Some(i); if row.is_canonical { - index_of_last_non_canonical_row = Some(i); break; - } else { - index_of_last_non_canonical_row = Some(i); } } match index_of_last_non_canonical_row { @@ -45,7 +47,7 @@ fn get_bottom_canonical_row_and_wraps(rows: &mut Vec<Row>) -> Vec<Row> { } fn transfer_rows_down( - source: &mut Vec<Row>, + source: &mut VecDeque<Row>, destination: &mut Vec<Row>, count: usize, max_src_width: Option<usize>, @@ -58,7 +60,7 @@ fn transfer_rows_down( break; } if next_lines.is_empty() { - match source.pop() { + match source.pop_back() { Some(next_line) => { let mut top_non_canonical_rows_in_dst = get_top_non_canonical_rows(destination); lines_added_to_destination -= top_non_canonical_rows_in_dst.len() as isize; @@ -84,13 +86,12 @@ fn transfer_rows_down( if !next_lines.is_empty() { match max_src_width { Some(max_row_width) => { - let mut excess_rows = - Row::from_rows(next_lines).split_to_rows_of_length(max_row_width); - source.append(&mut excess_rows); + let excess_rows = Row::from_rows(next_lines).split_to_rows_of_length(max_row_width); + source.extend(excess_rows); } None => { let excess_row = Row::from_rows(next_lines); - source.push(excess_row); + bounded_push(source, excess_row); } } } @@ -98,7 +99,7 @@ fn transfer_rows_down( fn transfer_rows_up( source: &mut Vec<Row>, - destination: &mut Vec<Row>, + destination: &mut VecDeque<Row>, count: usize, max_src_width: Option<usize>, max_dst_width: Option<usize>, @@ -124,7 +125,7 @@ fn transfer_rows_up( break; // no more rows } } - destination.push(next_lines.remove(0)); + bounded_push(destination, next_lines.remove(0)); } if !next_lines.is_empty() { match max_src_width { @@ -142,13 +143,25 @@ fn transfer_rows_up( } } +fn bounded_push(vec: &mut VecDeque<Row>, value: Row) { + if vec.len() >= SCROLL_BACK { + vec.pop_front(); + } + vec.push_back(value) +} + #[derive(Clone)] pub struct Grid { - lines_above: Vec<Row>, + lines_above: VecDeque<Row>, viewport: Vec<Row>, lines_below: Vec<Row>, + alternative_lines_above_viewport_and_cursor: Option<(VecDeque<Row>, Vec<Row>, Cursor)>, cursor: Cursor, scroll_region: Option<(usize, usize)>, + pending_styles: CharacterStyles, + pub should_render: bool, + pub cursor_key_mode: bool, // DECCKM - when set, cursor keys should send ANSI direction codes (eg. "OD") instead of the arrow keys (eg. "[D") + pub clear_viewport_before_rendering: bool, pub width: usize, pub height: usize, } @@ -169,13 +182,18 @@ impl Debug for Grid { impl Grid { pub fn new(rows: usize, columns: usize) -> Self { Grid { - lines_above: vec![], + lines_above: VecDeque::with_capacity(SCROLL_BACK), viewport: vec![Row::new().canonical()], lines_below: vec![], cursor: Cursor::new(0, 0), scroll_region: None, width: columns, height: rows, + pending_styles: CharacterStyles::new(), + should_render: true, + cursor_key_mode: false, + alternative_lines_above_viewport_and_cursor: None, + clear_viewport_before_rendering: false, } } pub fn advance_to_next_tabstop(&mut self, styles: CharacterStyles) { @@ -237,7 +255,7 @@ impl Grid { if !self.lines_above.is_empty() && self.viewport.len() == self.height { let line_to_push_down = self.viewport.pop().unwrap(); self.lines_below.insert(0, line_to_push_down); - let line_to_insert_at_viewport_top = self.lines_above.pop().unwrap(); + let line_to_insert_at_viewport_top = self.lines_above.pop_back().unwrap(); self.viewport.insert(0, line_to_insert_at_viewport_top); } } @@ -245,11 +263,11 @@ impl Grid { if !self.lines_below.is_empty() && self.viewport.len() == self.height { let mut line_to_push_up = self.viewport.remove(0); if line_to_push_up.is_canonical { - self.lines_above.push(line_to_push_up); + bounded_push(&mut self.lines_above, line_to_push_up); } else { - let mut last_line_above = self.lines_above.pop().unwrap(); + let mut last_line_above = self.lines_above.pop_back().unwrap(); last_line_above.append(&mut line_to_push_up.columns); - self.lines_above.push(last_line_above); + bounded_push(&mut self.lines_above, last_line_above); } let line_to_insert_at_viewport_bottom = self.lines_below.remove(0); self.viewport.push(line_to_insert_at_viewport_bottom); @@ -265,7 +283,7 @@ impl Grid { && viewport_canonical_lines.is_empty() && !self.lines_above.is_empty() { - let mut first_line_above = self.lines_above.pop().unwrap(); + let mut first_line_above = self.lines_above.pop_back().unwrap(); first_line_above.append(&mut row.columns); viewport_canonical_lines.push(first_line_above); cursor_canonical_line_index += 1; @@ -429,13 +447,35 @@ impl Grid { self.scroll_down_one_line(); } } - pub fn rotate_scroll_region_up(&mut self, _count: usize) { - // TBD + pub fn rotate_scroll_region_up(&mut self, count: usize) { + if let Some((scroll_region_top, scroll_region_bottom)) = self.scroll_region { + for _ in 0..count { + let columns = vec![EMPTY_TERMINAL_CHARACTER; self.width]; + if scroll_region_bottom < self.viewport.len() { + self.viewport.remove(scroll_region_bottom); + } + if scroll_region_top < self.viewport.len() { + self.viewport + .insert(scroll_region_top, Row::from_columns(columns).canonical()); + } + } + } } - pub fn rotate_scroll_region_down(&mut self, _count: usize) { - // TBD + pub fn rotate_scroll_region_down(&mut self, count: usize) { + if let Some((scroll_region_top, scroll_region_bottom)) = self.scroll_region { + for _ in 0..count { + let columns = vec![EMPTY_TERMINAL_CHARACTER; self.width]; + self.viewport.remove(scroll_region_top); + if self.viewport.len() > scroll_region_top { + self.viewport + .insert(scroll_region_bottom, Row::from_columns(columns).canonical()); + } else { + self.viewport.push(Row::from_columns(columns).canonical()); + } + } + } } - pub fn add_canonical_line(&mut self, pad_character: TerminalCharacter) { + pub fn add_canonical_line(&mut self) { if let Some((scroll_region_top, scroll_region_bottom)) = self.scroll_region { if self.cursor.y == scroll_region_bottom { // end of scroll region @@ -444,8 +484,12 @@ impl Grid { // then we add an empty line at its end which will be filled by the application // controlling the scroll region (presumably filled by whatever comes next in the // scroll buffer, but that's not something we control) + if scroll_region_top >= self.viewport.len() { + // the state is corrupted + return; + } self.viewport.remove(scroll_region_top); - let columns = vec![pad_character; self.width]; + let columns = vec![EMPTY_TERMINAL_CHARACTER; self.width]; self.viewport .insert(scroll_region_bottom, Row::from_columns(columns).canonical()); return; @@ -483,6 +527,24 @@ impl Grid { } pub fn insert_character_at_cursor_position(&mut self, terminal_character: TerminalCharacter) { match self.viewport.get_mut(self.cursor.y) { + Some(row) => { + row.insert_character_at(terminal_character, self.cursor.x); + if row.len() > self.width { + row.truncate(self.width); + } + } + None => { + // pad lines until cursor if they do not exist + for _ in self.viewport.len()..self.cursor.y { + self.viewport.push(Row::new().canonical()); + } + self.viewport + .push(Row::new().with_character(terminal_character).canonical()); + } + } + } + pub fn add_character_at_cursor_position(&mut self, terminal_character: TerminalCharacter) { + match self.viewport.get_mut(self.cursor.y) { Some(row) => row.add_character_at(terminal_character, self.cursor.x), None => { // pad lines until cursor if they do not exist @@ -496,9 +558,7 @@ impl Grid { } pub fn add_character(&mut self, terminal_character: TerminalCharacter) { // TODO: try to separate adding characters from moving the cursors in this function - if self.cursor.x < self.width { - self.insert_character_at_cursor_position(terminal_character); - } else { + if self.cursor.x >= self.width { // line wrap self.cursor.x = 0; if self.cursor.y == self.height - 1 { @@ -519,8 +579,8 @@ impl Grid { self.viewport.push(line_wrapped_row); } } - self.insert_character_at_cursor_position(terminal_character); } + self.add_character_at_cursor_position(terminal_character); self.move_cursor_forward_until_edge(1); } pub fn move_cursor_forward_until_edge(&mut self, count: usize) { @@ -546,15 +606,17 @@ impl Grid { row.replace_beginning_with(line_part); } pub fn clear_all_after_cursor(&mut self, replace_with: TerminalCharacter) { - let cursor_row = self.viewport.get_mut(self.cursor.y).unwrap(); - cursor_row.truncate(self.cursor.x); - let mut replace_with_columns_in_cursor_row = vec![replace_with; self.width - self.cursor.x]; - cursor_row.append(&mut replace_with_columns_in_cursor_row); + if let Some(cursor_row) = self.viewport.get_mut(self.cursor.y).as_mut() { + cursor_row.truncate(self.cursor.x); + let mut replace_with_columns_in_cursor_row = + vec![replace_with; self.width - self.cursor.x]; + cursor_row.append(&mut replace_with_columns_in_cursor_row); - let replace_with_columns = vec![replace_with; self.width]; - self.replace_characters_in_line_after_cursor(replace_with); - for row in self.viewport.iter_mut().skip(self.cursor.y + 1) { - row.replace_columns(replace_with_columns.clone()); + let replace_with_columns = vec![replace_with; self.width]; + self.replace_characters_in_line_after_cursor(replace_with); + for row in self.viewport.iter_mut().skip(self.cursor.y + 1) { + row.replace_columns(replace_with_columns.clone()); + } } } pub fn clear_cursor_line(&mut self) { @@ -600,7 +662,9 @@ impl Grid { if current_line_index == scroll_region_top { // if we're at the top line, we create a new line and remove the last line that // would otherwise overflow - self.viewport.remove(scroll_region_bottom); + if scroll_region_bottom < self.viewport.len() { + self.viewport.remove(scroll_region_bottom); + } self.viewport.insert(current_line_index, Row::new()); // TODO: .canonical() ? } else if current_line_index > scroll_region_top && current_line_index <= scroll_region_bottom @@ -621,7 +685,7 @@ impl Grid { self.cursor.y + count }; for _ in 0..lines_to_add { - self.add_canonical_line(pad_character); + self.add_canonical_line(); } self.pad_lines_until(self.cursor.y, pad_character); } @@ -663,8 +727,12 @@ impl Grid { for _ in 0..count { self.viewport.remove(current_line_index); let columns = vec![pad_character; self.width]; - self.viewport - .insert(scroll_region_bottom, Row::from_columns(columns).canonical()); + if self.viewport.len() > scroll_region_bottom { + self.viewport + .insert(scroll_region_bottom, Row::from_columns(columns).canonical()); + } else { + self.viewport.push(Row::from_columns(columns).canonical()); + } } } } @@ -683,7 +751,9 @@ impl Grid { // so we add an empty line where the cursor currently is, and delete the last line // of the scroll region for _ in 0..count { - self.viewport.remove(scroll_region_bottom); + if scroll_region_bottom < self.viewport.len() { + self.viewport.remove(scroll_region_bottom); + } let columns = vec![pad_character; self.width]; self.viewport .insert(current_line_index, Row::from_columns(columns).canonical()); @@ -723,6 +793,320 @@ impl Grid { .unwrap() .append(&mut empty_space_to_append); } + fn add_newline(&mut self) { + self.add_canonical_line(); + self.mark_for_rerender(); + } + pub fn mark_for_rerender(&mut self) { + self.should_render = true; + } + fn reset_terminal_state(&mut self) { + self.lines_above = VecDeque::with_capacity(SCROLL_BACK); + self.lines_below = vec![]; + self.viewport = vec![Row::new().canonical()]; + self.alternative_lines_above_viewport_and_cursor = None; + self.cursor_key_mode = false; + self.scroll_region = None; + self.clear_viewport_before_rendering = true; + self.cursor = Cursor::new(0, 0); + } +} + +impl vte::Perform for Grid { + fn print(&mut self, c: char) { + // apparently, building TerminalCharacter like this without a "new" method + // is a little faster + let terminal_character = TerminalCharacter { + character: c, + styles: self.pending_styles, + }; + self.add_character(terminal_character); + } + + fn execute(&mut self, byte: u8) { + match byte { + 8 => { + // backspace + self.move_cursor_backwards(1); + } + 9 => { + // tab + self.advance_to_next_tabstop(self.pending_styles); + } + 10 => { + // 0a, newline + self.add_newline(); + } + 13 => { + // 0d, carriage return + self.move_cursor_to_beginning_of_line(); + } + _ => {} + } + } + + fn hook(&mut self, _params: &[i64], _intermediates: &[u8], _ignore: bool, _c: char) { + // TBD + } + + fn put(&mut self, _byte: u8) { + // TBD + } + + fn unhook(&mut self) { + // TBD + } + + fn osc_dispatch(&mut self, _params: &[&[u8]], _bell_terminated: bool) { + // TBD + } + + fn csi_dispatch(&mut self, params: &[i64], _intermediates: &[u8], _ignore: bool, c: char) { + if c == 'm' { + self.pending_styles.add_style_from_ansi_params(params); + } else if c == 'C' { + // move cursor forward + let move_by = if params[0] == 0 { + 1 + } else { + params[0] as usize + }; + self.move_cursor_forward_until_edge(move_by); + } else if c == 'K' { + // clear line (0 => right, 1 => left, 2 => all) + if params[0] == 0 { + let mut char_to_replace = EMPTY_TERMINAL_CHARACTER; + char_to_replace.styles = self.pending_styles; + self.replace_characters_in_line_after_cursor(char_to_replace); + } else if params[0] == 1 { + let mut char_to_replace = EMPTY_TERMINAL_CHARACTER; + char_to_replace.styles = self.pending_styles; + self.replace_characters_in_line_before_cursor(char_to_replace); + } else if params[0] == 2 { + self.clear_cursor_line(); + } + } else if c == 'J' { + // clear all (0 => below, 1 => above, 2 => all, 3 => saved) + let mut char_to_replace = EMPTY_TERMINAL_CHARACTER; + char_to_replace.styles = self.pending_styles; + if params[0] == 0 { + self.clear_all_after_cursor(char_to_replace); + } else if params[0] == 2 { + self.clear_all(char_to_replace); + } + // TODO: implement 1 + } else if c == 'H' { + // goto row/col + // we subtract 1 from the row/column because these are 1 indexed + // (except when they are 0, in which case they should be 1 + // don't look at me, I don't make the rules) + let (row, col) = if params.len() == 1 { + if params[0] == 0 { + (0, params[0] as usize) + } else { + ((params[0] as usize).saturating_sub(1), params[0] as usize) + } + } else if params[0] == 0 { + (0, (params[1] as usize).saturating_sub(1)) + } else { + ( + (params[0] as usize).saturating_sub(1), + (params[1] as usize).saturating_sub(1), + ) + }; + let pad_character = EMPTY_TERMINAL_CHARACTER; + self.move_cursor_to(col, row, pad_character); + } else if c == 'A' { + // move cursor up until edge of screen + let move_up_count = if params[0] == 0 { 1 } else { params[0] }; + self.move_cursor_up(move_up_count as usize); + } else if c == 'B' { + // move cursor down until edge of screen + let move_down_count = if params[0] == 0 { 1 } else { params[0] }; + let pad_character = EMPTY_TERMINAL_CHARACTER; + self.move_cursor_down(move_down_count as usize, pad_character); + } else if c == 'D' { + let move_back_count = if params[0] == 0 { + 1 + } else { + params[0] as usize + }; + self.move_cursor_back(move_back_count); + } else if c == 'l' { + let first_intermediate_is_questionmark = match _intermediates.get(0) { + Some(b'?') => true, + None => false, + _ => false, + }; + if first_intermediate_is_questionmark { + match params.get(0) { + Some(&1049) => { + if let Some(( + alternative_lines_above, + alternative_viewport, + alternative_cursor, + )) = self.alternative_lines_above_viewport_and_cursor.as_mut() + { + std::mem::swap(&mut self.lines_above, alternative_lines_above); + std::mem::swap(&mut self.viewport, alternative_viewport); + std::mem::swap(&mut self.cursor, alternative_cursor); + } + self.alternative_lines_above_viewport_and_cursor = None; + self.clear_viewport_before_rendering = true; + self.change_size(self.height, self.width); // the alternative_viewport might have been of a different size... + self.mark_for_rerender(); + } + Some(&25) => { + self.hide_cursor(); + self.mark_for_rerender(); + } + Some(&1) => { + self.cursor_key_mode = false; + } + _ => {} + }; + } + } else if c == 'h' { + let first_intermediate_is_questionmark = match _intermediates.get(0) { + Some(b'?') => true, + None => false, + _ => false, + }; + if first_intermediate_is_questionmark { + match params.get(0) { + Some(&25) => { + self.show_cursor(); + self.mark_for_rerender(); + } + Some(&1049) => { + let current_lines_above = std::mem::replace( + &mut self.lines_above, + VecDeque::with_capacity(SCROLL_BACK), + ); + let current_viewport = + std::mem::replace(&mut self.viewport, vec![Row::new().canonical()]); + let current_cursor = std::mem::replace(&mut self.cursor, Cursor::new(0, 0)); + self.alternative_lines_above_viewport_and_cursor = + Some((current_lines_above, current_viewport, current_cursor)); + self.clear_viewport_before_rendering = true; + } + Some(&1) => { + self.cursor_key_mode = true; + } + _ => {} + }; + } + } else if c == 'r' { + if params.len() > 1 { + // minus 1 because these are 1 indexed + let top_line_index = (params[0] as usize).saturating_sub(1); + let bottom_line_index = (params[1] as usize).saturating_sub(1); + self.set_scroll_region(top_line_index, bottom_line_index); + self.show_cursor(); + } else { + self.clear_scroll_region(); + } + } else if c == 'M' { + // delete lines if currently inside scroll region + let line_count_to_delete = if params[0] == 0 { + 1 + } else { + params[0] as usize + }; + let pad_character = EMPTY_TERMINAL_CHARACTER; + self.delete_lines_in_scroll_region(line_count_to_delete, pad_character); + } else if c == 'L' { + // insert blank lines if inside scroll region + let line_count_to_add = if params[0] == 0 { + 1 + } else { + params[0] as usize + }; + let pad_character = EMPTY_TERMINAL_CHARACTER; + self.add_empty_lines_in_scroll_region(line_count_to_add, pad_character); + } else if c == 'q' { + // ignore for now to run on mac + } else if c == 'G' { + let column = if params[0] == 0 { + 0 + } else { + params[0] as usize - 1 + }; + self.move_cursor_to_column(column); + } else if c == 'd' { + // goto line + let line = if params[0] == 0 { + 1 + } else { + // minus 1 because this is 1 indexed + params[0] as usize - 1 + }; + let pad_character = EMPTY_TERMINAL_CHARACTER; + self.move_cursor_to_line(line, pad_character); + } else if c == 'P' { + // erase characters + let count = if params[0] == 0 { + 1 + } else { + params[0] as usize + }; + self.erase_characters(count, self.pending_styles); + } else if c == 'X' { + // erase characters and replace with empty characters of current style + let count = if params[0] == 0 { + 1 + } else { + params[0] as usize + }; + self.replace_with_empty_chars(count, self.pending_styles); + } else if c == 'T' { + /* + * 124 54 T SD + * Scroll down, new lines inserted at top of screen + * [4T = Scroll down 4, bring previous lines back into view + */ + let line_count: i64 = *params.get(0).expect("A number of lines was expected."); + + if line_count >= 0 { + self.rotate_scroll_region_up(line_count as usize); + } else { + // TODO: can this actually happen? + self.rotate_scroll_region_down(line_count.abs() as usize); + } + } else if c == 'S' { + // move scroll up + let count = if params[0] == 0 { + 1 + } else { + params[0] as usize + }; + self.rotate_scroll_region_down(count); + } else if c == '@' { + let count = if params[0] == 0 { + 1 + } else { + params[0] as usize + }; + for _ in 0..count { + // TODO: should this be styled? + self.insert_character_at_cursor_position(EMPTY_TERMINAL_CHARACTER); + } + } else { + let _ = debug_log_to_file(format!("Unhandled csi: {}->{:?}", c, params)); + } + } + + fn esc_dispatch(&mut self, intermediates: &[u8], _ignore: bool, byte: u8) { + match (byte, intermediates.get(0)) { + (b'M', None) => { + self.move_cursor_up_with_scrolling(1); + } + (b'c', None) => { + self.reset_terminal_state(); + } + _ => {} + } + } } #[derive(Clone)] @@ -786,10 +1170,24 @@ impl Row { } } } + pub fn insert_character_at(&mut self, terminal_character: TerminalCharacter, x: usize) { + match self.columns.len().cmp(&x) { + Ordering::Equal => self.columns.push(terminal_character), + Ordering::Less => { + self.columns.resize(x, EMPTY_TERMINAL_CHARACTER); + self.columns.push(terminal_character); + } + Ordering::Greater => { + self.columns.insert(x, terminal_character); + } + } + } pub fn replace_character_at(&mut self, terminal_character: TerminalCharacter, x: usize) { // this is much more performant than remove/insert - self.columns.push(terminal_character); - self.columns.swap_remove(x); + if x < self.columns.len() { + self.columns.push(terminal_character); + self.columns.swap_remove(x); + } } pub fn replace_columns(&mut self, columns: Vec<TerminalCharacter>) { self.columns = columns; @@ -804,7 +1202,11 @@ impl Row { self.columns.append(to_append); } pub fn replace_beginning_with(&mut self, mut line_part: Vec<TerminalCharacter>) { - drop(self.columns.drain(0..line_part.len())); + if line_part.len() > self.columns.len() { + self.columns.clear(); + } else { + drop(self.columns.drain(0..line_part.len())); + } line_part.append(&mut self.columns); self.columns = line_part; } @@ -812,7 +1214,9 @@ impl Row { self.columns.len() } pub fn delete_character(&mut self, x: usize) { - self.columns.remove(x); + if x < self.columns.len() { + self.columns.remove(x); + } } pub fn split_to_rows_of_length(&mut self, max_row_length: usize) -> Vec<Row> { let mut parts: Vec<Row> = vec![]; diff --git a/src/client/panes/plugin_pane.rs b/src/client/panes/plugin_pane.rs index 49cf2aee..24daec08 100644 --- a/src/client/panes/plugin_pane.rs +++ b/src/client/panes/plugin_pane.rs @@ -1,5 +1,3 @@ -#![allow(clippy::clippy::if_same_then_else)] - use crate::{common::SenderWithContext, pty_bus::VteBytes, tab::Pane, wasm_vm::PluginInstruction}; use std::{sync::mpsc::channel, unimplemented}; diff --git a/src/client/panes/terminal_character.rs b/src/client/panes/terminal_character.rs index ce967ef8..7569e993 100644 --- a/src/client/panes/terminal_character.rs +++ b/src/client/panes/terminal_character.rs @@ -48,7 +48,7 @@ pub enum NamedColor { } impl NamedColor { - fn to_foreground_ansi_code(&self) -> String { + fn to_foreground_ansi_code(self) -> String { match self { NamedColor::Black => format!("{}", 30), NamedColor::Red => format!("{}", 31), @@ -68,7 +68,7 @@ impl NamedColor { NamedColor::BrightWhite => format!("{}", 97), } } - fn to_background_ansi_code(&self) -> String { + fn to_background_ansi_code(self) -> String { match self { NamedColor::Black => format!("{}", 40), NamedColor::Red => format!("{}", 41), diff --git a/src/client/panes/terminal_pane.rs b/src/client/panes/terminal_pane.rs index d2473ba3..5d63a100 100644 --- a/src/client/panes/terminal_pane.rs +++ b/src/client/panes/terminal_pane.rs @@ -1,5 +1,3 @@ -#![allow(clippy::clippy::if_same_then_else)] - use crate::tab::Pane; use ::nix::pty::Winsize; use ::std::os::unix::io::RawFd; @@ -10,7 +8,6 @@ use crate::panes::terminal_character::{ CharacterStyles, TerminalCharacter, EMPTY_TERMINAL_CHARACTER, }; use crate::pty_bus::VteBytes; -use crate::utils::logging::debug_log_to_file; #[derive(PartialEq, Eq, Ord, PartialOrd, Hash, Clone, Copy, Debug)] pub enum PaneId { @@ -38,19 +35,14 @@ impl From<Winsize> for PositionAndSize { } } -#[derive(Debug)] pub struct TerminalPane { pub grid: Grid, - pub alternative_grid: Option<Grid>, // for 1049h/l instructions which tell us to switch between these two pub pid: RawFd, - pub should_render: bool, pub selectable: bool, pub position_and_size: PositionAndSize, pub position_and_size_override: Option<PositionAndSize>, - pub cursor_key_mode: bool, // DECCKM - when set, cursor keys should send ANSI direction codes (eg. "OD") instead of the arrow keys (eg. "[D") pub max_height: Option<usize>, - pending_styles: CharacterStyles, - clear_viewport_before_rendering: bool, + vte_parser: vte::Parser, } impl Pane for TerminalPane { @@ -86,9 +78,8 @@ impl Pane for TerminalPane { self.reflow_lines(); } fn handle_pty_bytes(&mut self, bytes: VteBytes) { - let mut vte_parser = vte::Parser::new(); for byte in bytes.iter() { - vte_parser.advance(self, *byte); + self.vte_parser.advance(&mut self.grid, *byte); } } fn cursor_coordinates(&self) -> Option<(usize, usize)> { @@ -103,7 +94,7 @@ impl Pane for TerminalPane { match input_bytes.as_slice() { [27, 91, 68] => { // left arrow - if self.cursor_key_mode { + if self.grid.cursor_key_mode { // please note that in the line below, there is an ANSI escape code (27) at the beginning of the string, // some editors will not show this return "OD".as_bytes().to_vec(); @@ -111,7 +102,7 @@ impl Pane for TerminalPane { } [27, 91, 67] => { // right arrow - if self.cursor_key_mode { + if self.grid.cursor_key_mode { // please note that in the line below, there is an ANSI escape code (27) at the beginning of the string, // some editors will not show this return "OC".as_bytes().to_vec(); @@ -119,7 +110,7 @@ impl Pane for TerminalPane { } [27, 91, 65] => { // up arrow - if self.cursor_key_mode { + if self.grid.cursor_key_mode { // please note that in the line below, there is an ANSI escape code (27) at the beginning of the string, // some editors will not show this return "OA".as_bytes().to_vec(); @@ -127,7 +118,7 @@ impl Pane for TerminalPane { } [27, 91, 66] => { // down arrow - if self.cursor_key_mode { + if self.grid.cursor_key_mode { // please note that in the line below, there is an ANSI escape code (27) at the beginning of the string, // some editors will not show this return "OB".as_bytes().to_vec(); @@ -142,10 +133,10 @@ impl Pane for TerminalPane { self.position_and_size_override } fn should_render(&self) -> bool { - self.should_render + self.grid.should_render } fn set_should_render(&mut self, should_render: bool) { - self.should_render = should_render; + self.grid.should_render = should_render; } fn selectable(&self) -> bool { self.selectable @@ -175,7 +166,7 @@ impl Pane for TerminalPane { let buffer_lines = &self.read_buffer_as_lines(); let display_cols = self.get_columns(); let mut character_styles = CharacterStyles::new(); - if self.clear_viewport_before_rendering { + if self.grid.clear_viewport_before_rendering { for line_index in 0..self.grid.height { let x = self.get_x(); let y = self.get_y(); @@ -188,7 +179,7 @@ impl Pane for TerminalPane { vte_output.push(EMPTY_TERMINAL_CHARACTER.character); } } - self.clear_viewport_before_rendering = false; + self.grid.clear_viewport_before_rendering = false; } for (row, line) in buffer_lines.iter().enumerate() { let x = self.get_x(); @@ -212,7 +203,7 @@ impl Pane for TerminalPane { } character_styles.clear(); } - self.should_render = false; + self.grid.should_render = false; Some(vte_output) } else { None @@ -271,40 +262,31 @@ impl Pane for TerminalPane { } fn scroll_up(&mut self, count: usize) { self.grid.move_viewport_up(count); - self.mark_for_rerender(); + self.grid.should_render = true; } fn scroll_down(&mut self, count: usize) { self.grid.move_viewport_down(count); - self.mark_for_rerender(); + self.grid.should_render = true; } fn clear_scroll(&mut self) { self.grid.reset_viewport(); - self.mark_for_rerender(); + self.grid.should_render = true; } } impl TerminalPane { pub fn new(pid: RawFd, position_and_size: PositionAndSize) -> TerminalPane { let grid = Grid::new(position_and_size.rows, position_and_size.columns); - let pending_styles = CharacterStyles::new(); - TerminalPane { pid, grid, - alternative_grid: None, - should_render: true, selectable: true, - pending_styles, position_and_size, position_and_size_override: None, - cursor_key_mode: false, - clear_viewport_before_rendering: false, max_height: None, + vte_parser: vte::Parser::new(), } } - pub fn mark_for_rerender(&mut self) { - self.should_render = true; - } pub fn get_x(&self) -> usize { match self.position_and_size_override { Some(position_and_size_override) => position_and_size_override.x, @@ -333,11 +315,7 @@ impl TerminalPane { let rows = self.get_rows(); let columns = self.get_columns(); self.grid.change_size(rows, columns); - if let Some(alternative_grid) = self.alternative_grid.as_mut() { - alternative_grid.change_size(rows, columns); - } } - pub fn read_buffer_as_lines(&self) -> Vec<Vec<TerminalCharacter>> { self.grid.as_character_lines() } @@ -346,328 +324,4 @@ impl TerminalPane { // (x, y) self.grid.cursor_coordinates() } - pub fn rotate_scroll_region_up(&mut self, count: usize) { - self.grid.rotate_scroll_region_up(count); - self.mark_for_rerender(); - } - pub fn rotate_scroll_region_down(&mut self, count: usize) { - self.grid.rotate_scroll_region_down(count); - self.mark_for_rerender(); - } - fn reset_terminal_state(&mut self) { - let rows = self.get_rows(); - let columns = self.get_columns(); - self.grid = Grid::new(rows, columns); - self.alternative_grid = None; - self.cursor_key_mode = false; - } - fn add_newline(&mut self) { - let pad_character = EMPTY_TERMINAL_CHARACTER; - self.grid.add_canonical_line(pad_character); - self.mark_for_rerender(); - } - fn move_to_beginning_of_line(&mut self) { - self.grid.move_cursor_to_beginning_of_line(); - } - fn move_cursor_backwards(&mut self, count: usize) { - self.grid.move_cursor_backwards(count); - } - fn _reset_all_ansi_codes(&mut self) { - self.pending_styles.clear(); - } -} - -impl vte::Perform for TerminalPane { - fn print(&mut self, c: char) { - // apparently, building TerminalCharacter like this without a "new" method - // is a little faster - let terminal_character = TerminalCharacter { - character: c, - styles: self.pending_styles, - }; - self.grid.add_character(terminal_character); - } - - fn execute(&mut self, byte: u8) { - match byte { - 8 => { - // backspace - self.move_cursor_backwards(1); - } - 9 => { - // tab - self.grid.advance_to_next_tabstop(self.pending_styles); - } - 10 => { - // 0a, newline - self.add_newline(); - } - 13 => { - // 0d, carriage return - self.move_to_beginning_of_line(); - } - _ => {} - } - } - - fn hook(&mut self, _params: &[i64], _intermediates: &[u8], _ignore: bool, _c: char) { - // TBD - } - - fn put(&mut self, _byte: u8) { - // TBD - } - - fn unhook(&mut self) { - // TBD - } - - fn osc_dispatch(&mut self, _params: &[&[u8]], _bell_terminated: bool) { - // TBD - } - - fn csi_dispatch(&mut self, params: &[i64], _intermediates: &[u8], _ignore: bool, c: char) { - if c == 'm' { - self.pending_styles.add_style_from_ansi_params(params); - } else if c == 'C' { - // move cursor forward - let move_by = if params[0] == 0 { - 1 - } else { - params[0] as usize - }; - self.grid.move_cursor_forward_until_edge(move_by); - } else if c == 'K' { - // clear line (0 => right, 1 => left, 2 => all) - if params[0] == 0 { - let mut char_to_replace = EMPTY_TERMINAL_CHARACTER; - char_to_replace.styles = self.pending_styles; - self.grid - .replace_characters_in_line_after_cursor(char_to_replace); - } else if params[0] == 1 { - let mut char_to_replace = EMPTY_TERMINAL_CHARACTER; - char_to_replace.styles = self.pending_styles; - self.grid - .replace_characters_in_line_before_cursor(char_to_replace); - } else if params[0] == 2 { - self.grid.clear_cursor_line(); - } - } else if c == 'J' { - // clear all (0 => below, 1 => above, 2 => all, 3 => saved) - let mut char_to_replace = EMPTY_TERMINAL_CHARACTER; - char_to_replace.styles = self.pending_styles; - if params[0] == 0 { - self.grid.clear_all_after_cursor(char_to_replace); - } else if params[0] == 2 { - self.grid.clear_all(char_to_replace); - } - // TODO: implement 1 - } else if c == 'H' { - // goto row/col - // we subtract 1 from the row/column because these are 1 indexed - // (except when they are 0, in which case they should be 1 - // don't look at me, I don't make the rules) - let (row, col) = if params.len() == 1 { - if params[0] == 0 { - (0, params[0] as usize) - } else { - (params[0] as usize - 1, params[0] as usize) - } - } else if params[0] == 0 { - (0, params[1] as usize - 1) - } else { - (params[0] as usize - 1, params[1] as usize - 1) - }; - let pad_character = EMPTY_TERMINAL_CHARACTER; - self.grid.move_cursor_to(col, row, pad_character); - } else if c == 'A' { - // move cursor up until edge of screen - let move_up_count = if params[0] == 0 { 1 } else { params[0] }; - self.grid.move_cursor_up(move_up_count as usize); - } else if c == 'B' { - // move cursor down until edge of screen - let move_down_count = if params[0] == 0 { 1 } else { params[0] }; - let pad_character = EMPTY_TERMINAL_CHARACTER; - self.grid - .move_cursor_down(move_down_count as usize, pad_character); - } else if c == 'D' { - let move_back_count = if params[0] == 0 { - 1 - } else { - params[0] as usize - }; - self.grid.move_cursor_back(move_back_count); - } else if c == 'l' { - let first_intermediate_is_questionmark = match _intermediates.get(0) { - Some(b'?') => true, - None => false, - _ => false, - }; - if first_intermediate_is_questionmark { - match params.get(0) { - Some(&1049) => { - if let Some(alternative_grid) = self.alternative_grid.as_mut() { - std::mem::swap(&mut self.grid, alternative_grid); - } - self.alternative_grid = None; - self.clear_viewport_before_rendering = true; - self.mark_for_rerender(); - } - Some(&25) => { - self.grid.hide_cursor(); - self.mark_for_rerender(); - } - Some(&1) => { - self.cursor_key_mode = false; - } - _ => {} - }; - } - } else if c == 'h' { - let first_intermediate_is_questionmark = match _intermediates.get(0) { - Some(b'?') => true, - None => false, - _ => false, - }; - if first_intermediate_is_questionmark { - match params.get(0) { - Some(&25) => { - self.grid.show_cursor(); - self.mark_for_rerender(); - } - Some(&1049) => { - let columns = self - .position_and_size_override - .map(|x| x.columns) - .unwrap_or(self.position_and_size.columns); - let rows = self - .position_and_size_override - .map(|x| x.rows) - .unwrap_or(self.position_and_size.rows); - let current_grid = - std::mem::replace(&mut self.grid, Grid::new(rows, columns)); - self.alternative_grid = Some(current_grid); - self.clear_viewport_before_rendering = true; - } - Some(&1) => { - self.cursor_key_mode = true; - } - _ => {} - }; - } - } else if c == 'r' { - if params.len() > 1 { - // minus 1 because these are 1 indexed - let top_line_index = params[0] as usize - 1; - let bottom_line_index = params[1] as usize - 1; - self.grid - .set_scroll_region(top_line_index, bottom_line_index); - self.grid.show_cursor(); - } else { - self.grid.clear_scroll_region(); - } - } else if c == 't' { - // TBD - title? - } else if c == 'n' { - // TBD - device status report - } else if c == 'c' { - // TBD - identify terminal - } else if c == 'M' { - // delete lines if currently inside scroll region - let line_count_to_delete = if params[0] == 0 { - 1 - } else { - params[0] as usize - }; - let pad_character = EMPTY_TERMINAL_CHARACTER; - self.grid - .delete_lines_in_scroll_region(line_count_to_delete, pad_character); - } else if c == 'L' { - // insert blank lines if inside scroll region - let line_count_to_add = if params[0] == 0 { - 1 - } else { - params[0] as usize - }; - let pad_character = EMPTY_TERMINAL_CHARACTER; - self.grid - .add_empty_lines_in_scroll_region(line_count_to_add, pad_character); - } else if c == 'q' { - // ignore for now to run on mac - } else if c == 'G' { - let column = if params[0] == 0 { - 0 - } else { - params[0] as usize - 1 - }; - self.grid.move_cursor_to_column(column); - } else if c == 'd' { - // goto line - let line = if params[0] == 0 { - 1 - } else { - // minus 1 because this is 1 indexed - params[0] as usize - 1 - }; - let pad_character = EMPTY_TERMINAL_CHARACTER; - self.grid.move_cursor_to_line(line, pad_character); - } else if c == 'P' { - // erase characters - let count = if params[0] == 0 { - 1 - } else { - params[0] as usize - }; - self.grid.erase_characters(count, self.pending_styles); - } else if c == 'X' { - // erase characters and replace with empty characters of current style - let count = if params[0] == 0 { - 1 - } else { - params[0] as usize - }; - self.grid - .replace_with_empty_chars(count, self.pending_styles); - } else if c == 'T' { - /* - * 124 54 T SD - * Scroll down, new lines inserted at top of screen - * [4T = Scroll down 4, bring previous lines back into view - */ - let line_count: i64 = *params.get(0).expect("A number of lines was expected."); - - if line_count >= 0 { - self.rotate_scroll_region_up(line_count as usize); - } else { - self.rotate_scroll_region_down(line_count.abs() as usize); - } - } else if c == 'S' { - // move scroll up - let count = if params[0] == 0 { - 1 - } else { - params[0] as usize - }; - let pad_character = EMPTY_TERMINAL_CHARACTER; - self.grid - .delete_lines_in_scroll_region(count, pad_character); - // TODO: since delete_lines_in_scroll_region also adds lines, is the below redundant? - self.grid - .add_empty_lines_in_scroll_region(count, pad_character); - } else { - let _ = debug_log_to_file(format!("Unhandled csi: {}->{:?}", c, params)); - } - } - - fn esc_dispatch(&mut self, intermediates: &[u8], _ignore: bool, byte: u8) { - match (byte, intermediates.get(0)) { - (b'M', None) => { - self.grid.move_cursor_up_with_scrolling(1); - } - (b'c', None) => { - self.reset_terminal_state(); - } - _ => {} - } - } } diff --git a/src/client/tab.rs b/src/client/tab.rs index 35fc3915..656c6093 100644 --- a/src/client/tab.rs +++ b/src/client/tab.rs @@ -20,7 +20,10 @@ use std::{io::Write, sync::mpsc::channel}; use zellij_tile::data::{colors, Event, InputMode, ModeInfo, Palette}; 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; + +// MIN_TERMINAL_HEIGHT here must be larger than the height of any of the status bars +// this is a dirty hack until we implement fixed panes +const MIN_TERMINAL_HEIGHT: usize = 3; const MIN_TERMINAL_WIDTH: usize = 4; type BorderAndPaneIds = (usize, Vec<PaneId>); @@ -67,7 +70,6 @@ pub struct Tab { pub send_pty_instructions: SenderWithContext<PtyInstruction>, 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, @@ -208,6 +210,7 @@ pub trait Pane { impl Tab { // FIXME: Too many arguments here! Maybe bundle all of the senders for the whole program in a struct? + #[allow(clippy::too_many_arguments)] pub fn new( index: usize, position: usize, @@ -250,7 +253,6 @@ impl Tab { send_app_instructions, send_pty_instructions, send_plugin_instructions, - expansion_boundary: None, should_clear_display_before_rendering: false, mode_info, input_mode, @@ -293,9 +295,6 @@ impl Tab { let mut new_pids = new_pids.iter(); for (layout, position_and_size) in positions_and_size { // Just a regular terminal - if layout.expansion_boundary { - self.expansion_boundary = Some(*position_and_size); - } if let Some(plugin) = &layout.plugin { let (pid_tx, pid_rx) = channel(); self.send_plugin_instructions @@ -365,9 +364,7 @@ impl Tab { let (id_of_terminal_to_check, terminal_to_check) = id_and_terminal_to_check; let terminal_size = (terminal_to_check.rows() * CURSOR_HEIGHT_WIDTH_RATIO) * terminal_to_check.columns(); - let terminal_pos_and_size = terminal_to_check.position_and_size(); let terminal_can_be_split = terminal_to_check.columns() >= MIN_TERMINAL_WIDTH - && self.pos_and_size_is_within_expansion_boundary(terminal_pos_and_size) && terminal_to_check.rows() >= MIN_TERMINAL_HEIGHT && ((terminal_to_check.columns() > terminal_to_check.min_width() * 2) || (terminal_to_check.rows() > terminal_to_check.min_height() * 2)); @@ -627,19 +624,17 @@ impl Tab { let active_terminal = self.panes.get_mut(&active_pane_id).unwrap(); active_terminal.reset_size_and_position_override(); } else { - let expand_to = self.expansion_boundary.unwrap_or(self.full_screen_ws); let panes = self.get_panes(); - let pane_ids_to_hide = panes.filter_map(|(&id, pane)| { - let position_and_size_for_pane = pane.position_and_size(); - if id != active_pane_id - && self - .pos_and_size_is_within_expansion_boundary(position_and_size_for_pane) - { - Some(id) - } else { - None - } - }); + let pane_ids_to_hide = + panes.filter_map( + |(&id, _)| { + if id != active_pane_id { + Some(id) + } else { + None + } + }, + ); self.panes_to_hide = pane_ids_to_hide.collect(); if self.panes_to_hide.is_empty() { // nothing to do, pane is already as fullscreen as it can be, let's bail @@ -647,9 +642,9 @@ impl Tab { } else { let active_terminal = self.panes.get_mut(&active_pane_id).unwrap(); active_terminal.override_size_and_position( - expand_to.x, - expand_to.y, - &expand_to, + self.full_screen_ws.x, + self.full_screen_ws.y, + &self.full_screen_ws, ); } } @@ -1503,21 +1498,6 @@ impl Tab { self.increase_pane_width_left(&terminal_id, count); } } - fn pos_and_size_is_within_expansion_boundary(&self, pos_and_size: PositionAndSize) -> bool { - match self.expansion_boundary { - Some(expansion_boundary) => { - pos_and_size.x >= expansion_boundary.x - && pos_and_size.x < expansion_boundary.x + expansion_boundary.columns - && pos_and_size.y >= expansion_boundary.y - && pos_and_size.y < expansion_boundary.y + expansion_boundary.rows - && pos_and_size.x + pos_and_size.columns - <= expansion_boundary.x + expansion_boundary.columns - && pos_and_size.y + pos_and_size.rows - <= expansion_boundary.y + expansion_boundary.rows - } - None => true, // no expansion boundary, no problem - } - } fn can_increase_pane_and_surroundings_right( &self, pane_id: &PaneId, @@ -1533,17 +1513,11 @@ impl Tab { } let mut new_pos_and_size_for_pane = pane.position_and_size(); new_pos_and_size_for_pane.columns += increase_by; - if !self.pos_and_size_is_within_expansion_boundary(new_pos_and_size_for_pane) { - return false; - } if let Some(panes_to_the_right) = self.pane_ids_directly_right_of(&pane_id) { return panes_to_the_right.iter().all(|id| { let p = self.panes.get(id).unwrap(); - let position_and_size_for_pane = p.position_and_size(); - self.pos_and_size_is_within_expansion_boundary(position_and_size_for_pane) - && p.columns() > increase_by - && p.columns() - increase_by >= p.min_width() + p.columns() > increase_by && p.columns() - increase_by >= p.min_width() }); } else { false @@ -1564,17 +1538,11 @@ impl Tab { } let mut new_pos_and_size_for_pane = pane.position_and_size(); new_pos_and_size_for_pane.x = new_pos_and_size_for_pane.x.saturating_sub(increase_by); - if !self.pos_and_size_is_within_expansion_boundary(new_pos_and_size_for_pane) { - return false; - } if let Some(panes_to_the_left) = self.pane_ids_directly_left_of(&pane_id) { return panes_to_the_left.iter().all(|id| { let p = self.panes.get(id).unwrap(); - let position_and_size_for_pane = p.position_and_size(); - self.pos_and_size_is_within_expansion_boundary(position_and_size_for_pane) - && p.columns() > increase_by - && p.columns() - increase_by >= p.min_width() + p.columns() > increase_by && p.columns() - increase_by >= p.min_width() }); } else { false @@ -1595,17 +1563,11 @@ impl Tab { } let mut new_pos_and_size_for_pane = pane.position_and_size(); new_pos_and_size_for_pane.rows += increase_by; - if !self.pos_and_size_is_within_expansion_boundary(new_pos_and_size_for_pane) { - return false; - } if let Some(panes_below) = self.pane_ids_directly_below(&pane_id) { return panes_below.iter().all(|id| { let p = self.panes.get(id).unwrap(); - let position_and_size_for_pane = p.position_and_size(); - self.pos_and_size_is_within_expansion_boundary(position_and_size_for_pane) - && p.rows() > increase_by - && p.rows() - increase_by >= p.min_height() + p.rows() > increase_by && p.rows() - increase_by >= p.min_height() }); } else { false @@ -1622,17 +1584,11 @@ impl Tab { } let mut new_pos_and_size_for_pane = pane.position_and_size(); new_pos_and_size_for_pane.y = new_pos_and_size_for_pane.y.saturating_sub(increase_by); - if !self.pos_and_size_is_within_expansion_boundary(new_pos_and_size_for_pane) { - return false; - } if let Some(panes_above) = self.pane_ids_directly_above(&pane_id) { return panes_above.iter().all(|id| { let p = self.panes.get(id).unwrap(); - let position_and_size_for_pane = p.position_and_size(); - self.pos_and_size_is_within_expansion_boundary(position_and_size_for_pane) - && p.rows() > increase_by - && p.rows() - increase_by >= p.min_height() + p.rows() > increase_by && p.rows() - increase_by >= p.min_height() }); } else { false @@ -1649,11 +1605,9 @@ impl Tab { if let Some(panes_to_the_left) = self.pane_ids_directly_left_of(&pane_id) { return panes_to_the_left.iter().all(|id| { let p = self.panes.get(id).unwrap(); - let position_and_size_for_pane = p.position_and_size(); - self.pos_and_size_is_within_expansion_boundary(position_and_size_for_pane) - && p.max_width() - .map(|max_width| p.columns() + reduce_by <= max_width) - .unwrap_or(true) // no max width, increase to your heart's content + p.max_width() + .map(|max_width| p.columns() + reduce_by <= max_width) + .unwrap_or(true) // no max width, increase to your heart's content }); } else { false @@ -1670,11 +1624,9 @@ impl Tab { if let Some(panes_to_the_right) = self.pane_ids_directly_right_of(&pane_id) { return panes_to_the_right.iter().all(|id| { let p = self.panes.get(id).unwrap(); - let position_and_size_for_pane = p.position_and_size(); - self.pos_and_size_is_within_expansion_boundary(position_and_size_for_pane) - && p.max_width() - .map(|max_width| p.columns() + reduce_by <= max_width) - .unwrap_or(true) // no max width, increase to your heart's content + p.max_width() + .map(|max_width| p.columns() + reduce_by <= max_width) + .unwrap_or(true) // no max width, increase to your heart's content }); } else { false @@ -1691,11 +1643,9 @@ impl Tab { if let Some(panes_above) = self.pane_ids_directly_above(&pane_id) { return panes_above.iter().all(|id| { let p = self.panes.get(id).unwrap(); - let position_and_size_for_pane = p.position_and_size(); - self.pos_and_size_is_within_expansion_boundary(position_and_size_for_pane) - && p.max_height() - .map(|max_height| p.rows() + reduce_by <= max_height) - .unwrap_or(true) // no max height, increase to your heart's content + p.max_height() + .map(|max_height| p.rows() + reduce_by <= max_height) + .unwrap_or(true) // no max height, increase to your heart's content }); } else { false @@ -1712,11 +1662,9 @@ impl Tab { if let Some(panes_below) = self.pane_ids_directly_below(&pane_id) { return panes_below.iter().all(|id| { let p = self.panes.get(id).unwrap(); - let position_and_size_for_pane = p.position_and_size(); - self.pos_and_size_is_within_expansion_boundary(position_and_size_for_pane) - && p.max_height() - .map(|max_height| p.rows() + reduce_by <= max_height) - .unwrap_or(true) // no max height, increase to your heart's content + p.max_height() + .map(|max_height| p.rows() + reduce_by <= max_height) + .unwrap_or(true) // no max height, increase to your heart's content }); } else { false @@ -1724,27 +1672,18 @@ impl Tab { } 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 + // this is not ideal, we can improve this self.toggle_active_pane_fullscreen(); } - match PaneResizer::new(&mut self.panes, &mut self.os_api) - .resize(self.full_screen_ws, new_screen_size) + if let Some((column_difference, row_difference)) = + 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; - } - None => {} + self.should_clear_display_before_rendering = true; + 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; }; } pub fn resize_left(&mut self) { @@ -2242,6 +2181,30 @@ impl Tab { self.render(); } } + pub fn scroll_active_terminal_up_page(&mut self) { + if let Some(active_terminal_id) = self.get_active_terminal_id() { + let active_terminal = self + .panes + .get_mut(&PaneId::Terminal(active_terminal_id)) + .unwrap(); + // prevent overflow when row == 0 + let scroll_columns = active_terminal.rows().max(1) - 1; + active_terminal.scroll_up(scroll_columns); + self.render(); + } + } + pub fn scroll_active_terminal_down_page(&mut self) { + if let Some(active_terminal_id) = self.get_active_terminal_id() { + let active_terminal = self + .panes + .get_mut(&PaneId::Terminal(active_terminal_id)) + .unwrap(); + // prevent overflow when row == 0 + let scroll_columns = active_terminal.rows().max(1) - 1; + active_terminal.scroll_down(scroll_columns); + self.render(); + } + } pub fn clear_active_terminal_scroll(&mut self) { if let Some(active_terminal_id) = self.get_active_terminal_id() { let active_terminal = self diff --git a/src/common/errors.rs b/src/common/errors.rs index 9801428c..dd675738 100644 --- a/src/common/errors.rs +++ b/src/common/errors.rs @@ -1,7 +1,7 @@ //! Error context system based on a thread-local representation of the call stack, itself based on //! the instructions that are sent between threads. -use super::{AppInstruction, OPENCALLS}; +use super::{AppInstruction, ASYNCOPENCALLS, OPENCALLS}; use crate::pty_bus::PtyInstruction; use crate::screen::ScreenInstruction; @@ -72,6 +72,12 @@ pub fn handle_panic( } } +pub fn get_current_ctx() -> ErrorContext { + ASYNCOPENCALLS + .try_with(|ctx| *ctx.borrow()) + .unwrap_or_else(|_| OPENCALLS.with(|ctx| *ctx.borrow())) +} + /// A representation of the call stack. #[derive(Clone, Copy)] pub struct ErrorContext { @@ -95,7 +101,9 @@ impl ErrorContext { break; } } - OPENCALLS.with(|ctx| *ctx.borrow_mut() = *self); + ASYNCOPENCALLS + .try_with(|ctx| *ctx.borrow_mut() = *self) + .unwrap_or_else(|_| OPENCALLS.with(|ctx| *ctx.borrow_mut() = *self)); } } @@ -188,6 +196,8 @@ pub enum ScreenContext { Quit, ScrollUp, ScrollDown, + PageScrollUp, + PageScrollDown, ClearScroll, CloseFocusedPane, ToggleActiveTerminalFullscreen, @@ -230,6 +240,8 @@ impl From<&ScreenInstruction> for ScreenContext { ScreenInstruction::Quit => ScreenContext::Quit, ScreenInstruction::ScrollUp => ScreenContext::ScrollUp, ScreenInstruction::ScrollDown => ScreenContext::ScrollDown, + ScreenInstruction::PageScrollUp => ScreenContext::PageScrollUp, + ScreenInstruction::PageScrollDown => ScreenContext::PageScrollDown, ScreenInstruction::ClearScroll => ScreenContext::ClearScroll, ScreenInstruction::CloseFocusedPane => ScreenContext::CloseFocusedPane, ScreenInstruction::ToggleActiveTerminalFullscreen => { diff --git a/src/common/input/actions.rs b/src/common/input/actions.rs index 47a5f763..3bcadf15 100644 --- a/src/common/input/actions.rs +++ b/src/common/input/actions.rs @@ -33,6 +33,10 @@ pub enum Action { ScrollUp, /// Scroll down in focus pane. ScrollDown, + /// Scroll up one page in focus pane. + PageScrollUp, + /// Scroll down one page in focus pane. + PageScrollDown, /// Toggle between fullscreen focus pane and normal layout. ToggleFocusFullscreen, /// Open a new pane in the specified direction (relative to focus). diff --git a/src/common/input/config.rs b/src/common/input/config.rs index 4bb9e10f..542116d9 100644 --- a/src/common/input/config.rs +++ b/src/common/input/config.rs @@ -51,7 +51,6 @@ impl Config { } /// Deserializes from given path. - #[allow(unused_must_use)] pub fn new(path: &Path) -> ConfigResult { match File::open(path) { Ok(mut file) => { @@ -80,20 +79,23 @@ impl Config { /// Entry point of the configuration #[cfg(not(test))] - pub fn from_cli_config(cli_config: Option<ConfigCli>) -> ConfigResult { + pub fn from_cli_config( + location: Option<PathBuf>, + cli_config: Option<ConfigCli>, + ) -> ConfigResult { + if let Some(path) = location { + return Config::new(&path); + } + match cli_config { Some(ConfigCli::Config { clean, .. }) if clean => Ok(Config::default()), - Some(ConfigCli::Config { path, .. }) if path.is_some() => { - Ok(Config::new(&path.unwrap())?) - } Some(_) | None => Ok(Config::from_default_path()?), } } - //#[allow(unused_must_use)] /// In order not to mess up tests from changing configurations #[cfg(test)] - pub fn from_cli_config(_: Option<ConfigCli>) -> ConfigResult { + pub fn from_cli_config(_: Option<PathBuf>, _: Option<ConfigCli>) -> ConfigResult { Ok(Config::default()) } } @@ -139,19 +141,15 @@ mod config_test { #[test] fn clean_option_equals_default_config() { - let no_file = PathBuf::from(r"../fixtures/config/config.yamlll"); - let cli_config = ConfigCli::Config { - path: Some(no_file), - clean: true, - }; - let config = Config::from_cli_config(Some(cli_config)).unwrap(); + let cli_config = ConfigCli::Config { clean: true }; + let config = Config::from_cli_config(None, Some(cli_config)).unwrap(); let default = Config::default(); assert_eq!(config, default); } #[test] fn no_config_option_file_equals_default_config() { - let config = Config::from_cli_config(None).unwrap(); + let config = Config::from_cli_config(None, None).unwrap(); let default = Config::default(); assert_eq!(config, default); } diff --git a/src/common/input/handler.rs b/src/common/input/handler.rs index 2484f08c..bbb594a3 100644 --- a/src/common/input/handler.rs +++ b/src/common/input/handler.rs @@ -59,9 +59,6 @@ impl InputHandler { fn handle_input(&mut self) { let mut err_ctx = OPENCALLS.with(|ctx| *ctx.borrow()); err_ctx.add_call(ContextType::StdinHandler); - self.send_pty_instructions.update(err_ctx); - self.send_app_instructions.update(err_ctx); - self.send_screen_instructions.update(err_ctx); let keybinds = self.config.keybinds.clone(); let alt_left_bracket = vec![27, 91]; loop { @@ -188,6 +185,16 @@ impl InputHandler { .send(ScreenInstruction::ScrollDown) .unwrap(); } + Action::PageScrollUp => { + self.send_screen_instructions + .send(ScreenInstruction::PageScrollUp) + .unwrap(); + } + Action::PageScrollDown => { + self.send_screen_instructions + .send(ScreenInstruction::PageScrollDown) + .unwrap(); + } Action::ToggleFocusFullscreen => { self.send_screen_instructions .send(ScreenInstruction::ToggleActiveTerminalFullscreen) @@ -298,6 +305,7 @@ pub fn get_mode_info(mode: InputMode) -> ModeInfo { } InputMode::Scroll => { keybinds.push(("↓↑".to_string(), "Scroll".to_string())); + keybinds.push(("PgUp/PgDn".to_string(), "Scroll Page".to_string())); } InputMode::RenameTab => { keybinds.push(("Enter".to_string(), "when done".to_string())); diff --git a/src/common/input/keybinds.rs b/src/common/input/keybinds.rs index 8a064970..8e04c44a 100644 --- a/src/common/input/keybinds.rs +++ b/src/common/input/keybinds.rs @@ -7,14 +7,30 @@ use serde::Deserialize; use strum::IntoEnumIterator; use zellij_tile::data::*; +/// Used in the config struct #[derive(Clone, Debug, PartialEq)] pub struct Keybinds(HashMap<InputMode, ModeKeybinds>); #[derive(Clone, Debug, Default, PartialEq)] pub struct ModeKeybinds(HashMap<Key, Vec<Action>>); /// Intermediate struct used for deserialisation +/// Used in the config file. #[derive(Clone, Debug, PartialEq, Deserialize)] -pub struct KeybindsFromYaml(HashMap<InputMode, Vec<KeyActionFromYaml>>); +pub struct KeybindsFromYaml { + #[serde(flatten)] + keybinds: HashMap<InputMode, Vec<KeyActionUnbind>>, + #[serde(default)] + unbind: Unbind, +} + +/// Intermediate enum used for deserialisation +#[derive(Clone, Debug, PartialEq, Deserialize)] +#[serde(untagged)] +enum KeyActionUnbind { + KeyAction(KeyActionFromYaml), + // TODO: use the enum + //Unbind(UnbindFromYaml), +} /// Intermediate struct used for deserialisation #[derive(Clone, Debug, PartialEq, Deserialize)] @@ -23,6 +39,22 @@ pub struct KeyActionFromYaml { key: Vec<Key>, } +/// Intermediate struct used for deserialisation +#[derive(Clone, Debug, PartialEq, Eq, Hash, Deserialize)] +struct UnbindFromYaml { + unbind: Unbind, +} + +/// List of keys, for which to disable their respective default actions +/// `All` is a catch all, and will disable the default actions for all keys. +#[derive(Clone, Debug, PartialEq, Eq, Hash, Deserialize)] +#[serde(untagged)] +enum Unbind { + All(bool), + // TODO@a-kenji: use the enum + //Keys(Vec<Key>), +} + impl Default for Keybinds { fn default() -> Keybinds { let mut defaults = Keybinds::new(); @@ -41,9 +73,16 @@ impl Keybinds { Keybinds(HashMap::<InputMode, ModeKeybinds>::new()) } - pub fn get_default_keybinds_with_config(keybinds: Option<KeybindsFromYaml>) -> Keybinds { - let default_keybinds = Keybinds::default(); - if let Some(keybinds) = keybinds { + pub fn get_default_keybinds_with_config(from_yaml: Option<KeybindsFromYaml>) -> Keybinds { + let default_keybinds = match from_yaml.clone() { + Some(keybinds) => match keybinds.unbind { + Unbind::All(true) => Keybinds::new(), + Unbind::All(false) => Keybinds::default(), + }, + None => Keybinds::default(), + }; + + if let Some(keybinds) = from_yaml { default_keybinds.merge_keybinds(Keybinds::from(keybinds)) } else { default_keybinds @@ -301,6 +340,11 @@ impl Keybinds { defaults.insert(Key::Char('j'), vec![Action::ScrollDown]); defaults.insert(Key::Char('k'), vec![Action::ScrollUp]); + defaults.insert(Key::Ctrl('f'), vec![Action::PageScrollDown]); + defaults.insert(Key::Ctrl('b'), vec![Action::PageScrollUp]); + defaults.insert(Key::PageDown, vec![Action::PageScrollDown]); + defaults.insert(Key::PageUp, vec![Action::PageScrollUp]); + defaults.insert(Key::Down, vec![Action::ScrollDown]); defaults.insert(Key::Up, vec![Action::ScrollUp]); @@ -383,7 +427,7 @@ impl From<KeybindsFromYaml> for Keybinds { for mode in InputMode::iter() { let mut mode_keybinds = ModeKeybinds::new(); - for key_action in keybinds_from_yaml.0.get(&mode).iter() { + for key_action in keybinds_from_yaml.keybinds.get(&mode).iter() { for keybind in key_action.iter() { mode_keybinds = mode_keybinds.merge(ModeKeybinds::from(keybind.clone())); } @@ -409,6 +453,21 @@ impl From<KeyActionFromYaml> for ModeKeybinds { } } +// Currently an enum for future use +impl From<KeyActionUnbind> for ModeKeybinds { + fn from(key_action_unbind: KeyActionUnbind) -> ModeKeybinds { + match key_action_unbind { + KeyActionUnbind::KeyAction(key_action) => ModeKeybinds::from(key_action), + } + } +} + +impl Default for Unbind { + fn default() -> Unbind { + Unbind::All(false) + } +} + // The unit test location. #[cfg(test)] #[path = "./unit/keybinds_test.rs"] diff --git a/src/common/input/unit/keybinds_test.rs b/src/common/input/unit/keybinds_test.rs index 6411d017..e0d78b62 100644 --- a/src/common/input/unit/keybinds_test.rs +++ b/src/common/input/unit/keybinds_test.rs @@ -124,12 +124,25 @@ fn from_keyaction_from_yaml_to_mode_keybindings() { assert_eq!(expected, ModeKeybinds::from(keyaction)); } -//#[test] -//fn from_keybinds_from_yaml_to_keybinds(){ -//let mut keybinds_from_yaml = KeybindsFromYaml(HashMap<InputMode, Vec<KeyActionFromYaml>>); -//let actions = vec![Action::NoOp, Action::GoToTab(1), ]; -//let keyaction = KeyActionFromYaml { -//action : actions.clone(), -//key : vec![ Key::F(1), Key::Backspace , Key::Char('t'), ], -//}; -//} +#[test] +fn toplevel_unbind_unbinds_all() { + let from_yaml = KeybindsFromYaml { + unbind: Unbind::All(true), + keybinds: HashMap::new(), + }; + + let keybinds_from_yaml = Keybinds::get_default_keybinds_with_config(Some(from_yaml)); + + assert_eq!(keybinds_from_yaml, Keybinds::new()); +} + +fn no_unbind_unbinds_none() { + let from_yaml = KeybindsFromYaml { + unbind: Unbind::All(false), + keybinds: HashMap::new(), + }; + + let keybinds_from_yaml = Keybinds::get_default_keybinds_with_config(Some(from_yaml)); + + assert_eq!(keybinds_from_yaml, Keybinds::new()); +} diff --git a/src/common/install.rs b/src/common/install.rs index 8b070848..86fdd269 100644 --- a/src/common/install.rs +++ b/src/common/install.rs @@ -1,12 +1,41 @@ +use std::{fs, path::Path}; + +const VERSION: &str = env!("CARGO_PKG_VERSION"); + #[macro_export] macro_rules! asset_map { ($($src:literal => $dst:literal),+ $(,)?) => { { let mut assets = std::collections::HashMap::new(); $( - assets.insert($dst, include_bytes!(concat!("../", $src)).to_vec()); + assets.insert($dst, include_bytes!(concat!(env!("CARGO_MANIFEST_DIR"), "/", $src)).to_vec()); )+ assets } } } + +pub fn populate_data_dir(data_dir: &Path) { + // First run installation of default plugins & layouts + let mut assets = asset_map! { + "assets/layouts/default.yaml" => "layouts/default.yaml", + "assets/layouts/strider.yaml" => "layouts/strider.yaml", + }; + assets.extend(asset_map! { + "assets/plugins/status-bar.wasm" => "plugins/status-bar.wasm", + "assets/plugins/tab-bar.wasm" => "plugins/tab-bar.wasm", + "assets/plugins/strider.wasm" => "plugins/strider.wasm", + }); + assets.insert("VERSION", VERSION.as_bytes().to_vec()); + + let last_version = fs::read_to_string(data_dir.join("VERSION")).unwrap_or_default(); + let out_of_date = VERSION != last_version; + + for (path, bytes) in assets { + let path = data_dir.join(path); + fs::create_dir_all(path.parent().unwrap()).unwrap(); + if out_of_date || !path.exists() { + fs::write(path, bytes).expect("Failed to install default assets!"); + } + } +} diff --git a/src/common/mod.rs b/src/common/mod.rs index b3bcec9b..3bb5ca88 100644 --- a/src/common/mod.rs +++ b/src/common/mod.rs @@ -16,6 +16,7 @@ use std::thread; use std::{collections::HashMap, fs}; use std::{ collections::HashSet, + env, io::Write, str::FromStr, sync::{Arc, Mutex}, @@ -26,10 +27,15 @@ use crate::common::input::config::Config; use crate::layout::Layout; use crate::panes::PaneId; use colors_transform::{Color, Rgb}; +use async_std::task_local; use command_is_executing::CommandIsExecuting; use directories_next::ProjectDirs; -use errors::{AppContext, ContextType, ErrorContext, PluginContext, PtyContext, ScreenContext}; +use errors::{ + get_current_ctx, AppContext, ContextType, ErrorContext, PluginContext, PtyContext, + ScreenContext, +}; use input::handler::input_loop; +use install::populate_data_dir; use os_input_output::OsApi; use pty_bus::{PtyBus, PtyInstruction}; use screen::{Screen, ScreenInstruction}; @@ -76,32 +82,23 @@ enum SenderType<T: Clone> { /// synchronously or asynchronously depending on the underlying [`SenderType`]. #[derive(Clone)] pub struct SenderWithContext<T: Clone> { - err_ctx: ErrorContext, sender: SenderType<T>, } impl<T: Clone> SenderWithContext<T> { - fn new(err_ctx: ErrorContext, sender: SenderType<T>) -> Self { - Self { err_ctx, sender } + fn new(sender: SenderType<T>) -> Self { + Self { sender } } /// Sends an event, along with the current [`ErrorContext`], on this /// [`SenderWithContext`]'s channel. pub fn send(&self, event: T) -> Result<(), mpsc::SendError<(T, ErrorContext)>> { + let err_ctx = get_current_ctx(); match self.sender { - SenderType::Sender(ref s) => s.send((event, self.err_ctx)), - SenderType::SyncSender(ref s) => s.send((event, self.err_ctx)), + SenderType::Sender(ref s) => s.send((event, err_ctx)), + SenderType::SyncSender(ref s) => s.send((event, err_ctx)), } } - - /// Updates this [`SenderWithContext`]'s [`ErrorContext`]. This is the way one adds - /// a call to the error context. - /// - /// Updating [`ErrorContext`]s works in this way so that these contexts are only ever - /// allocated on the stack (which is thread-specific), and not on the heap. - pub fn update(&mut self, new_ctx: ErrorContext) { - self.err_ctx = new_ctx; - } } unsafe impl<T: Clone> Send for SenderWithContext<T> {} @@ -113,6 +110,12 @@ thread_local!( static OPENCALLS: RefCell<ErrorContext> = RefCell::default() ); +task_local! { + /// A key to some task local storage that holds a representation of the task's call + /// stack in the form of an [`ErrorContext`]. + static ASYNCOPENCALLS: RefCell<ErrorContext> = RefCell::default() +} + /// Instructions related to the entire application. #[derive(Clone)] pub enum AppInstruction { @@ -130,7 +133,9 @@ pub fn start(mut os_input: Box<dyn OsApi>, opts: CliArgs) { .write(take_snapshot.as_bytes()) .unwrap(); - let config = Config::from_cli_config(opts.config) + env::set_var(&"ZELLIJ", "0"); + + let config = Config::from_cli_config(opts.config, opts.option) .map_err(|e| { eprintln!("There was an error in the config file:\n{}", e); std::process::exit(1); @@ -144,25 +149,23 @@ pub fn start(mut os_input: Box<dyn OsApi>, opts: CliArgs) { let (send_screen_instructions, receive_screen_instructions): ChannelWithContext< ScreenInstruction, > = mpsc::channel(); - let err_ctx = OPENCALLS.with(|ctx| *ctx.borrow()); - let mut send_screen_instructions = - SenderWithContext::new(err_ctx, SenderType::Sender(send_screen_instructions)); + let send_screen_instructions = + SenderWithContext::new(SenderType::Sender(send_screen_instructions)); let (send_pty_instructions, receive_pty_instructions): ChannelWithContext<PtyInstruction> = mpsc::channel(); - let mut send_pty_instructions = - SenderWithContext::new(err_ctx, SenderType::Sender(send_pty_instructions)); + let send_pty_instructions = SenderWithContext::new(SenderType::Sender(send_pty_instructions)); let (send_plugin_instructions, receive_plugin_instructions): ChannelWithContext< PluginInstruction, > = mpsc::channel(); let send_plugin_instructions = - SenderWithContext::new(err_ctx, SenderType::Sender(send_plugin_instructions)); + SenderWithContext::new(SenderType::Sender(send_plugin_instructions)); let (send_app_instructions, receive_app_instructions): SyncChannelWithContext<AppInstruction> = mpsc::sync_channel(0); let send_app_instructions = - SenderWithContext::new(err_ctx, SenderType::SyncSender(send_app_instructions)); + SenderWithContext::new(SenderType::SyncSender(send_app_instructions)); let mut pty_bus = PtyBus::new( receive_pty_instructions, @@ -172,12 +175,22 @@ pub fn start(mut os_input: Box<dyn OsApi>, opts: CliArgs) { opts.debug, ); + // Determine and initialize the data directory + let project_dirs = ProjectDirs::from("org", "Zellij Contributors", "Zellij").unwrap(); + let data_dir = opts + .data_dir + .unwrap_or_else(|| project_dirs.data_dir().to_path_buf()); + populate_data_dir(&data_dir); + // Don't use default layouts in tests, but do everywhere else #[cfg(not(test))] let default_layout = Some(PathBuf::from("default")); #[cfg(test)] let default_layout = None; - let maybe_layout = opts.layout.or(default_layout).map(Layout::new); + let maybe_layout = opts + .layout + .or(default_layout) + .map(|p| Layout::new(&p, &data_dir)); #[cfg(not(test))] std::panic::set_hook({ @@ -199,7 +212,6 @@ pub fn start(mut os_input: Box<dyn OsApi>, opts: CliArgs) { .recv() .expect("failed to receive event on channel"); err_ctx.add_call(ContextType::Pty(PtyContext::from(&event))); - pty_bus.send_screen_instructions.update(err_ctx); match event { PtyInstruction::SpawnTerminal(file_to_open) => { let pid = pty_bus.spawn_terminal(file_to_open); @@ -282,8 +294,6 @@ pub fn start(mut os_input: Box<dyn OsApi>, opts: CliArgs) { .recv() .expect("failed to receive event on channel"); err_ctx.add_call(ContextType::Screen(ScreenContext::from(&event))); - screen.send_app_instructions.update(err_ctx); - screen.send_pty_instructions.update(err_ctx); match event { ScreenInstruction::PtyBytes(pid, vte_bytes) => { let active_tab = screen.get_active_tab_mut().unwrap(); @@ -369,6 +379,18 @@ pub fn start(mut os_input: Box<dyn OsApi>, opts: CliArgs) { .unwrap() .scroll_active_terminal_down(); } + ScreenInstruction::PageScrollUp => { + screen + .get_active_tab_mut() + .unwrap() + .scroll_active_terminal_up_page(); + } + ScreenInstruction::PageScrollDown => { + screen + .get_active_tab_mut() + .unwrap() + .scroll_active_terminal_down_page(); + } ScreenInstruction::ClearScroll => { screen .get_active_tab_mut() @@ -443,9 +465,9 @@ pub fn start(mut os_input: Box<dyn OsApi>, opts: CliArgs) { let wasm_thread = thread::Builder::new() .name("wasm".to_string()) .spawn({ - let mut send_pty_instructions = send_pty_instructions.clone(); - let mut send_screen_instructions = send_screen_instructions.clone(); - let mut send_app_instructions = send_app_instructions.clone(); + let send_pty_instructions = send_pty_instructions.clone(); + let send_screen_instructions = send_screen_instructions.clone(); + let send_app_instructions = send_app_instructions.clone(); let store = Store::default(); let mut plugin_id = 0; @@ -455,14 +477,9 @@ pub fn start(mut os_input: Box<dyn OsApi>, opts: CliArgs) { .recv() .expect("failed to receive event on channel"); err_ctx.add_call(ContextType::Plugin(PluginContext::from(&event))); - send_screen_instructions.update(err_ctx); - send_pty_instructions.update(err_ctx); - send_app_instructions.update(err_ctx); match event { PluginInstruction::Load(pid_tx, path) => { - let project_dirs = - ProjectDirs::from("org", "Zellij Contributors", "Zellij").unwrap(); - let plugin_dir = project_dirs.data_dir().join("plugins/"); + let plugin_dir = data_dir.join("plugins/"); let wasm_bytes = fs::read(&path) .or_else(|_| fs::read(&path.with_extension("wasm"))) .or_else(|_| fs::read(&plugin_dir.join(&path).with_extension("wasm"))) @@ -566,16 +583,14 @@ pub fn start(mut os_input: Box<dyn OsApi>, opts: CliArgs) { .name("ipc_server".to_string()) .spawn({ use std::io::Read; - let mut send_pty_instructions = send_pty_instructions.clone(); - let mut send_screen_instructions = send_screen_instructions.clone(); + let send_pty_instructions = send_pty_instructions.clone(); + let send_screen_instructions = send_screen_instructions.clone(); move || { std::fs::remove_file(ZELLIJ_IPC_PIPE).ok(); let listener = std::os::unix::net::UnixListener::bind(ZELLIJ_IPC_PIPE) .expect("could not listen on ipc socket"); let mut err_ctx = OPENCALLS.with(|ctx| *ctx.borrow()); err_ctx.add_call(ContextType::IpcServer); - send_pty_instructions.update(err_ctx); - send_screen_instructions.update(err_ctx); for stream in listener.incoming() { match stream { @@ -647,8 +662,6 @@ pub fn start(mut os_input: Box<dyn OsApi>, opts: CliArgs) { .expect("failed to receive app instruction on channel"); err_ctx.add_call(ContextType::App(AppContext::from(&app_instruction))); - send_screen_instructions.update(err_ctx); - send_pty_instructions.update(err_ctx); match app_instruction { AppInstruction::Exit => { break; @@ -662,7 +675,11 @@ pub fn start(mut os_input: Box<dyn OsApi>, opts: CliArgs) { let _ = wasm_thread.join(); os_input.unset_raw_mode(0); let goto_start_of_last_line = format!("\u{1b}[{};{}H", full_screen_ws.rows, 1); - let error = format!("{}\n{}", goto_start_of_last_line, backtrace); + let restore_snapshot = "\u{1b}[?1049l"; + let error = format!( + "{}\n{}{}", + goto_start_of_last_line, restore_snapshot, backtrace + ); let _ = os_input .get_stdout_writer() .write(error.as_bytes()) diff --git a/src/common/os_input_output.rs b/src/common/os_input_output.rs index 013b9f12..35d77fdd 100644 --- a/src/common/os_input_output.rs +++ b/src/common/os_input_output.rs @@ -84,15 +84,10 @@ fn handle_command_exit(mut child: Child) { } for signal in signals.pending() { - // FIXME: We need to handle more signals here! - #[allow(clippy::single_match)] - match signal { - SIGINT => { - child.kill().unwrap(); - child.wait().unwrap(); - break 'handle_exit; - } - _ => {} + if let SIGINT = signal { + child.kill().unwrap(); + child.wait().unwrap(); + break 'handle_exit; } } } diff --git a/src/common/pty_bus.rs b/src/common/pty_bus.rs index 2cab8ae8..2c132228 100644 --- a/src/common/pty_bus.rs +++ b/src/common/pty_bus.rs @@ -8,11 +8,11 @@ use ::std::sync::mpsc::Receiver; use ::std::time::{Duration, Instant}; use std::path::PathBuf; -use super::{ScreenInstruction, SenderWithContext, OPENCALLS}; +use super::{ScreenInstruction, SenderWithContext}; use crate::os_input_output::OsApi; use crate::utils::logging::debug_to_file; use crate::{ - errors::{ContextType, ErrorContext}, + errors::{get_current_ctx, ContextType, ErrorContext}, panes::PaneId, }; use crate::{layout::Layout, wasm_vm::PluginInstruction}; @@ -43,7 +43,7 @@ impl Stream for ReadFromPid { // indicates end of file Poll::Ready(None) } else { - let res = Some(read_buffer[..=*res].to_vec()); + let res = Some(read_buffer[..*res].to_vec()); Poll::Ready(res) } } @@ -89,15 +89,14 @@ pub struct PtyBus { fn stream_terminal_bytes( pid: RawFd, - mut send_screen_instructions: SenderWithContext<ScreenInstruction>, + send_screen_instructions: SenderWithContext<ScreenInstruction>, os_input: Box<dyn OsApi>, debug: bool, ) -> JoinHandle<()> { - let mut err_ctx = OPENCALLS.with(|ctx| *ctx.borrow()); + let mut err_ctx = get_current_ctx(); task::spawn({ async move { err_ctx.add_call(ContextType::AsyncTask); - send_screen_instructions.update(err_ctx); let mut terminal_bytes = ReadFromPid::new(&pid, os_input); let mut last_byte_receive_time: Option<Instant> = None; diff --git a/src/common/screen.rs b/src/common/screen.rs index 563221e9..03cfa0bf 100644 --- a/src/common/screen.rs +++ b/src/common/screen.rs @@ -38,6 +38,8 @@ pub enum ScreenInstruction { Quit, ScrollUp, ScrollDown, + PageScrollUp, + PageScrollDown, ClearScroll, CloseFocusedPane, ToggleActiveTerminalFullscreen, @@ -83,7 +85,9 @@ pub struct Screen { } impl Screen { + // FIXME: This lint needs actual fixing! Maybe by bundling the Senders /// Creates and returns a new [`Screen`]. + #[allow(clippy::too_many_arguments)] pub fn new( receive_screen_instructions: Receiver<(ScreenInstruction, ErrorContext)>, send_pty_instructions: SenderWithContext<PtyInstruction>, diff --git a/src/common/utils/logging.rs b/src/common/utils/logging.rs index d08639aa..06827bfc 100644 --- a/src/common/utils/logging.rs +++ b/src/common/utils/logging.rs @@ -47,8 +47,7 @@ pub fn _debug_log_to_file_pid_3(message: String, pid: RawFd) -> io::Result<()> { } } -#[allow(dead_code)] -pub fn delete_log_file() -> io::Result<()> { +pub fn _delete_log_file() -> io::Result<()> { if fs::metadata(ZELLIJ_TMP_LOG_FILE).is_ok() { fs::remove_file(ZELLIJ_TMP_LOG_FILE) } else { @@ -56,8 +55,7 @@ pub fn delete_log_file() -> io::Result<()> { } } -#[allow(dead_code)] -pub fn delete_log_dir() -> io::Result<()> { +pub fn _delete_log_dir() -> io::Result<()> { if fs::metadata(ZELLIJ_TMP_LOG_DIR).is_ok() { fs::remove_dir_all(ZELLIJ_TMP_LOG_DIR) } else { diff --git a/src/common/utils/shared.rs b/src/common/utils/shared.rs index 5d01e78e..de15d784 100644 --- a/src/common/utils/shared.rs +++ b/src/common/utils/shared.rs @@ -22,9 +22,9 @@ pub fn adjust_to_size(s: &str, rows: usize, columns: usize) -> String { if actual_len > columns { let mut line = String::from(l); line.truncate(columns); - return line; + line } else { - return [l, &str::repeat(" ", columns - ansi_len(l))].concat(); + [l, &str::repeat(" ", columns - ansi_len(l))].concat() } }) .chain(iter::repeat(str::repeat(" ", columns))) diff --git a/src/main.rs b/src/main.rs index 7d8ca6d5..ec249e8a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,23 +1,10 @@ -#[cfg(test)] -mod tests; - mod cli; mod common; +#[cfg(test)] +mod tests; // TODO mod server; mod client; -use client::{boundaries, layout, panes, tab}; -use common::{ - command_is_executing, errors, os_input_output, pty_bus, screen, start, utils, wasm_vm, - ApiCommand, -}; -use directories_next::ProjectDirs; - -use std::os::unix::net::UnixStream; -use std::{fs, io::Write}; - -use structopt::StructOpt; - use crate::cli::CliArgs; use crate::command_is_executing::CommandIsExecuting; use crate::os_input_output::get_os_input; @@ -25,37 +12,16 @@ use crate::utils::{ consts::{ZELLIJ_IPC_PIPE, ZELLIJ_TMP_DIR, ZELLIJ_TMP_LOG_DIR}, logging::*, }; +use client::{boundaries, layout, panes, tab}; +use common::{ + command_is_executing, errors, os_input_output, pty_bus, screen, start, utils, wasm_vm, + ApiCommand, +}; +use std::io::Write; +use std::os::unix::net::UnixStream; +use structopt::StructOpt; pub fn main() { - // First run installation of default plugins & layouts - let project_dirs = ProjectDirs::from("org", "Zellij Contributors", "Zellij").unwrap(); - let data_dir = project_dirs.data_dir(); - let mut assets = asset_map! { - "assets/layouts/default.yaml" => "layouts/default.yaml", - "assets/layouts/strider.yaml" => "layouts/strider.yaml", - }; - // FIXME: This is a hideous hack and I hate it (a lot) - #[cfg(not(feature = "publish"))] - assets.extend(asset_map! { - "target/status-bar.wasm" => "plugins/status-bar.wasm", - "target/tab-bar.wasm" => "plugins/tab-bar.wasm", - "target/strider.wasm" => "plugins/strider.wasm", - }); - #[cfg(feature = "publish")] - assets.extend(asset_map! { - "assets/plugins/status-bar.wasm" => "plugins/status-bar.wasm", - "assets/plugins/tab-bar.wasm" => "plugins/tab-bar.wasm", - "assets/plugins/strider.wasm" => "plugins/strider.wasm", - }); - - for (path, bytes) in assets { - let path = data_dir.join(path); - fs::create_dir_all(path.parent().unwrap()).unwrap(); - if !path.exists() { - fs::write(path, bytes).expect("Failed to install default assets!"); - } - } - let opts = CliArgs::from_args(); if let Some(split_dir) = opts.split { match split_dir { diff --git a/src/tests/fixtures/layouts/expansion-boundary-in-the-middle.yaml b/src/tests/fixtures/layouts/expansion-boundary-in-the-middle.yaml deleted file mode 100644 index 9227c080..00000000 --- a/src/tests/fixtures/layouts/expansion-boundary-in-the-middle.yaml +++ /dev/null @@ -1,19 +0,0 @@ ---- -direction: Horizontal -parts: - - direction: Vertical - split_size: - Percent: 40 - - direction: Vertical - parts: - - direction: Horizontal - split_size: - Percent: 40 - - direction: Horizontal - expansion_boundary: true - - direction: Horizontal - split_size: - Percent: 40 - - direction: Vertical - split_size: - Percent: 40 diff --git a/src/tests/integration/basic.rs b/src/tests/integration/basic.rs index 377e25b2..e57f8c75 100644 --- a/src/tests/integration/basic.rs +++ b/src/tests/integration/basic.rs @@ -3,8 +3,9 @@ use ::insta::assert_snapshot; use crate::tests::fakes::FakeInputOutput; use crate::tests::utils::commands::{ - PANE_MODE, QUIT, SCROLL_DOWN_IN_SCROLL_MODE, SCROLL_MODE, SCROLL_UP_IN_SCROLL_MODE, - SPAWN_TERMINAL_IN_PANE_MODE, SPLIT_DOWN_IN_PANE_MODE, SPLIT_RIGHT_IN_PANE_MODE, + PANE_MODE, QUIT, SCROLL_DOWN_IN_SCROLL_MODE, SCROLL_MODE, SCROLL_PAGE_DOWN_IN_SCROLL_MODE, + SCROLL_PAGE_UP_IN_SCROLL_MODE, SCROLL_UP_IN_SCROLL_MODE, SPAWN_TERMINAL_IN_PANE_MODE, + SPLIT_DOWN_IN_PANE_MODE, SPLIT_RIGHT_IN_PANE_MODE, TOGGLE_ACTIVE_TERMINAL_FULLSCREEN_IN_PANE_MODE, }; use crate::tests::utils::{get_next_to_last_snapshot, get_output_frame_snapshots}; @@ -238,6 +239,67 @@ pub fn scrolling_down_inside_a_pane() { } #[test] +pub fn scrolling_page_up_inside_a_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(&[ + &PANE_MODE, + &SPLIT_DOWN_IN_PANE_MODE, + &SPLIT_RIGHT_IN_PANE_MODE, + &SCROLL_MODE, + &SCROLL_PAGE_UP_IN_SCROLL_MODE, + &QUIT, + ]); + start(Box::new(fake_input_output.clone()), CliArgs::default()); + 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 scrolling_page_down_inside_a_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(&[ + &PANE_MODE, + &SPLIT_DOWN_IN_PANE_MODE, + &SPLIT_RIGHT_IN_PANE_MODE, + &SCROLL_MODE, + &SCROLL_PAGE_UP_IN_SCROLL_MODE, + &SCROLL_PAGE_UP_IN_SCROLL_MODE, + &SCROLL_PAGE_DOWN_IN_SCROLL_MODE, + &SCROLL_PAGE_DOWN_IN_SCROLL_MODE, + &QUIT, + ]); + start(Box::new(fake_input_output.clone()), CliArgs::default()); + 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 max_panes() { // with the --max-panes option, we only allow a certain amount of panes on screen // simultaneously, new panes beyond this limit will close older panes on screen diff --git a/src/tests/integration/expansion_boundary.rs b/src/tests/integration/expansion_boundary.rs deleted file mode 100644 index c68c1d5a..00000000 --- a/src/tests/integration/expansion_boundary.rs +++ /dev/null @@ -1,117 +0,0 @@ -use insta::assert_snapshot; -use std::path::PathBuf; - -use crate::panes::PositionAndSize; -use crate::tests::fakes::FakeInputOutput; -use crate::tests::utils::commands::{ - PANE_MODE, QUIT, RESIZE_DOWN_IN_RESIZE_MODE, RESIZE_MODE, SLEEP, SPAWN_TERMINAL_IN_PANE_MODE, - TOGGLE_ACTIVE_TERMINAL_FULLSCREEN_IN_PANE_MODE, -}; -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 new_panes_are_open_inside_expansion_border() { - let fake_win_size = PositionAndSize { - columns: 121, - rows: 50, - x: 0, - y: 0, - }; - let mut fake_input_output = get_fake_os_input(&fake_win_size); - fake_input_output.add_terminal_input(&[ - &PANE_MODE, - &SPAWN_TERMINAL_IN_PANE_MODE, - &SLEEP, - &QUIT, - ]); - let mut opts = CliArgs::default(); - opts.layout = Some(PathBuf::from( - "src/tests/fixtures/layouts/expansion-boundary-in-the-middle.yaml", - )); - - 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 next_to_last_snapshot = get_next_to_last_snapshot(snapshots).unwrap(); - assert_snapshot!(next_to_last_snapshot); -} - -#[test] -pub fn resize_pane_inside_expansion_border() { - let fake_win_size = PositionAndSize { - columns: 121, - rows: 50, - x: 0, - y: 0, - }; - let mut fake_input_output = get_fake_os_input(&fake_win_size); - fake_input_output.add_terminal_input(&[ - &PANE_MODE, - &SPAWN_TERMINAL_IN_PANE_MODE, - &RESIZE_MODE, - &RESIZE_DOWN_IN_RESIZE_MODE, - &SLEEP, - &QUIT, - ]); - let mut opts = CliArgs::default(); - opts.layout = Some(PathBuf::from( - "src/tests/fixtures/layouts/expansion-boundary-in-the-middle.yaml", - )); - - 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 next_to_last_snapshot = get_next_to_last_snapshot(snapshots).unwrap(); - assert_snapshot!(next_to_last_snapshot); -} - -#[test] -pub fn toggling_fullcsreen_in_expansion_border_expands_only_until_border() { - let fake_win_size = PositionAndSize { - columns: 121, - rows: 50, - x: 0, - y: 0, - }; - let mut fake_input_output = get_fake_os_input(&fake_win_size); - fake_input_output.add_terminal_input(&[ - &PANE_MODE, - &SPAWN_TERMINAL_IN_PANE_MODE, - &TOGGLE_ACTIVE_TERMINAL_FULLSCREEN_IN_PANE_MODE, - &SLEEP, - &QUIT, - ]); - let mut opts = CliArgs::default(); - opts.layout = Some(PathBuf::from( - "src/tests/fixtures/layouts/expansion-boundary-in-the-middle.yaml", - )); - - 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 next_to_last_snapshot = get_next_to_last_snapshot(snapshots).unwrap(); - assert_snapshot!(next_to_last_snapshot); -} - -// TODO: -// * fullscreen with expansion boundary diff --git a/src/tests/integration/mod.rs b/src/tests/integration/mod.rs index 83cb7d22..0511fc9c 100644 --- a/src/tests/integration/mod.rs +++ b/src/tests/integration/mod.rs @@ -1,7 +1,6 @@ pub mod basic; pub mod close_pane; pub mod compatibility; -pub mod expansion_boundary; pub mod layouts; pub mod move_focus_down; pub mod move_focus_left; diff --git a/src/tests/integration/resize_down.rs b/src/tests/integration/resize_down.rs index 4957b33e..773eaa86 100644 --- a/src/tests/integration/resize_down.rs +++ b/src/tests/integration/resize_down.rs @@ -98,17 +98,18 @@ pub fn resize_down_with_panes_above_and_below() { // ┌───────────┐ ┌───────────┐ // │ │ │ │ // │ │ │ │ - // ├───────────┤ │ │ - // │███████████│ ==resize=down==> ├───────────┤ - // │███████████│ │███████████│ // ├───────────┤ ├───────────┤ - // │ │ │ │ + // │███████████│ ==resize=down==> │███████████│ + // │███████████│ │███████████│ + // │███████████│ │███████████│ + // ├───────────┤ │███████████│ + // │ │ ├───────────┤ // │ │ │ │ // └───────────┘ └───────────┘ // █ == focused pane let fake_win_size = PositionAndSize { columns: 121, - rows: 20, + rows: 25, x: 0, y: 0, }; @@ -599,7 +600,7 @@ pub fn cannot_resize_down_when_pane_below_is_at_minimum_height() { // █ == focused pane let fake_win_size = PositionAndSize { columns: 121, - rows: 5, + rows: 7, x: 0, y: 0, }; diff --git a/src/tests/integration/resize_up.rs b/src/tests/integration/resize_up.rs index 9d4dd05a..5f720172 100644 --- a/src/tests/integration/resize_up.rs +++ b/src/tests/integration/resize_up.rs @@ -594,7 +594,7 @@ pub fn cannot_resize_up_when_pane_above_is_at_minimum_height() { // █ == focused pane let fake_win_size = PositionAndSize { columns: 121, - rows: 5, + rows: 7, x: 0, y: 0, }; diff --git a/src/tests/integration/snapshots/zellij__tests__integration__basic__scrolling_page_down_inside_a_pane.snap b/src/tests/integration/snapshots/zellij__tests__integration__basic__scrolling_page_down_inside_a_pane.snap new file mode 100644 index 00000000..8f4ec6e2 --- /dev/null +++ b/src/tests/integration/snapshots/zellij__tests__integration__basic__scrolling_page_down_inside_a_pane.snap @@ -0,0 +1,25 @@ +--- +source: src/tests/integration/basic.rs +expression: snapshot_before_quit + +--- +line11-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +line12-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +line13-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +line14-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +line15-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +line16-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +line17-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +line18-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +line19-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +prompt $ +────────────────────────────────────────────────────────────┬──────────────────────────────────────────────────────────── +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa│line12-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb +a │line13-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb +line18-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa│line14-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa│line15-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb +a │line16-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb +line19-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa│line17-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa│line18-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb +a │line19-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb +prompt $ │prompt $ █ diff --git a/src/tests/integration/snapshots/zellij__tests__integration__basic__scrolling_page_up_inside_a_pane.snap b/src/tests/integration/snapshots/zellij__tests__integration__basic__scrolling_page_up_inside_a_pane.snap new file mode 100644 index 00000000..d37580c6 --- /dev/null +++ b/src/tests/integration/snapshots/zellij__tests__integration__basic__scrolling_page_up_inside_a_pane.snap @@ -0,0 +1,25 @@ +--- +source: src/tests/integration/basic.rs +expression: snapshot_before_quit + +--- +line11-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +line12-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +line13-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +line14-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +line15-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +line16-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +line17-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +line18-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +line19-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +prompt $ +────────────────────────────────────────────────────────────┬──────────────────────────────────────────────────────────── +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa│line4-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb +a │line5-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb +line18-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa│line6-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa│line7-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb +a │line8-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb +line19-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa│line9-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa│line10-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb +a │line11-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb +prompt $ │line12-bb█bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb diff --git a/src/tests/integration/snapshots/zellij__tests__integration__expansion_boundary__new_panes_are_open_inside_expansion_border.snap b/src/tests/integration/snapshots/zellij__tests__integration__expansion_boundary__new_panes_are_open_inside_expansion_border.snap deleted file mode 100644 index 661eaf96..00000000 --- a/src/tests/integration/snapshots/zellij__tests__integration__expansion_boundary__new_panes_are_open_inside_expansion_border.snap +++ /dev/null @@ -1,55 +0,0 @@ ---- -source: src/tests/integration/expansion_boundary.rs -expression: next_to_last_snapshot - ---- -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 $ -───────────────────────────────────────────────┬─────────────────────────┬─────────────────────────────────────────────── -line11-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb│line16-bbbbbbbbbbbbbbbbbb│line11-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb -line12-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb│line17-bbbbbbbbbbbbbbbbbb│line12-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb -line13-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb│line18-bbbbbbbbbbbbbbbbbb│line13-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb -line14-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb│line19-bbbbbbbbbbbbbbbbbb│line14-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb -line15-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb│prompt $ │line15-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb -line16-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb├─────────────────────────┤line16-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb -line17-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb│line17-bbbbbbbbbbbbbbbbbb│line17-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb -line18-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb│line18-bbbbbbbbbbbbbbbbbb│line18-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb -line19-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb│line19-bbbbbbbbbbbbbbbbbb│line19-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb -prompt $ │prompt $ █ │prompt $ -───────────────────────────────────────────────┴─────────────────────────┴─────────────────────────────────────────────── -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 $ diff --git a/src/tests/integration/snapshots/zellij__tests__integration__expansion_boundary__resize_pane_inside_expansion_border.snap b/src/tests/integration/snapshots/zellij__tests__integration__expansion_boundary__resize_pane_inside_expansion_border.snap deleted file mode 100644 index a3d009ce..00000000 --- a/src/tests/integration/snapshots/zellij__tests__integration__expansion_boundary__resize_pane_inside_expansion_border.snap +++ /dev/null @@ -1,55 +0,0 @@ ---- -source: src/tests/integration/expansion_boundary.rs -expression: next_to_last_snapshot - ---- -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 $ -───────────────────────────────────────────────┬─────────────────────────┬─────────────────────────────────────────────── -line11-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb│line14-bbbbbbbbbbbbbbbbbb│line11-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb -line12-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb│line15-bbbbbbbbbbbbbbbbbb│line12-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb -line13-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb│line16-bbbbbbbbbbbbbbbbbb│line13-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb -line14-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb│line17-bbbbbbbbbbbbbbbbbb│line14-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb -line15-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb│line18-bbbbbbbbbbbbbbbbbb│line15-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb -line16-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb│line19-bbbbbbbbbbbbbbbbbb│line16-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb -line17-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb│prompt $ │line17-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb -line18-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb├─────────────────────────┤line18-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb -line19-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb│line19-bbbbbbbbbbbbbbbbbb│line19-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb -prompt $ │prompt $ █ │prompt $ -───────────────────────────────────────────────┴─────────────────────────┴─────────────────────────────────────────────── -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 $ diff --git a/src/tests/integration/snapshots/zellij__tests__integration__expansion_boundary__toggling_fullcsreen_in_expansion_border_expands_only_until_border.snap b/src/tests/integration/snapshots/zellij__tests__integration__expansion_boundary__toggling_fullcsreen_in_expansion_border_expands_only_until_border.snap deleted file mode 100644 index 41a54185..00000000 --- a/src/tests/integration/snapshots/zellij__tests__integration__expansion_boundary__toggling_fullcsreen_in_expansion_border_expands_only_until_border.snap +++ /dev/null @@ -1,55 +0,0 @@ ---- -source: src/tests/integration/expansion_boundary.rs -expression: next_to_last_snapshot - ---- -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 $ -───────────────────────────────────────────────┬─────────────────────────┬─────────────────────────────────────────────── -line11-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb│line11-bbbbbbbbbbbbbbbbbb│line11-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb -line12-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb│line12-bbbbbbbbbbbbbbbbbb│line12-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb -line13-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb│line13-bbbbbbbbbbbbbbbbbb│line13-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb -line14-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb│line14-bbbbbbbbbbbbbbbbbb│line14-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb -line15-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb│line15-bbbbbbbbbbbbbbbbbb│line15-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb -line16-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb│line16-bbbbbbbbbbbbbbbbbb│line16-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb -line17-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb│line17-bbbbbbbbbbbbbbbbbb│line17-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb -line18-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb│line18-bbbbbbbbbbbbbbbbbb│line18-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb -line19-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb│line19-bbbbbbbbbbbbbbbbbb│line19-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb -prompt $ │prompt $ █ │prompt $ -───────────────────────────────────────────────┴─────────────────────────┴─────────────────────────────────────────────── -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 $ diff --git a/src/tests/integration/snapshots/zellij__tests__integration__resize_down__cannot_resize_down_when_pane_below_is_at_minimum_height.snap b/src/tests/integration/snapshots/zellij__tests__integration__resize_down__cannot_resize_down_when_pane_below_is_at_minimum_height.snap index 523612a9..5eedc89f 100644 --- a/src/tests/integration/snapshots/zellij__tests__integration__resize_down__cannot_resize_down_when_pane_below_is_at_minimum_height.snap +++ b/src/tests/integration/snapshots/zellij__tests__integration__resize_down__cannot_resize_down_when_pane_below_is_at_minimum_height.snap @@ -3,8 +3,10 @@ source: src/tests/integration/resize_down.rs expression: snapshot_before_quit --- +line18-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa line19-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa prompt $ ───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── +line18-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa line19-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa prompt $ █ diff --git a/src/tests/integration/snapshots/zellij__tests__integration__resize_down__resize_down_with_panes_above_and_below.snap b/src/tests/integration/snapshots/zellij__tests__integration__resize_down__resize_down_with_panes_above_and_below.snap index 0d404ed1..29c9a76a 100644 --- a/src/tests/integration/snapshots/zellij__tests__integration__resize_down__resize_down_with_panes_above_and_below.snap +++ b/src/tests/integration/snapshots/zellij__tests__integration__resize_down__resize_down_with_panes_above_and_below.snap @@ -3,6 +3,8 @@ source: src/tests/integration/resize_down.rs expression: snapshot_before_quit --- +line9-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +line10-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa line11-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa line12-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa line13-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa @@ -14,6 +16,8 @@ line18-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa line19-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa prompt $ ───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── +line13-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +line14-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa line15-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa line16-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa line17-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa @@ -21,5 +25,6 @@ line18-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa line19-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa prompt $ █ ───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── +line18-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa line19-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa prompt $ diff --git a/src/tests/integration/snapshots/zellij__tests__integration__resize_up__cannot_resize_up_when_pane_above_is_at_minimum_height.snap b/src/tests/integration/snapshots/zellij__tests__integration__resize_up__cannot_resize_up_when_pane_above_is_at_minimum_height.snap index e1f6bee0..5b09c7bd 100644 --- a/src/tests/integration/snapshots/zellij__tests__integration__resize_up__cannot_resize_up_when_pane_above_is_at_minimum_height.snap +++ b/src/tests/integration/snapshots/zellij__tests__integration__resize_up__cannot_resize_up_when_pane_above_is_at_minimum_height.snap @@ -3,8 +3,10 @@ source: src/tests/integration/resize_up.rs expression: snapshot_before_quit --- +line18-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa line19-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa prompt $ ───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── +line18-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa line19-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa prompt $ █ diff --git a/src/tests/utils.rs b/src/tests/utils.rs index 915adfb0..aa622fe7 100644 --- a/src/tests/utils.rs +++ b/src/tests/utils.rs @@ -12,7 +12,7 @@ pub fn get_output_frame_snapshots( let mut snapshots = vec![]; for frame in output_frames.iter() { for byte in frame.iter() { - vte_parser.advance(&mut terminal_output, *byte); + vte_parser.advance(&mut terminal_output.grid, *byte); } let output_lines = terminal_output.read_buffer_as_lines(); let cursor_coordinates = terminal_output.cursor_coordinates(); @@ -63,6 +63,8 @@ pub mod commands { pub const SCROLL_MODE: [u8; 1] = [19]; // ctrl-s pub const SCROLL_UP_IN_SCROLL_MODE: [u8; 1] = [107]; // k pub const SCROLL_DOWN_IN_SCROLL_MODE: [u8; 1] = [106]; // j + pub const SCROLL_PAGE_UP_IN_SCROLL_MODE: [u8; 1] = [2]; // ctrl-b + pub const SCROLL_PAGE_DOWN_IN_SCROLL_MODE: [u8; 1] = [6]; // ctrl-f pub const RESIZE_MODE: [u8; 1] = [18]; // ctrl-r pub const RESIZE_DOWN_IN_RESIZE_MODE: [u8; 1] = [106]; // j |
