r61346@onn: sartak | 2008-05-31 12:56:47 -0400
[p5sagit/Devel-REPL.git] / lib / Devel / REPL / Plugin / Completion.pm
CommitLineData
e4ac8502 1package Devel::REPL::Plugin::Completion;
1989c3d2 2use Devel::REPL::Plugin;
3use Scalar::Util 'weaken';
4use PPI;
e4ac8502 5use namespace::clean -except => [ 'meta' ];
6
1989c3d2 7has current_matches => (
314f2293 8 is => 'rw',
9 isa => 'ArrayRef',
10 lazy => 1,
11 default => sub { [] },
1989c3d2 12);
ac71b56c 13
1989c3d2 14has match_index => (
314f2293 15 is => 'rw',
16 isa => 'Int',
17 lazy => 1,
18 default => sub { 0 },
1989c3d2 19);
e4ac8502 20
97d28d6b 21has no_term_class_warning => (
22 isa => "Bool",
23 is => "rw",
24 default => 0,
25);
26
839614c7 27before 'read' => sub {
1989c3d2 28 my ($self) = @_;
e4ac8502 29
839614c7 30 unless ($self->term->isa("Term::ReadLine::Gnu") and !$self->no_term_class_warning) {
31 warn "Term::ReadLine::Gnu is required for the Completion plugin to work";
32 $self->no_term_class_warning(1);
33 }
34
1989c3d2 35 my $weakself = $self;
36 weaken($weakself);
ac71b56c 37
1989c3d2 38 $self->term->Attribs->{attempted_completion_function} = sub {
39 $weakself->_completion(@_);
40 };
839614c7 41};
97d28d6b 42
1989c3d2 43sub _completion {
44 my ($self, $text, $line, $start, $end) = @_;
45
46 # we're discarding everything after the cursor for completion purposes
314f2293 47 # we can't just use $text because we want all the code before the cursor to
48 # matter, not just the current word
1989c3d2 49 substr($line, $end) = '';
50
51 my $document = PPI::Document->new(\$line);
52 return unless defined($document);
53
314f2293 54 $document->prune('PPI::Token::Whitespace');
55
1989c3d2 56 my @matches = $self->complete($text, $document);
ac71b56c 57
1989c3d2 58 # iterate through the completions
59 return $self->term->completion_matches($text, sub {
60 my ($text, $state) = @_;
61
62 if (!$state) {
63 $self->current_matches(\@matches);
64 $self->match_index(0);
65 }
66 else {
67 $self->match_index($self->match_index + 1);
ac71b56c 68 }
69
1989c3d2 70 return $self->current_matches->[$self->match_index];
71 });
72}
73
74sub complete {
75 return ();
76}
e4ac8502 77
8051a5e0 78# recursively find the last element
79sub last_ppi_element {
80 my ($self, $document, $type) = @_;
81 my $last = $document;
82 while ($last->can('last_element') && defined($last->last_element)) {
83 $last = $last->last_element;
84 return $last if $type && $last->isa($type);
85 }
86 return $last;
87}
88
e4ac8502 891;
1989c3d2 90
cfd1094b 91__END__
92
93=head1 NAME
94
95Devel::REPL::Plugin::Completion - Extensible tab completion
96
30b459d4 97=head1 AUTHOR
98
99Shawn M Moore, C<< <sartak at gmail dot com> >>
100
cfd1094b 101=cut
102