1use crate::geometry::Rect;
4use crate::style::Style;
5use alloc::string::String;
6use alloc::vec::Vec;
7use core::fmt;
8use unicode_width::UnicodeWidthStr;
9
10#[cfg(feature = "serde")]
11use serde::{Deserialize, Serialize};
12
13#[derive(Debug, Clone, PartialEq, Eq)]
17#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
18pub struct Cell {
19 pub symbol: String,
21 pub style: Style,
23 pub skip: bool,
25}
26
27impl Default for Cell {
28 fn default() -> Self {
29 Self {
30 symbol: String::from(" "),
31 style: Style::default(),
32 skip: false,
33 }
34 }
35}
36
37impl Cell {
38 #[must_use]
49 pub fn new(symbol: impl Into<String>, style: Style) -> Self {
50 Self {
51 symbol: symbol.into(),
52 style,
53 skip: false,
54 }
55 }
56
57 pub fn reset(&mut self) {
59 self.symbol.clear();
60 self.symbol.push(' ');
61 self.style = Style::default();
62 self.skip = false;
63 }
64
65 pub fn set_symbol(&mut self, symbol: impl Into<String>) {
67 self.symbol = symbol.into();
68 }
69
70 pub fn set_style(&mut self, style: Style) {
72 self.style = style;
73 }
74
75 #[must_use]
77 pub fn width(&self) -> usize {
78 self.symbol.width()
79 }
80}
81
82#[derive(Debug, Clone, PartialEq, Eq)]
98#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
99pub struct Buffer {
100 pub area: Rect,
102 pub content: Vec<Cell>,
104}
105
106impl Buffer {
107 #[must_use]
111 pub fn empty(area: Rect) -> Self {
112 let cell_count = area.area() as usize;
113 Self {
114 area,
115 content: vec![Cell::default(); cell_count],
116 }
117 }
118
119 #[must_use]
121 pub fn filled(area: Rect, cell: &Cell) -> Self {
122 let cell_count = area.area() as usize;
123 Self {
124 area,
125 content: vec![cell.clone(); cell_count],
126 }
127 }
128
129 #[must_use]
133 pub const fn index_of(&self, x: u16, y: u16) -> Option<usize> {
134 if x >= self.area.x
135 && x < self.area.x + self.area.width
136 && y >= self.area.y
137 && y < self.area.y + self.area.height
138 {
139 let row = (y - self.area.y) as usize;
140 let col = (x - self.area.x) as usize;
141 Some(row * self.area.width as usize + col)
142 } else {
143 None
144 }
145 }
146
147 #[must_use]
149 pub fn get(&self, x: u16, y: u16) -> Option<&Cell> {
150 self.index_of(x, y).and_then(|i| self.content.get(i))
151 }
152
153 pub fn get_mut(&mut self, x: u16, y: u16) -> Option<&mut Cell> {
155 if let Some(i) = self.index_of(x, y) {
156 self.content.get_mut(i)
157 } else {
158 None
159 }
160 }
161
162 pub fn set(&mut self, x: u16, y: u16, symbol: impl Into<String>, style: Style) -> bool {
177 if let Some(cell) = self.get_mut(x, y) {
178 let symbol = symbol.into();
179 let width = symbol.width();
180 cell.symbol = symbol;
181 cell.style = style;
182 cell.skip = false;
183
184 if width > 1 {
186 for i in 1..width {
187 if let Some(next_cell) = self.get_mut(x + i as u16, y) {
188 next_cell.reset();
189 next_cell.skip = true;
190 }
191 }
192 }
193 true
194 } else {
195 false
196 }
197 }
198
199 pub fn set_string(&mut self, x: u16, y: u16, string: &str, style: Style) -> u16 {
215 let mut x = x;
216 for grapheme in unicode_segmentation::UnicodeSegmentation::graphemes(string, true) {
217 if x >= self.area.right() {
218 break;
219 }
220 self.set(x, y, grapheme, style);
221 x += grapheme.width() as u16;
222 }
223 x
224 }
225
226 pub fn set_styled_string(&mut self, x: u16, y: u16, string: &str, style: Style) -> u16 {
230 self.set_string(x, y, string, style)
231 }
232
233 pub fn clear(&mut self) {
235 for cell in &mut self.content {
236 cell.reset();
237 }
238 }
239
240 pub fn clear_region(&mut self, region: Rect) {
242 let region = self.area.intersection(region);
243 for y in region.top()..region.bottom() {
244 for x in region.left()..region.right() {
245 if let Some(cell) = self.get_mut(x, y) {
246 cell.reset();
247 }
248 }
249 }
250 }
251
252 pub fn set_style(&mut self, _style: Style) {
254 }
256
257 pub fn resize(&mut self, area: Rect) {
261 if area == self.area {
262 return;
263 }
264
265 let mut new_buffer = Self::empty(area);
266 let intersection = self.area.intersection(area);
267
268 for y in intersection.top()..intersection.bottom() {
270 for x in intersection.left()..intersection.right() {
271 if let Some(cell) = self.get(x, y) {
272 if let Some(idx) = new_buffer.index_of(x, y) {
273 new_buffer.content[idx] = cell.clone();
274 }
275 }
276 }
277 }
278
279 *self = new_buffer;
280 }
281
282 pub fn merge(&mut self, other: &Self) {
284 let area = self.area.intersection(other.area);
285 for y in area.top()..area.bottom() {
286 for x in area.left()..area.right() {
287 if let Some(cell) = other.get(x, y) {
288 if !cell.skip {
289 self.set(x, y, cell.symbol.as_str(), cell.style);
290 }
291 }
292 }
293 }
294 }
295
296 #[must_use]
300 pub fn diff<'a>(&'a self, other: &'a Self) -> Vec<Diff<'a>> {
301 let mut diffs = Vec::new();
302
303 if self.area != other.area {
304 for y in other.area.top()..other.area.bottom() {
306 let mut start_x = None;
307 let mut current_style = None;
308
309 for x in other.area.left()..other.area.right() {
310 if let Some(cell) = other.get(x, y) {
311 if cell.skip {
312 continue;
313 }
314
315 if start_x.is_none() {
316 start_x = Some(x);
317 current_style = Some(cell.style);
318 }
319
320 if Some(cell.style) != current_style {
321 if let Some(sx) = start_x {
323 diffs.push(Diff {
324 x: sx,
325 y,
326 cells: Vec::new(), });
328 }
329 start_x = Some(x);
330 current_style = Some(cell.style);
331 }
332 }
333 }
334 }
335 return diffs;
336 }
337
338 for y in self.area.top()..self.area.bottom() {
340 let mut x = self.area.left();
341 while x < self.area.right() {
342 let old_cell = self.get(x, y);
343 let new_cell = other.get(x, y);
344
345 if old_cell != new_cell {
346 if let Some(new_cell) = new_cell {
347 diffs.push(Diff {
348 x,
349 y,
350 cells: alloc::vec![new_cell],
351 });
352 }
353 }
354 x += 1;
355 }
356 }
357
358 diffs
359 }
360}
361
362impl fmt::Display for Buffer {
363 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
364 for y in self.area.top()..self.area.bottom() {
365 for x in self.area.left()..self.area.right() {
366 if let Some(cell) = self.get(x, y) {
367 if !cell.skip {
368 write!(f, "{}", cell.symbol)?;
369 }
370 }
371 }
372 if y < self.area.bottom() - 1 {
373 writeln!(f)?;
374 }
375 }
376 Ok(())
377 }
378}
379
380#[derive(Debug, Clone)]
382pub struct Diff<'a> {
383 pub x: u16,
385 pub y: u16,
387 pub cells: Vec<&'a Cell>,
389}
390
391#[cfg(test)]
392mod tests {
393 use super::*;
394 use crate::style::Color;
395
396 #[test]
397 fn test_buffer_set_get() {
398 let mut buffer = Buffer::empty(Rect::new(0, 0, 10, 10));
399 buffer.set(5, 5, "X", Style::default());
400
401 let cell = buffer.get(5, 5).unwrap();
402 assert_eq!(cell.symbol, "X");
403 }
404
405 #[test]
406 fn test_buffer_set_string() {
407 let mut buffer = Buffer::empty(Rect::new(0, 0, 20, 5));
408 let end_x = buffer.set_string(0, 0, "Hello", Style::default());
409
410 assert_eq!(end_x, 5);
411 assert_eq!(buffer.get(0, 0).unwrap().symbol, "H");
412 assert_eq!(buffer.get(4, 0).unwrap().symbol, "o");
413 }
414
415 #[test]
416 fn test_buffer_clear() {
417 let mut buffer = Buffer::empty(Rect::new(0, 0, 10, 10));
418 buffer.set(5, 5, "X", Style::default().fg(Color::Red));
419 buffer.clear();
420
421 let cell = buffer.get(5, 5).unwrap();
422 assert_eq!(cell.symbol, " ");
423 assert_eq!(cell.style, Style::default());
424 }
425
426 #[test]
427 fn test_buffer_merge() {
428 let mut base = Buffer::empty(Rect::new(0, 0, 10, 10));
429 let mut overlay = Buffer::empty(Rect::new(0, 0, 10, 10));
430
431 overlay.set(5, 5, "O", Style::default());
432 base.merge(&overlay);
433
434 assert_eq!(base.get(5, 5).unwrap().symbol, "O");
435 }
436}