# $Id: PCompletion.pm,v 1.20 2003/01/16 19:21:17 gregor Exp $
# Copyright (c) 2000-2003 Hiroo Hayashi. All Rights Reserved.
# This program is free software; you can redistribute it and/or
# modify it under the same terms as Perl itself.
package Psh
::PCompletion
;
use vars
qw(%COMPSPEC %ACTION @ISA @EXPORT_OK);
$Psh::PCompletion::LOADED=1; # tell other packages which optionally want to call us that we're here now
@EXPORT_OK = qw(compgen);
# borrowed from bash-2.04
sub CA_ARRAYVAR
{ 1<<1; }
sub CA_DIRECTORY
{ 1<<5; }
sub CA_DISABLED
{ 1<<6; }
sub CA_FUNCTION
{ 1<<10; }
sub CA_HELPTOPIC
{ 1<<11; }
sub CA_HOSTNAME
{ 1<<12; }
sub CA_KEYWORD
{ 1<<14; }
sub CA_RUNNING
{ 1<<15; }
sub CA_STOPPED
{ 1<<19; }
sub CA_VARIABLE
{ 1<<21; }
arrayvar
=> CA_ARRAYVAR
, # Perl array variable
directory
=> CA_DIRECTORY
,
disabled
=> CA_DISABLED
, # not implemented yet
enabled
=> CA_ENABLED
, # not implemented yet
function
=> CA_FUNCTION
, # Perl function
helptopic
=> CA_HELPTOPIC
,
setopt
=> CA_SETOPT
, # not implemented yet
shopt
=> CA_SHOPT
, # not implemented yet
variable
=> CA_VARIABLE
, # Perl variable
hashvar
=> CA_HASH
, # Perl hash variable
my($__line, $__start, $__cmd);
# global variables for compgen()
#use vars qw($__line $__start $__cmd);
# convert from bash (and ksh?) extglob to Perl regular expression
# ?(...), *(...), +(...) -> ()?, ()*, ()?
s/([^\\])([?*+])\(([^)]*)\)/$1($3)$2/g;
s/^([?*+])\(([^)]*)\)/($2)$1/g;
s/([^\\])@\(([^)]*)\)/$1($2)/g;
# `!(...)' is not supported yet.
my ($cs, $text, $line, $start, $cmd) = @_;
my ($pretext) = substr($line, 0, $start) =~ /(\S*)$/;
if ($cs->{action
} & CA_ALIAS
and !$pretext) {
if (Psh
::Strategy
::active
('built_in')) {
push(@l, grep { /^\Q$text/ } Psh
::Support
::Alias
::get_alias_commands
());
if ($cs->{action
} & CA_BINDING
and !$pretext) {
# only Term::ReadLine::Gnu 1.09 and later support funmap_names()
# use `eval' for other versions
eval { push(@l, grep { /^\Q$text/ } $Psh::term
->funmap_names) };
Psh
::Util
::print_debug_class
('e',"Error: $@") if $@
;
if ($cs->{action
} & CA_BUILTIN
|| $cs->{action
} & CA_HELPTOPIC
) {
if (Psh
::Strategy
::active
('built_in')) {
push(@l, grep { /^\Q$text/ } Psh
::Support
::Builtins
::get_builtin_commands
());
if ($cs->{action
} & CA_COMMAND
and !$pretext) {
push(@l, Psh
::Completion
::cmpl_executable
($text));
if ($cs->{action
} & CA_DIRECTORY
) {
push(@l, Psh
::Completion
::cmpl_directories
($pretext . $text));
if ($cs->{action
} & CA_EXPORT
and !$pretext) {
push(@l, grep { /^\Q$text/ } keys %ENV);
if ($cs->{action
} & CA_FILE
) {
my @f = Psh
::Completion
::cmpl_filenames
($pretext . $text);
if (defined $cs->{ffilterpat
}) {
my $pat = $cs->{ffilterpat
};
$pat = glob2regexp
(substr($pat, 1));
$pat = glob2regexp
($pat);
push(@l, Psh
::Completion
::cmpl_directories
($pretext . $text));
if ($cs->{action
} & CA_HOSTNAME
and !$pretext) {
push(@l, grep { /^\Q$text/ } Psh
::Completion
::bookmarks
());
if ($cs->{action
} & CA_KEYWORD
and !$pretext) {
push(@l, grep { /^\Q$text/ } @Psh::Completion
::keyword
);
if ($cs->{action
} & CA_SIGNAL
and !$pretext) {
push(@l, grep { /^\Q$text/ } grep(!/^__/, keys %SIG));
if ($cs->{action
} & CA_USER
and !$pretext) {
# Why are usernames in @user_completion prepended by `~'?
push(@l, map { substr($_, 1) }
grep { /^~\Q$text/ } Psh
::OS
::get_all_users
());
if ($cs->{action
} & CA_JOB
and !$pretext) {
grep { $_->{call
} =~ /^\Q$text/ }
Psh
::Joblist
::list_jobs
());
if ($cs->{action
} & CA_RUNNING
and !$pretext) {
grep { $_->{running
} && $_->{call
} =~ /^\Q$text/ }
Psh
::Joblist
::list_jobs
());
if ($cs->{action
} & CA_STOPPED
and !$pretext) {
grep { ! $_->{running
} && $_->{call
} =~ /^\Q$text/ }
Psh
::Joblist
::list_jobs
());
# Perl Symbol completions
# printf "[$text,%08x]\n", $cs->{action};
my $pkg = $Psh::PerlEval
::current_package
.'::';
if ($cs->{action
} & CA_VARIABLE
and !$pretext) {
push(@l, grep { /^\w+$/ && /^\Q$text/
&& eval "defined \$$pkg$_" } keys %$pkg);
if ($cs->{action
} & CA_ARRAYVAR
and !$pretext) {
@l = grep {($sym = $pkg . $_, defined *$sym{ARRAY
})
grep { /^\w+$/ && ($sym = $pkg . $_, defined *$sym{ARRAY
})
if ($cs->{action
} & CA_HASH
and !$pretext) {
push(@l, grep { /^\w+$/ && /^\Q$text/
&& ($sym = $pkg . $_, defined *$sym{HASH
})
if ($cs->{action
} & CA_FUNCTION
and !$pretext) {
push(@l, grep { /^\w+$/ && /^\Q$text/
&& ($sym = $pkg . $_, defined *$sym{CODE
})
# This does not work without modifying the specification of
# Term::ReadLine::Perl::completion_function, which matches again
# if (defined $cs->{globpat}) {
# my $pat = glob2regexp($cs->{globpat});
# my $dir = $pretext || '.';
# or warn "cannot open directory `$dir': $!\n", return ();
# push(@l, grep(/$pat/, @d));
push(@l, grep { /^\Q$text/ } split(' ', $cs->{wordlist
}))
if defined $cs->{wordlist
} and !$pretext;
if (defined $cs->{function
} and !$pretext) {
# warn "[$text,$line,$start,$cmd]\n";
$__line = $line; $__start = $start; $__cmd = $cmd; # for compgen()
if ($cs->{function
} =~/^(.*)\:\:[^:]+$/) {
# Function is in a package, so try autoloading it
eval "require $package;";
&{$cs->{functionpackage
}.'::'.$cs->{function
}}($text, $line, $start, $cmd);
push(@l, grep { /^\Q$text/ } @t);
if (defined $cs->{command
} and !$pretext) {
# $ENV{COMP_LINE} = $line;
# $ENV{COMP_POINT} = $start;
my $cmd = "$cs->{command}";
# remove surrounding quotes
$cmd =~ s/^\s*'(.*)'\s*$/$1/;
$cmd =~ s/^\s*"(.*)"\s*$/$1/;
push(@l, grep { chomp, /^\Q$text/ }
`$cmd "$text" "$line" "$start" "$cmd"`);
warn "$0: $cs->{command}: command not found\n" if $?
;
# $ENV{COMP_LINE} = $ENV{COMP_POINT} = undef;
if (defined $cs->{filterpat
}) {
my $pat = $cs->{filterpat
};
$pat = glob2regexp
(substr($pat, 1));
$pat = glob2regexp
($pat);
@l = map { $cs->{prefix
} . $_ } @l if defined $cs->{prefix
};
@l = map { $_ . $cs->{suffix
} } @l if defined $cs->{suffix
};
########################################################################
my $ar = $_[0]; # reference to an array of arguments
while (defined ($ar->[0]) and $_ = $ar->[0], /^-/) {
$cs{action
} |= CA_BUILTIN
;
$cs{action
} |= CA_COMMAND
;
$cs{action
} |= CA_DIRECTORY
;
$cs{action
} |= CA_EXPORT
;
$cs{action
} |= CA_KEYWORD
;
$cs{action
} |= CA_VARIABLE
;
$cs{option
} = Psh
::Parser
::unquote
(shift @
{$ar});
$_ = Psh
::Parser
::unquote
(shift @
{$ar}) || return undef;
$cs{action
} |= $ACTION{$_};
$cs{globpat
} = Psh
::Parser
::unquote
(shift @
{$ar});
$cs{wordlist
} = Psh
::Parser
::unquote
(shift @
{$ar});
$cs{command
} = Psh
::Parser
::unquote
(shift @
{$ar});
$cs{function
} = Psh
::Parser
::unquote
(shift @
{$ar});
$cs{function_package
}= $Psh::PerlEval
::current_package
;
$cs{filterpat
} = Psh
::Parser
::unquote
(shift @
{$ar});
} elsif (/^-x/) { # psh specific (at least now)
$cs{ffilterpat
} = Psh
::Parser
::unquote
(shift @
{$ar});
$cs{prefix
} = Psh
::Parser
::unquote
(shift @
{$ar});
$cs{suffix
} = Psh
::Parser
::unquote
(shift @
{$ar});
return compgen
('-f', $cur);
} elsif (_redir_op
($prev)) {
return compgen
('-f', $cur);
my $cs = pcomp_getopts
($_[0]) or usage_compgen
(), return ;
usage_compgen
() if $cs->{print} or $cs->{remove
} or $#_ > 1;
pcomp_list
($cs, $_[0] || '', $__line, $__start, $__cmd);
compgen [-abcdefjkvu] [-A ACTION] [-G GLOBPAT] [-W WORDLIST]
[-P PREFIX] [-S SUFFIX] [-X FILTERPAT] [-x FILTERPAT]
[-F FUNCTION] [-C COMMAND] [WORD]
# compgen() routine is called by function which is assigned by `-F' option
Psh
::PCompletion
::compgen
(\
@_);