File Coverage

blib/lib/Devel/REPL/Plugin/CompletionDriver/INC.pm
Criterion Covered Total %
statement 23 23 100.0
branch n/a
condition n/a
subroutine 8 8 100.0
pod 0 1 0.0
total 31 32 96.8


line stmt bran cond sub pod time code
1 2     2   3871 use strict;
  2         4  
  2         61  
2 2     2   7 use warnings;
  2         3  
  2         112  
3             package Devel::REPL::Plugin::CompletionDriver::INC;
4             # ABSTRACT: Complete module names in use and require
5              
6             our $VERSION = '1.003028';
7              
8 2     2   8 use Devel::REPL::Plugin;
  2         2  
  2         12  
9 2     2   6303 use Devel::REPL::Plugin::Completion; # die early if cannot load
  2         2  
  2         43  
10 2     2   524 use File::Next;
  2         1435  
  2         37  
11 2     2   8 use File::Spec;
  2         3  
  2         30  
12 2     2   7 use namespace::autoclean;
  2         2  
  2         13  
13              
14             sub BEFORE_PLUGIN {
15 1     1 0 2 my $self = shift;
16 1         4 $self->load_plugin('Completion');
17             }
18              
19             around complete => sub {
20             my $orig = shift;
21             my ($self, $text, $document) = @_;
22              
23             my $last = $self->last_ppi_element($document, 'PPI::Statement::Include');
24              
25             return $orig->(@_)
26             unless $last->isa('PPI::Statement::Include');
27              
28             my @elements = $last->children;
29             shift @elements; # use or require
30              
31             # too late for us to care, they're completing on something like
32             # use List::Util qw(m
33             # OR they just have "use " and are tab completing. we'll spare them the flood
34             return $orig->(@_)
35             if @elements != 1;
36              
37             my $package = shift @elements;
38             my $outsep = '::';
39             my $insep = "::";
40             my $keep_extension = 0;
41             my $prefix = '';
42              
43             # require "Foo/Bar.pm" -- not supported yet, ->string doesn't work for
44             # partially completed elements
45             #if ($package->isa('PPI::Token::Quote'))
46             #{
47             # # we need to strip off the leading quote and stash it
48             # $package = $package->string;
49             # my $start = index($package->quote, $package);
50             # $prefix = substr($package->quote, 0, $start);
51              
52             # # we're completing something like: require "Foo/Bar.pm"
53             # $outsep = $insep = '/';
54             # $keep_extension = 1;
55             #}
56             if ($package =~ /'/)
57             {
58             # the goofball is using the ancient ' package sep, we'll humor him
59             $outsep = "'";
60             $insep = "'|::";
61             }
62              
63             my @directories = split $insep, $package;
64              
65             # split drops trailing fields
66             push @directories, '' if $package =~ /(?:$insep)$/;
67             my $final = pop @directories;
68             my $final_re = qr/^\Q$final/;
69              
70             my @found;
71              
72             # most VCSes don't litter every single fucking directory with garbage. if you
73             # know of any other, just stick them in here. No one wants to complete
74             # Devel::REPL::Plugin::.svn
75             my %ignored =
76             (
77             '.' => 1,
78             '..' => 1,
79             '.svn' => 1,
80             );
81              
82             # this will take a directory and add to @found all of the possible matches
83             my $add_recursively;
84             $add_recursively = sub {
85             my ($path, $iteration, @more) = @_;
86             opendir((my $dirhandle), $path) || return;
87             for (grep { !$ignored{$_} } readdir $dirhandle)
88             {
89             my $match = $_;
90              
91             # if this is the first time around, we need respect whatever the user had
92             # at the very end when he pressed tab
93             next if $iteration == 0 && $match !~ $final_re;
94              
95             my $fullmatch = File::Spec->rel2abs($match, $path);
96             if (-d $fullmatch)
97             {
98             $add_recursively->($fullmatch, $iteration + 1, @more, $match);
99             }
100             else
101             {
102             $match =~ s/\..*// unless $keep_extension;
103             push @found, join '', $prefix,
104             join $outsep, @directories, @more, $match;
105             }
106             }
107             };
108              
109             # look through all of
110             INC: for (@INC)
111             {
112             my $path = $_;
113              
114             # match all of the fragments they have, so "use Moose::Meta::At<tab>"
115             # will only begin looking in ../Moose/Meta/
116             for my $subdir (@directories)
117             {
118             $path = File::Spec->catdir($path, $subdir);
119             -d $path or next INC;
120             }
121              
122             $add_recursively->($path, 0);
123             }
124              
125             return $orig->(@_), @found;
126             };
127              
128             1;
129              
130             __END__
131              
132             =pod
133              
134             =encoding UTF-8
135              
136             =head1 NAME
137              
138             Devel::REPL::Plugin::CompletionDriver::INC - Complete module names in use and require
139              
140             =head1 VERSION
141              
142             version 1.003028
143              
144             =head1 SUPPORT
145              
146             Bugs may be submitted through L<the RT bug tracker|https://rt.cpan.org/Public/Dist/Display.html?Name=Devel-REPL>
147             (or L<bug-Devel-REPL@rt.cpan.org|mailto:bug-Devel-REPL@rt.cpan.org>).
148              
149             There is also an irc channel available for users of this distribution, at
150             L<C<#devel> on C<irc.perl.org>|irc://irc.perl.org/#devel-repl>.
151              
152             =head1 AUTHOR
153              
154             Shawn M Moore, C<< <sartak at gmail dot com> >>
155              
156             =head1 COPYRIGHT AND LICENCE
157              
158             This software is copyright (c) 2007 by Matt S Trout - mst (at) shadowcatsystems.co.uk (L<http://www.shadowcatsystems.co.uk/>).
159              
160             This is free software; you can redistribute it and/or modify it under
161             the same terms as the Perl 5 programming language system itself.
162              
163             =cut