my $APPEND="not_implemented";
@Psh::Completion
::bookmarks
= ();
@Psh::Completion
::autoload
=();
my $attribs=$Psh::term
->Attribs;
# The following is ridiculous, but....
if( $Psh::term
->ReadLine eq 'Term::ReadLine::Perl') {
$APPEND='completer_terminator_character';
} elsif( $Psh::term
->ReadLine eq 'Term::ReadLine::Gnu') {
$APPEND='completion_append_character';
# Only ::Gnu understand it, and ::Perl ignores it silently.
$attribs->{completion_display_matches_hook
}
my $file= $Psh::Completion
::modules
{$command};
return if $module_loaded{$file};
my $text= join('',@lines);
Psh
::process_variable
($text);
return @Psh::Completion
::bookmarks
if $kh_loaded;
push @Psh::Completion
::bookmarks
, Psh
::OS
::get_known_hosts
();
return @Psh::Completion
::bookmarks
;
# Returns a list of possible file completions
my $executable_only= shift||0;
# HACK HACK HACK - this needs to be fixed some other way -
# the completion code is severly messed I fear
$text= Psh
::Parser
::unquote
($text);
if( substr($text,0,1) eq '"') {
$globtext= substr($text,1);
if (substr($globtext,0,1) eq '~' and !($globtext=~/\//)) {
# after ~ try username completion
@result= cmpl_usernames
($globtext);
$Psh::Completion
::ac
="/" if @result;
@result= Psh
::OS
::glob("$globtext*");
if( Psh
::Options
::has_option
('fignore')) {
my @ignore= Psh
::Options
::get_option
('fignore');
my $result= ! grep { Psh
::Util
::ends_with
($item,$_) } @ignore;
@result= grep { -x
$_ || -d _
} @result;
@result= map { -d
$_ ?
"$_/" : $_ } @result;
# HACK: This won't help much if user tries to do another completion
# on the same item afterwards
@result= map { s/([ \'\"\ยด\`])/\\$1/g; $_ } @result unless $prepend eq '"';
if (substr($result[0],-1) eq '/') {
$Psh::Completion
::ac
=$prepend.$Psh::Completion
::ac
if $prepend;
# Returns a list of possible directory completions
if( substr($text,0,1) eq '"') {
$globtext= substr($text,1);
if (substr($globtext,0,1) eq '~' and !($globtext=~/\//)) {
# after ~ try username completion
@result= cmpl_usernames
($globtext);
$Psh::Completion
::ac
="/" if @result;
@result= grep { -d
$_ } Psh
::OS
::glob("$globtext*");
$Psh::Completion
::ac
=$prepend||'';
@result= map { $_.'/' } @result;
# Returns an array with possible username completions
my @result= grep { Psh
::Util
::starts_with
($_,$text) } Psh
::OS
::get_all_users
();
# Tries to find executables for possible completions
if (Psh
::Strategy
::active
('built_in')) {
if ($Psh::Support
::Alias
::loaded
) {
push @result, grep { Psh
::Util
::starts_with
($_,$cmd) } Psh
::Support
::Alias
::get_alias_commands
();
push @result, grep { Psh
::Util
::starts_with
($_,$cmd) } Psh
::Support
::Builtins
::get_builtin_commands
();
push @result, cmpl_directories
($cmd) if $Psh::Completion
::complete_first_word_dirs
;
# set up absed_path if not already set and check
foreach my $dir (@Psh::absed_path
) {
push( @result, map { $exclam?
'!'.$_:$_ }
grep { -x
$dir.'/'.$_ && ! -d _
} Psh
::OS
::glob("$cmd*",$dir) );
%type = ('$' => 'SCALAR', '*' => 'SCALAR',
'@' => 'ARRAY', '$#' => 'ARRAY',
my ($text, $line, $start) = @_;
my ($prefix, $pre, $pkg, $sym);
($prefix, $pre, $pkg) = ($text =~ m/^((\$#|[\@\$%&])(.*::)?)/);
my @packages = grep /::$/, $pkg ?
keys %$pkg : keys %::;
$pkg = ($Psh::PerlEval
::current_package
eq 'main' ?
'::' : $Psh::PerlEval
::current_package
. '::') unless $pkg;
no strict
'vars'; # make `eval' quiet
# I cannot use `defined *$sym{SCALAR}',
# since it is always true.
&& (eval "defined $prefix$_"
|| defined *$sym{HASH
})),
defined *$sym{$type{$pre}}),
# Do we need a user customizable variable to ignore @packages?
map($prefix . $_, @packages, @symbols));
# Completes key names for Perl hashes
my ($text, $line, $start) = @_;
my $tmp= substr($line, 0, $start + 1);
my ($var,$arrow) = ($tmp =~ m/^[\$\%]([\w:]+)\s*(->)?\s*\{\s*['"]?/);
$var = "$Psh::PerlEval::current_package::$var" unless ($var =~ m/::/);
my $hashref = eval "\$$var";
return grep(/^\Q$text/, keys %$hashref);
return grep(/^\Q$text/, keys %$var);
my $isa = "${mypkg}::ISA";
return $mypkg, map _search_ISA
($_), @
$isa;
my ($text, $line, $start) = @_;
my ($var, $pkg, $sym, $pk);
$var = (substr($line, 0, $start + 1)
=~ m/\$([\w:]+)\s*->\s*$/)[0];
$pkg = ref eval (($var =~ m/::/) ?
"\$$var" : "\$$Psh::PerlEval::current_package::$var");
&& ($sym = "${pk}$_", defined *$sym{CODE
}),
# complete perl bare words (Perl function, subroutines, filehandle)
my ($prefix, $pkg, $sym);
($prefix, $pkg) = ($text =~ m/^((.*::)?)/);
my @packages = grep /::$/, $pkg ?
keys %$pkg : keys %::;
$pkg = ($Psh::PerlEval
::current_package
eq 'main' ?
'::' : $Psh::PerlEval
::current_package
. '::') unless $pkg;
|| defined *$sym{FILEHANDLE
}),
# Do we need a user customizable variable to ignore @packages?
my @result= grep(/^\Q$text/,
!$prefix && @Psh::Completion
::keyword
,
map($prefix . $_, @packages, @subs));
# from perl5.004_02 perlfunc
@Psh::Completion
::keyword
= qw(
chomp chop chr crypt hex index lc lcfirst
reverse rindex sprintf substr tr uc ucfirst
m pos quotemeta s split study qr
abs atan2 cos exp hex int log oct rand sin
pop push shift splice unshift
grep join map qw reverse sort unpack
delete each exists keys values
binmode close closedir dbmclose dbmopen die
eof fileno flock format getc print printf
read readdir rewinddir seek seekdir select
syscall sysread sysseek syswrite tell telldir
pack read syscall sysread syswrite unpack vec
chdir chmod chown chroot fcntl glob ioctl
link lstat mkdir open opendir readlink rename
rmdir stat symlink umask unlink utime
caller continue die do dump eval exit goto
last next redo return sub wantarray
caller import local my package use
defined dump eval formline local my reset
alarm exec fork getpgrp getppid getpriority
kill pipe qx setpgrp setpriority sleep
system times wait waitpid
do import no package require use
bless dbmclose dbmopen package ref tie tied
accept bind connect getpeername getsockname
getsockopt listen recv send setsockopt shutdown
msgctl msgget msgrcv msgsnd semctl semget
semop shmctl shmget shmread shmwrite
endgrent endhostent endnetent endpwent getgrent
getgrgid getgrnam getlogin getpwent getpwnam
getpwuid setgrent setpwent
endprotoent endservent gethostbyaddr
gethostbyname gethostent getnetbyaddr
getnetbyname getnetent getprotobyname
getprotobynumber getprotoent getservbyname
getservbyport getservent sethostent setnetent
gmtime localtime time times
abs bless chomp chr exists formline glob
import lc lcfirst map my no prototype qx qw
readline readpipe ref sub sysopen tie tied
# completion(text,line,start,end)
# Main Completion function
my ($text, $line, $start) = @_;
my $attribs = $Psh::term
->Attribs;
my $starttext= substr($line, 0, $start);
if ($starttext =~ /((?:\S|\\\s)+\\\s)$/) {
$starttext= substr($line, 0, $start);
my $startchar= substr($line, $start, 1);
$starttext =~ /^\s*(\S+)\s+/;
if( $starttext =~ /--\w+=(\S*)$/) {
} elsif ( $starttext =~ /\s(\S*)$/) {
} elsif( $starttext =~ /^(\S*)$/) {
# are we in backticks or after a pipe ?
if( $starttext =~ /.*[\|\`]\s*(\S+)\s+/) {
my $firstflag= $starttext !~/\s/ || 0;
$Psh::Completion
::ac
=' ';
$command =~ m
|^\s
*(\S
*/)?
(\S
*)|;
($Psh::debugging
eq '1' or
$Psh::debugging
=~ /c/)) {
Psh
::Util
::print_debug_class
('c',"\n");
Psh
::Util
::print_debug_class
('c',"Completion: text=$text, line=$line, start=$start, starttext=$starttext, command=$command, first=$firstflag\n");
if ($Psh::Completion
::modules
{$cmd= $dir.$base} or
$Psh::Completion
::modules
{$cmd= $base}) {
if ($Psh::PCompletion
::LOADED
) {
# Check completion-spec is defined or not.
my $cs = $Psh::PCompletion
::COMPSPEC
{$cmd = $dir . $base}
|| $Psh::PCompletion
::COMPSPEC
{$cmd = $base};
$cs= $Psh::PCompletion
::COMPSPEC
{'*'};
# Do programmable completion if completion-spec is defined.
# This is done here to keep the compatibility with bash.
# remove prefix string if it is already prefixed.
$text =~ s/^\Q$cs->{prefix}//
if (defined $cs->{prefix
});
@tmp = Psh
::PCompletion
::pcomp_list
($cs, $text, $line, $start, $cmd);
if ($cs->{option
} and $cs->{option
} eq 'default') {
$attribs->{$APPEND}=$Psh::Completion
::ac
;
if ($starttext =~ m/\$([\w:]+)\s*(->)?\s*{\s*['"]?$/) {
@tmp= cmpl_hashkeys
($text, $line, $start);
$Psh::Completion
::ac
= '}';
} elsif ($starttext =~ m/\$([\w:]+)\s*->\s*['"]?$/) {
@tmp= cmpl_method
($text, $line, $start);
$Psh::Completion
::ac
= ' ';
} elsif ( $text =~ /^\$#|[\@\$%&]/) {
# $foo, @foo, $#foo, %foo, &foo
@tmp= cmpl_symbol
($text, $line, $start);
$Psh::Completion
::ac
= '';
} elsif( $firstflag || $starttext =~ /[\|\`]\s*$/) {
# we have the first word in the line or a pipe sign/backtick in front
# of the current item, so we try to complete executables
@tmp = cmpl_filenames
($pretext.$text,1)
@tmp= cmpl_executable
($text);
# Afterwards we add possible matches for perl barewords
push @tmp, cmpl_perl_function
($text);
@tmp = cmpl_filenames
($pretext.$text);
if (Psh
::Strategy
::active
('built_in') and
grep { $_ eq $command } Psh
::Support
::Builtins
::get_builtin_commands
() ) {
my $pkg= ucfirst($command);
eval "require Psh::Builtins::$pkg";
Psh
::Util
::print_debug_class
('e',"Error: $@") if $@
;
my @tmp2= eval 'Psh::Builtins::'.$pkg.'::cmpl_'."$command('$text','$pretext','$starttext','$line')";
$attribs->{$APPEND}=$Psh::Completion
::ac
;
@tmp= map { substr($_, $cut)} @tmp;
my($matches, $num_matches, $max_length) = @_;
my @matches= @
$matches; # make a copy, otherwise there's memory managment trouble
map { $_ =~ s/^((\$#|[\@\$%&])?).*::(.+)/$3/; }(@matches);
my @tmp= split /:/, $ENV{LS_COLORS
};
if (substr($_,0,3) eq 'di=') {
map { $_ =~ s/^([^\/]+)\/$/\001\e[${col}m\002$1\001\e[00m\002\//; } (@matches);
Psh
::Util
::print_list
(\
@matches,$max_length);
# $Psh::term->display_match_list($matches);
$Psh::term
->forced_update_display if defined $Psh::term
;
Psh::Completion - containing the completion routines of psh.
Currently works with Term::ReadLine::Gnu and Term::ReadLine::Perl.
Markus Peter, warp@spin.de
Hiroo Hayashi, hiroo.hayashi@computer.org