use super::{ Segment, parse_segments };
pub fn has_ansi( text : &str ) -> bool
{
if !text.contains( '\x1b' )
{
return false;
}
parse_segments( text )
.iter()
.any( | seg | matches!( seg, Segment::Ansi( _ ) ) )
}
pub fn has_unclosed_formatting( text : &str ) -> bool
{
let mut formatting_active = false;
for segment in parse_segments( text )
{
if let Segment::Ansi( code ) = segment
{
if is_reset_code( code )
{
formatting_active = false;
}
else if is_sgr_code( code )
{
formatting_active = true;
}
}
}
formatting_active
}
fn is_reset_code( code : &str ) -> bool
{
code == "\x1b[0m" || code == "\x1b[m"
}
fn is_sgr_code( code : &str ) -> bool
{
code.ends_with( 'm' ) && code.starts_with( "\x1b[" )
}
#[ cfg( test ) ]
mod tests
{
use super::*;
#[ test ]
fn has_ansi_empty()
{
assert!( !has_ansi( "" ) );
}
#[ test ]
fn has_ansi_plain_text()
{
assert!( !has_ansi( "hello world" ) );
assert!( !has_ansi( "no colors here" ) );
}
#[ test ]
fn has_ansi_with_ansi()
{
assert!( has_ansi( "\x1b[31mred\x1b[0m" ) );
assert!( has_ansi( "\x1b[0m" ) );
assert!( has_ansi( "prefix \x1b[32mgreen" ) );
}
#[ test ]
fn has_ansi_lone_escape()
{
assert!( !has_ansi( "before\x1bafter" ) );
}
#[ test ]
fn has_ansi_rgb_color()
{
assert!( has_ansi( "\x1b[38;2;255;128;0morange\x1b[0m" ) );
}
#[ test ]
fn unclosed_empty()
{
assert!( !has_unclosed_formatting( "" ) );
}
#[ test ]
fn unclosed_plain_text()
{
assert!( !has_unclosed_formatting( "hello world" ) );
}
#[ test ]
fn unclosed_properly_closed()
{
assert!( !has_unclosed_formatting( "\x1b[31mred\x1b[0m" ) );
assert!( !has_unclosed_formatting( "\x1b[1;31mbold\x1b[0m" ) );
}
#[ test ]
fn unclosed_not_closed()
{
assert!( has_unclosed_formatting( "\x1b[31mred" ) );
assert!( has_unclosed_formatting( "\x1b[1m" ) );
}
#[ test ]
fn unclosed_reset_only()
{
assert!( !has_unclosed_formatting( "\x1b[0m" ) );
assert!( !has_unclosed_formatting( "\x1b[m" ) );
}
#[ test ]
fn unclosed_multiple_sequences()
{
assert!( has_unclosed_formatting( "\x1b[31mred\x1b[0m\x1b[32mgreen" ) );
assert!( !has_unclosed_formatting( "\x1b[31mred\x1b[0m\x1b[32mgreen\x1b[0m" ) );
}
#[ test ]
fn unclosed_reset_abbreviation()
{
assert!( !has_unclosed_formatting( "\x1b[31mred\x1b[m" ) );
}
#[ test ]
fn is_reset_code_test()
{
assert!( is_reset_code( "\x1b[0m" ) );
assert!( is_reset_code( "\x1b[m" ) );
assert!( !is_reset_code( "\x1b[31m" ) );
assert!( !is_reset_code( "\x1b[1m" ) );
}
#[ test ]
fn is_sgr_code_test()
{
assert!( is_sgr_code( "\x1b[0m" ) );
assert!( is_sgr_code( "\x1b[31m" ) );
assert!( is_sgr_code( "\x1b[1;31;44m" ) );
assert!( is_sgr_code( "\x1b[38;2;255;128;0m" ) );
assert!( !is_sgr_code( "\x1b[2J" ) ); assert!( !is_sgr_code( "\x1b[H" ) ); }
}