From f002171c84a2b31f156c0401b6b2423e4e77f831 Mon Sep 17 00:00:00 2001 From: Christian Duerr Date: Sun, 23 Jun 2019 23:29:01 +0000 Subject: Fix performance issues with text reflow Fixes #2567. Fixes #2414. --- alacritty_terminal/src/grid/storage.rs | 1062 ++++++++++++++------------------ 1 file changed, 448 insertions(+), 614 deletions(-) (limited to 'alacritty_terminal/src/grid/storage.rs') 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 Storage { self.zero = (self.zero + count) % self.inner.len(); } - #[inline] - pub fn insert(&mut self, index: usize, row: Row, 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> { + self.truncate(); + self.inner.drain(..) } - #[inline] - pub fn remove(&mut self, index: usize) -> Row { - 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>) { + self.len = vec.len(); + self.inner = vec; + self.zero = 0; } } @@ -359,564 +306,451 @@ impl IndexMut for Storage { } } -/// 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); + } } -- cgit v1.2.3-54-g00ecf