App-ccdiff
view release on metacpan or search on metacpan
}
next;
}
$d1 .= $c;
$d2 .= $c;
$c =~ s/\S/$chr_eql/g;
$x1 .= $c;
$x2 .= $c;
next;
}
if (@co) {
$heu->{old} += scalar @co;
$d1 .= $cml.$clr_old;
$d1 .= s/\n/$reset\n$clr_old/gr for @co;
$d1 .= $reset.$cmr;
$x1 .= $_ for map { s/[^\t\r\n]/$cmd/gr } @co;
$opt_v and push @h1, map { $opt_U ? charnames::viacode (ord) : unpack "H*"; } @co;
}
if (@cn) {
$heu->{new} += scalar @cn;
$d2 .= $cml.$clr_new;
$d2 .= s/\n/$reset\n$clr_new/gr for @cn;
$d2 .= $reset.$cmr;
$x2 .= $_ for map { s/[^\t\r\n]/$cma/gr } @cn;
$opt_v and push @h2, map { $opt_U ? charnames::viacode (ord) : unpack "H*"; } @cn;
}
}
$heu->{pct} = ($heu->{old} + $heu->{new}) / (2 * $heu->{same});
my @d = map { [ split m/(?<=\n)/ => s/\n*\z/\n/r ] } $d1, $d2;
if ($opt_m) {
$opt_v > 1 and s/(\S+)/ $1 /g for $x1, $x2;
s/[ \t]*\n*\z/\n/ for $x1, $x2;
my @x = map { /\S/ ? [ split m/(?<=\n)/ ] : [] } $x1, $x2;
foreach my $n (0, 1) {
@{$x[$n]} and $d[$n] = [ map {( $d[$n][$_], $x[$n][$_] // "" )} 0 .. (scalar @{$d[$n]} - 1) ];
}
}
if ($opt_v) {
$opt_U && $opt_v > 2 and $_ .= sprintf " (U+%06X)", charnames::vianame ($_) for @h1, @h2;
@h1 and push @{$d[0]}, sprintf " -- ${clr_dbg}verbose$reset : %s\n", join ", " => map { $clr_old.$_.$reset } @h1;
@h2 and push @{$d[1]}, sprintf " -- ${clr_dbg}verbose$reset : %s\n", join ", " => map { $clr_new.$_.$reset } @h2;
}
@d;
} # subdiff
sub read_rc {
my $home = $ENV{HOME} || $ENV{USERPROFILE} || $ENV{HOMEPATH};
foreach my $rcf (
"$home/ccdiff.rc",
"$home/.ccdiffrc",
"$home/.config/ccdiff",
) {
-s $rcf or next;
(stat $rcf)[2] & 022 and next;
open my $fh, "<", $rcf or next;
while (<$fh>) {
my ($k, $v) = (m/^\s*([-\w]+)\s*[:=]\s*(.*\S)/) or next;
$rc{ lc $k
=~ s{[-_]colou?r$}{}ir
=~ s{background}{bg}ir
=~ s{^(?:unicode|utf-?8?)$}{utf8}ir
} = $v
=~ s{U\+?([0-9A-Fa-f]{2,7})}{chr hex $1}ger
=~ s{^(?:no|false)$}{0}ir
=~ s{^(?:yes|true)$}{-1}ir; # -1 is still true
}
}
} # read_rc
# Return the known colors from Term::ANSIColor
# Stolen straight from the pm
sub tac_colors {
my %c256;
foreach my $r (0 .. 5) {
foreach my $g (0 .. 5) {
$c256{lc $_}++ for map {("RGB$r$g$_", "ON_RGB$r$g$_")} 0 .. 5;
}
}
$c256{lc $_}++ for
# Basic colors
qw(
CLEAR RESET BOLD DARK
FAINT ITALIC UNDERLINE UNDERSCORE
BLINK REVERSE CONCEALED
BLACK RED GREEN YELLOW
BLUE MAGENTA CYAN WHITE
ON_BLACK ON_RED ON_GREEN ON_YELLOW
ON_BLUE ON_MAGENTA ON_CYAN ON_WHITE
BRIGHT_BLACK BRIGHT_RED BRIGHT_GREEN BRIGHT_YELLOW
BRIGHT_BLUE BRIGHT_MAGENTA BRIGHT_CYAN BRIGHT_WHITE
ON_BRIGHT_BLACK ON_BRIGHT_RED ON_BRIGHT_GREEN ON_BRIGHT_YELLOW
ON_BRIGHT_BLUE ON_BRIGHT_MAGENTA ON_BRIGHT_CYAN ON_BRIGHT_WHITE
),
# 256 colors
(map { ("ANSI$_", "ON_ANSI$_") } 0 .. 255),
(map { ("GREY$_", "ON_GREY$_") } 0 .. 23);
my $ACV = $Term::ANSIColor::VERSION;
$ACV < 3.02 and delete @c256{grep m/italic/ => keys %c256};
$ACV < 4.00 and delete @c256{grep m/rgb|grey/ => keys %c256};
$ACV < 4.06 and delete @c256{grep m/ansi/ => keys %c256};
sort keys %c256;
} # tac_colors
1;
__END__
=encoding utf-8
=head1 NAME
ccdiff - Colored Character diff
=head1 SYNOPSIS
ccdiff [options] file1|- file2|-
ccdiff [options] dir1 dir2
=item header (-H --header --HC=color --header-color=color)
header : 1
header : blue_on_white
Defines if a header is displayed above the diff (default is 1), supported
colors are allowed.
If the value is a valid supported color, it will show the header in that
color scheme. To disable the header set it to C<0> in the RC file or use
C<--no-header> as a command line argument.
=item old-label
=item new-label
Defines the tag(s) in the header for the source file(s)/stream(s).
App::ccdiff::ccdiff ($left, $right);
=>
< *STDIN Fri Nov 7 10:14:51 2025
> *STDIN Fri Nov 7 10:14:51 2025
App::ccdiff::ccdiff ($left, $right,
{ "old-label" => "OLD", "new-label" => "NEW" });
=>
< OLD Fri Nov 7 10:14:51 2025
> NEW Fri Nov 7 10:14:51 2025
=item verbose
verbose : cyan
Defines the color to be used as color for the verbose tag. The default is
C<cyan>. This color will only be used under C<--verbose>.
The color C<none> is also accepted and disables this color.
Any color accepted by L<Term::ANSIColor> is allowed. Any other color will
result in a warning.
This option may also be specified as
verbose-color
verbose_color
verbose-colour
verbose_colour
=item utf8 (-U)
utf8 : yes
Defines whether all I/O is to be interpreted as UTF-8. The default is C<no>.
This option may also be specified as
unicode
utf
utf-8
=item index (-I)
index : no
Defines if the position indication for a change chunk is prefixed with an
index number. The default is C<no>. The index is 1-based.
Without this option, the position indication would be like
5,5c5,5
19,19d18
42a42,42
with this option, it would be
[001] 5,5c5,5
[002] 19,19d18
[005] 42a42,42
When this option contains a positive integer, C<ccdiff> will only show the
diff chunk with that index.
=item emacs
emacs : no
If this option is yes/true, calling C<ccdiff> with just one single argument,
and that argument being an existing file, the arguments will act as
$ ccdiff file~ file
if file~ exists.
=item threshold (-t)
threshold : 2
Defines the number of lines a change block may differ before the fall-back of
horizontal diff to vertical diff.
=item heuristics (-h)
heuristics : 40
Defines the percentage of character-changes a change block may differ before
the fall-back of horizontal diff to vertical diff. The default is undefined,
meaning no fallback based on heuristics.
=item ellipsis (-e)
ellipsis : 0
Defines the number of characters to keep on each side of a horizontal-equal
segment. The default is C<0>, meaning to not compress. See also C<chr_eli>.
=item chr_old
( run in 0.527 second using v1.01-cache-2.11-cpan-d7f47b0818f )