1use crate::{
2 layout::Rect,
3 style::{Color, Modifier, Style},
4 text::{Span, Spans},
5};
6use std::cmp::min;
7use unicode_segmentation::UnicodeSegmentation;
8use unicode_width::UnicodeWidthStr;
9
10#[derive(Debug, Clone, PartialEq)]
12pub struct Cell {
13 pub symbol: String,
14 pub fg: Color,
15 pub bg: Color,
16 pub modifier: Modifier,
17}
18
19impl Cell {
20 pub fn set_symbol(&mut self, symbol: &str) -> &mut Cell {
21 self.symbol.clear();
22 self.symbol.push_str(symbol);
23 self
24 }
25
26 pub fn set_char(&mut self, ch: char) -> &mut Cell {
27 self.symbol.clear();
28 self.symbol.push(ch);
29 self
30 }
31
32 pub fn set_fg(&mut self, color: Color) -> &mut Cell {
33 self.fg = color;
34 self
35 }
36
37 pub fn set_bg(&mut self, color: Color) -> &mut Cell {
38 self.bg = color;
39 self
40 }
41
42 pub fn set_style(&mut self, style: Style) -> &mut Cell {
43 if let Some(c) = style.fg {
44 self.fg = c;
45 }
46 if let Some(c) = style.bg {
47 self.bg = c;
48 }
49 self.modifier.insert(style.add_modifier);
50 self.modifier.remove(style.sub_modifier);
51 self
52 }
53
54 pub fn style(&self) -> Style {
55 Style::default()
56 .fg(self.fg)
57 .bg(self.bg)
58 .add_modifier(self.modifier)
59 }
60
61 pub fn reset(&mut self) {
62 self.symbol.clear();
63 self.symbol.push(' ');
64 self.fg = Color::Reset;
65 self.bg = Color::Reset;
66 self.modifier = Modifier::empty();
67 }
68}
69
70impl Default for Cell {
71 fn default() -> Cell {
72 Cell {
73 symbol: " ".into(),
74 fg: Color::Reset,
75 bg: Color::Reset,
76 modifier: Modifier::empty(),
77 }
78 }
79}
80
81#[derive(Debug, Clone, PartialEq)]
109pub struct Buffer {
110 pub area: Rect,
112 pub content: Vec<Cell>,
115}
116
117impl Default for Buffer {
118 fn default() -> Buffer {
119 Buffer {
120 area: Default::default(),
121 content: Vec::new(),
122 }
123 }
124}
125
126impl Buffer {
127 pub fn empty(area: Rect) -> Buffer {
129 let cell: Cell = Default::default();
130 Buffer::filled(area, &cell)
131 }
132
133 pub fn filled(area: Rect, cell: &Cell) -> Buffer {
135 let size = area.area() as usize;
136 let mut content = Vec::with_capacity(size);
137 for _ in 0..size {
138 content.push(cell.clone());
139 }
140 Buffer { area, content }
141 }
142
143 pub fn with_lines<S>(lines: Vec<S>) -> Buffer
145 where
146 S: AsRef<str>,
147 {
148 let height = lines.len() as u16;
149 let width = lines
150 .iter()
151 .map(|i| i.as_ref().width() as u16)
152 .max()
153 .unwrap_or_default();
154 let mut buffer = Buffer::empty(Rect {
155 x: 0,
156 y: 0,
157 width,
158 height,
159 });
160 for (y, line) in lines.iter().enumerate() {
161 buffer.set_string(0, y as u16, line, Style::default());
162 }
163 buffer
164 }
165
166 pub fn content(&self) -> &[Cell] {
168 &self.content
169 }
170
171 pub fn area(&self) -> &Rect {
173 &self.area
174 }
175
176 pub fn get(&self, x: u16, y: u16) -> &Cell {
178 let i = self.index_of(x, y);
179 &self.content[i]
180 }
181
182 pub fn get_mut(&mut self, x: u16, y: u16) -> &mut Cell {
184 let i = self.index_of(x, y);
185 &mut self.content[i]
186 }
187
188 pub fn index_of(&self, x: u16, y: u16) -> usize {
217 debug_assert!(
218 x >= self.area.left()
219 && x < self.area.right()
220 && y >= self.area.top()
221 && y < self.area.bottom(),
222 "Trying to access position outside the buffer: x={}, y={}, area={:?}",
223 x,
224 y,
225 self.area
226 );
227 ((y - self.area.y) * self.area.width + (x - self.area.x)) as usize
228 }
229
230 pub fn pos_of(&self, i: usize) -> (u16, u16) {
258 debug_assert!(
259 i < self.content.len(),
260 "Trying to get the coords of a cell outside the buffer: i={} len={}",
261 i,
262 self.content.len()
263 );
264 (
265 self.area.x + i as u16 % self.area.width,
266 self.area.y + i as u16 / self.area.width,
267 )
268 }
269
270 pub fn set_string<S>(&mut self, x: u16, y: u16, string: S, style: Style)
272 where
273 S: AsRef<str>,
274 {
275 self.set_stringn(x, y, string, usize::MAX, style);
276 }
277
278 pub fn set_stringn<S>(
281 &mut self,
282 x: u16,
283 y: u16,
284 string: S,
285 width: usize,
286 style: Style,
287 ) -> (u16, u16)
288 where
289 S: AsRef<str>,
290 {
291 let mut index = self.index_of(x, y);
292 let mut x_offset = x as usize;
293 let graphemes = UnicodeSegmentation::graphemes(string.as_ref(), true);
294 let max_offset = min(self.area.right() as usize, width.saturating_add(x as usize));
295 for s in graphemes {
296 let width = s.width();
297 if width == 0 {
298 continue;
299 }
300 if width > max_offset.saturating_sub(x_offset) {
303 break;
304 }
305
306 self.content[index].set_symbol(s);
307 self.content[index].set_style(style);
308 for i in index + 1..index + width {
310 self.content[i].reset();
311 }
312 index += width;
313 x_offset += width;
314 }
315 (x_offset as u16, y)
316 }
317
318 pub fn set_spans<'a>(&mut self, x: u16, y: u16, spans: &Spans<'a>, width: u16) -> (u16, u16) {
319 let mut remaining_width = width;
320 let mut x = x;
321 for span in &spans.0 {
322 if remaining_width == 0 {
323 break;
324 }
325 let pos = self.set_stringn(
326 x,
327 y,
328 span.content.as_ref(),
329 remaining_width as usize,
330 span.style,
331 );
332 let w = pos.0.saturating_sub(x);
333 x = pos.0;
334 remaining_width = remaining_width.saturating_sub(w);
335 }
336 (x, y)
337 }
338
339 pub fn set_span<'a>(&mut self, x: u16, y: u16, span: &Span<'a>, width: u16) -> (u16, u16) {
340 self.set_stringn(x, y, span.content.as_ref(), width as usize, span.style)
341 }
342
343 #[deprecated(
344 since = "0.10.0",
345 note = "You should use styling capabilities of `Buffer::set_style`"
346 )]
347 pub fn set_background(&mut self, area: Rect, color: Color) {
348 for y in area.top()..area.bottom() {
349 for x in area.left()..area.right() {
350 self.get_mut(x, y).set_bg(color);
351 }
352 }
353 }
354
355 pub fn set_style(&mut self, area: Rect, style: Style) {
356 for y in area.top()..area.bottom() {
357 for x in area.left()..area.right() {
358 self.get_mut(x, y).set_style(style);
359 }
360 }
361 }
362
363 pub fn resize(&mut self, area: Rect) {
366 let length = area.area() as usize;
367 if self.content.len() > length {
368 self.content.truncate(length);
369 } else {
370 self.content.resize(length, Default::default());
371 }
372 self.area = area;
373 }
374
375 pub fn reset(&mut self) {
377 for c in &mut self.content {
378 c.reset();
379 }
380 }
381
382 pub fn merge(&mut self, other: &Buffer) {
384 let area = self.area.union(other.area);
385 let cell: Cell = Default::default();
386 self.content.resize(area.area() as usize, cell.clone());
387
388 let size = self.area.area() as usize;
390 for i in (0..size).rev() {
391 let (x, y) = self.pos_of(i);
392 let k = ((y - area.y) * area.width + x - area.x) as usize;
394 if i != k {
395 self.content[k] = self.content[i].clone();
396 self.content[i] = cell.clone();
397 }
398 }
399
400 let size = other.area.area() as usize;
403 for i in 0..size {
404 let (x, y) = other.pos_of(i);
405 let k = ((y - area.y) * area.width + x - area.x) as usize;
407 self.content[k] = other.content[i].clone();
408 }
409 self.area = area;
410 }
411
412 pub fn diff<'a>(&self, other: &'a Buffer) -> Vec<(u16, u16, &'a Cell)> {
441 let previous_buffer = &self.content;
442 let next_buffer = &other.content;
443 let width = self.area.width;
444
445 let mut updates: Vec<(u16, u16, &Cell)> = vec![];
446 let mut invalidated: usize = 0;
448 let mut to_skip: usize = 0;
451 for (i, (current, previous)) in next_buffer.iter().zip(previous_buffer.iter()).enumerate() {
452 if (current != previous || invalidated > 0) && to_skip == 0 {
453 let x = i as u16 % width;
454 let y = i as u16 / width;
455 updates.push((x, y, &next_buffer[i]));
456 }
457
458 to_skip = current.symbol.width().saturating_sub(1);
459
460 let affected_width = std::cmp::max(current.symbol.width(), previous.symbol.width());
461 invalidated = std::cmp::max(affected_width, invalidated).saturating_sub(1);
462 }
463 updates
464 }
465}
466
467#[cfg(test)]
468mod tests {
469 use super::*;
470
471 fn cell(s: &str) -> Cell {
472 let mut cell = Cell::default();
473 cell.set_symbol(s);
474 cell
475 }
476
477 #[test]
478 fn it_translates_to_and_from_coordinates() {
479 let rect = Rect::new(200, 100, 50, 80);
480 let buf = Buffer::empty(rect);
481
482 assert_eq!(buf.pos_of(0), (200, 100));
484 assert_eq!(buf.index_of(200, 100), 0);
485
486 assert_eq!(buf.pos_of(buf.content.len() - 1), (249, 179));
488 assert_eq!(buf.index_of(249, 179), buf.content.len() - 1);
489 }
490
491 #[test]
492 #[should_panic(expected = "outside the buffer")]
493 fn pos_of_panics_on_out_of_bounds() {
494 let rect = Rect::new(0, 0, 10, 10);
495 let buf = Buffer::empty(rect);
496
497 buf.pos_of(100);
499 }
500
501 #[test]
502 #[should_panic(expected = "outside the buffer")]
503 fn index_of_panics_on_out_of_bounds() {
504 let rect = Rect::new(0, 0, 10, 10);
505 let buf = Buffer::empty(rect);
506
507 buf.index_of(10, 0);
509 }
510
511 #[test]
512 fn buffer_set_string() {
513 let area = Rect::new(0, 0, 5, 1);
514 let mut buffer = Buffer::empty(area);
515
516 buffer.set_stringn(0, 0, "aaa", 0, Style::default());
518 assert_eq!(buffer, Buffer::with_lines(vec![" "]));
519
520 buffer.set_string(0, 0, "aaa", Style::default());
521 assert_eq!(buffer, Buffer::with_lines(vec!["aaa "]));
522
523 buffer.set_stringn(0, 0, "bbbbbbbbbbbbbb", 4, Style::default());
525 assert_eq!(buffer, Buffer::with_lines(vec!["bbbb "]));
526
527 buffer.set_string(0, 0, "12345", Style::default());
528 assert_eq!(buffer, Buffer::with_lines(vec!["12345"]));
529
530 buffer.set_string(0, 0, "123456", Style::default());
532 assert_eq!(buffer, Buffer::with_lines(vec!["12345"]));
533 }
534
535 #[test]
536 fn buffer_set_string_zero_width() {
537 let area = Rect::new(0, 0, 1, 1);
538 let mut buffer = Buffer::empty(area);
539
540 let s = "\u{1}a";
542 buffer.set_stringn(0, 0, s, 1, Style::default());
543 assert_eq!(buffer, Buffer::with_lines(vec!["a"]));
544
545 let s = "a\u{1}";
547 buffer.set_stringn(0, 0, s, 1, Style::default());
548 assert_eq!(buffer, Buffer::with_lines(vec!["a"]));
549 }
550
551 #[test]
552 fn buffer_set_string_double_width() {
553 let area = Rect::new(0, 0, 5, 1);
554 let mut buffer = Buffer::empty(area);
555 buffer.set_string(0, 0, "コン", Style::default());
556 assert_eq!(buffer, Buffer::with_lines(vec!["コン "]));
557
558 buffer.set_string(0, 0, "コンピ", Style::default());
560 assert_eq!(buffer, Buffer::with_lines(vec!["コン "]));
561 }
562
563 #[test]
564 fn buffer_with_lines() {
565 let buffer =
566 Buffer::with_lines(vec!["┌────────┐", "│コンピュ│", "│ーa 上で│", "└────────┘"]);
567 assert_eq!(buffer.area.x, 0);
568 assert_eq!(buffer.area.y, 0);
569 assert_eq!(buffer.area.width, 10);
570 assert_eq!(buffer.area.height, 4);
571 }
572
573 #[test]
574 fn buffer_diffing_empty_empty() {
575 let area = Rect::new(0, 0, 40, 40);
576 let prev = Buffer::empty(area);
577 let next = Buffer::empty(area);
578 let diff = prev.diff(&next);
579 assert_eq!(diff, vec![]);
580 }
581
582 #[test]
583 fn buffer_diffing_empty_filled() {
584 let area = Rect::new(0, 0, 40, 40);
585 let prev = Buffer::empty(area);
586 let next = Buffer::filled(area, Cell::default().set_symbol("a"));
587 let diff = prev.diff(&next);
588 assert_eq!(diff.len(), 40 * 40);
589 }
590
591 #[test]
592 fn buffer_diffing_filled_filled() {
593 let area = Rect::new(0, 0, 40, 40);
594 let prev = Buffer::filled(area, Cell::default().set_symbol("a"));
595 let next = Buffer::filled(area, Cell::default().set_symbol("a"));
596 let diff = prev.diff(&next);
597 assert_eq!(diff, vec![]);
598 }
599
600 #[test]
601 fn buffer_diffing_single_width() {
602 let prev = Buffer::with_lines(vec![
603 " ",
604 "┌Title─┐ ",
605 "│ │ ",
606 "│ │ ",
607 "└──────┘ ",
608 ]);
609 let next = Buffer::with_lines(vec![
610 " ",
611 "┌TITLE─┐ ",
612 "│ │ ",
613 "│ │ ",
614 "└──────┘ ",
615 ]);
616 let diff = prev.diff(&next);
617 assert_eq!(
618 diff,
619 vec![
620 (2, 1, &cell("I")),
621 (3, 1, &cell("T")),
622 (4, 1, &cell("L")),
623 (5, 1, &cell("E")),
624 ]
625 );
626 }
627
628 #[test]
629 #[rustfmt::skip]
630 fn buffer_diffing_multi_width() {
631 let prev = Buffer::with_lines(vec![
632 "┌Title─┐ ",
633 "└──────┘ ",
634 ]);
635 let next = Buffer::with_lines(vec![
636 "┌称号──┐ ",
637 "└──────┘ ",
638 ]);
639 let diff = prev.diff(&next);
640 assert_eq!(
641 diff,
642 vec![
643 (1, 0, &cell("称")),
644 (3, 0, &cell("号")),
646 (5, 0, &cell("─")),
648 ]
649 );
650 }
651
652 #[test]
653 fn buffer_diffing_multi_width_offset() {
654 let prev = Buffer::with_lines(vec!["┌称号──┐"]);
655 let next = Buffer::with_lines(vec!["┌─称号─┐"]);
656
657 let diff = prev.diff(&next);
658 assert_eq!(
659 diff,
660 vec![(1, 0, &cell("─")), (2, 0, &cell("称")), (4, 0, &cell("号")),]
661 );
662 }
663
664 #[test]
665 fn buffer_merge() {
666 let mut one = Buffer::filled(
667 Rect {
668 x: 0,
669 y: 0,
670 width: 2,
671 height: 2,
672 },
673 Cell::default().set_symbol("1"),
674 );
675 let two = Buffer::filled(
676 Rect {
677 x: 0,
678 y: 2,
679 width: 2,
680 height: 2,
681 },
682 Cell::default().set_symbol("2"),
683 );
684 one.merge(&two);
685 assert_eq!(one, Buffer::with_lines(vec!["11", "11", "22", "22"]));
686 }
687
688 #[test]
689 fn buffer_merge2() {
690 let mut one = Buffer::filled(
691 Rect {
692 x: 2,
693 y: 2,
694 width: 2,
695 height: 2,
696 },
697 Cell::default().set_symbol("1"),
698 );
699 let two = Buffer::filled(
700 Rect {
701 x: 0,
702 y: 0,
703 width: 2,
704 height: 2,
705 },
706 Cell::default().set_symbol("2"),
707 );
708 one.merge(&two);
709 assert_eq!(
710 one,
711 Buffer::with_lines(vec!["22 ", "22 ", " 11", " 11"])
712 );
713 }
714
715 #[test]
716 fn buffer_merge3() {
717 let mut one = Buffer::filled(
718 Rect {
719 x: 3,
720 y: 3,
721 width: 2,
722 height: 2,
723 },
724 Cell::default().set_symbol("1"),
725 );
726 let two = Buffer::filled(
727 Rect {
728 x: 1,
729 y: 1,
730 width: 3,
731 height: 4,
732 },
733 Cell::default().set_symbol("2"),
734 );
735 one.merge(&two);
736 let mut merged = Buffer::with_lines(vec!["222 ", "222 ", "2221", "2221"]);
737 merged.area = Rect {
738 x: 1,
739 y: 1,
740 width: 4,
741 height: 4,
742 };
743 assert_eq!(one, merged);
744 }
745}