File Coverage

blib/lib/Vroom.pm
Criterion Covered Total %
statement 43 382 11.2
branch 0 176 0.0
condition 0 15 0.0
subroutine 15 49 30.6
pod 1 31 3.2
total 59 653 9.0


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

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

315            

[% config.title | html %]

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

    This presentation was generated by

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

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

    [% notes %]

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

    }g;

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