#!/usr/bin/perl
use strict;
use warnings;
#
# the view that turns pod into S5
#
package Pod::POM::View::MyHTML;
use base 'Pod::POM::View::HTML::Filter';
sub view_pod {
my ( $self, $pod ) = @_;
$pod->content->present($self);
}
sub view_head1 {
my ( $self, $pod ) = @_;
qq'
\n
'
. $pod->title->present($self)
. qq'
\n
\n'
. $pod->content->present($self)
. qq'
\n';
}
# add support for ul classes (incremental style, etc.)
my @OVER;
# because @OVER is a private variable in Pod::POM::View::HTML,
# I had to copy view_item() verbatim, in addition to the slightly
# modified view_over() :-(
sub view_over {
my ($self, $over) = @_;
my ($start, $end, $strip);
my $items = $over->item();
return "" unless @$items;
my $first_title = $items->[0]->title();
my $style =
$over->indent =~ /^incremental/ ? ' class="' . $over->indent . '"' : '';
if ($first_title =~ /^\s*\*\s*/) {
# '=item *' =>
$start = "\n";
$strip = qr/^\s*\*\s*/;
}
elsif ($first_title =~ /^\s*\d+\.?\s*/) {
# '=item 1.' or '=item 1 ' =>
$start = "\n";
$end = "
\n";
$strip = qr/^\s*\d+\.?\s*/;
}
else {
$start = "\n";
$strip = '';
}
my $overstack = ref $self ? $self->{ OVER } : \@OVER;
push(@$overstack, $strip);
my $content = $over->content->present($self);
pop(@$overstack);
return $start
. $content
. $end;
}
# this block is straight from Pod::POM::View::HTML :-(
sub view_item {
my ($self, $item) = @_;
my $over = ref $self ? $self->{ OVER } : \@OVER;
my $title = $item->title();
my $strip = $over->[-1];
if (defined $title) {
$title = $title->present($self) if ref $title;
$title =~ s/$strip// if $strip;
if (length $title) {
my $anchor = $title;
$anchor =~ s/^\s*|\s*$//g; # strip leading and closing spaces
$anchor =~ s/\W/_/g;
$title = qq{$title};
}
}
return '- '
. "$title\n"
. $item->content->present($self)
. "
\n";
}
#
# the actual spod5 script
#
package main;
use Pod::POM 'meta';
use Pod::POM::View::HTML::Filter;
use Getopt::Long;
use Template;
use File::Spec;
use File::Basename;
our $VERSION = '0.02';
# usage message
my $usage = << "USAGE";
Available options:
--quiet : be silent
--force : clobber existing html files
--exec : enables =exec lines
--base : directory containing the S5 .css and .js files
--slides : alternate slides.css (relative to --base)
--debug : print the intermediate pod to STDOUT
--multi : create one HTML file per slide
USAGE
# basic command-line params
my %conf = (
quiet => 0,
force => 0,
debug => 0,
base => File::Spec->catfile( 'ui', 'default' ),
slides => 'slides.css',
exec => 0,
multi => 0,
);
GetOptions( \%conf, "quiet!", "force!", "debug!", "base=s", "exec!",
"slides=s", "multi!", "help!", "version!" )
or die $usage;
# information
print STDERR "spod5 version $VERSION\n" if $conf{version};
print STDERR $usage if $conf{help};
exit if $conf{help} || $conf{version};
# all the useful stuff here
my $parser = Pod::POM->new();
my $tt = Template->new();
my @template = split /^EOT\n/m, join( '', );
$|++;
# helper sub
sub include {
my ($src, $inc) = @_;
$inc = File::Spec->catfile( dirname($src), $inc )
if !File::Spec->file_name_is_absolute($inc);
open my $fh, "<", $inc
or do { my $err = "$inc: $!"; warn $err; return $err };
my $t = join "\n", <$fh>;
close $fh;
$t;
}
my @files = @ARGV;
for my $file (@files) {
@ARGV = ($file);
( my $new = $file ) =~ s/(?:\.pod)?$/.html/;
print STDERR "$file... " unless $conf{quiet};
next
if !$conf{force}
&& -e $new
&& ( stat $new )[9] > ( stat $file )[9]
&& !$conf{quiet}
&& print STDERR "skipped (use --force)\n";
my $text = join '', <>;
next unless $text;
# convert text shortcuts back to pod
# ain't that plain ugly?
$text =~ s/^(=+) +/=head@{[length $1]} /gm;
$text =~ s/^\* +/\n=item *\n\n/gm;
$text =~ s/^# +/\n=item 1\n\n/gm;
$text =~ s/^\+\s*$/\n=over 4\n/gm;
$text =~ s/^\+>\s*$/\n=over incremental show-first\n/gm;
$text =~ s/^\+>>\s*$/\n=over incremental\n/gm;
$text =~ s/^\-\s*$/\n=back\n\n/gm;
$text =~ s/\A\s*//; # Pod::POM does not likes newlines at the beginning
$text =~ s!^{{(.*?)^}}!=for html \n\n$1\n=for html
\n\n!gms;
$text =~ s!^=img\s+(\S+)!=for html
\n\n!gm;
$text =~ s{^=include\s+(\S+)}{include($file, $1)}egm;
$text =~ s{^=exec\s+(.+)}{`$1`}egm if $conf{exec};
# debug the intermediate pod
print STDOUT "\n$text" if $conf{debug};
# parse the pod
my $pom = $parser->parse_text($text);
$pom->metadata( base => $conf{base} );
$pom->metadata( slides => $pom->metadata('slides') || $conf{slides} );
if( $conf{multi} ) {
# file name
$new = basename($new);
$new =~ s/\.html$/%04d.html/;
# print table of contents using each =head1 title
my $n = 0;
my $zero = sprintf( $new, $n );
my $total =()= $pom->head1();
$total--; # counting from 0
for my $slide ($pom->head1()) {
my $prev = $n > 0 ? sprintf( $new, $n - 1 ) : '';
my $next = $n < $total ? sprintf( $new, $n + 1 ) : '';
$tt->process(
\$template[1],
{
pom => $slide,
slide => {
total => $total,
number => $n,
zero => $zero,
next => $next,
prev => $prev,
},
view => Pod::POM::View::MyHTML->new(),
meta => $pom->metadata,
},
sprintf( $new, $n )
)
|| warn $tt->error;
$n++;
}
}
else { # produce the HTML in a single file
$tt->process(
\$template[0],
{
pom => $pom,
view => Pod::POM::View::MyHTML->new(),
meta => $pom->metadata,
},
$new
)
|| warn $tt->error;
}
print STDERR "done\n" unless $conf{quiet};
}
=pod
=head1 NAME
spod5 - Turn pod into S5
=head1 SYNOPSIS
B [--I] [--I] [--I] [I<--base> F]
[--I F] [--I] [--I] [--I]
file.pod [ ... ]
=head1 DESCRIPTION
B is a I tool, that uses C
to add syntax coloring to your slides.
=head2 Command-line options
B supports the following options:
=over 4
=item --I
Do not print information messages.
=item I<--force>
Clobber existing F<.html> files.
=item --I F
Directory where the S5 CSS and JavaScript files are to be found.
Default is F.
=item --I F
Provide a replacement for the standard F file found in
F. This allows one to define their own styles. See also
the C<=meta slides> directive in the source file.
=item --I
Use an alternative template to create an HTML file per slide.
(This is still beta.)
=item --I
Execute the commands in C<=exec> directives.
=item --I
Provide the list of available options and exit.
=item --I
Print version information and exit.
=back
=head1 WRITING A SPOD5 DOCUMENT
Writing a presentation with B is rather easy: all the C<=head1>
headers mark the beginning of a new slide. The rest of the pod mark-up
is converted as usual.
B add several shortcuts and features:
=over 4
=item *
C<=begin filter> / C<=end filter> sections allow support for syntax
highlighting as done by C.
Several shortcuts are recognised:
=item *
convert into a bulleted list (can be nested):
+
* bam
* powie
* kapow
-
=item *
support the C and C classes, by
using an explicit C<=over I
[% meta.title_top %]
[% meta.title %]
[% meta.author %]
[% meta.company %]
[% meta.title_bottom %]
[% pom.present(view) %]