mirror of
https://github.com/wez/wezterm.git
synced 2024-12-24 13:52:55 +03:00
term: restore line length pre-allocation
A while back I made the line lengths lazily grown; the reduction in memory was nice, and it helped with render performance for really wide screens. Unfortunately, it puts a bunch of reallocation into the hot path of the parser and updating the terminal model when people run the inevitable `cat giant-file.txt` benchmark. This commit reinstates pre-allocating lines to match the physical terminal width, and tweaks the code a bit to take advantage of const Cell allocation and to avoid some clones (a really micro optimization).
This commit is contained in:
parent
9134da8c07
commit
6c2f9f2d18
@ -63,7 +63,7 @@ impl Screen {
|
||||
let mut lines =
|
||||
VecDeque::with_capacity(physical_rows + scrollback_size(config, allow_scrollback));
|
||||
for _ in 0..physical_rows {
|
||||
lines.push_back(Line::with_width(0));
|
||||
lines.push_back(Line::with_width(physical_cols));
|
||||
}
|
||||
|
||||
Screen {
|
||||
@ -215,7 +215,7 @@ impl Screen {
|
||||
// lines than the viewport size, or we resized taller,
|
||||
// pad us back out to the viewport size
|
||||
while self.lines.len() < physical_rows {
|
||||
self.lines.push_back(Line::with_width(0));
|
||||
self.lines.push_back(Line::with_width(self.physical_cols));
|
||||
}
|
||||
|
||||
let new_cursor_y;
|
||||
@ -236,7 +236,7 @@ impl Screen {
|
||||
physical_rows.saturating_sub(new_cursor_y as usize);
|
||||
let actual_num_rows_after_cursor = self.lines.len().saturating_sub(cursor_y);
|
||||
for _ in actual_num_rows_after_cursor..required_num_rows_after_cursor {
|
||||
self.lines.push_back(Line::with_width(0));
|
||||
self.lines.push_back(Line::with_width(self.physical_cols));
|
||||
}
|
||||
} else {
|
||||
// Compute the new cursor location; this is logically the inverse
|
||||
@ -595,7 +595,7 @@ impl Screen {
|
||||
for _ in 0..to_move {
|
||||
let mut line = self.lines.remove(remove_idx).unwrap();
|
||||
// Make the line like a new one of the appropriate width
|
||||
line.resize_and_clear(0, seqno);
|
||||
line.resize_and_clear(self.physical_cols, seqno);
|
||||
line.update_last_change_seqno(seqno);
|
||||
if scroll_region.end as usize == self.physical_rows {
|
||||
self.lines.push_back(line);
|
||||
@ -620,11 +620,12 @@ impl Screen {
|
||||
if scroll_region.end as usize == self.physical_rows {
|
||||
// It's cheaper to push() than it is insert() at the end
|
||||
for _ in 0..to_add {
|
||||
self.lines.push_back(Line::with_width(0));
|
||||
self.lines.push_back(Line::with_width(self.physical_cols));
|
||||
}
|
||||
} else {
|
||||
for _ in 0..to_add {
|
||||
self.lines.insert(phys_scroll.end, Line::with_width(0));
|
||||
self.lines
|
||||
.insert(phys_scroll.end, Line::with_width(self.physical_cols));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -672,7 +673,8 @@ impl Screen {
|
||||
}
|
||||
|
||||
for _ in 0..num_rows {
|
||||
self.lines.insert(phys_scroll.start, Line::with_width(0));
|
||||
self.lines
|
||||
.insert(phys_scroll.start, Line::with_width(self.physical_cols));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -59,10 +59,7 @@ impl<'a> Performer<'a> {
|
||||
let seqno = self.seqno;
|
||||
let mut p = std::mem::take(&mut self.print);
|
||||
|
||||
let mut graphemes =
|
||||
unicode_segmentation::UnicodeSegmentation::graphemes(p.as_str(), true).peekable();
|
||||
|
||||
while let Some(g) = graphemes.next() {
|
||||
for g in unicode_segmentation::UnicodeSegmentation::graphemes(p.as_str(), true) {
|
||||
let g = if (self.shift_out && self.g1_charset == CharSet::DecLineDrawing)
|
||||
|| (!self.shift_out && self.g0_charset == CharSet::DecLineDrawing)
|
||||
{
|
||||
@ -138,7 +135,6 @@ impl<'a> Performer<'a> {
|
||||
// If we didn't do this, then we'd effectively filter them out from
|
||||
// the model, which seems like a lossy design choice.
|
||||
let print_width = grapheme_column_width(g).max(1);
|
||||
let is_last = graphemes.peek().is_none();
|
||||
let wrappable = x + print_width >= width;
|
||||
|
||||
let cell = Cell::new_grapheme_with_width(g, print_width, pen);
|
||||
@ -153,10 +149,9 @@ impl<'a> Performer<'a> {
|
||||
|
||||
// Assign the cell
|
||||
log::trace!(
|
||||
"print x={} y={} is_last={} print_width={} width={} cell={:?}",
|
||||
"print x={} y={} print_width={} width={} cell={:?}",
|
||||
x,
|
||||
y,
|
||||
is_last,
|
||||
print_width,
|
||||
width,
|
||||
cell
|
||||
|
@ -34,7 +34,12 @@ fn test_irm() {
|
||||
term.print("foo");
|
||||
term.cup(0, 0);
|
||||
term.print("\x1b[4hBAR");
|
||||
assert_visible_contents(&term, file!(), line!(), &["BARfoo", "", ""]);
|
||||
assert_visible_contents(
|
||||
&term,
|
||||
file!(),
|
||||
line!(),
|
||||
&["BARfoo ", " ", " "],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -327,7 +327,18 @@ fn test_semantic() {
|
||||
));
|
||||
term.print("there");
|
||||
|
||||
assert_visible_contents(&term, file!(), line!(), &["hello", "there", "", "", ""]);
|
||||
assert_visible_contents(
|
||||
&term,
|
||||
file!(),
|
||||
line!(),
|
||||
&[
|
||||
"hello ",
|
||||
"there ",
|
||||
" ",
|
||||
" ",
|
||||
" ",
|
||||
],
|
||||
);
|
||||
|
||||
term.cup(0, 2);
|
||||
term.print(format!(
|
||||
@ -339,7 +350,13 @@ fn test_semantic() {
|
||||
&term,
|
||||
file!(),
|
||||
line!(),
|
||||
&["hello", "there", "three", "", ""],
|
||||
&[
|
||||
"hello ",
|
||||
"there ",
|
||||
"three ",
|
||||
" ",
|
||||
" ",
|
||||
],
|
||||
);
|
||||
|
||||
k9::snapshot!(
|
||||
@ -349,8 +366,8 @@ fn test_semantic() {
|
||||
SemanticZone {
|
||||
start_y: 0,
|
||||
start_x: 0,
|
||||
end_y: 2,
|
||||
end_x: 4,
|
||||
end_y: 4,
|
||||
end_x: 9,
|
||||
semantic_type: Output,
|
||||
},
|
||||
]
|
||||
@ -457,7 +474,18 @@ fn basic_output() {
|
||||
|
||||
term.set_auto_wrap(false);
|
||||
term.print("hello, world!");
|
||||
assert_visible_contents(&term, file!(), line!(), &["", " hello, w!", "", "", ""]);
|
||||
assert_visible_contents(
|
||||
&term,
|
||||
file!(),
|
||||
line!(),
|
||||
&[
|
||||
" ",
|
||||
" hello, w!",
|
||||
" ",
|
||||
" ",
|
||||
" ",
|
||||
],
|
||||
);
|
||||
|
||||
term.set_auto_wrap(true);
|
||||
term.erase_in_display(EraseInDisplay::EraseToStartOfDisplay);
|
||||
@ -467,7 +495,13 @@ fn basic_output() {
|
||||
&term,
|
||||
file!(),
|
||||
line!(),
|
||||
&[" ", " hello, wo", "rld!", "", ""],
|
||||
&[
|
||||
" ",
|
||||
" hello, wo",
|
||||
"rld! ",
|
||||
" ",
|
||||
" ",
|
||||
],
|
||||
);
|
||||
|
||||
term.erase_in_display(EraseInDisplay::EraseToStartOfDisplay);
|
||||
@ -475,7 +509,13 @@ fn basic_output() {
|
||||
&term,
|
||||
file!(),
|
||||
line!(),
|
||||
&[" ", " ", " ", "", ""],
|
||||
&[
|
||||
" ",
|
||||
" ",
|
||||
" ",
|
||||
" ",
|
||||
" ",
|
||||
],
|
||||
);
|
||||
|
||||
term.cup(0, 2);
|
||||
@ -494,7 +534,13 @@ fn basic_output() {
|
||||
&term,
|
||||
file!(),
|
||||
line!(),
|
||||
&[" ", " ", " ", "", ""],
|
||||
&[
|
||||
" ",
|
||||
" ",
|
||||
" ",
|
||||
" ",
|
||||
" ",
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
@ -553,7 +599,7 @@ fn scroll_up_within_left_and_right_margins() {
|
||||
&term,
|
||||
file!(),
|
||||
line!(),
|
||||
&[&ones, &twos, &threes, &fours, &fives],
|
||||
&["111 ", "222 ", "333 ", "44444", "555 "],
|
||||
);
|
||||
|
||||
term.set_mode("?69", true); // allow left/right margins to be set
|
||||
@ -566,8 +612,8 @@ fn scroll_up_within_left_and_right_margins() {
|
||||
file!(),
|
||||
line!(),
|
||||
&[
|
||||
&ones,
|
||||
&twos,
|
||||
"111 ",
|
||||
"222 ",
|
||||
&format!("3{}", "4".repeat(NUM_COLS + 1)),
|
||||
&format!("4{}", "5".repeat(NUM_COLS - 1)),
|
||||
&format!("5{} ", " ".repeat(NUM_COLS - 1)),
|
||||
@ -599,7 +645,7 @@ fn scroll_down_within_left_and_right_margins() {
|
||||
&term,
|
||||
file!(),
|
||||
line!(),
|
||||
&[&ones, &twos, &threes, &fours, &fives],
|
||||
&["111 ", "222 ", "333 ", "44444", "555 "],
|
||||
);
|
||||
|
||||
term.set_mode("?69", true); // allow left/right margins to be set
|
||||
@ -616,8 +662,8 @@ fn scroll_down_within_left_and_right_margins() {
|
||||
file!(),
|
||||
line!(),
|
||||
&[
|
||||
&ones,
|
||||
&twos,
|
||||
"111 ",
|
||||
"222 ",
|
||||
&format!("3{} ", " ".repeat(NUM_COLS - 1)),
|
||||
&format!("4{}", "3".repeat(NUM_COLS - 1)),
|
||||
&format!("5{}", "4".repeat(NUM_COLS + 1)),
|
||||
@ -647,7 +693,12 @@ fn test_delete_lines() {
|
||||
let seqno = term.current_seqno();
|
||||
term.assert_dirty_lines(seqno, &[], None);
|
||||
term.delete_lines(2);
|
||||
assert_visible_contents(&term, file!(), line!(), &["111", "444", "555", "", ""]);
|
||||
assert_visible_contents(
|
||||
&term,
|
||||
file!(),
|
||||
line!(),
|
||||
&["111", "444", "555", " ", " "],
|
||||
);
|
||||
term.assert_dirty_lines(seqno, &[1, 2, 3, 4], None);
|
||||
|
||||
term.cup(0, 3);
|
||||
@ -668,7 +719,12 @@ fn test_delete_lines() {
|
||||
print_all_lines(&term);
|
||||
term.delete_lines(2);
|
||||
|
||||
assert_visible_contents(&term, file!(), line!(), &["111", "aaa", "", "", "bbb"]);
|
||||
assert_visible_contents(
|
||||
&term,
|
||||
file!(),
|
||||
line!(),
|
||||
&["111", "aaa", " ", " ", "bbb"],
|
||||
);
|
||||
term.assert_dirty_lines(seqno, &[1, 2, 3], None);
|
||||
|
||||
// expand the scroll region to fill the screen
|
||||
@ -678,7 +734,12 @@ fn test_delete_lines() {
|
||||
print_all_lines(&term);
|
||||
term.delete_lines(1);
|
||||
|
||||
assert_visible_contents(&term, file!(), line!(), &["aaa", "", "", "bbb", ""]);
|
||||
assert_visible_contents(
|
||||
&term,
|
||||
file!(),
|
||||
line!(),
|
||||
&["aaa", " ", " ", "bbb", " "],
|
||||
);
|
||||
term.assert_dirty_lines(seqno, &[4], None);
|
||||
}
|
||||
|
||||
@ -692,7 +753,10 @@ fn test_dec_special_graphics() {
|
||||
&term,
|
||||
file!(),
|
||||
line!(),
|
||||
&["ABC▒␉␌␍␊°±␋┘┐┌└┼⎺⎻─⎼⎽├┤┴┬│≤≥DEF", "hello"],
|
||||
&[
|
||||
"ABC▒␉␌␍␊°±␋┘┐┌└┼⎺⎻─⎼⎽├┤┴┬│≤≥DEF ",
|
||||
"hello ",
|
||||
],
|
||||
);
|
||||
|
||||
term = TestTerm::new(2, 50, 0);
|
||||
@ -701,7 +765,10 @@ fn test_dec_special_graphics() {
|
||||
&term,
|
||||
file!(),
|
||||
line!(),
|
||||
&["SO-ABC▒␉␌␍␊°±␋┘┐┌└┼⎺⎻─⎼⎽├┤┴┬│≤≥DEF", "SI-hello"],
|
||||
&[
|
||||
"SO-ABC▒␉␌␍␊°±␋┘┐┌└┼⎺⎻─⎼⎽├┤┴┬│≤≥DEF ",
|
||||
"SI-hello ",
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
@ -715,7 +782,12 @@ fn test_dec_double_width() {
|
||||
&term,
|
||||
file!(),
|
||||
line!(),
|
||||
&["line1", "line2", "line3", "line4"],
|
||||
&[
|
||||
"line1 ",
|
||||
"line2 ",
|
||||
"line3 ",
|
||||
"line4 ",
|
||||
],
|
||||
);
|
||||
|
||||
let lines = term.screen().visible_lines();
|
||||
@ -736,7 +808,9 @@ fn test_resize_wrap() {
|
||||
&term,
|
||||
file!(),
|
||||
line!(),
|
||||
&["111", "2222", "aa", "333", "", "", "", ""],
|
||||
&[
|
||||
"111 ", "2222", "aa ", "333 ", " ", " ", " ", " ",
|
||||
],
|
||||
);
|
||||
term.resize(LINES, 5, 0, 0);
|
||||
assert_visible_contents(
|
||||
@ -750,21 +824,27 @@ fn test_resize_wrap() {
|
||||
&term,
|
||||
file!(),
|
||||
line!(),
|
||||
&["111", "2222aa", "333", "", "", "", "", ""],
|
||||
&[
|
||||
"111 ", "2222aa", "333 ", " ", " ", " ", " ", " ",
|
||||
],
|
||||
);
|
||||
term.resize(LINES, 7, 0, 0);
|
||||
assert_visible_contents(
|
||||
&term,
|
||||
file!(),
|
||||
line!(),
|
||||
&["111", "2222aa", "333", "", "", "", "", ""],
|
||||
&[
|
||||
"111 ", "2222aa", "333 ", " ", " ", " ", " ", " ",
|
||||
],
|
||||
);
|
||||
term.resize(LINES, 8, 0, 0);
|
||||
assert_visible_contents(
|
||||
&term,
|
||||
file!(),
|
||||
line!(),
|
||||
&["111", "2222aa", "333", "", "", "", "", ""],
|
||||
&[
|
||||
"111 ", "2222aa", "333 ", " ", " ", " ", " ", " ",
|
||||
],
|
||||
);
|
||||
|
||||
// Resize smaller again
|
||||
@ -773,28 +853,36 @@ fn test_resize_wrap() {
|
||||
&term,
|
||||
file!(),
|
||||
line!(),
|
||||
&["111", "2222aa", "333", "", "", "", "", ""],
|
||||
&[
|
||||
"111 ", "2222aa", "333 ", " ", " ", " ", " ", " ",
|
||||
],
|
||||
);
|
||||
term.resize(LINES, 6, 0, 0);
|
||||
assert_visible_contents(
|
||||
&term,
|
||||
file!(),
|
||||
line!(),
|
||||
&["111", "2222aa", "333", "", "", "", "", ""],
|
||||
&[
|
||||
"111 ", "2222aa", "333 ", " ", " ", " ", " ", " ",
|
||||
],
|
||||
);
|
||||
term.resize(LINES, 5, 0, 0);
|
||||
assert_visible_contents(
|
||||
&term,
|
||||
file!(),
|
||||
line!(),
|
||||
&["111", "2222a", "a", "333", "", "", "", ""],
|
||||
&[
|
||||
"111 ", "2222a", "a", "333 ", " ", " ", " ", " ",
|
||||
],
|
||||
);
|
||||
term.resize(LINES, 4, 0, 0);
|
||||
assert_visible_contents(
|
||||
&term,
|
||||
file!(),
|
||||
line!(),
|
||||
&["111", "2222", "aa", "333", "", "", "", ""],
|
||||
&[
|
||||
"111 ", "2222", "aa", "333 ", " ", " ", " ", " ",
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
@ -901,7 +989,12 @@ fn test_scroll_margins() {
|
||||
|
||||
term.cup(0, 1);
|
||||
term.print("W\n");
|
||||
assert_all_contents(&term, file!(), line!(), &["1", "2", "z", "a", "W", "", ""]);
|
||||
assert_all_contents(
|
||||
&term,
|
||||
file!(),
|
||||
line!(),
|
||||
&["1", "2", "z", "a", "W", " ", " "],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -941,7 +1034,11 @@ fn test_hyperlinks() {
|
||||
file!(),
|
||||
line!(),
|
||||
&term.screen().visible_lines(),
|
||||
&[Line::from_text("hello", &linked), "".into(), "".into()],
|
||||
&[
|
||||
Line::from_text("hello", &linked),
|
||||
" ".into(),
|
||||
" ".into(),
|
||||
],
|
||||
Compare::TEXT | Compare::ATTRS,
|
||||
);
|
||||
|
||||
|
@ -62,7 +62,7 @@ pub enum DoubleClickRange {
|
||||
impl Line {
|
||||
pub fn with_width(width: usize) -> Self {
|
||||
let mut cells = Vec::with_capacity(width);
|
||||
cells.resize(width, Cell::default());
|
||||
cells.resize_with(width, Cell::blank);
|
||||
let bits = LineBits::NONE;
|
||||
Self {
|
||||
bits,
|
||||
@ -99,16 +99,17 @@ impl Line {
|
||||
}
|
||||
|
||||
pub fn resize_and_clear(&mut self, width: usize, seqno: SequenceNo) {
|
||||
let blank = Cell::default();
|
||||
self.cells.clear();
|
||||
self.cells.resize(width, blank);
|
||||
for c in &mut self.cells {
|
||||
*c = Cell::blank();
|
||||
}
|
||||
self.cells.resize_with(width, Cell::blank);
|
||||
self.cells.shrink_to_fit();
|
||||
self.update_last_change_seqno(seqno);
|
||||
self.bits = LineBits::NONE;
|
||||
}
|
||||
|
||||
pub fn resize(&mut self, width: usize, seqno: SequenceNo) {
|
||||
self.cells.resize(width, Cell::default());
|
||||
self.cells.resize_with(width, Cell::blank);
|
||||
self.update_last_change_seqno(seqno);
|
||||
}
|
||||
|
||||
@ -116,7 +117,7 @@ impl Line {
|
||||
/// Returns the list of resultant line(s)
|
||||
pub fn wrap(mut self, width: usize, seqno: SequenceNo) -> Vec<Self> {
|
||||
if let Some(end_idx) = self.cells.iter().rposition(|c| c.str() != " ") {
|
||||
self.cells.resize(end_idx + 1, Cell::default());
|
||||
self.cells.resize_with(end_idx + 1, Cell::blank);
|
||||
|
||||
let mut lines: Vec<_> = self
|
||||
.cells
|
||||
@ -448,7 +449,7 @@ impl Line {
|
||||
|
||||
// if the line isn't wide enough, pad it out with the default attributes.
|
||||
if idx + width > self.cells.len() {
|
||||
self.cells.resize(idx + width, Cell::default());
|
||||
self.cells.resize_with(idx + width, Cell::blank);
|
||||
}
|
||||
|
||||
self.invalidate_implicit_hyperlinks(seqno);
|
||||
@ -511,7 +512,7 @@ impl Line {
|
||||
}
|
||||
|
||||
if x >= self.cells.len() {
|
||||
self.cells.resize(x, Cell::default());
|
||||
self.cells.resize_with(x, Cell::blank);
|
||||
}
|
||||
|
||||
// If we're inserting a wide cell, we should also insert the overlapped cells.
|
||||
@ -557,7 +558,7 @@ impl Line {
|
||||
.iter()
|
||||
.rposition(|c| c.str() != " " || c.attrs() != &def_attr)
|
||||
{
|
||||
self.cells.resize(end_idx + 1, Cell::default());
|
||||
self.cells.resize_with(end_idx + 1, Cell::blank);
|
||||
self.update_last_change_seqno(seqno);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user