diff --git a/lib/Data/Printer.pm b/lib/Data/Printer.pm index cd263e4..6dbc18a 100644 --- a/lib/Data/Printer.pm +++ b/lib/Data/Printer.pm @@ -377,45 +377,39 @@ sub _escape_chars { $orig_color = color( $orig_color ); my $esc_color = color( $p->{color}{escaped} ); - # if we're escaping everything then we don't need to keep swapping - # colors in and out, and we need to return right away because - # we no longer need to print_escapes - if ($p->{escape_chars} eq 'all') { - return $esc_color - . join('', map { sprintf '\x{%02x}', ord $_ } split //, $str) - . $orig_color - } - - $str =~ s/\e/$esc_color\\e$orig_color/g if $p->{print_escapes}; + my %special_escapes = ( + "\n" => '\n', + "\r" => '\r', + "\t" => '\t', + "\f" => '\f', + "\b" => '\b', + "\a" => '\a', + "\0" => '\0', + "\e" => '\e', + ); + + my $blacklist; - if ($p->{escape_chars} eq 'nonascii') { - $str =~ s{([^\x{00}-\x{7f}]+)}{ - $esc_color - . (join '', map { sprintf '\x{%02x}', ord $_ } split //, $1) - . $orig_color - }ge; + if ($p->{escape_chars} eq 'all') { + # escape everything, and systematically + $blacklist = "(.+)"; + %special_escapes = (); + } elsif ($p->{escape_chars} eq 'nonascii') { + $blacklist = "([^\x{20}-\x{7e}]+)"; } elsif ($p->{escape_chars} eq 'nonlatin1') { - $str =~ s{([^\x{00}-\x{ff}]+)}{ - $esc_color - . (join '', map { sprintf '\x{%02x}', ord $_ } split //, $1) . $orig_color - }ge; + $blacklist = "([^\x{20}-\x{7e}\x{a0}-\x{ff}]+)"; + } elsif ($p->{print_escapes}) { + $blacklist = "([\0\e\n\r\t\f\b\a]+)"; + } else { + # always escape nulls and the escape character + $blacklist = "([\0\e]+)"; } - if ($p->{print_escapes}) { - my %escaped = ( - "\n" => '\n', - "\r" => '\r', - "\t" => '\t', - "\f" => '\f', - "\b" => '\b', - "\a" => '\a', - ); - foreach my $k ( keys %escaped ) { - $str =~ s/$k/$esc_color$escaped{$k}$orig_color/g; - } - } - # always escape the null character - $str =~ s/\0/$esc_color\\0$orig_color/g; + $str =~ s{$blacklist}{ + $esc_color + . (join '', map { $special_escapes{$_} || sprintf '\x{%02x}', ord $_ } split //, $1) + . $orig_color + }ge; return $str; } diff --git a/t/30-print_escapes.t b/t/30-print_escapes.t index 389d9d0..d451643 100644 --- a/t/30-print_escapes.t +++ b/t/30-print_escapes.t @@ -60,7 +60,6 @@ foreach my $item (@stuff) { $mixed->{original} .= $item->{original}; $mixed->{unescaped} .= $item->{unescaped}; - $mixed->{colored} .= $colored; is( p( $item->{original} ), @@ -74,6 +73,11 @@ foreach my $item (@stuff) { ); } +$mixed->{colored} = color('bright_red') + . $mixed->{unescaped} + . color('bright_yellow') + ; + is( p( $mixed->{original} ), color('reset') diff --git a/t/40-escape_chars.t b/t/40-escape_chars.t index a4869e8..3ba82bc 100644 --- a/t/40-escape_chars.t +++ b/t/40-escape_chars.t @@ -16,11 +16,19 @@ BEGIN { }; my $string = "L\x{e9}on likes to build a m\x{f8}\x{f8}se \x{2603} with \x{2744}\x{2746}"; +my $ctl_string = "\n\x{14}\x{7f}\x{9b}"; # "common" control character, C0, DEL, C1 my %hash = ( $string => $string ); sub col(@) { my $return = color('bright_red'); - $return .= '\\x{' . shift . '}' while @_; + $return .= '\\x{' . shift() . '}' while @_; + $return .= color('bright_yellow'); + return $return; +} + +sub col_sp(@) { + my $return = color('bright_red'); + $return .= '\\' . shift() while @_; $return .= color('bright_yellow'); return $return; } @@ -29,7 +37,7 @@ sub str($) { return color('reset') . '"' . color('bright_yellow') - . shift + . shift() . color('reset') . '"'; } @@ -58,6 +66,12 @@ is( "Testing 'nonascii'" ); +is( + p( $ctl_string ), + str( col_sp('n','x{14}','x{7f}','x{9b}') ), + "Testing 'nonascii' control characters" +); + ### nonlatin1 ### use_ok ( @@ -73,6 +87,12 @@ is( "Testing 'nonlatin1'" ); +is( + p( $ctl_string ), + str( col_sp('n','x{14}','x{7f}','x{9b}') ), + "Testing 'nonlatin1' control characters" +); + ### all ### use_ok (