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:
parent
381e572700
commit
10f0403973
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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 {
|
||||
|
@ -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],
|
||||
|
@ -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(
|
||||
|
Loading…
Reference in New Issue
Block a user