Author: Manos Pitsidianakis [manos@pitsidianak.is]
Hash: e8e7697001a8a41caee8dc108f6f76a9ea988c1e
Timestamp: Thu, 30 May 2024 10:52:56 +0000 (3 months ago)

+362 -100 +/-25 browse
terminal: fix edge case with strings/linebreaking
terminal: fix edge case with strings/linebreaking

When printing and line-breaking a string in CellBuffer::write_string(),
the line should continue from the "beginning" of the previous one.
However it might be different than the offset of the first character of
the string, because it may be indented already.

This would result in awkward line breaks like:

            Available actions: [ list- |# end of terminal/border
            post, list-unsubscribe, lis|
            t-archive ]

This commit adds an extra argument to write_string() to specify the x
offset of the string, so that we can apply it while printing characters
but ignore it when the line changes; then the x coordinate will take the
value of the line_break value.

Signed-off-by: Manos Pitsidianakis <manos@pitsidianak.is>
1diff --git a/meli/src/contacts/editor.rs b/meli/src/contacts/editor.rs
2index 57b4ee6..d5f9a40 100644
3--- a/meli/src/contacts/editor.rs
4+++ b/meli/src/contacts/editor.rs
5 @@ -86,6 +86,7 @@ impl ContactManager {
6 self.theme_default.attrs,
7 area,
8 None,
9+ None,
10 );
11 area = area.skip_cols(x);
12 let (x, y) = self.content.grid_mut().write_string(
13 @@ -95,6 +96,7 @@ impl ContactManager {
14 self.theme_default.attrs,
15 area,
16 None,
17+ None,
18 );
19 area = area.skip(x, y);
20
21 @@ -107,6 +109,7 @@ impl ContactManager {
22 self.theme_default.attrs,
23 area,
24 None,
25+ None,
26 );
27 }
28
29 diff --git a/meli/src/contacts/list.rs b/meli/src/contacts/list.rs
30index 3a9da83..c0881f1 100644
31--- a/meli/src/contacts/list.rs
32+++ b/meli/src/contacts/list.rs
33 @@ -178,6 +178,7 @@ impl ContactList {
34 self.theme_default.attrs,
35 area,
36 None,
37+ None,
38 )
39 };
40
41 @@ -190,6 +191,7 @@ impl ContactList {
42 self.theme_default.attrs,
43 area,
44 None,
45+ None,
46 )
47 };
48
49 @@ -202,6 +204,7 @@ impl ContactList {
50 self.theme_default.attrs,
51 area,
52 None,
53+ None,
54 )
55 };
56
57 @@ -218,6 +221,7 @@ impl ContactList {
58 self.theme_default.attrs,
59 area,
60 None,
61+ None,
62 )
63 };
64 }
65 @@ -234,6 +238,7 @@ impl ContactList {
66 self.theme_default.attrs,
67 area,
68 None,
69+ None,
70 );
71 }
72 }
73 @@ -298,6 +303,7 @@ impl ContactList {
74 account_attrs.attrs,
75 area,
76 None,
77+ None,
78 );
79 grid.write_string(
80 &s,
81 @@ -306,6 +312,7 @@ impl ContactList {
82 account_attrs.attrs,
83 area.skip_cols(area.width().saturating_sub(s.len())),
84 None,
85+ None,
86 );
87
88 if a.name.grapheme_len() + s.len() > width + 1 {
89 @@ -316,6 +323,7 @@ impl ContactList {
90 account_attrs.attrs,
91 area.skip_cols(area.width().saturating_sub(s.len() + 1)),
92 None,
93+ None,
94 );
95 }
96 }
97 @@ -449,6 +457,7 @@ impl ContactList {
98 .skip_cols(x)
99 .take_cols(x + (self.data_columns.widths[i])),
100 None,
101+ None,
102 );
103
104 x += self.data_columns.widths[i] + 2; // + SEPARATOR
105 diff --git a/meli/src/jobs_view.rs b/meli/src/jobs_view.rs
106index 18c128c..cf81367 100644
107--- a/meli/src/jobs_view.rs
108+++ b/meli/src/jobs_view.rs
109 @@ -199,6 +199,7 @@ impl JobManager {
110 self.theme_default.attrs,
111 area,
112 None,
113+ None,
114 );
115 }
116
117 @@ -211,6 +212,7 @@ impl JobManager {
118 self.theme_default.attrs,
119 area,
120 None,
121+ None,
122 );
123 }
124
125 @@ -227,6 +229,7 @@ impl JobManager {
126 self.theme_default.attrs,
127 area,
128 None,
129+ None,
130 );
131 }
132
133 @@ -247,6 +250,7 @@ impl JobManager {
134 self.theme_default.attrs,
135 area,
136 None,
137+ None,
138 );
139 }
140
141 @@ -263,6 +267,7 @@ impl JobManager {
142 self.theme_default.attrs,
143 area,
144 None,
145+ None,
146 );
147 }
148 }
149 @@ -279,6 +284,7 @@ impl JobManager {
150 self.theme_default.attrs,
151 area,
152 None,
153+ None,
154 );
155 }
156 }
157 @@ -444,6 +450,7 @@ impl Component for JobManager {
158 self.theme_default.attrs | Attr::BOLD,
159 area.skip_cols(x_offset),
160 None,
161+ None,
162 );
163 if self.sort_col as usize == i {
164 use SortOrder::*;
165 @@ -460,6 +467,7 @@ impl Component for JobManager {
166 self.theme_default.attrs,
167 area.skip_cols(x_offset + h.len()),
168 None,
169+ None,
170 );
171 }
172 x_offset += w + 2;
173 diff --git a/meli/src/mail/compose.rs b/meli/src/mail/compose.rs
174index fa4d8a8..5f71e79 100644
175--- a/meli/src/mail/compose.rs
176+++ b/meli/src/mail/compose.rs
177 @@ -716,6 +716,7 @@ To: {}
178 theme_default.attrs,
179 area.skip_rows(1),
180 None,
181+ None,
182 );
183 } else {
184 grid.write_string(
185 @@ -729,6 +730,7 @@ To: {}
186 theme_default.attrs,
187 area.skip_rows(1),
188 None,
189+ None,
190 );
191 }
192 #[cfg(feature = "gpgme")]
193 @@ -769,6 +771,7 @@ To: {}
194 theme_default.attrs,
195 area.skip_rows(2),
196 None,
197+ None,
198 );
199 } else {
200 grid.write_string(
201 @@ -782,6 +785,7 @@ To: {}
202 theme_default.attrs,
203 area.skip_rows(2),
204 None,
205+ None,
206 );
207 }
208 if attachments_no == 0 {
209 @@ -796,6 +800,7 @@ To: {}
210 theme_default.attrs,
211 area.skip_rows(3),
212 None,
213+ None,
214 );
215 } else {
216 grid.write_string(
217 @@ -809,6 +814,7 @@ To: {}
218 theme_default.attrs,
219 area.skip_rows(3),
220 None,
221+ None,
222 );
223 for (i, a) in self.draft.attachments().iter().enumerate() {
224 grid.write_string(
225 @@ -833,6 +839,7 @@ To: {}
226 theme_default.attrs,
227 area.skip_rows(4 + i),
228 None,
229+ None,
230 );
231 }
232 }
233 @@ -935,6 +942,7 @@ impl Component for Composer {
234 crate::conf::value(context, "highlight").attrs,
235 area.nth_row(0),
236 None,
237+ None,
238 );
239 }
240
241 @@ -1020,6 +1028,7 @@ impl Component for Composer {
242 theme_default.attrs,
243 inner_area.skip_rows(i),
244 None,
245+ None,
246 );
247 }
248 context.dirty_areas.push_back(area);
249 diff --git a/meli/src/mail/compose/edit_attachments.rs b/meli/src/mail/compose/edit_attachments.rs
250index d2b9a70..61daa31 100644
251--- a/meli/src/mail/compose/edit_attachments.rs
252+++ b/meli/src/mail/compose/edit_attachments.rs
253 @@ -132,6 +132,7 @@ impl Component for EditAttachmentsRefMut<'_, '_> {
254 theme_default.attrs,
255 area,
256 None,
257+ None,
258 );
259 } else {
260 grid.write_string(
261 @@ -141,6 +142,7 @@ impl Component for EditAttachmentsRefMut<'_, '_> {
262 theme_default.attrs,
263 area,
264 None,
265+ None,
266 );
267 for (i, a) in self.draft.attachments().iter().enumerate() {
268 let bg = if let EditAttachmentCursor::AttachmentNo(u) = self.inner.cursor {
269 @@ -174,6 +176,7 @@ impl Component for EditAttachmentsRefMut<'_, '_> {
270 theme_default.attrs,
271 area.skip(2, 2 + i),
272 None,
273+ None,
274 );
275 }
276 }
277 diff --git a/meli/src/mail/compose/gpg.rs b/meli/src/mail/compose/gpg.rs
278index 77ff10f..790630d 100644
279--- a/meli/src/mail/compose/gpg.rs
280+++ b/meli/src/mail/compose/gpg.rs
281 @@ -95,6 +95,7 @@ impl Component for KeySelection {
282 theme_default.bg,
283 theme_default.attrs,
284 area.center_inside((15, 2)),
285+ None,
286 Some(0),
287 );
288 }
289 diff --git a/meli/src/mail/listing.rs b/meli/src/mail/listing.rs
290index 88474bb..45fb0c9 100644
291--- a/meli/src/mail/listing.rs
292+++ b/meli/src/mail/listing.rs
293 @@ -3021,6 +3021,7 @@ impl Listing {
294 account_attrs.attrs,
295 area,
296 None,
297+ None,
298 );
299 area = self.menu.area().skip_rows(account_y);
300
301 @@ -3032,6 +3033,7 @@ impl Listing {
302 account_attrs.attrs,
303 area.skip_rows(1),
304 None,
305+ None,
306 );
307 return 0;
308 }
309 @@ -3186,6 +3188,7 @@ impl Listing {
310 index_att.attrs,
311 area.nth_row(y + 1),
312 None,
313+ None,
314 );
315 area = self.menu.area().skip_rows(account_y);
316 {
317 @@ -3219,6 +3222,7 @@ impl Listing {
318 att.attrs,
319 area.nth_row(y + 1).skip_cols(x),
320 None,
321+ None,
322 )
323 .0
324 + x;
325 @@ -3234,6 +3238,7 @@ impl Listing {
326 att.attrs,
327 area.nth_row(y + 1).skip_cols(x),
328 None,
329+ None,
330 )
331 .0
332 + x;
333 @@ -3267,6 +3272,7 @@ impl Listing {
334 area.nth_row(y + 1)
335 .skip_cols(x.min(area.width().saturating_sub(count_string.len()))),
336 None,
337+ None,
338 )
339 .0
340 + x.min(area.width().saturating_sub(count_string.len()));
341 diff --git a/meli/src/mail/listing/compact.rs b/meli/src/mail/listing/compact.rs
342index 2afcfb8..88eb756 100644
343--- a/meli/src/mail/listing/compact.rs
344+++ b/meli/src/mail/listing/compact.rs
345 @@ -242,6 +242,7 @@ impl MailListingTrait for CompactListing {
346 self.color_cache.theme_default.attrs,
347 area_col_0,
348 None,
349+ None,
350 );
351 }
352 return;
353 @@ -544,6 +545,7 @@ impl MailListingTrait for CompactListing {
354 self.color_cache.theme_default.attrs,
355 area_col_0,
356 None,
357+ None,
358 );
359 }
360 }
361 @@ -1165,6 +1167,7 @@ impl CompactListing {
362 row_attr.attrs,
363 area,
364 None,
365+ None,
366 )
367 };
368 for c in {
369 @@ -1184,6 +1187,7 @@ impl CompactListing {
370 row_attr.attrs,
371 area,
372 None,
373+ None,
374 )
375 };
376 for c in {
377 @@ -1203,6 +1207,7 @@ impl CompactListing {
378 row_attr.attrs,
379 area,
380 None,
381+ None,
382 )
383 };
384 for c in {
385 @@ -1232,6 +1237,7 @@ impl CompactListing {
386 row_attr.attrs,
387 area_col_3,
388 None,
389+ None,
390 ));
391 if strings.highlight_self {
392 let (x, _) = columns[3].grid_mut().write_string(
393 @@ -1248,6 +1254,7 @@ impl CompactListing {
394 row_attr.attrs | Attr::FORCE_TEXT,
395 area_col_3,
396 None,
397+ None,
398 );
399 for c in columns[3].grid().row_iter(area_col_3, 0..x, 0) {
400 columns[3].grid_mut()[c].set_keep_fg(true);
401 @@ -1269,6 +1276,7 @@ impl CompactListing {
402 row_attr.attrs,
403 area_col_4,
404 None,
405+ None,
406 ));
407 #[cfg(feature = "regexp")]
408 {
409 @@ -1293,6 +1301,7 @@ impl CompactListing {
410 self.color_cache.tag_default.attrs,
411 area_col_4,
412 None,
413+ None,
414 );
415 for c in columns[4].grid().row_iter(area_col_4, 0..(x + 1), 0) {
416 columns[4].grid_mut()[c]
417 @@ -1323,6 +1332,7 @@ impl CompactListing {
418 self.color_cache.theme_default.attrs,
419 area_col_0,
420 None,
421+ None,
422 );
423 }
424 }
425 @@ -1417,6 +1427,7 @@ impl CompactListing {
426 row_attr.attrs,
427 area.nth_row(i),
428 None,
429+ None,
430 );
431 }
432 }
433 @@ -1496,6 +1507,7 @@ impl Component for CompactListing {
434 self.color_cache.theme_default.bg,
435 self.color_cache.theme_default.attrs,
436 area,
437+ None,
438 Some(0),
439 );
440
441 diff --git a/meli/src/mail/listing/conversations.rs b/meli/src/mail/listing/conversations.rs
442index 3fae4c4..f2eaf38 100644
443--- a/meli/src/mail/listing/conversations.rs
444+++ b/meli/src/mail/listing/conversations.rs
445 @@ -460,6 +460,7 @@ impl ListingTrait for ConversationsListing {
446 self.color_cache.theme_default.attrs,
447 area,
448 None,
449+ None,
450 );
451 context.dirty_areas.push_back(area);
452 return;
453 @@ -876,6 +877,7 @@ impl ConversationsListing {
454 row_attr.attrs,
455 area,
456 None,
457+ None,
458 );
459 if !strings.flag.is_empty() {
460 for c in grid.row_iter(area, x..(x + 1), 0) {
461 @@ -898,6 +900,7 @@ impl ConversationsListing {
462 subject_attr.attrs,
463 area.skip_cols(x),
464 None,
465+ None,
466 );
467 x += x_;
468 let mut subject_overflowed = subject_overflowed > 0;
469 @@ -914,6 +917,7 @@ impl ConversationsListing {
470 self.color_cache.tag_default.attrs,
471 area.skip_cols(1),
472 None,
473+ None,
474 );
475 if _y > 0 {
476 subject_overflowed = true;
477 @@ -950,6 +954,7 @@ impl ConversationsListing {
478 date_attr.attrs,
479 area.skip(x, 1),
480 None,
481+ None,
482 )
483 .0;
484 for c in grid.row_iter(area, x..(x + 4), 1) {
485 @@ -972,6 +977,7 @@ impl ConversationsListing {
486 from_attr.attrs,
487 area.skip(x, 1),
488 None,
489+ None,
490 )
491 .0;
492
493 @@ -1044,6 +1050,7 @@ impl Component for ConversationsListing {
494 self.color_cache.theme_default.bg,
495 self.color_cache.theme_default.attrs,
496 area,
497+ None,
498 Some(0),
499 );
500 for c in grid.row_iter(area, x..area.width(), y) {
501 diff --git a/meli/src/mail/listing/offline.rs b/meli/src/mail/listing/offline.rs
502index 4d2964d..07b305d 100644
503--- a/meli/src/mail/listing/offline.rs
504+++ b/meli/src/mail/listing/offline.rs
505 @@ -148,6 +148,7 @@ impl Component for OfflineListing {
506 error_message.attrs,
507 area,
508 None,
509+ None,
510 );
511
512 let (_, mut y_offset) = grid.write_string(
513 @@ -155,7 +156,8 @@ impl Component for OfflineListing {
514 error_message.fg,
515 error_message.bg,
516 error_message.attrs,
517- area.skip_cols(x + 1),
518+ area,
519+ Some(x + 1),
520 Some(0),
521 );
522 y_offset += 1;
523 @@ -167,6 +169,7 @@ impl Component for OfflineListing {
524 Attr::BOLD,
525 area.skip_rows(y_offset),
526 None,
527+ None,
528 );
529 }
530 y_offset += 1;
531 @@ -178,6 +181,7 @@ impl Component for OfflineListing {
532 text_unfocused.attrs,
533 area.skip_rows(y_offset + i),
534 None,
535+ None,
536 );
537 }
538 } else {
539 @@ -188,6 +192,7 @@ impl Component for OfflineListing {
540 conf::value(context, "highlight").attrs,
541 area,
542 None,
543+ None,
544 );
545 let mut jobs: SmallVec<[_; 64]> = context.accounts[&self.cursor_pos.0]
546 .active_jobs
547 @@ -202,6 +207,7 @@ impl Component for OfflineListing {
548 text_unfocused.attrs,
549 area.skip_rows(i + 1),
550 None,
551+ None,
552 );
553 }
554
555 diff --git a/meli/src/mail/listing/plain.rs b/meli/src/mail/listing/plain.rs
556index cee18ee..d095ca8 100644
557--- a/meli/src/mail/listing/plain.rs
558+++ b/meli/src/mail/listing/plain.rs
559 @@ -226,6 +226,7 @@ impl MailListingTrait for PlainListing {
560 self.color_cache.theme_default.attrs,
561 area,
562 None,
563+ None,
564 );
565 }
566 return;
567 @@ -892,6 +893,7 @@ impl PlainListing {
568 row_attr.attrs,
569 area_col_0,
570 None,
571+ None,
572 ));
573 for c in columns[0].grid().row_iter(area_col_0, 0..min_width.0, 0) {
574 columns[0].grid_mut()[c]
575 @@ -909,6 +911,7 @@ impl PlainListing {
576 row_attr.attrs,
577 area_col_1,
578 None,
579+ None,
580 ));
581 for c in columns[1].grid().row_iter(area_col_1, 0..min_width.1, 0) {
582 columns[1].grid_mut()[c]
583 @@ -925,6 +928,7 @@ impl PlainListing {
584 row_attr.attrs,
585 area_col_2,
586 None,
587+ None,
588 );
589 #[cfg(feature = "regexp")]
590 {
591 @@ -958,6 +962,7 @@ impl PlainListing {
592 row_attr.attrs,
593 area_col_3,
594 None,
595+ None,
596 ));
597 if strings.highlight_self {
598 let (x, _) = columns[3].grid_mut().write_string(
599 @@ -974,6 +979,7 @@ impl PlainListing {
600 row_attr.attrs | Attr::FORCE_TEXT,
601 area_col_3,
602 None,
603+ None,
604 );
605 for c in columns[3].grid().row_iter(area_col_3, 0..x, 0) {
606 columns[3].grid_mut()[c].set_keep_fg(true);
607 @@ -995,6 +1001,7 @@ impl PlainListing {
608 row_attr.attrs,
609 area_col_4,
610 None,
611+ None,
612 ));
613 #[cfg(feature = "regexp")]
614 {
615 @@ -1019,6 +1026,7 @@ impl PlainListing {
616 self.color_cache.tag_default.attrs,
617 area_col_4.skip_cols(1),
618 None,
619+ None,
620 );
621 for c in columns[4].grid().row_iter(area_col_4, 0..(x + 1), 0) {
622 columns[4].grid_mut()[c]
623 @@ -1048,6 +1056,7 @@ impl PlainListing {
624 self.color_cache.theme_default.attrs,
625 area,
626 None,
627+ None,
628 );
629 }
630 }
631 @@ -1098,6 +1107,7 @@ impl PlainListing {
632 row_attr.attrs,
633 area,
634 None,
635+ None,
636 )
637 };
638 for c in {
639 @@ -1117,6 +1127,7 @@ impl PlainListing {
640 row_attr.attrs,
641 area,
642 None,
643+ None,
644 )
645 };
646 for c in {
647 @@ -1136,6 +1147,7 @@ impl PlainListing {
648 row_attr.attrs,
649 area,
650 None,
651+ None,
652 )
653 };
654 for c in {
655 @@ -1155,6 +1167,7 @@ impl PlainListing {
656 row_attr.attrs,
657 area_col_3,
658 None,
659+ None,
660 ));
661 if strings.highlight_self {
662 let (x, _) = columns[3].grid_mut().write_string(
663 @@ -1171,6 +1184,7 @@ impl PlainListing {
664 row_attr.attrs | Attr::FORCE_TEXT,
665 area_col_3,
666 None,
667+ None,
668 );
669 for c in columns[3].grid().row_iter(area_col_3, 0..x, 0) {
670 columns[3].grid_mut()[c].set_keep_fg(true);
671 @@ -1195,6 +1209,7 @@ impl PlainListing {
672 row_attr.attrs,
673 area_col_4,
674 None,
675+ None,
676 ));
677 #[cfg(feature = "regexp")]
678 {
679 @@ -1215,6 +1230,7 @@ impl PlainListing {
680 self.color_cache.tag_default.attrs,
681 area_col_4.skip_cols(1),
682 None,
683+ None,
684 );
685 for c in columns[4].grid().row_iter(area_col_4, 0..(x + 1), 0) {
686 columns[4].grid_mut()[c]
687 @@ -1323,6 +1339,7 @@ impl PlainListing {
688 row_attr.attrs,
689 area.nth_row(i),
690 None,
691+ None,
692 );
693 }
694 }
695 @@ -1402,6 +1419,7 @@ impl Component for PlainListing {
696 self.color_cache.theme_default.bg,
697 self.color_cache.theme_default.attrs,
698 area,
699+ None,
700 Some(0),
701 );
702
703 diff --git a/meli/src/mail/listing/thread.rs b/meli/src/mail/listing/thread.rs
704index 22eb4c1..f35db74 100644
705--- a/meli/src/mail/listing/thread.rs
706+++ b/meli/src/mail/listing/thread.rs
707 @@ -227,6 +227,7 @@ impl MailListingTrait for ThreadListing {
708 self.color_cache.theme_default.attrs,
709 area,
710 None,
711+ None,
712 );
713 return;
714 }
715 @@ -267,6 +268,7 @@ impl MailListingTrait for ThreadListing {
716 self.color_cache.theme_default.attrs,
717 area,
718 None,
719+ None,
720 );
721 return;
722 }
723 @@ -944,6 +946,7 @@ impl ThreadListing {
724 row_attr.attrs,
725 area_col_0,
726 None,
727+ None,
728 ));
729 for c in columns[0].grid().row_iter(area_col_0, 0..min_width.0, 0) {
730 columns[0].grid_mut()[c]
731 @@ -961,6 +964,7 @@ impl ThreadListing {
732 row_attr.attrs,
733 area_col_1,
734 None,
735+ None,
736 ));
737 for c in columns[1].grid().row_iter(area_col_1, 0..min_width.1, 0) {
738 columns[1].grid_mut()[c]
739 @@ -977,6 +981,7 @@ impl ThreadListing {
740 row_attr.attrs,
741 area_col_2,
742 None,
743+ None,
744 );
745 #[cfg(feature = "regexp")]
746 {
747 @@ -1010,6 +1015,7 @@ impl ThreadListing {
748 row_attr.attrs,
749 area_col_3,
750 None,
751+ None,
752 ));
753 if strings.highlight_self {
754 let (x, _) = columns[3].grid_mut().write_string(
755 @@ -1026,6 +1032,7 @@ impl ThreadListing {
756 row_attr.attrs | Attr::FORCE_TEXT,
757 area_col_3,
758 None,
759+ None,
760 );
761 for c in columns[3].grid().row_iter(area_col_3, 0..x, 0) {
762 columns[3].grid_mut()[c].set_keep_fg(true);
763 @@ -1047,6 +1054,7 @@ impl ThreadListing {
764 row_attr.attrs,
765 area_col_4,
766 None,
767+ None,
768 ));
769 #[cfg(feature = "regexp")]
770 {
771 @@ -1071,6 +1079,7 @@ impl ThreadListing {
772 self.color_cache.tag_default.attrs,
773 area_col_4.skip_cols(1),
774 None,
775+ None,
776 );
777 for c in columns[4].grid().row_iter(area_col_4, 0..(x + 1), 0) {
778 columns[4].grid_mut()[c]
779 @@ -1183,6 +1192,7 @@ impl ThreadListing {
780 row_attr.attrs,
781 area.nth_row(i),
782 None,
783+ None,
784 );
785 }
786 }
787 @@ -1262,6 +1272,7 @@ impl Component for ThreadListing {
788 self.color_cache.theme_default.bg,
789 self.color_cache.theme_default.attrs,
790 area,
791+ None,
792 Some(0),
793 );
794
795 diff --git a/meli/src/mail/status.rs b/meli/src/mail/status.rs
796index f0c0cd9..8b463c5 100644
797--- a/meli/src/mail/status.rs
798+++ b/meli/src/mail/status.rs
799 @@ -79,6 +79,7 @@ impl AccountStatus {
800 self.theme_default.attrs | Attr::UNDERLINE,
801 area,
802 None,
803+ None,
804 );
805 let area = self.content.area().skip(_x + 1, _y);
806 let (_x, _y) = self.content.grid_mut().write_string(
807 @@ -88,6 +89,7 @@ impl AccountStatus {
808 Attr::BOLD | Attr::UNDERLINE,
809 area,
810 None,
811+ None,
812 );
813 let mut line = 2;
814
815 @@ -99,6 +101,7 @@ impl AccountStatus {
816 Attr::BOLD,
817 area,
818 None,
819+ None,
820 );
821 line += 2;
822
823 @@ -111,6 +114,7 @@ impl AccountStatus {
824 self.theme_default.attrs,
825 area,
826 None,
827+ None,
828 );
829 if let JobRequest::DeleteMailbox { mailbox_hash, .. }
830 | JobRequest::SetMailboxPermissions { mailbox_hash, .. }
831 @@ -126,6 +130,7 @@ impl AccountStatus {
832 self.theme_default.attrs,
833 area,
834 None,
835+ None,
836 );
837 }
838
839 @@ -142,6 +147,7 @@ impl AccountStatus {
840 Attr::BOLD,
841 area,
842 None,
843+ None,
844 );
845 let area = self.content.area().skip(_x + 1, _y + line);
846 self.content.grid_mut().write_string(
847 @@ -155,6 +161,7 @@ impl AccountStatus {
848 self.theme_default.attrs,
849 area,
850 None,
851+ None,
852 );
853 line += 1;
854 let area = self.content.area().skip(1, line);
855 @@ -165,6 +172,7 @@ impl AccountStatus {
856 Attr::BOLD,
857 area,
858 None,
859+ None,
860 );
861 let area = self.content.area().skip(_x + 1, _y + line);
862 self.content.grid_mut().write_string(
863 @@ -194,6 +202,7 @@ impl AccountStatus {
864 self.theme_default.attrs,
865 area,
866 None,
867+ None,
868 );
869 line += 1;
870
871 @@ -205,6 +214,7 @@ impl AccountStatus {
872 Attr::BOLD,
873 area,
874 None,
875+ None,
876 );
877 for f in a
878 .mailbox_entries
879 @@ -221,6 +231,7 @@ impl AccountStatus {
880 self.theme_default.attrs,
881 area,
882 None,
883+ None,
884 );
885 }
886 line += 2;
887 @@ -232,6 +243,7 @@ impl AccountStatus {
888 Attr::BOLD,
889 area,
890 None,
891+ None,
892 );
893 line += 2;
894 for mailbox_node in a.list_mailboxes() {
895 @@ -245,6 +257,7 @@ impl AccountStatus {
896 self.theme_default.attrs,
897 area,
898 None,
899+ None,
900 );
901 line += 1;
902 }
903 @@ -260,6 +273,7 @@ impl AccountStatus {
904 Attr::BOLD,
905 area,
906 None,
907+ None,
908 );
909 let max_name_width = std::cmp::max(
910 "Server Extensions:".len(),
911 @@ -277,6 +291,7 @@ impl AccountStatus {
912 self.theme_default.attrs,
913 area,
914 None,
915+ None,
916 );
917 line += 1;
918 for (name, status) in extensions.iter() {
919 @@ -288,6 +303,7 @@ impl AccountStatus {
920 self.theme_default.attrs,
921 area,
922 None,
923+ None,
924 );
925
926 let (x, y) = {
927 @@ -310,6 +326,7 @@ impl AccountStatus {
928 self.theme_default.attrs,
929 area,
930 None,
931+ None,
932 )
933 };
934 match status {
935 @@ -329,6 +346,7 @@ impl AccountStatus {
936 self.theme_default.attrs,
937 area,
938 None,
939+ None,
940 );
941 let area = self
942 .content
943 @@ -343,6 +361,7 @@ impl AccountStatus {
944 self.theme_default.attrs,
945 area,
946 None,
947+ None,
948 );
949 let area = self
950 .content
951 @@ -356,6 +375,7 @@ impl AccountStatus {
952 self.theme_default.attrs,
953 area,
954 None,
955+ None,
956 );
957 }
958 }
959 diff --git a/meli/src/mail/view/envelope.rs b/meli/src/mail/view/envelope.rs
960index b731607..482acbb 100644
961--- a/meli/src/mail/view/envelope.rs
962+++ b/meli/src/mail/view/envelope.rs
963 @@ -750,22 +750,24 @@ impl Component for EnvelopeView {
964 );
965 let (_x, _y) =
966 grid.write_string(
967- &format!("{}:", $header),
968- hdr_name_theme.fg,
969- hdr_name_theme.bg,
970- hdr_name_theme.attrs,
971- area.skip_rows(y),
972- Some(0),
973- );
974+ &format!("{}:", $header),
975+ hdr_name_theme.fg,
976+ hdr_name_theme.bg,
977+ hdr_name_theme.attrs,
978+ area.skip_rows(y),
979+ None,
980+ Some(0)
981+ );
982 let (__x, __y) =
983 grid.write_string(
984- &$string,
985- hdr_theme.fg,
986- hdr_theme.bg,
987- hdr_theme.attrs,
988- area.skip(_x+1, y+ _y),
989- Some(0),
990- );
991+ &$string,
992+ hdr_theme.fg,
993+ hdr_theme.bg,
994+ hdr_theme.attrs,
995+ area.skip_rows(y + _y),
996+ Some(_x + 1),
997+ Some(2)
998+ );
999 y += _y +__y + 1;
1000 }
1001 } else {
1002 @@ -867,26 +869,34 @@ impl Component for EnvelopeView {
1003 if let Some(id) = id {
1004 if sticky || skip_header_ctr == 0 {
1005 grid.clear_area(area.nth_row(y), hdr_area_theme);
1006- let (_x, _) = grid.write_string(
1007+ let (_x, _y) = grid.write_string(
1008 "List-ID: ",
1009 hdr_name_theme.fg,
1010 hdr_name_theme.bg,
1011 hdr_name_theme.attrs,
1012 area.nth_row(y),
1013 None,
1014+ Some(0),
1015 );
1016- x = _x;
1017+ if _y != 0 {
1018+ x = _x;
1019+ } else {
1020+ x += _x;
1021+ }
1022+ y += _y;
1023 let (_x, _y) = grid.write_string(
1024 id,
1025 hdr_theme.fg,
1026 hdr_theme.bg,
1027 hdr_theme.attrs,
1028- area.nth_row(y).skip_cols(_x),
1029- None,
1030+ area.nth_row(y),
1031+ Some(x),
1032+ Some(0),
1033 );
1034- x += _x;
1035 if _y != 0 {
1036- x = 0;
1037+ x = _x;
1038+ } else {
1039+ x += _x;
1040 }
1041 y += _y;
1042 }
1043 @@ -899,10 +909,15 @@ impl Component for EnvelopeView {
1044 hdr_name_theme.fg,
1045 hdr_name_theme.bg,
1046 hdr_name_theme.attrs,
1047- area.skip(x, y),
1048+ area.skip(0, y),
1049+ Some(x),
1050 Some(0),
1051 );
1052- x += _x;
1053+ if _y != 0 {
1054+ x = _x;
1055+ } else {
1056+ x += _x;
1057+ }
1058 y += _y;
1059 }
1060 if archive.is_some() {
1061 @@ -911,10 +926,15 @@ impl Component for EnvelopeView {
1062 hdr_theme.fg,
1063 hdr_theme.bg,
1064 hdr_theme.attrs,
1065- area.skip(x, y),
1066+ area.skip(0, y),
1067+ Some(x),
1068 Some(0),
1069 );
1070- x += _x;
1071+ if _y != 0 {
1072+ x = _x;
1073+ } else {
1074+ x += _x;
1075+ }
1076 y += _y;
1077 }
1078 if post.is_some() {
1079 @@ -923,10 +943,15 @@ impl Component for EnvelopeView {
1080 hdr_theme.fg,
1081 hdr_theme.bg,
1082 hdr_theme.attrs,
1083- area.skip(x, y),
1084+ area.skip(0, y),
1085+ Some(x),
1086 Some(0),
1087 );
1088- x += _x;
1089+ if _y != 0 {
1090+ x = _x;
1091+ } else {
1092+ x += _x;
1093+ }
1094 y += _y;
1095 }
1096 if unsubscribe.is_some() {
1097 @@ -935,10 +960,15 @@ impl Component for EnvelopeView {
1098 hdr_theme.fg,
1099 hdr_theme.bg,
1100 hdr_theme.attrs,
1101- area.skip(x, y),
1102+ area.skip(0, y),
1103+ Some(x),
1104 Some(0),
1105 );
1106- x += _x;
1107+ if _y != 0 {
1108+ x = _x;
1109+ } else {
1110+ x += _x;
1111+ }
1112 y += _y;
1113 }
1114 if archive.is_some() || post.is_some() || unsubscribe.is_some() {
1115 @@ -1118,6 +1148,7 @@ impl Component for EnvelopeView {
1116 self.view_settings.theme_default.attrs,
1117 l.skip_cols_from_end(8),
1118 None,
1119+ None,
1120 );
1121 }
1122
1123 diff --git a/meli/src/mail/view/thread.rs b/meli/src/mail/view/thread.rs
1124index 097f2fd..29fd87c 100644
1125--- a/meli/src/mail/view/thread.rs
1126+++ b/meli/src/mail/view/thread.rs
1127 @@ -372,6 +372,7 @@ impl ThreadView {
1128 theme_default.attrs,
1129 area,
1130 None,
1131+ None,
1132 );
1133 }
1134 if highlight_reply_subjects[y].is_some() {
1135 @@ -402,6 +403,7 @@ impl ThreadView {
1136 theme_default.attrs,
1137 area,
1138 None,
1139+ None,
1140 );
1141 }
1142 if highlight_reply_subjects[y].is_some() {
1143 @@ -604,6 +606,7 @@ impl ThreadView {
1144 theme_default.bg,
1145 theme_default.attrs,
1146 area,
1147+ None,
1148 Some(0),
1149 );
1150 context.dirty_areas.push_back(area);
1151 @@ -668,6 +671,7 @@ impl ThreadView {
1152 theme_default.bg,
1153 theme_default.attrs,
1154 area,
1155+ None,
1156 Some(0),
1157 );
1158 context.dirty_areas.push_back(area);
1159 diff --git a/meli/src/mailbox_management.rs b/meli/src/mailbox_management.rs
1160index 595fc32..cca2b64 100644
1161--- a/meli/src/mailbox_management.rs
1162+++ b/meli/src/mailbox_management.rs
1163 @@ -190,6 +190,7 @@ impl MailboxManager {
1164 self.theme_default.attrs,
1165 area,
1166 None,
1167+ None,
1168 );
1169 }
1170
1171 @@ -202,6 +203,7 @@ impl MailboxManager {
1172 self.theme_default.attrs,
1173 area,
1174 None,
1175+ None,
1176 );
1177 }
1178
1179 @@ -215,6 +217,7 @@ impl MailboxManager {
1180 self.theme_default.attrs,
1181 area,
1182 None,
1183+ None,
1184 );
1185 }
1186
1187 @@ -231,6 +234,7 @@ impl MailboxManager {
1188 self.theme_default.attrs,
1189 area,
1190 None,
1191+ None,
1192 );
1193 }
1194 }
1195 @@ -247,6 +251,7 @@ impl MailboxManager {
1196 self.theme_default.attrs,
1197 area,
1198 None,
1199+ None,
1200 );
1201 }
1202 }
1203 @@ -415,6 +420,7 @@ impl Component for MailboxManager {
1204 self.theme_default.attrs | Attr::BOLD,
1205 area.skip_cols(x_offset),
1206 None,
1207+ None,
1208 );
1209 if self.sort_col as usize == i {
1210 use SortOrder::*;
1211 @@ -431,6 +437,7 @@ impl Component for MailboxManager {
1212 self.theme_default.attrs,
1213 area.skip_cols(x_offset + h.len()),
1214 None,
1215+ None,
1216 );
1217 }
1218 x_offset += w + 2;
1219 diff --git a/meli/src/notifications.rs b/meli/src/notifications.rs
1220index 8ed843c..53750c5 100644
1221--- a/meli/src/notifications.rs
1222+++ b/meli/src/notifications.rs
1223 @@ -435,6 +435,7 @@ impl Component for DisplayMessageBox {
1224 noto_colors.bg,
1225 noto_colors.attrs,
1226 box_displ_area.skip_rows(idx),
1227+ None,
1228 Some(0),
1229 );
1230 lines_no += 1 + y;
1231 @@ -463,6 +464,7 @@ impl Component for DisplayMessageBox {
1232 noto_colors.bg,
1233 noto_colors.attrs,
1234 box_displ_area.skip_rows(lines_no),
1235+ None,
1236 Some(0),
1237 );
1238 }
1239 diff --git a/meli/src/terminal/cells.rs b/meli/src/terminal/cells.rs
1240index 51bda21..53ab811 100644
1241--- a/meli/src/terminal/cells.rs
1242+++ b/meli/src/terminal/cells.rs
1243 @@ -633,6 +633,7 @@ impl CellBuffer {
1244 ret
1245 }
1246
1247+ #[allow(clippy::too_many_arguments)]
1248 /// Write an `&str` to a `CellBuffer` in a specified `Area` with the passed
1249 /// colors.
1250 pub fn write_string(
1251 @@ -641,13 +642,29 @@ impl CellBuffer {
1252 fg_color: Color,
1253 bg_color: Color,
1254 attrs: Attr,
1255- area: Area,
1256+ og_area: Area,
1257+ skip_cols: Option<usize>,
1258 // The left-most x coordinate.
1259 line_break: Option<usize>,
1260 ) -> Pos {
1261+ let skip_cols = skip_cols.unwrap_or(0);
1262+ let area = og_area.skip_cols(skip_cols);
1263+
1264 debug_assert_eq!(area.generation(), self.generation());
1265 if area.generation() != self.generation() {
1266- // [ref:TODO] log error
1267+ let backtrace = std::backtrace::Backtrace::force_capture();
1268+ log::error!(
1269+ "BUG: write_string() received an area argument of generation {} but the \
1270+ CellBuffer has generation of {}.",
1271+ area.generation(),
1272+ self.generation()
1273+ );
1274+ log::error!(
1275+ "BUG: Please report this.\nString was: {:?}.\nArea was: {:?}\nBacktrace:\n{}",
1276+ s,
1277+ og_area,
1278+ backtrace
1279+ );
1280 return (0, 0);
1281 }
1282 if area.is_empty() {
1283 @@ -665,7 +682,8 @@ impl CellBuffer {
1284 }
1285
1286 let mut bounds = self.size();
1287- let upper_left = area.upper_left();
1288+ let og_upper_left = og_area.upper_left();
1289+ let mut upper_left = area.upper_left();
1290 let bottom_right = area.bottom_right();
1291 let (mut x, mut y) = upper_left;
1292 let mut prev_coords = upper_left;
1293 @@ -707,83 +725,129 @@ impl CellBuffer {
1294 } else {
1295 s.into()
1296 };
1297- for c in input.chars() {
1298- if c == crate::emoji_text_presentation_selector!() {
1299- let prev_attrs = self[prev_coords].attrs();
1300- self[prev_coords].set_attrs(prev_attrs | Attr::FORCE_TEXT);
1301- continue;
1302- }
1303+ // Outer loop goes through the iterator elements.
1304+ // Inner loop handles only one element at a time.
1305+ // It might need to repeat itself if the end of a line is reached and line
1306+ // breaking is permitted.
1307+ 'char_loop: for c in input.chars() {
1308+ 'inner_loop: loop {
1309+ macro_rules! cell_mut {
1310+ ($x:expr, $y:expr) => {{
1311+ let ret;
1312+ if let Some(c) = self.get_mut($x, $y) {
1313+ ret = c;
1314+ } else {
1315+ log::debug!(
1316+ "Could not access cell (x, y) = ({}, {}) while writing char c = \
1317+ {:?} of string {:?} in area {:?}.",
1318+ $x,
1319+ $y,
1320+ c,
1321+ s,
1322+ og_area
1323+ );
1324+ break 'char_loop;
1325+ }
1326+ ret
1327+ }};
1328+ }
1329
1330- if c == '\r' {
1331- continue;
1332- }
1333- if c == '\n' {
1334- prev_coords = (x, y);
1335- y += 1;
1336- if let Some(_x) = line_break {
1337- x = _x + get_x(upper_left);
1338- continue;
1339- } else {
1340- break;
1341+ if c == crate::emoji_text_presentation_selector!() {
1342+ let prev_attrs = self[prev_coords].attrs();
1343+ self[prev_coords].set_attrs(prev_attrs | Attr::FORCE_TEXT);
1344+ continue 'char_loop;
1345 }
1346- }
1347- if y > get_y(bottom_right)
1348- || x > get_x(bottom_right)
1349- || y > get_y(bounds)
1350- || x > get_x(bounds)
1351- {
1352- if let Some(_x) = line_break {
1353- if !(y > get_y(bottom_right) || y > get_y(bounds)) {
1354- x = _x + get_x(upper_left);
1355- y += 1;
1356- continue;
1357- }
1358+
1359+ if c == '\r' {
1360+ continue 'char_loop;
1361 }
1362- break;
1363- }
1364- prev_coords = (x, y);
1365- if c == '\t' {
1366- self[(x, y)].set_ch(' ');
1367- x += 1;
1368- if let Some(c) = self.get_mut(x, y) {
1369- c.set_ch(' ');
1370- } else if let Some(_x) = line_break {
1371- if !(y > get_y(bottom_right) || y > get_y(bounds)) {
1372- x = _x + get_x(upper_left);
1373- y += 1;
1374- continue;
1375+ if c == '\n' {
1376+ prev_coords = (x, y);
1377+ y += 1;
1378+ if let Some(_x) = line_break {
1379+ x = if upper_left == og_upper_left {
1380+ _x + get_x(upper_left)
1381+ } else {
1382+ upper_left = og_upper_left;
1383+ _x + get_x(og_upper_left)
1384+ };
1385+ continue 'char_loop;
1386 } else {
1387- break;
1388+ break 'char_loop;
1389 }
1390 }
1391- } else {
1392- self[(x, y)].set_ch(c);
1393- }
1394- self[(x, y)]
1395- .set_fg(fg_color)
1396- .set_bg(bg_color)
1397- .set_attrs(attrs);
1398-
1399- match wcwidth(u32::from(c)) {
1400- Some(0) | None => {
1401- /* Skip drawing zero width characters */
1402- self[(x, y)].empty = true;
1403+ if y > get_y(bottom_right)
1404+ || x > get_x(bottom_right)
1405+ || y > get_y(bounds)
1406+ || x > get_x(bounds)
1407+ {
1408+ if let Some(_x) = line_break {
1409+ if !(y > get_y(bottom_right) || y > get_y(bounds)) {
1410+ x = if upper_left == og_upper_left {
1411+ _x + get_x(upper_left)
1412+ } else {
1413+ upper_left = og_upper_left;
1414+ _x + get_x(og_upper_left)
1415+ };
1416+ y += 1;
1417+ continue 'inner_loop;
1418+ }
1419+ }
1420+ break 'char_loop;
1421+ }
1422+ prev_coords = (x, y);
1423+ if c == '\t' {
1424+ cell_mut!(x, y).set_ch(' ');
1425+ x += 1;
1426+ if let Some(c) = self.get_mut(x, y) {
1427+ c.set_ch(' ');
1428+ } else if let Some(_x) = line_break {
1429+ if !(y > get_y(bottom_right) || y > get_y(bounds)) {
1430+ x = if upper_left == og_upper_left {
1431+ _x + get_x(upper_left)
1432+ } else {
1433+ upper_left = og_upper_left;
1434+ _x + get_x(og_upper_left)
1435+ };
1436+ y += 1;
1437+ continue 'char_loop;
1438+ } else {
1439+ break 'char_loop;
1440+ }
1441+ }
1442+ } else {
1443+ cell_mut!(x, y).set_ch(c);
1444 }
1445- Some(2) => {
1446- /* Grapheme takes more than one column, so the next cell will be
1447- * drawn over. Set it as empty to skip drawing it. */
1448- if let Some(c) = self.get_mut(x + 1, y) {
1449- x += 1;
1450- *c = Cell::default();
1451- c.set_fg(fg_color)
1452- .set_bg(bg_color)
1453- .set_attrs(attrs)
1454- .set_empty(true);
1455+ cell_mut!(x, y)
1456+ .set_fg(fg_color)
1457+ .set_bg(bg_color)
1458+ .set_attrs(attrs);
1459+
1460+ match wcwidth(u32::from(c)) {
1461+ Some(0) | None => {
1462+ // Skip drawing zero width characters
1463+ self[(x, y)].empty = true;
1464 }
1465+ Some(2) => {
1466+ // Grapheme takes more than one column, so the next cell will be drawn
1467+ // over. Set it as empty to skip drawing it.
1468+ if let Some(c) = self.get_mut(x + 1, y) {
1469+ x += 1;
1470+ *c = Cell::default();
1471+ c.set_fg(fg_color)
1472+ .set_bg(bg_color)
1473+ .set_attrs(attrs)
1474+ .set_empty(true);
1475+ }
1476+ }
1477+ _ => {}
1478 }
1479- _ => {}
1480+ x += 1;
1481+ break 'inner_loop;
1482 }
1483- x += 1;
1484+ }
1485+ if y - upper_left.1 > 0 && line_break.is_some() {
1486+ return (x - og_upper_left.0, y - upper_left.1);
1487 }
1488 (x - upper_left.0, y - upper_left.1)
1489 }
1490 diff --git a/meli/src/terminal/screen.rs b/meli/src/terminal/screen.rs
1491index e71c0a2..c4dc554 100644
1492--- a/meli/src/terminal/screen.rs
1493+++ b/meli/src/terminal/screen.rs
1494 @@ -61,6 +61,17 @@ impl Default for ScreenGeneration {
1495 }
1496 }
1497
1498+ impl std::fmt::Display for ScreenGeneration {
1499+ fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
1500+ let pair = self.0;
1501+ write!(
1502+ fmt,
1503+ "{}",
1504+ uuid::Uuid::from_u64_pair(pair.0, pair.1).as_simple()
1505+ )
1506+ }
1507+ }
1508+
1509 #[derive(Clone, Copy, Debug)]
1510 pub struct Virtual;
1511
1512 diff --git a/meli/src/utilities.rs b/meli/src/utilities.rs
1513index 8837851..d8b6042 100644
1514--- a/meli/src/utilities.rs
1515+++ b/meli/src/utilities.rs
1516 @@ -149,6 +149,7 @@ impl StatusBar {
1517 attribute.attrs,
1518 area,
1519 None,
1520+ None,
1521 );
1522 let offset = self.status.find('|').unwrap_or(self.status.len());
1523 for c in grid.row_iter(area, offset..(area.width()), 0) {
1524 @@ -178,6 +179,7 @@ impl StatusBar {
1525 attribute.attrs,
1526 area.skip_cols(x + 1),
1527 None,
1528+ None,
1529 );
1530 }
1531
1532 @@ -198,6 +200,7 @@ impl StatusBar {
1533 attribute.attrs,
1534 area.skip_cols(skip),
1535 None,
1536+ None,
1537 );
1538
1539 context.dirty_areas.push_back(area);
1540 @@ -237,6 +240,7 @@ impl StatusBar {
1541 command_bar.attrs,
1542 area,
1543 None,
1544+ None,
1545 );
1546 grid.change_theme(area, command_bar);
1547 if let Some(c) = grid
1548 @@ -909,7 +913,7 @@ impl Tabbed {
1549 tab_unfocused_attribute
1550 };
1551 let name = format!(" {c} ");
1552- grid.write_string(&name, fg, bg, attrs, area.skip_cols(x), None);
1553+ grid.write_string(&name, fg, bg, attrs, area.skip_cols(x), None, None);
1554 x += name.len() + 1;
1555 if idx == self.pinned.saturating_sub(1) {
1556 x += 2;
1557 @@ -1002,6 +1006,7 @@ impl Component for Tabbed {
1558 self.theme_default.attrs | Attr::BOLD,
1559 inner_area.skip_cols(2),
1560 None,
1561+ None,
1562 );
1563 grid.write_string(
1564 &format!(
1565 @@ -1013,6 +1018,7 @@ impl Component for Tabbed {
1566 self.theme_default.attrs | Attr::ITALICS,
1567 inner_area.skip(4 + x, y),
1568 None,
1569+ None,
1570 );
1571 let inner_area = inner_area.skip_rows(y + 1).skip_rows_from_end(1);
1572 let (width, height) = self.help_view.content.grid().size();
1573 @@ -1118,6 +1124,7 @@ impl Component for Tabbed {
1574 self.theme_default.attrs,
1575 help_area.skip(2, 1),
1576 None,
1577+ None,
1578 );
1579 let mut idx = 2;
1580 for (desc, shortcuts) in children_maps.iter() {
1581 @@ -1129,6 +1136,7 @@ impl Component for Tabbed {
1582 self.theme_default.attrs,
1583 help_area.skip(2, 2 + idx),
1584 None,
1585+ None,
1586 );
1587 idx += 2;
1588 for (k, v) in shortcuts {
1589 @@ -1144,6 +1152,7 @@ impl Component for Tabbed {
1590 self.theme_default.attrs | Attr::BOLD,
1591 help_area.skip(2, 2 + idx),
1592 None,
1593+ None,
1594 );
1595 let help_area = self.help_view.content.area();
1596 self.help_view.content.grid_mut().write_string(
1597 @@ -1153,6 +1162,7 @@ impl Component for Tabbed {
1598 self.theme_default.attrs,
1599 help_area.skip(x + 4, 2 + idx),
1600 None,
1601+ None,
1602 );
1603 idx += 1;
1604 }
1605 @@ -1180,6 +1190,7 @@ impl Component for Tabbed {
1606 self.theme_default.attrs | Attr::BOLD,
1607 inner_area.skip_cols(2),
1608 None,
1609+ None,
1610 );
1611 grid.write_string(
1612 &format!(
1613 @@ -1191,6 +1202,7 @@ impl Component for Tabbed {
1614 self.theme_default.attrs | Attr::ITALICS,
1615 inner_area.skip(4 + x, y),
1616 None,
1617+ None,
1618 );
1619 let inner_area = inner_area.skip_rows(y + 1).skip_rows_from_end(1);
1620 let (width, height) = self.help_view.content.area().size();
1621 @@ -1279,6 +1291,7 @@ impl Component for Tabbed {
1622 self.theme_default.attrs | Attr::ITALICS,
1623 help_area.skip(2, 2),
1624 None,
1625+ None,
1626 );
1627 }
1628
1629 diff --git a/meli/src/utilities/dialogs.rs b/meli/src/utilities/dialogs.rs
1630index b63af6f..2d419d8 100644
1631--- a/meli/src/utilities/dialogs.rs
1632+++ b/meli/src/utilities/dialogs.rs
1633 @@ -594,6 +594,7 @@ impl<T: PartialEq + std::fmt::Debug + Clone + Sync + Send, F: 'static + Sync + S
1634 self.theme_default.attrs | Attr::BOLD,
1635 inner_area.skip_cols(2),
1636 None,
1637+ None,
1638 );
1639
1640 let y = self
1641 @@ -606,6 +607,7 @@ impl<T: PartialEq + std::fmt::Debug + Clone + Sync + Send, F: 'static + Sync + S
1642 self.theme_default.attrs | Attr::ITALICS,
1643 inner_area.skip_cols(2).skip_rows(y + 2),
1644 None,
1645+ None,
1646 )
1647 .1
1648 + y
1649 @@ -628,6 +630,7 @@ impl<T: PartialEq + std::fmt::Debug + Clone + Sync + Send, F: 'static + Sync + S
1650 attr.attrs,
1651 inner_area.nth_row(i),
1652 None,
1653+ None,
1654 );
1655 }
1656 } else {
1657 @@ -644,6 +647,7 @@ impl<T: PartialEq + std::fmt::Debug + Clone + Sync + Send, F: 'static + Sync + S
1658 attr.attrs,
1659 inner_area.nth_row(i),
1660 None,
1661+ None,
1662 );
1663 }
1664 let inner_area = inner_area.nth_row(self.entry_titles.len() + 2).skip_cols(2);
1665 @@ -659,6 +663,7 @@ impl<T: PartialEq + std::fmt::Debug + Clone + Sync + Send, F: 'static + Sync + S
1666 attr.attrs | Attr::BOLD,
1667 inner_area,
1668 None,
1669+ None,
1670 );
1671 let attr = if matches!(self.cursor, SelectorCursor::Cancel) {
1672 highlighted_attrs
1673 @@ -672,6 +677,7 @@ impl<T: PartialEq + std::fmt::Debug + Clone + Sync + Send, F: 'static + Sync + S
1674 attr.attrs,
1675 inner_area.skip(CANCEL_OFFSET + x, y),
1676 None,
1677+ None,
1678 );
1679 }
1680 self.initialized = true;
1681 diff --git a/meli/src/utilities/pager.rs b/meli/src/utilities/pager.rs
1682index 681e8fe..e1bb750 100644
1683--- a/meli/src/utilities/pager.rs
1684+++ b/meli/src/utilities/pager.rs
1685 @@ -373,6 +373,7 @@ impl Pager {
1686 Attr::DEFAULT,
1687 area2,
1688 None,
1689+ None,
1690 );
1691 if l.starts_with('⤷') {
1692 grid[area2.upper_left()]
1693 @@ -651,6 +652,7 @@ impl Component for Pager {
1694 attribute.attrs,
1695 area.nth_row(area.height().saturating_sub(1)),
1696 None,
1697+ None,
1698 );
1699 /* set search pattern to italics */
1700 let start_x = RESULTS_STR.len();
1701 diff --git a/meli/src/utilities/text.rs b/meli/src/utilities/text.rs
1702index 234cd29..8a6ac88 100644
1703--- a/meli/src/utilities/text.rs
1704+++ b/meli/src/utilities/text.rs
1705 @@ -189,6 +189,7 @@ impl Component for TextField {
1706 theme_attr.attrs,
1707 area,
1708 None,
1709+ None,
1710 );
1711 }
1712
1713 diff --git a/meli/src/utilities/widgets.rs b/meli/src/utilities/widgets.rs
1714index 78246be..d05a609 100644
1715--- a/meli/src/utilities/widgets.rs
1716+++ b/meli/src/utilities/widgets.rs
1717 @@ -125,6 +125,7 @@ impl Component for Field {
1718 theme_attr.attrs,
1719 area,
1720 None,
1721+ None,
1722 );
1723 }
1724 }
1725 @@ -373,6 +374,7 @@ impl<T: 'static + std::fmt::Debug + Copy + Default + Send + Sync> Component for
1726 theme_attr.attrs,
1727 area.nth_row(i).skip_cols(1),
1728 None,
1729+ None,
1730 );
1731 /* draw field */
1732 v.draw(
1733 @@ -616,6 +618,7 @@ where
1734 Attr::BOLD,
1735 area.skip_cols(len),
1736 None,
1737+ None,
1738 );
1739 len += cur_len + 3;
1740 }
1741 @@ -756,6 +759,7 @@ impl Component for AutoComplete {
1742 Attr::DEFAULT,
1743 area.nth_row(i).take_cols(width),
1744 None,
1745+ None,
1746 );
1747 grid.write_string(
1748 &e.description,
1749 @@ -764,6 +768,7 @@ impl Component for AutoComplete {
1750 Attr::ITALICS,
1751 area.nth_row(i).skip_cols(x + 2).take_cols(width),
1752 None,
1753+ None,
1754 );
1755 grid.write_string(
1756 "▒",
1757 @@ -772,6 +777,7 @@ impl Component for AutoComplete {
1758 Attr::DEFAULT,
1759 area.nth_row(i).skip_cols(width - 1),
1760 None,
1761+ None,
1762 );
1763 }
1764
1765 @@ -1179,6 +1185,7 @@ impl Component for ProgressSpinner {
1766 self.theme_attr.attrs,
1767 area,
1768 None,
1769+ None,
1770 );
1771 }
1772 context.dirty_areas.push_back(area);
1773 diff --git a/tools/src/embedded.rs b/tools/src/embedded.rs
1774index cab1271..907b71f 100644
1775--- a/tools/src/embedded.rs
1776+++ b/tools/src/embedded.rs
1777 @@ -156,6 +156,7 @@ impl Component for EmbeddedContainer {
1778 theme_default.attrs,
1779 inner_area.skip_rows(i),
1780 None,
1781+ None,
1782 );
1783 }
1784 context.dirty_areas.push_back(area);