App-File-Grepper

 view release on metacpan or  search on metacpan

lib/App/File/Grepper.pm  view on Meta::CPAN

=head1 SYNOPSIS

Runs a File::Find on the specified directories, and greps all text
files for a pattern.

    use App::File::Grepper;
    App::File::Grepper->main( $options, @dirs );

=head1 RATIONALE

There are many tools that can do this, e.g. C<ack>. However none of
these can call an editor when a file matches the search argument and
that is something B<I> often need.

=head1 OPTIONS

The first argument to the main() method is a reference to a hash with
options.

=over 4

=item pattern

The pattern to grep. If it starts with a slash it is interpreted as a
perl pattern. Otherwise it is assumed to be a literal text to grep
for.

If the text does not contain any uppercase letters, matching will be
done case-insensitive unless overridden by option ignorecase.

=item ignorecase

If defined, matching will be case-insensitive according to the value
of ignorecase.

=item edit-with-emacs

Pass each file where the pattern is found to the emacs editor client.

=item edit-with-vi

Pass each file where the pattern is found to the vi editor.

=item view

Pass each file where the pattern is found to the less viewer.

=item filter

A list of perl patterns to select which files must be processed. Note
that these patterns are applied to the basename of each file, not the
full path.

=item exclude

A list of perl patterns to select which files must be rejected. Note
that these patterns are applied to the basename of each file, not the
full path. Also, these pattern are applied before the filter patterns.

Version control directories C<RCS>, C<CVS>, C<.svn>, C<.git> and
C<.hg> are always excluded, as are common editor backups.

=back

=cut

use File::Find;
use Term::ANSIColor;

sub main {

    my $self = shift;
    unshift(@_, $self) unless UNIVERSAL::isa( $self, __PACKAGE__ );
    my $opts = shift;
    my @dirs = @_;

    my $pat = $opts->{pattern};
    my $edit = "";
    if ( $opts->{'edit-with-emacs'} ) {
	$edit = 'emacs';
    }
    elsif ( $opts->{'edit-with-vi'} ) {
	$edit = 'vi';
    }
    elsif ( $opts->{'view'} ) {
	$edit = 'less';
    }

    my $ignorecase =
      defined($opts->{ignorecase})
      ? $opts->{ignorecase}
      : $pat !~ /[A-Z]/;

    my $opat = $pat;

    $pat = $pat =~ m;^/(.*);
      ? $ignorecase ? qr/$1/i : qr/$1/
      : $ignorecase ? qr/\Q$pat\E/i : qr/\Q$pat\E/;
    warn("PAT:  $pat\n") if $opts->{debug};

    *hilite = ( !$edit && -t STDOUT )
      ? sub { color('red bold').$_[0].color('reset') }
	: sub { $_[0] };

    my $filter;
    if ( defined $opts->{filter} && @{$opts->{filter}} ) {
	$filter = '(?:' . join('|', @{$opts->{filter}}) . ')';
	$filter = qr/$filter/;
    }
    my $exclude;
    if ( defined $opts->{exclude} && @{$opts->{exclude}} ) {
	$exclude = '(?:' . join('|', @{$opts->{exclude}}) . ')';
	$exclude = qr/$exclude/;
    }
    else {
	$exclude = qr{ (?: ^\# | ^\.(?>\.?)(?!/) | ~$ ) }x;
    }

    binmode( STDOUT, ":utf8" );

    my $grepper = sub {



( run in 1.294 second using v1.01-cache-2.11-cpan-ad19def0cd9 )