whitespace fixes
[p5sagit/Devel-REPL.git] / lib / Devel / REPL / Plugin / CompletionDriver / INC.pm
index d2996e3..cdcf74f 100644 (file)
@@ -1,8 +1,15 @@
+use strict;
+use warnings;
 package Devel::REPL::Plugin::CompletionDriver::INC;
 use Devel::REPL::Plugin;
 use File::Next;
 use File::Spec;
-use namespace::clean -except => [ 'meta' ];
+use namespace::autoclean;
+
+sub BEFORE_PLUGIN {
+    my $self = shift;
+    $self->load_plugin('Completion');
+}
 
 around complete => sub {
   my $orig = shift;
@@ -24,20 +31,28 @@ around complete => sub {
 
   my $package = shift @elements;
   my $outsep  = '::';
-  my $insep   = '::';
+  my $insep   = "::";
   my $keep_extension = 0;
+  my $prefix  = '';
 
-  # require "Module"
-  if ($package->isa('PPI::Token::Quote'))
-  {
-      $outsep = $insep = '/';
-      $keep_extension = 1;
-  }
-  elsif ($package =~ /'/)
+  # require "Foo/Bar.pm" -- not supported yet, ->string doesn't work for
+  # partially completed elements
+  #if ($package->isa('PPI::Token::Quote'))
+  #{
+  #  # we need to strip off the leading quote and stash it
+  #  $package = $package->string;
+  #  my $start = index($package->quote, $package);
+  #  $prefix = substr($package->quote, 0, $start);
+
+  #  # we're completing something like: require "Foo/Bar.pm"
+  #  $outsep = $insep = '/';
+  #  $keep_extension = 1;
+  #}
+  if ($package =~ /'/)
   {
-      # the goofball is using the ancient ' package sep, we'll humor him
-      $outsep = q{'};
-      $insep = "'|::";
+    # the goofball is using the ancient ' package sep, we'll humor him
+    $outsep = "'";
+    $insep = "'|::";
   }
 
   my @directories = split $insep, $package;
@@ -49,21 +64,57 @@ around complete => sub {
 
   my @found;
 
+  # most VCSes don't litter every single fucking directory with garbage. if you
+  # know of any other, just stick them in here. noone wants to complete
+  # Devel::REPL::Plugin::.svn
+  my %ignored =
+  (
+      '.'    => 1,
+      '..'   => 1,
+      '.svn' => 1,
+  );
+
+  # this will take a directory and add to @found all of the possible matches
+  my $add_recursively;
+  $add_recursively = sub {
+    my ($path, $iteration, @more) = @_;
+    opendir((my $dirhandle), $path) || return;
+    for (grep { !$ignored{$_} } readdir $dirhandle)
+    {
+      my $match = $_;
+
+      # if this is the first time around, we need respect whatever the user had
+      # at the very end when he pressed tab
+      next if $iteration == 0 && $match !~ $final_re;
+
+      my $fullmatch = File::Spec->rel2abs($match, $path);
+      if (-d $fullmatch)
+      {
+        $add_recursively->($fullmatch, $iteration + 1, @more, $match);
+      }
+      else
+      {
+        $match =~ s/\..*// unless $keep_extension;
+        push @found, join '', $prefix,
+                              join $outsep, @directories, @more, $match;
+      }
+    }
+  };
+
+  # look through all of
   INC: for (@INC)
   {
     my $path = $_;
+
+    # match all of the fragments they have, so "use Moose::Meta::At<tab>"
+    # will only begin looking in ../Moose/Meta/
     for my $subdir (@directories)
     {
       $path = File::Spec->catdir($path, $subdir);
       -d $path or next INC;
     }
 
-    opendir((my $dirhandle), $path);
-    for my $match (grep { $_ =~ $final_re } readdir $dirhandle)
-    {
-      $match =~ s/\..*// unless $keep_extension;
-      push @found, join $outsep, @directories, $match;
-    }
+    $add_recursively->($path, 0);
   }
 
   return $orig->(@_), @found;
@@ -71,3 +122,15 @@ around complete => sub {
 
 1;
 
+__END__
+
+=head1 NAME
+
+Devel::REPL::Plugin::CompletionDriver::INC - Complete module names in use and require
+
+=head1 AUTHOR
+
+Shawn M Moore, C<< <sartak at gmail dot com> >>
+
+=cut
+