1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126
|
package Devel::REPL::Plugin::MultiLine::PPI;
use Moose::Role;
use PPI;
use namespace::clean -except => [ 'meta' ];
has 'continuation_prompt' => (
is => 'rw', required => 1, lazy => 1,
default => sub { '> ' }
);
has 'line_depth' => (
is => 'rw', required => 1, lazy => 1,
default => sub { 0 }
);
around 'read' => sub {
my $orig = shift;
my ($self, @args) = @_;
my $line = $self->$orig(@args);
if (defined $line) {
while (needs_continuation($line)) {
my $orig_prompt = $self->prompt;
$self->prompt($self->continuation_prompt);
$self->line_depth($self->line_depth + 1);
my $append = $self->read(@args);
$self->line_depth($self->line_depth - 1);
$line .= $append if defined($append);
$self->prompt($orig_prompt);
# ^D means "shut up and eval already"
return $line if !defined($append);
}
}
return $line;
};
sub needs_continuation
{
my $line = shift;
my $document = PPI::Document->new(\$line);
return 0 if !defined($document);
# this could use more logic, such as returning 1 on s/foo/ba<Enter>
my $unfinished_structure = sub
{
my ($document, $element) = @_;
return 0 unless $element->isa('PPI::Structure');
return 1 unless $element->start && $element->finish;
return 0;
};
return $document->find_any($unfinished_structure);
}
1;
__END__
=head1 NAME
Devel::REPL::Plugin::MultiLine::PPI - read lines until all blocks are closed
=head1 SYNOPSIS
#!/usr/bin/perl
use lib './lib';
use Devel::REPL;
my $repl = Devel::REPL->new;
$repl->load_plugin('LexEnv');
$repl->load_plugin('History');
$repl->load_plugin('MultiLine::PPI');
$repl->run;
=head1 DESCRIPTION
Plugin that will collect lines until you have no unfinished structures. This
lets you write subroutines, C<if> statements, loops, etc. more naturally.
For example, without a MultiLine plugin,
$ my $x = 3;
3
$ if ($x == 3) {
will throw a compile error, because that C<if> statement is incomplete. With a
MultiLine plugin,
$ my $x = 3;
3
$ if ($x == 3) {
> print "OH NOES!"
> }
OH NOES
1
you may write the code across multiple lines, such as in C<irb> and C<python>.
This module uses L<PPI>. This plugin is named C<MultiLine::PPI> because someone
else may conceivably implement similar behavior some other less
dependency-heavy way.
=head1 SEE ALSO
C<Devel::REPL>
=head1 AUTHOR
Shawn M Moore, C<< <sartak at gmail dot com> >>
=head1 COPYRIGHT AND LICENSE
Copyright (C) 2007 by Shawn M Moore
This library is free software; you can redistribute it and/or modify
it under the same terms as Perl itself.
=cut
|