File Coverage

blib/lib/Term/BashTab.pm
Criterion Covered Total %
statement 15 130 11.5
branch 0 70 0.0
condition 0 28 0.0
subroutine 5 8 62.5
pod n/a
total 20 236 8.4


line stmt bran cond sub pod time code
1             package Term::BashTab;
2              
3 1     1   40241 use 5.008007;
  1         4  
  1         76  
4 1     1   6 use strict;
  1         2  
  1         35  
5 1     1   6 use warnings;
  1         6  
  1         53  
6              
7             require Exporter;
8 1     1   1245 use AutoLoader qw(AUTOLOAD);
  1         1970  
  1         6  
9              
10 1     1   1220 use subs qw(new readline);
  1         27  
  1         5  
11              
12             require Term::ReadLine;
13             our @ISA = qw(Term::ReadLine);
14              
15             # Items to export into callers namespace by default. Note: do not export
16             # names by default without a very good reason. Use EXPORT_OK instead.
17             # Do not simply export all your public functions/methods/constants.
18              
19             # This allows declaration use Term::BashTab ':all';
20             # If you do not need this, moving things directly into @EXPORT or @EXPORT_OK
21             # will save memory.
22             #our %EXPORT_TAGS = ( 'all' => [ qw(
23             #
24             #) ] );
25              
26             #our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
27              
28             #our @EXPORT = qw(
29             #
30             #);
31              
32             our $VERSION = '0.03';
33              
34             # Default global command list
35             our @COMMAND = qw();
36             # Treat first param as ONLY command by default
37             our $FIRST_NOT_COMMAND = undef;
38             # Directory separator, Unix family by default
39             our $DIR_SEPARATOR = $^O eq 'MSWin32' ? q(\\)
40             : q(/);
41              
42             # Preloaded methods go here.
43              
44             sub new {
45 0     0     require Term::ReadLine;
46 0   0       my $class = shift || __PACKAGE__;
47 0           my $term = Term::ReadLine->new(@_);
48             # re-blessed
49 0           bless $term, $class;
50             }
51              
52             sub __complete(@) {
53             # @_ is (current last param, entire command line, length)
54 0     0     my ($last, $cmd) = @_;
55             #print "\n", $last, ":", $cmd, "\n";
56            
57 0           local *DIR;
58 0 0 0       if($last eq $cmd and not $FIRST_NOT_COMMAND) {
59             # one param only
60             # complete list is @COMMAND if no input
61 0 0         return @COMMAND if $cmd eq '';
62             # complete list grepped from `keys $COMMAND'
63 0           return sort grep { m/^\Q$last\E/ } @COMMAND;
  0            
64             } else {
65 0           my $path;
66 0 0         if($FIRST_NOT_COMMAND) {
67 0           $path = $cmd;
68             } else {
69             # command + path
70 0           (undef, $path) = split / /, $cmd, 2;
71             }
72            
73 0           my (@entry, @match);
74             #print "\npath = '$path'\n";
75 0 0         if($path) {
76             # return if no need to complete
77 0 0 0       return +() if
78             substr($path, -1, 1) eq ' ' and
79             -e substr($path, 0, length($path)-1);
80             # glob all the matched entries if possible
81            
82 0 0         my $dirmatch_reg
83             = $^O eq 'MSWin32' ? qr/^((?i:[a-z]\:\\)?(?:\\?[^\\]+)*)\\(.*)/o
84             : qr{^((?:/?[^/]+)*)/(.*)}o;
85            
86             #if($path =~ m#^((?:/?[^/]*)*)/(.*)#o) {
87 0 0         if ($path =~ $dirmatch_reg) {
88             #print "\n1 = '$1'\n2 = '$2'";
89             # $1 is basedir or null
90 0 0         return +() unless -d $1.$DIR_SEPARATOR;
91            
92 0 0         opendir DIR, "$1$DIR_SEPARATOR" or do {
93             #warn "opendir: $!";
94 0           return +();
95             };
96 0           @entry = readdir DIR;
97 0 0         closedir DIR or warn "closedir: $!";
98 0 0         if($2) {
99 0           @match = sort grep { m/^\Q$2\E/ } @entry;
  0            
100 0 0         if(scalar(@match) == 1) {
    0          
101             # complete will add a ' ' automatically
102             # for a file ok
103             # for a dir this will block the
104             # following match
105             # a small trick here to remove the
106             # tail space for dir
107 0           my $file = $1.$DIR_SEPARATOR.$match[0];
108             #print $1, "\n";
109            
110 0           my $complete;
111             # check space in $2 and then $1
112             # $1 will be replaced after next reg-match
113 0           my $dir = $1;
114 0           my $name = $2;
115 0 0 0       if ($name and $name =~ m/ /o) {
    0 0        
116 0           $complete = substr($match[0],
117             rindex($name, " ")+1);
118             } elsif ($dir and $dir =~ m/ /o) {
119 0           $complete = (split / /, $dir)[-1].$DIR_SEPARATOR.$match[0];
120             } else {
121 0           $complete = $file;
122             }
123 0 0         if (-d $file) {
124 0           return +($complete.$DIR_SEPARATOR,
125             $complete.$DIR_SEPARATOR." ");
126             } else {
127 0           return $complete;
128             }
129             } elsif (scalar(@match) == 0) {
130             # no match, no complete
131 0           return +();
132             } else {
133             # grep the match list and try to get the
134             # longest common string
135 0           my ($min_match) = (sort {
136 0           length($a) <=> length($b) } @match)[0];
137 0           my $min_length = length($min_match);
138 0           my $common;
139            
140 0           COMMON: for (my $length =
141             length($2);;$length++) {
142            
143 0 0         if($length == $min_length) {
144 0           $common = $min_match;
145 0           last COMMON;
146             }
147            
148 0           my $char = substr($match[0], $length, 1);
149             #print "\nchar = $char\n";
150 0           foreach (@match[1 .. $#match]) {
151 0 0         if(substr($_, $length, 1) ne $char) {
152 0           $common = substr($match[0], 0,
153             $length);
154 0           last COMMON;
155             }
156             }
157             }
158            
159 0 0         if ($2 eq $common) {
160             # $2 is the longest common string
161 0           return +(@match, undef);
162             } else {
163             # check space in $2 and then $1
164 0           my $complete;
165 0           my $dir = $1;
166 0           my $name = $2;
167             #print $name, "\n";
168 0 0 0       if ($name and $name =~ m/ /o) {
    0 0        
169 0           $complete = substr($common,
170             rindex($name, " ")+1);
171             } elsif ($dir and $dir =~ m/ /o) {
172 0           $complete = (split / /, $dir)[-1].
173             $DIR_SEPARATOR."$common";
174             } else {
175 0           $complete = $1.$DIR_SEPARATOR.$common;
176             }
177 0           return +("$complete",
178             "$complete ");
179             }
180             # NOREACH
181             }
182             } else {
183 0           return sort @entry;
184             }
185             } else {
186             # search under cwd
187 0 0         opendir DIR, "." or do {
188             #warn "opendir: $!";
189 0           return +();
190             };
191 0           @entry = readdir DIR;
192 0 0         closedir DIR or warn "closedir: $!";
193 0           @match = sort grep { m/^\Q$path\E/ } @entry;
  0            
194 0 0         if(scalar(@match) == 1) {
    0          
195 0           my $file = $match[0];
196 0           my $complete;
197             # check space in $path
198             # $1 will be replaced after next reg-match
199 0           my $name = $path;
200 0 0 0       if ($name and $name =~ m/ /o) {
201 0           $complete = substr($match[0], rindex($path, " ")+1);
202             } else {
203 0           $complete = $file;
204             }
205 0 0         if (-d $file) {
206 0           return +($complete.$DIR_SEPARATOR,
207             $complete.$DIR_SEPARATOR." ");
208             } else {
209 0           return $complete;
210             }
211             } elsif (scalar(@match) == 0) {
212 0           return +();
213             } else {
214             # grep the match list and try to get the
215             # longest common string
216 0           my ($min_match) = (sort {
217 0           length($a) <=> length($b) } @match)[0];
218 0           my $min_length = length($min_match);
219 0           my $common;
220            
221 0           COMMON: for (my $length =
222             length($path);;$length++) {
223              
224 0 0         if($length == $min_length) {
225 0           $common = $min_match;
226 0           last COMMON;
227             }
228            
229 0           my $char = substr($match[0], $length, 1);
230 0           foreach (@match[1 .. $#match]) {
231 0 0         if(substr($_, $length, 1) ne $char) {
232 0           $common = substr($match[0], 0,
233             $length);
234 0           last COMMON;
235             }
236             }
237             }
238            
239 0 0         if ($path eq $common) {
240             # $path is the longest common string
241 0           return +(@match, undef);
242             } else {
243             # check space in $path
244 0           my $complete;
245 0           my $name = $path;
246 0 0 0       if ($name and $name =~ m/ /o) {
247 0           $complete = substr($common,
248             rindex($name, " ")+1);
249             } else {
250 0           $complete = $common;
251             }
252 0           return +("$complete",
253             "$complete ");
254             }
255             # NOREACH
256             }
257             }
258             } else {
259             # no param
260             # ls all entries under cwd
261 0 0         opendir DIR, "." or do {
262             #warn "opendir: $!";
263 0           return +();
264             };
265 0           @entry = readdir DIR;
266 0 0         closedir DIR or warn "closedir: $!";
267 0           return sort grep { /^[^.]/o } @entry;
  0            
268             }
269             }
270             # NOREACH
271             }
272              
273             sub readline {
274 0     0     my $term = shift;
275 0   0       my $prompt = shift || '';
276             # set callback stub
277 0           my $attr = $term->Attribs;
278 0 0         if($term->ReadLine eq "Term::ReadLine::Gnu") {
    0          
279 0           $attr->{attempted_completion_function} =
280             __PACKAGE__."::__complete";
281             } elsif($term->ReadLine eq "Term::ReadLine::Perl") {
282 0           $attr->{completion_function} = __PACKAGE__."::__complete";
283             } else {
284             # Term::ReadLine::Stub
285             # do nothing
286             }
287 0           return $term->SUPER::readline($prompt);
288             }
289              
290             # Autoload methods go after =cut, and are processed by the autosplit program.
291              
292             1;
293             __END__