@@ -453,6 +453,39 @@ impl<'a> Line<'a> {
453
453
self . spans . iter_mut ( )
454
454
}
455
455
456
+ /// Returns a line that's truncated corresponding to it's alignment and result width
457
+ #[ must_use = "method returns the modified value" ]
458
+ fn truncated ( & ' a self , result_width : u16 ) -> Self {
459
+ let mut truncated_line = Line :: default ( ) ;
460
+ let width = self . width ( ) as u16 ;
461
+ let mut offset = match self . alignment {
462
+ Some ( Alignment :: Center ) => ( width. saturating_sub ( result_width) ) / 2 ,
463
+ Some ( Alignment :: Right ) => width. saturating_sub ( result_width) ,
464
+ _ => 0 ,
465
+ } ;
466
+ let mut x = 0 ;
467
+ for span in & self . spans {
468
+ let span_width = span. width ( ) as u16 ;
469
+ if offset >= span_width {
470
+ offset -= span_width;
471
+ continue ;
472
+ }
473
+ let mut new_span = span. clone ( ) ;
474
+ let new_span_width = span_width - offset;
475
+ if x + new_span_width > result_width {
476
+ let span_end = ( result_width - x + offset) as usize ;
477
+ new_span. content = Cow :: from ( & span. content [ offset as usize ..span_end] ) ;
478
+ truncated_line. spans . push ( new_span) ;
479
+ break ;
480
+ }
481
+
482
+ new_span. content = Cow :: from ( & span. content [ offset as usize ..] ) ;
483
+ truncated_line. spans . push ( new_span) ;
484
+ x += new_span_width;
485
+ offset = 0 ;
486
+ }
487
+ truncated_line
488
+ }
456
489
/// Adds a span to the line.
457
490
///
458
491
/// `span` can be any type that is convertible into a `Span`. For example, you can pass a
@@ -554,17 +587,23 @@ impl WidgetRef for Line<'_> {
554
587
let area = area. intersection ( buf. area ) ;
555
588
buf. set_style ( area, self . style ) ;
556
589
let width = self . width ( ) as u16 ;
557
- let offset = match self . alignment {
558
- Some ( Alignment :: Center ) => ( area. width . saturating_sub ( width) ) / 2 ,
559
- Some ( Alignment :: Right ) => area. width . saturating_sub ( width) ,
560
- Some ( Alignment :: Left ) | None => 0 ,
590
+ let mut x = area. left ( ) ;
591
+ let line = if width > area. width {
592
+ self . truncated ( area. width )
593
+ } else {
594
+ let offset = match self . alignment {
595
+ Some ( Alignment :: Center ) => ( area. width . saturating_sub ( width) ) / 2 ,
596
+ Some ( Alignment :: Right ) => area. width . saturating_sub ( width) ,
597
+ Some ( Alignment :: Left ) | None => 0 ,
598
+ } ;
599
+ x = x. saturating_add ( offset) ;
600
+ self . to_owned ( )
561
601
} ;
562
- let mut x = area. left ( ) . saturating_add ( offset) ;
563
- for span in & self . spans {
602
+ for span in & line. spans {
564
603
let span_width = span. width ( ) as u16 ;
565
604
let span_area = Rect {
566
605
x,
567
- width : span_width. min ( area. right ( ) - x ) ,
606
+ width : span_width. min ( area. right ( ) . saturating_sub ( x ) ) ,
568
607
..area
569
608
} ;
570
609
span. render ( span_area, buf) ;
@@ -604,6 +643,7 @@ mod tests {
604
643
use rstest:: { fixture, rstest} ;
605
644
606
645
use super :: * ;
646
+ use crate :: assert_buffer_eq;
607
647
608
648
#[ fixture]
609
649
fn small_buf ( ) -> Buffer {
@@ -847,6 +887,53 @@ mod tests {
847
887
848
888
assert_eq ! ( format!( "{line_from_styled_span}" ) , "Hello, world!" ) ;
849
889
}
890
+ #[ test]
891
+ fn render_truncates_left ( ) {
892
+ let mut buf = Buffer :: empty ( Rect :: new ( 0 , 0 , 5 , 1 ) ) ;
893
+ Line :: from ( "Hello world" )
894
+ . left_aligned ( )
895
+ . render ( buf. area , & mut buf) ;
896
+ let expected = Buffer :: with_lines ( vec ! [ "Hello" ] ) ;
897
+ assert_buffer_eq ! ( buf, expected) ;
898
+ }
899
+
900
+ #[ test]
901
+ fn render_truncates_right ( ) {
902
+ let mut buf = Buffer :: empty ( Rect :: new ( 0 , 0 , 5 , 1 ) ) ;
903
+ Line :: from ( "Hello world" )
904
+ . right_aligned ( )
905
+ . render ( buf. area , & mut buf) ;
906
+ let expected = Buffer :: with_lines ( vec ! [ "world" ] ) ;
907
+ assert_buffer_eq ! ( buf, expected) ;
908
+ }
909
+
910
+ #[ test]
911
+ fn render_truncates_center ( ) {
912
+ let mut buf = Buffer :: empty ( Rect :: new ( 0 , 0 , 5 , 1 ) ) ;
913
+ Line :: from ( "Hello world" )
914
+ . centered ( )
915
+ . render ( buf. area , & mut buf) ;
916
+ let expected = Buffer :: with_lines ( vec ! [ "lo wo" ] ) ;
917
+ assert_buffer_eq ! ( buf, expected) ;
918
+ }
919
+
920
+ #[ test]
921
+ fn truncate_line_with_multiple_spans ( ) {
922
+ let line = Line :: default ( ) . spans ( vec ! [ "foo" , "bar" ] ) ;
923
+ assert_eq ! (
924
+ line. right_aligned( ) . truncated( 4 ) . to_string( ) ,
925
+ String :: from( "obar" )
926
+ ) ;
927
+ }
928
+
929
+ #[ test]
930
+ fn truncation_ignores_useless_spans ( ) {
931
+ let line = Line :: default ( ) . spans ( vec ! [ "foo" , "bar" ] ) ;
932
+ assert_eq ! (
933
+ line. right_aligned( ) . truncated( 3 ) ,
934
+ Line :: default ( ) . spans( vec![ "bar" ] )
935
+ ) ;
936
+ }
850
937
851
938
#[ test]
852
939
fn left_aligned ( ) {
0 commit comments