1mod hbox;
3mod repeat;
4mod text_widget;
5mod truncatable;
6pub use hbox::*;
7pub use repeat::*;
8pub use text_widget::*;
9pub use truncatable::*;
10
11#[cfg(test)]
12mod test {
13 use super::*;
14 use crate::text::{Pushable, Span, Spans, WidthSliceable};
15 use crate::widget::truncatable::TruncationStyle;
16 use ansi_term::{ANSIStrings, Color, Style};
17 use std::borrow::Cow;
18 fn make_spans(style: &Style, text: &str) -> Spans<Style> {
19 let ansistring = style.paint(text);
20 let span: Span<Style> = ansistring.into();
21 let mut spans: Spans<Style> = Default::default();
22 spans.push(&span);
23 spans
24 }
25
26 #[test]
27 fn truncate_trivial_left() {
28 let style = Color::Red.normal();
29 let content = "0123456";
30 let text = make_spans(&style, content);
31 let ellipsis_style = Color::Blue.normal();
32 let ellipsis = "…";
33 let ellipsis_span = make_spans(&ellipsis_style, ellipsis);
34 let truncation = TruncationStyle::Left(Some(ellipsis_span));
35 let widget = TextWidget::new(Cow::Borrowed(&text), Cow::Borrowed(&truncation));
36 let mut hbox = HBox::new();
37 hbox.push(Box::new(widget));
38 let actual = format!("{}", hbox.truncate(4));
39 let expected = format!(
40 "{}",
41 ANSIStrings(&[style.paint("012"), ellipsis_style.paint(ellipsis)])
42 );
43 assert_eq!(expected, actual);
44 }
45
46 #[test]
47 fn truncate_compound_span_left() {
48 let style0 = Color::Red.normal();
49 let style1 = Color::Green.normal();
50 let content0 = "0123456";
51 let content1 = "789";
52 let text = {
53 let mut text = make_spans(&style0, content0);
54 text.push(&make_spans(&style1, content1));
55 text
56 };
57 let ellipsis_style = Color::Blue.normal();
58 let ellipsis = "…";
59 let ellipsis_span = make_spans(&ellipsis_style, ellipsis);
60 let truncation = TruncationStyle::Left(Some(ellipsis_span));
61 let widget = TextWidget::new(Cow::Borrowed(&text), Cow::Borrowed(&truncation));
62 let mut hbox = HBox::new();
63 hbox.push(Box::new(widget));
64 let actual = format!("{}", hbox.truncate(4));
65 let expected = format!(
66 "{}",
67 ANSIStrings(&[style0.paint("012"), ellipsis_style.paint(ellipsis)])
68 );
69 assert_eq!(expected, actual);
70 }
71
72 #[test]
73 fn truncate_compound_span_2_left() {
74 let style0 = Color::Red.normal();
75 let style1 = Color::Green.normal();
76 let content0 = "0123456";
77 let content1 = "789";
78 let text = {
79 let mut text = make_spans(&style0, content0);
80 text.push(&make_spans(&style1, content1));
81 text
82 };
83 let ellipsis_style = Color::Blue.normal();
84 let ellipsis = "…";
85 let ellipsis_span = make_spans(&ellipsis_style, ellipsis);
86 let truncation = TruncationStyle::Left(Some(ellipsis_span));
87 let widget = TextWidget::new(Cow::Borrowed(&text), Cow::Borrowed(&truncation));
88 let mut hbox = HBox::new();
89 hbox.push(Box::new(widget));
90 let actual = format!("{}", hbox.truncate(9));
91 let expected = format!(
92 "{}",
93 ANSIStrings(&[
94 style0.paint(content0),
95 style1.paint("7"),
96 ellipsis_style.paint(ellipsis),
97 ]),
98 );
99 assert_eq!(expected, actual);
100 }
101
102 #[test]
103 fn truncate_two_widgets_first_left() {
104 let style0 = Color::Red.normal();
105 let style1 = Color::Green.normal();
106 let content0 = "01234";
107 let content1 = "56789";
108 let first_span = make_spans(&style0, content0);
109 let second_span = make_spans(&style1, content1);
110 let ellipsis_style = Color::Blue.normal();
111 let ellipsis = "…";
112 let ellipsis_span = make_spans(&ellipsis_style, ellipsis);
113 let truncation = TruncationStyle::Left(Some(ellipsis_span));
114 let hbox = vec![&first_span, &second_span]
115 .iter()
116 .map(|s| {
117 let foo: Box<dyn Fitable<_>> =
118 Box::new(TextWidget::<Spans<_>, TruncationStyle<_>>::new(
119 Cow::Borrowed(s),
120 Cow::Borrowed(&truncation),
121 ));
122 foo
123 })
124 .collect::<HBox<Spans<_>>>();
125 let actual = format!("{}", hbox.truncate(8));
126 let expected = format!(
127 "{}",
128 ANSIStrings(&[
129 style0.paint("012"),
130 ellipsis_style.paint(ellipsis),
131 style1.paint("567"),
132 ellipsis_style.paint(ellipsis),
133 ])
134 );
135 assert_eq!(expected, actual);
136 }
137
138 #[test]
139 fn truncate_trivial_left_noop() {
140 let style = Color::Red.normal();
141 let content = "0123456";
142 let string = style.paint(content);
143 let text = make_spans(&style, content);
144 let ellipsis_style = Color::Blue.normal();
145 let ellipsis = "…";
146 let ellipsis_span = make_spans(&ellipsis_style, ellipsis);
147 let truncation = TruncationStyle::Left(Some(ellipsis_span));
148 let widget = TextWidget::new(Cow::Borrowed(&text), Cow::Borrowed(&truncation));
149 let mut hbox = HBox::new();
150 hbox.push(Box::new(widget));
151 let actual = format!("{}", hbox.truncate(7));
152 let expected = format!("{}", ANSIStrings(&[string]));
153 assert_eq!(expected, actual);
154 }
155
156 #[test]
157 fn trunctate_infinite_left() {
158 let span = Span::<Style>::new(
159 Cow::Owned(Color::Blue.normal()),
160 Cow::Owned("=".to_string()),
161 );
162 use std::ops::Bound;
163 span.slice_width((Bound::Unbounded, Bound::Included(5)));
164 let repeat_widget = Repeat::new(span);
165 let truncator_style = Color::Black.normal();
166 let truncator_text = ".";
167 let truncator_span = make_spans(&truncator_style, truncator_text);
168 let truncation = TruncationStyle::Left(Some(truncator_span));
169 let repeat_text_widget =
170 TextWidget::new(Cow::Borrowed(&repeat_widget), Cow::Borrowed(&truncation));
171 let mut hbox = HBox::new();
172 hbox.push(Box::new(repeat_text_widget));
173 let actual = format!("{}", hbox.truncate(5));
174 let expected = format!(
175 "{}",
176 ANSIStrings(&[
177 Color::Blue.normal().paint("===="),
178 truncator_style.paint(truncator_text),
179 ])
180 );
181 assert_eq!(expected, actual);
182 }
183
184 #[test]
185 fn truncate_trivial_right() {
186 let style = Color::Red.normal();
187 let content = "0123456";
188 let text = make_spans(&style, content);
189 let ellipsis_style = Color::Blue.normal();
190 let ellipsis = "…";
191 let ellipsis_span = make_spans(&ellipsis_style, ellipsis);
192 let truncation = TruncationStyle::Right(Some(ellipsis_span));
193 let widget = TextWidget::new(Cow::Borrowed(&text), Cow::Borrowed(&truncation));
194 let mut hbox = HBox::new();
195 hbox.push(Box::new(widget));
196 let actual = format!("{}", hbox.truncate(4));
197 let expected = format!(
198 "{}",
199 ANSIStrings(&[ellipsis_style.paint(ellipsis), style.paint("456")])
200 );
201 assert_eq!(expected, actual);
202 }
203
204 #[test]
205 fn truncate_compound_span_right() {
206 let style0 = Color::Red.normal();
207 let style1 = Color::Green.normal();
208 let content0 = "0123456";
209 let content1 = "789";
210 let text = {
211 let mut text = make_spans(&style0, content0);
212 text.push(&make_spans(&style1, content1));
213 text
214 };
215 let ellipsis_style = Color::Blue.normal();
216 let ellipsis = "…";
217 let ellipsis_span = make_spans(&ellipsis_style, ellipsis);
218 let truncation = TruncationStyle::Right(Some(ellipsis_span));
219 let widget = TextWidget::new(Cow::Borrowed(&text), Cow::Borrowed(&truncation));
220 let mut hbox = HBox::new();
221 hbox.push(Box::new(widget));
222 let actual = format!("{}", hbox.truncate(6));
223 let expected = format!(
224 "{}",
225 ANSIStrings(&[
226 ellipsis_style.paint(ellipsis),
227 style0.paint("56"),
228 style1.paint("789"),
229 ])
230 );
231 assert_eq!(expected, actual);
232 }
233
234 #[test]
235 fn truncate_compound_span_2_right() {
236 let style0 = Color::Red.normal();
237 let style1 = Color::Green.normal();
238 let content0 = "0123456";
239 let content1 = "789";
240 let text = {
241 let mut text = make_spans(&style0, content0);
242 text.push(&make_spans(&style1, content1));
243 text
244 };
245 let ellipsis_style = Color::Blue.normal();
246 let ellipsis = "…";
247 let ellipsis_span = make_spans(&ellipsis_style, ellipsis);
248 let truncation = TruncationStyle::Right(Some(ellipsis_span));
249 let widget = TextWidget::new(Cow::Borrowed(&text), Cow::Borrowed(&truncation));
250 let mut hbox = HBox::new();
251 hbox.push(Box::new(widget));
252 let actual = format!("{}", hbox.truncate(9));
253 let expected = format!(
254 "{}",
255 ANSIStrings(&[
256 ellipsis_style.paint(ellipsis),
257 style0.paint("23456"),
258 style1.paint(content1),
259 ])
260 );
261 assert_eq!(expected, actual);
262 }
263
264 #[test]
265 fn truncate_two_widgets_first_right() {
266 let style0 = Color::Red.normal();
267 let style1 = Color::Green.normal();
268 let content0 = "01234";
269 let content1 = "56789";
270 let first_span = make_spans(&style0, content0);
271 let second_span = make_spans(&style1, content1);
272 let ellipsis_style = Color::Blue.normal();
273 let ellipsis = "…";
274 let ellipsis_span = make_spans(&ellipsis_style, ellipsis);
275 let truncation = TruncationStyle::Right(Some(ellipsis_span));
276 let hbox = vec![&first_span, &second_span]
277 .iter()
278 .map(|s| {
279 let b: Box<dyn Fitable<_>> =
280 Box::new(TextWidget::<Spans<_>, TruncationStyle<_>>::new(
281 Cow::Borrowed(s),
282 Cow::Borrowed(&truncation),
283 ));
284 b
285 })
286 .collect::<HBox<_>>();
287 let actual = format!("{}", hbox.truncate(8));
288 let expected = format!(
289 "{}",
290 ANSIStrings(&[
291 ellipsis_style.paint(ellipsis),
292 style0.paint("234"),
293 ellipsis_style.paint(ellipsis),
294 style1.paint("789"),
295 ])
296 );
297 assert_eq!(expected, actual);
298 }
299
300 #[test]
301 fn truncate_trivial_right_noop() {
302 let style = Color::Red.normal();
303 let content = "0123456";
304 let string = style.paint(content);
305 let text = make_spans(&style, content);
306 let ellipsis_style = Color::Blue.normal();
307 let ellipsis = "…";
308 let ellipsis_span = make_spans(&ellipsis_style, ellipsis);
309 let truncation = TruncationStyle::Right(Some(ellipsis_span));
310 let widget = TextWidget::new(Cow::Borrowed(&text), Cow::Borrowed(&truncation));
311 let mut hbox = HBox::new();
312 hbox.push(Box::new(widget));
313 let actual = format!("{}", hbox.truncate(7));
314 let expected = format!("{}", ANSIStrings(&[string]));
315 assert_eq!(expected, actual);
316 }
317
318 #[test]
319 fn trunctate_infinite_right() {
320 let repeat_widget = Repeat::new(Span::<Style>::new(
321 Cow::Owned(Color::Blue.normal()),
322 Cow::Owned("=".to_string()),
323 ));
324 let truncator_style = Color::Black.normal();
325 let truncator_str = ".";
326 let truncator_span = make_spans(&truncator_style, truncator_str);
327 let truncation = TruncationStyle::Right(Some(truncator_span));
328 let repeat_text_widget =
329 TextWidget::new(Cow::Borrowed(&repeat_widget), Cow::Borrowed(&truncation));
330 let mut hbox = HBox::new();
331 hbox.push(Box::new(repeat_text_widget));
332 let actual = format!("{}", hbox.truncate(5));
333 let expected = format!(
334 "{}",
335 ANSIStrings(&[
336 truncator_style.paint(truncator_str),
337 Color::Blue.normal().paint("===="),
338 ])
339 );
340 assert_eq!(expected, actual);
341 }
342
343 #[test]
344 fn truncate_trivial_inner() {
345 let style = Color::Red.normal();
346 let content = "0123456";
347 let text = make_spans(&style, content);
348 let ellipsis_style = Color::Blue.normal();
349 let ellipsis = "…";
350 let ellipsis_span = make_spans(&ellipsis_style, ellipsis);
351 let truncation = TruncationStyle::Inner(Some(ellipsis_span));
352 let widget = TextWidget::new(Cow::Borrowed(&text), Cow::Borrowed(&truncation));
353 let mut hbox = HBox::new();
354 hbox.push(Box::new(widget));
355 let actual = format!("{}", hbox.truncate(4));
356 let expected = format!(
357 "{}",
358 ANSIStrings(&[
359 style.paint("01"),
360 ellipsis_style.paint(ellipsis),
361 style.paint("6"),
362 ])
363 );
364 assert_eq!(expected, actual);
365 }
366
367 #[test]
368 fn truncate_compound_span_inner() {
369 let style0 = Color::Red.normal();
370 let style1 = Color::Green.normal();
371 let content0 = "01234";
372 let content1 = "56789";
373 let text = {
374 let mut text = make_spans(&style0, content0);
375 text.push(&make_spans(&style1, content1));
376 text
377 };
378 let ellipsis_style = Color::Blue.normal();
379 let ellipsis = "…";
380 let ellipsis_span = make_spans(&ellipsis_style, ellipsis);
381 let truncation = TruncationStyle::Inner(Some(ellipsis_span));
382 let widget = TextWidget::new(Cow::Borrowed(&text), Cow::Borrowed(&truncation));
383 let mut hbox = HBox::new();
384 hbox.push(Box::new(widget));
385 let actual = format!("{}", hbox.truncate(6));
386 let expected = format!(
387 "{}",
388 ANSIStrings(&[
389 style0.paint("012"),
390 ellipsis_style.paint(ellipsis),
391 style1.paint("89"),
392 ])
393 );
394 assert_eq!(expected, actual);
395 }
396
397 #[test]
398 fn truncate_compound_span_2_inner() {
399 let style0 = Color::Red.normal();
400 let style1 = Color::Green.normal();
401 let content0 = "0123456";
402 let content1 = "789";
403 let text = {
404 let mut text = make_spans(&style0, content0);
405 text.push(&make_spans(&style1, content1));
406 text
407 };
408 let ellipsis_style = Color::Blue.normal();
409 let ellipsis = "…";
410 let ellipsis_span = make_spans(&ellipsis_style, ellipsis);
411 let truncation = TruncationStyle::Inner(Some(ellipsis_span));
412 let widget = TextWidget::new(Cow::Borrowed(&text), Cow::Borrowed(&truncation));
413 let mut hbox = HBox::new();
414 hbox.push(Box::new(widget));
415 let actual = format!("{}", hbox.truncate(9));
416 let expected = format!(
417 "{}",
418 ANSIStrings(&[
419 style0.paint("0123"),
420 ellipsis_style.paint(ellipsis),
421 style0.paint("6"),
422 style1.paint(content1),
423 ])
424 );
425 eprintln!("expected: {}", expected);
426 eprintln!("actual: {}", actual);
427 assert_eq!(expected, actual);
428 }
429
430 #[test]
431 fn truncate_two_widgets_first_inner() {
432 let style0 = Color::Red.normal();
433 let style1 = Color::Green.normal();
434 let content0 = "01234";
435 let content1 = "56789";
436 let first_span = make_spans(&style0, content0);
437 let second_span = make_spans(&style1, content1);
438 let ellipsis_style = Color::Blue.normal();
439 let ellipsis = "…";
440 let ellipsis_span = make_spans(&ellipsis_style, ellipsis);
441 let truncation = TruncationStyle::Inner(Some(ellipsis_span));
442 let hbox = vec![&first_span, &second_span]
443 .iter()
444 .map(|s| {
445 let b: Box<dyn Fitable<_>> =
446 Box::new(TextWidget::<Spans<_>, TruncationStyle<_>>::new(
447 Cow::Borrowed(s),
448 Cow::Borrowed(&truncation),
449 ));
450 b
451 })
452 .collect::<HBox<_>>();
453
454 let actual = format!("{}", hbox.truncate(8));
455 let expected = format!(
456 "{}",
457 ANSIStrings(&[
458 style0.paint("01"),
459 ellipsis_style.paint(ellipsis),
460 style0.paint("4"),
461 style1.paint("56"),
462 ellipsis_style.paint(ellipsis),
463 style1.paint("9"),
464 ])
465 );
466 assert_eq!(expected, actual);
467 }
468
469 #[test]
470 fn truncate_trivial_inner_noop() {
471 let style = Color::Red.normal();
472 let content = "0123456";
473 let text = make_spans(&style, content);
474 let ellipsis_style = Color::Blue.normal();
475 let ellipsis = "…";
476 let ellipsis_span = make_spans(&ellipsis_style, ellipsis);
477 let truncation = TruncationStyle::Inner(Some(ellipsis_span));
478 let widget = TextWidget::new(Cow::Borrowed(&text), Cow::Borrowed(&truncation));
479 let mut hbox = HBox::new();
480 hbox.push(Box::new(widget));
481 let actual = format!("{}", hbox.truncate(7));
482 let expected = format!("{}", ANSIStrings(&[style.paint(content)]));
483 assert_eq!(expected, actual);
484 }
485
486 #[test]
487 fn trunctate_infinite_inner() {
488 let repeat_widget = Repeat::new(Span::<Style>::new(
489 Cow::Owned(Color::Blue.normal()),
490 Cow::Owned("=".to_string()),
491 ));
492 let truncator_style = Color::Black.normal();
493 let truncator_text = ".";
494 let truncator = truncator_style.paint(truncator_text);
495 let truncator_span = make_spans(&truncator_style, truncator_text);
496 let truncation = TruncationStyle::Inner(Some(truncator_span));
497 let repeat_text_widget =
498 TextWidget::new(Cow::Borrowed(&repeat_widget), Cow::Borrowed(&truncation));
499 let mut hbox = HBox::new();
500 hbox.push(Box::new(repeat_text_widget));
501 let actual = format!("{}", hbox.truncate(5));
502 let expected = format!(
503 "{}",
504 ANSIStrings(&[
505 Color::Blue.normal().paint("=="),
506 truncator.clone(),
507 Color::Blue.normal().paint("=="),
508 ])
509 );
510 assert_eq!(expected, actual);
511 }
512
513 #[test]
514 fn trunctate_infinite_none_left() {
515 let span = Span::<Style>::new(
516 Cow::Owned(Color::Blue.normal()),
517 Cow::Owned("=".to_string()),
518 );
519 use std::ops::Bound;
520 span.slice_width((Bound::Unbounded, Bound::Included(5)));
521 let repeat_widget = Repeat::new(span);
522 let truncator_style = Color::Black.normal();
523 let truncator_text = ".";
524 let truncator_span = make_spans(&truncator_style, truncator_text);
525 let truncation = TruncationStyle::Left(Some(truncator_span));
526 let repeat_text_widget =
527 TextWidget::new(Cow::Borrowed(&repeat_widget), Cow::Borrowed(&truncation));
528 let mut hbox = HBox::new();
529 hbox.push(Box::new(repeat_text_widget));
530 let actual = format!("{}", hbox.truncate(0));
531 let expected = String::new();
532 assert_eq!(expected, actual);
533 }
534
535 #[test]
536 fn trunctate_infinite_none_right() {
537 let span = Span::<Style>::new(
538 Cow::Owned(Color::Blue.normal()),
539 Cow::Owned("=".to_string()),
540 );
541 use std::ops::Bound;
542 span.slice_width((Bound::Unbounded, Bound::Included(5)));
543 let repeat_widget = Repeat::new(span);
544 let truncator_style = Color::Black.normal();
545 let truncator_text = ".";
546 let truncator_span = make_spans(&truncator_style, truncator_text);
547 let truncation = TruncationStyle::Right(Some(truncator_span));
548 let repeat_text_widget =
549 TextWidget::new(Cow::Borrowed(&repeat_widget), Cow::Borrowed(&truncation));
550 let mut hbox = HBox::new();
551 hbox.push(Box::new(repeat_text_widget));
552 let actual = format!("{}", hbox.truncate(0));
553 let expected = String::new();
554 assert_eq!(expected, actual);
555 }
556
557 #[test]
558 fn trunctate_infinite_none_inner() {
559 let span = Span::<Style>::new(
560 Cow::Owned(Color::Blue.normal()),
561 Cow::Owned("=".to_string()),
562 );
563 use std::ops::Bound;
564 span.slice_width((Bound::Unbounded, Bound::Included(5)));
565 let repeat_widget = Repeat::new(span);
566 let truncator_style = Color::Black.normal();
567 let truncator_text = ".";
568 let truncator_span = make_spans(&truncator_style, truncator_text);
569 let truncation = TruncationStyle::Inner(Some(truncator_span));
570 let repeat_text_widget =
571 TextWidget::new(Cow::Borrowed(&repeat_widget), Cow::Borrowed(&truncation));
572 let mut hbox = HBox::new();
573 hbox.push(Box::new(repeat_text_widget));
574 let actual = format!("{}", hbox.truncate(0));
575 let expected = String::new();
576 assert_eq!(expected, actual);
577 }
578
579 #[test]
580 fn trunctate_infinite_only_symbol() {
581 let span = Span::<Style>::new(
582 Cow::Owned(Color::Blue.normal()),
583 Cow::Owned("=".to_string()),
584 );
585 use std::ops::Bound;
586 span.slice_width((Bound::Unbounded, Bound::Included(5)));
587 let repeat_widget = Repeat::new(span);
588 let truncator_style = Color::Black.normal();
589 let truncator_text = ".";
590 let truncator_span = make_spans(&truncator_style, truncator_text);
591 let truncation = TruncationStyle::Inner(Some(truncator_span));
592 let repeat_text_widget =
593 TextWidget::new(Cow::Borrowed(&repeat_widget), Cow::Borrowed(&truncation));
594 let mut hbox = HBox::new();
595 hbox.push(Box::new(repeat_text_widget));
596 let actual = format!("{}", hbox.truncate(1));
597 let expected = format!("{}", truncator_style.paint(truncator_text));
598 assert_eq!(expected, actual);
599 }
600}