summaryrefslogtreecommitdiff
path: root/alacritty_terminal/src/grid
diff options
context:
space:
mode:
authorChristian Duerr <contact@christianduerr.com>2020-05-30 20:45:44 +0000
committerGitHub <noreply@github.com>2020-05-30 20:45:44 +0000
commit1dacc99183373bffa3ba287aa3241f3b1da67016 (patch)
treed5dbefde927b02bff10e29d8596a0bfab65d88f1 /alacritty_terminal/src/grid
parentf7fb67f870943f3f760826b748c8463b8e434983 (diff)
downloadalacritty-1dacc99183373bffa3ba287aa3241f3b1da67016.tar.gz
alacritty-1dacc99183373bffa3ba287aa3241f3b1da67016.zip
Refactor Term/Grid separation
This commit aims to clear up the separation between Term and Grid to make way for implementing search. The `cursor` and `cursor_save` have been moved to the grid, since they're always bound to their specific grid and this makes updating easier. Since the selection is independent of the active grid, it has been moved to the `Term`.
Diffstat (limited to 'alacritty_terminal/src/grid')
-rw-r--r--alacritty_terminal/src/grid/mod.rs377
-rw-r--r--alacritty_terminal/src/grid/resize.rs274
-rw-r--r--alacritty_terminal/src/grid/row.rs12
-rw-r--r--alacritty_terminal/src/grid/storage.rs225
-rw-r--r--alacritty_terminal/src/grid/tests.rs22
5 files changed, 482 insertions, 428 deletions
diff --git a/alacritty_terminal/src/grid/mod.rs b/alacritty_terminal/src/grid/mod.rs
index 71545dca..a136b1b5 100644
--- a/alacritty_terminal/src/grid/mod.rs
+++ b/alacritty_terminal/src/grid/mod.rs
@@ -14,22 +14,22 @@
//! A specialized 2D grid implementation optimized for use in a terminal.
-use std::cmp::{max, min, Ordering};
+use std::cmp::{max, min};
use std::ops::{Deref, Index, IndexMut, Range, RangeFrom, RangeFull, RangeTo};
use serde::{Deserialize, Serialize};
+use crate::ansi::{CharsetIndex, StandardCharset};
use crate::index::{Column, IndexRange, Line, Point};
-use crate::selection::Selection;
-use crate::term::cell::Flags;
+use crate::term::cell::{Cell, Flags};
+pub mod resize;
mod row;
-pub use self::row::Row;
-
+mod storage;
#[cfg(test)]
mod tests;
-mod storage;
+pub use self::row::Row;
use self::storage::Storage;
/// Bidirectional iterator.
@@ -60,7 +60,6 @@ impl<T: PartialEq> ::std::cmp::PartialEq for Grid<T> {
&& self.cols.eq(&other.cols)
&& self.lines.eq(&other.lines)
&& self.display_offset.eq(&other.display_offset)
- && self.selection.eq(&other.selection)
}
}
@@ -76,7 +75,36 @@ pub trait GridCell {
fn fast_eq(&self, other: Self) -> bool;
}
-/// Represents the terminal display contents.
+#[derive(Debug, Default, Copy, Clone, PartialEq, Eq)]
+pub struct Cursor {
+ /// The location of this cursor.
+ pub point: Point,
+
+ /// Template cell when using this cursor.
+ pub template: Cell,
+
+ /// Currently configured graphic character sets.
+ pub charsets: Charsets,
+}
+
+#[derive(Debug, Default, Copy, Clone, PartialEq, Eq)]
+pub struct Charsets([StandardCharset; 4]);
+
+impl Index<CharsetIndex> for Charsets {
+ type Output = StandardCharset;
+
+ fn index(&self, index: CharsetIndex) -> &StandardCharset {
+ &self.0[index as usize]
+ }
+}
+
+impl IndexMut<CharsetIndex> for Charsets {
+ fn index_mut(&mut self, index: CharsetIndex) -> &mut StandardCharset {
+ &mut self.0[index as usize]
+ }
+}
+
+/// Grid based terminal content storage.
///
/// ```notrust
/// ┌─────────────────────────┐ <-- max_scroll_limit + lines
@@ -105,6 +133,14 @@ pub trait GridCell {
/// ```
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct Grid<T> {
+ /// Current cursor for writing data.
+ #[serde(skip)]
+ pub cursor: Cursor,
+
+ /// Last saved cursor.
+ #[serde(skip)]
+ pub saved_cursor: Cursor,
+
/// Lines in the grid. Each row holds a list of cells corresponding to the
/// columns in that row.
raw: Storage<T>,
@@ -122,10 +158,6 @@ pub struct Grid<T> {
/// updates this offset accordingly.
display_offset: usize,
- /// Selected region.
- #[serde(skip)]
- pub selection: Option<Selection>,
-
/// Maximum number of lines in history.
max_scroll_limit: usize,
}
@@ -139,10 +171,17 @@ pub enum Scroll {
Bottom,
}
-impl<T: GridCell + PartialEq + Copy> 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));
- Grid { raw, cols, lines, display_offset: 0, selection: None, max_scroll_limit: scrollback }
+impl<T: GridCell + Default + PartialEq + Copy> Grid<T> {
+ pub fn new(lines: Line, cols: Column, max_scroll_limit: usize, template: T) -> Grid<T> {
+ Grid {
+ raw: Storage::with_capacity(lines, Row::new(cols, template)),
+ max_scroll_limit,
+ display_offset: 0,
+ saved_cursor: Cursor::default(),
+ cursor: Cursor::default(),
+ lines,
+ cols,
+ }
}
/// Clamp a buffer point to the visible region.
@@ -191,33 +230,7 @@ impl<T: GridCell + PartialEq + Copy> Grid<T> {
}
}
- pub fn resize(
- &mut self,
- reflow: bool,
- lines: Line,
- cols: Column,
- cursor_pos: &mut Point,
- template: &T,
- ) {
- // Check that there's actually work to do and return early if not.
- if lines == self.lines && cols == self.cols {
- return;
- }
-
- match self.lines.cmp(&lines) {
- Ordering::Less => self.grow_lines(lines, cursor_pos, template),
- Ordering::Greater => self.shrink_lines(lines, cursor_pos, template),
- Ordering::Equal => (),
- }
-
- match self.cols.cmp(&cols) {
- Ordering::Less => self.grow_cols(reflow, cols, cursor_pos, template),
- Ordering::Greater => self.shrink_cols(reflow, cols, template),
- Ordering::Equal => (),
- }
- }
-
- fn increase_scroll_limit(&mut self, count: usize, template: &T) {
+ fn increase_scroll_limit(&mut self, count: usize, template: T) {
let count = min(count, self.max_scroll_limit - self.history_size());
if count != 0 {
self.raw.initialize(count, template, self.cols);
@@ -228,238 +241,12 @@ impl<T: GridCell + PartialEq + Copy> Grid<T> {
let count = min(count, self.history_size());
if count != 0 {
self.raw.shrink_lines(min(count, self.history_size()));
+ self.display_offset = min(self.display_offset, self.history_size());
}
}
- /// Add lines to the visible area.
- ///
- /// Alacritty keeps the cursor at the bottom of the terminal as long as there
- /// is scrollback available. Once scrollback is exhausted, new lines are
- /// simply added to the bottom of the screen.
- fn grow_lines(&mut self, new_line_count: Line, cursor_pos: &mut Point, template: &T) {
- let lines_added = new_line_count - self.lines;
-
- // Need to "resize" before updating buffer.
- self.raw.grow_visible_lines(new_line_count, Row::new(self.cols, template));
- self.lines = new_line_count;
-
- let history_size = self.history_size();
- let from_history = min(history_size, lines_added.0);
-
- // Move cursor down for all lines pulled from history.
- cursor_pos.line += from_history;
-
- if from_history != lines_added.0 {
- // Move existing lines up for every line that couldn't be pulled from history.
- self.scroll_up(&(Line(0)..new_line_count), lines_added - from_history, template);
- }
-
- self.decrease_scroll_limit(*lines_added);
- self.display_offset = self.display_offset.saturating_sub(*lines_added);
- }
-
- /// Grow number of columns in each row, reflowing if necessary.
- fn grow_cols(&mut self, reflow: bool, cols: Column, cursor_pos: &mut Point, template: &T) {
- // Check if a row needs to be wrapped.
- let should_reflow = |row: &Row<T>| -> bool {
- let len = Column(row.len());
- reflow && len < cols && row[len - 1].flags().contains(Flags::WRAPLINE)
- };
-
- let mut new_empty_lines = 0;
- let mut reversed: Vec<Row<T>> = Vec::with_capacity(self.raw.len());
- for (i, mut row) in self.raw.drain().enumerate().rev() {
- // Check if reflowing should be performed.
- let last_row = match reversed.last_mut() {
- Some(last_row) if should_reflow(last_row) => last_row,
- _ => {
- reversed.push(row);
- continue;
- },
- };
-
- // Remove wrap flag before appending additional cells.
- if let Some(cell) = last_row.last_mut() {
- cell.flags_mut().remove(Flags::WRAPLINE);
- }
-
- // Remove leading spacers when reflowing wide char to the previous line.
- let last_len = last_row.len();
- if last_len >= 2
- && !last_row[Column(last_len - 2)].flags().contains(Flags::WIDE_CHAR)
- && last_row[Column(last_len - 1)].flags().contains(Flags::WIDE_CHAR_SPACER)
- {
- last_row.shrink(Column(last_len - 1));
- }
-
- // Append as many cells from the next line as possible.
- let len = min(row.len(), cols.0 - last_row.len());
-
- // Insert leading spacer when there's not enough room for reflowing wide char.
- let mut cells = if row[Column(len - 1)].flags().contains(Flags::WIDE_CHAR) {
- let mut cells = row.front_split_off(len - 1);
-
- let mut spacer = *template;
- spacer.flags_mut().insert(Flags::WIDE_CHAR_SPACER);
- cells.push(spacer);
-
- cells
- } else {
- row.front_split_off(len)
- };
-
- last_row.append(&mut cells);
-
- if row.is_empty() {
- if i + reversed.len() < self.lines.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 if i < self.display_offset {
- // Keep viewport in place if line is outside of the visible area.
- self.display_offset = self.display_offset.saturating_sub(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.flags_mut().insert(Flags::WRAPLINE);
- }
-
- reversed.push(row);
- }
-
- // Add padding lines.
- reversed.append(&mut vec![Row::new(cols, template); new_empty_lines]);
-
- // Fill remaining cells and reverse iterator.
- let mut new_raw = Vec::with_capacity(reversed.len());
- for mut row in reversed.drain(..).rev() {
- if row.len() < cols.0 {
- row.grow(cols, template);
- }
- new_raw.push(row);
- }
-
- self.raw.replace_inner(new_raw);
-
- self.display_offset = min(self.display_offset, self.history_size());
- self.cols = cols;
- }
-
- /// Shrink number of columns in each row, reflowing if necessary.
- fn shrink_cols(&mut self, reflow: bool, cols: 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() {
- // Append lines left over from previous row.
- if let Some(buffered) = buffered.take() {
- row.append_front(buffered);
- }
-
- loop {
- // Check if reflowing should be performed.
- let mut wrapped = match row.shrink(cols) {
- Some(wrapped) if reflow => wrapped,
- _ => {
- new_raw.push(row);
- break;
- },
- };
-
- // Insert spacer if a wide char would be wrapped into the last column.
- if row.len() >= cols.0 && row[cols - 1].flags().contains(Flags::WIDE_CHAR) {
- wrapped.insert(0, row[cols - 1]);
-
- let mut spacer = *template;
- spacer.flags_mut().insert(Flags::WIDE_CHAR_SPACER);
- row[cols - 1] = spacer;
- }
-
- // Remove wide char spacer before shrinking.
- let len = wrapped.len();
- if (len == 1 || (len >= 2 && !wrapped[len - 2].flags().contains(Flags::WIDE_CHAR)))
- && wrapped[len - 1].flags().contains(Flags::WIDE_CHAR_SPACER)
- {
- if len == 1 {
- row[cols - 1].flags_mut().insert(Flags::WRAPLINE);
- new_raw.push(row);
- break;
- } else {
- wrapped[len - 2].flags_mut().insert(Flags::WRAPLINE);
- wrapped.truncate(len - 1);
- }
- }
-
- new_raw.push(row);
-
- // Set line as wrapped if cells got removed.
- if let Some(cell) = new_raw.last_mut().and_then(|r| r.last_mut()) {
- cell.flags_mut().insert(Flags::WRAPLINE);
- }
-
- if wrapped
- .last()
- .map(|c| c.flags().contains(Flags::WRAPLINE) && i >= 1)
- .unwrap_or(false)
- && wrapped.len() < cols.0
- {
- // Make sure previous wrap flag doesn't linger around.
- if let Some(cell) = wrapped.last_mut() {
- cell.flags_mut().remove(Flags::WRAPLINE);
- }
-
- // Add removed cells to start of next row.
- buffered = Some(wrapped);
- break;
- } else {
- // Make sure viewport doesn't move if line is outside of the visible area.
- if i < self.display_offset {
- self.display_offset = min(self.display_offset + 1, self.max_scroll_limit);
- }
-
- // Make sure new row is at least as long as new width.
- let occ = wrapped.len();
- if occ < cols.0 {
- wrapped.append(&mut vec![*template; cols.0 - occ]);
- }
- row = Row::from_vec(wrapped, occ);
- }
- }
- }
-
- 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;
- }
-
- /// Remove lines from the visible area.
- ///
- /// The behavior in Terminal.app and iTerm.app is to keep the cursor at the
- /// bottom of the screen. This is achieved by pushing history "out the top"
- /// of the terminal window.
- ///
- /// Alacritty takes the same approach.
- fn shrink_lines(&mut self, target: Line, cursor_pos: &mut Point, template: &T) {
- // Scroll up to keep cursor inside the window.
- let required_scrolling = (cursor_pos.line + 1).saturating_sub(target.0);
- if required_scrolling > 0 {
- self.scroll_up(&(Line(0)..self.lines), Line(required_scrolling), template);
- }
-
- self.selection = None;
- self.raw.rotate((self.lines - target).0 as isize);
- self.raw.shrink_visible_lines(target);
- self.lines = target;
- }
-
#[inline]
- pub fn scroll_down(&mut self, region: &Range<Line>, positions: Line, template: &T) {
- let num_lines = self.num_lines().0;
- let num_cols = self.num_cols().0;
-
+ pub fn scroll_down(&mut self, region: &Range<Line>, positions: Line, template: T) {
// Whether or not there is a scrolling region active, as long as it
// starts at the top, we can do a full rotation which just involves
// changing the start index.
@@ -469,10 +256,6 @@ impl<T: GridCell + PartialEq + Copy> Grid<T> {
// Rotate the entire line buffer. If there's a scrolling region
// active, the bottom lines are restored in the next step.
self.raw.rotate_up(*positions);
- self.selection = self
- .selection
- .take()
- .and_then(|s| s.rotate(num_lines, num_cols, region, -(*positions as isize)));
self.decrease_scroll_limit(*positions);
@@ -484,22 +267,16 @@ impl<T: GridCell + PartialEq + Copy> Grid<T> {
// Finally, reset recycled lines.
for i in IndexRange(Line(0)..positions) {
- self.raw[i].reset(&template);
+ self.raw[i].reset(template);
}
} else {
- // Rotate selection to track content.
- self.selection = self
- .selection
- .take()
- .and_then(|s| s.rotate(num_lines, num_cols, region, -(*positions as isize)));
-
// Subregion rotation.
for line in IndexRange((region.start + positions)..region.end).rev() {
self.raw.swap_lines(line, line - positions);
}
for line in IndexRange(region.start..(region.start + positions)) {
- self.raw[line].reset(&template);
+ self.raw[line].reset(template);
}
}
}
@@ -507,9 +284,8 @@ impl<T: GridCell + PartialEq + Copy> Grid<T> {
/// Move lines at the bottom towards the top.
///
/// This is the performance-sensitive part of scrolling.
- pub fn scroll_up(&mut self, region: &Range<Line>, positions: Line, template: &T) {
+ pub fn scroll_up(&mut self, region: &Range<Line>, positions: Line, template: T) {
let num_lines = self.num_lines().0;
- let num_cols = self.num_cols().0;
if region.start == Line(0) {
// Update display offset when not pinned to active area.
@@ -522,10 +298,6 @@ impl<T: GridCell + PartialEq + Copy> Grid<T> {
// Rotate the entire line buffer. If there's a scrolling region
// active, the bottom lines are restored in the next step.
self.raw.rotate(-(*positions as isize));
- self.selection = self
- .selection
- .take()
- .and_then(|s| s.rotate(num_lines, num_cols, region, *positions as isize));
// This next loop swaps "fixed" lines outside of a scroll region
// back into place after the rotation. The work is done in buffer-
@@ -541,15 +313,9 @@ impl<T: GridCell + PartialEq + Copy> Grid<T> {
//
// Recycled lines are just above the end of the scrolling region.
for i in 0..*positions {
- self.raw[i + fixed_lines].reset(&template);
+ self.raw[i + fixed_lines].reset(template);
}
} else {
- // Rotate selection to track content.
- self.selection = self
- .selection
- .take()
- .and_then(|s| s.rotate(num_lines, num_cols, region, *positions as isize));
-
// Subregion rotation.
for line in IndexRange(region.start..(region.end - positions)) {
self.raw.swap_lines(line, line + positions);
@@ -557,12 +323,12 @@ impl<T: GridCell + PartialEq + Copy> Grid<T> {
// Clear reused lines.
for line in IndexRange((region.end - positions)..region.end) {
- self.raw[line].reset(&template);
+ self.raw[line].reset(template);
}
}
}
- pub fn clear_viewport(&mut self, template: &T) {
+ pub fn clear_viewport(&mut self, template: T) {
// Determine how many lines to scroll up by.
let end = Point { line: 0, col: self.num_cols() };
let mut iter = self.iter_from(end);
@@ -583,12 +349,12 @@ impl<T: GridCell + PartialEq + Copy> Grid<T> {
// Reset rotated lines.
for i in positions.0..self.lines.0 {
- self.raw[i].reset(&template);
+ self.raw[i].reset(template);
}
}
/// Completely reset the grid state.
- pub fn reset(&mut self, template: &T) {
+ pub fn reset(&mut self, template: T) {
self.clear_history();
// Reset all visible lines.
@@ -596,8 +362,9 @@ impl<T: GridCell + PartialEq + Copy> Grid<T> {
self.raw[row].reset(template);
}
+ self.saved_cursor = Cursor::default();
+ self.cursor = Cursor::default();
self.display_offset = 0;
- self.selection = None;
}
}
@@ -637,7 +404,7 @@ impl<T> Grid<T> {
/// 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
T: Copy + GridCell,
{
@@ -663,6 +430,12 @@ impl<T> Grid<T> {
pub fn display_offset(&self) -> usize {
self.display_offset
}
+
+ #[inline]
+ pub fn cursor_cell(&mut self) -> &mut T {
+ let point = self.cursor.point;
+ &mut self[&point]
+ }
}
pub struct GridIterator<'a, T> {
diff --git a/alacritty_terminal/src/grid/resize.rs b/alacritty_terminal/src/grid/resize.rs
new file mode 100644
index 00000000..796c5859
--- /dev/null
+++ b/alacritty_terminal/src/grid/resize.rs
@@ -0,0 +1,274 @@
+//! Grid resize and reflow.
+
+use std::cmp::{min, Ordering};
+
+use crate::index::{Column, Line};
+use crate::term::cell::Flags;
+
+use crate::grid::row::Row;
+use crate::grid::{Grid, GridCell};
+
+impl<T: GridCell + Default + PartialEq + Copy> Grid<T> {
+ /// Resize the grid's width and/or height.
+ pub fn resize(&mut self, reflow: bool, lines: Line, cols: Column) {
+ match self.lines.cmp(&lines) {
+ Ordering::Less => self.grow_lines(lines),
+ Ordering::Greater => self.shrink_lines(lines),
+ Ordering::Equal => (),
+ }
+
+ match self.cols.cmp(&cols) {
+ Ordering::Less => self.grow_cols(cols, reflow),
+ Ordering::Greater => self.shrink_cols(cols, reflow),
+ Ordering::Equal => (),
+ }
+ }
+
+ /// Add lines to the visible area.
+ ///
+ /// Alacritty keeps the cursor at the bottom of the terminal as long as there
+ /// is scrollback available. Once scrollback is exhausted, new lines are
+ /// simply added to the bottom of the screen.
+ fn grow_lines(&mut self, new_line_count: Line) {
+ let lines_added = new_line_count - self.lines;
+
+ // Need to resize before updating buffer.
+ self.raw.grow_visible_lines(new_line_count, Row::new(self.cols, T::default()));
+ self.lines = new_line_count;
+
+ let history_size = self.history_size();
+ let from_history = min(history_size, lines_added.0);
+
+ // Move existing lines up for every line that couldn't be pulled from history.
+ if from_history != lines_added.0 {
+ let delta = lines_added - from_history;
+ self.scroll_up(&(Line(0)..new_line_count), delta, T::default());
+ }
+
+ // Move cursor down for every line pulled from history.
+ self.saved_cursor.point.line += from_history;
+ self.cursor.point.line += from_history;
+
+ self.display_offset = self.display_offset.saturating_sub(*lines_added);
+ self.decrease_scroll_limit(*lines_added);
+ }
+
+ /// Remove lines from the visible area.
+ ///
+ /// The behavior in Terminal.app and iTerm.app is to keep the cursor at the
+ /// bottom of the screen. This is achieved by pushing history "out the top"
+ /// of the terminal window.
+ ///
+ /// Alacritty takes the same approach.
+ fn shrink_lines(&mut self, target: Line) {
+ // Scroll up to keep content inside the window.
+ let required_scrolling = (self.cursor.point.line + 1).saturating_sub(target.0);
+ if required_scrolling > 0 {
+ self.scroll_up(&(Line(0)..self.lines), Line(required_scrolling), T::default());
+
+ // Clamp cursors to the new viewport size.
+ self.saved_cursor.point.line = min(self.saved_cursor.point.line, target - 1);
+ self.cursor.point.line = min(self.cursor.point.line, target - 1);
+ }
+
+ self.raw.rotate((self.lines - target).0 as isize);
+ self.raw.shrink_visible_lines(target);
+ self.lines = target;
+ }
+
+ /// Grow number of columns in each row, reflowing if necessary.
+ fn grow_cols(&mut self, cols: Column, reflow: bool) {
+ // Check if a row needs to be wrapped.
+ let should_reflow = |row: &Row<T>| -> bool {
+ let len = Column(row.len());
+ reflow && len < cols && row[len - 1].flags().contains(Flags::WRAPLINE)
+ };
+
+ self.cols = cols;
+
+ let mut reversed: Vec<Row<T>> = Vec::with_capacity(self.raw.len());
+ let mut new_empty_lines = 0;
+
+ let mut rows = self.raw.take_all();
+
+ for (i, mut row) in rows.drain(..).enumerate().rev() {
+ // Check if reflowing should be performed.
+ let last_row = match reversed.last_mut() {
+ Some(last_row) if should_reflow(last_row) => last_row,
+ _ => {
+ reversed.push(row);
+ continue;
+ },
+ };
+
+ // Remove wrap flag before appending additional cells.
+ if let Some(cell) = last_row.last_mut() {
+ cell.flags_mut().remove(Flags::WRAPLINE);
+ }
+
+ // Remove leading spacers when reflowing wide char to the previous line.
+ let mut last_len = last_row.len();
+ if last_len >= 2
+ && !last_row[Column(last_len - 2)].flags().contains(Flags::WIDE_CHAR)
+ && last_row[Column(last_len - 1)].flags().contains(Flags::WIDE_CHAR_SPACER)
+ {
+ last_row.shrink(Column(last_len - 1));
+ last_len -= 1;
+ }
+
+ // Don't try to pull more cells from the next line than available.
+ let len = min(row.len(), cols.0 - last_len);
+
+ // Insert leading spacer when there's not enough room for reflowing wide char.
+ let mut cells = if row[Column(len - 1)].flags().contains(Flags::WIDE_CHAR) {
+ let mut cells = row.front_split_off(len - 1);
+
+ let mut spacer = T::default();
+ spacer.flags_mut().insert(Flags::WIDE_CHAR_SPACER);
+ cells.push(spacer);
+
+ cells
+ } else {
+ row.front_split_off(len)
+ };
+
+ // Reflow cells to previous row.
+ last_row.append(&mut cells);
+
+ if row.is_empty() {
+ if i + reversed.len() < self.lines.0 {
+ // Add new line and move everything up if we can't pull from history.
+ self.saved_cursor.point.line.0 = self.saved_cursor.point.line.saturating_sub(1);
+ self.cursor.point.line.0 = self.cursor.point.line.saturating_sub(1);
+ new_empty_lines += 1;
+ } else {
+ // Since we removed a line, rotate down the viewport.
+ self.display_offset = self.display_offset.saturating_sub(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.flags_mut().insert(Flags::WRAPLINE);
+ }
+
+ reversed.push(row);
+ }
+
+ // Add all new empty lines in one go.
+ reversed.append(&mut vec![Row::new(cols, T::default()); new_empty_lines]);
+
+ // Reverse iterator and fill all rows that are still too short.
+ let mut new_raw = Vec::with_capacity(reversed.len());
+ for mut row in reversed.drain(..).rev() {
+ if row.len() < cols.0 {
+ row.grow(cols, T::default());
+ }
+ new_raw.push(row);
+ }
+
+ self.raw.replace_inner(new_raw);
+
+ // Clamp display offset in case lines above it got merged.
+ self.display_offset = min(self.display_offset, self.history_size());
+ }
+
+ /// Shrink number of columns in each row, reflowing if necessary.
+ fn shrink_cols(&mut self, cols: Column, reflow: bool) {
+ self.cols = cols;
+
+ let mut rows = self.raw.take_all();
+
+ let mut new_raw = Vec::with_capacity(self.raw.len());
+ let mut buffered: Option<Vec<T>> = None;
+
+ for (i, mut row) in rows.drain(..).enumerate().rev() {
+ // Append lines left over from the previous row.
+ if let Some(buffered) = buffered.take() {
+ row.append_front(buffered);
+ }
+
+ loop {
+ // Remove all cells which require reflowing.
+ let mut wrapped = match row.shrink(cols) {
+ Some(wrapped) if reflow => wrapped,
+ _ => {
+ new_raw.push(row);
+ break;
+ },
+ };
+
+ // Insert spacer if a wide char would be wrapped into the last column.
+ if row.len() >= cols.0 && row[cols - 1].flags().contains(Flags::WIDE_CHAR) {
+ wrapped.insert(0, row[cols - 1]);
+
+ let mut spacer = T::default();
+ spacer.flags_mut().insert(Flags::WIDE_CHAR_SPACER);
+ row[cols - 1] = spacer;
+ }
+
+ // Remove wide char spacer before shrinking.
+ let len = wrapped.len();
+ if (len == 1 || (len >= 2 && !wrapped[len - 2].flags().contains(Flags::WIDE_CHAR)))
+ && wrapped[len - 1].flags().contains(Flags::WIDE_CHAR_SPACER)
+ {
+ if len == 1 {
+ // Delete the wrapped content if it contains only a leading spacer.
+ row[cols - 1].flags_mut().insert(Flags::WRAPLINE);
+ new_raw.push(row);
+ break;
+ } else {
+ // Remove the leading spacer from the end of the wrapped row.
+ wrapped[len - 2].flags_mut().insert(Flags::WRAPLINE);
+ wrapped.truncate(len - 1);
+ }
+ }
+
+ new_raw.push(row);
+
+ // Set line as wrapped if cells got removed.
+ if let Some(cell) = new_raw.last_mut().and_then(|r| r.last_mut()) {
+ cell.flags_mut().insert(Flags::WRAPLINE);
+ }
+
+ if wrapped
+ .last()
+ .map(|c| c.flags().contains(Flags::WRAPLINE) && i >= 1)
+ .unwrap_or(false)
+ && wrapped.len() < cols.0
+ {
+ // Make sure previous wrap flag doesn't linger around.
+ if let Some(cell) = wrapped.last_mut() {
+ cell.flags_mut().remove(Flags::WRAPLINE);
+ }
+
+ // Add removed cells to start of next row.
+ buffered = Some(wrapped);
+ break;
+ } else {
+ // Since we added a line, rotate up the viewport.
+ if i < self.display_offset {
+ self.display_offset = min(self.display_offset + 1, self.max_scroll_limit);
+ }
+
+ // Make sure new row is at least as long as new width.
+ let occ = wrapped.len();
+ if occ < cols.0 {
+ wrapped.append(&mut vec![T::default(); cols.0 - occ]);
+ }
+ row = Row::from_vec(wrapped, occ);
+ }
+ }
+ }
+
+ // Reverse iterator and use it as the new grid storage.
+ 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);
+
+ // Wrap content going beyond new width if necessary.
+ self.saved_cursor.point.col = min(self.saved_cursor.point.col, self.cols - 1);
+ self.cursor.point.col = min(self.cursor.point.col, self.cols - 1);
+ }
+}
diff --git a/alacritty_terminal/src/grid/row.rs b/alacritty_terminal/src/grid/row.rs
index 22a10625..b5248ad7 100644
--- a/alacritty_terminal/src/grid/row.rs
+++ b/alacritty_terminal/src/grid/row.rs
@@ -43,20 +43,20 @@ impl<T: PartialEq> PartialEq for Row<T> {
}
impl<T: Copy> Row<T> {
- pub fn new(columns: Column, template: &T) -> Row<T>
+ pub fn new(columns: Column, template: T) -> Row<T>
where
T: GridCell,
{
let occ = if template.is_empty() { 0 } else { columns.0 };
- Row { inner: vec![*template; columns.0], occ }
+ Row { inner: vec![template; columns.0], occ }
}
- pub fn grow(&mut self, cols: Column, template: &T) {
+ pub fn grow(&mut self, cols: Column, template: T) {
if self.inner.len() >= cols.0 {
return;
}
- self.inner.append(&mut vec![*template; cols.0 - self.len()]);
+ self.inner.append(&mut vec![template; cols.0 - self.len()]);
}
pub fn shrink(&mut self, cols: Column) -> Option<Vec<T>>
@@ -83,14 +83,12 @@ impl<T: Copy> Row<T> {
/// Reset all cells in the row to the `template` cell.
#[inline]
- pub fn reset(&mut self, template: &T)
+ pub fn reset(&mut self, template: T)
where
T: GridCell + PartialEq,
{
debug_assert!(!self.inner.is_empty());
- let template = *template;
-
// Mark all cells as dirty if template cell changed.
let len = self.inner.len();
if !self.inner[len - 1].fast_eq(template) {
diff --git a/alacritty_terminal/src/grid/storage.rs b/alacritty_terminal/src/grid/storage.rs
index 4820036f..4b7ca41a 100644
--- a/alacritty_terminal/src/grid/storage.rs
+++ b/alacritty_terminal/src/grid/storage.rs
@@ -1,6 +1,6 @@
use std::cmp::{max, PartialEq};
+use std::mem;
use std::ops::{Index, IndexMut};
-use std::vec::Drain;
use serde::{Deserialize, Serialize};
@@ -142,7 +142,7 @@ impl<T> Storage<T> {
/// Dynamically grow the storage buffer at runtime.
#[inline]
- pub fn initialize(&mut self, additional_rows: usize, template: &T, cols: Column)
+ pub fn initialize(&mut self, additional_rows: usize, template: T, cols: Column)
where
T: GridCell + Copy,
{
@@ -238,18 +238,27 @@ impl<T> Storage<T> {
self.zero = (self.zero + count) % self.inner.len();
}
- /// Drain all rows in the grid.
- pub fn drain(&mut self) -> Drain<'_, Row<T>> {
- self.truncate();
- self.inner.drain(..)
- }
-
/// Update the raw storage buffer.
+ #[inline]
pub fn replace_inner(&mut self, vec: Vec<Row<T>>) {
self.len = vec.len();
self.inner = vec;
self.zero = 0;
}
+
+ /// Remove all rows from storage.
+ #[inline]
+ pub fn take_all(&mut self) -> Vec<Row<T>> {
+ self.truncate();
+
+ let mut buffer = Vec::new();
+
+ mem::swap(&mut buffer, &mut self.inner);
+ self.zero = 0;
+ self.len = 0;
+
+ buffer
+ }
}
impl<T> Index<usize> for Storage<T> {
@@ -315,7 +324,7 @@ mod tests {
#[test]
fn with_capacity() {
- let storage = Storage::with_capacity(Line(3), Row::new(Column(0), &' '));
+ let storage = Storage::with_capacity(Line(3), Row::new(Column(0), ' '));
assert_eq!(storage.inner.len(), 3);
assert_eq!(storage.len, 3);
@@ -325,33 +334,33 @@ mod tests {
#[test]
fn indexing() {
- let mut storage = Storage::with_capacity(Line(3), Row::new(Column(0), &' '));
+ 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');
+ 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'));
+ 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'));
+ 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_inner_len() {
- let storage = Storage::with_capacity(Line(1), Row::new(Column(0), &' '));
+ 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), &' '));
+ let mut storage = Storage::with_capacity(Line(3), Row::new(Column(0), ' '));
storage.rotate(2);
assert_eq!(storage.zero, 2);
storage.shrink_lines(2);
@@ -376,9 +385,9 @@ mod tests {
// Setup storage area
let mut storage = Storage {
inner: vec![
- Row::new(Column(1), &'0'),
- Row::new(Column(1), &'1'),
- Row::new(Column(1), &'-'),
+ Row::new(Column(1), '0'),
+ Row::new(Column(1), '1'),
+ Row::new(Column(1), '-'),
],
zero: 0,
visible_lines: Line(3),
@@ -386,15 +395,15 @@ mod tests {
};
// Grow buffer
- storage.grow_visible_lines(Line(4), Row::new(Column(1), &'-'));
+ 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), &'-'),
+ Row::new(Column(1), '-'),
+ Row::new(Column(1), '0'),
+ Row::new(Column(1), '1'),
+ Row::new(Column(1), '-'),
],
zero: 1,
visible_lines: Line(4),
@@ -422,9 +431,9 @@ mod tests {
// Setup storage area.
let mut storage = Storage {
inner: vec![
- Row::new(Column(1), &'-'),
- Row::new(Column(1), &'0'),
- Row::new(Column(1), &'1'),
+ Row::new(Column(1), '-'),
+ Row::new(Column(1), '0'),
+ Row::new(Column(1), '1'),
],
zero: 1,
visible_lines: Line(3),
@@ -432,15 +441,15 @@ mod tests {
};
// Grow buffer.
- storage.grow_visible_lines(Line(4), Row::new(Column(1), &'-'));
+ 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'),
+ Row::new(Column(1), '-'),
+ Row::new(Column(1), '-'),
+ Row::new(Column(1), '0'),
+ Row::new(Column(1), '1'),
],
zero: 2,
visible_lines: Line(4),
@@ -467,9 +476,9 @@ mod tests {
// Setup storage area.
let mut storage = Storage {
inner: vec![
- Row::new(Column(1), &'2'),
- Row::new(Column(1), &'0'),
- Row::new(Column(1), &'1'),
+ Row::new(Column(1), '2'),
+ Row::new(Column(1), '0'),
+ Row::new(Column(1), '1'),
],
zero: 1,
visible_lines: Line(3),
@@ -482,9 +491,9 @@ mod tests {
// 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'),
+ Row::new(Column(1), '2'),
+ Row::new(Column(1), '0'),
+ Row::new(Column(1), '1'),
],
zero: 1,
visible_lines: Line(2),
@@ -511,9 +520,9 @@ mod tests {
// Setup storage area.
let mut storage = Storage {
inner: vec![
- Row::new(Column(1), &'0'),
- Row::new(Column(1), &'1'),
- Row::new(Column(1), &'2'),
+ Row::new(Column(1), '0'),
+ Row::new(Column(1), '1'),
+ Row::new(Column(1), '2'),
],
zero: 0,
visible_lines: Line(3),
@@ -526,9 +535,9 @@ mod tests {
// 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'),
+ Row::new(Column(1), '0'),
+ Row::new(Column(1), '1'),
+ Row::new(Column(1), '2'),
],
zero: 0,
visible_lines: Line(2),
@@ -561,12 +570,12 @@ mod tests {
// 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'),
+ 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(6),
@@ -579,12 +588,12 @@ mod tests {
// 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'),
+ 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(2),
@@ -613,12 +622,12 @@ mod tests {
// 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'),
+ 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),
@@ -630,7 +639,7 @@ mod tests {
// Make sure the result is correct.
let expected = Storage {
- inner: vec![Row::new(Column(1), &'0'), Row::new(Column(1), &'1')],
+ inner: vec![Row::new(Column(1), '0'), Row::new(Column(1), '1')],
zero: 0,
visible_lines: Line(1),
len: 2,
@@ -655,9 +664,9 @@ mod tests {
// Setup storage area.
let mut storage = Storage {
inner: vec![
- Row::new(Column(1), &'1'),
- Row::new(Column(1), &'2'),
- Row::new(Column(1), &'0'),
+ Row::new(Column(1), '1'),
+ Row::new(Column(1), '2'),
+ Row::new(Column(1), '0'),
],
zero: 2,
visible_lines: Line(1),
@@ -669,7 +678,7 @@ mod tests {
// Make sure the result is correct.
let expected = Storage {
- inner: vec![Row::new(Column(1), &'0'), Row::new(Column(1), &'1')],
+ inner: vec![Row::new(Column(1), '0'), Row::new(Column(1), '1')],
zero: 0,
visible_lines: Line(1),
len: 2,
@@ -709,12 +718,12 @@ mod tests {
// 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'),
+ 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),
@@ -727,12 +736,12 @@ mod tests {
// 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'),
+ 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),
@@ -743,18 +752,18 @@ mod tests {
assert_eq!(storage.len, shrinking_expected.len);
// Grow buffer.
- storage.grow_lines(4, Row::new(Column(1), &'-'));
+ 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'),
+ 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),
@@ -770,12 +779,12 @@ mod tests {
// 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'),
+ 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),
@@ -784,18 +793,18 @@ mod tests {
// Initialize additional lines.
let init_size = 3;
- storage.initialize(init_size, &'-', Column(1));
+ storage.initialize(init_size, '-', Column(1));
// Make sure the lines are present and at the right location.
let expected_init_size = std::cmp::max(init_size, MAX_CACHE_SIZE);
- let mut expected_inner = vec![Row::new(Column(1), &'4'), Row::new(Column(1), &'5')];
- expected_inner.append(&mut vec![Row::new(Column(1), &'-'); expected_init_size]);
+ let mut expected_inner = vec![Row::new(Column(1), '4'), Row::new(Column(1), '5')];
+ expected_inner.append(&mut vec![Row::new(Column(1), '-'); expected_init_size]);
expected_inner.append(&mut vec![
- Row::new(Column(1), &'0'),
- Row::new(Column(1), &'1'),
- Row::new(Column(1), &'2'),
- Row::new(Column(1), &'3'),
+ Row::new(Column(1), '0'),
+ Row::new(Column(1), '1'),
+ Row::new(Column(1), '2'),
+ Row::new(Column(1), '3'),
]);
let expected_storage = Storage {
inner: expected_inner,
@@ -813,9 +822,9 @@ mod tests {
fn rotate_wrap_zero() {
let mut storage = Storage {
inner: vec![
- Row::new(Column(1), &'-'),
- Row::new(Column(1), &'-'),
- Row::new(Column(1), &'-'),
+ Row::new(Column(1), '-'),
+ Row::new(Column(1), '-'),
+ Row::new(Column(1), '-'),
],
zero: 2,
visible_lines: Line(0),
diff --git a/alacritty_terminal/src/grid/tests.rs b/alacritty_terminal/src/grid/tests.rs
index ef011d16..04400afc 100644
--- a/alacritty_terminal/src/grid/tests.rs
+++ b/alacritty_terminal/src/grid/tests.rs
@@ -79,7 +79,7 @@ fn scroll_up() {
grid[Line(i)][Column(0)] = i;
}
- grid.scroll_up(&(Line(0)..Line(10)), Line(2), &0);
+ grid.scroll_up(&(Line(0)..Line(10)), Line(2), 0);
assert_eq!(grid[Line(0)][Column(0)], 2);
assert_eq!(grid[Line(0)].occ, 1);
@@ -111,7 +111,7 @@ fn scroll_down() {
grid[Line(i)][Column(0)] = i;
}
- grid.scroll_down(&(Line(0)..Line(10)), Line(2), &0);
+ grid.scroll_down(&(Line(0)..Line(10)), Line(2), 0);
assert_eq!(grid[Line(0)][Column(0)], 0); // was 8.
assert_eq!(grid[Line(0)].occ, 0);
@@ -183,7 +183,7 @@ fn shrink_reflow() {
grid[Line(0)][Column(3)] = cell('4');
grid[Line(0)][Column(4)] = cell('5');
- grid.resize(true, Line(1), Column(2), &mut Point::new(Line(0), Column(0)), &Cell::default());
+ grid.resize(true, Line(1), Column(2));
assert_eq!(grid.len(), 3);
@@ -209,8 +209,8 @@ fn shrink_reflow_twice() {
grid[Line(0)][Column(3)] = cell('4');
grid[Line(0)][Column(4)] = cell('5');
- 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());
+ grid.resize(true, Line(1), Column(4));
+ grid.resize(true, Line(1), Column(2));
assert_eq!(grid.len(), 3);
@@ -236,7 +236,7 @@ fn shrink_reflow_empty_cell_inside_line() {
grid[Line(0)][Column(3)] = cell('4');
grid[Line(0)][Column(4)] = Cell::default();
- grid.resize(true, Line(1), Column(2), &mut Point::new(Line(0), Column(0)), &Cell::default());
+ grid.resize(true, Line(1), Column(2));
assert_eq!(grid.len(), 2);
@@ -248,7 +248,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(true, Line(1), Column(1), &mut Point::new(Line(0), Column(0)), &Cell::default());
+ grid.resize(true, Line(1), Column(1));
assert_eq!(grid.len(), 4);
@@ -273,7 +273,7 @@ fn grow_reflow() {
grid[Line(1)][Column(0)] = cell('3');
grid[Line(1)][Column(1)] = Cell::default();
- grid.resize(true, Line(2), Column(3), &mut Point::new(Line(0), Column(0)), &Cell::default());
+ grid.resize(true, Line(2), Column(3));
assert_eq!(grid.len(), 2);
@@ -299,7 +299,7 @@ fn grow_reflow_multiline() {
grid[Line(2)][Column(0)] = cell('5');
grid[Line(2)][Column(1)] = cell('6');
- grid.resize(true, Line(3), Column(6), &mut Point::new(Line(0), Column(0)), &Cell::default());
+ grid.resize(true, Line(3), Column(6));
assert_eq!(grid.len(), 3);
@@ -330,7 +330,7 @@ fn grow_reflow_disabled() {
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());
+ grid.resize(false, Line(2), Column(3));
assert_eq!(grid.len(), 2);
@@ -354,7 +354,7 @@ fn shrink_reflow_disabled() {
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());
+ grid.resize(false, Line(1), Column(2));
assert_eq!(grid.len(), 1);