1
0
Fork 0
mirror of https://github.com/alacritty/alacritty.git synced 2024-11-25 14:05:41 -05:00

Fix performance issues with text reflow

Fixes #2567.
Fixes #2414.
This commit is contained in:
Christian Duerr 2019-06-23 23:29:01 +00:00 committed by GitHub
parent 743d5d9c66
commit f002171c84
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 617 additions and 724 deletions

View file

@ -14,6 +14,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- GUI programs launched by Alacritty starting in the background on X11 - GUI programs launched by Alacritty starting in the background on X11
- Text Cursor position when scrolling - Text Cursor position when scrolling
- Performance issues while resizing Alacritty
## 0.3.3 ## 0.3.3

38
Cargo.lock generated
View file

@ -64,8 +64,8 @@ dependencies = [
"notify 4.0.12 (registry+https://github.com/rust-lang/crates.io-index)", "notify 4.0.12 (registry+https://github.com/rust-lang/crates.io-index)",
"objc 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", "objc 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
"parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.93 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.93 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_yaml 0.8.9 (registry+https://github.com/rust-lang/crates.io-index)", "serde_yaml 0.8.9 (registry+https://github.com/rust-lang/crates.io-index)",
"signal-hook 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", "signal-hook 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
@ -465,7 +465,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 0.15.36 (registry+https://github.com/rust-lang/crates.io-index)", "syn 0.15.37 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
@ -508,8 +508,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.93 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.93 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
@ -586,7 +586,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 0.15.36 (registry+https://github.com/rust-lang/crates.io-index)", "syn 0.15.37 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
@ -614,7 +614,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 0.15.36 (registry+https://github.com/rust-lang/crates.io-index)", "syn 0.15.37 (registry+https://github.com/rust-lang/crates.io-index)",
"synstructure 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)", "synstructure 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
@ -674,7 +674,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 0.15.36 (registry+https://github.com/rust-lang/crates.io-index)", "syn 0.15.37 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
@ -1248,7 +1248,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 0.15.36 (registry+https://github.com/rust-lang/crates.io-index)", "syn 0.15.37 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
@ -1786,17 +1786,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "serde" name = "serde"
version = "1.0.92" version = "1.0.93"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "serde_derive" name = "serde_derive"
version = "1.0.92" version = "1.0.93"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 0.15.36 (registry+https://github.com/rust-lang/crates.io-index)", "syn 0.15.37 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
@ -1806,7 +1806,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
"ryu 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "ryu 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.93 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
@ -1816,7 +1816,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"dtoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", "dtoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
"linked-hash-map 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", "linked-hash-map 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.93 (registry+https://github.com/rust-lang/crates.io-index)",
"yaml-rust 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "yaml-rust 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
@ -1971,7 +1971,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "syn" name = "syn"
version = "0.15.36" version = "0.15.37"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1986,7 +1986,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 0.15.36 (registry+https://github.com/rust-lang/crates.io-index)", "syn 0.15.37 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
@ -2671,8 +2671,8 @@ dependencies = [
"checksum security-framework-sys 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9636f8989cbf61385ae4824b98c1aaa54c994d7d8b41f11c601ed799f0549a56" "checksum security-framework-sys 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9636f8989cbf61385ae4824b98c1aaa54c994d7d8b41f11c601ed799f0549a56"
"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" "checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" "checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
"checksum serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)" = "32746bf0f26eab52f06af0d0aa1984f641341d06d8d673c693871da2d188c9be" "checksum serde 1.0.93 (registry+https://github.com/rust-lang/crates.io-index)" = "960e29cf7004b3b6e65fc5002981400eb3ccc017a08a2406940823e58e7179a9"
"checksum serde_derive 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)" = "46a3223d0c9ba936b61c0d2e3e559e3217dbfb8d65d06d26e8b3c25de38bae3e" "checksum serde_derive 1.0.93 (registry+https://github.com/rust-lang/crates.io-index)" = "c4cce6663696bd38272e90bf34a0267e1226156c33f52d3f3915a2dd5d802085"
"checksum serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)" = "5a23aa71d4a4d43fdbfaac00eff68ba8a06a51759a89ac3304323e800c4dd40d" "checksum serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)" = "5a23aa71d4a4d43fdbfaac00eff68ba8a06a51759a89ac3304323e800c4dd40d"
"checksum serde_yaml 0.8.9 (registry+https://github.com/rust-lang/crates.io-index)" = "38b08a9a90e5260fe01c6480ec7c811606df6d3a660415808c3c3fa8ed95b582" "checksum serde_yaml 0.8.9 (registry+https://github.com/rust-lang/crates.io-index)" = "38b08a9a90e5260fe01c6480ec7c811606df6d3a660415808c3c3fa8ed95b582"
"checksum servo-fontconfig 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a088f8d775a5c5314aae09bd77340bc9c67d72b9a45258be34c83548b4814cd9" "checksum servo-fontconfig 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a088f8d775a5c5314aae09bd77340bc9c67d72b9a45258be34c83548b4814cd9"
@ -2692,7 +2692,7 @@ dependencies = [
"checksum static_assertions 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "b4f8de36da215253eb5f24020bfaa0646613b48bf7ebe36cdfa37c3b3b33b241" "checksum static_assertions 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "b4f8de36da215253eb5f24020bfaa0646613b48bf7ebe36cdfa37c3b3b33b241"
"checksum stb_truetype 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "69b7df505db8e81d54ff8be4693421e5b543e08214bd8d99eb761fcb4d5668ba" "checksum stb_truetype 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "69b7df505db8e81d54ff8be4693421e5b543e08214bd8d99eb761fcb4d5668ba"
"checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" "checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
"checksum syn 0.15.36 (registry+https://github.com/rust-lang/crates.io-index)" = "8b4f551a91e2e3848aeef8751d0d4eec9489b6474c720fd4c55958d8d31a430c" "checksum syn 0.15.37 (registry+https://github.com/rust-lang/crates.io-index)" = "e11410033fd5cf69a1cf2084604e011190c56f11e08ffc53df880f5f65f1c6e4"
"checksum synstructure 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "02353edf96d6e4dc81aea2d8490a7e9db177bf8acb0e951c24940bf866cb313f" "checksum synstructure 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "02353edf96d6e4dc81aea2d8490a7e9db177bf8acb0e951c24940bf866cb313f"
"checksum tempfile 3.0.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7dc4738f2e68ed2855de5ac9cdbe05c9216773ecde4739b2f095002ab03a13ef" "checksum tempfile 3.0.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7dc4738f2e68ed2855de5ac9cdbe05c9216773ecde4739b2f095002ab03a13ef"
"checksum termcolor 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "96d6098003bde162e4277c70665bd87c326f5a0c3f3fbfb285787fa482d54e6e" "checksum termcolor 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "96d6098003bde162e4277c70665bd87c326f5a0c3f3fbfb285787fa482d54e6e"

View file

@ -189,6 +189,7 @@ impl<T: GridCell + Copy + Clone> Grid<T> {
pub fn resize( pub fn resize(
&mut self, &mut self,
reflow: bool,
lines: index::Line, lines: index::Line,
cols: index::Column, cols: index::Column,
cursor_pos: &mut Point, cursor_pos: &mut Point,
@ -206,8 +207,8 @@ impl<T: GridCell + Copy + Clone> Grid<T> {
} }
match self.cols.cmp(&cols) { match self.cols.cmp(&cols) {
Ordering::Less => self.grow_cols(cols, cursor_pos, template), Ordering::Less => self.grow_cols(reflow, cols, cursor_pos, template),
Ordering::Greater => self.shrink_cols(cols, template), Ordering::Greater => self.shrink_cols(reflow, cols, template),
Ordering::Equal => (), Ordering::Equal => (),
} }
} }
@ -252,93 +253,107 @@ impl<T: GridCell + Copy + Clone> Grid<T> {
self.display_offset = self.display_offset.saturating_sub(*lines_added); self.display_offset = self.display_offset.saturating_sub(*lines_added);
} }
fn grow_cols(&mut self, cols: index::Column, cursor_pos: &mut Point, template: &T) { fn grow_cols(
// Truncate all buffered lines &mut self,
self.raw.grow_hidden(cols, template); reflow: bool,
cols: index::Column,
let max_lines = self.lines.0 + self.max_scroll_limit; cursor_pos: &mut Point,
template: &T,
// Iterate backwards with indices for mutation during iteration ) {
let mut i = self.raw.len(); let mut new_empty_lines = 0;
while i > 0 { let mut new_raw: Vec<Row<T>> = Vec::with_capacity(self.raw.len());
i -= 1; for (i, mut row) in self.raw.drain().enumerate().rev() {
if let Some(last_row) = new_raw.last_mut() {
// Grow the current line if there's wrapped content available // Grow the current line if there's wrapped content available
while i >= 1 if reflow
&& self.raw[i].len() < cols.0 && last_row.len() < cols.0
&& self.raw[i].last().map(GridCell::is_wrap) == Some(true) && last_row.last().map(GridCell::is_wrap) == Some(true)
{ {
// Remove wrap flag before appending additional cells // Remove wrap flag before appending additional cells
if let Some(cell) = self.raw[i].last_mut() { if let Some(cell) = last_row.last_mut() {
cell.set_wrap(false); cell.set_wrap(false);
} }
// Append as many cells from the next line as possible // Append as many cells from the next line as possible
let len = min(self.raw[i - 1].len(), cols.0 - self.raw[i].len()); let len = min(row.len(), cols.0 - last_row.len());
let mut cells = self.raw[i - 1].front_split_off(len); let mut cells = row.front_split_off(len);
self.raw[i].append(&mut cells); last_row.append(&mut cells);
if self.raw[i - 1].is_empty() { if row.is_empty() {
// Remove following line if all cells have been drained let raw_len = i + 1 + new_raw.len();;
self.raw.remove(i - 1); if raw_len < self.lines.0 || self.scroll_limit == 0 {
if self.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
self.raw.insert(0, Row::new(cols, template), max_lines);
cursor_pos.line = Line(cursor_pos.line.saturating_sub(1)); cursor_pos.line = Line(cursor_pos.line.saturating_sub(1));
new_empty_lines += 1;
} else { } else {
// Make sure viewport doesn't move if line is outside of the visible area // Make sure viewport doesn't move if line is outside of the visible
// area
if i < self.display_offset { if i < self.display_offset {
self.display_offset = self.display_offset.saturating_sub(1); self.display_offset = self.display_offset.saturating_sub(1);
} }
// Remove one line from scrollback, since we just moved it to the viewport // Remove one line from scrollback, since we just moved it to the
// viewport
self.scroll_limit = self.scroll_limit.saturating_sub(1); self.scroll_limit = self.scroll_limit.saturating_sub(1);
self.display_offset = min(self.display_offset, self.scroll_limit); self.display_offset = min(self.display_offset, self.scroll_limit);
i -= 1;
} }
} else if let Some(cell) = self.raw[i].last_mut() {
// 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 // Set wrap flag if next line still has cells
cell.set_wrap(true); cell.set_wrap(true);
} }
} }
}
// Fill remaining cells new_raw.push(row);
if self.raw[i].len() < cols.0 {
self.raw[i].grow(cols, template);
} }
// Add padding lines
new_raw.append(&mut vec![Row::new(cols, template); new_empty_lines]);
// Fill remaining cells and reverse iterator
let mut reversed = Vec::with_capacity(new_raw.len());
for mut row in new_raw.drain(..).rev() {
if row.len() < cols.0 {
row.grow(cols, template);
} }
reversed.push(row);
}
self.raw.replace_inner(reversed);
self.cols = cols; self.cols = cols;
} }
fn shrink_cols(&mut self, cols: index::Column, template: &T) { fn shrink_cols(&mut self, reflow: bool, cols: index::Column, template: &T) {
// Truncate all buffered lines let mut new_raw = Vec::with_capacity(self.raw.len());
self.raw.shrink_hidden(cols); let mut buffered = None;
for (i, mut row) in self.raw.drain().enumerate().rev() {
if let Some(buffered) = buffered.take() {
row.append_front(buffered);
}
let max_lines = self.lines.0 + self.max_scroll_limit; let mut wrapped = row.shrink(cols);
new_raw.push(row);
// Iterate backwards with indices for mutation during iteration while let (Some(mut wrapped_cells), true) = (wrapped.take(), reflow) {
let mut i = self.raw.len();
while i > 0 {
i -= 1;
if let Some(mut new_row) = self.raw[i].shrink(cols) {
// Set line as wrapped if cells got removed // Set line as wrapped if cells got removed
if let Some(cell) = self.raw[i].last_mut() { if let Some(cell) = new_raw.last_mut().and_then(|r| r.last_mut()) {
cell.set_wrap(true); cell.set_wrap(true);
} }
if Some(true) == new_row.last().map(|c| c.is_wrap() && i >= 1) if Some(true) == wrapped_cells.last().map(|c| c.is_wrap() && i >= 1)
&& new_row.len() < cols.0 && wrapped_cells.len() < cols.0
{ {
// Make sure previous wrap flag doesn't linger around // Make sure previous wrap flag doesn't linger around
if let Some(cell) = new_row.last_mut() { if let Some(cell) = wrapped_cells.last_mut() {
cell.set_wrap(false); cell.set_wrap(false);
} }
// Add removed cells to start of next row // Add removed cells to start of next row
self.raw[i - 1].append_front(new_row); buffered = Some(wrapped_cells);
} else { } else {
// Make sure viewport doesn't move if line is outside of the visible area // Make sure viewport doesn't move if line is outside of the visible area
if i < self.display_offset { if i < self.display_offset {
@ -346,24 +361,27 @@ impl<T: GridCell + Copy + Clone> Grid<T> {
} }
// Make sure new row is at least as long as new width // Make sure new row is at least as long as new width
let occ = new_row.len(); let occ = wrapped_cells.len();
if occ < cols.0 { if occ < cols.0 {
new_row.append(&mut vec![*template; cols.0 - occ]); wrapped_cells.append(&mut vec![*template; cols.0 - occ]);
} }
let row = Row::from_vec(new_row, occ); let mut row = Row::from_vec(wrapped_cells, occ);
// Since inserted might exceed cols, we need to check it again
wrapped = row.shrink(cols);
// Add new row with all removed cells // Add new row with all removed cells
self.raw.insert(i, row, max_lines); new_raw.push(row);
// Increase scrollback history // Increase scrollback history
self.scroll_limit = min(self.scroll_limit + 1, self.max_scroll_limit); self.scroll_limit = min(self.scroll_limit + 1, self.max_scroll_limit);
// Since inserted might exceed cols, we need to check the same line again
i += 1;
} }
} }
} }
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; self.cols = cols;
} }

View file

@ -12,12 +12,12 @@
/// implementation is provided. Anything from Vec that should be exposed must be /// implementation is provided. Anything from Vec that should be exposed must be
/// done so manually. /// done so manually.
use std::ops::{Index, IndexMut}; use std::ops::{Index, IndexMut};
use std::vec::Drain;
use static_assertions::assert_eq_size; use static_assertions::assert_eq_size;
use super::Row; use super::Row;
use crate::grid::GridCell; use crate::index::Line;
use crate::index::{Column, Line};
/// Maximum number of invisible lines before buffer is resized /// Maximum number of invisible lines before buffer is resized
const TRUNCATE_STEP: usize = 100; const TRUNCATE_STEP: usize = 100;
@ -258,69 +258,16 @@ impl<T> Storage<T> {
self.zero = (self.zero + count) % self.inner.len(); self.zero = (self.zero + count) % self.inner.len();
} }
#[inline] pub fn drain(&mut self) -> Drain<'_, Row<T>> {
pub fn insert(&mut self, index: usize, row: Row<T>, max_lines: usize) { self.truncate();
let index = self.compute_index(index); self.inner.drain(..)
self.inner.insert(index, row);
if index < self.zero {
self.zero += 1;
} }
if self.len < max_lines { /// Update the raw storage buffer
self.len += 1; pub fn replace_inner(&mut self, vec: Vec<Row<T>>) {
} self.len = vec.len();
} self.inner = vec;
self.zero = 0;
#[inline]
pub fn remove(&mut self, index: usize) -> Row<T> {
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);
}
} }
} }
@ -359,6 +306,12 @@ impl<T> IndexMut<Line> for Storage<T> {
} }
} }
#[cfg(test)]
mod test {
use crate::grid::row::Row;
use crate::grid::storage::Storage;
use crate::index::{Column, Line};
/// Grow the buffer one line at the end of the buffer /// Grow the buffer one line at the end of the buffer
/// ///
/// Before: /// Before:
@ -800,123 +753,4 @@ fn initialize() {
assert_eq!(storage.zero, shrinking_expected.zero); assert_eq!(storage.zero, shrinking_expected.zero);
assert_eq!(storage.len, shrinking_expected.len); assert_eq!(storage.len, shrinking_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);
}
#[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);
}
#[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);
} }

View file

@ -140,7 +140,7 @@ fn shrink_reflow() {
grid[Line(0)][Column(3)] = cell('4'); grid[Line(0)][Column(3)] = cell('4');
grid[Line(0)][Column(4)] = cell('5'); grid[Line(0)][Column(4)] = cell('5');
grid.resize(Line(1), Column(2), &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());
assert_eq!(grid.len(), 3); assert_eq!(grid.len(), 3);
@ -166,8 +166,8 @@ fn shrink_reflow_twice() {
grid[Line(0)][Column(3)] = cell('4'); grid[Line(0)][Column(3)] = cell('4');
grid[Line(0)][Column(4)] = cell('5'); grid[Line(0)][Column(4)] = cell('5');
grid.resize(Line(1), Column(4), &mut Point::new(Line(0), Column(0)), &Cell::default()); grid.resize(true, Line(1), Column(4), &mut Point::new(Line(0), Column(0)), &Cell::default());
grid.resize(Line(1), Column(2), &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());
assert_eq!(grid.len(), 3); assert_eq!(grid.len(), 3);
@ -193,7 +193,7 @@ fn shrink_reflow_empty_cell_inside_line() {
grid[Line(0)][Column(3)] = cell('4'); grid[Line(0)][Column(3)] = cell('4');
grid[Line(0)][Column(4)] = Cell::default(); grid[Line(0)][Column(4)] = Cell::default();
grid.resize(Line(1), Column(2), &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());
assert_eq!(grid.len(), 2); assert_eq!(grid.len(), 2);
@ -205,7 +205,7 @@ fn shrink_reflow_empty_cell_inside_line() {
assert_eq!(grid[0][Column(0)], cell('3')); assert_eq!(grid[0][Column(0)], cell('3'));
assert_eq!(grid[0][Column(1)], cell('4')); assert_eq!(grid[0][Column(1)], cell('4'));
grid.resize(Line(1), Column(1), &mut Point::new(Line(0), Column(0)), &Cell::default()); grid.resize(true, Line(1), Column(1), &mut Point::new(Line(0), Column(0)), &Cell::default());
assert_eq!(grid.len(), 4); assert_eq!(grid.len(), 4);
@ -230,7 +230,7 @@ fn grow_reflow() {
grid[Line(1)][Column(0)] = cell('3'); grid[Line(1)][Column(0)] = cell('3');
grid[Line(1)][Column(1)] = Cell::default(); grid[Line(1)][Column(1)] = Cell::default();
grid.resize(Line(2), Column(3), &mut Point::new(Line(0), Column(0)), &Cell::default()); grid.resize(true, Line(2), Column(3), &mut Point::new(Line(0), Column(0)), &Cell::default());
assert_eq!(grid.len(), 2); assert_eq!(grid.len(), 2);
@ -256,7 +256,7 @@ fn grow_reflow_multiline() {
grid[Line(2)][Column(0)] = cell('5'); grid[Line(2)][Column(0)] = cell('5');
grid[Line(2)][Column(1)] = cell('6'); grid[Line(2)][Column(1)] = cell('6');
grid.resize(Line(3), Column(6), &mut Point::new(Line(0), Column(0)), &Cell::default()); grid.resize(true, Line(3), Column(6), &mut Point::new(Line(0), Column(0)), &Cell::default());
assert_eq!(grid.len(), 3); assert_eq!(grid.len(), 3);
@ -279,6 +279,47 @@ fn grow_reflow_multiline() {
} }
} }
#[test]
fn grow_reflow_disabled() {
let mut grid = Grid::new(Line(2), Column(2), 0, cell('x'));
grid[Line(0)][Column(0)] = cell('1');
grid[Line(0)][Column(1)] = wrap_cell('2');
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());
assert_eq!(grid.len(), 2);
assert_eq!(grid[1].len(), 3);
assert_eq!(grid[1][Column(0)], cell('1'));
assert_eq!(grid[1][Column(1)], wrap_cell('2'));
assert_eq!(grid[1][Column(2)], Cell::default());
assert_eq!(grid[0].len(), 3);
assert_eq!(grid[0][Column(0)], cell('3'));
assert_eq!(grid[0][Column(1)], Cell::default());
assert_eq!(grid[0][Column(2)], Cell::default());
}
#[test]
fn shrink_reflow_disabled() {
let mut grid = Grid::new(Line(1), Column(5), 2, cell('x'));
grid[Line(0)][Column(0)] = cell('1');
grid[Line(0)][Column(1)] = cell('2');
grid[Line(0)][Column(2)] = cell('3');
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());
assert_eq!(grid.len(), 1);
assert_eq!(grid[0].len(), 2);
assert_eq!(grid[0][Column(0)], cell('1'));
assert_eq!(grid[0][Column(1)], cell('2'));
}
fn cell(c: char) -> Cell { fn cell(c: char) -> Cell {
let mut cell = Cell::default(); let mut cell = Cell::default();
cell.c = c; cell.c = c;

View file

@ -1228,13 +1228,11 @@ impl Term {
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);
// Resize grids to new size // Resize grids to new size
let alt_cursor_point = if self.mode.contains(TermMode::ALT_SCREEN) { let is_alt = self.mode.contains(TermMode::ALT_SCREEN);
&mut self.cursor_save.point let alt_cursor_point =
} else { if is_alt { &mut self.cursor_save.point } else { &mut self.cursor_save_alt.point };
&mut self.cursor_save_alt.point self.grid.resize(!is_alt, num_lines, num_cols, &mut self.cursor.point, &Cell::default());
}; self.alt_grid.resize(is_alt, num_lines, num_cols, alt_cursor_point, &Cell::default());
self.grid.resize(num_lines, num_cols, &mut self.cursor.point, &Cell::default());
self.alt_grid.resize(num_lines, num_cols, alt_cursor_point, &Cell::default());
// Reset scrolling region to new size // Reset scrolling region to new size
self.scroll_region = Line(0)..self.grid.num_lines(); self.scroll_region = Line(0)..self.grid.num_lines();

View file

@ -2,6 +2,7 @@ extern crate copypasta;
#[cfg(target_os = "linux")] #[cfg(target_os = "linux")]
use copypasta::x11_clipboard::{Primary, X11ClipboardContext}; use copypasta::x11_clipboard::{Primary, X11ClipboardContext};
#[cfg(target_os = "linux")]
use copypasta::ClipboardProvider; use copypasta::ClipboardProvider;
#[cfg(target_os = "linux")] #[cfg(target_os = "linux")]