File Coverage

blib/lib/File/CodeSearch/Highlighter.pm
Criterion Covered Total %
statement 71 71 100.0
branch 25 28 89.2
condition 3 3 100.0
subroutine 9 9 100.0
pod 2 2 100.0
total 110 113 97.3


line stmt bran cond sub pod time code
1             package File::CodeSearch::Highlighter;
2              
3             # Created on: 2009-08-07 18:42:16
4             # Create by: Ivan Wills
5             # $Id$
6             # $Revision$, $HeadURL$, $Date$
7             # $Revision$, $Source$, $Date$
8              
9 4     4   54940 use Moose;
  4         782903  
  4         26  
10 4     4   23053 use warnings;
  4         6  
  4         114  
11 4     4   1241 use version;
  4         2943  
  4         23  
12 4     4   222 use Carp;
  4         6  
  4         294  
13 4     4   930 use English qw/ -no_match_vars /;
  4         7810  
  4         24  
14 4     4   2085 use Term::ANSIColor qw/:constants/;
  4         5550  
  4         1344  
15 4     4   2269 use Term::Size::Any;
  4         959  
  4         24  
16              
17             our $VERSION = version->new('0.7.4');
18              
19             extends 'File::CodeSearch::RegexBuilder';
20              
21             has highlight_re => (
22             is => 'rw',
23             );
24             has before_match => (
25             is => 'rw',
26             isa => 'Str',
27             default => BOLD . RED,
28             );
29             has after_match => (
30             is => 'rw',
31             isa => 'Str',
32             default => RESET,
33             );
34             has before_nomatch => (
35             is => 'rw',
36             isa => 'Str',
37             default => CYAN,
38             );
39             has after_nomatch => (
40             is => 'rw',
41             isa => 'Str',
42             default => RESET,
43             );
44             has before_snip => (
45             is => 'rw',
46             isa => 'Str',
47             default => RESET . RED . ON_BLACK,
48             );
49             has after_snip => (
50             is => 'rw',
51             isa => 'Str',
52             default => RESET,
53             );
54             has limit => (
55             is => 'rw',
56             isa => 'Int',
57             default => sub {
58             my ($cols, $rows) = Term::Size::Any::chars;
59             return $cols || 212;
60             }
61             );
62             has snip => (
63             is => 'rw',
64             isa => 'Bool',
65             default => 1,
66             );
67              
68             sub make_highlight_re {
69 19     19 1 7778 my ($self) = @_;
70              
71 19 100       738 return $self->highlight_re if $self->highlight_re;
72              
73 13         49 my $re = $self->make_regex;
74              
75             # make sure that all brackets are for non capture groups
76 13         43 $re =~ s/ (?<! \\ | \[ ) [(] (?! [?] ) /(?:/gxms;
77              
78 13         381 return $self->highlight_re($re);
79             }
80              
81             sub highlight {
82 9     9 1 7675 my ($self, $string) = @_;
83 9         19 my $re = $self->make_highlight_re;
84 9         12 my $out = '';
85              
86 9         65 my @parts = split /($re)/, $string;
87              
88 9         10 my $match_length = 0;
89 9         27 for my $i ( 0 .. @parts - 1 ) {
90 35 100       56 if ( $i % 2 ) {
91 13         21 $match_length += length $parts[$i];
92             }
93             }
94              
95             # 5 is the magic number of characters used to show the line number
96 9         261 my $limit = $self->limit - $match_length - 5;
97 9         21 my $joins = @parts - ( @parts - 1 ) / 2;
98 9         17 my $chars = ( $limit / $joins ) / 2 - 2;
99 9         12 my $chars_front = int $chars;
100 9         9 my $chars_back = int $chars;
101 9         16 my $total = $joins * ( $chars_front + $chars_back + 3 ) + 1;
102 9 100       18 if (length $parts[-1] < $chars * 2) {
103 5         6 $total -= $chars_front + $chars_back - length $parts[-1];
104             }
105              
106 9 100       16 my $inc = $limit - $total > $joins * 2 ? 1 : 0;
107 9         6 $chars += $inc;
108 9         9 $chars_front = int $chars;
109 9         40 $chars_back = int $chars;
110 9         13 $total = $joins * ( $chars_front + $chars_back + 3 ) + 1;
111 9 100       15 if (length $parts[-1] < $chars * 2) {
112 5         6 $total -= $chars_front + $chars_back - length $parts[-1];
113             }
114             #warn "match = $match_length\nchars = $chars\nlimit = $limit ($total)\nparts = " . (scalar @parts) . "\njoins = $joins\n";
115              
116 9         14 for my $i ( 0 .. @parts - 1 ) {
117 35 100       46 if ( $i % 2 ) {
118 13         338 $out .= $self->before_match . $parts[$i] . $self->after_match;
119             }
120             else {
121 22         23 my $part = $parts[$i];
122 22 100 100     567 if ($self->snip && length $string > $self->limit) {
123 7         6 my $chars_front_tmp = $chars_front;
124 7         7 my $chars_back_tmp = $chars_back;
125 7 100       9 if ($total < $limit) {
126 1         2 $chars_front_tmp++;
127 1         1 $total++;
128             }
129 7 100       13 if ($total < $limit) {
130 1         1 $chars_back_tmp++;
131 1         1 $total++;
132             }
133              
134             # Check if
135 7 50       12 if ($chars_front_tmp + $chars_back_tmp < length $parts[$i]) {
136 7         44 my ($front) = $parts[$i] =~ /\A (.{$chars_front_tmp}) /xms;
137 7         25 my ($back) = $parts[$i] =~ / (.{$chars_back_tmp}) \Z/xms;
138 7 50       193 $part = (defined $front ? $front : '') . $self->before_snip . '...' . $self->after_snip . $self->before_nomatch . (defined $back ? $back : '');
    50          
139             }
140             }
141 22         573 $out .= $self->before_nomatch . $part . $self->after_nomatch;
142             }
143             }
144              
145 9         129 $out .= RESET;
146 9 100       79 $out .= "\\N" if $string !~ /\n/xms;
147 9 100       19 $out .= "\n" if $out !~ /\n/xms;
148              
149 9         133 return $out;
150             }
151              
152             1;
153              
154             __END__
155              
156             =head1 NAME
157              
158             File::CodeSearch::Highlighter - Highlights matched parts of a line.
159              
160             =head1 VERSION
161              
162             This documentation refers to File::CodeSearch::Highlighter version 0.7.4.
163              
164              
165             =head1 SYNOPSIS
166              
167             use File::CodeSearch::Highlighter;
168              
169             # Brief but working code example(s) here showing the most common usage(s)
170             # This section will be as far as many users bother reading, so make it as
171             # educational and exemplary as possible.
172              
173              
174             =head1 DESCRIPTION
175              
176             =head1 ATTRIBUTES
177              
178             =over 4
179              
180             =item C<highlight_re>
181              
182             The regular expression used to find what to highlight
183              
184             =item C<before_match (Str, BOLD RED)>
185              
186             A string put before a match
187              
188             =item C<after_match (Str RESET)>
189              
190             A string put after a match
191              
192             =item C<before_nomatch (Str, CYAN)>
193              
194             A string for before text that doesn't match
195              
196             =item C<after_nomatch (Str, RESET)>
197              
198             A string for after text that doesn't match
199              
200             =item C<before_snip (Str, RESET . RED . ON_BLACK)>
201              
202             A string for before snipped out text.
203              
204             =item C<after_snip (Str, RESET)>
205              
206             A string for after snipped out text.
207              
208             =item C<limit (Int, columns in terminal)>
209              
210             The size of the limit for line length of text that is extremely long.
211              
212             =item C<snip (Bool, 1)>
213              
214             Cut out non-matching text so that one line of text matches on line of output
215              
216             =back
217              
218             =head1 SUBROUTINES/METHODS
219              
220             =head3 C<highlight ( $search, )>
221              
222             Param: C<$search> - type (detail) - description
223              
224             Return: File::CodeSearch::Highlighter -
225              
226             Description:
227              
228             =head3 C<make_highlight_re ( $search, )>
229              
230             =head1 DIAGNOSTICS
231              
232             =head1 CONFIGURATION AND ENVIRONMENT
233              
234             =head1 DEPENDENCIES
235              
236             =head1 INCOMPATIBILITIES
237              
238             =head1 BUGS AND LIMITATIONS
239              
240             There are no known bugs in this module.
241              
242             Please report problems to Ivan Wills (ivan.wills@gmail.com).
243              
244             Patches are welcome.
245              
246             =head1 AUTHOR
247              
248             Ivan Wills - (ivan.wills@gmail.com)
249              
250             =head1 LICENSE AND COPYRIGHT
251              
252             Copyright (c) 2009 Ivan Wills (14 Mullion Close, Hornsby Heights, NSW Australia 2077).
253             All rights reserved.
254              
255             This module is free software; you can redistribute it and/or modify it under
256             the same terms as Perl itself. See L<perlartistic>. This program is
257             distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
258             without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
259             PARTICULAR PURPOSE.
260              
261             =cut