whitespace fixes
[p5sagit/Devel-REPL.git] / lib / Devel / REPL / Plugin / Completion.pm
CommitLineData
1716b200 1use strict;
2use warnings;
e4ac8502 3package Devel::REPL::Plugin::Completion;
1716b200 4
1989c3d2 5use Devel::REPL::Plugin;
6use Scalar::Util 'weaken';
7use PPI;
aa8b7647 8use namespace::autoclean;
e4ac8502 9
1989c3d2 10has current_matches => (
fd81abf1 11 is => 'rw',
12 isa => 'ArrayRef',
13 lazy => 1,
14 default => sub { [] },
1989c3d2 15);
ac71b56c 16
1989c3d2 17has match_index => (
fd81abf1 18 is => 'rw',
19 isa => 'Int',
20 lazy => 1,
21 default => sub { 0 },
1989c3d2 22);
e4ac8502 23
97d28d6b 24has no_term_class_warning => (
fd81abf1 25 isa => "Bool",
26 is => "rw",
27 default => 0,
28);
29
30has do_readline_filename_completion => ( # so default is no if Completion loaded
31 isa => "Bool",
32 is => "rw",
33 lazy => 1,
34 default => sub { 0 },
97d28d6b 35);
36
839614c7 37before 'read' => sub {
fd81abf1 38 my ($self) = @_;
e4ac8502 39
fd81abf1 40 if ((!$self->term->isa("Term::ReadLine::Gnu") and !$self->term->isa("Term::ReadLine::Perl"))
41 and !$self->no_term_class_warning) {
42 warn "Term::ReadLine::Gnu or Term::ReadLine::Perl is required for the Completion plugin to work";
43 $self->no_term_class_warning(1);
44 }
839614c7 45
fd81abf1 46 my $weakself = $self;
47 weaken($weakself);
ac71b56c 48
fd81abf1 49 if ($self->term->isa("Term::ReadLine::Gnu")) {
50 $self->term->Attribs->{attempted_completion_function} = sub {
51 $weakself->_completion(@_);
52 };
53 }
c8fafb5a 54
fd81abf1 55 if ($self->term->isa("Term::ReadLine::Perl")) {
56 $self->term->Attribs->{completion_function} = sub {
57 $weakself->_completion(@_);
58 };
59 }
f2833460 60
839614c7 61};
97d28d6b 62
1989c3d2 63sub _completion {
c8fafb5a 64 my $is_trp = scalar(@_) == 4 ? 1 : 0;
65 my ($self, $text, $line, $start, $end) = @_;
66 $end = $start+length($text) if $is_trp;
67
68 # we're discarding everything after the cursor for completion purposes
69 # we can't just use $text because we want all the code before the cursor to
70 # matter, not just the current word
71 substr($line, $end) = '';
72
73 my $document = PPI::Document->new(\$line);
74 return unless defined($document);
75
76 $document->prune('PPI::Token::Whitespace');
77
78 my @matches = $self->complete($text, $document);
79
80 # iterate through the completions
81 if ($is_trp) {
82 if (scalar(@matches)) {
83 return @matches;
84 } else {
fd81abf1 85 return ($self->do_readline_filename_completion) ? readline::rl_filename_list($text) : () ;
c8fafb5a 86 }
87 } else {
fd81abf1 88 $self->term->Attribs->{attempted_completion_over} = 1 unless $self->do_readline_filename_completion;
c8fafb5a 89 if (scalar(@matches)) {
90 return $self->term->completion_matches($text, sub {
91 my ($text, $state) = @_;
92
93 if (!$state) {
94 $self->current_matches(\@matches);
95 $self->match_index(0);
96 }
97 else {
98 $self->match_index($self->match_index + 1);
99 }
100
101 return $self->current_matches->[$self->match_index];
102 });
103 } else {
c8fafb5a 104 return;
105 }
106 }
1989c3d2 107}
108
109sub complete {
fd81abf1 110 return ();
1989c3d2 111}
e4ac8502 112
8051a5e0 113# recursively find the last element
114sub last_ppi_element {
fd81abf1 115 my ($self, $document, $type) = @_;
116 my $last = $document;
117 while ($last->can('last_element') && defined($last->last_element)) {
118 $last = $last->last_element;
119 return $last if $type && $last->isa($type);
120 }
121 return $last;
8051a5e0 122}
123
e4ac8502 1241;
1989c3d2 125
cfd1094b 126__END__
127
128=head1 NAME
129
130Devel::REPL::Plugin::Completion - Extensible tab completion
131
1a00e38d 132=head1 NOTE
133
134By default, the Completion plugin explicitly does I<not> use the Gnu readline
135or Term::ReadLine::Perl fallback filename completion.
136
137Set the attribute C<do_readline_filename_completion> to 1 to enable this feature.
138
30b459d4 139=head1 AUTHOR
140
141Shawn M Moore, C<< <sartak at gmail dot com> >>
142
cfd1094b 143=cut
144