App-Greple

 view release on metacpan or  search on metacpan

script/greple  view on Meta::CPAN

use App::Greple::Filter;

my $version = $App::Greple::VERSION;

=encoding utf8

=head1 NAME


greple - extensible grep with lexical expression and region control


=head1 VERSION


Version 10.04


=head1 SYNOPSIS


B<greple> [B<-M>I<module>] [ B<-options> ] pattern [ file... ]

  PATTERN
    pattern              'and +must -not ?optional &function'
    -x, --le   pattern   lexical expression (same as bare pattern)
    -e, --and  pattern   pattern match across line boundary
    -r, --must pattern   pattern cannot be compromised
    -t, --may  pattern   pattern may exist
    -v, --not  pattern   pattern not to be matched
    -E, --re   pattern   regular expression
        --fe   pattern   fixed expression
    -f, --file file      file contains search pattern
    --select index       select indexed pattern from -f file
  MATCH
    -i, --ignore-case    ignore case
    -G, --capture-group  match capture groups rather than the whole pattern
    -S, --stretch        stretch the matched area to the enclosing block
    --need=[+-]n         required positive match count
    --allow=[+-]n        acceptable negative match count
    --matchcount=n[,m]   required match count for each block
  STYLE
    -l                   list filename only
    -c                   print count of matched block only
    -n                   print line number
    -b                   print block number
    -H, -h               do or do not display filenames
    -o                   print only the matching part
    --all                print entire data
    -F, --filter         use as a filter (implies --all --need=0 --exit=0)
    -m, --max=n[,m]      max count of blocks to be shown
    -A,-B,-C [n]         after/before/both match context
    --join               remove newline in the matched part
    --joinby=string      replace newline in the matched text with a string
    --nonewline          do not add newline character at the end of block
    --filestyle=style    how filenames are printed (once, separate, line)
    --linestyle=style    how line numbers are printed (separate, line)
    --blockstyle=style   how block numbers are printed (separate, line)
    --separate           set filestyle, linestyle, blockstyle "separate"
    --format LABEL=...   define the format for line number and file name
    --frame-top          top frame line
    --frame-middle       middle frame line
    --frame-bottom       bottom frame line
  FILE
    --glob=glob          glob target files
    --chdir=dir          change directory before search
    --readlist           get filenames from stdin
  COLOR
    --color=when         use terminal colors (auto, always, never)
    --nocolor            same as --color=never
    --colormap=color     R, G, B, C, M, Y, etc.
    --colorsub=...       shortcut for --colormap="sub{...}"
    --colorful           use default multiple colors
    --colorindex=flags   color index method: Ascend/Descend/Block/Random/Unique/Group/GP
    --random             use a random color each time (--colorindex=R)
    --uniqcolor          use a different color for each unique string (--colorindex=U)
    --uniqsub=func       preprocess function to check uniqueness
    --ansicolor=s        ANSI color 16, 256 or 24bit
    --[no]256            same as --ansicolor 256 or 16
    --regioncolor        use different color for inside and outside regions
    --face               enable or disable visual effects
  BLOCK
    -p, --paragraph      enable paragraph mode
    --border=pattern     specify a border pattern
    --block=pattern      specify a block of records
    --blockend=s         block-end mark (Default: "--")
    --join-blocks        join consecutive blocks that are back-to-back
  REGION
    --inside=pattern     select matches inside of pattern
    --outside=pattern    select matches outside of pattern
    --include=pattern    limit matches to the area
    --exclude=pattern    limit matches to outside of the area
    --strict             enable strict mode for --inside/outside --block
  CHARACTER CODE
    --icode=name         input file encoding
    --ocode=name         output file encoding
  FILTER
    --if,--of=filter     input/output filter command
    --pf=filter          post-process filter command
    --noif               disable the default input filter
  RUNTIME FUNCTION
    --begin=func         call a function before starting the search
    --end=func           call a function after completing the search
    --prologue=func      call a function before executing the command
    --epilogue=func      call a function after executing the command
    --postgrep=func      call a function after each grep operation
    --callback=func      callback function for each matched string
  OTHER
    --usage[=expand]     show this help message
    --version            show version
    --exit=n             set the command exit status
    --norc               skip reading startup file
    --man                display the manual page for the command or module
    --show               display the module file contents
    --path               display the path to the  module file
    --error=action       action to take after a read error occurs
    --warn=type          runtime error handling type
    --alert [name=#]     set alert parameters (size/time)
    -d flags             display info (f:file d:dir c:color m:misc s:stat)

=cut

my @baseclass = qw( App::Greple Getopt::EX );

script/greple  view on Meta::CPAN


my @opt_colormap;
sub opt_colormap { push @opt_colormap, $_[1] }
sub opt_colorsub { push @opt_colormap, "sub{ $_[1] }" }

my %opt_format = (LINE => '%d:', FILE => '%s:', BLOCK => '%s:');
my %opt_alert  = (size => 512 * 1024, time => 2);
my %opt_warn   = (read => 0, skip => 1, retry => 0, begin => 0);

newopt

    ##
    ## PATTERN
    ##
    ' and    |e =s ' => \&opt_pattern ,
    ' must   |r =s ' => \&opt_pattern ,
    ' may    |t =s ' => \&opt_pattern ,
    ' not    |v =s ' => \&opt_pattern ,
    ' le     |x =s ' => \&opt_pattern ,
    ' re     |E =s ' => \&opt_pattern ,
    ' fe        =s ' => \&opt_pattern ,
    ' file   |f =s ' => \ my @opt_f ,
    ' select    =s ' => \ my $opt_select ,

    ##
    ## MATCH
    ##
    ' ignore-case        |i  !  ' => \ my $opt_i ,
    ' need                   =s ' => \ my @opt_need ,
    ' allow                  =s ' => \ my @opt_allow ,
    ' matchcount         |mc =s ' => \ my $opt_matchcount ,
    ' capture-group      |G  !  ' => \ my $opt_capture_group ,
    ' stretch            |S  !  ' => \ my $opt_stretch ,

    ##
    ## STYLE
    ##
    ' files-with-matches |l     ' => \ my $opt_l ,
    ' count              |c     ' => \ my $opt_c ,
    ' line-number        |n  !  ' => \ my $opt_n ,
    ' block-number       |b  !  ' => \ my $opt_b ,
    ' filename           |H     ' => \ my $opt_H ,
    ' no-filename        |h     ' => \ my $opt_h ,
    ' only-matching      |o  !  ' => \ my $opt_o ,
    ' all                    !  ' => \ my $opt_all ,
    ' filter             |F  !  ' => \ my $opt_filter ,
    ' max-count          |m  =s ' => \ my $opt_m ,
    ' after-context      |A  :2 ' => \(my $opt_A = 0) ,
    ' before-context     |B  :2 ' => \(my $opt_B = 0) ,
    ' context            |C  :2 ' => \(my $opt_C = 0) ,
    ' join                   !  ' => \ my $opt_join ,
    ' joinby                 =s ' => \(my $opt_joinby = "") ,
    ' newline                !  ' => \(my $opt_newline = 1) ,
    ' filestyle          |fs =s ' => \(my $opt_filestyle = 'line') ,
    ' linestyle          |ls =s ' => \(my $opt_linestyle = 'line') ,
    ' blockstyle         |bs =s ' => \(my $opt_blockstyle = 'line') ,
    ' separate ' => sub {
	opt('filestyle') = opt('linestyle') = opt('blockstyle') = $_[0];
    },
    ' format                 =s ' => \    %opt_format ,
    ' frame-top              :s ' => \(my $opt_frame_top    = '') ,
    ' frame-middle           :s ' => \(my $opt_frame_middle = '') ,
    ' frame-bottom           :s ' => \(my $opt_frame_bottom = '') ,

    ##
    ## FILE
    ##
    ' glob                   =s ' => \ my @opt_glob ,
    ' chdir                  =s ' => \ my @opt_chdir ,
    ' readlist               !  ' => \ my $opt_readlist ,

    ##
    ## COLOR
    ##
    ' color                  =s ' => \(my $opt_color = 'auto') ,
    ' colormap           |cm =s ' => \&opt_colormap ,
    ' colorsub           |cs =s ' => \&opt_colorsub ,
    ' colorful               !  ' => \(my $opt_colorful = 1) ,
    ' colorindex         |ci =s ' => \(my $opt_colorindex = '') ,
    ' ansicolor              =s ' => \(my $opt_ansicolor = '256') ,
    ' regioncolor        |rc !  ' => \ my $opt_regioncolor ,
    ' uniqsub            |us =s ' => \ my @opt_uniqsub ,
    ' face                   =s ' => \ my @opt_face ,
    ' nocolor | no-color ' => sub {
	opt('color') = 'never';
    },
    ' 256! ' => sub {
	opt('ansicolor') = $_[1] ? '256' : '16';
    },
    ' random! ' => sub {
	if ($_[1]) { opt('colorindex') .= 'R' }
	else       { opt('colorindex') =~ s/R//gi }
    },
    ' uniqcolor |uc ' => sub {
	opt('colorindex') = 'U';
    },

    ##
    ## BLOCK
    ##
    ' paragraph          |p  !  ' => \ my $opt_p ,
    ' border                 =s ' => \ my $opt_border ,
    ' block                  =s ' => \ my @opt_block ,
    ' blockend               :s ' => \(my $opt_blockend) ,
    ' join-blocks            !  ' => \(my $opt_join_blocks = 0) ,

    ##
    ## REGION
    ##
    ' inside                 =s ' => \ my @opt_inside ,
    ' outside                =s ' => \ my @opt_outside ,
    ' include                =s ' => \ my @opt_include ,
    ' exclude                =s ' => \ my @opt_exclude ,
    ' strict                 !  ' => \(my $opt_strict = 0) ,

    ##
    ## CHARACTER CODE
    ##
    ' icode                  =s ' => \ my @opt_icode ,
    ' ocode                  =s ' => \ my $opt_ocode ,

    ##
    ## FILTER

script/greple  view on Meta::CPAN

    : qw(000D/544 000D/454 000D/445
	 000D/455 000D/545 000D/554
	 000D/543 000D/453 000D/435
	 000D/534 000D/354 000D/345
	 000D/444
	 000D/433 000D/343 000D/334
	 000D/344 000D/434 000D/443
	 000D/333)
    ;

if ($color_handler->list == 0) {
    $color_handler->append
	($opt_colorful ? @default_color : $default_color[0]);
}

if ($opt_ansicolor eq '24bit') {
    no warnings 'once';
    $Getopt::EX::Colormap::RGB24 = 1;
}

for my $opt (@opt_face) {
    while ($opt =~ /(?<mk>[-+=]) (?<s>[^-+=]*) | (?<s>[^-+=]+) /xg) {
	my($mk, $s) = ($+{mk} // '', $+{s});
	for my $c (@colors) {
	    if ($mk eq '-') {
		$c =~ s/[\Q$s\E]//g if $s ne '';
	    } elsif ($mk eq '=') {
		$c = $s;
	    } elsif ($s ne '') {
		$c .= "^" if $c ne '';
		$c .= $s;
	    }
	}
    }
}

my $need_color = (($opt_color eq 'always')
		  or (($opt_color eq 'auto') and (!$opt_o and -t STDOUT)));

if (!$need_color) {
    $Getopt::EX::Colormap::NO_COLOR = 1;
}

my %_esc = ( t => "\t", n => "\n", r => "\r", f => "\f" );
sub expand_escape {
    $_[0] =~ s{\\(.)}{$_esc{$1} // $1}egr;
}

$_ = expand_escape($_) for values %opt_format;

my $blockend = "--";
if (defined $opt_blockend) {
    $blockend = expand_escape($opt_blockend);
}

my $_file     = sub { $color_handler->color('FILE' , sprintf($opt_format{FILE}, $_[0])) };
my $_line     = sub { $color_handler->color('LINE' , sprintf($opt_format{LINE}, $_[0])) };
my $_block    = sub { $color_handler->color('BLOCK', sprintf($opt_format{BLOCK}, $_[0])) };
my $_text     = sub { $color_handler->color('TEXT' , $_[0]) };
my $_blockend = $color_handler->color('BLOCKEND', $blockend);
my $_top      = $color_handler->color('TOP'     , $opt_frame_top);
my $_middle   = $color_handler->color('MIDDLE'  , $opt_frame_middle);
my $_bottom   = $color_handler->color('BOTTOM'  , $opt_frame_bottom);

sub index_color {
    $color_handler->index_color(@_);
}

sub color {
    $color_handler->color(@_);
}

my $uniq_color = UniqIndex->new(
    ignore_newline => 1,
    prepare => \@opt_uniqsub,
    );

sub dump_uniqcolor {
    my $list  = $uniq_color->list;
    my $count = $uniq_color->count;
    for my $i (keys @$list) {
	warn sprintf("%3d (%3d) %s\n",
		     $i, $count->[$i],
		     index_color($i, $list->[$i]));
    }
}

# --colorindex
my %color_index = map { uc $_ => 1 } $opt_colorindex =~ /\w/g;
my $indexer = do {
    if ($color_index{S}) {
	@colors = shuffle @colors;
    }
    if ($color_index{A} or $color_index{D}) {
	my $i = 0;
	Indexer->new(
	    index   => sub { $i++   },
	    reset   => sub { $i = 0 },
	    block   => $color_index{B},
	    reverse => $color_index{D},
	    );
    }
    elsif ($color_index{R}) {
	Indexer->new(index => sub { int rand @colors });
    }
    else { undef }
};
my $opt_uniqcolor = $color_index{U};

# -dc
if ($opt_d{c}) {
    my $dump = sub {
	local $_ = Dumper shift;
	s/^\s*'\K([^'\s]+)(?=')/color($1, $1)/mge;
	$_;
    };
    warn 'colormap = ', $dump->(\%colormap);
    warn 'colors = ', $dump->(\@colors);
}

##
## border regex
##

script/greple  view on Meta::CPAN


    greple -ho --join '\p{InKatakana}+(\n\p{InKatakana}+)*'

Space separated word sequence can be processed with C<--joinby>
option.  Next example prints all C<for *something*> pattern in pod
documents within Perl script.

    greple -Mperl --pod -ioe '\bfor \w+' --joinby ' '

=item B<--[no]newline>

Since B<greple> can handle arbitrary blocks other than normal text
lines, they sometimes do not end with newline character.  Option C<-o>
makes similar situation.  In that case, extra newline is appended at
the end of block to be shown.  Option C<--no-newline> disables this
behavior.

=item B<--filestyle>=[C<line>,C<once>,C<separate>], B<--fs>

Default style is I<line>, and B<greple> prints filename at the
beginning of each line.  Style I<once> prints the filename only once
at the first time.  Style I<separate> prints filename in the separate
line before each line or block.

=item B<--linestyle>=[C<line>,C<separate>], B<--ls>

Default style is I<line>, and B<greple> prints line numbers at the
beginning of each line.  Style I<separate> prints line number in the
separate line before each line or block.

=item B<--blockstyle>=[C<line>,C<separate>], B<--bs>

Default style is I<line>, and B<greple> prints block numbers at the
beginning of each line.  Style I<separate> prints block number in the
separate line before each line or block.

=item B<--separate>

Shortcut for C<--filestyle=separate> C<--linestyle=separate>
C<--blockstyle=separate>.  This is convenient to use block mode search
and visiting each location from supporting tool, such as Emacs.

=item B<--format> B<LABEL>=I<format>

Define the format string of line number (LINE), file name (FILE) and
block number (BLOCK) to be displayed.  Default is:

    --format LINE='%d:'

    --format FILE='%s:'

    --format BLOCK='%s:'

Format string is passed to C<sprintf> function.  Escape sequences
C<\t>, C<\n>, C<\r>, and C<\f> are recognized.

Next example will show line numbers in five digits with tab space:

    --format LINE='%05d\t'

=item B<--frame-top>=I<string>

=item B<--frame-middle>=I<string>

=item B<--frame-bottom>=I<string>

Print surrounding frames before and after each block.  C<top> frame is
printed at the beginning, C<bottom> frame at the end, C<middle> frame
between blocks.

=back

B<Related options:>
B<--block>/B<-p> (L</BLOCKS>),
B<--color>/B<--colormap> (L</COLORS>)


=head2 FILES


=over 7

=item B<--glob>=I<pattern>

Get files matches to specified pattern and use them as a target files.
Using C<--chdir> and C<--glob> makes easy to use B<greple> for fixed
common job.

=item B<--chdir>=I<directory>

Change directory before processing files.  When multiple directories
are specified in C<--chdir> option, by using wildcard form or
repeating option, C<--glob> file expansion will be done for every
directories.

    greple --chdir '/usr/share/man/man?' --glob '*.[0-9]' ...

=item B<--readlist>

Get filenames from standard input.  Read standard input and use each
line as a filename for searching.  You can feed the output from other
command like L<find(1)> for B<greple> with this option.  Next example
searches string from files modified within 7 days:

    find . -mtime -7 -print | greple --readlist pattern

Using B<find> module, this can be done like:

    greple -Mfind . -mtime -7 -- pattern

=back


=head2 COLORS


=over 7

=item B<--color>=[C<auto>,C<always>,C<never>], B<--nocolor>

Use terminal color capability to emphasize the matched text.  Default
is C<auto>: effective when STDOUT is a terminal and option C<-o> is
not given, not otherwise.  Option value C<always> and C<never> will
work as expected.

Option B<--nocolor> is alias for B<--color>=I<never>.

When color output is disabled, ANSI terminal sequence is not produced,



( run in 0.677 second using v1.01-cache-2.11-cpan-e1769b4cff6 )