1package Pod::POM::View::HTML::Filter;
2use Pod::POM::View::HTML;
3our @ISA = qw( Pod::POM::View::HTML );
4
5use warnings;
6use strict;
7use Carp;
8
9our $VERSION = '0.09';
10
11my  %filter;
12our %builtin = (
13    default => {
14        code => sub {
15            my $s = shift;
16            $s =~ s/&/&/g;
17            $s =~ s/</&lt;/g;
18            $s =~ s/>/&gt;/g;
19            $s;
20        },
21        verbatim => 1,
22    },
23    perl_tidy => {
24        code     => \&perl_tidy_filter,
25        requires => [qw( Perl::Tidy )],
26        verbatim => 1,
27        alias    => [qw( perl )],
28    },
29    perl_ppi => {
30        code     => \&perl_ppi_filter,
31        requires => [qw( PPI PPI::HTML )],
32        verbatim => 1,
33        alias    => [qw( ppi )],
34    },
35    html => {
36        code     => \&html_filter,
37        requires => [qw( Syntax::Highlight::HTML )],
38        verbatim => 1,
39    },
40    shell => {
41        code     => \&shell_filter,
42        requires => [qw( Syntax::Highlight::Shell )],
43        verbatim => 1,
44    },
45    kate => {
46        code     => \&kate_filter,
47        requires => [qw( Syntax::Highlight::Engine::Kate )],
48        verbatim => 1,
49    },
50    wiki => {
51        code     => \&wiki_filter,
52        requires => [qw( Text::WikiFormat )],
53        verbatim => 0,
54    },
55    wikimedia => {
56        code     => \&wikimedia_filter,
57        requires => [qw( Text::MediawikiFormat )],
58        verbatim => 0,
59    },
60);
61
62# automatically register built-in handlers
63my $INIT = 1;
64Pod::POM::View::HTML::Filter->add( %builtin );
65$INIT = 0;
66
67#
68# Specific methods
69#
70sub new {
71    my $class = shift;
72    return $class->SUPER::new(
73        auto_unindent => 1,
74        @_,
75        filter => {},    # instance filters
76        FILTER => [],    # stack maintaining info for filters
77    );
78}
79
80sub add {
81    my ($self, %args) = @_;
82    my $filter = $self->__filter();
83
84    for my $lang ( keys %args ) {
85        my $nok = 0;
86        if( exists $args{$lang}{requires} ) {
87            for ( @{ $args{$lang}{requires} } ) {
88                eval "require $_;";
89                if ($@) {
90                    $nok++;
91                    carp "$lang\: pre-requisite $_ could not be loaded"
92                      unless $INIT;    # don't warn for built-ins
93                }
94            }
95        }
96        croak "$lang: no code parameter given"
97          unless exists $args{$lang}{code};
98
99        if ( !$nok ) {
100            $filter->{$lang} = $args{$lang};
101            if ( $args{$lang}{alias} ) {
102                $filter->{$_} = $args{$lang} for @{ $args{$lang}{alias} };
103            }
104        }
105    }
106}
107
108sub delete {
109    my ( $self, $lang ) = @_;
110    my $filter = $self->__filter();
111    my $old = $self->_filter()->{$lang};
112    $filter->{$lang} = undef;
113    return $old;
114}
115
116# return a hashref of current filters for the class|instance
117sub _filter {
118    my ($self) = @_;
119    my $filter =
120        ref $self
121        && UNIVERSAL::isa( $self, 'Pod::POM::View::HTML::Filter' )
122        ? { %filter, %{ $self->{filter} } }
123        : \%filter;
124    $filter->{$_} || delete $filter->{$_} for keys %$filter;
125    return $filter;
126}
127
128# return the real inner filter list for the class|instance
129sub __filter {
130    my ($self) = @_;
131    return
132        ref $self
133        && UNIVERSAL::isa( $self, 'Pod::POM::View::HTML::Filter' )
134        ? $self->{filter}
135        : \%filter;
136}
137
138sub know {
139    my ($self, $lang) = @_;
140    return exists $self->_filter()->{$lang};
141}
142
143sub filters { keys %{ $_[0]->_filter() }; }
144
145#
146# overridden Pod::POM::View::HTML methods
147#
148sub view_for {
149    my ($self, $for)    = @_;
150    my $format = $for->format;
151    my $filter = $self->_filter();
152
153    return $for->text() . "\n\n" if $format =~ /^html\b/;
154
155    if ( $format =~ /^filter\b/ ) {
156        my $args   = (split '=', $format, 2)[1];
157        return '' unless defined $args; # silently skip
158
159        my $text = $for->text;
160        my $verbatim = 0;
161
162        # select the filters and options
163        my @langs;
164        for my $lang (split /\|/, $args) {
165            ( $lang, my $opts ) = ( split( ':', $lang, 2 ), '' );
166            $opts =~ y/:/ /;
167            $lang = exists $filter->{$lang} ? $lang : 'default';
168            push @langs, [ $lang, $opts ];
169            $verbatim++ if $filter->{$lang}{verbatim};
170        }
171
172        # cancel filtering if one filter is missing
173        @langs = ( grep { $_->[0] eq 'default' } @langs )
174            ? ( [ 'default', '' ] )
175            : @langs;
176
177        # process the text
178        $text = $filter->{ $_->[0] }{code}->( $text, $_->[1] ) for @langs;
179
180        return $verbatim ? "<pre>$text</pre>\n" : "$text\n";
181    }
182
183    # fall-through
184    return '';
185}
186
187sub view_begin {
188    my ($self, $begin)  = @_;
189    my ($format, $args) = split(' ', $begin->format(), 2);
190    my $filter = $self->_filter();
191
192    if ( $format eq 'html' ) {
193        return $self->SUPER::view_begin( $begin );
194    }
195    elsif( $format eq 'filter' ) {
196        my @filters = map { s/^\s*|\s*$//g; $_ } split /\|/, $args;
197
198        # fetch the text and verbatim blocks in the begin section
199        # and remember the type of each block
200        my $verbatim = 0;
201        my $prev = '';
202        my $text = '';
203        for my $item ( @{ $begin->content } ) {
204            $text .= ($prev ? "\n\n" :'') . $item->text();
205            $prev = 1;
206            $verbatim++ if $item->type eq 'verbatim';
207        }
208
209        # a block is verbatim only if all subblocks are verbatim
210        $verbatim = 0 if $verbatim != @{ $begin->content };
211
212        # select the filters and options
213        my @langs;
214        for my $f (@filters) {
215            my ( $lang, $opts ) = split( ' ', $f, 2 );
216            $lang = exists $filter->{$lang} ? $lang : 'default';
217            push @langs, [ $lang, $opts ];
218            $verbatim++ if $filter->{$lang}{verbatim};
219        }
220
221        # cancel filtering if one filter is missing
222        @langs = ( grep { $_->[0] eq 'default' } @langs )
223            ? ( [ 'default', '' ] )
224            : @langs;
225
226        # process the text
227        ( my $indent, $text ) = _unindent($text)
228            if $self->{auto_unindent};
229        $text = $filter->{ $_->[0] }{code}->( $text, $_->[1] ) for @langs;
230        $text =~ s/^(?=.+)/$indent/gm
231            if $self->{auto_unindent};
232
233        # the enclosing tags depend on the block and the last filter
234        return $verbatim ? "<pre>$text</pre>\n" : "$text\n";
235    }
236
237    # fall-through
238    return '';
239}
240
241#
242# utility functions
243#
244
245# a simple filter output cleanup routine
246sub _cleanup {
247    local $_ = shift;
248    s!\A<pre>\n?|\n?</pre>\n\z!!gm; # remove <pre></pre>
249    $_;
250}
251
252sub _unindent {
253    my $str = shift;
254    my $indent;
255    while ( $str =~ /^( *)\S/gmc ) {
256        $indent =
257              !defined $indent             ? $1
258            : length($1) < length($indent) ? $1
259            :                                $indent;
260    }
261    $indent ||= '';
262    $str =~ s/^$indent//gm;
263    return ( $indent, $str );
264}
265
266#
267# builtin filters
268#
269
270# a cache for multiple parsers with the same options
271my %filter_parser;
272
273# Perl highlighting, thanks to Perl::Tidy
274sub perl_tidy_filter {
275    my ($code, $opts) = ( shift, shift || "" );
276    my $output = "";
277
278    # Perl::Tidy 20031021 uses Getopt::Long and expects the default config
279    # this is a workaround (a patch was sent to Perl::Tidy's author)
280    my $glc = Getopt::Long::Configure();
281    Getopt::Long::ConfigDefaults();
282
283    Perl::Tidy::perltidy(
284        source      => \$code,
285        destination => \$output,
286        argv        => "-html -pre -nopod2html " . $opts,
287        stderr      => '-',
288        errorfile   => '-',
289    );
290    $output = _cleanup( $output ); # remove <pre></pre>
291
292    # put back Getopt::Long previous configuration, if needed
293    Getopt::Long::Configure( $glc );
294
295    return $output;
296}
297
298# Perl highlighting, thanks to PPI::HTML
299sub perl_ppi_filter {
300    my ($code, $opts) = ( shift, shift || '');
301
302    # PPI::HTML options
303    my %ppi_opt = map { !/=/ && s/$/=1/ ; split /=/, $_, 2 } split / /, $opts;
304
305    # create PPI::HTML syntax highlighter
306    my $highlighter = $filter_parser{ppi}{$opts} ||= PPI::HTML->new(%ppi_opt);
307
308    # highlight the code and clean up the resulting HTML
309    my $pretty = $highlighter->html(\$code);
310    $pretty =~ s/<br>$//gsm;
311
312    return $pretty;
313}
314
315# HTML highlighting thanks to Syntax::Highlight::HTML
316sub html_filter {
317    my ($code, $opts) = ( shift, shift || "" );
318
319    my $parser = $filter_parser{html}{$opts}
320      ||= Syntax::Highlight::HTML->new( map { (split /=/) } split ' ', $opts );
321    return _cleanup( $parser->parse($code) );
322}
323
324# Shell highlighting thanks to Syntax::Highlight::Shell
325sub shell_filter {
326    my ($code, $opts) = ( shift, shift || "" );
327
328    my $parser = $filter_parser{shell}{$opts}
329      ||= Syntax::Highlight::Shell->new( map { (split /=/) } split ' ', $opts );
330    return _cleanup( $parser->parse($code) );
331}
332
333# Kate highligthing thanks to Syntax::Highlight::Engine::Kate
334sub kate_filter {
335    my ($code, $opts) = @_;
336    my ($lang) = split ' ', $opts || '';
337
338    my $parser = $filter_parser{kate}{$lang}
339      ||= Syntax::Highlight::Engine::Kate->new(
340        language => $lang,
341        substitutions => {
342            '<' => '&lt;',
343            '>' => '&gt;',
344            '&' => '&amp;',
345        },
346        format_table => {
347            Alert        => [ '<span class="k-alert">',        '</span>' ],
348            BaseN        => [ '<span class="k-basen">',        '</span>' ],
349            BString      => [ '<span class="k-bstring">',      '</span>' ],
350            Char         => [ '<span class="k-char">',         '</span>' ],
351            Comment      => [ '<span class="k-comment">',      '</span>' ],
352            DataType     => [ '<span class="k-datatype">',     '</span>' ],
353            DecVal       => [ '<span class="k-decval">',       '</span>' ],
354            Error        => [ '<span class="k-error">',        '</span>' ],
355            Float        => [ '<span class="k-float">',        '</span>' ],
356            Function     => [ '<span class="k-function">',     '</span>' ],
357            IString      => [ '<span class="k-istring">',      '</span>' ],
358            Keyword      => [ '<span class="k-keyword">',      '</span>' ],
359            Normal       => [ '',                              '' ],
360            Operator     => [ '<span class="k-operator">',     '</span>' ],
361            Others       => [ '<span class="k-others">',       '</span>' ],
362            RegionMarker => [ '<span class="k-regionmarker">', '</span>' ],
363            Reserved     => [ '<span class="k-reserved">',     '</span>' ],
364            String       => [ '<span class="k-string">',       '</span>' ],
365            Variable     => [ '<span class="k-variable">',     '</span>' ],
366            Warning      => [ '<span class="k-warning">',      '</span>' ],
367        },
368    );
369
370    return $parser->highlightText($code);
371}
372
373sub wiki_filter {
374    my ($code, $opts) = (shift, shift || '');
375    return Text::WikiFormat::format( $code , {},
376        { map { ( split /=/ ) } split ' ', $opts } );
377}
378
379sub wikimedia_filter {
380    my ($code, $opts) = (shift, shift || '');
381    return Text::MediawikiFormat::format( $code , {},
382        { map { ( split /=/ ) } split ' ', $opts } );
383}
384
3851;
386
387__END__
388
389=head1 NAME
390
391Pod::POM::View::HTML::Filter - Use filters on sections of your pod documents
392
393=cut
394
395=head1 SYNOPSIS
396
397In your POD:
398
399    Some coloured Perl code:
400
401    =begin filter perl
402
403        # now in full colour!
404        $A++;
405
406    =end filter
407
408    =for filter=perl $A++; # this works too
409
410    This should read C<bar bar bar>:
411
412    =begin filter foo
413
414    bar foo bar
415
416    =end filter
417
418In your code:
419
420    my $view = Pod::POM::View::HTML::Filter->new;
421    $view->add(
422        foo => {
423            code => sub { my $s = shift; $s =~ s/foo/bar/gm; $s },
424            # other options are available
425        }
426    );
427
428    my $pom = Pod::POM->parse_file( '/my/pod/file' );
429    $pom->present($view);
430
431=begin html
432
433<style type="text/css">
434<!--
435/* HTML colouring styles */
436.h-decl { color: #336699; font-style: italic; }   /* doctype declaration  */
437.h-pi   { color: #336699;                     }   /* process instruction  */
438.h-com  { color: #338833; font-style: italic; }   /* comment              */
439.h-ab   { color: #000000; font-weight: bold;  }   /* angles as tag delim. */
440.h-tag  { color: #993399; font-weight: bold;  }   /* tag name             */
441.h-attr { color: #000000; font-weight: bold;  }   /* attribute name       */
442.h-attv { color: #333399;                     }   /* attribute value      */
443.h-ent  { color: #cc3333;                     }   /* entity               */
444.h-lno  { color: #aaaaaa; background: #f7f7f7;}   /* line numbers         */
445
446/* Perl colouring styles */
447.c  { color: #228B22;} /* comment */
448.cm { color: #000000;} /* comma */
449.co { color: #000000;} /* colon */
450.h  { color: #CD5555; font-weight:bold;} /* here-doc-target */
451.hh { color: #CD5555; font-style:italic;} /* here-doc-text */
452.i  { color: #00688B;} /* identifier */
453.j  { color: #CD5555; font-weight:bold;} /* label */
454.k  { color: #8B008B; font-weight:bold;} /* keyword */
455.m  { color: #FF0000; font-weight:bold;} /* subroutine */
456.n  { color: #B452CD;} /* numeric */
457.p  { color: #000000;} /* paren */
458.pd { color: #228B22; font-style:italic;} /* pod-text */
459.pu { color: #000000;} /* punctuation */
460.q  { color: #CD5555;} /* quote */
461.s  { color: #000000;} /* structure */
462.sc { color: #000000;} /* semicolon */
463.v  { color: #B452CD;} /* v-string */
464.w  { color: #000000;} /* bareword */
465-->
466</style>
467
468<p>The resulting HTML will look like this (modulo the stylesheet):</p>
469
470<pre>    <span class="c"># now in full colour!</span>
471    <span class="i">$A</span>++<span class="sc">;</span></pre>
472<pre><span class="i">$A</span>++<span class="sc">;</span> <span class="c"># this works too</span></pre>
473<p>This should read <code>bar bar bar</code>:</p>
474<p>bar bar bar</p>
475
476=end html
477
478=head1 DESCRIPTION
479
480This module is a subclass of C<Pod::POM::View::HTML> that support the
481C<filter> extension. This can be used in C<=begin> / C<=end> and
482C<=for> pod blocks.
483
484Please note that since the view maintains an internal state, only
485an instance of the view can be used to present the POM object.
486Either use:
487
488    my $view = Pod::POM::View::HTML::Filter->new;
489    $pom->present( $view );
490
491or
492
493    $Pod::POM::DEFAULT_VIEW = Pod::POM::View::HTML::Filter->new;
494    $pom->present;
495
496Even though the module was specifically designed
497for use with C<Perl::Tidy>, you can write your own filters quite
498easily (see L<Writing your own filters>).
499
500=head1 FILTERING POD?
501
502The whole idea of this module is to take advantage of all the syntax
503colouring modules that exist (actually, C<Perl::Tidy> was my first target)
504to produce colourful code examples in a POD document (after conversion
505to HTML).
506
507Filters can be used in two different POD constructs:
508
509=over 4
510
511=item C<=begin filter I<filter>>
512
513The data in the C<=begin filter> ... C<=end filter> region is passed to
514the filter and the result is output in place in the document.
515
516The general form of a C<=begin filter> block is as follow:
517
518    =begin filter lang optionstring
519
520    # some text to process with filter "lang"
521
522    =end filter
523
524The optionstring is trimed for whitespace and passed as a single string
525to the filter routine which must perform its own parsing.
526
527=item C<=for filter=I<filter>>
528
529C<=for> filters work just like C<=begin>/C=<end> filters, except that
530a single paragraph is the target.
531
532The general form of a C<=for filter> block is as follow:
533
534    =for filter=lang:option1:option2
535    # some code in language lang
536
537The option string sent to the filter C<lang> would be C<option1 option2>
538(colons are replaced with spaces).
539
540=back
541
542=head2 Options
543
544Some filters may accept options that alter their behaviour.
545Options are separated by whitespace, and appear after the name of the
546filter. For example, the following code will be rendered in colour and
547with line numbers:
548
549    =begin filter perl -nnn
550
551        $a = 123;
552        $b = 3;
553        print $a * $b;     # prints 369
554        print $a x $b;     # prints 123123123
555
556    =end filter
557
558C<=for> filters can also accept options, but the syntax is less clear.
559(This is because C<=for> expects the I<formatname> to match C<\S+>.)
560
561The syntax is the following:
562
563    =for filter=html:nnn=1
564         <center><img src="camel.png" />
565         A camel</center>
566
567In summary, options are separated by space for C<=begin> blocks and by
568colons for C<=for> paragraphs.
569
570The options and their paramater depend on the filter, but they cannot contain
571the pipe (C<|>) or colon (C<:>) character, for obvious reasons.
572
573=head2 Pipes
574
575Having filter to modify a block of text is usefule, but what's more useful
576(and fun) than a filter? Answer: a stack of filters piped together!
577
578Take the imaginary filters C<foo> (which does a simple C<s/foo/bar/g>)
579and C<bang> (which does an even simpler C<tr/r/!/>). The following block
580
581    =begin filter foo|bar
582
583    foo bar baz
584
585    =end
586
587will become C<ba! ba! baz>.
588
589And naturally,
590
591    =for filter=bar|foo
592    foo bar baz
593
594will return C<bar ba! baz>.
595
596=head2 A note on verbatim and text blocks
597
598B<Note:> The fact that I mention I<verbatim> and I<paragraph> in
599this section is due to an old bug in C<Pod::POM>, which parses the
600content of C<begin>/C<end> sections as the usual POD paragraph
601and verbatim blocks. This is a bug in C<Pod::POM>, around which
602C<Pod::POM::View::HTML::Filter> tries to work around.
603
604As from version 0.06, C<Pod::POM::View::HTML::Filter> gets to the
605original text contained in the C<=begin> / C<=end> block (it was
606easier than I thought, actually) and put that string throught all
607the filters.
608
609If any filter in the stack is defined as C<verbatim>, or if C<Pod::POM>
610detect any block in the C<=begin> / C<=end> block as verbatim, then
611the output will be produced between C<< <pre> >> and C<< </pre> >> tags.
612Otherwise, no special tags will be added (his is left to the formatter).
613
614=head2 Examples
615
616An example of the power of pipes can be seen in the following example.
617Take a bit of Perl code to colour:
618
619    =begin filter perl
620
621        "hot cross buns" =~ /cross/;
622        print "Matched: <$`> $& <$'>\n";    # Matched: <hot > cross < buns>
623        print "Left:    <$`>\n";            # Left:    <hot >
624        print "Match:   <$&>\n";            # Match:   <cross>
625        print "Right:   <$'>\n";            # Right:   < buns>
626
627    =end
628
629This will produce the following HTML code:
630
631    <pre>    <span class="q">&quot;hot cross buns&quot;</span> =~ <span class="q">/cross/</span><span class="sc">;</span>
632         <span class="k">print</span> <span class="q">&quot;Matched: &lt;$`&gt; $&amp; &lt;$'&gt;\n&quot;</span><span class="sc">;</span>    <span class="c"># Matched: &lt;hot &gt; cross &lt; buns&gt;</span>
633         <span class="k">print</span> <span class="q">&quot;Left:    &lt;$`&gt;\n&quot;</span><span class="sc">;</span>            <span class="c"># Left:    &lt;hot &gt;</span>
634         <span class="k">print</span> <span class="q">&quot;Match:   &lt;$&amp;&gt;\n&quot;</span><span class="sc">;</span>            <span class="c"># Match:   &lt;cross&gt;</span>
635         <span class="k">print</span> <span class="q">&quot;Right:   &lt;$'&gt;\n&quot;</span><span class="sc">;</span>            <span class="c"># Right:   &lt; buns&gt;</span></pre>
636
637=begin html
638
639<p>Which your browser will render as:</p>
640
641<pre>    <span class="q">&quot;hot cross buns&quot;</span> =~ <span class="q">/cross/</span><span class="sc">;</span>
642    <span class="k">print</span> <span class="q">&quot;Matched: &lt;$`&gt; $&amp; &lt;$'&gt;\n&quot;</span><span class="sc">;</span>    <span class="c"># Matched: &lt;hot &gt; cross &lt; buns&gt;</span>
643    <span class="k">print</span> <span class="q">&quot;Left:    &lt;$`&gt;\n&quot;</span><span class="sc">;</span>            <span class="c"># Left:    &lt;hot &gt;</span>
644    <span class="k">print</span> <span class="q">&quot;Match:   &lt;$&amp;&gt;\n&quot;</span><span class="sc">;</span>            <span class="c"># Match:   &lt;cross&gt;</span>
645    <span class="k">print</span> <span class="q">&quot;Right:   &lt;$'&gt;\n&quot;</span><span class="sc">;</span>            <span class="c"># Right:   &lt; buns&gt;</span></pre>
646
647=end html
648
649Now if you want to colour and number the HTML code produced, it's as simple
650as tackling the C<html> on top of the C<perl> filter:
651
652    =begin filter perl | html nnn=1
653
654        "hot cross buns" =~ /cross/;
655        print "Matched: <$`> $& <$'>\n";    # Matched: <hot > cross < buns>
656        print "Left:    <$`>\n";            # Left:    <hot >
657        print "Match:   <$&>\n";            # Match:   <cross>
658        print "Right:   <$'>\n";            # Right:   < buns>
659
660    =end
661
662Which produces the rather unreadable piece of HTML:
663
664    <pre><span class="h-lno">  1</span>     <span class="h-ab">&lt;</span><span class="h-tag">span</span> <span class="h-attr">class</span>=<span class="h-attv">"q</span>"<span class="h-ab">&gt;</span><span class="h-ent">&amp;quot;</span>hot cross buns<span class="h-ent">&amp;quot;</span><span class="h-ab">&lt;/</span><span class="h-tag">span</span><span class="h-ab">&gt;</span> =~ <span class="h-ab">&lt;</span><span class="h-tag">span</span> <span class="h-attr">class</span>=<span class="h-attv">"q</span>"<span class="h-ab">&gt;</span>/cross/<span class="h-ab">&lt;/</span><span class="h-tag">span</span><span class="h-ab">&gt;</span><span class="h-ab">&lt;</span><span class="h-tag">span</span> <span class="h-attr">class</span>=<span class="h-attv">"sc</span>"<span class="h-ab">&gt;</span>;<span class="h-ab">&lt;/</span><span class="h-tag">span</span><span class="h-ab">&gt;</span>
665    <span class="h-lno">  2</span>     <span class="h-ab">&lt;</span><span class="h-tag">span</span> <span class="h-attr">class</span>=<span class="h-attv">"k</span>"<span class="h-ab">&gt;</span>print<span class="h-ab">&lt;/</span><span class="h-tag">span</span><span class="h-ab">&gt;</span> <span class="h-ab">&lt;</span><span class="h-tag">span</span> <span class="h-attr">class</span>=<span class="h-attv">"q</span>"<span class="h-ab">&gt;</span><span class="h-ent">&amp;quot;</span>Matched: <span class="h-ent">&amp;lt;</span>$`<span class="h-ent">&amp;gt;</span> $<span class="h-ent">&amp;amp;</span> <span class="h-ent">&amp;lt;</span>$'<span class="h-ent">&amp;gt;</span>\n<span class="h-ent">&amp;quot;</span><span class="h-ab">&lt;/</span><span class="h-tag">span</span><span class="h-ab">&gt;</span><span class="h-ab">&lt;</span><span class="h-tag">span</span> <span class="h-attr">class</span>=<span class="h-attv">"sc</span>"<span class="h-ab">&gt;</span>;<span class="h-ab">&lt;/</span><span class="h-tag">span</span><span class="h-ab">&gt;</span>    <span class="h-ab">&lt;</span><span class="h-tag">span</span> <span class="h-attr">class</span>=<span class="h-attv">"c</span>"<span class="h-ab">&gt;</span># Matched: <span class="h-ent">&amp;lt;</span>hot <span class="h-ent">&amp;gt;</span> cross <span class="h-ent">&amp;lt;</span> buns<span class="h-ent">&amp;gt;</span><span class="h-ab">&lt;/</span><span class="h-tag">span</span><span class="h-ab">&gt;</span>
666    <span class="h-lno">  3</span>     <span class="h-ab">&lt;</span><span class="h-tag">span</span> <span class="h-attr">class</span>=<span class="h-attv">"k</span>"<span class="h-ab">&gt;</span>print<span class="h-ab">&lt;/</span><span class="h-tag">span</span><span class="h-ab">&gt;</span> <span class="h-ab">&lt;</span><span class="h-tag">span</span> <span class="h-attr">class</span>=<span class="h-attv">"q</span>"<span class="h-ab">&gt;</span><span class="h-ent">&amp;quot;</span>Left:    <span class="h-ent">&amp;lt;</span>$`<span class="h-ent">&amp;gt;</span>\n<span class="h-ent">&amp;quot;</span><span class="h-ab">&lt;/</span><span class="h-tag">span</span><span class="h-ab">&gt;</span><span class="h-ab">&lt;</span><span class="h-tag">span</span> <span class="h-attr">class</span>=<span class="h-attv">"sc</span>"<span class="h-ab">&gt;</span>;<span class="h-ab">&lt;/</span><span class="h-tag">span</span><span class="h-ab">&gt;</span>            <span class="h-ab">&lt;</span><span class="h-tag">span</span> <span class="h-attr">class</span>=<span class="h-attv">"c</span>"<span class="h-ab">&gt;</span># Left:    <span class="h-ent">&amp;lt;</span>hot <span class="h-ent">&amp;gt;</span><span class="h-ab">&lt;/</span><span class="h-tag">span</span><span class="h-ab">&gt;</span>
667    <span class="h-lno">  4</span>     <span class="h-ab">&lt;</span><span class="h-tag">span</span> <span class="h-attr">class</span>=<span class="h-attv">"k</span>"<span class="h-ab">&gt;</span>print<span class="h-ab">&lt;/</span><span class="h-tag">span</span><span class="h-ab">&gt;</span> <span class="h-ab">&lt;</span><span class="h-tag">span</span> <span class="h-attr">class</span>=<span class="h-attv">"q</span>"<span class="h-ab">&gt;</span><span class="h-ent">&amp;quot;</span>Match:   <span class="h-ent">&amp;lt;</span>$<span class="h-ent">&amp;amp;</span><span class="h-ent">&amp;gt;</span>\n<span class="h-ent">&amp;quot;</span><span class="h-ab">&lt;/</span><span class="h-tag">span</span><span class="h-ab">&gt;</span><span class="h-ab">&lt;</span><span class="h-tag">span</span> <span class="h-attr">class</span>=<span class="h-attv">"sc</span>"<span class="h-ab">&gt;</span>;<span class="h-ab">&lt;/</span><span class="h-tag">span</span><span class="h-ab">&gt;</span>            <span class="h-ab">&lt;</span><span class="h-tag">span</span> <span class="h-attr">class</span>=<span class="h-attv">"c</span>"<span class="h-ab">&gt;</span># Match:   <span class="h-ent">&amp;lt;</span>cross<span class="h-ent">&amp;gt;</span><span class="h-ab">&lt;/</span><span class="h-tag">span</span><span class="h-ab">&gt;</span>
668    <span class="h-lno">  5</span>     <span class="h-ab">&lt;</span><span class="h-tag">span</span> <span class="h-attr">class</span>=<span class="h-attv">"k</span>"<span class="h-ab">&gt;</span>print<span class="h-ab">&lt;/</span><span class="h-tag">span</span><span class="h-ab">&gt;</span> <span class="h-ab">&lt;</span><span class="h-tag">span</span> <span class="h-attr">class</span>=<span class="h-attv">"q</span>"<span class="h-ab">&gt;</span><span class="h-ent">&amp;quot;</span>Right:   <span class="h-ent">&amp;lt;</span>$'<span class="h-ent">&amp;gt;</span>\n<span class="h-ent">&amp;quot;</span><span class="h-ab">&lt;/</span><span class="h-tag">span</span><span class="h-ab">&gt;</span><span class="h-ab">&lt;</span><span class="h-tag">span</span> <span class="h-attr">class</span>=<span class="h-attv">"sc</span>"<span class="h-ab">&gt;</span>;<span class="h-ab">&lt;/</span><span class="h-tag">span</span><span class="h-ab">&gt;</span>            <span class="h-ab">&lt;</span><span class="h-tag">span</span> <span class="h-attr">class</span>=<span class="h-attv">"c</span>"<span class="h-ab">&gt;</span># Right:   <span class="h-ent">&amp;lt;</span> buns<span class="h-ent">&amp;gt;</span><span class="h-ab">&lt;/</span><span class="h-tag">span</span><span class="h-ab">&gt;</span></pre>
669
670=begin html
671
672<p>But your your browser will render it as:</p>
673
674
675<pre><span class="h-lno">  1</span>     <span class="h-ab">&lt;</span><span class="h-tag">span</span> <span class="h-attr">class</span>=<span class="h-attv">"q</span>"<span class="h-ab">&gt;</span><span class="h-ent">&amp;quot;</span>hot cross buns<span class="h-ent">&amp;quot;</span><span class="h-ab">&lt;/</span><span class="h-tag">span</span><span class="h-ab">&gt;</span> =~ <span class="h-ab">&lt;</span><span class="h-tag">span</span> <span class="h-attr">class</span>=<span class="h-attv">"q</span>"<span class="h-ab">&gt;</span>/cross/<span class="h-ab">&lt;/</span><span class="h-tag">span</span><span class="h-ab">&gt;</span><span class="h-ab">&lt;</span><span class="h-tag">span</span> <span class="h-attr">class</span>=<span class="h-attv">"sc</span>"<span class="h-ab">&gt;</span>;<span class="h-ab">&lt;/</span><span class="h-tag">span</span><span class="h-ab">&gt;</span>
676<span class="h-lno">  2</span>     <span class="h-ab">&lt;</span><span class="h-tag">span</span> <span class="h-attr">class</span>=<span class="h-attv">"k</span>"<span class="h-ab">&gt;</span>print<span class="h-ab">&lt;/</span><span class="h-tag">span</span><span class="h-ab">&gt;</span> <span class="h-ab">&lt;</span><span class="h-tag">span</span> <span class="h-attr">class</span>=<span class="h-attv">"q</span>"<span class="h-ab">&gt;</span><span class="h-ent">&amp;quot;</span>Matched: <span class="h-ent">&amp;lt;</span>$`<span class="h-ent">&amp;gt;</span> $<span class="h-ent">&amp;amp;</span> <span class="h-ent">&amp;lt;</span>$'<span class="h-ent">&amp;gt;</span>\n<span class="h-ent">&amp;quot;</span><span class="h-ab">&lt;/</span><span class="h-tag">span</span><span class="h-ab">&gt;</span><span class="h-ab">&lt;</span><span class="h-tag">span</span> <span class="h-attr">class</span>=<span class="h-attv">"sc</span>"<span class="h-ab">&gt;</span>;<span class="h-ab">&lt;/</span><span class="h-tag">span</span><span class="h-ab">&gt;</span>    <span class="h-ab">&lt;</span><span class="h-tag">span</span> <span class="h-attr">class</span>=<span class="h-attv">"c</span>"<span class="h-ab">&gt;</span># Matched: <span class="h-ent">&amp;lt;</span>hot <span class="h-ent">&amp;gt;</span> cross <span class="h-ent">&amp;lt;</span> buns<span class="h-ent">&amp;gt;</span><span class="h-ab">&lt;/</span><span class="h-tag">span</span><span class="h-ab">&gt;</span>
677<span class="h-lno">  3</span>     <span class="h-ab">&lt;</span><span class="h-tag">span</span> <span class="h-attr">class</span>=<span class="h-attv">"k</span>"<span class="h-ab">&gt;</span>print<span class="h-ab">&lt;/</span><span class="h-tag">span</span><span class="h-ab">&gt;</span> <span class="h-ab">&lt;</span><span class="h-tag">span</span> <span class="h-attr">class</span>=<span class="h-attv">"q</span>"<span class="h-ab">&gt;</span><span class="h-ent">&amp;quot;</span>Left:    <span class="h-ent">&amp;lt;</span>$`<span class="h-ent">&amp;gt;</span>\n<span class="h-ent">&amp;quot;</span><span class="h-ab">&lt;/</span><span class="h-tag">span</span><span class="h-ab">&gt;</span><span class="h-ab">&lt;</span><span class="h-tag">span</span> <span class="h-attr">class</span>=<span class="h-attv">"sc</span>"<span class="h-ab">&gt;</span>;<span class="h-ab">&lt;/</span><span class="h-tag">span</span><span class="h-ab">&gt;</span>            <span class="h-ab">&lt;</span><span class="h-tag">span</span> <span class="h-attr">class</span>=<span class="h-attv">"c</span>"<span class="h-ab">&gt;</span># Left:    <span class="h-ent">&amp;lt;</span>hot <span class="h-ent">&amp;gt;</span><span class="h-ab">&lt;/</span><span class="h-tag">span</span><span class="h-ab">&gt;</span>
678<span class="h-lno">  4</span>     <span class="h-ab">&lt;</span><span class="h-tag">span</span> <span class="h-attr">class</span>=<span class="h-attv">"k</span>"<span class="h-ab">&gt;</span>print<span class="h-ab">&lt;/</span><span class="h-tag">span</span><span class="h-ab">&gt;</span> <span class="h-ab">&lt;</span><span class="h-tag">span</span> <span class="h-attr">class</span>=<span class="h-attv">"q</span>"<span class="h-ab">&gt;</span><span class="h-ent">&amp;quot;</span>Match:   <span class="h-ent">&amp;lt;</span>$<span class="h-ent">&amp;amp;</span><span class="h-ent">&amp;gt;</span>\n<span class="h-ent">&amp;quot;</span><span class="h-ab">&lt;/</span><span class="h-tag">span</span><span class="h-ab">&gt;</span><span class="h-ab">&lt;</span><span class="h-tag">span</span> <span class="h-attr">class</span>=<span class="h-attv">"sc</span>"<span class="h-ab">&gt;</span>;<span class="h-ab">&lt;/</span><span class="h-tag">span</span><span class="h-ab">&gt;</span>            <span class="h-ab">&lt;</span><span class="h-tag">span</span> <span class="h-attr">class</span>=<span class="h-attv">"c</span>"<span class="h-ab">&gt;</span># Match:   <span class="h-ent">&amp;lt;</span>cross<span class="h-ent">&amp;gt;</span><span class="h-ab">&lt;/</span><span class="h-tag">span</span><span class="h-ab">&gt;</span>
679<span class="h-lno">  5</span>     <span class="h-ab">&lt;</span><span class="h-tag">span</span> <span class="h-attr">class</span>=<span class="h-attv">"k</span>"<span class="h-ab">&gt;</span>print<span class="h-ab">&lt;/</span><span class="h-tag">span</span><span class="h-ab">&gt;</span> <span class="h-ab">&lt;</span><span class="h-tag">span</span> <span class="h-attr">class</span>=<span class="h-attv">"q</span>"<span class="h-ab">&gt;</span><span class="h-ent">&amp;quot;</span>Right:   <span class="h-ent">&amp;lt;</span>$'<span class="h-ent">&amp;gt;</span>\n<span class="h-ent">&amp;quot;</span><span class="h-ab">&lt;/</span><span class="h-tag">span</span><span class="h-ab">&gt;</span><span class="h-ab">&lt;</span><span class="h-tag">span</span> <span class="h-attr">class</span>=<span class="h-attv">"sc</span>"<span class="h-ab">&gt;</span>;<span class="h-ab">&lt;/</span><span class="h-tag">span</span><span class="h-ab">&gt;</span>            <span class="h-ab">&lt;</span><span class="h-tag">span</span> <span class="h-attr">class</span>=<span class="h-attv">"c</span>"<span class="h-ab">&gt;</span># Right:   <span class="h-ent">&amp;lt;</span> buns<span class="h-ent">&amp;gt;</span><span class="h-ab">&lt;/</span><span class="h-tag">span</span><span class="h-ab">&gt;</span></pre>
680
681=end html
682
683=head2 Caveats
684
685There were a few things to keep in mind when mixing verbatim and text paragraphs
686in a C<=begin> block. These problems do not exist any more as from version
6870.06.
688
689=over 4
690
691=item Text paragraphs are not processed for POD escapes any more
692
693Because the C<=begin> / C<=end> block is now processed as a single
694string of text, the following block:
695
696    =begin filter html
697
698    B<foo>
699
700    =end
701
702will not be transformed into C< <b>foo</b> > before being passed to the
703filters, but will produce the expected:
704
705    <pre>B<span class="h-ab">&lt;</span><span class="h-tag">foo</span><span class="h-ab">&gt;</span></pre>
706
707=begin html
708
709<p>This will be rendered by your web browser as:</p>
710
711    <pre>B<span class="h-ab">&lt;</span><span class="h-tag">foo</span><span class="h-ab">&gt;</span></pre>
712
713=end html
714
715And the same text in a verbatim block
716
717    =begin filter html
718
719        B<foo>
720
721    =end
722
723will produce the same results.
724
725    <pre>    B<span class="h-ab">&lt;</span><span class="h-tag">foo</span><span class="h-ab">&gt;</span></pre>
726
727=begin html
728
729<p>Which a web browser will render as:</p>
730
731    <pre>    B<span class="h-ab">&lt;</span><span class="h-tag">foo</span><span class="h-ab">&gt;</span></pre>
732
733=end html
734
735Which looks quite the same, doesn't it?
736
737=item Separate paragraphs aren't filtered separately any more
738
739As seen in L<A note on verbatim and text blocks>, the filter now processes
740the begin block as a single string of text. So, if you have a filter
741that replace each C<*> character with an auto-incremented number in
742square brackets, like this:
743
744    $view->add(
745        notes => {
746            code => sub {
747                my ( $text, $opt ) = @_;
748                my $n = $opt =~ /(\d+)/ ? $1 : 1;
749                $text =~ s/\*/'[' . $n++ . ']'/ge;
750                $text;
751              }
752        }
753    );
754
755And you try to process the following block:
756
757    =begin filter notes 2
758
759    TIMTOWDI*, but your library should DWIM* when possible.
760
761    You can't always claims that PICNIC*, can you?
762
763    =end filter
764
765You'll get the expected result (contrary to previous versions):
766
767    <p>TIMTOWDI[2], but your library should DWIM[3] when possible.
768
769    You can't always claims that PICNIC[4], can you?</p>
770
771The filter was really called only once, starting at C<2>, just like requested.
772
773Future versions of C<Pod::POM::View::HTML::Filter> I<may> support
774C<init>, C<begin> and C<end> callbacks to run filter initialisation and
775clean up code.
776
777=back
778
779=head1 METHODS
780
781=head2 Public methods
782
783The following methods are available:
784
785=over 4
786
787=item C<< add( lang => { I<options> }, ... ) >>
788
789Add support for one or more languages. Options are passed in a hash
790reference.
791
792The required C<code> option is a reference to the filter routine. The
793filter must take a string as its only argument and return the formatted
794HTML string (coloured accordingly to the language grammar, hopefully).
795
796Available options are:
797
798    Name       Type       Content
799    ----       ----       -------
800
801    code       CODEREF    filter implementation
802
803    verbatim   BOOLEAN    if true, force the full content of the
804                          =begin/=end block to be passed verbatim
805                          to the filter
806
807    requires   ARRAYREF   list of required modules for this filter
808
809Note that C<add()> is both a class and an instance method.
810
811When used as a class method, the new language is immediately available
812for all future and existing instances.
813
814When used as an instance method, the new language is only available for
815the instance itself.
816
817=item C<delete( $lang )>
818
819Remove the given language from the list of class or instance filters.
820The deleted filter is returned by this method.
821
822C<delete()> is both a class and an instance method, just like C<add()>.
823
824=item C<filters()>
825
826Return the list of languages supported.
827
828=item C<know( I<$lang> )>
829
830Return true if the view knows how to handle language C<$lang>.
831
832=back
833
834=head2 Overloaded methods
835
836The following C<Pod::POM::View::HTML> methods are overridden in
837C<Pod::POM::View::HTML::Filter>:
838
839=over 4
840
841=item C<new()>
842
843The overloaded constructor initialises some internal structures.
844This means that you'll have to use a instance of the class as a
845view for your C<Pod::POM> object. Therefore you must use C<new>.
846
847    $Pod::POM::DEFAULT_VIEW = 'Pod::POM::View::HTML::Filter'; # WRONG
848    $pom->present( 'Pod::POM::View::HTML::Filter' );          # WRONG
849
850    # this is CORRECT
851    $Pod::POM::DEFAULT_VIEW = Pod::POM::View::HTML::Filter->new;
852
853    # this is also CORRECT
854    my $view = Pod::POM::View::HTML::Filter->new;
855    $pom->present( $view );
856
857The only option at this time is C<auto_unindent>, which is enabled by
858default. This option remove leading indentation from all verbatim blocks
859within the begin blocks, and put it back after highlighting.
860
861=item C<view_begin()>
862
863=item C<view_for()>
864
865These are the methods that support the C<filter> format.
866
867=back
868
869=head1 FILTERS
870
871=head2 Built-in filters
872
873C<Pod::POM::View::HTML::Filter> is shipped with a few built-in filters.
874
875The name for the filter is obtained by removing C<_filter> from the
876names listed below (except for C<default>):
877
878=over 4
879
880=item default
881
882This filter is called when the required filter is not known by
883C<Pod::POM::View::HTML::Filter>. It does nothing more than normal POD
884processing (POD escapes for text paragraphs and C<< <pre> >> for
885verbatim paragraphs.
886
887You can use the C<delete()> method to remove a filter and therefore
888make it behave like C<default>.
889
890=item perl_tidy_filter
891
892This filter does Perl syntax highlighting with a lot of help from
893C<Perl::Tidy>.
894
895It accepts options to C<Perl::Tidy>, such as C<-nnn> to number lines of
896code. Check C<Perl::Tidy>'s documentation for more information about
897those options.
898
899=item perl_ppi_filter
900
901This filter does Perl syntax highlighting using C<PPI::HTML>, which is
902itself based on the incredible C<PPI>.
903
904It accepts the same options as C<PPI::HTML>, which at this time solely
905consist of C<line_numbers> to, as one may guess, add line numbers to the
906output.
907
908=item html_filter
909
910This filter does HTML syntax highlighting with the help of
911C<Syntax::Highlight::HTML>.
912
913The filter supports C<Syntax::Highlight::HTML> options:
914
915    =begin filter html nnn=1
916
917    <p>The lines of the HTML code will be numbered.</p>
918    <p>This is line 2.</p>
919
920    =end filter
921
922See C<Syntax::Highlight::HTML> for the list of supported options.
923
924=item shell_filter
925
926This filter does shell script syntax highlighting with the help of
927C<Syntax::Highlight::Shell>.
928
929The filter supports C<Syntax::Highlight::Shell> options:
930
931    =begin filter shell nnn=1
932
933        #!/bin/sh
934        echo "This is a foo test" | sed -e 's/foo/shell/'
935
936    =end filter
937
938See C<Syntax::Highlight::Shell> for the list of supported options.
939
940=item kate_filter
941
942This filter support syntax highlighting for numerous languages
943with the help of C<Syntax::Highlight::Engine::Kate>.
944
945The filter supports C<Syntax::Highlight::Engine::Kate> languages as options:
946
947     =begin filter kate Diff
948
949         Index: lib/Pod/POM/View/HTML/Filter.pm
950         ===================================================================
951         --- lib/Pod/POM/View/HTML/Filter.pm     (revision 99)
952         +++ lib/Pod/POM/View/HTML/Filter.pm     (working copy)
953         @@ -27,6 +27,11 @@
954                  requires => [qw( Syntax::Highlight::Shell )],
955                  verbatim => 1,
956              },
957         +    kate => {
958         +        code     => \&kate_filter,
959         +        requires => [qw( Syntax::Highlight::Engine::Kate )],
960         +        verbatim => 1,
961         +    },
962          );
963
964          my $HTML_PROTECT = 0;
965
966     =end filter
967
968Check the C<Syntax::Highlight::Engine::Kate> documentation for the full
969list of supported languages. Please note that some of them aren't well
970supported yet (by C<Syntax::Highlight::Engine::Kate>), so the output
971may not be what you expect.
972
973Here is a list of languages we have successfully tested with
974C<Syntax::Highlight::Engine::Kate> version 0.02:
975C<C>, C<Diff>, C<Fortran>, C<JavaScript>, C<LDIF>, C<SQL>.
976
977=item wiki_filter
978
979This filter converts the wiki format parsed by C<Text::WikiFormat>
980in HTML.
981
982The supported options are: C<prefix>, C<extended>, C<implicit_links>,
983C<absolute_links>. The option and value are separated by a C<=> character,
984as in the example below:
985
986    =begin filter wiki extended=1
987
988    [link|title]
989
990    =end
991
992=item wikimedia_filter
993
994This filter converts the wiki format parsed by C<Text::MediawikiFormat>
995in HTML.
996
997The supported options are: C<prefix>, C<extended>, C<implicit_links>,
998C<absolute_links> and C<process_html>. The option and value are separated
999by a C<=> character.
1000
1001=back
1002
1003=head2 Writing your own filters
1004
1005Write a filter is quite easy: a filter is a subroutine that takes two
1006arguments (text to parse and option string) and returns the filtered
1007string.
1008
1009The filter is added to C<Pod::POM::View::HTML::Filter>'s internal filter
1010list with the C<add()> method:
1011
1012    $view->add(
1013        foo => {
1014            code     => \&foo_filter,
1015            requires => [],
1016        }
1017    );
1018
1019When presenting the following piece of pod,
1020
1021    =begin filter foo bar baz
1022
1023    Some text to filter.
1024
1025    =end filter
1026
1027the C<foo_filter()> routine will be called with two arguments, like this:
1028
1029    foo_filter( "Some text to filter.", "bar baz" );
1030
1031If you have a complex set of options, your routine will have to parse
1032the option string by itself.
1033
1034Please note that in a C<=for> construct, whitespace in the option string
1035must be replaced with colons:
1036
1037    =for filter=foo:bar:baz Some text to filter.
1038
1039The C<foo_filter()> routine will be called with the same two arguments
1040as before.
1041
1042=head1 BUILT-IN FILTERS CSS STYLES
1043
1044Each filter uses its own CSS classes, so that one can define their
1045favourite colours in a custom CSS file.
1046
1047=head2 C<perl> filter
1048
1049C<Perl::Tidy>'s HTML code looks like:
1050
1051    <span class="i">$A</span>++<span class="sc">;</span>
1052
1053Here are the classes used by C<Perl::Tidy>:
1054
1055    n        numeric
1056    p        paren
1057    q        quote
1058    s        structure
1059    c        comment
1060    v        v-string
1061    cm       comma
1062    w        bareword
1063    co       colon
1064    pu       punctuation
1065    i        identifier
1066    j        label
1067    h        here-doc-target
1068    hh       here-doc-text
1069    k        keyword
1070    sc       semicolon
1071    m        subroutine
1072    pd       pod-text
1073
1074=head2 C<ppi> filter
1075
1076C<PPI::HTML> uses the following CSS classes:
1077
1078    comment
1079    double
1080    heredoc_content
1081    interpolate
1082    keyword            for language keywords (my, use
1083    line_number
1084    number
1085    operator           for language operators
1086    pragma             for pragmatas (strict, warnings)
1087    single
1088    structure          for syntaxic symbols
1089    substitute
1090    symbol
1091    word               for module, function and method names
1092    words
1093    match
1094
1095=head2 C<html> filter
1096
1097C<Syntax::Highlight::HTML> makes use of the following classes:
1098
1099    h-decl   declaration    # declaration <!DOCTYPE ...>
1100    h-pi     process        # process instruction <?xml ...?>
1101    h-com    comment        # comment <!-- ... -->
1102    h-ab     angle_bracket  # the characters '<' and '>' as tag delimiters
1103    h-tag    tag_name       # the tag name of an element
1104    h-attr   attr_name      # the attribute name
1105    h-attv   attr_value     # the attribute value
1106    h-ent    entity         # any entities: &eacute; &#171;
1107
1108=head2 C<shell> filter
1109
1110C<Syntax::Highlight::Shell> makes use of the following classes:
1111
1112    s-key                   # shell keywords (like if, for, while, do...)
1113    s-blt                   # the builtins commands
1114    s-cmd                   # the external commands
1115    s-arg                   # the command arguments
1116    s-mta                   # shell metacharacters (|, >, \, &)
1117    s-quo                   # the single (') and double (") quotes
1118    s-var                   # expanded variables: $VARIABLE
1119    s-avr                   # assigned variables: VARIABLE=value
1120    s-val                   # shell values (inside quotes)
1121    s-cmt                   # shell comments
1122
1123=head2 C<kate> filter
1124
1125Output formatted with C<Syntax::Highlight::Engine::Kate> makes use
1126of the following classes:
1127
1128    k-alert                 # Alert
1129    k-basen                 # BaseN
1130    k-bstring               # BString
1131    k-char                  # Char
1132    k-comment               # Comment
1133    k-datatype              # DataType
1134    k-decval                # DecVal
1135    k-error                 # Error
1136    k-float                 # Float
1137    k-function              # Function
1138    k-istring               # IString
1139    k-keyword               # Keyword
1140    k-normal                # Normal
1141    k-operator              # Operator
1142    k-others                # Others
1143    k-regionmarker          # RegionMarker
1144    k-reserved              # Reserved
1145    k-string                # String
1146    k-variable              # Variable
1147    k-warning               # Warning
1148
1149=head1 HISTORY
1150
1151The goal behind this module was to produce nice looking HTML pages from the
1152articles the French Perl Mongers are writing for the French magazine
1153GNU/Linux Magazine France (L<http://www.linuxmag-france.org/>).
1154
1155The resulting web pages can be seen at
1156L<http://articles.mongueurs.net/magazines/>.
1157
1158=head1 AUTHOR
1159
1160Philippe "BooK" Bruhat, C<< <book@cpan.org> >>
1161
1162=head1 THANKS
1163
1164Many thanks to S�bastien Aperghis-Tramoni (Maddingue), who helped
1165debugging the module and wrote C<Syntax::Highlight::HTML> and
1166C<Syntax::Highlight::Shell> so that I could ship PPVHF with more than
1167one filter. He also pointed me to C<Syntax::Highlight::Engine::Kate>,
1168which led me to clean up PPVHF before adding support for SHEK.
1169
1170Perl code examples where borrowed in Amelia,
1171aka I<Programming Perl, 3rd edition>.
1172
1173=head1 TODO
1174
1175There are a few other syntax highlighting modules on CPAN, which I should
1176try to add support for in C<Pod::POM::View::HTML::Filter>:
1177
1178=over 4
1179
1180=item *
1181
1182C<Syntax::Highlight::Universal>
1183
1184=item *
1185
1186C<Syntax::Highlight::Mason>
1187
1188=item *
1189
1190C<Syntax::Highlight::Perl> (seems old)
1191
1192=item *
1193
1194C<Syntax::Highlight::Perl::Improved>
1195
1196=back
1197
1198=head1 BUGS
1199
1200Please report any bugs or feature requests to
1201C<bug-pod-pom-view-html-filter@rt.cpan.org>, or through the web interface at
1202L<http://rt.cpan.org>.  I will be notified, and then you'll automatically
1203be notified of progress on your bug as I make changes.
1204
1205=head1 COPYRIGHT & LICENSE
1206
1207Copyright 2004 Philippe "BooK" Bruhat, All Rights Reserved.
1208
1209This program is free software; you can redistribute it and/or modify it
1210under the same terms as Perl itself.
1211
1212=cut
1213
1214