ratatui_toolkit/primitives/termtui/
row.rs1use crate::primitives::termtui::attrs::Attrs;
4use crate::primitives::termtui::cell::Cell;
5
6#[derive(Clone, Debug)]
8pub struct Row {
9 cells: Vec<Cell>,
11 size: u16,
13 wrapped: bool,
15}
16
17impl Row {
18 pub fn new(width: u16) -> Self {
20 Self {
21 cells: (0..width).map(|_| Cell::new()).collect(),
22 size: 0,
23 wrapped: false,
24 }
25 }
26
27 pub fn new_with_attrs(width: u16, attrs: Attrs) -> Self {
29 Self {
30 cells: (0..width).map(|_| Cell::with_attrs(attrs)).collect(),
31 size: 0,
32 wrapped: false,
33 }
34 }
35
36 pub fn width(&self) -> u16 {
38 self.cells.len() as u16
39 }
40
41 pub fn get(&self, col: u16) -> Option<&Cell> {
43 self.cells.get(col as usize)
44 }
45
46 pub fn get_mut(&mut self, col: u16) -> Option<&mut Cell> {
48 if col >= self.size {
50 self.size = col + 1;
51 }
52 self.cells.get_mut(col as usize)
53 }
54
55 pub fn insert(&mut self, col: u16, cell: Cell) {
57 let col = col as usize;
58 if col < self.cells.len() {
59 self.cells.insert(col, cell);
60 self.cells.pop(); }
62 }
63
64 pub fn remove(&mut self, col: u16) {
66 let col = col as usize;
67 if col < self.cells.len() {
68 self.cells.remove(col);
69 self.cells.push(Cell::new()); }
71 }
72
73 pub fn clear(&mut self) {
75 for cell in &mut self.cells {
76 cell.clear();
77 }
78 self.size = 0;
79 self.wrapped = false;
80 }
81
82 pub fn erase(&mut self, start: u16, end: u16) {
84 let start = start as usize;
85 let end = (end as usize).min(self.cells.len());
86
87 for cell in &mut self.cells[start..end] {
88 cell.clear();
89 }
90 }
91
92 pub fn resize(&mut self, new_width: u16) {
94 let new_width = new_width as usize;
95 if new_width > self.cells.len() {
96 self.cells.resize_with(new_width, Cell::new);
97 } else {
98 self.cells.truncate(new_width);
99 }
100 }
101
102 pub fn wrapped(&self) -> bool {
104 self.wrapped
105 }
106
107 pub fn set_wrapped(&mut self, wrapped: bool) {
109 self.wrapped = wrapped;
110 }
111
112 pub fn is_wide_continuation(&self, col: u16) -> bool {
114 self.cells
115 .get(col as usize)
116 .map(|c| c.is_wide_continuation())
117 .unwrap_or(false)
118 }
119
120 pub fn clear_wide(&mut self, col: u16) {
122 let col = col as usize;
123 if col < self.cells.len() {
124 if self.cells[col].width() == 2 && col + 1 < self.cells.len() {
126 self.cells[col].clear();
127 self.cells[col + 1].clear();
128 } else if col > 0 && self.cells[col].is_wide_continuation() {
129 self.cells[col - 1].clear();
131 self.cells[col].clear();
132 } else {
133 self.cells[col].clear();
134 }
135 }
136 }
137
138 pub fn write_contents(&self, output: &mut String, start: u16, end: u16) {
140 let start = start as usize;
141 let end = (end as usize).min(self.cells.len());
142
143 for cell in &self.cells[start..end] {
144 if !cell.is_wide_continuation() {
145 output.push_str(cell.text());
146 }
147 }
148 }
149
150 pub fn contents_trimmed(&self) -> String {
152 let mut output = String::new();
153 self.write_contents(&mut output, 0, self.width());
154 output.trim_end().to_string()
155 }
156
157 pub fn cells(&self) -> impl Iterator<Item = &Cell> {
159 self.cells.iter()
160 }
161
162 pub fn used_width(&self) -> u16 {
164 self.size
165 }
166}
167
168impl Default for Row {
169 fn default() -> Self {
170 Self::new(80)
171 }
172}
173
174#[cfg(test)]
175mod tests {
176 use super::*;
177
178 #[test]
179 fn test_row_new() {
180 let row = Row::new(80);
181 assert_eq!(row.width(), 80);
182 assert!(!row.wrapped());
183 }
184
185 #[test]
186 fn test_row_get_set() {
187 let mut row = Row::new(80);
188
189 if let Some(cell) = row.get_mut(5) {
190 cell.set_text("X");
191 }
192
193 assert_eq!(row.get(5).map(|c| c.text()), Some("X"));
194 }
195
196 #[test]
197 fn test_row_clear() {
198 let mut row = Row::new(80);
199
200 if let Some(cell) = row.get_mut(5) {
201 cell.set_text("X");
202 }
203
204 row.clear();
205 assert_eq!(row.get(5).map(|c| c.text()), Some(" "));
206 }
207
208 #[test]
209 fn test_row_erase() {
210 let mut row = Row::new(80);
211
212 for i in 0..10 {
213 if let Some(cell) = row.get_mut(i) {
214 cell.set_text("X");
215 }
216 }
217
218 row.erase(3, 7);
219 assert_eq!(row.get(2).map(|c| c.text()), Some("X"));
220 assert_eq!(row.get(3).map(|c| c.text()), Some(" "));
221 assert_eq!(row.get(6).map(|c| c.text()), Some(" "));
222 assert_eq!(row.get(7).map(|c| c.text()), Some("X"));
223 }
224
225 #[test]
226 fn test_row_contents() {
227 let mut row = Row::new(80);
228
229 for (i, c) in "Hello".chars().enumerate() {
230 if let Some(cell) = row.get_mut(i as u16) {
231 cell.set_text(c.to_string());
232 }
233 }
234
235 let contents = row.contents_trimmed();
236 assert_eq!(contents, "Hello");
237 }
238
239 #[test]
240 fn test_row_wrapped() {
241 let mut row = Row::new(80);
242 assert!(!row.wrapped());
243
244 row.set_wrapped(true);
245 assert!(row.wrapped());
246 }
247}