Commit | Line | Data |
1716b200 |
1 | use strict; |
2 | use warnings; |
9cdb543b |
3 | package Devel::REPL::Plugin::MultiLine::PPI; |
9d2a4940 |
4 | # ABSTRACT: Read lines until all blocks are closed |
9cdb543b |
5 | |
54beb05d |
6 | our $VERSION = '1.003027'; |
7 | |
6a5409bc |
8 | use Devel::REPL::Plugin; |
9cdb543b |
9 | use PPI; |
aa8b7647 |
10 | use namespace::autoclean; |
9cdb543b |
11 | |
12 | has 'continuation_prompt' => ( |
b595a818 |
13 | is => 'rw', |
14 | lazy => 1, |
9cdb543b |
15 | default => sub { '> ' } |
16 | ); |
17 | |
b21e7551 |
18 | has 'line_depth' => ( |
b595a818 |
19 | is => 'rw', |
20 | lazy => 1, |
b21e7551 |
21 | default => sub { 0 } |
22 | ); |
23 | |
9cdb543b |
24 | around '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 | |
36 | sub 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 |
58 | sub 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 | |
86 | 1; |
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 | |
104 | Plugin that will collect lines until you have no unfinished structures. This |
105 | lets you write subroutines, C<if> statements, loops, etc. more naturally. |
106 | |
107 | For example, without a MultiLine plugin, |
108 | |
109 | $ my $x = 3; |
110 | 3 |
111 | $ if ($x == 3) { |
112 | |
113 | will throw a compile error, because that C<if> statement is incomplete. With a |
114 | MultiLine 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 | |
126 | you may write the code across multiple lines, such as in C<irb> and C<python>. |
127 | |
128 | This module uses L<PPI>. This plugin is named C<MultiLine::PPI> because someone |
129 | else may conceivably implement similar behavior some other less |
130 | dependency-heavy way. |
131 | |
132 | =head1 SEE ALSO |
133 | |
134 | C<Devel::REPL> |
135 | |
136 | =head1 AUTHOR |
137 | |
138 | Shawn M Moore, C<< <sartak at gmail dot com> >> |
139 | |
140 | =head1 COPYRIGHT AND LICENSE |
141 | |
142 | Copyright (C) 2007 by Shawn M Moore |
143 | |
144 | This library is free software; you can redistribute it and/or modify |
145 | it under the same terms as Perl itself. |
146 | |
147 | =cut |