diff options
Diffstat (limited to 'alacritty_terminal')
-rw-r--r-- | alacritty_terminal/src/grid/mod.rs | 160 | ||||
-rw-r--r-- | alacritty_terminal/src/grid/storage.rs | 1062 | ||||
-rw-r--r-- | alacritty_terminal/src/grid/tests.rs | 55 | ||||
-rw-r--r-- | alacritty_terminal/src/term/mod.rs | 12 |
4 files changed, 590 insertions, 699 deletions
diff --git a/alacritty_terminal/src/grid/mod.rs b/alacritty_terminal/src/grid/mod.rs index 54b496af..792dd844 100644 --- a/alacritty_terminal/src/grid/mod.rs +++ b/alacritty_terminal/src/grid/mod.rs @@ -189,6 +189,7 @@ impl<T: GridCell + Copy + Clone> Grid<T> { pub fn resize( &mut self, + reflow: bool, lines: index::Line, cols: index::Column, cursor_pos: &mut Point, @@ -206,8 +207,8 @@ impl<T: GridCell + Copy + Clone> Grid<T> { } match self.cols.cmp(&cols) { - Ordering::Less => self.grow_cols(cols, cursor_pos, template), - Ordering::Greater => self.shrink_cols(cols, template), + Ordering::Less => self.grow_cols(reflow, cols, cursor_pos, template), + Ordering::Greater => self.shrink_cols(reflow, cols, template), Ordering::Equal => (), } } @@ -252,93 +253,107 @@ impl<T: GridCell + Copy + Clone> Grid<T> { self.display_offset = self.display_offset.saturating_sub(*lines_added); } - fn grow_cols(&mut self, cols: index::Column, cursor_pos: &mut Point, template: &T) { - // Truncate all buffered lines - self.raw.grow_hidden(cols, template); - - let max_lines = self.lines.0 + self.max_scroll_limit; - - // Iterate backwards with indices for mutation during iteration - let mut i = self.raw.len(); - while i > 0 { - i -= 1; - - // Grow the current line if there's wrapped content available - while i >= 1 - && self.raw[i].len() < cols.0 - && self.raw[i].last().map(GridCell::is_wrap) == Some(true) - { - // Remove wrap flag before appending additional cells - if let Some(cell) = self.raw[i].last_mut() { - cell.set_wrap(false); - } + fn grow_cols( + &mut self, + reflow: bool, + cols: index::Column, + cursor_pos: &mut Point, + template: &T, + ) { + let mut new_empty_lines = 0; + let mut new_raw: Vec<Row<T>> = Vec::with_capacity(self.raw.len()); + for (i, mut row) in self.raw.drain().enumerate().rev() { + if let Some(last_row) = new_raw.last_mut() { + // Grow the current line if there's wrapped content available + if reflow + && last_row.len() < cols.0 + && last_row.last().map(GridCell::is_wrap) == Some(true) + { + // Remove wrap flag before appending additional cells + if let Some(cell) = last_row.last_mut() { + cell.set_wrap(false); + } - // Append as many cells from the next line as possible - let len = min(self.raw[i - 1].len(), cols.0 - self.raw[i].len()); - let mut cells = self.raw[i - 1].front_split_off(len); - self.raw[i].append(&mut cells); - - if self.raw[i - 1].is_empty() { - // Remove following line if all cells have been drained - self.raw.remove(i - 1); - - if self.raw.len() < self.lines.0 || self.scroll_limit == 0 { - // Add new line and move lines up if we can't pull from history - self.raw.insert(0, Row::new(cols, template), max_lines); - cursor_pos.line = Line(cursor_pos.line.saturating_sub(1)); - } else { - // Make sure viewport doesn't move if line is outside of the visible area - if i < self.display_offset { - self.display_offset = self.display_offset.saturating_sub(1); + // Append as many cells from the next line as possible + let len = min(row.len(), cols.0 - last_row.len()); + let mut cells = row.front_split_off(len); + last_row.append(&mut cells); + + if row.is_empty() { + let raw_len = i + 1 + new_raw.len();; + if raw_len < self.lines.0 || self.scroll_limit == 0 { + // Add new line and move lines up if we can't pull from history + cursor_pos.line = Line(cursor_pos.line.saturating_sub(1)); + new_empty_lines += 1; + } else { + // Make sure viewport doesn't move if line is outside of the visible + // area + if i < self.display_offset { + self.display_offset = self.display_offset.saturating_sub(1); + } + + // Remove one line from scrollback, since we just moved it to the + // viewport + self.scroll_limit = self.scroll_limit.saturating_sub(1); + self.display_offset = min(self.display_offset, self.scroll_limit); } - // Remove one line from scrollback, since we just moved it to the viewport - self.scroll_limit = self.scroll_limit.saturating_sub(1); - self.display_offset = min(self.display_offset, self.scroll_limit); - i -= 1; + // Don't push line into the new buffer + continue; + } else if let Some(cell) = last_row.last_mut() { + // Set wrap flag if next line still has cells + cell.set_wrap(true); } - } else if let Some(cell) = self.raw[i].last_mut() { - // Set wrap flag if next line still has cells - cell.set_wrap(true); } } - // Fill remaining cells - if self.raw[i].len() < cols.0 { - self.raw[i].grow(cols, template); + new_raw.push(row); + } + + // Add padding lines + new_raw.append(&mut vec![Row::new(cols, template); new_empty_lines]); + + // Fill remaining cells and reverse iterator + let mut reversed = Vec::with_capacity(new_raw.len()); + for mut row in new_raw.drain(..).rev() { + if row.len() < cols.0 { + row.grow(cols, template); } + reversed.push(row); } + self.raw.replace_inner(reversed); + self.cols = cols; } - fn shrink_cols(&mut self, cols: index::Column, template: &T) { - // Truncate all buffered lines - self.raw.shrink_hidden(cols); - - let max_lines = self.lines.0 + self.max_scroll_limit; + fn shrink_cols(&mut self, reflow: bool, cols: index::Column, template: &T) { + let mut new_raw = Vec::with_capacity(self.raw.len()); + let mut buffered = None; + for (i, mut row) in self.raw.drain().enumerate().rev() { + if let Some(buffered) = buffered.take() { + row.append_front(buffered); + } - // Iterate backwards with indices for mutation during iteration - let mut i = self.raw.len(); - while i > 0 { - i -= 1; + let mut wrapped = row.shrink(cols); + new_raw.push(row); - if let Some(mut new_row) = self.raw[i].shrink(cols) { + while let (Some(mut wrapped_cells), true) = (wrapped.take(), reflow) { // Set line as wrapped if cells got removed - if let Some(cell) = self.raw[i].last_mut() { + if let Some(cell) = new_raw.last_mut().and_then(|r| r.last_mut()) { cell.set_wrap(true); } - if Some(true) == new_row.last().map(|c| c.is_wrap() && i >= 1) - && new_row.len() < cols.0 + if Some(true) == wrapped_cells.last().map(|c| c.is_wrap() && i >= 1) + && wrapped_cells.len() < cols.0 { // Make sure previous wrap flag doesn't linger around - if let Some(cell) = new_row.last_mut() { + if let Some(cell) = wrapped_cells.last_mut() { cell.set_wrap(false); } // Add removed cells to start of next row - self.raw[i - 1].append_front(new_row); + buffered = Some(wrapped_cells); } else { // Make sure viewport doesn't move if line is outside of the visible area if i < self.display_offset { @@ -346,24 +361,27 @@ impl<T: GridCell + Copy + Clone> Grid<T> { } // Make sure new row is at least as long as new width - let occ = new_row.len(); + let occ = wrapped_cells.len(); if occ < cols.0 { - new_row.append(&mut vec![*template; cols.0 - occ]); + wrapped_cells.append(&mut vec![*template; cols.0 - occ]); } - let row = Row::from_vec(new_row, occ); + let mut row = Row::from_vec(wrapped_cells, occ); + + // Since inserted might exceed cols, we need to check it again + wrapped = row.shrink(cols); // Add new row with all removed cells - self.raw.insert(i, row, max_lines); + new_raw.push(row); // Increase scrollback history self.scroll_limit = min(self.scroll_limit + 1, self.max_scroll_limit); - - // Since inserted might exceed cols, we need to check the same line again - i += 1; } } } + let mut reversed: Vec<Row<T>> = new_raw.drain(..).rev().collect(); + reversed.truncate(self.max_scroll_limit + self.lines.0); + self.raw.replace_inner(reversed); self.cols = cols; } diff --git a/alacritty_terminal/src/grid/storage.rs b/alacritty_terminal/src/grid/storage.rs index 32260426..9b8b0b2a 100644 --- a/alacritty_terminal/src/grid/storage.rs +++ b/alacritty_terminal/src/grid/storage.rs @@ -12,12 +12,12 @@ /// implementation is provided. Anything from Vec that should be exposed must be /// done so manually. use std::ops::{Index, IndexMut}; +use std::vec::Drain; use static_assertions::assert_eq_size; use super::Row; -use crate::grid::GridCell; -use crate::index::{Column, Line}; +use crate::index::Line; /// Maximum number of invisible lines before buffer is resized const TRUNCATE_STEP: usize = 100; @@ -258,69 +258,16 @@ impl<T> Storage<T> { self.zero = (self.zero + count) % self.inner.len(); } - #[inline] - pub fn insert(&mut self, index: usize, row: Row<T>, max_lines: usize) { - let index = self.compute_index(index); - self.inner.insert(index, row); - - if index < self.zero { - self.zero += 1; - } - - if self.len < max_lines { - self.len += 1; - } + pub fn drain(&mut self) -> Drain<'_, Row<T>> { + self.truncate(); + self.inner.drain(..) } - #[inline] - pub fn remove(&mut self, index: usize) -> Row<T> { - let index = self.compute_index(index); - if index < self.zero { - self.zero -= 1; - } - self.len -= 1; - - self.inner.remove(index) - } - - /// Shrink columns of hidden buffered lines. - /// - /// XXX This suggests that Storage is a leaky abstraction. Ultimately, this - /// is needed because of the grow/shrink lines functionality. - #[inline] - pub fn shrink_hidden(&mut self, cols: Column) - where - T: GridCell + Copy, - { - let start = self.zero + self.len; - let end = self.zero + self.inner.len(); - for mut i in start..end { - if i >= self.inner.len() { - i -= self.inner.len(); - } - - self.inner[i].shrink(cols); - } - } - - /// Grow columns of hidden buffered lines. - /// - /// XXX This suggests that Storage is a leaky abstraction. Ultimately, this - /// is needed because of the grow/shrink lines functionality. - #[inline] - pub fn grow_hidden(&mut self, cols: Column, template: &T) - where - T: Copy + Clone, - { - let start = self.zero + self.len; - let end = self.zero + self.inner.len(); - for mut i in start..end { - if i >= self.inner.len() { - i -= self.inner.len(); - } - - self.inner[i].grow(cols, template); - } + /// Update the raw storage buffer + pub fn replace_inner(&mut self, vec: Vec<Row<T>>) { + self.len = vec.len(); + self.inner = vec; + self.zero = 0; } } @@ -359,564 +306,451 @@ impl<T> IndexMut<Line> for Storage<T> { } } -/// Grow the buffer one line at the end of the buffer -/// -/// Before: -/// 0: 0 <- Zero -/// 1: 1 -/// 2: - -/// After: -/// 0: - -/// 1: 0 <- Zero -/// 2: 1 -/// 3: - -#[test] -fn grow_after_zero() { - // Setup storage area - let mut storage = Storage { - inner: vec![ - Row::new(Column(1), &'0'), - Row::new(Column(1), &'1'), - Row::new(Column(1), &'-'), - ], - zero: 0, - visible_lines: Line(2), - len: 3, - }; - - // Grow buffer - storage.grow_visible_lines(Line(4), Row::new(Column(1), &'-')); - - // Make sure the result is correct - let expected = Storage { - inner: vec![ - Row::new(Column(1), &'-'), - Row::new(Column(1), &'0'), - Row::new(Column(1), &'1'), - Row::new(Column(1), &'-'), - ], - zero: 1, - visible_lines: Line(0), - len: 4, - }; - assert_eq!(storage.inner, expected.inner); - assert_eq!(storage.zero, expected.zero); - assert_eq!(storage.len, expected.len); -} - -/// Grow the buffer one line at the start of the buffer -/// -/// Before: -/// 0: - -/// 1: 0 <- Zero -/// 2: 1 -/// After: -/// 0: - -/// 1: - -/// 2: 0 <- Zero -/// 3: 1 -#[test] -fn grow_before_zero() { - // Setup storage area - let mut storage = Storage { - inner: vec![ - Row::new(Column(1), &'-'), - Row::new(Column(1), &'0'), - Row::new(Column(1), &'1'), - ], - zero: 1, - visible_lines: Line(2), - len: 3, - }; - - // Grow buffer - storage.grow_visible_lines(Line(4), Row::new(Column(1), &'-')); - - // Make sure the result is correct - let expected = Storage { - inner: vec![ - Row::new(Column(1), &'-'), - Row::new(Column(1), &'-'), - Row::new(Column(1), &'0'), - Row::new(Column(1), &'1'), - ], - zero: 2, - visible_lines: Line(0), - len: 4, - }; - assert_eq!(storage.inner, expected.inner); - assert_eq!(storage.zero, expected.zero); - assert_eq!(storage.len, expected.len); -} +#[cfg(test)] +mod test { + use crate::grid::row::Row; + use crate::grid::storage::Storage; + use crate::index::{Column, Line}; -/// Shrink the buffer one line at the start of the buffer -/// -/// Before: -/// 0: 2 -/// 1: 0 <- Zero -/// 2: 1 -/// After: -/// 0: 2 <- Hidden -/// 0: 0 <- Zero -/// 1: 1 -#[test] -fn shrink_before_zero() { - // Setup storage area - let mut storage = Storage { - inner: vec![ - Row::new(Column(1), &'2'), - Row::new(Column(1), &'0'), - Row::new(Column(1), &'1'), - ], - zero: 1, - visible_lines: Line(2), - len: 3, - }; - - // Shrink buffer - storage.shrink_visible_lines(Line(2)); - - // Make sure the result is correct - let expected = Storage { - inner: vec![ - Row::new(Column(1), &'2'), - Row::new(Column(1), &'0'), - Row::new(Column(1), &'1'), - ], - zero: 1, - visible_lines: Line(0), - len: 2, - }; - assert_eq!(storage.inner, expected.inner); - assert_eq!(storage.zero, expected.zero); - assert_eq!(storage.len, expected.len); -} - -/// Shrink the buffer one line at the end of the buffer -/// -/// Before: -/// 0: 0 <- Zero -/// 1: 1 -/// 2: 2 -/// After: -/// 0: 0 <- Zero -/// 1: 1 -/// 2: 2 <- Hidden -#[test] -fn shrink_after_zero() { - // Setup storage area - let mut storage = Storage { - inner: vec![ - Row::new(Column(1), &'0'), - Row::new(Column(1), &'1'), - Row::new(Column(1), &'2'), - ], - zero: 0, - visible_lines: Line(2), - len: 3, - }; - - // Shrink buffer - storage.shrink_visible_lines(Line(2)); - - // Make sure the result is correct - let expected = Storage { - inner: vec![ - Row::new(Column(1), &'0'), - Row::new(Column(1), &'1'), - Row::new(Column(1), &'2'), - ], - zero: 0, - visible_lines: Line(0), - len: 2, - }; - assert_eq!(storage.inner, expected.inner); - assert_eq!(storage.zero, expected.zero); - assert_eq!(storage.len, expected.len); -} + /// Grow the buffer one line at the end of the buffer + /// + /// Before: + /// 0: 0 <- Zero + /// 1: 1 + /// 2: - + /// After: + /// 0: - + /// 1: 0 <- Zero + /// 2: 1 + /// 3: - + #[test] + fn grow_after_zero() { + // Setup storage area + let mut storage = Storage { + inner: vec![ + Row::new(Column(1), &'0'), + Row::new(Column(1), &'1'), + Row::new(Column(1), &'-'), + ], + zero: 0, + visible_lines: Line(2), + len: 3, + }; + + // Grow buffer + storage.grow_visible_lines(Line(4), Row::new(Column(1), &'-')); + + // Make sure the result is correct + let expected = Storage { + inner: vec![ + Row::new(Column(1), &'-'), + Row::new(Column(1), &'0'), + Row::new(Column(1), &'1'), + Row::new(Column(1), &'-'), + ], + zero: 1, + visible_lines: Line(0), + len: 4, + }; + assert_eq!(storage.inner, expected.inner); + assert_eq!(storage.zero, expected.zero); + assert_eq!(storage.len, expected.len); + } -/// Shrink the buffer at the start and end of the buffer -/// -/// Before: -/// 0: 4 -/// 1: 5 -/// 2: 0 <- Zero -/// 3: 1 -/// 4: 2 -/// 5: 3 -/// After: -/// 0: 4 <- Hidden -/// 1: 5 <- Hidden -/// 2: 0 <- Zero -/// 3: 1 -/// 4: 2 <- Hidden -/// 5: 3 <- Hidden -#[test] -fn shrink_before_and_after_zero() { - // Setup storage area - let mut storage = Storage { - inner: vec![ - Row::new(Column(1), &'4'), - Row::new(Column(1), &'5'), - Row::new(Column(1), &'0'), - Row::new(Column(1), &'1'), - Row::new(Column(1), &'2'), - Row::new(Column(1), &'3'), - ], - zero: 2, - visible_lines: Line(5), - len: 6, - }; - - // Shrink buffer - storage.shrink_visible_lines(Line(2)); - - // Make sure the result is correct - let expected = Storage { - inner: vec![ - Row::new(Column(1), &'4'), - Row::new(Column(1), &'5'), - Row::new(Column(1), &'0'), - Row::new(Column(1), &'1'), - Row::new(Column(1), &'2'), - Row::new(Column(1), &'3'), - ], - zero: 2, - visible_lines: Line(0), - len: 2, - }; - assert_eq!(storage.inner, expected.inner); - assert_eq!(storage.zero, expected.zero); - assert_eq!(storage.len, expected.len); -} + /// Grow the buffer one line at the start of the buffer + /// + /// Before: + /// 0: - + /// 1: 0 <- Zero + /// 2: 1 + /// After: + /// 0: - + /// 1: - + /// 2: 0 <- Zero + /// 3: 1 + #[test] + fn grow_before_zero() { + // Setup storage area + let mut storage = Storage { + inner: vec![ + Row::new(Column(1), &'-'), + Row::new(Column(1), &'0'), + Row::new(Column(1), &'1'), + ], + zero: 1, + visible_lines: Line(2), + len: 3, + }; + + // Grow buffer + storage.grow_visible_lines(Line(4), Row::new(Column(1), &'-')); + + // Make sure the result is correct + let expected = Storage { + inner: vec![ + Row::new(Column(1), &'-'), + Row::new(Column(1), &'-'), + Row::new(Column(1), &'0'), + Row::new(Column(1), &'1'), + ], + zero: 2, + visible_lines: Line(0), + len: 4, + }; + assert_eq!(storage.inner, expected.inner); + assert_eq!(storage.zero, expected.zero); + assert_eq!(storage.len, expected.len); + } -/// Check that when truncating all hidden lines are removed from the raw buffer -/// -/// Before: -/// 0: 4 <- Hidden -/// 1: 5 <- Hidden -/// 2: 0 <- Zero -/// 3: 1 -/// 4: 2 <- Hidden -/// 5: 3 <- Hidden -/// After: -/// 0: 0 <- Zero -/// 1: 1 -#[test] -fn truncate_invisible_lines() { - // Setup storage area - let mut storage = Storage { - inner: vec![ - Row::new(Column(1), &'4'), - Row::new(Column(1), &'5'), - Row::new(Column(1), &'0'), - Row::new(Column(1), &'1'), - Row::new(Column(1), &'2'), - Row::new(Column(1), &'3'), - ], - zero: 2, - visible_lines: Line(1), - len: 2, - }; - - // Truncate buffer - storage.truncate(); - - // Make sure the result is correct - let expected = Storage { - inner: vec![Row::new(Column(1), &'0'), Row::new(Column(1), &'1')], - zero: 0, - visible_lines: Line(1), - len: 2, - }; - assert_eq!(storage.visible_lines, expected.visible_lines); - assert_eq!(storage.inner, expected.inner); - assert_eq!(storage.zero, expected.zero); - assert_eq!(storage.len, expected.len); -} + /// Shrink the buffer one line at the start of the buffer + /// + /// Before: + /// 0: 2 + /// 1: 0 <- Zero + /// 2: 1 + /// After: + /// 0: 2 <- Hidden + /// 0: 0 <- Zero + /// 1: 1 + #[test] + fn shrink_before_zero() { + // Setup storage area + let mut storage = Storage { + inner: vec![ + Row::new(Column(1), &'2'), + Row::new(Column(1), &'0'), + Row::new(Column(1), &'1'), + ], + zero: 1, + visible_lines: Line(2), + len: 3, + }; + + // Shrink buffer + storage.shrink_visible_lines(Line(2)); + + // Make sure the result is correct + let expected = Storage { + inner: vec![ + Row::new(Column(1), &'2'), + Row::new(Column(1), &'0'), + Row::new(Column(1), &'1'), + ], + zero: 1, + visible_lines: Line(0), + len: 2, + }; + assert_eq!(storage.inner, expected.inner); + assert_eq!(storage.zero, expected.zero); + assert_eq!(storage.len, expected.len); + } -/// Truncate buffer only at the beginning -/// -/// Before: -/// 0: 1 -/// 1: 2 <- Hidden -/// 2: 0 <- Zero -/// After: -/// 0: 1 -/// 0: 0 <- Zero -#[test] -fn truncate_invisible_lines_beginning() { - // Setup storage area - let mut storage = Storage { - inner: vec![ - Row::new(Column(1), &'1'), - Row::new(Column(1), &'2'), - Row::new(Column(1), &'0'), - ], - zero: 2, - visible_lines: Line(1), - len: 2, - }; - - // Truncate buffer - storage.truncate(); - - // Make sure the result is correct - let expected = Storage { - inner: vec![Row::new(Column(1), &'0'), Row::new(Column(1), &'1')], - zero: 0, - visible_lines: Line(1), - len: 2, - }; - assert_eq!(storage.visible_lines, expected.visible_lines); - assert_eq!(storage.inner, expected.inner); - assert_eq!(storage.zero, expected.zero); - assert_eq!(storage.len, expected.len); -} + /// Shrink the buffer one line at the end of the buffer + /// + /// Before: + /// 0: 0 <- Zero + /// 1: 1 + /// 2: 2 + /// After: + /// 0: 0 <- Zero + /// 1: 1 + /// 2: 2 <- Hidden + #[test] + fn shrink_after_zero() { + // Setup storage area + let mut storage = Storage { + inner: vec![ + Row::new(Column(1), &'0'), + Row::new(Column(1), &'1'), + Row::new(Column(1), &'2'), + ], + zero: 0, + visible_lines: Line(2), + len: 3, + }; + + // Shrink buffer + storage.shrink_visible_lines(Line(2)); + + // Make sure the result is correct + let expected = Storage { + inner: vec![ + Row::new(Column(1), &'0'), + Row::new(Column(1), &'1'), + Row::new(Column(1), &'2'), + ], + zero: 0, + visible_lines: Line(0), + len: 2, + }; + assert_eq!(storage.inner, expected.inner); + assert_eq!(storage.zero, expected.zero); + assert_eq!(storage.len, expected.len); + } -/// First shrink the buffer and then grow it again -/// -/// Before: -/// 0: 4 -/// 1: 5 -/// 2: 0 <- Zero -/// 3: 1 -/// 4: 2 -/// 5: 3 -/// After Shrinking: -/// 0: 4 <- Hidden -/// 1: 5 <- Hidden -/// 2: 0 <- Zero -/// 3: 1 -/// 4: 2 -/// 5: 3 <- Hidden -/// After Growing: -/// 0: 4 -/// 1: 5 -/// 2: - -/// 3: 0 <- Zero -/// 4: 1 -/// 5: 2 -/// 6: 3 -#[test] -fn shrink_then_grow() { - // Setup storage area - let mut storage = Storage { - inner: vec![ - Row::new(Column(1), &'4'), - Row::new(Column(1), &'5'), - Row::new(Column(1), &'0'), - Row::new(Column(1), &'1'), - Row::new(Column(1), &'2'), - Row::new(Column(1), &'3'), - ], - zero: 2, - visible_lines: Line(0), - len: 6, - }; - - // Shrink buffer - storage.shrink_lines(3); - - // Make sure the result after shrinking is correct - let shrinking_expected = Storage { - inner: vec![ - Row::new(Column(1), &'4'), - Row::new(Column(1), &'5'), - Row::new(Column(1), &'0'), - Row::new(Column(1), &'1'), - Row::new(Column(1), &'2'), - Row::new(Column(1), &'3'), - ], - zero: 2, - visible_lines: Line(0), - len: 3, - }; - assert_eq!(storage.inner, shrinking_expected.inner); - assert_eq!(storage.zero, shrinking_expected.zero); - assert_eq!(storage.len, shrinking_expected.len); - - // Grow buffer - storage.grow_lines(4, Row::new(Column(1), &'-')); - - // Make sure the result after shrinking is correct - let growing_expected = Storage { - inner: vec![ - Row::new(Column(1), &'4'), - Row::new(Column(1), &'5'), - Row::new(Column(1), &'-'), - Row::new(Column(1), &'0'), - Row::new(Column(1), &'1'), - Row::new(Column(1), &'2'), - Row::new(Column(1), &'3'), - ], - zero: 3, - visible_lines: Line(0), - len: 7, - }; - assert_eq!(storage.inner, growing_expected.inner); - assert_eq!(storage.zero, growing_expected.zero); - assert_eq!(storage.len, growing_expected.len); -} + /// Shrink the buffer at the start and end of the buffer + /// + /// Before: + /// 0: 4 + /// 1: 5 + /// 2: 0 <- Zero + /// 3: 1 + /// 4: 2 + /// 5: 3 + /// After: + /// 0: 4 <- Hidden + /// 1: 5 <- Hidden + /// 2: 0 <- Zero + /// 3: 1 + /// 4: 2 <- Hidden + /// 5: 3 <- Hidden + #[test] + fn shrink_before_and_after_zero() { + // Setup storage area + let mut storage = Storage { + inner: vec![ + Row::new(Column(1), &'4'), + Row::new(Column(1), &'5'), + Row::new(Column(1), &'0'), + Row::new(Column(1), &'1'), + Row::new(Column(1), &'2'), + Row::new(Column(1), &'3'), + ], + zero: 2, + visible_lines: Line(5), + len: 6, + }; + + // Shrink buffer + storage.shrink_visible_lines(Line(2)); + + // Make sure the result is correct + let expected = Storage { + inner: vec![ + Row::new(Column(1), &'4'), + Row::new(Column(1), &'5'), + Row::new(Column(1), &'0'), + Row::new(Column(1), &'1'), + Row::new(Column(1), &'2'), + Row::new(Column(1), &'3'), + ], + zero: 2, + visible_lines: Line(0), + len: 2, + }; + assert_eq!(storage.inner, expected.inner); + assert_eq!(storage.zero, expected.zero); + assert_eq!(storage.len, expected.len); + } -#[test] -fn initialize() { - // Setup storage area - let mut storage = Storage { - inner: vec![ - Row::new(Column(1), &'4'), - Row::new(Column(1), &'5'), - Row::new(Column(1), &'0'), - Row::new(Column(1), &'1'), - Row::new(Column(1), &'2'), - Row::new(Column(1), &'3'), - ], - zero: 2, - visible_lines: Line(0), - len: 6, - }; - - // Initialize additional lines - storage.initialize(3, Row::new(Column(1), &'-')); - - // Make sure the lines are present and at the right location - let shrinking_expected = Storage { - inner: vec![ - Row::new(Column(1), &'4'), - Row::new(Column(1), &'5'), - Row::new(Column(1), &'-'), - Row::new(Column(1), &'-'), - Row::new(Column(1), &'-'), - Row::new(Column(1), &'0'), - Row::new(Column(1), &'1'), - Row::new(Column(1), &'2'), - Row::new(Column(1), &'3'), - ], - zero: 5, - visible_lines: Line(0), - len: 9, - }; - assert_eq!(storage.inner, shrinking_expected.inner); - assert_eq!(storage.zero, shrinking_expected.zero); - assert_eq!(storage.len, shrinking_expected.len); -} + /// Check that when truncating all hidden lines are removed from the raw buffer + /// + /// Before: + /// 0: 4 <- Hidden + /// 1: 5 <- Hidden + /// 2: 0 <- Zero + /// 3: 1 + /// 4: 2 <- Hidden + /// 5: 3 <- Hidden + /// After: + /// 0: 0 <- Zero + /// 1: 1 + #[test] + fn truncate_invisible_lines() { + // Setup storage area + let mut storage = Storage { + inner: vec![ + Row::new(Column(1), &'4'), + Row::new(Column(1), &'5'), + Row::new(Column(1), &'0'), + Row::new(Column(1), &'1'), + Row::new(Column(1), &'2'), + Row::new(Column(1), &'3'), + ], + zero: 2, + visible_lines: Line(1), + len: 2, + }; + + // Truncate buffer + storage.truncate(); + + // Make sure the result is correct + let expected = Storage { + inner: vec![Row::new(Column(1), &'0'), Row::new(Column(1), &'1')], + zero: 0, + visible_lines: Line(1), + len: 2, + }; + assert_eq!(storage.visible_lines, expected.visible_lines); + assert_eq!(storage.inner, expected.inner); + assert_eq!(storage.zero, expected.zero); + assert_eq!(storage.len, expected.len); + } -#[test] -fn insert() { - // Setup storage area - let mut storage = Storage { - inner: vec![ - Row::new(Column(1), &'4'), - Row::new(Column(1), &'5'), - Row::new(Column(1), &'0'), - Row::new(Column(1), &'1'), - Row::new(Column(1), &'2'), - Row::new(Column(1), &'3'), - ], - zero: 2, - visible_lines: Line(0), - len: 6, - }; - - // Initialize additional lines - storage.insert(2, Row::new(Column(1), &'-'), 100); - - // Make sure the lines are present and at the right location - let shrinking_expected = Storage { - inner: vec![ - Row::new(Column(1), &'4'), - Row::new(Column(1), &'5'), - Row::new(Column(1), &'0'), - Row::new(Column(1), &'1'), - Row::new(Column(1), &'-'), - Row::new(Column(1), &'2'), - Row::new(Column(1), &'3'), - ], - zero: 2, - visible_lines: Line(0), - len: 7, - }; - assert_eq!(storage.inner, shrinking_expected.inner); - assert_eq!(storage.zero, shrinking_expected.zero); - assert_eq!(storage.len, shrinking_expected.len); -} + /// Truncate buffer only at the beginning + /// + /// Before: + /// 0: 1 + /// 1: 2 <- Hidden + /// 2: 0 <- Zero + /// After: + /// 0: 1 + /// 0: 0 <- Zero + #[test] + fn truncate_invisible_lines_beginning() { + // Setup storage area + let mut storage = Storage { + inner: vec![ + Row::new(Column(1), &'1'), + Row::new(Column(1), &'2'), + Row::new(Column(1), &'0'), + ], + zero: 2, + visible_lines: Line(1), + len: 2, + }; + + // Truncate buffer + storage.truncate(); + + // Make sure the result is correct + let expected = Storage { + inner: vec![Row::new(Column(1), &'0'), Row::new(Column(1), &'1')], + zero: 0, + visible_lines: Line(1), + len: 2, + }; + assert_eq!(storage.visible_lines, expected.visible_lines); + assert_eq!(storage.inner, expected.inner); + assert_eq!(storage.zero, expected.zero); + assert_eq!(storage.len, expected.len); + } -#[test] -fn insert_truncate_max() { - // Setup storage area - let mut storage = Storage { - inner: vec![ - Row::new(Column(1), &'4'), - Row::new(Column(1), &'5'), - Row::new(Column(1), &'0'), - Row::new(Column(1), &'1'), - Row::new(Column(1), &'2'), - Row::new(Column(1), &'3'), - ], - zero: 2, - visible_lines: Line(0), - len: 6, - }; - - // Initialize additional lines - storage.insert(2, Row::new(Column(1), &'-'), 6); - - // Make sure the lines are present and at the right location - let shrinking_expected = Storage { - inner: vec![ - Row::new(Column(1), &'4'), - Row::new(Column(1), &'5'), - Row::new(Column(1), &'0'), - Row::new(Column(1), &'1'), - Row::new(Column(1), &'-'), - Row::new(Column(1), &'2'), - Row::new(Column(1), &'3'), - ], - zero: 2, - visible_lines: Line(0), - len: 6, - }; - assert_eq!(storage.inner, shrinking_expected.inner); - assert_eq!(storage.zero, shrinking_expected.zero); - assert_eq!(storage.len, shrinking_expected.len); -} + /// First shrink the buffer and then grow it again + /// + /// Before: + /// 0: 4 + /// 1: 5 + /// 2: 0 <- Zero + /// 3: 1 + /// 4: 2 + /// 5: 3 + /// After Shrinking: + /// 0: 4 <- Hidden + /// 1: 5 <- Hidden + /// 2: 0 <- Zero + /// 3: 1 + /// 4: 2 + /// 5: 3 <- Hidden + /// After Growing: + /// 0: 4 + /// 1: 5 + /// 2: - + /// 3: 0 <- Zero + /// 4: 1 + /// 5: 2 + /// 6: 3 + #[test] + fn shrink_then_grow() { + // Setup storage area + let mut storage = Storage { + inner: vec![ + Row::new(Column(1), &'4'), + Row::new(Column(1), &'5'), + Row::new(Column(1), &'0'), + Row::new(Column(1), &'1'), + Row::new(Column(1), &'2'), + Row::new(Column(1), &'3'), + ], + zero: 2, + visible_lines: Line(0), + len: 6, + }; + + // Shrink buffer + storage.shrink_lines(3); + + // Make sure the result after shrinking is correct + let shrinking_expected = Storage { + inner: vec![ + Row::new(Column(1), &'4'), + Row::new(Column(1), &'5'), + Row::new(Column(1), &'0'), + Row::new(Column(1), &'1'), + Row::new(Column(1), &'2'), + Row::new(Column(1), &'3'), + ], + zero: 2, + visible_lines: Line(0), + len: 3, + }; + assert_eq!(storage.inner, shrinking_expected.inner); + assert_eq!(storage.zero, shrinking_expected.zero); + assert_eq!(storage.len, shrinking_expected.len); + + // Grow buffer + storage.grow_lines(4, Row::new(Column(1), &'-')); + + // Make sure the result after shrinking is correct + let growing_expected = Storage { + inner: vec![ + Row::new(Column(1), &'4'), + Row::new(Column(1), &'5'), + Row::new(Column(1), &'-'), + Row::new(Column(1), &'0'), + Row::new(Column(1), &'1'), + Row::new(Column(1), &'2'), + Row::new(Column(1), &'3'), + ], + zero: 3, + visible_lines: Line(0), + len: 7, + }; + assert_eq!(storage.inner, growing_expected.inner); + assert_eq!(storage.zero, growing_expected.zero); + assert_eq!(storage.len, growing_expected.len); + } -#[test] -fn insert_at_zero() { - // Setup storage area - let mut storage = Storage { - inner: vec![ - Row::new(Column(1), &'4'), - Row::new(Column(1), &'5'), - Row::new(Column(1), &'0'), - Row::new(Column(1), &'1'), - Row::new(Column(1), &'2'), - Row::new(Column(1), &'3'), - ], - zero: 2, - visible_lines: Line(0), - len: 6, - }; - - // Initialize additional lines - storage.insert(0, Row::new(Column(1), &'-'), 6); - - // Make sure the lines are present and at the right location - let shrinking_expected = Storage { - inner: vec![ - Row::new(Column(1), &'4'), - Row::new(Column(1), &'5'), - Row::new(Column(1), &'-'), - Row::new(Column(1), &'0'), - Row::new(Column(1), &'1'), - Row::new(Column(1), &'2'), - Row::new(Column(1), &'3'), - ], - zero: 2, - visible_lines: Line(0), - len: 6, - }; - assert_eq!(storage.inner, shrinking_expected.inner); - assert_eq!(storage.zero, shrinking_expected.zero); - assert_eq!(storage.len, shrinking_expected.len); + #[test] + fn initialize() { + // Setup storage area + let mut storage = Storage { + inner: vec![ + Row::new(Column(1), &'4'), + Row::new(Column(1), &'5'), + Row::new(Column(1), &'0'), + Row::new(Column(1), &'1'), + Row::new(Column(1), &'2'), + Row::new(Column(1), &'3'), + ], + zero: 2, + visible_lines: Line(0), + len: 6, + }; + + // Initialize additional lines + storage.initialize(3, Row::new(Column(1), &'-')); + + // Make sure the lines are present and at the right location + let shrinking_expected = Storage { + inner: vec![ + Row::new(Column(1), &'4'), + Row::new(Column(1), &'5'), + Row::new(Column(1), &'-'), + Row::new(Column(1), &'-'), + Row::new(Column(1), &'-'), + Row::new(Column(1), &'0'), + Row::new(Column(1), &'1'), + Row::new(Column(1), &'2'), + Row::new(Column(1), &'3'), + ], + zero: 5, + visible_lines: Line(0), + len: 9, + }; + assert_eq!(storage.inner, shrinking_expected.inner); + assert_eq!(storage.zero, shrinking_expected.zero); + assert_eq!(storage.len, shrinking_expected.len); + } } diff --git a/alacritty_terminal/src/grid/tests.rs b/alacritty_terminal/src/grid/tests.rs index 2c17c9b2..ce094b96 100644 --- a/alacritty_terminal/src/grid/tests.rs +++ b/alacritty_terminal/src/grid/tests.rs @@ -140,7 +140,7 @@ fn shrink_reflow() { grid[Line(0)][Column(3)] = cell('4'); grid[Line(0)][Column(4)] = cell('5'); - grid.resize(Line(1), Column(2), &mut Point::new(Line(0), Column(0)), &Cell::default()); + grid.resize(true, Line(1), Column(2), &mut Point::new(Line(0), Column(0)), &Cell::default()); assert_eq!(grid.len(), 3); @@ -166,8 +166,8 @@ fn shrink_reflow_twice() { grid[Line(0)][Column(3)] = cell('4'); grid[Line(0)][Column(4)] = cell('5'); - grid.resize(Line(1), Column(4), &mut Point::new(Line(0), Column(0)), &Cell::default()); - grid.resize(Line(1), Column(2), &mut Point::new(Line(0), Column(0)), &Cell::default()); + grid.resize(true, Line(1), Column(4), &mut Point::new(Line(0), Column(0)), &Cell::default()); + grid.resize(true, Line(1), Column(2), &mut Point::new(Line(0), Column(0)), &Cell::default()); assert_eq!(grid.len(), 3); @@ -193,7 +193,7 @@ fn shrink_reflow_empty_cell_inside_line() { grid[Line(0)][Column(3)] = cell('4'); grid[Line(0)][Column(4)] = Cell::default(); - grid.resize(Line(1), Column(2), &mut Point::new(Line(0), Column(0)), &Cell::default()); + grid.resize(true, Line(1), Column(2), &mut Point::new(Line(0), Column(0)), &Cell::default()); assert_eq!(grid.len(), 2); @@ -205,7 +205,7 @@ fn shrink_reflow_empty_cell_inside_line() { assert_eq!(grid[0][Column(0)], cell('3')); assert_eq!(grid[0][Column(1)], cell('4')); - grid.resize(Line(1), Column(1), &mut Point::new(Line(0), Column(0)), &Cell::default()); + grid.resize(true, Line(1), Column(1), &mut Point::new(Line(0), Column(0)), &Cell::default()); assert_eq!(grid.len(), 4); @@ -230,7 +230,7 @@ fn grow_reflow() { grid[Line(1)][Column(0)] = cell('3'); grid[Line(1)][Column(1)] = Cell::default(); - grid.resize(Line(2), Column(3), &mut Point::new(Line(0), Column(0)), &Cell::default()); + grid.resize(true, Line(2), Column(3), &mut Point::new(Line(0), Column(0)), &Cell::default()); assert_eq!(grid.len(), 2); @@ -256,7 +256,7 @@ fn grow_reflow_multiline() { grid[Line(2)][Column(0)] = cell('5'); grid[Line(2)][Column(1)] = cell('6'); - grid.resize(Line(3), Column(6), &mut Point::new(Line(0), Column(0)), &Cell::default()); + grid.resize(true, Line(3), Column(6), &mut Point::new(Line(0), Column(0)), &Cell::default()); assert_eq!(grid.len(), 3); @@ -279,6 +279,47 @@ fn grow_reflow_multiline() { } } +#[test] +fn grow_reflow_disabled() { + let mut grid = Grid::new(Line(2), Column(2), 0, cell('x')); + grid[Line(0)][Column(0)] = cell('1'); + grid[Line(0)][Column(1)] = wrap_cell('2'); + grid[Line(1)][Column(0)] = cell('3'); + grid[Line(1)][Column(1)] = Cell::default(); + + grid.resize(false, Line(2), Column(3), &mut Point::new(Line(0), Column(0)), &Cell::default()); + + assert_eq!(grid.len(), 2); + + assert_eq!(grid[1].len(), 3); + assert_eq!(grid[1][Column(0)], cell('1')); + assert_eq!(grid[1][Column(1)], wrap_cell('2')); + assert_eq!(grid[1][Column(2)], Cell::default()); + + assert_eq!(grid[0].len(), 3); + assert_eq!(grid[0][Column(0)], cell('3')); + assert_eq!(grid[0][Column(1)], Cell::default()); + assert_eq!(grid[0][Column(2)], Cell::default()); +} + +#[test] +fn shrink_reflow_disabled() { + let mut grid = Grid::new(Line(1), Column(5), 2, cell('x')); + grid[Line(0)][Column(0)] = cell('1'); + grid[Line(0)][Column(1)] = cell('2'); + grid[Line(0)][Column(2)] = cell('3'); + grid[Line(0)][Column(3)] = cell('4'); + grid[Line(0)][Column(4)] = cell('5'); + + grid.resize(false, Line(1), Column(2), &mut Point::new(Line(0), Column(0)), &Cell::default()); + + assert_eq!(grid.len(), 1); + + assert_eq!(grid[0].len(), 2); + assert_eq!(grid[0][Column(0)], cell('1')); + assert_eq!(grid[0][Column(1)], cell('2')); +} + fn cell(c: char) -> Cell { let mut cell = Cell::default(); cell.c = c; diff --git a/alacritty_terminal/src/term/mod.rs b/alacritty_terminal/src/term/mod.rs index ee257272..c167875b 100644 --- a/alacritty_terminal/src/term/mod.rs +++ b/alacritty_terminal/src/term/mod.rs @@ -1228,13 +1228,11 @@ impl Term { debug!("New num_cols is {} and num_lines is {}", num_cols, num_lines); // Resize grids to new size - let alt_cursor_point = if self.mode.contains(TermMode::ALT_SCREEN) { - &mut self.cursor_save.point - } else { - &mut self.cursor_save_alt.point - }; - self.grid.resize(num_lines, num_cols, &mut self.cursor.point, &Cell::default()); - self.alt_grid.resize(num_lines, num_cols, alt_cursor_point, &Cell::default()); + let is_alt = self.mode.contains(TermMode::ALT_SCREEN); + let alt_cursor_point = + if is_alt { &mut self.cursor_save.point } else { &mut self.cursor_save_alt.point }; + self.grid.resize(!is_alt, num_lines, num_cols, &mut self.cursor.point, &Cell::default()); + self.alt_grid.resize(is_alt, num_lines, num_cols, alt_cursor_point, &Cell::default()); // Reset scrolling region to new size self.scroll_region = Line(0)..self.grid.num_lines(); |