| Term-HiliteDiff documentation | Contained in the Term-HiliteDiff distribution. |
Term::HiliteDiff::_impl - Highlights differences in text with ANSI escape codes
version 0.10
Josh Jore <jjore@cpan.org>
This software is copyright (c) 2011 by Josh Jore.
This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.
| Term-HiliteDiff documentation | Contained in the Term-HiliteDiff distribution. |
package Term::HiliteDiff::_impl; BEGIN { $Term::HiliteDiff::_impl::VERSION = '0.10'; } ## no critic (NamingConventions::Capitalization) # ABSTRACT: Highlights differences in text with ANSI escape codes use strict; ## no critic (RequireUseWarnings) ## no critic (ProhibitCascadingIfElse) ## no critic (ProhibitMagicNumbers) ## no critic (RequireDotMatchAnything) use constant _PREVIOUS_INPUT => 0; sub new { my @self; $self[_PREVIOUS_INPUT] = undef; return bless \ @self, $_[0]; } sub hilite_diff { # Arguments: # 0: self # 1: input string or arrayref return $_[0]->_do_diff( $_[1], 0 ); } sub watch { # Arguments: # 0: self # 1: input string or arrayref return $_[0]->_do_diff( $_[1], 1 ); } # This library uses the following ANSI escape codes # \e[s Save a cursor position # \e[u Go back to the saved cursor position # \e[K Erase everything from the cursor to the end of the line # \e[31m Red # \e[32m Green # \e[33m Yellow # \e[0m Turns off all formatting sub _parse_input { # Arguments: # 0: self # 1: array mode # 2: input string # # Returns: # input arrayref, separator if ( $_[1] ) { return $_[2], "\t"; } elsif ( -1 != index( $_[2], "\t" ) ) { return [ split /\t/, $_[2], -1 ], "\t"; } elsif ( -1 != index( $_[2], '|' ) ) { return [ split /\|/, $_[2], -1 ], '|'; } elsif ( $_[2] =~ /\n(?!\z)/ ) { return [ split /\n/, $_[2], -1 ], "\n"; } else { return [ split ' ', $_[2], -1 ], ' '; } } sub _color { # Arguments: # 0: input hunk # Color the region local $^W = 0; my $val = "\e[7m$_[0]\e[0m"; # Turn off coloring over newlines $val =~ s/\n/\e[0m\n\e[7m/g; # Remove empty colored regions $val =~ s/\e\[7m\e\[0m//g; return $val; } # sdiff does the primary markup work for this module. Everything else # just riffs on this. sub _sdiff { local $^W = 0; # Arguments: # 0: previous input arrayref # 1: input arrayref # 2: redraw?: my $prev_max_index = $#{$_[0]}; my $new_max_index = $#{$_[1]}; my $max_index = $prev_max_index >= $new_max_index ? $prev_max_index : $new_max_index; my @sdiff = (undef) x (1 + $max_index); for my $idx ( 0 .. $max_index ) { if ( $_[0][$idx] eq $_[1][$idx] ) { $sdiff[$idx] = defined $_[1][$idx] ? $_[1][$idx] : ''; } elsif ( length $_[1][$idx] ) { $sdiff[$idx] = _color( $_[1][$idx] ); } else { # This was changed but it's empty so there's nothing to color. $sdiff[$idx] = ''; } } return \ @sdiff; } sub _do_diff { # Arguments: # 0: self # 1: input string or arrayref # 2: redraw mode? # We accept either an array and then we don't parse it or we # accept a string and we try to parse it. my $array_mode = 'ARRAY' eq ref $_[1]; # Interpret input my ( $input, $separator ) = $_[0]->_parse_input( $array_mode, $_[1] ); # Fetch previous input my $prev_input = $_[0][_PREVIOUS_INPUT]; $prev_input ||= $input; # Diff it my $sdiff = _sdiff( $prev_input, $input, $_[2], ); # Manage redrawing over the same place on the screen if ( $_[2] ) { if ( ! $_[0][_PREVIOUS_INPUT] ) { # Save the cursor position $sdiff->[0] = "\e[s$sdiff->[0]"; } else { # Restore the cursor position $sdiff->[0] = "\e[u$sdiff->[0]"; } } # Save our "previous" state into the object $_[0][_PREVIOUS_INPUT] = $input; if ( $array_mode ) { if ( $_[2] ) { for ( @$sdiff ) { s/(?<!\e\[K)(?=\n)/\e[K/g; s/(?<=\e\[K)(?:\e\[K)+//g; s/(?<!\e\[K)\z/\e[K/; } } return $sdiff; } else { my $output = join $separator, @$sdiff; if ( $_[2] ) { for ( $output ) { s/(?<!\e\[K)(?=\n)/\e[K/g; s/(?<=\e\[K)(?:\e\[K)+//g; s/(?<!\e\[K)\z/\e[K/; } } return $output; } } # Blatantly copied this from errantstory.com q[Wow, you're pretty uptight for a guy who worships a multi-armed, hermaphrodite embodiment of destruction who has a fetish for vaguely phallic shaped headgear.];
__END__