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.9.0'; # 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);
325 my $nmatched_files = 0;
328 while ( defined( my $file = $files->next ) ) {
329 my $matches_for_this_file = count_matches_in_file
( $file );
330 if ( $matches_for_this_file ) {
334 if ( not $opt_show_filename ) {
335 $total_count += $matches_for_this_file;
339 if ( !$opt_l || $matches_for_this_file > 0 ) {
340 if ( $opt_show_filename ) {
341 my $display_filename = $file->name;
343 $display_filename = Term
::ANSIColor
::colored
($display_filename, $ENV{ACK_COLOR_FILENAME
});
345 App
::Ack
::say( $display_filename, ':', $matches_for_this_file );
348 App
::Ack
::say( $matches_for_this_file );
353 if ( !$opt_show_filename ) {
354 App
::Ack
::say( $total_count );
357 return $nmatched_files;
365 while ( defined( my $file = $files->next ) ) {
366 my $is_match = count_matches_in_file
( $file, 1 );
368 if ( $opt_L ? !$is_match : $is_match ) {
369 App
::Ack
::say( $file->name );
373 last if defined($opt_m) && ($nmatches >= $opt_m);
381 sub _compile_descend_filter
{
385 my $dont_ignore_dirs = 0;
387 for my $filter (@{$opt->{idirs
} || []}) {
388 if ($filter->is_inverted()) {
396 # If we have one or more --noignore-dir directives, we can't ignore
397 # entire subdirectory hierarchies, so we return an "accept all"
398 # filter and scrutinize the files more in _compile_file_filter.
399 return if $dont_ignore_dirs;
400 return unless $idirs;
402 $idirs = $opt->{idirs
};
405 my $file = App
::Ack
::File-
>new($File::Next
::dir
);
406 return !grep { $_->filter($file) } @{$idirs};
411 sub _compile_file_filter
{
412 my ( $opt, $start ) = @_;
414 my $ifiles_filters = $opt->{ifiles
};
416 my $filters = $opt->{'filters'} || [];
417 my $direct_filters = App
::Ack
::Filter
::Collection-
>new();
418 my $inverse_filters = App
::Ack
::Filter
::Collection-
>new();
420 foreach my $filter (@{$filters}) {
421 if ($filter->is_inverted()) {
422 # We want to check if files match the uninverted filters
423 $inverse_filters->add($filter->invert());
426 $direct_filters->add($filter);
430 my %is_member_of_starting_set = map { (get_file_id
($_) => 1) } @{$start};
432 my @ignore_dir_filter = @{$opt->{idirs
} || []};
433 my @is_inverted = map { $_->is_inverted() } @ignore_dir_filter;
434 # This depends on InverseFilter->invert returning the original filter (for optimization).
435 @ignore_dir_filter = map { $_->is_inverted() ? $_->invert() : $_ } @ignore_dir_filter;
436 my $dont_ignore_dir_filter = grep { $_ } @is_inverted;
437 my $previous_dir = '';
438 my $previous_dir_ignore_result;
442 my $match = ($File::Next
::name
=~ /$re_match/o);
443 if ( $match && $re_not ) {
444 $match = ($File::Next
::name
!~ /$re_not/o);
454 # ack always selects files that are specified on the command
455 # line, regardless of filetype. If you want to ack a JPEG,
456 # and say "ack foo whatever.jpg" it will do it for you.
457 return 1 if $is_member_of_starting_set{ get_file_id
($File::Next
::name
) };
459 if ( $dont_ignore_dir_filter ) {
460 if ( $previous_dir eq $File::Next
::dir
) {
461 if ( $previous_dir_ignore_result ) {
466 my @dirs = File
::Spec-
>splitdir($File::Next
::dir
);
470 for ( my $i = 0; $i < @dirs; $i++) {
471 my $dir_rsrc = App
::Ack
::File-
>new(File
::Spec-
>catfile(@dirs[0 .. $i]));
474 for my $filter (@ignore_dir_filter) {
475 if ( $filter->filter($dir_rsrc) ) {
476 $is_ignoring = !$is_inverted[$j];
482 $previous_dir = $File::Next
::dir
;
483 $previous_dir_ignore_result = $is_ignoring;
485 if ( $is_ignoring ) {
491 # Ignore named pipes found in directory searching. Named
492 # pipes created by subprocesses get specified on the command
493 # line, so the rule of "always select whatever is on the
494 # command line" wins.
495 return 0 if -p
$File::Next
::name
;
497 # We can't handle unreadable filenames; report them.
499 use filetest
'access';
501 if ( not -R
$File::Next
::name
) {
502 if ( $App::Ack
::report_bad_filenames
) {
503 App
::Ack
::warn( "${File::Next::name}: cannot open file for reading" );
509 my $file = App
::Ack
::File-
>new($File::Next
::name
);
511 if ( $ifiles_filters && $ifiles_filters->filter($file) ) {
515 my $match_found = $direct_filters->filter($file);
517 # Don't bother invoking inverse filters unless we consider the current file a match.
518 if ( $match_found && $inverse_filters->filter( $file ) ) {
522 }; # End of compiled sub
526 # Returns a (fairly) unique identifier for a file.
527 # Use this function to compare two files to see if they're
528 # equal (ie. the same file, but with a different path/links/etc).
530 my ( $filename ) = @_;
532 if ( $App::Ack
::is_windows
) {
533 return File
::Next
::reslash
( $filename );
536 # XXX Is this the best method? It always hits the FS.
537 if ( my ( $dev, $inode ) = (stat($filename))[0, 1] ) {
538 return join(':', $dev, $inode);
541 # XXX This could be better.
552 # Number of context lines
553 my $n_before_ctx_lines;
554 my $n_after_ctx_lines;
556 # Array to keep track of lines that might be required for a "before" context
557 my @before_context_buf;
558 # Position to insert next line in @before_context_buf
559 my $before_context_pos;
561 # Number of "after" context lines still pending
562 my $after_context_pending;
564 # Number of latest line that got printed
568 state $has_printed_from_any_file;
571 sub file_loop_normal
{
574 $n_before_ctx_lines = $opt_output ? 0 : ($opt_B || 0);
575 $n_after_ctx_lines = $opt_output ? 0 : ($opt_A || 0);
577 @before_context_buf = (undef) x
$n_before_ctx_lines;
578 $before_context_pos = 0;
580 $is_tracking_context = $n_before_ctx_lines || $n_after_ctx_lines;
585 while ( defined( my $file = $files->next ) ) {
586 if ($is_tracking_context) {
588 $after_context_pending = 0;
589 if ( $opt_heading ) {
593 my $needs_line_scan = 1;
594 if ( !$opt_passthru && !$opt_v ) {
596 if ( $file->may_be_present( $re_scan ) ) {
600 $needs_line_scan = 0;
603 if ( $needs_line_scan ) {
605 $nmatches += print_matches_in_file
( $file );
607 last if $opt_1 && $nmatches;
614 sub print_matches_in_file
{
617 my $filename = $file->name;
619 my $fh = $file->open;
621 if ( $App::Ack
::report_bad_filenames
) {
622 App
::Ack
::warn( "$filename: $!" );
627 my $display_filename = $filename;
628 if ( $opt_show_filename && $opt_heading && $opt_color ) {
629 $display_filename = Term
::ANSIColor
::colored
($display_filename, $ENV{ACK_COLOR_FILENAME
});
632 # Check for context before the main loop, so we don't pay for it if we don't need it.
634 my $max_count = $opt_m || -1; # Go negative for no limit so it can never reduce to 0.
635 if ( $is_tracking_context ) {
636 $nmatches = pmif_context
( $fh, $filename, $display_filename, $max_count );
638 elsif ( $opt_passthru ) {
639 $nmatches = pmif_passthru
( $fh, $filename, $display_filename, $max_count );
642 $nmatches = pmif_opt_v
( $fh, $filename, $display_filename, $max_count );
645 $nmatches = pmif_normal
( $fh, $filename, $display_filename, $max_count );
654 my $filename = shift;
655 my $display_filename = shift;
656 my $max_count = shift;
658 my $in_range = range_setup
();
659 my $has_printed_from_this_file;
662 $after_context_pending = 0;
667 $match_colno = undef;
669 $in_range = 1 if ( $using_ranges && !$in_range && defined($opt_range_start) && /$opt_range_start/o );
673 $does_match = /$re_match/o;
674 if ( $does_match && defined($re_not) ) {
676 $does_match = !/$re_not/o;
679 $does_match = !$does_match;
683 # @- = @LAST_MATCH_START
684 $match_colno = $-[0] + 1;
689 if ( $does_match && $max_count ) {
690 if ( !$has_printed_from_this_file ) {
691 $stats{filematches
}++;
692 if ( $opt_break && $has_printed_from_any_file ) {
693 App
::Ack
::print_blank_line
();
695 if ( $opt_show_filename && $opt_heading ) {
696 App
::Ack
::say( $display_filename );
699 print_line_with_context
( $filename, $_, $. );
700 $has_printed_from_this_file = 1;
701 $stats{linematches
}++;
706 if ( $after_context_pending ) {
707 # Disable $opt_column since there are no matches in the context lines.
708 local $opt_column = 0;
709 print_line_with_options
( $filename, $_, $., '-' );
710 --$after_context_pending;
712 elsif ( $n_before_ctx_lines ) {
713 # Save line for "before" context.
714 $before_context_buf[$before_context_pos] = $_;
715 $before_context_pos = ($before_context_pos+1) % $n_before_ctx_lines;
719 $in_range = 0 if ( $using_ranges && $in_range && defined($opt_range_end) && /$opt_range_end/o );
721 last if ($max_count == 0) && ($after_context_pending == 0);
730 my $filename = shift;
731 my $display_filename = shift;
732 my $max_count = shift;
734 my $in_range = range_setup
();
735 my $has_printed_from_this_file;
743 $in_range = 1 if ( $using_ranges && !$in_range && defined($opt_range_start) && /$opt_range_start/o );
745 $match_colno = undef;
746 my $does_match = /$re_match/o;
747 if ( $does_match && defined($re_not) ) {
749 $does_match = !/$re_not/o;
751 if ( $in_range && $does_match ) {
752 $match_colno = $-[0] + 1;
753 if ( !$has_printed_from_this_file ) {
754 if ( $opt_break && $has_printed_from_any_file ) {
755 App
::Ack
::print_blank_line
();
757 if ( $opt_show_filename && $opt_heading ) {
758 App
::Ack
::say( $display_filename );
761 print_line_with_options
( $filename, $_, $., ':' );
762 $has_printed_from_this_file = 1;
767 if ( $opt_break && !$has_printed_from_this_file && $has_printed_from_any_file ) {
768 App
::Ack
::print_blank_line
();
770 print_line_with_options
( $filename, $_, $., '-', 1 );
771 $has_printed_from_this_file = 1;
774 $in_range = 0 if ( $using_ranges && $in_range && defined($opt_range_end) && /$opt_range_end/o );
776 last if $max_count == 0;
785 my $filename = shift;
786 my $display_filename = shift;
787 my $max_count = shift;
789 my $in_range = range_setup
();
790 my $has_printed_from_this_file;
793 $match_colno = undef;
799 $in_range = 1 if ( $using_ranges && !$in_range && defined($opt_range_start) && /$opt_range_start/o );
802 my $does_match = /$re_match/o;
803 if ( $does_match && defined($re_not) ) {
804 # local @-; No need to localize this because we don't use @-.
805 $does_match = !/$re_not/o;
807 if ( !$does_match ) {
808 if ( !$has_printed_from_this_file ) {
809 if ( $opt_break && $has_printed_from_any_file ) {
810 App
::Ack
::print_blank_line
();
812 if ( $opt_show_filename && $opt_heading ) {
813 App
::Ack
::say( $display_filename );
816 print_line_with_context
( $filename, $_, $. );
817 $has_printed_from_this_file = 1;
823 $in_range = 0 if ( $using_ranges && $in_range && defined($opt_range_end) && /$opt_range_end/o );
825 last if $max_count == 0;
834 my $filename = shift;
835 my $display_filename = shift;
836 my $max_count = shift;
838 my $in_range = range_setup
();
839 my $has_printed_from_this_file;
842 my $last_match_lineno;
848 $in_range = 1 if ( $using_ranges && !$in_range && defined($opt_range_start) && /$opt_range_start/o );
851 $match_colno = undef;
852 my $is_match = /$re_match/o;
853 if ( $is_match && defined($re_not) ) {
855 $is_match = !/$re_not/o;
858 $match_colno = $-[0] + 1;
859 if ( !$has_printed_from_this_file ) {
860 $stats{filematches
}++;
861 if ( $opt_break && $has_printed_from_any_file ) {
862 App
::Ack
::print_blank_line
();
864 if ( $opt_show_filename && $opt_heading ) {
865 App
::Ack
::say( $display_filename );
869 if ( $last_match_lineno ) {
870 if ( $. > $last_match_lineno + $opt_p ) {
871 App
::Ack
::print_blank_line
();
874 elsif ( !$opt_break && $has_printed_from_any_file ) {
875 App
::Ack
::print_blank_line
();
879 print_line_with_options
( $filename, $_, $., ':' );
880 $has_printed_from_this_file = 1;
882 $stats{linematches
}++;
884 $last_match_lineno = $.;
888 $in_range = 0 if ( $using_ranges && $in_range && defined($opt_range_end) && /$opt_range_end/o );
890 last if $max_count == 0;
897 sub print_line_with_options
{
898 my ( $filename, $line, $lineno, $separator, $skip_coloring ) = @_;
900 $has_printed_from_any_file = 1;
901 $printed_lineno = $lineno;
905 if ( $opt_show_filename && defined($filename) ) {
909 $disp_filename = Term
::ANSIColor
::colored
( $filename, $ENV{ACK_COLOR_FILENAME
} );
910 $disp_lineno = Term
::ANSIColor
::colored
( $lineno, $ENV{ACK_COLOR_LINENO
} );
913 $disp_filename = $filename;
914 $disp_lineno = $lineno;
917 if ( $opt_heading ) {
918 push @line_parts, $disp_lineno;
921 push @line_parts, $disp_filename, $disp_lineno;
925 my $colno = get_match_colno
();
926 $colno = Term
::ANSIColor
::colored
( $colno, $ENV{ACK_COLOR_COLNO
} ) if $opt_color;
927 push @line_parts, $colno;
932 while ( $line =~ /$re_match/og ) {
933 my $output = $opt_output;
934 if ( @special_vars_used_by_opt_output ) {
937 # Stash copies of the special variables because we can't rely
938 # on them not changing in the process of doing the s///.
940 my %keep = map { ($_ => ${$_} // '') } @special_vars_used_by_opt_output;
941 $keep{_
} = $line if exists $keep{_
}; # Manually set it because $_ gets reset in a map.
942 $keep{f
} = $filename if exists $keep{f
};
943 my $special_vars_used_by_opt_output = join( '', @special_vars_used_by_opt_output );
944 $output =~ s/\$([$special_vars_used_by_opt_output])/$keep{$1}/ego;
946 App
::Ack
::say( join( $separator, @line_parts, $output ) );
952 # We have to do underlining before any highlighting because highlighting modifies string length.
953 if ( $opt_underline && !$skip_coloring ) {
954 while ( $line =~ /$re_hilite/og ) {
955 my $match_start = $-[0] // next;
956 my $match_end = $+[0];
957 my $match_length = $match_end - $match_start;
958 last if $match_length <= 0;
960 my $spaces_needed = $match_start - length $underline;
962 $underline .= (' ' x
$spaces_needed);
963 $underline .= ('^' x
$match_length);
966 if ( $opt_color && !$skip_coloring ) {
967 my $highlighted = 0; # If highlighted, need to escape afterwards.
969 while ( $line =~ /$re_hilite/og ) {
970 my $match_start = $-[0] // next;
971 my $match_end = $+[0];
972 my $match_length = $match_end - $match_start;
973 last if $match_length <= 0;
975 my $substring = substr( $line, $match_start, $match_length );
976 my $substitution = Term
::ANSIColor
::colored
( $substring, $ENV{ACK_COLOR_MATCH
} );
978 # Fourth argument replaces the string specified by the first three.
979 substr( $line, $match_start, $match_length, $substitution );
981 # Move the offset of where /g left off forward the number of spaces of highlighting.
982 pos($line) = $match_end + (length( $substitution ) - length( $substring ));
985 # Reset formatting and delete everything to the end of the line.
986 $line .= "\e[0m\e[K" if $highlighted;
989 push @line_parts, $line;
990 App
::Ack
::say( join( $separator, @line_parts ) );
992 # Print the underline, if appropriate.
993 if ( $underline ne '' ) {
994 # Figure out how many spaces are used per line for the ANSI coloring.
995 state $chars_used_by_coloring;
996 if ( !defined($chars_used_by_coloring) ) {
997 $chars_used_by_coloring = 0;
999 my $len_fn = sub { length( Term
::ANSIColor
::colored
( 'x', $ENV{$_[0]} ) ) - 1 };
1000 $chars_used_by_coloring += $len_fn->('ACK_COLOR_FILENAME') unless $opt_heading;
1001 $chars_used_by_coloring += $len_fn->('ACK_COLOR_LINENO');
1002 $chars_used_by_coloring += $len_fn->('ACK_COLOR_COLNO') if $opt_column;
1006 pop @line_parts; # Leave only the stuff on the left.
1007 if ( @line_parts ) {
1008 my $stuff_on_the_left = join( $separator, @line_parts );
1009 my $spaces_needed = length($stuff_on_the_left) - $chars_used_by_coloring + 1;
1011 App
::Ack
::print( ' ' x
$spaces_needed );
1013 App
::Ack
::say( $underline );
1020 sub print_line_with_context
{
1021 my ( $filename, $matching_line, $lineno ) = @_;
1023 $matching_line =~ s/[\r\n]+$//;
1025 # Check if we need to print context lines first.
1026 if ( $opt_A || $opt_B ) {
1027 my $before_unprinted = $lineno - $printed_lineno - 1;
1028 if ( !$is_first_match && ( !$printed_lineno || $before_unprinted > $n_before_ctx_lines ) ) {
1029 App
::Ack
::say( '--' );
1032 # We want at most $n_before_ctx_lines of context.
1033 if ( $before_unprinted > $n_before_ctx_lines ) {
1034 $before_unprinted = $n_before_ctx_lines;
1037 while ( $before_unprinted > 0 ) {
1038 my $line = $before_context_buf[($before_context_pos - $before_unprinted + $n_before_ctx_lines) % $n_before_ctx_lines];
1042 # Disable $opt->{column} since there are no matches in the context lines.
1043 local $opt_column = 0;
1045 print_line_with_options
( $filename, $line, $lineno-$before_unprinted, '-' );
1046 $before_unprinted--;
1050 print_line_with_options
( $filename, $matching_line, $lineno, ':' );
1052 # We want to get the next $n_after_ctx_lines printed.
1053 $after_context_pending = $n_after_ctx_lines;
1055 $is_first_match = 0;
1062 sub get_match_colno
{
1063 return $match_colno;
1066 sub count_matches_in_file
{
1068 my $bail = shift; # True if we're just checking for existence.
1073 if ( !$file->open() ) {
1075 if ( $App::Ack
::report_bad_filenames
) {
1076 App
::Ack
::warn( $file->name . ": $!" );
1081 if ( !$file->may_be_present( $re_scan ) ) {
1090 my $in_range = range_setup
();
1092 my $fh = $file->{fh
};
1093 if ( $using_ranges ) {
1096 $in_range = 1 if ( !$in_range && defined($opt_range_start) && /$opt_range_start/o );
1098 my $is_match = /$re_match/o;
1099 if ( $is_match && defined($re_not) ) {
1100 $is_match = !/$re_not/o;
1102 if ( $is_match xor $opt_v ) {
1107 $in_range = 0 if ( $in_range && defined($opt_range_end) && /$opt_range_end/o );
1113 my $is_match = /$re_match/o;
1114 if ( $is_match && defined($re_not) ) {
1115 $is_match = !/$re_not/o;
1117 if ( $is_match xor $opt_v ) {
1131 return !$using_ranges || (!$opt_range_start && $opt_range_end);
1141 ack - grep-like text finder
1145 ack [options] PATTERN [FILE...]
1146 ack -f [options] [DIRECTORY...]
1150 ack is designed as an alternative to F<grep> for programmers.
1152 ack searches the named input FILEs or DIRECTORYs for lines containing a
1153 match to the given PATTERN. By default, ack prints the matching lines.
1154 If no FILE or DIRECTORY is given, the current directory will be searched.
1156 PATTERN is a Perl regular expression. Perl regular expressions
1157 are commonly found in other programming languages, but for the particulars
1158 of their behavior, please consult
1159 L<perlreref|https://perldoc.perl.org/perlreref.html>. If you don't know
1160 how to use regular expression but are interested in learning, you may
1161 consult L<perlretut|https://perldoc.perl.org/perlretut.html>. If you do not
1162 need or want ack to use regular expressions, please see the
1163 C<-Q>/C<--literal> option.
1165 Ack can also list files that would be searched, without actually
1166 searching them, to let you take advantage of ack's file-type filtering
1169 =head1 FILE SELECTION
1171 If files are not specified for searching, either on the command
1172 line or piped in with the C<-x> option, I<ack> delves into
1173 subdirectories selecting files for searching.
1175 I<ack> is intelligent about the files it searches. It knows about
1176 certain file types, based on both the extension on the file and,
1177 in some cases, the contents of the file. These selections can be
1178 made with the B<--type> option.
1180 With no file selection, I<ack> searches through regular files that
1181 are not explicitly excluded by B<--ignore-dir> and B<--ignore-file>
1182 options, either present in F<ackrc> files or on the command line.
1184 The default options for I<ack> ignore certain files and directories. These
1189 =item * Backup files: Files matching F<#*#> or ending with F<~>.
1191 =item * Coredumps: Files matching F<core.\d+>
1193 =item * Version control directories like F<.svn> and F<.git>.
1197 Run I<ack> with the C<--dump> option to see what settings are set.
1199 However, I<ack> always searches the files given on the command line,
1200 no matter what type. If you tell I<ack> to search in a coredump,
1201 it will search in a coredump.
1203 =head1 DIRECTORY SELECTION
1205 I<ack> descends through the directory tree of the starting directories
1206 specified. If no directories are specified, the current working directory is
1207 used. However, it will ignore the shadow directories used by
1208 many version control systems, and the build directories used by the
1209 Perl MakeMaker system. You may add or remove a directory from this
1210 list with the B<--[no]ignore-dir> option. The option may be repeated
1211 to add/remove multiple directories from the ignore list.
1213 For a complete list of directories that do not get searched, run
1216 =head1 MATCHING IN A RANGE OF LINES
1218 The C<--range-start> and C<--range-end> options let you specify ranges of
1219 lines to search within each file.
1221 Say you had the following file, called F<testfile>:
1223 # This function calls print on "foo".
1233 Calling C<ack print> will give us five matches:
1235 $ ack print testfile
1236 # This function calls print on "foo".
1242 What if we only want to search for C<print> within the subroutines? We can
1243 specify ranges of lines that we want ack to search. The range starts with
1244 any line that matches the pattern C<^sub \w+>, and stops with any line that
1247 $ ack --range-start='^sub \w+' --range-end='^}' print testfile
1251 Note that ack searched two ranges of lines. The listing below shows which
1252 lines were in a range and which were out of the range.
1254 Out # This function calls print on "foo".
1262 Out my $task = 'print';
1264 You don't have to specify both C<--range-start> and C<--range-end>. IF
1265 C<--range-start> is omitted, then the range runs from the first line in the
1266 file until the first line that matches C<--range-end>. Similarly, if
1267 C<--range-end> is omitted, the range runs from the first line matching
1268 C<--range-start> to the end of the file.
1270 For example, if you wanted to search all HTML files up until the first
1271 instance of the C<< <body> >>, you could do
1273 ack foo --html --range-end='<body>'
1275 Or to search after Perl's `__DATA__` or `__END__` markers, you would do
1277 ack pattern --perl --range-start='^__(END|DATA)__'
1279 It's possible for a range to start and stop on the same line. For example
1281 --range-start='<title>' --range-end='</title>'
1283 would match this line as both the start and end of the range, making a
1286 <title>Page title</title>
1288 Note that the patterns in C<--range-start> and C<--range-end> are not
1289 affected by options like C<-i>, C<-w> and C<-Q> that modify the behavior of
1290 the main pattern being matched.
1292 Again, ranges only affect where matches are looked for. Everything else in
1293 ack works the same way. Using C<-c> option with a range will give a count
1294 of all the matches that appear within those ranges. The C<-l> shows those
1295 files that have a match within a range, and the C<-L> option shows files
1296 that do not have a match within a range.
1298 The C<-v> option for negating a match works inside the range, too.
1299 To see lines that don't match "google" within the "<head>" section of
1300 your HTML files, you could do:
1302 ack google -v --html --range-start='<head' --range-end='</head>'
1304 Specifying a range to search does not affect how matches are displayed.
1305 The context for a match will still be the same, and
1307 Using the context options work the same way, and will show context
1308 lines for matches even if the context lines fall outside the range.
1309 Similarly, C<--passthru> will show all lines in the file, but only show
1310 matches for lines within the range.
1318 Specifies an ackrc file to load after all others; see L</"ACKRC LOCATION SEMANTICS">.
1320 =item B<--and=PATTERN>
1322 Specifies a I<PATTERN> that MUST ALSO be found on a given line for a match to
1323 occur. This option can be repeated.
1325 If you want to find all the lines with both "dogs" or "cats", use:
1329 Note that the options that affect "dogs" also affect "cats", so if you have
1331 ack -i -w dogs --and cats
1333 then the search for both "dogs" and "cats" will be case-insensitive and be
1336 C<--and> cannot be used with C<--or>.
1338 =item B<-A I<NUM>>, B<--after-context=I<NUM>>
1340 Print I<NUM> lines of trailing context after matching lines.
1342 =item B<-B I<NUM>>, B<--before-context=I<NUM>>
1344 Print I<NUM> lines of leading context before matching lines.
1346 =item B<--[no]break>
1348 Print a break between results from different files. On by default
1349 when used interactively.
1351 =item B<-C [I<NUM>]>, B<--context[=I<NUM>]>
1353 Print I<NUM> lines (default 2) of context around matching lines.
1354 You can specify zero lines of context to override another context
1355 specified in an ackrc.
1357 =item B<-c>, B<--count>
1359 Suppress normal output; instead print a count of matching lines for
1360 each input file. If B<-l> is in effect, it will only show the
1361 number of lines for each file that has lines matching. Without
1362 B<-l>, some line counts may be zeroes.
1364 If combined with B<-h> (B<--no-filename>) ack outputs only one total
1367 =item B<--[no]color>, B<--[no]colour>
1369 B<--color> highlights the matching text. B<--nocolor> suppresses
1370 the color. This is on by default unless the output is redirected.
1372 On Windows, this option is off by default unless the
1373 L<Win32::Console::ANSI> module is installed or the C<ACK_PAGER_COLOR>
1374 environment variable is used.
1376 =item B<--color-filename=I<color>>
1378 Sets the color to be used for filenames.
1380 =item B<--color-match=I<color>>
1382 Sets the color to be used for matches.
1384 =item B<--color-colno=I<color>>
1386 Sets the color to be used for column numbers.
1388 =item B<--color-lineno=I<color>>
1390 Sets the color to be used for line numbers.
1392 =item B<--[no]column>
1394 Show the column number of the first match. This is helpful for
1395 editors that can place your cursor at a given position.
1397 =item B<--create-ackrc>
1399 Dumps the default ack options to standard output. This is useful for
1400 when you want to customize the defaults.
1404 Writes the list of options loaded and where they came from to standard
1405 output. Handy for debugging.
1409 B<--noenv> disables all environment processing. No F<.ackrc> is
1410 read and all environment variables are ignored. By default, F<ack>
1411 considers F<.ackrc> and settings in the environment.
1415 B<--flush> flushes output immediately. This is off by default
1416 unless ack is running interactively (when output goes to a pipe or
1421 Only print the files that would be searched, without actually doing
1422 any searching. PATTERN must not be specified, or it will be taken
1423 as a path to search.
1425 =item B<--files-from=I<FILE>>
1427 The list of files to be searched is specified in I<FILE>. The list of
1428 files are separated by newlines. If I<FILE> is C<->, the list is loaded
1429 from standard input.
1431 Note that the list of files is B<not> filtered in any way. If you
1432 add C<--type=html> in addition to C<--files-from>, the C<--type> will
1436 =item B<--[no]filter>
1438 Forces ack to act as if it were receiving input via a pipe.
1440 =item B<--[no]follow>
1442 Follow or don't follow symlinks, other than whatever starting files
1443 or directories were specified on the command line.
1445 This is off by default.
1447 =item B<-g I<PATTERN>>
1449 Print searchable files where the relative path + filename matches
1456 is exactly the same as
1460 This means that just as ack will not search, for example, F<.jpg>
1461 files, C<-g> will not list F<.jpg> files either. ack is not intended
1462 to be a general-purpose file finder.
1464 Note also that if you have C<-i> in your .ackrc that the filenames
1465 to be matched will be case-insensitive as well.
1467 This option can be combined with B<--color> to make it easier to
1470 =item B<--[no]group>
1472 B<--group> groups matches by file name. This is the default
1473 when used interactively.
1475 B<--nogroup> prints one result per line, like grep. This is the
1476 default when output is redirected.
1478 =item B<-H>, B<--with-filename>
1480 Print the filename for each match. This is the default unless searching
1481 a single explicitly specified file.
1483 =item B<-h>, B<--no-filename>
1485 Suppress the prefixing of filenames on output when multiple files are
1488 =item B<--[no]heading>
1490 Print a filename heading above each file's results. This is the default
1491 when used interactively.
1495 Print a short help statement.
1497 =item B<--help-types>
1499 Print all known types.
1501 =item B<--help-colors>
1503 Print a chart of various color combinations.
1505 =item B<--help-rgb-colors>
1507 Like B<--help-colors> but with more precise RGB colors.
1509 =item B<-i>, B<--ignore-case>
1511 Ignore case distinctions in PATTERN. Overrides B<--smart-case> and B<-I>.
1513 =item B<-I>, B<--no-ignore-case>
1515 Turns on case distinctions in PATTERN. Overrides B<--smart-case> and B<-i>.
1517 =item B<--ignore-ack-defaults>
1519 Tells ack to completely ignore the default definitions provided with ack.
1520 This is useful in combination with B<--create-ackrc> if you I<really> want
1523 =item B<--[no]ignore-dir=I<DIRNAME>>, B<--[no]ignore-directory=I<DIRNAME>>
1525 Ignore directory (as CVS, .svn, etc are ignored). May be used
1526 multiple times to ignore multiple directories. For example, mason
1527 users may wish to include B<--ignore-dir=data>. The B<--noignore-dir>
1528 option allows users to search directories which would normally be
1529 ignored (perhaps to research the contents of F<.svn/props> directories).
1531 The I<DIRNAME> must always be a simple directory name. Nested
1532 directories like F<foo/bar> are NOT supported. You would need to
1533 specify B<--ignore-dir=foo> and then no files from any foo directory
1534 are taken into account by ack unless given explicitly on the command
1537 =item B<--ignore-file=I<FILTER:ARGS>>
1539 Ignore files matching I<FILTER:ARGS>. The filters are specified
1540 identically to file type filters as seen in L</"Defining your own types">.
1542 =item B<-k>, B<--known-types>
1544 Limit selected files to those with types that ack knows about.
1546 =item B<-l>, B<--files-with-matches>
1548 Only print the filenames of matching files, instead of the matching text.
1550 =item B<-L>, B<--files-without-matches>
1552 Only print the filenames of files that do I<NOT> match.
1554 =item B<--match I<PATTERN>>
1556 Specify the I<PATTERN> explicitly. This is helpful if you don't want to put the
1557 regex as your first argument, e.g. when executing multiple searches over the
1560 # search for foo and bar in given files
1561 ack file1 t/file* --match foo
1562 ack file1 t/file* --match bar
1564 =item B<-m=I<NUM>>, B<--max-count=I<NUM>>
1566 Print only I<NUM> matches out of each file. If you want to stop ack
1567 after printing the first match of any kind, use the B<-1> options.
1571 Print this manual page.
1573 =item B<-n>, B<--no-recurse>
1575 No descending into subdirectories.
1577 =item B<--not=PATTERN>
1579 Specifies a I<PATTERN> that must NOT be true on a given line for a match to
1580 occur. This option can be repeated.
1582 If you want to find all the lines with "dogs" but not if "cats" or "fish"
1583 appear on the line, use:
1585 ack dogs --not cats --not fish
1587 Note that the options that affect "dogs" also affect "cats" and "fish", so
1590 ack -i -w dogs --not cats
1592 then the search for both "dogs" and "cats" will be case-insensitive and be
1597 Show only the part of each line matching PATTERN (turns off text
1598 highlighting). This is exactly the same as C<--output=$&>.
1600 =item B<--or=PATTERN>
1602 Specifies a I<PATTERN> that MAY be found on a given line for a match to
1603 occur. This option can be repeated.
1605 If you want to find all the lines with "dogs" or "cats", use:
1609 Note that the options that affect "dogs" also affect "cats", so if you have
1611 ack -i -w dogs --or cats
1613 then the search for both "dogs" and "cats" will be case-insensitive and be
1616 C<--or> cannot be used with C<--and>.
1618 =item B<--output=I<expr>>
1620 Output the evaluation of I<expr> for each line (turns off text
1621 highlighting). If PATTERN matches more than once then a line is
1622 output for each non-overlapping match.
1624 I<expr> may contain the strings "\n", "\r" and "\t", which will be
1625 expanded to their corresponding characters line feed, carriage return
1626 and tab, respectively.
1628 I<expr> may also contain the following Perl special variables:
1632 =item C<$1> through C<$9>
1634 The subpattern from the corresponding set of capturing parentheses.
1635 If your pattern is C<(.+) and (.+)>, and the string is "this and
1636 that', then C<$1> is "this" and C<$2> is "that".
1640 The contents of the line in the file.
1644 The number of the line in the file.
1646 =item C<$&>, C<$`> and C<$'>
1648 C<$&> is the string matched by the pattern, C<$`> is what
1649 precedes the match, and C<$'> is what follows it. If the pattern
1650 is C<gra(ph|nd)> and the string is "lexicographic", then C<$&> is
1651 "graph", C<$`> is "lexico" and C<$'> is "ic".
1653 Use of these variables in your output will slow down the pattern
1658 The match made by the last parentheses that matched in the pattern.
1659 For example, if your pattern is C<Version: (.+)|Revision: (.+)>,
1660 then C<$+> will contain whichever set of parentheses matched.
1664 C<$f> is available, in C<--output> only, to insert the filename.
1665 This is a stand-in for the discovered C<$filename> usage in old C<< ack2 --output >>,
1666 which is disallowed with C<ack3> improved security.
1668 The intended usage is to provide the grep or compile-error syntax needed for editor/IDE go-to-line integration,
1669 e.g. C<--output=$f:$.:$_> or C<--output=$f\t$.\t$&>
1673 =item B<--pager=I<program>>, B<--nopager>
1675 B<--pager> directs ack's output through I<program>. This can also be specified
1676 via the C<ACK_PAGER> and C<ACK_PAGER_COLOR> environment variables.
1678 Using --pager does not suppress grouping and coloring like piping
1679 output on the command-line does.
1681 B<--nopager> cancels any setting in F<~/.ackrc>, C<ACK_PAGER> or C<ACK_PAGER_COLOR>.
1682 No output will be sent through a pager.
1686 Prints all lines, whether or not they match the expression. Highlighting
1687 will still work, though, so it can be used to highlight matches while
1688 still seeing the entire file, as in:
1690 # Watch a log file, and highlight a certain IP address.
1691 $ tail -f ~/access.log | ack --passthru 123.45.67.89
1695 Only works in conjunction with B<-f>, B<-g>, B<-l> or B<-c>, options
1696 that only list filenames. The filenames are output separated with a
1697 null byte instead of the usual newline. This is helpful when dealing
1698 with filenames that contain whitespace, e.g.
1700 # Remove all files of type HTML.
1701 ack -f --html --print0 | xargs -0 rm -f
1703 =item B<-p[N]>, B<--proximate[=N]>
1705 Groups together match lines that are within N lines of each other.
1706 This is useful for visually picking out matches that appear close
1709 For example, if you got these results without the C<--proximate> option,
1716 they would look like this with C<--proximate=1>
1725 and this with C<--proximate=3>.
1733 If N is omitted, N is set to 1.
1737 Negates the effect of the B<--proximate> option. Shortcut for B<--proximate=0>.
1739 =item B<-Q>, B<--literal>
1741 Quote all metacharacters in PATTERN, it is treated as a literal.
1743 =item B<-r>, B<-R>, B<--recurse>
1745 Recurse into sub-directories. This is the default and just here for
1746 compatibility with grep. You can also use it for turning B<--no-recurse> off.
1748 =item B<--range-start=PATTERN>, B<--range-end=PATTERN>
1750 Specifies patterns that mark the start and end of a range. See
1751 L<MATCHING IN A RANGE OF LINES> for details.
1755 Suppress error messages about nonexistent or unreadable files. This is taken
1758 =item B<-S>, B<--[no]smart-case>, B<--no-smart-case>
1760 Ignore case in the search strings if PATTERN contains no uppercase
1761 characters. This is similar to C<smartcase> in the vim text editor.
1762 The options overrides B<-i> and B<-I>.
1764 B<-S> is a synonym for B<--smart-case>.
1766 B<-i> always overrides this option.
1768 =item B<--sort-files>
1770 Sorts the found files lexicographically. Use this if you want your file
1771 listings to be deterministic between runs of I<ack>.
1773 =item B<--show-types>
1775 Outputs the filetypes that ack associates with each file.
1777 Works with B<-f> and B<-g> options.
1779 =item B<-t TYPE>, B<--type=TYPE>, B<--TYPE>
1781 Specify the types of files to include in the search.
1782 TYPE is a filetype, like I<perl> or I<xml>. B<--type=perl> can
1783 also be specified as B<--perl>, although this is deprecated.
1785 Type inclusions can be repeated and are ORed together.
1787 See I<ack --help-types> for a list of valid types.
1789 =item B<-T TYPE>, B<--type=noTYPE>, B<--noTYPE>
1791 Specifies the type of files to exclude from the search. B<--type=noperl>
1792 can be done as B<--noperl>, although this is deprecated.
1794 If a file is of both type "foo" and "bar", specifying both B<--type=foo>
1795 and B<--type=nobar> will exclude the file, because an exclusion takes
1796 precedence over an inclusion.
1798 =item B<--type-add I<TYPE>:I<FILTER>:I<ARGS>>
1800 Files with the given ARGS applied to the given FILTER
1801 are recognized as being of (the existing) type TYPE.
1802 See also L</"Defining your own types">.
1804 =item B<--type-set I<TYPE>:I<FILTER>:I<ARGS>>
1806 Files with the given ARGS applied to the given FILTER are recognized as
1807 being of type TYPE. This replaces an existing definition for type TYPE. See
1808 also L</"Defining your own types">.
1810 =item B<--type-del I<TYPE>>
1812 The filters associated with TYPE are removed from Ack, and are no longer considered
1815 =item B<--[no]underline>
1817 Turns on underlining of matches, where "underlining" is printing a line of
1818 carets under the match.
1822 17: Come kick the football you fool
1824 623: Price per square foot
1827 This is useful if you're dumping the results of an ack run into a text
1828 file or printer that doesn't support ANSI color codes.
1830 The setting of underline does not affect highlighting of matches.
1832 =item B<-v>, B<--invert-match>
1834 Invert match: select non-matching lines.
1838 Display version and copyright information.
1840 =item B<-w>, B<--word-regexp>
1842 Force PATTERN to match only whole words.
1846 An abbreviation for B<--files-from=->. The list of files to search are read
1847 from standard input, with one line per file.
1849 Note that the list of files is B<not> filtered in any way. If you add
1850 C<--type=html> in addition to C<-x>, the C<--type> will be ignored.
1854 Stops after reporting first match of any kind. This is different
1855 from B<--max-count=1> or B<-m1>, where only one match per file is
1856 shown. Also, B<-1> works with B<-f> and B<-g>, where B<-m> does
1861 Display the all-important Bill The Cat logo. Note that the exact
1862 spelling of B<--thpppppt> is not important. It's checked against
1863 a regular expression.
1867 Check with the admiral for traps.
1871 Chocolate, Chocolate, Chocolate!
1875 =head1 THE .ackrc FILE
1877 The F<.ackrc> file contains command-line options that are prepended
1878 to the command line before processing. Multiple options may live
1879 on multiple lines. Lines beginning with a # are ignored. A F<.ackrc>
1880 might look like this:
1882 # Always sort the files
1885 # Always color, even if piping to another program
1888 # Use "less -r" as my pager
1891 Note that arguments with spaces in them do not need to be quoted,
1892 as they are not interpreted by the shell. Basically, each I<line>
1893 in the F<.ackrc> file is interpreted as one element of C<@ARGV>.
1895 F<ack> looks in several locations for F<.ackrc> files; the searching
1896 process is detailed in L</"ACKRC LOCATION SEMANTICS">. These
1897 files are not considered if B<--noenv> is specified on the command line.
1899 =head1 Defining your own types
1901 ack allows you to define your own types in addition to the predefined
1902 types. This is done with command line options that are best put into
1903 an F<.ackrc> file - then you do not have to define your types over and
1904 over again. In the following examples the options will always be shown
1905 on one command line so that they can be easily copy & pasted.
1907 File types can be specified both with the I<--type=xxx> option,
1908 or the file type as an option itself. For example, if you create
1909 a filetype of "cobol", you can specify I<--type=cobol> or simply
1910 I<--cobol>. File types must be at least two characters long. This
1911 is why the C language is I<--cc> and the R language is I<--rr>.
1913 I<ack --perl foo> searches for foo in all perl files. I<ack --help-types>
1914 tells you, that perl files are files ending
1915 in .pl, .pm, .pod or .t. So what if you would like to include .xs
1916 files as well when searching for --perl files? I<ack --type-add perl:ext:xs --perl foo>
1917 does this for you. B<--type-add> appends
1918 additional extensions to an existing type.
1920 If you want to define a new type, or completely redefine an existing
1921 type, then use B<--type-set>. I<ack --type-set eiffel:ext:e,eiffel> defines
1922 the type I<eiffel> to include files with
1923 the extensions .e or .eiffel. So to search for all eiffel files
1924 containing the word Bertrand use I<ack --type-set eiffel:ext:e,eiffel --eiffel Bertrand>.
1925 As usual, you can also write B<--type=eiffel>
1926 instead of B<--eiffel>. Negation also works, so B<--noeiffel> excludes
1927 all eiffel files from a search. Redefining also works: I<ack --type-set cc:ext:c,h>
1928 and I<.xs> files no longer belong to the type I<cc>.
1930 When defining your own types in the F<.ackrc> file you have to use
1933 --type-set=eiffel:ext:e,eiffel
1935 or writing on separate lines
1940 The following does B<NOT> work in the F<.ackrc> file:
1942 --type-set eiffel:ext:e,eiffel
1944 In order to see all currently defined types, use I<--help-types>, e.g.
1945 I<ack --type-set backup:ext:bak --type-add perl:ext:perl --help-types>
1947 In addition to filtering based on extension, ack offers additional
1948 filter types. The generic syntax is
1949 I<--type-set TYPE:FILTER:ARGS>; I<ARGS> depends on the value
1954 =item is:I<FILENAME>
1956 I<is> filters match the target filename exactly. It takes exactly one
1957 argument, which is the name of the file to match.
1961 --type-set make:is:Makefile
1963 =item ext:I<EXTENSION>[,I<EXTENSION2>[,...]]
1965 I<ext> filters match the extension of the target file against a list
1966 of extensions. No leading dot is needed for the extensions.
1970 --type-set perl:ext:pl,pm,t
1972 =item match:I<PATTERN>
1974 I<match> filters match the target filename against a regular expression.
1975 The regular expression is made case-insensitive for the search.
1979 --type-set make:match:/(gnu)?makefile/
1981 =item firstlinematch:I<PATTERN>
1983 I<firstlinematch> matches the first line of the target file against a
1984 regular expression. Like I<match>, the regular expression is made
1989 --type-add perl:firstlinematch:/perl/
1995 ack allows customization of the colors it uses when presenting matches
1996 onscreen. It uses the colors available in Perl's L<Term::ANSIColor>
1997 module, which provides the following listed values. Note that case does not
1998 matter when using these values.
2000 There are four different colors ack uses:
2002 Aspect Option Env. variable Default
2003 -------- ----------------- ------------------ ---------------
2004 filename --color-filename ACK_COLOR_FILENAME black on_yellow
2005 match --color-match ACK_COLOR_MATCH bold green
2006 line no. --color-lineno ACK_COLOR_LINENO bold yellow
2007 column no. --color-colno ACK_COLOR_COLNO bold yellow
2009 The column number column is only used if the column number is shown because
2010 of the --column option.
2012 Colors may be specified by command-line option, such as
2013 C<ack --color-filename='red on_white'>, or by setting an environment
2014 variable, such as C<ACK_COLOR_FILENAME='red on_white'>. Options for colors
2015 can be set in your ACKRC file (See "THE .ackrc FILE").
2017 ack can understand the following colors for the foreground:
2019 black red green yellow blue magenta cyan white
2021 The optional background color is specified by prepending "on_" to one of
2022 the foreground colors:
2024 on_black on_red on_green on_yellow on_blue on_magenta on_cyan on_white
2026 Each of the foreground colors can be modified with the following
2027 attributes, which may or may not be supported by your terminal:
2029 bold faint italic underline blink reverse concealed
2031 Any combinations of modifiers can be added to the foreground color. If your
2032 terminal supports it, and you enjoy visual punishment, you can specify:
2034 ack --color-filename="blink italic underline bold red on_yellow"
2036 For charts of the colors and what they look like, run C<ack --help-colors>
2037 and C<ack --help-rgb-colors>.
2039 If the eight standard colors, in their bold, faint and unmodified states,
2040 aren't enough for you to choose from, you can also specify colors by their
2041 RGB values. They are specified as "rgbXYZ" where X, Y, and Z are values
2042 between 0 and 5 giving the intensity of red, green and blue, respectively.
2043 Therefore, "rgb500" is pure red, "rgb505" is purple, and so on.
2045 Background colors can be specified with the "on_" prefix prepended on an
2046 RGB color, so that "on_rgb505" would be a purple background.
2048 The modifier attributes of blink, italic, underscore and so on may or may
2049 not work on the RGB colors.
2051 For a chart of the 216 possible RGB colors, run C<ack --help-rgb-colors>.
2053 =head1 ENVIRONMENT VARIABLES
2055 For commonly-used ack options, environment variables can make life
2056 much easier. These variables are ignored if B<--noenv> is specified
2057 on the command line.
2063 Specifies the location of the user's F<.ackrc> file. If this file doesn't
2064 exist, F<ack> looks in the default location.
2066 =item ACK_COLOR_COLNO
2068 Color specification for the column number in ack's output. By default, the
2069 column number is not shown. You have to enable it with the B<--column>
2070 option. See the section "ack Colors" above.
2072 =item ACK_COLOR_FILENAME
2074 Color specification for the filename in ack's output. See the section "ack
2077 =item ACK_COLOR_LINENO
2079 Color specification for the line number in ack's output. See the section
2082 =item ACK_COLOR_MATCH
2084 Color specification for the matched text in ack's output. See the section
2089 Specifies a pager program, such as C<more>, C<less> or C<most>, to which
2090 ack will send its output.
2092 Using C<ACK_PAGER> does not suppress grouping and coloring like
2093 piping output on the command-line does, except that on Windows
2094 ack will assume that C<ACK_PAGER> does not support color.
2096 C<ACK_PAGER_COLOR> overrides C<ACK_PAGER> if both are specified.
2098 =item ACK_PAGER_COLOR
2100 Specifies a pager program that understands ANSI color sequences.
2101 Using C<ACK_PAGER_COLOR> does not suppress grouping and coloring
2102 like piping output on the command-line does.
2104 If you are not on Windows, you never need to use C<ACK_PAGER_COLOR>.
2108 =head1 ACK & OTHER TOOLS
2110 =head2 Simple vim integration
2112 F<ack> integrates easily with the Vim text editor. Set this in your
2113 F<.vimrc> to use F<ack> instead of F<grep>:
2117 That example uses C<-k> to search through only files of the types ack
2118 knows about, but you may use other default flags. Now you can search
2119 with F<ack> and easily step through the results in Vim:
2121 :grep Dumper perllib
2123 =head2 Editor integration
2125 Many users have integrated ack into their preferred text editors.
2126 For details and links, see L<https://beyondgrep.com/more-tools/>.
2128 =head2 Shell and Return Code
2130 For greater compatibility with I<grep>, I<ack> in normal use returns
2131 shell return or exit code of 0 only if something is found and 1 if
2134 (Shell exit code 1 is C<$?=256> in perl with C<system> or backticks.)
2136 The I<grep> code 2 for errors is not used.
2138 If C<-f> or C<-g> are specified, then 0 is returned if at least one
2139 file is found. If no files are found, then 1 is returned.
2143 =head1 DEBUGGING ACK PROBLEMS
2145 If ack gives you output you're not expecting, start with a few simple steps.
2147 =head2 Try it with B<--noenv>
2149 Your environment variables and F<.ackrc> may be doing things you're
2150 not expecting, or forgotten you specified. Use B<--noenv> to ignore
2151 your environment and F<.ackrc>.
2153 =head2 Use B<-f> to see what files have been selected for searching
2155 Ack's B<-f> was originally added as a debugging tool. If ack is
2156 not finding matches you think it should find, run F<ack -f> to see
2157 what files have been selected. You can also add the C<--show-types>
2158 options to show the type of each file selected.
2160 =head2 Use B<--dump>
2162 This lists the ackrc files that are loaded and the options loaded
2163 from them. You may be loading an F<.ackrc> file that you didn't know
2166 =head1 ACKRC LOCATION SEMANTICS
2168 Ack can load its configuration from many sources. The following list
2169 specifies the sources Ack looks for configuration files; each one
2170 that is found is loaded in the order specified here, and
2171 each one overrides options set in any of the sources preceding
2172 it. (For example, if I set --sort-files in my user ackrc, and
2173 --nosort-files on the command line, the command line takes
2180 Defaults are loaded from App::Ack::ConfigDefaults. This can be omitted
2181 using C<--ignore-ack-defaults>.
2183 =item * Global ackrc
2185 Options are then loaded from the global ackrc. This is located at
2186 C</etc/ackrc> on Unix-like systems.
2188 Under Windows XP and earlier, the global ackrc is at
2189 C<C:\Documents and Settings\All Users\Application Data\ackrc>
2191 Under Windows Vista/7, the global ackrc is at
2192 C<C:\ProgramData\ackrc>
2194 The C<--noenv> option prevents all ackrc files from being loaded.
2198 Options are then loaded from the user's ackrc. This is located at
2199 C<$HOME/.ackrc> on Unix-like systems.
2201 Under Windows XP and earlier, the user's ackrc is at
2202 C<C:\Documents and Settings\$USER\Application Data\ackrc>.
2204 Under Windows Vista/7, the user's ackrc is at
2205 C<C:\Users\$USER\AppData\Roaming\ackrc>.
2207 If you want to load a different user-level ackrc, it may be specified
2208 with the C<$ACKRC> environment variable.
2210 The C<--noenv> option prevents all ackrc files from being loaded.
2212 =item * Project ackrc
2214 Options are then loaded from the project ackrc. The project ackrc is
2215 the first ackrc file with the name C<.ackrc> or C<_ackrc>, first searching
2216 in the current directory, then the parent directory, then the grandparent
2217 directory, etc. This can be omitted using C<--noenv>.
2221 The C<--ackrc> option may be included on the command line to specify an
2222 ackrc file that can override all others. It is consulted even if C<--noenv>
2225 =item * Command line
2227 Options are then loaded from the command line.
2231 =head1 BUGS & ENHANCEMENTS
2233 ack is based at GitHub at L<https://github.com/beyondgrep/ack3>
2235 Please report any bugs or feature requests to the issues list at
2236 GitHub: L<https://github.com/beyondgrep/ack3/issues>.
2238 Please include the operating system that you're using; the output of
2239 the command C<ack --version>; and any customizations in your F<.ackrc>
2242 To suggest enhancements, please submit an issue at
2243 L<https://github.com/beyondgrep/ack3/issues>. Also read the
2244 F<DEVELOPERS.md> file in the ack code repository.
2246 Also, feel free to discuss your issues on the ack mailing
2247 list at L<https://groups.google.com/group/ack-users>.
2251 Support for and information about F<ack> can be found at:
2255 =item * The ack homepage
2257 L<https://beyondgrep.com/>
2259 =item * Source repository
2261 L<https://github.com/beyondgrep/ack3>
2263 =item * The ack issues list at GitHub
2265 L<https://github.com/beyondgrep/ack3/issues>
2267 =item * The ack announcements mailing list
2269 L<https://groups.google.com/group/ack-announcement>
2271 =item * The ack users' mailing list
2273 L<https://groups.google.com/group/ack-users>
2275 =item * The ack development mailing list
2277 L<https://groups.google.com/group/ack-users>
2283 There are ack mailing lists and a Slack channel for ack. See
2284 L<https://beyondgrep.com/community/> for details.
2288 This is the Frequently Asked Questions list for ack.
2290 =head2 Can I stop using grep now?
2292 Many people find I<ack> to be better than I<grep> as an everyday tool
2293 99% of the time, but don't throw I<grep> away, because there are times
2294 you'll still need it. For example, you might be looking through huge
2295 log files and not using regular expressions. In that case, I<grep>
2296 will probably perform better.
2298 =head2 Why isn't ack finding a match in (some file)?
2300 First, take a look and see if ack is even looking at the file. ack is
2301 intelligent in what files it will search and which ones it won't, but
2302 sometimes that can be surprising.
2304 Use the C<-f> switch, with no regex, to see a list of files that ack
2305 will search for you. If your file doesn't show up in the list of files
2306 that C<ack -f> shows, then ack never looks in it.
2308 =head2 Wouldn't it be great if F<ack> did search & replace?
2310 No, ack will always be read-only. Perl has a perfectly good way
2311 to do search & replace in files, using the C<-i>, C<-p> and C<-n>
2314 You can certainly use ack to select your files to update. For
2315 example, to change all "foo" to "bar" in all PHP files, you can do
2316 this from the Unix shell:
2318 $ perl -i -p -e's/foo/bar/g' $(ack -f --php)
2320 =head2 Can I make ack recognize F<.xyz> files?
2322 Yes! Please see L</"Defining your own types"> in the ack manual.
2324 =head2 Will you make ack recognize F<.xyz> files by default?
2326 We might, depending on how widely-used the file format is.
2328 Submit an issue at in the GitHub issue queue at
2329 L<https://github.com/beyondgrep/ack3/issues>. Explain what the file format
2330 is, where we can find out more about it, and what you have been using
2331 in your F<.ackrc> to support it.
2333 Please do not bother creating a pull request. The code for filetypes
2334 is trivial compared to the rest of the process we go through.
2336 =head2 Why is it called ack if it's called ack-grep?
2338 The name of the program is "ack". Some packagers have called it
2339 "ack-grep" when creating packages because there's already a package
2340 out there called "ack" that has nothing to do with this ack.
2342 I suggest you make a symlink named F<ack> that points to F<ack-grep>
2343 because one of the crucial benefits of ack is having a name that's
2344 so short and simple to type.
2346 To do that, run this with F<sudo> or as root:
2348 ln -s /usr/bin/ack-grep /usr/bin/ack
2350 Alternatively, you could use a shell alias:
2358 =head2 What does F<ack> mean?
2360 Nothing. I wanted a name that was easy to type and that you could
2361 pronounce as a single syllable.
2363 =head2 Can I do multi-line regexes?
2365 No, ack does not support regexes that match multiple lines. Doing
2366 so would require reading in the entire file at a time.
2368 If you want to see lines near your match, use the C<--A>, C<--B>
2369 and C<--C> switches for displaying context.
2371 =head2 Why is ack telling me I have an invalid option when searching for C<+foo>?
2373 ack treats command line options beginning with C<+> or C<-> as options; if you
2374 would like to search for these, you may prefix your search term with C<--> or
2375 use the C<--match> option. (However, don't forget that C<+> is a regular
2376 expression metacharacter!)
2378 =head2 Why does C<"ack '.{40000,}'"> fail? Isn't that a valid regex?
2380 The Perl language limits the repetition quantifier to 32K. You
2381 can search for C<.{32767}> but not C<.{32768}>.
2383 =head2 Ack does "X" and shouldn't, should it?
2385 We try to remain as close to grep's behavior as possible, so when in
2386 doubt, see what grep does! If there's a mismatch in functionality there,
2387 please submit an issue to GitHub, and/or bring it up on the ack-users
2392 =head1 ACKNOWLEDGEMENTS
2394 How appropriate to have I<ack>nowledgements!
2396 Thanks to everyone who has contributed to ack in any way, including
2408 Grzegorz Kaczmarczyk,
2425 SE<eacute>bastien FeugE<egrave>re,
2432 RaE<uacute>l GundE<iacute>n,
2438 RaE<aacute>l GundE<aacute>n,
2474 Eric Van Dewoestine,
2483 Christopher J. Madsen,
2495 GE<aacute>bor SzabE<oacute>,
2498 E<AElig>var ArnfjE<ouml>rE<eth> Bjarmason,
2502 Mark Leighton Fisher,
2508 Nilson Santos F. Jr,
2513 Ask BjE<oslash>rn Hansen,
2517 Slaven ReziE<0x107>,
2529 Andy Lester, C<< <andy at petdance.com> >>
2531 =head1 COPYRIGHT & LICENSE
2533 Copyright 2005-2025 Andy Lester.
2535 This program is free software; you can redistribute it and/or modify
2536 it under the terms of the Artistic License v2.0.
2538 See https://www.perlfoundation.org/artistic-license-20.html or the LICENSE.md
2539 file that comes with the ack distribution.
2555 $VERSION = 'v3.9.0'; # Check https://beyondgrep.com/ for updates
2556 $COPYRIGHT = 'Copyright 2005-2025 Andy Lester.';
2558 our $STANDALONE = 0;
2559 our $ORIGINAL_PROGRAM_NAME;
2573 our $is_filter_mode;
2574 our $output_to_pipe;
2578 our $debug_nopens = 0;
2580 # Line ending, changes to "\0" if --print0.
2584 # These have to be checked before any filehandle diddling.
2585 $output_to_pipe = not -t
*STDOUT
;
2586 $is_filter_mode = -p STDIN
;
2588 $is_windows = ($^O eq 'MSWin32');
2593 return CORE
::warn( _my_program
(), ': ', @_, "\n" );
2598 return CORE
::die( _my_program
(), ': ', @_, "\n" );
2602 require File
::Basename
;
2603 return File
::Basename
::basename
( $0 );
2608 my $y = q{_ /|,\\'!.x',=(www)=, U };
2609 $y =~ tr/,x!w/\nOo_/;
2611 App
::Ack
::print( "$y ack $_[0]!\n" );
2619 3~!I#7#I"7#I!?!+!="+"="+!:!
2620 2?#I!7!I!?#I!7!I"+"=%+"=#
2621 1?"+!?*+!=#~"=!+#?"="+!
2622 0?"+!?"I"?&+!="~!=!~"=!+%="+"
2623 /I!+!?)+!?!+!=$~!=!~!="+!="+"?!="?!
2625 ,,!?%I"?(+$=$~!=#:"~$:!~!
2626 ,I!?!I!?"I"?!+#?"+!?!+#="~$:!~!:!~!:!,!:!,":#~!
2627 +I!?&+!="+!?#+$=!~":!~!:!~!:!,!:#,!:!,%:"
2628 *+!I!?!+$=!+!=!+!?$+#=!~":!~":#,$:",#:!,!:!
2629 *I!?"+!?!+!=$+!?#+#=#~":$,!:",!:!,&:"
2630 )I!?$=!~!=#+"?!+!=!+!=!~!="~!:!~":!,'.!,%:!~!
2631 (=!?"+!?!=!~$?"+!?!+!=#~"=",!="~$,$.",#.!:!=!
2632 (I"+"="~"=!+&=!~"=!~!,!~!+!=!?!+!?!=!I!?!+"=!.",!.!,":!
2633 %I$?!+!?!=%+!~!+#~!=!~#:#=!~!+!~!=#:!,%.!,!.!:"
2634 $I!?!=!?!I!+!?"+!=!~!=!~!?!I!?!=!+!=!~#:",!~"=!~!:"~!=!:",&:" '-/
2635 $?!+!I!?"+"=!+"~!,!:"+#~#:#,"=!~"=!,!~!,!.",!:".!:! */! !I!t!'!s! !a! !g!r!e!p!!! !/!
2636 $+"=!+!?!+"~!=!:!~!:"I!+!,!~!=!:!~!,!:!,$:!~".&:"~!,# (-/
2637 %~!=!~!=!:!.!+"~!:!,!.!,!~!=!:$.!,":!,!.!:!~!,!:!=!.#="~!,!:" ./!
2638 %=!~!?!+"?"+!=!~",!.!:!?!~!.!:!,!:!,#.!,!:","~!:!=!~!=!:",!~! ./!
2639 %+"~":!~!=#~!:!~!,!.!~!:",!~!=!~!.!:!,!.",!:!,":!=":!.!,!:!7! -/!
2640 %~",!:".#:!=!:!,!:"+!:!~!:!.!,!~!,!.#,!.!,$:"~!,":"~!=! */!
2641 &=!~!=#+!=!~",!.!:",#:#,!.",+:!,!.",!=!+!?!
2642 &~!=!~!=!~!:"~#:",!.!,#~!:!.!+!,!.",$.",$.#,!+!I!?!
2643 &~!="~!:!~":!~",!~!=!~":!,!:!~!,!:!,&.$,#."+!?!I!?!I!
2644 &~!=!~!=!+!,!:!~!:!=!,!:!~&:$,!.!,".!,".!,#."~!+!?$I!
2645 &~!=!~!="~!=!:!~":!,!~%:#,!:",!.!,#.",#I!7"I!?!+!?"I"
2646 &+!I!7!:#~"=!~!:!,!:"~$.!=!.!,!~!,$.#,!~!7!I#?!+!?"I"7!
2647 %7#?!+!~!:!=!~!=!~":!,!:"~":#.!,)7#I"?"I!7&
2648 %7#I!=":!=!~!:"~$:"~!:#,!:!,!:!~!:#,!7#I!?#7)
2649 $7$+!,!~!=#~!:!~!:!~$:#,!.!~!:!=!,":!7#I"?#7+=!?!
2650 $7#I!~!,!~#=!~!:"~!:!,!:!,#:!=!~",":!7$I!?#I!7*+!=!+"
2651 "I!7$I!,":!,!.!=":$,!:!,$:$7$I!+!?"I!7+?"I!7!I!7!,!
2652 !,!7%I!:",!."~":!,&.!,!:!~!I!7$I!+!?"I!7,?!I!7',!
2653 !7(,!.#~":!,%.!,!7%I!7!?#I"7,+!?!7*
2654 7+:!,!~#,"=!7'I!?#I"7/+!7+
2655 77I!+!7!?!7!I"71+!7,
2658 return _pic_decode
($x);
2664 0|! "C!H!O!C!O!L!A!T!E!!! !|!
2665 0|! "C!H!O!C!O!L!A!T!E!!! !|!
2666 0|! "C!H!O!C!O!L!A!T!E!!! !|!
2672 4.! $\! /M!~!.!8! +.!M# 4
2673 0,!.! (\! .~!M!N! ,+!I!.!M!.! 3
2674 /?!O!.!M!:! '\! .O!.! +~!Z!=!N!.! 4
2675 ..! !D!Z!.!Z!.! '\! 9=!M".! 6
2676 /.! !.!~!M".! '\! 8~! 9
2678 4.! &:!M! !N"M# !M"N!M! #D!M&=! =
2679 :M!7!M#:! !~!M!7!,!$!M!:! #.! !O!N!.!M!:!M# ;
2680 8Z!M"~!N!$!D!.!N!?! !I!N!.! (?!M! !M!,!D!M".! 9
2681 (?!Z!M!N!:! )=!M!O!8!.!M!+!M! !M!,! !O!M! +,!M!.!M!~!Z!N!M!:! &:!~! 0
2682 &8!7!.!~!M"D!M!,! &M!?!=!8! !M!,!O! !M!+! !+!O!.!M! $M#~! !.!8!M!Z!.!M! !O!M"Z! %:!~!M!Z!M!Z!.! +
2683 &:!M!7!,! *M!.!Z!M! !8"M!.!M!~! !.!M!.!=! #~!8!.!M! !7!M! "N!Z#I! !D!M!,!M!.! $."M!,! !M!.! *
2684 2$!O! "N! !.!M!I! !7" "M! "+!O! !~!M! !d!O!.!7!I!M!.! !.!O!=!M!.! !M",!M!.! %.!$!O!D! +
2685 1~!O! "M!+! !8!$! "M! "?!O! %Z!8!D!M!?!8!I!O!7!M! #M!.!M! "M",!M! 4
2686 07!~! ".!8! !.!M! "I!+! !.!M! &Z!D!.!7!=!M! !:!.!M! #:!8"+! !.!+!8! !8! 3
2687 /~!M! #N! !~!M!$! !.!M! !.!M" &~!M! "~!M!O! "D! $M! !8! "M!,!M!+!D!.! 1
2688 #.! #?!M!N!.! #~!O! $M!.!7!$! "?" !?!~!M! '7!8!?!M!.!+!M"O! $?"$!D! !.!O! !$!7!I!.! 0
2689 $,!M!:!O!?! ".! !?!=! $=!:!O! !M! "M! !M! !+!$! (.! +.!M! !M!.! !8! !+"Z!~! $:!M!$! !.! '
2690 #.!8!.!I!$! $7!I! %M" !=!M! !~!M!D! "7!I! .I!O! %?!=!,!D! !,!M! !D!~!8!~! %D!M! (
2691 #.!M"?! $=!O! %=!N! "8!.! !Z!M! #M!~! (M!:! #.!M" &O! !M!.! !?!,! !8!.!N!~! $8!N!M!,!.! %
2692 *$!O! &M!,! "O! !.!M!.! #M! (~!M( &O!.! !7! "M! !.!M!.!M!,! #.!M! !M! &
2693 )=!8!.! $.!M!O!.! "$!.!I!N! !I!M# (7!M(I! %D"Z!M! "=!I! "M! !M!:! #~!D! '
2694 )D! &8!N!:! ".!O! !M!="M! "M! (7!M) %." !M!D!."M!.! !$!=! !M!,! +
2695 (M! &+!.!M! #Z!7!O!M!.!~!8! +,!M#D!?!M#D! #.!Z!M#,!Z!?! !~!N! "N!.! !M! +
2696 'D!:! %$!D! !?! #M!Z! !8!.! !M"?!7!?!7! '+!I!D! !?!O!:!M!:! ":!M!:! !M!7".!M! "8!+! !:!D! !.!M! *
2697 %.!O!:! $.!O!+! !D!.! #M! "M!.!+!N!I!Z! "7!M!N!M!N!?!I!7!Z!=!M'D"~! #M!.!8!$! !:! !.!M! "N!?! !,!O! )
2698 !.!?!M!:!M!I! %8!,! "M!.! #M! "N! !M!.! !M!.! !+!~! !.!M!.! ':!M! $M! $M!Z!$! !M!.! "D! "M! "?!M! (
2699 !7!8! !+!I! ".! "$!=! ":!$! "+! !M!.! !O! !M!I!M".! !=!~! ",!O! '=!M! $$!,! #N!:! ":!8!.! !D!~! !,!M!.! !:!M!.! &
2700 !:!,!.! &Z" #D! !.!8!."M!.! !8!?!Z!M!.!M! #Z!~! !?!M!Z!.! %~!O!.!8!$!N!8!O!I!:!~! !+! #M!.! !.!M!.! !+!M! ".!~!M!+! $
2701 !.! 'D!I! #?!M!.!M!,! !.!Z! !.!8! #M&O!I!?! (~!I!M"." !M!Z!.! !M!N!.! "+!$!.! "M!.! !M!?!.! "8!M! $
2702 (O!8! $M! !M!.! ".!:! !+!=! #M! #.!M! !+" *$!M":!.! !M!~! "M!7! #M! #7!Z! "M"$!M!.! !.! #
2703 '$!Z! #.!7!+!M! $.!,! !+!:! #N! #.!M!.!+!M! +D!M! #=!N! ":!O! #=!M! #Z!D! $M!I! %
2704 $,! ".! $.!M" %$!.! !?!~! "+!7!." !.!M!,! !M! *,!N!M!.$M!?! "D!,! #M!.! #N! +
2705 ,M!Z! &M! "I!,! "M! %I!M! !?!=!.! (Z!8!M! $:!M!.! !,!M! $D! #.!M!.! )
2706 +8!O! &.!8! "I!,! !~!M! &N!M! !M!D! '?!N!O!." $?!7! "?!~! #M!.! #I!D!.! (
2707 3M!,! "N!.! !D" &.!+!M!.! !M":!.":!M!7!M!D! 'M!.! "M!.! "M!,! $I! )
2708 3I! #M! "M!,! !:! &.!M" ".!,! !.!$!M!I! #.! !:! !.!M!?! "N!+! ".! /
2709 1M!,! #.!M!8!M!=!.! +~!N"O!Z"~! *+!M!.! "M! 2
2710 0.!M! &M!.! 8:! %.!M!Z! "M!=! *O!,! %
2711 0?!$! &N! )." .,! %."M! ":!M!.! 0
2712 0N!:! %?!O! #.! ..! &,! &.!D!,! "N!I! 0
2714 return _pic_decode
($x);
2718 my($compressed) = @_;
2719 $compressed =~ s/(.)(.)/$1x(ord($2)-32)/eg;
2720 App
::Ack
::print( $compressed );
2726 App
::Ack
::print( <<"END_OF_HELP" );
2727 Usage: ack [OPTION]... PATTERN [FILES OR DIRECTORIES]
2729 Search for PATTERN in each source file in the tree from the current
2730 directory on down. If any files or directories are specified, then
2731 only those files and directories are checked. ack may also search
2732 STDIN, but only if no file or directory arguments are specified,
2733 or if one of them is "-".
2735 Default switches may be specified in an .ackrc file. If you want no dependency
2736 on the environment, turn it off with --noenv.
2738 File select actions:
2739 -f Only print the files selected, without
2740 searching. The PATTERN must not be specified.
2741 -g Same as -f, but only select files matching
2744 File listing actions:
2745 -l, --files-with-matches Print filenames with at least one match
2746 -L, --files-without-matches Print filenames with no matches
2747 -c, --count Print filenames and count of matching lines
2750 -i, --ignore-case Ignore case distinctions in PATTERN
2751 -S, --[no]smart-case Ignore case distinctions in PATTERN,
2752 only if PATTERN contains no upper case.
2753 Ignored if -i or -I are specified.
2754 -I, --no-ignore-case Turns on case-sensitivity in PATTERN.
2755 Negates -i and --smart-case.
2756 -v, --invert-match Invert match: select non-matching lines
2757 -w, --word-regexp Force PATTERN to match only whole words
2758 -Q, --literal Quote all metacharacters; PATTERN is literal
2759 --range-start PATTERN Specify PATTERN as the start of a match range.
2760 --range-end PATTERN Specify PATTERN as the end of a match range.
2761 --match PATTERN Specify PATTERN explicitly. Typically omitted.
2762 --and PATTERN Specifies PATTERN that MUST also be found on
2763 the line for a match to occur. Repeatable.
2764 --or PATTERN Specifies PATTERN that MAY also be found on
2765 the line for a match to occur. Repeatable.
2766 --not PATTERN Specifies PATTERN that must NOT be found on
2767 the line for a match to occur. Repeatable.
2770 --output=expr Output the evaluation of expr for each line
2771 (turns off text highlighting)
2772 -o Show only the part of a line matching PATTERN
2773 Same as --output='\$&'
2774 --passthru Print all lines, whether matching or not
2775 -m, --max-count=NUM Stop searching in each file after NUM matches
2776 -1 Stop searching after one match of any kind
2777 -H, --with-filename Print the filename for each match (default:
2778 on unless explicitly searching a single file)
2779 -h, --no-filename Suppress the prefixing filename on output
2780 --[no]column Show the column number of the first match
2782 -A NUM, --after-context=NUM Print NUM lines of trailing context after
2784 -B NUM, --before-context=NUM Print NUM lines of leading context before
2786 -C [NUM], --context[=NUM] Print NUM lines (default 2) of output context.
2788 --print0 Print null byte as separator between filenames,
2789 only works with -f, -g, -l, -L or -c.
2791 -s Suppress error messages about nonexistent or
2796 --pager=COMMAND Pipes all ack output through COMMAND. For
2797 example, --pager="less -R". Ignored if output
2799 --nopager Do not send output through a pager. Cancels
2800 any setting in ~/.ackrc, ACK_PAGER or
2802 --[no]heading Print a filename heading above each file's
2803 results. (default: on when used interactively)
2804 --[no]break Print a break between results from different
2805 files. (default: on when used interactively)
2806 --group Same as --heading --break
2807 --nogroup Same as --noheading --nobreak
2808 -p, --proximate=LINES Separate match output with blank lines unless
2809 they are within LINES lines from each other.
2810 -P, --proximate=0 Negates --proximate.
2811 --[no]underline Print a line of carets under the matched text.
2812 --[no]color, --[no]colour Highlight the matching text (default: on unless
2813 output is redirected, or on Windows)
2814 --color-filename=COLOR
2817 --color-lineno=COLOR Set the color for filenames, matches, line and
2819 --help-colors Show a list of possible color combinations.
2820 --help-rgb-colors Show a list of advanced RGB colors.
2821 --flush Flush output immediately, even when ack is used
2822 non-interactively (when output goes to a pipe or
2827 --sort-files Sort the found files lexically.
2828 --show-types Show which types each file has.
2829 --files-from=FILE Read the list of files to search from FILE.
2830 -x Read the list of files to search from STDIN.
2832 File inclusion/exclusion:
2833 --[no]ignore-dir=name Add/remove directory from list of ignored dirs
2834 --[no]ignore-directory=name Synonym for ignore-dir
2835 --ignore-file=FILTER:ARGS Add filter for ignoring files.
2836 -r, -R, --recurse Recurse into subdirectories (default: on)
2837 -n, --no-recurse No descending into subdirectories
2838 --[no]follow Follow symlinks. Default is off.
2840 File type inclusion/exclusion:
2841 -t X, --type=X Include only X files, where X is a filetype,
2842 e.g. python, html, markdown, etc
2843 -T X, --type=noX Exclude X files, where X is a filetype.
2844 -k, --known-types Include only files of types that ack recognizes.
2845 --help-types Display all known types, and how they're defined.
2847 File type specification:
2848 --type-set=TYPE:FILTER:ARGS Files with the given ARGS applied to the given
2849 FILTER are recognized as being of type TYPE.
2850 This replaces an existing definition for TYPE.
2851 --type-add=TYPE:FILTER:ARGS Files with the given ARGS applied to the given
2852 FILTER are recognized as being type TYPE.
2853 --type-del=TYPE Removes all filters associated with TYPE.
2856 --version Display version & copyright
2857 --[no]env Ignore environment variables and global ackrc
2858 files. --env is legal but redundant.
2859 --ackrc=filename Specify an ackrc file to use
2860 --ignore-ack-defaults Ignore default definitions included with ack.
2861 --create-ackrc Outputs a default ackrc for your customization
2863 --dump Dump information on which options are loaded
2864 and where they're defined.
2865 --[no]filter Force ack to treat standard input as a pipe
2866 (--filter) or tty (--nofilter)
2868 --man Print the manual.
2869 --help-types Display all known types, and how they're defined.
2870 --help-colors Show a list of possible color combinations.
2871 --help-rgb-colors Show a list of advanced RGB colors.
2872 --thpppt Bill the Cat
2873 --bar The warning admiral
2874 --cathy Chocolate! Chocolate! Chocolate!
2876 Filter specifications:
2877 If FILTER is "ext", ARGS is a list of extensions checked against the
2879 If FILTER is "is", ARGS must match the file's name exactly.
2880 If FILTER is "match", ARGS is matched as a case-insensitive regex
2881 against the filename.
2882 If FILTER is "firstlinematch", ARGS is matched as a regex the first
2883 line of the file's contents.
2885 Exit status is 0 if match, 1 if no match.
2887 ack's home page is at https://beyondgrep.com/
2889 The full ack manual is available by running "ack --man".
2891 This is version $App::Ack::VERSION of ack. Run "ack --version" for full version info.
2899 sub show_help_types
{
2900 App
::Ack
::print( <<'END_OF_HELP' );
2901 Usage: ack [OPTION]... PATTERN [FILES OR DIRECTORIES]
2903 The following is the list of filetypes supported by ack. You can specify a
2904 filetype to include with -t TYPE or --type=TYPE. You can exclude a
2905 filetype with -T TYPE or --type=noTYPE.
2907 Note that some files may appear in multiple types. For example, a file
2908 called Rakefile is both Ruby (--type=ruby) and Rakefile (--type=rakefile).
2912 my @types = keys %App::Ack
::mappings
;
2915 $maxlen = length if $maxlen < length;
2917 for my $type ( sort @types ) {
2918 next if $type =~ /^-/; # Stuff to not show
2919 my $ext_list = $mappings{$type};
2921 if ( ref $ext_list ) {
2922 $ext_list = join( '; ', map { $_->to_string } @{$ext_list} );
2924 App
::Ack
::print( sprintf( " %-*.*s %s\n", $maxlen, $maxlen, $type, $ext_list ) );
2932 sub show_help_colors
{
2933 App
::Ack
::print( <<'END_OF_HELP' );
2934 ack allows customization of the colors it uses when presenting matches
2935 onscreen. See the "ACK COLORS" section of the ack manual (ack --man).
2937 Here is a chart of how various color combinations appear: Each of the eight
2938 foreground colors, on each of the eight background colors or no background
2939 color, with and without the bold modifier.
2941 Run ack --help-rgb-colors for a chart of the RGB colors.
2953 App
::Ack
::print( <<'END_OF_HELP' );
2954 ack allows customization of the colors it uses when presenting matches
2955 onscreen. See the "ACK COLORS" section of the ack manual (ack --man).
2957 Colors may be specified as "rgbNNN" where "NNN" is a triplet of digits
2958 from 0 to 5 specifying the intensity of red, green and blue, respectively.
2960 Here is a grid of the 216 possible values for NNN.
2966 App
::Ack
::say( 'Here are the 216 possible colors with the "reverse" modifier applied.', "\n" );
2968 _show_rgb_grid
( 'reverse' );
2974 sub _show_color_grid
{
2977 my @fg_colors = qw( black red green yellow blue magenta cyan white );
2978 my @bg_colors = map { "on_$_" } @fg_colors;
2982 map { _color_cell
( $_ ) } @fg_colors
2987 map { _color_cell
( '-' x
$cell_width ) } @fg_colors
2990 for my $bg ( '', @bg_colors ) {
2993 ( map { _color_cell
( $_, "$_ $bg" ) } @fg_colors ),
2998 _color_cell
( 'bold' ),
2999 ( map { _color_cell
( $_, "bold $_ $bg" ) } @fg_colors ),
3014 $text = sprintf( '%-*s', $cell_width, $text );
3016 return ($color ? Term
::ANSIColor
::colored
( $text, $color ) : $text) . ' ';
3020 sub _show_rgb_grid
{
3021 my $modifier = shift // '';
3023 my $grid = <<'HERE';
3024 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
3025 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
3026 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
3027 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
3028 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
3029 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
3030 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
3031 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
3033 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
3035 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
3037 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
3039 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
3041 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
3042 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
3044 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
3046 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
3047 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
3048 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
3049 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
3050 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
3051 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
3054 $grid =~ s/(\d\d\d)/Term::ANSIColor::colored( "$1", "$modifier rgb$1" )/eg;
3056 App
::Ack
::say( $grid );
3064 Pod
::Usage
::pod2usage
({
3065 -input
=> $App::Ack
::ORIGINAL_PROGRAM_NAME
,
3075 sub get_version_statement
{
3078 my $copyright = $App::Ack
::COPYRIGHT
;
3079 my $this_perl = $Config::Config
{perlpath
};
3081 my $ext = $Config::Config
{_exe
};
3082 $this_perl .= $ext unless $this_perl =~ m/$ext$/i;
3084 my $perl_ver = sprintf( 'v%vd', $^V );
3086 my $build_type = $App::Ack
::STANDALONE
? 'standalone version' : 'standard build';
3088 return <<"END_OF_VERSION";
3089 ack $App::Ack::VERSION ($build_type)
3090 Running under Perl $perl_ver at $this_perl
3094 This program is free software. You may modify or distribute it
3095 under the terms of the Artistic License v2.0.
3100 sub print { print {$fh} @_; return; }
3101 sub say { print {$fh} @_, $ors; return; }
3102 sub print_blank_line
{ print {$fh} "\n"; return; }
3105 my $command = shift;
3107 return if App
::Ack
::output_to_pipe
();
3110 if ( not open( $pager, '|-', $command ) ) {
3111 App
::Ack
::die( qq{Unable to pipe to pager "$command": $!} );
3119 sub output_to_pipe
{
3120 return $output_to_pipe;
3125 my $nmatches = shift;
3127 my $rc = $nmatches ? 0 : 1;
3135 my @types = filetypes
( $file );
3136 my $arrow = @types ? ' => ' : ' =>';
3137 App
::Ack
::say( $file->name, $arrow, join( ',', @types ) );
3148 foreach my $k (keys %App::Ack
::mappings
) {
3149 my $filters = $App::Ack
::mappings
{$k};
3151 foreach my $filter (@{$filters}) {
3153 my $clone = $file->clone;
3154 if ( $filter->filter($clone) ) {
3161 # https://metacpan.org/pod/distribution/Perl-Critic/lib/Perl/Critic/Policy/Subroutines/ProhibitReturnSort.pm
3162 @matches = sort @matches;
3170 # The simplest case.
3171 return 1 if lc($pat) eq $pat;
3173 # If we have capitals, then go clean up any metacharacters that might have capitals.
3175 # Get rid of any literal backslashes first to avoid confusion.
3178 my $metacharacter = qr{
3179 |\\A
# Beginning of string
3180 |\\B
# Not word boundary
3181 |\\c
[a-zA-Z
] # Control characters
3182 |\\D
# Non-digit character
3183 |\\G
# End-of-match position of prior match
3184 |\\H
# Not horizontal whitespace
3185 |\\K
# Keep to the left
3186 |\\N
(\
{.+?\
})? # Anything but \n, OR Unicode sequence
3187 |\\[pP
]\
{.+?\
} # Named property and negation
3188 |\\[pP
][A-Z
] # Named property and negation, single-character shorthand
3190 |\\S
# Non-space character
3191 |\\V
# Not vertical whitespace
3192 |\\W
# Non-word character
3194 |\\x
[0-9A-Fa-f
]{2} # Hex sequence
3195 |\\Z
# End of string
3197 $pat =~ s/$metacharacter//g;
3199 my $name = qr/[_A-Za-z][_A-Za-z0-9]*?/;
3200 # Eliminate named captures.
3201 $pat =~ s/\(\?'$name'//g;
3202 $pat =~ s/\(\?<$name>//g;
3204 # Eliminate named backreferences.
3205 $pat =~ s/\\k'$name'//g;
3206 $pat =~ s/\\k<$name>//g;
3207 $pat =~ s/\\k\{$name\}//g;
3209 # Now with those metacharacters and named things removed, now see if it's lowercase.
3210 return 1 if lc($pat) eq $pat;
3216 # Returns a regex object based on a string and command-line options.
3217 # Dies when the regex $str is undefined (i.e. not given on command line).
3223 # Check for lowercaseness before we do any modifications.
3224 my $regex_is_lc = App
::Ack
::is_lowercase
( $str );
3227 $str = quotemeta( $str );
3230 # Compile the regex to see if it dies or throws warnings.
3231 local $SIG{__WARN__
} = sub { CORE
::die @_ }; # Anything that warns becomes a die.
3232 my $scratch_regex = eval { qr/$str/ };
3233 if ( not $scratch_regex ) {
3237 if ( $err =~ m{^(.+?); marked by <-- HERE in m/(.+?) <-- HERE} ) {
3238 my ($why, $where) = ($1,$2);
3239 my $pointy = ' ' x
(6+length($where)) . '^---HERE';
3240 App
::Ack
::die( "Invalid regex '$str'\nRegex: $str\n$pointy $why" );
3243 App
::Ack
::die( "Invalid regex '$str'\n$err" );
3248 my $scan_str = $str;
3254 if ( $str =~ /^\\[wd]/ ) {
3255 # Explicit \w is good.
3258 # Can start with \w, (, [ or dot.
3259 if ( $str !~ /^[\w\(\[\.]/ ) {
3264 # Can end with \w, }, ), ], +, *, or dot.
3265 if ( $str !~ /[\w\}\)\]\+\*\?\.]$/ ) {
3268 # ... unless it's escaped.
3269 elsif ( $str =~ /\\[\}\)\]\+\*\?\.]$/ ) {
3274 App
::Ack
::die( '-w will not do the right thing if your regex does not begin and end with a word character.' );
3277 if ( $str =~ /^\w+$/ ) {
3278 # No need for fancy regex if it's a simple word.
3279 $str = sprintf( '\b(?:%s)\b', $str );
3282 $str = sprintf( '(?:^|\b|\s)\K(?:%s)(?=\s|\b|$)', $str );
3286 if ( $opt->{i
} || ($opt->{S
} && $regex_is_lc) ) {
3287 $_ = "(?i)$_" for ( $str, $scan_str );
3290 my $scan_regex = undef;
3291 my $regex = eval { qr/$str/ };
3293 if ( $scan_str !~ /\$/ ) {
3294 # No line_scan is possible if there's a $ in the regex.
3295 $scan_regex = eval { qr/$scan_str/m };
3301 App
::Ack
::die( "Invalid regex '$str':\n $err" );
3304 return ($regex, $scan_regex);
3308 sub build_all_regexes
{
3309 my $opt_regex = shift;
3319 # AND: alpha AND beta
3320 if ( @parts = @{$opt->{and}} ) {
3324 for my $part ( @parts ) {
3325 my ($match, undef) = build_regex
( $part, $opt );
3326 push @match_parts, "(?=.*$match)";
3327 push @hilite_parts, $match;
3330 my ($match, $scan) = build_regex
( $opt_regex, $opt );
3331 push @match_parts, ".*$match";
3332 push @hilite_parts, $match;
3334 $re_match = join( '', @match_parts );
3335 $re_hilite = join( '|', @hilite_parts );
3339 elsif ( @parts = @{$opt->{or}} ) {
3343 for my $part ( $opt_regex, @parts ) {
3344 my ($match, $scan) = build_regex
( $part, $opt );
3345 push @match_parts, $match;
3346 push @scan_parts, $scan;
3349 $re_match = join( '|', @match_parts );
3350 $re_hilite = $re_match;
3351 $re_scan = join( '|', @scan_parts );
3354 ($re_match, $re_scan) = build_regex
( $opt_regex, $opt );
3355 $re_hilite = $re_match;
3358 # The --not does not affect the main regex. It is checked separately.
3359 # NOT: alpha NOT beta
3360 if ( @parts = @{$opt->{not}} ) {
3362 for my $part ( @parts ) {
3363 (my $re, undef) = build_regex
( $part, $opt );
3364 push @not_parts, $re;
3366 $re_not = join( '|', @not_parts );
3369 return ($re_match, $re_not, $re_hilite, $re_scan);
3373 1; # End of App::Ack
3376 package App
::Ack
::ConfigDefault
;
3385 return split( /\n/, _options_block
() );
3390 return grep { /./ && !/^#/ } options
();
3394 sub _options_block
{
3395 my $lines = <<'HERE';
3396 # This is the default ackrc for ack version ==VERSION==.
3398 # There are four different ways to match
3400 # is: Match the filename exactly
3402 # ext: Match the extension of the filename exactly
3404 # match: Match the filename against a Perl regular expression
3406 # firstlinematch: Match the first 250 characters of the first line
3407 # of text against a Perl regular expression. This is only for
3408 # the --type-add option.
3411 ### Directories to ignore
3414 # https://bazaar.canonical.com/
3415 --ignore-directory=is:.bzr
3418 # http://freshmeat.sourceforge.net/projects/codeville
3419 --ignore-directory=is:.cdv
3421 # Interface Builder (Xcode)
3422 # https://en.wikipedia.org/wiki/Interface_Builder
3423 --ignore-directory=is:~.dep
3424 --ignore-directory=is:~.dot
3425 --ignore-directory=is:~.nib
3426 --ignore-directory=is:~.plst
3429 # https://git-scm.com/
3430 --ignore-directory=is:.git
3431 # When submodules are used, .git is a file.
3432 --ignore-file=is:.git
3435 # https://www.mercurial-scm.org/
3436 --ignore-directory=is:.hg
3439 # https://directory.fsf.org/wiki/Quilt
3440 --ignore-directory=is:.pc
3443 # https://subversion.apache.org/
3444 --ignore-directory=is:.svn
3447 # https://www.monotone.ca/
3448 --ignore-directory=is:_MTN
3451 # https://savannah.nongnu.org/projects/cvs
3452 --ignore-directory=is:CVS
3455 # https://www.gnu.org/software/rcs/
3456 --ignore-directory=is:RCS
3459 # https://en.wikipedia.org/wiki/Source_Code_Control_System
3460 --ignore-directory=is:SCCS
3464 --ignore-directory=is:_darcs
3467 --ignore-directory=is:_sgbak
3470 # https://www.gnu.org/software/autoconf/
3471 --ignore-directory=is:autom4te.cache
3473 # Perl module building
3474 --ignore-directory=is:blib
3475 --ignore-directory=is:_build
3477 # Perl Devel::Cover module's output directory
3478 # https://metacpan.org/release/Devel-Cover
3479 --ignore-directory=is:cover_db
3481 # Node modules created by npm
3482 --ignore-directory=is:node_modules
3485 # https://www.cmake.org/
3486 --ignore-directory=is:CMakeFiles
3488 # Eclipse workspace folder
3489 # https://eclipse.org/
3490 --ignore-directory=is:.metadata
3492 # Cabal (Haskell) sandboxes
3493 # https://www.haskell.org/cabal/users-guide/installing-packages.html
3494 --ignore-directory=is:.cabal-sandbox
3497 # https://docs.python.org/3/tutorial/modules.html
3498 --ignore-directory=is:__pycache__
3499 --ignore-directory=is:.pytest_cache
3501 # macOS Finder remnants
3502 --ignore-directory=is:__MACOSX
3503 --ignore-file=is:.DS_Store
3508 --ignore-file=ext:bak
3509 --ignore-file=match:/~$/
3512 --ignore-file=match:/^#.+#$/
3514 # vi/vim swap files https://www.vim.org/
3515 --ignore-file=match:/[._].*[.]swp$/
3518 --ignore-file=match:/core[.]\d+$/
3520 # minified JavaScript
3521 --ignore-file=match:/[.-]min[.]js$/
3522 --ignore-file=match:/[.]js[.]min$/
3525 --ignore-file=match:/[.]min[.]css$/
3526 --ignore-file=match:/[.]css[.]min$/
3528 # JS and CSS source maps
3529 --ignore-file=match:/[.]js[.]map$/
3530 --ignore-file=match:/[.]css[.]map$/
3532 # PDFs, because they pass Perl's -T detection
3533 --ignore-file=ext:pdf
3535 # Common graphics, just as an optimization
3536 --ignore-file=ext:gif,jpg,jpeg,png
3538 # Common archives, as an optimization
3539 --ignore-file=ext:gz,tar,tgz,zip
3541 # Python compiled modules
3542 --ignore-file=ext:pyc,pyd,pyo
3544 # Python's pickle serialization format
3545 # https://docs.python.org/2/library/pickle.html#example
3546 # https://docs.python.org/3.7/library/pickle.html#examples
3547 --ignore-file=ext:pkl,pickle
3550 --ignore-file=ext:so
3552 # Compiled gettext files
3553 --ignore-file=ext:mo
3555 # Visual Studio user and workspace settings
3556 # https://code.visualstudio.com/docs/getstarted/settings
3557 --ignore-dir=is:.vscode
3559 ### Filetypes defined
3562 # https://www.gnu.org/s/make/
3563 --type-add=make:ext:mk
3564 --type-add=make:ext:mak
3565 --type-add=make:is:makefile
3566 --type-add=make:is:Makefile
3567 --type-add=make:is:Makefile.Debug
3568 --type-add=make:is:Makefile.Release
3569 --type-add=make:is:GNUmakefile
3572 # https://rake.rubyforge.org/
3573 --type-add=rake:is:Rakefile
3576 # https://cmake.org/
3577 --type-add=cmake:is:CMakeLists.txt
3578 --type-add=cmake:ext:cmake
3581 # https://docs.bazel.build/versions/master/skylark/bzl-style.html
3582 --type-add=bazel:ext:bzl
3583 # https://docs.bazel.build/versions/master/guide.html#bazelrc-the-bazel-configuration-file
3584 --type-add=bazel:ext:bazelrc
3585 # https://docs.bazel.build/versions/master/build-ref.html#BUILD_files
3586 --type-add=bazel:is:BUILD
3587 # https://docs.bazel.build/versions/master/build-ref.html#workspace
3588 --type-add=bazel:is:WORKSPACE
3592 --type-add=actionscript:ext:as,mxml
3595 # https://www.adaic.org/
3596 --type-add=ada:ext:ada,adb,ads
3599 # https://docs.microsoft.com/en-us/previous-versions/office/developer/server-technologies/aa286483(v=msdn.10)
3600 --type-add=asp:ext:asp
3603 # https://dotnet.microsoft.com/apps/aspnet
3604 --type-add=aspx:ext:master,ascx,asmx,aspx,svc
3607 --type-add=asm:ext:asm,s
3610 --type-add=batch:ext:bat,cmd
3613 # https://en.wikipedia.org/wiki/ColdFusion
3614 --type-add=cfmx:ext:cfc,cfm,cfml
3617 # https://clojure.org/
3618 --type-add=clojure:ext:clj,cljs,edn,cljc
3621 # .xs are Perl C files
3622 --type-add=cc:ext:c,h,xs
3628 # https://coffeescript.org/
3629 --type-add=coffeescript:ext:coffee
3632 --type-add=cpp:ext:cpp,cc,cxx,m,hpp,hh,h,hxx
3635 --type-add=hpp:ext:hpp,hh,h,hxx
3638 --type-add=csharp:ext:cs
3641 # https://crystal-lang.org/
3642 --type-add=crystal:ext:cr,ecr
3645 # https://www.w3.org/Style/CSS/
3646 --type-add=css:ext:css
3650 --type-add=dart:ext:dart
3653 # https://en.wikipedia.org/wiki/Embarcadero_Delphi
3654 --type-add=delphi:ext:pas,int,dfm,nfm,dof,dpk,dproj,groupproj,bdsgroup,bdsproj
3657 # https://elixir-lang.org/
3658 --type-add=elixir:ext:ex,exs
3661 # https://elm-lang.org
3662 --type-add=elm:ext:elm
3665 # https://www.gnu.org/software/emacs
3666 --type-add=elisp:ext:el
3669 # https://www.erlang.org/
3670 --type-add=erlang:ext:erl,hrl
3673 # https://en.wikipedia.org/wiki/Fortran
3674 --type-add=fortran:ext:f,f77,f90,f95,f03,for,ftn,fpp
3677 # https://golang.org/
3678 --type-add=go:ext:go
3681 # https://www.groovy-lang.org/
3682 --type-add=groovy:ext:groovy,gtmpl,gpp,grunit,gradle
3685 # https://gsp.grails.org/
3686 --type-add=gsp:ext:gsp
3689 # https://www.haskell.org/
3690 --type-add=haskell:ext:hs,lhs
3693 --type-add=html:ext:htm,html,xhtml
3696 # http://jade-lang.com/
3697 --type-add=jade:ext:jade
3700 # https://www.oracle.com/technetwork/java/index.html
3701 --type-add=java:ext:java,properties
3704 --type-add=js:ext:js
3707 # https://www.oracle.com/technetwork/java/javaee/jsp/index.html
3708 --type-add=jsp:ext:jsp,jspx,jspf,jhtm,jhtml
3712 --type-add=json:ext:json
3715 # https://kotlinlang.org/
3716 --type-add=kotlin:ext:kt,kts
3719 # http://www.lesscss.org/
3720 --type-add=less:ext:less
3723 # https://common-lisp.net/
3724 --type-add=lisp:ext:lisp,lsp
3727 # https://www.lua.org/
3728 --type-add=lua:ext:lua
3729 --type-add=lua:firstlinematch:/^#!.*\blua(jit)?/
3732 # https://en.wikipedia.org/wiki/Markdown
3733 --type-add=markdown:ext:md,markdown
3734 # We understand that there are many ad hoc extensions for markdown
3735 # that people use. .md and .markdown are the two that ack recognizes.
3736 # You are free to add your own in your ackrc file.
3739 # https://en.wikipedia.org/wiki/MATLAB
3740 --type-add=matlab:ext:m
3743 --type-add=objc:ext:m,h
3746 --type-add=objcpp:ext:mm,h
3749 # https://ocaml.org/
3750 --type-add=ocaml:ext:ml,mli,mll,mly
3754 --type-add=perl:ext:pl,pm,pod,t,psgi
3755 --type-add=perl:firstlinematch:/^#!.*\bperl/
3758 --type-add=perltest:ext:t
3760 # Perl's Plain Old Documentation format, POD
3761 --type-add=pod:ext:pod
3764 # https://www.php.net/
3765 --type-add=php:ext:php,phpt,php3,php4,php5,phtml
3766 --type-add=php:firstlinematch:/^#!.*\bphp/
3769 # https://plone.org/
3770 --type-add=plone:ext:pt,cpt,metadata,cpy,py
3773 # https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_scripts
3774 # https://learn.microsoft.com/en-us/powershell/scripting/developer/module/understanding-a-windows-powershell-module
3775 --type-add=powershell:ext:ps1,psm1
3778 # https://www.purescript.org
3779 --type-add=purescript:ext:purs
3782 # https://www.python.org/
3783 --type-add=python:ext:py
3784 --type-add=python:firstlinematch:/^#!.*\bpython/
3787 # https://pytest.org/
3788 # Pytest files are *.py files that start with test_ or end with _test.py
3789 # https://docs.pytest.org/en/stable/explanation/goodpractices.html#test-discovery
3790 --type-add=pytest:match:_test\.py$
3791 --type-add=pytest:match:^test_.*\.py$
3794 # https://www.r-project.org/
3795 # https://r4ds.had.co.nz/r-markdown.html
3796 --type-add=rr:ext:R,Rmd
3799 # https://docutils.sourceforge.io/rst.html
3800 --type-add=rst:ext:rst
3803 # https://www.ruby-lang.org/
3804 --type-add=ruby:ext:rb,rhtml,rjs,rxml,erb,rake,spec
3805 --type-add=ruby:is:Rakefile
3806 --type-add=ruby:firstlinematch:/^#!.*\bruby/
3809 # https://www.rust-lang.org/
3810 --type-add=rust:ext:rs
3813 # https://sass-lang.com
3814 --type-add=sass:ext:sass,scss
3817 # https://www.scala-lang.org/
3818 --type-add=scala:ext:scala,sbt
3821 # https://groups.csail.mit.edu/mac/projects/scheme/
3822 --type-add=scheme:ext:scm,ss
3825 --type-add=shell:ext:sh,bash,csh,tcsh,ksh,zsh,fish
3826 --type-add=shell:firstlinematch:/^#!.*\b(?:ba|t?c|k|z|fi)?sh\b/
3829 # http://www.smalltalk.org/
3830 --type-add=smalltalk:ext:st
3833 # https://www.smarty.net/
3834 --type-add=smarty:ext:tpl
3837 # https://www.iso.org/standard/45498.html
3838 --type-add=sql:ext:sql,ctl
3841 # http://stylus-lang.com/
3842 --type-add=stylus:ext:styl
3845 # https://en.wikipedia.org/wiki/Scalable_Vector_Graphics
3846 --type-add=svg:ext:svg
3849 # https://developer.apple.com/swift/
3850 --type-add=swift:ext:swift
3851 --type-add=swift:firstlinematch:/^#!.*\bswift/
3854 # https://www.tcl.tk/
3855 --type-add=tcl:ext:tcl,itcl,itk
3858 # https://github.com/hashicorp/terraform
3859 --type-add=terraform=.tf,.tfvars
3862 # https://www.latex-project.org/
3863 --type-add=tex:ext:tex,cls,sty
3865 # Template Toolkit (Perl)
3866 # http//template-toolkit.org/
3867 --type-add=ttml:ext:tt,tt2,ttml
3871 --type-add=toml:ext:toml
3874 # https://www.typescriptlang.org/
3875 --type-add=ts:ext:ts,tsx
3878 --type-add=vb:ext:bas,cls,frm,ctl,vb,resx
3881 --type-add=verilog:ext:v,vh,sv
3884 # http://www.eda.org/twiki/bin/view.cgi/P1076/WebHome
3885 --type-add=vhdl:ext:vhd,vhdl
3888 # https://www.vim.org/
3889 --type-add=vim:ext:vim
3892 # https://www.w3.org/TR/REC-xml/
3893 --type-add=xml:ext:xml,dtd,xsd,xsl,xslt,ent,wsdl
3894 --type-add=xml:firstlinematch:/<[?]xml/
3898 --type-add=yaml:ext:yaml,yml
3900 $lines =~ s/==VERSION==/$App::Ack::VERSION/sm;
3908 package App
::Ack
::ConfigFinder
;
3915 use File
::Spec
3.00 ();
3917 use if ($^O eq 'MSWin32'), 'Win32';
3923 return bless {}, $class;
3927 sub _remove_redundancies
{
3932 foreach my $config (@configs) {
3933 my $path = $config->{path
};
3934 my $key = -e
$path ? Cwd
::realpath
( $path ) : $path;
3935 if ( not $App::Ack
::is_windows
) {
3936 # On Unix, uniquify on inode.
3937 my ($dev, $inode) = (stat $key)[0, 1];
3938 $key = "$dev:$inode" if defined $dev;
3940 push( @uniq, $config ) unless $seen{$key}++;
3946 sub _check_for_ackrc
{
3947 return unless defined $_[0];
3949 my @files = grep { -f
}
3950 map { File
::Spec-
>catfile(@_, $_) }
3953 App
::Ack
::die( File
::Spec-
>catdir(@_) . ' contains both .ackrc and _ackrc. Please remove one of those files.' )
3956 return wantarray ? @files : $files[0];
3957 } # end _check_for_ackrc
3961 sub find_config_files
{
3964 if ( $App::Ack
::is_windows
) {
3965 push @config_files, map { +{ path
=> File
::Spec-
>catfile($_, 'ackrc') } } (
3966 Win32
::GetFolderPath
(Win32
::CSIDL_COMMON_APPDATA
()),
3967 Win32
::GetFolderPath
(Win32
::CSIDL_APPDATA
()),
3971 push @config_files, { path
=> '/etc/ackrc' };
3975 if ( $ENV{'ACKRC'} && -f
$ENV{'ACKRC'} ) {
3976 push @config_files, { path
=> $ENV{'ACKRC'} };
3979 push @config_files, map { +{ path
=> $_ } } _check_for_ackrc
($ENV{'HOME'});
3982 my $cwd = Cwd
::getcwd
();
3983 return () unless defined $cwd;
3985 # XXX This should go through some untainted cwd-fetching function, and not get untainted brute-force like this.
3988 my @dirs = File
::Spec-
>splitdir( $cwd );
3990 my $ackrc = _check_for_ackrc
(@dirs);
3991 if ( defined $ackrc ) {
3992 push @config_files, { project
=> 1, path
=> $ackrc };
3998 # We only test for existence here, so if the file is deleted out from under us, this will fail later.
3999 return _remove_redundancies
( @config_files );
4005 package App
::Ack
::ConfigLoader
;
4011 use File
::Spec
3.00 ();
4012 use Getopt
::Long
2.38 ();
4013 use Text
::ParseWords
3.1 ();
4015 sub configure_parser
{
4025 Getopt
::Long
::Configure
( @standard, @opts );
4031 sub _generate_ignore_dir
{
4032 my ( $option_name, $opt ) = @_;
4034 my $is_inverted = $option_name =~ /^--no/;
4037 my ( undef, $dir ) = @_;
4039 $dir = _remove_directory_separator
( $dir );
4040 if ( $dir !~ /:/ ) {
4041 $dir = 'is:' . $dir;
4044 my ( $filter_type, $args ) = split /:/, $dir, 2;
4046 if ( $filter_type eq 'firstlinematch' ) {
4047 App
::Ack
::die( qq{Invalid filter specification "$filter_type" for option '$option_name'} );
4050 my $filter = App
::Ack
::Filter-
>create_filter($filter_type, split(/,/, $args));
4053 my $previous_inversion_matches = $opt->{idirs
} && !($is_inverted xor $opt->{idirs
}[-1]->is_inverted());
4055 if ( $previous_inversion_matches ) {
4056 $collection = $opt->{idirs
}[-1];
4058 if ( $is_inverted ) {
4059 # This relies on invert of an inverted filter to return the original.
4060 $collection = $collection->invert();
4064 $collection = App
::Ack
::Filter
::Collection-
>new();
4065 push @{ $opt->{idirs
} }, $is_inverted ? $collection->invert() : $collection;
4068 $collection->add($filter);
4070 if ( $filter_type eq 'is' ) {
4071 $collection->add(App
::Ack
::Filter
::IsPath-
>new($args));
4077 sub _remove_directory_separator
{
4080 state $dir_sep_chars = $App::Ack
::is_windows
? quotemeta( '\\/' ) : quotemeta( File
::Spec-
>catfile( '', '' ) );
4082 $path =~ s/[$dir_sep_chars]$//;
4088 sub _process_filter_spec
{
4091 if ( $spec =~ /^(\w+):(\w+):(.*)/ ) {
4092 my ( $type_name, $ext_type, $arguments ) = ( $1, $2, $3 );
4094 return ( $type_name,
4095 App
::Ack
::Filter-
>create_filter($ext_type, split(/,/, $arguments)) );
4097 elsif ( $spec =~ /^(\w+)=(.*)/ ) { # Check to see if we have ack1-style argument specification.
4098 my ( $type_name, $extensions ) = ( $1, $2 );
4100 my @extensions = split(/,/, $extensions);
4101 foreach my $extension ( @extensions ) {
4102 $extension =~ s/^[.]//;
4105 return ( $type_name, App
::Ack
::Filter-
>create_filter('ext', @extensions) );
4108 App
::Ack
::die( "Invalid filter specification '$spec'" );
4113 sub _uninvert_filter
{
4114 my ( $opt, @filters ) = @_;
4116 return unless defined $opt->{filters
} && @filters;
4118 # Loop through all the registered filters. If we hit one that
4119 # matches this extension and it's inverted, we need to delete it from
4121 for ( my $i = 0; $i < @{ $opt->{filters
} }; $i++ ) {
4122 my $opt_filter = @{ $opt->{filters
} }[$i];
4124 # XXX Do a real list comparison? This just checks string equivalence.
4125 if ( $opt_filter->is_inverted() && "$opt_filter->{filter}" eq "@filters" ) {
4126 splice @{ $opt->{filters
} }, $i, 1;
4135 sub _process_filetypes
{
4136 my ( $opt, $arg_sources ) = @_;
4138 my %additional_specs;
4140 my $add_spec = sub {
4141 my ( undef, $spec ) = @_;
4143 my ( $name, $filter ) = _process_filter_spec
($spec);
4145 push @{ $App::Ack
::mappings
{$name} }, $filter;
4147 $additional_specs{$name . '!'} = sub {
4148 my ( undef, $value ) = @_;
4150 my @filters = @{ $App::Ack
::mappings
{$name} };
4152 @filters = map { $_->invert() } @filters;
4155 _uninvert_filter
( $opt, @filters );
4158 push @{ $opt->{'filters'} }, @filters;
4162 my $set_spec = sub {
4163 my ( undef, $spec ) = @_;
4165 my ( $name, $filter ) = _process_filter_spec
($spec);
4167 $App::Ack
::mappings
{$name} = [ $filter ];
4169 $additional_specs{$name . '!'} = sub {
4170 my ( undef, $value ) = @_;
4172 my @filters = @{ $App::Ack
::mappings
{$name} };
4174 @filters = map { $_->invert() } @filters;
4177 push @{ $opt->{'filters'} }, @filters;
4181 my $delete_spec = sub {
4182 my ( undef, $name ) = @_;
4184 delete $App::Ack
::mappings
{$name};
4185 delete $additional_specs{$name . '!'};
4188 my %type_arg_specs = (
4189 'type-add=s' => $add_spec,
4190 'type-set=s' => $set_spec,
4191 'type-del=s' => $delete_spec,
4194 configure_parser
( 'no_auto_abbrev', 'pass_through' );
4195 foreach my $source (@{$arg_sources}) {
4196 my $args = $source->{contents
};
4199 # $args are modified in place, so no need to munge $arg_sources
4200 Getopt
::Long
::GetOptionsFromArray
( $args, %type_arg_specs );
4203 ( undef, $source->{contents
} ) =
4204 Getopt
::Long
::GetOptionsFromString
( $args, %type_arg_specs );
4208 $additional_specs{'k|known-types'} = sub {
4209 my @filters = map { @{$_} } values(%App::Ack
::mappings
);
4211 push @{ $opt->{'filters'} }, @filters;
4214 return \
%additional_specs;
4219 my ( $opt, $extra_specs ) = @_;
4223 my ( $getopt, $value ) = @_;
4226 if ( $value =~ s/^no// ) {
4233 $callback = $extra_specs->{ $value . '!' };
4237 $callback->( $getopt, $cb_value );
4240 App
::Ack
::die( "Unknown type '$value'" );
4251 1 => sub { $opt->{1} = $opt->{m
} = 1 },
4252 'and=s' => $opt->{and},
4253 'A|after-context:-1' => sub { shift; $opt->{A
} = _context_value
(shift) },
4254 'B|before-context:-1' => sub { shift; $opt->{B
} = _context_value
(shift) },
4255 'C|context:-1' => sub { shift; $opt->{B
} = $opt->{A
} = _context_value
(shift) },
4256 'break!' => \
$opt->{break},
4257 'c|count' => \
$opt->{c
},
4258 'color|colour!' => \
$opt->{color
},
4259 'color-match=s' => \
$ENV{ACK_COLOR_MATCH
},
4260 'color-filename=s' => \
$ENV{ACK_COLOR_FILENAME
},
4261 'color-colno=s' => \
$ENV{ACK_COLOR_COLNO
},
4262 'color-lineno=s' => \
$ENV{ACK_COLOR_LINENO
},
4263 'column!' => \
$opt->{column
},
4264 'create-ackrc' => sub { say for ( '--ignore-ack-defaults', App
::Ack
::ConfigDefault
::options
() ); exit; },
4265 'debug' => \
$opt->{debug
},
4267 my ( undef, $value ) = @_;
4270 $opt->{noenv_seen
} = 1;
4274 'files-from=s' => \
$opt->{files_from
},
4275 'filter!' => \
$App::Ack
::is_filter_mode
,
4276 flush
=> sub { $| = 1 },
4277 'follow!' => \
$opt->{follow
},
4279 'group!' => sub { shift; $opt->{heading
} = $opt->{break} = shift },
4280 'heading!' => \
$opt->{heading
},
4281 'h|no-filename' => \
$opt->{h
},
4282 'H|with-filename' => \
$opt->{H
},
4283 'i|ignore-case' => sub { $opt->{i
} = 1; $opt->{S
} = 0; },
4284 'I|no-ignore-case' => sub { $opt->{i
} = 0; $opt->{S
} = 0; },
4285 'ignore-directory|ignore-dir=s' => _generate_ignore_dir
('--ignore-dir', $opt),
4286 'ignore-file=s' => sub {
4287 my ( undef, $file ) = @_;
4289 my ( $filter_type, $args ) = split /:/, $file, 2;
4291 my $filter = App
::Ack
::Filter-
>create_filter($filter_type, split(/,/, $args//''));
4293 if ( !$opt->{ifiles
} ) {
4294 $opt->{ifiles
} = App
::Ack
::Filter
::Collection-
>new();
4296 $opt->{ifiles
}->add($filter);
4298 'l|files-with-matches'
4300 'L|files-without-matches'
4302 'm|max-count=i' => \
$opt->{m
},
4303 'match=s' => \
$opt->{regex
},
4304 'n|no-recurse' => \
$opt->{n
},
4305 o
=> sub { $opt->{output
} = '$&' },
4306 'output=s' => \
$opt->{output
},
4308 my ( undef, $value ) = @_;
4310 $opt->{pager
} = $value || $ENV{PAGER
};
4312 'noignore-directory|noignore-dir=s' => _generate_ignore_dir
('--noignore-dir', $opt),
4313 'nopager' => sub { $opt->{pager
} = undef },
4314 'not=s' => $opt->{not},
4315 'or=s' => $opt->{or},
4316 'passthru' => \
$opt->{passthru
},
4317 'print0' => \
$opt->{print0
},
4318 'p|proximate:1' => \
$opt->{p
},
4319 'P' => sub { $opt->{p
} = 0 },
4320 'Q|literal' => \
$opt->{Q
},
4321 'r|R|recurse' => sub { $opt->{n
} = 0 },
4322 'range-start=s' => \
$opt->{range_start
},
4323 'range-end=s' => \
$opt->{range_end
},
4324 'range-invert!' => \
$opt->{range_invert
},
4326 'show-types' => \
$opt->{show_types
},
4327 'S|smart-case!' => sub { my (undef,$value) = @_; $opt->{S
} = $value; $opt->{i
} = 0 if $value; },
4328 'sort-files' => \
$opt->{sort_files
},
4329 't|type=s' => \
&_type_handler
,
4330 'T=s' => sub { my ($getopt,$value) = @_; $value="no$value"; _type_handler
($getopt,$value); },
4331 'underline!' => \
$opt->{underline
},
4332 'v|invert-match' => \
$opt->{v
},
4333 'w|word-regexp' => \
$opt->{w
},
4334 'x' => sub { $opt->{files_from
} = '-' },
4336 'help' => sub { App
::Ack
::show_help
(); exit; },
4337 'help-types' => sub { App
::Ack
::show_help_types
(); exit; },
4338 'help-colors' => sub { App
::Ack
::show_help_colors
(); exit; },
4339 'help-rgb-colors' => sub { App
::Ack
::show_help_rgb
(); exit; },
4340 $extra_specs ? %{$extra_specs} : (),
4345 sub _context_value
{
4348 # Contexts default to 2.
4349 return (!defined($val) || ($val < 0)) ? 2 : $val;
4353 sub _process_other
{
4354 my ( $opt, $extra_specs, $arg_sources ) = @_;
4357 my $is_help_types_active;
4359 foreach my $source (@{$arg_sources}) {
4360 if ( $source->{name
} eq 'ARGV' ) {
4361 $argv_source = $source->{contents
};
4366 if ( $argv_source ) { # This *should* always be true, but you never know...
4367 configure_parser
( 'pass_through' );
4368 Getopt
::Long
::GetOptionsFromArray
( [ @{$argv_source} ],
4369 'help-types' => \
$is_help_types_active,
4373 my $arg_specs = get_arg_spec
( $opt, $extra_specs );
4376 foreach my $source (@{$arg_sources}) {
4377 my ( $source_name, $args ) = @{$source}{qw
/name contents/};
4379 my $args_for_source = { %{$arg_specs} };
4381 if ( $source->{is_ackrc
} ) {
4384 App
::Ack
::die( "Option --$name is forbidden in .ackrc files." );
4387 $args_for_source = {
4388 %{$args_for_source},
4389 'output=s' => $illegal,
4390 'match=s' => $illegal,
4393 if ( $source->{project
} ) {
4396 App
::Ack
::die( "Option --$name is forbidden in project .ackrc files." );
4399 $args_for_source = {
4400 %{$args_for_source},
4401 'pager:s' => $illegal,
4407 $ret = Getopt
::Long
::GetOptionsFromArray
( $args, %{$args_for_source} );
4410 ( $ret, $source->{contents
} ) =
4411 Getopt
::Long
::GetOptionsFromString
( $args, %{$args_for_source} );
4414 if ( !$is_help_types_active ) {
4415 my $where = $source_name eq 'ARGV' ? 'on command line' : "in $source_name";
4416 App
::Ack
::die( "Invalid option $where" );
4419 if ( $opt->{noenv_seen
} ) {
4420 App
::Ack
::die( "--noenv found in $source_name" );
4424 # XXX We need to check on a -- in the middle of a non-ARGV source
4430 sub _explode_sources
{
4431 my ( $sources ) = @_;
4436 my $arg_spec = get_arg_spec
( \
%opt, {} );
4438 my $dummy_sub = sub {};
4439 my $add_type = sub {
4440 my ( undef, $arg ) = @_;
4442 if ( $arg =~ /(\w+)=/) {
4443 $arg_spec->{$1} = $dummy_sub;
4446 ( $arg ) = split /:/, $arg;
4447 $arg_spec->{$arg} = $dummy_sub;
4451 my $del_type = sub {
4452 my ( undef, $arg ) = @_;
4454 delete $arg_spec->{$arg};
4457 configure_parser
( 'pass_through' );
4458 foreach my $source (@{$sources}) {
4459 my ( $name, $options ) = @{$source}{qw
/name contents/};
4460 if ( ref($options) ne 'ARRAY' ) {
4461 $source->{contents
} = $options =
4462 [ Text
::ParseWords
::shellwords
($options) ];
4465 for my $j ( 0 .. @{$options}-1 ) {
4466 next unless $options->[$j] =~ /^-/;
4467 my @chunk = ( $options->[$j] );
4468 push @chunk, $options->[$j] while ++$j < @{$options} && $options->[$j] !~ /^-/;
4472 Getopt
::Long
::GetOptionsFromArray
( [@chunk],
4473 'type-add=s' => $add_type,
4474 'type-set=s' => $add_type,
4475 'type-del=s' => $del_type,
4479 push @new_sources, {
4486 return \
@new_sources;
4493 my $first_a = $a->[0];
4494 my $first_b = $b->[0];
4496 $first_a =~ s/^--?//;
4497 $first_b =~ s/^--?//;
4499 return $first_a cmp $first_b;
4504 my ( $sources ) = @_;
4506 $sources = _explode_sources
($sources);
4511 foreach my $source (@{$sources}) {
4512 my $name = $source->{name
};
4513 if ( not $opts_by_source{$name} ) {
4514 $opts_by_source{$name} = [];
4515 push @source_names, $name;
4517 push @{$opts_by_source{$name}}, $source->{contents
};
4520 foreach my $name (@source_names) {
4521 my $contents = $opts_by_source{$name};
4524 say '=' x
length($name);
4525 say ' ', join(' ', @{$_}) for sort { _compare_opts
($a, $b) } @{$contents};
4532 sub _remove_default_options_if_needed
{
4533 my ( $sources ) = @_;
4537 foreach my $index ( 0 .. $#{$sources} ) {
4538 if ( $sources->[$index]{'name'} eq 'Defaults' ) {
4539 $default_index = $index;
4544 return $sources unless defined $default_index;
4546 my $should_remove = 0;
4548 configure_parser
( 'no_auto_abbrev', 'pass_through' );
4550 foreach my $index ( $default_index + 1 .. $#{$sources} ) {
4551 my $args = $sources->[$index]->{contents
};
4554 Getopt
::Long
::GetOptionsFromArray
( $args,
4555 'ignore-ack-defaults' => \
$should_remove,
4559 ( undef, $sources->[$index]{contents
} ) = Getopt
::Long
::GetOptionsFromString
( $args,
4560 'ignore-ack-defaults' => \
$should_remove,
4565 return $sources unless $should_remove;
4567 my @copy = @{$sources};
4568 splice @copy, $default_index, 1;
4574 my $arg_sources = \
@_;
4577 pager
=> $ENV{ACK_PAGER_COLOR
} || $ENV{ACK_PAGER
},
4580 $arg_sources = _remove_default_options_if_needed
($arg_sources);
4582 # Check for --dump early.
4583 foreach my $source (@{$arg_sources}) {
4584 if ( $source->{name
} eq 'ARGV' ) {
4586 configure_parser
( 'pass_through' );
4587 Getopt
::Long
::GetOptionsFromArray
( $source->{contents
},
4591 _dump_options
($arg_sources);
4597 my $type_specs = _process_filetypes
(\
%opt, $arg_sources);
4599 _check_for_mutex_options
( $type_specs );
4601 _process_other
(\
%opt, $type_specs, $arg_sources);
4602 while ( @{$arg_sources} ) {
4603 my $source = shift @{$arg_sources};
4604 my $args = $source->{contents
};
4606 # All of our sources should be transformed into an array ref
4608 my $source_name = $source->{name
};
4609 if ( $source_name eq 'ARGV' ) {
4613 App
::Ack
::die( "Source '$source_name' has extra arguments!" );
4617 App
::Ack
::die( 'The impossible has occurred!' );
4620 my $filters = ($opt{filters
} ||= []);
4622 # Throw the default filter in if no others are selected.
4623 if ( not grep { !$_->is_inverted() } @{$filters} ) {
4624 push @{$filters}, App
::Ack
::Filter
::Default-
>new();
4630 sub retrieve_arg_sources
{
4636 configure_parser
( 'no_auto_abbrev', 'pass_through' );
4637 Getopt
::Long
::GetOptions
(
4639 'ackrc=s' => \
$ackrc,
4645 my $finder = App
::Ack
::ConfigFinder-
>new;
4646 @files = $finder->find_config_files;
4649 # We explicitly use open so we get a nice error message.
4650 # XXX This is a potential race condition!.
4651 if ( open my $fh, '<', $ackrc ) {
4655 App
::Ack
::die( "Unable to load ackrc '$ackrc': $!" );
4657 push( @files, { path
=> $ackrc } );
4660 push @arg_sources, {
4662 contents
=> [ App
::Ack
::ConfigDefault
::options_clean
() ],
4665 foreach my $file ( @files) {
4666 my @lines = read_rcfile
($file->{path
});
4668 push @arg_sources, {
4669 name
=> $file->{path
},
4670 contents
=> \
@lines,
4671 project
=> $file->{project
},
4677 push @arg_sources, {
4679 contents
=> [ @ARGV ],
4682 return @arg_sources;
4689 return unless defined $file && -e
$file;
4693 open( my $fh, '<', $file ) or App
::Ack
::die( "Unable to read $file: $!" );
4694 while ( defined( my $line = <$fh> ) ) {
4699 next if $line eq '';
4700 next if $line =~ /^\s*#/;
4702 push( @lines, $line );
4704 close $fh or App
::Ack
::die( "Unable to close $file: $!" );
4710 # Verifies no mutex options were passed. Dies if they were.
4711 sub _check_for_mutex_options
{
4712 my $type_specs = shift;
4714 my $mutex = mutex_options
();
4716 my ($raw,$used) = _options_used
( $type_specs );
4718 my @used = sort { lc $a cmp lc $b } keys %{$used};
4720 for my $i ( @used ) {
4721 for my $j ( @used ) {
4723 if ( $mutex->{$i}{$j} ) {
4724 my $x = $raw->[ $used->{$i} ];
4725 my $y = $raw->[ $used->{$j} ];
4726 App
::Ack
::die( "Options '$x' and '$y' can't be used together." );
4735 # Processes the command line option and returns a hash of the options that were
4736 # used on the command line, using their full name. "--prox" shows up in the hash as "--proximate".
4738 my $type_specs = shift;
4741 my $real_spec = get_arg_spec
( \
%dummy_opt, $type_specs );
4743 # The real argument parsing doesn't check for --type-add, --type-del or --type-set because
4744 # they get removed by the argument processing. We have to account for them here.
4745 my $sub_dummy = sub {};
4748 'type-add=s' => $sub_dummy,
4749 'type-del=s' => $sub_dummy,
4750 'type-set=s' => $sub_dummy,
4751 'ignore-ack-defaults' => $sub_dummy,
4756 my %spec_capture_parsed;
4757 my %spec_capture_raw;
4760 # Capture the %parsed hash.
4763 my $sub_count = sub {
4766 $parsed{$arg} = $parsed_pos++;
4768 %spec_capture_parsed = (
4769 '<>' => sub { $parsed_pos++ }, # Bump forward one pos for non-options.
4770 map { $_ => $sub_count } keys %{$real_spec}
4774 # Capture the @raw array.
4777 %spec_capture_raw = (
4778 '<>' => sub { $raw_pos++ }, # Bump forward one pos for non-options.
4781 my $sub_count = sub {
4785 $raw[$raw_pos] = length($arg) == 1 ? "-$arg" : "--$arg";
4789 for my $opt_spec ( keys %{$real_spec} ) {
4794 $negatable = ($opt_spec =~ s/!$//);
4796 if ( $opt_spec =~ s/(=[si])$// ) {
4799 if ( $opt_spec =~ s/(:.+)$// ) {
4803 my @aliases = split( /\|/, $opt_spec );
4804 for my $alias ( @aliases ) {
4805 $alias .= $type if defined $type;
4806 $alias .= $default if defined $default;
4807 $alias .= '!' if $negatable;
4809 $spec_capture_raw{$alias} = $sub_count;
4814 # Parse @ARGV twice, once with each capture spec.
4815 configure_parser
( 'pass_through' ); # Ignore invalid options.
4816 Getopt
::Long
::GetOptionsFromArray
( [@ARGV], %spec_capture_raw );
4817 Getopt
::Long
::GetOptionsFromArray
( [@ARGV], %spec_capture_parsed );
4819 return (\
@raw,\
%parsed);
4824 # This list is machine-generated by dev/crank-mutex. Do not modify it by hand.
4895 'with-filename' => 1,
5037 'with-filename' => 1,
5145 'with-filename' => {
5156 } # End of mutex_options()
5159 1; # End of App::Ack::ConfigLoader
5162 package App
::Ack
::File
;
5172 my $filename = shift;
5175 filename
=> $filename,
5179 if ( $self->{filename
} eq '-' ) {
5180 $self->{fh
} = *STDIN
;
5189 return $_[0]->{filename
};
5197 return $self->{basename
} //= (File
::Spec-
>splitpath($self->name))[2];
5205 if ( !$self->{fh
} ) {
5206 if ( open $self->{fh
}, '<', $self->{filename
} ) {
5210 $self->{fh
} = undef;
5218 sub may_be_present
{
5222 # Tells if the file needs a line-by-line scan. This is a big
5223 # optimization because if you can tell from the outset that the pattern
5224 # is not found in the file at all, then there's no need to do the
5225 # line-by-line iteration.
5227 # Slurp up an entire file up to 10M, see if there are any matches
5228 # in it, and if so, let us know so we can iterate over it directly.
5230 # The $regex may be undef if it had a "$" in it, and is therefore unsuitable for this heuristic.
5232 my $may_be_present = 1;
5233 if ( $regex && $self->open() && -f
$self->{fh
} ) {
5235 my $size = 10_000_000;
5236 my $rc = sysread( $self->{fh
}, $buffer, $size );
5237 if ( !defined($rc) ) {
5238 if ( $App::Ack
::report_bad_filenames
) {
5239 App
::Ack
::warn( $self->name . ": $!" );
5241 $may_be_present = 0;
5244 # If we read all 10M, then we need to scan the rest.
5245 # If there are any carriage returns, our results are flaky, so scan the rest.
5246 if ( ($rc == $size) || (index($buffer,"\r") >= 0) ) {
5247 $may_be_present = 1;
5250 if ( $buffer !~ /$regex/o ) {
5251 $may_be_present = 0;
5257 return $may_be_present;
5265 if ( defined($self->{fh
}) ) {
5266 return unless -f
$self->{fh
};
5268 if ( !seek( $self->{fh
}, 0, 0 ) && $App::Ack
::report_bad_filenames
) {
5269 App
::Ack
::warn( "$self->{filename}: $!" );
5281 if ( $self->{fh
} ) {
5282 if ( !close($self->{fh
}) && $App::Ack
::report_bad_filenames
) {
5283 App
::Ack
::warn( $self->name() . ": $!" );
5285 $self->{fh
} = undef;
5296 return __PACKAGE__-
>new($self->name);
5304 if ( !exists $self->{firstliney
} ) {
5305 my $fh = $self->open();
5307 if ( $App::Ack
::report_bad_filenames
) {
5308 App
::Ack
::warn( $self->name . ': ' . $! );
5310 $self->{firstliney
} = '';
5314 my $rc = sysread( $fh, $buffer, 250 );
5316 $buffer =~ s/[\r\n].*//s;
5319 if ( !defined($rc) ) {
5320 App
::Ack
::warn( $self->name . ': ' . $! );
5324 $self->{firstliney
} = $buffer;
5329 return $self->{firstliney
};
5335 package App
::Ack
::Files
;
5349 my $self = bless {}, $class;
5351 my $descend_filter = $opt->{descend_filter
};
5354 $descend_filter = sub {
5360 File
::Next
::files
( {
5361 file_filter
=> $opt->{file_filter
},
5362 descend_filter
=> $descend_filter,
5363 error_handler
=> _generate_error_handler
(),
5364 warning_handler
=> sub {},
5365 sort_files
=> $opt->{sort_files
},
5366 follow_symlinks
=> $opt->{follow
},
5378 my $error_handler = _generate_error_handler
();
5380 File
::Next
::from_file
( {
5381 error_handler
=> $error_handler,
5382 warning_handler
=> $error_handler,
5383 sort_files
=> $opt->{sort_files
},
5384 }, $file ) or return undef;
5397 my $self = bless {}, $class;
5399 $self->{iter
} = sub {
5400 state $has_been_called = 0;
5402 if ( !$has_been_called ) {
5403 $has_been_called = 1;
5416 my $file = $self->{iter
}->();
5418 return unless defined($file);
5420 return App
::Ack
::File-
>new( $file );
5424 sub _generate_error_handler
{
5425 if ( $App::Ack
::report_bad_filenames
) {
5428 App
::Ack
::warn( $msg );
5439 package App
::Ack
::Filter
;
5449 my ( undef, $type, @args ) = @_;
5451 if ( my $package = $filter_types{$type} ) {
5452 return $package->new(@args);
5454 my $allowed_types = join( ', ', sort keys %filter_types );
5455 App
::Ack
::die( "Unknown filter type '$type'. Type must be one of: $allowed_types." );
5459 sub register_filter
{
5460 my ( undef, $type, $package ) = @_;
5462 $filter_types{$type} = $package;
5471 return App
::Ack
::Filter
::Inverse-
>new( $self );
5481 return '(unimplemented to_string)';
5494 package App
::Ack
::Filter
::Collection
;
5500 our @ISA = 'App::Ack::Filter';
5513 my ( $self, $file ) = @_;
5515 for my $group (values %{$self->{groups
}}) {
5516 return 1 if $group->filter($file);
5519 for my $filter (@{$self->{ungrouped
}}) {
5520 return 1 if $filter->filter($file);
5527 my ( $self, $filter ) = @_;
5529 if (exists $filter->{'groupname'}) {
5530 my $group = ($self->{groups
}->{$filter->{groupname
}} ||= $filter->create_group());
5531 $group->add($filter);
5534 push @{$self->{'ungrouped'}}, $filter;
5543 return ref($self) . " - $self";
5549 return join(', ', map { "($_)" } @{$self->{ungrouped
}});
5555 package App
::Ack
::Filter
::Default
;
5561 our @ISA = 'App::Ack::Filter';
5567 return bless {}, $class;
5571 my ( undef, $file ) = @_;
5573 return -T
$file->name;
5579 package App
::Ack
::Filter
::Extension
;
5585 our @ISA = 'App::Ack::Filter';
5590 my ( $class, @extensions ) = @_;
5592 my $exts = join('|', map { "\Q$_\E"} @extensions);
5593 my $re = qr/[.](?:$exts)$/i;
5596 extensions
=> \
@extensions,
5598 groupname
=> 'ExtensionGroup',
5603 return App
::Ack
::Filter
::ExtensionGroup-
>new();
5607 my ( $self, $file ) = @_;
5609 return $file->name =~ /$self->{regex}/;
5615 return ref($self) . ' - ' . $self->{regex
};
5621 return join( ' ', map { ".$_" } @{$self->{extensions
}} );
5625 App
::Ack
::Filter-
>register_filter(ext
=> __PACKAGE__
);
5631 package App
::Ack
::Filter
::ExtensionGroup
;
5637 our @ISA = 'App::Ack::Filter';
5649 my ( $self, $filter ) = @_;
5651 foreach my $ext (@{$filter->{extensions
}}) {
5652 $self->{data
}->{lc $ext} = 1;
5659 my ( $self, $file ) = @_;
5661 if ($file->name =~ /[.]([^.]*)$/) {
5662 return exists $self->{'data'}->{lc $1};
5671 return ref($self) . " - $self";
5677 return join(' ', map { ".$_" } sort keys %{$self->{data
}});
5683 package App
::Ack
::Filter
::FirstLineMatch
;
5690 our @ISA = 'App::Ack::Filter';
5694 my ( $class, $re ) = @_;
5696 $re =~ s{^/|/$}{}g; # XXX validate?
5704 # This test reads the first 250 characters of a file, then just uses the
5705 # first line found in that. This prevents reading something like an entire
5706 # .min.js file (which might be only one "line" long) into memory.
5709 my ( $self, $file ) = @_;
5711 return $file->firstliney =~ /$self->{regex}/;
5718 return ref($self) . ' - ' . $self->{regex
};
5724 (my $re = $self->{regex
}) =~ s{\([^:]*:(.*)\)$}{$1};
5726 return "First line matches /$re/";
5730 App
::Ack
::Filter-
>register_filter(firstlinematch
=> __PACKAGE__
);
5736 package App
::Ack
::Filter
::Inverse
;
5743 our @ISA = 'App::Ack::Filter';
5747 my ( $class, $filter ) = @_;
5755 my ( $self, $file ) = @_;
5757 return !$self->{filter
}->filter( $file );
5763 return $self->{'filter'};
5773 my $filter = $self->{'filter'};
5781 package App
::Ack
::Filter
::Is
;
5787 our @ISA = 'App::Ack::Filter';
5790 use File
::Spec
3.00 ();
5793 my ( $class, $filename ) = @_;
5796 filename
=> $filename,
5797 groupname
=> 'IsGroup',
5802 return App
::Ack
::Filter
::IsGroup-
>new();
5806 my ( $self, $file ) = @_;
5808 return (File
::Spec-
>splitpath($file->name))[2] eq $self->{filename
};
5814 return ref($self) . ' - ' . $self->{filename
};
5820 return $self->{filename
};
5824 App
::Ack
::Filter-
>register_filter(is => __PACKAGE__
);
5830 package App
::Ack
::Filter
::IsGroup
;
5836 our @ISA = 'App::Ack::Filter';
5848 my ( $self, $filter ) = @_;
5850 $self->{data
}->{ $filter->{filename
} } = 1;
5856 my ( $self, $file ) = @_;
5858 return exists $self->{data
}->{ $file->basename };
5864 return ref($self) . " - $self";
5870 return join(' ', keys %{$self->{data
}});
5876 package App
::Ack
::Filter
::IsPath
;
5882 our @ISA = 'App::Ack::Filter';
5887 my ( $class, $filename ) = @_;
5890 filename
=> $filename,
5891 groupname
=> 'IsPathGroup',
5896 return App
::Ack
::Filter
::IsPathGroup-
>new();
5900 my ( $self, $file ) = @_;
5902 return $file->name eq $self->{filename
};
5908 return ref($self) . ' - ' . $self->{filename
};
5914 return $self->{filename
};
5920 package App
::Ack
::Filter
::IsPathGroup
;
5926 our @ISA = 'App::Ack::Filter';
5938 my ( $self, $filter ) = @_;
5940 $self->{data
}->{ $filter->{filename
} } = 1;
5946 my ( $self, $file ) = @_;
5948 return exists $self->{data
}->{$file->name};
5954 return ref($self) . " - $self";
5960 return join(' ', keys %{$self->{data
}});
5966 package App
::Ack
::Filter
::Match
;
5971 our @ISA = 'App::Ack::Filter';
5977 my ( $class, $re ) = @_;
5979 $re =~ s{^/|/$}{}g; # XXX validate?
5984 groupname
=> 'MatchGroup',
5989 return App
::Ack
::Filter
::MatchGroup-
>new;
5993 my ( $self, $file ) = @_;
5995 return $file->basename =~ /$self->{regex}/;
6001 return ref($self) . ' - ' . $self->{regex
};
6007 return "Filename matches $self->{regex}";
6011 App
::Ack
::Filter-
>register_filter(match
=> __PACKAGE__
);
6017 package App
::Ack
::Filter
::MatchGroup
;
6023 our @ISA = 'App::Ack::Filter';
6036 my ( $self, $filter ) = @_;
6038 push @{ $self->{matches
} }, $filter->{regex
};
6040 my $re = join('|', map { "(?:$_)" } @{ $self->{matches
} });
6041 $self->{big_re
} = qr/$re/;
6047 my ( $self, $file ) = @_;
6049 return $file->basename =~ /$self->{big_re}/;
6052 # This class has no inspect() or to_string() method.
6053 # It will just use the default one unless someone writes something useful.
6064 our $VERSION = '1.18';
6070 our $name; # name of the current file
6071 our $dir; # dir of the current file
6073 our %files_defaults;
6078 file_filter
=> undef,
6079 descend_filter
=> undef,
6080 error_handler
=> sub { CORE
::die $_[0] },
6081 warning_handler
=> sub { CORE
::warn @_ },
6082 sort_files
=> undef,
6083 follow_symlinks
=> 1,
6086 %skip_dirs = map {($_,1)} (File
::Spec-
>curdir, File
::Spec-
>updir);
6091 die _bad_invocation
() if @_ && defined($_[0]) && ($_[0] eq __PACKAGE__
);
6093 my ($parms,@queue) = _setup
( \
%files_defaults, @_ );
6095 my $filter = $parms->{file_filter
};
6097 while ( my $entry = shift @queue ) {
6098 my ( $dirname, $file, $fullpath, $is_dir, $is_file, $is_fifo ) = @{$entry};
6099 if ( $is_file || $is_fifo ) {
6102 local $File::Next
::dir
= $dirname;
6103 local $File::Next
::name
= $fullpath;
6104 next if not $filter->();
6106 return wantarray ? ($dirname,$file,$fullpath) : $fullpath;
6109 unshift( @queue, _candidate_files
( $parms, $fullpath ) );
6124 die _bad_invocation
() if @_ && defined($_[0]) && ($_[0] eq __PACKAGE__
);
6126 my ($parms,@queue) = _setup
( \
%files_defaults, @_ );
6127 my $err = $parms->{error_handler
};
6128 my $warn = $parms->{warning_handler
};
6130 my $filename = $queue[0]->[1];
6132 if ( !defined($filename) ) {
6133 $err->( 'Must pass a filename to from_file()' );
6138 if ( $filename eq '-' ) {
6142 if ( !open( $fh, '<', $filename ) ) {
6143 $err->( "Unable to open $filename: $!", $! + 0 );
6148 my $filter = $parms->{file_filter
};
6150 local $/ = $parms->{nul_separated
} ? "\x00" : $/;
6151 while ( my $fullpath = <$fh> ) {
6153 next unless $fullpath =~ /./;
6154 if ( not ( -f
$fullpath || -p _
) ) {
6155 $warn->( "$fullpath: No such file" );
6159 my ($volume,$dirname,$file) = File
::Spec-
>splitpath( $fullpath );
6162 local $File::Next
::dir
= $dirname;
6163 local $File::Next
::name
= $fullpath;
6164 next if not $filter->();
6166 return wantarray ? ($dirname,$file,$fullpath) : $fullpath;
6174 sub _bad_invocation
{
6175 my $good = (caller(1))[3];
6177 $bad =~ s/(.+)::/$1->/;
6178 return "$good must not be invoked as $bad";
6181 sub sort_standard
($$) { return $_[0]->[1] cmp $_[1]->[1] }
6182 sub sort_reverse
($$) { return $_[1]->[1] cmp $_[0]->[1] }
6187 my @parts = split( /\//, $path );
6189 return $path if @parts < 2;
6191 return File
::Spec-
>catfile( @parts );
6197 my $defaults = shift;
6198 my $passed_parms = ref $_[0] eq 'HASH' ? {%{+shift}} : {}; # copy parm hash
6200 my %passed_parms = %{$passed_parms};
6203 for my $key ( keys %{$defaults} ) {
6205 exists $passed_parms{$key}
6206 ? delete $passed_parms{$key}
6207 : $defaults->{$key};
6210 # Any leftover keys are bogus
6211 for my $badkey ( sort keys %passed_parms ) {
6212 my $sub = (caller(1))[3];
6213 $parms->{error_handler
}->( "Invalid option passed to $sub(): $badkey" );
6216 # If it's not a code ref, assume standard sort
6217 if ( $parms->{sort_files
} && ( ref($parms->{sort_files
}) ne 'CODE' ) ) {
6218 $parms->{sort_files
} = \
&sort_standard
;
6223 my $start = reslash
( $_ );
6224 my $is_dir = -d
$start;
6226 my $is_fifo = (-p _
) || ($start =~ m{^/dev/fd});
6229 ? [ $start, undef, $start, $is_dir, $is_file, $is_fifo ]
6230 : [ undef, $start, $start, $is_dir, $is_file, $is_fifo ];
6233 return ($parms,@queue);
6237 sub _candidate_files
{
6239 my $dirname = shift;
6242 if ( !opendir $dh, $dirname ) {
6243 $parms->{error_handler
}->( "$dirname: $!", $! + 0 );
6248 my $descend_filter = $parms->{descend_filter
};
6249 my $follow_symlinks = $parms->{follow_symlinks
};
6251 for my $file ( grep { !exists $skip_dirs{$_} } readdir $dh ) {
6252 my $fullpath = File
::Spec-
>catdir( $dirname, $file );
6253 if ( !$follow_symlinks ) {
6254 next if -l
$fullpath;
6261 my $is_fifo = (-p _
) || ($fullpath =~ m{^/dev/fd});
6263 # Only do directory checking if we have a descend_filter
6264 if ( $descend_filter ) {
6266 local $File::Next
::dir
= $fullpath;
6268 next if not $descend_filter->();
6271 push @newfiles, [ $dirname, $file, $fullpath, $is_dir, $is_file, $is_fifo ];
6275 my $sort_sub = $parms->{sort_files
};
6277 @newfiles = sort $sort_sub @newfiles;
6285 1; # End of File::Next