Skip to content
Browse files

Merge branch 'master' of https://github.com/petdance/ack2

  • Loading branch information...
2 parents d60ad61 + 9ac5a07 commit e9310262f1ab525bab8bee3f27bb74eae1650668 @shlomif committed Mar 24, 2012
Showing with 339 additions and 25 deletions.
  1. +62 −7 Ack.pm
  2. +12 −2 ack-base
  3. +1 −0 ackrc
  4. +10 −10 t/Util.pm
  5. +119 −0 t/ack-group.t
  6. +50 −0 t/ack-match.t
  7. +84 −0 t/ack-o.t
  8. +0 −6 t/context.t
  9. +1 −0 t/etc/shebang.py.xxx
View
69 Ack.pm
@@ -603,16 +603,34 @@ sub print_matches_in_resource {
my $max_count = $opt->{m} || -1;
my $nmatches = 0;
my $filename = $resource->name;
+ my $break = $opt->{break};
+ my $heading = $opt->{heading};
+ my $ors = $opt->{print0} ? "\0" : "\n";
+
+ my $has_printed_for_this_resource = 0;
App::Ack::iterate($resource, $opt, sub {
if ( App::Ack::does_match($opt, $_) ) {
+ if( !$has_printed_for_this_resource ) {
+ if( $break && has_printed_something() ) {
+ App::Ack::print_blank_line();
+ }
+ if( $heading ) {
+ App::Ack::print_filename( $resource->name, $ors );
+ }
+ }
App::Ack::print_line_with_context($opt, $filename, $_, $.);
+ $has_printed_for_this_resource = 1;
$nmatches++;
$max_count--;
}
elsif ( $passthru ) {
chomp;
+ if( $break && !$has_printed_for_this_resource && has_printed_something() ) {
+ App::Ack::print_blank_line();
+ }
App::Ack::print_line_with_options($opt, $filename, $_, $., ':');
+ $has_printed_for_this_resource = 1;
}
return $max_count != 0;
});
@@ -668,6 +686,9 @@ sub iterate {
$is_iterating = 1;
+ local $opt->{before_context} = $opt->{output} ? 0 : $opt->{before_context};
+ local $opt->{after_context} = $opt->{output} ? 0 : $opt->{after_context};
+
my $n_before_ctx_lines = $opt->{before_context} || 0;
my $n_after_ctx_lines = $opt->{after_context} || 0;
my $current_line;
@@ -709,23 +730,53 @@ sub iterate {
}
+my $has_printed_something;
+
+BEGIN {
+ $has_printed_something = 0;
+}
+
+sub has_printed_something {
+ return $has_printed_something;
+}
+
sub print_line_with_options {
my ( $opt, $filename, $line, $line_no, $separator ) = @_;
+ $has_printed_something = 1;
+
my $print_filename = $opt->{H} && !$opt->{h};
my $print_column = $opt->{column};
my $ors = $opt->{print0} ? "\0" : "\n";
+ my $heading = $opt->{heading};
+ my $output_expr = $opt->{output};
+ my $re = $opt->{regex};
my @line_parts;
if($print_filename) {
- push @line_parts, $filename, $line_no;
+ if( $heading ) {
+ push @line_parts, $line_no;
+ }
+ else {
+ push @line_parts, $filename, $line_no;
+ }
+
if( $print_column ) {
push @line_parts, get_match_column();
}
}
- push @line_parts, $line;
- App::Ack::print( join( $separator, @line_parts ), $ors );
+ if( $output_expr ) {
+ # XXX avoid re-evaluation if we can
+ while( $line =~ /$re/g ) {
+ my $output = eval qq{"$output_expr"};
+ App::Ack::print( join( $separator, @line_parts, $output ), $ors );
+ }
+ }
+ else {
+ push @line_parts, $line;
+ App::Ack::print( join( $separator, @line_parts ), $ors );
+ }
return;
}
@@ -744,17 +795,24 @@ BEGIN {
sub print_line_with_context {
my ( $opt, $filename, $matching_line, $line_no ) = @_;
+ my $heading = $opt->{heading};
+
if( !defined($previous_file_processed) ||
$previous_file_processed ne $filename ) {
$previous_file_processed = $filename;
$previous_line_printed = -1;
+
+ if( $heading ) {
+ $is_first_match = 1;
+ }
}
my $ors = $opt->{print0} ? "\0" : "\n";
my $color = $opt->{color};
my $match_word = $opt->{w};
my $re = $opt->{regex};
my $is_tracking_context = $opt->{after_context} || $opt->{before_context};
+ my $output_expr = $opt->{output};
chomp $matching_line;
@@ -763,9 +821,6 @@ sub print_line_with_context {
if($before_context) {
my $first_line = $. - @{$before_context};
if( !$is_first_match && $previous_line_printed != $first_line - 1 ) {
- if( $first_line == 10 ) {
- print $is_first_match ? 'yes' : 'no', ' ', $previous_line_printed, ' ', $first_line, "\n";
- }
App::Ack::print('--', $ors);
}
$previous_line_printed = $.; # XXX unless --after-context
@@ -790,7 +845,7 @@ sub print_line_with_context {
}
my @capture_indices = get_capture_indices();
- if(@capture_indices) {
+ if( @capture_indices && !$output_expr ) {
my $offset = 0; # additional offset for when we add stuff
foreach my $index_pair ( @capture_indices ) {
View
14 ack-base
@@ -152,7 +152,12 @@ sub main {
my $resources;
if ( $App::Ack::is_filter_mode ) {
$resources = App::Ack::Resources->from_stdin( $opt );
- $opt->{regex} = App::Ack::build_regex(shift @ARGV, $opt);
+ if( my $regex = $opt->{regex} ) {
+ $opt->{regex} = App::Ack::build_regex( $regex, $opt );
+ }
+ else {
+ $opt->{regex} = App::Ack::build_regex( shift @ARGV, $opt );
+ }
}
else {
if ( $opt->{f} || $opt->{lines} ) {
@@ -162,7 +167,12 @@ sub main {
}
}
else {
- $opt->{regex} = App::Ack::build_regex(shift @ARGV, $opt);
+ if( my $regex = $opt->{regex} ) {
+ $opt->{regex} = App::Ack::build_regex( $regex, $opt );
+ }
+ else {
+ $opt->{regex} = App::Ack::build_regex( shift @ARGV, $opt );
+ }
}
my @start = @ARGV;
unless(@start == 1 && -f $start[0]) {
View
1 ackrc
@@ -193,6 +193,7 @@
# Python http://www.python.org/
--type-add=python,ext,py
+--type-add=python,firstlinematch,/python($|\s)/
# Ruby http://www.ruby-lang.org/
--type-add=ruby,ext,rb,rhtml,rjs,rxml,erb,rake,spec
View
20 t/Util.pm
@@ -37,6 +37,16 @@ sub build_command_line {
sub build_ack_command_line {
my @args = @_;
+ # The --noenv makes sure we don't pull in anything from the user
+ # unless explicitly specified in the test
+ if ( !grep { /^--(no)?env$/ } @args ) {
+ unshift( @args, '--noenv' );
+ }
+ # --ackrc makes sure we pull in "default" definitions
+ if( !grep { /^--ackrc=/ } @args) {
+ unshift( @args, '--ackrc=./ackrc' );
+ }
+
return build_command_line( './ack', @args );
}
@@ -114,16 +124,6 @@ sub run_ack_with_stderr {
my @stdout;
my @stderr;
- # The --noenv makes sure we don't pull in anything from the user
- # unless explicitly specified in the test
- if ( !grep { /^--(no)?env$/ } @args ) {
- unshift( @args, '--noenv' );
- }
- # --ackrc makes sure we pull in "default" definitions
- if( !grep { /^--ackrc=/ } @args) {
- unshift( @args, '--ackrc=./ackrc' );
- }
-
my $cmd = build_ack_command_line( @args );
return run_cmd($cmd);
View
119 t/ack-group.t
@@ -0,0 +1,119 @@
+#!/usr/bin/perl
+
+use strict;
+use warnings;
+
+use Test::More tests => 12;
+use File::Next ();
+
+use lib 't';
+use Util;
+
+prep_environment();
+
+my $freedom = File::Next::reslash( 't/text/freedom-of-choice.txt' );
+my $bobbie = File::Next::reslash( 't/text/me-and-bobbie-mcgee.txt' );
+
+NO_GROUPING: {
+ my @expected = split( /\n/, <<"EOF" );
+$freedom:2:Nobody ever said life was free
+$freedom:4:But use your freedom of choice
+$freedom:6:I'll say it again in the land of the free
+$freedom:7:Use your freedom of choice
+$freedom:8:Your freedom of choice
+$freedom:28:I'll say it again in the land of the free
+$freedom:29:Use your freedom of choice
+$bobbie:12: Nothin' don't mean nothin' if it ain't free
+$bobbie:27: Nothin' don't mean nothin' if it ain't free
+EOF
+
+ my @files = sort glob( 't/text/*.txt' );
+
+ my @arg_sets = (
+ [qw( --nogroup --nocolor free )],
+ [qw( --nobreak --noheading --nocolor free )],
+ );
+ for my $set ( @arg_sets ) {
+ my @results = run_ack( @{$set}, @files );
+ lists_match( \@results, \@expected, 'No grouping' );
+ }
+}
+
+
+STANDARD_GROUPING: {
+ my @expected = split( /\n/, <<"EOF" );
+$freedom
+2:Nobody ever said life was free
+4:But use your freedom of choice
+6:I'll say it again in the land of the free
+7:Use your freedom of choice
+8:Your freedom of choice
+28:I'll say it again in the land of the free
+29:Use your freedom of choice
+
+$bobbie
+12: Nothin' don't mean nothin' if it ain't free
+27: Nothin' don't mean nothin' if it ain't free
+EOF
+
+ my @files = sort glob( 't/text/*.txt' );
+ my @arg_sets = (
+ [qw( --group --nocolor free )],
+ [qw( --heading --break --nocolor free )],
+ );
+ for my $set ( @arg_sets ) {
+ my @results = run_ack( @{$set}, @files );
+ lists_match( \@results, \@expected, 'Standard grouping' );
+ }
+}
+
+HEADING_NO_BREAK: {
+ my @expected = split( /\n/, <<"EOF" );
+$freedom
+2:Nobody ever said life was free
+4:But use your freedom of choice
+6:I'll say it again in the land of the free
+7:Use your freedom of choice
+8:Your freedom of choice
+28:I'll say it again in the land of the free
+29:Use your freedom of choice
+$bobbie
+12: Nothin' don't mean nothin' if it ain't free
+27: Nothin' don't mean nothin' if it ain't free
+EOF
+
+ my @files = sort glob( 't/text/*.txt' );
+ my @arg_sets = (
+ [qw( --heading --nobreak --nocolor free )],
+ );
+ for my $set ( @arg_sets ) {
+ my @results = run_ack( @{$set}, @files );
+ lists_match( \@results, \@expected, 'Standard grouping' );
+ }
+}
+
+BREAK_NO_HEADING: {
+ my @expected = split( /\n/, <<"EOF" );
+$freedom:2:Nobody ever said life was free
+$freedom:4:But use your freedom of choice
+$freedom:6:I'll say it again in the land of the free
+$freedom:7:Use your freedom of choice
+$freedom:8:Your freedom of choice
+$freedom:28:I'll say it again in the land of the free
+$freedom:29:Use your freedom of choice
+
+$bobbie:12: Nothin' don't mean nothin' if it ain't free
+$bobbie:27: Nothin' don't mean nothin' if it ain't free
+EOF
+
+ my @files = sort glob( 't/text/*.txt' );
+
+ my @arg_sets = (
+ [qw( --break --noheading --nocolor free )],
+ );
+ for my $set ( @arg_sets ) {
+ my @results = run_ack( @{$set}, @files );
+ lists_match( \@results, \@expected, 'No grouping' );
+ }
+}
+
View
50 t/ack-match.t
@@ -0,0 +1,50 @@
+#!/usr/bin/perl
+
+use strict;
+use warnings;
+
+use Test::More;
+use lib 't';
+use Util;
+
+prep_environment();
+
+my @files = qw( t/text );
+
+my @tests = (
+ [ qw/Sue -a/ ],
+ [ qw/boy -a -i/ ], # case-insensitive is handled correctly with --match
+ [ qw/ll+ -a -Q/ ], # quotemeta is handled correctly with --match
+ [ qw/gon -a -w/ ], # words is handled correctly with --match
+);
+
+# 3 tests for each call to test_match()
+# and 4 other test
+#plan tests => @tests * 3 + 4;
+
+test_match( @{$_} ) for @tests;
+
+# giving only the --match argument (and no other args) should not
+# result in an error
+run_ack( '--match', 'Sue' );
+
+# not giving a regex when piping into ack should result in an error
+my ($stdout, $stderr) = pipe_into_ack_with_stderr( 't/text/4th-of-july.txt', '--perl' );
+ok( get_rc() != 0, 'ack should return an error when piped into without a regex' );
+is( scalar @{$stdout}, 0, 'ack should return no STDOUT when piped into without a regex' );
+is( scalar @{$stderr}, 1, 'ack should return one line of error message when piped into without a regex' ) or diag(explain($stderr));
+
+done_testing;
+
+# call ack normally and compare output to calling with --match regex
+#
+# due to 2 calls to run_ack, this sub runs altogether 3 tests
+sub test_match {
+ my $regex = shift;
+ my @args = @_;
+
+ my @results_normal = run_ack( @args, $regex, @files );
+ my @results_match = run_ack( @args, @files, '--match', $regex );
+
+ return sets_match( \@results_normal, \@results_match, "Same output for regex '$regex'." );
+}
View
84 t/ack-o.t
@@ -0,0 +1,84 @@
+#!perl
+
+use warnings;
+use strict;
+
+use Test::More tests => 6;
+use File::Next ();
+
+use lib 't';
+use Util;
+
+prep_environment();
+
+NO_O: {
+ my @files = qw( t/text/boy-named-sue.txt );
+ my @args = qw( the\\s+\\S+ );
+ my @expected = split( /\n/, <<'EOF' );
+ But the meanest thing that he ever did
+ But I made me a vow to the moon and stars
+ That I'd search the honky-tonks and bars
+ Sat the dirty, mangy dog that named me Sue.
+ Well, I hit him hard right between the eyes
+ And we crashed through the wall and into the street
+ Kicking and a-gouging in the mud and the blood and the beer.
+ And it's the name that helped to make you strong."
+ And I know you hate me, and you got the right
+ For the gravel in ya gut and the spit in ya eye
+ Cause I'm the son-of-a-bitch that named you Sue."
+EOF
+ s/^\s+// for @expected;
+
+ my @results = run_ack( @args, @files );
+
+ lists_match( \@results, \@expected, 'Find all the things without -o' );
+}
+
+
+WITH_O: {
+ my @files = qw( t/text/boy-named-sue.txt );
+ my @args = qw( the\\s+\\S+ -o );
+ my @expected = split( /\n/, <<'EOF' );
+ the meanest
+ the moon
+ the honky-tonks
+ the dirty,
+ the eyes
+ the wall
+ the street
+ the mud
+ the blood
+ the beer.
+ the name
+ the right
+ the gravel
+ the spit
+ the son-of-a-bitch
+EOF
+ s/^\s+// for @expected;
+
+ my @results = run_ack( @args, @files );
+
+ lists_match( \@results, \@expected, 'Find all the things with -o' );
+}
+
+
+# give a output function and find match in multiple files (so print filenames, just like grep -o)
+WITH_OUTPUT: {
+ my @files = qw( t/text/ );
+ my @args = qw/ --output=x$1x question(\\S+) /;
+
+ my @target_file = (
+ File::Next::reslash( 't/text/science-of-myth.txt' ),
+ File::Next::reslash( 't/text/shut-up-be-happy.txt' ),
+ );
+ my @expected = (
+ "$target_file[0]:1:xedx",
+ "$target_file[1]:15:xs.x",
+ "$target_file[1]:21:x.x",
+ );
+
+ my @results = run_ack( @args, @files );
+
+ sets_match( \@results, \@expected, 'Find all the things with --output function' );
+}
View
6 t/context.t
@@ -137,8 +137,6 @@ HIGHLIGHTING: {
# grouping works with context (single file)
GROUPING_SINGLE_FILE: {
- local $TODO = 'grouping not yet implemented';
-
my $target_file = File::Next::reslash( 't/etc/shebang.py.xxx' );
my @expected = split( /\n/, <<"EOF" );
$target_file
@@ -155,8 +153,6 @@ EOF
# grouping works with context and multiple files
# i.e. a separator line between different matches in the same file and no separator between files
GROUPING_MULTIPLE_FILES: {
- local $TODO = 'grouping not yet implemented';
-
my @target_file = (
File::Next::reslash( 't/text/boy-named-sue.txt' ),
File::Next::reslash( 't/text/me-and-bobbie-mcgee.txt' ),
@@ -206,8 +202,6 @@ ACK_G: {
# ack -o disables context
WITH_O: {
- local $TODO = '--output not yet implemented';
-
my @files = qw( t/text/boy-named-sue.txt );
my @args = qw( the\\s+\\S+ -o -C2 );
my @expected = split( /\n/, <<'EOF' );
View
1 t/etc/shebang.py.xxx
@@ -0,0 +1 @@
+#!/usr/bin/python

0 comments on commit e931026

Please sign in to comment.
Something went wrong with that request. Please try again.