File: PPI.pm

package info (click to toggle)
libdevel-repl-perl 1.002001-2
  • links: PTS, VCS
  • area: main
  • in suites: lenny
  • size: 256 kB
  • ctags: 185
  • sloc: perl: 2,323; makefile: 47
file content (126 lines) | stat: -rw-r--r-- 2,675 bytes parent folder | download
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