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