]> Tony Duckles's Git Repositories (git.nynim.org) - dotfiles.git/blob - bin/ack
bin/ack: ack v3.3.1
[dotfiles.git] / bin / ack
1 #!/usr/bin/env perl
2 #
3 # This file, ack, is generated code.
4 # Please DO NOT EDIT or send patches for it.
5 #
6 # Please take a look at the source from
7 # https://github.com/beyondgrep/ack3
8 # and submit patches against the individual files
9 # that build ack.
10 #
11
12 $App::Ack::STANDALONE = 1;
13 package main;
14
15 use strict;
16 use warnings;
17
18 our $VERSION = 'v3.3.1'; # Check https://beyondgrep.com/ for updates
19
20 use 5.010001;
21
22 use File::Spec ();
23
24
25
26 # Global command-line options
27 our $opt_1;
28 our $opt_A;
29 our $opt_B;
30 our $opt_break;
31 our $opt_color;
32 our $opt_column;
33 our $opt_debug;
34 our $opt_c;
35 our $opt_f;
36 our $opt_g;
37 our $opt_heading;
38 our $opt_L;
39 our $opt_l;
40 our $opt_m;
41 our $opt_output;
42 our $opt_passthru;
43 our $opt_p;
44 our $opt_range_start;
45 our $opt_range_end;
46 our $opt_range_invert;
47 our $opt_regex;
48 our $opt_show_filename;
49 our $opt_show_types;
50 our $opt_underline;
51 our $opt_v;
52
53 # Flag if we need any context tracking.
54 our $is_tracking_context;
55
56 # The regex that we search for in each file.
57 our $search_re;
58
59 # Special /m version of our $search_re.
60 our $scan_re;
61
62 our @special_vars_used_by_opt_output;
63
64 our $using_ranges;
65
66 # Internal stats for debugging.
67 our %stats;
68
69 MAIN: {
70 $App::Ack::ORIGINAL_PROGRAM_NAME = $0;
71 $0 = join(' ', 'ack', $0);
72 $App::Ack::ors = "\n";
73 if ( $App::Ack::VERSION ne $main::VERSION ) {
74 App::Ack::die( "Program/library version mismatch\n\t$0 is $main::VERSION\n\t$INC{'App/Ack.pm'} is $App::Ack::VERSION" );
75 }
76
77 # Do preliminary arg checking;
78 my $env_is_usable = 1;
79 for my $arg ( @ARGV ) {
80 last if ( $arg eq '--' );
81
82 # Get the --thpppt, --bar, --cathy and --man checking out of the way.
83 $arg =~ /^--th[pt]+t+$/ and App::Ack::thpppt($arg);
84 $arg eq '--bar' and App::Ack::ackbar();
85 $arg eq '--cathy' and App::Ack::cathy();
86
87 # See if we want to ignore the environment. (Don't tell Al Gore.)
88 $arg eq '--env' and $env_is_usable = 1;
89 $arg eq '--noenv' and $env_is_usable = 0;
90 }
91
92 if ( $env_is_usable ) {
93 if ( $ENV{ACK_OPTIONS} ) {
94 App::Ack::warn( 'WARNING: ack no longer uses the ACK_OPTIONS environment variable. Use an ackrc file instead.' );
95 }
96 }
97 else {
98 my @keys = ( 'ACKRC', grep { /^ACK_/ } keys %ENV );
99 delete @ENV{@keys};
100 }
101
102 # Load colors
103 my $modules_loaded_ok = eval 'use Term::ANSIColor 1.10 (); 1;';
104 if ( $modules_loaded_ok && $App::Ack::is_windows ) {
105 $modules_loaded_ok = eval 'use Win32::Console::ANSI; 1;';
106 }
107 if ( $modules_loaded_ok ) {
108 $ENV{ACK_COLOR_MATCH} ||= 'black on_yellow';
109 $ENV{ACK_COLOR_FILENAME} ||= 'bold green';
110 $ENV{ACK_COLOR_LINENO} ||= 'bold yellow';
111 $ENV{ACK_COLOR_COLNO} ||= 'bold yellow';
112 }
113
114 my $p = App::Ack::ConfigLoader::opt_parser( 'no_auto_abbrev', 'pass_through' );
115 $p->getoptions(
116 help => sub { App::Ack::show_help(); exit; },
117 version => sub { App::Ack::print( App::Ack::get_version_statement() ); exit; },
118 man => sub { App::Ack::show_man(); },
119 );
120
121 if ( !@ARGV ) {
122 App::Ack::show_help();
123 exit 1;
124 }
125
126 my @arg_sources = App::Ack::ConfigLoader::retrieve_arg_sources();
127
128 my $opt = App::Ack::ConfigLoader::process_args( @arg_sources );
129
130 $opt_1 = $opt->{1};
131 $opt_A = $opt->{A};
132 $opt_B = $opt->{B};
133 $opt_break = $opt->{break};
134 $opt_c = $opt->{c};
135 $opt_color = $opt->{color};
136 $opt_column = $opt->{column};
137 $opt_debug = $opt->{debug};
138 $opt_f = $opt->{f};
139 $opt_g = $opt->{g};
140 $opt_heading = $opt->{heading};
141 $opt_L = $opt->{L};
142 $opt_l = $opt->{l};
143 $opt_m = $opt->{m};
144 $opt_output = $opt->{output};
145 $opt_p = $opt->{p};
146 $opt_passthru = $opt->{passthru};
147 $opt_range_start = $opt->{range_start};
148 $opt_range_end = $opt->{range_end};
149 $opt_range_invert = $opt->{range_invert};
150 $opt_regex = $opt->{regex};
151 $opt_show_filename = $opt->{show_filename};
152 $opt_show_types = $opt->{show_types};
153 $opt_underline = $opt->{underline};
154 $opt_v = $opt->{v};
155
156 if ( $opt_show_types && not( $opt_f || $opt_g ) ) {
157 App::Ack::die( '--show-types can only be used with -f or -g.' );
158 }
159
160 if ( $opt_range_start ) {
161 ($opt_range_start, undef) = build_regex( $opt_range_start, {} );
162 }
163 if ( $opt_range_end ) {
164 ($opt_range_end, undef) = build_regex( $opt_range_end, {} );
165 }
166 $using_ranges = $opt_range_start || $opt_range_end;
167
168 $App::Ack::report_bad_filenames = !$opt->{s};
169 $App::Ack::ors = $opt->{print0} ? "\0" : "\n";
170
171 if ( !defined($opt_color) && !$opt_g ) {
172 my $windows_color = 1;
173 if ( $App::Ack::is_windows ) {
174 $windows_color = eval { require Win32::Console::ANSI; };
175 }
176 $opt_color = !App::Ack::output_to_pipe() && $windows_color;
177 }
178 $opt_heading //= !App::Ack::output_to_pipe();
179 $opt_break //= !App::Ack::output_to_pipe();
180
181 if ( defined($opt->{H}) || defined($opt->{h}) ) {
182 $opt_show_filename = $opt->{show_filename} = $opt->{H} && !$opt->{h};
183 }
184
185 if ( defined $opt_output ) {
186 # Expand out \t, \n and \r.
187 $opt_output =~ s/\\n/\n/g;
188 $opt_output =~ s/\\r/\r/g;
189 $opt_output =~ s/\\t/\t/g;
190
191 my @supported_special_variables = ( 1..9, qw( _ . ` & ' + f ) );
192 @special_vars_used_by_opt_output = grep { $opt_output =~ /\$$_/ } @supported_special_variables;
193
194 # If the $opt_output contains $&, $` or $', those vars won't be
195 # captured until they're used at least once in the program.
196 # Do the eval to make this happen.
197 for my $i ( @special_vars_used_by_opt_output ) {
198 if ( $i eq q{&} || $i eq q{'} || $i eq q{`} ) {
199 no warnings; # They will be undef, so don't warn.
200 eval qq{"\$$i"};
201 }
202 }
203 }
204
205 # Set up file filters.
206 my $files;
207 if ( $App::Ack::is_filter_mode && !$opt->{files_from} ) { # probably -x
208 $files = App::Ack::Files->from_stdin();
209 $opt_regex //= shift @ARGV;
210 ($search_re, $scan_re) = build_regex( $opt_regex, $opt );
211 $stats{search_re} = $search_re;
212 $stats{scan_re} = $scan_re;
213 }
214 else {
215 if ( $opt_f ) {
216 # No need to check for regex, since mutex options are handled elsewhere.
217 }
218 else {
219 $opt_regex //= shift @ARGV;
220 ($search_re, $scan_re) = build_regex( $opt_regex, $opt );
221 $stats{search_re} = $search_re;
222 $stats{scan_re} = $scan_re;
223 }
224 # XXX What is this checking for?
225 if ( $search_re && $search_re =~ /\n/ ) {
226 App::Ack::exit_from_ack( 0 );
227 }
228 my @start;
229 if ( not defined $opt->{files_from} ) {
230 @start = @ARGV;
231 }
232 if ( !exists($opt->{show_filename}) ) {
233 unless(@start == 1 && !(-d $start[0])) {
234 $opt_show_filename = $opt->{show_filename} = 1;
235 }
236 }
237
238 if ( defined $opt->{files_from} ) {
239 $files = App::Ack::Files->from_file( $opt, $opt->{files_from} );
240 exit 1 unless $files;
241 }
242 else {
243 @start = ('.') unless @start;
244 foreach my $target (@start) {
245 if ( !-e $target && $App::Ack::report_bad_filenames) {
246 App::Ack::warn( "$target: No such file or directory" );
247 }
248 }
249
250 $opt->{file_filter} = _compile_file_filter($opt, \@start);
251 $opt->{descend_filter} = _compile_descend_filter($opt);
252
253 $files = App::Ack::Files->from_argv( $opt, \@start );
254 }
255 }
256 App::Ack::set_up_pager( $opt->{pager} ) if defined $opt->{pager};
257
258 my $nmatches;
259 if ( $opt_f || $opt_g ) {
260 $nmatches = file_loop_fg( $files );
261 }
262 elsif ( $opt_c ) {
263 $nmatches = file_loop_c( $files );
264 }
265 elsif ( $opt_l || $opt_L ) {
266 $nmatches = file_loop_lL( $files );
267 }
268 else {
269 $nmatches = file_loop_normal( $files );
270 }
271
272 if ( $opt_debug ) {
273 require List::Util;
274 my @stats = qw( search_re scan_re prescans linescans filematches linematches );
275 my $width = List::Util::max( map { length } @stats );
276
277 for my $stat ( @stats ) {
278 App::Ack::warn( sprintf( '%-*.*s = %s', $width, $width, $stat, $stats{$stat} // 'undef' ) );
279 }
280 }
281
282 close $App::Ack::fh;
283
284 App::Ack::exit_from_ack( $nmatches );
285 }
286
287 # End of MAIN
288
289 sub file_loop_fg {
290 my $files = shift;
291
292 my $nmatches = 0;
293 while ( defined( my $file = $files->next ) ) {
294 if ( $opt_show_types ) {
295 App::Ack::show_types( $file );
296 }
297 elsif ( $opt_g ) {
298 print_line_with_options( undef, $file->name, 0, $App::Ack::ors );
299 }
300 else {
301 App::Ack::say( $file->name );
302 }
303 ++$nmatches;
304 last if defined($opt_m) && ($nmatches >= $opt_m);
305 }
306
307 return $nmatches;
308 }
309
310
311 sub file_loop_c {
312 my $files = shift;
313
314 my $total_count = 0;
315 while ( defined( my $file = $files->next ) ) {
316 my $matches_for_this_file = count_matches_in_file( $file );
317
318 if ( not $opt_show_filename ) {
319 $total_count += $matches_for_this_file;
320 next;
321 }
322
323 if ( !$opt_l || $matches_for_this_file > 0 ) {
324 if ( $opt_show_filename ) {
325 App::Ack::say( $file->name, ':', $matches_for_this_file );
326 }
327 else {
328 App::Ack::say( $matches_for_this_file );
329 }
330 }
331 }
332
333 if ( !$opt_show_filename ) {
334 App::Ack::say( $total_count );
335 }
336
337 return;
338 }
339
340
341 sub file_loop_lL {
342 my $files = shift;
343
344 my $nmatches = 0;
345 while ( defined( my $file = $files->next ) ) {
346 my $is_match = count_matches_in_file( $file, 1 );
347
348 if ( $opt_L ? !$is_match : $is_match ) {
349 App::Ack::say( $file->name );
350 ++$nmatches;
351
352 last if $opt_1;
353 last if defined($opt_m) && ($nmatches >= $opt_m);
354 }
355 }
356
357 return $nmatches;
358 }
359
360
361 sub _compile_descend_filter {
362 my ( $opt ) = @_;
363
364 my $idirs = 0;
365 my $dont_ignore_dirs = 0;
366
367 for my $filter (@{$opt->{idirs} || []}) {
368 if ($filter->is_inverted()) {
369 $dont_ignore_dirs++;
370 }
371 else {
372 $idirs++;
373 }
374 }
375
376 # If we have one or more --noignore-dir directives, we can't ignore
377 # entire subdirectory hierarchies, so we return an "accept all"
378 # filter and scrutinize the files more in _compile_file_filter.
379 return if $dont_ignore_dirs;
380 return unless $idirs;
381
382 $idirs = $opt->{idirs};
383
384 return sub {
385 my $file = App::Ack::File->new($File::Next::dir);
386 return !grep { $_->filter($file) } @{$idirs};
387 };
388 }
389
390 sub _compile_file_filter {
391 my ( $opt, $start ) = @_;
392
393 my $ifiles_filters = $opt->{ifiles};
394
395 my $filters = $opt->{'filters'} || [];
396 my $direct_filters = App::Ack::Filter::Collection->new();
397 my $inverse_filters = App::Ack::Filter::Collection->new();
398
399 foreach my $filter (@{$filters}) {
400 if ($filter->is_inverted()) {
401 # We want to check if files match the uninverted filters
402 $inverse_filters->add($filter->invert());
403 }
404 else {
405 $direct_filters->add($filter);
406 }
407 }
408
409 my %is_member_of_starting_set = map { (get_file_id($_) => 1) } @{$start};
410
411 my @ignore_dir_filter = @{$opt->{idirs} || []};
412 my @is_inverted = map { $_->is_inverted() } @ignore_dir_filter;
413 # This depends on InverseFilter->invert returning the original filter (for optimization).
414 @ignore_dir_filter = map { $_->is_inverted() ? $_->invert() : $_ } @ignore_dir_filter;
415 my $dont_ignore_dir_filter = grep { $_ } @is_inverted;
416 my $previous_dir = '';
417 my $previous_dir_ignore_result;
418
419 return sub {
420 if ( $opt_g ) {
421 if ( $File::Next::name =~ /$search_re/o ) {
422 return 0 if $opt_v;
423 }
424 else {
425 return 0 if !$opt_v;
426 }
427 }
428 # ack always selects files that are specified on the command
429 # line, regardless of filetype. If you want to ack a JPEG,
430 # and say "ack foo whatever.jpg" it will do it for you.
431 return 1 if $is_member_of_starting_set{ get_file_id($File::Next::name) };
432
433 if ( $dont_ignore_dir_filter ) {
434 if ( $previous_dir eq $File::Next::dir ) {
435 if ( $previous_dir_ignore_result ) {
436 return 0;
437 }
438 }
439 else {
440 my @dirs = File::Spec->splitdir($File::Next::dir);
441
442 my $is_ignoring = 0;
443
444 for ( my $i = 0; $i < @dirs; $i++) {
445 my $dir_rsrc = App::Ack::File->new(File::Spec->catfile(@dirs[0 .. $i]));
446
447 my $j = 0;
448 for my $filter (@ignore_dir_filter) {
449 if ( $filter->filter($dir_rsrc) ) {
450 $is_ignoring = !$is_inverted[$j];
451 }
452 $j++;
453 }
454 }
455
456 $previous_dir = $File::Next::dir;
457 $previous_dir_ignore_result = $is_ignoring;
458
459 if ( $is_ignoring ) {
460 return 0;
461 }
462 }
463 }
464
465 # Ignore named pipes found in directory searching. Named
466 # pipes created by subprocesses get specified on the command
467 # line, so the rule of "always select whatever is on the
468 # command line" wins.
469 return 0 if -p $File::Next::name;
470
471 # We can't handle unreadable filenames; report them.
472 if ( not -r _ ) {
473 use filetest 'access';
474
475 if ( not -R $File::Next::name ) {
476 if ( $App::Ack::report_bad_filenames ) {
477 App::Ack::warn( "${File::Next::name}: cannot open file for reading" );
478 }
479 return 0;
480 }
481 }
482
483 my $file = App::Ack::File->new($File::Next::name);
484
485 if ( $ifiles_filters && $ifiles_filters->filter($file) ) {
486 return 0;
487 }
488
489 my $match_found = $direct_filters->filter($file);
490
491 # Don't bother invoking inverse filters unless we consider the current file a match.
492 if ( $match_found && $inverse_filters->filter( $file ) ) {
493 $match_found = 0;
494 }
495 return $match_found;
496 };
497 }
498
499
500 # Returns a (fairly) unique identifier for a file.
501 # Use this function to compare two files to see if they're
502 # equal (ie. the same file, but with a different path/links/etc).
503 sub get_file_id {
504 my ( $filename ) = @_;
505
506 if ( $App::Ack::is_windows ) {
507 return File::Next::reslash( $filename );
508 }
509 else {
510 # XXX Is this the best method? It always hits the FS.
511 if ( my ( $dev, $inode ) = (stat($filename))[0, 1] ) {
512 return join(':', $dev, $inode);
513 }
514 else {
515 # XXX This could be better.
516 return $filename;
517 }
518 }
519 }
520
521 # Returns a regex object based on a string and command-line options.
522 # Dies when the regex $str is undefined (i.e. not given on command line).
523
524 sub build_regex {
525 my $str = shift;
526 my $opt = shift;
527
528 defined $str or App::Ack::die( 'No regular expression found.' );
529
530 if ( !$opt->{Q} ) {
531 # Compile the regex to see if it dies or throws warnings.
532 local $SIG{__WARN__} = sub { die @_ }; # Anything that warns becomes a die.
533 my $scratch_regex = eval { qr/$str/ };
534 if ( not $scratch_regex ) {
535 my $err = $@;
536 chomp $err;
537
538 if ( $err =~ m{^(.+?); marked by <-- HERE in m/(.+?) <-- HERE} ) {
539 my ($why, $where) = ($1,$2);
540 my $pointy = ' ' x (6+length($where)) . '^---HERE';
541 App::Ack::die( "Invalid regex '$str'\nRegex: $str\n$pointy $why" );
542 }
543 else {
544 App::Ack::die( "Invalid regex '$str'\n$err" );
545 }
546 }
547 }
548
549 # Check for lowercaseness before we do any modifications.
550 my $regex_is_lc = App::Ack::is_lowercase( $str );
551
552 $str = quotemeta( $str ) if $opt->{Q};
553
554 my $scan_str = $str;
555
556 # Whole words only.
557 if ( $opt->{w} ) {
558 my $ok = 1;
559
560 if ( $str =~ /^\\[wd]/ ) {
561 # Explicit \w is good.
562 }
563 else {
564 # Can start with \w, (, [ or dot.
565 if ( $str !~ /^[\w\(\[\.]/ ) {
566 $ok = 0;
567 }
568 }
569
570 # Can end with \w, }, ), ], +, *, or dot.
571 if ( $str !~ /[\w\}\)\]\+\*\?\.]$/ ) {
572 $ok = 0;
573 }
574 # ... unless it's escaped.
575 elsif ( $str =~ /\\[\}\)\]\+\*\?\.]$/ ) {
576 $ok = 0;
577 }
578
579 if ( !$ok ) {
580 App::Ack::die( '-w will not do the right thing if your regex does not begin and end with a word character.' );
581 }
582
583 if ( $str =~ /^\w+$/ ) {
584 # No need for fancy regex if it's a simple word.
585 $str = sprintf( '\b(?:%s)\b', $str );
586 }
587 else {
588 $str = sprintf( '(?:^|\b|\s)\K(?:%s)(?=\s|\b|$)', $str );
589 }
590 }
591
592 if ( $opt->{i} || ($opt->{S} && $regex_is_lc) ) {
593 $_ = "(?i)$_" for ( $str, $scan_str );
594 }
595
596 my $scan_regex = undef;
597 my $regex = eval { qr/$str/ };
598 if ( $regex ) {
599 if ( $scan_str !~ /\$/ ) {
600 # No line_scan is possible if there's a $ in the regex.
601 $scan_regex = eval { qr/$scan_str/m };
602 }
603 }
604 else {
605 my $err = $@;
606 chomp $err;
607 App::Ack::die( "Invalid regex '$str':\n $err" );
608 }
609
610 return ($regex, $scan_regex);
611 }
612
613 my $match_colno;
614
615 {
616
617 # Number of context lines
618 my $n_before_ctx_lines;
619 my $n_after_ctx_lines;
620
621 # Array to keep track of lines that might be required for a "before" context
622 my @before_context_buf;
623 # Position to insert next line in @before_context_buf
624 my $before_context_pos;
625
626 # Number of "after" context lines still pending
627 my $after_context_pending;
628
629 # Number of latest line that got printed
630 my $printed_lineno;
631
632 my $is_first_match;
633 state $has_printed_from_any_file = 0;
634
635
636 sub file_loop_normal {
637 my $files = shift;
638
639 $n_before_ctx_lines = $opt_output ? 0 : ($opt_B || 0);
640 $n_after_ctx_lines = $opt_output ? 0 : ($opt_A || 0);
641
642 @before_context_buf = (undef) x $n_before_ctx_lines;
643 $before_context_pos = 0;
644
645 $is_tracking_context = $n_before_ctx_lines || $n_after_ctx_lines;
646
647 $is_first_match = 1;
648
649 my $nmatches = 0;
650 while ( defined( my $file = $files->next ) ) {
651 if ($is_tracking_context) {
652 $printed_lineno = 0;
653 $after_context_pending = 0;
654 if ( $opt_heading ) {
655 $is_first_match = 1;
656 }
657 }
658 my $needs_line_scan = 1;
659 if ( !$opt_passthru && !$opt_v ) {
660 $stats{prescans}++;
661 if ( $file->may_be_present( $scan_re ) ) {
662 $file->reset();
663 }
664 else {
665 $needs_line_scan = 0;
666 }
667 }
668 if ( $needs_line_scan ) {
669 $stats{linescans}++;
670 $nmatches += print_matches_in_file( $file );
671 }
672 last if $opt_1 && $nmatches;
673 }
674
675 return $nmatches;
676 }
677
678
679 sub print_matches_in_file {
680 my $file = shift;
681
682 my $max_count = $opt_m || -1; # Go negative for no limit so it can never reduce to 0.
683 my $nmatches = 0;
684 my $filename = $file->name;
685
686 my $has_printed_from_this_file = 0;
687
688 my $fh = $file->open;
689 if ( !$fh ) {
690 if ( $App::Ack::report_bad_filenames ) {
691 App::Ack::warn( "$filename: $!" );
692 }
693 return 0;
694 }
695
696 my $display_filename = $filename;
697 if ( $opt_show_filename && $opt_heading && $opt_color ) {
698 $display_filename = Term::ANSIColor::colored($display_filename, $ENV{ACK_COLOR_FILENAME});
699 }
700
701 # Check for context before the main loop, so we don't pay for it if we don't need it.
702 if ( $is_tracking_context ) {
703 local $_ = undef;
704
705 $after_context_pending = 0;
706
707 my $in_range = range_setup();
708
709 while ( <$fh> ) {
710 chomp;
711 $match_colno = undef;
712
713 $in_range = 1 if ( $using_ranges && !$in_range && $opt_range_start && /$opt_range_start/o );
714
715 my $does_match;
716 if ( $in_range ) {
717 if ( $opt_v ) {
718 $does_match = !/$search_re/o;
719 }
720 else {
721 if ( $does_match = /$search_re/o ) {
722 # @- = @LAST_MATCH_START
723 # @+ = @LAST_MATCH_END
724 $match_colno = $-[0] + 1;
725 }
726 }
727 }
728
729 if ( $does_match && $max_count ) {
730 if ( !$has_printed_from_this_file ) {
731 $stats{filematches}++;
732 if ( $opt_break && $has_printed_from_any_file ) {
733 App::Ack::print_blank_line();
734 }
735 if ( $opt_show_filename && $opt_heading ) {
736 App::Ack::say( $display_filename );
737 }
738 }
739 print_line_with_context( $filename, $_, $. );
740 $has_printed_from_this_file = 1;
741 $stats{linematches}++;
742 $nmatches++;
743 $max_count--;
744 }
745 else {
746 if ( $after_context_pending ) {
747 # Disable $opt_column since there are no matches in the context lines.
748 local $opt_column = 0;
749 print_line_with_options( $filename, $_, $., '-' );
750 --$after_context_pending;
751 }
752 elsif ( $n_before_ctx_lines ) {
753 # Save line for "before" context.
754 $before_context_buf[$before_context_pos] = $_;
755 $before_context_pos = ($before_context_pos+1) % $n_before_ctx_lines;
756 }
757 }
758
759 $in_range = 0 if ( $using_ranges && $in_range && $opt_range_end && /$opt_range_end/o );
760
761 last if ($max_count == 0) && ($after_context_pending == 0);
762 }
763 }
764 elsif ( $opt_passthru ) {
765 local $_ = undef;
766
767 my $in_range = range_setup();
768
769 while ( <$fh> ) {
770 chomp;
771
772 $in_range = 1 if ( $using_ranges && !$in_range && $opt_range_start && /$opt_range_start/o );
773
774 $match_colno = undef;
775 if ( $in_range && ($opt_v xor /$search_re/o) ) {
776 if ( !$opt_v ) {
777 $match_colno = $-[0] + 1;
778 }
779 if ( !$has_printed_from_this_file ) {
780 if ( $opt_break && $has_printed_from_any_file ) {
781 App::Ack::print_blank_line();
782 }
783 if ( $opt_show_filename && $opt_heading ) {
784 App::Ack::say( $display_filename );
785 }
786 }
787 print_line_with_options( $filename, $_, $., ':' );
788 $has_printed_from_this_file = 1;
789 $nmatches++;
790 $max_count--;
791 }
792 else {
793 if ( $opt_break && !$has_printed_from_this_file && $has_printed_from_any_file ) {
794 App::Ack::print_blank_line();
795 }
796 print_line_with_options( $filename, $_, $., '-', 1 );
797 $has_printed_from_this_file = 1;
798 }
799
800 $in_range = 0 if ( $using_ranges && $in_range && $opt_range_end && /$opt_range_end/o );
801
802 last if $max_count == 0;
803 }
804 }
805 elsif ( $opt_v ) {
806 local $_ = undef;
807
808 $match_colno = undef;
809 my $in_range = range_setup();
810
811 while ( <$fh> ) {
812 chomp;
813
814 $in_range = 1 if ( $using_ranges && !$in_range && $opt_range_start && /$opt_range_start/o );
815
816 if ( $in_range ) {
817 if ( !/$search_re/o ) {
818 if ( !$has_printed_from_this_file ) {
819 if ( $opt_break && $has_printed_from_any_file ) {
820 App::Ack::print_blank_line();
821 }
822 if ( $opt_show_filename && $opt_heading ) {
823 App::Ack::say( $display_filename );
824 }
825 }
826 print_line_with_context( $filename, $_, $. );
827 $has_printed_from_this_file = 1;
828 $nmatches++;
829 $max_count--;
830 }
831 }
832
833 $in_range = 0 if ( $using_ranges && $in_range && $opt_range_end && /$opt_range_end/o );
834
835 last if $max_count == 0;
836 }
837 }
838 else { # Normal search: No context, no -v, no --passthru
839 local $_ = undef;
840
841 my $last_match_lineno;
842 my $in_range = range_setup();
843
844 while ( <$fh> ) {
845 chomp;
846
847 $in_range = 1 if ( $using_ranges && !$in_range && $opt_range_start && /$opt_range_start/o );
848
849 if ( $in_range ) {
850 $match_colno = undef;
851 if ( /$search_re/o ) {
852 $match_colno = $-[0] + 1;
853 if ( !$has_printed_from_this_file ) {
854 $stats{filematches}++;
855 if ( $opt_break && $has_printed_from_any_file ) {
856 App::Ack::print_blank_line();
857 }
858 if ( $opt_show_filename && $opt_heading ) {
859 App::Ack::say( $display_filename );
860 }
861 }
862 if ( $opt_p ) {
863 if ( $last_match_lineno ) {
864 if ( $. > $last_match_lineno + $opt_p ) {
865 App::Ack::print_blank_line();
866 }
867 }
868 elsif ( !$opt_break && $has_printed_from_any_file ) {
869 App::Ack::print_blank_line();
870 }
871 }
872 s/[\r\n]+$//;
873 print_line_with_options( $filename, $_, $., ':' );
874 $has_printed_from_this_file = 1;
875 $nmatches++;
876 $stats{linematches}++;
877 $max_count--;
878 $last_match_lineno = $.;
879 }
880 }
881
882 $in_range = 0 if ( $using_ranges && $in_range && $opt_range_end && /$opt_range_end/o );
883
884 last if $max_count == 0;
885 }
886 }
887
888 return $nmatches;
889 }
890
891
892 sub print_line_with_options {
893 my ( $filename, $line, $lineno, $separator, $skip_coloring ) = @_;
894
895 $has_printed_from_any_file = 1;
896 $printed_lineno = $lineno;
897
898 my @line_parts;
899
900 if ( $opt_show_filename && defined($filename) ) {
901 my $colno;
902 $colno = get_match_colno() if $opt_column;
903 if ( $opt_color ) {
904 $filename = Term::ANSIColor::colored( $filename, $ENV{ACK_COLOR_FILENAME} );
905 $lineno = Term::ANSIColor::colored( $lineno, $ENV{ACK_COLOR_LINENO} );
906 $colno = Term::ANSIColor::colored( $colno, $ENV{ACK_COLOR_COLNO} ) if $opt_column;
907 }
908 if ( $opt_heading ) {
909 push @line_parts, $lineno;
910 }
911 else {
912 push @line_parts, $filename, $lineno;
913 }
914 push @line_parts, $colno if $opt_column;
915 }
916
917 if ( $opt_output ) {
918 while ( $line =~ /$search_re/og ) {
919 my $output = $opt_output;
920 if ( @special_vars_used_by_opt_output ) {
921 no strict;
922
923 # Stash copies of the special variables because we can't rely
924 # on them not changing in the process of doing the s///.
925
926 my %keep = map { ($_ => ${$_} // '') } @special_vars_used_by_opt_output;
927 $keep{_} = $line if exists $keep{_}; # Manually set it because $_ gets reset in a map.
928 $keep{f} = $filename if exists $keep{f};
929 my $special_vars_used_by_opt_output = join( '', @special_vars_used_by_opt_output );
930 $output =~ s/\$([$special_vars_used_by_opt_output])/$keep{$1}/ego;
931 }
932 App::Ack::say( join( $separator, @line_parts, $output ) );
933 }
934 }
935 else {
936 my $underline = '';
937
938 # We have to do underlining before any highlighting because highlighting modifies string length.
939 if ( $opt_underline && !$skip_coloring ) {
940 while ( $line =~ /$search_re/og ) {
941 my $match_start = $-[0] // next;
942 my $match_end = $+[0];
943 my $match_length = $match_end - $match_start;
944 last if $match_length <= 0;
945
946 my $spaces_needed = $match_start - length $underline;
947
948 $underline .= (' ' x $spaces_needed);
949 $underline .= ('^' x $match_length);
950 }
951 }
952 if ( $opt_color && !$skip_coloring ) {
953 my $highlighted = 0; # If highlighted, need to escape afterwards.
954
955 while ( $line =~ /$search_re/og ) {
956 my $match_start = $-[0] // next;
957 my $match_end = $+[0];
958 my $match_length = $match_end - $match_start;
959 last if $match_length <= 0;
960
961 my $substring = substr( $line, $match_start, $match_length );
962 my $substitution = Term::ANSIColor::colored( $substring, $ENV{ACK_COLOR_MATCH} );
963
964 # Fourth argument replaces the string specified by the first three.
965 substr( $line, $match_start, $match_length, $substitution );
966
967 # Move the offset of where /g left off forward the number of spaces of highlighting.
968 pos($line) = $match_end + (length( $substitution ) - length( $substring ));
969 $highlighted = 1;
970 }
971 # Reset formatting and delete everything to the end of the line.
972 $line .= "\e[0m\e[K" if $highlighted;
973 }
974
975 push @line_parts, $line;
976 App::Ack::say( join( $separator, @line_parts ) );
977
978 # Print the underline, if appropriate.
979 if ( $underline ne '' ) {
980 # Figure out how many spaces are used per line for the ANSI coloring.
981 state $chars_used_by_coloring;
982 if ( !defined($chars_used_by_coloring) ) {
983 $chars_used_by_coloring = 0;
984 if ( $opt_color ) {
985 my $len_fn = sub { length( Term::ANSIColor::colored( 'x', $ENV{$_[0]} ) ) - 1 };
986 $chars_used_by_coloring += $len_fn->('ACK_COLOR_FILENAME') unless $opt_heading;
987 $chars_used_by_coloring += $len_fn->('ACK_COLOR_LINENO');
988 $chars_used_by_coloring += $len_fn->('ACK_COLOR_COLNO') if $opt_column;
989 }
990 }
991
992 pop @line_parts; # Leave only the stuff on the left.
993 if ( @line_parts ) {
994 my $stuff_on_the_left = join( $separator, @line_parts );
995 my $spaces_needed = length($stuff_on_the_left) - $chars_used_by_coloring + 1;
996
997 App::Ack::print( ' ' x $spaces_needed );
998 }
999 App::Ack::say( $underline );
1000 }
1001 }
1002
1003 return;
1004 }
1005
1006 sub print_line_with_context {
1007 my ( $filename, $matching_line, $lineno ) = @_;
1008
1009 $matching_line =~ s/[\r\n]+$//;
1010
1011 # Check if we need to print context lines first.
1012 if ( $opt_A || $opt_B ) {
1013 my $before_unprinted = $lineno - $printed_lineno - 1;
1014 if ( !$is_first_match && ( !$printed_lineno || $before_unprinted > $n_before_ctx_lines ) ) {
1015 App::Ack::say( '--' );
1016 }
1017
1018 # We want at most $n_before_ctx_lines of context.
1019 if ( $before_unprinted > $n_before_ctx_lines ) {
1020 $before_unprinted = $n_before_ctx_lines;
1021 }
1022
1023 while ( $before_unprinted > 0 ) {
1024 my $line = $before_context_buf[($before_context_pos - $before_unprinted + $n_before_ctx_lines) % $n_before_ctx_lines];
1025
1026 chomp $line;
1027
1028 # Disable $opt->{column} since there are no matches in the context lines.
1029 local $opt_column = 0;
1030
1031 print_line_with_options( $filename, $line, $lineno-$before_unprinted, '-' );
1032 $before_unprinted--;
1033 }
1034 }
1035
1036 print_line_with_options( $filename, $matching_line, $lineno, ':' );
1037
1038 # We want to get the next $n_after_ctx_lines printed.
1039 $after_context_pending = $n_after_ctx_lines;
1040
1041 $is_first_match = 0;
1042
1043 return;
1044 }
1045
1046 }
1047
1048 sub get_match_colno {
1049 return $match_colno;
1050 }
1051
1052 sub count_matches_in_file {
1053 my $file = shift;
1054 my $bail = shift; # True if we're just checking for existence.
1055
1056 my $nmatches = 0;
1057 my $do_scan = 1;
1058
1059 if ( !$file->open() ) {
1060 $do_scan = 0;
1061 if ( $App::Ack::report_bad_filenames ) {
1062 App::Ack::warn( $file->name . ": $!" );
1063 }
1064 }
1065 else {
1066 if ( !$opt_v ) {
1067 if ( !$file->may_be_present( $scan_re ) ) {
1068 $do_scan = 0;
1069 }
1070 }
1071 }
1072
1073 if ( $do_scan ) {
1074 $file->reset();
1075
1076 my $in_range = range_setup();
1077
1078 my $fh = $file->{fh};
1079 if ( $using_ranges ) {
1080 while ( <$fh> ) {
1081 chomp;
1082 $in_range = 1 if ( !$in_range && $opt_range_start && /$opt_range_start/o );
1083 if ( $in_range ) {
1084 if ( /$search_re/o xor $opt_v ) {
1085 ++$nmatches;
1086 last if $bail;
1087 }
1088 }
1089 $in_range = 0 if ( $in_range && $opt_range_end && /$opt_range_end/o );
1090 }
1091 }
1092 else {
1093 while ( <$fh> ) {
1094 chomp;
1095 if ( /$search_re/o xor $opt_v ) {
1096 ++$nmatches;
1097 last if $bail;
1098 }
1099 }
1100 }
1101 }
1102 $file->close;
1103
1104 return $nmatches;
1105 }
1106
1107
1108 sub range_setup {
1109 return !$using_ranges || (!$opt_range_start && $opt_range_end);
1110 }
1111
1112
1113 =pod
1114
1115 =encoding UTF-8
1116
1117 =head1 NAME
1118
1119 ack - grep-like text finder
1120
1121 =head1 SYNOPSIS
1122
1123 ack [options] PATTERN [FILE...]
1124 ack -f [options] [DIRECTORY...]
1125
1126 =head1 DESCRIPTION
1127
1128 ack is designed as an alternative to F<grep> for programmers.
1129
1130 ack searches the named input FILEs or DIRECTORYs for lines containing a
1131 match to the given PATTERN. By default, ack prints the matching lines.
1132 If no FILE or DIRECTORY is given, the current directory will be searched.
1133
1134 PATTERN is a Perl regular expression. Perl regular expressions
1135 are commonly found in other programming languages, but for the particulars
1136 of their behavior, please consult
1137 L<perlreref|https://perldoc.perl.org/perlreref.html>. If you don't know
1138 how to use regular expression but are interested in learning, you may
1139 consult L<perlretut|https://perldoc.perl.org/perlretut.html>. If you do not
1140 need or want ack to use regular expressions, please see the
1141 C<-Q>/C<--literal> option.
1142
1143 Ack can also list files that would be searched, without actually
1144 searching them, to let you take advantage of ack's file-type filtering
1145 capabilities.
1146
1147 =head1 FILE SELECTION
1148
1149 If files are not specified for searching, either on the command
1150 line or piped in with the C<-x> option, I<ack> delves into
1151 subdirectories selecting files for searching.
1152
1153 I<ack> is intelligent about the files it searches. It knows about
1154 certain file types, based on both the extension on the file and,
1155 in some cases, the contents of the file. These selections can be
1156 made with the B<--type> option.
1157
1158 With no file selection, I<ack> searches through regular files that
1159 are not explicitly excluded by B<--ignore-dir> and B<--ignore-file>
1160 options, either present in F<ackrc> files or on the command line.
1161
1162 The default options for I<ack> ignore certain files and directories. These
1163 include:
1164
1165 =over 4
1166
1167 =item * Backup files: Files matching F<#*#> or ending with F<~>.
1168
1169 =item * Coredumps: Files matching F<core.\d+>
1170
1171 =item * Version control directories like F<.svn> and F<.git>.
1172
1173 =back
1174
1175 Run I<ack> with the C<--dump> option to see what settings are set.
1176
1177 However, I<ack> always searches the files given on the command line,
1178 no matter what type. If you tell I<ack> to search in a coredump,
1179 it will search in a coredump.
1180
1181 =head1 DIRECTORY SELECTION
1182
1183 I<ack> descends through the directory tree of the starting directories
1184 specified. If no directories are specified, the current working directory is
1185 used. However, it will ignore the shadow directories used by
1186 many version control systems, and the build directories used by the
1187 Perl MakeMaker system. You may add or remove a directory from this
1188 list with the B<--[no]ignore-dir> option. The option may be repeated
1189 to add/remove multiple directories from the ignore list.
1190
1191 For a complete list of directories that do not get searched, run
1192 C<ack --dump>.
1193
1194 =head1 MATCHING IN A RANGE OF LINES
1195
1196 The C<--range-start> and C<--range-end> options let you specify ranges of
1197 lines to search within each file.
1198
1199 Say you had the following file, called F<testfile>:
1200
1201 # This function calls print on "foo".
1202 sub foo {
1203 print 'foo';
1204 }
1205 my $print = 1;
1206 sub bar {
1207 print 'bar';
1208 }
1209 my $task = 'print';
1210
1211 Calling C<ack print> will give us five matches:
1212
1213 $ ack print testfile
1214 # This function calls print on "foo".
1215 print 'foo';
1216 my $print = 1;
1217 print 'bar';
1218 my $task = 'print';
1219
1220 What if we only want to search for C<print> within the subroutines? We can
1221 specify ranges of lines that we want ack to search. The range starts with
1222 any line that matches the pattern C<^sub \w+>, and stops with any line that
1223 matches C<^}>.
1224
1225 $ ack --range-start='^sub \w+' --range-end='^}' print testfile
1226 print 'foo';
1227 print 'bar';
1228
1229 Note that ack searched two ranges of lines. The listing below shows which
1230 lines were in a range and which were out of the range.
1231
1232 Out # This function calls print on "foo".
1233 In sub foo {
1234 In print 'foo';
1235 In }
1236 Out my $print = 1;
1237 In sub bar {
1238 In print 'bar';
1239 In }
1240 Out my $task = 'print';
1241
1242 You don't have to specify both C<--range-start> and C<--range-end>. IF
1243 C<--range-start> is omitted, then the range runs from the first line in the
1244 file unitl the first line that matches C<--range-end>. Similarly, if
1245 C<--range-end> is omitted, the range runs from the first line matching
1246 C<--range-start> to the end of the file.
1247
1248 For example, if you wanted to search all HTML files up until the first
1249 instance of the C<< <body> >>, you could do
1250
1251 ack foo --range-end='<body>'
1252
1253 Or to search after Perl's `__DATA__` or `__END__` markers, you would do
1254
1255 ack pattern --range-end='^__(END|DATA)__'
1256
1257 It's possible for a range to start and stop on the same line. For example
1258
1259 --range-start='<title>' --range-end='</title>'
1260
1261 would match this line as both the start and end of the range, making a
1262 one-line range.
1263
1264 <title>Page title</title>
1265
1266 Note that the patterns in C<--range-start> and C<--range-end> are not
1267 affected by options like C<-i>, C<-w> and C<-Q> that modify the behavior of
1268 the main pattern being matched.
1269
1270 Again, ranges only affect where matches are looked for. Everything else in
1271 ack works the same way. Using C<-c> option with a range will give a count
1272 of all the matches that appear within those ranges. The C<-l> shows those
1273 files that have a match within a range, and the C<-L> option shows files
1274 that do not have a match within a range.
1275
1276 The C<-v> option for negating a match works inside the range, too.
1277 To see lines that don't match "google" within the "<head>" section of
1278 your HTML files, you could do:
1279
1280 ack google -v --html --range-start='<head' --range-end='</head>'
1281
1282 Specifying a range to search does not affect how matches are displayed.
1283 The context for a match will still be the same, and
1284
1285 Using the context options work the same way, and will show context
1286 lines for matches even if the context lines fall outside the range.
1287 Similarly, C<--passthru> will show all lines in the file, but only show
1288 matches for lines within the range.
1289
1290 =head1 OPTIONS
1291
1292 =over 4
1293
1294 =item B<--ackrc>
1295
1296 Specifies an ackrc file to load after all others; see L</"ACKRC LOCATION SEMANTICS">.
1297
1298 =item B<-A I<NUM>>, B<--after-context=I<NUM>>
1299
1300 Print I<NUM> lines of trailing context after matching lines.
1301
1302 =item B<-B I<NUM>>, B<--before-context=I<NUM>>
1303
1304 Print I<NUM> lines of leading context before matching lines.
1305
1306 =item B<--[no]break>
1307
1308 Print a break between results from different files. On by default
1309 when used interactively.
1310
1311 =item B<-C [I<NUM>]>, B<--context[=I<NUM>]>
1312
1313 Print I<NUM> lines (default 2) of context around matching lines.
1314 You can specify zero lines of context to override another context
1315 specified in an ackrc.
1316
1317 =item B<-c>, B<--count>
1318
1319 Suppress normal output; instead print a count of matching lines for
1320 each input file. If B<-l> is in effect, it will only show the
1321 number of lines for each file that has lines matching. Without
1322 B<-l>, some line counts may be zeroes.
1323
1324 If combined with B<-h> (B<--no-filename>) ack outputs only one total
1325 count.
1326
1327 =item B<--[no]color>, B<--[no]colour>
1328
1329 B<--color> highlights the matching text. B<--nocolor> suppresses
1330 the color. This is on by default unless the output is redirected.
1331
1332 On Windows, this option is off by default unless the
1333 L<Win32::Console::ANSI> module is installed or the C<ACK_PAGER_COLOR>
1334 environment variable is used.
1335
1336 =item B<--color-filename=I<color>>
1337
1338 Sets the color to be used for filenames.
1339
1340 =item B<--color-match=I<color>>
1341
1342 Sets the color to be used for matches.
1343
1344 =item B<--color-colno=I<color>>
1345
1346 Sets the color to be used for column numbers.
1347
1348 =item B<--color-lineno=I<color>>
1349
1350 Sets the color to be used for line numbers.
1351
1352 =item B<--[no]column>
1353
1354 Show the column number of the first match. This is helpful for
1355 editors that can place your cursor at a given position.
1356
1357 =item B<--create-ackrc>
1358
1359 Dumps the default ack options to standard output. This is useful for
1360 when you want to customize the defaults.
1361
1362 =item B<--dump>
1363
1364 Writes the list of options loaded and where they came from to standard
1365 output. Handy for debugging.
1366
1367 =item B<--[no]env>
1368
1369 B<--noenv> disables all environment processing. No F<.ackrc> is
1370 read and all environment variables are ignored. By default, F<ack>
1371 considers F<.ackrc> and settings in the environment.
1372
1373 =item B<--flush>
1374
1375 B<--flush> flushes output immediately. This is off by default
1376 unless ack is running interactively (when output goes to a pipe or
1377 file).
1378
1379 =item B<-f>
1380
1381 Only print the files that would be searched, without actually doing
1382 any searching. PATTERN must not be specified, or it will be taken
1383 as a path to search.
1384
1385 =item B<--files-from=I<FILE>>
1386
1387 The list of files to be searched is specified in I<FILE>. The list of
1388 files are separated by newlines. If I<FILE> is C<->, the list is loaded
1389 from standard input.
1390
1391 Note that the list of files is B<not> filtered in any way. If you
1392 add C<--type=html> in addition to C<--files-from>, the C<--type> will
1393 be ignored.
1394
1395
1396 =item B<--[no]filter>
1397
1398 Forces ack to act as if it were receiving input via a pipe.
1399
1400 =item B<--[no]follow>
1401
1402 Follow or don't follow symlinks, other than whatever starting files
1403 or directories were specified on the command line.
1404
1405 This is off by default.
1406
1407 =item B<-g I<PATTERN>>
1408
1409 Print searchable files where the relative path + filename matches
1410 I<PATTERN>.
1411
1412 Note that
1413
1414 ack -g foo
1415
1416 is exactly the same as
1417
1418 ack -f | ack foo
1419
1420 This means that just as ack will not search, for example, F<.jpg>
1421 files, C<-g> will not list F<.jpg> files either. ack is not intended
1422 to be a general-purpose file finder.
1423
1424 Note also that if you have C<-i> in your .ackrc that the filenames
1425 to be matched will be case-insensitive as well.
1426
1427 This option can be combined with B<--color> to make it easier to
1428 spot the match.
1429
1430 =item B<--[no]group>
1431
1432 B<--group> groups matches by file name. This is the default
1433 when used interactively.
1434
1435 B<--nogroup> prints one result per line, like grep. This is the
1436 default when output is redirected.
1437
1438 =item B<-H>, B<--with-filename>
1439
1440 Print the filename for each match. This is the default unless searching
1441 a single explicitly specified file.
1442
1443 =item B<-h>, B<--no-filename>
1444
1445 Suppress the prefixing of filenames on output when multiple files are
1446 searched.
1447
1448 =item B<--[no]heading>
1449
1450 Print a filename heading above each file's results. This is the default
1451 when used interactively.
1452
1453 =item B<--help>
1454
1455 Print a short help statement.
1456
1457 =item B<--help-types>
1458
1459 Print all known types.
1460
1461 =item B<--help-colors>
1462
1463 Print a chart of various color combinations.
1464
1465 =item B<--help-rgb-colors>
1466
1467 Like B<--help-colors> but with more precise RGB colors.
1468
1469 =item B<-i>, B<--ignore-case>
1470
1471 Ignore case distinctions in PATTERN. Overrides B<--smart-case> and B<-I>.
1472
1473 =item B<-I>, B<--no-ignore-case>
1474
1475 Turns on case distinctions in PATTERN. Overrides B<--smart-case> and B<-i>.
1476
1477 =item B<--ignore-ack-defaults>
1478
1479 Tells ack to completely ignore the default definitions provided with ack.
1480 This is useful in combination with B<--create-ackrc> if you I<really> want
1481 to customize ack.
1482
1483 =item B<--[no]ignore-dir=I<DIRNAME>>, B<--[no]ignore-directory=I<DIRNAME>>
1484
1485 Ignore directory (as CVS, .svn, etc are ignored). May be used
1486 multiple times to ignore multiple directories. For example, mason
1487 users may wish to include B<--ignore-dir=data>. The B<--noignore-dir>
1488 option allows users to search directories which would normally be
1489 ignored (perhaps to research the contents of F<.svn/props> directories).
1490
1491 The I<DIRNAME> must always be a simple directory name. Nested
1492 directories like F<foo/bar> are NOT supported. You would need to
1493 specify B<--ignore-dir=foo> and then no files from any foo directory
1494 are taken into account by ack unless given explicitly on the command
1495 line.
1496
1497 =item B<--ignore-file=I<FILTER:ARGS>>
1498
1499 Ignore files matching I<FILTER:ARGS>. The filters are specified
1500 identically to file type filters as seen in L</"Defining your own types">.
1501
1502 =item B<-k>, B<--known-types>
1503
1504 Limit selected files to those with types that ack knows about.
1505
1506 =item B<-l>, B<--files-with-matches>
1507
1508 Only print the filenames of matching files, instead of the matching text.
1509
1510 =item B<-L>, B<--files-without-matches>
1511
1512 Only print the filenames of files that do I<NOT> match.
1513
1514 =item B<--match I<PATTERN>>
1515
1516 Specify the I<PATTERN> explicitly. This is helpful if you don't want to put the
1517 regex as your first argument, e.g. when executing multiple searches over the
1518 same set of files.
1519
1520 # search for foo and bar in given files
1521 ack file1 t/file* --match foo
1522 ack file1 t/file* --match bar
1523
1524 =item B<-m=I<NUM>>, B<--max-count=I<NUM>>
1525
1526 Print only I<NUM> matches out of each file. If you want to stop ack
1527 after printing the first match of any kind, use the B<-1> options.
1528
1529 =item B<--man>
1530
1531 Print this manual page.
1532
1533 =item B<-n>, B<--no-recurse>
1534
1535 No descending into subdirectories.
1536
1537 =item B<-o>
1538
1539 Show only the part of each line matching PATTERN (turns off text
1540 highlighting). This is exactly the same as C<--output=$&>.
1541
1542 =item B<--output=I<expr>>
1543
1544 Output the evaluation of I<expr> for each line (turns off text
1545 highlighting). If PATTERN matches more than once then a line is
1546 output for each non-overlapping match.
1547
1548 I<expr> may contain the strings "\n", "\r" and "\t", which will be
1549 expanded to their corresponding characters line feed, carriage return
1550 and tab, respectively.
1551
1552 I<expr> may also contain the following Perl special variables:
1553
1554 =over 4
1555
1556 =item C<$1> through C<$9>
1557
1558 The subpattern from the corresponding set of capturing parentheses.
1559 If your pattern is C<(.+) and (.+)>, and the string is "this and
1560 that', then C<$1> is "this" and C<$2> is "that".
1561
1562 =item C<$_>
1563
1564 The contents of the line in the file.
1565
1566 =item C<$.>
1567
1568 The number of the line in the file.
1569
1570 =item C<$&>, C<$`> and C<$'>
1571
1572 C<$&> is the the string matched by the pattern, C<$`> is what
1573 precedes the match, and C<$'> is what follows it. If the pattern
1574 is C<gra(ph|nd)> and the string is "lexicographic", then C<$&> is
1575 "graph", C<$`> is "lexico" and C<$'> is "ic".
1576
1577 Use of these variables in your output will slow down the pattern
1578 matching.
1579
1580 =item C<$+>
1581
1582 The match made by the last parentheses that matched in the pattern.
1583 For example, if your pattern is C<Version: (.+)|Revision: (.+)>,
1584 then C<$+> will contain whichever set of parentheses matched.
1585
1586 =item C<$f>
1587
1588 C<$f> is available, in C<--output> only, to insert the filename.
1589 This is a stand-in for the discovered C<$filename> usage in old C<< ack2 --output >>,
1590 which is disallowed with C<ack3> improved security.
1591
1592 The intended usage is to provide the grep or compile-error syntax needed for editor/IDE go-to-line integration,
1593 e.g. C<--output=$f:$.:$_> or C<--output=$f\t$.\t$&>
1594
1595 =back
1596
1597 =item B<--pager=I<program>>, B<--nopager>
1598
1599 B<--pager> directs ack's output through I<program>. This can also be specified
1600 via the C<ACK_PAGER> and C<ACK_PAGER_COLOR> environment variables.
1601
1602 Using --pager does not suppress grouping and coloring like piping
1603 output on the command-line does.
1604
1605 B<--nopager> cancels any setting in F<~/.ackrc>, C<ACK_PAGER> or C<ACK_PAGER_COLOR>.
1606 No output will be sent through a pager.
1607
1608 =item B<--passthru>
1609
1610 Prints all lines, whether or not they match the expression. Highlighting
1611 will still work, though, so it can be used to highlight matches while
1612 still seeing the entire file, as in:
1613
1614 # Watch a log file, and highlight a certain IP address.
1615 $ tail -f ~/access.log | ack --passthru 123.45.67.89
1616
1617 =item B<--print0>
1618
1619 Only works in conjunction with B<-f>, B<-g>, B<-l> or B<-c>, options
1620 that only list filenames. The filenames are output separated with a
1621 null byte instead of the usual newline. This is helpful when dealing
1622 with filenames that contain whitespace, e.g.
1623
1624 # Remove all files of type HTML.
1625 ack -f --html --print0 | xargs -0 rm -f
1626
1627 =item B<-p[N]>, B<--proximate[=N]>
1628
1629 Groups together match lines that are within N lines of each other.
1630 This is useful for visually picking out matches that appear close
1631 to other matches.
1632
1633 For example, if you got these results without the C<--proximate> option,
1634
1635 15: First match
1636 18: Second match
1637 19: Third match
1638 37: Fourth match
1639
1640 they would look like this with C<--proximate=1>
1641
1642 15: First match
1643
1644 18: Second match
1645 19: Third match
1646
1647 37: Fourth match
1648
1649 and this with C<--proximate=3>.
1650
1651 15: First match
1652 18: Second match
1653 19: Third match
1654
1655 37: Fourth match
1656
1657 If N is omitted, N is set to 1.
1658
1659 =item B<-P>
1660
1661 Negates the effect of the B<--proximate> option. Shortcut for B<--proximate=0>.
1662
1663 =item B<-Q>, B<--literal>
1664
1665 Quote all metacharacters in PATTERN, it is treated as a literal.
1666
1667 =item B<-r>, B<-R>, B<--recurse>
1668
1669 Recurse into sub-directories. This is the default and just here for
1670 compatibility with grep. You can also use it for turning B<--no-recurse> off.
1671
1672 =item B<--range-start=PATTERN>, B<--range-end=PATTERN>
1673
1674 Specifies patterns that mark the start and end of a range. See
1675 L<MATCHING IN A RANGE OF LINES> for details.
1676
1677 =item B<-s>
1678
1679 Suppress error messages about nonexistent or unreadable files. This is taken
1680 from fgrep.
1681
1682 =item B<-S>, B<--[no]smart-case>, B<--no-smart-case>
1683
1684 Ignore case in the search strings if PATTERN contains no uppercase
1685 characters. This is similar to C<smartcase> in the vim text editor.
1686 The options overrides B<-i> and B<-I>.
1687
1688 B<-S> is a synonym for B<--smart-case>.
1689
1690 B<-i> always overrides this option.
1691
1692 =item B<--sort-files>
1693
1694 Sorts the found files lexicographically. Use this if you want your file
1695 listings to be deterministic between runs of I<ack>.
1696
1697 =item B<--show-types>
1698
1699 Outputs the filetypes that ack associates with each file.
1700
1701 Works with B<-f> and B<-g> options.
1702
1703 =item B<-t TYPE>, B<--type=TYPE>, B<--TYPE>
1704
1705 Specify the types of files to include in the search.
1706 TYPE is a filetype, like I<perl> or I<xml>. B<--type=perl> can
1707 also be specified as B<--perl>, although this is deprecated.
1708
1709 Type inclusions can be repeated and are ORed together.
1710
1711 See I<ack --help-types> for a list of valid types.
1712
1713 =item B<-T TYPE>, B<--type=noTYPE>, B<--noTYPE>
1714
1715 Specifies the type of files to exclude from the search. B<--type=noperl>
1716 can be done as B<--noperl>, although this is deprecated.
1717
1718 If a file is of both type "foo" and "bar", specifying both B<--type=foo>
1719 and B<--type=nobar> will exclude the file, because an exclusion takes
1720 precedence over an inclusion.
1721
1722 =item B<--type-add I<TYPE>:I<FILTER>:I<ARGS>>
1723
1724 Files with the given ARGS applied to the given FILTER
1725 are recognized as being of (the existing) type TYPE.
1726 See also L</"Defining your own types">.
1727
1728 =item B<--type-set I<TYPE>:I<FILTER>:I<ARGS>>
1729
1730 Files with the given ARGS applied to the given FILTER are recognized as
1731 being of type TYPE. This replaces an existing definition for type TYPE. See
1732 also L</"Defining your own types">.
1733
1734 =item B<--type-del I<TYPE>>
1735
1736 The filters associated with TYPE are removed from Ack, and are no longer considered
1737 for searches.
1738
1739 =item B<--[no]underline>
1740
1741 Turns on underlining of matches, where "underlining" is printing a line of
1742 carets under the match.
1743
1744 $ ack -u foo
1745 peanuts.txt
1746 17: Come kick the football you fool
1747 ^^^ ^^^
1748 623: Price per square foot
1749 ^^^
1750
1751 This is useful if you're dumping the results of an ack run into a text
1752 file or printer that doesn't support ANSI color codes.
1753
1754 The setting of underline does not affect highlighting of matches.
1755
1756 =item B<-v>, B<--invert-match>
1757
1758 Invert match: select non-matching lines.
1759
1760 =item B<--version>
1761
1762 Display version and copyright information.
1763
1764 =item B<-w>, B<--word-regexp>
1765
1766 Force PATTERN to match only whole words.
1767
1768 =item B<-x>
1769
1770 An abbreviation for B<--files-from=->. The list of files to search are read
1771 from standard input, with one line per file.
1772
1773 Note that the list of files is B<not> filtered in any way. If you add
1774 C<--type=html> in addition to C<-x>, the C<--type> will be ignored.
1775
1776 =item B<-1>
1777
1778 Stops after reporting first match of any kind. This is different
1779 from B<--max-count=1> or B<-m1>, where only one match per file is
1780 shown. Also, B<-1> works with B<-f> and B<-g>, where B<-m> does
1781 not.
1782
1783 =item B<--thpppt>
1784
1785 Display the all-important Bill The Cat logo. Note that the exact
1786 spelling of B<--thpppppt> is not important. It's checked against
1787 a regular expression.
1788
1789 =item B<--bar>
1790
1791 Check with the admiral for traps.
1792
1793 =item B<--cathy>
1794
1795 Chocolate, Chocolate, Chocolate!
1796
1797 =back
1798
1799 =head1 THE .ackrc FILE
1800
1801 The F<.ackrc> file contains command-line options that are prepended
1802 to the command line before processing. Multiple options may live
1803 on multiple lines. Lines beginning with a # are ignored. A F<.ackrc>
1804 might look like this:
1805
1806 # Always sort the files
1807 --sort-files
1808
1809 # Always color, even if piping to another program
1810 --color
1811
1812 # Use "less -r" as my pager
1813 --pager=less -r
1814
1815 Note that arguments with spaces in them do not need to be quoted,
1816 as they are not interpreted by the shell. Basically, each I<line>
1817 in the F<.ackrc> file is interpreted as one element of C<@ARGV>.
1818
1819 F<ack> looks in several locations for F<.ackrc> files; the searching
1820 process is detailed in L</"ACKRC LOCATION SEMANTICS">. These
1821 files are not considered if B<--noenv> is specified on the command line.
1822
1823 =head1 Defining your own types
1824
1825 ack allows you to define your own types in addition to the predefined
1826 types. This is done with command line options that are best put into
1827 an F<.ackrc> file - then you do not have to define your types over and
1828 over again. In the following examples the options will always be shown
1829 on one command line so that they can be easily copy & pasted.
1830
1831 File types can be specified both with the the I<--type=xxx> option,
1832 or the file type as an option itself. For example, if you create
1833 a filetype of "cobol", you can specify I<--type=cobol> or simply
1834 I<--cobol>. File types must be at least two characters long. This
1835 is why the C language is I<--cc> and the R language is I<--rr>.
1836
1837 I<ack --perl foo> searches for foo in all perl files. I<ack --help-types>
1838 tells you, that perl files are files ending
1839 in .pl, .pm, .pod or .t. So what if you would like to include .xs
1840 files as well when searching for --perl files? I<ack --type-add perl:ext:xs --perl foo>
1841 does this for you. B<--type-add> appends
1842 additional extensions to an existing type.
1843
1844 If you want to define a new type, or completely redefine an existing
1845 type, then use B<--type-set>. I<ack --type-set eiffel:ext:e,eiffel> defines
1846 the type I<eiffel> to include files with
1847 the extensions .e or .eiffel. So to search for all eiffel files
1848 containing the word Bertrand use I<ack --type-set eiffel:ext:e,eiffel --eiffel Bertrand>.
1849 As usual, you can also write B<--type=eiffel>
1850 instead of B<--eiffel>. Negation also works, so B<--noeiffel> excludes
1851 all eiffel files from a search. Redefining also works: I<ack --type-set cc:ext:c,h>
1852 and I<.xs> files no longer belong to the type I<cc>.
1853
1854 When defining your own types in the F<.ackrc> file you have to use
1855 the following:
1856
1857 --type-set=eiffel:ext:e,eiffel
1858
1859 or writing on separate lines
1860
1861 --type-set
1862 eiffel:ext:e,eiffel
1863
1864 The following does B<NOT> work in the F<.ackrc> file:
1865
1866 --type-set eiffel:ext:e,eiffel
1867
1868 In order to see all currently defined types, use I<--help-types>, e.g.
1869 I<ack --type-set backup:ext:bak --type-add perl:ext:perl --help-types>
1870
1871 In addition to filtering based on extension, ack offers additional
1872 filter types. The generic syntax is
1873 I<--type-set TYPE:FILTER:ARGS>; I<ARGS> depends on the value
1874 of I<FILTER>.
1875
1876 =over 4
1877
1878 =item is:I<FILENAME>
1879
1880 I<is> filters match the target filename exactly. It takes exactly one
1881 argument, which is the name of the file to match.
1882
1883 Example:
1884
1885 --type-set make:is:Makefile
1886
1887 =item ext:I<EXTENSION>[,I<EXTENSION2>[,...]]
1888
1889 I<ext> filters match the extension of the target file against a list
1890 of extensions. No leading dot is needed for the extensions.
1891
1892 Example:
1893
1894 --type-set perl:ext:pl,pm,t
1895
1896 =item match:I<PATTERN>
1897
1898 I<match> filters match the target filename against a regular expression.
1899 The regular expression is made case-insensitive for the search.
1900
1901 Example:
1902
1903 --type-set make:match:/(gnu)?makefile/
1904
1905 =item firstlinematch:I<PATTERN>
1906
1907 I<firstlinematch> matches the first line of the target file against a
1908 regular expression. Like I<match>, the regular expression is made
1909 case insensitive.
1910
1911 Example:
1912
1913 --type-add perl:firstlinematch:/perl/
1914
1915 =back
1916
1917 =head1 ACK COLORS
1918
1919 ack allows customization of the colors it uses when presenting matches
1920 onscreen. It uses the colors available in Perl's L<Term::ANSIColor>
1921 module, which provides the following listed values. Note that case does not
1922 matter when using these values.
1923
1924 There are four different colors ack uses:
1925
1926 Aspect Option Env. variable Default
1927 -------- ----------------- ------------------ ---------------
1928 filename --color-filename ACK_COLOR_FILENAME black on_yellow
1929 match --color-match ACK_COLOR_MATCH bold green
1930 line no. --color-lineno ACK COLOR_LINENO bold yellow
1931 column no. --color-colno ACK COLOR_COLNO bold yellow
1932
1933 The column number column is only used if the column number is shown because
1934 of the --column option.
1935
1936 Colors may be specified by command-line option, such as
1937 C<ack --color-filename='red on_white'>, or by setting an environment
1938 variable, such as C<ACK_COLOR_FILENAME='red on_white'>. Options for colors
1939 can be set in your ACKRC file (See "THE .ackrc FILE").
1940
1941 ack can understand the following colors for the foreground:
1942
1943 black red green yellow blue magenta cyan white
1944
1945 The optional background color is specified by prepending "on_" to one of
1946 the foreground colors:
1947
1948 on_black on_red on_green on_yellow on_blue on_magenta on_cyan on_white
1949
1950 Each of the foreground colors can be modified with the following
1951 attributes, which may or may not be supported by your terminal:
1952
1953 bold faint italic underline blink reverse concealed
1954
1955 Any combinations of modifiers can be added to the foreground color. If your
1956 terminal supports it, and you enjoy visual punishment, you can specify:
1957
1958 ack --color-filename="blink italic underline bold red on_yellow"
1959
1960 For charts of the colors and what they look like, run C<ack --help-colors>
1961 and C<ack --help-rgb-colors>.
1962
1963 If the eight standard colors, in their bold, faint and unmodified states,
1964 aren't enough for you to choose from, you can also specify colors by their
1965 RGB values. They are specified as "rgbXYZ" where X, Y, and Z are values
1966 between 0 and 5 giving the intensity of red, green and blue, respectively.
1967 Therefore, "rgb500" is pure red, "rgb505" is purple, and so on.
1968
1969 Background colors can be specified with the "on_" prefix prepended on an
1970 RGB color, so that "on_rgb505" would be a purple background.
1971
1972 The modifier attributes of blink, italic, underscore and so on may or may
1973 not work on the RGB colors.
1974
1975 For a chart of the 216 possible RGB colors, run C<ack --help-rgb-colors>.
1976
1977 =head1 ENVIRONMENT VARIABLES
1978
1979 For commonly-used ack options, environment variables can make life
1980 much easier. These variables are ignored if B<--noenv> is specified
1981 on the command line.
1982
1983 =over 4
1984
1985 =item ACKRC
1986
1987 Specifies the location of the user's F<.ackrc> file. If this file doesn't
1988 exist, F<ack> looks in the default location.
1989
1990 =item ACK_COLOR_COLNO
1991
1992 Color specification for the column number in ack's output. By default, the
1993 column number is not shown. You have to enable it with the B<--column>
1994 option. See the section "ack Colors" above.
1995
1996 =item ACK_COLOR_FILENAME
1997
1998 Color specification for the filename in ack's output. See the section "ack
1999 Colors" above.
2000
2001 =item ACK_COLOR_LINENO
2002
2003 Color specification for the line number in ack's output. See the section
2004 "ack Colors" above.
2005
2006 =item ACK_COLOR_MATCH
2007
2008 Color specification for the matched text in ack's output. See the section
2009 "ack Colors" above.
2010
2011 =item ACK_PAGER
2012
2013 Specifies a pager program, such as C<more>, C<less> or C<most>, to which
2014 ack will send its output.
2015
2016 Using C<ACK_PAGER> does not suppress grouping and coloring like
2017 piping output on the command-line does, except that on Windows
2018 ack will assume that C<ACK_PAGER> does not support color.
2019
2020 C<ACK_PAGER_COLOR> overrides C<ACK_PAGER> if both are specified.
2021
2022 =item ACK_PAGER_COLOR
2023
2024 Specifies a pager program that understands ANSI color sequences.
2025 Using C<ACK_PAGER_COLOR> does not suppress grouping and coloring
2026 like piping output on the command-line does.
2027
2028 If you are not on Windows, you never need to use C<ACK_PAGER_COLOR>.
2029
2030 =back
2031
2032 =head1 ACK & OTHER TOOLS
2033
2034 =head2 Simple vim integration
2035
2036 F<ack> integrates easily with the Vim text editor. Set this in your
2037 F<.vimrc> to use F<ack> instead of F<grep>:
2038
2039 set grepprg=ack\ -k
2040
2041 That example uses C<-k> to search through only files of the types ack
2042 knows about, but you may use other default flags. Now you can search
2043 with F<ack> and easily step through the results in Vim:
2044
2045 :grep Dumper perllib
2046
2047 =head2 Editor integration
2048
2049 Many users have integrated ack into their preferred text editors.
2050 For details and links, see L<https://beyondgrep.com/more-tools/>.
2051
2052 =head2 Shell and Return Code
2053
2054 For greater compatibility with I<grep>, I<ack> in normal use returns
2055 shell return or exit code of 0 only if something is found and 1 if
2056 no match is found.
2057
2058 (Shell exit code 1 is C<$?=256> in perl with C<system> or backticks.)
2059
2060 The I<grep> code 2 for errors is not used.
2061
2062 If C<-f> or C<-g> are specified, then 0 is returned if at least one
2063 file is found. If no files are found, then 1 is returned.
2064
2065 =cut
2066
2067 =head1 DEBUGGING ACK PROBLEMS
2068
2069 If ack gives you output you're not expecting, start with a few simple steps.
2070
2071 =head2 Try it with B<--noenv>
2072
2073 Your environment variables and F<.ackrc> may be doing things you're
2074 not expecting, or forgotten you specified. Use B<--noenv> to ignore
2075 your environment and F<.ackrc>.
2076
2077 =head2 Use B<-f> to see what files have been selected for searching
2078
2079 Ack's B<-f> was originally added as a debugging tool. If ack is
2080 not finding matches you think it should find, run F<ack -f> to see
2081 what files have been selected. You can also add the C<--show-types>
2082 options to show the type of each file selected.
2083
2084 =head2 Use B<--dump>
2085
2086 This lists the ackrc files that are loaded and the options loaded
2087 from them. You may be loading an F<.ackrc> file that you didn't know
2088 you were loading.
2089
2090 =head1 ACKRC LOCATION SEMANTICS
2091
2092 Ack can load its configuration from many sources. The following list
2093 specifies the sources Ack looks for configuration files; each one
2094 that is found is loaded in the order specified here, and
2095 each one overrides options set in any of the sources preceding
2096 it. (For example, if I set --sort-files in my user ackrc, and
2097 --nosort-files on the command line, the command line takes
2098 precedence)
2099
2100 =over 4
2101
2102 =item *
2103
2104 Defaults are loaded from App::Ack::ConfigDefaults. This can be omitted
2105 using C<--ignore-ack-defaults>.
2106
2107 =item * Global ackrc
2108
2109 Options are then loaded from the global ackrc. This is located at
2110 C</etc/ackrc> on Unix-like systems.
2111
2112 Under Windows XP and earlier, the global ackrc is at
2113 C<C:\Documents and Settings\All Users\Application Data\ackrc>
2114
2115 Under Windows Vista/7, the global ackrc is at
2116 C<C:\ProgramData\ackrc>
2117
2118 The C<--noenv> option prevents all ackrc files from being loaded.
2119
2120 =item * User ackrc
2121
2122 Options are then loaded from the user's ackrc. This is located at
2123 C<$HOME/.ackrc> on Unix-like systems.
2124
2125 Under Windows XP and earlier, the user's ackrc is at
2126 C<C:\Documents and Settings\$USER\Application Data\ackrc>.
2127
2128 Under Windows Vista/7, the user's ackrc is at
2129 C<C:\Users\$USER\AppData\Roaming\ackrc>.
2130
2131 If you want to load a different user-level ackrc, it may be specified
2132 with the C<$ACKRC> environment variable.
2133
2134 The C<--noenv> option prevents all ackrc files from being loaded.
2135
2136 =item * Project ackrc
2137
2138 Options are then loaded from the project ackrc. The project ackrc is
2139 the first ackrc file with the name C<.ackrc> or C<_ackrc>, first searching
2140 in the current directory, then the parent directory, then the grandparent
2141 directory, etc. This can be omitted using C<--noenv>.
2142
2143 =item * --ackrc
2144
2145 The C<--ackrc> option may be included on the command line to specify an
2146 ackrc file that can override all others. It is consulted even if C<--noenv>
2147 is present.
2148
2149 =item * Command line
2150
2151 Options are then loaded from the command line.
2152
2153 =back
2154
2155 =head1 BUGS & ENHANCEMENTS
2156
2157 ack is based at GitHub at L<https://github.com/beyondgrep/ack3>
2158
2159 Please report any bugs or feature requests to the issues list at
2160 Github: L<https://github.com/beyondgrep/ack3/issues>.
2161
2162 Please include the operating system that you're using; the output of
2163 the command C<ack --version>; and any customizations in your F<.ackrc>
2164 you may have.
2165
2166 To suggest enhancements, please submit an issue at
2167 L<https://github.com/beyondgrep/ack3/issues>. Also read the
2168 F<DEVELOPERS.md> file in the ack code repository.
2169
2170 Also, feel free to discuss your issues on the ack mailing
2171 list at L<https://groups.google.com/group/ack-users>.
2172
2173 =head1 SUPPORT
2174
2175 Support for and information about F<ack> can be found at:
2176
2177 =over 4
2178
2179 =item * The ack homepage
2180
2181 L<https://beyondgrep.com/>
2182
2183 =item * Source repository
2184
2185 L<https://github.com/beyondgrep/ack3>
2186
2187 =item * The ack issues list at Github
2188
2189 L<https://github.com/beyondgrep/ack3/issues>
2190
2191 =item * The ack announcements mailing list
2192
2193 L<https://groups.google.com/group/ack-announcement>
2194
2195 =item * The ack users' mailing list
2196
2197 L<https://groups.google.com/group/ack-users>
2198
2199 =item * The ack development mailing list
2200
2201 L<https://groups.google.com/group/ack-users>
2202
2203 =back
2204
2205 =head1 COMMUNITY
2206
2207 There are ack mailing lists and a Slack channel for ack. See
2208 L<https://beyondgrep.com/community/> for details.
2209
2210 =head1 FAQ
2211
2212 This is the Frequently Asked Questions list for ack.
2213
2214 =head2 Can I stop using grep now?
2215
2216 Many people find I<ack> to be better than I<grep> as an everyday tool
2217 99% of the time, but don't throw I<grep> away, because there are times
2218 you'll still need it. For example, you might be looking through huge
2219 log files and not using regular expressions. In that case, I<grep>
2220 will probably perform better.
2221
2222 =head2 Why isn't ack finding a match in (some file)?
2223
2224 First, take a look and see if ack is even looking at the file. ack is
2225 intelligent in what files it will search and which ones it won't, but
2226 sometimes that can be surprising.
2227
2228 Use the C<-f> switch, with no regex, to see a list of files that ack
2229 will search for you. If your file doesn't show up in the list of files
2230 that C<ack -f> shows, then ack never looks in it.
2231
2232 =head2 Wouldn't it be great if F<ack> did search & replace?
2233
2234 No, ack will always be read-only. Perl has a perfectly good way
2235 to do search & replace in files, using the C<-i>, C<-p> and C<-n>
2236 switches.
2237
2238 You can certainly use ack to select your files to update. For
2239 example, to change all "foo" to "bar" in all PHP files, you can do
2240 this from the Unix shell:
2241
2242 $ perl -i -p -e's/foo/bar/g' $(ack -f --php)
2243
2244 =head2 Can I make ack recognize F<.xyz> files?
2245
2246 Yes! Please see L</"Defining your own types"> in the ack manual.
2247
2248 =head2 Will you make ack recognize F<.xyz> files by default?
2249
2250 We might, depending on how widely-used the file format is.
2251
2252 Submit an issue at in the GitHub issue queue at
2253 L<https://github.com/beyondgrep/ack3/issues>. Explain what the file format
2254 is, where we can find out more about it, and what you have been using
2255 in your F<.ackrc> to support it.
2256
2257 Please do not bother creating a pull request. The code for filetypes
2258 is trivial compared to the rest of the process we go through.
2259
2260 =head2 Why is it called ack if it's called ack-grep?
2261
2262 The name of the program is "ack". Some packagers have called it
2263 "ack-grep" when creating packages because there's already a package
2264 out there called "ack" that has nothing to do with this ack.
2265
2266 I suggest you make a symlink named F<ack> that points to F<ack-grep>
2267 because one of the crucial benefits of ack is having a name that's
2268 so short and simple to type.
2269
2270 To do that, run this with F<sudo> or as root:
2271
2272 ln -s /usr/bin/ack-grep /usr/bin/ack
2273
2274 Alternatively, you could use a shell alias:
2275
2276 # bash/zsh
2277 alias ack=ack-grep
2278
2279 # csh
2280 alias ack ack-grep
2281
2282 =head2 What does F<ack> mean?
2283
2284 Nothing. I wanted a name that was easy to type and that you could
2285 pronounce as a single syllable.
2286
2287 =head2 Can I do multi-line regexes?
2288
2289 No, ack does not support regexes that match multiple lines. Doing
2290 so would require reading in the entire file at a time.
2291
2292 If you want to see lines near your match, use the C<--A>, C<--B>
2293 and C<--C> switches for displaying context.
2294
2295 =head2 Why is ack telling me I have an invalid option when searching for C<+foo>?
2296
2297 ack treats command line options beginning with C<+> or C<-> as options; if you
2298 would like to search for these, you may prefix your search term with C<--> or
2299 use the C<--match> option. (However, don't forget that C<+> is a regular
2300 expression metacharacter!)
2301
2302 =head2 Why does C<"ack '.{40000,}'"> fail? Isn't that a valid regex?
2303
2304 The Perl language limits the repetition quantifier to 32K. You
2305 can search for C<.{32767}> but not C<.{32768}>.
2306
2307 =head2 Ack does "X" and shouldn't, should it?
2308
2309 We try to remain as close to grep's behavior as possible, so when in
2310 doubt, see what grep does! If there's a mismatch in functionality there,
2311 please submit an issue to GitHub, and/or bring it up on the ack-users
2312 mailing list.
2313
2314 =cut
2315
2316 =head1 ACKNOWLEDGEMENTS
2317
2318 How appropriate to have I<ack>nowledgements!
2319
2320 Thanks to everyone who has contributed to ack in any way, including
2321 Dan Book,
2322 Tomasz Konojacki,
2323 Salomon Smeke,
2324 M. Scott Ford,
2325 Anders Eriksson,
2326 H.Merijn Brand,
2327 Duke Leto,
2328 Gerhard Poul,
2329 Ethan Mallove,
2330 Marek Kubica,
2331 Ray Donnelly,
2332 Nikolaj Schumacher,
2333 Ed Avis,
2334 Nick Morrott,
2335 Austin Chamberlin,
2336 Varadinsky,
2337 SE<eacute>bastien FeugE<egrave>re,
2338 Jakub Wilk,
2339 Pete Houston,
2340 Stephen Thirlwall,
2341 Jonah Bishop,
2342 Chris Rebert,
2343 Denis Howe,
2344 RaE<uacute>l GundE<iacute>n,
2345 James McCoy,
2346 Daniel Perrett,
2347 Steven Lee,
2348 Jonathan Perret,
2349 Fraser Tweedale,
2350 RaE<aacute>l GundE<aacute>n,
2351 Steffen Jaeckel,
2352 Stephan Hohe,
2353 Michael Beijen,
2354 Alexandr Ciornii,
2355 Christian Walde,
2356 Charles Lee,
2357 Joe McMahon,
2358 John Warwick,
2359 David Steinbrunner,
2360 Kara Martens,
2361 Volodymyr Medvid,
2362 Ron Savage,
2363 Konrad Borowski,
2364 Dale Sedivic,
2365 Michael McClimon,
2366 Andrew Black,
2367 Ralph Bodenner,
2368 Shaun Patterson,
2369 Ryan Olson,
2370 Shlomi Fish,
2371 Karen Etheridge,
2372 Olivier Mengue,
2373 Matthew Wild,
2374 Scott Kyle,
2375 Nick Hooey,
2376 Bo Borgerson,
2377 Mark Szymanski,
2378 Marq Schneider,
2379 Packy Anderson,
2380 JR Boyens,
2381 Dan Sully,
2382 Ryan Niebur,
2383 Kent Fredric,
2384 Mike Morearty,
2385 Ingmar Vanhassel,
2386 Eric Van Dewoestine,
2387 Sitaram Chamarty,
2388 Adam James,
2389 Richard Carlsson,
2390 Pedro Melo,
2391 AJ Schuster,
2392 Phil Jackson,
2393 Michael Schwern,
2394 Jan Dubois,
2395 Christopher J. Madsen,
2396 Matthew Wickline,
2397 David Dyck,
2398 Jason Porritt,
2399 Jjgod Jiang,
2400 Thomas Klausner,
2401 Uri Guttman,
2402 Peter Lewis,
2403 Kevin Riggle,
2404 Ori Avtalion,
2405 Torsten Blix,
2406 Nigel Metheringham,
2407 GE<aacute>bor SzabE<oacute>,
2408 Tod Hagan,
2409 Michael Hendricks,
2410 E<AElig>var ArnfjE<ouml>rE<eth> Bjarmason,
2411 Piers Cawley,
2412 Stephen Steneker,
2413 Elias Lutfallah,
2414 Mark Leighton Fisher,
2415 Matt Diephouse,
2416 Christian Jaeger,
2417 Bill Sully,
2418 Bill Ricker,
2419 David Golden,
2420 Nilson Santos F. Jr,
2421 Elliot Shank,
2422 Merijn Broeren,
2423 Uwe Voelker,
2424 Rick Scott,
2425 Ask BjE<oslash>rn Hansen,
2426 Jerry Gay,
2427 Will Coleda,
2428 Mike O'Regan,
2429 Slaven ReziE<0x107>,
2430 Mark Stosberg,
2431 David Alan Pisoni,
2432 Adriano Ferreira,
2433 James Keenan,
2434 Leland Johnson,
2435 Ricardo Signes,
2436 Pete Krawczyk and
2437 Rob Hoelz.
2438
2439 =head1 AUTHOR
2440
2441 Andy Lester, C<< <andy at petdance.com> >>
2442
2443 =head1 COPYRIGHT & LICENSE
2444
2445 Copyright 2005-2020 Andy Lester.
2446
2447 This program is free software; you can redistribute it and/or modify
2448 it under the terms of the Artistic License v2.0.
2449
2450 See https://www.perlfoundation.org/artistic-license-20.html or the LICENSE.md
2451 file that comes with the ack distribution.
2452
2453 =cut
2454
2455 1;
2456 package App::Ack;
2457
2458 use warnings;
2459 use strict;
2460
2461
2462 our $VERSION;
2463 our $COPYRIGHT;
2464 BEGIN {
2465 $VERSION = 'v3.3.1'; # Check https://beyondgrep.com/ for updates
2466 $COPYRIGHT = 'Copyright 2005-2020 Andy Lester.';
2467 }
2468 our $STANDALONE = 0;
2469 our $ORIGINAL_PROGRAM_NAME;
2470
2471 our $fh;
2472
2473 BEGIN {
2474 $fh = *STDOUT;
2475 }
2476
2477
2478 our %types;
2479 our %type_wanted;
2480 our %mappings;
2481 our %ignore_dirs;
2482
2483 our $is_filter_mode;
2484 our $output_to_pipe;
2485
2486 our $is_windows;
2487
2488 our $debug_nopens = 0;
2489
2490 # Line ending, changes to "\0" if --print0.
2491 our $ors = "\n";
2492
2493 BEGIN {
2494 # These have to be checked before any filehandle diddling.
2495 $output_to_pipe = not -t *STDOUT;
2496 $is_filter_mode = -p STDIN;
2497
2498 $is_windows = ($^O eq 'MSWin32');
2499 }
2500
2501
2502 sub warn {
2503 return CORE::warn( _my_program(), ': ', @_, "\n" );
2504 }
2505
2506
2507 sub die {
2508 return CORE::die( _my_program(), ': ', @_, "\n" );
2509 }
2510
2511 sub _my_program {
2512 require File::Basename;
2513 return File::Basename::basename( $0 );
2514 }
2515
2516
2517 sub thpppt {
2518 my $y = q{_ /|,\\'!.x',=(www)=, U };
2519 $y =~ tr/,x!w/\nOo_/;
2520
2521 App::Ack::print( "$y ack $_[0]!\n" );
2522 exit 0;
2523 }
2524
2525 sub ackbar {
2526 my $x;
2527 $x = <<'_BAR';
2528 6?!I'7!I"?%+!
2529 3~!I#7#I"7#I!?!+!="+"="+!:!
2530 2?#I!7!I!?#I!7!I"+"=%+"=#
2531 1?"+!?*+!=#~"=!+#?"="+!
2532 0?"+!?"I"?&+!="~!=!~"=!+%="+"
2533 /I!+!?)+!?!+!=$~!=!~!="+!="+"?!="?!
2534 .?%I"?%+%='?!=#~$="
2535 ,,!?%I"?(+$=$~!=#:"~$:!~!
2536 ,I!?!I!?"I"?!+#?"+!?!+#="~$:!~!:!~!:!,!:!,":#~!
2537 +I!?&+!="+!?#+$=!~":!~!:!~!:!,!:#,!:!,%:"
2538 *+!I!?!+$=!+!=!+!?$+#=!~":!~":#,$:",#:!,!:!
2539 *I!?"+!?!+!=$+!?#+#=#~":$,!:",!:!,&:"
2540 )I!?$=!~!=#+"?!+!=!+!=!~!="~!:!~":!,'.!,%:!~!
2541 (=!?"+!?!=!~$?"+!?!+!=#~"=",!="~$,$.",#.!:!=!
2542 (I"+"="~"=!+&=!~"=!~!,!~!+!=!?!+!?!=!I!?!+"=!.",!.!,":!
2543 %I$?!+!?!=%+!~!+#~!=!~#:#=!~!+!~!=#:!,%.!,!.!:"
2544 $I!?!=!?!I!+!?"+!=!~!=!~!?!I!?!=!+!=!~#:",!~"=!~!:"~!=!:",&:" '-/
2545 $?!+!I!?"+"=!+"~!,!:"+#~#:#,"=!~"=!,!~!,!.",!:".!:! */! !I!t!'!s! !a! !g!r!e!p!!! !/!
2546 $+"=!+!?!+"~!=!:!~!:"I!+!,!~!=!:!~!,!:!,$:!~".&:"~!,# (-/
2547 %~!=!~!=!:!.!+"~!:!,!.!,!~!=!:$.!,":!,!.!:!~!,!:!=!.#="~!,!:" ./!
2548 %=!~!?!+"?"+!=!~",!.!:!?!~!.!:!,!:!,#.!,!:","~!:!=!~!=!:",!~! ./!
2549 %+"~":!~!=#~!:!~!,!.!~!:",!~!=!~!.!:!,!.",!:!,":!=":!.!,!:!7! -/!
2550 %~",!:".#:!=!:!,!:"+!:!~!:!.!,!~!,!.#,!.!,$:"~!,":"~!=! */!
2551 &=!~!=#+!=!~",!.!:",#:#,!.",+:!,!.",!=!+!?!
2552 &~!=!~!=!~!:"~#:",!.!,#~!:!.!+!,!.",$.",$.#,!+!I!?!
2553 &~!="~!:!~":!~",!~!=!~":!,!:!~!,!:!,&.$,#."+!?!I!?!I!
2554 &~!=!~!=!+!,!:!~!:!=!,!:!~&:$,!.!,".!,".!,#."~!+!?$I!
2555 &~!=!~!="~!=!:!~":!,!~%:#,!:",!.!,#.",#I!7"I!?!+!?"I"
2556 &+!I!7!:#~"=!~!:!,!:"~$.!=!.!,!~!,$.#,!~!7!I#?!+!?"I"7!
2557 %7#?!+!~!:!=!~!=!~":!,!:"~":#.!,)7#I"?"I!7&
2558 %7#I!=":!=!~!:"~$:"~!:#,!:!,!:!~!:#,!7#I!?#7)
2559 $7$+!,!~!=#~!:!~!:!~$:#,!.!~!:!=!,":!7#I"?#7+=!?!
2560 $7#I!~!,!~#=!~!:"~!:!,!:!,#:!=!~",":!7$I!?#I!7*+!=!+"
2561 "I!7$I!,":!,!.!=":$,!:!,$:$7$I!+!?"I!7+?"I!7!I!7!,!
2562 !,!7%I!:",!."~":!,&.!,!:!~!I!7$I!+!?"I!7,?!I!7',!
2563 !7(,!.#~":!,%.!,!7%I!7!?#I"7,+!?!7*
2564 7+:!,!~#,"=!7'I!?#I"7/+!7+
2565 77I!+!7!?!7!I"71+!7,
2566 _BAR
2567
2568 return _pic_decode($x);
2569 }
2570
2571 sub cathy {
2572 my $x = <<'CATHY';
2573 0+!--+!
2574 0|! "C!H!O!C!O!L!A!T!E!!! !|!
2575 0|! "C!H!O!C!O!L!A!T!E!!! !|!
2576 0|! "C!H!O!C!O!L!A!T!E!!! !|!
2577 0|! $A"C!K!!! $|!
2578 0+!--+!
2579 6\! 1:!,!.! !
2580 7\! /.!M!~!Z!M!~!
2581 8\! /~!D! "M! !
2582 4.! $\! /M!~!.!8! +.!M# 4
2583 0,!.! (\! .~!M!N! ,+!I!.!M!.! 3
2584 /?!O!.!M!:! '\! .O!.! +~!Z!=!N!.! 4
2585 ..! !D!Z!.!Z!.! '\! 9=!M".! 6
2586 /.! !.!~!M".! '\! 8~! 9
2587 4M!.! /.!7!N!M!.! F
2588 4.! &:!M! !N"M# !M"N!M! #D!M&=! =
2589 :M!7!M#:! !~!M!7!,!$!M!:! #.! !O!N!.!M!:!M# ;
2590 8Z!M"~!N!$!D!.!N!?! !I!N!.! (?!M! !M!,!D!M".! 9
2591 (?!Z!M!N!:! )=!M!O!8!.!M!+!M! !M!,! !O!M! +,!M!.!M!~!Z!N!M!:! &:!~! 0
2592 &8!7!.!~!M"D!M!,! &M!?!=!8! !M!,!O! !M!+! !+!O!.!M! $M#~! !.!8!M!Z!.!M! !O!M"Z! %:!~!M!Z!M!Z!.! +
2593 &:!M!7!,! *M!.!Z!M! !8"M!.!M!~! !.!M!.!=! #~!8!.!M! !7!M! "N!Z#I! !D!M!,!M!.! $."M!,! !M!.! *
2594 2$!O! "N! !.!M!I! !7" "M! "+!O! !~!M! !d!O!.!7!I!M!.! !.!O!=!M!.! !M",!M!.! %.!$!O!D! +
2595 1~!O! "M!+! !8!$! "M! "?!O! %Z!8!D!M!?!8!I!O!7!M! #M!.!M! "M",!M! 4
2596 07!~! ".!8! !.!M! "I!+! !.!M! &Z!D!.!7!=!M! !:!.!M! #:!8"+! !.!+!8! !8! 3
2597 /~!M! #N! !~!M!$! !.!M! !.!M" &~!M! "~!M!O! "D! $M! !8! "M!,!M!+!D!.! 1
2598 #.! #?!M!N!.! #~!O! $M!.!7!$! "?" !?!~!M! '7!8!?!M!.!+!M"O! $?"$!D! !.!O! !$!7!I!.! 0
2599 $,!M!:!O!?! ".! !?!=! $=!:!O! !M! "M! !M! !+!$! (.! +.!M! !M!.! !8! !+"Z!~! $:!M!$! !.! '
2600 #.!8!.!I!$! $7!I! %M" !=!M! !~!M!D! "7!I! .I!O! %?!=!,!D! !,!M! !D!~!8!~! %D!M! (
2601 #.!M"?! $=!O! %=!N! "8!.! !Z!M! #M!~! (M!:! #.!M" &O! !M!.! !?!,! !8!.!N!~! $8!N!M!,!.! %
2602 *$!O! &M!,! "O! !.!M!.! #M! (~!M( &O!.! !7! "M! !.!M!.!M!,! #.!M! !M! &
2603 )=!8!.! $.!M!O!.! "$!.!I!N! !I!M# (7!M(I! %D"Z!M! "=!I! "M! !M!:! #~!D! '
2604 )D! &8!N!:! ".!O! !M!="M! "M! (7!M) %." !M!D!."M!.! !$!=! !M!,! +
2605 (M! &+!.!M! #Z!7!O!M!.!~!8! +,!M#D!?!M#D! #.!Z!M#,!Z!?! !~!N! "N!.! !M! +
2606 'D!:! %$!D! !?! #M!Z! !8!.! !M"?!7!?!7! '+!I!D! !?!O!:!M!:! ":!M!:! !M!7".!M! "8!+! !:!D! !.!M! *
2607 %.!O!:! $.!O!+! !D!.! #M! "M!.!+!N!I!Z! "7!M!N!M!N!?!I!7!Z!=!M'D"~! #M!.!8!$! !:! !.!M! "N!?! !,!O! )
2608 !.!?!M!:!M!I! %8!,! "M!.! #M! "N! !M!.! !M!.! !+!~! !.!M!.! ':!M! $M! $M!Z!$! !M!.! "D! "M! "?!M! (
2609 !7!8! !+!I! ".! "$!=! ":!$! "+! !M!.! !O! !M!I!M".! !=!~! ",!O! '=!M! $$!,! #N!:! ":!8!.! !D!~! !,!M!.! !:!M!.! &
2610 !:!,!.! &Z" #D! !.!8!."M!.! !8!?!Z!M!.!M! #Z!~! !?!M!Z!.! %~!O!.!8!$!N!8!O!I!:!~! !+! #M!.! !.!M!.! !+!M! ".!~!M!+! $
2611 !.! 'D!I! #?!M!.!M!,! !.!Z! !.!8! #M&O!I!?! (~!I!M"." !M!Z!.! !M!N!.! "+!$!.! "M!.! !M!?!.! "8!M! $
2612 (O!8! $M! !M!.! ".!:! !+!=! #M! #.!M! !+" *$!M":!.! !M!~! "M!7! #M! #7!Z! "M"$!M!.! !.! #
2613 '$!Z! #.!7!+!M! $.!,! !+!:! #N! #.!M!.!+!M! +D!M! #=!N! ":!O! #=!M! #Z!D! $M!I! %
2614 $,! ".! $.!M" %$!.! !?!~! "+!7!." !.!M!,! !M! *,!N!M!.$M!?! "D!,! #M!.! #N! +
2615 ,M!Z! &M! "I!,! "M! %I!M! !?!=!.! (Z!8!M! $:!M!.! !,!M! $D! #.!M!.! )
2616 +8!O! &.!8! "I!,! !~!M! &N!M! !M!D! '?!N!O!." $?!7! "?!~! #M!.! #I!D!.! (
2617 3M!,! "N!.! !D" &.!+!M!.! !M":!.":!M!7!M!D! 'M!.! "M!.! "M!,! $I! )
2618 3I! #M! "M!,! !:! &.!M" ".!,! !.!$!M!I! #.! !:! !.!M!?! "N!+! ".! /
2619 1M!,! #.!M!8!M!=!.! +~!N"O!Z"~! *+!M!.! "M! 2
2620 0.!M! &M!.! 8:! %.!M!Z! "M!=! *O!,! %
2621 0?!$! &N! )." .,! %."M! ":!M!.! 0
2622 0N!:! %?!O! #.! ..! &,! &.!D!,! "N!I! 0
2623 CATHY
2624 return _pic_decode($x);
2625 }
2626
2627 sub _pic_decode {
2628 my($compressed) = @_;
2629 $compressed =~ s/(.)(.)/$1x(ord($2)-32)/eg;
2630 App::Ack::print( $compressed );
2631 exit 0;
2632 }
2633
2634
2635 sub show_help {
2636 App::Ack::print( <<"END_OF_HELP" );
2637 Usage: ack [OPTION]... PATTERN [FILES OR DIRECTORIES]
2638
2639 Search for PATTERN in each source file in the tree from the current
2640 directory on down. If any files or directories are specified, then
2641 only those files and directories are checked. ack may also search
2642 STDIN, but only if no file or directory arguments are specified,
2643 or if one of them is "-".
2644
2645 Default switches may be specified in an .ackrc file. If you want no dependency
2646 on the environment, turn it off with --noenv.
2647
2648 File select actions:
2649 -f Only print the files selected, without
2650 searching. The PATTERN must not be specified.
2651 -g Same as -f, but only select files matching
2652 PATTERN.
2653
2654 File listing actions:
2655 -l, --files-with-matches Print filenames with at least one match
2656 -L, --files-without-matches Print filenames with no matches
2657 -c, --count Print filenames and count of matching lines
2658
2659 Searching:
2660 -i, --ignore-case Ignore case distinctions in PATTERN
2661 -S, --[no]smart-case Ignore case distinctions in PATTERN,
2662 only if PATTERN contains no upper case.
2663 Ignored if -i or -I are specified.
2664 -I, --no-ignore-case Turns on case-sensitivity in PATTERN.
2665 Negates -i and --smart-case.
2666 -v, --invert-match Invert match: select non-matching lines
2667 -w, --word-regexp Force PATTERN to match only whole words
2668 -Q, --literal Quote all metacharacters; PATTERN is literal
2669 --range-start PATTERN Specify PATTERN as the start of a match range.
2670 --range-end PATTERN Specify PATTERN as the end of a match range.
2671 --match PATTERN Specify PATTERN explicitly. Typically omitted.
2672
2673 Search output:
2674 --output=expr Output the evaluation of expr for each line
2675 (turns off text highlighting)
2676 -o Show only the part of a line matching PATTERN
2677 Same as --output='\$&'
2678 --passthru Print all lines, whether matching or not
2679 -m, --max-count=NUM Stop searching in each file after NUM matches
2680 -1 Stop searching after one match of any kind
2681 -H, --with-filename Print the filename for each match (default:
2682 on unless explicitly searching a single file)
2683 -h, --no-filename Suppress the prefixing filename on output
2684 --[no]column Show the column number of the first match
2685
2686 -A NUM, --after-context=NUM Print NUM lines of trailing context after
2687 matching lines.
2688 -B NUM, --before-context=NUM Print NUM lines of leading context before
2689 matching lines.
2690 -C [NUM], --context[=NUM] Print NUM lines (default 2) of output context.
2691
2692 --print0 Print null byte as separator between filenames,
2693 only works with -f, -g, -l, -L or -c.
2694
2695 -s Suppress error messages about nonexistent or
2696 unreadable files.
2697
2698
2699 File presentation:
2700 --pager=COMMAND Pipes all ack output through COMMAND. For
2701 example, --pager="less -R". Ignored if output
2702 is redirected.
2703 --nopager Do not send output through a pager. Cancels
2704 any setting in ~/.ackrc, ACK_PAGER or
2705 ACK_PAGER_COLOR.
2706 --[no]heading Print a filename heading above each file's
2707 results. (default: on when used interactively)
2708 --[no]break Print a break between results from different
2709 files. (default: on when used interactively)
2710 --group Same as --heading --break
2711 --nogroup Same as --noheading --nobreak
2712 -p, --proximate=LINES Separate match output with blank lines unless
2713 they are within LINES lines from each other.
2714 -P, --proximate=0 Negates --proximate.
2715 --[no]underline Print a line of carets under the matched text.
2716 --[no]color, --[no]colour Highlight the matching text (default: on unless
2717 output is redirected, or on Windows)
2718 --color-filename=COLOR
2719 --color-match=COLOR
2720 --color-colno=COLOR
2721 --color-lineno=COLOR Set the color for filenames, matches, line and
2722 column numbers.
2723 --help-colors Show a list of possible color combinations.
2724 --help-rgb-colors Show a list of advanced RGB colors.
2725 --flush Flush output immediately, even when ack is used
2726 non-interactively (when output goes to a pipe or
2727 file).
2728
2729
2730 File finding:
2731 --sort-files Sort the found files lexically.
2732 --show-types Show which types each file has.
2733 --files-from=FILE Read the list of files to search from FILE.
2734 -x Read the list of files to search from STDIN.
2735
2736 File inclusion/exclusion:
2737 --[no]ignore-dir=name Add/remove directory from list of ignored dirs
2738 --[no]ignore-directory=name Synonym for ignore-dir
2739 --ignore-file=FILTER:ARGS Add filter for ignoring files.
2740 -r, -R, --recurse Recurse into subdirectories (default: on)
2741 -n, --no-recurse No descending into subdirectories
2742 --[no]follow Follow symlinks. Default is off.
2743
2744 File type inclusion/exclusion:
2745 -t X, --type=X Include only X files, where X is a filetype,
2746 e.g. python, html, markdown, etc
2747 -T X, --type=noX Exclude X files, where X is a filetype.
2748 -k, --known-types Include only files of types that ack recognizes.
2749 --help-types Display all known types, and how they're defined.
2750
2751 File type specification:
2752 --type-set=TYPE:FILTER:ARGS Files with the given ARGS applied to the given
2753 FILTER are recognized as being of type TYPE.
2754 This replaces an existing definition for TYPE.
2755 --type-add=TYPE:FILTER:ARGS Files with the given ARGS applied to the given
2756 FILTER are recognized as being type TYPE.
2757 --type-del=TYPE Removes all filters associated with TYPE.
2758
2759 Miscellaneous:
2760 --version Display version & copyright
2761 --[no]env Ignore environment variables and global ackrc
2762 files. --env is legal but redundant.
2763 --ackrc=filename Specify an ackrc file to use
2764 --ignore-ack-defaults Ignore default definitions included with ack.
2765 --create-ackrc Outputs a default ackrc for your customization
2766 to standard output.
2767 --dump Dump information on which options are loaded
2768 and where they're defined.
2769 --[no]filter Force ack to treat standard input as a pipe
2770 (--filter) or tty (--nofilter)
2771 --help This help
2772 --man Print the manual.
2773 --help-types Display all known types, and how they're defined.
2774 --help-colors Show a list of possible color combinations.
2775 --help-rgb-colors Show a list of advanced RGB colors.
2776 --thpppt Bill the Cat
2777 --bar The warning admiral
2778 --cathy Chocolate! Chocolate! Chocolate!
2779
2780 Filter specifications:
2781 If FILTER is "ext", ARGS is a list of extensions checked against the
2782 file's extension.
2783 If FILTER is "is", ARGS must match the file's name exactly.
2784 If FILTER is "match", ARGS is matched as a case-insensitive regex
2785 against the filename.
2786 If FILTER is "firstlinematch", ARGS is matched as a regex the first
2787 line of the file's contents.
2788
2789 Exit status is 0 if match, 1 if no match.
2790
2791 ack's home page is at https://beyondgrep.com/
2792
2793 The full ack manual is available by running "ack --man".
2794
2795 This is version $App::Ack::VERSION of ack. Run "ack --version" for full version info.
2796 END_OF_HELP
2797
2798 return;
2799 }
2800
2801
2802
2803 sub show_help_types {
2804 App::Ack::print( <<'END_OF_HELP' );
2805 Usage: ack [OPTION]... PATTERN [FILES OR DIRECTORIES]
2806
2807 The following is the list of filetypes supported by ack. You can specify a
2808 filetype to include with -t TYPE or --type=TYPE. You can exclude a
2809 filetype with -T TYPE or --type=noTYPE.
2810
2811 Note that some files may appear in multiple types. For example, a file
2812 called Rakefile is both Ruby (--type=ruby) and Rakefile (--type=rakefile).
2813
2814 END_OF_HELP
2815
2816 my @types = keys %App::Ack::mappings;
2817 my $maxlen = 0;
2818 for ( @types ) {
2819 $maxlen = length if $maxlen < length;
2820 }
2821 for my $type ( sort @types ) {
2822 next if $type =~ /^-/; # Stuff to not show
2823 my $ext_list = $mappings{$type};
2824
2825 if ( ref $ext_list ) {
2826 $ext_list = join( '; ', map { $_->to_string } @{$ext_list} );
2827 }
2828 App::Ack::print( sprintf( " %-*.*s %s\n", $maxlen, $maxlen, $type, $ext_list ) );
2829 }
2830
2831 return;
2832 }
2833
2834
2835
2836 sub show_help_colors {
2837 App::Ack::print( <<'END_OF_HELP' );
2838 ack allows customization of the colors it uses when presenting matches
2839 onscreen. See the "ACK COLORS" section of the ack manual (ack --man).
2840
2841 Here is a chart of how various color combinations appear: Each of the eight
2842 foreground colors, on each of the eight background colors or no background
2843 color, with and without the bold modifier.
2844
2845 Run ack --help-rgb-colors for a chart of the RGB colors.
2846
2847 END_OF_HELP
2848
2849 _show_color_grid();
2850
2851 return;
2852 }
2853
2854
2855
2856 sub show_help_rgb {
2857 App::Ack::print( <<'END_OF_HELP' );
2858 ack allows customization of the colors it uses when presenting matches
2859 onscreen. See the "ACK COLORS" section of the ack manual (ack --man).
2860
2861 Colors may be specified as "rggNNN" where "NNN" is a triplet of digits
2862 from 0 to 5 specifying the intensity of red, green and blue, respectively.
2863
2864 Here is a grid of the 216 possible values for NNN.
2865
2866 END_OF_HELP
2867
2868 _show_rgb_grid();
2869
2870 App::Ack::say( 'Here are the 216 possible colors with the "reverse" modifier applied.', "\n" );
2871
2872 _show_rgb_grid( 'reverse' );
2873
2874 return;
2875 }
2876
2877
2878 sub _show_color_grid {
2879 my $cell_width = 7;
2880
2881 my @fg_colors = qw( black red green yellow blue magenta cyan white );
2882 my @bg_colors = map { "on_$_" } @fg_colors;
2883
2884 App::Ack::say(
2885 _color_cell( '' ),
2886 map { _color_cell( $_ ) } @fg_colors
2887 );
2888
2889 App::Ack::say(
2890 _color_cell( '' ),
2891 map { _color_cell( '-' x $cell_width ) } @fg_colors
2892 );
2893
2894 for my $bg ( '', @bg_colors ) {
2895 App::Ack::say(
2896 _color_cell( '' ),
2897 ( map { _color_cell( $_, "$_ $bg" ) } @fg_colors ),
2898 $bg
2899 );
2900
2901 App::Ack::say(
2902 _color_cell( 'bold' ),
2903 ( map { _color_cell( $_, "bold $_ $bg" ) } @fg_colors ),
2904 $bg
2905 );
2906 App::Ack::say();
2907 }
2908
2909 return;
2910 }
2911
2912
2913 sub _color_cell {
2914 my $text = shift;
2915 my $color = shift;
2916
2917 my $cell_width = 7;
2918 $text = sprintf( '%-*s', $cell_width, $text );
2919
2920 return ($color ? Term::ANSIColor::colored( $text, $color ) : $text) . ' ';
2921 }
2922
2923
2924 sub _show_rgb_grid {
2925 my $modifier = shift // '';
2926
2927 my $grid = <<'HERE';
2928 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
2929 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
2930 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
2931 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
2932 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
2933 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
2934 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
2935 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
2936
2937 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
2938
2939 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
2940
2941 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
2942
2943 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
2944
2945 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
2946 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
2947
2948 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
2949
2950 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
2951 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
2952 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
2953 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
2954 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
2955 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
2956 HERE
2957
2958 $grid =~ s/(\d\d\d)/Term::ANSIColor::colored( "$1", "$modifier rgb$1" )/eg;
2959
2960 App::Ack::say( $grid );
2961
2962 return;
2963 }
2964
2965
2966 sub show_man {
2967 require Pod::Usage;
2968 Pod::Usage::pod2usage({
2969 -input => $App::Ack::ORIGINAL_PROGRAM_NAME,
2970 -verbose => 2,
2971 -exitval => 0,
2972 });
2973
2974 return;
2975 }
2976
2977
2978
2979 sub get_version_statement {
2980 require Config;
2981
2982 my $copyright = $App::Ack::COPYRIGHT;
2983 my $this_perl = $Config::Config{perlpath};
2984 if ($^O ne 'VMS') {
2985 my $ext = $Config::Config{_exe};
2986 $this_perl .= $ext unless $this_perl =~ m/$ext$/i;
2987 }
2988 my $perl_ver = sprintf( 'v%vd', $^V );
2989
2990 my $build_type = $App::Ack::STANDALONE ? 'standalone version' : 'standard build';
2991
2992 return <<"END_OF_VERSION";
2993 ack $App::Ack::VERSION ($build_type)
2994 Running under Perl $perl_ver at $this_perl
2995
2996 $copyright
2997
2998 This program is free software. You may modify or distribute it
2999 under the terms of the Artistic License v2.0.
3000 END_OF_VERSION
3001 }
3002
3003
3004 sub print { print {$fh} @_; return; }
3005 sub say { print {$fh} @_, $ors; return; }
3006 sub print_blank_line { print {$fh} "\n"; return; }
3007
3008 sub set_up_pager {
3009 my $command = shift;
3010
3011 return if App::Ack::output_to_pipe();
3012
3013 my $pager;
3014 if ( not open( $pager, '|-', $command ) ) {
3015 App::Ack::die( qq{Unable to pipe to pager "$command": $!} );
3016 }
3017 $fh = $pager;
3018
3019 return;
3020 }
3021
3022
3023 sub output_to_pipe {
3024 return $output_to_pipe;
3025 }
3026
3027
3028 sub exit_from_ack {
3029 my $nmatches = shift;
3030
3031 my $rc = $nmatches ? 0 : 1;
3032 exit $rc;
3033 }
3034
3035
3036 sub show_types {
3037 my $file = shift;
3038
3039 my @types = filetypes( $file );
3040 my $arrow = @types ? ' => ' : ' =>';
3041 App::Ack::say( $file->name, $arrow, join( ',', @types ) );
3042
3043 return;
3044 }
3045
3046
3047 sub filetypes {
3048 my ( $file ) = @_;
3049
3050 my @matches;
3051
3052 foreach my $k (keys %App::Ack::mappings) {
3053 my $filters = $App::Ack::mappings{$k};
3054
3055 foreach my $filter (@{$filters}) {
3056 # Clone the file.
3057 my $clone = $file->clone;
3058 if ( $filter->filter($clone) ) {
3059 push @matches, $k;
3060 last;
3061 }
3062 }
3063 }
3064
3065 # https://metacpan.org/pod/distribution/Perl-Critic/lib/Perl/Critic/Policy/Subroutines/ProhibitReturnSort.pm
3066 @matches = sort @matches;
3067 return @matches;
3068 }
3069
3070
3071 sub is_lowercase {
3072 my $pat = shift;
3073
3074 # The simplest case.
3075 return 1 if lc($pat) eq $pat;
3076
3077 # If we have capitals, then go clean up any metacharacters that might have capitals.
3078
3079 # Get rid of any literal backslashes first to avoid confusion.
3080 $pat =~ s/\\\\//g;
3081
3082 my $metacharacter = qr/
3083 |\\A # Beginning of string
3084 |\\B # Not word boundary
3085 |\\c[a-zA-Z] # Control characters
3086 |\\D # Non-digit character
3087 |\\G # End-of-match position of prior match
3088 |\\H # Not horizontal whitespace
3089 |\\K # Keep to the left
3090 |\\N(\{.+?\})? # Anything but \n, OR Unicode sequence
3091 |\\[pP]\{.+?\} # Named property and negation
3092 |\\[pP][A-Z] # Named property and negation, single-character shorthand
3093 |\\R # Linebreak
3094 |\\S # Non-space character
3095 |\\V # Not vertical whitespace
3096 |\\W # Non-word character
3097 |\\X # ???
3098 |\\x[0-9A-Fa-f]{2} # Hex sequence
3099 |\\Z # End of string
3100 /x;
3101 $pat =~ s/$metacharacter//g;
3102
3103 my $name = qr/[_A-Za-z][_A-Za-z0-9]*?/;
3104 # Eliminate named captures.
3105 $pat =~ s/\(\?'$name'//g;
3106 $pat =~ s/\(\?<$name>//g;
3107
3108 # Eliminate named backreferences.
3109 $pat =~ s/\\k'$name'//g;
3110 $pat =~ s/\\k<$name>//g;
3111 $pat =~ s/\\k\{$name\}//g;
3112
3113 # Now with those metacharacters and named things removed, now see if it's lowercase.
3114 return 1 if lc($pat) eq $pat;
3115
3116 return 0;
3117 }
3118
3119
3120 1; # End of App::Ack
3121 package App::Ack::ConfigDefault;
3122
3123 use warnings;
3124 use strict;
3125
3126
3127
3128
3129 sub options {
3130 return split( /\n/, _options_block() );
3131 }
3132
3133
3134 sub options_clean {
3135 return grep { /./ && !/^#/ } options();
3136 }
3137
3138
3139 sub _options_block {
3140 my $lines = <<'HERE';
3141 # This is the default ackrc for ack version ==VERSION==.
3142
3143 # There are four different ways to match
3144 #
3145 # is: Match the filename exactly
3146 #
3147 # ext: Match the extension of the filename exactly
3148 #
3149 # match: Match the filename against a Perl regular expression
3150 #
3151 # firstlinematch: Match the first 250 characters of the first line
3152 # of text against a Perl regular expression. This is only for
3153 # the --type-add option.
3154
3155
3156 ### Directories to ignore
3157
3158 # Bazaar
3159 # https://bazaar.canonical.com/
3160 --ignore-directory=is:.bzr
3161
3162 # Codeville
3163 # http://freshmeat.sourceforge.net/projects/codeville
3164 --ignore-directory=is:.cdv
3165
3166 # Interface Builder (Xcode)
3167 # https://en.wikipedia.org/wiki/Interface_Builder
3168 --ignore-directory=is:~.dep
3169 --ignore-directory=is:~.dot
3170 --ignore-directory=is:~.nib
3171 --ignore-directory=is:~.plst
3172
3173 # Git
3174 # https://git-scm.com/
3175 --ignore-directory=is:.git
3176 # When submodules are used, .git is a file.
3177 --ignore-file=is:.git
3178
3179 # Mercurial
3180 # https://www.mercurial-scm.org/
3181 --ignore-directory=is:.hg
3182
3183 # Quilt
3184 # https://directory.fsf.org/wiki/Quilt
3185 --ignore-directory=is:.pc
3186
3187 # Subversion
3188 # https://subversion.apache.org/
3189 --ignore-directory=is:.svn
3190
3191 # Monotone
3192 # https://www.monotone.ca/
3193 --ignore-directory=is:_MTN
3194
3195 # CVS
3196 # https://savannah.nongnu.org/projects/cvs
3197 --ignore-directory=is:CVS
3198
3199 # RCS
3200 # https://www.gnu.org/software/rcs/
3201 --ignore-directory=is:RCS
3202
3203 # SCCS
3204 # https://en.wikipedia.org/wiki/Source_Code_Control_System
3205 --ignore-directory=is:SCCS
3206
3207 # darcs
3208 # http://darcs.net/
3209 --ignore-directory=is:_darcs
3210
3211 # Vault/Fortress
3212 --ignore-directory=is:_sgbak
3213
3214 # autoconf
3215 # https://www.gnu.org/software/autoconf/
3216 --ignore-directory=is:autom4te.cache
3217
3218 # Perl module building
3219 --ignore-directory=is:blib
3220 --ignore-directory=is:_build
3221
3222 # Perl Devel::Cover module's output directory
3223 # https://metacpan.org/release/Devel-Cover
3224 --ignore-directory=is:cover_db
3225
3226 # Node modules created by npm
3227 --ignore-directory=is:node_modules
3228
3229 # CMake cache
3230 # https://www.cmake.org/
3231 --ignore-directory=is:CMakeFiles
3232
3233 # Eclipse workspace folder
3234 # https://eclipse.org/
3235 --ignore-directory=is:.metadata
3236
3237 # Cabal (Haskell) sandboxes
3238 # https://www.haskell.org/cabal/users-guide/installing-packages.html
3239 --ignore-directory=is:.cabal-sandbox
3240
3241 # Python caches
3242 # https://docs.python.org/3/tutorial/modules.html
3243 --ignore-directory=is:__pycache__
3244 --ignore-directory=is:.pytest_cache
3245
3246 # macOS Finder remnants
3247 --ignore-directory=is:__MACOSX
3248 --ignore-file=is:.DS_Store
3249
3250 ### Files to ignore
3251
3252 # Backup files
3253 --ignore-file=ext:bak
3254 --ignore-file=match:/~$/
3255
3256 # Emacs swap files
3257 --ignore-file=match:/^#.+#$/
3258
3259 # vi/vim swap files https://www.vim.org/
3260 --ignore-file=match:/[._].*[.]swp$/
3261
3262 # core dumps
3263 --ignore-file=match:/core[.]\d+$/
3264
3265 # minified Javascript
3266 --ignore-file=match:/[.-]min[.]js$/
3267 --ignore-file=match:/[.]js[.]min$/
3268
3269 # minified CSS
3270 --ignore-file=match:/[.]min[.]css$/
3271 --ignore-file=match:/[.]css[.]min$/
3272
3273 # JS and CSS source maps
3274 --ignore-file=match:/[.]js[.]map$/
3275 --ignore-file=match:/[.]css[.]map$/
3276
3277 # PDFs, because they pass Perl's -T detection
3278 --ignore-file=ext:pdf
3279
3280 # Common graphics, just as an optimization
3281 --ignore-file=ext:gif,jpg,jpeg,png
3282
3283 # Common archives, as an optimization
3284 --ignore-file=ext:gz,tar,tgz,zip
3285
3286 # Python compiles modules
3287 --ignore-file=ext:pyc,pyd,pyo
3288
3289 # C extensions
3290 --ignore-file=ext:so
3291
3292 # Compiled gettext files
3293 --ignore-file=ext:mo
3294
3295 ### Filetypes defined
3296
3297 # Makefiles
3298 # https://www.gnu.org/s/make/
3299 --type-add=make:ext:mk
3300 --type-add=make:ext:mak
3301 --type-add=make:is:makefile
3302 --type-add=make:is:Makefile
3303 --type-add=make:is:Makefile.Debug
3304 --type-add=make:is:Makefile.Release
3305 --type-add=make:is:GNUmakefile
3306
3307 # Rakefiles
3308 # https://rake.rubyforge.org/
3309 --type-add=rake:is:Rakefile
3310
3311 # CMake
3312 # https://cmake.org/
3313 --type-add=cmake:is:CMakeLists.txt
3314 --type-add=cmake:ext:cmake
3315
3316 # Actionscript
3317 --type-add=actionscript:ext:as,mxml
3318
3319 # Ada
3320 # https://www.adaic.org/
3321 --type-add=ada:ext:ada,adb,ads
3322
3323 # ASP
3324 # https://docs.microsoft.com/en-us/previous-versions/office/developer/server-technologies/aa286483(v=msdn.10)
3325 --type-add=asp:ext:asp
3326
3327 # ASP.Net
3328 # https://dotnet.microsoft.com/apps/aspnet
3329 --type-add=aspx:ext:master,ascx,asmx,aspx,svc
3330
3331 # Assembly
3332 --type-add=asm:ext:asm,s
3333
3334 # DOS/Windows batch
3335 --type-add=batch:ext:bat,cmd
3336
3337 # ColdFusion
3338 # https://en.wikipedia.org/wiki/ColdFusion
3339 --type-add=cfmx:ext:cfc,cfm,cfml
3340
3341 # Clojure
3342 # https://clojure.org/
3343 --type-add=clojure:ext:clj,cljs,edn,cljc
3344
3345 # C
3346 # .xs are Perl C files
3347 --type-add=cc:ext:c,h,xs
3348
3349 # C header files
3350 --type-add=hh:ext:h
3351
3352 # CoffeeScript
3353 # https://coffeescript.org/
3354 --type-add=coffeescript:ext:coffee
3355
3356 # C++
3357 --type-add=cpp:ext:cpp,cc,cxx,m,hpp,hh,h,hxx
3358
3359 # C++ header files
3360 --type-add=hpp:ext:hpp,hh,h,hxx
3361
3362 # C#
3363 --type-add=csharp:ext:cs
3364
3365 # CSS
3366 # https://www.w3.org/Style/CSS/
3367 --type-add=css:ext:css
3368
3369 # Dart
3370 # https://dart.dev/
3371 --type-add=dart:ext:dart
3372
3373 # Delphi
3374 # https://en.wikipedia.org/wiki/Embarcadero_Delphi
3375 --type-add=delphi:ext:pas,int,dfm,nfm,dof,dpk,dproj,groupproj,bdsgroup,bdsproj
3376
3377 # Elixir
3378 # https://elixir-lang.org/
3379 --type-add=elixir:ext:ex,exs
3380
3381 # Emacs Lisp
3382 # https://www.gnu.org/software/emacs
3383 --type-add=elisp:ext:el
3384
3385 # Erlang
3386 # https://www.erlang.org/
3387 --type-add=erlang:ext:erl,hrl
3388
3389 # Fortran
3390 # https://en.wikipedia.org/wiki/Fortran
3391 --type-add=fortran:ext:f,f77,f90,f95,f03,for,ftn,fpp
3392
3393 # Go
3394 # https://golang.org/
3395 --type-add=go:ext:go
3396
3397 # Groovy
3398 # https://www.groovy-lang.org/
3399 --type-add=groovy:ext:groovy,gtmpl,gpp,grunit,gradle
3400
3401 # GSP
3402 # https://gsp.grails.org/
3403 --type-add=gsp:ext:gsp
3404
3405 # Haskell
3406 # https://www.haskell.org/
3407 --type-add=haskell:ext:hs,lhs
3408
3409 # HTML
3410 --type-add=html:ext:htm,html,xhtml
3411
3412 # Jade
3413 # http://jade-lang.com/
3414 --type-add=jade:ext:jade
3415
3416 # Java
3417 # https://www.oracle.com/technetwork/java/index.html
3418 --type-add=java:ext:java,properties
3419
3420 # JavaScript
3421 --type-add=js:ext:js
3422
3423 # JSP
3424 # https://www.oracle.com/technetwork/java/javaee/jsp/index.html
3425 --type-add=jsp:ext:jsp,jspx,jspf,jhtm,jhtml
3426
3427 # JSON
3428 # https://json.org/
3429 --type-add=json:ext:json
3430
3431 # Kotlin
3432 # https://kotlinlang.org/
3433 --type-add=kotlin:ext:kt,kts
3434
3435 # Less
3436 # http://www.lesscss.org/
3437 --type-add=less:ext:less
3438
3439 # Common Lisp
3440 # https://common-lisp.net/
3441 --type-add=lisp:ext:lisp,lsp
3442
3443 # Lua
3444 # https://www.lua.org/
3445 --type-add=lua:ext:lua
3446 --type-add=lua:firstlinematch:/^#!.*\blua(jit)?/
3447
3448 # Markdown
3449 # https://en.wikipedia.org/wiki/Markdown
3450 --type-add=markdown:ext:md,markdown
3451 # We understand that there are many ad hoc extensions for markdown
3452 # that people use. .md and .markdown are the two that ack recognizes.
3453 # You are free to add your own in your ackrc file.
3454
3455 # Matlab
3456 # https://en.wikipedia.org/wiki/MATLAB
3457 --type-add=matlab:ext:m
3458
3459 # Objective-C
3460 --type-add=objc:ext:m,h
3461
3462 # Objective-C++
3463 --type-add=objcpp:ext:mm,h
3464
3465 # OCaml
3466 # https://ocaml.org/
3467 --type-add=ocaml:ext:ml,mli,mll,mly
3468
3469 # Perl
3470 # https://perl.org/
3471 --type-add=perl:ext:pl,pm,pod,t,psgi
3472 --type-add=perl:firstlinematch:/^#!.*\bperl/
3473
3474 # Perl tests
3475 --type-add=perltest:ext:t
3476
3477 # Perl's Plain Old Documentation format, POD
3478 --type-add=pod:ext:pod
3479
3480 # PHP
3481 # https://www.php.net/
3482 --type-add=php:ext:php,phpt,php3,php4,php5,phtml
3483 --type-add=php:firstlinematch:/^#!.*\bphp/
3484
3485 # Plone
3486 # https://plone.org/
3487 --type-add=plone:ext:pt,cpt,metadata,cpy,py
3488
3489 # Python
3490 # https://www.python.org/
3491 --type-add=python:ext:py
3492 --type-add=python:firstlinematch:/^#!.*\bpython/
3493
3494 # R
3495 # https://www.r-project.org/
3496 --type-add=rr:ext:R
3497
3498 # reStructured Text
3499 # https://docutils.sourceforge.io/rst.html
3500 --type-add=rst:ext:rst
3501
3502 # Ruby
3503 # https://www.ruby-lang.org/
3504 --type-add=ruby:ext:rb,rhtml,rjs,rxml,erb,rake,spec
3505 --type-add=ruby:is:Rakefile
3506 --type-add=ruby:firstlinematch:/^#!.*\bruby/
3507
3508 # Rust
3509 # https://www.rust-lang.org/
3510 --type-add=rust:ext:rs
3511
3512 # Sass
3513 # https://sass-lang.com
3514 --type-add=sass:ext:sass,scss
3515
3516 # Scala
3517 # https://www.scala-lang.org/
3518 --type-add=scala:ext:scala
3519
3520 # Scheme
3521 # https://groups.csail.mit.edu/mac/projects/scheme/
3522 --type-add=scheme:ext:scm,ss
3523
3524 # Shell
3525 --type-add=shell:ext:sh,bash,csh,tcsh,ksh,zsh,fish
3526 --type-add=shell:firstlinematch:/^#!.*\b(?:ba|t?c|k|z|fi)?sh\b/
3527
3528 # Smalltalk
3529 # http://www.smalltalk.org/
3530 --type-add=smalltalk:ext:st
3531
3532 # Smarty
3533 # https://www.smarty.net/
3534 --type-add=smarty:ext:tpl
3535
3536 # SQL
3537 # https://www.iso.org/standard/45498.html
3538 --type-add=sql:ext:sql,ctl
3539
3540 # Stylus
3541 # http://stylus-lang.com/
3542 --type-add=stylus:ext:styl
3543
3544 # SVG
3545 # https://en.wikipedia.org/wiki/Scalable_Vector_Graphics
3546 --type-add=svg:ext:svg
3547
3548 # Swift
3549 # https://developer.apple.com/swift/
3550 --type-add=swift:ext:swift
3551 --type-add=swift:firstlinematch:/^#!.*\bswift/
3552
3553 # Tcl
3554 # https://www.tcl.tk/
3555 --type-add=tcl:ext:tcl,itcl,itk
3556
3557 # TeX & LaTeX
3558 # https://www.latex-project.org/
3559 --type-add=tex:ext:tex,cls,sty
3560
3561 # Template Toolkit (Perl)
3562 # http//template-toolkit.org/
3563 --type-add=ttml:ext:tt,tt2,ttml
3564
3565 # Typescript
3566 # https://www.typescriptlang.org/
3567 --type-add=ts:ext:ts,tsx
3568
3569 # Visual Basic
3570 --type-add=vb:ext:bas,cls,frm,ctl,vb,resx
3571
3572 # Verilog
3573 --type-add=verilog:ext:v,vh,sv
3574
3575 # VHDL
3576 # http://www.eda.org/twiki/bin/view.cgi/P1076/WebHome
3577 --type-add=vhdl:ext:vhd,vhdl
3578
3579 # Vim
3580 # https://www.vim.org/
3581 --type-add=vim:ext:vim
3582
3583 # XML
3584 # https://www.w3.org/TR/REC-xml/
3585 --type-add=xml:ext:xml,dtd,xsd,xsl,xslt,ent,wsdl
3586 --type-add=xml:firstlinematch:/<[?]xml/
3587
3588 # YAML
3589 # https://yaml.org/
3590 --type-add=yaml:ext:yaml,yml
3591 HERE
3592 $lines =~ s/==VERSION==/$App::Ack::VERSION/sm;
3593
3594 return $lines;
3595 }
3596
3597 1;
3598 package App::Ack::ConfigFinder;
3599
3600
3601 use strict;
3602 use warnings;
3603
3604 use Cwd 3.00 ();
3605 use File::Spec 3.00 ();
3606
3607 use if ($^O eq 'MSWin32'), 'Win32';
3608
3609
3610 sub new {
3611 my ( $class ) = @_;
3612
3613 return bless {}, $class;
3614 }
3615
3616
3617 sub _remove_redundancies {
3618 my @configs = @_;
3619
3620 my %seen;
3621 my @uniq;
3622 foreach my $config (@configs) {
3623 my $path = $config->{path};
3624 my $key = -e $path ? Cwd::realpath( $path ) : $path;
3625 if ( not $App::Ack::is_windows ) {
3626 # On Unix, uniquify on inode.
3627 my ($dev, $inode) = (stat $key)[0, 1];
3628 $key = "$dev:$inode" if defined $dev;
3629 }
3630 push( @uniq, $config ) unless $seen{$key}++;
3631 }
3632 return @uniq;
3633 }
3634
3635
3636 sub _check_for_ackrc {
3637 return unless defined $_[0];
3638
3639 my @files = grep { -f }
3640 map { File::Spec->catfile(@_, $_) }
3641 qw(.ackrc _ackrc);
3642
3643 App::Ack::die( File::Spec->catdir(@_) . ' contains both .ackrc and _ackrc. Please remove one of those files.' )
3644 if @files > 1;
3645
3646 return wantarray ? @files : $files[0];
3647 } # end _check_for_ackrc
3648
3649
3650
3651 sub find_config_files {
3652 my @config_files;
3653
3654 if ( $App::Ack::is_windows ) {
3655 push @config_files, map { +{ path => File::Spec->catfile($_, 'ackrc') } } (
3656 Win32::GetFolderPath(Win32::CSIDL_COMMON_APPDATA()),
3657 Win32::GetFolderPath(Win32::CSIDL_APPDATA()),
3658 );
3659 }
3660 else {
3661 push @config_files, { path => '/etc/ackrc' };
3662 }
3663
3664
3665 if ( $ENV{'ACKRC'} && -f $ENV{'ACKRC'} ) {
3666 push @config_files, { path => $ENV{'ACKRC'} };
3667 }
3668 else {
3669 push @config_files, map { +{ path => $_ } } _check_for_ackrc($ENV{'HOME'});
3670 }
3671
3672 my $cwd = Cwd::getcwd();
3673 return () unless defined $cwd;
3674
3675 # XXX This should go through some untainted cwd-fetching function, and not get untainted brute-force like this.
3676 $cwd =~ /(.+)/;
3677 $cwd = $1;
3678 my @dirs = File::Spec->splitdir( $cwd );
3679 while ( @dirs ) {
3680 my $ackrc = _check_for_ackrc(@dirs);
3681 if ( defined $ackrc ) {
3682 push @config_files, { project => 1, path => $ackrc };
3683 last;
3684 }
3685 pop @dirs;
3686 }
3687
3688 # We only test for existence here, so if the file is deleted out from under us, this will fail later.
3689 return _remove_redundancies( @config_files );
3690 }
3691
3692 1;
3693 package App::Ack::ConfigLoader;
3694
3695 use strict;
3696 use warnings;
3697 use 5.010;
3698
3699 use File::Spec 3.00 ();
3700 use Getopt::Long 2.39 ();
3701 use Text::ParseWords 3.1 ();
3702
3703 sub opt_parser {
3704 my @opts = @_;
3705
3706 my @standard = qw(
3707 default
3708 bundling
3709 no_auto_help
3710 no_auto_version
3711 no_ignore_case
3712 );
3713 return Getopt::Long::Parser->new( config => [ @standard, @opts ] );
3714 }
3715
3716 sub _generate_ignore_dir {
3717 my ( $option_name, $opt ) = @_;
3718
3719 my $is_inverted = $option_name =~ /^--no/;
3720
3721 return sub {
3722 my ( undef, $dir ) = @_;
3723
3724 $dir = _remove_directory_separator( $dir );
3725 if ( $dir !~ /:/ ) {
3726 $dir = 'is:' . $dir;
3727 }
3728
3729 my ( $filter_type, $args ) = split /:/, $dir, 2;
3730
3731 if ( $filter_type eq 'firstlinematch' ) {
3732 App::Ack::die( qq{Invalid filter specification "$filter_type" for option '$option_name'} );
3733 }
3734
3735 my $filter = App::Ack::Filter->create_filter($filter_type, split(/,/, $args));
3736 my $collection;
3737
3738 my $previous_inversion_matches = $opt->{idirs} && !($is_inverted xor $opt->{idirs}[-1]->is_inverted());
3739
3740 if ( $previous_inversion_matches ) {
3741 $collection = $opt->{idirs}[-1];
3742
3743 if ( $is_inverted ) {
3744 # This relies on invert of an inverted filter to return the original.
3745 $collection = $collection->invert();
3746 }
3747 }
3748 else {
3749 $collection = App::Ack::Filter::Collection->new();
3750 push @{ $opt->{idirs} }, $is_inverted ? $collection->invert() : $collection;
3751 }
3752
3753 $collection->add($filter);
3754
3755 if ( $filter_type eq 'is' ) {
3756 $collection->add(App::Ack::Filter::IsPath->new($args));
3757 }
3758 };
3759 }
3760
3761
3762 sub _remove_directory_separator {
3763 my $path = shift;
3764
3765 state $dir_sep_chars = $App::Ack::is_windows ? quotemeta( '\\/' ) : quotemeta( File::Spec->catfile( '', '' ) );
3766
3767 $path =~ s/[$dir_sep_chars]$//;
3768
3769 return $path;
3770 }
3771
3772
3773 sub _process_filter_spec {
3774 my ( $spec ) = @_;
3775
3776 if ( $spec =~ /^(\w+):(\w+):(.*)/ ) {
3777 my ( $type_name, $ext_type, $arguments ) = ( $1, $2, $3 );
3778
3779 return ( $type_name,
3780 App::Ack::Filter->create_filter($ext_type, split(/,/, $arguments)) );
3781 }
3782 elsif ( $spec =~ /^(\w+)=(.*)/ ) { # Check to see if we have ack1-style argument specification.
3783 my ( $type_name, $extensions ) = ( $1, $2 );
3784
3785 my @extensions = split(/,/, $extensions);
3786 foreach my $extension ( @extensions ) {
3787 $extension =~ s/^[.]//;
3788 }
3789
3790 return ( $type_name, App::Ack::Filter->create_filter('ext', @extensions) );
3791 }
3792 else {
3793 App::Ack::die( "Invalid filter specification '$spec'" );
3794 }
3795 }
3796
3797
3798 sub _uninvert_filter {
3799 my ( $opt, @filters ) = @_;
3800
3801 return unless defined $opt->{filters} && @filters;
3802
3803 # Loop through all the registered filters. If we hit one that
3804 # matches this extension and it's inverted, we need to delete it from
3805 # the options.
3806 for ( my $i = 0; $i < @{ $opt->{filters} }; $i++ ) {
3807 my $opt_filter = @{ $opt->{filters} }[$i];
3808
3809 # XXX Do a real list comparison? This just checks string equivalence.
3810 if ( $opt_filter->is_inverted() && "$opt_filter->{filter}" eq "@filters" ) {
3811 splice @{ $opt->{filters} }, $i, 1;
3812 $i--;
3813 }
3814 }
3815
3816 return;
3817 }
3818
3819
3820 sub _process_filetypes {
3821 my ( $opt, $arg_sources ) = @_;
3822
3823 my %additional_specs;
3824
3825 my $add_spec = sub {
3826 my ( undef, $spec ) = @_;
3827
3828 my ( $name, $filter ) = _process_filter_spec($spec);
3829
3830 push @{ $App::Ack::mappings{$name} }, $filter;
3831
3832 $additional_specs{$name . '!'} = sub {
3833 my ( undef, $value ) = @_;
3834
3835 my @filters = @{ $App::Ack::mappings{$name} };
3836 if ( not $value ) {
3837 @filters = map { $_->invert() } @filters;
3838 }
3839 else {
3840 _uninvert_filter( $opt, @filters );
3841 }
3842
3843 push @{ $opt->{'filters'} }, @filters;
3844 };
3845 };
3846
3847 my $set_spec = sub {
3848 my ( undef, $spec ) = @_;
3849
3850 my ( $name, $filter ) = _process_filter_spec($spec);
3851
3852 $App::Ack::mappings{$name} = [ $filter ];
3853
3854 $additional_specs{$name . '!'} = sub {
3855 my ( undef, $value ) = @_;
3856
3857 my @filters = @{ $App::Ack::mappings{$name} };
3858 if ( not $value ) {
3859 @filters = map { $_->invert() } @filters;
3860 }
3861
3862 push @{ $opt->{'filters'} }, @filters;
3863 };
3864 };
3865
3866 my $delete_spec = sub {
3867 my ( undef, $name ) = @_;
3868
3869 delete $App::Ack::mappings{$name};
3870 delete $additional_specs{$name . '!'};
3871 };
3872
3873 my %type_arg_specs = (
3874 'type-add=s' => $add_spec,
3875 'type-set=s' => $set_spec,
3876 'type-del=s' => $delete_spec,
3877 );
3878
3879 my $p = opt_parser( 'no_auto_abbrev', 'pass_through' );
3880 foreach my $source (@{$arg_sources}) {
3881 my $args = $source->{contents};
3882
3883 if ( ref($args) ) {
3884 # $args are modified in place, so no need to munge $arg_sources
3885 $p->getoptionsfromarray( $args, %type_arg_specs );
3886 }
3887 else {
3888 ( undef, $source->{contents} ) =
3889 $p->getoptionsfromstring( $args, %type_arg_specs );
3890 }
3891 }
3892
3893 $additional_specs{'k|known-types'} = sub {
3894 my @filters = map { @{$_} } values(%App::Ack::mappings);
3895
3896 push @{ $opt->{'filters'} }, @filters;
3897 };
3898
3899 return \%additional_specs;
3900 }
3901
3902
3903 sub get_arg_spec {
3904 my ( $opt, $extra_specs ) = @_;
3905
3906
3907 sub _type_handler {
3908 my ( $getopt, $value ) = @_;
3909
3910 my $cb_value = 1;
3911 if ( $value =~ s/^no// ) {
3912 $cb_value = 0;
3913 }
3914
3915 my $callback;
3916 {
3917 no warnings;
3918 $callback = $extra_specs->{ $value . '!' };
3919 }
3920
3921 if ( $callback ) {
3922 $callback->( $getopt, $cb_value );
3923 }
3924 else {
3925 App::Ack::die( "Unknown type '$value'" );
3926 }
3927
3928 return;
3929 }
3930
3931 return {
3932 1 => sub { $opt->{1} = $opt->{m} = 1 },
3933 'A|after-context:-1' => sub { shift; $opt->{A} = _context_value(shift) },
3934 'B|before-context:-1' => sub { shift; $opt->{B} = _context_value(shift) },
3935 'C|context:-1' => sub { shift; $opt->{B} = $opt->{A} = _context_value(shift) },
3936 'break!' => \$opt->{break},
3937 'c|count' => \$opt->{c},
3938 'color|colour!' => \$opt->{color},
3939 'color-match=s' => \$ENV{ACK_COLOR_MATCH},
3940 'color-filename=s' => \$ENV{ACK_COLOR_FILENAME},
3941 'color-colno=s' => \$ENV{ACK_COLOR_COLNO},
3942 'color-lineno=s' => \$ENV{ACK_COLOR_LINENO},
3943 'column!' => \$opt->{column},
3944 'create-ackrc' => sub { say for ( '--ignore-ack-defaults', App::Ack::ConfigDefault::options() ); exit; },
3945 'debug' => \$opt->{debug},
3946 'env!' => sub {
3947 my ( undef, $value ) = @_;
3948
3949 if ( !$value ) {
3950 $opt->{noenv_seen} = 1;
3951 }
3952 },
3953 f => \$opt->{f},
3954 'files-from=s' => \$opt->{files_from},
3955 'filter!' => \$App::Ack::is_filter_mode,
3956 flush => sub { $| = 1 },
3957 'follow!' => \$opt->{follow},
3958 g => \$opt->{g},
3959 'group!' => sub { shift; $opt->{heading} = $opt->{break} = shift },
3960 'heading!' => \$opt->{heading},
3961 'h|no-filename' => \$opt->{h},
3962 'H|with-filename' => \$opt->{H},
3963 'i|ignore-case' => sub { $opt->{i} = 1; $opt->{S} = 0; },
3964 'I|no-ignore-case' => sub { $opt->{i} = 0; $opt->{S} = 0; },
3965 'ignore-directory|ignore-dir=s' => _generate_ignore_dir('--ignore-dir', $opt),
3966 'ignore-file=s' => sub {
3967 my ( undef, $file ) = @_;
3968
3969 my ( $filter_type, $args ) = split /:/, $file, 2;
3970
3971 my $filter = App::Ack::Filter->create_filter($filter_type, split(/,/, $args//''));
3972
3973 if ( !$opt->{ifiles} ) {
3974 $opt->{ifiles} = App::Ack::Filter::Collection->new();
3975 }
3976 $opt->{ifiles}->add($filter);
3977 },
3978 'l|files-with-matches'
3979 => \$opt->{l},
3980 'L|files-without-matches'
3981 => \$opt->{L},
3982 'm|max-count=i' => \$opt->{m},
3983 'match=s' => \$opt->{regex},
3984 'n|no-recurse' => \$opt->{n},
3985 o => sub { $opt->{output} = '$&' },
3986 'output=s' => \$opt->{output},
3987 'pager:s' => sub {
3988 my ( undef, $value ) = @_;
3989
3990 $opt->{pager} = $value || $ENV{PAGER};
3991 },
3992 'noignore-directory|noignore-dir=s' => _generate_ignore_dir('--noignore-dir', $opt),
3993 'nopager' => sub { $opt->{pager} = undef },
3994 'passthru' => \$opt->{passthru},
3995 'print0' => \$opt->{print0},
3996 'p|proximate:1' => \$opt->{p},
3997 'P' => sub { $opt->{p} = 0 },
3998 'Q|literal' => \$opt->{Q},
3999 'r|R|recurse' => sub { $opt->{n} = 0 },
4000 'range-start=s' => \$opt->{range_start},
4001 'range-end=s' => \$opt->{range_end},
4002 'range-invert!' => \$opt->{range_invert},
4003 's' => \$opt->{s},
4004 'show-types' => \$opt->{show_types},
4005 'S|smart-case!' => sub { my (undef,$value) = @_; $opt->{S} = $value; $opt->{i} = 0 if $value; },
4006 'sort-files' => \$opt->{sort_files},
4007 't|type=s' => \&_type_handler,
4008 'T=s' => sub { my ($getopt,$value) = @_; $value="no$value"; _type_handler($getopt,$value); },
4009 'underline!' => \$opt->{underline},
4010 'v|invert-match' => \$opt->{v},
4011 'w|word-regexp' => \$opt->{w},
4012 'x' => sub { $opt->{files_from} = '-' },
4013
4014 'help' => sub { App::Ack::show_help(); exit; },
4015 'help-types' => sub { App::Ack::show_help_types(); exit; },
4016 'help-colors' => sub { App::Ack::show_help_colors(); exit; },
4017 'help-rgb-colors' => sub { App::Ack::show_help_rgb(); exit; },
4018 $extra_specs ? %{$extra_specs} : (),
4019 }; # arg_specs
4020 }
4021
4022
4023 sub _context_value {
4024 my $val = shift;
4025
4026 # Contexts default to 2.
4027 return (!defined($val) || ($val < 0)) ? 2 : $val;
4028 }
4029
4030
4031 sub _process_other {
4032 my ( $opt, $extra_specs, $arg_sources ) = @_;
4033
4034 my $argv_source;
4035 my $is_help_types_active;
4036
4037 foreach my $source (@{$arg_sources}) {
4038 if ( $source->{name} eq 'ARGV' ) {
4039 $argv_source = $source->{contents};
4040 last;
4041 }
4042 }
4043
4044 if ( $argv_source ) { # This *should* always be true, but you never know...
4045 my $p = opt_parser( 'pass_through' );
4046 $p->getoptionsfromarray( [ @{$argv_source} ],
4047 'help-types' => \$is_help_types_active,
4048 );
4049 }
4050
4051 my $arg_specs = get_arg_spec( $opt, $extra_specs );
4052
4053 my $p = opt_parser();
4054 foreach my $source (@{$arg_sources}) {
4055 my ( $source_name, $args ) = @{$source}{qw/name contents/};
4056
4057 my $args_for_source = { %{$arg_specs} };
4058
4059 if ( $source->{is_ackrc} ) {
4060 my $illegal = sub {
4061 my $name = shift;
4062 App::Ack::die( "Option --$name is forbidden in .ackrc files." );
4063 };
4064
4065 $args_for_source = {
4066 %{$args_for_source},
4067 'output=s' => $illegal,
4068 'match=s' => $illegal,
4069 };
4070 }
4071 if ( $source->{project} ) {
4072 my $illegal = sub {
4073 my $name = shift;
4074 App::Ack::die( "Option --$name is forbidden in project .ackrc files." );
4075 };
4076
4077 $args_for_source = {
4078 %{$args_for_source},
4079 'pager:s' => $illegal,
4080 };
4081 }
4082
4083 my $ret;
4084 if ( ref($args) ) {
4085 $ret = $p->getoptionsfromarray( $args, %{$args_for_source} );
4086 }
4087 else {
4088 ( $ret, $source->{contents} ) =
4089 $p->getoptionsfromstring( $args, %{$args_for_source} );
4090 }
4091 if ( !$ret ) {
4092 if ( !$is_help_types_active ) {
4093 my $where = $source_name eq 'ARGV' ? 'on command line' : "in $source_name";
4094 App::Ack::die( "Invalid option $where" );
4095 }
4096 }
4097 if ( $opt->{noenv_seen} ) {
4098 App::Ack::die( "--noenv found in $source_name" );
4099 }
4100 }
4101
4102 # XXX We need to check on a -- in the middle of a non-ARGV source
4103
4104 return;
4105 }
4106
4107
4108 sub _explode_sources {
4109 my ( $sources ) = @_;
4110
4111 my @new_sources;
4112
4113 my %opt;
4114 my $arg_spec = get_arg_spec( \%opt, {} );
4115
4116 my $dummy_sub = sub {};
4117 my $add_type = sub {
4118 my ( undef, $arg ) = @_;
4119
4120 if ( $arg =~ /(\w+)=/) {
4121 $arg_spec->{$1} = $dummy_sub;
4122 }
4123 else {
4124 ( $arg ) = split /:/, $arg;
4125 $arg_spec->{$arg} = $dummy_sub;
4126 }
4127 };
4128
4129 my $del_type = sub {
4130 my ( undef, $arg ) = @_;
4131
4132 delete $arg_spec->{$arg};
4133 };
4134
4135 my $p = opt_parser( 'pass_through' );
4136 foreach my $source (@{$sources}) {
4137 my ( $name, $options ) = @{$source}{qw/name contents/};
4138 if ( ref($options) ne 'ARRAY' ) {
4139 $source->{contents} = $options =
4140 [ Text::ParseWords::shellwords($options) ];
4141 }
4142
4143 for my $j ( 0 .. @{$options}-1 ) {
4144 next unless $options->[$j] =~ /^-/;
4145 my @chunk = ( $options->[$j] );
4146 push @chunk, $options->[$j] while ++$j < @{$options} && $options->[$j] !~ /^-/;
4147 $j--;
4148
4149 my @copy = @chunk;
4150 $p->getoptionsfromarray( [@chunk],
4151 'type-add=s' => $add_type,
4152 'type-set=s' => $add_type,
4153 'type-del=s' => $del_type,
4154 %{$arg_spec}
4155 );
4156
4157 push @new_sources, {
4158 name => $name,
4159 contents => \@copy,
4160 };
4161 }
4162 }
4163
4164 return \@new_sources;
4165 }
4166
4167
4168 sub _compare_opts {
4169 my ( $a, $b ) = @_;
4170
4171 my $first_a = $a->[0];
4172 my $first_b = $b->[0];
4173
4174 $first_a =~ s/^--?//;
4175 $first_b =~ s/^--?//;
4176
4177 return $first_a cmp $first_b;
4178 }
4179
4180
4181 sub _dump_options {
4182 my ( $sources ) = @_;
4183
4184 $sources = _explode_sources($sources);
4185
4186 my %opts_by_source;
4187 my @source_names;
4188
4189 foreach my $source (@{$sources}) {
4190 my $name = $source->{name};
4191 if ( not $opts_by_source{$name} ) {
4192 $opts_by_source{$name} = [];
4193 push @source_names, $name;
4194 }
4195 push @{$opts_by_source{$name}}, $source->{contents};
4196 }
4197
4198 foreach my $name (@source_names) {
4199 my $contents = $opts_by_source{$name};
4200
4201 say $name;
4202 say '=' x length($name);
4203 say ' ', join(' ', @{$_}) for sort { _compare_opts($a, $b) } @{$contents};
4204 }
4205
4206 return;
4207 }
4208
4209
4210 sub _remove_default_options_if_needed {
4211 my ( $sources ) = @_;
4212
4213 my $default_index;
4214
4215 foreach my $index ( 0 .. $#{$sources} ) {
4216 if ( $sources->[$index]{'name'} eq 'Defaults' ) {
4217 $default_index = $index;
4218 last;
4219 }
4220 }
4221
4222 return $sources unless defined $default_index;
4223
4224 my $should_remove = 0;
4225
4226 my $p = opt_parser( 'no_auto_abbrev', 'pass_through' );
4227
4228 foreach my $index ( $default_index + 1 .. $#{$sources} ) {
4229 my $args = $sources->[$index]->{contents};
4230
4231 if (ref($args)) {
4232 $p->getoptionsfromarray( $args,
4233 'ignore-ack-defaults' => \$should_remove,
4234 );
4235 }
4236 else {
4237 ( undef, $sources->[$index]{contents} ) = $p->getoptionsfromstring( $args,
4238 'ignore-ack-defaults' => \$should_remove,
4239 );
4240 }
4241 }
4242
4243 return $sources unless $should_remove;
4244
4245 my @copy = @{$sources};
4246 splice @copy, $default_index, 1;
4247 return \@copy;
4248 }
4249
4250
4251 sub process_args {
4252 my $arg_sources = \@_;
4253
4254 my %opt = (
4255 pager => $ENV{ACK_PAGER_COLOR} || $ENV{ACK_PAGER},
4256 );
4257
4258 $arg_sources = _remove_default_options_if_needed($arg_sources);
4259
4260 # Check for --dump early.
4261 foreach my $source (@{$arg_sources}) {
4262 if ( $source->{name} eq 'ARGV' ) {
4263 my $dump;
4264 my $p = opt_parser( 'pass_through' );
4265 $p->getoptionsfromarray( $source->{contents},
4266 'dump' => \$dump,
4267 );
4268 if ( $dump ) {
4269 _dump_options($arg_sources);
4270 exit(0);
4271 }
4272 }
4273 }
4274
4275 my $type_specs = _process_filetypes(\%opt, $arg_sources);
4276
4277 _check_for_mutex_options( $type_specs );
4278
4279 _process_other(\%opt, $type_specs, $arg_sources);
4280 while ( @{$arg_sources} ) {
4281 my $source = shift @{$arg_sources};
4282 my $args = $source->{contents};
4283
4284 # All of our sources should be transformed into an array ref
4285 if ( ref($args) ) {
4286 my $source_name = $source->{name};
4287 if ( $source_name eq 'ARGV' ) {
4288 @ARGV = @{$args};
4289 }
4290 elsif (@{$args}) {
4291 App::Ack::die( "Source '$source_name' has extra arguments!" );
4292 }
4293 }
4294 else {
4295 App::Ack::die( 'The impossible has occurred!' );
4296 }
4297 }
4298 my $filters = ($opt{filters} ||= []);
4299
4300 # Throw the default filter in if no others are selected.
4301 if ( not grep { !$_->is_inverted() } @{$filters} ) {
4302 push @{$filters}, App::Ack::Filter::Default->new();
4303 }
4304 return \%opt;
4305 }
4306
4307
4308 sub retrieve_arg_sources {
4309 my @arg_sources;
4310
4311 my $noenv;
4312 my $ackrc;
4313
4314 my $p = opt_parser( 'no_auto_abbrev', 'pass_through' );
4315 $p->getoptions(
4316 'noenv' => \$noenv,
4317 'ackrc=s' => \$ackrc,
4318 );
4319
4320 my @files;
4321
4322 if ( !$noenv ) {
4323 my $finder = App::Ack::ConfigFinder->new;
4324 @files = $finder->find_config_files;
4325 }
4326 if ( $ackrc ) {
4327 # We explicitly use open so we get a nice error message.
4328 # XXX This is a potential race condition!.
4329 if ( open my $fh, '<', $ackrc ) {
4330 close $fh;
4331 }
4332 else {
4333 App::Ack::die( "Unable to load ackrc '$ackrc': $!" );
4334 }
4335 push( @files, { path => $ackrc } );
4336 }
4337
4338 push @arg_sources, {
4339 name => 'Defaults',
4340 contents => [ App::Ack::ConfigDefault::options_clean() ],
4341 };
4342
4343 foreach my $file ( @files) {
4344 my @lines = read_rcfile($file->{path});
4345 if ( @lines ) {
4346 push @arg_sources, {
4347 name => $file->{path},
4348 contents => \@lines,
4349 project => $file->{project},
4350 is_ackrc => 1,
4351 };
4352 }
4353 }
4354
4355 push @arg_sources, {
4356 name => 'ARGV',
4357 contents => [ @ARGV ],
4358 };
4359
4360 return @arg_sources;
4361 }
4362
4363
4364 sub read_rcfile {
4365 my $file = shift;
4366
4367 return unless defined $file && -e $file;
4368
4369 my @lines;
4370
4371 open( my $fh, '<', $file ) or App::Ack::die( "Unable to read $file: $!" );
4372 while ( defined( my $line = <$fh> ) ) {
4373 chomp $line;
4374 $line =~ s/^\s+//;
4375 $line =~ s/\s+$//;
4376
4377 next if $line eq '';
4378 next if $line =~ /^\s*#/;
4379
4380 push( @lines, $line );
4381 }
4382 close $fh or App::Ack::die( "Unable to close $file: $!" );
4383
4384 return @lines;
4385 }
4386
4387
4388 # Verifies no mutex options were passed. Dies if they were.
4389 sub _check_for_mutex_options {
4390 my $type_specs = shift;
4391
4392 my $mutex = mutex_options();
4393
4394 my ($raw,$used) = _options_used( $type_specs );
4395
4396 my @used = sort { lc $a cmp lc $b } keys %{$used};
4397
4398 for my $i ( @used ) {
4399 for my $j ( @used ) {
4400 next if $i eq $j;
4401 if ( $mutex->{$i}{$j} ) {
4402 my $x = $raw->[ $used->{$i} ];
4403 my $y = $raw->[ $used->{$j} ];
4404 App::Ack::die( "Options '$x' and '$y' can't be used together." );
4405 }
4406 }
4407 }
4408
4409 return;
4410 }
4411
4412
4413 # Processes the command line option and returns a hash of the options that were
4414 # used on the command line, using their full name. "--prox" shows up in the hash as "--proximate".
4415 sub _options_used {
4416 my $type_specs = shift;
4417
4418 my %dummy_opt;
4419 my $real_spec = get_arg_spec( \%dummy_opt, $type_specs );
4420
4421 # The real argument parsing doesn't check for --type-add, --type-del or --type-set because
4422 # they get removed by the argument processing. We have to account for them here.
4423 my $sub_dummy = sub {};
4424 $real_spec = {
4425 %{$real_spec},
4426 'type-add=s' => $sub_dummy,
4427 'type-del=s' => $sub_dummy,
4428 'type-set=s' => $sub_dummy,
4429 'ignore-ack-defaults' => $sub_dummy,
4430 };
4431
4432 my %parsed;
4433 my @raw;
4434 my %spec_capture_parsed;
4435 my %spec_capture_raw;
4436
4437
4438 # Capture the %parsed hash.
4439 CAPTURE_PARSED: {
4440 my $parsed_pos = 0;
4441 my $sub_count = sub {
4442 my $arg = shift;
4443 $arg = "$arg";
4444 $parsed{$arg} = $parsed_pos++;
4445 };
4446 %spec_capture_parsed = (
4447 '<>' => sub { $parsed_pos++ }, # Bump forward one pos for non-options.
4448 map { $_ => $sub_count } keys %{$real_spec}
4449 );
4450 }
4451
4452 # Capture the @raw array.
4453 CAPTURE_RAW: {
4454 my $raw_pos = 0;
4455 %spec_capture_raw = (
4456 '<>' => sub { $raw_pos++ }, # Bump forward one pos for non-options.
4457 );
4458
4459 my $sub_count = sub {
4460 my $arg = shift;
4461
4462 $arg = "$arg";
4463 $raw[$raw_pos] = length($arg) == 1 ? "-$arg" : "--$arg";
4464 $raw_pos++;
4465 };
4466
4467 for my $opt_spec ( keys %{$real_spec} ) {
4468 my $negatable;
4469 my $type;
4470 my $default;
4471
4472 $negatable = ($opt_spec =~ s/!$//);
4473
4474 if ( $opt_spec =~ s/(=[si])$// ) {
4475 $type = $1;
4476 }
4477 if ( $opt_spec =~ s/(:.+)$// ) {
4478 $default = $1;
4479 }
4480
4481 my @aliases = split( /\|/, $opt_spec );
4482 for my $alias ( @aliases ) {
4483 $alias .= $type if defined $type;
4484 $alias .= $default if defined $default;
4485 $alias .= '!' if $negatable;
4486
4487 $spec_capture_raw{$alias} = $sub_count;
4488 }
4489 }
4490 }
4491
4492 # Parse @ARGV twice, once with each capture spec.
4493 my $p = opt_parser( 'pass_through' ); # Ignore invalid options.
4494 $p->getoptionsfromarray( [@ARGV], %spec_capture_raw );
4495 $p->getoptionsfromarray( [@ARGV], %spec_capture_parsed );
4496
4497 return (\@raw,\%parsed);
4498 }
4499
4500
4501 sub mutex_options {
4502 # This list is machine-generated by dev/crank-mutex. Do not modify it by hand.
4503
4504 return {
4505 1 => {
4506 m => 1,
4507 passthru => 1,
4508 },
4509 A => {
4510 L => 1,
4511 c => 1,
4512 f => 1,
4513 g => 1,
4514 l => 1,
4515 o => 1,
4516 output => 1,
4517 p => 1,
4518 passthru => 1,
4519 },
4520 B => {
4521 L => 1,
4522 c => 1,
4523 f => 1,
4524 g => 1,
4525 l => 1,
4526 o => 1,
4527 output => 1,
4528 p => 1,
4529 passthru => 1,
4530 },
4531 C => {
4532 L => 1,
4533 c => 1,
4534 f => 1,
4535 g => 1,
4536 l => 1,
4537 o => 1,
4538 output => 1,
4539 p => 1,
4540 passthru => 1,
4541 },
4542 H => {
4543 L => 1,
4544 f => 1,
4545 g => 1,
4546 l => 1,
4547 },
4548 L => {
4549 A => 1,
4550 B => 1,
4551 C => 1,
4552 H => 1,
4553 L => 1,
4554 break => 1,
4555 c => 1,
4556 column => 1,
4557 f => 1,
4558 g => 1,
4559 group => 1,
4560 h => 1,
4561 heading => 1,
4562 l => 1,
4563 'no-filename' => 1,
4564 o => 1,
4565 output => 1,
4566 p => 1,
4567 passthru => 1,
4568 'show-types' => 1,
4569 v => 1,
4570 'with-filename' => 1,
4571 },
4572 break => {
4573 L => 1,
4574 c => 1,
4575 f => 1,
4576 g => 1,
4577 l => 1,
4578 },
4579 c => {
4580 A => 1,
4581 B => 1,
4582 C => 1,
4583 L => 1,
4584 break => 1,
4585 column => 1,
4586 f => 1,
4587 g => 1,
4588 group => 1,
4589 heading => 1,
4590 m => 1,
4591 o => 1,
4592 output => 1,
4593 p => 1,
4594 passthru => 1,
4595 },
4596 column => {
4597 L => 1,
4598 c => 1,
4599 f => 1,
4600 g => 1,
4601 l => 1,
4602 o => 1,
4603 output => 1,
4604 passthru => 1,
4605 v => 1,
4606 },
4607 f => {
4608 A => 1,
4609 B => 1,
4610 C => 1,
4611 H => 1,
4612 L => 1,
4613 break => 1,
4614 c => 1,
4615 column => 1,
4616 f => 1,
4617 'files-from' => 1,
4618 g => 1,
4619 group => 1,
4620 h => 1,
4621 heading => 1,
4622 l => 1,
4623 m => 1,
4624 match => 1,
4625 o => 1,
4626 output => 1,
4627 p => 1,
4628 passthru => 1,
4629 u => 1,
4630 v => 1,
4631 x => 1,
4632 },
4633 'files-from' => {
4634 f => 1,
4635 g => 1,
4636 x => 1,
4637 },
4638 g => {
4639 A => 1,
4640 B => 1,
4641 C => 1,
4642 H => 1,
4643 L => 1,
4644 break => 1,
4645 c => 1,
4646 column => 1,
4647 f => 1,
4648 'files-from' => 1,
4649 g => 1,
4650 group => 1,
4651 h => 1,
4652 heading => 1,
4653 l => 1,
4654 m => 1,
4655 match => 1,
4656 o => 1,
4657 output => 1,
4658 p => 1,
4659 passthru => 1,
4660 u => 1,
4661 x => 1,
4662 },
4663 group => {
4664 L => 1,
4665 c => 1,
4666 f => 1,
4667 g => 1,
4668 l => 1,
4669 },
4670 h => {
4671 L => 1,
4672 f => 1,
4673 g => 1,
4674 l => 1,
4675 },
4676 heading => {
4677 L => 1,
4678 c => 1,
4679 f => 1,
4680 g => 1,
4681 l => 1,
4682 },
4683 l => {
4684 A => 1,
4685 B => 1,
4686 C => 1,
4687 H => 1,
4688 L => 1,
4689 break => 1,
4690 column => 1,
4691 f => 1,
4692 g => 1,
4693 group => 1,
4694 h => 1,
4695 heading => 1,
4696 l => 1,
4697 'no-filename' => 1,
4698 o => 1,
4699 output => 1,
4700 p => 1,
4701 passthru => 1,
4702 'show-types' => 1,
4703 'with-filename' => 1,
4704 },
4705 m => {
4706 1 => 1,
4707 c => 1,
4708 f => 1,
4709 g => 1,
4710 passthru => 1,
4711 },
4712 match => {
4713 f => 1,
4714 g => 1,
4715 },
4716 'no-filename' => {
4717 L => 1,
4718 l => 1,
4719 },
4720 o => {
4721 A => 1,
4722 B => 1,
4723 C => 1,
4724 L => 1,
4725 c => 1,
4726 column => 1,
4727 f => 1,
4728 g => 1,
4729 l => 1,
4730 o => 1,
4731 output => 1,
4732 p => 1,
4733 passthru => 1,
4734 'show-types' => 1,
4735 v => 1,
4736 },
4737 output => {
4738 A => 1,
4739 B => 1,
4740 C => 1,
4741 L => 1,
4742 c => 1,
4743 column => 1,
4744 f => 1,
4745 g => 1,
4746 l => 1,
4747 o => 1,
4748 output => 1,
4749 p => 1,
4750 passthru => 1,
4751 'show-types' => 1,
4752 u => 1,
4753 v => 1,
4754 },
4755 p => {
4756 A => 1,
4757 B => 1,
4758 C => 1,
4759 L => 1,
4760 c => 1,
4761 f => 1,
4762 g => 1,
4763 l => 1,
4764 o => 1,
4765 output => 1,
4766 p => 1,
4767 passthru => 1,
4768 },
4769 passthru => {
4770 1 => 1,
4771 A => 1,
4772 B => 1,
4773 C => 1,
4774 L => 1,
4775 c => 1,
4776 column => 1,
4777 f => 1,
4778 g => 1,
4779 l => 1,
4780 m => 1,
4781 o => 1,
4782 output => 1,
4783 p => 1,
4784 v => 1,
4785 },
4786 'show-types' => {
4787 L => 1,
4788 l => 1,
4789 o => 1,
4790 output => 1,
4791 },
4792 u => {
4793 f => 1,
4794 g => 1,
4795 output => 1,
4796 },
4797 v => {
4798 L => 1,
4799 column => 1,
4800 f => 1,
4801 o => 1,
4802 output => 1,
4803 passthru => 1,
4804 },
4805 'with-filename' => {
4806 L => 1,
4807 l => 1,
4808 },
4809 x => {
4810 f => 1,
4811 'files-from' => 1,
4812 g => 1,
4813 },
4814 };
4815
4816 } # End of mutex_options()
4817
4818
4819 1; # End of App::Ack::ConfigLoader
4820 package App::Ack::File;
4821
4822 use warnings;
4823 use strict;
4824
4825 use File::Spec ();
4826
4827
4828 sub new {
4829 my $class = shift;
4830 my $filename = shift;
4831
4832 my $self = bless {
4833 filename => $filename,
4834 fh => undef,
4835 }, $class;
4836
4837 if ( $self->{filename} eq '-' ) {
4838 $self->{fh} = *STDIN;
4839 }
4840
4841 return $self;
4842 }
4843
4844
4845
4846 sub name {
4847 return $_[0]->{filename};
4848 }
4849
4850
4851
4852 sub basename {
4853 my ( $self ) = @_;
4854
4855 return $self->{basename} //= (File::Spec->splitpath($self->name))[2];
4856 }
4857
4858
4859
4860 sub open {
4861 my ( $self ) = @_;
4862
4863 if ( !$self->{fh} ) {
4864 if ( open $self->{fh}, '<', $self->{filename} ) {
4865 # Do nothing.
4866 }
4867 else {
4868 $self->{fh} = undef;
4869 }
4870 }
4871
4872 return $self->{fh};
4873 }
4874
4875
4876 sub may_be_present {
4877 my $self = shift;
4878 my $regex = shift;
4879
4880 # Tells if the file needs a line-by-line scan. This is a big
4881 # optimization because if you can tell from the outset that the pattern
4882 # is not found in the file at all, then there's no need to do the
4883 # line-by-line iteration.
4884
4885 # Slurp up an entire file up to 10M, see if there are any matches
4886 # in it, and if so, let us know so we can iterate over it directly.
4887
4888 # The $regex may be undef if it had a "$" in it, and is therefore unsuitable for this heuristic.
4889
4890 my $may_be_present = 1;
4891 if ( $regex && $self->open() && -f $self->{fh} ) {
4892 my $buffer;
4893 my $size = 10_000_000;
4894 my $rc = sysread( $self->{fh}, $buffer, $size );
4895 if ( !defined($rc) ) {
4896 if ( $App::Ack::report_bad_filenames ) {
4897 App::Ack::warn( $self->name . ": $!" );
4898 }
4899 $may_be_present = 0;
4900 }
4901 else {
4902 # If we read all 10M, then we need to scan the rest.
4903 # If there are any carriage returns, our results are flaky, so scan the rest.
4904 if ( ($rc == $size) || (index($buffer,"\r") >= 0) ) {
4905 $may_be_present = 1;
4906 }
4907 else {
4908 if ( $buffer !~ /$regex/o ) {
4909 $may_be_present = 0;
4910 }
4911 }
4912 }
4913 }
4914
4915 return $may_be_present;
4916 }
4917
4918
4919
4920 sub reset {
4921 my $self = shift;
4922
4923 if ( defined($self->{fh}) ) {
4924 return unless -f $self->{fh};
4925
4926 if ( !seek( $self->{fh}, 0, 0 ) && $App::Ack::report_bad_filenames ) {
4927 App::Ack::warn( "$self->{filename}: $!" );
4928 }
4929 }
4930
4931 return;
4932 }
4933
4934
4935
4936 sub close {
4937 my $self = shift;
4938
4939 if ( $self->{fh} ) {
4940 if ( !close($self->{fh}) && $App::Ack::report_bad_filenames ) {
4941 App::Ack::warn( $self->name() . ": $!" );
4942 }
4943 $self->{fh} = undef;
4944 }
4945
4946 return;
4947 }
4948
4949
4950
4951 sub clone {
4952 my ( $self ) = @_;
4953
4954 return __PACKAGE__->new($self->name);
4955 }
4956
4957
4958
4959 sub firstliney {
4960 my ( $self ) = @_;
4961
4962 if ( !exists $self->{firstliney} ) {
4963 my $fh = $self->open();
4964 if ( !$fh ) {
4965 if ( $App::Ack::report_bad_filenames ) {
4966 App::Ack::warn( $self->name . ': ' . $! );
4967 }
4968 $self->{firstliney} = '';
4969 }
4970 else {
4971 my $buffer;
4972 my $rc = sysread( $fh, $buffer, 250 );
4973 if ( $rc ) {
4974 $buffer =~ s/[\r\n].*//s;
4975 }
4976 else {
4977 if ( !defined($rc) ) {
4978 App::Ack::warn( $self->name . ': ' . $! );
4979 }
4980 $buffer = '';
4981 }
4982 $self->{firstliney} = $buffer;
4983 $self->reset;
4984 }
4985 }
4986
4987 return $self->{firstliney};
4988 }
4989
4990 1;
4991 package App::Ack::Files;
4992
4993
4994
4995 use warnings;
4996 use strict;
4997 use 5.010;
4998
4999
5000 sub from_argv {
5001 my $class = shift;
5002 my $opt = shift;
5003 my $start = shift;
5004
5005 my $self = bless {}, $class;
5006
5007 my $descend_filter = $opt->{descend_filter};
5008
5009 if ( $opt->{n} ) {
5010 $descend_filter = sub {
5011 return 0;
5012 };
5013 }
5014
5015 $self->{iter} =
5016 File::Next::files( {
5017 file_filter => $opt->{file_filter},
5018 descend_filter => $descend_filter,
5019 error_handler => _generate_error_handler(),
5020 warning_handler => sub {},
5021 sort_files => $opt->{sort_files},
5022 follow_symlinks => $opt->{follow},
5023 }, @{$start} );
5024
5025 return $self;
5026 }
5027
5028
5029 sub from_file {
5030 my $class = shift;
5031 my $opt = shift;
5032 my $file = shift;
5033
5034 my $error_handler = _generate_error_handler();
5035 my $iter =
5036 File::Next::from_file( {
5037 error_handler => $error_handler,
5038 warning_handler => $error_handler,
5039 sort_files => $opt->{sort_files},
5040 }, $file ) or return undef;
5041
5042 return bless {
5043 iter => $iter,
5044 }, $class;
5045 }
5046
5047
5048
5049
5050 sub from_stdin {
5051 my $class = shift;
5052
5053 my $self = bless {}, $class;
5054
5055 $self->{iter} = sub {
5056 state $has_been_called = 0;
5057
5058 if ( !$has_been_called ) {
5059 $has_been_called = 1;
5060 return '-';
5061 }
5062 return;
5063 };
5064
5065 return $self;
5066 }
5067
5068
5069 sub next {
5070 my $self = shift;
5071
5072 my $file = $self->{iter}->();
5073
5074 return unless defined($file);
5075
5076 return App::Ack::File->new( $file );
5077 }
5078
5079
5080 sub _generate_error_handler {
5081 if ( $App::Ack::report_bad_filenames ) {
5082 return sub {
5083 my $msg = shift;
5084 App::Ack::warn( $msg );
5085 };
5086 }
5087 else {
5088 return sub {};
5089 }
5090 }
5091
5092 1;
5093 package App::Ack::Filter;
5094
5095 use strict;
5096 use warnings;
5097
5098
5099 my %filter_types;
5100
5101
5102 sub create_filter {
5103 my ( undef, $type, @args ) = @_;
5104
5105 if ( my $package = $filter_types{$type} ) {
5106 return $package->new(@args);
5107 }
5108 my $allowed_types = join( ', ', sort keys %filter_types );
5109 App::Ack::die( "Unknown filter type '$type'. Type must be one of: $allowed_types." );
5110 }
5111
5112
5113 sub register_filter {
5114 my ( undef, $type, $package ) = @_;
5115
5116 $filter_types{$type} = $package;
5117
5118 return;
5119 }
5120
5121
5122 sub invert {
5123 my ( $self ) = @_;
5124
5125 return App::Ack::Filter::Inverse->new( $self );
5126 }
5127
5128
5129 sub is_inverted {
5130 return 0;
5131 }
5132
5133
5134 sub to_string {
5135 return '(unimplemented to_string)';
5136 }
5137
5138
5139 sub inspect {
5140 my ( $self ) = @_;
5141
5142 return ref($self);
5143 }
5144
5145 1;
5146 package App::Ack::Filter::Collection;
5147
5148
5149 use strict;
5150 use warnings;
5151 BEGIN {
5152 our @ISA = 'App::Ack::Filter';
5153 }
5154
5155 sub new {
5156 my ( $class ) = @_;
5157
5158 return bless {
5159 groups => {},
5160 ungrouped => [],
5161 }, $class;
5162 }
5163
5164 sub filter {
5165 my ( $self, $file ) = @_;
5166
5167 for my $group (values %{$self->{groups}}) {
5168 return 1 if $group->filter($file);
5169 }
5170
5171 for my $filter (@{$self->{ungrouped}}) {
5172 return 1 if $filter->filter($file);
5173 }
5174
5175 return 0;
5176 }
5177
5178 sub add {
5179 my ( $self, $filter ) = @_;
5180
5181 if (exists $filter->{'groupname'}) {
5182 my $group = ($self->{groups}->{$filter->{groupname}} ||= $filter->create_group());
5183 $group->add($filter);
5184 }
5185 else {
5186 push @{$self->{'ungrouped'}}, $filter;
5187 }
5188
5189 return;
5190 }
5191
5192 sub inspect {
5193 my ( $self ) = @_;
5194
5195 return ref($self) . " - $self";
5196 }
5197
5198 sub to_string {
5199 my ( $self ) = @_;
5200
5201 return join(', ', map { "($_)" } @{$self->{ungrouped}});
5202 }
5203
5204 1;
5205 package App::Ack::Filter::Default;
5206
5207
5208 use strict;
5209 use warnings;
5210 BEGIN {
5211 our @ISA = 'App::Ack::Filter';
5212 }
5213
5214 sub new {
5215 my ( $class ) = @_;
5216
5217 return bless {}, $class;
5218 }
5219
5220 sub filter {
5221 my ( undef, $file ) = @_;
5222
5223 return -T $file->name;
5224 }
5225
5226 1;
5227 package App::Ack::Filter::Extension;
5228
5229
5230 use strict;
5231 use warnings;
5232 BEGIN {
5233 our @ISA = 'App::Ack::Filter';
5234 }
5235
5236
5237 sub new {
5238 my ( $class, @extensions ) = @_;
5239
5240 my $exts = join('|', map { "\Q$_\E"} @extensions);
5241 my $re = qr/[.](?:$exts)$/i;
5242
5243 return bless {
5244 extensions => \@extensions,
5245 regex => $re,
5246 groupname => 'ExtensionGroup',
5247 }, $class;
5248 }
5249
5250 sub create_group {
5251 return App::Ack::Filter::ExtensionGroup->new();
5252 }
5253
5254 sub filter {
5255 my ( $self, $file ) = @_;
5256
5257 return $file->name =~ /$self->{regex}/;
5258 }
5259
5260 sub inspect {
5261 my ( $self ) = @_;
5262
5263 return ref($self) . ' - ' . $self->{regex};
5264 }
5265
5266 sub to_string {
5267 my ( $self ) = @_;
5268
5269 return join( ' ', map { ".$_" } @{$self->{extensions}} );
5270 }
5271
5272 BEGIN {
5273 App::Ack::Filter->register_filter(ext => __PACKAGE__);
5274 }
5275
5276 1;
5277 package App::Ack::Filter::ExtensionGroup;
5278
5279
5280 use strict;
5281 use warnings;
5282 BEGIN {
5283 our @ISA = 'App::Ack::Filter';
5284 }
5285
5286 sub new {
5287 my ( $class ) = @_;
5288
5289 return bless {
5290 data => {},
5291 }, $class;
5292 }
5293
5294 sub add {
5295 my ( $self, $filter ) = @_;
5296
5297 foreach my $ext (@{$filter->{extensions}}) {
5298 $self->{data}->{lc $ext} = 1;
5299 }
5300
5301 return;
5302 }
5303
5304 sub filter {
5305 my ( $self, $file ) = @_;
5306
5307 if ($file->name =~ /[.]([^.]*)$/) {
5308 return exists $self->{'data'}->{lc $1};
5309 }
5310
5311 return 0;
5312 }
5313
5314 sub inspect {
5315 my ( $self ) = @_;
5316
5317 return ref($self) . " - $self";
5318 }
5319
5320 sub to_string {
5321 my ( $self ) = @_;
5322
5323 return join(' ', map { ".$_" } sort keys %{$self->{data}});
5324 }
5325
5326 1;
5327 package App::Ack::Filter::FirstLineMatch;
5328
5329
5330
5331 use strict;
5332 use warnings;
5333 BEGIN {
5334 our @ISA = 'App::Ack::Filter';
5335 }
5336
5337 sub new {
5338 my ( $class, $re ) = @_;
5339
5340 $re =~ s{^/|/$}{}g; # XXX validate?
5341 $re = qr{$re}i;
5342
5343 return bless {
5344 regex => $re,
5345 }, $class;
5346 }
5347
5348 # This test reads the first 250 characters of a file, then just uses the
5349 # first line found in that. This prevents reading something like an entire
5350 # .min.js file (which might be only one "line" long) into memory.
5351
5352 sub filter {
5353 my ( $self, $file ) = @_;
5354
5355 return $file->firstliney =~ /$self->{regex}/;
5356 }
5357
5358 sub inspect {
5359 my ( $self ) = @_;
5360
5361
5362 return ref($self) . ' - ' . $self->{regex};
5363 }
5364
5365 sub to_string {
5366 my ( $self ) = @_;
5367
5368 (my $re = $self->{regex}) =~ s{\([^:]*:(.*)\)$}{$1};
5369
5370 return "First line matches /$re/";
5371 }
5372
5373 BEGIN {
5374 App::Ack::Filter->register_filter(firstlinematch => __PACKAGE__);
5375 }
5376
5377 1;
5378 package App::Ack::Filter::Inverse;
5379
5380
5381
5382 use strict;
5383 use warnings;
5384 BEGIN {
5385 our @ISA = 'App::Ack::Filter';
5386 }
5387
5388 sub new {
5389 my ( $class, $filter ) = @_;
5390
5391 return bless {
5392 filter => $filter,
5393 }, $class;
5394 }
5395
5396 sub filter {
5397 my ( $self, $file ) = @_;
5398
5399 return !$self->{filter}->filter( $file );
5400 }
5401
5402 sub invert {
5403 my $self = shift;
5404
5405 return $self->{'filter'};
5406 }
5407
5408 sub is_inverted {
5409 return 1;
5410 }
5411
5412 sub inspect {
5413 my ( $self ) = @_;
5414
5415 my $filter = $self->{'filter'};
5416
5417 return "!$filter";
5418 }
5419
5420 1;
5421 package App::Ack::Filter::Is;
5422
5423
5424 use strict;
5425 use warnings;
5426 BEGIN {
5427 our @ISA = 'App::Ack::Filter';
5428 }
5429
5430 use File::Spec 3.00 ();
5431
5432 sub new {
5433 my ( $class, $filename ) = @_;
5434
5435 return bless {
5436 filename => $filename,
5437 groupname => 'IsGroup',
5438 }, $class;
5439 }
5440
5441 sub create_group {
5442 return App::Ack::Filter::IsGroup->new();
5443 }
5444
5445 sub filter {
5446 my ( $self, $file ) = @_;
5447
5448 return (File::Spec->splitpath($file->name))[2] eq $self->{filename};
5449 }
5450
5451 sub inspect {
5452 my ( $self ) = @_;
5453
5454 return ref($self) . ' - ' . $self->{filename};
5455 }
5456
5457 sub to_string {
5458 my ( $self ) = @_;
5459
5460 return $self->{filename};
5461 }
5462
5463 BEGIN {
5464 App::Ack::Filter->register_filter(is => __PACKAGE__);
5465 }
5466
5467 1;
5468 package App::Ack::Filter::IsGroup;
5469
5470
5471 use strict;
5472 use warnings;
5473 BEGIN {
5474 our @ISA = 'App::Ack::Filter';
5475 }
5476
5477 sub new {
5478 my ( $class ) = @_;
5479
5480 return bless {
5481 data => {},
5482 }, $class;
5483 }
5484
5485 sub add {
5486 my ( $self, $filter ) = @_;
5487
5488 $self->{data}->{ $filter->{filename} } = 1;
5489
5490 return;
5491 }
5492
5493 sub filter {
5494 my ( $self, $file ) = @_;
5495
5496 return exists $self->{data}->{ $file->basename };
5497 }
5498
5499 sub inspect {
5500 my ( $self ) = @_;
5501
5502 return ref($self) . " - $self";
5503 }
5504
5505 sub to_string {
5506 my ( $self ) = @_;
5507
5508 return join(' ', keys %{$self->{data}});
5509 }
5510
5511 1;
5512 package App::Ack::Filter::IsPath;
5513
5514
5515 use strict;
5516 use warnings;
5517 BEGIN {
5518 our @ISA = 'App::Ack::Filter';
5519 }
5520
5521
5522 sub new {
5523 my ( $class, $filename ) = @_;
5524
5525 return bless {
5526 filename => $filename,
5527 groupname => 'IsPathGroup',
5528 }, $class;
5529 }
5530
5531 sub create_group {
5532 return App::Ack::Filter::IsPathGroup->new();
5533 }
5534
5535 sub filter {
5536 my ( $self, $file ) = @_;
5537
5538 return $file->name eq $self->{filename};
5539 }
5540
5541 sub inspect {
5542 my ( $self ) = @_;
5543
5544 return ref($self) . ' - ' . $self->{filename};
5545 }
5546
5547 sub to_string {
5548 my ( $self ) = @_;
5549
5550 return $self->{filename};
5551 }
5552
5553 1;
5554 package App::Ack::Filter::IsPathGroup;
5555
5556
5557 use strict;
5558 use warnings;
5559 BEGIN {
5560 our @ISA = 'App::Ack::Filter';
5561 }
5562
5563 sub new {
5564 my ( $class ) = @_;
5565
5566 return bless {
5567 data => {},
5568 }, $class;
5569 }
5570
5571 sub add {
5572 my ( $self, $filter ) = @_;
5573
5574 $self->{data}->{ $filter->{filename} } = 1;
5575
5576 return;
5577 }
5578
5579 sub filter {
5580 my ( $self, $file ) = @_;
5581
5582 return exists $self->{data}->{$file->name};
5583 }
5584
5585 sub inspect {
5586 my ( $self ) = @_;
5587
5588 return ref($self) . " - $self";
5589 }
5590
5591 sub to_string {
5592 my ( $self ) = @_;
5593
5594 return join(' ', keys %{$self->{data}});
5595 }
5596
5597 1;
5598 package App::Ack::Filter::Match;
5599
5600 use strict;
5601 use warnings;
5602 BEGIN {
5603 our @ISA = 'App::Ack::Filter';
5604 }
5605
5606
5607
5608 sub new {
5609 my ( $class, $re ) = @_;
5610
5611 $re =~ s{^/|/$}{}g; # XXX validate?
5612 $re = qr/$re/i;
5613
5614 return bless {
5615 regex => $re,
5616 groupname => 'MatchGroup',
5617 }, $class;
5618 }
5619
5620 sub create_group {
5621 return App::Ack::Filter::MatchGroup->new;
5622 }
5623
5624 sub filter {
5625 my ( $self, $file ) = @_;
5626
5627 return $file->basename =~ /$self->{regex}/;
5628 }
5629
5630 sub inspect {
5631 my ( $self ) = @_;
5632
5633 return ref($self) . ' - ' . $self->{regex};
5634 }
5635
5636 sub to_string {
5637 my ( $self ) = @_;
5638
5639 return "Filename matches $self->{regex}";
5640 }
5641
5642 BEGIN {
5643 App::Ack::Filter->register_filter(match => __PACKAGE__);
5644 }
5645
5646 1;
5647 package App::Ack::Filter::MatchGroup;
5648
5649
5650 use strict;
5651 use warnings;
5652 BEGIN {
5653 our @ISA = 'App::Ack::Filter';
5654 }
5655
5656 sub new {
5657 my ( $class ) = @_;
5658
5659 return bless {
5660 matches => [],
5661 big_re => undef,
5662 }, $class;
5663 }
5664
5665 sub add {
5666 my ( $self, $filter ) = @_;
5667
5668 push @{ $self->{matches} }, $filter->{regex};
5669
5670 my $re = join('|', map { "(?:$_)" } @{ $self->{matches} });
5671 $self->{big_re} = qr/$re/;
5672
5673 return;
5674 }
5675
5676 sub filter {
5677 my ( $self, $file ) = @_;
5678
5679 return $file->basename =~ /$self->{big_re}/;
5680 }
5681
5682 # This class has no inspect() or to_string() method.
5683 # It will just use the default one unless someone writes something useful.
5684
5685 1;
5686 package File::Next;
5687
5688 use strict;
5689 use warnings;
5690
5691
5692 our $VERSION = '1.18';
5693
5694
5695
5696 use File::Spec ();
5697
5698 our $name; # name of the current file
5699 our $dir; # dir of the current file
5700
5701 our %files_defaults;
5702 our %skip_dirs;
5703
5704 BEGIN {
5705 %files_defaults = (
5706 file_filter => undef,
5707 descend_filter => undef,
5708 error_handler => sub { CORE::die $_[0] },
5709 warning_handler => sub { CORE::warn @_ },
5710 sort_files => undef,
5711 follow_symlinks => 1,
5712 nul_separated => 0,
5713 );
5714 %skip_dirs = map {($_,1)} (File::Spec->curdir, File::Spec->updir);
5715 }
5716
5717
5718 sub files {
5719 die _bad_invocation() if @_ && defined($_[0]) && ($_[0] eq __PACKAGE__);
5720
5721 my ($parms,@queue) = _setup( \%files_defaults, @_ );
5722
5723 my $filter = $parms->{file_filter};
5724 return sub {
5725 while ( my $entry = shift @queue ) {
5726 my ( $dirname, $file, $fullpath, $is_dir, $is_file, $is_fifo ) = @{$entry};
5727 if ( $is_file || $is_fifo ) {
5728 if ( $filter ) {
5729 local $_ = $file;
5730 local $File::Next::dir = $dirname;
5731 local $File::Next::name = $fullpath;
5732 next if not $filter->();
5733 }
5734 return wantarray ? ($dirname,$file,$fullpath) : $fullpath;
5735 }
5736 if ( $is_dir ) {
5737 unshift( @queue, _candidate_files( $parms, $fullpath ) );
5738 }
5739 } # while
5740
5741 return;
5742 }; # iterator
5743 }
5744
5745
5746
5747
5748
5749
5750
5751 sub from_file {
5752 die _bad_invocation() if @_ && defined($_[0]) && ($_[0] eq __PACKAGE__);
5753
5754 my ($parms,@queue) = _setup( \%files_defaults, @_ );
5755 my $err = $parms->{error_handler};
5756 my $warn = $parms->{warning_handler};
5757
5758 my $filename = $queue[0]->[1];
5759
5760 if ( !defined($filename) ) {
5761 $err->( 'Must pass a filename to from_file()' );
5762 return undef;
5763 }
5764
5765 my $fh;
5766 if ( $filename eq '-' ) {
5767 $fh = \*STDIN;
5768 }
5769 else {
5770 if ( !open( $fh, '<', $filename ) ) {
5771 $err->( "Unable to open $filename: $!", $! + 0 );
5772 return undef;
5773 }
5774 }
5775
5776 my $filter = $parms->{file_filter};
5777 return sub {
5778 local $/ = $parms->{nul_separated} ? "\x00" : $/;
5779 while ( my $fullpath = <$fh> ) {
5780 chomp $fullpath;
5781 next unless $fullpath =~ /./;
5782 if ( not ( -f $fullpath || -p _ ) ) {
5783 $warn->( "$fullpath: No such file" );
5784 next;
5785 }
5786
5787 my ($volume,$dirname,$file) = File::Spec->splitpath( $fullpath );
5788 if ( $filter ) {
5789 local $_ = $file;
5790 local $File::Next::dir = $dirname;
5791 local $File::Next::name = $fullpath;
5792 next if not $filter->();
5793 }
5794 return wantarray ? ($dirname,$file,$fullpath) : $fullpath;
5795 } # while
5796 close $fh;
5797
5798 return;
5799 }; # iterator
5800 }
5801
5802 sub _bad_invocation {
5803 my $good = (caller(1))[3];
5804 my $bad = $good;
5805 $bad =~ s/(.+)::/$1->/;
5806 return "$good must not be invoked as $bad";
5807 }
5808
5809 sub sort_standard($$) { return $_[0]->[1] cmp $_[1]->[1] }
5810 sub sort_reverse($$) { return $_[1]->[1] cmp $_[0]->[1] }
5811
5812 sub reslash {
5813 my $path = shift;
5814
5815 my @parts = split( /\//, $path );
5816
5817 return $path if @parts < 2;
5818
5819 return File::Spec->catfile( @parts );
5820 }
5821
5822
5823
5824 sub _setup {
5825 my $defaults = shift;
5826 my $passed_parms = ref $_[0] eq 'HASH' ? {%{+shift}} : {}; # copy parm hash
5827
5828 my %passed_parms = %{$passed_parms};
5829
5830 my $parms = {};
5831 for my $key ( keys %{$defaults} ) {
5832 $parms->{$key} =
5833 exists $passed_parms{$key}
5834 ? delete $passed_parms{$key}
5835 : $defaults->{$key};
5836 }
5837
5838 # Any leftover keys are bogus
5839 for my $badkey ( sort keys %passed_parms ) {
5840 my $sub = (caller(1))[3];
5841 $parms->{error_handler}->( "Invalid option passed to $sub(): $badkey" );
5842 }
5843
5844 # If it's not a code ref, assume standard sort
5845 if ( $parms->{sort_files} && ( ref($parms->{sort_files}) ne 'CODE' ) ) {
5846 $parms->{sort_files} = \&sort_standard;
5847 }
5848 my @queue;
5849
5850 for ( @_ ) {
5851 my $start = reslash( $_ );
5852 my $is_dir = -d $start;
5853 my $is_file = -f _;
5854 my $is_fifo = (-p _) || ($start =~ m{^/dev/fd});
5855 push @queue,
5856 $is_dir
5857 ? [ $start, undef, $start, $is_dir, $is_file, $is_fifo ]
5858 : [ undef, $start, $start, $is_dir, $is_file, $is_fifo ];
5859 }
5860
5861 return ($parms,@queue);
5862 }
5863
5864
5865 sub _candidate_files {
5866 my $parms = shift;
5867 my $dirname = shift;
5868
5869 my $dh;
5870 if ( !opendir $dh, $dirname ) {
5871 $parms->{error_handler}->( "$dirname: $!", $! + 0 );
5872 return;
5873 }
5874
5875 my @newfiles;
5876 my $descend_filter = $parms->{descend_filter};
5877 my $follow_symlinks = $parms->{follow_symlinks};
5878
5879 for my $file ( grep { !exists $skip_dirs{$_} } readdir $dh ) {
5880 my $fullpath = File::Spec->catdir( $dirname, $file );
5881 if ( !$follow_symlinks ) {
5882 next if -l $fullpath;
5883 }
5884 else {
5885 stat($fullpath);
5886 }
5887 my $is_dir = -d _;
5888 my $is_file = -f _;
5889 my $is_fifo = (-p _) || ($fullpath =~ m{^/dev/fd});
5890
5891 # Only do directory checking if we have a descend_filter
5892 if ( $descend_filter ) {
5893 if ( $is_dir ) {
5894 local $File::Next::dir = $fullpath;
5895 local $_ = $file;
5896 next if not $descend_filter->();
5897 }
5898 }
5899 push @newfiles, [ $dirname, $file, $fullpath, $is_dir, $is_file, $is_fifo ];
5900 }
5901 closedir $dh;
5902
5903 my $sort_sub = $parms->{sort_files};
5904 if ( $sort_sub ) {
5905 @newfiles = sort $sort_sub @newfiles;
5906 }
5907
5908 return @newfiles;
5909 }
5910
5911
5912
5913 1; # End of File::Next