increment $VERSION after 1.003029 release
[p5sagit/Devel-REPL.git] / lib / Devel / REPL / Plugin / MultiLine / PPI.pm
CommitLineData
1716b200 1use strict;
2use warnings;
9cdb543b 3package Devel::REPL::Plugin::MultiLine::PPI;
9d2a4940 4# ABSTRACT: Read lines until all blocks are closed
9cdb543b 5
77327851 6our $VERSION = '1.003030';
54beb05d 7
6a5409bc 8use Devel::REPL::Plugin;
9cdb543b 9use PPI;
aa8b7647 10use namespace::autoclean;
9cdb543b 11
12has 'continuation_prompt' => (
b595a818 13 is => 'rw',
14 lazy => 1,
9cdb543b 15 default => sub { '> ' }
16);
17
b21e7551 18has 'line_depth' => (
b595a818 19 is => 'rw',
20 lazy => 1,
b21e7551 21 default => sub { 0 }
22);
23
9cdb543b 24around 'read' => sub {
25 my $orig = shift;
26 my ($self, @args) = @_;
27 my $line = $self->$orig(@args);
28
29 if (defined $line) {
0cbfa921 30 return $self->continue_reading_if_necessary($line, @args);
31 } else {
32 return $line;
33 }
34};
35
36sub continue_reading_if_necessary {
37 my ( $self, $line, @args ) = @_;
38
39 while ($self->line_needs_continuation($line)) {
40 my $orig_prompt = $self->prompt;
41 $self->prompt($self->continuation_prompt);
9cdb543b 42
0cbfa921 43 $self->line_depth($self->line_depth + 1);
44 my $append = $self->read(@args);
45 $self->line_depth($self->line_depth - 1);
b21e7551 46
998f8107 47 $line .= "\n$append" if defined($append);
9cdb543b 48
0cbfa921 49 $self->prompt($orig_prompt);
9cdb543b 50
0cbfa921 51 # ^D means "shut up and eval already"
52 return $line if !defined($append);
9cdb543b 53 }
0cbfa921 54
9cdb543b 55 return $line;
0cbfa921 56}
9cdb543b 57
49946f5c 58sub line_needs_continuation
9cdb543b 59{
49946f5c 60 my $repl = shift;
9cdb543b 61 my $line = shift;
2fd5e077 62
63 # add this so we can test whether the document ends in PPI::Statement::Null
64 $line .= "\n;;";
65
9cdb543b 66 my $document = PPI::Document->new(\$line);
d954e450 67 return 0 if !defined($document);
9cdb543b 68
2fd5e077 69 # adding ";" to a complete document adds a PPI::Statement::Null. we added a ;;
70 # so if it doesn't end in null then there's probably something that's
71 # incomplete
d954e450 72 return 0 if $document->child(-1)->isa('PPI::Statement::Null');
2fd5e077 73
9cdb543b 74 # this could use more logic, such as returning 1 on s/foo/ba<Enter>
75 my $unfinished_structure = sub
76 {
77 my ($document, $element) = @_;
78 return 0 unless $element->isa('PPI::Structure');
2fd5e077 79 return 1 unless $element->finish;
9cdb543b 80 return 0;
81 };
82
83 return $document->find_any($unfinished_structure);
84}
85
861;
d9ba19d2 87
88__END__
89
9d2a4940 90=pod
d9ba19d2 91
92=head1 SYNOPSIS
93
d9ba19d2 94 use Devel::REPL;
95
96 my $repl = Devel::REPL->new;
97 $repl->load_plugin('LexEnv');
98 $repl->load_plugin('History');
99 $repl->load_plugin('MultiLine::PPI');
100 $repl->run;
101
102=head1 DESCRIPTION
103
104Plugin that will collect lines until you have no unfinished structures. This
105lets you write subroutines, C<if> statements, loops, etc. more naturally.
106
107For example, without a MultiLine plugin,
108
109 $ my $x = 3;
110 3
111 $ if ($x == 3) {
112
113will throw a compile error, because that C<if> statement is incomplete. With a
114MultiLine plugin,
115
116 $ my $x = 3;
117 3
118 $ if ($x == 3) {
119
120 > print "OH NOES!"
121
122 > }
123 OH NOES
124 1
125
126you may write the code across multiple lines, such as in C<irb> and C<python>.
127
128This module uses L<PPI>. This plugin is named C<MultiLine::PPI> because someone
129else may conceivably implement similar behavior some other less
130dependency-heavy way.
131
132=head1 SEE ALSO
133
134C<Devel::REPL>
135
136=head1 AUTHOR
137
138Shawn M Moore, C<< <sartak at gmail dot com> >>
139
140=head1 COPYRIGHT AND LICENSE
141
142Copyright (C) 2007 by Shawn M Moore
143
144This library is free software; you can redistribute it and/or modify
145it under the same terms as Perl itself.
146
147=cut