Adding the Compeltion plugin
[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 # 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;