aboutsummaryrefslogtreecommitdiff
path: root/alacritty_terminal/src/grid/storage.rs
diff options
context:
space:
mode:
authorNathan Lilienthal <nathan@nixpulvis.com>2019-11-18 16:15:25 -0500
committerChristian Duerr <contact@christianduerr.com>2019-11-18 22:15:25 +0100
commit182a9d5c2e01ec9b155fc7edf547e8e6de2f2bd5 (patch)
tree56889a5b18e40c7f4b30ea53b8eb152fbeb82a2d /alacritty_terminal/src/grid/storage.rs
parentbcdc605436ebe137173c531844a739eda6ee41ae (diff)
downloadalacritty-182a9d5c2e01ec9b155fc7edf547e8e6de2f2bd5.tar.gz
alacritty-182a9d5c2e01ec9b155fc7edf547e8e6de2f2bd5.zip
Fix deletion of lines when clearing the screen
Previously Alacritty would delete lines when clearing the screen, leading to a loss of data in the scrollback buffer. Instead of deleting these lines, they are now rotated outside of the visible region. This also fixes some issues with Alacritty only resetting lines partially when the background color of the template cell changed. Fixes #2199.
Diffstat (limited to 'alacritty_terminal/src/grid/storage.rs')
-rw-r--r--alacritty_terminal/src/grid/storage.rs99
1 files changed, 86 insertions, 13 deletions
diff --git a/alacritty_terminal/src/grid/storage.rs b/alacritty_terminal/src/grid/storage.rs
index 10091f2a..1a6d9913 100644
--- a/alacritty_terminal/src/grid/storage.rs
+++ b/alacritty_terminal/src/grid/storage.rs
@@ -1,17 +1,4 @@
use std::cmp::Ordering;
-/// Wrapper around Vec which supports fast indexing and rotation
-///
-/// The rotation implemented by grid::Storage is a simple integer addition.
-/// Compare with standard library rotation which requires rearranging items in
-/// memory.
-///
-/// As a consequence, the indexing operators need to be reimplemented for this
-/// type to account for the 0th element not always being at the start of the
-/// allocation.
-///
-/// Because certain Vec operations are no longer valid on this type, no Deref
-/// implementation is provided. Anything from Vec that should be exposed must be
-/// done so manually.
use std::ops::{Index, IndexMut};
use std::vec::Drain;
@@ -23,10 +10,34 @@ use crate::index::Line;
/// Maximum number of invisible lines before buffer is resized
const TRUNCATE_STEP: usize = 100;
+/// A ring buffer for optimizing indexing and rotation.
+///
+/// The [`Storage::rotate`] and [`Storage::rotate_up`] functions are fast modular additions on the
+/// internal [`zero`] field. As compared with [`slice::rotate_left`] which must rearrange items in
+/// memory.
+///
+/// As a consequence, both [`Index`] and [`IndexMut`] are reimplemented for this type to account
+/// for the zeroth element not always being at the start of the allocation.
+///
+/// Because certain [`Vec`] operations are no longer valid on this type, no [`Deref`]
+/// implementation is provided. Anything from [`Vec`] that should be exposed must be done so
+/// manually.
+///
+/// [`slice::rotate_left`]: https://doc.rust-lang.org/std/primitive.slice.html#method.rotate_left
+/// [`Deref`]: std::ops::Deref
+/// [`zero`]: #structfield.zero
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct Storage<T> {
inner: Vec<Row<T>>,
+
+ /// Starting point for the storage of rows.
+ ///
+ /// This value represents the starting line offset within the ring buffer. The value of this
+ /// offset may be larger than the `len` itself, and will wrap around to the start to form the
+ /// ring buffer. It represents the bottommost line of the terminal.
zero: usize,
+
+ /// An index separating the visible and scrollback regions.
visible_lines: Line,
/// Total number of lines currently active in the terminal (scrollback + visible)
@@ -326,6 +337,68 @@ mod test {
fn set_wrap(&mut self, _wrap: bool) {}
}
+ #[test]
+ fn with_capacity() {
+ let storage = Storage::with_capacity(Line(3), Row::new(Column(0), &' '));
+
+ assert_eq!(storage.inner.len(), 3);
+ assert_eq!(storage.len, 3);
+ assert_eq!(storage.zero, 0);
+ assert_eq!(storage.visible_lines, Line(2));
+ }
+
+ #[test]
+ fn indexing() {
+ let mut storage = Storage::with_capacity(Line(3), Row::new(Column(0), &' '));
+
+ storage[0] = Row::new(Column(1), &'0');
+ storage[1] = Row::new(Column(1), &'1');
+ storage[2] = Row::new(Column(1), &'2');
+
+ assert_eq!(storage[0], Row::new(Column(1), &'0'));
+ assert_eq!(storage[1], Row::new(Column(1), &'1'));
+ assert_eq!(storage[2], Row::new(Column(1), &'2'));
+
+ storage.zero += 1;
+
+ assert_eq!(storage[0], Row::new(Column(1), &'1'));
+ assert_eq!(storage[1], Row::new(Column(1), &'2'));
+ assert_eq!(storage[2], Row::new(Column(1), &'0'));
+ }
+
+ #[test]
+ #[should_panic]
+ fn indexing_above_len() {
+ let mut storage = Storage::with_capacity(Line(3), Row::new(Column(0), &' '));
+ storage.shrink_lines(2);
+ let _ = &storage[1];
+ }
+
+ #[test]
+ #[should_panic]
+ fn indexing_above_inner_len() {
+ let storage = Storage::with_capacity(Line(1), Row::new(Column(0), &' '));
+ let _ = &storage[2];
+ }
+
+ #[test]
+ fn rotate() {
+ let mut storage = Storage::with_capacity(Line(3), Row::new(Column(0), &' '));
+ storage.rotate(2);
+ assert_eq!(storage.zero, 2);
+ storage.shrink_lines(2);
+ assert_eq!(storage.len, 1);
+ assert_eq!(storage.inner.len(), 3);
+ assert_eq!(storage.zero, 2);
+ }
+
+ #[test]
+ #[should_panic]
+ fn rotate_overflow() {
+ let mut storage = Storage::with_capacity(Line(3), Row::new(Column(0), &' '));
+ storage.rotate(4);
+ }
+
/// Grow the buffer one line at the end of the buffer
///
/// Before: