3 # This file, ack, is generated code.
4 # Please DO NOT EDIT or send patches for it.
6 # Please take a look at the source from
7 # https://github.com/beyondgrep/ack3
8 # and submit patches against the individual files
12 $App::Ack
::STANDALONE
= 1;
19 our $VERSION = 'v3.8.1'; # Check https://beyondgrep.com/ for updates
28 # Global command-line options
49 our $opt_show_filename;
54 # Flag if we need any context tracking.
55 our $is_tracking_context;
57 # The regex that we use to match each line in the file.
60 # Regex for matching for highlighting in matched lines.
63 # The regex that matches for things we want to exclude via the --not option.
66 # Version of the match regex for checking to see if the file should be scanned line-by-line.
69 our @special_vars_used_by_opt_output;
73 # Internal stats for debugging.
77 $App::Ack
::ORIGINAL_PROGRAM_NAME
= $0;
78 $0 = join(' ', 'ack', $0);
79 $App::Ack
::ors
= "\n";
80 if ( $App::Ack
::VERSION
ne $main::VERSION
) {
81 App
::Ack
::die( "Program/library version mismatch\n\t$0 is $main::VERSION\n\t$INC{'App/Ack.pm'} is $App::Ack::VERSION" );
84 # Do preliminary arg checking;
85 my $env_is_usable = 1;
86 for my $arg ( @ARGV ) {
87 last if ( $arg eq '--' );
89 # Get the --thpppt, --bar, --cathy and --man checking out of the way.
90 $arg =~ /^--th[pt]+t+$/ and App
::Ack
::thpppt
($arg);
91 $arg eq '--bar' and App
::Ack
::ackbar
();
92 $arg eq '--cathy' and App
::Ack
::cathy
();
94 # See if we want to ignore the environment. (Don't tell Al Gore.)
95 $arg eq '--env' and $env_is_usable = 1;
96 $arg eq '--noenv' and $env_is_usable = 0;
99 if ( $env_is_usable ) {
100 if ( $ENV{ACK_OPTIONS
} ) {
101 App
::Ack
::warn( 'WARNING: ack no longer uses the ACK_OPTIONS environment variable. Use an ackrc file instead.' );
105 my @keys = ( 'ACKRC', grep { /^ACK_/ } keys %ENV );
110 my $modules_loaded_ok = eval 'use Term::ANSIColor 1.10 (); 1;';
111 if ( $modules_loaded_ok && $App::Ack
::is_windows
) {
112 $modules_loaded_ok = eval 'use Win32::Console::ANSI; 1;';
114 if ( $modules_loaded_ok ) {
115 $ENV{ACK_COLOR_MATCH
} ||= 'black on_yellow';
116 $ENV{ACK_COLOR_FILENAME
} ||= 'bold green';
117 $ENV{ACK_COLOR_LINENO
} ||= 'bold yellow';
118 $ENV{ACK_COLOR_COLNO
} ||= 'bold yellow';
121 App
::Ack
::ConfigLoader
::configure_parser
( 'no_auto_abbrev', 'pass_through' );
122 Getopt
::Long
::GetOptions
(
123 help
=> sub { App
::Ack
::show_help
(); exit; },
124 version
=> sub { App
::Ack
::print( App
::Ack
::get_version_statement
() ); exit; },
125 man
=> sub { App
::Ack
::show_man
(); },
129 App
::Ack
::show_help
();
133 my @arg_sources = App
::Ack
::ConfigLoader
::retrieve_arg_sources
();
135 my $opt = App
::Ack
::ConfigLoader
::process_args
( @arg_sources );
140 $opt_break = $opt->{break};
142 $opt_color = $opt->{color
};
143 $opt_column = $opt->{column
};
144 $opt_debug = $opt->{debug
};
147 $opt_heading = $opt->{heading
};
151 $opt_output = $opt->{output
};
153 $opt_passthru = $opt->{passthru
};
154 $opt_range_start = $opt->{range_start
};
155 $opt_range_end = $opt->{range_end
};
156 $opt_regex = $opt->{regex
};
157 $opt_show_filename = $opt->{show_filename
};
158 $opt_show_types = $opt->{show_types
};
159 $opt_underline = $opt->{underline
};
162 if ( $opt_show_types && not( $opt_f || $opt_g ) ) {
163 App
::Ack
::die( '--show-types can only be used with -f or -g.' );
166 if ( $opt_range_start ) {
167 ($opt_range_start, undef) = App
::Ack
::build_regex
( $opt_range_start, {} );
169 if ( $opt_range_end ) {
170 ($opt_range_end, undef) = App
::Ack
::build_regex
( $opt_range_end, {} );
172 $using_ranges = $opt_range_start || $opt_range_end;
174 $App::Ack
::report_bad_filenames
= !$opt->{s
};
175 $App::Ack
::ors
= $opt->{print0
} ? "\0" : "\n";
177 if ( !defined($opt_color) && !$opt_g ) {
178 my $windows_color = 1;
179 if ( $App::Ack
::is_windows
) {
180 $windows_color = eval { require Win32
::Console
::ANSI
; };
182 $opt_color = !App
::Ack
::output_to_pipe
() && $windows_color;
184 $opt_heading //= !App
::Ack
::output_to_pipe
();
185 $opt_break //= !App
::Ack
::output_to_pipe
();
187 if ( defined($opt->{H
}) || defined($opt->{h
}) ) {
188 $opt_show_filename = $opt->{show_filename
} = $opt->{H
} && !$opt->{h
};
191 if ( defined $opt_output ) {
192 # Expand out \t, \n and \r.
193 $opt_output =~ s/\\n/\n/g;
194 $opt_output =~ s/\\r/\r/g;
195 $opt_output =~ s/\\t/\t/g;
197 my @supported_special_variables = ( 1..9, qw( _ . ` & ' + f ) );
198 @special_vars_used_by_opt_output = grep { $opt_output =~ /\$$_/ } @supported_special_variables;
200 # If the $opt_output contains $&, $` or $', those vars won't be
201 # captured until they're used at least once in the program.
202 # Do the eval to make this happen.
203 for my $i ( @special_vars_used_by_opt_output ) {
204 if ( $i eq q{&} || $i eq q{'} || $i eq q{`} ) {
205 no warnings
; # They will be undef, so don't warn.
212 # Set up file filters.
214 if ( $App::Ack
::is_filter_mode
&& !$opt->{files_from
} ) { # probably -x
215 $files = App
::Ack
::Files-
>from_stdin();
216 $opt_regex //= shift @ARGV;
217 defined $opt_regex or App
::Ack
::die( 'No regular expression found.' );
218 ($re_match, $re_not, $re_hilite, $re_scan) = App
::Ack
::build_all_regexes
( $opt_regex, $opt );
219 $stats{re_match
} = $re_match;
220 $stats{re_not
} = $re_not;
221 $stats{re_hilite
} = $re_hilite;
222 $stats{re_scan
} = $re_scan;
226 # No need to check for regex, since mutex options are handled elsewhere.
229 $opt_regex //= shift @ARGV;
230 defined $opt_regex or App
::Ack
::die( 'No regular expression found.' );
231 ($re_match, $re_not, $re_hilite, $re_scan) = App
::Ack
::build_all_regexes
( $opt_regex, $opt );
232 $stats{re_match
} = $re_match;
233 $stats{re_not
} = $re_not;
234 $stats{re_hilite
} = $re_hilite;
235 $stats{re_scan
} = $re_scan;
238 if ( not defined $opt->{files_from
} ) {
241 if ( !exists($opt->{show_filename
}) ) {
242 unless(@start == 1 && !(-d
$start[0])) {
243 $opt_show_filename = $opt->{show_filename
} = 1;
247 if ( defined $opt->{files_from
} ) {
248 $files = App
::Ack
::Files-
>from_file( $opt, $opt->{files_from
} );
249 exit 1 unless $files;
252 @start = ('.') unless @start;
253 foreach my $target (@start) {
254 if ( !-e
$target && $App::Ack
::report_bad_filenames
) {
255 App
::Ack
::warn( "$target: No such file or directory" );
259 $opt->{file_filter
} = _compile_file_filter
($opt, \
@start);
260 $opt->{descend_filter
} = _compile_descend_filter
($opt);
262 $files = App
::Ack
::Files-
>from_argv( $opt, \
@start );
265 App
::Ack
::set_up_pager
( $opt->{pager
} ) if defined $opt->{pager
};
268 if ( $opt_f || $opt_g ) {
269 $nmatches = file_loop_fg
( $files );
272 $nmatches = file_loop_c
( $files );
274 elsif ( $opt_l || $opt_L ) {
275 $nmatches = file_loop_lL
( $files );
278 $nmatches = file_loop_normal
( $files );
283 my @stats = qw( re_match re_scan re_not prescans linescans filematches linematches );
284 my $width = List
::Util
::max
( map { length } @stats );
286 for my $stat ( @stats ) {
287 App
::Ack
::warn( sprintf( '%-*.*s = %s', $width, $width, $stat, $stats{$stat} // 'undef' ) );
293 App
::Ack
::exit_from_ack
( $nmatches );
304 while ( defined( my $file = $files->next ) ) {
305 if ( $opt_show_types ) {
306 App
::Ack
::show_types
( $file );
309 print_line_with_options
( undef, $file->name, 0, $App::Ack
::ors
);
312 App
::Ack
::say( $file->name );
315 last if defined($opt_m) && ($nmatches >= $opt_m);
326 while ( defined( my $file = $files->next ) ) {
327 my $matches_for_this_file = count_matches_in_file
( $file );
329 if ( not $opt_show_filename ) {
330 $total_count += $matches_for_this_file;
334 if ( !$opt_l || $matches_for_this_file > 0 ) {
335 if ( $opt_show_filename ) {
336 my $display_filename = $file->name;
338 $display_filename = Term
::ANSIColor
::colored
($display_filename, $ENV{ACK_COLOR_FILENAME
});
340 App
::Ack
::say( $display_filename, ':', $matches_for_this_file );
343 App
::Ack
::say( $matches_for_this_file );
348 if ( !$opt_show_filename ) {
349 App
::Ack
::say( $total_count );
360 while ( defined( my $file = $files->next ) ) {
361 my $is_match = count_matches_in_file
( $file, 1 );
363 if ( $opt_L ? !$is_match : $is_match ) {
364 App
::Ack
::say( $file->name );
368 last if defined($opt_m) && ($nmatches >= $opt_m);
376 sub _compile_descend_filter
{
380 my $dont_ignore_dirs = 0;
382 for my $filter (@{$opt->{idirs
} || []}) {
383 if ($filter->is_inverted()) {
391 # If we have one or more --noignore-dir directives, we can't ignore
392 # entire subdirectory hierarchies, so we return an "accept all"
393 # filter and scrutinize the files more in _compile_file_filter.
394 return if $dont_ignore_dirs;
395 return unless $idirs;
397 $idirs = $opt->{idirs
};
400 my $file = App
::Ack
::File-
>new($File::Next
::dir
);
401 return !grep { $_->filter($file) } @{$idirs};
406 sub _compile_file_filter
{
407 my ( $opt, $start ) = @_;
409 my $ifiles_filters = $opt->{ifiles
};
411 my $filters = $opt->{'filters'} || [];
412 my $direct_filters = App
::Ack
::Filter
::Collection-
>new();
413 my $inverse_filters = App
::Ack
::Filter
::Collection-
>new();
415 foreach my $filter (@{$filters}) {
416 if ($filter->is_inverted()) {
417 # We want to check if files match the uninverted filters
418 $inverse_filters->add($filter->invert());
421 $direct_filters->add($filter);
425 my %is_member_of_starting_set = map { (get_file_id
($_) => 1) } @{$start};
427 my @ignore_dir_filter = @{$opt->{idirs
} || []};
428 my @is_inverted = map { $_->is_inverted() } @ignore_dir_filter;
429 # This depends on InverseFilter->invert returning the original filter (for optimization).
430 @ignore_dir_filter = map { $_->is_inverted() ? $_->invert() : $_ } @ignore_dir_filter;
431 my $dont_ignore_dir_filter = grep { $_ } @is_inverted;
432 my $previous_dir = '';
433 my $previous_dir_ignore_result;
437 if ( $File::Next
::name
=~ /$re_match/o ) {
444 # ack always selects files that are specified on the command
445 # line, regardless of filetype. If you want to ack a JPEG,
446 # and say "ack foo whatever.jpg" it will do it for you.
447 return 1 if $is_member_of_starting_set{ get_file_id
($File::Next
::name
) };
449 if ( $dont_ignore_dir_filter ) {
450 if ( $previous_dir eq $File::Next
::dir
) {
451 if ( $previous_dir_ignore_result ) {
456 my @dirs = File
::Spec-
>splitdir($File::Next
::dir
);
460 for ( my $i = 0; $i < @dirs; $i++) {
461 my $dir_rsrc = App
::Ack
::File-
>new(File
::Spec-
>catfile(@dirs[0 .. $i]));
464 for my $filter (@ignore_dir_filter) {
465 if ( $filter->filter($dir_rsrc) ) {
466 $is_ignoring = !$is_inverted[$j];
472 $previous_dir = $File::Next
::dir
;
473 $previous_dir_ignore_result = $is_ignoring;
475 if ( $is_ignoring ) {
481 # Ignore named pipes found in directory searching. Named
482 # pipes created by subprocesses get specified on the command
483 # line, so the rule of "always select whatever is on the
484 # command line" wins.
485 return 0 if -p
$File::Next
::name
;
487 # We can't handle unreadable filenames; report them.
489 use filetest
'access';
491 if ( not -R
$File::Next
::name
) {
492 if ( $App::Ack
::report_bad_filenames
) {
493 App
::Ack
::warn( "${File::Next::name}: cannot open file for reading" );
499 my $file = App
::Ack
::File-
>new($File::Next
::name
);
501 if ( $ifiles_filters && $ifiles_filters->filter($file) ) {
505 my $match_found = $direct_filters->filter($file);
507 # Don't bother invoking inverse filters unless we consider the current file a match.
508 if ( $match_found && $inverse_filters->filter( $file ) ) {
512 }; # End of compiled sub
516 # Returns a (fairly) unique identifier for a file.
517 # Use this function to compare two files to see if they're
518 # equal (ie. the same file, but with a different path/links/etc).
520 my ( $filename ) = @_;
522 if ( $App::Ack
::is_windows
) {
523 return File
::Next
::reslash
( $filename );
526 # XXX Is this the best method? It always hits the FS.
527 if ( my ( $dev, $inode ) = (stat($filename))[0, 1] ) {
528 return join(':', $dev, $inode);
531 # XXX This could be better.
542 # Number of context lines
543 my $n_before_ctx_lines;
544 my $n_after_ctx_lines;
546 # Array to keep track of lines that might be required for a "before" context
547 my @before_context_buf;
548 # Position to insert next line in @before_context_buf
549 my $before_context_pos;
551 # Number of "after" context lines still pending
552 my $after_context_pending;
554 # Number of latest line that got printed
558 state $has_printed_from_any_file;
561 sub file_loop_normal
{
564 $n_before_ctx_lines = $opt_output ? 0 : ($opt_B || 0);
565 $n_after_ctx_lines = $opt_output ? 0 : ($opt_A || 0);
567 @before_context_buf = (undef) x
$n_before_ctx_lines;
568 $before_context_pos = 0;
570 $is_tracking_context = $n_before_ctx_lines || $n_after_ctx_lines;
575 while ( defined( my $file = $files->next ) ) {
576 if ($is_tracking_context) {
578 $after_context_pending = 0;
579 if ( $opt_heading ) {
583 my $needs_line_scan = 1;
584 if ( !$opt_passthru && !$opt_v ) {
586 if ( $file->may_be_present( $re_scan ) ) {
590 $needs_line_scan = 0;
593 if ( $needs_line_scan ) {
595 $nmatches += print_matches_in_file
( $file );
597 last if $opt_1 && $nmatches;
604 sub print_matches_in_file
{
607 my $filename = $file->name;
609 my $fh = $file->open;
611 if ( $App::Ack
::report_bad_filenames
) {
612 App
::Ack
::warn( "$filename: $!" );
617 my $display_filename = $filename;
618 if ( $opt_show_filename && $opt_heading && $opt_color ) {
619 $display_filename = Term
::ANSIColor
::colored
($display_filename, $ENV{ACK_COLOR_FILENAME
});
622 # Check for context before the main loop, so we don't pay for it if we don't need it.
624 my $max_count = $opt_m || -1; # Go negative for no limit so it can never reduce to 0.
625 if ( $is_tracking_context ) {
626 $nmatches = pmif_context
( $fh, $filename, $display_filename, $max_count );
628 elsif ( $opt_passthru ) {
629 $nmatches = pmif_passthru
( $fh, $filename, $display_filename, $max_count );
632 $nmatches = pmif_opt_v
( $fh, $filename, $display_filename, $max_count );
635 $nmatches = pmif_normal
( $fh, $filename, $display_filename, $max_count );
644 my $filename = shift;
645 my $display_filename = shift;
646 my $max_count = shift;
648 my $in_range = range_setup
();
649 my $has_printed_from_this_file;
652 $after_context_pending = 0;
657 $match_colno = undef;
659 $in_range = 1 if ( $using_ranges && !$in_range && defined($opt_range_start) && /$opt_range_start/o );
663 $does_match = /$re_match/o;
664 if ( $does_match && defined($re_not) ) {
666 $does_match = !/$re_not/o;
669 $does_match = !$does_match;
673 # @- = @LAST_MATCH_START
674 $match_colno = $-[0] + 1;
679 if ( $does_match && $max_count ) {
680 if ( !$has_printed_from_this_file ) {
681 $stats{filematches
}++;
682 if ( $opt_break && $has_printed_from_any_file ) {
683 App
::Ack
::print_blank_line
();
685 if ( $opt_show_filename && $opt_heading ) {
686 App
::Ack
::say( $display_filename );
689 print_line_with_context
( $filename, $_, $. );
690 $has_printed_from_this_file = 1;
691 $stats{linematches
}++;
696 if ( $after_context_pending ) {
697 # Disable $opt_column since there are no matches in the context lines.
698 local $opt_column = 0;
699 print_line_with_options
( $filename, $_, $., '-' );
700 --$after_context_pending;
702 elsif ( $n_before_ctx_lines ) {
703 # Save line for "before" context.
704 $before_context_buf[$before_context_pos] = $_;
705 $before_context_pos = ($before_context_pos+1) % $n_before_ctx_lines;
709 $in_range = 0 if ( $using_ranges && $in_range && defined($opt_range_end) && /$opt_range_end/o );
711 last if ($max_count == 0) && ($after_context_pending == 0);
720 my $filename = shift;
721 my $display_filename = shift;
722 my $max_count = shift;
724 my $in_range = range_setup
();
725 my $has_printed_from_this_file;
733 $in_range = 1 if ( $using_ranges && !$in_range && defined($opt_range_start) && /$opt_range_start/o );
735 $match_colno = undef;
736 my $does_match = /$re_match/o;
737 if ( $does_match && defined($re_not) ) {
739 $does_match = !/$re_not/o;
741 if ( $in_range && $does_match ) {
742 $match_colno = $-[0] + 1;
743 if ( !$has_printed_from_this_file ) {
744 if ( $opt_break && $has_printed_from_any_file ) {
745 App
::Ack
::print_blank_line
();
747 if ( $opt_show_filename && $opt_heading ) {
748 App
::Ack
::say( $display_filename );
751 print_line_with_options
( $filename, $_, $., ':' );
752 $has_printed_from_this_file = 1;
757 if ( $opt_break && !$has_printed_from_this_file && $has_printed_from_any_file ) {
758 App
::Ack
::print_blank_line
();
760 print_line_with_options
( $filename, $_, $., '-', 1 );
761 $has_printed_from_this_file = 1;
764 $in_range = 0 if ( $using_ranges && $in_range && defined($opt_range_end) && /$opt_range_end/o );
766 last if $max_count == 0;
775 my $filename = shift;
776 my $display_filename = shift;
777 my $max_count = shift;
779 my $in_range = range_setup
();
780 my $has_printed_from_this_file;
783 $match_colno = undef;
789 $in_range = 1 if ( $using_ranges && !$in_range && defined($opt_range_start) && /$opt_range_start/o );
792 my $does_match = /$re_match/o;
793 if ( $does_match && defined($re_not) ) {
794 # local @-; No need to localize this because we don't use @-.
795 $does_match = !/$re_not/o;
797 if ( !$does_match ) {
798 if ( !$has_printed_from_this_file ) {
799 if ( $opt_break && $has_printed_from_any_file ) {
800 App
::Ack
::print_blank_line
();
802 if ( $opt_show_filename && $opt_heading ) {
803 App
::Ack
::say( $display_filename );
806 print_line_with_context
( $filename, $_, $. );
807 $has_printed_from_this_file = 1;
813 $in_range = 0 if ( $using_ranges && $in_range && defined($opt_range_end) && /$opt_range_end/o );
815 last if $max_count == 0;
824 my $filename = shift;
825 my $display_filename = shift;
826 my $max_count = shift;
828 my $in_range = range_setup
();
829 my $has_printed_from_this_file;
832 my $last_match_lineno;
838 $in_range = 1 if ( $using_ranges && !$in_range && defined($opt_range_start) && /$opt_range_start/o );
841 $match_colno = undef;
842 my $is_match = /$re_match/o;
843 if ( $is_match && defined($re_not) ) {
845 $is_match = !/$re_not/o;
848 $match_colno = $-[0] + 1;
849 if ( !$has_printed_from_this_file ) {
850 $stats{filematches
}++;
851 if ( $opt_break && $has_printed_from_any_file ) {
852 App
::Ack
::print_blank_line
();
854 if ( $opt_show_filename && $opt_heading ) {
855 App
::Ack
::say( $display_filename );
859 if ( $last_match_lineno ) {
860 if ( $. > $last_match_lineno + $opt_p ) {
861 App
::Ack
::print_blank_line
();
864 elsif ( !$opt_break && $has_printed_from_any_file ) {
865 App
::Ack
::print_blank_line
();
869 print_line_with_options
( $filename, $_, $., ':' );
870 $has_printed_from_this_file = 1;
872 $stats{linematches
}++;
874 $last_match_lineno = $.;
878 $in_range = 0 if ( $using_ranges && $in_range && defined($opt_range_end) && /$opt_range_end/o );
880 last if $max_count == 0;
887 sub print_line_with_options
{
888 my ( $filename, $line, $lineno, $separator, $skip_coloring ) = @_;
890 $has_printed_from_any_file = 1;
891 $printed_lineno = $lineno;
895 if ( $opt_show_filename && defined($filename) ) {
897 $colno = get_match_colno
() if $opt_column;
899 $filename = Term
::ANSIColor
::colored
( $filename, $ENV{ACK_COLOR_FILENAME
} );
900 $lineno = Term
::ANSIColor
::colored
( $lineno, $ENV{ACK_COLOR_LINENO
} );
901 $colno = Term
::ANSIColor
::colored
( $colno, $ENV{ACK_COLOR_COLNO
} ) if $opt_column;
903 if ( $opt_heading ) {
904 push @line_parts, $lineno;
907 push @line_parts, $filename, $lineno;
909 push @line_parts, $colno if $opt_column;
913 while ( $line =~ /$re_match/og ) {
914 my $output = $opt_output;
915 if ( @special_vars_used_by_opt_output ) {
918 # Stash copies of the special variables because we can't rely
919 # on them not changing in the process of doing the s///.
921 my %keep = map { ($_ => ${$_} // '') } @special_vars_used_by_opt_output;
922 $keep{_
} = $line if exists $keep{_
}; # Manually set it because $_ gets reset in a map.
923 $keep{f
} = $filename if exists $keep{f
};
924 my $special_vars_used_by_opt_output = join( '', @special_vars_used_by_opt_output );
925 $output =~ s/\$([$special_vars_used_by_opt_output])/$keep{$1}/ego;
927 App
::Ack
::say( join( $separator, @line_parts, $output ) );
933 # We have to do underlining before any highlighting because highlighting modifies string length.
934 if ( $opt_underline && !$skip_coloring ) {
935 while ( $line =~ /$re_hilite/og ) {
936 my $match_start = $-[0] // next;
937 my $match_end = $+[0];
938 my $match_length = $match_end - $match_start;
939 last if $match_length <= 0;
941 my $spaces_needed = $match_start - length $underline;
943 $underline .= (' ' x
$spaces_needed);
944 $underline .= ('^' x
$match_length);
947 if ( $opt_color && !$skip_coloring ) {
948 my $highlighted = 0; # If highlighted, need to escape afterwards.
950 while ( $line =~ /$re_hilite/og ) {
951 my $match_start = $-[0] // next;
952 my $match_end = $+[0];
953 my $match_length = $match_end - $match_start;
954 last if $match_length <= 0;
956 my $substring = substr( $line, $match_start, $match_length );
957 my $substitution = Term
::ANSIColor
::colored
( $substring, $ENV{ACK_COLOR_MATCH
} );
959 # Fourth argument replaces the string specified by the first three.
960 substr( $line, $match_start, $match_length, $substitution );
962 # Move the offset of where /g left off forward the number of spaces of highlighting.
963 pos($line) = $match_end + (length( $substitution ) - length( $substring ));
966 # Reset formatting and delete everything to the end of the line.
967 $line .= "\e[0m\e[K" if $highlighted;
970 push @line_parts, $line;
971 App
::Ack
::say( join( $separator, @line_parts ) );
973 # Print the underline, if appropriate.
974 if ( $underline ne '' ) {
975 # Figure out how many spaces are used per line for the ANSI coloring.
976 state $chars_used_by_coloring;
977 if ( !defined($chars_used_by_coloring) ) {
978 $chars_used_by_coloring = 0;
980 my $len_fn = sub { length( Term
::ANSIColor
::colored
( 'x', $ENV{$_[0]} ) ) - 1 };
981 $chars_used_by_coloring += $len_fn->('ACK_COLOR_FILENAME') unless $opt_heading;
982 $chars_used_by_coloring += $len_fn->('ACK_COLOR_LINENO');
983 $chars_used_by_coloring += $len_fn->('ACK_COLOR_COLNO') if $opt_column;
987 pop @line_parts; # Leave only the stuff on the left.
989 my $stuff_on_the_left = join( $separator, @line_parts );
990 my $spaces_needed = length($stuff_on_the_left) - $chars_used_by_coloring + 1;
992 App
::Ack
::print( ' ' x
$spaces_needed );
994 App
::Ack
::say( $underline );
1001 sub print_line_with_context
{
1002 my ( $filename, $matching_line, $lineno ) = @_;
1004 $matching_line =~ s/[\r\n]+$//;
1006 # Check if we need to print context lines first.
1007 if ( $opt_A || $opt_B ) {
1008 my $before_unprinted = $lineno - $printed_lineno - 1;
1009 if ( !$is_first_match && ( !$printed_lineno || $before_unprinted > $n_before_ctx_lines ) ) {
1010 App
::Ack
::say( '--' );
1013 # We want at most $n_before_ctx_lines of context.
1014 if ( $before_unprinted > $n_before_ctx_lines ) {
1015 $before_unprinted = $n_before_ctx_lines;
1018 while ( $before_unprinted > 0 ) {
1019 my $line = $before_context_buf[($before_context_pos - $before_unprinted + $n_before_ctx_lines) % $n_before_ctx_lines];
1023 # Disable $opt->{column} since there are no matches in the context lines.
1024 local $opt_column = 0;
1026 print_line_with_options
( $filename, $line, $lineno-$before_unprinted, '-' );
1027 $before_unprinted--;
1031 print_line_with_options
( $filename, $matching_line, $lineno, ':' );
1033 # We want to get the next $n_after_ctx_lines printed.
1034 $after_context_pending = $n_after_ctx_lines;
1036 $is_first_match = 0;
1043 sub get_match_colno
{
1044 return $match_colno;
1047 sub count_matches_in_file
{
1049 my $bail = shift; # True if we're just checking for existence.
1054 if ( !$file->open() ) {
1056 if ( $App::Ack
::report_bad_filenames
) {
1057 App
::Ack
::warn( $file->name . ": $!" );
1062 if ( !$file->may_be_present( $re_scan ) ) {
1071 my $in_range = range_setup
();
1073 my $fh = $file->{fh
};
1074 if ( $using_ranges ) {
1077 $in_range = 1 if ( !$in_range && defined($opt_range_start) && /$opt_range_start/o );
1079 my $is_match = /$re_match/o;
1080 if ( $is_match && defined($re_not) ) {
1081 $is_match = !/$re_not/o;
1083 if ( $is_match xor $opt_v ) {
1088 $in_range = 0 if ( $in_range && defined($opt_range_end) && /$opt_range_end/o );
1094 my $is_match = /$re_match/o;
1095 if ( $is_match && defined($re_not) ) {
1096 $is_match = !/$re_not/o;
1098 if ( $is_match xor $opt_v ) {
1112 return !$using_ranges || (!$opt_range_start && $opt_range_end);
1122 ack - grep-like text finder
1126 ack [options] PATTERN [FILE...]
1127 ack -f [options] [DIRECTORY...]
1131 ack is designed as an alternative to F<grep> for programmers.
1133 ack searches the named input FILEs or DIRECTORYs for lines containing a
1134 match to the given PATTERN. By default, ack prints the matching lines.
1135 If no FILE or DIRECTORY is given, the current directory will be searched.
1137 PATTERN is a Perl regular expression. Perl regular expressions
1138 are commonly found in other programming languages, but for the particulars
1139 of their behavior, please consult
1140 L<perlreref|https://perldoc.perl.org/perlreref.html>. If you don't know
1141 how to use regular expression but are interested in learning, you may
1142 consult L<perlretut|https://perldoc.perl.org/perlretut.html>. If you do not
1143 need or want ack to use regular expressions, please see the
1144 C<-Q>/C<--literal> option.
1146 Ack can also list files that would be searched, without actually
1147 searching them, to let you take advantage of ack's file-type filtering
1150 =head1 FILE SELECTION
1152 If files are not specified for searching, either on the command
1153 line or piped in with the C<-x> option, I<ack> delves into
1154 subdirectories selecting files for searching.
1156 I<ack> is intelligent about the files it searches. It knows about
1157 certain file types, based on both the extension on the file and,
1158 in some cases, the contents of the file. These selections can be
1159 made with the B<--type> option.
1161 With no file selection, I<ack> searches through regular files that
1162 are not explicitly excluded by B<--ignore-dir> and B<--ignore-file>
1163 options, either present in F<ackrc> files or on the command line.
1165 The default options for I<ack> ignore certain files and directories. These
1170 =item * Backup files: Files matching F<#*#> or ending with F<~>.
1172 =item * Coredumps: Files matching F<core.\d+>
1174 =item * Version control directories like F<.svn> and F<.git>.
1178 Run I<ack> with the C<--dump> option to see what settings are set.
1180 However, I<ack> always searches the files given on the command line,
1181 no matter what type. If you tell I<ack> to search in a coredump,
1182 it will search in a coredump.
1184 =head1 DIRECTORY SELECTION
1186 I<ack> descends through the directory tree of the starting directories
1187 specified. If no directories are specified, the current working directory is
1188 used. However, it will ignore the shadow directories used by
1189 many version control systems, and the build directories used by the
1190 Perl MakeMaker system. You may add or remove a directory from this
1191 list with the B<--[no]ignore-dir> option. The option may be repeated
1192 to add/remove multiple directories from the ignore list.
1194 For a complete list of directories that do not get searched, run
1197 =head1 MATCHING IN A RANGE OF LINES
1199 The C<--range-start> and C<--range-end> options let you specify ranges of
1200 lines to search within each file.
1202 Say you had the following file, called F<testfile>:
1204 # This function calls print on "foo".
1214 Calling C<ack print> will give us five matches:
1216 $ ack print testfile
1217 # This function calls print on "foo".
1223 What if we only want to search for C<print> within the subroutines? We can
1224 specify ranges of lines that we want ack to search. The range starts with
1225 any line that matches the pattern C<^sub \w+>, and stops with any line that
1228 $ ack --range-start='^sub \w+' --range-end='^}' print testfile
1232 Note that ack searched two ranges of lines. The listing below shows which
1233 lines were in a range and which were out of the range.
1235 Out # This function calls print on "foo".
1243 Out my $task = 'print';
1245 You don't have to specify both C<--range-start> and C<--range-end>. IF
1246 C<--range-start> is omitted, then the range runs from the first line in the
1247 file until the first line that matches C<--range-end>. Similarly, if
1248 C<--range-end> is omitted, the range runs from the first line matching
1249 C<--range-start> to the end of the file.
1251 For example, if you wanted to search all HTML files up until the first
1252 instance of the C<< <body> >>, you could do
1254 ack foo --html --range-end='<body>'
1256 Or to search after Perl's `__DATA__` or `__END__` markers, you would do
1258 ack pattern --perl --range-start='^__(END|DATA)__'
1260 It's possible for a range to start and stop on the same line. For example
1262 --range-start='<title>' --range-end='</title>'
1264 would match this line as both the start and end of the range, making a
1267 <title>Page title</title>
1269 Note that the patterns in C<--range-start> and C<--range-end> are not
1270 affected by options like C<-i>, C<-w> and C<-Q> that modify the behavior of
1271 the main pattern being matched.
1273 Again, ranges only affect where matches are looked for. Everything else in
1274 ack works the same way. Using C<-c> option with a range will give a count
1275 of all the matches that appear within those ranges. The C<-l> shows those
1276 files that have a match within a range, and the C<-L> option shows files
1277 that do not have a match within a range.
1279 The C<-v> option for negating a match works inside the range, too.
1280 To see lines that don't match "google" within the "<head>" section of
1281 your HTML files, you could do:
1283 ack google -v --html --range-start='<head' --range-end='</head>'
1285 Specifying a range to search does not affect how matches are displayed.
1286 The context for a match will still be the same, and
1288 Using the context options work the same way, and will show context
1289 lines for matches even if the context lines fall outside the range.
1290 Similarly, C<--passthru> will show all lines in the file, but only show
1291 matches for lines within the range.
1299 Specifies an ackrc file to load after all others; see L</"ACKRC LOCATION SEMANTICS">.
1301 =item B<--and=PATTERN>
1303 Specifies a I<PATTERN> that MUST ALSO be found on a given line for a match to
1304 occur. This option can be repeated.
1306 If you want to find all the lines with both "dogs" or "cats", use:
1310 Note that the options that affect "dogs" also affect "cats", so if you have
1312 ack -i -w dogs --and cats
1314 then the search for both "dogs" and "cats" will be case-insensitive and be
1317 See also the other two boolean options C<--or> and C<--not>, neither of
1318 which can be used with C<--and>.
1320 =item B<-A I<NUM>>, B<--after-context=I<NUM>>
1322 Print I<NUM> lines of trailing context after matching lines.
1324 =item B<-B I<NUM>>, B<--before-context=I<NUM>>
1326 Print I<NUM> lines of leading context before matching lines.
1328 =item B<--[no]break>
1330 Print a break between results from different files. On by default
1331 when used interactively.
1333 =item B<-C [I<NUM>]>, B<--context[=I<NUM>]>
1335 Print I<NUM> lines (default 2) of context around matching lines.
1336 You can specify zero lines of context to override another context
1337 specified in an ackrc.
1339 =item B<-c>, B<--count>
1341 Suppress normal output; instead print a count of matching lines for
1342 each input file. If B<-l> is in effect, it will only show the
1343 number of lines for each file that has lines matching. Without
1344 B<-l>, some line counts may be zeroes.
1346 If combined with B<-h> (B<--no-filename>) ack outputs only one total
1349 =item B<--[no]color>, B<--[no]colour>
1351 B<--color> highlights the matching text. B<--nocolor> suppresses
1352 the color. This is on by default unless the output is redirected.
1354 On Windows, this option is off by default unless the
1355 L<Win32::Console::ANSI> module is installed or the C<ACK_PAGER_COLOR>
1356 environment variable is used.
1358 =item B<--color-filename=I<color>>
1360 Sets the color to be used for filenames.
1362 =item B<--color-match=I<color>>
1364 Sets the color to be used for matches.
1366 =item B<--color-colno=I<color>>
1368 Sets the color to be used for column numbers.
1370 =item B<--color-lineno=I<color>>
1372 Sets the color to be used for line numbers.
1374 =item B<--[no]column>
1376 Show the column number of the first match. This is helpful for
1377 editors that can place your cursor at a given position.
1379 =item B<--create-ackrc>
1381 Dumps the default ack options to standard output. This is useful for
1382 when you want to customize the defaults.
1386 Writes the list of options loaded and where they came from to standard
1387 output. Handy for debugging.
1391 B<--noenv> disables all environment processing. No F<.ackrc> is
1392 read and all environment variables are ignored. By default, F<ack>
1393 considers F<.ackrc> and settings in the environment.
1397 B<--flush> flushes output immediately. This is off by default
1398 unless ack is running interactively (when output goes to a pipe or
1403 Only print the files that would be searched, without actually doing
1404 any searching. PATTERN must not be specified, or it will be taken
1405 as a path to search.
1407 =item B<--files-from=I<FILE>>
1409 The list of files to be searched is specified in I<FILE>. The list of
1410 files are separated by newlines. If I<FILE> is C<->, the list is loaded
1411 from standard input.
1413 Note that the list of files is B<not> filtered in any way. If you
1414 add C<--type=html> in addition to C<--files-from>, the C<--type> will
1418 =item B<--[no]filter>
1420 Forces ack to act as if it were receiving input via a pipe.
1422 =item B<--[no]follow>
1424 Follow or don't follow symlinks, other than whatever starting files
1425 or directories were specified on the command line.
1427 This is off by default.
1429 =item B<-g I<PATTERN>>
1431 Print searchable files where the relative path + filename matches
1438 is exactly the same as
1442 This means that just as ack will not search, for example, F<.jpg>
1443 files, C<-g> will not list F<.jpg> files either. ack is not intended
1444 to be a general-purpose file finder.
1446 Note also that if you have C<-i> in your .ackrc that the filenames
1447 to be matched will be case-insensitive as well.
1449 This option can be combined with B<--color> to make it easier to
1452 =item B<--[no]group>
1454 B<--group> groups matches by file name. This is the default
1455 when used interactively.
1457 B<--nogroup> prints one result per line, like grep. This is the
1458 default when output is redirected.
1460 =item B<-H>, B<--with-filename>
1462 Print the filename for each match. This is the default unless searching
1463 a single explicitly specified file.
1465 =item B<-h>, B<--no-filename>
1467 Suppress the prefixing of filenames on output when multiple files are
1470 =item B<--[no]heading>
1472 Print a filename heading above each file's results. This is the default
1473 when used interactively.
1477 Print a short help statement.
1479 =item B<--help-types>
1481 Print all known types.
1483 =item B<--help-colors>
1485 Print a chart of various color combinations.
1487 =item B<--help-rgb-colors>
1489 Like B<--help-colors> but with more precise RGB colors.
1491 =item B<-i>, B<--ignore-case>
1493 Ignore case distinctions in PATTERN. Overrides B<--smart-case> and B<-I>.
1495 =item B<-I>, B<--no-ignore-case>
1497 Turns on case distinctions in PATTERN. Overrides B<--smart-case> and B<-i>.
1499 =item B<--ignore-ack-defaults>
1501 Tells ack to completely ignore the default definitions provided with ack.
1502 This is useful in combination with B<--create-ackrc> if you I<really> want
1505 =item B<--[no]ignore-dir=I<DIRNAME>>, B<--[no]ignore-directory=I<DIRNAME>>
1507 Ignore directory (as CVS, .svn, etc are ignored). May be used
1508 multiple times to ignore multiple directories. For example, mason
1509 users may wish to include B<--ignore-dir=data>. The B<--noignore-dir>
1510 option allows users to search directories which would normally be
1511 ignored (perhaps to research the contents of F<.svn/props> directories).
1513 The I<DIRNAME> must always be a simple directory name. Nested
1514 directories like F<foo/bar> are NOT supported. You would need to
1515 specify B<--ignore-dir=foo> and then no files from any foo directory
1516 are taken into account by ack unless given explicitly on the command
1519 =item B<--ignore-file=I<FILTER:ARGS>>
1521 Ignore files matching I<FILTER:ARGS>. The filters are specified
1522 identically to file type filters as seen in L</"Defining your own types">.
1524 =item B<-k>, B<--known-types>
1526 Limit selected files to those with types that ack knows about.
1528 =item B<-l>, B<--files-with-matches>
1530 Only print the filenames of matching files, instead of the matching text.
1532 =item B<-L>, B<--files-without-matches>
1534 Only print the filenames of files that do I<NOT> match.
1536 =item B<--match I<PATTERN>>
1538 Specify the I<PATTERN> explicitly. This is helpful if you don't want to put the
1539 regex as your first argument, e.g. when executing multiple searches over the
1542 # search for foo and bar in given files
1543 ack file1 t/file* --match foo
1544 ack file1 t/file* --match bar
1546 =item B<-m=I<NUM>>, B<--max-count=I<NUM>>
1548 Print only I<NUM> matches out of each file. If you want to stop ack
1549 after printing the first match of any kind, use the B<-1> options.
1553 Print this manual page.
1555 =item B<-n>, B<--no-recurse>
1557 No descending into subdirectories.
1559 =item B<--not=PATTERN>
1561 Specifies a I<PATTERN> that must NOT be true on a given line for a match to
1562 occur. This option can be repeated.
1564 If you want to find all the lines with "dogs" but not if "cats" or "fish"
1565 appear on the line, use:
1567 ack dogs --not cats --not fish
1569 Note that the options that affect "dogs" also affect "cats" and "fish", so
1572 ack -i -w dogs --not cats
1574 then the search for both "dogs" and "cats" will be case-insensitive and be
1577 See also the other two boolean options C<--and> and C<--or>, neither of
1578 which can be used with C<--not>.
1582 Show only the part of each line matching PATTERN (turns off text
1583 highlighting). This is exactly the same as C<--output=$&>.
1585 =item B<--or=PATTERN>
1587 Specifies a I<PATTERN> that MAY be found on a given line for a match to
1588 occur. This option can be repeated.
1590 If you want to find all the lines with "dogs" or "cats", use:
1594 Note that the options that affect "dogs" also affect "cats", so if you have
1596 ack -i -w dogs --or cats
1598 then the search for both "dogs" and "cats" will be case-insensitive and be
1601 See also the other two boolean options C<--and> and C<--not>, neither of
1602 which can be used with C<--or>.
1604 =item B<--output=I<expr>>
1606 Output the evaluation of I<expr> for each line (turns off text
1607 highlighting). If PATTERN matches more than once then a line is
1608 output for each non-overlapping match.
1610 I<expr> may contain the strings "\n", "\r" and "\t", which will be
1611 expanded to their corresponding characters line feed, carriage return
1612 and tab, respectively.
1614 I<expr> may also contain the following Perl special variables:
1618 =item C<$1> through C<$9>
1620 The subpattern from the corresponding set of capturing parentheses.
1621 If your pattern is C<(.+) and (.+)>, and the string is "this and
1622 that', then C<$1> is "this" and C<$2> is "that".
1626 The contents of the line in the file.
1630 The number of the line in the file.
1632 =item C<$&>, C<$`> and C<$'>
1634 C<$&> is the string matched by the pattern, C<$`> is what
1635 precedes the match, and C<$'> is what follows it. If the pattern
1636 is C<gra(ph|nd)> and the string is "lexicographic", then C<$&> is
1637 "graph", C<$`> is "lexico" and C<$'> is "ic".
1639 Use of these variables in your output will slow down the pattern
1644 The match made by the last parentheses that matched in the pattern.
1645 For example, if your pattern is C<Version: (.+)|Revision: (.+)>,
1646 then C<$+> will contain whichever set of parentheses matched.
1650 C<$f> is available, in C<--output> only, to insert the filename.
1651 This is a stand-in for the discovered C<$filename> usage in old C<< ack2 --output >>,
1652 which is disallowed with C<ack3> improved security.
1654 The intended usage is to provide the grep or compile-error syntax needed for editor/IDE go-to-line integration,
1655 e.g. C<--output=$f:$.:$_> or C<--output=$f\t$.\t$&>
1659 =item B<--pager=I<program>>, B<--nopager>
1661 B<--pager> directs ack's output through I<program>. This can also be specified
1662 via the C<ACK_PAGER> and C<ACK_PAGER_COLOR> environment variables.
1664 Using --pager does not suppress grouping and coloring like piping
1665 output on the command-line does.
1667 B<--nopager> cancels any setting in F<~/.ackrc>, C<ACK_PAGER> or C<ACK_PAGER_COLOR>.
1668 No output will be sent through a pager.
1672 Prints all lines, whether or not they match the expression. Highlighting
1673 will still work, though, so it can be used to highlight matches while
1674 still seeing the entire file, as in:
1676 # Watch a log file, and highlight a certain IP address.
1677 $ tail -f ~/access.log | ack --passthru 123.45.67.89
1681 Only works in conjunction with B<-f>, B<-g>, B<-l> or B<-c>, options
1682 that only list filenames. The filenames are output separated with a
1683 null byte instead of the usual newline. This is helpful when dealing
1684 with filenames that contain whitespace, e.g.
1686 # Remove all files of type HTML.
1687 ack -f --html --print0 | xargs -0 rm -f
1689 =item B<-p[N]>, B<--proximate[=N]>
1691 Groups together match lines that are within N lines of each other.
1692 This is useful for visually picking out matches that appear close
1695 For example, if you got these results without the C<--proximate> option,
1702 they would look like this with C<--proximate=1>
1711 and this with C<--proximate=3>.
1719 If N is omitted, N is set to 1.
1723 Negates the effect of the B<--proximate> option. Shortcut for B<--proximate=0>.
1725 =item B<-Q>, B<--literal>
1727 Quote all metacharacters in PATTERN, it is treated as a literal.
1729 =item B<-r>, B<-R>, B<--recurse>
1731 Recurse into sub-directories. This is the default and just here for
1732 compatibility with grep. You can also use it for turning B<--no-recurse> off.
1734 =item B<--range-start=PATTERN>, B<--range-end=PATTERN>
1736 Specifies patterns that mark the start and end of a range. See
1737 L<MATCHING IN A RANGE OF LINES> for details.
1741 Suppress error messages about nonexistent or unreadable files. This is taken
1744 =item B<-S>, B<--[no]smart-case>, B<--no-smart-case>
1746 Ignore case in the search strings if PATTERN contains no uppercase
1747 characters. This is similar to C<smartcase> in the vim text editor.
1748 The options overrides B<-i> and B<-I>.
1750 B<-S> is a synonym for B<--smart-case>.
1752 B<-i> always overrides this option.
1754 =item B<--sort-files>
1756 Sorts the found files lexicographically. Use this if you want your file
1757 listings to be deterministic between runs of I<ack>.
1759 =item B<--show-types>
1761 Outputs the filetypes that ack associates with each file.
1763 Works with B<-f> and B<-g> options.
1765 =item B<-t TYPE>, B<--type=TYPE>, B<--TYPE>
1767 Specify the types of files to include in the search.
1768 TYPE is a filetype, like I<perl> or I<xml>. B<--type=perl> can
1769 also be specified as B<--perl>, although this is deprecated.
1771 Type inclusions can be repeated and are ORed together.
1773 See I<ack --help-types> for a list of valid types.
1775 =item B<-T TYPE>, B<--type=noTYPE>, B<--noTYPE>
1777 Specifies the type of files to exclude from the search. B<--type=noperl>
1778 can be done as B<--noperl>, although this is deprecated.
1780 If a file is of both type "foo" and "bar", specifying both B<--type=foo>
1781 and B<--type=nobar> will exclude the file, because an exclusion takes
1782 precedence over an inclusion.
1784 =item B<--type-add I<TYPE>:I<FILTER>:I<ARGS>>
1786 Files with the given ARGS applied to the given FILTER
1787 are recognized as being of (the existing) type TYPE.
1788 See also L</"Defining your own types">.
1790 =item B<--type-set I<TYPE>:I<FILTER>:I<ARGS>>
1792 Files with the given ARGS applied to the given FILTER are recognized as
1793 being of type TYPE. This replaces an existing definition for type TYPE. See
1794 also L</"Defining your own types">.
1796 =item B<--type-del I<TYPE>>
1798 The filters associated with TYPE are removed from Ack, and are no longer considered
1801 =item B<--[no]underline>
1803 Turns on underlining of matches, where "underlining" is printing a line of
1804 carets under the match.
1808 17: Come kick the football you fool
1810 623: Price per square foot
1813 This is useful if you're dumping the results of an ack run into a text
1814 file or printer that doesn't support ANSI color codes.
1816 The setting of underline does not affect highlighting of matches.
1818 =item B<-v>, B<--invert-match>
1820 Invert match: select non-matching lines.
1824 Display version and copyright information.
1826 =item B<-w>, B<--word-regexp>
1828 Force PATTERN to match only whole words.
1832 An abbreviation for B<--files-from=->. The list of files to search are read
1833 from standard input, with one line per file.
1835 Note that the list of files is B<not> filtered in any way. If you add
1836 C<--type=html> in addition to C<-x>, the C<--type> will be ignored.
1840 Stops after reporting first match of any kind. This is different
1841 from B<--max-count=1> or B<-m1>, where only one match per file is
1842 shown. Also, B<-1> works with B<-f> and B<-g>, where B<-m> does
1847 Display the all-important Bill The Cat logo. Note that the exact
1848 spelling of B<--thpppppt> is not important. It's checked against
1849 a regular expression.
1853 Check with the admiral for traps.
1857 Chocolate, Chocolate, Chocolate!
1861 =head1 THE .ackrc FILE
1863 The F<.ackrc> file contains command-line options that are prepended
1864 to the command line before processing. Multiple options may live
1865 on multiple lines. Lines beginning with a # are ignored. A F<.ackrc>
1866 might look like this:
1868 # Always sort the files
1871 # Always color, even if piping to another program
1874 # Use "less -r" as my pager
1877 Note that arguments with spaces in them do not need to be quoted,
1878 as they are not interpreted by the shell. Basically, each I<line>
1879 in the F<.ackrc> file is interpreted as one element of C<@ARGV>.
1881 F<ack> looks in several locations for F<.ackrc> files; the searching
1882 process is detailed in L</"ACKRC LOCATION SEMANTICS">. These
1883 files are not considered if B<--noenv> is specified on the command line.
1885 =head1 Defining your own types
1887 ack allows you to define your own types in addition to the predefined
1888 types. This is done with command line options that are best put into
1889 an F<.ackrc> file - then you do not have to define your types over and
1890 over again. In the following examples the options will always be shown
1891 on one command line so that they can be easily copy & pasted.
1893 File types can be specified both with the I<--type=xxx> option,
1894 or the file type as an option itself. For example, if you create
1895 a filetype of "cobol", you can specify I<--type=cobol> or simply
1896 I<--cobol>. File types must be at least two characters long. This
1897 is why the C language is I<--cc> and the R language is I<--rr>.
1899 I<ack --perl foo> searches for foo in all perl files. I<ack --help-types>
1900 tells you, that perl files are files ending
1901 in .pl, .pm, .pod or .t. So what if you would like to include .xs
1902 files as well when searching for --perl files? I<ack --type-add perl:ext:xs --perl foo>
1903 does this for you. B<--type-add> appends
1904 additional extensions to an existing type.
1906 If you want to define a new type, or completely redefine an existing
1907 type, then use B<--type-set>. I<ack --type-set eiffel:ext:e,eiffel> defines
1908 the type I<eiffel> to include files with
1909 the extensions .e or .eiffel. So to search for all eiffel files
1910 containing the word Bertrand use I<ack --type-set eiffel:ext:e,eiffel --eiffel Bertrand>.
1911 As usual, you can also write B<--type=eiffel>
1912 instead of B<--eiffel>. Negation also works, so B<--noeiffel> excludes
1913 all eiffel files from a search. Redefining also works: I<ack --type-set cc:ext:c,h>
1914 and I<.xs> files no longer belong to the type I<cc>.
1916 When defining your own types in the F<.ackrc> file you have to use
1919 --type-set=eiffel:ext:e,eiffel
1921 or writing on separate lines
1926 The following does B<NOT> work in the F<.ackrc> file:
1928 --type-set eiffel:ext:e,eiffel
1930 In order to see all currently defined types, use I<--help-types>, e.g.
1931 I<ack --type-set backup:ext:bak --type-add perl:ext:perl --help-types>
1933 In addition to filtering based on extension, ack offers additional
1934 filter types. The generic syntax is
1935 I<--type-set TYPE:FILTER:ARGS>; I<ARGS> depends on the value
1940 =item is:I<FILENAME>
1942 I<is> filters match the target filename exactly. It takes exactly one
1943 argument, which is the name of the file to match.
1947 --type-set make:is:Makefile
1949 =item ext:I<EXTENSION>[,I<EXTENSION2>[,...]]
1951 I<ext> filters match the extension of the target file against a list
1952 of extensions. No leading dot is needed for the extensions.
1956 --type-set perl:ext:pl,pm,t
1958 =item match:I<PATTERN>
1960 I<match> filters match the target filename against a regular expression.
1961 The regular expression is made case-insensitive for the search.
1965 --type-set make:match:/(gnu)?makefile/
1967 =item firstlinematch:I<PATTERN>
1969 I<firstlinematch> matches the first line of the target file against a
1970 regular expression. Like I<match>, the regular expression is made
1975 --type-add perl:firstlinematch:/perl/
1981 ack allows customization of the colors it uses when presenting matches
1982 onscreen. It uses the colors available in Perl's L<Term::ANSIColor>
1983 module, which provides the following listed values. Note that case does not
1984 matter when using these values.
1986 There are four different colors ack uses:
1988 Aspect Option Env. variable Default
1989 -------- ----------------- ------------------ ---------------
1990 filename --color-filename ACK_COLOR_FILENAME black on_yellow
1991 match --color-match ACK_COLOR_MATCH bold green
1992 line no. --color-lineno ACK_COLOR_LINENO bold yellow
1993 column no. --color-colno ACK_COLOR_COLNO bold yellow
1995 The column number column is only used if the column number is shown because
1996 of the --column option.
1998 Colors may be specified by command-line option, such as
1999 C<ack --color-filename='red on_white'>, or by setting an environment
2000 variable, such as C<ACK_COLOR_FILENAME='red on_white'>. Options for colors
2001 can be set in your ACKRC file (See "THE .ackrc FILE").
2003 ack can understand the following colors for the foreground:
2005 black red green yellow blue magenta cyan white
2007 The optional background color is specified by prepending "on_" to one of
2008 the foreground colors:
2010 on_black on_red on_green on_yellow on_blue on_magenta on_cyan on_white
2012 Each of the foreground colors can be modified with the following
2013 attributes, which may or may not be supported by your terminal:
2015 bold faint italic underline blink reverse concealed
2017 Any combinations of modifiers can be added to the foreground color. If your
2018 terminal supports it, and you enjoy visual punishment, you can specify:
2020 ack --color-filename="blink italic underline bold red on_yellow"
2022 For charts of the colors and what they look like, run C<ack --help-colors>
2023 and C<ack --help-rgb-colors>.
2025 If the eight standard colors, in their bold, faint and unmodified states,
2026 aren't enough for you to choose from, you can also specify colors by their
2027 RGB values. They are specified as "rgbXYZ" where X, Y, and Z are values
2028 between 0 and 5 giving the intensity of red, green and blue, respectively.
2029 Therefore, "rgb500" is pure red, "rgb505" is purple, and so on.
2031 Background colors can be specified with the "on_" prefix prepended on an
2032 RGB color, so that "on_rgb505" would be a purple background.
2034 The modifier attributes of blink, italic, underscore and so on may or may
2035 not work on the RGB colors.
2037 For a chart of the 216 possible RGB colors, run C<ack --help-rgb-colors>.
2039 =head1 ENVIRONMENT VARIABLES
2041 For commonly-used ack options, environment variables can make life
2042 much easier. These variables are ignored if B<--noenv> is specified
2043 on the command line.
2049 Specifies the location of the user's F<.ackrc> file. If this file doesn't
2050 exist, F<ack> looks in the default location.
2052 =item ACK_COLOR_COLNO
2054 Color specification for the column number in ack's output. By default, the
2055 column number is not shown. You have to enable it with the B<--column>
2056 option. See the section "ack Colors" above.
2058 =item ACK_COLOR_FILENAME
2060 Color specification for the filename in ack's output. See the section "ack
2063 =item ACK_COLOR_LINENO
2065 Color specification for the line number in ack's output. See the section
2068 =item ACK_COLOR_MATCH
2070 Color specification for the matched text in ack's output. See the section
2075 Specifies a pager program, such as C<more>, C<less> or C<most>, to which
2076 ack will send its output.
2078 Using C<ACK_PAGER> does not suppress grouping and coloring like
2079 piping output on the command-line does, except that on Windows
2080 ack will assume that C<ACK_PAGER> does not support color.
2082 C<ACK_PAGER_COLOR> overrides C<ACK_PAGER> if both are specified.
2084 =item ACK_PAGER_COLOR
2086 Specifies a pager program that understands ANSI color sequences.
2087 Using C<ACK_PAGER_COLOR> does not suppress grouping and coloring
2088 like piping output on the command-line does.
2090 If you are not on Windows, you never need to use C<ACK_PAGER_COLOR>.
2094 =head1 ACK & OTHER TOOLS
2096 =head2 Simple vim integration
2098 F<ack> integrates easily with the Vim text editor. Set this in your
2099 F<.vimrc> to use F<ack> instead of F<grep>:
2103 That example uses C<-k> to search through only files of the types ack
2104 knows about, but you may use other default flags. Now you can search
2105 with F<ack> and easily step through the results in Vim:
2107 :grep Dumper perllib
2109 =head2 Editor integration
2111 Many users have integrated ack into their preferred text editors.
2112 For details and links, see L<https://beyondgrep.com/more-tools/>.
2114 =head2 Shell and Return Code
2116 For greater compatibility with I<grep>, I<ack> in normal use returns
2117 shell return or exit code of 0 only if something is found and 1 if
2120 (Shell exit code 1 is C<$?=256> in perl with C<system> or backticks.)
2122 The I<grep> code 2 for errors is not used.
2124 If C<-f> or C<-g> are specified, then 0 is returned if at least one
2125 file is found. If no files are found, then 1 is returned.
2129 =head1 DEBUGGING ACK PROBLEMS
2131 If ack gives you output you're not expecting, start with a few simple steps.
2133 =head2 Try it with B<--noenv>
2135 Your environment variables and F<.ackrc> may be doing things you're
2136 not expecting, or forgotten you specified. Use B<--noenv> to ignore
2137 your environment and F<.ackrc>.
2139 =head2 Use B<-f> to see what files have been selected for searching
2141 Ack's B<-f> was originally added as a debugging tool. If ack is
2142 not finding matches you think it should find, run F<ack -f> to see
2143 what files have been selected. You can also add the C<--show-types>
2144 options to show the type of each file selected.
2146 =head2 Use B<--dump>
2148 This lists the ackrc files that are loaded and the options loaded
2149 from them. You may be loading an F<.ackrc> file that you didn't know
2152 =head1 ACKRC LOCATION SEMANTICS
2154 Ack can load its configuration from many sources. The following list
2155 specifies the sources Ack looks for configuration files; each one
2156 that is found is loaded in the order specified here, and
2157 each one overrides options set in any of the sources preceding
2158 it. (For example, if I set --sort-files in my user ackrc, and
2159 --nosort-files on the command line, the command line takes
2166 Defaults are loaded from App::Ack::ConfigDefaults. This can be omitted
2167 using C<--ignore-ack-defaults>.
2169 =item * Global ackrc
2171 Options are then loaded from the global ackrc. This is located at
2172 C</etc/ackrc> on Unix-like systems.
2174 Under Windows XP and earlier, the global ackrc is at
2175 C<C:\Documents and Settings\All Users\Application Data\ackrc>
2177 Under Windows Vista/7, the global ackrc is at
2178 C<C:\ProgramData\ackrc>
2180 The C<--noenv> option prevents all ackrc files from being loaded.
2184 Options are then loaded from the user's ackrc. This is located at
2185 C<$HOME/.ackrc> on Unix-like systems.
2187 Under Windows XP and earlier, the user's ackrc is at
2188 C<C:\Documents and Settings\$USER\Application Data\ackrc>.
2190 Under Windows Vista/7, the user's ackrc is at
2191 C<C:\Users\$USER\AppData\Roaming\ackrc>.
2193 If you want to load a different user-level ackrc, it may be specified
2194 with the C<$ACKRC> environment variable.
2196 The C<--noenv> option prevents all ackrc files from being loaded.
2198 =item * Project ackrc
2200 Options are then loaded from the project ackrc. The project ackrc is
2201 the first ackrc file with the name C<.ackrc> or C<_ackrc>, first searching
2202 in the current directory, then the parent directory, then the grandparent
2203 directory, etc. This can be omitted using C<--noenv>.
2207 The C<--ackrc> option may be included on the command line to specify an
2208 ackrc file that can override all others. It is consulted even if C<--noenv>
2211 =item * Command line
2213 Options are then loaded from the command line.
2217 =head1 BUGS & ENHANCEMENTS
2219 ack is based at GitHub at L<https://github.com/beyondgrep/ack3>
2221 Please report any bugs or feature requests to the issues list at
2222 GitHub: L<https://github.com/beyondgrep/ack3/issues>.
2224 Please include the operating system that you're using; the output of
2225 the command C<ack --version>; and any customizations in your F<.ackrc>
2228 To suggest enhancements, please submit an issue at
2229 L<https://github.com/beyondgrep/ack3/issues>. Also read the
2230 F<DEVELOPERS.md> file in the ack code repository.
2232 Also, feel free to discuss your issues on the ack mailing
2233 list at L<https://groups.google.com/group/ack-users>.
2237 Support for and information about F<ack> can be found at:
2241 =item * The ack homepage
2243 L<https://beyondgrep.com/>
2245 =item * Source repository
2247 L<https://github.com/beyondgrep/ack3>
2249 =item * The ack issues list at GitHub
2251 L<https://github.com/beyondgrep/ack3/issues>
2253 =item * The ack announcements mailing list
2255 L<https://groups.google.com/group/ack-announcement>
2257 =item * The ack users' mailing list
2259 L<https://groups.google.com/group/ack-users>
2261 =item * The ack development mailing list
2263 L<https://groups.google.com/group/ack-users>
2269 There are ack mailing lists and a Slack channel for ack. See
2270 L<https://beyondgrep.com/community/> for details.
2274 This is the Frequently Asked Questions list for ack.
2276 =head2 Can I stop using grep now?
2278 Many people find I<ack> to be better than I<grep> as an everyday tool
2279 99% of the time, but don't throw I<grep> away, because there are times
2280 you'll still need it. For example, you might be looking through huge
2281 log files and not using regular expressions. In that case, I<grep>
2282 will probably perform better.
2284 =head2 Why isn't ack finding a match in (some file)?
2286 First, take a look and see if ack is even looking at the file. ack is
2287 intelligent in what files it will search and which ones it won't, but
2288 sometimes that can be surprising.
2290 Use the C<-f> switch, with no regex, to see a list of files that ack
2291 will search for you. If your file doesn't show up in the list of files
2292 that C<ack -f> shows, then ack never looks in it.
2294 =head2 Wouldn't it be great if F<ack> did search & replace?
2296 No, ack will always be read-only. Perl has a perfectly good way
2297 to do search & replace in files, using the C<-i>, C<-p> and C<-n>
2300 You can certainly use ack to select your files to update. For
2301 example, to change all "foo" to "bar" in all PHP files, you can do
2302 this from the Unix shell:
2304 $ perl -i -p -e's/foo/bar/g' $(ack -f --php)
2306 =head2 Can I make ack recognize F<.xyz> files?
2308 Yes! Please see L</"Defining your own types"> in the ack manual.
2310 =head2 Will you make ack recognize F<.xyz> files by default?
2312 We might, depending on how widely-used the file format is.
2314 Submit an issue at in the GitHub issue queue at
2315 L<https://github.com/beyondgrep/ack3/issues>. Explain what the file format
2316 is, where we can find out more about it, and what you have been using
2317 in your F<.ackrc> to support it.
2319 Please do not bother creating a pull request. The code for filetypes
2320 is trivial compared to the rest of the process we go through.
2322 =head2 Why is it called ack if it's called ack-grep?
2324 The name of the program is "ack". Some packagers have called it
2325 "ack-grep" when creating packages because there's already a package
2326 out there called "ack" that has nothing to do with this ack.
2328 I suggest you make a symlink named F<ack> that points to F<ack-grep>
2329 because one of the crucial benefits of ack is having a name that's
2330 so short and simple to type.
2332 To do that, run this with F<sudo> or as root:
2334 ln -s /usr/bin/ack-grep /usr/bin/ack
2336 Alternatively, you could use a shell alias:
2344 =head2 What does F<ack> mean?
2346 Nothing. I wanted a name that was easy to type and that you could
2347 pronounce as a single syllable.
2349 =head2 Can I do multi-line regexes?
2351 No, ack does not support regexes that match multiple lines. Doing
2352 so would require reading in the entire file at a time.
2354 If you want to see lines near your match, use the C<--A>, C<--B>
2355 and C<--C> switches for displaying context.
2357 =head2 Why is ack telling me I have an invalid option when searching for C<+foo>?
2359 ack treats command line options beginning with C<+> or C<-> as options; if you
2360 would like to search for these, you may prefix your search term with C<--> or
2361 use the C<--match> option. (However, don't forget that C<+> is a regular
2362 expression metacharacter!)
2364 =head2 Why does C<"ack '.{40000,}'"> fail? Isn't that a valid regex?
2366 The Perl language limits the repetition quantifier to 32K. You
2367 can search for C<.{32767}> but not C<.{32768}>.
2369 =head2 Ack does "X" and shouldn't, should it?
2371 We try to remain as close to grep's behavior as possible, so when in
2372 doubt, see what grep does! If there's a mismatch in functionality there,
2373 please submit an issue to GitHub, and/or bring it up on the ack-users
2378 =head1 ACKNOWLEDGEMENTS
2380 How appropriate to have I<ack>nowledgements!
2382 Thanks to everyone who has contributed to ack in any way, including
2394 Grzegorz Kaczmarczyk,
2411 SE<eacute>bastien FeugE<egrave>re,
2418 RaE<uacute>l GundE<iacute>n,
2424 RaE<aacute>l GundE<aacute>n,
2460 Eric Van Dewoestine,
2469 Christopher J. Madsen,
2481 GE<aacute>bor SzabE<oacute>,
2484 E<AElig>var ArnfjE<ouml>rE<eth> Bjarmason,
2488 Mark Leighton Fisher,
2494 Nilson Santos F. Jr,
2499 Ask BjE<oslash>rn Hansen,
2503 Slaven ReziE<0x107>,
2515 Andy Lester, C<< <andy at petdance.com> >>
2517 =head1 COPYRIGHT & LICENSE
2519 Copyright 2005-2024 Andy Lester.
2521 This program is free software; you can redistribute it and/or modify
2522 it under the terms of the Artistic License v2.0.
2524 See https://www.perlfoundation.org/artistic-license-20.html or the LICENSE.md
2525 file that comes with the ack distribution.
2541 $VERSION = 'v3.8.1'; # Check https://beyondgrep.com/ for updates
2542 $COPYRIGHT = 'Copyright 2005-2024 Andy Lester.';
2544 our $STANDALONE = 0;
2545 our $ORIGINAL_PROGRAM_NAME;
2559 our $is_filter_mode;
2560 our $output_to_pipe;
2564 our $debug_nopens = 0;
2566 # Line ending, changes to "\0" if --print0.
2570 # These have to be checked before any filehandle diddling.
2571 $output_to_pipe = not -t
*STDOUT
;
2572 $is_filter_mode = -p STDIN
;
2574 $is_windows = ($^O eq 'MSWin32');
2579 return CORE
::warn( _my_program
(), ': ', @_, "\n" );
2584 return CORE
::die( _my_program
(), ': ', @_, "\n" );
2588 require File
::Basename
;
2589 return File
::Basename
::basename
( $0 );
2594 my $y = q{_ /|,\\'!.x',=(www)=, U };
2595 $y =~ tr/,x!w/\nOo_/;
2597 App
::Ack
::print( "$y ack $_[0]!\n" );
2605 3~!I#7#I"7#I!?!+!="+"="+!:!
2606 2?#I!7!I!?#I!7!I"+"=%+"=#
2607 1?"+!?*+!=#~"=!+#?"="+!
2608 0?"+!?"I"?&+!="~!=!~"=!+%="+"
2609 /I!+!?)+!?!+!=$~!=!~!="+!="+"?!="?!
2611 ,,!?%I"?(+$=$~!=#:"~$:!~!
2612 ,I!?!I!?"I"?!+#?"+!?!+#="~$:!~!:!~!:!,!:!,":#~!
2613 +I!?&+!="+!?#+$=!~":!~!:!~!:!,!:#,!:!,%:"
2614 *+!I!?!+$=!+!=!+!?$+#=!~":!~":#,$:",#:!,!:!
2615 *I!?"+!?!+!=$+!?#+#=#~":$,!:",!:!,&:"
2616 )I!?$=!~!=#+"?!+!=!+!=!~!="~!:!~":!,'.!,%:!~!
2617 (=!?"+!?!=!~$?"+!?!+!=#~"=",!="~$,$.",#.!:!=!
2618 (I"+"="~"=!+&=!~"=!~!,!~!+!=!?!+!?!=!I!?!+"=!.",!.!,":!
2619 %I$?!+!?!=%+!~!+#~!=!~#:#=!~!+!~!=#:!,%.!,!.!:"
2620 $I!?!=!?!I!+!?"+!=!~!=!~!?!I!?!=!+!=!~#:",!~"=!~!:"~!=!:",&:" '-/
2621 $?!+!I!?"+"=!+"~!,!:"+#~#:#,"=!~"=!,!~!,!.",!:".!:! */! !I!t!'!s! !a! !g!r!e!p!!! !/!
2622 $+"=!+!?!+"~!=!:!~!:"I!+!,!~!=!:!~!,!:!,$:!~".&:"~!,# (-/
2623 %~!=!~!=!:!.!+"~!:!,!.!,!~!=!:$.!,":!,!.!:!~!,!:!=!.#="~!,!:" ./!
2624 %=!~!?!+"?"+!=!~",!.!:!?!~!.!:!,!:!,#.!,!:","~!:!=!~!=!:",!~! ./!
2625 %+"~":!~!=#~!:!~!,!.!~!:",!~!=!~!.!:!,!.",!:!,":!=":!.!,!:!7! -/!
2626 %~",!:".#:!=!:!,!:"+!:!~!:!.!,!~!,!.#,!.!,$:"~!,":"~!=! */!
2627 &=!~!=#+!=!~",!.!:",#:#,!.",+:!,!.",!=!+!?!
2628 &~!=!~!=!~!:"~#:",!.!,#~!:!.!+!,!.",$.",$.#,!+!I!?!
2629 &~!="~!:!~":!~",!~!=!~":!,!:!~!,!:!,&.$,#."+!?!I!?!I!
2630 &~!=!~!=!+!,!:!~!:!=!,!:!~&:$,!.!,".!,".!,#."~!+!?$I!
2631 &~!=!~!="~!=!:!~":!,!~%:#,!:",!.!,#.",#I!7"I!?!+!?"I"
2632 &+!I!7!:#~"=!~!:!,!:"~$.!=!.!,!~!,$.#,!~!7!I#?!+!?"I"7!
2633 %7#?!+!~!:!=!~!=!~":!,!:"~":#.!,)7#I"?"I!7&
2634 %7#I!=":!=!~!:"~$:"~!:#,!:!,!:!~!:#,!7#I!?#7)
2635 $7$+!,!~!=#~!:!~!:!~$:#,!.!~!:!=!,":!7#I"?#7+=!?!
2636 $7#I!~!,!~#=!~!:"~!:!,!:!,#:!=!~",":!7$I!?#I!7*+!=!+"
2637 "I!7$I!,":!,!.!=":$,!:!,$:$7$I!+!?"I!7+?"I!7!I!7!,!
2638 !,!7%I!:",!."~":!,&.!,!:!~!I!7$I!+!?"I!7,?!I!7',!
2639 !7(,!.#~":!,%.!,!7%I!7!?#I"7,+!?!7*
2640 7+:!,!~#,"=!7'I!?#I"7/+!7+
2641 77I!+!7!?!7!I"71+!7,
2644 return _pic_decode
($x);
2650 0|! "C!H!O!C!O!L!A!T!E!!! !|!
2651 0|! "C!H!O!C!O!L!A!T!E!!! !|!
2652 0|! "C!H!O!C!O!L!A!T!E!!! !|!
2658 4.! $\! /M!~!.!8! +.!M# 4
2659 0,!.! (\! .~!M!N! ,+!I!.!M!.! 3
2660 /?!O!.!M!:! '\! .O!.! +~!Z!=!N!.! 4
2661 ..! !D!Z!.!Z!.! '\! 9=!M".! 6
2662 /.! !.!~!M".! '\! 8~! 9
2664 4.! &:!M! !N"M# !M"N!M! #D!M&=! =
2665 :M!7!M#:! !~!M!7!,!$!M!:! #.! !O!N!.!M!:!M# ;
2666 8Z!M"~!N!$!D!.!N!?! !I!N!.! (?!M! !M!,!D!M".! 9
2667 (?!Z!M!N!:! )=!M!O!8!.!M!+!M! !M!,! !O!M! +,!M!.!M!~!Z!N!M!:! &:!~! 0
2668 &8!7!.!~!M"D!M!,! &M!?!=!8! !M!,!O! !M!+! !+!O!.!M! $M#~! !.!8!M!Z!.!M! !O!M"Z! %:!~!M!Z!M!Z!.! +
2669 &:!M!7!,! *M!.!Z!M! !8"M!.!M!~! !.!M!.!=! #~!8!.!M! !7!M! "N!Z#I! !D!M!,!M!.! $."M!,! !M!.! *
2670 2$!O! "N! !.!M!I! !7" "M! "+!O! !~!M! !d!O!.!7!I!M!.! !.!O!=!M!.! !M",!M!.! %.!$!O!D! +
2671 1~!O! "M!+! !8!$! "M! "?!O! %Z!8!D!M!?!8!I!O!7!M! #M!.!M! "M",!M! 4
2672 07!~! ".!8! !.!M! "I!+! !.!M! &Z!D!.!7!=!M! !:!.!M! #:!8"+! !.!+!8! !8! 3
2673 /~!M! #N! !~!M!$! !.!M! !.!M" &~!M! "~!M!O! "D! $M! !8! "M!,!M!+!D!.! 1
2674 #.! #?!M!N!.! #~!O! $M!.!7!$! "?" !?!~!M! '7!8!?!M!.!+!M"O! $?"$!D! !.!O! !$!7!I!.! 0
2675 $,!M!:!O!?! ".! !?!=! $=!:!O! !M! "M! !M! !+!$! (.! +.!M! !M!.! !8! !+"Z!~! $:!M!$! !.! '
2676 #.!8!.!I!$! $7!I! %M" !=!M! !~!M!D! "7!I! .I!O! %?!=!,!D! !,!M! !D!~!8!~! %D!M! (
2677 #.!M"?! $=!O! %=!N! "8!.! !Z!M! #M!~! (M!:! #.!M" &O! !M!.! !?!,! !8!.!N!~! $8!N!M!,!.! %
2678 *$!O! &M!,! "O! !.!M!.! #M! (~!M( &O!.! !7! "M! !.!M!.!M!,! #.!M! !M! &
2679 )=!8!.! $.!M!O!.! "$!.!I!N! !I!M# (7!M(I! %D"Z!M! "=!I! "M! !M!:! #~!D! '
2680 )D! &8!N!:! ".!O! !M!="M! "M! (7!M) %." !M!D!."M!.! !$!=! !M!,! +
2681 (M! &+!.!M! #Z!7!O!M!.!~!8! +,!M#D!?!M#D! #.!Z!M#,!Z!?! !~!N! "N!.! !M! +
2682 'D!:! %$!D! !?! #M!Z! !8!.! !M"?!7!?!7! '+!I!D! !?!O!:!M!:! ":!M!:! !M!7".!M! "8!+! !:!D! !.!M! *
2683 %.!O!:! $.!O!+! !D!.! #M! "M!.!+!N!I!Z! "7!M!N!M!N!?!I!7!Z!=!M'D"~! #M!.!8!$! !:! !.!M! "N!?! !,!O! )
2684 !.!?!M!:!M!I! %8!,! "M!.! #M! "N! !M!.! !M!.! !+!~! !.!M!.! ':!M! $M! $M!Z!$! !M!.! "D! "M! "?!M! (
2685 !7!8! !+!I! ".! "$!=! ":!$! "+! !M!.! !O! !M!I!M".! !=!~! ",!O! '=!M! $$!,! #N!:! ":!8!.! !D!~! !,!M!.! !:!M!.! &
2686 !:!,!.! &Z" #D! !.!8!."M!.! !8!?!Z!M!.!M! #Z!~! !?!M!Z!.! %~!O!.!8!$!N!8!O!I!:!~! !+! #M!.! !.!M!.! !+!M! ".!~!M!+! $
2687 !.! 'D!I! #?!M!.!M!,! !.!Z! !.!8! #M&O!I!?! (~!I!M"." !M!Z!.! !M!N!.! "+!$!.! "M!.! !M!?!.! "8!M! $
2688 (O!8! $M! !M!.! ".!:! !+!=! #M! #.!M! !+" *$!M":!.! !M!~! "M!7! #M! #7!Z! "M"$!M!.! !.! #
2689 '$!Z! #.!7!+!M! $.!,! !+!:! #N! #.!M!.!+!M! +D!M! #=!N! ":!O! #=!M! #Z!D! $M!I! %
2690 $,! ".! $.!M" %$!.! !?!~! "+!7!." !.!M!,! !M! *,!N!M!.$M!?! "D!,! #M!.! #N! +
2691 ,M!Z! &M! "I!,! "M! %I!M! !?!=!.! (Z!8!M! $:!M!.! !,!M! $D! #.!M!.! )
2692 +8!O! &.!8! "I!,! !~!M! &N!M! !M!D! '?!N!O!." $?!7! "?!~! #M!.! #I!D!.! (
2693 3M!,! "N!.! !D" &.!+!M!.! !M":!.":!M!7!M!D! 'M!.! "M!.! "M!,! $I! )
2694 3I! #M! "M!,! !:! &.!M" ".!,! !.!$!M!I! #.! !:! !.!M!?! "N!+! ".! /
2695 1M!,! #.!M!8!M!=!.! +~!N"O!Z"~! *+!M!.! "M! 2
2696 0.!M! &M!.! 8:! %.!M!Z! "M!=! *O!,! %
2697 0?!$! &N! )." .,! %."M! ":!M!.! 0
2698 0N!:! %?!O! #.! ..! &,! &.!D!,! "N!I! 0
2700 return _pic_decode
($x);
2704 my($compressed) = @_;
2705 $compressed =~ s/(.)(.)/$1x(ord($2)-32)/eg;
2706 App
::Ack
::print( $compressed );
2712 App
::Ack
::print( <<"END_OF_HELP" );
2713 Usage: ack [OPTION]... PATTERN [FILES OR DIRECTORIES]
2715 Search for PATTERN in each source file in the tree from the current
2716 directory on down. If any files or directories are specified, then
2717 only those files and directories are checked. ack may also search
2718 STDIN, but only if no file or directory arguments are specified,
2719 or if one of them is "-".
2721 Default switches may be specified in an .ackrc file. If you want no dependency
2722 on the environment, turn it off with --noenv.
2724 File select actions:
2725 -f Only print the files selected, without
2726 searching. The PATTERN must not be specified.
2727 -g Same as -f, but only select files matching
2730 File listing actions:
2731 -l, --files-with-matches Print filenames with at least one match
2732 -L, --files-without-matches Print filenames with no matches
2733 -c, --count Print filenames and count of matching lines
2736 -i, --ignore-case Ignore case distinctions in PATTERN
2737 -S, --[no]smart-case Ignore case distinctions in PATTERN,
2738 only if PATTERN contains no upper case.
2739 Ignored if -i or -I are specified.
2740 -I, --no-ignore-case Turns on case-sensitivity in PATTERN.
2741 Negates -i and --smart-case.
2742 -v, --invert-match Invert match: select non-matching lines
2743 -w, --word-regexp Force PATTERN to match only whole words
2744 -Q, --literal Quote all metacharacters; PATTERN is literal
2745 --range-start PATTERN Specify PATTERN as the start of a match range.
2746 --range-end PATTERN Specify PATTERN as the end of a match range.
2747 --match PATTERN Specify PATTERN explicitly. Typically omitted.
2748 --and PATTERN Specifies PATTERN that MUST also be found on
2749 the line for a match to occur. Repeatable.
2750 --or PATTERN Specifies PATTERN that MAY also be found on
2751 the line for a match to occur. Repeatable.
2752 --not PATTERN Specifies PATTERN that must NOT be found on
2753 the line for a match to occur. Repeatable.
2756 --output=expr Output the evaluation of expr for each line
2757 (turns off text highlighting)
2758 -o Show only the part of a line matching PATTERN
2759 Same as --output='\$&'
2760 --passthru Print all lines, whether matching or not
2761 -m, --max-count=NUM Stop searching in each file after NUM matches
2762 -1 Stop searching after one match of any kind
2763 -H, --with-filename Print the filename for each match (default:
2764 on unless explicitly searching a single file)
2765 -h, --no-filename Suppress the prefixing filename on output
2766 --[no]column Show the column number of the first match
2768 -A NUM, --after-context=NUM Print NUM lines of trailing context after
2770 -B NUM, --before-context=NUM Print NUM lines of leading context before
2772 -C [NUM], --context[=NUM] Print NUM lines (default 2) of output context.
2774 --print0 Print null byte as separator between filenames,
2775 only works with -f, -g, -l, -L or -c.
2777 -s Suppress error messages about nonexistent or
2782 --pager=COMMAND Pipes all ack output through COMMAND. For
2783 example, --pager="less -R". Ignored if output
2785 --nopager Do not send output through a pager. Cancels
2786 any setting in ~/.ackrc, ACK_PAGER or
2788 --[no]heading Print a filename heading above each file's
2789 results. (default: on when used interactively)
2790 --[no]break Print a break between results from different
2791 files. (default: on when used interactively)
2792 --group Same as --heading --break
2793 --nogroup Same as --noheading --nobreak
2794 -p, --proximate=LINES Separate match output with blank lines unless
2795 they are within LINES lines from each other.
2796 -P, --proximate=0 Negates --proximate.
2797 --[no]underline Print a line of carets under the matched text.
2798 --[no]color, --[no]colour Highlight the matching text (default: on unless
2799 output is redirected, or on Windows)
2800 --color-filename=COLOR
2803 --color-lineno=COLOR Set the color for filenames, matches, line and
2805 --help-colors Show a list of possible color combinations.
2806 --help-rgb-colors Show a list of advanced RGB colors.
2807 --flush Flush output immediately, even when ack is used
2808 non-interactively (when output goes to a pipe or
2813 --sort-files Sort the found files lexically.
2814 --show-types Show which types each file has.
2815 --files-from=FILE Read the list of files to search from FILE.
2816 -x Read the list of files to search from STDIN.
2818 File inclusion/exclusion:
2819 --[no]ignore-dir=name Add/remove directory from list of ignored dirs
2820 --[no]ignore-directory=name Synonym for ignore-dir
2821 --ignore-file=FILTER:ARGS Add filter for ignoring files.
2822 -r, -R, --recurse Recurse into subdirectories (default: on)
2823 -n, --no-recurse No descending into subdirectories
2824 --[no]follow Follow symlinks. Default is off.
2826 File type inclusion/exclusion:
2827 -t X, --type=X Include only X files, where X is a filetype,
2828 e.g. python, html, markdown, etc
2829 -T X, --type=noX Exclude X files, where X is a filetype.
2830 -k, --known-types Include only files of types that ack recognizes.
2831 --help-types Display all known types, and how they're defined.
2833 File type specification:
2834 --type-set=TYPE:FILTER:ARGS Files with the given ARGS applied to the given
2835 FILTER are recognized as being of type TYPE.
2836 This replaces an existing definition for TYPE.
2837 --type-add=TYPE:FILTER:ARGS Files with the given ARGS applied to the given
2838 FILTER are recognized as being type TYPE.
2839 --type-del=TYPE Removes all filters associated with TYPE.
2842 --version Display version & copyright
2843 --[no]env Ignore environment variables and global ackrc
2844 files. --env is legal but redundant.
2845 --ackrc=filename Specify an ackrc file to use
2846 --ignore-ack-defaults Ignore default definitions included with ack.
2847 --create-ackrc Outputs a default ackrc for your customization
2849 --dump Dump information on which options are loaded
2850 and where they're defined.
2851 --[no]filter Force ack to treat standard input as a pipe
2852 (--filter) or tty (--nofilter)
2854 --man Print the manual.
2855 --help-types Display all known types, and how they're defined.
2856 --help-colors Show a list of possible color combinations.
2857 --help-rgb-colors Show a list of advanced RGB colors.
2858 --thpppt Bill the Cat
2859 --bar The warning admiral
2860 --cathy Chocolate! Chocolate! Chocolate!
2862 Filter specifications:
2863 If FILTER is "ext", ARGS is a list of extensions checked against the
2865 If FILTER is "is", ARGS must match the file's name exactly.
2866 If FILTER is "match", ARGS is matched as a case-insensitive regex
2867 against the filename.
2868 If FILTER is "firstlinematch", ARGS is matched as a regex the first
2869 line of the file's contents.
2871 Exit status is 0 if match, 1 if no match.
2873 ack's home page is at https://beyondgrep.com/
2875 The full ack manual is available by running "ack --man".
2877 This is version $App::Ack::VERSION of ack. Run "ack --version" for full version info.
2885 sub show_help_types
{
2886 App
::Ack
::print( <<'END_OF_HELP' );
2887 Usage: ack [OPTION]... PATTERN [FILES OR DIRECTORIES]
2889 The following is the list of filetypes supported by ack. You can specify a
2890 filetype to include with -t TYPE or --type=TYPE. You can exclude a
2891 filetype with -T TYPE or --type=noTYPE.
2893 Note that some files may appear in multiple types. For example, a file
2894 called Rakefile is both Ruby (--type=ruby) and Rakefile (--type=rakefile).
2898 my @types = keys %App::Ack
::mappings
;
2901 $maxlen = length if $maxlen < length;
2903 for my $type ( sort @types ) {
2904 next if $type =~ /^-/; # Stuff to not show
2905 my $ext_list = $mappings{$type};
2907 if ( ref $ext_list ) {
2908 $ext_list = join( '; ', map { $_->to_string } @{$ext_list} );
2910 App
::Ack
::print( sprintf( " %-*.*s %s\n", $maxlen, $maxlen, $type, $ext_list ) );
2918 sub show_help_colors
{
2919 App
::Ack
::print( <<'END_OF_HELP' );
2920 ack allows customization of the colors it uses when presenting matches
2921 onscreen. See the "ACK COLORS" section of the ack manual (ack --man).
2923 Here is a chart of how various color combinations appear: Each of the eight
2924 foreground colors, on each of the eight background colors or no background
2925 color, with and without the bold modifier.
2927 Run ack --help-rgb-colors for a chart of the RGB colors.
2939 App
::Ack
::print( <<'END_OF_HELP' );
2940 ack allows customization of the colors it uses when presenting matches
2941 onscreen. See the "ACK COLORS" section of the ack manual (ack --man).
2943 Colors may be specified as "rgbNNN" where "NNN" is a triplet of digits
2944 from 0 to 5 specifying the intensity of red, green and blue, respectively.
2946 Here is a grid of the 216 possible values for NNN.
2952 App
::Ack
::say( 'Here are the 216 possible colors with the "reverse" modifier applied.', "\n" );
2954 _show_rgb_grid
( 'reverse' );
2960 sub _show_color_grid
{
2963 my @fg_colors = qw( black red green yellow blue magenta cyan white );
2964 my @bg_colors = map { "on_$_" } @fg_colors;
2968 map { _color_cell
( $_ ) } @fg_colors
2973 map { _color_cell
( '-' x
$cell_width ) } @fg_colors
2976 for my $bg ( '', @bg_colors ) {
2979 ( map { _color_cell
( $_, "$_ $bg" ) } @fg_colors ),
2984 _color_cell
( 'bold' ),
2985 ( map { _color_cell
( $_, "bold $_ $bg" ) } @fg_colors ),
3000 $text = sprintf( '%-*s', $cell_width, $text );
3002 return ($color ? Term
::ANSIColor
::colored
( $text, $color ) : $text) . ' ';
3006 sub _show_rgb_grid
{
3007 my $modifier = shift // '';
3009 my $grid = <<'HERE';
3010 544 544 544 544 544 554 554 554 554 554 454 454 454 454 454 455 455 455 455 455 445 445 445 445 445 545 545 545 545 545
3011 533 533 533 543 543 553 553 553 453 453 353 353 353 354 354 355 355 355 345 345 335 335 335 435 435 535 535 535 534 534
3012 511 521 531 531 541 551 451 451 351 251 151 152 152 153 154 155 145 145 135 125 115 215 215 315 415 515 514 514 513 512
3013 500 510 520 530 540 550 450 350 250 150 050 051 052 053 054 055 045 035 025 015 005 105 205 305 405 505 504 503 502 501
3014 400 410 410 420 430 440 340 340 240 140 040 041 041 042 043 044 034 034 024 014 004 104 104 204 304 404 403 403 402 401
3015 300 300 310 320 320 330 330 230 130 130 030 030 031 032 032 033 033 023 013 013 003 003 103 203 203 303 303 302 301 301
3016 200 200 200 210 210 220 220 220 120 120 020 020 020 021 021 022 022 022 012 012 002 002 002 102 102 202 202 202 201 201
3017 100 100 100 100 100 110 110 110 110 110 010 010 010 010 010 011 011 011 011 011 001 001 001 001 001 101 101 101 101 101
3019 522 522 532 542 542 552 552 452 352 352 252 252 253 254 254 255 255 245 235 235 225 225 325 425 425 525 525 524 523 523
3021 411 411 421 431 431 441 441 341 241 241 141 141 142 143 143 144 144 134 124 124 114 114 214 314 314 414 414 413 412 412
3023 422 422 432 432 432 442 442 442 342 342 242 242 242 243 243 244 244 244 234 234 224 224 224 324 324 424 424 424 423 423
3025 311 311 311 321 321 331 331 331 231 231 131 131 131 132 132 133 133 133 123 123 113 113 113 213 213 313 313 313 312 312
3027 433 433 433 433 433 443 443 443 443 443 343 343 343 343 343 344 344 344 344 344 334 334 334 334 334 434 434 434 434 434
3028 211 211 211 211 211 221 221 221 221 221 121 121 121 121 121 122 122 122 122 122 112 112 112 112 112 212 212 212 212 212
3030 322 322 322 322 322 332 332 332 332 332 232 232 232 232 232 233 233 233 233 233 223 223 223 223 223 323 323 323 323 323
3032 555 555 555 555 555 555 555 555 555 555 555 555 555 555 555 555 555 555 555 555 555 555 555 555 555 555 555 555 555 555
3033 444 444 444 444 444 444 444 444 444 444 444 444 444 444 444 444 444 444 444 444 444 444 444 444 444 444 444 444 444 444
3034 333 333 333 333 333 333 333 333 333 333 333 333 333 333 333 333 333 333 333 333 333 333 333 333 333 333 333 333 333 333
3035 222 222 222 222 222 222 222 222 222 222 222 222 222 222 222 222 222 222 222 222 222 222 222 222 222 222 222 222 222 222
3036 111 111 111 111 111 111 111 111 111 111 111 111 111 111 111 111 111 111 111 111 111 111 111 111 111 111 111 111 111 111
3037 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000
3040 $grid =~ s/(\d\d\d)/Term::ANSIColor::colored( "$1", "$modifier rgb$1" )/eg;
3042 App
::Ack
::say( $grid );
3050 Pod
::Usage
::pod2usage
({
3051 -input
=> $App::Ack
::ORIGINAL_PROGRAM_NAME
,
3061 sub get_version_statement
{
3064 my $copyright = $App::Ack
::COPYRIGHT
;
3065 my $this_perl = $Config::Config
{perlpath
};
3067 my $ext = $Config::Config
{_exe
};
3068 $this_perl .= $ext unless $this_perl =~ m/$ext$/i;
3070 my $perl_ver = sprintf( 'v%vd', $^V );
3072 my $build_type = $App::Ack
::STANDALONE
? 'standalone version' : 'standard build';
3074 return <<"END_OF_VERSION";
3075 ack $App::Ack::VERSION ($build_type)
3076 Running under Perl $perl_ver at $this_perl
3080 This program is free software. You may modify or distribute it
3081 under the terms of the Artistic License v2.0.
3086 sub print { print {$fh} @_; return; }
3087 sub say { print {$fh} @_, $ors; return; }
3088 sub print_blank_line
{ print {$fh} "\n"; return; }
3091 my $command = shift;
3093 return if App
::Ack
::output_to_pipe
();
3096 if ( not open( $pager, '|-', $command ) ) {
3097 App
::Ack
::die( qq{Unable to pipe to pager "$command": $!} );
3105 sub output_to_pipe
{
3106 return $output_to_pipe;
3111 my $nmatches = shift;
3113 my $rc = $nmatches ? 0 : 1;
3121 my @types = filetypes
( $file );
3122 my $arrow = @types ? ' => ' : ' =>';
3123 App
::Ack
::say( $file->name, $arrow, join( ',', @types ) );
3134 foreach my $k (keys %App::Ack
::mappings
) {
3135 my $filters = $App::Ack
::mappings
{$k};
3137 foreach my $filter (@{$filters}) {
3139 my $clone = $file->clone;
3140 if ( $filter->filter($clone) ) {
3147 # https://metacpan.org/pod/distribution/Perl-Critic/lib/Perl/Critic/Policy/Subroutines/ProhibitReturnSort.pm
3148 @matches = sort @matches;
3156 # The simplest case.
3157 return 1 if lc($pat) eq $pat;
3159 # If we have capitals, then go clean up any metacharacters that might have capitals.
3161 # Get rid of any literal backslashes first to avoid confusion.
3164 my $metacharacter = qr{
3165 |\\A
# Beginning of string
3166 |\\B
# Not word boundary
3167 |\\c
[a-zA-Z
] # Control characters
3168 |\\D
# Non-digit character
3169 |\\G
# End-of-match position of prior match
3170 |\\H
# Not horizontal whitespace
3171 |\\K
# Keep to the left
3172 |\\N
(\
{.+?\
})? # Anything but \n, OR Unicode sequence
3173 |\\[pP
]\
{.+?\
} # Named property and negation
3174 |\\[pP
][A-Z
] # Named property and negation, single-character shorthand
3176 |\\S
# Non-space character
3177 |\\V
# Not vertical whitespace
3178 |\\W
# Non-word character
3180 |\\x
[0-9A-Fa-f
]{2} # Hex sequence
3181 |\\Z
# End of string
3183 $pat =~ s/$metacharacter//g;
3185 my $name = qr/[_A-Za-z][_A-Za-z0-9]*?/;
3186 # Eliminate named captures.
3187 $pat =~ s/\(\?'$name'//g;
3188 $pat =~ s/\(\?<$name>//g;
3190 # Eliminate named backreferences.
3191 $pat =~ s/\\k'$name'//g;
3192 $pat =~ s/\\k<$name>//g;
3193 $pat =~ s/\\k\{$name\}//g;
3195 # Now with those metacharacters and named things removed, now see if it's lowercase.
3196 return 1 if lc($pat) eq $pat;
3202 # Returns a regex object based on a string and command-line options.
3203 # Dies when the regex $str is undefined (i.e. not given on command line).
3209 # Check for lowercaseness before we do any modifications.
3210 my $regex_is_lc = App
::Ack
::is_lowercase
( $str );
3213 $str = quotemeta( $str );
3216 # Compile the regex to see if it dies or throws warnings.
3217 local $SIG{__WARN__
} = sub { CORE
::die @_ }; # Anything that warns becomes a die.
3218 my $scratch_regex = eval { qr/$str/ };
3219 if ( not $scratch_regex ) {
3223 if ( $err =~ m{^(.+?); marked by <-- HERE in m/(.+?) <-- HERE} ) {
3224 my ($why, $where) = ($1,$2);
3225 my $pointy = ' ' x
(6+length($where)) . '^---HERE';
3226 App
::Ack
::die( "Invalid regex '$str'\nRegex: $str\n$pointy $why" );
3229 App
::Ack
::die( "Invalid regex '$str'\n$err" );
3234 my $scan_str = $str;
3240 if ( $str =~ /^\\[wd]/ ) {
3241 # Explicit \w is good.
3244 # Can start with \w, (, [ or dot.
3245 if ( $str !~ /^[\w\(\[\.]/ ) {
3250 # Can end with \w, }, ), ], +, *, or dot.
3251 if ( $str !~ /[\w\}\)\]\+\*\?\.]$/ ) {
3254 # ... unless it's escaped.
3255 elsif ( $str =~ /\\[\}\)\]\+\*\?\.]$/ ) {
3260 App
::Ack
::die( '-w will not do the right thing if your regex does not begin and end with a word character.' );
3263 if ( $str =~ /^\w+$/ ) {
3264 # No need for fancy regex if it's a simple word.
3265 $str = sprintf( '\b(?:%s)\b', $str );
3268 $str = sprintf( '(?:^|\b|\s)\K(?:%s)(?=\s|\b|$)', $str );
3272 if ( $opt->{i
} || ($opt->{S
} && $regex_is_lc) ) {
3273 $_ = "(?i)$_" for ( $str, $scan_str );
3276 my $scan_regex = undef;
3277 my $regex = eval { qr/$str/ };
3279 if ( $scan_str !~ /\$/ ) {
3280 # No line_scan is possible if there's a $ in the regex.
3281 $scan_regex = eval { qr/$scan_str/m };
3287 App
::Ack
::die( "Invalid regex '$str':\n $err" );
3290 return ($regex, $scan_regex);
3294 sub build_all_regexes
{
3295 my $opt_regex = shift;
3305 # AND: alpha and beta
3306 if ( @parts = @{$opt->{and}} ) {
3310 for my $part ( @parts ) {
3311 my ($match, undef) = build_regex
( $part, $opt );
3312 push @match_parts, "(?=.*$match)";
3313 push @hilite_parts, $match;
3316 my ($match, $scan) = build_regex
( $opt_regex, $opt );
3317 push @match_parts, ".*$match";
3318 push @hilite_parts, $match;
3320 $re_match = join( '', @match_parts );
3321 $re_hilite = join( '|', @hilite_parts );
3325 elsif ( @parts = @{$opt->{or}} ) {
3329 for my $part ( $opt_regex, @parts ) {
3330 my ($match, $scan) = build_regex
( $part, $opt );
3331 push @match_parts, $match;
3332 push @scan_parts, $scan;
3335 $re_match = join( '|', @match_parts );
3336 $re_hilite = $re_match;
3337 $re_scan = join( '|', @scan_parts );
3339 # NOT: alpha NOT beta
3340 elsif ( @parts = @{$opt->{not}} ) {
3341 ($re_match, $re_scan) = build_regex
( $opt_regex, $opt );
3342 $re_hilite = $re_match;
3345 for my $part ( @parts ) {
3346 (my $re, undef) = build_regex
( $part, $opt );
3347 push @not_parts, $re;
3349 $re_not = join( '|', @not_parts );
3353 ($re_match, $re_scan) = build_regex
( $opt_regex, $opt );
3354 $re_hilite = $re_match;
3357 return ($re_match, $re_not, $re_hilite, $re_scan);
3361 1; # End of App::Ack
3364 package App
::Ack
::ConfigDefault
;
3373 return split( /\n/, _options_block
() );
3378 return grep { /./ && !/^#/ } options
();
3382 sub _options_block
{
3383 my $lines = <<'HERE';
3384 # This is the default ackrc for ack version ==VERSION==.
3386 # There are four different ways to match
3388 # is: Match the filename exactly
3390 # ext: Match the extension of the filename exactly
3392 # match: Match the filename against a Perl regular expression
3394 # firstlinematch: Match the first 250 characters of the first line
3395 # of text against a Perl regular expression. This is only for
3396 # the --type-add option.
3399 ### Directories to ignore
3402 # https://bazaar.canonical.com/
3403 --ignore-directory=is:.bzr
3406 # http://freshmeat.sourceforge.net/projects/codeville
3407 --ignore-directory=is:.cdv
3409 # Interface Builder (Xcode)
3410 # https://en.wikipedia.org/wiki/Interface_Builder
3411 --ignore-directory=is:~.dep
3412 --ignore-directory=is:~.dot
3413 --ignore-directory=is:~.nib
3414 --ignore-directory=is:~.plst
3417 # https://git-scm.com/
3418 --ignore-directory=is:.git
3419 # When submodules are used, .git is a file.
3420 --ignore-file=is:.git
3423 # https://www.mercurial-scm.org/
3424 --ignore-directory=is:.hg
3427 # https://directory.fsf.org/wiki/Quilt
3428 --ignore-directory=is:.pc
3431 # https://subversion.apache.org/
3432 --ignore-directory=is:.svn
3435 # https://www.monotone.ca/
3436 --ignore-directory=is:_MTN
3439 # https://savannah.nongnu.org/projects/cvs
3440 --ignore-directory=is:CVS
3443 # https://www.gnu.org/software/rcs/
3444 --ignore-directory=is:RCS
3447 # https://en.wikipedia.org/wiki/Source_Code_Control_System
3448 --ignore-directory=is:SCCS
3452 --ignore-directory=is:_darcs
3455 --ignore-directory=is:_sgbak
3458 # https://www.gnu.org/software/autoconf/
3459 --ignore-directory=is:autom4te.cache
3461 # Perl module building
3462 --ignore-directory=is:blib
3463 --ignore-directory=is:_build
3465 # Perl Devel::Cover module's output directory
3466 # https://metacpan.org/release/Devel-Cover
3467 --ignore-directory=is:cover_db
3469 # Node modules created by npm
3470 --ignore-directory=is:node_modules
3473 # https://www.cmake.org/
3474 --ignore-directory=is:CMakeFiles
3476 # Eclipse workspace folder
3477 # https://eclipse.org/
3478 --ignore-directory=is:.metadata
3480 # Cabal (Haskell) sandboxes
3481 # https://www.haskell.org/cabal/users-guide/installing-packages.html
3482 --ignore-directory=is:.cabal-sandbox
3485 # https://docs.python.org/3/tutorial/modules.html
3486 --ignore-directory=is:__pycache__
3487 --ignore-directory=is:.pytest_cache
3489 # macOS Finder remnants
3490 --ignore-directory=is:__MACOSX
3491 --ignore-file=is:.DS_Store
3496 --ignore-file=ext:bak
3497 --ignore-file=match:/~$/
3500 --ignore-file=match:/^#.+#$/
3502 # vi/vim swap files https://www.vim.org/
3503 --ignore-file=match:/[._].*[.]swp$/
3506 --ignore-file=match:/core[.]\d+$/
3508 # minified JavaScript
3509 --ignore-file=match:/[.-]min[.]js$/
3510 --ignore-file=match:/[.]js[.]min$/
3513 --ignore-file=match:/[.]min[.]css$/
3514 --ignore-file=match:/[.]css[.]min$/
3516 # JS and CSS source maps
3517 --ignore-file=match:/[.]js[.]map$/
3518 --ignore-file=match:/[.]css[.]map$/
3520 # PDFs, because they pass Perl's -T detection
3521 --ignore-file=ext:pdf
3523 # Common graphics, just as an optimization
3524 --ignore-file=ext:gif,jpg,jpeg,png
3526 # Common archives, as an optimization
3527 --ignore-file=ext:gz,tar,tgz,zip
3529 # Python compiled modules
3530 --ignore-file=ext:pyc,pyd,pyo
3532 # Python's pickle serialization format
3533 # https://docs.python.org/2/library/pickle.html#example
3534 # https://docs.python.org/3.7/library/pickle.html#examples
3535 --ignore-file=ext:pkl,pickle
3538 --ignore-file=ext:so
3540 # Compiled gettext files
3541 --ignore-file=ext:mo
3543 # Visual Studio user and workspace settings
3544 # https://code.visualstudio.com/docs/getstarted/settings
3545 --ignore-dir=is:.vscode
3547 ### Filetypes defined
3550 # https://www.gnu.org/s/make/
3551 --type-add=make:ext:mk
3552 --type-add=make:ext:mak
3553 --type-add=make:is:makefile
3554 --type-add=make:is:Makefile
3555 --type-add=make:is:Makefile.Debug
3556 --type-add=make:is:Makefile.Release
3557 --type-add=make:is:GNUmakefile
3560 # https://rake.rubyforge.org/
3561 --type-add=rake:is:Rakefile
3564 # https://cmake.org/
3565 --type-add=cmake:is:CMakeLists.txt
3566 --type-add=cmake:ext:cmake
3569 # https://docs.bazel.build/versions/master/skylark/bzl-style.html
3570 --type-add=bazel:ext:bzl
3571 # https://docs.bazel.build/versions/master/guide.html#bazelrc-the-bazel-configuration-file
3572 --type-add=bazel:ext:bazelrc
3573 # https://docs.bazel.build/versions/master/build-ref.html#BUILD_files
3574 --type-add=bazel:is:BUILD
3575 # https://docs.bazel.build/versions/master/build-ref.html#workspace
3576 --type-add=bazel:is:WORKSPACE
3580 --type-add=actionscript:ext:as,mxml
3583 # https://www.adaic.org/
3584 --type-add=ada:ext:ada,adb,ads
3587 # https://docs.microsoft.com/en-us/previous-versions/office/developer/server-technologies/aa286483(v=msdn.10)
3588 --type-add=asp:ext:asp
3591 # https://dotnet.microsoft.com/apps/aspnet
3592 --type-add=aspx:ext:master,ascx,asmx,aspx,svc
3595 --type-add=asm:ext:asm,s
3598 --type-add=batch:ext:bat,cmd
3601 # https://en.wikipedia.org/wiki/ColdFusion
3602 --type-add=cfmx:ext:cfc,cfm,cfml
3605 # https://clojure.org/
3606 --type-add=clojure:ext:clj,cljs,edn,cljc
3609 # .xs are Perl C files
3610 --type-add=cc:ext:c,h,xs
3616 # https://coffeescript.org/
3617 --type-add=coffeescript:ext:coffee
3620 --type-add=cpp:ext:cpp,cc,cxx,m,hpp,hh,h,hxx
3623 --type-add=hpp:ext:hpp,hh,h,hxx
3626 --type-add=csharp:ext:cs
3629 # https://crystal-lang.org/
3630 --type-add=crystal:ext:cr,ecr
3633 # https://www.w3.org/Style/CSS/
3634 --type-add=css:ext:css
3638 --type-add=dart:ext:dart
3641 # https://en.wikipedia.org/wiki/Embarcadero_Delphi
3642 --type-add=delphi:ext:pas,int,dfm,nfm,dof,dpk,dproj,groupproj,bdsgroup,bdsproj
3645 # https://elixir-lang.org/
3646 --type-add=elixir:ext:ex,exs
3649 # https://elm-lang.org
3650 --type-add=elm:ext:elm
3653 # https://www.gnu.org/software/emacs
3654 --type-add=elisp:ext:el
3657 # https://www.erlang.org/
3658 --type-add=erlang:ext:erl,hrl
3661 # https://en.wikipedia.org/wiki/Fortran
3662 --type-add=fortran:ext:f,f77,f90,f95,f03,for,ftn,fpp
3665 # https://golang.org/
3666 --type-add=go:ext:go
3669 # https://www.groovy-lang.org/
3670 --type-add=groovy:ext:groovy,gtmpl,gpp,grunit,gradle
3673 # https://gsp.grails.org/
3674 --type-add=gsp:ext:gsp
3677 # https://www.haskell.org/
3678 --type-add=haskell:ext:hs,lhs
3681 --type-add=html:ext:htm,html,xhtml
3684 # http://jade-lang.com/
3685 --type-add=jade:ext:jade
3688 # https://www.oracle.com/technetwork/java/index.html
3689 --type-add=java:ext:java,properties
3692 --type-add=js:ext:js
3695 # https://www.oracle.com/technetwork/java/javaee/jsp/index.html
3696 --type-add=jsp:ext:jsp,jspx,jspf,jhtm,jhtml
3700 --type-add=json:ext:json
3703 # https://kotlinlang.org/
3704 --type-add=kotlin:ext:kt,kts
3707 # http://www.lesscss.org/
3708 --type-add=less:ext:less
3711 # https://common-lisp.net/
3712 --type-add=lisp:ext:lisp,lsp
3715 # https://www.lua.org/
3716 --type-add=lua:ext:lua
3717 --type-add=lua:firstlinematch:/^#!.*\blua(jit)?/
3720 # https://en.wikipedia.org/wiki/Markdown
3721 --type-add=markdown:ext:md,markdown
3722 # We understand that there are many ad hoc extensions for markdown
3723 # that people use. .md and .markdown are the two that ack recognizes.
3724 # You are free to add your own in your ackrc file.
3727 # https://en.wikipedia.org/wiki/MATLAB
3728 --type-add=matlab:ext:m
3731 --type-add=objc:ext:m,h
3734 --type-add=objcpp:ext:mm,h
3737 # https://ocaml.org/
3738 --type-add=ocaml:ext:ml,mli,mll,mly
3742 --type-add=perl:ext:pl,pm,pod,t,psgi
3743 --type-add=perl:firstlinematch:/^#!.*\bperl/
3746 --type-add=perltest:ext:t
3748 # Perl's Plain Old Documentation format, POD
3749 --type-add=pod:ext:pod
3752 # https://www.php.net/
3753 --type-add=php:ext:php,phpt,php3,php4,php5,phtml
3754 --type-add=php:firstlinematch:/^#!.*\bphp/
3757 # https://plone.org/
3758 --type-add=plone:ext:pt,cpt,metadata,cpy,py
3761 # https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_scripts
3762 # https://learn.microsoft.com/en-us/powershell/scripting/developer/module/understanding-a-windows-powershell-module
3763 --type-add=powershell:ext:ps1,psm1
3766 # https://www.purescript.org
3767 --type-add=purescript:ext:purs
3770 # https://www.python.org/
3771 --type-add=python:ext:py
3772 --type-add=python:firstlinematch:/^#!.*\bpython/
3775 # https://pytest.org/
3776 # Pytest files are *.py files that start with test_ or end with _test.py
3777 # https://docs.pytest.org/en/stable/explanation/goodpractices.html#test-discovery
3778 --type-add=pytest:match:_test\.py$
3779 --type-add=pytest:match:^test_.*\.py$
3782 # https://www.r-project.org/
3783 # https://r4ds.had.co.nz/r-markdown.html
3784 --type-add=rr:ext:R,Rmd
3787 # https://docutils.sourceforge.io/rst.html
3788 --type-add=rst:ext:rst
3791 # https://www.ruby-lang.org/
3792 --type-add=ruby:ext:rb,rhtml,rjs,rxml,erb,rake,spec
3793 --type-add=ruby:is:Rakefile
3794 --type-add=ruby:firstlinematch:/^#!.*\bruby/
3797 # https://www.rust-lang.org/
3798 --type-add=rust:ext:rs
3801 # https://sass-lang.com
3802 --type-add=sass:ext:sass,scss
3805 # https://www.scala-lang.org/
3806 --type-add=scala:ext:scala,sbt
3809 # https://groups.csail.mit.edu/mac/projects/scheme/
3810 --type-add=scheme:ext:scm,ss
3813 --type-add=shell:ext:sh,bash,csh,tcsh,ksh,zsh,fish
3814 --type-add=shell:firstlinematch:/^#!.*\b(?:ba|t?c|k|z|fi)?sh\b/
3817 # http://www.smalltalk.org/
3818 --type-add=smalltalk:ext:st
3821 # https://www.smarty.net/
3822 --type-add=smarty:ext:tpl
3825 # https://www.iso.org/standard/45498.html
3826 --type-add=sql:ext:sql,ctl
3829 # http://stylus-lang.com/
3830 --type-add=stylus:ext:styl
3833 # https://en.wikipedia.org/wiki/Scalable_Vector_Graphics
3834 --type-add=svg:ext:svg
3837 # https://developer.apple.com/swift/
3838 --type-add=swift:ext:swift
3839 --type-add=swift:firstlinematch:/^#!.*\bswift/
3842 # https://www.tcl.tk/
3843 --type-add=tcl:ext:tcl,itcl,itk
3846 # https://github.com/hashicorp/terraform
3847 --type-add=terraform=.tf,.tfvars
3850 # https://www.latex-project.org/
3851 --type-add=tex:ext:tex,cls,sty
3853 # Template Toolkit (Perl)
3854 # http//template-toolkit.org/
3855 --type-add=ttml:ext:tt,tt2,ttml
3859 --type-add=toml:ext:toml
3862 # https://www.typescriptlang.org/
3863 --type-add=ts:ext:ts,tsx
3866 --type-add=vb:ext:bas,cls,frm,ctl,vb,resx
3869 --type-add=verilog:ext:v,vh,sv
3872 # http://www.eda.org/twiki/bin/view.cgi/P1076/WebHome
3873 --type-add=vhdl:ext:vhd,vhdl
3876 # https://www.vim.org/
3877 --type-add=vim:ext:vim
3880 # https://www.w3.org/TR/REC-xml/
3881 --type-add=xml:ext:xml,dtd,xsd,xsl,xslt,ent,wsdl
3882 --type-add=xml:firstlinematch:/<[?]xml/
3886 --type-add=yaml:ext:yaml,yml
3888 $lines =~ s/==VERSION==/$App::Ack::VERSION/sm;
3896 package App
::Ack
::ConfigFinder
;
3903 use File
::Spec
3.00 ();
3905 use if ($^O eq 'MSWin32'), 'Win32';
3911 return bless {}, $class;
3915 sub _remove_redundancies
{
3920 foreach my $config (@configs) {
3921 my $path = $config->{path
};
3922 my $key = -e
$path ? Cwd
::realpath
( $path ) : $path;
3923 if ( not $App::Ack
::is_windows
) {
3924 # On Unix, uniquify on inode.
3925 my ($dev, $inode) = (stat $key)[0, 1];
3926 $key = "$dev:$inode" if defined $dev;
3928 push( @uniq, $config ) unless $seen{$key}++;
3934 sub _check_for_ackrc
{
3935 return unless defined $_[0];
3937 my @files = grep { -f
}
3938 map { File
::Spec-
>catfile(@_, $_) }
3941 App
::Ack
::die( File
::Spec-
>catdir(@_) . ' contains both .ackrc and _ackrc. Please remove one of those files.' )
3944 return wantarray ? @files : $files[0];
3945 } # end _check_for_ackrc
3949 sub find_config_files
{
3952 if ( $App::Ack
::is_windows
) {
3953 push @config_files, map { +{ path
=> File
::Spec-
>catfile($_, 'ackrc') } } (
3954 Win32
::GetFolderPath
(Win32
::CSIDL_COMMON_APPDATA
()),
3955 Win32
::GetFolderPath
(Win32
::CSIDL_APPDATA
()),
3959 push @config_files, { path
=> '/etc/ackrc' };
3963 if ( $ENV{'ACKRC'} && -f
$ENV{'ACKRC'} ) {
3964 push @config_files, { path
=> $ENV{'ACKRC'} };
3967 push @config_files, map { +{ path
=> $_ } } _check_for_ackrc
($ENV{'HOME'});
3970 my $cwd = Cwd
::getcwd
();
3971 return () unless defined $cwd;
3973 # XXX This should go through some untainted cwd-fetching function, and not get untainted brute-force like this.
3976 my @dirs = File
::Spec-
>splitdir( $cwd );
3978 my $ackrc = _check_for_ackrc
(@dirs);
3979 if ( defined $ackrc ) {
3980 push @config_files, { project
=> 1, path
=> $ackrc };
3986 # We only test for existence here, so if the file is deleted out from under us, this will fail later.
3987 return _remove_redundancies
( @config_files );
3993 package App
::Ack
::ConfigLoader
;
3999 use File
::Spec
3.00 ();
4000 use Getopt
::Long
2.38 ();
4001 use Text
::ParseWords
3.1 ();
4003 sub configure_parser
{
4013 Getopt
::Long
::Configure
( @standard, @opts );
4019 sub _generate_ignore_dir
{
4020 my ( $option_name, $opt ) = @_;
4022 my $is_inverted = $option_name =~ /^--no/;
4025 my ( undef, $dir ) = @_;
4027 $dir = _remove_directory_separator
( $dir );
4028 if ( $dir !~ /:/ ) {
4029 $dir = 'is:' . $dir;
4032 my ( $filter_type, $args ) = split /:/, $dir, 2;
4034 if ( $filter_type eq 'firstlinematch' ) {
4035 App
::Ack
::die( qq{Invalid filter specification "$filter_type" for option '$option_name'} );
4038 my $filter = App
::Ack
::Filter-
>create_filter($filter_type, split(/,/, $args));
4041 my $previous_inversion_matches = $opt->{idirs
} && !($is_inverted xor $opt->{idirs
}[-1]->is_inverted());
4043 if ( $previous_inversion_matches ) {
4044 $collection = $opt->{idirs
}[-1];
4046 if ( $is_inverted ) {
4047 # This relies on invert of an inverted filter to return the original.
4048 $collection = $collection->invert();
4052 $collection = App
::Ack
::Filter
::Collection-
>new();
4053 push @{ $opt->{idirs
} }, $is_inverted ? $collection->invert() : $collection;
4056 $collection->add($filter);
4058 if ( $filter_type eq 'is' ) {
4059 $collection->add(App
::Ack
::Filter
::IsPath-
>new($args));
4065 sub _remove_directory_separator
{
4068 state $dir_sep_chars = $App::Ack
::is_windows
? quotemeta( '\\/' ) : quotemeta( File
::Spec-
>catfile( '', '' ) );
4070 $path =~ s/[$dir_sep_chars]$//;
4076 sub _process_filter_spec
{
4079 if ( $spec =~ /^(\w+):(\w+):(.*)/ ) {
4080 my ( $type_name, $ext_type, $arguments ) = ( $1, $2, $3 );
4082 return ( $type_name,
4083 App
::Ack
::Filter-
>create_filter($ext_type, split(/,/, $arguments)) );
4085 elsif ( $spec =~ /^(\w+)=(.*)/ ) { # Check to see if we have ack1-style argument specification.
4086 my ( $type_name, $extensions ) = ( $1, $2 );
4088 my @extensions = split(/,/, $extensions);
4089 foreach my $extension ( @extensions ) {
4090 $extension =~ s/^[.]//;
4093 return ( $type_name, App
::Ack
::Filter-
>create_filter('ext', @extensions) );
4096 App
::Ack
::die( "Invalid filter specification '$spec'" );
4101 sub _uninvert_filter
{
4102 my ( $opt, @filters ) = @_;
4104 return unless defined $opt->{filters
} && @filters;
4106 # Loop through all the registered filters. If we hit one that
4107 # matches this extension and it's inverted, we need to delete it from
4109 for ( my $i = 0; $i < @{ $opt->{filters
} }; $i++ ) {
4110 my $opt_filter = @{ $opt->{filters
} }[$i];
4112 # XXX Do a real list comparison? This just checks string equivalence.
4113 if ( $opt_filter->is_inverted() && "$opt_filter->{filter}" eq "@filters" ) {
4114 splice @{ $opt->{filters
} }, $i, 1;
4123 sub _process_filetypes
{
4124 my ( $opt, $arg_sources ) = @_;
4126 my %additional_specs;
4128 my $add_spec = sub {
4129 my ( undef, $spec ) = @_;
4131 my ( $name, $filter ) = _process_filter_spec
($spec);
4133 push @{ $App::Ack
::mappings
{$name} }, $filter;
4135 $additional_specs{$name . '!'} = sub {
4136 my ( undef, $value ) = @_;
4138 my @filters = @{ $App::Ack
::mappings
{$name} };
4140 @filters = map { $_->invert() } @filters;
4143 _uninvert_filter
( $opt, @filters );
4146 push @{ $opt->{'filters'} }, @filters;
4150 my $set_spec = sub {
4151 my ( undef, $spec ) = @_;
4153 my ( $name, $filter ) = _process_filter_spec
($spec);
4155 $App::Ack
::mappings
{$name} = [ $filter ];
4157 $additional_specs{$name . '!'} = sub {
4158 my ( undef, $value ) = @_;
4160 my @filters = @{ $App::Ack
::mappings
{$name} };
4162 @filters = map { $_->invert() } @filters;
4165 push @{ $opt->{'filters'} }, @filters;
4169 my $delete_spec = sub {
4170 my ( undef, $name ) = @_;
4172 delete $App::Ack
::mappings
{$name};
4173 delete $additional_specs{$name . '!'};
4176 my %type_arg_specs = (
4177 'type-add=s' => $add_spec,
4178 'type-set=s' => $set_spec,
4179 'type-del=s' => $delete_spec,
4182 configure_parser
( 'no_auto_abbrev', 'pass_through' );
4183 foreach my $source (@{$arg_sources}) {
4184 my $args = $source->{contents
};
4187 # $args are modified in place, so no need to munge $arg_sources
4188 Getopt
::Long
::GetOptionsFromArray
( $args, %type_arg_specs );
4191 ( undef, $source->{contents
} ) =
4192 Getopt
::Long
::GetOptionsFromString
( $args, %type_arg_specs );
4196 $additional_specs{'k|known-types'} = sub {
4197 my @filters = map { @{$_} } values(%App::Ack
::mappings
);
4199 push @{ $opt->{'filters'} }, @filters;
4202 return \
%additional_specs;
4207 my ( $opt, $extra_specs ) = @_;
4211 my ( $getopt, $value ) = @_;
4214 if ( $value =~ s/^no// ) {
4221 $callback = $extra_specs->{ $value . '!' };
4225 $callback->( $getopt, $cb_value );
4228 App
::Ack
::die( "Unknown type '$value'" );
4239 1 => sub { $opt->{1} = $opt->{m
} = 1 },
4240 'and=s' => $opt->{and},
4241 'A|after-context:-1' => sub { shift; $opt->{A
} = _context_value
(shift) },
4242 'B|before-context:-1' => sub { shift; $opt->{B
} = _context_value
(shift) },
4243 'C|context:-1' => sub { shift; $opt->{B
} = $opt->{A
} = _context_value
(shift) },
4244 'break!' => \
$opt->{break},
4245 'c|count' => \
$opt->{c
},
4246 'color|colour!' => \
$opt->{color
},
4247 'color-match=s' => \
$ENV{ACK_COLOR_MATCH
},
4248 'color-filename=s' => \
$ENV{ACK_COLOR_FILENAME
},
4249 'color-colno=s' => \
$ENV{ACK_COLOR_COLNO
},
4250 'color-lineno=s' => \
$ENV{ACK_COLOR_LINENO
},
4251 'column!' => \
$opt->{column
},
4252 'create-ackrc' => sub { say for ( '--ignore-ack-defaults', App
::Ack
::ConfigDefault
::options
() ); exit; },
4253 'debug' => \
$opt->{debug
},
4255 my ( undef, $value ) = @_;
4258 $opt->{noenv_seen
} = 1;
4262 'files-from=s' => \
$opt->{files_from
},
4263 'filter!' => \
$App::Ack
::is_filter_mode
,
4264 flush
=> sub { $| = 1 },
4265 'follow!' => \
$opt->{follow
},
4267 'group!' => sub { shift; $opt->{heading
} = $opt->{break} = shift },
4268 'heading!' => \
$opt->{heading
},
4269 'h|no-filename' => \
$opt->{h
},
4270 'H|with-filename' => \
$opt->{H
},
4271 'i|ignore-case' => sub { $opt->{i
} = 1; $opt->{S
} = 0; },
4272 'I|no-ignore-case' => sub { $opt->{i
} = 0; $opt->{S
} = 0; },
4273 'ignore-directory|ignore-dir=s' => _generate_ignore_dir
('--ignore-dir', $opt),
4274 'ignore-file=s' => sub {
4275 my ( undef, $file ) = @_;
4277 my ( $filter_type, $args ) = split /:/, $file, 2;
4279 my $filter = App
::Ack
::Filter-
>create_filter($filter_type, split(/,/, $args//''));
4281 if ( !$opt->{ifiles
} ) {
4282 $opt->{ifiles
} = App
::Ack
::Filter
::Collection-
>new();
4284 $opt->{ifiles
}->add($filter);
4286 'l|files-with-matches'
4288 'L|files-without-matches'
4290 'm|max-count=i' => \
$opt->{m
},
4291 'match=s' => \
$opt->{regex
},
4292 'n|no-recurse' => \
$opt->{n
},
4293 o
=> sub { $opt->{output
} = '$&' },
4294 'output=s' => \
$opt->{output
},
4296 my ( undef, $value ) = @_;
4298 $opt->{pager
} = $value || $ENV{PAGER
};
4300 'noignore-directory|noignore-dir=s' => _generate_ignore_dir
('--noignore-dir', $opt),
4301 'nopager' => sub { $opt->{pager
} = undef },
4302 'not=s' => $opt->{not},
4303 'or=s' => $opt->{or},
4304 'passthru' => \
$opt->{passthru
},
4305 'print0' => \
$opt->{print0
},
4306 'p|proximate:1' => \
$opt->{p
},
4307 'P' => sub { $opt->{p
} = 0 },
4308 'Q|literal' => \
$opt->{Q
},
4309 'r|R|recurse' => sub { $opt->{n
} = 0 },
4310 'range-start=s' => \
$opt->{range_start
},
4311 'range-end=s' => \
$opt->{range_end
},
4312 'range-invert!' => \
$opt->{range_invert
},
4314 'show-types' => \
$opt->{show_types
},
4315 'S|smart-case!' => sub { my (undef,$value) = @_; $opt->{S
} = $value; $opt->{i
} = 0 if $value; },
4316 'sort-files' => \
$opt->{sort_files
},
4317 't|type=s' => \
&_type_handler
,
4318 'T=s' => sub { my ($getopt,$value) = @_; $value="no$value"; _type_handler
($getopt,$value); },
4319 'underline!' => \
$opt->{underline
},
4320 'v|invert-match' => \
$opt->{v
},
4321 'w|word-regexp' => \
$opt->{w
},
4322 'x' => sub { $opt->{files_from
} = '-' },
4324 'help' => sub { App
::Ack
::show_help
(); exit; },
4325 'help-types' => sub { App
::Ack
::show_help_types
(); exit; },
4326 'help-colors' => sub { App
::Ack
::show_help_colors
(); exit; },
4327 'help-rgb-colors' => sub { App
::Ack
::show_help_rgb
(); exit; },
4328 $extra_specs ? %{$extra_specs} : (),
4333 sub _context_value
{
4336 # Contexts default to 2.
4337 return (!defined($val) || ($val < 0)) ? 2 : $val;
4341 sub _process_other
{
4342 my ( $opt, $extra_specs, $arg_sources ) = @_;
4345 my $is_help_types_active;
4347 foreach my $source (@{$arg_sources}) {
4348 if ( $source->{name
} eq 'ARGV' ) {
4349 $argv_source = $source->{contents
};
4354 if ( $argv_source ) { # This *should* always be true, but you never know...
4355 configure_parser
( 'pass_through' );
4356 Getopt
::Long
::GetOptionsFromArray
( [ @{$argv_source} ],
4357 'help-types' => \
$is_help_types_active,
4361 my $arg_specs = get_arg_spec
( $opt, $extra_specs );
4364 foreach my $source (@{$arg_sources}) {
4365 my ( $source_name, $args ) = @{$source}{qw
/name contents/};
4367 my $args_for_source = { %{$arg_specs} };
4369 if ( $source->{is_ackrc
} ) {
4372 App
::Ack
::die( "Option --$name is forbidden in .ackrc files." );
4375 $args_for_source = {
4376 %{$args_for_source},
4377 'output=s' => $illegal,
4378 'match=s' => $illegal,
4381 if ( $source->{project
} ) {
4384 App
::Ack
::die( "Option --$name is forbidden in project .ackrc files." );
4387 $args_for_source = {
4388 %{$args_for_source},
4389 'pager:s' => $illegal,
4395 $ret = Getopt
::Long
::GetOptionsFromArray
( $args, %{$args_for_source} );
4398 ( $ret, $source->{contents
} ) =
4399 Getopt
::Long
::GetOptionsFromString
( $args, %{$args_for_source} );
4402 if ( !$is_help_types_active ) {
4403 my $where = $source_name eq 'ARGV' ? 'on command line' : "in $source_name";
4404 App
::Ack
::die( "Invalid option $where" );
4407 if ( $opt->{noenv_seen
} ) {
4408 App
::Ack
::die( "--noenv found in $source_name" );
4412 # XXX We need to check on a -- in the middle of a non-ARGV source
4418 sub _explode_sources
{
4419 my ( $sources ) = @_;
4424 my $arg_spec = get_arg_spec
( \
%opt, {} );
4426 my $dummy_sub = sub {};
4427 my $add_type = sub {
4428 my ( undef, $arg ) = @_;
4430 if ( $arg =~ /(\w+)=/) {
4431 $arg_spec->{$1} = $dummy_sub;
4434 ( $arg ) = split /:/, $arg;
4435 $arg_spec->{$arg} = $dummy_sub;
4439 my $del_type = sub {
4440 my ( undef, $arg ) = @_;
4442 delete $arg_spec->{$arg};
4445 configure_parser
( 'pass_through' );
4446 foreach my $source (@{$sources}) {
4447 my ( $name, $options ) = @{$source}{qw
/name contents/};
4448 if ( ref($options) ne 'ARRAY' ) {
4449 $source->{contents
} = $options =
4450 [ Text
::ParseWords
::shellwords
($options) ];
4453 for my $j ( 0 .. @{$options}-1 ) {
4454 next unless $options->[$j] =~ /^-/;
4455 my @chunk = ( $options->[$j] );
4456 push @chunk, $options->[$j] while ++$j < @{$options} && $options->[$j] !~ /^-/;
4460 Getopt
::Long
::GetOptionsFromArray
( [@chunk],
4461 'type-add=s' => $add_type,
4462 'type-set=s' => $add_type,
4463 'type-del=s' => $del_type,
4467 push @new_sources, {
4474 return \
@new_sources;
4481 my $first_a = $a->[0];
4482 my $first_b = $b->[0];
4484 $first_a =~ s/^--?//;
4485 $first_b =~ s/^--?//;
4487 return $first_a cmp $first_b;
4492 my ( $sources ) = @_;
4494 $sources = _explode_sources
($sources);
4499 foreach my $source (@{$sources}) {
4500 my $name = $source->{name
};
4501 if ( not $opts_by_source{$name} ) {
4502 $opts_by_source{$name} = [];
4503 push @source_names, $name;
4505 push @{$opts_by_source{$name}}, $source->{contents
};
4508 foreach my $name (@source_names) {
4509 my $contents = $opts_by_source{$name};
4512 say '=' x
length($name);
4513 say ' ', join(' ', @{$_}) for sort { _compare_opts
($a, $b) } @{$contents};
4520 sub _remove_default_options_if_needed
{
4521 my ( $sources ) = @_;
4525 foreach my $index ( 0 .. $#{$sources} ) {
4526 if ( $sources->[$index]{'name'} eq 'Defaults' ) {
4527 $default_index = $index;
4532 return $sources unless defined $default_index;
4534 my $should_remove = 0;
4536 configure_parser
( 'no_auto_abbrev', 'pass_through' );
4538 foreach my $index ( $default_index + 1 .. $#{$sources} ) {
4539 my $args = $sources->[$index]->{contents
};
4542 Getopt
::Long
::GetOptionsFromArray
( $args,
4543 'ignore-ack-defaults' => \
$should_remove,
4547 ( undef, $sources->[$index]{contents
} ) = Getopt
::Long
::GetOptionsFromString
( $args,
4548 'ignore-ack-defaults' => \
$should_remove,
4553 return $sources unless $should_remove;
4555 my @copy = @{$sources};
4556 splice @copy, $default_index, 1;
4562 my $arg_sources = \
@_;
4565 pager
=> $ENV{ACK_PAGER_COLOR
} || $ENV{ACK_PAGER
},
4568 $arg_sources = _remove_default_options_if_needed
($arg_sources);
4570 # Check for --dump early.
4571 foreach my $source (@{$arg_sources}) {
4572 if ( $source->{name
} eq 'ARGV' ) {
4574 configure_parser
( 'pass_through' );
4575 Getopt
::Long
::GetOptionsFromArray
( $source->{contents
},
4579 _dump_options
($arg_sources);
4585 my $type_specs = _process_filetypes
(\
%opt, $arg_sources);
4587 _check_for_mutex_options
( $type_specs );
4589 _process_other
(\
%opt, $type_specs, $arg_sources);
4590 while ( @{$arg_sources} ) {
4591 my $source = shift @{$arg_sources};
4592 my $args = $source->{contents
};
4594 # All of our sources should be transformed into an array ref
4596 my $source_name = $source->{name
};
4597 if ( $source_name eq 'ARGV' ) {
4601 App
::Ack
::die( "Source '$source_name' has extra arguments!" );
4605 App
::Ack
::die( 'The impossible has occurred!' );
4608 my $filters = ($opt{filters
} ||= []);
4610 # Throw the default filter in if no others are selected.
4611 if ( not grep { !$_->is_inverted() } @{$filters} ) {
4612 push @{$filters}, App
::Ack
::Filter
::Default-
>new();
4618 sub retrieve_arg_sources
{
4624 configure_parser
( 'no_auto_abbrev', 'pass_through' );
4625 Getopt
::Long
::GetOptions
(
4627 'ackrc=s' => \
$ackrc,
4633 my $finder = App
::Ack
::ConfigFinder-
>new;
4634 @files = $finder->find_config_files;
4637 # We explicitly use open so we get a nice error message.
4638 # XXX This is a potential race condition!.
4639 if ( open my $fh, '<', $ackrc ) {
4643 App
::Ack
::die( "Unable to load ackrc '$ackrc': $!" );
4645 push( @files, { path
=> $ackrc } );
4648 push @arg_sources, {
4650 contents
=> [ App
::Ack
::ConfigDefault
::options_clean
() ],
4653 foreach my $file ( @files) {
4654 my @lines = read_rcfile
($file->{path
});
4656 push @arg_sources, {
4657 name
=> $file->{path
},
4658 contents
=> \
@lines,
4659 project
=> $file->{project
},
4665 push @arg_sources, {
4667 contents
=> [ @ARGV ],
4670 return @arg_sources;
4677 return unless defined $file && -e
$file;
4681 open( my $fh, '<', $file ) or App
::Ack
::die( "Unable to read $file: $!" );
4682 while ( defined( my $line = <$fh> ) ) {
4687 next if $line eq '';
4688 next if $line =~ /^\s*#/;
4690 push( @lines, $line );
4692 close $fh or App
::Ack
::die( "Unable to close $file: $!" );
4698 # Verifies no mutex options were passed. Dies if they were.
4699 sub _check_for_mutex_options
{
4700 my $type_specs = shift;
4702 my $mutex = mutex_options
();
4704 my ($raw,$used) = _options_used
( $type_specs );
4706 my @used = sort { lc $a cmp lc $b } keys %{$used};
4708 for my $i ( @used ) {
4709 for my $j ( @used ) {
4711 if ( $mutex->{$i}{$j} ) {
4712 my $x = $raw->[ $used->{$i} ];
4713 my $y = $raw->[ $used->{$j} ];
4714 App
::Ack
::die( "Options '$x' and '$y' can't be used together." );
4723 # Processes the command line option and returns a hash of the options that were
4724 # used on the command line, using their full name. "--prox" shows up in the hash as "--proximate".
4726 my $type_specs = shift;
4729 my $real_spec = get_arg_spec
( \
%dummy_opt, $type_specs );
4731 # The real argument parsing doesn't check for --type-add, --type-del or --type-set because
4732 # they get removed by the argument processing. We have to account for them here.
4733 my $sub_dummy = sub {};
4736 'type-add=s' => $sub_dummy,
4737 'type-del=s' => $sub_dummy,
4738 'type-set=s' => $sub_dummy,
4739 'ignore-ack-defaults' => $sub_dummy,
4744 my %spec_capture_parsed;
4745 my %spec_capture_raw;
4748 # Capture the %parsed hash.
4751 my $sub_count = sub {
4754 $parsed{$arg} = $parsed_pos++;
4756 %spec_capture_parsed = (
4757 '<>' => sub { $parsed_pos++ }, # Bump forward one pos for non-options.
4758 map { $_ => $sub_count } keys %{$real_spec}
4762 # Capture the @raw array.
4765 %spec_capture_raw = (
4766 '<>' => sub { $raw_pos++ }, # Bump forward one pos for non-options.
4769 my $sub_count = sub {
4773 $raw[$raw_pos] = length($arg) == 1 ? "-$arg" : "--$arg";
4777 for my $opt_spec ( keys %{$real_spec} ) {
4782 $negatable = ($opt_spec =~ s/!$//);
4784 if ( $opt_spec =~ s/(=[si])$// ) {
4787 if ( $opt_spec =~ s/(:.+)$// ) {
4791 my @aliases = split( /\|/, $opt_spec );
4792 for my $alias ( @aliases ) {
4793 $alias .= $type if defined $type;
4794 $alias .= $default if defined $default;
4795 $alias .= '!' if $negatable;
4797 $spec_capture_raw{$alias} = $sub_count;
4802 # Parse @ARGV twice, once with each capture spec.
4803 configure_parser
( 'pass_through' ); # Ignore invalid options.
4804 Getopt
::Long
::GetOptionsFromArray
( [@ARGV], %spec_capture_raw );
4805 Getopt
::Long
::GetOptionsFromArray
( [@ARGV], %spec_capture_parsed );
4807 return (\
@raw,\
%parsed);
4812 # This list is machine-generated by dev/crank-mutex. Do not modify it by hand.
4883 'with-filename' => 1,
5030 'with-filename' => 1,
5143 'with-filename' => {
5154 } # End of mutex_options()
5157 1; # End of App::Ack::ConfigLoader
5160 package App
::Ack
::File
;
5170 my $filename = shift;
5173 filename
=> $filename,
5177 if ( $self->{filename
} eq '-' ) {
5178 $self->{fh
} = *STDIN
;
5187 return $_[0]->{filename
};
5195 return $self->{basename
} //= (File
::Spec-
>splitpath($self->name))[2];
5203 if ( !$self->{fh
} ) {
5204 if ( open $self->{fh
}, '<', $self->{filename
} ) {
5208 $self->{fh
} = undef;
5216 sub may_be_present
{
5220 # Tells if the file needs a line-by-line scan. This is a big
5221 # optimization because if you can tell from the outset that the pattern
5222 # is not found in the file at all, then there's no need to do the
5223 # line-by-line iteration.
5225 # Slurp up an entire file up to 10M, see if there are any matches
5226 # in it, and if so, let us know so we can iterate over it directly.
5228 # The $regex may be undef if it had a "$" in it, and is therefore unsuitable for this heuristic.
5230 my $may_be_present = 1;
5231 if ( $regex && $self->open() && -f
$self->{fh
} ) {
5233 my $size = 10_000_000;
5234 my $rc = sysread( $self->{fh
}, $buffer, $size );
5235 if ( !defined($rc) ) {
5236 if ( $App::Ack
::report_bad_filenames
) {
5237 App
::Ack
::warn( $self->name . ": $!" );
5239 $may_be_present = 0;
5242 # If we read all 10M, then we need to scan the rest.
5243 # If there are any carriage returns, our results are flaky, so scan the rest.
5244 if ( ($rc == $size) || (index($buffer,"\r") >= 0) ) {
5245 $may_be_present = 1;
5248 if ( $buffer !~ /$regex/o ) {
5249 $may_be_present = 0;
5255 return $may_be_present;
5263 if ( defined($self->{fh
}) ) {
5264 return unless -f
$self->{fh
};
5266 if ( !seek( $self->{fh
}, 0, 0 ) && $App::Ack
::report_bad_filenames
) {
5267 App
::Ack
::warn( "$self->{filename}: $!" );
5279 if ( $self->{fh
} ) {
5280 if ( !close($self->{fh
}) && $App::Ack
::report_bad_filenames
) {
5281 App
::Ack
::warn( $self->name() . ": $!" );
5283 $self->{fh
} = undef;
5294 return __PACKAGE__-
>new($self->name);
5302 if ( !exists $self->{firstliney
} ) {
5303 my $fh = $self->open();
5305 if ( $App::Ack
::report_bad_filenames
) {
5306 App
::Ack
::warn( $self->name . ': ' . $! );
5308 $self->{firstliney
} = '';
5312 my $rc = sysread( $fh, $buffer, 250 );
5314 $buffer =~ s/[\r\n].*//s;
5317 if ( !defined($rc) ) {
5318 App
::Ack
::warn( $self->name . ': ' . $! );
5322 $self->{firstliney
} = $buffer;
5327 return $self->{firstliney
};
5333 package App
::Ack
::Files
;
5347 my $self = bless {}, $class;
5349 my $descend_filter = $opt->{descend_filter
};
5352 $descend_filter = sub {
5358 File
::Next
::files
( {
5359 file_filter
=> $opt->{file_filter
},
5360 descend_filter
=> $descend_filter,
5361 error_handler
=> _generate_error_handler
(),
5362 warning_handler
=> sub {},
5363 sort_files
=> $opt->{sort_files
},
5364 follow_symlinks
=> $opt->{follow
},
5376 my $error_handler = _generate_error_handler
();
5378 File
::Next
::from_file
( {
5379 error_handler
=> $error_handler,
5380 warning_handler
=> $error_handler,
5381 sort_files
=> $opt->{sort_files
},
5382 }, $file ) or return undef;
5395 my $self = bless {}, $class;
5397 $self->{iter
} = sub {
5398 state $has_been_called = 0;
5400 if ( !$has_been_called ) {
5401 $has_been_called = 1;
5414 my $file = $self->{iter
}->();
5416 return unless defined($file);
5418 return App
::Ack
::File-
>new( $file );
5422 sub _generate_error_handler
{
5423 if ( $App::Ack
::report_bad_filenames
) {
5426 App
::Ack
::warn( $msg );
5437 package App
::Ack
::Filter
;
5447 my ( undef, $type, @args ) = @_;
5449 if ( my $package = $filter_types{$type} ) {
5450 return $package->new(@args);
5452 my $allowed_types = join( ', ', sort keys %filter_types );
5453 App
::Ack
::die( "Unknown filter type '$type'. Type must be one of: $allowed_types." );
5457 sub register_filter
{
5458 my ( undef, $type, $package ) = @_;
5460 $filter_types{$type} = $package;
5469 return App
::Ack
::Filter
::Inverse-
>new( $self );
5479 return '(unimplemented to_string)';
5492 package App
::Ack
::Filter
::Collection
;
5498 our @ISA = 'App::Ack::Filter';
5511 my ( $self, $file ) = @_;
5513 for my $group (values %{$self->{groups
}}) {
5514 return 1 if $group->filter($file);
5517 for my $filter (@{$self->{ungrouped
}}) {
5518 return 1 if $filter->filter($file);
5525 my ( $self, $filter ) = @_;
5527 if (exists $filter->{'groupname'}) {
5528 my $group = ($self->{groups
}->{$filter->{groupname
}} ||= $filter->create_group());
5529 $group->add($filter);
5532 push @{$self->{'ungrouped'}}, $filter;
5541 return ref($self) . " - $self";
5547 return join(', ', map { "($_)" } @{$self->{ungrouped
}});
5553 package App
::Ack
::Filter
::Default
;
5559 our @ISA = 'App::Ack::Filter';
5565 return bless {}, $class;
5569 my ( undef, $file ) = @_;
5571 return -T
$file->name;
5577 package App
::Ack
::Filter
::Extension
;
5583 our @ISA = 'App::Ack::Filter';
5588 my ( $class, @extensions ) = @_;
5590 my $exts = join('|', map { "\Q$_\E"} @extensions);
5591 my $re = qr/[.](?:$exts)$/i;
5594 extensions
=> \
@extensions,
5596 groupname
=> 'ExtensionGroup',
5601 return App
::Ack
::Filter
::ExtensionGroup-
>new();
5605 my ( $self, $file ) = @_;
5607 return $file->name =~ /$self->{regex}/;
5613 return ref($self) . ' - ' . $self->{regex
};
5619 return join( ' ', map { ".$_" } @{$self->{extensions
}} );
5623 App
::Ack
::Filter-
>register_filter(ext
=> __PACKAGE__
);
5629 package App
::Ack
::Filter
::ExtensionGroup
;
5635 our @ISA = 'App::Ack::Filter';
5647 my ( $self, $filter ) = @_;
5649 foreach my $ext (@{$filter->{extensions
}}) {
5650 $self->{data
}->{lc $ext} = 1;
5657 my ( $self, $file ) = @_;
5659 if ($file->name =~ /[.]([^.]*)$/) {
5660 return exists $self->{'data'}->{lc $1};
5669 return ref($self) . " - $self";
5675 return join(' ', map { ".$_" } sort keys %{$self->{data
}});
5681 package App
::Ack
::Filter
::FirstLineMatch
;
5688 our @ISA = 'App::Ack::Filter';
5692 my ( $class, $re ) = @_;
5694 $re =~ s{^/|/$}{}g; # XXX validate?
5702 # This test reads the first 250 characters of a file, then just uses the
5703 # first line found in that. This prevents reading something like an entire
5704 # .min.js file (which might be only one "line" long) into memory.
5707 my ( $self, $file ) = @_;
5709 return $file->firstliney =~ /$self->{regex}/;
5716 return ref($self) . ' - ' . $self->{regex
};
5722 (my $re = $self->{regex
}) =~ s{\([^:]*:(.*)\)$}{$1};
5724 return "First line matches /$re/";
5728 App
::Ack
::Filter-
>register_filter(firstlinematch
=> __PACKAGE__
);
5734 package App
::Ack
::Filter
::Inverse
;
5741 our @ISA = 'App::Ack::Filter';
5745 my ( $class, $filter ) = @_;
5753 my ( $self, $file ) = @_;
5755 return !$self->{filter
}->filter( $file );
5761 return $self->{'filter'};
5771 my $filter = $self->{'filter'};
5779 package App
::Ack
::Filter
::Is
;
5785 our @ISA = 'App::Ack::Filter';
5788 use File
::Spec
3.00 ();
5791 my ( $class, $filename ) = @_;
5794 filename
=> $filename,
5795 groupname
=> 'IsGroup',
5800 return App
::Ack
::Filter
::IsGroup-
>new();
5804 my ( $self, $file ) = @_;
5806 return (File
::Spec-
>splitpath($file->name))[2] eq $self->{filename
};
5812 return ref($self) . ' - ' . $self->{filename
};
5818 return $self->{filename
};
5822 App
::Ack
::Filter-
>register_filter(is => __PACKAGE__
);
5828 package App
::Ack
::Filter
::IsGroup
;
5834 our @ISA = 'App::Ack::Filter';
5846 my ( $self, $filter ) = @_;
5848 $self->{data
}->{ $filter->{filename
} } = 1;
5854 my ( $self, $file ) = @_;
5856 return exists $self->{data
}->{ $file->basename };
5862 return ref($self) . " - $self";
5868 return join(' ', keys %{$self->{data
}});
5874 package App
::Ack
::Filter
::IsPath
;
5880 our @ISA = 'App::Ack::Filter';
5885 my ( $class, $filename ) = @_;
5888 filename
=> $filename,
5889 groupname
=> 'IsPathGroup',
5894 return App
::Ack
::Filter
::IsPathGroup-
>new();
5898 my ( $self, $file ) = @_;
5900 return $file->name eq $self->{filename
};
5906 return ref($self) . ' - ' . $self->{filename
};
5912 return $self->{filename
};
5918 package App
::Ack
::Filter
::IsPathGroup
;
5924 our @ISA = 'App::Ack::Filter';
5936 my ( $self, $filter ) = @_;
5938 $self->{data
}->{ $filter->{filename
} } = 1;
5944 my ( $self, $file ) = @_;
5946 return exists $self->{data
}->{$file->name};
5952 return ref($self) . " - $self";
5958 return join(' ', keys %{$self->{data
}});
5964 package App
::Ack
::Filter
::Match
;
5969 our @ISA = 'App::Ack::Filter';
5975 my ( $class, $re ) = @_;
5977 $re =~ s{^/|/$}{}g; # XXX validate?
5982 groupname
=> 'MatchGroup',
5987 return App
::Ack
::Filter
::MatchGroup-
>new;
5991 my ( $self, $file ) = @_;
5993 return $file->basename =~ /$self->{regex}/;
5999 return ref($self) . ' - ' . $self->{regex
};
6005 return "Filename matches $self->{regex}";
6009 App
::Ack
::Filter-
>register_filter(match
=> __PACKAGE__
);
6015 package App
::Ack
::Filter
::MatchGroup
;
6021 our @ISA = 'App::Ack::Filter';
6034 my ( $self, $filter ) = @_;
6036 push @{ $self->{matches
} }, $filter->{regex
};
6038 my $re = join('|', map { "(?:$_)" } @{ $self->{matches
} });
6039 $self->{big_re
} = qr/$re/;
6045 my ( $self, $file ) = @_;
6047 return $file->basename =~ /$self->{big_re}/;
6050 # This class has no inspect() or to_string() method.
6051 # It will just use the default one unless someone writes something useful.
6062 our $VERSION = '1.18';
6068 our $name; # name of the current file
6069 our $dir; # dir of the current file
6071 our %files_defaults;
6076 file_filter
=> undef,
6077 descend_filter
=> undef,
6078 error_handler
=> sub { CORE
::die $_[0] },
6079 warning_handler
=> sub { CORE
::warn @_ },
6080 sort_files
=> undef,
6081 follow_symlinks
=> 1,
6084 %skip_dirs = map {($_,1)} (File
::Spec-
>curdir, File
::Spec-
>updir);
6089 die _bad_invocation
() if @_ && defined($_[0]) && ($_[0] eq __PACKAGE__
);
6091 my ($parms,@queue) = _setup
( \
%files_defaults, @_ );
6093 my $filter = $parms->{file_filter
};
6095 while ( my $entry = shift @queue ) {
6096 my ( $dirname, $file, $fullpath, $is_dir, $is_file, $is_fifo ) = @{$entry};
6097 if ( $is_file || $is_fifo ) {
6100 local $File::Next
::dir
= $dirname;
6101 local $File::Next
::name
= $fullpath;
6102 next if not $filter->();
6104 return wantarray ? ($dirname,$file,$fullpath) : $fullpath;
6107 unshift( @queue, _candidate_files
( $parms, $fullpath ) );
6122 die _bad_invocation
() if @_ && defined($_[0]) && ($_[0] eq __PACKAGE__
);
6124 my ($parms,@queue) = _setup
( \
%files_defaults, @_ );
6125 my $err = $parms->{error_handler
};
6126 my $warn = $parms->{warning_handler
};
6128 my $filename = $queue[0]->[1];
6130 if ( !defined($filename) ) {
6131 $err->( 'Must pass a filename to from_file()' );
6136 if ( $filename eq '-' ) {
6140 if ( !open( $fh, '<', $filename ) ) {
6141 $err->( "Unable to open $filename: $!", $! + 0 );
6146 my $filter = $parms->{file_filter
};
6148 local $/ = $parms->{nul_separated
} ? "\x00" : $/;
6149 while ( my $fullpath = <$fh> ) {
6151 next unless $fullpath =~ /./;
6152 if ( not ( -f
$fullpath || -p _
) ) {
6153 $warn->( "$fullpath: No such file" );
6157 my ($volume,$dirname,$file) = File
::Spec-
>splitpath( $fullpath );
6160 local $File::Next
::dir
= $dirname;
6161 local $File::Next
::name
= $fullpath;
6162 next if not $filter->();
6164 return wantarray ? ($dirname,$file,$fullpath) : $fullpath;
6172 sub _bad_invocation
{
6173 my $good = (caller(1))[3];
6175 $bad =~ s/(.+)::/$1->/;
6176 return "$good must not be invoked as $bad";
6179 sub sort_standard
($$) { return $_[0]->[1] cmp $_[1]->[1] }
6180 sub sort_reverse
($$) { return $_[1]->[1] cmp $_[0]->[1] }
6185 my @parts = split( /\//, $path );
6187 return $path if @parts < 2;
6189 return File
::Spec-
>catfile( @parts );
6195 my $defaults = shift;
6196 my $passed_parms = ref $_[0] eq 'HASH' ? {%{+shift}} : {}; # copy parm hash
6198 my %passed_parms = %{$passed_parms};
6201 for my $key ( keys %{$defaults} ) {
6203 exists $passed_parms{$key}
6204 ? delete $passed_parms{$key}
6205 : $defaults->{$key};
6208 # Any leftover keys are bogus
6209 for my $badkey ( sort keys %passed_parms ) {
6210 my $sub = (caller(1))[3];
6211 $parms->{error_handler
}->( "Invalid option passed to $sub(): $badkey" );
6214 # If it's not a code ref, assume standard sort
6215 if ( $parms->{sort_files
} && ( ref($parms->{sort_files
}) ne 'CODE' ) ) {
6216 $parms->{sort_files
} = \
&sort_standard
;
6221 my $start = reslash
( $_ );
6222 my $is_dir = -d
$start;
6224 my $is_fifo = (-p _
) || ($start =~ m{^/dev/fd});
6227 ? [ $start, undef, $start, $is_dir, $is_file, $is_fifo ]
6228 : [ undef, $start, $start, $is_dir, $is_file, $is_fifo ];
6231 return ($parms,@queue);
6235 sub _candidate_files
{
6237 my $dirname = shift;
6240 if ( !opendir $dh, $dirname ) {
6241 $parms->{error_handler
}->( "$dirname: $!", $! + 0 );
6246 my $descend_filter = $parms->{descend_filter
};
6247 my $follow_symlinks = $parms->{follow_symlinks
};
6249 for my $file ( grep { !exists $skip_dirs{$_} } readdir $dh ) {
6250 my $fullpath = File
::Spec-
>catdir( $dirname, $file );
6251 if ( !$follow_symlinks ) {
6252 next if -l
$fullpath;
6259 my $is_fifo = (-p _
) || ($fullpath =~ m{^/dev/fd});
6261 # Only do directory checking if we have a descend_filter
6262 if ( $descend_filter ) {
6264 local $File::Next
::dir
= $fullpath;
6266 next if not $descend_filter->();
6269 push @newfiles, [ $dirname, $file, $fullpath, $is_dir, $is_file, $is_fifo ];
6273 my $sort_sub = $parms->{sort_files
};
6275 @newfiles = sort $sort_sub @newfiles;
6283 1; # End of File::Next