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

term/termwiz: microoptimize set cell

If we can avoid constructing a Cell then do so
This commit is contained in:
Wez Furlong 2022-07-24 09:14:44 -07:00
parent e8dfb553b4
commit c722db22d6
3 changed files with 97 additions and 6 deletions

View File

@ -386,6 +386,20 @@ impl Screen {
line.set_cell(x, cell.clone(), seqno);
}
pub fn set_cell_grapheme(
&mut self,
x: usize,
y: VisibleRowIndex,
text: &str,
width: usize,
attr: CellAttributes,
seqno: SequenceNo,
) {
let line_idx = self.phys_row(y);
let line = self.line_mut(line_idx);
line.set_cell_grapheme(x, text, width, attr, seqno);
}
pub fn cell_mut(&mut self, x: usize, y: VisibleRowIndex) -> Option<&mut Cell> {
let line_idx = self.phys_row(y);
let line = self.lines.get_mut(line_idx)?;

View File

@ -152,8 +152,6 @@ impl<'a> Performer<'a> {
let wrappable = x + print_width >= width;
let cell = Cell::new_grapheme_with_width(g, print_width, pen);
if self.insert {
let margin = self.left_and_right_margins.end;
let screen = self.screen_mut();
@ -164,14 +162,16 @@ impl<'a> Performer<'a> {
// Assign the cell
log::trace!(
"print x={} y={} print_width={} width={} cell={:?}",
"print x={} y={} print_width={} width={} cell={} {:?}",
x,
y,
print_width,
width,
cell
g,
self.pen
);
self.screen_mut().set_cell(x, y, &cell, seqno);
self.screen_mut()
.set_cell_grapheme(x, y, g, print_width, pen, seqno);
if !wrappable {
self.cursor.x += print_width;

View File

@ -461,6 +461,7 @@ impl Line {
/// If we have any cells with an implicit hyperlink, remove the hyperlink
/// from the cell attributes but leave the remainder of the attributes alone.
#[inline]
pub fn invalidate_implicit_hyperlinks(&mut self, seqno: SequenceNo) {
if (self.bits & (LineBits::SCANNED_IMPLICIT_HYPERLINKS | LineBits::HAS_IMPLICIT_HYPERLINKS))
== LineBits::NONE
@ -473,6 +474,10 @@ impl Line {
return;
}
self.invalidate_implicit_hyperlinks_impl(seqno);
}
fn invalidate_implicit_hyperlinks_impl(&mut self, seqno: SequenceNo) {
let cells = self.coerce_vec_storage();
for cell in cells.iter_mut() {
let replace = match cell.attrs().hyperlink() {
@ -652,6 +657,46 @@ impl Line {
self.set_cell_impl(idx, cell, false, seqno);
}
/// Assign a cell using grapheme text with a known width and attributes.
/// This is a micro-optimization over first constructing a Cell from
/// the grapheme info. If assigning this particular cell can be optimized
/// to an append to the interal clustered storage then the cost of
/// constructing and dropping the Cell can be avoided.
pub fn set_cell_grapheme(
&mut self,
idx: usize,
text: &str,
width: usize,
attr: CellAttributes,
seqno: SequenceNo,
) {
if attr.hyperlink().is_some() {
self.bits |= LineBits::HAS_HYPERLINK;
}
if let CellStorage::C(cl) = &mut self.cells {
if idx >= cl.len && text == " " && attr == CellAttributes::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_grapheme(" ", 1, CellAttributes::blank());
}
if idx == cl.len {
cl.append_grapheme(text, width, attr);
self.invalidate_implicit_hyperlinks(seqno);
self.invalidate_zones();
self.update_last_change_seqno(seqno);
return;
}
}
self.set_cell(idx, Cell::new_grapheme_with_width(text, width, attr), seqno);
}
pub fn set_cell_clearing_image_placements(
&mut self,
idx: usize,
@ -691,7 +736,7 @@ impl Line {
while cl.len < idx {
// Fill out any implied blanks until we can append
// their intended cell content
cl.append(Cell::blank());
cl.append_grapheme(" ", 1, CellAttributes::blank());
}
if idx == cl.len {
cl.append(cell);
@ -1418,6 +1463,38 @@ impl ClusteredLine {
}
}
fn append_grapheme(&mut self, text: &str, cell_width: usize, attrs: CellAttributes) {
let new_cluster = match self.clusters.last() {
Some(cluster) => cluster.attrs != attrs,
None => true,
};
let new_cell_index = self.len;
if new_cluster {
self.clusters.push(Cluster { attrs, cell_width });
} else if let Some(cluster) = self.clusters.last_mut() {
cluster.cell_width += cell_width;
}
self.text.push_str(text);
if cell_width > 1 {
let bitset = match self.is_double_wide.take() {
Some(mut bitset) => {
bitset.grow(new_cell_index + 1);
bitset.set(new_cell_index, true);
bitset
}
None => {
let mut bitset = FixedBitSet::with_capacity(new_cell_index + 1);
bitset.set(new_cell_index, true);
bitset
}
};
self.is_double_wide.replace(bitset);
}
self.last_cell_width = NonZeroU8::new(cell_width as u8);
self.len += cell_width;
}
fn append(&mut self, cell: Cell) {
let new_cluster = match self.clusters.last() {
Some(cluster) => cluster.attrs != *cell.attrs(),