Beefy Boxes and Bandwidth Generously Provided by pair Networks
Your skill will accomplish
what the force of many cannot
 
PerlMonks  

Color diff for terminal

by polettix (Vicar)
on Aug 12, 2006 at 12:07 UTC ( [id://567025]=sourcecode: print w/replies, xml ) Need Help??
Category: Utility Scripts
Author/Contact Info "Flavio Poletti" <flavio at polettix.it>
Description: Update: there's a stripped down Perl 6 version, check it out!

This will help you browse diff-like outputs (either plain or unified) on the terminal, colorising differences. It will also be able to invoke other programs that produce diff-like output (like some commands for version control systems).

The approach is different from other colorising script-s:

  • I'm not using Algorithm::Diff, and
  • I'm using terminal colorising capabilities, not HTML
Regarding the first bullet, it's better than it may look like. To diff two files I'm either fork()-ing a diff process, or requesting you to do so, but this is intended because it allows to access (nearly) all options that diff has. Moreover, this script works with all diff-producing programs (if the format is compatible with diff, either in the "plain" style or in the "unified" one), while Algorithm::Diff would be restricted to the two-files-diffing world (more or less).

Regarding the second bullet, I needed something to quickly show me the differences on the terminal - just like diff (or cvs diff, or svk diff, or...) do, but with colors to make them outstand. The drawbacks are many, among which:

  • you have to use a terminal that works with Term::ANSIColor
  • it's mostly useless for very long diffs
Again, this was no problem for me because I have such a terminal and the diffs I check are usually less than a few (terminal) pages.

As a final note, if you have symbolic links you can get the most out of the script by:

  • installing it as colordiff somewhere inside $PATH
  • make a symbolic link to it named cdiff, again inside the $PATH
Invoking the script when it's called cdiff basically turns it into a drop-in replacement for diff(1), so that you can:
shell$ cdiff -u file1 file2 # with colors, instead of shell$ diff -u file1 file2 # without colors, or shell$ diff -u file1 file2 | colordiff # wow, way too long!
I know that this name-based behaviour change is generally frowned upon, but I think that in this case the advantage is self-evident.

Be sure to check the documentation for hints about using this with version control systems, like CVS or SVK. I hope you'll find it useful!

#!/usr/bin/perl
use strict;
use warnings;
use Carp;
use Pod::Usage qw( pod2usage );
use Getopt::Long qw( :config gnu_getopt require_order pass_through );
use Fatal qw( open );
use Term::ANSIColor qw( :constants );
use File::Basename qw( basename );

use version; my $VERSION = qv('0.0.1');

# Pre-mangling based on the name used to install the program
my %config;
if (basename($0) eq 'cdiff') {
   # Blindly re-route all options to diff. @ARGV shall be used to
   # build the external command that will output the text to be colori
+sed
   unshift @ARGV, 'diff';
}
else {
   GetOptions(\%config, 'usage', 'help', 'man', 'version');
   pod2usage("$0 v$VERSION") if $config{version};
   pod2usage(-verbose => 99, -sections => 'USAGE') if $config{usage};
   pod2usage(-verbose => 99, -sections => 'NAME|USAGE|OPTIONS|EXAMPLES
+')
     if $config{help};
   pod2usage(-verbose => 2) if $config{man};
}

# Other recommended modules (uncomment to use):
#  use IO::Prompt;
#  use Readonly;
#  use Data::Dumper;
#  use Log::Log4perl qw( :easy );

# Script implementation here
my %color_for = (
   '<' => RED,
   '-' => RED,
   '>' => GREEN,
   '+' => GREEN,
   '@' => BLUE,
);

# Establish input
my $fh;
if (scalar @ARGV) {
   my $command = join ' ', map { quotemeta } @ARGV;
   open $fh, '-|', $command;
}
else {
   $fh = \*STDIN;
}

# Iterate over input and color it
while (<$fh>) {
   my $first_char = substr $_, 0, 1;
   delete $color_for{'-'} if $first_char eq '<';
   print BOLD, $color_for{$first_char} if exists $color_for{$first_cha
+r};
   print;
   print RESET if exists $color_for{$first_char};
}
close $fh;

__END__

=head1 NAME

colordiff - colorise a C<diff> output, optionally invoking a command 
cdiff     - call C<diff(1)> and colorise its output


=head1 VERSION

Call with C<--version> (not available in C<cdiff>). It should be 0.0.1
+.


=head1 USAGE

   colordiff [--usage] [--help] [--man] [--version]

   [ some command producing diff output ] | colordiff
   colordiff < some-diff-file

   colordiff [ some command producing diff output ]

   cdiff [ diff(1) options and command line ]

=head1 OPTIONS

C<colordiff> has the same options of the subcommand it's required to
call, with the following exceptions:

=over

=item --help

print a somewhat more verbose help, showing usage, this description of
the options and some examples from the synopsis.

=item --man

print out the full documentation for the script.

=item --usage

print a concise usage line and exit.

=item --version

print the version of the script.

=back

C<cdiff> always I<forwards> the command line to C<diff(1)>, so see
the manpage to find the options. Note that not all options will be
meaningful to use with C<cdiff>; notably, if you want to produce a
compact style diff the colorisation will be mostly unuseful.



=head1 EXAMPLES

   # get full documentation
   shell$ colordiff --man

   # Use as a filter
   shell$ diff file1 file2 | colordiff

   # We can spare a few typing, simple invocation of diff
   shell$ cdiff file1 file2

   # Pass options to diff, e.g. get unified diff
   shell$ cdiff -u file1 file2

   # The filter incarnation is still useful, anyway - e.g.
   # with version control systems
   shell$ cvs diff -u -r REL_1_0 somefile | colordiff
   shell$ svk diff somefile | colordiff

   # Save a few types
   shell$ colordiff cvs diff -u -r REL_1_0 somefile
   shell$ colordiff svk diff somefile

   # These two are equivalent, choose the best for you
   shell$ colordiff diff -u file1 file2
   shell$ cdiff -u file1 file2

   # These aliases could turn useful, assumes sh or compatibles
   shell$ alias svkdiff='colordiff svk diff'
   shell$ svkdiff somefile
   shell$ svkdiff -r -1 somefile

   shell$ alias cvsdiff='colordiff cvs diff -u' # I like unified diff
   shell$ cvsdiff -r REL_1_0 somefile

  
=head1 DESCRIPTION

C<colordiff> colorises a C<diff(1)> text on the terminal, in order to 
+make
it visually clear where the changes are. It is best suited to situatio
+n where
the differences are small, i.e. they do not take pages and pages, beca
+use
all colorisation happens in the terminal.

When the command line of C<colordiff> is empty, the input text to colo
+rise
is assumed to be on standard input. Otherwise, the command line is
assumed to be a command which is invoked and whose output must be
colorised. So, the following are equivalent:

   shell$ command foo bar baz | colordiff
   shell$ colordiff command foo bar baz

but you can save a little typing with the latter.

When installed as C<cdiff>, it is assumed to be a blind wrapper around
C<diff(1)>. In this case, C<diff(1)> will be invoked with the remainin
+g
options, so the following are equivalent:

   shell$ cdiff foo bar baz
   shell$ colordiff diff foo bar baz

but the former is stunningly faster to type and better to remember.

Note that only "plain diff" and unified styles are supported for
colorisation.

=head1 DIAGNOSTICS

None particular. If for some reason the pipe from the diff command can
+not
be established the script will die with a hopefully meaningful message
+.


=head1 CONFIGURATION AND ENVIRONMENT

colordiff requires no configuration files or environment variables.


=head1 DEPENDENCIES

You won't get far without Term::ANSIColor.


=head1 BUGS AND LIMITATIONS

No bugs have been reported.

The error code from the diff command is not replicated as exit code of
C<colordiff>. This should not be a real limitation, because C<colordif
+f>
is intended for interactive usage more than batch.

Please report any bugs or feature requests through http://rt.cpan.org/


=head1 AUTHOR

Flavio Poletti C<flavio@polettix.it>


=head1 LICENCE AND COPYRIGHT

Copyright (c) 2006, Flavio Poletti C<flavio@polettix.it>. All rights r
+eserved.

This script is free software; you can redistribute it and/or
modify it under the same terms as Perl itself. See L<perlartistic>
and L<perlgpl>.

Questo script è software libero: potete ridistribuirlo e/o
modificarlo negli stessi termini di Perl stesso. Vedete anche
L<perlartistic> e L<perlgpl>.


=head1 DISCLAIMER OF WARRANTY

BECAUSE THIS SOFTWARE IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE SOFTWARE, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WH
+EN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE SOFTWARE "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER
EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. TH
+E
ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE SOFTWARE IS WITH
YOU. SHOULD THE SOFTWARE PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL
NECESSARY SERVICING, REPAIR, OR CORRECTION.

IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE SOFTWARE AS PERMITTED BY THE ABOVE LICENCE, BE
LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL,
OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE
THE SOFTWARE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
FAILURE OF THE SOFTWARE TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.

=head1 NEGAZIONE DELLA GARANZIA

Poiché questo software viene dato con una licenza gratuita, non
c'è alcuna garanzia associata ad esso, ai fini e per quanto permesso
dalle leggi applicabili. A meno di quanto possa essere specificato
altrove, il proprietario e detentore del copyright fornisce questo
software "così com'è" senza garanzia di alcun tipo, sia essa espressa
o implicita, includendo fra l'altro (senza però limitarsi a questo)
eventuali garanzie implicite di commerciabilità e adeguatezza per
uno scopo particolare. L'intero rischio riguardo alla qualità ed
alle prestazioni di questo software rimane a voi. Se il software
dovesse dimostrarsi difettoso, vi assumete tutte le responsabilità
ed i costi per tutti i necessari servizi, riparazioni o correzioni.

In nessun caso, a meno che ciò non sia richiesto dalle leggi vigenti
o sia regolato da un accordo scritto, alcuno dei detentori del diritto
di copyright, o qualunque altra parte che possa modificare, o redistri
+buire
questo software così come consentito dalla licenza di cui sopra, potrà
essere considerato responsabile nei vostri confronti per danni, ivi
inclusi danni generali, speciali, incidentali o conseguenziali, deriva
+nti
dall'utilizzo o dall'incapacità di utilizzo di questo software. Ciò
include, a puro titolo di esempio e senza limitarsi ad essi, la perdit
+a
di dati, l'alterazione involontaria o indesiderata di dati, le perdite
sostenute da voi o da terze parti o un fallimento del software ad
operare con un qualsivoglia altro software. Tale negazione di garanzia
rimane in essere anche se i dententori del copyright, o qualsiasi altr
+a
parte, è stata avvisata della possibilità di tali danneggiamenti.

Se decidete di utilizzare questo software, lo fate a vostro rischio
e pericolo. Se pensate che i termini di questa negazione di garanzia
non si confacciano alle vostre esigenze, o al vostro modo di
considerare un software, o ancora al modo in cui avete sempre trattato
software di terze parti, non usatelo. Se lo usate, accettate espressam
+ente
questa negazione di garanzia e la piena responsabilità per qualsiasi
tipo di danno, di qualsiasi natura, possa derivarne.

=cut

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: sourcecode [id://567025]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others sharing their wisdom with the Monastery: (5)
As of 2024-03-28 22:32 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found