summaryrefslogtreecommitdiffstats
path: root/alacritty_terminal
diff options
context:
space:
mode:
authorChristian Duerr <chrisduerr@users.noreply.github.com>2019-06-23 23:29:01 +0000
committerGitHub <noreply@github.com>2019-06-23 23:29:01 +0000
commitf002171c84a2b31f156c0401b6b2423e4e77f831 (patch)
tree8a42e1d7b0192f39cfc3d4fb3d6f35d9361f5a36 /alacritty_terminal
parent743d5d9c6614a807ab398473e62fad280845519e (diff)
Fix performance issues with text reflow
Fixes #2567. Fixes #2414.
Diffstat (limited to 'alacritty_terminal')
-rw-r--r--alacritty_terminal/src/grid/mod.rs160
-rw-r--r--alacritty_terminal/src/grid/storage.rs1062
-rw-r--r--alacritty_terminal/src/grid/tests.rs55
-rw-r--r--alacritty_terminal/src/term/mod.rs12
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
+ ///
+ /// Befo