File Coverage

blib/lib/App/Ack.pm
Criterion Covered Total %
statement 12 142 8.4
branch 0 28 0.0
condition 0 2 0.0
subroutine 5 30 16.6
pod 10 20 50.0
total 27 222 12.1


line stmt bran cond sub pod time code
1             package App::Ack;
2              
3 2     2   113891 use warnings;
  2         11  
  2         56  
4 2     2   12 use strict;
  2         2  
  2         102  
5              
6             =head1 NAME
7              
8             App::Ack
9              
10             =head1 DESCRIPTION
11              
12             A container for functions for the ack program.
13              
14             =cut
15              
16             our $VERSION;
17             our $COPYRIGHT;
18             BEGIN {
19 2     2   5 $VERSION = 'v3.6.0'; # Check https://beyondgrep.com/ for updates
20 2         84 $COPYRIGHT = 'Copyright 2005-2022 Andy Lester.';
21             }
22             our $STANDALONE = 0;
23             our $ORIGINAL_PROGRAM_NAME;
24              
25             our $fh;
26              
27             BEGIN {
28 2     2   231 $fh = *STDOUT;
29             }
30              
31              
32             our %types;
33             our %type_wanted;
34             our %mappings;
35             our %ignore_dirs;
36              
37             our $is_filter_mode;
38             our $output_to_pipe;
39              
40             our $is_windows;
41              
42             our $debug_nopens = 0;
43              
44             # Line ending, changes to "\0" if --print0.
45             our $ors = "\n";
46              
47             BEGIN {
48             # These have to be checked before any filehandle diddling.
49 2     2   19 $output_to_pipe = not -t *STDOUT;
50 2         18 $is_filter_mode = -p STDIN;
51              
52 2         3575 $is_windows = ($^O eq 'MSWin32');
53             }
54              
55             =head1 SYNOPSIS
56              
57             If you want to know about the F program, see the F file itself.
58              
59             No user-serviceable parts inside. F is all that should use this.
60              
61             =head1 FUNCTIONS
62              
63             =head2 warn( @_ )
64              
65             Put out an ack-specific warning.
66              
67             =cut
68              
69             sub warn {
70 0     0 1   return CORE::warn( _my_program(), ': ', @_, "\n" );
71             }
72              
73             =head2 die( @msgs )
74              
75             Die in an ack-specific way.
76              
77             =cut
78              
79             sub die {
80 0     0 1   return CORE::die( _my_program(), ': ', @_, "\n" );
81             }
82              
83             sub _my_program {
84 0     0     require File::Basename;
85 0           return File::Basename::basename( $0 );
86             }
87              
88              
89             sub thpppt {
90 0     0 0   my $y = q{_ /|,\\'!.x',=(www)=, U };
91 0           $y =~ tr/,x!w/\nOo_/;
92              
93 0           App::Ack::print( "$y ack $_[0]!\n" );
94 0           exit 0;
95             }
96              
97             sub ackbar {
98 0     0 0   my $x;
99 0           $x = <<'_BAR';
100             6?!I'7!I"?%+!
101             3~!I#7#I"7#I!?!+!="+"="+!:!
102             2?#I!7!I!?#I!7!I"+"=%+"=#
103             1?"+!?*+!=#~"=!+#?"="+!
104             0?"+!?"I"?&+!="~!=!~"=!+%="+"
105             /I!+!?)+!?!+!=$~!=!~!="+!="+"?!="?!
106             .?%I"?%+%='?!=#~$="
107             ,,!?%I"?(+$=$~!=#:"~$:!~!
108             ,I!?!I!?"I"?!+#?"+!?!+#="~$:!~!:!~!:!,!:!,":#~!
109             +I!?&+!="+!?#+$=!~":!~!:!~!:!,!:#,!:!,%:"
110             *+!I!?!+$=!+!=!+!?$+#=!~":!~":#,$:",#:!,!:!
111             *I!?"+!?!+!=$+!?#+#=#~":$,!:",!:!,&:"
112             )I!?$=!~!=#+"?!+!=!+!=!~!="~!:!~":!,'.!,%:!~!
113             (=!?"+!?!=!~$?"+!?!+!=#~"=",!="~$,$.",#.!:!=!
114             (I"+"="~"=!+&=!~"=!~!,!~!+!=!?!+!?!=!I!?!+"=!.",!.!,":!
115             %I$?!+!?!=%+!~!+#~!=!~#:#=!~!+!~!=#:!,%.!,!.!:"
116             $I!?!=!?!I!+!?"+!=!~!=!~!?!I!?!=!+!=!~#:",!~"=!~!:"~!=!:",&:" '-/
117             $?!+!I!?"+"=!+"~!,!:"+#~#:#,"=!~"=!,!~!,!.",!:".!:! */! !I!t!'!s! !a! !g!r!e!p!!! !/!
118             $+"=!+!?!+"~!=!:!~!:"I!+!,!~!=!:!~!,!:!,$:!~".&:"~!,# (-/
119             %~!=!~!=!:!.!+"~!:!,!.!,!~!=!:$.!,":!,!.!:!~!,!:!=!.#="~!,!:" ./!
120             %=!~!?!+"?"+!=!~",!.!:!?!~!.!:!,!:!,#.!,!:","~!:!=!~!=!:",!~! ./!
121             %+"~":!~!=#~!:!~!,!.!~!:",!~!=!~!.!:!,!.",!:!,":!=":!.!,!:!7! -/!
122             %~",!:".#:!=!:!,!:"+!:!~!:!.!,!~!,!.#,!.!,$:"~!,":"~!=! */!
123             &=!~!=#+!=!~",!.!:",#:#,!.",+:!,!.",!=!+!?!
124             &~!=!~!=!~!:"~#:",!.!,#~!:!.!+!,!.",$.",$.#,!+!I!?!
125             &~!="~!:!~":!~",!~!=!~":!,!:!~!,!:!,&.$,#."+!?!I!?!I!
126             &~!=!~!=!+!,!:!~!:!=!,!:!~&:$,!.!,".!,".!,#."~!+!?$I!
127             &~!=!~!="~!=!:!~":!,!~%:#,!:",!.!,#.",#I!7"I!?!+!?"I"
128             &+!I!7!:#~"=!~!:!,!:"~$.!=!.!,!~!,$.#,!~!7!I#?!+!?"I"7!
129             %7#?!+!~!:!=!~!=!~":!,!:"~":#.!,)7#I"?"I!7&
130             %7#I!=":!=!~!:"~$:"~!:#,!:!,!:!~!:#,!7#I!?#7)
131             $7$+!,!~!=#~!:!~!:!~$:#,!.!~!:!=!,":!7#I"?#7+=!?!
132             $7#I!~!,!~#=!~!:"~!:!,!:!,#:!=!~",":!7$I!?#I!7*+!=!+"
133             "I!7$I!,":!,!.!=":$,!:!,$:$7$I!+!?"I!7+?"I!7!I!7!,!
134             !,!7%I!:",!."~":!,&.!,!:!~!I!7$I!+!?"I!7,?!I!7',!
135             !7(,!.#~":!,%.!,!7%I!7!?#I"7,+!?!7*
136             7+:!,!~#,"=!7'I!?#I"7/+!7+
137             77I!+!7!?!7!I"71+!7,
138             _BAR
139              
140 0           return _pic_decode($x);
141             }
142              
143             sub cathy {
144 0     0 0   my $x = <<'CATHY';
145             0+!--+!
146             0|! "C!H!O!C!O!L!A!T!E!!! !|!
147             0|! "C!H!O!C!O!L!A!T!E!!! !|!
148             0|! "C!H!O!C!O!L!A!T!E!!! !|!
149             0|! $A"C!K!!! $|!
150             0+!--+!
151             6\! 1:!,!.! !
152             7\! /.!M!~!Z!M!~!
153             8\! /~!D! "M! !
154             4.! $\! /M!~!.!8! +.!M# 4
155             0,!.! (\! .~!M!N! ,+!I!.!M!.! 3
156             /?!O!.!M!:! '\! .O!.! +~!Z!=!N!.! 4
157             ..! !D!Z!.!Z!.! '\! 9=!M".! 6
158             /.! !.!~!M".! '\! 8~! 9
159             4M!.! /.!7!N!M!.! F
160             4.! &:!M! !N"M# !M"N!M! #D!M&=! =
161             :M!7!M#:! !~!M!7!,!$!M!:! #.! !O!N!.!M!:!M# ;
162             8Z!M"~!N!$!D!.!N!?! !I!N!.! (?!M! !M!,!D!M".! 9
163             (?!Z!M!N!:! )=!M!O!8!.!M!+!M! !M!,! !O!M! +,!M!.!M!~!Z!N!M!:! &:!~! 0
164             &8!7!.!~!M"D!M!,! &M!?!=!8! !M!,!O! !M!+! !+!O!.!M! $M#~! !.!8!M!Z!.!M! !O!M"Z! %:!~!M!Z!M!Z!.! +
165             &:!M!7!,! *M!.!Z!M! !8"M!.!M!~! !.!M!.!=! #~!8!.!M! !7!M! "N!Z#I! !D!M!,!M!.! $."M!,! !M!.! *
166             2$!O! "N! !.!M!I! !7" "M! "+!O! !~!M! !d!O!.!7!I!M!.! !.!O!=!M!.! !M",!M!.! %.!$!O!D! +
167             1~!O! "M!+! !8!$! "M! "?!O! %Z!8!D!M!?!8!I!O!7!M! #M!.!M! "M",!M! 4
168             07!~! ".!8! !.!M! "I!+! !.!M! &Z!D!.!7!=!M! !:!.!M! #:!8"+! !.!+!8! !8! 3
169             /~!M! #N! !~!M!$! !.!M! !.!M" &~!M! "~!M!O! "D! $M! !8! "M!,!M!+!D!.! 1
170             #.! #?!M!N!.! #~!O! $M!.!7!$! "?" !?!~!M! '7!8!?!M!.!+!M"O! $?"$!D! !.!O! !$!7!I!.! 0
171             $,!M!:!O!?! ".! !?!=! $=!:!O! !M! "M! !M! !+!$! (.! +.!M! !M!.! !8! !+"Z!~! $:!M!$! !.! '
172             #.!8!.!I!$! $7!I! %M" !=!M! !~!M!D! "7!I! .I!O! %?!=!,!D! !,!M! !D!~!8!~! %D!M! (
173             #.!M"?! $=!O! %=!N! "8!.! !Z!M! #M!~! (M!:! #.!M" &O! !M!.! !?!,! !8!.!N!~! $8!N!M!,!.! %
174             *$!O! &M!,! "O! !.!M!.! #M! (~!M( &O!.! !7! "M! !.!M!.!M!,! #.!M! !M! &
175             )=!8!.! $.!M!O!.! "$!.!I!N! !I!M# (7!M(I! %D"Z!M! "=!I! "M! !M!:! #~!D! '
176             )D! &8!N!:! ".!O! !M!="M! "M! (7!M) %." !M!D!."M!.! !$!=! !M!,! +
177             (M! &+!.!M! #Z!7!O!M!.!~!8! +,!M#D!?!M#D! #.!Z!M#,!Z!?! !~!N! "N!.! !M! +
178             'D!:! %$!D! !?! #M!Z! !8!.! !M"?!7!?!7! '+!I!D! !?!O!:!M!:! ":!M!:! !M!7".!M! "8!+! !:!D! !.!M! *
179             %.!O!:! $.!O!+! !D!.! #M! "M!.!+!N!I!Z! "7!M!N!M!N!?!I!7!Z!=!M'D"~! #M!.!8!$! !:! !.!M! "N!?! !,!O! )
180             !.!?!M!:!M!I! %8!,! "M!.! #M! "N! !M!.! !M!.! !+!~! !.!M!.! ':!M! $M! $M!Z!$! !M!.! "D! "M! "?!M! (
181             !7!8! !+!I! ".! "$!=! ":!$! "+! !M!.! !O! !M!I!M".! !=!~! ",!O! '=!M! $$!,! #N!:! ":!8!.! !D!~! !,!M!.! !:!M!.! &
182             !:!,!.! &Z" #D! !.!8!."M!.! !8!?!Z!M!.!M! #Z!~! !?!M!Z!.! %~!O!.!8!$!N!8!O!I!:!~! !+! #M!.! !.!M!.! !+!M! ".!~!M!+! $
183             !.! 'D!I! #?!M!.!M!,! !.!Z! !.!8! #M&O!I!?! (~!I!M"." !M!Z!.! !M!N!.! "+!$!.! "M!.! !M!?!.! "8!M! $
184             (O!8! $M! !M!.! ".!:! !+!=! #M! #.!M! !+" *$!M":!.! !M!~! "M!7! #M! #7!Z! "M"$!M!.! !.! #
185             '$!Z! #.!7!+!M! $.!,! !+!:! #N! #.!M!.!+!M! +D!M! #=!N! ":!O! #=!M! #Z!D! $M!I! %
186             $,! ".! $.!M" %$!.! !?!~! "+!7!." !.!M!,! !M! *,!N!M!.$M!?! "D!,! #M!.! #N! +
187             ,M!Z! &M! "I!,! "M! %I!M! !?!=!.! (Z!8!M! $:!M!.! !,!M! $D! #.!M!.! )
188             +8!O! &.!8! "I!,! !~!M! &N!M! !M!D! '?!N!O!." $?!7! "?!~! #M!.! #I!D!.! (
189             3M!,! "N!.! !D" &.!+!M!.! !M":!.":!M!7!M!D! 'M!.! "M!.! "M!,! $I! )
190             3I! #M! "M!,! !:! &.!M" ".!,! !.!$!M!I! #.! !:! !.!M!?! "N!+! ".! /
191             1M!,! #.!M!8!M!=!.! +~!N"O!Z"~! *+!M!.! "M! 2
192             0.!M! &M!.! 8:! %.!M!Z! "M!=! *O!,! %
193             0?!$! &N! )." .,! %."M! ":!M!.! 0
194             0N!:! %?!O! #.! ..! &,! &.!D!,! "N!I! 0
195             CATHY
196 0           return _pic_decode($x);
197             }
198              
199             sub _pic_decode {
200 0     0     my($compressed) = @_;
201 0           $compressed =~ s/(.)(.)/$1x(ord($2)-32)/eg;
  0            
202 0           App::Ack::print( $compressed );
203 0           exit 0;
204             }
205              
206             =head2 show_help()
207              
208             Dumps the help page to the user.
209              
210             =cut
211              
212             sub show_help {
213 0     0 1   App::Ack::print( <<"END_OF_HELP" );
214             Usage: ack [OPTION]... PATTERN [FILES OR DIRECTORIES]
215              
216             Search for PATTERN in each source file in the tree from the current
217             directory on down. If any files or directories are specified, then
218             only those files and directories are checked. ack may also search
219             STDIN, but only if no file or directory arguments are specified,
220             or if one of them is "-".
221              
222             Default switches may be specified in an .ackrc file. If you want no dependency
223             on the environment, turn it off with --noenv.
224              
225             File select actions:
226             -f Only print the files selected, without
227             searching. The PATTERN must not be specified.
228             -g Same as -f, but only select files matching
229             PATTERN.
230              
231             File listing actions:
232             -l, --files-with-matches Print filenames with at least one match
233             -L, --files-without-matches Print filenames with no matches
234             -c, --count Print filenames and count of matching lines
235              
236             Searching:
237             -i, --ignore-case Ignore case distinctions in PATTERN
238             -S, --[no]smart-case Ignore case distinctions in PATTERN,
239             only if PATTERN contains no upper case.
240             Ignored if -i or -I are specified.
241             -I, --no-ignore-case Turns on case-sensitivity in PATTERN.
242             Negates -i and --smart-case.
243             -v, --invert-match Invert match: select non-matching lines
244             -w, --word-regexp Force PATTERN to match only whole words
245             -Q, --literal Quote all metacharacters; PATTERN is literal
246             --range-start PATTERN Specify PATTERN as the start of a match range.
247             --range-end PATTERN Specify PATTERN as the end of a match range.
248             --match PATTERN Specify PATTERN explicitly. Typically omitted.
249              
250             Search output:
251             --output=expr Output the evaluation of expr for each line
252             (turns off text highlighting)
253             -o Show only the part of a line matching PATTERN
254             Same as --output='\$&'
255             --passthru Print all lines, whether matching or not
256             -m, --max-count=NUM Stop searching in each file after NUM matches
257             -1 Stop searching after one match of any kind
258             -H, --with-filename Print the filename for each match (default:
259             on unless explicitly searching a single file)
260             -h, --no-filename Suppress the prefixing filename on output
261             --[no]column Show the column number of the first match
262              
263             -A NUM, --after-context=NUM Print NUM lines of trailing context after
264             matching lines.
265             -B NUM, --before-context=NUM Print NUM lines of leading context before
266             matching lines.
267             -C [NUM], --context[=NUM] Print NUM lines (default 2) of output context.
268              
269             --print0 Print null byte as separator between filenames,
270             only works with -f, -g, -l, -L or -c.
271              
272             -s Suppress error messages about nonexistent or
273             unreadable files.
274              
275              
276             File presentation:
277             --pager=COMMAND Pipes all ack output through COMMAND. For
278             example, --pager="less -R". Ignored if output
279             is redirected.
280             --nopager Do not send output through a pager. Cancels
281             any setting in ~/.ackrc, ACK_PAGER or
282             ACK_PAGER_COLOR.
283             --[no]heading Print a filename heading above each file's
284             results. (default: on when used interactively)
285             --[no]break Print a break between results from different
286             files. (default: on when used interactively)
287             --group Same as --heading --break
288             --nogroup Same as --noheading --nobreak
289             -p, --proximate=LINES Separate match output with blank lines unless
290             they are within LINES lines from each other.
291             -P, --proximate=0 Negates --proximate.
292             --[no]underline Print a line of carets under the matched text.
293             --[no]color, --[no]colour Highlight the matching text (default: on unless
294             output is redirected, or on Windows)
295             --color-filename=COLOR
296             --color-match=COLOR
297             --color-colno=COLOR
298             --color-lineno=COLOR Set the color for filenames, matches, line and
299             column numbers.
300             --help-colors Show a list of possible color combinations.
301             --help-rgb-colors Show a list of advanced RGB colors.
302             --flush Flush output immediately, even when ack is used
303             non-interactively (when output goes to a pipe or
304             file).
305              
306              
307             File finding:
308             --sort-files Sort the found files lexically.
309             --show-types Show which types each file has.
310             --files-from=FILE Read the list of files to search from FILE.
311             -x Read the list of files to search from STDIN.
312              
313             File inclusion/exclusion:
314             --[no]ignore-dir=name Add/remove directory from list of ignored dirs
315             --[no]ignore-directory=name Synonym for ignore-dir
316             --ignore-file=FILTER:ARGS Add filter for ignoring files.
317             -r, -R, --recurse Recurse into subdirectories (default: on)
318             -n, --no-recurse No descending into subdirectories
319             --[no]follow Follow symlinks. Default is off.
320              
321             File type inclusion/exclusion:
322             -t X, --type=X Include only X files, where X is a filetype,
323             e.g. python, html, markdown, etc
324             -T X, --type=noX Exclude X files, where X is a filetype.
325             -k, --known-types Include only files of types that ack recognizes.
326             --help-types Display all known types, and how they're defined.
327              
328             File type specification:
329             --type-set=TYPE:FILTER:ARGS Files with the given ARGS applied to the given
330             FILTER are recognized as being of type TYPE.
331             This replaces an existing definition for TYPE.
332             --type-add=TYPE:FILTER:ARGS Files with the given ARGS applied to the given
333             FILTER are recognized as being type TYPE.
334             --type-del=TYPE Removes all filters associated with TYPE.
335              
336             Miscellaneous:
337             --version Display version & copyright
338             --[no]env Ignore environment variables and global ackrc
339             files. --env is legal but redundant.
340             --ackrc=filename Specify an ackrc file to use
341             --ignore-ack-defaults Ignore default definitions included with ack.
342             --create-ackrc Outputs a default ackrc for your customization
343             to standard output.
344             --dump Dump information on which options are loaded
345             and where they're defined.
346             --[no]filter Force ack to treat standard input as a pipe
347             (--filter) or tty (--nofilter)
348             --help This help
349             --man Print the manual.
350             --help-types Display all known types, and how they're defined.
351             --help-colors Show a list of possible color combinations.
352             --help-rgb-colors Show a list of advanced RGB colors.
353             --thpppt Bill the Cat
354             --bar The warning admiral
355             --cathy Chocolate! Chocolate! Chocolate!
356              
357             Filter specifications:
358             If FILTER is "ext", ARGS is a list of extensions checked against the
359             file's extension.
360             If FILTER is "is", ARGS must match the file's name exactly.
361             If FILTER is "match", ARGS is matched as a case-insensitive regex
362             against the filename.
363             If FILTER is "firstlinematch", ARGS is matched as a regex the first
364             line of the file's contents.
365              
366             Exit status is 0 if match, 1 if no match.
367              
368             ack's home page is at https://beyondgrep.com/
369              
370             The full ack manual is available by running "ack --man".
371              
372             This is version $App::Ack::VERSION of ack. Run "ack --version" for full version info.
373             END_OF_HELP
374              
375 0           return;
376             }
377              
378              
379             =head2 show_help_types()
380              
381             Display the filetypes help subpage.
382              
383             =cut
384              
385             sub show_help_types {
386 0     0 1   App::Ack::print( <<'END_OF_HELP' );
387             Usage: ack [OPTION]... PATTERN [FILES OR DIRECTORIES]
388              
389             The following is the list of filetypes supported by ack. You can specify a
390             filetype to include with -t TYPE or --type=TYPE. You can exclude a
391             filetype with -T TYPE or --type=noTYPE.
392              
393             Note that some files may appear in multiple types. For example, a file
394             called Rakefile is both Ruby (--type=ruby) and Rakefile (--type=rakefile).
395              
396             END_OF_HELP
397              
398 0           my @types = keys %App::Ack::mappings;
399 0           my $maxlen = 0;
400 0           for ( @types ) {
401 0 0         $maxlen = length if $maxlen < length;
402             }
403 0           for my $type ( sort @types ) {
404 0 0         next if $type =~ /^-/; # Stuff to not show
405 0           my $ext_list = $mappings{$type};
406              
407 0 0         if ( ref $ext_list ) {
408 0           $ext_list = join( '; ', map { $_->to_string } @{$ext_list} );
  0            
  0            
409             }
410 0           App::Ack::print( sprintf( " %-*.*s %s\n", $maxlen, $maxlen, $type, $ext_list ) );
411             }
412              
413 0           return;
414             }
415              
416              
417             =head2 show_help_colors()
418              
419             Display the colors help subpage.
420              
421             =cut
422              
423             sub show_help_colors {
424 0     0 1   App::Ack::print( <<'END_OF_HELP' );
425             ack allows customization of the colors it uses when presenting matches
426             onscreen. See the "ACK COLORS" section of the ack manual (ack --man).
427              
428             Here is a chart of how various color combinations appear: Each of the eight
429             foreground colors, on each of the eight background colors or no background
430             color, with and without the bold modifier.
431              
432             Run ack --help-rgb-colors for a chart of the RGB colors.
433              
434             END_OF_HELP
435              
436 0           _show_color_grid();
437              
438 0           return;
439             }
440              
441              
442             =head2 show_help_rgb()
443              
444             Display the RGB help subpage.
445              
446             =cut
447              
448             sub show_help_rgb {
449 0     0 1   App::Ack::print( <<'END_OF_HELP' );
450             ack allows customization of the colors it uses when presenting matches
451             onscreen. See the "ACK COLORS" section of the ack manual (ack --man).
452              
453             Colors may be specified as "rgbNNN" where "NNN" is a triplet of digits
454             from 0 to 5 specifying the intensity of red, green and blue, respectively.
455              
456             Here is a grid of the 216 possible values for NNN.
457              
458             END_OF_HELP
459              
460 0           _show_rgb_grid();
461              
462 0           App::Ack::say( 'Here are the 216 possible colors with the "reverse" modifier applied.', "\n" );
463              
464 0           _show_rgb_grid( 'reverse' );
465              
466 0           return;
467             }
468              
469              
470             sub _show_color_grid {
471 0     0     my $cell_width = 7;
472              
473 0           my @fg_colors = qw( black red green yellow blue magenta cyan white );
474 0           my @bg_colors = map { "on_$_" } @fg_colors;
  0            
475              
476             App::Ack::say(
477             _color_cell( '' ),
478 0           map { _color_cell( $_ ) } @fg_colors
  0            
479             );
480              
481             App::Ack::say(
482             _color_cell( '' ),
483 0           map { _color_cell( '-' x $cell_width ) } @fg_colors
  0            
484             );
485              
486 0           for my $bg ( '', @bg_colors ) {
487             App::Ack::say(
488             _color_cell( '' ),
489 0           ( map { _color_cell( $_, "$_ $bg" ) } @fg_colors ),
  0            
490             $bg
491             );
492              
493             App::Ack::say(
494             _color_cell( 'bold' ),
495 0           ( map { _color_cell( $_, "bold $_ $bg" ) } @fg_colors ),
  0            
496             $bg
497             );
498 0           App::Ack::say();
499             }
500              
501 0           return;
502             }
503              
504              
505             sub _color_cell {
506 0     0     my $text = shift;
507 0           my $color = shift;
508              
509 0           my $cell_width = 7;
510 0           $text = sprintf( '%-*s', $cell_width, $text );
511              
512 0 0         return ($color ? Term::ANSIColor::colored( $text, $color ) : $text) . ' ';
513             }
514              
515              
516             sub _show_rgb_grid {
517 0   0 0     my $modifier = shift // '';
518              
519 0           my $grid = <<'HERE';
520             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
521             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
522             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
523             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
524             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
525             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
526             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
527             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
528              
529             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
530              
531             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
532              
533             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
534              
535             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
536              
537             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
538             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
539              
540             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
541              
542             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
543             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
544             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
545             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
546             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
547             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
548             HERE
549              
550 0           $grid =~ s/(\d\d\d)/Term::ANSIColor::colored( "$1", "$modifier rgb$1" )/eg;
  0            
551              
552 0           App::Ack::say( $grid );
553              
554 0           return;
555             }
556              
557              
558             sub show_man {
559 0     0 0   require Pod::Usage;
560 0           Pod::Usage::pod2usage({
561             -input => $App::Ack::ORIGINAL_PROGRAM_NAME,
562             -verbose => 2,
563             -exitval => 0,
564             });
565              
566 0           return;
567             }
568              
569              
570             =head2 get_version_statement
571              
572             Returns the version information for ack.
573              
574             =cut
575              
576             sub get_version_statement {
577 0     0 1   require Config;
578              
579 0           my $copyright = $App::Ack::COPYRIGHT;
580 0           my $this_perl = $Config::Config{perlpath};
581 0 0         if ($^O ne 'VMS') {
582 0           my $ext = $Config::Config{_exe};
583 0 0         $this_perl .= $ext unless $this_perl =~ m/$ext$/i;
584             }
585 0           my $perl_ver = sprintf( 'v%vd', $^V );
586              
587 0 0         my $build_type = $App::Ack::STANDALONE ? 'standalone version' : 'standard build';
588              
589 0           return <<"END_OF_VERSION";
590             ack $App::Ack::VERSION ($build_type)
591             Running under Perl $perl_ver at $this_perl
592              
593             $copyright
594              
595             This program is free software. You may modify or distribute it
596             under the terms of the Artistic License v2.0.
597             END_OF_VERSION
598             }
599              
600              
601 0     0 0   sub print { print {$fh} @_; return; }
  0            
  0            
602 0     0 0   sub say { print {$fh} @_, $ors; return; }
  0            
  0            
603 0     0 0   sub print_blank_line { print {$fh} "\n"; return; }
  0            
  0            
604              
605             sub set_up_pager {
606 0     0 0   my $command = shift;
607              
608 0 0         return if App::Ack::output_to_pipe();
609              
610 0           my $pager;
611 0 0         if ( not open( $pager, '|-', $command ) ) {
612 0           App::Ack::die( qq{Unable to pipe to pager "$command": $!} );
613             }
614 0           $fh = $pager;
615              
616 0           return;
617             }
618              
619             =head2 output_to_pipe()
620              
621             Returns true if ack's input is coming from a pipe.
622              
623             =cut
624              
625             sub output_to_pipe {
626 0     0 1   return $output_to_pipe;
627             }
628              
629             =head2 exit_from_ack( $nmatches )
630              
631             Exit from the application with the correct exit code.
632              
633             Returns with 0 if a match was found, otherwise with 1. The number of matches is
634             handed in as the only argument.
635              
636             =cut
637              
638             sub exit_from_ack {
639 0     0 1   my $nmatches = shift;
640              
641 0 0         my $rc = $nmatches ? 0 : 1;
642 0           exit $rc;
643             }
644              
645             =head2 show_types( $file )
646              
647             Shows the filetypes associated with a given file.
648              
649             =cut
650              
651             sub show_types {
652 0     0 1   my $file = shift;
653              
654 0           my @types = filetypes( $file );
655 0 0         my $arrow = @types ? ' => ' : ' =>';
656 0           App::Ack::say( $file->name, $arrow, join( ',', @types ) );
657              
658 0           return;
659             }
660              
661              
662             sub filetypes {
663 0     0 0   my ( $file ) = @_;
664              
665 0           my @matches;
666              
667 0           foreach my $k (keys %App::Ack::mappings) {
668 0           my $filters = $App::Ack::mappings{$k};
669              
670 0           foreach my $filter (@{$filters}) {
  0            
671             # Clone the file.
672 0           my $clone = $file->clone;
673 0 0         if ( $filter->filter($clone) ) {
674 0           push @matches, $k;
675 0           last;
676             }
677             }
678             }
679              
680             # https://metacpan.org/pod/distribution/Perl-Critic/lib/Perl/Critic/Policy/Subroutines/ProhibitReturnSort.pm
681 0           @matches = sort @matches;
682 0           return @matches;
683             }
684              
685              
686             sub is_lowercase {
687 0     0 0   my $pat = shift;
688              
689             # The simplest case.
690 0 0         return 1 if lc($pat) eq $pat;
691              
692             # If we have capitals, then go clean up any metacharacters that might have capitals.
693              
694             # Get rid of any literal backslashes first to avoid confusion.
695 0           $pat =~ s/\\\\//g;
696              
697 0           my $metacharacter = qr{
698             |\\A # Beginning of string
699             |\\B # Not word boundary
700             |\\c[a-zA-Z] # Control characters
701             |\\D # Non-digit character
702             |\\G # End-of-match position of prior match
703             |\\H # Not horizontal whitespace
704             |\\K # Keep to the left
705             |\\N(\{.+?\})? # Anything but \n, OR Unicode sequence
706             |\\[pP]\{.+?\} # Named property and negation
707             |\\[pP][A-Z] # Named property and negation, single-character shorthand
708             |\\R # Linebreak
709             |\\S # Non-space character
710             |\\V # Not vertical whitespace
711             |\\W # Non-word character
712             |\\X # ???
713             |\\x[0-9A-Fa-f]{2} # Hex sequence
714             |\\Z # End of string
715             }x;
716 0           $pat =~ s/$metacharacter//g;
717              
718 0           my $name = qr/[_A-Za-z][_A-Za-z0-9]*?/;
719             # Eliminate named captures.
720 0           $pat =~ s/\(\?'$name'//g;
721 0           $pat =~ s/\(\?<$name>//g;
722              
723             # Eliminate named backreferences.
724 0           $pat =~ s/\\k'$name'//g;
725 0           $pat =~ s/\\k<$name>//g;
726 0           $pat =~ s/\\k\{$name\}//g;
727              
728             # Now with those metacharacters and named things removed, now see if it's lowercase.
729 0 0         return 1 if lc($pat) eq $pat;
730              
731 0           return 0;
732             }
733              
734              
735             1; # End of App::Ack