diff --git a/src/backend/test.rs b/src/backend/test.rs index 78f318be..746b17f7 100644 --- a/src/backend/test.rs +++ b/src/backend/test.rs @@ -329,8 +329,7 @@ mod tests { #[test] fn draw() { let mut backend = TestBackend::new(10, 2); - let mut cell = Cell::default(); - cell.set_symbol("a"); + let cell = Cell::new("a"); backend.draw([(0, 0, &cell)].into_iter()).unwrap(); backend.draw([(0, 1, &cell)].into_iter()).unwrap(); backend.assert_buffer_lines(["a "; 2]); @@ -366,8 +365,7 @@ mod tests { #[test] fn clear() { let mut backend = TestBackend::new(4, 2); - let mut cell = Cell::default(); - cell.set_symbol("a"); + let cell = Cell::new("a"); backend.draw([(0, 0, &cell)].into_iter()).unwrap(); backend.draw([(0, 1, &cell)].into_iter()).unwrap(); backend.clear().unwrap(); diff --git a/src/buffer/buffer.rs b/src/buffer/buffer.rs index 53733125..e460c79d 100644 --- a/src/buffer/buffer.rs +++ b/src/buffer/buffer.rs @@ -54,7 +54,7 @@ impl Buffer { /// Returns a Buffer with all cells set to the default one #[must_use] pub fn empty(area: Rect) -> Self { - Self::filled(area, &Cell::default()) + Self::filled(area, &Cell::EMPTY) } /// Returns a Buffer with all cells initialized with the attributes of the given Cell @@ -278,7 +278,7 @@ impl Buffer { if self.content.len() > length { self.content.truncate(length); } else { - self.content.resize(length, Cell::default()); + self.content.resize(length, Cell::EMPTY); } self.area = area; } @@ -293,7 +293,7 @@ impl Buffer { /// Merge an other buffer into this one pub fn merge(&mut self, other: &Self) { let area = self.area.union(other.area); - self.content.resize(area.area() as usize, Cell::default()); + self.content.resize(area.area() as usize, Cell::EMPTY); // Move original content to the appropriate space let size = self.area.area() as usize; @@ -453,12 +453,6 @@ mod tests { use super::*; - fn cell(s: &str) -> Cell { - let mut cell = Cell::default(); - cell.set_symbol(s); - cell - } - #[test] fn debug_empty_buffer() { let buffer = Buffer::empty(Rect::ZERO); @@ -749,14 +743,14 @@ mod tests { let prev = Buffer::empty(area); let next = Buffer::empty(area); let diff = prev.diff(&next); - assert_eq!(diff, vec![]); + assert_eq!(diff, []); } #[test] fn diff_empty_filled() { let area = Rect::new(0, 0, 40, 40); let prev = Buffer::empty(area); - let next = Buffer::filled(area, Cell::default().set_symbol("a")); + let next = Buffer::filled(area, &Cell::new("a")); let diff = prev.diff(&next); assert_eq!(diff.len(), 40 * 40); } @@ -764,10 +758,10 @@ mod tests { #[test] fn diff_filled_filled() { let area = Rect::new(0, 0, 40, 40); - let prev = Buffer::filled(area, Cell::default().set_symbol("a")); - let next = Buffer::filled(area, Cell::default().set_symbol("a")); + let prev = Buffer::filled(area, &Cell::new("a")); + let next = Buffer::filled(area, &Cell::new("a")); let diff = prev.diff(&next); - assert_eq!(diff, vec![]); + assert_eq!(diff, []); } #[test] @@ -789,22 +783,23 @@ mod tests { let diff = prev.diff(&next); assert_eq!( diff, - vec![ - (2, 1, &cell("I")), - (3, 1, &cell("T")), - (4, 1, &cell("L")), - (5, 1, &cell("E")), + [ + (2, 1, &Cell::new("I")), + (3, 1, &Cell::new("T")), + (4, 1, &Cell::new("L")), + (5, 1, &Cell::new("E")), ] ); } #[test] - #[rustfmt::skip] fn diff_multi_width() { + #[rustfmt::skip] let prev = Buffer::with_lines([ "┌Title─┐ ", "└──────┘ ", ]); + #[rustfmt::skip] let next = Buffer::with_lines([ "┌称号──┐ ", "└──────┘ ", @@ -812,12 +807,12 @@ mod tests { let diff = prev.diff(&next); assert_eq!( diff, - vec![ - (1, 0, &cell("称")), + [ + (1, 0, &Cell::new("称")), // Skipped "i" - (3, 0, &cell("号")), + (3, 0, &Cell::new("号")), // Skipped "l" - (5, 0, &cell("─")), + (5, 0, &Cell::new("─")), ] ); } @@ -830,7 +825,11 @@ mod tests { let diff = prev.diff(&next); assert_eq!( diff, - vec![(1, 0, &cell("─")), (2, 0, &cell("称")), (4, 0, &cell("号")),] + [ + (1, 0, &Cell::new("─")), + (2, 0, &Cell::new("称")), + (4, 0, &Cell::new("号")), + ] ); } @@ -843,59 +842,25 @@ mod tests { } let diff = prev.diff(&next); - assert_eq!(diff, vec![(0, 0, &cell("4"))],); + assert_eq!(diff, [(0, 0, &Cell::new("4"))],); } - #[test] - fn merge() { - let mut one = Buffer::filled( - Rect { - x: 0, - y: 0, - width: 2, - height: 2, - }, - Cell::default().set_symbol("1"), - ); - let two = Buffer::filled( - Rect { - x: 0, - y: 2, - width: 2, - height: 2, - }, - Cell::default().set_symbol("2"), - ); + #[rstest] + #[case(Rect::new(0, 0, 2, 2), Rect::new(0, 2, 2, 2), ["11", "11", "22", "22"])] + #[case(Rect::new(2, 2, 2, 2), Rect::new(0, 0, 2, 2), ["22 ", "22 ", " 11", " 11"])] + fn merge<'line, Lines>(#[case] one: Rect, #[case] two: Rect, #[case] expected: Lines) + where + Lines: IntoIterator, + Lines::Item: Into>, + { + let mut one = Buffer::filled(one, &Cell::new("1")); + let two = Buffer::filled(two, &Cell::new("2")); one.merge(&two); - assert_eq!(one, Buffer::with_lines(["11", "11", "22", "22"])); + assert_eq!(one, Buffer::with_lines(expected)); } #[test] - fn merge2() { - let mut one = Buffer::filled( - Rect { - x: 2, - y: 2, - width: 2, - height: 2, - }, - Cell::default().set_symbol("1"), - ); - let two = Buffer::filled( - Rect { - x: 0, - y: 0, - width: 2, - height: 2, - }, - Cell::default().set_symbol("2"), - ); - one.merge(&two); - assert_eq!(one, Buffer::with_lines(["22 ", "22 ", " 11", " 11"])); - } - - #[test] - fn merge3() { + fn merge_with_offset() { let mut one = Buffer::filled( Rect { x: 3, @@ -903,7 +868,7 @@ mod tests { width: 2, height: 2, }, - Cell::default().set_symbol("1"), + &Cell::new("1"), ); let two = Buffer::filled( Rect { @@ -912,21 +877,23 @@ mod tests { width: 3, height: 4, }, - Cell::default().set_symbol("2"), + &Cell::new("2"), ); one.merge(&two); - let mut merged = Buffer::with_lines(["222 ", "222 ", "2221", "2221"]); - merged.area = Rect { + let mut expected = Buffer::with_lines(["222 ", "222 ", "2221", "2221"]); + expected.area = Rect { x: 1, y: 1, width: 4, height: 4, }; - assert_eq!(one, merged); + assert_eq!(one, expected); } - #[test] - fn merge_skip() { + #[rstest] + #[case(false, true, [false, false, true, true, true, true])] + #[case(true, false, [true, true, false, false, false, false])] + fn merge_skip(#[case] one: bool, #[case] two: bool, #[case] expected: [bool; 6]) { let mut one = Buffer::filled( Rect { x: 0, @@ -934,7 +901,7 @@ mod tests { width: 2, height: 2, }, - Cell::default().set_symbol("1"), + Cell::new("1").set_skip(one), ); let two = Buffer::filled( Rect { @@ -943,36 +910,11 @@ mod tests { width: 2, height: 2, }, - Cell::default().set_symbol("2").set_skip(true), + Cell::new("2").set_skip(two), ); one.merge(&two); - let skipped: Vec = one.content().iter().map(|c| c.skip).collect(); - assert_eq!(skipped, vec![false, false, true, true, true, true]); - } - - #[test] - fn merge_skip2() { - let mut one = Buffer::filled( - Rect { - x: 0, - y: 0, - width: 2, - height: 2, - }, - Cell::default().set_symbol("1").set_skip(true), - ); - let two = Buffer::filled( - Rect { - x: 0, - y: 1, - width: 2, - height: 2, - }, - Cell::default().set_symbol("2"), - ); - one.merge(&two); - let skipped: Vec = one.content().iter().map(|c| c.skip).collect(); - assert_eq!(skipped, vec![true, true, false, false, false, false]); + let skipped = one.content().iter().map(|c| c.skip).collect::>(); + assert_eq!(skipped, expected); } #[test] diff --git a/src/buffer/cell.rs b/src/buffer/cell.rs index 1698bffc..858331f0 100644 --- a/src/buffer/cell.rs +++ b/src/buffer/cell.rs @@ -34,6 +34,27 @@ pub struct Cell { } impl Cell { + /// An empty `Cell` + pub const EMPTY: Self = Self::new(" "); + + /// Creates a new `Cell` with the given symbol. + /// + /// This works at compile time and puts the symbol onto the stack. Fails to build when the + /// symbol doesnt fit onto the stack and requires to be placed on the heap. Use + /// `Self::default().set_symbol()` in that case. See [`CompactString::new_inline`] for more + /// details on this. + pub const fn new(symbol: &str) -> Self { + Self { + symbol: CompactString::new_inline(symbol), + fg: Color::Reset, + bg: Color::Reset, + #[cfg(feature = "underline-color")] + underline_color: Color::Reset, + modifier: Modifier::empty(), + skip: false, + } + } + /// Gets the symbol of the cell. #[must_use] pub fn symbol(&self) -> &str { @@ -108,7 +129,7 @@ impl Cell { self } - /// Resets the cell to the default state. + /// Resets the cell to the empty state. pub fn reset(&mut self) { self.symbol = CompactString::new_inline(" "); self.fg = Color::Reset; @@ -124,15 +145,7 @@ impl Cell { impl Default for Cell { fn default() -> Self { - Self { - symbol: CompactString::new_inline(" "), - fg: Color::Reset, - bg: Color::Reset, - #[cfg(feature = "underline-color")] - underline_color: Color::Reset, - modifier: Modifier::empty(), - skip: false, - } + Self::EMPTY } } @@ -142,11 +155,15 @@ mod tests { #[test] fn symbol_field() { - let mut cell = Cell::default(); + let mut cell = Cell::EMPTY; assert_eq!(cell.symbol(), " "); cell.set_symbol("あ"); // Multi-byte character assert_eq!(cell.symbol(), "あ"); cell.set_symbol("👨‍👩‍👧‍👦"); // Multiple code units combined with ZWJ assert_eq!(cell.symbol(), "👨‍👩‍👧‍👦"); + + // above Cell::EMPTY is put into a mutable variable and is changed then. + // While this looks like it might change the constant, it actually doesnt: + assert_eq!(Cell::EMPTY.symbol(), " "); } } diff --git a/src/text/line.rs b/src/text/line.rs index 79e1d44d..5e45d6d4 100644 --- a/src/text/line.rs +++ b/src/text/line.rs @@ -1169,7 +1169,7 @@ mod tests { fn render_truncates_away_from_0x0(#[case] alignment: Alignment, #[case] expected: &str) { let line = Line::from(vec![Span::raw("a🦀b"), Span::raw("c🦀d")]).alignment(alignment); // Fill buffer with stuff to ensure the output is indeed padded - let mut buf = Buffer::filled(Rect::new(0, 0, 10, 1), Cell::default().set_symbol("X")); + let mut buf = Buffer::filled(Rect::new(0, 0, 10, 1), &Cell::new("X")); let area = Rect::new(2, 0, 6, 1); line.render_ref(area, &mut buf); assert_eq!(buf, Buffer::with_lines([expected])); @@ -1188,7 +1188,7 @@ mod tests { let line = Line::from(vec![Span::raw("a🦀b"), Span::raw("c🦀d")]).right_aligned(); let area = Rect::new(0, 0, buf_width, 1); // Fill buffer with stuff to ensure the output is indeed padded - let mut buf = Buffer::filled(area, Cell::default().set_symbol("X")); + let mut buf = Buffer::filled(area, &Cell::new("X")); line.render_ref(buf.area, &mut buf); assert_eq!(buf, Buffer::with_lines([expected])); } diff --git a/src/widgets/canvas.rs b/src/widgets/canvas.rs index 66312436..c2991af8 100644 --- a/src/widgets/canvas.rs +++ b/src/widgets/canvas.rs @@ -817,9 +817,7 @@ mod tests { // results in the expected output fn test_marker(marker: Marker, expected: &str) { let area = Rect::new(0, 0, 5, 5); - let mut cell = Cell::default(); - cell.set_char('x'); - let mut buf = Buffer::filled(area, &cell); + let mut buf = Buffer::filled(area, &Cell::new("x")); let horizontal_line = Line { x1: 0.0, y1: 0.0, diff --git a/src/widgets/sparkline.rs b/src/widgets/sparkline.rs index 1eca9c5e..363d84dc 100644 --- a/src/widgets/sparkline.rs +++ b/src/widgets/sparkline.rs @@ -239,9 +239,7 @@ mod tests { // filled with x symbols to make it easier to assert on the result fn render(widget: Sparkline, width: u16) -> Buffer { let area = Rect::new(0, 0, width, 1); - let mut cell = Cell::default(); - cell.set_symbol("x"); - let mut buffer = Buffer::filled(area, &cell); + let mut buffer = Buffer::filled(area, &Cell::new("x")); widget.render(area, &mut buffer); buffer }