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 perl pattern to select which files must be processed. Note that this
pattern is applied to the basename of each file, not the full path.

=item exclude

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

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} ) {
	$filter = $opts->{filter};
	$filter = qr/$filter/;
    }
    my $exclude;
    if ( defined $opts->{exclude} ) {
	$exclude = $opts->{exclude};
	$exclude = qr/$exclude/;
    }
    else {
	$exclude = qr{ (?: ^\# | ^\.\.?(?!/) | ~$ ) }x;
    }

    binmode( STDOUT, ":utf8" );

    my $grepper = sub {



( run in 0.520 second using v1.01-cache-2.11-cpan-df04353d9ac )