@@ -814,6 +814,10 @@ pub(crate) fn char_width(_c: char) -> usize {
814
814
/// escapes code will still be honored. If truncation takes place
815
815
/// the tail string will be appended.
816
816
pub fn truncate_str < ' a > ( s : & ' a str , width : usize , tail : & str ) -> Cow < ' a , str > {
817
+ if measure_text_width ( s) <= width {
818
+ return Cow :: Borrowed ( s) ;
819
+ }
820
+
817
821
#[ cfg( feature = "ansi-parsing" ) ]
818
822
{
819
823
use std:: cmp:: Ordering ;
@@ -825,12 +829,12 @@ pub fn truncate_str<'a>(s: &'a str, width: usize, tail: &str) -> Cow<'a, str> {
825
829
match item {
826
830
( s, false ) => {
827
831
if rv. is_none ( ) {
828
- if str_width ( s) + length > width - str_width ( tail) {
832
+ if str_width ( s) + length > width. saturating_sub ( str_width ( tail) ) {
829
833
let ts = iter. current_slice ( ) ;
830
834
831
835
let mut s_byte = 0 ;
832
836
let mut s_width = 0 ;
833
- let rest_width = width - str_width ( tail) - length;
837
+ let rest_width = width. saturating_sub ( str_width ( tail) ) . saturating_sub ( length) ;
834
838
for c in s. chars ( ) {
835
839
s_byte += c. len_utf8 ( ) ;
836
840
s_width += char_width ( c) ;
@@ -869,15 +873,11 @@ pub fn truncate_str<'a>(s: &'a str, width: usize, tail: &str) -> Cow<'a, str> {
869
873
870
874
#[ cfg( not( feature = "ansi-parsing" ) ) ]
871
875
{
872
- if s. len ( ) <= width - tail. len ( ) {
873
- Cow :: Borrowed ( s)
874
- } else {
875
- Cow :: Owned ( format ! (
876
- "{}{}" ,
877
- s. get( ..width - tail. len( ) ) . unwrap_or_default( ) ,
878
- tail
879
- ) )
880
- }
876
+ Cow :: Owned ( format ! (
877
+ "{}{}" ,
878
+ & s[ ..width. saturating_sub( tail. len( ) ) ] ,
879
+ tail
880
+ ) )
881
881
}
882
882
}
883
883
@@ -998,13 +998,23 @@ fn test_truncate_str() {
998
998
& truncate_str( & s, 6 , "" ) ,
999
999
& format!( "foo {}" , style( "バ" ) . red( ) . force_styling( true ) )
1000
1000
) ;
1001
+ let s = format ! ( "foo {}" , style( "バー" ) . red( ) . force_styling( true ) ) ;
1002
+ assert_eq ! (
1003
+ & truncate_str( & s, 2 , "!!!" ) ,
1004
+ & format!( "!!!{}" , style( "" ) . red( ) . force_styling( true ) )
1005
+ ) ;
1001
1006
}
1002
1007
1003
1008
#[ test]
1004
1009
fn test_truncate_str_no_ansi ( ) {
1010
+ assert_eq ! ( & truncate_str( "foo bar" , 7 , "!" ) , "foo bar" ) ;
1005
1011
assert_eq ! ( & truncate_str( "foo bar" , 5 , "" ) , "foo b" ) ;
1006
1012
assert_eq ! ( & truncate_str( "foo bar" , 5 , "!" ) , "foo !" ) ;
1007
1013
assert_eq ! ( & truncate_str( "foo bar baz" , 10 , "..." ) , "foo bar..." ) ;
1014
+ assert_eq ! ( & truncate_str( "foo bar" , 0 , "" ) , "" ) ;
1015
+ assert_eq ! ( & truncate_str( "foo bar" , 0 , "!" ) , "!" ) ;
1016
+ assert_eq ! ( & truncate_str( "foo bar" , 2 , "!!!" ) , "!!!" ) ;
1017
+ assert_eq ! ( & truncate_str( "ab" , 2 , "!!!" ) , "ab" ) ;
1008
1018
}
1009
1019
1010
1020
#[ test]
0 commit comments