File Coverage

blib/lib/Vroom.pm
Criterion Covered Total %
statement 43 379 11.3
branch 0 170 0.0
condition 0 15 0.0
subroutine 15 49 30.6
pod 1 31 3.2
total 59 644 9.1


line stmt bran cond sub pod time code
1 2     2   41631 use strict; use warnings;
  2     2   4  
  2         109  
  2         12  
  2         4  
  2         104  
2             package Vroom;
3             our $VERSION = '0.37';
4 2     2   1043 use Vroom::Mo;
  2         12  
  2         12  
5              
6 2     2   3043 use File::HomeDir;
  2         14636  
  2         159  
7 2     2   1798 use IO::All;
  2         32803  
  2         21  
8 2     2   2074 use Template::Toolkit::Simple;
  2         147757  
  2         120  
9 2     2   2011 use Term::Size;
  2         7023  
  2         107  
10 2     2   19 use YAML::XS;
  2         4  
  2         100  
11              
12 2     2   11 use Getopt::Long;
  2         3  
  2         20  
13 2     2   296 use Cwd;
  2         4  
  2         116  
14 2     2   11 use Carp;
  2         5  
  2         96  
15              
16 2     2   33 use Encode;
  2         5  
  2         2451  
17              
18             has input => 'slides.vroom';
19             has notesfile => 'notes.txt';
20             has has_notes => 0;
21             has stream => '';
22             has ext => '';
23             has help => 0;
24             has clean => 0;
25             has compile => 0;
26             has sample => 0;
27             has run => 0;
28             has html => 0;
29             has text => 0;
30             has ghpublish => 0;
31             has start => 0;
32             has digits => 0;
33             has skip => 0;
34             has config => {
35             title => 'Untitled Presentation',
36             height => 24,
37             width => 80,
38             list_indent => 10,
39             skip => 0,
40             vim => 'vim',
41             vim_opts => '-u NONE',
42             vimrc => '',
43             gvimrc => '',
44             script => '',
45             auto_size => 0,
46             };
47              
48             sub usage {
49 0     0 0   return <<'...';
50             Usage: vroom [options]
51              
52             Commands:
53             new - Create a sample 'slides.vroom' file
54             vroom - Start slideshow
55             compile - Generate slides
56             html - Publish slides as HTML
57             text - Publish slides as plain text
58             clean - Delete generated files
59             help - Get help!
60              
61             Options:
62             --skip=# - Skip # of slides
63             --input=name - Specify an input file name
64              
65             ...
66             }
67              
68             sub vroom {
69 0 0   0 1   my $self = ref($_[0]) ? shift : (shift)->new;
70              
71 0           $self->getOptions;
72              
73 0 0         if ($self->sample) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
74 0           $self->sampleSlides;
75             }
76             elsif ($self->run) {
77 0           $self->runSlide;
78             }
79             elsif ($self->clean) {
80 0           $self->cleanAll;
81             }
82             elsif ($self->compile) {
83 0           $self->makeSlides;
84             }
85             elsif ($self->start) {
86 0           $self->makeSlides;
87 0           $self->startUp;
88             }
89             elsif ($self->html) {
90 0           $self->makeHTML;
91             }
92             elsif ($self->text) {
93 0           $self->makeText;
94             }
95             elsif ($self->ghpublish) {
96 0           $self->makePublisher;
97             }
98             elsif ($self->help) {
99 0           warn $self->usage;
100             }
101             else {
102 0           warn $self->usage;
103             }
104             }
105              
106             sub getOptions {
107 0     0 0   my $self = shift;
108              
109 0 0         die <<'...' if cwd eq File::HomeDir->my_home;
110              
111             Don't run vroom in your home directory.
112              
113             Create a new directory for your slides and run vroom from there.
114             ...
115              
116 0 0         my $cmd = shift(@ARGV) or die $self->usage;
117 0 0         die $self->usage unless $cmd =~ s/
118             ^-{0,2}(
119             help |
120             new |
121             vroom |
122             compile |
123             run |
124             html |
125             text |
126             clean |
127             ghpublish
128             )$
129             /$1/x;
130 0 0         $cmd = 'start' if $cmd eq 'vroom';
131 0 0         $cmd = 'sample' if $cmd eq 'new';
132 0           $self->{$cmd} = 1;
133              
134 0 0         GetOptions(
135             "input=s" => \$self->{input},
136             "skip=i" => \$self->{skip},
137             ) or die $self->usage;
138              
139 0 0         do { delete $self->{$_} unless defined $self->{$_} }
140 0           for qw(clean compile input vroom);
141             }
142              
143             sub cleanUp {
144 0     0 0   my $self = shift;
145 0           unlink(glob "0*");
146 0           unlink('.help');
147 0           unlink('.vimrc');
148 0           unlink('.gvimrc');
149 0           unlink('run.slide');
150 0           unlink($self->notesfile);
151 0           io->dir('bin')->rmtree;
152 0           io->dir('done')->rmtree;
153             }
154              
155             sub cleanAll {
156 0     0 0   my $self = shift;
157 0           $self->cleanUp;
158 0           io->dir('html')->rmtree;
159 0           io->dir('text')->rmtree;
160             }
161              
162             sub runSlide {
163 0     0 0   my $self = shift;
164 0           my $slide = $ARGV[0];
165              
166 0 0         if ($slide =~ /\.pl$/) {
167 0           exec "clear; $^X $slide";
168             }
169              
170 0           $self->trim_slide;
171              
172 0 0         if ($slide =~ /\.py$/) {
    0          
    0          
    0          
    0          
    0          
    0          
173 0           exec "clear; python run.slide";
174             }
175             elsif ($slide =~ /\.rb$/) {
176 0           exec "clear; ruby run.slide";
177             }
178             elsif ($slide =~ /\.php$/) {
179 0           exec "clear; php run.slide";
180             }
181             elsif ($slide =~ /\.js$/) {
182 0           exec "clear; js run.slide";
183             }
184             elsif ($slide =~ /\.hs$/) {
185 0           exec "clear; runghc run.slide";
186             }
187             elsif ($slide =~ /\.yaml$/) {
188 0           exec "clear; $^X -MYAML::XS -MData::Dumper -e '\$Data::Dumper::Terse = 1; \$Data::Dumper::Indent = 1; print Dumper YAML::XS::LoadFile(shift)' run.slide";
189             }
190             elsif ($slide =~ /\.sh$/) {
191 0           exec "clear; $ENV{SHELL} -i run.slide";
192             }
193             }
194              
195             sub trim_slide {
196 0     0 0   my $self = shift;
197 0           my $slide = $ARGV[0];
198              
199 0           my $text < io($slide);
200 0           $text =~ s/^\s*\n//;
201 0           $text =~ s/\n\s*$/\n/;
202 0           while ($text !~ /^\S/m) {
203 0           $text =~ s/^ //mg;
204             }
205 0           $text > io('run.slide');
206             }
207              
208             sub makeSlides {
209 0     0 0   my $self = shift;
210 0           $self->cleanUp;
211 0           $self->getInput;
212 0           $self->buildSlides;
213 0           $self->writeVimrc;
214 0           $self->writeScriptRunner;
215 0           $self->writeHelp;
216             }
217              
218             sub makeText {
219 0     0 0   my $self = shift;
220 0           $self->cleanAll;
221 0           $self->makeSlides;
222 0           io('text')->mkdir;
223 0           my @slides = glob('0*');
224 0           for my $slide (@slides) {
225 0 0         next unless $slide =~ /^(\d+)(\.\S+)?$/;
226 0           my $num = $1;
227 0   0       my $ext = $2 || '';
228 0 0         my $text = io(-e "${num}z$ext" ? "${num}z$ext" : "$num$ext")->all();
229 0           io("text/$slide")->print($text);
230             }
231 0           eval {
232 0           system("cp .vimrc text");
233             };
234 0           $self->cleanUp;
235             }
236              
237             sub makeHTML {
238 0     0 0   my $self = shift;
239 0           $self->cleanAll;
240 0           $self->makeSlides;
241 0           io('html')->mkdir;
242 0           my @slides = glob('0*');
243 0           my @notes = $self->parse_notesfile;
244 0           for (my $i = 0; $i < @slides; $i++) {
245 0           my $slide = $slides[$i];
246 0 0         my $prev = ($i > 0) ? $slides[$i - 1] : 'index';
247 0 0         my $next = ($i + 1 < @slides) ? $slides[$i + 1] : '';
248 0           my $text = io($slide)->all;
249 0           $text = Template::Toolkit::Simple->new()->render(
250             $self->slideTemplate,
251             {
252             title => $notes[$i]->{'title'},
253             prev => $prev,
254             next => $next,
255             content => decode_utf8($text),
256             notes => $self->htmlize_note($notes[$i]->{'text'}),
257             }
258             );
259 0           io("html/$slide.html")->print($text);
260             }
261              
262 0           my $index = [];
263 0           for (my $i = 0; $i < @slides; $i++) {
264 0           my $slide = $slides[$i];
265 0 0         next if $slide =~ /^\d+[a-z]/;
266 0           my $title = io($slide)->all;
267 0           $title =~ s/.*?((?-s:\S.*)).*/$1/s;
268 0           push @$index, [$slide, decode_utf8($title)];
269             }
270              
271 0           io("html/index.html")->print(
272             Template::Toolkit::Simple->new()->render(
273             $self->indexTemplate,
274             {
275             config => $self->config,
276             index => $index,
277              
278             }
279             )
280             );
281 0           $self->cleanUp;
282             }
283              
284             sub indexTemplate {
285             \ <<'...'
286            
287            
288             [% config.title | html %]
289            
290            
302            
310            
311            
312            

Use SPACEBAR to peruse the slides or click one to start...

313            

[% config.title | html %]

314            
315             [% FOR entry = index -%]
316             [% slide = entry.shift() -%]
317             [% title = entry.shift() -%]
318            
  • [% title | html %]
  • 319             [% END -%]
    320            
    321            

    This presentation was generated by

    322             href="http://ingydotnet.github.com/vroom-pm">Vroom. Use <SPACE> key to go
    323             forward and <BACKSPACE> to go backwards.
    324            

    325            
    326            
    327             ...
    328 0     0 0   }
    329              
    330             sub slideTemplate {
    331             \ <<'...'
    332            
    333            
    334             [% title | html %]
    335            
    336            
    360            
    361            
    362            
    363            
     
    364             [%- content | html -%]
    365            
    366            
    367            
    368            
    369            

    [% notes %]

    370            
    371            
    372            
    373             ...
    374 0     0 0   }
    375              
    376             sub getInput {
    377 0     0 0   my $self = shift;
    378 0 0         my @stream = io($self->input)->slurp
    379             or croak "No input provided. Make a file called 'slides.vroom'";
    380 0 0         my $stream = join '', map {
    381 0           /^----\s+include\s+(\S+)/
    382             ? scalar(io($1)->all)
    383             : $_
    384             } @stream;
    385 0           $self->stream($stream);
    386             }
    387              
    388             my $TRANSITION = qr/^\+/m;
    389             my $SLIDE_MARKER = qr/^={4}\n/m;
    390             my $TITLE_MARKER = qr/^%\s*(.*?)\n/m;
    391              
    392             sub buildSlides {
    393 0     0 0   my $self = shift;
    394 0           my @split = split /^(----\ *.*)\n/m, $self->stream;
    395 0           shift @split;
    396 0           @split = grep length, @split;
    397 0 0         push @split, '----' if $split[0] =~ /\n/;
    398 0           my (@raw_configs, @raw_slides);
    399 0           while (@split) {
    400 0           my ($config, $slide) = splice(@split, 0, 2);
    401 0           $config =~ s/^----\s*(.*?)\s*$/$1/;
    402 0           push @raw_configs, $config;
    403 0           push @raw_slides, $slide;
    404 0 0         $self->has_notes(1) if $slide =~ $SLIDE_MARKER;
    405             }
    406 0           $self->{digits} = int(log(@raw_slides)/log(10)) + 2;
    407              
    408 0           my $number = 0;
    409              
    410 0 0         '' > io($self->notesfile) if $self->has_notes; # start with a blank file so we can append
    411 0           for my $raw_slide (@raw_slides) {
    412 0           my $config = $self->parseSlideConfig(shift @raw_configs);
    413              
    414 0 0         next if $config->{skip};
    415              
    416             # could move the increment of $number up here, but then we'd count config slides
    417             # and we don't really want to do that
    418             # so just use $number + 1 for now, and we'll increment below
    419 0           my ($title, $notes) = $self->extract_notes($raw_slide, $number + 1);
    420              
    421 0 0         $raw_slide = $self->applyOptions($raw_slide, $config)
    422             or next;
    423              
    424 0           $number++;
    425              
    426 0 0 0       if ($self->config->{skip} or $self->skip) {
    427 0 0         $self->config->{skip}-- if $self->config->{skip};
    428 0 0         $self->{skip}-- if $self->{skip};
    429 0           next;
    430             }
    431              
    432 0 0         $self->print_notes($title, $number, $notes) if $self->has_notes;
    433              
    434 0           $raw_slide = $self->padVertical($raw_slide);
    435              
    436 0           my @slides;
    437             my @scripts;
    438 0           my $slide = '';
    439 0           for my $part (split /$TRANSITION/, $raw_slide) {
    440 0 0         $slide = '' if $config->{replace};
    441 0           my $script = '';
    442 0 0         if ($self->config->{script}) {
    443 0           ($part, $script) = $self->parseScript($part);
    444             }
    445 0           $slide .= $part;
    446 0 0         $slide = $self->padVertical($slide)
    447             if $config->{replace};
    448 0           push @slides, $slide;
    449 0           push @scripts, $script;
    450             }
    451              
    452 0           my $base_name = $self->formatNumber($number);
    453              
    454 0           my $suffix = 'a';
    455 0           for (my $i = 1; $i <= @slides; $i++) {
    456 0           my $slide = $self->padFullScreen($slides[$i - 1]);
    457 0           chomp $slide;
    458 0           $slide .= "\n";
    459 0 0         if ($slide =~ s/^\ *!(.*\n)//m) {
    460 0           $slide .= $1;
    461             }
    462             # this option can't be applied ahead of time
    463 0 0         if ($config->{undent}) {
    464 0           my $undent = $config->{undent};
    465 0           $slide =~ s/^.{$undent}//gm;
    466             }
    467 0           $slide =~ s{^\ *==\ +(.*?)\ *$}
    468 0           {' ' x (($self->config->{width} - length($1)) / 2) . $1}gem;
    469 0           my $suf = $suffix++;
    470 0 0         $suf = $suf eq 'a'
        0          
    471             ? ''
    472             : $i == @slides
    473             ? 'z'
    474             : $suf;
    475 0           my $file_name = "$base_name$suf" . $self->ext;
    476 0           io($file_name)->print($slide);
    477 0 0         if (my $script = shift @scripts) {
    478 0           io("bin/$file_name")->assert->print($script);
    479             }
    480             }
    481             }
    482             }
    483              
    484             my $NEXT_SLIDE = '';
    485              
    486             sub extract_notes {
    487 0     0 0   my $self = shift;
    488             # have to deal with the slide argument in $_[0] directly so we can modify it
    489 0           my $number = $_[1];
    490              
    491 0 0         my $title = $_[0] =~ s/$TITLE_MARKER// ? $1 : "Slide $number";
    492 0 0         my $notes = $_[0] =~ s/$SLIDE_MARKER(.*)\s*\Z//s ? $1 : '';
    493              
    494             # verify that the number of transitions in the notes matches the number of transitions in the slide
    495             # if not, do something about it
    496             # (note: using a secret operator here; see http://www.catonmat.net/blog/secret-perl-operators/#goatse )
    497 0           my $num_slide_transitions =()= $_[0] =~ /$TRANSITION/g;
    498 0           my $num_notes_transitions =()= $notes =~ /$TRANSITION/g;
    499 0 0         if ($num_notes_transitions < $num_slide_transitions)
        0          
    500             {
    501             # add more transitions
    502 0           $notes .= "\n+" x ($num_slide_transitions - $num_notes_transitions);
    503             }
    504             elsif ($num_notes_transitions > $num_slide_transitions)
    505             {
    506             # warn, and then remove transitions
    507             # we'll reverse the string so we can remove transitions from back to front
    508 0           warn("too many transitions for slide $title");
    509 0           $notes = reverse $notes;
    510 0           $notes =~ s/\+\n/\n/ for 1..($num_notes_transitions - $num_slide_transitions);
    511 0           $notes = reverse $notes;
    512             }
    513              
    514 0           $notes =~ s/$TRANSITION/$NEXT_SLIDE\n/g;
    515              
    516 0           return ($title, $notes);
    517             }
    518              
    519             sub print_notes {
    520 0     0 0   my $self = shift;
    521 0           my ($title, $number, $notes) = @_;
    522              
    523 0 0         "\n" . ($number == 1 ? ' ' x length($NEXT_SLIDE) : $NEXT_SLIDE) . " -- $title --\n\n$notes\n" >> io($self->notesfile);
    524             }
    525              
    526             sub parse_notesfile
    527             {
    528 0     0 0   my $self = shift;
    529              
    530 0 0         return () unless -r $self->notesfile;
    531 0           my $notes = io($self->notesfile)->slurp;
    532              
    533             # first slide doesn't have a marker, so we'll add one, for consistency
    534 0           $notes = $NEXT_SLIDE . $notes;
    535              
    536 0           my @notes;
    537 0           my @stream = split(/\Q$NEXT_SLIDE\E(?:\s+-- (.*?) --)?\s*/, $notes);
    538             # skipping 0 because, since we're starting with what we're splitting on, the first field will
    539             # always be empty
    540 0           for (1..$#stream)
    541             {
    542 0 0         if ($_ % 2)
    543             {
    544 0           my $title = $stream[$_];
    545 0 0         $title = $notes[-1]->{'title'} unless defined $title;
    546 0           push @notes, { title => $title };
    547             }
    548             else
    549             {
    550 0           my $text = $stream[$_];
    551 0           $text =~ s/\s+\Z//;
    552 0           $notes[-1]->{'text'} = $stream[$_];
    553             }
    554             }
    555              
    556 0           return @notes;
    557             }
    558              
    559 2     2   5340 my %inline_tags; BEGIN { %inline_tags = ( BQ => 'code', IT => 'i', BO => 'b', ); }
    560 0     0 0   sub inline_element { my $t = $_[1]; $t =~ s/^.//; $t =~ s/.$//; return "<$inline_tags{$_[0]}>$t" }
      0            
      0            
      0            
    561             sub htmlize_note
    562             {
    563 2     2   2530 use Text::Balanced qw< extract_multiple extract_delimited >;
      2         60635  
      2         4029  
    564              
    565 0     0 0   my $self = shift;
    566 0           my ($note) = @_;
    567 0 0         $note = '' unless defined $note;
    568              
    569 0           $note =~ s{((^\s*\*\s+.+?\n)+)}{"
      " . join('', map { s/^\s*\*\s+//; "
    • $_
    • " } split("\n", $1)) . "
    "}meg;
      0            
      0            
      0            
    570              
    571 0           my @bits;
    572 0 0         $note = join('', map { ref $_ ? scalar((push @bits, inline_element(ref $_, $$_)), "{X$#bits}") : $_ }
    573             extract_multiple($note,
    574             [
    575 0     0     { BQ => sub { extract_delimited($_[0], q{`}, '', q{`}) } },
    576 0     0     { IT => sub { extract_delimited($_[0], q{_}, '', q{_}) } },
    577 0     0     { BO => sub { extract_delimited($_[0], q{*}, '', q{*}) } },
    578 0           qr/[^`_*]+/,
    579             ])
    580             );
    581 0           $note =~ s{--}{—}g;
    582 0           $note =~ s{ \.\.\.}{ ...}g;
    583 0           $note =~ s{\n+}{

    }g;

    584 0           $note =~ s/{X(\d+)}/$bits[$1]/g;
    585              
    586 0           return $note;
    587             }
    588              
    589             sub parseScript {
    590 0     0 0   my $self = shift;
    591 0           my $text = shift;
    592 0           chomp $text;
    593 0           $text .= "\n";
    594 0           my $script = '';
    595 0           my $delim = $self->config->{script};
    596 0           while ($text =~ s/^[\ \t]*\Q$delim\E(.*\n)//m) {
    597 0           $script .= $1;
    598             }
    599 0           return ($text, $script);
    600             }
    601              
    602             sub formatNumber {
    603 0     0 0   my $self = shift;
    604 0           my $number = shift;
    605 0           my $digits = $self->digits;
    606 0           return sprintf "%0${digits}d", $number;
    607             }
    608              
    609             my $types = {
    610             # add pl6 and py3
    611             perl => 'pl', pl => 'pl', pm => 'pm',
    612             ruby => 'rb', rb => 'rb',
    613             python => 'py', py => 'py',
    614             haskell => 'hs', hs => 'hs',
    615             javascript => 'js', js => 'js',
    616             actionscript => 'as', as => 'as',
    617             shell => 'sh', sh => 'sh',
    618             php => 'php',
    619             java => 'java',
    620             yaml => 'yaml',
    621             xml => 'xml',
    622             json => 'json',
    623             html => 'html',
    624             make => 'make',
    625             diff => 'diff',
    626             conf => 'conf',
    627             };
    628             sub parseSlideConfig {
    629 0     0 0   my $self = shift;
    630 0           my $string = shift;
    631 0           my $config = {};
    632 0           my $type_list = join '|', keys %$types;
    633 0           for my $option (split /\s*,\s*/, $string) {
    634 0 0         $config->{$option} = 1
    635             if $option =~ /^cd/;
    636 0 0         $config->{$1} = 1
    637             if $option =~ /^(config|skip|center|replace|$type_list)$/;
    638 0 0         $config->{$1} = 1
    639             if $option =~ /^(\.\w+)$/;
    640 0 0         $config->{indent} = $1
    641             if $option =~ /i(\d+)/;
    642 0 0         $config->{undent} = $1
    643             if $option =~ /i-(\d+)/;
    644             }
    645 0           return $config;
    646             }
    647              
    648             sub applyOptions {
    649 0     0 0   my $self = shift;
    650 0           my ($slide, $config) = @_;
    651              
    652 0           $config = {
    653 0           %{$self->config},
    654             %$config,
    655             };
    656              
    657 0 0         if ($config->{config}) {
    658 0           $config = {
    659 0           %{$self->config},
    660 0           %{(YAML::XS::Load($slide))},
    661             };
    662              
    663 0 0         if ($config->{auto_size}) {
    664 0           my ($columns, $rows) = Term::Size::chars *STDOUT{IO};
    665              
    666 0           $config->{width} = $columns;
    667 0           $config->{height} = $rows;
    668             }
    669              
    670 0           $self->config($config);
    671 0           return '';
    672             }
    673              
    674 0   0       $slide ||= '';
    675 0 0         if ($config->{center}) {
        0          
        0          
    676 0           $slide =~ s{^(\+?)\ *(.*?)\ *$}
    677 0           {$1 . ' ' x (($self->config->{width} - length($2)) / 2) . $2}gem;
    678 0           $slide =~ s{^\s*$}{}gm;
    679             }
    680             elsif (defined $config->{indent}) {
    681 0           my $indent = $config->{indent};
    682 0           $slide =~ s{^(\+?)}{$1 . ' ' x $indent}gem;
      0            
    683             }
    684             elsif ($slide =~ /^\+?\*/m) {
    685 0           my $indent = $config->{list_indent};
    686 0           $slide =~ s{^(\+?)}{$1 . ' ' x $indent}gem;
      0            
    687             }
    688              
    689 0           my $ext = '';
    690 0           for my $key (keys %$config) {
    691 0 0         if (my $e = $types->{$key}) {
        0          
        0          
    692 0           $ext = ".$e";
    693 0           last;
    694             }
    695             elsif ($key =~ s/^cd//) {
    696 0 0         if (my $e = $types->{$key}) {
    697 0           $ext = ".cd.$e";
    698 0           last;
    699             }
    700             }
    701             elsif ($key =~ s/^\.(\w+)//) {
    702 0           $ext = ".$1";
    703 0           last;
    704             }
    705             }
    706 0           $self->ext($ext);
    707              
    708 0           return $slide;
    709             }
    710              
    711             sub padVertical {
    712 0     0 0   my $self = shift;
    713 0           my $slide = shift;
    714 0           $slide =~ s/\A\s*\n//;
    715 0           $slide =~ s/\n\s*\z//;
    716 0           $slide =~ s/ +$//mg;
    717 0           my @lines = split /\n/, $slide;
    718 0           my $lines = @lines;
    719 0           my $before = int(($self->config->{height} - $lines) / 2) - 1;
    720 0           return "\n" x $before . $slide;
    721             }
    722              
    723             sub padFullScreen {
    724 0     0 0   my $self = shift;
    725 0           my $slide = shift;
    726 0           chomp $slide;
    727 0           my @lines = split /\n/, $slide;
    728 0           my $lines = @lines;
    729 0           my $after = $self->config->{height} - $lines + 1;
    730 0           return $slide . "\n" x $after;
    731             }
    732              
    733             sub writeVimrc {
    734 0     0 0   my $self = shift;
    735              
    736 0           my $home_vimrc = File::HomeDir->my_home . "/.vroom/vimrc";
    737 0 0         my $home_vimrc_content = -e $home_vimrc ? io($home_vimrc)->all : '';
    738              
    739 0 0         my $next_cmd = $self->config->{script}
    740             ? ':n::call RunIf():gg'
    741             : ':n:gg';
    742 0 0         my $script_functions = $self->config->{script} ? <<'...' : '';
    743             function RunIf()
    744             let script = "bin/" . expand("%")
    745             let done = "done/" . expand("%")
    746             if filereadable(done)
    747             return
    748             endif
    749             if filereadable(script)
    750             call system("sh " . script)
    751             call system("touch " . done)
    752             endif
    753             return
    754             endfunction
    755              
    756             function RunNow()
    757             let done = "done/" . expand("%")
    758             call system("rm -f " . done)
    759             call RunIf()
    760             endfunction
    761             ...
    762              
    763 0 0 0       die <<'...'
    764             The .vimrc in your current directory does not look like vroom created it.
    765              
    766             If you are sure it can be overwritten, please delete it yourself this one
    767             time, and rerun vroom. You should not get this message again.
    768              
    769             ...
    770             if -e '.vimrc' and io('.vimrc')->getline !~ /Vroom-\d\.\d\d/;
    771              
    772 0           my $title = "%-20f " . $self->config->{title};
    773 0           $title =~ s/\s/\\ /g;
    774 2     2   28 no strict 'refs';
      2         5  
      2         1414  
    775 0           io(".vimrc")->print(<<"...");
    776 0           " This .vimrc file was created by Vroom-${"VERSION"}
      0            
    777             set nocompatible
    778             syntax on
    779             $script_functions
    780             map $next_cmd
    781             map :N:gg
    782             map R :!vroom -run %
    783             map RR :!vroom -run %
    784             map AA :call RunNow():
    785             map VV :!vroom -vroom
    786             map QQ :q!
    787             map OO :!open
    788             map EE :e
    789             map !! G:!open
    790             map ?? :e .help
    791             set laststatus=2
    792             set statusline=$title
    793              
    794             " Overrides from $home_vimrc
    795             $home_vimrc_content
    796              
    797             " Values from slides.vroom config section. (under 'vimrc')
    798             ${\ $self->config->{vimrc}}
    799             ...
    800              
    801 0 0         if ($self->config->{vim} =~ /\bgvim\b/) {
    802 0           my $home_gvimrc = File::HomeDir->my_home . "/.vroom/gvimrc";
    803 0 0         my $home_gvimrc_content = -e $home_gvimrc ? io($home_gvimrc)->all : '';
    804              
    805 0           io(".gvimrc")->print(<<"...");
    806             " Values from slides.vroom config section. (under 'gvimrc')
    807 0           ${\ $self->config->{gvimrc}}
    808              
    809             " Overrides from $home_gvimrc
    810             $home_gvimrc_content
    811             ...
    812             }
    813             }
    814              
    815             sub writeScriptRunner {
    816 0     0 0   my $self = shift;
    817 0 0         return unless $self->config->{script};
    818 0           mkdir 'done';
    819             }
    820              
    821             sub writeHelp {
    822 0     0 0   my $self = shift;
    823 0           io('.help')->print(<<'...');
    824              
    825             Advance
    826             Go back
    827              
    828             ?? Help
    829             QQ Quit Vroom
    830              
    831             RR Run slide as a program
    832             VV vroom vroom
    833             EE Edit file under cursor
    834             OO Open file under cursor (Mac OS X)
    835              
    836              
    837             (Press SPACE to leave Help screen and continue)
    838              
    839             ...
    840             }
    841              
    842             sub startUp {
    843 0     0 0   my $self = shift;
    844 0           my $vim = $self->config->{vim};
    845 0   0       my $vim_opts = $self->config->{vim_opts} || '';
    846 0           exec "$vim $vim_opts '+source .vimrc' 0*";
    847             }
    848              
    849             sub sampleSlides {
    850 0     0 0   my $self = shift;
    851 0           my $file = $self->input;
    852 0 0         die <<"..." if -e $file;
    853             '$file' already exists.
    854              
    855             If you really want to generate a new template slides file,
    856             please delete or move this one.
    857             ...
    858 0           io($file)->print(<<'...');
    859             # This is a sample Vroom input file. It should help you get started.
    860             #
    861             # Edit this file with your content. Then run `vroom vroom` to start
    862             # the show!
    863             #
    864             # See `perldoc Vroom` for complete details.
    865             #
    866             ---- config
    867             # Basic config options.
    868             title: Vroom!
    869             indent: 5
    870             auto_size: 1
    871             # height: 18
    872             # width: 69
    873             vim_opts: '-u NONE'
    874             skip: 0
    875              
    876             # The following options are for Gvim usage.
    877             # vim: gvim
    878             # gvimrc: |
    879             # set fuopt=maxhorz,maxvert
    880             # set guioptions=egmLtT
    881             # set guifont=Bitstream_Vera_Sans_Mono:h18
    882             # set guicursor=a:blinkon0-ver25-Cursor
    883             # colorscheme default
    884              
    885             ---- center
    886             Vroom!
    887              
    888             by Ingy döt Net
    889              
    890             (hint: press the spacebar)
    891              
    892             ----
    893             == Slideshows in Vim
    894              
    895             * Hate using PowerPoint or HTML Slides for Talks?
    896             +* Use Vroom!
    897              
    898             +* You can write you slides in Vim...
    899             * ...and present them in Vim!
    900              
    901             ----
    902             == Getting Started
    903              
    904             * Write a file called 'slides.vroom'.
    905             * Do this in a new directory.
    906             * Run 'vroom vroom'.
    907             * Voilà!
    908              
    909             ----
    910             == Navigation
    911              
    912             * Hit to move forward.
    913             * Hit to go backwards.
    914             * Hit 'Q' to quit.
    915              
    916             ---- perl,i4
    917             # This is some Perl code.
    918             # Notice the syntax highlighting.
    919             # Run it with the vim command.
    920             for my $word (qw(Vroom totally rocks!)) {
    921             print "$word\n";
    922             }
    923              
    924             ----
    925             == Get Vroom!
    926              
    927             * http://search.cpan.org/dist/Vroom/
    928             * http://github.com/ingydotnet/vroom-pm/
    929              
    930             ----
    931             == Vroom as HTML
    932              
    933             * http://ingydotnet.github.com/vroom-pm/
    934              
    935             ----
    936             == The End
    937             ...
    938 0           print "'$file' created.\n";
    939             }
    940              
    941             sub makePublisher {
    942 0     0 0   my $self = shift;
    943 0           my $input = $self->input;
    944 0 0         die "Error: This doesn't look like a Vroom directory.\n"
    945             unless -f $input;
    946 0 0         die "Error: This doesn't look like a git repository.\n"
    947             unless -d '.git';
    948 0 0 0       die "Error: No writeable /tmp directory on this system.\n"
    949             unless -d '/tmp' and -w '/tmp';
    950 0 0         die "Error: There is no git branch called 'gh-pages'.\n" .
    951             "Perhaps you should run `git branch gh-pages` first.\n"
    952             unless `git branch` =~ /\bgh-pages\b/;
    953 0           io('ghpublish')->print(<<'...');
    954             #!/bin/sh
    955              
    956             # This script is experimental. Please understand it before you run it on
    957             # your system. Just because it works for Ingy, doesn't mean it will work
    958             # for you.
    959              
    960             if [ -e "/tmp/html" ]; then
    961             echo "Error: /tmp/html already exists. Perhaps remove it."
    962             exit 13
    963             fi
    964              
    965             # Create HTML slides.
    966             vroom html || exit 1
    967             # Move the html directory to /tmp
    968             mv html /tmp || exit 1
    969             # Stash any local stuff that isn't committed.
    970             git stash || exit 1
    971             # Switch to your gh-pages branch. (That you already created. Right?)
    972             git checkout gh-pages || exit 1
    973             # Remove all the html files from the gh-pages branch.
    974             rm -f *.html || exit 1
    975             # Move the HTML slides in here.
    976             mv /tmp/html/* . || exit 1
    977             # Remove the html directory from /tmp
    978             rmdir /tmp/html || exit 1
    979             # Add any new files to git.
    980             git add 0* index.html || exit 1
    981             # Commit your changes.
    982             git commit -am 'Publish my slides' || exit 1
    983             # Push them to GitHub.
    984             git push origin gh-pages || exit 1
    985             # Switch back to the master branch.
    986             git checkout master || exit 1
    987             # Get your uncommitted changes back.
    988             git stash pop || exit 1
    989              
    990             # Voilà! (hopefully)
    991             ...
    992              
    993 0           chmod 0755, 'ghpublish';
    994              
    995 0           print <<'...';
    996             Created the shell script called 'ghpublish'.
    997              
    998             This script is somewhat experimental, so please read the code to make sure
    999             it makes sense on your system.
    1000              
    1001             If it makes sense to you, run it. (at your own risk :)
    1002             ...
    1003             }
    1004              
    1005             1;