File Coverage

blib/lib/Vroom.pm
Criterion Covered Total %
statement 43 376 11.4
branch 0 166 0.0
condition 0 15 0.0
subroutine 15 49 30.6
pod 1 31 3.2
total 59 637 9.2


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