1
1
mirror of https://github.com/wez/wezterm.git synced 2024-12-23 05:12:40 +03:00

termwiz: avoid cluster -> vec conversions in a few more cases

This reduces the resident memory by another ~10% because it avoids
keeping as many runs of whitespace.

Runtime for `time cat enwiki8.wiki` is still ~11-12s, resident: 530K

refs: https://github.com/wez/wezterm/issues/1626
This commit is contained in:
Wez Furlong 2022-07-24 07:57:33 -07:00
parent 8002a17242
commit 7be01110ca
3 changed files with 69 additions and 38 deletions

View File

@ -509,39 +509,24 @@ fn basic_output() {
term.erase_in_display(EraseInDisplay::EraseToStartOfDisplay);
term.cup(1, 1);
term.print("hello, world!");
assert_visible_contents(
&term,
file!(),
line!(),
&[" ", " hello, wo", "rld!", "", ""],
);
assert_visible_contents(&term, file!(), line!(), &["", " hello, wo", "rld!", "", ""]);
term.erase_in_display(EraseInDisplay::EraseToStartOfDisplay);
assert_visible_contents(
&term,
file!(),
line!(),
&[" ", " ", " ", "", ""],
&["", " ", " ", "", ""],
);
term.cup(0, 2);
term.print("woot");
term.cup(2, 2);
term.erase_in_line(EraseInLine::EraseToEndOfLine);
assert_visible_contents(
&term,
file!(),
line!(),
&[" ", " ", "wo", "", ""],
);
assert_visible_contents(&term, file!(), line!(), &["", " ", "wo", "", ""]);
term.erase_in_line(EraseInLine::EraseToStartOfLine);
assert_visible_contents(
&term,
file!(),
line!(),
&[" ", " ", " ", "", ""],
);
assert_visible_contents(&term, file!(), line!(), &["", " ", " ", "", ""]);
}
/// Ensure that we dirty lines as the cursor is moved around, otherwise

View File

@ -11,6 +11,7 @@ keywords = ["terminal", "readline", "console", "curses"]
readme = "README.md"
[dependencies]
# backtrace = "0.3"
base64 = "0.13"
bitflags = "1.3"
cassowary = {version="0.3", optional=true}

View File

@ -682,22 +682,20 @@ impl Line {
}
if let CellStorage::C(cl) = &mut self.cells {
if idx == cl.len {
cl.append(cell);
return;
}
if idx > cl.len
&& cell.str() == " "
&& cl
.clusters
.last()
.map(|c| c.attrs == *cell.attrs())
.unwrap_or_else(|| *cell.attrs() == CellAttributes::default())
{
if idx >= cl.len && cell == Cell::blank() {
// Appending blank beyond end of line; is already
// implicitly blank
return;
}
while cl.len < idx {
// Fill out any implied blanks until we can append
// their intended cell content
cl.append(Cell::blank());
}
if idx == cl.len {
cl.append(cell);
return;
}
/*
log::info!(
"cannot append {cell:?} to {:?} as idx={idx} and cl.len is {}",
@ -837,11 +835,12 @@ impl Line {
}
pub fn prune_trailing_blanks(&mut self, seqno: SequenceNo) {
if let CellStorage::C(cl) = &self.cells {
if !cl.text.ends_with(' ') {
// There are no trailing blanks
return;
if let CellStorage::C(cl) = &mut self.cells {
if cl.prune_trailing_blanks() {
self.update_last_change_seqno(seqno);
self.invalidate_zones();
}
return;
}
let def_attr = CellAttributes::blank();
@ -857,6 +856,11 @@ impl Line {
}
pub fn fill_range(&mut self, cols: Range<usize>, cell: &Cell, seqno: SequenceNo) {
if self.len() == 0 && *cell == Cell::blank() {
// We would be filling it with blanks only to prune
// them all away again before we return; NOP
return;
}
for x in cols {
// FIXME: we can skip the look-back for second and subsequent iterations
self.set_cell_impl(x, cell.clone(), true, seqno);
@ -904,6 +908,7 @@ impl Line {
CellStorage::V(_) => return,
CellStorage::C(cl) => cl.to_cell_vec(),
};
// log::info!("make_cells\n{:?}", backtrace::Backtrace::new());
self.cells = CellStorage::V(VecStorage::new(cells));
}
@ -967,9 +972,19 @@ impl Line {
/// to this line.
/// This function is used by rewrapping logic when joining wrapped
/// lines back together.
pub fn append_line(&mut self, mut other: Line, seqno: SequenceNo) {
self.coerce_vec_storage()
.append(&mut other.coerce_vec_storage());
pub fn append_line(&mut self, other: Line, seqno: SequenceNo) {
match &mut self.cells {
CellStorage::V(cells) => {
for cell in other.visible_cells() {
cells.push(cell.as_cell());
}
}
CellStorage::C(cl) => {
for cell in other.visible_cells() {
cl.append(cell.as_cell());
}
}
}
self.update_last_change_seqno(seqno);
self.invalidate_zones();
}
@ -1450,6 +1465,36 @@ impl ClusteredLine {
self.len += cell_width;
}
fn prune_trailing_blanks(&mut self) -> bool {
let num_spaces = self.text.chars().rev().take_while(|&c| c == ' ').count();
if num_spaces == 0 {
return false;
}
let blank = CellAttributes::blank();
let mut pruned = false;
for _ in 0..num_spaces {
let mut need_pop = false;
if let Some(cluster) = self.clusters.last_mut() {
if cluster.attrs != blank {
break;
}
cluster.cell_width -= 1;
self.text.pop();
self.len -= 1;
pruned = true;
if cluster.cell_width == 0 {
need_pop = true;
}
}
if need_pop {
self.clusters.pop();
}
}
pruned
}
fn set_last_cell_was_wrapped(&mut self, wrapped: bool) {
if let Some(last_cell) = self.iter().last() {
if last_cell.attrs().wrapped() == wrapped {