colordiffの文字単位版ccdiffを作ったid:yappo++

diffに色付けしたかったけど、colordiffみたいな行単位じゃなくて、文字単位で色付けしたい。
id:yappoString::Diff - Simple diff to String - metacpan.org使ってccdiff(charactor color diff)というのをでっちあげた。


ってか後から単語単位の方がいいかなと思った。
でwdiffとcolordiffの組み合わせとか試してみたけど、

% cat foo.patch | wdiff -d | colordiff

だと、日本語の扱いもおかしくて何か出力が微妙で…。
Text::WordDiff - Track changes between documents - metacpan.orgも軽く試したけど「行単位で単語単位(説明難しい…)」ができないっぽくてやめた。
String::Diffより最適なモジュールがあるかもしれんけど探すのめんどいのでとりあえずこのままで。


使い方

以下のデータががあるとき。

% cat foo.old
abc
% cat foo.new
azc
% cat foo.patch
--- foo.old     2010-11-04 12:27:27.040992700 +0900
+++ foo.new     2010-11-04 12:27:33.149776700 +0900
@@ -1 +1 @@
-abc
+azc

1. unified形式のパッチを渡す

% diff -u foo.old foo.new | ccdiff

% cat foo.patch | ccdiff

% cat - | ccdiff
パッチ貼り付け
^D

svn diffでもいい。


2. またはdiffと同じようにファイル(およびdiffのオプションも可)を渡す(内部でdiffを呼んでる)

% ccdiff foo.old foo.new

出力はどれも同じで以下のようになる。

--- foo.old     2010-11-04 12:27:27.040992700 +0900
+++ foo.new     2010-11-04 12:27:33.149776700 +0900
@@ -1 +1 @@
-abc
+azc

現在のところunified形式しか受け付けません。

#! perl
#
# $Id: ccdiff 1008 2010-11-04 10:16:41Z hyoshida $
#
eval 'exec /usr/bin/perl -S $0 ${1+"$@"}'
  if 0;
use strict;
use warnings;
use version; our $VERSION = qv('0.0.1');

use autodie;
use IO::Pipe;
use String::Diff qw(diff);
use Term::ANSIColor;

%String::Diff::DEFAULT_MARKS = (
    remove_open  => ( color 'red' ),
    remove_close => ( color 'reset' ),
    append_open  => ( color 'green' ),
    append_close => ( color 'reset' ),
    separator    => q{},
);

if ( 2 <= @ARGV ) {

    # TODO: deal with existing STDIN
    open STDIN, q{<&=}, IO::Pipe->new->reader( 'diff', '-u', @ARGV );
    undef @ARGV;
}

my @s = (q{}) x 2;
foreach (<>) {
        /^[-]/msx ? ( $s[0] .= $_ )
      : /^[+]/msx ? ( $s[1] .= $_ )
      : do {
        print diff(@s), $_;
        @s = (q{}) x 2;
      };
}
print diff(@s);

__END__

=head1 NAME

ccdiff - a tool to colorize by the character diff output

=head1 USAGE

    $ ccdiff foo.old foo.new

    $ diff -u foo.old foo.new | ccdiff
    $ cat foo.patch | ccdiff

=head1 DESCRIPTION

a tool to colorize by the character diff output

=head1 REQUIRED ARGUMENTS

None.

=head1 OPTIONS

None.

=head1 DIAGNOSTICS

None.

=head1 EXIT STATUS

None.

=head1 CONFIGURATION

ccdiff requires no configuration files.

=head1 DEPENDENCIES

L<String::Diff|String::Diff>

=head1 INCOMPATIBILITIES

None reported.

=head1 BUGS AND LIMITATIONS

No bugs have been reported.

=over

=item TODO: add copied context support

=item TODO: add ~/.colordiffrc support

=item TODO: add multibyte support

=back

=head1 AUTHOR

Hironori Yoshida <yoshida@cpan.org>

=head1 LICENSE AND COPYRIGHT

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

=cut
  • STDINの処理の辺り自信が無い。closeしないといけないのかとか<&=とか。
  • 最初whileで逐次処理してたけど、これだとcat - | ccdiffの時に逐一出力されてしまって都合が悪いのでforeachに置き換えた。