1
1
mirror of https://github.com/wez/wezterm.git synced 2024-12-23 21:32:13 +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:
Wez Furlong 2021-08-11 21:43:14 -07:00
parent 9134da8c07
commit 6c2f9f2d18
6 changed files with 207 additions and 107 deletions

View File

@ -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));
}
}

View File

@ -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

View File

@ -7,12 +7,12 @@ fn test_ind() {
let mut term = TestTerm::new(4, 4, 0);
term.print("a\r\nb\x1bD");
term.assert_cursor_pos(1, 2, None, None);
assert_visible_contents(&term, file!(), line!(), &["a", "b", "", ""]);
assert_visible_contents(&term, file!(), line!(), &["a ", "b ", " ", " "]);
term.print("\x1bD");
term.assert_cursor_pos(1, 3, None, None);
term.print("\x1bD");
term.assert_cursor_pos(1, 3, None, Some(term.current_seqno() - 1));
assert_visible_contents(&term, file!(), line!(), &["b", "", "", ""]);
assert_visible_contents(&term, file!(), line!(), &["b ", " ", " ", " "]);
}
#[test]
@ -24,7 +24,7 @@ fn test_nel() {
term.assert_cursor_pos(0, 3, None, None);
term.print("\x1bE");
term.assert_cursor_pos(0, 3, None, None);
assert_visible_contents(&term, file!(), line!(), &["b", "", "", ""]);
assert_visible_contents(&term, file!(), line!(), &["b ", " ", " ", " "]);
}
#[test]
@ -57,7 +57,7 @@ fn test_hts() {
fn test_ri() {
let mut term = TestTerm::new(4, 2, 0);
term.print("a\r\nb\r\nc\r\nd.");
assert_visible_contents(&term, file!(), line!(), &["a", "b", "c", "d."]);
assert_visible_contents(&term, file!(), line!(), &["a ", "b ", "c ", "d."]);
term.assert_cursor_pos(1, 3, None, None);
term.print("\x1bM");
term.assert_cursor_pos(1, 2, None, None);
@ -68,5 +68,5 @@ fn test_ri() {
let seqno = term.current_seqno();
term.print("\x1bM");
term.assert_cursor_pos(1, 0, None, Some(seqno));
assert_visible_contents(&term, file!(), line!(), &["", "a", "b", "c"]);
assert_visible_contents(&term, file!(), line!(), &[" ", "a ", "b ", "c "]);
}

View File

@ -25,7 +25,7 @@ fn test_rep() {
term.print("h");
term.cup(1, 0);
term.print("\x1b[2ba");
assert_visible_contents(&term, file!(), line!(), &["hhha", "", ""]);
assert_visible_contents(&term, file!(), line!(), &["hhha", " ", " "]);
}
#[test]
@ -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]
@ -43,12 +48,12 @@ fn test_ich() {
term.print("hey!wat?");
term.cup(1, 0);
term.print("\x1b[2@");
assert_visible_contents(&term, file!(), line!(), &["h e", "wat?", ""]);
assert_visible_contents(&term, file!(), line!(), &["h e", "wat?", " "]);
// check how we handle overflowing the width
term.print("\x1b[12@");
assert_visible_contents(&term, file!(), line!(), &["h ", "wat?", ""]);
assert_visible_contents(&term, file!(), line!(), &["h ", "wat?", " "]);
term.print("\x1b[-12@");
assert_visible_contents(&term, file!(), line!(), &["h ", "wat?", ""]);
assert_visible_contents(&term, file!(), line!(), &["h ", "wat?", " "]);
}
#[test]
@ -57,12 +62,12 @@ fn test_ech() {
term.print("hey!wat?");
term.cup(1, 0);
term.print("\x1b[2X");
assert_visible_contents(&term, file!(), line!(), &["h !", "wat?", ""]);
assert_visible_contents(&term, file!(), line!(), &["h !", "wat?", " "]);
// check how we handle overflowing the width
term.print("\x1b[12X");
assert_visible_contents(&term, file!(), line!(), &["h ", "wat?", ""]);
assert_visible_contents(&term, file!(), line!(), &["h ", "wat?", " "]);
term.print("\x1b[-12X");
assert_visible_contents(&term, file!(), line!(), &["h ", "wat?", ""]);
assert_visible_contents(&term, file!(), line!(), &["h ", "wat?", " "]);
}
#[test]
@ -71,14 +76,14 @@ fn test_dch() {
term.print("hello world");
term.cup(1, 0);
term.print("\x1b[P");
assert_visible_contents(&term, file!(), line!(), &["hllo world"]);
assert_visible_contents(&term, file!(), line!(), &["hllo world "]);
term.cup(4, 0);
term.print("\x1b[2P");
assert_visible_contents(&term, file!(), line!(), &["hlloorld"]);
assert_visible_contents(&term, file!(), line!(), &["hlloorld "]);
term.print("\x1b[-2P");
assert_visible_contents(&term, file!(), line!(), &["hlloorld"]);
assert_visible_contents(&term, file!(), line!(), &["hlloorld "]);
}
#[test]
@ -118,11 +123,11 @@ fn test_dl() {
term.cup(0, 1);
let seqno = term.current_seqno();
term.delete_lines(1);
assert_visible_contents(&term, file!(), line!(), &["a", "c", ""]);
assert_visible_contents(&term, file!(), line!(), &["a", "c", " "]);
term.assert_cursor_pos(0, 1, None, Some(seqno));
term.cup(0, 0);
term.delete_lines(2);
assert_visible_contents(&term, file!(), line!(), &["", "", ""]);
assert_visible_contents(&term, file!(), line!(), &[" ", " ", " "]);
term.print("1\r\n2\r\n3");
term.cup(0, 1);
term.delete_lines(-2);
@ -185,7 +190,7 @@ fn test_ed() {
fn test_ed_erase_scrollback() {
let mut term = TestTerm::new(3, 3, 3);
term.print("abc\r\ndef\r\nghi\r\n111\r\n222\r\na\x1b[3J");
assert_all_contents(&term, file!(), line!(), &["111", "222", "a"]);
assert_all_contents(&term, file!(), line!(), &["111", "222", "a "]);
term.print("b");
assert_all_contents(&term, file!(), line!(), &["111", "222", "ab"]);
assert_all_contents(&term, file!(), line!(), &["111", "222", "ab "]);
}

View File

@ -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,
},
]
@ -386,7 +403,7 @@ fn test_semantic() {
let mut input = CellAttributes::default();
input.set_semantic_type(SemanticType::Input);
let mut prompt_line = Line::from_text("> ls -l", &output);
let mut prompt_line = Line::from_text("> ls -l ", &output);
for i in 0..2 {
prompt_line.cells_mut()[i]
.attrs_mut()
@ -439,11 +456,11 @@ fn test_semantic() {
line!(),
&term.screen().visible_lines(),
&[
Line::from_text("hello", &output),
Line::from_text("there", &output),
Line::from_text("three", &output),
Line::from_text("hello ", &output),
Line::from_text("there ", &output),
Line::from_text("three ", &output),
prompt_line,
Line::from_text("some file", &output),
Line::from_text("some file ", &output),
],
Compare::TEXT | Compare::ATTRS,
);
@ -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);
@ -486,7 +526,7 @@ fn basic_output() {
&term,
file!(),
line!(),
&[" ", " ", "wo", "", ""],
&[" ", " ", "wo", " ", " "],
);
term.erase_in_line(EraseInLine::EraseToStartOfLine);
@ -494,7 +534,13 @@ fn basic_output() {
&term,
file!(),
line!(),
&[" ", " ", " ", "", ""],
&[
" ",
" ",
" ",
" ",
" ",
],
);
}
@ -506,7 +552,7 @@ fn cursor_movement_damage() {
let seqno = term.current_seqno();
term.print("fooo.");
assert_visible_contents(&term, file!(), line!(), &["foo", "o."]);
assert_visible_contents(&term, file!(), line!(), &["foo", "o. "]);
term.assert_cursor_pos(2, 1, None, None);
term.assert_dirty_lines(seqno, &[0, 1], None);
@ -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,11 +612,11 @@ 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)),
&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,9 +662,9 @@ fn scroll_down_within_left_and_right_margins() {
file!(),
line!(),
&[
&ones,
&twos,
&format!("3{}", " ".repeat(NUM_COLS - 1)),
"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,35 +808,43 @@ fn test_resize_wrap() {
&term,
file!(),
line!(),
&["111", "2222", "aa", "333", "", "", "", ""],
&[
"111 ", "2222", "aa ", "333 ", " ", " ", " ", " ",
],
);
term.resize(LINES, 5, 0, 0);
assert_visible_contents(
&term,
file!(),
line!(),
&["111", "2222a", "a", "333", "", "", "", ""],
&["111 ", "2222a", "a", "333 ", " ", " ", " ", " "],
);
term.resize(LINES, 6, 0, 0);
assert_visible_contents(
&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 ", " ", " ", " ", " ",
],
);
}
@ -803,9 +891,9 @@ fn test_resize_wrap_issue_971() {
const LINES: usize = 4;
let mut term = TestTerm::new(LINES, 4, 0);
term.print("====\r\nSS\r\n");
assert_visible_contents(&term, file!(), line!(), &["====", "SS", "", ""]);
assert_visible_contents(&term, file!(), line!(), &["====", "SS ", " ", " "]);
term.resize(LINES, 6, 0, 0);
assert_visible_contents(&term, file!(), line!(), &["====", "SS", "", ""]);
assert_visible_contents(&term, file!(), line!(), &["====", "SS ", " ", " "]);
}
#[test]
@ -813,9 +901,9 @@ fn test_resize_wrap_sgc_issue_978() {
const LINES: usize = 4;
let mut term = TestTerm::new(LINES, 4, 0);
term.print("\u{1b}(0qqqq\u{1b}(B\r\nSS\r\n");
assert_visible_contents(&term, file!(), line!(), &["────", "SS", "", ""]);
assert_visible_contents(&term, file!(), line!(), &["────", "SS ", " ", " "]);
term.resize(LINES, 6, 0, 0);
assert_visible_contents(&term, file!(), line!(), &["────", "SS", "", ""]);
assert_visible_contents(&term, file!(), line!(), &["────", "SS ", " ", " "]);
}
#[test]
@ -823,9 +911,9 @@ fn test_resize_wrap_dectcm_issue_978() {
const LINES: usize = 4;
let mut term = TestTerm::new(LINES, 4, 0);
term.print("\u{1b}[?25l====\u{1b}[?25h\r\nSS\r\n");
assert_visible_contents(&term, file!(), line!(), &["====", "SS", "", ""]);
assert_visible_contents(&term, file!(), line!(), &["====", "SS ", " ", " "]);
term.resize(LINES, 6, 0, 0);
assert_visible_contents(&term, file!(), line!(), &["====", "SS", "", ""]);
assert_visible_contents(&term, file!(), line!(), &["====", "SS ", " ", " "]);
}
#[test]
@ -833,44 +921,44 @@ fn test_resize_wrap_escape_code_issue_978() {
const LINES: usize = 4;
let mut term = TestTerm::new(LINES, 4, 0);
term.print("====\u{1b}[0m\r\nSS\r\n");
assert_visible_contents(&term, file!(), line!(), &["====", "SS", "", ""]);
assert_visible_contents(&term, file!(), line!(), &["====", "SS ", " ", " "]);
term.resize(LINES, 6, 0, 0);
assert_visible_contents(&term, file!(), line!(), &["====", "SS", "", ""]);
assert_visible_contents(&term, file!(), line!(), &["====", "SS ", " ", " "]);
}
#[test]
fn test_scrollup() {
let mut term = TestTerm::new(2, 1, 4);
term.print("1\n");
assert_all_contents(&term, file!(), line!(), &["1", ""]);
assert_all_contents(&term, file!(), line!(), &["1", " "]);
assert_eq!(term.screen().visible_row_to_stable_row(0), 0);
term.print("2\n");
assert_all_contents(&term, file!(), line!(), &["1", "2", ""]);
assert_all_contents(&term, file!(), line!(), &["1", "2", " "]);
assert_eq!(term.screen().visible_row_to_stable_row(0), 1);
term.print("3\n");
assert_all_contents(&term, file!(), line!(), &["1", "2", "3", ""]);
assert_all_contents(&term, file!(), line!(), &["1", "2", "3", " "]);
assert_eq!(term.screen().visible_row_to_stable_row(0), 2);
term.print("4\n");
assert_all_contents(&term, file!(), line!(), &["1", "2", "3", "4", ""]);
assert_all_contents(&term, file!(), line!(), &["1", "2", "3", "4", " "]);
assert_eq!(term.screen().visible_row_to_stable_row(0), 3);
term.print("5\n");
assert_all_contents(&term, file!(), line!(), &["1", "2", "3", "4", "5", ""]);
assert_all_contents(&term, file!(), line!(), &["1", "2", "3", "4", "5", " "]);
assert_eq!(term.screen().visible_row_to_stable_row(0), 4);
term.print("6\n");
assert_all_contents(&term, file!(), line!(), &["2", "3", "4", "5", "6", ""]);
assert_all_contents(&term, file!(), line!(), &["2", "3", "4", "5", "6", " "]);
assert_eq!(term.screen().visible_row_to_stable_row(0), 5);
term.print("7\n");
assert_all_contents(&term, file!(), line!(), &["3", "4", "5", "6", "7", ""]);
assert_all_contents(&term, file!(), line!(), &["3", "4", "5", "6", "7", " "]);
assert_eq!(term.screen().visible_row_to_stable_row(0), 6);
term.print("8\n");
assert_all_contents(&term, file!(), line!(), &["4", "5", "6", "7", "8", ""]);
assert_all_contents(&term, file!(), line!(), &["4", "5", "6", "7", "8", " "]);
assert_eq!(term.screen().visible_row_to_stable_row(0), 7);
}
@ -878,14 +966,14 @@ fn test_scrollup() {
fn test_ri() {
let mut term = TestTerm::new(3, 1, 10);
term.print("1\n\u{8d}\n");
assert_all_contents(&term, file!(), line!(), &["1", "", ""]);
assert_all_contents(&term, file!(), line!(), &["1", " ", " "]);
}
#[test]
fn test_scroll_margins() {
let mut term = TestTerm::new(3, 1, 10);
term.print("1\n2\n3\n4\n");
assert_all_contents(&term, file!(), line!(), &["1", "2", "3", "4", ""]);
assert_all_contents(&term, file!(), line!(), &["1", "2", "3", "4", " "]);
let margins = CSI::Cursor(termwiz::escape::csi::Cursor::SetTopAndBottomMargins {
top: OneBased::new(1),
@ -894,14 +982,19 @@ fn test_scroll_margins() {
term.print(format!("{}", margins));
term.print("z\n");
assert_all_contents(&term, file!(), line!(), &["1", "2", "z", "4", ""]);
assert_all_contents(&term, file!(), line!(), &["1", "2", "z", "4", " "]);
term.print("a\n");
assert_all_contents(&term, file!(), line!(), &["1", "2", "z", "a", "", ""]);
assert_all_contents(&term, file!(), line!(), &["1", "2", "z", "a", " ", " "]);
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]
@ -919,9 +1012,9 @@ fn test_emoji_with_modifier() {
file!(),
line!(),
&[
&format!("{}", waving_hand),
&format!("{}", waving_hand_dark_tone),
"",
&format!("{} ", waving_hand),
&format!("{} ", waving_hand_dark_tone),
" ",
],
);
}
@ -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,
);
@ -958,7 +1055,7 @@ fn test_hyperlinks() {
&[
Line::from_text_with_wrapped_last_col("hello", &linked),
Line::from_text("hey!!", &linked),
"".into(),
" ".into(),
],
Compare::TEXT | Compare::ATTRS,
);

View File

@ -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);
}
}