Fix incorrect grid.len() and grid.history_size()

This commit is contained in:
Kirill Chibisov 2020-01-26 16:49:58 +03:00 committed by Christian Duerr
parent f48204eee2
commit 4cc6421daa
37 changed files with 163 additions and 218 deletions

View File

@ -32,8 +32,6 @@ mod tests;
mod storage; mod storage;
use self::storage::Storage; use self::storage::Storage;
const MIN_INIT_SIZE: usize = 1_000;
/// Bidirection iterator /// Bidirection iterator
pub trait BidirectionalIterator: Iterator { pub trait BidirectionalIterator: Iterator {
fn prev(&mut self) -> Option<Self::Item>; fn prev(&mut self) -> Option<Self::Item>;
@ -62,7 +60,6 @@ impl<T: PartialEq> ::std::cmp::PartialEq for Grid<T> {
&& self.cols.eq(&other.cols) && self.cols.eq(&other.cols)
&& self.lines.eq(&other.lines) && self.lines.eq(&other.lines)
&& self.display_offset.eq(&other.display_offset) && self.display_offset.eq(&other.display_offset)
&& self.scroll_limit.eq(&other.scroll_limit)
&& self.selection.eq(&other.selection) && self.selection.eq(&other.selection)
} }
} }
@ -86,11 +83,11 @@ pub trait GridCell {
/// │ │ /// │ │
/// │ UNINITIALIZED │ /// │ UNINITIALIZED │
/// │ │ /// │ │
/// ├─────────────────────────┤ <-- raw.len() /// ├─────────────────────────┤ <-- self.raw.inner.len()
/// │ │ /// │ │
/// │ RESIZE BUFFER │ /// │ RESIZE BUFFER │
/// │ │ /// │ │
/// ├─────────────────────────┤ <-- scroll_limit + lines /// ├─────────────────────────┤ <-- self.history_size() + lines
/// │ │ /// │ │
/// │ SCROLLUP REGION │ /// │ SCROLLUP REGION │
/// │ │ /// │ │
@ -112,26 +109,24 @@ pub struct Grid<T> {
/// columns in that row. /// columns in that row.
raw: Storage<T>, raw: Storage<T>,
/// Number of columns /// Number of columns.
cols: Column, cols: Column,
/// Number of visible lines. /// Number of visible lines.
lines: Line, lines: Line,
/// Offset of displayed area /// Offset of displayed area.
/// ///
/// If the displayed region isn't at the bottom of the screen, it stays /// If the displayed region isn't at the bottom of the screen, it stays
/// stationary while more text is emitted. The scrolling implementation /// stationary while more text is emitted. The scrolling implementation
/// updates this offset accordingly. /// updates this offset accordingly.
display_offset: usize, display_offset: usize,
/// An limit on how far back it's possible to scroll /// Selected region.
scroll_limit: usize,
/// Selected region
#[serde(skip)] #[serde(skip)]
pub selection: Option<Selection>, pub selection: Option<Selection>,
/// Maximum number of lines in history.
max_scroll_limit: usize, max_scroll_limit: usize,
} }
@ -147,15 +142,7 @@ pub enum Scroll {
impl<T: GridCell + PartialEq + Copy> Grid<T> { impl<T: GridCell + PartialEq + Copy> Grid<T> {
pub fn new(lines: Line, cols: Column, scrollback: usize, template: T) -> Grid<T> { pub fn new(lines: Line, cols: Column, scrollback: usize, template: T) -> Grid<T> {
let raw = Storage::with_capacity(lines, Row::new(cols, &template)); let raw = Storage::with_capacity(lines, Row::new(cols, &template));
Grid { Grid { raw, cols, lines, display_offset: 0, selection: None, max_scroll_limit: scrollback }
raw,
cols,
lines,
display_offset: 0,
scroll_limit: 0,
selection: None,
max_scroll_limit: scrollback,
}
} }
pub fn buffer_to_visible(&self, point: impl Into<Point<usize>>) -> Option<Point<usize>> { pub fn buffer_to_visible(&self, point: impl Into<Point<usize>>) -> Option<Point<usize>> {
@ -179,11 +166,13 @@ impl<T: GridCell + PartialEq + Copy> Grid<T> {
} }
/// Update the size of the scrollback history /// Update the size of the scrollback history
pub fn update_history(&mut self, history_size: usize, template: &T) { pub fn update_history(&mut self, history_size: usize) {
self.raw.update_history(history_size, Row::new(self.cols, &template)); let current_history_size = self.history_size();
if current_history_size > history_size {
self.raw.shrink_lines(current_history_size - history_size);
}
self.display_offset = min(self.display_offset, history_size);
self.max_scroll_limit = history_size; self.max_scroll_limit = history_size;
self.scroll_limit = min(self.scroll_limit, history_size);
self.display_offset = min(self.display_offset, self.scroll_limit);
} }
pub fn scroll_display(&mut self, scroll: Scroll) { pub fn scroll_display(&mut self, scroll: Scroll) {
@ -191,16 +180,16 @@ impl<T: GridCell + PartialEq + Copy> Grid<T> {
Scroll::Lines(count) => { Scroll::Lines(count) => {
self.display_offset = min( self.display_offset = min(
max((self.display_offset as isize) + count, 0isize) as usize, max((self.display_offset as isize) + count, 0isize) as usize,
self.scroll_limit, self.history_size(),
); );
}, },
Scroll::PageUp => { Scroll::PageUp => {
self.display_offset = min(self.display_offset + self.lines.0, self.scroll_limit); self.display_offset = min(self.display_offset + self.lines.0, self.history_size());
}, },
Scroll::PageDown => { Scroll::PageDown => {
self.display_offset -= min(self.display_offset, self.lines.0); self.display_offset -= min(self.display_offset, self.lines.0);
}, },
Scroll::Top => self.display_offset = self.scroll_limit, Scroll::Top => self.display_offset = self.history_size(),
Scroll::Bottom => self.display_offset = 0, Scroll::Bottom => self.display_offset = 0,
} }
} }
@ -232,21 +221,17 @@ impl<T: GridCell + PartialEq + Copy> Grid<T> {
} }
fn increase_scroll_limit(&mut self, count: usize, template: &T) { fn increase_scroll_limit(&mut self, count: usize, template: &T) {
self.scroll_limit = min(self.scroll_limit + count, self.max_scroll_limit); let count = min(count, self.max_scroll_limit - self.history_size());
if count != 0 {
// Initialize new lines when the history buffer is smaller than the scroll limit self.raw.initialize(count, template, self.cols);
let history_size = self.raw.len().saturating_sub(*self.lines);
if history_size < self.scroll_limit {
let new = min(
max(self.scroll_limit - history_size, MIN_INIT_SIZE),
self.max_scroll_limit - history_size,
);
self.raw.initialize(new, Row::new(self.cols, template));
} }
} }
fn decrease_scroll_limit(&mut self, count: usize) { fn decrease_scroll_limit(&mut self, count: usize) {
self.scroll_limit = self.scroll_limit.saturating_sub(count); let count = min(count, self.history_size());
if count != 0 {
self.raw.shrink_lines(min(count, self.history_size()));
}
} }
/// Add lines to the visible area /// Add lines to the visible area
@ -262,12 +247,12 @@ impl<T: GridCell + PartialEq + Copy> Grid<T> {
self.lines = new_line_count; self.lines = new_line_count;
// Move existing lines up if there is no scrollback to fill new lines // Move existing lines up if there is no scrollback to fill new lines
if lines_added.0 > self.scroll_limit { let history_size = self.history_size();
let scroll_lines = lines_added - self.scroll_limit; if lines_added.0 > history_size {
self.scroll_up(&(Line(0)..new_line_count), scroll_lines, template); self.scroll_up(&(Line(0)..new_line_count), lines_added - history_size, template);
} }
self.scroll_limit = self.scroll_limit.saturating_sub(*lines_added); self.decrease_scroll_limit(*lines_added);
self.display_offset = self.display_offset.saturating_sub(*lines_added); self.display_offset = self.display_offset.saturating_sub(*lines_added);
} }
@ -326,22 +311,13 @@ impl<T: GridCell + PartialEq + Copy> Grid<T> {
last_row.append(&mut cells); last_row.append(&mut cells);
if row.is_empty() { if row.is_empty() {
let raw_len = i + 1 + reversed.len(); if i + reversed.len() < self.lines.0 {
if raw_len < self.lines.0 || self.scroll_limit == 0 {
// Add new line and move lines up if we can't pull from history // Add new line and move lines up if we can't pull from history
cursor_pos.line = Line(cursor_pos.line.saturating_sub(1)); cursor_pos.line = Line(cursor_pos.line.saturating_sub(1));
new_empty_lines += 1; new_empty_lines += 1;
} else { } else if i < self.display_offset {
// Make sure viewport doesn't move if line is outside of the visible // Keep viewport in place if line is outside of the visible area
// area self.display_offset = self.display_offset.saturating_sub(1);
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);
} }
// Don't push line into the new buffer // Don't push line into the new buffer
@ -368,6 +344,7 @@ impl<T: GridCell + PartialEq + Copy> Grid<T> {
self.raw.replace_inner(new_raw); self.raw.replace_inner(new_raw);
self.display_offset = min(self.display_offset, self.history_size());
self.cols = cols; self.cols = cols;
} }
@ -450,9 +427,6 @@ impl<T: GridCell + PartialEq + Copy> Grid<T> {
wrapped.append(&mut vec![*template; cols.0 - occ]); wrapped.append(&mut vec![*template; cols.0 - occ]);
} }
row = Row::from_vec(wrapped, occ); row = Row::from_vec(wrapped, occ);
// Increase scrollback history
self.scroll_limit = min(self.scroll_limit + 1, self.max_scroll_limit);
} }
} }
} }
@ -643,6 +617,7 @@ impl<T> Grid<T> {
self.lines self.lines
} }
#[inline]
pub fn display_iter(&self) -> DisplayIter<'_, T> { pub fn display_iter(&self) -> DisplayIter<'_, T> {
DisplayIter::new(self) DisplayIter::new(self)
} }
@ -652,16 +627,10 @@ impl<T> Grid<T> {
self.cols self.cols
} }
#[inline]
pub fn clear_history(&mut self) { pub fn clear_history(&mut self) {
// Explicitly purge all lines from history // Explicitly purge all lines from history
let shrinkage = self.raw.len() - self.lines.0; self.raw.shrink_lines(self.history_size());
self.raw.shrink_lines(shrinkage);
self.scroll_limit = 0;
}
#[inline]
pub fn scroll_limit(&self) -> usize {
self.scroll_limit
} }
/// Total number of lines in the buffer, this includes scrollback + visible lines /// Total number of lines in the buffer, this includes scrollback + visible lines
@ -672,23 +641,29 @@ impl<T> Grid<T> {
#[inline] #[inline]
pub fn history_size(&self) -> usize { pub fn history_size(&self) -> usize {
self.raw.len().saturating_sub(*self.lines) self.raw.len() - *self.lines
} }
/// This is used only for initializing after loading ref-tests /// This is used only for initializing after loading ref-tests
#[inline]
pub fn initialize_all(&mut self, template: &T) pub fn initialize_all(&mut self, template: &T)
where where
T: Copy + GridCell, T: Copy + GridCell,
{ {
let history_size = self.raw.len().saturating_sub(*self.lines); // Remove all cached lines to clear them of any content
self.raw.initialize(self.max_scroll_limit - history_size, Row::new(self.cols, template)); self.truncate();
// Initialize everything with empty new lines
self.raw.initialize(self.max_scroll_limit - self.history_size(), template, self.cols);
} }
/// This is used only for truncating before saving ref-tests /// This is used only for truncating before saving ref-tests
#[inline]
pub fn truncate(&mut self) { pub fn truncate(&mut self) {
self.raw.truncate(); self.raw.truncate();
} }
#[inline]
pub fn iter_from(&self, point: Point<usize>) -> GridIterator<'_, T> { pub fn iter_from(&self, point: Point<usize>) -> GridIterator<'_, T> {
GridIterator { grid: self, cur: point } GridIterator { grid: self, cur: point }
} }

View File

@ -1,14 +1,15 @@
use std::cmp::{Ordering, PartialEq}; use std::cmp::{max, PartialEq};
use std::ops::{Index, IndexMut}; use std::ops::{Index, IndexMut};
use std::vec::Drain; use std::vec::Drain;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use super::Row; use super::Row;
use crate::index::Line; use crate::grid::GridCell;
use crate::index::{Column, Line};
/// Maximum number of invisible lines before buffer is resized /// Maximum number of buffered lines outside of the grid for performance optimization.
const TRUNCATE_STEP: usize = 100; const MAX_CACHE_SIZE: usize = 1_000;
/// A ring buffer for optimizing indexing and rotation. /// A ring buffer for optimizing indexing and rotation.
/// ///
@ -37,7 +38,7 @@ pub struct Storage<T> {
/// ring buffer. It represents the bottommost line of the terminal. /// ring buffer. It represents the bottommost line of the terminal.
zero: usize, zero: usize,
/// An index separating the visible and scrollback regions. /// Number of visible lines.
visible_lines: Line, visible_lines: Line,
/// Total number of lines currently active in the terminal (scrollback + visible) /// Total number of lines currently active in the terminal (scrollback + visible)
@ -51,81 +52,40 @@ pub struct Storage<T> {
impl<T: PartialEq> PartialEq for Storage<T> { impl<T: PartialEq> PartialEq for Storage<T> {
fn eq(&self, other: &Self) -> bool { fn eq(&self, other: &Self) -> bool {
// Make sure length is equal // Both storage buffers need to be truncated and zeroed
if self.inner.len() != other.inner.len() { assert_eq!(self.zero, 0);
return false; assert_eq!(other.zero, 0);
}
// Check which vec has the bigger zero self.inner == other.inner && self.len == other.len
let (ref bigger, ref smaller) =
if self.zero >= other.zero { (self, other) } else { (other, self) };
// Calculate the actual zero offset
let bigger_zero = bigger.zero;
let smaller_zero = smaller.zero;
// Compare the slices in chunks
// Chunks:
// - Bigger zero to the end
// - Remaining lines in smaller zero vec
// - Beginning of smaller zero vec
//
// Example:
// Bigger Zero (6):
// 4 5 6 | 7 8 9 | 0 1 2 3
// C2 C2 C2 | C3 C3 C3 | C1 C1 C1 C1
// Smaller Zero (3):
// 7 8 9 | 0 1 2 3 | 4 5 6
// C3 C3 C3 | C1 C1 C1 C1 | C2 C2 C2
let len = self.inner.len();
bigger.inner[bigger_zero..]
== smaller.inner[smaller_zero..smaller_zero + (len - bigger_zero)]
&& bigger.inner[..bigger_zero - smaller_zero]
== smaller.inner[smaller_zero + (len - bigger_zero)..]
&& bigger.inner[bigger_zero - smaller_zero..bigger_zero]
== smaller.inner[..smaller_zero]
} }
} }
impl<T> Storage<T> { impl<T> Storage<T> {
#[inline] #[inline]
pub fn with_capacity(lines: Line, template: Row<T>) -> Storage<T> pub fn with_capacity(visible_lines: Line, template: Row<T>) -> Storage<T>
where where
T: Clone, T: Clone,
{ {
// Initialize visible lines, the scrollback buffer is initialized dynamically // Initialize visible lines, the scrollback buffer is initialized dynamically
let inner = vec![template; lines.0]; let inner = vec![template; visible_lines.0];
Storage { inner, zero: 0, visible_lines: lines - 1, len: lines.0 } Storage { inner, zero: 0, visible_lines, len: visible_lines.0 }
} }
/// Update the size of the scrollback history /// Increase the number of lines in the buffer.
pub fn update_history(&mut self, history_size: usize, template_row: Row<T>)
where
T: Clone,
{
let current_history = self.len - (self.visible_lines.0 + 1);
match history_size.cmp(&current_history) {
Ordering::Greater => self.grow_lines(history_size - current_history, template_row),
Ordering::Less => self.shrink_lines(current_history - history_size),
_ => (),
}
}
/// Increase the number of lines in the buffer
pub fn grow_visible_lines(&mut self, next: Line, template_row: Row<T>) pub fn grow_visible_lines(&mut self, next: Line, template_row: Row<T>)
where where
T: Clone, T: Clone,
{ {
// Number of lines the buffer needs to grow // Number of lines the buffer needs to grow
let growage = (next - (self.visible_lines + 1)).0; let growage = next - self.visible_lines;
self.grow_lines(growage, template_row); self.grow_lines(growage.0, template_row);
// Update visible lines // Update visible lines
self.visible_lines = next - 1; self.visible_lines = next;
} }
/// Grow the number of lines in the buffer, filling new lines with the template /// Grow the number of lines in the buffer, filling new lines with the template.
fn grow_lines(&mut self, growage: usize, template_row: Row<T>) fn grow_lines(&mut self, growage: usize, template_row: Row<T>)
where where
T: Clone, T: Clone,
@ -152,14 +112,14 @@ impl<T> Storage<T> {
self.len += growage; self.len += growage;
} }
/// Decrease the number of lines in the buffer /// Decrease the number of lines in the buffer.
pub fn shrink_visible_lines(&mut self, next: Line) { pub fn shrink_visible_lines(&mut self, next: Line) {
// Shrink the size without removing any lines // Shrink the size without removing any lines
let shrinkage = (self.visible_lines - (next - 1)).0; let shrinkage = self.visible_lines - next;
self.shrink_lines(shrinkage); self.shrink_lines(shrinkage.0);
// Update visible lines // Update visible lines
self.visible_lines = next - 1; self.visible_lines = next;
} }
// Shrink the number of lines in the buffer // Shrink the number of lines in the buffer
@ -167,12 +127,12 @@ impl<T> Storage<T> {
self.len -= shrinkage; self.len -= shrinkage;
// Free memory // Free memory
if self.inner.len() > self.len() + TRUNCATE_STEP { if self.inner.len() > self.len + MAX_CACHE_SIZE {
self.truncate(); self.truncate();
} }
} }
/// Truncate the invisible elements from the raw buffer /// Truncate the invisible elements from the raw buffer.
pub fn truncate(&mut self) { pub fn truncate(&mut self) {
self.inner.rotate_left(self.zero); self.inner.rotate_left(self.zero);
self.inner.truncate(self.len); self.inner.truncate(self.len);
@ -180,19 +140,22 @@ impl<T> Storage<T> {
self.zero = 0; self.zero = 0;
} }
/// Dynamically grow the storage buffer at runtime /// Dynamically grow the storage buffer at runtime.
pub fn initialize(&mut self, num_rows: usize, template_row: Row<T>) #[inline]
pub fn initialize(&mut self, additional_rows: usize, template: &T, cols: Column)
where where
T: Clone, T: GridCell + Copy,
{ {
let mut new = vec![template_row; num_rows]; if self.len + additional_rows > self.inner.len() {
let realloc_size = max(additional_rows, MAX_CACHE_SIZE);
let mut new = vec![Row::new(cols, template); realloc_size];
let mut split = self.inner.split_off(self.zero);
self.inner.append(&mut new);
self.inner.append(&mut split);
self.zero += realloc_size;
}
let mut split = self.inner.split_off(self.zero); self.len += additional_rows;
self.inner.append(&mut new);
self.inner.append(&mut split);
self.zero += num_rows;
self.len += num_rows;
} }
#[inline] #[inline]
@ -219,7 +182,7 @@ impl<T> Storage<T> {
} }
pub fn swap_lines(&mut self, a: Line, b: Line) { pub fn swap_lines(&mut self, a: Line, b: Line) {
let offset = self.inner.len() + self.zero + *self.visible_lines; let offset = self.inner.len() + self.zero + *self.visible_lines - 1;
let a = (offset - *a) % self.inner.len(); let a = (offset - *a) % self.inner.len();
let b = (offset - *b) % self.inner.len(); let b = (offset - *b) % self.inner.len();
self.inner.swap(a, b); self.inner.swap(a, b);
@ -311,7 +274,7 @@ impl<T> Index<Line> for Storage<T> {
#[inline] #[inline]
fn index(&self, index: Line) -> &Self::Output { fn index(&self, index: Line) -> &Self::Output {
let index = self.visible_lines - index; let index = self.visible_lines - 1 - index;
&self[*index] &self[*index]
} }
} }
@ -319,7 +282,7 @@ impl<T> Index<Line> for Storage<T> {
impl<T> IndexMut<Line> for Storage<T> { impl<T> IndexMut<Line> for Storage<T> {
#[inline] #[inline]
fn index_mut(&mut self, index: Line) -> &mut Self::Output { fn index_mut(&mut self, index: Line) -> &mut Self::Output {
let index = self.visible_lines - index; let index = self.visible_lines - 1 - index;
&mut self[*index] &mut self[*index]
} }
} }
@ -327,7 +290,7 @@ impl<T> IndexMut<Line> for Storage<T> {
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use crate::grid::row::Row; use crate::grid::row::Row;
use crate::grid::storage::Storage; use crate::grid::storage::{Storage, MAX_CACHE_SIZE};
use crate::grid::GridCell; use crate::grid::GridCell;
use crate::index::{Column, Line}; use crate::index::{Column, Line};
use crate::term::cell::Flags; use crate::term::cell::Flags;
@ -357,7 +320,7 @@ mod test {
assert_eq!(storage.inner.len(), 3); assert_eq!(storage.inner.len(), 3);
assert_eq!(storage.len, 3); assert_eq!(storage.len, 3);
assert_eq!(storage.zero, 0); assert_eq!(storage.zero, 0);
assert_eq!(storage.visible_lines, Line(2)); assert_eq!(storage.visible_lines, Line(3));
} }
#[test] #[test]
@ -418,7 +381,7 @@ mod test {
Row::new(Column(1), &'-'), Row::new(Column(1), &'-'),
], ],
zero: 0, zero: 0,
visible_lines: Line(2), visible_lines: Line(3),
len: 3, len: 3,
}; };
@ -434,9 +397,10 @@ mod test {
Row::new(Column(1), &'-'), Row::new(Column(1), &'-'),
], ],
zero: 1, zero: 1,
visible_lines: Line(0), visible_lines: Line(4),
len: 4, len: 4,
}; };
assert_eq!(storage.visible_lines, expected.visible_lines);
assert_eq!(storage.inner, expected.inner); assert_eq!(storage.inner, expected.inner);
assert_eq!(storage.zero, expected.zero); assert_eq!(storage.zero, expected.zero);
assert_eq!(storage.len, expected.len); assert_eq!(storage.len, expected.len);
@ -463,7 +427,7 @@ mod test {
Row::new(Column(1), &'1'), Row::new(Column(1), &'1'),
], ],
zero: 1, zero: 1,
visible_lines: Line(2), visible_lines: Line(3),
len: 3, len: 3,
}; };
@ -479,9 +443,10 @@ mod test {
Row::new(Column(1), &'1'), Row::new(Column(1), &'1'),
], ],
zero: 2, zero: 2,
visible_lines: Line(0), visible_lines: Line(4),
len: 4, len: 4,
}; };
assert_eq!(storage.visible_lines, expected.visible_lines);
assert_eq!(storage.inner, expected.inner); assert_eq!(storage.inner, expected.inner);
assert_eq!(storage.zero, expected.zero); assert_eq!(storage.zero, expected.zero);
assert_eq!(storage.len, expected.len); assert_eq!(storage.len, expected.len);
@ -507,7 +472,7 @@ mod test {
Row::new(Column(1), &'1'), Row::new(Column(1), &'1'),
], ],
zero: 1, zero: 1,
visible_lines: Line(2), visible_lines: Line(3),
len: 3, len: 3,
}; };
@ -522,9 +487,10 @@ mod test {
Row::new(Column(1), &'1'), Row::new(Column(1), &'1'),
], ],
zero: 1, zero: 1,
visible_lines: Line(0), visible_lines: Line(2),
len: 2, len: 2,
}; };
assert_eq!(storage.visible_lines, expected.visible_lines);
assert_eq!(storage.inner, expected.inner); assert_eq!(storage.inner, expected.inner);
assert_eq!(storage.zero, expected.zero); assert_eq!(storage.zero, expected.zero);
assert_eq!(storage.len, expected.len); assert_eq!(storage.len, expected.len);
@ -550,7 +516,7 @@ mod test {
Row::new(Column(1), &'2'), Row::new(Column(1), &'2'),
], ],
zero: 0, zero: 0,
visible_lines: Line(2), visible_lines: Line(3),
len: 3, len: 3,
}; };
@ -565,9 +531,10 @@ mod test {
Row::new(Column(1), &'2'), Row::new(Column(1), &'2'),
], ],
zero: 0, zero: 0,
visible_lines: Line(0), visible_lines: Line(2),
len: 2, len: 2,
}; };
assert_eq!(storage.visible_lines, expected.visible_lines);
assert_eq!(storage.inner, expected.inner); assert_eq!(storage.inner, expected.inner);
assert_eq!(storage.zero, expected.zero); assert_eq!(storage.zero, expected.zero);
assert_eq!(storage.len, expected.len); assert_eq!(storage.len, expected.len);
@ -602,7 +569,7 @@ mod test {
Row::new(Column(1), &'3'), Row::new(Column(1), &'3'),
], ],
zero: 2, zero: 2,
visible_lines: Line(5), visible_lines: Line(6),
len: 6, len: 6,
}; };
@ -620,9 +587,10 @@ mod test {
Row::new(Column(1), &'3'), Row::new(Column(1), &'3'),
], ],
zero: 2, zero: 2,
visible_lines: Line(0), visible_lines: Line(2),
len: 2, len: 2,
}; };
assert_eq!(storage.visible_lines, expected.visible_lines);
assert_eq!(storage.inner, expected.inner); assert_eq!(storage.inner, expected.inner);
assert_eq!(storage.zero, expected.zero); assert_eq!(storage.zero, expected.zero);
assert_eq!(storage.len, expected.len); assert_eq!(storage.len, expected.len);
@ -815,28 +783,30 @@ mod test {
}; };
// Initialize additional lines // Initialize additional lines
storage.initialize(3, Row::new(Column(1), &'-')); let init_size = 3;
storage.initialize(init_size, &'-', Column(1));
// Make sure the lines are present and at the right location // Make sure the lines are present and at the right location
let shrinking_expected = Storage {
inner: vec![ let expected_init_size = std::cmp::max(init_size, MAX_CACHE_SIZE);
Row::new(Column(1), &'4'), let mut expected_inner = vec![Row::new(Column(1), &'4'), Row::new(Column(1), &'5')];
Row::new(Column(1), &'5'), expected_inner.append(&mut vec![Row::new(Column(1), &'-'); expected_init_size]);
Row::new(Column(1), &'-'), expected_inner.append(&mut vec![
Row::new(Column(1), &'-'), Row::new(Column(1), &'0'),
Row::new(Column(1), &'-'), Row::new(Column(1), &'1'),
Row::new(Column(1), &'0'), Row::new(Column(1), &'2'),
Row::new(Column(1), &'1'), Row::new(Column(1), &'3'),
Row::new(Column(1), &'2'), ]);
Row::new(Column(1), &'3'), let expected_storage = Storage {
], inner: expected_inner,
zero: 5, zero: 2 + expected_init_size,
visible_lines: Line(0), visible_lines: Line(0),
len: 9, len: 9,
}; };
assert_eq!(storage.inner, shrinking_expected.inner);
assert_eq!(storage.zero, shrinking_expected.zero); assert_eq!(storage.inner, expected_storage.inner);
assert_eq!(storage.len, shrinking_expected.len); assert_eq!(storage.zero, expected_storage.zero);
assert_eq!(storage.len, expected_storage.len);
} }
#[test] #[test]

View File

@ -937,7 +937,7 @@ impl<T> Term<T> {
} }
self.default_cursor_style = config.cursor.style; self.default_cursor_style = config.cursor.style;
self.dynamic_title = config.dynamic_title(); self.dynamic_title = config.dynamic_title();
self.grid.update_history(config.scrolling.history() as usize, &self.cursor.template); self.grid.update_history(config.scrolling.history() as usize);
} }
/// Convert the active selection to a String. /// Convert the active selection to a String.
@ -1099,14 +1099,9 @@ impl<T> Term<T> {
} }
// Move prompt down when growing if scrollback lines are available // Move prompt down when growing if scrollback lines are available
if num_lines > old_lines { if num_lines > old_lines && !self.mode.contains(TermMode::ALT_SCREEN) {
if self.mode.contains(TermMode::ALT_SCREEN) { let growage = min(num_lines - old_lines, Line(self.grid.history_size()));
let growage = min(num_lines - old_lines, Line(self.alt_grid.scroll_limit())); self.cursor.point.line += growage;
self.cursor_save.point.line += growage;
} else {
let growage = min(num_lines - old_lines, Line(self.grid.scroll_limit()));
self.cursor.point.line += growage;
}
} }
debug!("New num_cols is {} and num_lines is {}", num_cols, num_lines); debug!("New num_cols is {} and num_lines is {}", num_cols, num_lines);
@ -2298,6 +2293,11 @@ mod tests {
// Make sure that scrolling does not change the grid // Make sure that scrolling does not change the grid
let mut scrolled_grid = term.grid.clone(); let mut scrolled_grid = term.grid.clone();
scrolled_grid.scroll_display(Scroll::Top); scrolled_grid.scroll_display(Scroll::Top);
// Truncate grids for comparison
scrolled_grid.truncate();
term.grid.truncate();
assert_eq!(term.grid, scrolled_grid); assert_eq!(term.grid, scrolled_grid);
} }

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1 +1 @@
{"raw":{"inner":[{"inner":[{"c":" ","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0},"extra":[" "," "," "," "," "]},{"c":" ","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0},"extra":[" "," "," "," "," "]},{"c":" ","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0},"extra":[" "," "," "," "," "]},{"c":" ","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0},"extra":[" "," "," "," "," "]},{"c":" ","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0},"extra":[" "," "," "," "," "]},{"c":" ","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0},"extra":[" "," "," "," "," "]},{"c":" ","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0},"extra":[" "," "," "," "," "]},{"c":" ","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0},"extra":[" "," "," "," "," "]},{"c":" ","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0},"extra":[" "," "," "," "," "]},{"c":" ","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0},"extra":[" "," "," "," "," "]}],"occ":0},{"inner":[{"c":"A","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0},"extra":[" "," "," "," "," "]},{"c":"B","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0},"extra":[" "," "," "," "," "]},{"c":"C","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0},"extra":[" "," "," "," "," "]},{"c":" ","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0},"extra":[" "," "," "," "," "]},{"c":" ","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0},"extra":[" "," "," "," "," "]},{"c":" ","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0},"extra":[" "," "," "," "," "]},{"c":" ","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0},"extra":[" "," "," "," "," "]},{"c":" ","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0},"extra":[" "," "," "," "," "]},{"c":" ","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0},"extra":[" "," "," "," "," "]},{"c":" ","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0},"extra":[" "," "," "," "," "]}],"occ":3},{"inner":[{"c":"A","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0},"extra":[" "," "," "," "," "]},{"c":"B","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0},"extra":[" "," "," "," "," "]},{"c":"C","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0},"extra":[" "," "," "," "," "]},{"c":" ","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0},"extra":[" "," "," "," "," "]},{"c":" ","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0},"extra":[" "," "," "," "," "]},{"c":" ","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0},"extra":[" "," "," "," "," "]},{"c":" ","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0},"extra":[" "," "," "," "," "]},{"c":" ","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0},"extra":[" "," "," "," "," "]},{"c":" ","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0},"extra":[" "," "," "," "," "]},{"c":" ","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0},"extra":[" "," "," "," "," "]}],"occ":3}],"zero":0,"visible_lines":2,"len":3},"cols":10,"lines":3,"display_offset":0,"scroll_limit":0,"max_scroll_limit":0,"url_highlight":null} {"raw":{"inner":[{"inner":[{"c":" ","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0},"extra":[" "," "," "," "," "]},{"c":" ","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0},"extra":[" "," "," "," "," "]},{"c":" ","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0},"extra":[" "," "," "," "," "]},{"c":" ","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0},"extra":[" "," "," "," "," "]},{"c":" ","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0},"extra":[" "," "," "," "," "]},{"c":" ","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0},"extra":[" "," "," "," "," "]},{"c":" ","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0},"extra":[" "," "," "," "," "]},{"c":" ","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0},"extra":[" "," "," "," "," "]},{"c":" ","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0},"extra":[" "," "," "," "," "]},{"c":" ","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0},"extra":[" "," "," "," "," "]}],"occ":0},{"inner":[{"c":"A","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0},"extra":[" "," "," "," "," "]},{"c":"B","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0},"extra":[" "," "," "," "," "]},{"c":"C","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0},"extra":[" "," "," "," "," "]},{"c":" ","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0},"extra":[" "," "," "," "," "]},{"c":" ","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0},"extra":[" "," "," "," "," "]},{"c":" ","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0},"extra":[" "," "," "," "," "]},{"c":" ","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0},"extra":[" "," "," "," "," "]},{"c":" ","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0},"extra":[" "," "," "," "," "]},{"c":" ","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0},"extra":[" "," "," "," "," "]},{"c":" ","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0},"extra":[" "," "," "," "," "]}],"occ":3},{"inner":[{"c":"A","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0},"extra":[" "," "," "," "," "]},{"c":"B","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0},"extra":[" "," "," "," "," "]},{"c":"C","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0},"extra":[" "," "," "," "," "]},{"c":" ","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0},"extra":[" "," "," "," "," "]},{"c":" ","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0},"extra":[" "," "," "," "," "]},{"c":" ","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0},"extra":[" "," "," "," "," "]},{"c":" ","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0},"extra":[" "," "," "," "," "]},{"c":" ","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0},"extra":[" "," "," "," "," "]},{"c":" ","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0},"extra":[" "," "," "," "," "]},{"c":" ","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0},"extra":[" "," "," "," "," "]}],"occ":3}],"zero":0,"visible_lines":2,"len":3},"cols":10,"lines":3,"display_offset":0,"max_scroll_limit":0,"url_highlight":null}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long