1use std::cmp::min;
2use std::fmt;
3use std::usize;
4
5use unicode_segmentation::UnicodeSegmentation;
6use unicode_width::UnicodeWidthStr;
7
8use crate::layout::Rect;
9use crate::style::{Color, Modifier, Style};
10
11#[derive(Debug, Clone, PartialEq)]
13pub struct Cell {
14 pub symbol: String,
15 pub style: Style,
16}
17
18impl Cell {
19 pub fn set_symbol(&mut self, symbol: &str) -> &mut Cell {
20 self.symbol.clear();
21 self.symbol.push_str(symbol);
22 self
23 }
24
25 pub fn set_char(&mut self, ch: char) -> &mut Cell {
26 self.symbol.clear();
27 self.symbol.push(ch);
28 self
29 }
30
31 pub fn set_fg(&mut self, color: Color) -> &mut Cell {
32 self.style.fg = color;
33 self
34 }
35
36 pub fn set_bg(&mut self, color: Color) -> &mut Cell {
37 self.style.bg = color;
38 self
39 }
40
41 pub fn set_modifier(&mut self, modifier: Modifier) -> &mut Cell {
42 self.style.modifier = modifier;
43 self
44 }
45
46 pub fn set_style(&mut self, style: Style) -> &mut Cell {
47 self.style = style;
48 self
49 }
50
51 pub fn reset(&mut self) {
52 self.symbol.clear();
53 self.symbol.push(' ');
54 self.style.reset();
55 }
56}
57
58impl Default for Cell {
59 fn default() -> Cell {
60 Cell {
61 symbol: " ".into(),
62 style: Default::default(),
63 }
64 }
65}
66
67#[derive(Clone, PartialEq)]
98pub struct Buffer {
99 pub area: Rect,
101 pub content: Vec<Cell>,
104}
105
106impl Default for Buffer {
107 fn default() -> Buffer {
108 Buffer {
109 area: Default::default(),
110 content: Vec::new(),
111 }
112 }
113}
114
115impl fmt::Debug for Buffer {
116 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
117 writeln!(f, "Buffer: {:?}", self.area)?;
118 f.write_str("Content (quoted lines):\n")?;
119 for cells in self.content.chunks(self.area.width as usize) {
120 let mut line = String::new();
121 let mut overwritten = vec![];
122 let mut skip: usize = 0;
123 for (x, c) in cells.iter().enumerate() {
124 if skip == 0 {
125 line.push_str(&c.symbol);
126 } else {
127 overwritten.push((x, &c.symbol))
128 }
129 skip = std::cmp::max(skip, c.symbol.width()).saturating_sub(1);
130 }
131 f.write_fmt(format_args!("{:?},", line))?;
132 if !overwritten.is_empty() {
133 f.write_fmt(format_args!(
134 " Hidden by multi-width symbols: {:?}",
135 overwritten
136 ))?;
137 }
138 f.write_str("\n")?;
139 }
140 f.write_str("Style:\n")?;
141 for cells in self.content.chunks(self.area.width as usize) {
142 f.write_str("|")?;
143 for cell in cells {
144 write!(
145 f,
146 "{} {} {}|",
147 cell.style.fg.code(),
148 cell.style.bg.code(),
149 cell.style.modifier.code()
150 )?;
151 }
152 f.write_str("\n")?;
153 }
154 Ok(())
155 }
156}
157
158impl Buffer {
159 pub fn empty(area: Rect) -> Buffer {
161 let cell: Cell = Default::default();
162 Buffer::filled(area, &cell)
163 }
164
165 pub fn filled(area: Rect, cell: &Cell) -> Buffer {
167 let size = area.area() as usize;
168 let mut content = Vec::with_capacity(size);
169 for _ in 0..size {
170 content.push(cell.clone());
171 }
172 Buffer { area, content }
173 }
174
175 pub fn with_lines<S>(lines: Vec<S>) -> Buffer
177 where
178 S: AsRef<str>,
179 {
180 let height = lines.len() as u16;
181 let width = lines.iter().fold(0, |acc, item| {
182 std::cmp::max(acc, item.as_ref().width() as u16)
183 });
184 let mut buffer = Buffer::empty(Rect {
185 x: 0,
186 y: 0,
187 width,
188 height,
189 });
190 for (y, line) in lines.iter().enumerate() {
191 buffer.set_string(0, y as u16, line, Style::default());
192 }
193 buffer
194 }
195
196 pub fn content(&self) -> &[Cell] {
198 &self.content
199 }
200
201 pub fn area(&self) -> &Rect {
203 &self.area
204 }
205
206 pub fn get(&self, x: u16, y: u16) -> &Cell {
208 let i = self.index_of(x, y);
209 &self.content[i]
210 }
211
212 pub fn get_mut(&mut self, x: u16, y: u16) -> &mut Cell {
214 let i = self.index_of(x, y);
215 &mut self.content[i]
216 }
217
218 pub fn index_of(&self, x: u16, y: u16) -> usize {
247 debug_assert!(
248 x >= self.area.left()
249 && x < self.area.right()
250 && y >= self.area.top()
251 && y < self.area.bottom(),
252 "Trying to access position outside the buffer: x={}, y={}, area={:?}",
253 x,
254 y,
255 self.area
256 );
257 ((y - self.area.y) * self.area.width + (x - self.area.x)) as usize
258 }
259
260 pub fn pos_of(&self, i: usize) -> (u16, u16) {
288 debug_assert!(
289 i < self.content.len(),
290 "Trying to get the coords of a cell outside the buffer: i={} len={}",
291 i,
292 self.content.len()
293 );
294 (
295 self.area.x + i as u16 % self.area.width,
296 self.area.y + i as u16 / self.area.width,
297 )
298 }
299
300 pub fn set_string<S>(&mut self, x: u16, y: u16, string: S, style: Style)
302 where
303 S: AsRef<str>,
304 {
305 self.set_stringn(x, y, string, usize::MAX, style);
306 }
307
308 pub fn set_stringn<S>(&mut self, x: u16, y: u16, string: S, width: usize, style: Style)
311 where
312 S: AsRef<str>,
313 {
314 let mut index = self.index_of(x, y);
315 let mut x_offset = x as usize;
316 let graphemes = UnicodeSegmentation::graphemes(string.as_ref(), true);
317 let max_offset = min(self.area.right() as usize, width.saturating_add(x as usize));
318 for s in graphemes {
319 let width = s.width();
320 if width > max_offset.saturating_sub(x_offset) {
323 break;
324 }
325
326 self.content[index].set_symbol(s);
327 self.content[index].set_style(style);
328 for i in index + 1..index + width {
330 self.content[i].reset();
331 }
332 index += width;
333 x_offset += width;
334 }
335 }
336
337 pub fn resize(&mut self, area: Rect) {
340 let length = area.area() as usize;
341 if self.content.len() > length {
342 self.content.truncate(length);
343 } else {
344 self.content.resize(length, Default::default());
345 }
346 self.area = area;
347 }
348
349 pub fn reset(&mut self) {
351 for c in &mut self.content {
352 c.reset();
353 }
354 }
355
356 pub fn merge(&mut self, other: &Buffer) {
358 let area = self.area.union(other.area);
359 let cell: Cell = Default::default();
360 self.content.resize(area.area() as usize, cell.clone());
361
362 let size = self.area.area() as usize;
364 for i in (0..size).rev() {
365 let (x, y) = self.pos_of(i);
366 let k = ((y - area.y) * area.width + x - area.x) as usize;
368 if i != k {
369 self.content[k] = self.content[i].clone();
370 self.content[i] = cell.clone();
371 }
372 }
373
374 let size = other.area.area() as usize;
377 for i in 0..size {
378 let (x, y) = other.pos_of(i);
379 let k = ((y - area.y) * area.width + x - area.x) as usize;
381 self.content[k] = other.content[i].clone();
382 }
383 self.area = area;
384 }
385
386 pub fn diff<'a>(&self, other: &'a Buffer) -> Vec<(u16, u16, &'a Cell)> {
415 let previous_buffer = &self.content;
416 let next_buffer = &other.content;
417 let width = self.area.width;
418
419 let mut updates: Vec<(u16, u16, &Cell)> = vec![];
420 let mut invalidated: usize = 0;
422 let mut to_skip: usize = 0;
425 for (i, (current, previous)) in next_buffer.iter().zip(previous_buffer.iter()).enumerate() {
426 if (current != previous || invalidated > 0) && to_skip == 0 {
427 let x = i as u16 % width;
428 let y = i as u16 / width;
429 updates.push((x, y, &next_buffer[i]));
430 }
431
432 to_skip = current.symbol.width().saturating_sub(1);
433
434 let affected_width = std::cmp::max(current.symbol.width(), previous.symbol.width());
435 invalidated = std::cmp::max(affected_width, invalidated).saturating_sub(1);
436 }
437 updates
438 }
439}
440
441#[cfg(test)]
442mod tests {
443 use super::*;
444
445 fn cell(s: &str) -> Cell {
446 let mut cell = Cell::default();
447 cell.set_symbol(s);
448 cell
449 }
450
451 #[test]
452 fn it_translates_to_and_from_coordinates() {
453 let rect = Rect::new(200, 100, 50, 80);
454 let buf = Buffer::empty(rect);
455
456 assert_eq!(buf.pos_of(0), (200, 100));
458 assert_eq!(buf.index_of(200, 100), 0);
459
460 assert_eq!(buf.pos_of(buf.content.len() - 1), (249, 179));
462 assert_eq!(buf.index_of(249, 179), buf.content.len() - 1);
463 }
464
465 #[test]
466 #[should_panic(expected = "outside the buffer")]
467 fn pos_of_panics_on_out_of_bounds() {
468 let rect = Rect::new(0, 0, 10, 10);
469 let buf = Buffer::empty(rect);
470
471 buf.pos_of(100);
473 }
474
475 #[test]
476 #[should_panic(expected = "outside the buffer")]
477 fn index_of_panics_on_out_of_bounds() {
478 let rect = Rect::new(0, 0, 10, 10);
479 let buf = Buffer::empty(rect);
480
481 buf.index_of(10, 0);
483 }
484
485 #[test]
486 fn buffer_set_string() {
487 let area = Rect::new(0, 0, 5, 1);
488 let mut buffer = Buffer::empty(area);
489
490 buffer.set_stringn(0, 0, "aaa", 0, Style::default());
492 assert_eq!(buffer, Buffer::with_lines(vec![" "]));
493
494 buffer.set_string(0, 0, "aaa", Style::default());
495 assert_eq!(buffer, Buffer::with_lines(vec!["aaa "]));
496
497 buffer.set_stringn(0, 0, "bbbbbbbbbbbbbb", 4, Style::default());
499 assert_eq!(buffer, Buffer::with_lines(vec!["bbbb "]));
500
501 buffer.set_string(0, 0, "12345", Style::default());
502 assert_eq!(buffer, Buffer::with_lines(vec!["12345"]));
503
504 buffer.set_string(0, 0, "123456", Style::default());
506 assert_eq!(buffer, Buffer::with_lines(vec!["12345"]));
507 }
508
509 #[test]
510 fn buffer_set_string_double_width() {
511 let area = Rect::new(0, 0, 5, 1);
512 let mut buffer = Buffer::empty(area);
513 buffer.set_string(0, 0, "コン", Style::default());
514 assert_eq!(buffer, Buffer::with_lines(vec!["コン "]));
515
516 buffer.set_string(0, 0, "コンピ", Style::default());
518 assert_eq!(buffer, Buffer::with_lines(vec!["コン "]));
519 }
520
521 #[test]
522 fn buffer_with_lines() {
523 let buffer =
524 Buffer::with_lines(vec!["┌────────┐", "│コンピュ│", "│ーa 上で│", "└────────┘"]);
525 assert_eq!(buffer.area.x, 0);
526 assert_eq!(buffer.area.y, 0);
527 assert_eq!(buffer.area.width, 10);
528 assert_eq!(buffer.area.height, 4);
529 }
530
531 #[test]
532 fn buffer_diffing_empty_empty() {
533 let area = Rect::new(0, 0, 40, 40);
534 let prev = Buffer::empty(area);
535 let next = Buffer::empty(area);
536 let diff = prev.diff(&next);
537 assert_eq!(diff, vec![]);
538 }
539
540 #[test]
541 fn buffer_diffing_empty_filled() {
542 let area = Rect::new(0, 0, 40, 40);
543 let prev = Buffer::empty(area);
544 let next = Buffer::filled(area, Cell::default().set_symbol("a"));
545 let diff = prev.diff(&next);
546 assert_eq!(diff.len(), 40 * 40);
547 }
548
549 #[test]
550 fn buffer_diffing_filled_filled() {
551 let area = Rect::new(0, 0, 40, 40);
552 let prev = Buffer::filled(area, Cell::default().set_symbol("a"));
553 let next = Buffer::filled(area, Cell::default().set_symbol("a"));
554 let diff = prev.diff(&next);
555 assert_eq!(diff, vec![]);
556 }
557
558 #[test]
559 fn buffer_diffing_single_width() {
560 let prev = Buffer::with_lines(vec![
561 " ",
562 "┌Title─┐ ",
563 "│ │ ",
564 "│ │ ",
565 "└──────┘ ",
566 ]);
567 let next = Buffer::with_lines(vec![
568 " ",
569 "┌TITLE─┐ ",
570 "│ │ ",
571 "│ │ ",
572 "└──────┘ ",
573 ]);
574 let diff = prev.diff(&next);
575 assert_eq!(
576 diff,
577 vec![
578 (2, 1, &cell("I")),
579 (3, 1, &cell("T")),
580 (4, 1, &cell("L")),
581 (5, 1, &cell("E")),
582 ]
583 );
584 }
585
586 #[test]
587 #[rustfmt::skip]
588 fn buffer_diffing_multi_width() {
589 let prev = Buffer::with_lines(vec![
590 "┌Title─┐ ",
591 "└──────┘ ",
592 ]);
593 let next = Buffer::with_lines(vec![
594 "┌称号──┐ ",
595 "└──────┘ ",
596 ]);
597 let diff = prev.diff(&next);
598 assert_eq!(
599 diff,
600 vec![
601 (1, 0, &cell("称")),
602 (3, 0, &cell("号")),
604 (5, 0, &cell("─")),
606 ]
607 );
608 }
609
610 #[test]
611 fn buffer_diffing_multi_width_offset() {
612 let prev = Buffer::with_lines(vec!["┌称号──┐"]);
613 let next = Buffer::with_lines(vec!["┌─称号─┐"]);
614
615 let diff = prev.diff(&next);
616 assert_eq!(
617 diff,
618 vec![(1, 0, &cell("─")), (2, 0, &cell("称")), (4, 0, &cell("号")),]
619 );
620 }
621
622 #[test]
623 fn buffer_merge() {
624 let mut one = Buffer::filled(
625 Rect {
626 x: 0,
627 y: 0,
628 width: 2,
629 height: 2,
630 },
631 Cell::default().set_symbol("1"),
632 );
633 let two = Buffer::filled(
634 Rect {
635 x: 0,
636 y: 2,
637 width: 2,
638 height: 2,
639 },
640 Cell::default().set_symbol("2"),
641 );
642 one.merge(&two);
643 assert_eq!(one, Buffer::with_lines(vec!["11", "11", "22", "22"]));
644 }
645
646 #[test]
647 fn buffer_merge2() {
648 let mut one = Buffer::filled(
649 Rect {
650 x: 2,
651 y: 2,
652 width: 2,
653 height: 2,
654 },
655 Cell::default().set_symbol("1"),
656 );
657 let two = Buffer::filled(
658 Rect {
659 x: 0,
660 y: 0,
661 width: 2,
662 height: 2,
663 },
664 Cell::default().set_symbol("2"),
665 );
666 one.merge(&two);
667 assert_eq!(
668 one,
669 Buffer::with_lines(vec!["22 ", "22 ", " 11", " 11"])
670 );
671 }
672
673 #[test]
674 fn buffer_merge3() {
675 let mut one = Buffer::filled(
676 Rect {
677 x: 3,
678 y: 3,
679 width: 2,
680 height: 2,
681 },
682 Cell::default().set_symbol("1"),
683 );
684 let two = Buffer::filled(
685 Rect {
686 x: 1,
687 y: 1,
688 width: 3,
689 height: 4,
690 },
691 Cell::default().set_symbol("2"),
692 );
693 one.merge(&two);
694 let mut merged = Buffer::with_lines(vec!["222 ", "222 ", "2221", "2221"]);
695 merged.area = Rect {
696 x: 1,
697 y: 1,
698 width: 4,
699 height: 4,
700 };
701 assert_eq!(one, merged);
702 }
703}