File Coverage

blib/lib/DB/Color/Highlight.pm
Criterion Covered Total %
statement 80 104 76.9
branch 10 28 35.7
condition 1 3 33.3
subroutine 22 23 95.6
pod 0 2 0.0
total 113 160 70.6


line stmt bran cond sub pod time code
1             package DB::Color::Highlight;
2              
3 2     2   20597 use strict;
  2         5  
  2         70  
4 2     2   10 use warnings;
  2         3  
  2         59  
5 2     2   1964890 use Term::ANSIColor ':constants';
  2         25315  
  2         2109  
6 2     2   23 use Digest::MD5 'md5_hex';
  2         4  
  2         113  
7 2     2   1973 use File::Spec::Functions qw(catfile catdir);
  2         1833  
  2         155  
8 2     2   13 use File::Path 'make_path';
  2         3  
  2         146  
9              
10             BEGIN {
11 2 50   2   82 if ( !( Term::ANSIColor->VERSION >= 3 ) ) {
12 2     2   10 no warnings 'redefine';
  2         3  
  2         190  
13 0         0 *BRIGHT_BLUE = sub { BLUE };
  0         0  
14             }
15             }
16              
17 2     2   2790 use Syntax::Highlight::Engine::Kate::Perl;
  2         54957  
  2         136  
18              
19             =head1 NAME
20              
21             DB::Color::Highlight - Provides highlighting for DB::Color
22              
23             =head1 VERSION
24              
25             Version 0.10
26              
27             =cut
28              
29             our $VERSION = '0.10';
30              
31             # increase this number by one to force the cache to generate new md5 numbers
32             my $FORMAT_NUMBER = 1;
33              
34             BEGIN {
35 2     2   27 no warnings 'redefine';
  2         4  
  2         134  
36 2     2   2067 *Syntax::Highlight::Engine::Kate::Template::logwarning = sub { };
  54     54   14930259  
37             }
38              
39             sub new {
40 2     2 0 1232 my ( $class, $args ) = @_;
41 2         8 my $self = bless {} => $class;
42 2         11 $self->_initialize($args);
43 2         13 return $self;
44             }
45              
46             sub _initialize {
47 2     2   4 my ( $self, $args ) = @_;
48              
49 2         6 my $cache_dir = $args->{cache_dir};
50 2         16 $self->{debug_fh} = $args->{debug_fh};
51 2         5 $self->{cache_dir} = $cache_dir;
52              
53 2 50 33     61 if ( defined $cache_dir and not -d $cache_dir ) {
54 0 0       0 mkdir $cache_dir or die "Cannot mkdir ($cache_dir): $!";
55             }
56              
57             # CLEAR RESET BOLD DARK
58             # FAINT ITALIC UNDERLINE UNDERSCORE
59             # BLINK REVERSE CONCEALED
60             #
61             # BLACK RED GREEN YELLOW
62             # BLUE MAGENTA CYAN WHITE
63             # BRIGHT_BLACK BRIGHT_RED BRIGHT_GREEN BRIGHT_YELLOW
64             # BRIGHT_BLUE BRIGHT_MAGENTA BRIGHT_CYAN BRIGHT_WHITE
65             #
66             # ON_BLACK ON_RED ON_GREEN ON_YELLOW
67             # ON_BLUE ON_MAGENTA ON_CYAN ON_WHITE
68             # ON_BRIGHT_BLACK ON_BRIGHT_RED ON_BRIGHT_GREEN ON_BRIGHT_YELLOW
69             # ON_BRIGHT_BLUE ON_BRIGHT_MAGENTA ON_BRIGHT_CYAN ON_BRIGHT_WHITE
70              
71 2         26 my $highlighter = Syntax::Highlight::Engine::Kate::Perl->new(
72             format_table => {
73             'Keyword' => [ YELLOW, RESET ],
74             'Comment' => [ BRIGHT_BLUE, RESET ],
75             'Decimal' => [ YELLOW, RESET ],
76             'Float' => [ YELLOW, RESET ],
77             'Function' => [ CYAN, RESET ],
78             'Identifier' => [ RED, RESET ],
79             'Normal' => [ WHITE, RESET ],
80             'Operator' => [ CYAN, RESET ],
81             'Preprocessor' => [ RED, RESET ],
82             'String' => [ MAGENTA, RESET ],
83             'String Char' => [ RED, RESET ],
84             'Symbol' => [ CYAN, RESET ],
85             'DataType' => [ CYAN, RESET ], # variable names
86             }
87             );
88 2         5581 $self->{highlighter} = $highlighter;
89             }
90              
91 1     1   25 sub _highlighter { $_[0]->{highlighter} }
92 4     4   21 sub _cache_dir { $_[0]->{cache_dir} }
93 2     2   6 sub _should_cache { defined $_[0]->_cache_dir }
94              
95             sub _debug {
96 2     2   4 my ( $self, $message ) = @_;
97 2 50       7 return unless my $debug = $self->{debug_fh};
98 2         16 print $debug "$message\n";
99             }
100              
101             sub highlight_text {
102 0     0 0 0 my ( $self, $code ) = @_;
103              
104 0 0       0 if ( $self->_should_cache ) {
105 0         0 my ( $path, $file ) = $self->_get_path_and_file($code);
106 0 0       0 unless ( -d $path ) {
107 0         0 make_path($path);
108             }
109 0         0 $file = catfile( $path, $file );
110              
111 0 0       0 if ( -e $file ) {
112 0         0 $self->_debug("Cache hit on '$file'");
113              
114             # update the atime, mtime to ensure that our naive cache recognizes
115             # this as a "recent" file
116 0 0       0 utime time, time, $file or die "Cannot 'utime atime, mtime $file: $!";
117 0 0       0 open my $fh, '<', $file or die "Cannot open '$file' for reading: $!";
118 0         0 return do { local $/; <$fh> };
  0         0  
  0         0  
119             }
120             else {
121 0         0 $self->_debug("Cache miss on '$file'");
122 0         0 my $highlighted = $self->_get_highlighted_text($code);
123 0 0       0 open my $fh, '>', $file or die "Cannot open '$file' for writing: $!";
124 0         0 print $fh $highlighted;
125 0         0 return $highlighted;
126             }
127             }
128             else {
129 0         0 return $self->_get_highlighted_text($code);
130             }
131             }
132              
133             sub _get_highlighted_text {
134 1     1   1093 my ( $self, $code ) = @_;
135              
136 1         2 my @code;
137 1         1 my $line_num = 0;
138 1         2 my $in_pod = 0;
139 1         1 my %pod_lines;
140             my @pod_line_nums;
141 1         636 foreach ( split /\n/ => $code ) {
142 1913 100       2957 if (/^=(?!cut\b)/) {
143 79         76 $in_pod = 1;
144             }
145 1913 100       2192 if ($in_pod) {
146 1147         2221 $pod_lines{$line_num} = $_;
147 1147         1553 push @pod_line_nums => $line_num;
148 1147         1453 push @code => '';
149             }
150             else {
151 766         1006 push @code => $_;
152             }
153 1913 100       2808 if (/^=cut\b/) {
154 24         24 $in_pod = 0;
155             }
156 1913         1830 $line_num++;
157             }
158 1         318 $code = join "\n" => @code;
159 1         9 my $highlighted = $self->_highlighter->highlightText($code);
160 1         18078 @code = split /\n/ => $highlighted;
161 1         436 @code[@pod_line_nums] = @pod_lines{@pod_line_nums};
162 1         38 return join "\n" => map { BLUE . $_ . RESET } @code;
  1913         77027  
163             }
164              
165             sub _get_path_and_file {
166 2     2   520 my ( $self, $code ) = @_;
167 2 50       6 unless ( $self->_should_cache ) {
168 0         0 $self->_debug("Caching disabled");
169 0         0 return;
170             }
171 2         8 my $md5 = md5_hex( $self->_get_unique_factors, $code );
172 2         9 my $dir = substr $md5, 0, 2, '';
173 2         3 my $file = $md5;
174              
175 2         5 my $path = catdir( $self->_cache_dir, $dir );
176 2         10 $self->_debug("Cache path is '$path'. Cache file is '$file'");
177 2         8 return $path, $file;
178             }
179              
180             sub _format_number {
181 2     2   381 return $FORMAT_NUMBER;
182             }
183              
184             sub _get_unique_factors {
185 2     2   5 my $self = shift;
186 2         26 return ( $self->_format_number, ref $self );
187             }
188              
189             1;
190             __END__