File Coverage

blib/lib/App/highlight.pm
Criterion Covered Total %
statement 65 73 89.0
branch 25 28 89.2
condition 15 21 71.4
subroutine 9 9 100.0
pod 3 3 100.0
total 117 134 87.3


line stmt bran cond sub pod time code
1 10     10   566678 use strict;
  10         26  
  10         578  
2 10     10   57 use warnings;
  10         23  
  10         735  
3              
4             package App::highlight;
5             {
6             $App::highlight::VERSION = '0.14';
7             }
8 10     10   66 use base 'App::Cmd::Simple';
  10         17  
  10         9664  
9              
10 10     10   555527 use Try::Tiny;
  10         25  
  10         795  
11 10     10   10590 use Module::Load qw(load);
  10         14891  
  10         78  
12 10     10   10632 use Getopt::Long::Descriptive;
  10         361345  
  10         103  
13              
14             my $COLOR_SUPPORT = 1;
15             my @COLORS;
16              
17             my %COLOR_MODULES = (
18             'Term::ANSIColor' => [ 'color', 'colored' ],
19             );
20              
21             # windows support
22             if ($^O eq 'MSWin32') {
23             $COLOR_MODULES{'Win32::Console::ANSI'} = [];
24             }
25              
26             try {
27             for my $module (sort keys %COLOR_MODULES) {
28             load($module, @{ $COLOR_MODULES{$module} });
29             }
30              
31             @COLORS = map { [ color("bold $_"), color('reset') ] } (
32             qw(red green yellow blue magenta cyan)
33             );
34             }
35             catch {
36             $COLOR_SUPPORT = 0;
37             };
38              
39             my @NOCOLORS = (
40             [ '<<', '>>' ],
41             [ '[[', ']]' ],
42             [ '((', '))' ],
43             [ '{{', '}}' ],
44             [ '**', '**' ],
45             [ '__', '__' ],
46             );
47              
48             sub opt_spec {
49             return (
50             [
51 18     18 1 184254 one_of => [
52             [ 'color|c' => "use terminal color for highlighting (default)" ],
53             [ 'no-color|C' => "don't use terminal color" ],
54             ],
55             ],
56             [
57             one_of => [
58             [ 'escape|e' => "auto-escape input (default)" ],
59             [ 'no-escape|regex|n|r' => "don't auto-escape input (regex mode)" ],
60             ]
61             ],
62             [ 'ignore-case|i' => "ignore case for matches" ],
63             [ 'full-line|l' => "highlight the whole matched line" ],
64             [ 'one-color|o' => "use only one color for all matches" ],
65             [ 'show-bad-spaces|b' => "highlight spaces at the end of lines" ],
66             [ 'version|v' => "show version number" ],
67             [ 'help|h' => "display a usage message" ],
68             );
69             }
70              
71             sub validate_args {
72 17     17 1 49716 my ($self, $opt, $args) = @_;
73              
74 17 50       288 if ($opt->{'help'}) {
    100          
75 0         0 my ($opt, $usage) = describe_options(
76             $self->usage_desc(),
77             $self->opt_spec(),
78             );
79 0         0 print $usage;
80 0         0 print "\n";
81 0         0 print "For more detailed help see 'perldoc App::highlight'\n";
82 0         0 print "\n";
83 0         0 exit;
84             }
85             elsif ($opt->{'version'}) {
86 1         10 print $App::highlight::VERSION, "\n";
87 1         26 exit;
88             }
89              
90 16 50 66     87 if (!@$args && !$opt->{'show_bad_spaces'}) {
91 0         0 $self->usage_error(
92             "No arguments given!\n" .
93             "What do you want me to highlight?\n"
94             );
95             }
96              
97 16         49 return;
98             }
99              
100             sub execute {
101 16     16 1 624 my ($self, $opt, $args) = @_;
102              
103 16         29 my @matches;
104 16 100       56 if (scalar @$args) {
105 14 100 100     6199 if ($opt->{'escape'} || !$opt->{'no_escape'}) {
106 13         38 @$args = map { "\Q$_" } grep { defined } @$args;
  20         82  
  20         61  
107             }
108 14         47 @matches = @$args;
109             }
110              
111 16         30 my @HIGHLIGHTS;
112 16 100 66     128 if ($COLOR_SUPPORT &&
      66        
113             ($opt->{'color'} || !$opt->{'no_color'})) {
114 13         48 @HIGHLIGHTS = @COLORS;
115             }
116             else {
117 3         12 @HIGHLIGHTS = @NOCOLORS;
118             }
119              
120 16 100 66     69 if (!$COLOR_SUPPORT &&
      66        
121             ($opt->{'color'} || !$opt->{'no_color'})) {
122 1         3 my $mod_msg = join(' and ', sort keys %COLOR_MODULES);
123 1         11 warn "Color support disabled. Install $mod_msg to enable it.\n";
124             }
125              
126 16 100       121 if ($opt->{'one_color'}) {
127 1         3 @HIGHLIGHTS = ($HIGHLIGHTS[0]);
128             }
129              
130 16         36 my $ignore_case = '';
131 16 100       64 if ($opt->{'ignore_case'}) {
132 1 50       18 if ($^V lt v5.14.0) {
133 0         0 $ignore_case = '(?i)';
134             }
135             else {
136 1         2 $ignore_case = '(?^i)';
137             }
138             }
139              
140 16         702 while () {
141 174         3408 my $i = 0;
142 174         259 foreach my $m (@matches) {
143 249 100       437 if ($opt->{'full_line'}) {
144 13 100       822 if (m/${ignore_case}$m/) {
145 5         27 s/^/$HIGHLIGHTS[$i][0]/;
146 5         23 s/$/$HIGHLIGHTS[$i][1]/;
147             }
148             }
149             else {
150 236         1718 s/(${ignore_case}$m)/$HIGHLIGHTS[$i][0] . $1 . $HIGHLIGHTS[$i][1]/ge;
  66         275  
151             }
152              
153 249         337 $i++;
154 249         799 $i %= @HIGHLIGHTS;
155             }
156              
157 174 100       409 if ($opt->{'show_bad_spaces'}) {
158 16 100 66     69 if ($opt->{'color'} || !$opt->{'no_color'}) {
159 8         63 s{(\s+)(?=$/)$}{colored($1, "white on_red")}e;
  2         8  
160             #s{(\s+)(?=$/)$}{"[start-red]" . $1 . "[end-red]"}e;
161             }
162             else {
163 8         61 s{(\s+)(?=$/)$}{"X" x length($1)}e;
  2         36  
164             }
165             }
166              
167 174         633 print;
168             }
169              
170 16         755 return;
171             }
172              
173             1;
174              
175             __END__