File Coverage

blib/lib/App/Ack.pm
Criterion Covered Total %
statement 28 142 19.7
branch 4 28 14.2
condition 0 2 0.0
subroutine 8 30 26.6
pod 10 20 50.0
total 50 222 22.5


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