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