Add Devel::REPL::Plugin::MutliLine::PPI
[p5sagit/Devel-REPL.git] / lib / Devel / REPL / Plugin / MultiLine / PPI.pm
1 package Devel::REPL::Plugin::MultiLine::PPI;
2
3 use Moose::Role;
4 use PPI;
5 use namespace::clean -except => [ 'meta' ];
6
7 has 'continuation_prompt' => (
8   is => 'rw', required => 1, lazy => 1,
9   default => sub { '> ' }
10 );
11
12 around 'read' => sub {
13   my $orig = shift;
14   my ($self, @args) = @_;
15   my $line = $self->$orig(@args);
16
17   if (defined $line) {
18     while (needs_continuation($line)) {
19       my $orig_prompt = $self->prompt;
20       $self->prompt($self->continuation_prompt);
21
22       my $append = $self->read(@args);
23       $line .= $append if defined($append);
24
25       $self->prompt($orig_prompt);
26
27       # ^D means "shut up and eval already"
28       return $line if !defined($append);
29     }
30   }
31   return $line;
32 };
33
34 sub needs_continuation
35 {
36   my $line = shift;
37   my $document = PPI::Document->new(\$line);
38   return 0 if !defined($document);
39
40   # this could use more logic, such as returning 1 on s/foo/ba<Enter>
41   my $unfinished_structure = sub
42   {
43     my ($document, $element) = @_;
44     return 0 unless $element->isa('PPI::Structure');
45     return 1 unless $element->start && $element->finish;
46     return 0;
47   };
48
49   return $document->find_any($unfinished_structure);
50 }
51
52 1;