ratatui_toolkit/primitives/termtui/
cell.rs

1//! Terminal cell representation
2
3use crate::primitives::termtui::attrs::Attrs;
4use ratatui::buffer::Cell as RatatuiCell;
5use unicode_width::UnicodeWidthChar;
6
7/// A single terminal cell
8#[derive(Clone, Debug, Default)]
9pub struct Cell {
10    /// Cell text (may contain combining characters)
11    text: String,
12    /// Cell attributes
13    attrs: Attrs,
14}
15
16impl Cell {
17    /// Create a new empty cell
18    pub fn new() -> Self {
19        Self {
20            text: " ".to_string(),
21            attrs: Attrs::default(),
22        }
23    }
24
25    /// Create a cell with specific attributes
26    pub fn with_attrs(attrs: Attrs) -> Self {
27        Self {
28            text: " ".to_string(),
29            attrs,
30        }
31    }
32
33    /// Get the cell text
34    pub fn text(&self) -> &str {
35        &self.text
36    }
37
38    /// Set the cell text
39    pub fn set_text(&mut self, text: impl Into<String>) {
40        self.text = text.into();
41    }
42
43    /// Get the cell attributes
44    pub fn attrs(&self) -> &Attrs {
45        &self.attrs
46    }
47
48    /// Get mutable reference to attributes
49    pub fn attrs_mut(&mut self) -> &mut Attrs {
50        &mut self.attrs
51    }
52
53    /// Set the cell attributes
54    pub fn set_attrs(&mut self, attrs: Attrs) {
55        self.attrs = attrs;
56    }
57
58    /// Get the display width of this cell
59    pub fn width(&self) -> usize {
60        self.text
61            .chars()
62            .next()
63            .and_then(|c| c.width())
64            .unwrap_or(1)
65    }
66
67    /// Check if this cell is a wide character continuation
68    /// (placeholder for second column of wide char)
69    pub fn is_wide_continuation(&self) -> bool {
70        self.text.is_empty()
71    }
72
73    /// Set this cell as a wide character continuation
74    pub fn set_wide_continuation(&mut self) {
75        self.text.clear();
76    }
77
78    /// Clear the cell (reset to space with default attrs)
79    pub fn clear(&mut self) {
80        self.text = " ".to_string();
81        self.attrs = Attrs::default();
82    }
83
84    /// Clear the cell but keep attributes
85    pub fn clear_keep_attrs(&mut self) {
86        self.text = " ".to_string();
87    }
88
89    /// Convert to ratatui cell
90    pub fn to_ratatui(&self) -> RatatuiCell {
91        let mut cell = RatatuiCell::default();
92
93        // Get the first character or space
94        let ch = self.text.chars().next().unwrap_or(' ');
95        cell.set_char(ch);
96        cell.set_style(self.attrs.to_ratatui());
97
98        cell
99    }
100}
101
102impl PartialEq for Cell {
103    fn eq(&self, other: &Self) -> bool {
104        self.text == other.text && self.attrs == other.attrs
105    }
106}
107
108impl Eq for Cell {}
109
110#[cfg(test)]
111mod tests {
112    use super::*;
113
114    #[test]
115    fn test_cell_new() {
116        let cell = Cell::new();
117        assert_eq!(cell.text(), " ");
118        assert_eq!(cell.width(), 1);
119    }
120
121    #[test]
122    fn test_cell_set_text() {
123        let mut cell = Cell::new();
124        cell.set_text("A");
125        assert_eq!(cell.text(), "A");
126    }
127
128    #[test]
129    fn test_cell_wide_char() {
130        let mut cell = Cell::new();
131        cell.set_text("你");
132        assert_eq!(cell.width(), 2);
133    }
134
135    #[test]
136    fn test_cell_clear() {
137        let mut cell = Cell::new();
138        cell.set_text("X");
139        cell.attrs_mut().set_bold(true);
140
141        cell.clear();
142        assert_eq!(cell.text(), " ");
143        assert!(!cell.attrs().bold());
144    }
145
146    #[test]
147    fn test_cell_to_ratatui() {
148        let mut cell = Cell::new();
149        cell.set_text("A");
150        cell.attrs_mut().set_bold(true);
151
152        let ratatui_cell = cell.to_ratatui();
153        assert_eq!(ratatui_cell.symbol(), "A");
154    }
155}