diff options
author | Christian Duerr <contact@christianduerr.com> | 2020-11-05 04:45:14 +0000 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-11-05 04:45:14 +0000 |
commit | ec42b42ce601808070462111c0c28edb0e89babb (patch) | |
tree | 48006abca4497f66307f3b4d485bb1f162f4bf32 /alacritty_terminal/src/grid/resize.rs | |
parent | 9028fb451a967d69a9e258a083ba64b052a9a5dd (diff) | |
download | alacritty-ec42b42ce601808070462111c0c28edb0e89babb.tar.gz alacritty-ec42b42ce601808070462111c0c28edb0e89babb.zip |
Use dynamic storage for zerowidth characters
The zerowidth characters were conventionally stored in a [char; 5].
This creates problems both by limiting the maximum number of zerowidth
characters and by increasing the cell size beyond what is necessary even
when no zerowidth characters are used.
Instead of storing zerowidth characters as a slice, a new CellExtra
struct is introduced which can store arbitrary optional cell data that
is rarely required. Since this is stored behind an optional pointer
(Option<Box<CellExtra>>), the initialization and dropping in the case
of no extra data are extremely cheap and the size penalty to cells
without this extra data is limited to 8 instead of 20 bytes.
The most noticible difference with this PR should be a reduction in
memory size of up to at least 30% (1.06G -> 733M, 100k scrollback, 72
lines, 280 columns). Since the zerowidth characters are now stored
dynamically, the limit of 5 per cell is also no longer present.
Diffstat (limited to 'alacritty_terminal/src/grid/resize.rs')
-rw-r--r-- | alacritty_terminal/src/grid/resize.rs | 47 |
1 files changed, 33 insertions, 14 deletions
diff --git a/alacritty_terminal/src/grid/resize.rs b/alacritty_terminal/src/grid/resize.rs index acdc040e..1a16e09e 100644 --- a/alacritty_terminal/src/grid/resize.rs +++ b/alacritty_terminal/src/grid/resize.rs @@ -1,16 +1,24 @@ //! Grid resize and reflow. use std::cmp::{min, Ordering}; +use std::mem; use crate::index::{Column, Line}; -use crate::term::cell::Flags; +use crate::term::cell::{Flags, ResetDiscriminant}; use crate::grid::row::Row; use crate::grid::{Dimensions, Grid, GridCell}; -impl<T: GridCell + Default + PartialEq + Copy> Grid<T> { +impl<T: GridCell + Default + PartialEq + Clone> Grid<T> { /// Resize the grid's width and/or height. - pub fn resize(&mut self, reflow: bool, lines: Line, cols: Column) { + pub fn resize<D>(&mut self, reflow: bool, lines: Line, cols: Column) + where + T: ResetDiscriminant<D>, + D: PartialEq, + { + // Use empty template cell for resetting cells due to resize. + let template = mem::take(&mut self.cursor.template); + match self.lines.cmp(&lines) { Ordering::Less => self.grow_lines(lines), Ordering::Greater => self.shrink_lines(lines), @@ -22,6 +30,9 @@ impl<T: GridCell + Default + PartialEq + Copy> Grid<T> { Ordering::Greater => self.shrink_cols(reflow, cols), Ordering::Equal => (), } + + // Restore template cell. + self.cursor.template = template; } /// Add lines to the visible area. @@ -29,11 +40,15 @@ impl<T: GridCell + Default + PartialEq + Copy> Grid<T> { /// 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) { + fn grow_lines<D>(&mut self, new_line_count: Line) + where + T: ResetDiscriminant<D>, + D: PartialEq, + { 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.raw.grow_visible_lines(new_line_count); self.lines = new_line_count; let history_size = self.history_size(); @@ -42,7 +57,7 @@ impl<T: GridCell + Default + PartialEq + Copy> Grid<T> { // 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()); + self.scroll_up(&(Line(0)..new_line_count), delta); } // Move cursor down for every line pulled from history. @@ -60,11 +75,15 @@ impl<T: GridCell + Default + PartialEq + Copy> Grid<T> { /// of the terminal window. /// /// Alacritty takes the same approach. - fn shrink_lines(&mut self, target: Line) { + fn shrink_lines<D>(&mut self, target: Line) + where + T: ResetDiscriminant<D>, + D: PartialEq, + { // 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()); + self.scroll_up(&(Line(0)..self.lines), Line(required_scrolling)); // Clamp cursors to the new viewport size. self.cursor.point.line = min(self.cursor.point.line, target - 1); @@ -194,7 +213,7 @@ impl<T: GridCell + Default + PartialEq + Copy> Grid<T> { if reversed.len() < self.lines.0 { let delta = self.lines.0 - reversed.len(); self.cursor.point.line.0 = self.cursor.point.line.saturating_sub(delta); - reversed.append(&mut vec![Row::new(cols, T::default()); delta]); + reversed.resize_with(self.lines.0, || Row::new(cols)); } // Pull content down to put cursor in correct position, or move cursor up if there's no @@ -211,7 +230,7 @@ impl<T: GridCell + Default + PartialEq + Copy> Grid<T> { 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()); + row.grow(cols); } new_raw.push(row); } @@ -269,11 +288,11 @@ impl<T: GridCell + Default + PartialEq + Copy> Grid<T> { // 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::LEADING_WIDE_CHAR_SPACER); - row[cols - 1] = spacer; + + let wide_char = mem::replace(&mut row[cols - 1], spacer); + wrapped.insert(0, wide_char); } // Remove wide char spacer before shrinking. @@ -330,7 +349,7 @@ impl<T: GridCell + Default + PartialEq + Copy> Grid<T> { // 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]); + wrapped.resize_with(cols.0, T::default); } row = Row::from_vec(wrapped, occ); } |