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 )