File Coverage

blib/lib/Syntax/Highlight/Mason.pm
Criterion Covered Total %
statement 80 105 76.1
branch 6 12 50.0
condition n/a
subroutine 26 37 70.2
pod 15 23 65.2
total 127 177 71.7


line stmt bran cond sub pod time code
1             #!/usr/bin/perl
2             package Syntax::Highlight::Mason;
3              
4             =head1 NAME
5              
6             Syntax::Highlight::Mason - Perl extension to Highlight HTML::Mason code
7              
8             =head1 SYNOPSIS
9              
10             use Syntax::Highlight::Mason;
11             use IO::All;
12             my $compiler = Syntax::Highlight::Mason->new();
13             while (my $file = shift @ARGV) {
14             my $source < io($file);
15             print $compiler->compile($source);
16             }
17              
18             =head1 DESCRIPTION
19              
20             Produce colorized and HTML escaped code from HTML::Mason source
21             suitable for displaying on the WWW and perhaps even in an Mason
22             environment. Lots of things are customizable, but the defaults
23             are pretty reasonable.
24              
25             =head2 Customization
26              
27             The following items can be customized:
28              
29             $debug Set it to 1 to enable debugging output
30             $style_sheet A CSS style sheet that maps HTML ids to colors
31             $preamble HTML that gets inserted at the beginning of a page
32             $postamble HTML that gets inserted at the end of a page
33             $color_table A mapping of perl syntax elements to colors
34             @mason_highlight An array, element[0] is inserted before mason code
35             element[1] is inserted after mason code
36              
37             These are all package Global variables, which you can just set to
38             your own values if desired. A simple:
39             C<$Syntax::Highlight::Mason::debug = 1;>
40             should do the trick.
41              
42             =cut
43              
44 1     1   23185 use strict;
  1         3  
  1         53  
45             our $VERSION = '1.23';
46              
47 1     1   877 use HTML::Mason::Lexer;
  1         48834  
  1         39  
48 1     1   13 use HTML::Mason::Exceptions (abbr => [qw(syntax_error)]);
  1         7  
  1         11  
49 1     1   1219 use HTML::Mason::Compiler;
  1         23251  
  1         33  
50 1     1   936 use HTML::Entities ();
  1         7413  
  1         53  
51 1     1   1037 use Syntax::Highlight::HTML;
  1         1140  
  1         34  
52 1     1   7222 use Syntax::Highlight::Perl::Improved ':FULL';
  1         12157  
  1         360  
53 1     1   13 use Class::Container;
  1         2  
  1         30  
54 1     1   6 use Params::Validate qw(:all);
  1         2  
  1         200  
55 1     1   6 use base qw(HTML::Mason::Compiler);
  1         2  
  1         2056  
56              
57             our $debug = 0;
58             ################################################################
59             ## Copied from: ##
60             ## CPAN Syntax::Highlight::HTML distribution ##
61             ################################################################
62             our $style_sheet = <
63            
84             END
85              
86             our $preamble = <
87            
88            
89             $style_sheet
90            
91            
92            
 
93             END
94              
95             our $postamble = <
96            
97            
98            
99             END
100              
101             ################################################################
102             ## Copied from: ##
103             ## http://sedition.com/perl/perl-colorizer.html ##
104             ################################################################
105             our $color_table = {
106             'Variable_Scalar' => 'color:#080;',
107             'Variable_Array' => 'color:#f70;',
108             'Variable_Hash' => 'color:#80f;',
109             'Variable_Typeglob' => 'color:#f03;',
110             'Subroutine' => 'color:#980;',
111             'Quote' => 'color:#00a;',
112             'String' => 'color:#00a;',
113             'Comment_Normal' => 'color:#069;font-style:italic;',
114             'Comment_POD' => 'color:#014;font-family:' .
115             'garamond,serif;font-size:11pt;',
116             'Bareword' => 'color:#3A3;',
117             'Package' => 'color:#900;',
118             'Number' => 'color:#f0f;',
119             'Operator' => 'color:#000;',
120             'Symbol' => 'color:#000;',
121             'Keyword' => 'color:#000;',
122             'Builtin_Operator' => 'color:#300;',
123             'Builtin_Function' => 'color:#001;',
124             'Character' => 'color:#800;',
125             'Directive' => 'color:#399;font-style:italic;',
126             'Label' => 'color:#939;font-style:italic;',
127             'Line' => 'color:#000;',
128             };
129              
130             our @mason_highlight = ( '', '' );
131              
132             =head3 Further Customization
133              
134             More customization can be done by passing parmeters to the
135             C method if desired. You can set the B,
136             B, and B parameters here too. In
137             addition, you can specify your own callback subroutines which
138             encode B, B, B (text), and B code.
139             The defaults use I for perl,
140             I for HTML, I
141             for plain text, and bold blue I for
142             mason code.
143              
144             =cut
145              
146             my %spec;
147             foreach (qw(preamble postamble color_table)) {
148             $spec{$_} = {type => SCALAR, parse => 'string', optional => 1};
149             }
150             foreach (qw(perl html plain mason)) {
151             $spec{$_} = {type => CODEREF, parse => 'code', optional => 1};
152             }
153              
154             __PACKAGE__->valid_params(%spec);
155             undef %spec;
156              
157             sub initialize {
158 1     1 0 3 my $self = shift;
159 1         13 my $perl_formatter = Syntax::Highlight::Perl::Improved->new();
160 1         416 my $html_formatter = Syntax::Highlight::HTML->new(pre => 0);
161 1         209 $html_formatter->xml_mode(1);
162             my $actions =
163             {
164 2     2   13 perl => sub { return $perl_formatter->format_string(@_)},
165 1     1   6 html => sub { my $t = $html_formatter->parse(@_);
166 1         181 return $t
167             },
168 3     3   13 plain => sub {return HTML::Entities::encode(join('',@_))},
169 6     6   31 mason => sub {return $mason_highlight[0] .
170             HTML::Entities::encode(join('',@_)) .
171             $mason_highlight[1]}
172 1         17 };
173 1         42 my %p = validate(@_,{
174             preamble => {default => $preamble},
175             postamble => {default => $postamble},
176             color_table => {default => $color_table},
177             perl => {default => $actions->{perl}},
178             html => {default => $actions->{html}},
179             plain => {default => $actions->{plain}},
180             mason => {default => $actions->{mason}}
181             });
182 1         13 $perl_formatter->define_substitution('<' => '<',
183             '>' => '>',
184             '&' => '&'); # HTML escapes.
185              
186 1         21 while ( my ( $type, $style ) = each %{$p{color_table}} ) {
  22         408  
187              
188 21         109 $perl_formatter->set_format($type, [ qq||,
189             '' ] );
190             }
191 1         4 $self->{HighlightMason} = \%p;
192 1         6 $self->{HighlightMason}->{out} = '';
193             }
194              
195             # Subclass HTML::Mason::compiler. If it ever stops returning a
196             # blessed hash, this code is going to be very unhappy.
197              
198             sub new {
199 1     1 1 16 my $class = shift;
200 1         19 my $self = $class->SUPER::new(@_);
201 1         1962 $self->initialize(@_);
202 1         6 return $self;
203             }
204              
205             # All output is collected and returned here.
206              
207             sub collect_output(@) {
208 13     13 0 10121 my $self = shift;
209 13 50       36 return $self->{HighlightMason}->{out} unless @_;
210 13 50       89 $self->{HighlightMason}->{out} .= join('',@_) if @_;
211             }
212              
213             # Sends back collected output wrapped with the preamble and the
214             # postamble
215              
216             sub result {
217 0     0 0 0 my $self = shift;
218 0         0 return join('',
219             $self->{HighlightMason}->{preamble},
220             $self->collect_output(),
221             $self->{HighlightMason}->{postamble}
222             );
223             }
224              
225             =item $self->highlight($type,@args)
226              
227             calls the apropriate callback subroutine set up in C
228             above, depending on the type of encoding (perl, html, plain,
229             mason) to be performed. Output is collected for later. You
230             could also subclass this if you wanted to generate your own
231             highlighting
232              
233             =cut
234              
235             sub highlight {
236 12     12 1 30 my ($self,$type,@rest) = @_;
237 12         36 $self->collect_output($self->{HighlightMason}->{$type}(@rest));
238             }
239              
240             =cut $self->compile($source)
241              
242             This subclasses the HTML::Mason compiler, and instead of
243             compiling code suitable for the HTML::Mason::Interp module,
244             generates colorified HTML text of the code,
245              
246             =cut
247              
248             sub compile {
249 1     1 1 2 my ($self,$source) = @_;
250 1         3 $self->{HighlightMason}->{out} = '';
251 1         12 $self->lexer->lex( comp_source => $source,
252             name => "Highlight",
253             compiler => $self );
254 0         0 return $self->result;
255             }
256              
257             # See the HTML::Mason::Compiler pod documentation for why these
258             # methods are defined here, and how they are supposed to behave.
259              
260             # Let Perl write some code. This way we get debugging at no runtime cost,
261             # how cool is that?
262              
263             my @code_definition =
264             (
265             # name args to $self->highlight
266             [ "init_block", '"perl", $p{block}' ],
267             [ "doc_block", '"plain", $p{block}' ],
268             [ "text_block", '"plain", $p{block}'],
269             [ "raw_block", '"perl", $p{block}' ],
270             [ "perl_block", '"perl", $p{block}' ],
271             [ "start_block", '"mason", "<%" . $p{block_type} . ">\n"' ], #" (emacs)
272             [ "end_block", '"mason", "\n"' ],
273             [ "start_named_block", '"mason", "<%" . $p{block_type} . " " . $p{name} . ">\n"' ],
274             [ "end_named_block", '"mason", "\n"' ],
275             [ "text", '"html", $p{text}' ],
276             [ "component_call", '"mason", "<&" . $p{call} . "&>"' ],
277             [ "component_content_call", '"mason", "<&|" . $p{call} . "&>"' ],
278             [ "component_content_call_end", '"mason", ""' ],
279             [ "key_value_pair", '"plain", $p{key} . " => " . $p{value} ,"\n"' ]
280             );
281              
282             my $code = '';
283              
284             foreach (@code_definition) {
285             my ($name,$type) = @$_;
286             $code .= <<'END';
287             sub {
288             my ($self,%p) = @_;
289             END
290             if ($debug) {
291             $code .= <<'END';
292             $self->collect_output('');
293             print STDERR "In \n";
294             $self->highlight();
295             $self->collect_output('');
296             END
297             } else {
298             $code .= q{ $self->highlight();};
299             }
300             $code .= "}\n";
301             $code =~ s//$name/gs;
302             $code =~ s//$type/gs;
303             }
304              
305             # The code generated by the above looks like this if we are
306             # debugging:
307              
308             # sub init_block {
309             # my ($self,%p) = @_;
310             # $self->collect_output('');
311             # print STDERR "In init_block\n";
312             # $self->highlight("perl", $p{block});
313             # $self->collect_output('');
314             # }
315              
316             # and like this we are are not:
317              
318             # sub init_block {
319             # my ($self,%p) = @_;
320             # $self->highlight("perl", $p{block});
321             # }
322              
323             print STDERR $code if $debug;
324              
325 0     0 1 0 eval $code; die $@ if $@;
  0     0 1 0  
  0     0 1 0  
  0     1 0 0  
  0     3 1 0  
  0     0 1 0  
  1     0 0 99  
  1     0 1 5  
  3     0 0 194  
  3     1 0 16  
  0     3 1 0  
  0     0 1 0  
  0     1 1 0  
  0     0 0 0  
  0         0  
  0         0  
  0         0  
  0         0  
  1         96  
  1         6  
  3         563  
  3         20  
  0         0  
  0         0  
  1         116  
  1         9  
  0         0  
  0         0  
326              
327             # There are always exceptions to every rule, and here they are:
328              
329             sub perl_line {
330 1 50   1 1 50 print STDERR "In block perl_line\n" if $debug;
331 1         4 my ($self,%p) = @_;
332 1         3 my $line = $p{line};
333 1         3 $line =~ s/^%//;
334 1         4 $self->collect_output(' %'); # fudge a space in front so Mason is happy
335 1         4 $self->highlight('perl',"$line\n");
336             }
337              
338             sub substitution {
339 0     0 1 0 my ($self,%p) = @_;
340 0         0 my $content = $p{substitution};
341 0 0       0 $content .= " | " . $p{escape} if $p{escape};
342 0         0 $self->highlight('mason',"<%" . $content . " %>"); # another fudged space
343             }
344              
345             # Why did I put that extra space before the % sign?
346             # Because if the output of this module is fed directly to a Mason app
347             # it will try to execute those lines beginning with a % as perl code
348             # which is NOT what I wanted.
349              
350             sub variable_declaration {
351 2     2 1 222 my ($self,%p) = @_;
352 2 50       7 print STDERR "In block variable_declaration\n" if $debug;
353 2         7 my $text = $p{type} . $p{name};
354 2 100       11 $text .= ' => ' . $p{default} if defined $p{default};
355 2         8 $self->highlight('plain', $text ,"\n");
356             }
357              
358             1;
359              
360             =head1 AUTHOR
361              
362             Henry Laxen nadine.and.henry@pobox.com
363              
364             =head1 SEE ALSO
365              
366             Syntax::Highlight::HTML Syntax::Highlight::Perl::Improved
367             HTML::Mason
368              
369             =cut