1use crate::term::BufWrite as _;
2
3#[derive(Clone, Debug)]
4pub struct Row {
5 cells: Vec<crate::cell::Cell>,
6 wrapped: bool,
7}
8
9impl Row {
10 pub fn new(cols: u16) -> Self {
11 Self {
12 cells: vec![crate::cell::Cell::default(); usize::from(cols)],
13 wrapped: false,
14 }
15 }
16
17 fn cols(&self) -> u16 {
18 self.cells
19 .len()
20 .try_into()
21 .unwrap()
23 }
24
25 pub fn clear(&mut self, attrs: crate::attrs::Attrs) {
26 for cell in &mut self.cells {
27 cell.clear(attrs);
28 }
29 self.wrapped = false;
30 }
31
32 fn cells(&self) -> impl Iterator<Item = &crate::cell::Cell> {
33 self.cells.iter()
34 }
35
36 pub fn get(&self, col: u16) -> Option<&crate::cell::Cell> {
37 self.cells.get(usize::from(col))
38 }
39
40 pub fn get_mut(&mut self, col: u16) -> Option<&mut crate::cell::Cell> {
41 self.cells.get_mut(usize::from(col))
42 }
43
44 pub fn insert(&mut self, i: u16, cell: crate::cell::Cell) {
45 self.cells.insert(usize::from(i), cell);
46 self.wrapped = false;
47 }
48
49 pub fn remove(&mut self, i: u16) {
50 self.clear_wide(i);
51 self.cells.remove(usize::from(i));
52 self.wrapped = false;
53 }
54
55 pub fn erase(&mut self, i: u16, attrs: crate::attrs::Attrs) {
56 let wide = self.cells[usize::from(i)].is_wide();
57 self.clear_wide(i);
58 self.cells[usize::from(i)].clear(attrs);
59 if i == self.cols() - if wide { 2 } else { 1 } {
60 self.wrapped = false;
61 }
62 }
63
64 pub fn truncate(&mut self, len: u16) {
65 self.cells.truncate(usize::from(len));
66 self.wrapped = false;
67 let last_cell = &mut self.cells[usize::from(len) - 1];
68 if last_cell.is_wide() {
69 last_cell.clear(*last_cell.attrs());
70 }
71 }
72
73 pub fn resize(&mut self, len: u16, cell: crate::cell::Cell) {
74 self.cells.resize(usize::from(len), cell);
75 self.wrapped = false;
76 }
77
78 pub fn wrap(&mut self, wrap: bool) {
79 self.wrapped = wrap;
80 }
81
82 pub fn wrapped(&self) -> bool {
83 self.wrapped
84 }
85
86 pub fn clear_wide(&mut self, col: u16) {
87 let cell = &self.cells[usize::from(col)];
88 let other = if cell.is_wide() {
89 &mut self.cells[usize::from(col + 1)]
90 } else if cell.is_wide_continuation() {
91 &mut self.cells[usize::from(col - 1)]
92 } else {
93 return;
94 };
95 other.clear(*other.attrs());
96 }
97
98 pub fn write_contents(
99 &self,
100 contents: &mut String,
101 start: u16,
102 width: u16,
103 wrapping: bool,
104 ) {
105 let mut prev_was_wide = false;
106
107 let mut prev_col = start;
108 for (col, cell) in self
109 .cells()
110 .enumerate()
111 .skip(usize::from(start))
112 .take(usize::from(width))
113 {
114 if prev_was_wide {
115 prev_was_wide = false;
116 continue;
117 }
118 prev_was_wide = cell.is_wide();
119
120 let col: u16 = col.try_into().unwrap();
122 if cell.has_contents() {
123 for _ in 0..(col - prev_col) {
124 contents.push(' ');
125 }
126 prev_col += col - prev_col;
127
128 contents.push_str(&cell.contents());
129 prev_col += if cell.is_wide() { 2 } else { 1 };
130 }
131 }
132 if prev_col == start && wrapping {
133 contents.push('\n');
134 }
135 }
136
137 pub fn write_contents_formatted(
138 &self,
139 contents: &mut Vec<u8>,
140 start: u16,
141 width: u16,
142 row: u16,
143 wrapping: bool,
144 prev_pos: Option<crate::grid::Pos>,
145 prev_attrs: Option<crate::attrs::Attrs>,
146 ) -> (crate::grid::Pos, crate::attrs::Attrs) {
147 let mut prev_was_wide = false;
148 let default_cell = crate::cell::Cell::default();
149
150 let mut prev_pos = prev_pos.unwrap_or_else(|| {
151 if wrapping {
152 crate::grid::Pos {
153 row: row - 1,
154 col: self.cols(),
155 }
156 } else {
157 crate::grid::Pos { row, col: start }
158 }
159 });
160 let mut prev_attrs = prev_attrs.unwrap_or_default();
161
162 let first_cell = &self.cells[usize::from(start)];
163 if wrapping && first_cell == &default_cell {
164 let default_attrs = default_cell.attrs();
165 if &prev_attrs != default_attrs {
166 default_attrs.write_escape_code_diff(contents, &prev_attrs);
167 prev_attrs = *default_attrs;
168 }
169 contents.push(b' ');
170 crate::term::Backspace::default().write_buf(contents);
171 crate::term::EraseChar::new(1).write_buf(contents);
172 prev_pos = crate::grid::Pos { row, col: 0 };
173 }
174
175 let mut erase: Option<(u16, &crate::attrs::Attrs)> = None;
176 for (col, cell) in self
177 .cells()
178 .enumerate()
179 .skip(usize::from(start))
180 .take(usize::from(width))
181 {
182 if prev_was_wide {
183 prev_was_wide = false;
184 continue;
185 }
186 prev_was_wide = cell.is_wide();
187
188 let col: u16 = col.try_into().unwrap();
190 let pos = crate::grid::Pos { row, col };
191
192 if let Some((prev_col, attrs)) = erase {
193 if cell.has_contents() || cell.attrs() != attrs {
194 let new_pos = crate::grid::Pos { row, col: prev_col };
195 if wrapping
196 && prev_pos.row + 1 == new_pos.row
197 && prev_pos.col >= self.cols()
198 {
199 if new_pos.col > 0 {
200 contents.extend(
201 " ".repeat(usize::from(new_pos.col))
202 .as_bytes(),
203 );
204 } else {
205 contents.extend(b" ");
206 crate::term::Backspace::default()
207 .write_buf(contents);
208 }
209 } else {
210 crate::term::MoveFromTo::new(prev_pos, new_pos)
211 .write_buf(contents);
212 }
213 prev_pos = new_pos;
214 if &prev_attrs != attrs {
215 attrs.write_escape_code_diff(contents, &prev_attrs);
216 prev_attrs = *attrs;
217 }
218 crate::term::EraseChar::new(pos.col - prev_col)
219 .write_buf(contents);
220 erase = None;
221 }
222 }
223
224 if cell != &default_cell {
225 let attrs = cell.attrs();
226 if cell.has_contents() {
227 if pos != prev_pos {
228 if !wrapping
229 || prev_pos.row + 1 != pos.row
230 || prev_pos.col
231 < self.cols() - u16::from(cell.is_wide())
232 || pos.col != 0
233 {
234 crate::term::MoveFromTo::new(prev_pos, pos)
235 .write_buf(contents);
236 }
237 prev_pos = pos;
238 }
239
240 if &prev_attrs != attrs {
241 attrs.write_escape_code_diff(contents, &prev_attrs);
242 prev_attrs = *attrs;
243 }
244
245 prev_pos.col += if cell.is_wide() { 2 } else { 1 };
246 let cell_contents = cell.contents();
247 contents.extend(cell_contents.as_bytes());
248 } else if erase.is_none() {
249 erase = Some((pos.col, attrs));
250 }
251 }
252 }
253 if let Some((prev_col, attrs)) = erase {
254 let new_pos = crate::grid::Pos { row, col: prev_col };
255 if wrapping
256 && prev_pos.row + 1 == new_pos.row
257 && prev_pos.col >= self.cols()
258 {
259 if new_pos.col > 0 {
260 contents.extend(
261 " ".repeat(usize::from(new_pos.col)).as_bytes(),
262 );
263 } else {
264 contents.extend(b" ");
265 crate::term::Backspace::default().write_buf(contents);
266 }
267 } else {
268 crate::term::MoveFromTo::new(prev_pos, new_pos)
269 .write_buf(contents);
270 }
271 prev_pos = new_pos;
272 if &prev_attrs != attrs {
273 attrs.write_escape_code_diff(contents, &prev_attrs);
274 prev_attrs = *attrs;
275 }
276 crate::term::ClearRowForward::default().write_buf(contents);
277 }
278
279 (prev_pos, prev_attrs)
280 }
281
282 pub fn write_contents_diff(
286 &self,
287 contents: &mut Vec<u8>,
288 prev: &Self,
289 start: u16,
290 width: u16,
291 row: u16,
292 wrapping: bool,
293 prev_wrapping: bool,
294 mut prev_pos: crate::grid::Pos,
295 mut prev_attrs: crate::attrs::Attrs,
296 ) -> (crate::grid::Pos, crate::attrs::Attrs) {
297 let mut prev_was_wide = false;
298
299 let first_cell = &self.cells[usize::from(start)];
300 let prev_first_cell = &prev.cells[usize::from(start)];
301 if wrapping
302 && !prev_wrapping
303 && first_cell == prev_first_cell
304 && prev_pos.row + 1 == row
305 && prev_pos.col
306 >= self.cols() - u16::from(prev_first_cell.is_wide())
307 {
308 let first_cell_attrs = first_cell.attrs();
309 if &prev_attrs != first_cell_attrs {
310 first_cell_attrs
311 .write_escape_code_diff(contents, &prev_attrs);
312 prev_attrs = *first_cell_attrs;
313 }
314 let mut cell_contents = prev_first_cell.contents();
315 let need_erase = if cell_contents.is_empty() {
316 cell_contents = " ".to_string();
317 true
318 } else {
319 false
320 };
321 contents.extend(cell_contents.as_bytes());
322 crate::term::Backspace::default().write_buf(contents);
323 if prev_first_cell.is_wide() {
324 crate::term::Backspace::default().write_buf(contents);
325 }
326 if need_erase {
327 crate::term::EraseChar::new(1).write_buf(contents);
328 }
329 prev_pos = crate::grid::Pos { row, col: 0 };
330 }
331
332 let mut erase: Option<(u16, &crate::attrs::Attrs)> = None;
333 for (col, (cell, prev_cell)) in self
334 .cells()
335 .zip(prev.cells())
336 .enumerate()
337 .skip(usize::from(start))
338 .take(usize::from(width))
339 {
340 if prev_was_wide {
341 prev_was_wide = false;
342 continue;
343 }
344 prev_was_wide = cell.is_wide();
345
346 let col: u16 = col.try_into().unwrap();
348 let pos = crate::grid::Pos { row, col };
349
350 if let Some((prev_col, attrs)) = erase {
351 if cell.has_contents() || cell.attrs() != attrs {
352 let new_pos = crate::grid::Pos { row, col: prev_col };
353 if wrapping
354 && prev_pos.row + 1 == new_pos.row
355 && prev_pos.col >= self.cols()
356 {
357 if new_pos.col > 0 {
358 contents.extend(
359 " ".repeat(usize::from(new_pos.col))
360 .as_bytes(),
361 );
362 } else {
363 contents.extend(b" ");
364 crate::term::Backspace::default()
365 .write_buf(contents);
366 }
367 } else {
368 crate::term::MoveFromTo::new(prev_pos, new_pos)
369 .write_buf(contents);
370 }
371 prev_pos = new_pos;
372 if &prev_attrs != attrs {
373 attrs.write_escape_code_diff(contents, &prev_attrs);
374 prev_attrs = *attrs;
375 }
376 crate::term::EraseChar::new(pos.col - prev_col)
377 .write_buf(contents);
378 erase = None;
379 }
380 }
381
382 if cell != prev_cell {
383 let attrs = cell.attrs();
384 if cell.has_contents() {
385 if pos != prev_pos {
386 if !wrapping
387 || prev_pos.row + 1 != pos.row
388 || prev_pos.col
389 < self.cols() - u16::from(cell.is_wide())
390 || pos.col != 0
391 {
392 crate::term::MoveFromTo::new(prev_pos, pos)
393 .write_buf(contents);
394 }
395 prev_pos = pos;
396 }
397
398 if &prev_attrs != attrs {
399 attrs.write_escape_code_diff(contents, &prev_attrs);
400 prev_attrs = *attrs;
401 }
402
403 prev_pos.col += if cell.is_wide() { 2 } else { 1 };
404 contents.extend(cell.contents().as_bytes());
405 } else if erase.is_none() {
406 erase = Some((pos.col, attrs));
407 }
408 }
409 }
410 if let Some((prev_col, attrs)) = erase {
411 let new_pos = crate::grid::Pos { row, col: prev_col };
412 if wrapping
413 && prev_pos.row + 1 == new_pos.row
414 && prev_pos.col >= self.cols()
415 {
416 if new_pos.col > 0 {
417 contents.extend(
418 " ".repeat(usize::from(new_pos.col)).as_bytes(),
419 );
420 } else {
421 contents.extend(b" ");
422 crate::term::Backspace::default().write_buf(contents);
423 }
424 } else {
425 crate::term::MoveFromTo::new(prev_pos, new_pos)
426 .write_buf(contents);
427 }
428 prev_pos = new_pos;
429 if &prev_attrs != attrs {
430 attrs.write_escape_code_diff(contents, &prev_attrs);
431 prev_attrs = *attrs;
432 }
433 crate::term::ClearRowForward::default().write_buf(contents);
434 }
435
436 if (!self.wrapped && prev.wrapped) || (!prev.wrapped && self.wrapped)
442 {
443 let end_pos = if self.cells[usize::from(self.cols() - 1)]
444 .is_wide_continuation()
445 {
446 crate::grid::Pos {
447 row,
448 col: self.cols() - 2,
449 }
450 } else {
451 crate::grid::Pos {
452 row,
453 col: self.cols() - 1,
454 }
455 };
456 crate::term::MoveFromTo::new(prev_pos, end_pos)
457 .write_buf(contents);
458 prev_pos = end_pos;
459 if !self.wrapped {
460 crate::term::EraseChar::new(1).write_buf(contents);
461 }
462 let end_cell = &self.cells[usize::from(end_pos.col)];
463 if end_cell.has_contents() {
464 let attrs = end_cell.attrs();
465 if &prev_attrs != attrs {
466 attrs.write_escape_code_diff(contents, &prev_attrs);
467 prev_attrs = *attrs;
468 }
469 contents.extend(end_cell.contents().as_bytes());
470 prev_pos.col += if end_cell.is_wide() { 2 } else { 1 };
471 }
472 }
473
474 (prev_pos, prev_attrs)
475 }
476}