Commit | Line | Data |
e4ac8502 |
1 | package Devel::REPL::Plugin::Completion; |
2 | |
3 | use Moose::Role; |
4 | use namespace::clean -except => [ 'meta' ]; |
5 | |
6 | # push the given string in the completion list |
7 | sub push_completion |
8 | { |
9 | my ($self, $string) = @_; |
10 | $self->term->Attribs->{completion_entry_function} = |
11 | $self->term->Attribs->{list_completion_function}; |
12 | push @{$self->term->Attribs->{completion_word}}, $string; |
13 | }; |
14 | |
15 | # return the namespace of the module given |
16 | sub get_namespace |
17 | { |
18 | my ($self, $module) = @_; |
19 | my $namespace; |
20 | eval '$namespace = \%'.$module.'::'; |
21 | return $namespace; |
22 | } |
23 | |
24 | # we wrap the run method to init the completion list |
25 | # with filenames found in the current dir and init |
26 | # the completion list. |
27 | # yes, this is our 'init the plugin' stuff actually |
28 | sub BEFORE_PLUGIN |
29 | { |
30 | my ($self) = @_; |
31 | # set the completion function |
32 | $self->term->Attribs->{completion_entry_function} = |
33 | $self->term->Attribs->{list_completion_function}; |
34 | |
35 | # init the completion with an arrayref (could be the Perl built-ins) |
36 | $self->term->Attribs->{completion_word} = []; |
37 | |
38 | # now put each file in curdir in the completion list |
39 | my $curdir = File::Spec->curdir(); |
40 | if (opendir(CURDIR, $curdir)) { |
41 | while (my $file = readdir(CURDIR)) { |
42 | next if $file =~ /^\.+$/; # we skip "." and ".." |
43 | $self->push_completion($file); |
44 | } |
45 | } |
46 | closedir(CURDIR); |
47 | } |
48 | |
49 | # wrap the read method so we save in the completion list |
50 | # each variable declaration |
51 | around 'read' => sub { |
52 | my $orig = shift; |
53 | my ($self, @args) = @_; |
54 | my $line = $self->$orig(@args); |
55 | if (defined $line) { |
56 | if ($line =~ /\s*[\$\%\@](\S+)\s*=/) { |
57 | my $str = $1; |
58 | $self->push_completion($str); |
59 | } |
60 | } |
61 | return $line; |
62 | }; |
63 | |
64 | # wrap the eval one to catch each 'use' statement in order to |
65 | # load the namespace in the completion list (module functions and friends) |
66 | # we do that around the eval method cause we want the module to be actually loaded. |
67 | around 'eval' => sub { |
68 | my $orig = shift; |
69 | my ($self, $line) = @_; |
70 | my @ret = $self->$orig($line); |
71 | if ($line =~ /use\s+(\S+)/) { |
72 | my $module = $1; |
73 | foreach my $keyword (keys %{$self->get_namespace($module)}) { |
74 | $self->push_completion($keyword); |
75 | } |
76 | } |
77 | return @ret; |
78 | }; |
79 | |
80 | 1; |