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