File Coverage

blib/lib/DB/Color/Highlight.pm
Criterion Covered Total %
statement 80 103 77.6
branch 12 28 42.8
condition 2 3 66.6
subroutine 22 23 95.6
pod 0 2 0.0
total 116 159 72.9


line stmt bran cond sub pod time code
1             package DB::Color::Highlight;
2              
3 2     2   20575 use strict;
  2         4  
  2         49  
4 2     2   8 use warnings;
  2         4  
  2         52  
5 2     2   262320 use Term::ANSIColor ':constants';
  2         115558  
  2         1647  
6 2     2   17 use Digest::MD5 'md5_hex';
  2         2  
  2         116  
7 2     2   1813 use File::Spec::Functions qw(catfile catdir);
  2         1667  
  2         152  
8 2     2   12 use File::Path 'make_path';
  2         2  
  2         146  
9              
10             BEGIN {
11 2 50   2   82 if ( !( Term::ANSIColor->VERSION >= 3 ) ) {
12 2     2   10 no warnings 'redefine';
  2         4  
  2         136  
13 0         0 *BRIGHT_BLUE = sub { BLUE };
  0         0  
14             }
15             }
16              
17 2     2   2609 use Syntax::Highlight::Engine::Kate::Perl;
  2         53027  
  2         126  
18              
19             =head1 NAME
20              
21             DB::Color::Highlight - Provides highlighting for DB::Color
22              
23             =head1 VERSION
24              
25             Version 0.20
26              
27             =cut
28              
29             our $VERSION = '0.20';
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   20 no warnings 'redefine';
  2         6  
  2         136  
36 2     2   2239 *Syntax::Highlight::Engine::Kate::Template::logwarning = sub { };
        54      
37             }
38              
39             sub new {
40 2     2 0 952 my ( $class, $args ) = @_;
41 2         6 my $self = bless {} => $class;
42 2         8 $self->_initialize($args);
43 2         10 return $self;
44             }
45              
46             sub _initialize {
47 2     2   4 my ( $self, $args ) = @_;
48              
49 2         5 my $cache_dir = $args->{cache_dir};
50 2         13 $self->{debug_fh} = $args->{debug_fh};
51 2         5 $self->{cache_dir} = $cache_dir;
52              
53 2 100 66     64 if ( defined $cache_dir and not -d $cache_dir ) {
54 1 50       112 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         23 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         5093 $self->{highlighter} = $highlighter;
89             }
90              
91 1     1   16 sub _highlighter { $_[0]->{highlighter} }
92 4     4   19 sub _cache_dir { $_[0]->{cache_dir} }
93 2     2   7 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         7 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   1166 my ( $self, $code ) = @_;
135              
136 1         2 my @code;
137 1         2 my $line_num = 0;
138 1         2 my $in_pod = 0;
139 1         2 my %pod_lines;
140             my @pod_line_nums;
141 1         512 foreach ( split /\n/ => $code ) {
142 1948 100       3798 if (/^=(?!cut\b)/) {
143 89         109 $in_pod = 1;
144             }
145 1948 100       2778 if ($in_pod) {
146 1181         2590 $pod_lines{$line_num} = $_;
147 1181         1853 push @pod_line_nums => $line_num;
148 1181         1961 push @code => '';
149             }
150             else {
151 767         1140 push @code => $_;
152             }
153 1948 100       3524 if (/^=cut\b/) {
154 24         37 $in_pod = 0;
155             }
156 1948         2346 $line_num++;
157             }
158 1         280 $code = join "\n" => @code;
159 1         6 my $highlighted = $self->_highlighter->highlightText($code);
160 1         22665 @code = split /\n/ => $highlighted;
161 1         413 @code[@pod_line_nums] = @pod_lines{@pod_line_nums};
162 1         48 return join "\n" => map { BLUE . $_ . RESET } @code;
  1948         85177  
163             }
164              
165             sub _get_path_and_file {
166 2     2   492 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         7 my $md5 = md5_hex( $self->_get_unique_factors, $code );
172 2         7 my $dir = substr $md5, 0, 2, '';
173 2         4 my $file = $md5;
174              
175 2         3 my $path = catdir( $self->_cache_dir, $dir );
176 2         9 $self->_debug("Cache path is '$path'. Cache file is '$file'");
177 2         7 return $path, $file;
178             }
179              
180             sub _format_number {
181 2     2   477 return $FORMAT_NUMBER;
182             }
183              
184             sub _get_unique_factors {
185 2     2   4 my $self = shift;
186 2         6 return ( $self->_format_number, ref $self );
187             }
188              
189             1;
190             __END__