Fixed History to work with ReadLineHistory
[p5sagit/Devel-REPL.git] / lib / Devel / REPL / Plugin / History.pm
1 package Devel::REPL::Plugin::History;
2
3 use Devel::REPL::Plugin;
4 use namespace::clean -except => [ 'meta' ];
5
6 has 'history' => (
7    isa => 'ArrayRef', is => 'rw', required => 1, lazy => 1,
8    default => sub { [] }
9 );
10
11 # lazy so ReadLineHistory Plugin can set this
12 has 'have_readline_history' => (
13    is => 'rw', required => 1, lazy => 1,
14    default => sub { 0 }
15 );
16
17 sub push_history {
18    my ($self, $line) = @_;
19    # Push history is not needed if we have Term::ReadLine
20    # support.  We put the test inside push_history() in case
21    # someone has modified it in their code.
22    if ($self->have_readline_history) {
23       # update history to keep consistent with Term::ReadLine
24       $self->history( [ $self->term->GetHistory ] );
25    } else {
26       # not used with Term::ReadLine history support
27       push(@{$self->history}, $line);
28    }
29 }
30
31 around 'read' => sub {
32    my $orig = shift;
33    my ($self, @args) = @_;
34    my $line = $self->$orig(@args);
35    if (defined $line) {
36       if ($line =~ m/^!(.*)$/) {
37          my $call = $1;
38          $line = $self->history_call($call);
39          if (defined $line) {
40             $self->print($line."\n");
41          } else {
42             return "'Unable to find ${call} in history'";
43          }
44       }
45       if ($line =~ m/\S/) {
46          $self->push_history($line);
47       }
48    }
49    return $line;
50 };
51
52 sub history_call {
53    my ($self, $call) = @_;
54    if ($call =~ m/^(-?\d+)$/) { # handle !1 or !-1
55       my $idx = $1;
56       $idx-- if ($idx > 0); # !1 gets history element 0
57       my $line = $self->history->[$idx];
58       return $line;
59    }
60    my $re = qr/^\Q${call}\E/;
61    foreach my $line (reverse @{$self->history}) {
62       return $line if ($line =~ $re);
63    }
64    return;
65 };
66
67 1;
68
69 __END__
70
71 =head1 NAME
72
73 Devel::REPL::Plugin::History - Keep track of all input, provide shortcuts !1, !-1
74
75 =cut
76