1
1
mirror of https://github.com/wez/wezterm.git synced 2024-12-25 22:33:52 +03:00

improve encapsulation of Line struct

This commit is contained in:
Wez Furlong 2018-08-04 18:33:44 -07:00
parent 381e572700
commit 10f0403973
5 changed files with 98 additions and 55 deletions

View File

@ -13,7 +13,7 @@ enum ImplicitHyperlinks {
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct Line {
pub cells: Vec<Cell>,
cells: Vec<Cell>,
dirty: bool,
has_hyperlink: bool,
has_implicit_hyperlinks: ImplicitHyperlinks,
@ -76,6 +76,79 @@ impl Line {
}
}
fn invalidate_grapheme_at_or_before(&mut self, idx: usize) {
// Assumption: that the width of a grapheme is never > 2.
// This constrains the amount of look-back that we need to do here.
if idx > 0 {
let prior = idx - 1;
let width = self.cells[prior].width();
if width > 1 {
let attrs = self.cells[prior].attrs().clone();
for nerf in prior..prior + width {
self.cells[nerf] = Cell::new(' ', attrs.clone());
}
}
}
}
/// If we're about to modify a cell obscured by a double-width
/// character ahead of that cell, we need to nerf that sequence
/// of cells to avoid partial rendering concerns.
/// Similarly, when we assign a cell, we need to blank out those
/// occluded successor cells.
pub fn set_cell(&mut self, idx: usize, cell: Cell) -> &Cell {
// if the line isn't wide enough, pad it out with the default attributes
if idx >= self.cells.len() {
self.cells.resize(idx, Cell::default());
}
self.invalidate_grapheme_at_or_before(idx);
// For double-wide or wider chars, ensure that the cells that
// are overlapped by this one are blanked out.
let width = cell.width();
for i in 1..=width.saturating_sub(1) {
self.cells[idx + i] = Cell::new(' ', cell.attrs().clone());
}
self.cells[idx] = cell;
&self.cells[idx]
}
pub fn insert_cell(&mut self, x: usize, cell: Cell) {
self.invalidate_implicit_links();
// If we're inserting a wide cell, we should also insert the overlapped cells.
// We insert them first so that the grapheme winds up left-most.
let width = cell.width();
for _ in 1..=width.saturating_sub(1) {
self.cells.insert(x, Cell::new(' ', cell.attrs().clone()));
}
self.cells.insert(x, cell);
}
pub fn erase_cell(&mut self, x: usize) {
self.invalidate_implicit_links();
self.invalidate_grapheme_at_or_before(x);
self.cells.remove(x);
self.cells.push(Cell::default());
}
pub fn fill_range(&mut self, cols: impl Iterator<Item = usize>, cell: &Cell) {
let max_col = self.cells.len();
for x in cols {
if x >= max_col {
break;
}
self.set_cell(x, cell.clone());
}
}
pub fn cells(&self) -> &[Cell] {
&self.cells
}
/// Iterates the visible cells, respecting the width of the cell.
/// For instance, a double-width cell overlaps the following (blank)
/// cell, so that blank cell is omitted from the iterator results.

View File

@ -103,16 +103,13 @@ impl Screen {
pub fn insert_cell(&mut self, x: usize, y: VisibleRowIndex) {
let line_idx = self.phys_row(y);
let line = self.line_mut(line_idx);
line.invalidate_implicit_links();
line.cells.insert(x, Cell::default());
line.insert_cell(x, Cell::default());
}
pub fn erase_cell(&mut self, x: usize, y: VisibleRowIndex) {
let line_idx = self.phys_row(y);
let line = self.line_mut(line_idx);
line.invalidate_implicit_links();
line.cells.remove(x);
line.cells.push(Cell::default());
line.erase_cell(x);
}
/// Set a cell. the x and y coordinates are relative to the visible screeen
@ -137,18 +134,7 @@ impl Screen {
line.set_has_hyperlink(true);
}
let width = line.cells.len();
let cell = Cell::new(c, attr.clone());
if x == width {
line.cells.push(cell);
} else if x > width {
// if the line isn't wide enough, pad it out with the default attributes
line.cells.resize(x, Cell::default());
line.cells.push(cell);
} else {
line.cells[x] = cell;
}
&line.cells[x]
line.set_cell(x, Cell::new(c, attr.clone()))
}
pub fn clear_line(
@ -159,13 +145,7 @@ impl Screen {
) {
let line_idx = self.phys_row(y);
let line = self.line_mut(line_idx);
let max_col = line.cells.len();
for x in cols {
if x >= max_col {
break;
}
line.cells[x] = Cell::new(' ', attr.clone());
}
line.fill_range(cols, &Cell::new(' ', attr.clone()));
}
/// Translate a VisibleRowIndex into a PhysRowIndex. The resultant index

View File

@ -305,7 +305,7 @@ impl TerminalState {
match screen.lines.get_mut(idx) {
Some(ref mut line) => {
line.find_hyperlinks(rules);
match line.cells.get(x) {
match line.cells().get(x) {
Some(cell) => cell.attrs().hyperlink.as_ref().cloned(),
None => None,
}
@ -1460,20 +1460,6 @@ impl<'a> Performer<'a> {
cell.width()
};
// for double- or triple-wide cells, the client of the terminal
// expects the cursor to move by the visible width, which means that
// we need to generate non-printing cells to pad out the gap. They
// need to be non-printing rather than space so that that renderer
// doesn't render an actual space between the glyphs.
for non_print_x in 1..print_width {
self.screen_mut().set_cell(
x + non_print_x,
y,
0 as char, // non-printable
&pen,
);
}
self.clear_selection_if_intersects(x..x + print_width, y as ScrollbackOrVisibleRowIndex);
if x + print_width < width {

View File

@ -151,9 +151,7 @@ fn test_ed() {
.set_background(color::AnsiColor::Navy)
.clone();
let mut line: Line = " ".into();
line.cells[0] = Cell::new(' ', attr.clone());
line.cells[1] = Cell::new(' ', attr.clone());
line.cells[2] = Cell::new(' ', attr.clone());
line.fill_range(0..=2, &Cell::new(' ', attr.clone()));
assert_lines_equal(
&term.screen().visible_lines(),
&[line.clone(), line.clone(), line],

View File

@ -256,8 +256,8 @@ fn assert_lines_equal(lines: &[Line], expect_lines: &[Line], compare: Compare) {
}
if compare.contains(Compare::ATTRS) {
let line_attrs: Vec<_> = line.cells.iter().map(|c| c.attrs().clone()).collect();
let expect_attrs: Vec<_> = expect.cells.iter().map(|c| c.attrs().clone()).collect();
let line_attrs: Vec<_> = line.cells().iter().map(|c| c.attrs().clone()).collect();
let expect_attrs: Vec<_> = expect.cells().iter().map(|c| c.attrs().clone()).collect();
assert_eq!(expect_attrs, line_attrs, "line {} attrs didn't match", idx,);
}
if compare.contains(Compare::TEXT) {
@ -510,17 +510,23 @@ fn test_hyperlinks() {
term.print("00t");
let mut partial_line: Line = "wo00t".into();
partial_line.cells[0] = Cell::new(
'w',
CellAttributes::default()
.set_hyperlink(Some(Rc::clone(&otherlink)))
.clone(),
partial_line.set_cell(
0,
Cell::new(
'w',
CellAttributes::default()
.set_hyperlink(Some(Rc::clone(&otherlink)))
.clone(),
),
);
partial_line.cells[1] = Cell::new(
'o',
CellAttributes::default()
.set_hyperlink(Some(Rc::clone(&otherlink)))
.clone(),
partial_line.set_cell(
1,
Cell::new(
'o',
CellAttributes::default()
.set_hyperlink(Some(Rc::clone(&otherlink)))
.clone(),
),
);
assert_lines_equal(