Skip to main content

spec_ai/spec_ai_tui/buffer/
cell.rs

1//! A single terminal cell with content and style
2
3use crate::spec_ai_tui::style::{Color, Modifier, Style};
4
5/// A single terminal cell with content and style
6#[derive(Debug, Clone, PartialEq, Eq)]
7pub struct Cell {
8    /// The character(s) displayed (supports Unicode grapheme clusters)
9    pub symbol: String,
10    /// Foreground color
11    pub fg: Color,
12    /// Background color
13    pub bg: Color,
14    /// Style modifiers (bold, italic, etc.)
15    pub modifier: Modifier,
16}
17
18impl Cell {
19    /// Create a new empty cell (space character, default style)
20    pub fn empty() -> Self {
21        Self {
22            symbol: " ".to_string(),
23            fg: Color::Reset,
24            bg: Color::Reset,
25            modifier: Modifier::empty(),
26        }
27    }
28
29    /// Create a cell with a single character
30    pub fn new<S: Into<String>>(symbol: S) -> Self {
31        Self {
32            symbol: symbol.into(),
33            fg: Color::Reset,
34            bg: Color::Reset,
35            modifier: Modifier::empty(),
36        }
37    }
38
39    /// Set foreground color
40    pub fn fg(mut self, color: Color) -> Self {
41        self.fg = color;
42        self
43    }
44
45    /// Set background color
46    pub fn bg(mut self, color: Color) -> Self {
47        self.bg = color;
48        self
49    }
50
51    /// Set modifier
52    pub fn modifier(mut self, modifier: Modifier) -> Self {
53        self.modifier = modifier;
54        self
55    }
56
57    /// Apply a style to this cell
58    pub fn style(mut self, style: Style) -> Self {
59        self.fg = style.fg;
60        self.bg = style.bg;
61        self.modifier = style.modifier;
62        self
63    }
64
65    /// Set the symbol
66    pub fn set_symbol<S: Into<String>>(&mut self, symbol: S) {
67        self.symbol = symbol.into();
68    }
69
70    /// Set the style from a Style struct
71    pub fn set_style(&mut self, style: Style) {
72        self.fg = style.fg;
73        self.bg = style.bg;
74        self.modifier = style.modifier;
75    }
76
77    /// Reset the cell to empty
78    pub fn reset(&mut self) {
79        self.symbol = " ".to_string();
80        self.fg = Color::Reset;
81        self.bg = Color::Reset;
82        self.modifier = Modifier::empty();
83    }
84
85    /// Get the style as a Style struct
86    pub fn get_style(&self) -> Style {
87        Style {
88            fg: self.fg,
89            bg: self.bg,
90            modifier: self.modifier,
91        }
92    }
93}
94
95impl Default for Cell {
96    fn default() -> Self {
97        Self::empty()
98    }
99}
100
101impl From<char> for Cell {
102    fn from(c: char) -> Self {
103        Self::new(c.to_string())
104    }
105}
106
107#[cfg(test)]
108mod tests {
109    use super::*;
110
111    #[test]
112    fn test_cell_empty() {
113        let cell = Cell::empty();
114        assert_eq!(cell.symbol, " ");
115        assert_eq!(cell.fg, Color::Reset);
116        assert_eq!(cell.bg, Color::Reset);
117        assert!(cell.modifier.is_empty());
118    }
119
120    #[test]
121    fn test_cell_new() {
122        let cell = Cell::new("X");
123        assert_eq!(cell.symbol, "X");
124    }
125
126    #[test]
127    fn test_cell_builder() {
128        let cell = Cell::new("A")
129            .fg(Color::Red)
130            .bg(Color::Blue)
131            .modifier(Modifier::BOLD);
132
133        assert_eq!(cell.symbol, "A");
134        assert_eq!(cell.fg, Color::Red);
135        assert_eq!(cell.bg, Color::Blue);
136        assert!(cell.modifier.contains(Modifier::BOLD));
137    }
138
139    #[test]
140    fn test_cell_reset() {
141        let mut cell = Cell::new("X").fg(Color::Red);
142        cell.reset();
143        assert_eq!(cell.symbol, " ");
144        assert_eq!(cell.fg, Color::Reset);
145    }
146
147    #[test]
148    fn test_cell_style() {
149        let style = Style::new().fg(Color::Green).bold();
150        let cell = Cell::new("Y").style(style);
151
152        assert_eq!(cell.fg, Color::Green);
153        assert!(cell.modifier.contains(Modifier::BOLD));
154    }
155}